xoseperez / espurna

Home automation firmware for ESP8266-based devices
http://tinkerman.cat
GNU General Public License v3.0
2.98k stars 635 forks source link

Feature Request Sonoff Basic WiFi #1529

Open peteeee opened 5 years ago

peteeee commented 5 years ago

Originally posted this in Gitter and it was suggested that I post it here.

Currently using a SonOff WiFi basic / Tasmota in multiple function mode as a Garage door sensor, opener and have added one DS18B20 sensor for temperature only monitoring. GPIO 4, 14 and a pulse for GDO. (IE: door open sensor, door closed sensor, push button pulse to open garage door and temperature sensor) It has worked fine over the last few months.

Over the last few months though have switched from Tasmota to Espurna firmware.

Automation sand box here using Homeseer MQTT, Home Assistant, Openhab, Domoticz, and Homegenie. (continue to utilize X10, UPB, Zigbee and ZWave). Personally like the Espurna firmware a bit better than Tasmota firmware. Where would I make a request for same functionality using Espurna firmware versus Tasmota custom firmware? I noticed it is much easier to solder modifications to the SonOff WiFi basic board versus the Magic Home RGB controller (which I am currently using with customized Espurna firmware).

In a recap the firmware would be multi functional for use with the modded SonOff WiFi basic device. Hardware modifications to testing SonOff WiFi basic: 1 - cut high voltage traces for relay to use low voltage 2 - soldered pins to RX, TX, Ground, GPIO 4, GPIO14. (GPIO 1,3,4,14) 3 - connected GPIO 3 to one door sensor, GPIO 4 to second door sensor, GPIO 14 to DS18B20.

Using MQTT to monitor status of GPIO 3 and GPIO4 and GPIO 14 and toggle relay for garage door opener.

This is a low cost WiFi basic combination garage door opener, door monitor and temperature sensor.

sonofftasmota

lbdroid commented 5 years ago

So correct me if I'm wrong, but it looks like your objective is just to be able to read the state of the GPIO pins over MQTT, is that correct?

Try this: (which I am using for a garage door opener)

diff --git a/code/espurna/config/hardware.h b/code/espurna/config/hardware.h
index 6068a274..82ce69d7 100644
--- a/code/espurna/config/hardware.h
+++ b/code/espurna/config/hardware.h
@@ -259,19 +259,63 @@
     // Info
     #define MANUFACTURER        "ITEAD"
     #define DEVICE              "SONOFF_BASIC"
+    #define DEBUG_SERIAL_SUPPORT 0
+
+    // Note that GPIOs 4, 5, and 16 are NC and accessible.

     // Buttons
     #define BUTTON1_PIN         0
     #define BUTTON1_MODE        BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
     #define BUTTON1_RELAY       1
+
     #define BUTTON2_PIN         14
-    #define BUTTON2_MODE        BUTTON_SWITCH | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
-    #define BUTTON2_RELAY       1
+    #define BUTTON2_MODE        BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH
+    #define BUTTON2_PRESS  BUTTON_MODE_ON
+    #define BUTTON2_CLICK  BUTTON_MODE_OFF
+    #define BUTTON2_DBLCLICK   BUTTON_MODE_OFF
+    #define BUTTON2_LNGCLICK   BUTTON_MODE_OFF
+    #define BUTTON2_LNGLNGCLICK    BUTTON_MODE_OFF
+    #define BUTTON2_RELAY  2
+
+    #define BUTTON3_PIN        1
+    #define BUTTON3_MODE   BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP
+    #define BUTTON3_PRESS  BUTTON_MODE_ON
+    #define BUTTON3_CLICK  BUTTON_MODE_OFF
+    #define BUTTON3_DBLCLICK   BUTTON_MODE_OFF
+    #define BUTTON3_LNGCLICK   BUTTON_MODE_OFF
+    #define BUTTON3_LNGLNGCLICK    BUTTON_MODE_OFF
+    #define BUTTON3_RELAY  3
+
+    #define BUTTON4_PIN        3
+    #define BUTTON4_MODE   BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP
+    #define BUTTON4_PRESS  BUTTON_MODE_ON
+    #define BUTTON4_CLICK  BUTTON_MODE_OFF
+    #define BUTTON4_DBLCLICK   BUTTON_MODE_OFF
+    #define BUTTON4_LNGCLICK   BUTTON_MODE_OFF
+    #define BUTTON4_LNGLNGCLICK    BUTTON_MODE_OFF
+    #define BUTTON4_RELAY  4

     // Relays
     #define RELAY1_PIN          12
     #define RELAY1_TYPE         RELAY_TYPE_NORMAL

+    // Fake relays defined manually.
+    #define RELAY2_PIN     0
+    #define RELAY2_TYPE        RELAY_TYPE_FAKE
+    #define RELAY2_RESET_PIN   0
+    #define RELAY2_DELAY_ON    0
+    #define RELAY2_DELAY_OFF   0
+    #define RELAY3_PIN     0
+    #define RELAY3_TYPE        RELAY_TYPE_FAKE
+    #define RELAY3_RESET_PIN   0
+    #define RELAY3_DELAY_ON    0
+    #define RELAY3_DELAY_OFF   0
+    #define RELAY4_PIN     0
+    #define RELAY4_TYPE        RELAY_TYPE_FAKE
+    #define RELAY4_RESET_PIN   0
+    #define RELAY4_DELAY_ON    0
+    #define RELAY4_DELAY_OFF   0
+
     // LEDs
     #define LED1_PIN            13
     #define LED1_PIN_INVERSE    1

diff --git a/code/espurna/config/types.h b/code/espurna/config/types.h
index a984bb7e..aabebf82 100644
--- a/code/espurna/config/types.h
+++ b/code/espurna/config/types.h
@@ -68,6 +68,7 @@
 #define RELAY_TYPE_INVERSE          1
 #define RELAY_TYPE_LATCHED          2
 #define RELAY_TYPE_LATCHED_INVERSE  3
+#define RELAY_TYPE_FAKE             4

 #define RELAY_SYNC_ANY              0
 #define RELAY_SYNC_NONE_OR_ONE      1
diff --git a/code/espurna/relay.ino b/code/espurna/relay.ino
index df01fbc4..9bcd27be 100644
--- a/code/espurna/relay.ino
+++ b/code/espurna/relay.ino
@@ -558,7 +558,7 @@ void _relayBoot() {
 void _relayConfigure() {
     for (unsigned int i=0; i<_relays.size(); i++) {
         pinMode(_relays[i].pin, OUTPUT);
-        if (GPIO_NONE != _relays[i].reset_pin) {
+        if (GPIO_NONE != _relays[i].reset_pin && RELAY_TYPE_FAKE != _relays[i].type) {
             pinMode(_relays[i].reset_pin, OUTPUT);
         }
         if (_relays[i].type == RELAY_TYPE_INVERSE) {
@@ -583,7 +583,7 @@ bool _relayWebSocketOnReceive(const char * key, JsonVariant& value) {
 void _relayWebSocketUpdate(JsonObject& root) {
     JsonArray& relay = root.createNestedArray("relayStatus");
     for (unsigned char i=0; i<relayCount(); i++) {
-        relay.add(_relays[i].target_status);
+        if (_relays[i].type != RELAY_TYPE_FAKE) relay.add(_relays[i].target_status);
     }
 }

@@ -597,18 +597,20 @@ void _relayWebSocketOnStart(JsonObject& root) {
     // Configuration
     JsonArray& config = root.createNestedArray("relayConfig");
     for (unsigned char i=0; i<relayCount(); i++) {
-        JsonObject& line = config.createNestedObject();
-        line["gpio"] = _relays[i].pin;
-        line["type"] = _relays[i].type;
-        line["reset"] = _relays[i].reset_pin;
-        line["boot"] = getSetting("relayBoot", i, RELAY_BOOT_MODE).toInt();
-        line["pulse"] = _relays[i].pulse;
-        line["pulse_ms"] = _relays[i].pulse_ms / 1000.0;
-        #if MQTT_SUPPORT
-            line["group"] = getSetting("mqttGroup", i, "");
-            line["group_inv"] = getSetting("mqttGroupInv", i, 0).toInt();
-            line["on_disc"] = getSetting("relayOnDisc", i, 0).toInt();
-        #endif
+        if (_relays[i].type != RELAY_TYPE_FAKE){
+            JsonObject& line = config.createNestedObject();
+            line["gpio"] = _relays[i].pin;
+            line["type"] = _relays[i].type;
+            line["reset"] = _relays[i].reset_pin;
+            line["boot"] = getSetting("relayBoot", i, RELAY_BOOT_MODE).toInt();
+            line["pulse"] = _relays[i].pulse;
+            line["pulse_ms"] = _relays[i].pulse_ms / 1000.0;
+            #if MQTT_SUPPORT
+                line["group"] = getSetting("mqttGroup", i, "");
+                line["group_inv"] = getSetting("mqttGroupInv", i, 0).toInt();
+                line["on_disc"] = getSetting("relayOnDisc", i, 0).toInt();
+            #endif
+        }
     }

     if (relayCount() > 1) {
@@ -841,7 +843,7 @@ void relayMQTTCallback(unsigned int type, const char * topic, const char * paylo

             unsigned int id = t.substring(strlen(MQTT_TOPIC_PULSE)+1).toInt();

-            if (id >= relayCount()) {
+            if (id >= relayCount() || _relays[id].type==RELAY_TYPE_FAKE) {
                 DEBUG_MSG_P(PSTR("[RELAY] Wrong relayID (%d)\n"), id);
                 return;
             }
@@ -866,7 +868,7 @@ void relayMQTTCallback(unsigned int type, const char * topic, const char * paylo

             // Get relay ID
             unsigned int id = t.substring(strlen(MQTT_TOPIC_RELAY)+1).toInt();
-            if (id >= relayCount()) {
+            if (id >= relayCount() || _relays[id].type==RELAY_TYPE_FAKE) {
                 DEBUG_MSG_P(PSTR("[RELAY] Wrong relayID (%d)\n"), id);
                 return;
             }

I also suggest adding a transistor to the I/O pins you are using to attach to the garage door opener's limit switches. Even if your door opener is reading 3.3v, the unknown circuit doesn't give you any guarantees. You can use something easy like 2N7000, attach the gate to the switch on the garage door opener motor, source to ground (which should be common between the sonoff and the garage door opener, you can safely ignore the children who write the wiki at tasmota with their claims that it will catch on fire with a common ground -- its utter nonsense), and drain to the I/O pin on the sonoff.

peteeee commented 5 years ago

@lbdroid

So correct me if I'm wrong, but it looks like your objective is just to be able to read the state of the GPIO pins over MQTT, is that correct?

Yes thank you and utilize the relay and connect one DS18B20. Doing that now using Tasmota firmware as shown above. I just want to change over to using Espurna firmware.

I am still learning to program the firmware and really not well at doing this.

There are no direct connections from the SonOff Wifi Basic to anything directly connected to the GDO. There are two sets of autonomously wired limit switches (magnetic switches on the door). Two plus button are wired to the Leviton Omni Pro 2 combo security panel. Two plus another button are for testing the Sonoff / MQTT stuff.

1 - GPIO 3 and GPIO 4 connect to two magnetic switches. One mounted low on the garage door rail and one mounted high for closed, open and intermediate views of the garage door. Common comes from the Sonoff basic Wifi.

2 - GPIO 14 is used for the DS18B20 (DQ, VCC and ground) DQ has a resistor to VCC.

3 - the relay is used for the button. The new button is a hardware modified digital button programmed to the GDO.

In fact due to automating the GDO in the 1990's there is a set of limited rules. IE: back then and today it is connected to an alarm panel with hard wired up and down switches and button to the Leviton OmniPro 2 alarm panel. All built in saftey features are all connected as originally installed. I would not recommend anyone play with these features.

Way long time ago in the 1990's the GDO was automated and sync'd to the alarm panel. Wife drove in to the garage while on a conference call leaving the car running and not shutting off the alarm. The GDO automagically closed the garage door and she freaked out. Since then I go slow with the automation of the GDO. I also utilize RFID tags on the vehicles to ID which one is where plus utilize under the driveway hard wired sensors and wired PIR sensors inside and ouside plus CCTV.

xoseperez commented 5 years ago

As an alternate method to the one proposed by @lbdroid, there is also the option to use the DigitalSensor or the EventSensor to monitor GPIO statuses. Unfortunately, we cannot configure them on the fly yet (hopefully soon).

peteeee commented 5 years ago

Thank you @xoseperez

lbdroid commented 4 years ago

@xoseperez: correct me if I'm wrong, but it is currently only possible to configure ONE DigitalSensor pin on a board. Is my understanding correct?

And EventSensor, while it can be applied to up to 10 pins, only can register transitions, not states.

I think that DigitalSensor would be excellent, IF it were to be expanded to work with more than just one pin.