├── .gitignore ├── LICENSE ├── README.md ├── arduino ├── ESP OTA Id Map.txt ├── ESPsonoff-v1.01p │ └── ESPsonoff-v1.01p.ino ├── ESPsonoff-v1.01pOTA │ └── ESPsonoff-v1.01pOTA.ino ├── ESPsonoff-v1.01t │ └── ESPsonoff-v1.01t.ino ├── ESPsonoff-v1.01tOTA │ └── ESPsonoff-v1.01tOTA.ino ├── ESPsonoff-v1.0p │ └── ESPsonoff-v1.0p.ino ├── ESPsonoff-v1.0t │ └── ESPsonoff-v1.0t.ino ├── ESPsonoff_4CH-v1.01p │ └── ESPsonoff_4CH-v1.01p.ino ├── ESPsonoff_4CH-v1.01pOTA │ └── ESPsonoff_4CH-v1.01pOTA.ino ├── ESPsonoff_POW-v1.0 │ ├── ESPsonoff_POW-v1.0.ino │ ├── power.cpp │ └── power.h ├── ESPsonoff_POW-v1.01 │ ├── ESPsonoff_POW-v1.01.ino │ ├── power.cpp │ └── power.h ├── ESPsonoff_TH-v1.01p │ └── ESPsonoff_TH-v1.01p.ino ├── ESPsonoff_TH-v1.01pOTA │ └── ESPsonoff_TH-v1.01pOTA.ino ├── ESPsonoff_TH-v1.01pt │ └── ESPsonoff_TH-v1.01pt.ino ├── ESPsonoff_TH-v1.01ptOTA │ └── ESPsonoff_TH-v1.01ptOTA.ino ├── ESPsonoff_TH-v1.01t │ └── ESPsonoff_TH-v1.01t.ino ├── ESPsonoff_TH-v1.01tOTA │ └── ESPsonoff_TH-v1.01tOTA.ino ├── ESPsonoff_TH-v1.0p │ └── ESPsonoff_TH-v1.0p.ino └── ESPsonoff_TH-v1.0t │ └── ESPsonof_TH-v1.0t.ino ├── home-assistant ├── living_room_switch.yaml └── sensors.yaml └── images ├── sensor_wiring.jpg ├── sonoff.png ├── sonoff_temp.JPG ├── th10.JPG └── th10ftdi.JPG /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /arduino/ESP OTA Id Map.txt: -------------------------------------------------------------------------------- 1 | esp8266 OTA Unit ID Map 2 | 3 | NAME UNIT TYPE LOCATION MQTT TOPIC INFO 4 | ------------------------------------------------------------------------------------------------------------------------------------------- 5 | * esp8266-xxxxxx Sonoff TH IT Cupboard home/sonoff/IT_closet/1 Plugged into Cupboard Fan 6 | * esp8266-xxxxxx Sonoff LED Workbench home/sonoff_led/test Above Workbench 7 | * esp8266-xxxxxx ESP8266MOD Workbench home/esp_devices/workbench Test unit on Protoboard 8 | * esp8266-xxxxxx Basic Sonoff Garage home/sonoff/garage/1 Main light switch behind Wallswitch 9 | -------------------------------------------------------------------------------- /arduino/ESPsonoff-v1.01p/ESPsonoff-v1.01p.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2017 @KmanOz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | ============================================================================== 24 | Changes in v1.01 25 | 26 | - Relay state now stored in EEPROM and will power up with last relay state 27 | ============================================================================== 28 | 29 | **** USE THIS Firmware for: Original Sonoff, Sonoff SV, Sonoff Touch, Sonoff S20 Smart Socket **** 30 | 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #define BUTTON 0 // (Don't Change for Original Sonoff, Sonoff SV, Sonoff Touch, Sonoff S20 Socket) 39 | #define RELAY 12 // (Don't Change for Original Sonoff, Sonoff SV, Sonoff Touch, Sonoff S20 Socket) 40 | #define LED 13 // (Don't Change for Original Sonoff, Sonoff SV, Sonoff Touch, Sonoff S20 Socket) 41 | 42 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.01p" // mqtt client_id (Must be unique for each Sonoff) 43 | #define MQTT_SERVER "192.168.0.100" // mqtt server 44 | #define MQTT_PORT 1883 // mqtt port 45 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 46 | #define MQTT_USER "user" // mqtt user 47 | #define MQTT_PASS "pass" // mqtt password 48 | 49 | #define WIFI_SSID "homewifi" // wifi ssid 50 | #define WIFI_PASS "homepass" // wifi password 51 | 52 | #define VERSION "\n\n------------------ Sonoff Powerpoint v1.01p ------------------" 53 | 54 | bool rememberRelayState = true; // If 'true' remembers the state of the relay before power loss. 55 | bool sendStatus = false; // (Do not Change) 56 | bool requestRestart = false; // (Do not Change) 57 | 58 | int kUpdFreq = 1; // Update frequency in Mintes to check for mqtt connection 59 | int kRetries = 10; // WiFi retry count. Increase if not connecting to router. 60 | int lastRelayState; // (Do not Change) 61 | 62 | unsigned long TTasks; // (Do not Change) 63 | unsigned long count = 0; // (Do not Change) 64 | 65 | extern "C" { 66 | #include "user_interface.h" 67 | } 68 | 69 | WiFiClient wifiClient; 70 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 71 | Ticker btn_timer; 72 | 73 | void callback(const MQTT::Publish& pub) { 74 | if (pub.payload_string() == "stat") { 75 | } 76 | else if (pub.payload_string() == "on") { 77 | digitalWrite(LED, LOW); 78 | digitalWrite(RELAY, HIGH); 79 | } 80 | else if (pub.payload_string() == "off") { 81 | digitalWrite(LED, HIGH); 82 | digitalWrite(RELAY, LOW); 83 | } 84 | else if (pub.payload_string() == "reset") { 85 | requestRestart = true; 86 | } 87 | sendStatus = true; 88 | } 89 | 90 | void setup() { 91 | pinMode(LED, OUTPUT); 92 | pinMode(RELAY, OUTPUT); 93 | pinMode(BUTTON, INPUT); 94 | digitalWrite(LED, HIGH); 95 | digitalWrite(RELAY, LOW); 96 | Serial.begin(115200); 97 | EEPROM.begin(8); 98 | lastRelayState = EEPROM.read(0); 99 | if (rememberRelayState && lastRelayState == 1) { 100 | digitalWrite(LED, LOW); 101 | digitalWrite(RELAY, HIGH); 102 | } 103 | btn_timer.attach(0.05, button); 104 | mqttClient.set_callback(callback); 105 | WiFi.mode(WIFI_STA); 106 | WiFi.begin(WIFI_SSID, WIFI_PASS); 107 | Serial.println(VERSION); 108 | Serial.print("\nUnit ID: "); 109 | Serial.print("esp8266-"); 110 | Serial.print(ESP.getChipId(), HEX); 111 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 112 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 113 | delay(500); 114 | Serial.print(" ."); 115 | } 116 | if (WiFi.status() == WL_CONNECTED) { 117 | Serial.println(" DONE"); 118 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 119 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 120 | delay(500); 121 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 122 | Serial.print(" ."); 123 | delay(1000); 124 | } 125 | if(mqttClient.connected()) { 126 | Serial.println(" DONE"); 127 | Serial.println("\n---------------------------- Logs ----------------------------"); 128 | Serial.println(); 129 | mqttClient.subscribe(MQTT_TOPIC); 130 | blinkLED(LED, 40, 8); 131 | if(digitalRead(RELAY) == HIGH) { 132 | digitalWrite(LED, LOW); 133 | } else { 134 | digitalWrite(LED, HIGH); 135 | } 136 | } 137 | else { 138 | Serial.println(" FAILED!"); 139 | Serial.println("\n----------------------------------------------------------------"); 140 | Serial.println(); 141 | } 142 | } 143 | else { 144 | Serial.println(" WiFi FAILED!"); 145 | Serial.println("\n----------------------------------------------------------------"); 146 | Serial.println(); 147 | } 148 | } 149 | 150 | void loop() { 151 | mqttClient.loop(); 152 | timedTasks(); 153 | checkStatus(); 154 | } 155 | 156 | void blinkLED(int pin, int duration, int n) { 157 | for(int i=0; i 1 && count <= 40) { 171 | digitalWrite(LED, !digitalRead(LED)); 172 | digitalWrite(RELAY, !digitalRead(RELAY)); 173 | sendStatus = true; 174 | } 175 | else if (count >40){ 176 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 177 | requestRestart = true; 178 | } 179 | count=0; 180 | } 181 | } 182 | 183 | void checkConnection() { 184 | if (WiFi.status() == WL_CONNECTED) { 185 | if (mqttClient.connected()) { 186 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 187 | } 188 | else { 189 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 190 | requestRestart = true; 191 | } 192 | } 193 | else { 194 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 195 | requestRestart = true; 196 | } 197 | } 198 | 199 | void checkStatus() { 200 | if (sendStatus) { 201 | if(digitalRead(LED) == LOW) { 202 | if (rememberRelayState) { 203 | EEPROM.write(0, 1); 204 | } 205 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 206 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 207 | } else { 208 | if (rememberRelayState) { 209 | EEPROM.write(0, 0); 210 | } 211 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 212 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 213 | } 214 | if (rememberRelayState) { 215 | EEPROM.commit(); 216 | } 217 | sendStatus = false; 218 | } 219 | if (requestRestart) { 220 | blinkLED(LED, 400, 4); 221 | ESP.restart(); 222 | } 223 | } 224 | 225 | void timedTasks() { 226 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 227 | TTasks = millis(); 228 | checkConnection(); 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /arduino/ESPsonoff-v1.01pOTA/ESPsonoff-v1.01pOTA.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2017 @KmanOz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | ============================================================================== 24 | Changes in v1.01pOTA 25 | 26 | - Relay state now stored in EEPROM and will power up with last relay state 27 | - OTA Firmware Upgradable 28 | ============================================================================== 29 | 30 | **** USE THIS Firmware for: Original Sonoff, Sonoff SV, Sonoff Touch, Sonoff S20 Smart Socket **** 31 | 32 | */ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #define BUTTON 0 // (Don't Change for Original Sonoff, Sonoff SV, Sonoff Touch, Sonoff S20 Socket) 43 | #define RELAY 12 // (Don't Change for Original Sonoff, Sonoff SV, Sonoff Touch, Sonoff S20 Socket) 44 | #define LED 13 // (Don't Change for Original Sonoff, Sonoff SV, Sonoff Touch, Sonoff S20 Socket) 45 | 46 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.01pOTA" // mqtt client_id (Must be unique for each Sonoff) 47 | #define MQTT_SERVER "192.168.0.100" // mqtt server 48 | #define MQTT_PORT 1883 // mqtt port 49 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 50 | #define MQTT_USER "user" // mqtt user 51 | #define MQTT_PASS "pass" // mqtt password 52 | 53 | #define WIFI_SSID "homewifi" // wifi ssid 54 | #define WIFI_PASS "homepass" // wifi password 55 | 56 | #define VERSION "\n\n---------------- Sonoff Powerpoint v1.01pOTA -----------------" 57 | 58 | bool rememberRelayState = true; // If 'true' remembers the state of the relay before power loss. 59 | bool OTAupdate = false; // (Do not Change) 60 | bool sendStatus = false; // (Do not Change) 61 | bool requestRestart = false; // (Do not Change) 62 | 63 | int kUpdFreq = 1; // Update frequency in Mintes to check for mqtt connection 64 | int kRetries = 10; // WiFi retry count. Increase if not connecting to router. 65 | int lastRelayState; // (Do not Change) 66 | 67 | unsigned long TTasks; // (Do not Change) 68 | unsigned long count = 0; // (Do not Change) 69 | 70 | extern "C" { 71 | #include "user_interface.h" 72 | } 73 | 74 | WiFiClient wifiClient; 75 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 76 | Ticker btn_timer; 77 | 78 | void callback(const MQTT::Publish& pub) { 79 | if (pub.payload_string() == "stat") { 80 | } 81 | else if (pub.payload_string() == "on") { 82 | digitalWrite(LED, LOW); 83 | digitalWrite(RELAY, HIGH); 84 | } 85 | else if (pub.payload_string() == "off") { 86 | digitalWrite(LED, HIGH); 87 | digitalWrite(RELAY, LOW); 88 | } 89 | else if (pub.payload_string() == "reset") { 90 | requestRestart = true; 91 | } 92 | sendStatus = true; 93 | } 94 | 95 | void setup() { 96 | pinMode(LED, OUTPUT); 97 | pinMode(RELAY, OUTPUT); 98 | pinMode(BUTTON, INPUT); 99 | digitalWrite(LED, HIGH); 100 | digitalWrite(RELAY, LOW); 101 | Serial.begin(115200); 102 | EEPROM.begin(8); 103 | lastRelayState = EEPROM.read(0); 104 | if (rememberRelayState && lastRelayState == 1) { 105 | digitalWrite(LED, LOW); 106 | digitalWrite(RELAY, HIGH); 107 | } 108 | btn_timer.attach(0.05, button); 109 | mqttClient.set_callback(callback); 110 | WiFi.mode(WIFI_STA); 111 | WiFi.begin(WIFI_SSID, WIFI_PASS); 112 | ArduinoOTA.onStart([]() { 113 | OTAupdate = true; 114 | blinkLED(LED, 400, 2); 115 | digitalWrite(LED, HIGH); 116 | Serial.println("OTA Update Initiated . . ."); 117 | }); 118 | ArduinoOTA.onEnd([]() { 119 | Serial.println("\nOTA Update Ended . . .s"); 120 | ESP.restart(); 121 | }); 122 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { 123 | digitalWrite(LED, LOW); 124 | delay(5); 125 | digitalWrite(LED, HIGH); 126 | Serial.printf("Progress: %u%%\r", (progress / (total / 100))); 127 | }); 128 | ArduinoOTA.onError([](ota_error_t error) { 129 | blinkLED(LED, 40, 2); 130 | OTAupdate = false; 131 | Serial.printf("OTA Error [%u] ", error); 132 | if (error == OTA_AUTH_ERROR) Serial.println(". . . . . . . . . . . . . . . Auth Failed"); 133 | else if (error == OTA_BEGIN_ERROR) Serial.println(". . . . . . . . . . . . . . . Begin Failed"); 134 | else if (error == OTA_CONNECT_ERROR) Serial.println(". . . . . . . . . . . . . . . Connect Failed"); 135 | else if (error == OTA_RECEIVE_ERROR) Serial.println(". . . . . . . . . . . . . . . Receive Failed"); 136 | else if (error == OTA_END_ERROR) Serial.println(". . . . . . . . . . . . . . . End Failed"); 137 | }); 138 | ArduinoOTA.begin(); 139 | Serial.println(VERSION); 140 | Serial.print("\nUnit ID: "); 141 | Serial.print("esp8266-"); 142 | Serial.print(ESP.getChipId(), HEX); 143 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 144 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 145 | delay(500); 146 | Serial.print(" ."); 147 | } 148 | if (WiFi.status() == WL_CONNECTED) { 149 | Serial.println(" DONE"); 150 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 151 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 152 | delay(500); 153 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 154 | Serial.print(" ."); 155 | delay(1000); 156 | } 157 | if(mqttClient.connected()) { 158 | Serial.println(" DONE"); 159 | Serial.println("\n---------------------------- Logs ----------------------------"); 160 | Serial.println(); 161 | mqttClient.subscribe(MQTT_TOPIC); 162 | blinkLED(LED, 40, 8); 163 | if(digitalRead(RELAY) == HIGH) { 164 | digitalWrite(LED, LOW); 165 | } else { 166 | digitalWrite(LED, HIGH); 167 | } 168 | } 169 | else { 170 | Serial.println(" FAILED!"); 171 | Serial.println("\n----------------------------------------------------------------"); 172 | Serial.println(); 173 | } 174 | } 175 | else { 176 | Serial.println(" WiFi FAILED!"); 177 | Serial.println("\n----------------------------------------------------------------"); 178 | Serial.println(); 179 | } 180 | } 181 | 182 | void loop() { 183 | ArduinoOTA.handle(); 184 | if (OTAupdate == false) { 185 | mqttClient.loop(); 186 | timedTasks(); 187 | checkStatus(); 188 | } 189 | } 190 | 191 | void blinkLED(int pin, int duration, int n) { 192 | for(int i=0; i 1 && count <= 40) { 206 | digitalWrite(LED, !digitalRead(LED)); 207 | digitalWrite(RELAY, !digitalRead(RELAY)); 208 | sendStatus = true; 209 | } 210 | else if (count >40){ 211 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 212 | requestRestart = true; 213 | } 214 | count=0; 215 | } 216 | } 217 | 218 | void checkConnection() { 219 | if (WiFi.status() == WL_CONNECTED) { 220 | if (mqttClient.connected()) { 221 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 222 | } 223 | else { 224 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 225 | requestRestart = true; 226 | } 227 | } 228 | else { 229 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 230 | requestRestart = true; 231 | } 232 | } 233 | 234 | void checkStatus() { 235 | if (sendStatus) { 236 | if(digitalRead(LED) == LOW) { 237 | if (rememberRelayState) { 238 | EEPROM.write(0, 1); 239 | } 240 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 241 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 242 | } else { 243 | if (rememberRelayState) { 244 | EEPROM.write(0, 0); 245 | } 246 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 247 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 248 | } 249 | if (rememberRelayState) { 250 | EEPROM.commit(); 251 | } 252 | sendStatus = false; 253 | } 254 | if (requestRestart) { 255 | blinkLED(LED, 400, 4); 256 | ESP.restart(); 257 | } 258 | } 259 | 260 | void timedTasks() { 261 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 262 | TTasks = millis(); 263 | checkConnection(); 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /arduino/ESPsonoff-v1.01t/ESPsonoff-v1.01t.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2017 @KmanOz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | ============================================================================== 24 | Changes in v1.01 25 | 26 | - Relay state now stored in EEPROM and will power up from power loss with 27 | last relay state. 28 | ============================================================================== 29 | 30 | **** USE THIS Firmware for: Original Sonof fitted with DHT22 as per Github Instructions **** 31 | 32 | */ 33 | 34 | #include "DHT.h" 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #define BUTTON 0 // (Don't Change for Sonoff) 41 | #define RELAY 12 // (Don't Change for Sonoff) 42 | #define LED 13 // (Don't Change for Sonoff) 43 | #define DHTPIN 14 // (Don't Change for Sonoff) 44 | 45 | #define DHTTYPE DHT22 // (11 or 22) DHT Type 46 | 47 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.01t" // mqtt client_id (Must be unique for each Sonoff) 48 | #define MQTT_SERVER "192.168.0.100" // mqtt server 49 | #define MQTT_PORT 1883 // mqtt port 50 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 51 | #define MQTT_USER "user" // mqtt user 52 | #define MQTT_PASS "pass" // mqtt password 53 | 54 | #define WIFI_SSID "homewifi" // wifi ssid 55 | #define WIFI_PASS "homepass" // wifi password 56 | 57 | #define VERSION "\n\n------------------ Sonoff Powerpoint v1.01t ------------------" 58 | 59 | bool rememberRelayState = true; // If 'true' remembers the state of the relay before power loss. 60 | bool sendStatus = false; // (Do not Change) 61 | bool requestRestart = false; // (Do not Change) 62 | bool tempReport = false; // (Do not Change) 63 | 64 | int kUpdFreq = 1; // Update frequency in Mintes to check for mqtt connection 65 | int kRetries = 10; // WiFi retry count. Increase if not connecting to router. 66 | int lastRelayState; // (Do not Change) 67 | 68 | unsigned long TTasks; // (Do not Change) 69 | unsigned long count = 0; // (Do not Change) 70 | 71 | DHT dht(DHTPIN, DHTTYPE, 11); // (Don't Change for Sonoff) 72 | 73 | extern "C" { 74 | #include "user_interface.h" 75 | } 76 | 77 | WiFiClient wifiClient; 78 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 79 | Ticker btn_timer; 80 | 81 | void callback(const MQTT::Publish& pub) { 82 | if (pub.payload_string() == "stat") { 83 | } 84 | else if (pub.payload_string() == "on") { 85 | digitalWrite(LED, LOW); 86 | digitalWrite(RELAY, HIGH); 87 | } 88 | else if (pub.payload_string() == "off") { 89 | digitalWrite(LED, HIGH); 90 | digitalWrite(RELAY, LOW); 91 | } 92 | else if (pub.payload_string() == "reset") { 93 | requestRestart = true; 94 | } 95 | sendStatus = true; 96 | } 97 | 98 | void setup() { 99 | pinMode(LED, OUTPUT); 100 | pinMode(RELAY, OUTPUT); 101 | pinMode(BUTTON, INPUT); 102 | digitalWrite(LED, HIGH); 103 | digitalWrite(RELAY, LOW); 104 | Serial.begin(115200); 105 | EEPROM.begin(8); 106 | lastRelayState = EEPROM.read(0); 107 | if (rememberRelayState && lastRelayState == 1) { 108 | digitalWrite(LED, LOW); 109 | digitalWrite(RELAY, HIGH); 110 | } 111 | btn_timer.attach(0.05, button); 112 | mqttClient.set_callback(callback); 113 | WiFi.mode(WIFI_STA); 114 | WiFi.begin(WIFI_SSID, WIFI_PASS); 115 | Serial.println(VERSION); 116 | Serial.print("\nUnit ID: "); 117 | Serial.print("esp8266-"); 118 | Serial.print(ESP.getChipId(), HEX); 119 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 120 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 121 | delay(500); 122 | Serial.print(" ."); 123 | } 124 | if (WiFi.status() == WL_CONNECTED) { 125 | Serial.println(" DONE"); 126 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 127 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 128 | delay(500); 129 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 130 | Serial.print(" ."); 131 | delay(1000); 132 | } 133 | if(mqttClient.connected()) { 134 | Serial.println(" DONE"); 135 | Serial.println("\n---------------------------- Logs ----------------------------"); 136 | Serial.println(); 137 | mqttClient.subscribe(MQTT_TOPIC); 138 | blinkLED(LED, 40, 8); 139 | if(digitalRead(RELAY) == HIGH) { 140 | digitalWrite(LED, LOW); 141 | } else { 142 | digitalWrite(LED, HIGH); 143 | } 144 | } 145 | else { 146 | Serial.println(" FAILED!"); 147 | Serial.println("\n----------------------------------------------------------------"); 148 | Serial.println(); 149 | } 150 | } 151 | else { 152 | Serial.println(" WiFi FAILED!"); 153 | Serial.println("\n----------------------------------------------------------------"); 154 | Serial.println(); 155 | } 156 | } 157 | 158 | void loop() { 159 | mqttClient.loop(); 160 | timedTasks(); 161 | checkStatus(); 162 | if (tempReport) { 163 | getTemp(); 164 | } 165 | } 166 | 167 | void blinkLED(int pin, int duration, int n) { 168 | for(int i=0; i 1 && count <= 40) { 182 | digitalWrite(LED, !digitalRead(LED)); 183 | digitalWrite(RELAY, !digitalRead(RELAY)); 184 | sendStatus = true; 185 | } 186 | else if (count >40){ 187 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 188 | requestRestart = true; 189 | } 190 | count=0; 191 | } 192 | } 193 | 194 | void checkConnection() { 195 | if (WiFi.status() == WL_CONNECTED) { 196 | if (mqttClient.connected()) { 197 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 198 | } 199 | else { 200 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 201 | requestRestart = true; 202 | } 203 | } 204 | else { 205 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 206 | requestRestart = true; 207 | } 208 | } 209 | 210 | void checkStatus() { 211 | if (sendStatus) { 212 | if(digitalRead(LED) == LOW) { 213 | if (rememberRelayState) { 214 | EEPROM.write(0, 1); 215 | } 216 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 217 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 218 | } else { 219 | if (rememberRelayState) { 220 | EEPROM.write(0, 0); 221 | } 222 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 223 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 224 | } 225 | if (rememberRelayState) { 226 | EEPROM.commit(); 227 | } 228 | sendStatus = false; 229 | } 230 | if (requestRestart) { 231 | blinkLED(LED, 400, 4); 232 | ESP.restart(); 233 | } 234 | } 235 | 236 | void getTemp() { 237 | Serial.print("DHT read . . . . . . . . . . . . . . . . . "); 238 | float dhtH, dhtT; 239 | char message_buff[60]; 240 | dhtH = dht.readHumidity(); 241 | dhtT = dht.readTemperature(); 242 | if(digitalRead(LED) == LOW) { 243 | blinkLED(LED, 100, 1); 244 | } else { 245 | blinkLED(LED, 100, 1); 246 | digitalWrite(LED, HIGH); 247 | } 248 | if (isnan(dhtH) || isnan(dhtT)) { 249 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug","\"DHT Read Error\"").set_retain().set_qos(1)); 250 | Serial.println("ERROR"); 251 | tempReport = false; 252 | return; 253 | } 254 | String pubString = "{\"Temp\": "+String(dhtT)+", "+"\"Humidity\": "+String(dhtH) + "}"; 255 | pubString.toCharArray(message_buff, pubString.length()+1); 256 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/temp", message_buff).set_retain().set_qos(1)); 257 | Serial.println("OK"); 258 | tempReport = false; 259 | } 260 | 261 | void timedTasks() { 262 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 263 | TTasks = millis(); 264 | checkConnection(); 265 | tempReport = true; 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /arduino/ESPsonoff-v1.01tOTA/ESPsonoff-v1.01tOTA.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2017 @KmanOz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | ============================================================================== 24 | Changes in v1.01tOTA 25 | 26 | - Relay state now stored in EEPROM and will power up with last relay state 27 | - OTA Firmware Upgradable 28 | ============================================================================== 29 | 30 | **** USE THIS Firmware for: Original Sonof fitted with DHT22 as per Github Instructions **** 31 | 32 | */ 33 | 34 | #include "DHT.h" 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #define BUTTON 0 // (Don't Change for Sonoff) 44 | #define RELAY 12 // (Don't Change for Sonoff) 45 | #define LED 13 // (Don't Change for Sonoff) 46 | #define DHTPIN 14 // (Don't Change for Sonoff) 47 | 48 | #define DHTTYPE DHT22 // (11 or 22) DHT Type 49 | 50 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.01tOTA" // mqtt client_id (Must be unique for each Sonoff) 51 | #define MQTT_SERVER "192.168.0.100" // mqtt server 52 | #define MQTT_PORT 1883 // mqtt port 53 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 54 | #define MQTT_USER "user" // mqtt user 55 | #define MQTT_PASS "pass" // mqtt password 56 | 57 | #define WIFI_SSID "homewifi" // wifi ssid 58 | #define WIFI_PASS "homepass" // wifi password 59 | 60 | #define VERSION "\n\n---------------- Sonoff Powerpoint v1.01tOTA -----------------" 61 | 62 | bool rememberRelayState = true; // If 'true' remembers the state of the relay before power loss. 63 | bool OTAupdate = false; // (Do not Change) 64 | bool sendStatus = false; // (Do not Change) 65 | bool requestRestart = false; // (Do not Change) 66 | bool tempReport = false; // (Do not Change) 67 | 68 | int kUpdFreq = 1; // Update frequency in Mintes to check for mqtt connection 69 | int kRetries = 10; // WiFi retry count. Increase if not connecting to router. 70 | int lastRelayState; // (Do not Change) 71 | 72 | unsigned long TTasks; // (Do not Change) 73 | unsigned long count = 0; // (Do not Change) 74 | 75 | DHT dht(DHTPIN, DHTTYPE, 11); // (Don't Change for Sonoff) 76 | 77 | extern "C" { 78 | #include "user_interface.h" 79 | } 80 | 81 | WiFiClient wifiClient; 82 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 83 | Ticker btn_timer; 84 | 85 | void callback(const MQTT::Publish& pub) { 86 | if (pub.payload_string() == "stat") { 87 | } 88 | else if (pub.payload_string() == "on") { 89 | digitalWrite(LED, LOW); 90 | digitalWrite(RELAY, HIGH); 91 | } 92 | else if (pub.payload_string() == "off") { 93 | digitalWrite(LED, HIGH); 94 | digitalWrite(RELAY, LOW); 95 | } 96 | else if (pub.payload_string() == "reset") { 97 | requestRestart = true; 98 | } 99 | sendStatus = true; 100 | } 101 | 102 | void setup() { 103 | pinMode(LED, OUTPUT); 104 | pinMode(RELAY, OUTPUT); 105 | pinMode(BUTTON, INPUT); 106 | digitalWrite(LED, HIGH); 107 | digitalWrite(RELAY, LOW); 108 | Serial.begin(115200); 109 | EEPROM.begin(8); 110 | lastRelayState = EEPROM.read(0); 111 | if (rememberRelayState && lastRelayState == 1) { 112 | digitalWrite(LED, LOW); 113 | digitalWrite(RELAY, HIGH); 114 | } 115 | btn_timer.attach(0.05, button); 116 | mqttClient.set_callback(callback); 117 | WiFi.mode(WIFI_STA); 118 | WiFi.begin(WIFI_SSID, WIFI_PASS); 119 | ArduinoOTA.onStart([]() { 120 | OTAupdate = true; 121 | blinkLED(LED, 400, 2); 122 | digitalWrite(LED, HIGH); 123 | Serial.println("OTA Update Initiated . . ."); 124 | }); 125 | ArduinoOTA.onEnd([]() { 126 | Serial.println("\nOTA Update Ended . . .s"); 127 | ESP.restart(); 128 | }); 129 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { 130 | digitalWrite(LED, LOW); 131 | delay(5); 132 | digitalWrite(LED, HIGH); 133 | Serial.printf("Progress: %u%%\r", (progress / (total / 100))); 134 | }); 135 | ArduinoOTA.onError([](ota_error_t error) { 136 | blinkLED(LED, 40, 2); 137 | OTAupdate = false; 138 | Serial.printf("OTA Error [%u] ", error); 139 | if (error == OTA_AUTH_ERROR) Serial.println(". . . . . . . . . . . . . . . Auth Failed"); 140 | else if (error == OTA_BEGIN_ERROR) Serial.println(". . . . . . . . . . . . . . . Begin Failed"); 141 | else if (error == OTA_CONNECT_ERROR) Serial.println(". . . . . . . . . . . . . . . Connect Failed"); 142 | else if (error == OTA_RECEIVE_ERROR) Serial.println(". . . . . . . . . . . . . . . Receive Failed"); 143 | else if (error == OTA_END_ERROR) Serial.println(". . . . . . . . . . . . . . . End Failed"); 144 | }); 145 | ArduinoOTA.begin(); 146 | Serial.println(VERSION); 147 | Serial.print("\nUnit ID: "); 148 | Serial.print("esp8266-"); 149 | Serial.print(ESP.getChipId(), HEX); 150 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 151 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 152 | delay(500); 153 | Serial.print(" ."); 154 | } 155 | if (WiFi.status() == WL_CONNECTED) { 156 | Serial.println(" DONE"); 157 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 158 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 159 | delay(500); 160 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 161 | Serial.print(" ."); 162 | delay(1000); 163 | } 164 | if(mqttClient.connected()) { 165 | Serial.println(" DONE"); 166 | Serial.println("\n---------------------------- Logs ----------------------------"); 167 | Serial.println(); 168 | mqttClient.subscribe(MQTT_TOPIC); 169 | blinkLED(LED, 40, 8); 170 | if(digitalRead(RELAY) == HIGH) { 171 | digitalWrite(LED, LOW); 172 | } else { 173 | digitalWrite(LED, HIGH); 174 | } 175 | } 176 | else { 177 | Serial.println(" FAILED!"); 178 | Serial.println("\n----------------------------------------------------------------"); 179 | Serial.println(); 180 | } 181 | } 182 | else { 183 | Serial.println(" WiFi FAILED!"); 184 | Serial.println("\n----------------------------------------------------------------"); 185 | Serial.println(); 186 | } 187 | } 188 | 189 | void loop() { 190 | ArduinoOTA.handle(); 191 | if (OTAupdate == false) { 192 | mqttClient.loop(); 193 | timedTasks(); 194 | checkStatus(); 195 | if (tempReport) { 196 | getTemp(); 197 | } 198 | } 199 | } 200 | 201 | void blinkLED(int pin, int duration, int n) { 202 | for(int i=0; i 1 && count <= 40) { 216 | digitalWrite(LED, !digitalRead(LED)); 217 | digitalWrite(RELAY, !digitalRead(RELAY)); 218 | sendStatus = true; 219 | } 220 | else if (count >40){ 221 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 222 | requestRestart = true; 223 | } 224 | count=0; 225 | } 226 | } 227 | 228 | void checkConnection() { 229 | if (WiFi.status() == WL_CONNECTED) { 230 | if (mqttClient.connected()) { 231 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 232 | } 233 | else { 234 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 235 | requestRestart = true; 236 | } 237 | } 238 | else { 239 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 240 | requestRestart = true; 241 | } 242 | } 243 | 244 | void checkStatus() { 245 | if (sendStatus) { 246 | if(digitalRead(LED) == LOW) { 247 | if (rememberRelayState) { 248 | EEPROM.write(0, 1); 249 | } 250 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 251 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 252 | } else { 253 | if (rememberRelayState) { 254 | EEPROM.write(0, 0); 255 | } 256 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 257 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 258 | } 259 | if (rememberRelayState) { 260 | EEPROM.commit(); 261 | } 262 | sendStatus = false; 263 | } 264 | if (requestRestart) { 265 | blinkLED(LED, 400, 4); 266 | ESP.restart(); 267 | } 268 | } 269 | 270 | void getTemp() { 271 | Serial.print("DHT read . . . . . . . . . . . . . . . . . "); 272 | float dhtH, dhtT; 273 | char message_buff[60]; 274 | dhtH = dht.readHumidity(); 275 | dhtT = dht.readTemperature(); 276 | if(digitalRead(LED) == LOW) { 277 | blinkLED(LED, 100, 1); 278 | } else { 279 | blinkLED(LED, 100, 1); 280 | digitalWrite(LED, HIGH); 281 | } 282 | if (isnan(dhtH) || isnan(dhtT)) { 283 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug","\"DHT Read Error\"").set_retain().set_qos(1)); 284 | Serial.println("ERROR"); 285 | tempReport = false; 286 | return; 287 | } 288 | String pubString = "{\"Temp\": "+String(dhtT)+", "+"\"Humidity\": "+String(dhtH) + "}"; 289 | pubString.toCharArray(message_buff, pubString.length()+1); 290 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/temp", message_buff).set_retain().set_qos(1)); 291 | Serial.println("OK"); 292 | tempReport = false; 293 | } 294 | 295 | void timedTasks() { 296 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 297 | TTasks = millis(); 298 | checkConnection(); 299 | tempReport = true; 300 | } 301 | } 302 | -------------------------------------------------------------------------------- /arduino/ESPsonoff-v1.0p/ESPsonoff-v1.0p.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define BUTTON 0 // (Don't Change for Sonoff) 6 | #define RELAY 12 // (Don't Change for Sonoff) 7 | #define LED 13 // (Don't Change for Sonoff) 8 | 9 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.0p" // mqtt client_id (Must be unique for each Sonoff) 10 | #define MQTT_SERVER "192.168.0.100" // mqtt server 11 | #define MQTT_PORT 1883 // mqtt port 12 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 13 | #define MQTT_USER "user" // mqtt user 14 | #define MQTT_PASS "pass" // mqtt password 15 | 16 | #define WIFI_SSID "homewifi" // wifi ssid 17 | #define WIFI_PASS "homepass" // wifi password 18 | 19 | #define VERSION "\n\n------------------ Sonoff Powerpoint v1.0p -------------------" 20 | 21 | extern "C" { 22 | #include "user_interface.h" 23 | } 24 | 25 | bool sendStatus = false; 26 | bool requestRestart = false; 27 | 28 | int kUpdFreq = 1; 29 | int kRetries = 10; 30 | 31 | unsigned long TTasks; 32 | unsigned long count = 0; 33 | 34 | WiFiClient wifiClient; 35 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 36 | Ticker btn_timer; 37 | 38 | void callback(const MQTT::Publish& pub) { 39 | if (pub.payload_string() == "stat") { 40 | } 41 | else if (pub.payload_string() == "on") { 42 | digitalWrite(LED, LOW); 43 | digitalWrite(RELAY, HIGH); 44 | } 45 | else if (pub.payload_string() == "off") { 46 | digitalWrite(LED, HIGH); 47 | digitalWrite(RELAY, LOW); 48 | } 49 | else if (pub.payload_string() == "reset") { 50 | requestRestart = true; 51 | } 52 | sendStatus = true; 53 | } 54 | 55 | void setup() { 56 | pinMode(LED, OUTPUT); 57 | pinMode(RELAY, OUTPUT); 58 | pinMode(BUTTON, INPUT); 59 | 60 | digitalWrite(LED, HIGH); 61 | digitalWrite(RELAY, LOW); 62 | 63 | btn_timer.attach(0.05, button); 64 | 65 | mqttClient.set_callback(callback); 66 | 67 | WiFi.mode(WIFI_STA); 68 | WiFi.begin(WIFI_SSID, WIFI_PASS); 69 | Serial.begin(115200); 70 | Serial.println(VERSION); 71 | Serial.print("\nESP ChipID: "); 72 | Serial.print(ESP.getChipId(), HEX); 73 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 74 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 75 | delay(500); 76 | Serial.print(" ."); 77 | } 78 | if (WiFi.status() == WL_CONNECTED) { 79 | Serial.println(" DONE"); 80 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 81 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 82 | delay(500); 83 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 84 | Serial.print(" ."); 85 | delay(1000); 86 | } 87 | if(mqttClient.connected()) { 88 | Serial.println(" DONE"); 89 | Serial.println("\n---------------------------- Logs ----------------------------"); 90 | Serial.println(); 91 | mqttClient.subscribe(MQTT_TOPIC); 92 | blinkLED(LED, 40, 8); 93 | digitalWrite(LED, HIGH); 94 | } 95 | else { 96 | Serial.println(" FAILED!"); 97 | Serial.println("\n----------------------------------------------------------------"); 98 | Serial.println(); 99 | } 100 | } 101 | else { 102 | Serial.println(" WiFi FAILED!"); 103 | Serial.println("\n----------------------------------------------------------------"); 104 | Serial.println(); 105 | } 106 | } 107 | 108 | void loop() { 109 | mqttClient.loop(); 110 | timedTasks(); 111 | checkStatus(); 112 | } 113 | 114 | void blinkLED(int pin, int duration, int n) { 115 | for(int i=0; i 1 && count <= 40) { 129 | digitalWrite(LED, !digitalRead(LED)); 130 | digitalWrite(RELAY, !digitalRead(RELAY)); 131 | sendStatus = true; 132 | } 133 | else if (count >40){ 134 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 135 | requestRestart = true; 136 | } 137 | count=0; 138 | } 139 | } 140 | 141 | void checkConnection() { 142 | if (WiFi.status() == WL_CONNECTED) { 143 | if (mqttClient.connected()) { 144 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 145 | } 146 | else { 147 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 148 | requestRestart = true; 149 | } 150 | } 151 | else { 152 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 153 | requestRestart = true; 154 | } 155 | } 156 | 157 | void checkStatus() { 158 | if (sendStatus) { 159 | if(digitalRead(LED) == LOW) { 160 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 161 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 162 | } else { 163 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 164 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 165 | } 166 | sendStatus = false; 167 | } 168 | if (requestRestart) { 169 | blinkLED(LED, 400, 4); 170 | ESP.restart(); 171 | } 172 | } 173 | 174 | void timedTasks() { 175 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 176 | TTasks = millis(); 177 | checkConnection(); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /arduino/ESPsonoff-v1.0t/ESPsonoff-v1.0t.ino: -------------------------------------------------------------------------------- 1 | #include "DHT.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #define BUTTON 0 // (Don't Change for Sonoff) 7 | #define RELAY 12 // (Don't Change for Sonoff) 8 | #define LED 13 // (Don't Change for Sonoff) 9 | #define DHTPIN 14 // (Don't Change for Sonoff) 10 | 11 | #define DHTTYPE DHT22 // (11 or 22) DHT Type 12 | 13 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.0t" // mqtt client_id (Must be unique for each Sonoff) 14 | #define MQTT_SERVER "192.168.0.100" // mqtt server 15 | #define MQTT_PORT 1883 // mqtt port 16 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 17 | #define MQTT_USER "user" // mqtt user 18 | #define MQTT_PASS "pass" // mqtt password 19 | 20 | #define WIFI_SSID "homewifi" // wifi ssid 21 | #define WIFI_PASS "homepass" // wifi password 22 | 23 | #define VERSION "\n\n------------------ Sonoff Powerpoint v1.0t -------------------" 24 | 25 | DHT dht(DHTPIN, DHTTYPE, 11); // (Don't Change for Sonoff) 26 | 27 | extern "C" { 28 | #include "user_interface.h" 29 | } 30 | 31 | bool sendStatus = false; 32 | bool requestRestart = false; 33 | bool tempReport = false; 34 | 35 | int kUpdFreq = 1; 36 | int kRetries = 10; 37 | 38 | unsigned long TTasks; 39 | unsigned long count = 0; 40 | 41 | WiFiClient wifiClient; 42 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 43 | Ticker btn_timer; 44 | 45 | void callback(const MQTT::Publish& pub) { 46 | if (pub.payload_string() == "stat") { 47 | } 48 | else if (pub.payload_string() == "on") { 49 | digitalWrite(LED, LOW); 50 | digitalWrite(RELAY, HIGH); 51 | } 52 | else if (pub.payload_string() == "off") { 53 | digitalWrite(LED, HIGH); 54 | digitalWrite(RELAY, LOW); 55 | } 56 | else if (pub.payload_string() == "reset") { 57 | requestRestart = true; 58 | } 59 | else if (pub.payload_string() == "temp") { 60 | tempReport = true; 61 | } 62 | sendStatus = true; 63 | } 64 | 65 | void setup() { 66 | pinMode(LED, OUTPUT); 67 | pinMode(RELAY, OUTPUT); 68 | pinMode(BUTTON, INPUT); 69 | 70 | digitalWrite(LED, HIGH); 71 | digitalWrite(RELAY, LOW); 72 | 73 | btn_timer.attach(0.05, button); 74 | 75 | mqttClient.set_callback(callback); 76 | 77 | WiFi.mode(WIFI_STA); 78 | WiFi.begin(WIFI_SSID, WIFI_PASS); 79 | Serial.begin(115200); 80 | Serial.println(VERSION); 81 | Serial.print("\nESP ChipID: "); 82 | Serial.print(ESP.getChipId(), HEX); 83 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 84 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 85 | delay(500); 86 | Serial.print(" ."); 87 | } 88 | if (WiFi.status() == WL_CONNECTED) { 89 | Serial.println(" DONE"); 90 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 91 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 92 | delay(500); 93 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 94 | Serial.print(" ."); 95 | delay(1000); 96 | } 97 | if(mqttClient.connected()) { 98 | Serial.println(" DONE"); 99 | Serial.println("\n---------------------------- Logs ----------------------------"); 100 | Serial.println(); 101 | mqttClient.subscribe(MQTT_TOPIC); 102 | blinkLED(LED, 40, 8); 103 | digitalWrite(LED, HIGH); 104 | } 105 | else { 106 | Serial.println(" FAILED!"); 107 | Serial.println("\n----------------------------------------------------------------"); 108 | Serial.println(); 109 | } 110 | } 111 | else { 112 | Serial.println(" WiFi FAILED!"); 113 | Serial.println("\n----------------------------------------------------------------"); 114 | Serial.println(); 115 | } 116 | getTemp(); 117 | } 118 | 119 | void loop() { 120 | mqttClient.loop(); 121 | timedTasks(); 122 | checkStatus(); 123 | if (tempReport) { 124 | getTemp(); 125 | } 126 | } 127 | 128 | void blinkLED(int pin, int duration, int n) { 129 | for(int i=0; i 1 && count <= 40) { 143 | digitalWrite(LED, !digitalRead(LED)); 144 | digitalWrite(RELAY, !digitalRead(RELAY)); 145 | sendStatus = true; 146 | } 147 | else if (count >40){ 148 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 149 | requestRestart = true; 150 | } 151 | count=0; 152 | } 153 | } 154 | 155 | void checkConnection() { 156 | if (WiFi.status() == WL_CONNECTED) { 157 | if (mqttClient.connected()) { 158 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 159 | } 160 | else { 161 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 162 | requestRestart = true; 163 | } 164 | } 165 | else { 166 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 167 | requestRestart = true; 168 | } 169 | } 170 | 171 | void checkStatus() { 172 | if (sendStatus) { 173 | if(digitalRead(LED) == LOW) { 174 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 175 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 176 | } else { 177 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 178 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 179 | } 180 | sendStatus = false; 181 | } 182 | if (requestRestart) { 183 | blinkLED(LED, 400, 4); 184 | ESP.restart(); 185 | } 186 | } 187 | 188 | void getTemp() { 189 | Serial.print("DHT read . . . . . . . . . . . . . . . . . "); 190 | float dhtH, dhtT; 191 | char message_buff[60]; 192 | dhtH = dht.readHumidity(); 193 | dhtT = dht.readTemperature(); 194 | if(digitalRead(LED) == LOW) { 195 | blinkLED(LED, 100, 1); 196 | } else { 197 | blinkLED(LED, 100, 1); 198 | digitalWrite(LED, HIGH); 199 | } 200 | if (isnan(dhtH) || isnan(dhtT)) { 201 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug","\"DHT Read Error\"").set_retain().set_qos(1)); 202 | Serial.println("ERROR"); 203 | tempReport = false; 204 | return; 205 | } 206 | String pubString = "{\"Temp\": "+String(dhtT)+", "+"\"Humidity\": "+String(dhtH) + "}"; 207 | pubString.toCharArray(message_buff, pubString.length()+1); 208 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/temp", message_buff).set_retain().set_qos(1)); 209 | Serial.println("OK"); 210 | tempReport = false; 211 | } 212 | 213 | void timedTasks() { 214 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 215 | TTasks = millis(); 216 | checkConnection(); 217 | tempReport = true; 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_4CH-v1.01p/ESPsonoff_4CH-v1.01p.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2017 @KmanOz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | **** USE THIS Firmware for: Sonoff 4CH **** 24 | **** Make sure to select "Generic ESP8285 Module" from the BOARD menu in TOOLS **** 25 | **** Flash Size "1M (64K SPIFFS)" **** 26 | 27 | */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #define BUTTON1 0 // (Don't Change for Sonoff 4CH) 35 | #define BUTTON2 9 // (Don't Change for Sonoff 4CH) 36 | #define BUTTON3 10 // (Don't Change for Sonoff 4CH) 37 | #define BUTTON4 14 // (Don't Change for Sonoff 4CH) 38 | #define RELAY1 12 // (Don't Change for Sonoff 4CH) 39 | #define RELAY2 5 // (Don't Change for Sonoff 4CH) 40 | #define RELAY3 4 // (Don't Change for Sonoff 4CH) 41 | #define RELAY4 15 // (Don't Change for Sonoff 4CH) 42 | #define LED 13 // (Don't Change for Sonoff 4CH) 43 | 44 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.0pow" // mqtt client_id (Must be unique for each Sonoff) 45 | #define MQTT_SERVER "192.168.0.100" // mqtt server 46 | #define MQTT_PORT 1883 // mqtt port 47 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 48 | #define MQTT_USER "user" // mqtt user 49 | #define MQTT_PASS "pass" // mqtt password 50 | 51 | #define WIFI_SSID "homewifi" // wifi ssid 52 | #define WIFI_PASS "homepass" // wifi password 53 | 54 | #define VERSION "\n\n---------------- Sonoff TH Powerpoint v1.01p -----------------" 55 | 56 | bool rememberRelayState1 = true; // If 'true' remembers the state of the relay 1 before power loss. 57 | bool rememberRelayState2 = true; // If 'true' remembers the state of the relay 2 before power loss. 58 | bool rememberRelayState3 = true; // If 'true' remembers the state of the relay 3 before power loss. 59 | bool rememberRelayState4 = true; // If 'true' remembers the state of the relay 4 before power loss. 60 | bool requestRestart = false; // (Do not Change) 61 | bool sendStatus1 = false, sendStatus2 = false; // (Do not Change) 62 | bool sendStatus3 = false, sendStatus4 = false; // (Do not Change) 63 | 64 | int kUpdFreq = 1; // Update frequency in Mintes to check for mqtt connection 65 | int kRetries = 10; // WiFi retry count. Increase if not connecting to router. 66 | int lastRelayState1, lastRelayState2; // (Do not Change) 67 | int lastRelayState3, lastRelayState4; // (Do not Change) 68 | 69 | unsigned long TTasks; // (Do not Change) 70 | unsigned long count1 = 0; // (Do not Change) 71 | unsigned long count2 = 0; // (Do not Change) 72 | unsigned long count3 = 0; // (Do not Change) 73 | unsigned long count4 = 0; // (Do not Change) 74 | 75 | extern "C" { 76 | #include "user_interface.h" 77 | } 78 | 79 | WiFiClient wifiClient; 80 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 81 | Ticker btn_timer1, btn_timer2, btn_timer3, btn_timer4; 82 | 83 | void callback(const MQTT::Publish& pub) { 84 | if (pub.payload_string() == "stat") { 85 | } 86 | else if (pub.payload_string() == "1on") { 87 | digitalWrite(RELAY1, HIGH); 88 | sendStatus1 = true; 89 | } 90 | else if (pub.payload_string() == "1off") { 91 | digitalWrite(RELAY1, LOW); 92 | sendStatus1 = true; 93 | } 94 | else if (pub.payload_string() == "2on") { 95 | digitalWrite(RELAY2, HIGH); 96 | sendStatus2 = true; 97 | } 98 | else if (pub.payload_string() == "2off") { 99 | digitalWrite(RELAY2, LOW); 100 | sendStatus2 = true; 101 | } 102 | else if (pub.payload_string() == "3on") { 103 | digitalWrite(RELAY3, HIGH); 104 | sendStatus3 = true; 105 | } 106 | else if (pub.payload_string() == "3off") { 107 | digitalWrite(RELAY3, LOW); 108 | sendStatus3 = true; 109 | } 110 | else if (pub.payload_string() == "4on") { 111 | digitalWrite(RELAY4, HIGH); 112 | sendStatus4 = true; 113 | } 114 | else if (pub.payload_string() == "4off") { 115 | digitalWrite(RELAY4, LOW); 116 | sendStatus4 = true; 117 | } 118 | else if (pub.payload_string() == "reset") { 119 | requestRestart = true; 120 | } 121 | } 122 | 123 | void setup() { 124 | pinMode(LED, OUTPUT); 125 | pinMode(RELAY1, OUTPUT); 126 | pinMode(RELAY2, OUTPUT); 127 | pinMode(RELAY3, OUTPUT); 128 | pinMode(RELAY4, OUTPUT); 129 | pinMode(BUTTON1, INPUT); 130 | pinMode(BUTTON2, INPUT); 131 | pinMode(BUTTON3, INPUT); 132 | pinMode(BUTTON4, INPUT); 133 | digitalWrite(LED, HIGH); 134 | digitalWrite(RELAY1, LOW); 135 | digitalWrite(RELAY2, LOW); 136 | digitalWrite(RELAY3, LOW); 137 | digitalWrite(RELAY4, LOW); 138 | Serial.begin(115200); 139 | EEPROM.begin(8); 140 | lastRelayState1 = EEPROM.read(0); 141 | lastRelayState2 = EEPROM.read(1); 142 | lastRelayState3 = EEPROM.read(2); 143 | lastRelayState4 = EEPROM.read(3); 144 | if (rememberRelayState1 && lastRelayState1 == 1) { 145 | digitalWrite(RELAY1, HIGH); 146 | } 147 | if (rememberRelayState2 && lastRelayState2 == 1) { 148 | digitalWrite(RELAY2, HIGH); 149 | } 150 | if (rememberRelayState3 && lastRelayState3 == 1) { 151 | digitalWrite(RELAY3, HIGH); 152 | } 153 | if (rememberRelayState4 && lastRelayState4 == 1) { 154 | digitalWrite(RELAY4, HIGH); 155 | } 156 | btn_timer1.attach(0.05, button1); 157 | btn_timer2.attach(0.05, button2); 158 | btn_timer3.attach(0.05, button3); 159 | btn_timer4.attach(0.05, button4); 160 | mqttClient.set_callback(callback); 161 | WiFi.mode(WIFI_STA); 162 | WiFi.begin(WIFI_SSID, WIFI_PASS); 163 | Serial.println(VERSION); 164 | Serial.print("\nUnit ID: "); 165 | Serial.print("esp8266-"); 166 | Serial.print(ESP.getChipId(), HEX); 167 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 168 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 169 | delay(500); 170 | Serial.print(" ."); 171 | } 172 | if (WiFi.status() == WL_CONNECTED) { 173 | Serial.println(" DONE"); 174 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 175 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 176 | delay(500); 177 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 178 | Serial.print(" ."); 179 | delay(1000); 180 | } 181 | if(mqttClient.connected()) { 182 | Serial.println(" DONE"); 183 | Serial.println("\n---------------------------- Logs ----------------------------"); 184 | Serial.println(); 185 | mqttClient.subscribe(MQTT_TOPIC); 186 | blinkLED(LED, 40, 8); 187 | digitalWrite(LED, LOW); 188 | } 189 | else { 190 | Serial.println(" FAILED!"); 191 | Serial.println("\n----------------------------------------------------------------"); 192 | Serial.println(); 193 | } 194 | } 195 | else { 196 | Serial.println(" WiFi FAILED!"); 197 | Serial.println("\n----------------------------------------------------------------"); 198 | Serial.println(); 199 | } 200 | } 201 | 202 | void loop() { 203 | mqttClient.loop(); 204 | timedTasks(); 205 | checkStatus(); 206 | } 207 | 208 | void blinkLED(int pin, int duration, int n) { 209 | for(int i=0; i 1 && count1 <= 40) { 223 | digitalWrite(RELAY1, !digitalRead(RELAY1)); 224 | sendStatus1 = true; 225 | } 226 | else if (count1 >40){ 227 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 228 | requestRestart = true; 229 | } 230 | count1=0; 231 | } 232 | } 233 | 234 | void button2() { 235 | if (!digitalRead(BUTTON2)) { 236 | count2++; 237 | } 238 | else { 239 | if (count2 > 1 && count2 <= 40) { 240 | digitalWrite(RELAY2, !digitalRead(RELAY2)); 241 | sendStatus2 = true; 242 | } 243 | count2=0; 244 | } 245 | } 246 | 247 | void button3() { 248 | if (!digitalRead(BUTTON3)) { 249 | count3++; 250 | } 251 | else { 252 | if (count3 > 1 && count3 <= 40) { 253 | digitalWrite(RELAY3, !digitalRead(RELAY3)); 254 | sendStatus3 = true; 255 | } 256 | count3=0; 257 | } 258 | } 259 | 260 | void button4() { 261 | if (!digitalRead(BUTTON4)) { 262 | count4++; 263 | } 264 | else { 265 | if (count4 > 1 && count4 <= 40) { 266 | digitalWrite(RELAY4, !digitalRead(RELAY4)); 267 | sendStatus4 = true; 268 | } 269 | count4=0; 270 | } 271 | } 272 | 273 | void checkConnection() { 274 | if (WiFi.status() == WL_CONNECTED) { 275 | if (mqttClient.connected()) { 276 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 277 | } 278 | else { 279 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 280 | requestRestart = true; 281 | } 282 | } 283 | else { 284 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 285 | requestRestart = true; 286 | } 287 | } 288 | 289 | void checkStatus() { 290 | if (sendStatus1) { 291 | if(digitalRead(RELAY1) == LOW) { 292 | if (rememberRelayState1) { 293 | EEPROM.write(0, 0); 294 | } 295 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "1off").set_retain().set_qos(1)); 296 | Serial.println("Relay 1 . . . . . . . . . . . . . . . . . . OFF"); 297 | } else { 298 | if (rememberRelayState1) { 299 | EEPROM.write(0, 1); 300 | } 301 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "1on").set_retain().set_qos(1)); 302 | Serial.println("Relay 1 . . . . . . . . . . . . . . . . . . ON"); 303 | } 304 | sendStatus1 = false; 305 | } 306 | if (sendStatus2) { 307 | if(digitalRead(RELAY2) == LOW) { 308 | if (rememberRelayState2) { 309 | EEPROM.write(1, 0); 310 | } 311 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "2off").set_retain().set_qos(2)); 312 | Serial.println("Relay 2 . . . . . . . . . . . . . . . . . . OFF"); 313 | } else { 314 | if (rememberRelayState2) { 315 | EEPROM.write(1, 1); 316 | } 317 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "2on").set_retain().set_qos(2)); 318 | Serial.println("Relay 2 . . . . . . . . . . . . . . . . . . ON"); 319 | } 320 | sendStatus2 = false; 321 | } 322 | if (sendStatus3) { 323 | if(digitalRead(RELAY3) == LOW) { 324 | if (rememberRelayState3) { 325 | EEPROM.write(2, 0); 326 | } 327 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "3off").set_retain().set_qos(3)); 328 | Serial.println("Relay 3 . . . . . . . . . . . . . . . . . . OFF"); 329 | } else { 330 | if (rememberRelayState3) { 331 | EEPROM.write(2, 1); 332 | } 333 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "3on").set_retain().set_qos(3)); 334 | Serial.println("Relay 3 . . . . . . . . . . . . . . . . . . ON"); 335 | } 336 | sendStatus3 = false; 337 | } 338 | if (sendStatus4) { 339 | if(digitalRead(RELAY4) == LOW) { 340 | if (rememberRelayState4) { 341 | EEPROM.write(3, 0); 342 | } 343 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "4off").set_retain().set_qos(4)); 344 | Serial.println("Relay 4 . . . . . . . . . . . . . . . . . . OFF"); 345 | } else { 346 | if (rememberRelayState4) { 347 | EEPROM.write(3, 1); 348 | } 349 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "4on").set_retain().set_qos(4)); 350 | Serial.println("Relay 4 . . . . . . . . . . . . . . . . . . ON"); 351 | } 352 | sendStatus4 = false; 353 | } 354 | if (rememberRelayState1 || rememberRelayState2 || rememberRelayState3 || rememberRelayState4) { 355 | EEPROM.commit(); 356 | } 357 | if (requestRestart) { 358 | blinkLED(LED, 400, 4); 359 | ESP.restart(); 360 | } 361 | } 362 | 363 | void timedTasks() { 364 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 365 | TTasks = millis(); 366 | checkConnection(); 367 | } 368 | } 369 | 370 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_4CH-v1.01pOTA/ESPsonoff_4CH-v1.01pOTA.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2017 @KmanOz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | **** USE THIS Firmware for: Sonoff 4CH **** 24 | **** Make sure to select "Generic ESP8285 Module" from the BOARD menu in TOOLS **** 25 | **** Flash Size "1M (64K SPIFFS)" **** 26 | 27 | */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #define BUTTON1 0 // (Do not Change) 38 | #define BUTTON2 9 // (Do not Change) 39 | #define BUTTON3 10 // (Do not Change) 40 | #define BUTTON4 14 // (Do not Change) 41 | #define RELAY1 12 // (Do not Change) 42 | #define RELAY2 5 // (Do not Change) 43 | #define RELAY3 4 // (Do not Change) 44 | #define RELAY4 15 // (Do not Change) 45 | #define LED 13 // (Do not Change) 46 | 47 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.0pow" // mqtt client_id (Must be unique for each Sonoff) 48 | #define MQTT_SERVER "192.168.0.100" // mqtt server 49 | #define MQTT_PORT 1883 // mqtt port 50 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 51 | #define MQTT_USER "user" // mqtt user 52 | #define MQTT_PASS "pass" // mqtt password 53 | 54 | #define WIFI_SSID "homewifi" // wifi ssid 55 | #define WIFI_PASS "homepass" // wifi password 56 | 57 | #define VERSION "\n\n--------------- Sonoff TH Powerpoint v1.01pOTA ---------------" 58 | 59 | bool rememberRelayState1 = true; // If 'true' remembers the state of the relay 1 before power loss. 60 | bool rememberRelayState2 = true; // If 'true' remembers the state of the relay 2 before power loss. 61 | bool rememberRelayState3 = true; // If 'true' remembers the state of the relay 3 before power loss. 62 | bool rememberRelayState4 = true; // If 'true' remembers the state of the relay 4 before power loss. 63 | bool requestRestart = false; // (Do not Change) 64 | bool sendStatus1 = false, sendStatus2 = false; // (Do not Change) 65 | bool sendStatus3 = false, sendStatus4 = false; // (Do not Change) 66 | bool OTAupdate = false; // (Do not Change) 67 | 68 | int kUpdFreq = 1; // Update frequency in Mintes to check for mqtt connection 69 | int kRetries = 10; // WiFi retry count. Increase if not connecting to router. 70 | int lastRelayState1, lastRelayState2; // (Do not Change) 71 | int lastRelayState3, lastRelayState4; // (Do not Change) 72 | 73 | unsigned long TTasks; // (Do not Change) 74 | unsigned long count1 = 0; // (Do not Change) 75 | unsigned long count2 = 0; // (Do not Change) 76 | unsigned long count3 = 0; // (Do not Change) 77 | unsigned long count4 = 0; // (Do not Change) 78 | 79 | extern "C" { 80 | #include "user_interface.h" 81 | } 82 | 83 | WiFiClient wifiClient; 84 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 85 | Ticker btn_timer1, btn_timer2, btn_timer3, btn_timer4; 86 | 87 | void callback(const MQTT::Publish& pub) { 88 | if (pub.payload_string() == "stat") { 89 | } 90 | else if (pub.payload_string() == "1on") { 91 | digitalWrite(RELAY1, HIGH); 92 | sendStatus1 = true; 93 | } 94 | else if (pub.payload_string() == "1off") { 95 | digitalWrite(RELAY1, LOW); 96 | sendStatus1 = true; 97 | } 98 | else if (pub.payload_string() == "2on") { 99 | digitalWrite(RELAY2, HIGH); 100 | sendStatus2 = true; 101 | } 102 | else if (pub.payload_string() == "2off") { 103 | digitalWrite(RELAY2, LOW); 104 | sendStatus2 = true; 105 | } 106 | else if (pub.payload_string() == "3on") { 107 | digitalWrite(RELAY3, HIGH); 108 | sendStatus3 = true; 109 | } 110 | else if (pub.payload_string() == "3off") { 111 | digitalWrite(RELAY3, LOW); 112 | sendStatus3 = true; 113 | } 114 | else if (pub.payload_string() == "4on") { 115 | digitalWrite(RELAY4, HIGH); 116 | sendStatus4 = true; 117 | } 118 | else if (pub.payload_string() == "4off") { 119 | digitalWrite(RELAY4, LOW); 120 | sendStatus4 = true; 121 | } 122 | else if (pub.payload_string() == "reset") { 123 | requestRestart = true; 124 | } 125 | } 126 | 127 | void setup() { 128 | pinMode(LED, OUTPUT); 129 | pinMode(RELAY1, OUTPUT); 130 | pinMode(RELAY2, OUTPUT); 131 | pinMode(RELAY3, OUTPUT); 132 | pinMode(RELAY4, OUTPUT); 133 | pinMode(BUTTON1, INPUT); 134 | pinMode(BUTTON2, INPUT); 135 | pinMode(BUTTON3, INPUT); 136 | pinMode(BUTTON4, INPUT); 137 | digitalWrite(LED, HIGH); 138 | digitalWrite(RELAY1, LOW); 139 | digitalWrite(RELAY2, LOW); 140 | digitalWrite(RELAY3, LOW); 141 | digitalWrite(RELAY4, LOW); 142 | Serial.begin(115200); 143 | EEPROM.begin(8); 144 | lastRelayState1 = EEPROM.read(0); 145 | lastRelayState2 = EEPROM.read(1); 146 | lastRelayState3 = EEPROM.read(2); 147 | lastRelayState4 = EEPROM.read(3); 148 | if (rememberRelayState1 && lastRelayState1 == 1) { 149 | digitalWrite(RELAY1, HIGH); 150 | } 151 | if (rememberRelayState2 && lastRelayState2 == 1) { 152 | digitalWrite(RELAY2, HIGH); 153 | } 154 | if (rememberRelayState3 && lastRelayState3 == 1) { 155 | digitalWrite(RELAY3, HIGH); 156 | } 157 | if (rememberRelayState4 && lastRelayState4 == 1) { 158 | digitalWrite(RELAY4, HIGH); 159 | } 160 | btn_timer1.attach(0.05, button1); 161 | btn_timer2.attach(0.05, button2); 162 | btn_timer3.attach(0.05, button3); 163 | btn_timer4.attach(0.05, button4); 164 | mqttClient.set_callback(callback); 165 | WiFi.mode(WIFI_STA); 166 | WiFi.begin(WIFI_SSID, WIFI_PASS); 167 | ArduinoOTA.onStart([]() { 168 | OTAupdate = true; 169 | blinkLED(LED, 400, 2); 170 | digitalWrite(LED, HIGH); 171 | Serial.println("OTA Update Initiated . . ."); 172 | }); 173 | ArduinoOTA.onEnd([]() { 174 | Serial.println("\nOTA Update Ended . . .s"); 175 | OTAupdate = false; 176 | requestRestart = true; 177 | }); 178 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { 179 | digitalWrite(LED, LOW); 180 | delay(5); 181 | digitalWrite(LED, HIGH); 182 | Serial.printf("Progress: %u%%\r", (progress / (total / 100))); 183 | }); 184 | ArduinoOTA.onError([](ota_error_t error) { 185 | blinkLED(LED, 40, 2); 186 | OTAupdate = false; 187 | Serial.printf("OTA Error [%u] ", error); 188 | if (error == OTA_AUTH_ERROR) Serial.println(". . . . . . . . . . . . . . . Auth Failed"); 189 | else if (error == OTA_BEGIN_ERROR) Serial.println(". . . . . . . . . . . . . . . Begin Failed"); 190 | else if (error == OTA_CONNECT_ERROR) Serial.println(". . . . . . . . . . . . . . . Connect Failed"); 191 | else if (error == OTA_RECEIVE_ERROR) Serial.println(". . . . . . . . . . . . . . . Receive Failed"); 192 | else if (error == OTA_END_ERROR) Serial.println(". . . . . . . . . . . . . . . End Failed"); 193 | }); 194 | ArduinoOTA.begin(); 195 | Serial.println(VERSION); 196 | Serial.print("\nUnit ID: "); 197 | Serial.print("esp8266-"); 198 | Serial.print(ESP.getChipId(), HEX); 199 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 200 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 201 | delay(500); 202 | Serial.print(" ."); 203 | } 204 | if (WiFi.status() == WL_CONNECTED) { 205 | Serial.println(" DONE"); 206 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 207 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 208 | delay(500); 209 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 210 | Serial.print(" ."); 211 | delay(1000); 212 | } 213 | if(mqttClient.connected()) { 214 | Serial.println(" DONE"); 215 | Serial.println("\n---------------------------- Logs ----------------------------"); 216 | Serial.println(); 217 | mqttClient.subscribe(MQTT_TOPIC); 218 | blinkLED(LED, 40, 8); 219 | digitalWrite(LED, LOW); 220 | } 221 | else { 222 | Serial.println(" FAILED!"); 223 | Serial.println("\n----------------------------------------------------------------"); 224 | Serial.println(); 225 | } 226 | } 227 | else { 228 | Serial.println(" WiFi FAILED!"); 229 | Serial.println("\n----------------------------------------------------------------"); 230 | Serial.println(); 231 | } 232 | } 233 | 234 | void loop() { 235 | ArduinoOTA.handle(); 236 | if (OTAupdate == false) { 237 | mqttClient.loop(); 238 | timedTasks(); 239 | checkStatus(); 240 | } 241 | } 242 | 243 | void blinkLED(int pin, int duration, int n) { 244 | for(int i=0; i 1 && count1 <= 40) { 258 | digitalWrite(RELAY1, !digitalRead(RELAY1)); 259 | sendStatus1 = true; 260 | } 261 | else if (count1 >40){ 262 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 263 | requestRestart = true; 264 | } 265 | count1=0; 266 | } 267 | } 268 | 269 | void button2() { 270 | if (!digitalRead(BUTTON2)) { 271 | count2++; 272 | } 273 | else { 274 | if (count2 > 1 && count2 <= 40) { 275 | digitalWrite(RELAY2, !digitalRead(RELAY2)); 276 | sendStatus2 = true; 277 | } 278 | count2=0; 279 | } 280 | } 281 | 282 | void button3() { 283 | if (!digitalRead(BUTTON3)) { 284 | count3++; 285 | } 286 | else { 287 | if (count3 > 1 && count3 <= 40) { 288 | digitalWrite(RELAY3, !digitalRead(RELAY3)); 289 | sendStatus3 = true; 290 | } 291 | count3=0; 292 | } 293 | } 294 | 295 | void button4() { 296 | if (!digitalRead(BUTTON4)) { 297 | count4++; 298 | } 299 | else { 300 | if (count4 > 1 && count4 <= 40) { 301 | digitalWrite(RELAY4, !digitalRead(RELAY4)); 302 | sendStatus4 = true; 303 | } 304 | count4=0; 305 | } 306 | } 307 | 308 | void checkConnection() { 309 | if (WiFi.status() == WL_CONNECTED) { 310 | if (mqttClient.connected()) { 311 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 312 | } 313 | else { 314 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 315 | requestRestart = true; 316 | } 317 | } 318 | else { 319 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 320 | requestRestart = true; 321 | } 322 | } 323 | 324 | void checkStatus() { 325 | if (sendStatus1) { 326 | if(digitalRead(RELAY1) == LOW) { 327 | if (rememberRelayState1) { 328 | EEPROM.write(0, 0); 329 | } 330 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "1off").set_retain().set_qos(1)); 331 | Serial.println("Relay 1 . . . . . . . . . . . . . . . . . . OFF"); 332 | } else { 333 | if (rememberRelayState1) { 334 | EEPROM.write(0, 1); 335 | } 336 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "1on").set_retain().set_qos(1)); 337 | Serial.println("Relay 1 . . . . . . . . . . . . . . . . . . ON"); 338 | } 339 | sendStatus1 = false; 340 | } 341 | if (sendStatus2) { 342 | if(digitalRead(RELAY2) == LOW) { 343 | if (rememberRelayState2) { 344 | EEPROM.write(1, 0); 345 | } 346 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "2off").set_retain().set_qos(2)); 347 | Serial.println("Relay 2 . . . . . . . . . . . . . . . . . . OFF"); 348 | } else { 349 | if (rememberRelayState2) { 350 | EEPROM.write(1, 1); 351 | } 352 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "2on").set_retain().set_qos(2)); 353 | Serial.println("Relay 2 . . . . . . . . . . . . . . . . . . ON"); 354 | } 355 | sendStatus2 = false; 356 | } 357 | if (sendStatus3) { 358 | if(digitalRead(RELAY3) == LOW) { 359 | if (rememberRelayState3) { 360 | EEPROM.write(2, 0); 361 | } 362 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "3off").set_retain().set_qos(3)); 363 | Serial.println("Relay 3 . . . . . . . . . . . . . . . . . . OFF"); 364 | } else { 365 | if (rememberRelayState3) { 366 | EEPROM.write(2, 1); 367 | } 368 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "3on").set_retain().set_qos(3)); 369 | Serial.println("Relay 3 . . . . . . . . . . . . . . . . . . ON"); 370 | } 371 | sendStatus3 = false; 372 | } 373 | if (sendStatus4) { 374 | if(digitalRead(RELAY4) == LOW) { 375 | if (rememberRelayState4) { 376 | EEPROM.write(3, 0); 377 | } 378 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "4off").set_retain().set_qos(4)); 379 | Serial.println("Relay 4 . . . . . . . . . . . . . . . . . . OFF"); 380 | } else { 381 | if (rememberRelayState4) { 382 | EEPROM.write(3, 1); 383 | } 384 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "4on").set_retain().set_qos(4)); 385 | Serial.println("Relay 4 . . . . . . . . . . . . . . . . . . ON"); 386 | } 387 | sendStatus4 = false; 388 | } 389 | if (rememberRelayState1 || rememberRelayState2 || rememberRelayState3 || rememberRelayState4) { 390 | EEPROM.commit(); 391 | } 392 | if (requestRestart) { 393 | blinkLED(LED, 400, 4); 394 | ESP.restart(); 395 | } 396 | } 397 | 398 | void timedTasks() { 399 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 400 | TTasks = millis(); 401 | checkConnection(); 402 | } 403 | } 404 | 405 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_POW-v1.0/ESPsonoff_POW-v1.0.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 @KmanOz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "power.h" 27 | 28 | #define BUTTON 0 // (Don't Change for Sonoff POW) 29 | #define RELAY 12 // (Don't Change for Sonoff POW) 30 | #define LED 15 // (Don't Change for Sonoff POW) 31 | 32 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.0p" // mqtt client_id (Must be unique for each Sonoff) 33 | #define MQTT_SERVER "192.168.0.100" // mqtt server 34 | #define MQTT_PORT 1883 // mqtt port 35 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 36 | #define MQTT_USER "user" // mqtt user 37 | #define MQTT_PASS "pass" // mqtt password 38 | 39 | #define WIFI_SSID "homewifi" // wifi ssid 40 | #define WIFI_PASS "homepass" // wifi password 41 | 42 | #define VERSION "\n\n----------------- Sonoff POW Powerpoint v1.0 -----------------" 43 | 44 | extern "C" { 45 | #include "user_interface.h" 46 | } 47 | 48 | bool debug = false; // Make debug true for easy access to Serial Debug Window 49 | bool sendStatus = false; 50 | bool requestRestart = false; 51 | 52 | char message_buff[60]; 53 | 54 | int kUpdFreq = 1; // Update frequency in Mintes to check mqtt connection 55 | int kPwrUpdFreq = 15; // Update frequency in Seconds to publish power usage 56 | int kRetries = 10; // WiFi retry count. Increase if not connecting to router. 57 | 58 | unsigned long TTasks1; 59 | unsigned long TTasks2; 60 | unsigned long count = 0; 61 | 62 | WiFiClient wifiClient; 63 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 64 | ESP8266PowerClass power_read; 65 | Ticker btn_timer; 66 | 67 | void callback(const MQTT::Publish& pub) { 68 | if (pub.payload_string() == "on") { 69 | digitalWrite(RELAY, HIGH); 70 | } 71 | else if (pub.payload_string() == "off") { 72 | digitalWrite(RELAY, LOW); 73 | } 74 | else if (pub.payload_string() == "reset") { 75 | requestRestart = true; 76 | } 77 | sendStatus = true; 78 | } 79 | 80 | void setup() { 81 | pinMode(LED, OUTPUT); 82 | pinMode(RELAY, OUTPUT); 83 | pinMode(BUTTON, INPUT); 84 | 85 | digitalWrite(LED, LOW); 86 | digitalWrite(RELAY, LOW); 87 | 88 | power_read.enableMeasurePower(); 89 | power_read.selectMeasureCurrentOrVoltage(VOLTAGE); 90 | power_read.startMeasure(); 91 | 92 | btn_timer.attach(0.05, button); 93 | 94 | mqttClient.set_callback(callback); 95 | 96 | WiFi.mode(WIFI_STA); 97 | WiFi.begin(WIFI_SSID, WIFI_PASS); 98 | delay(500); 99 | if (debug) { 100 | Serial.begin(115200); 101 | blinkLED(LED, 25, 120); 102 | Serial.println(VERSION); 103 | Serial.print("\nESP ChipID: "); 104 | Serial.print(ESP.getChipId(), HEX); 105 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 106 | } 107 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 108 | delay(500); 109 | if (debug) { 110 | Serial.print(" ."); 111 | } 112 | } 113 | if (WiFi.status() == WL_CONNECTED) { 114 | if (debug) { 115 | Serial.println(" DONE"); 116 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 117 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 118 | } 119 | delay(500); 120 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(120).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 121 | if (debug) { 122 | Serial.print(" ."); 123 | } 124 | delay(1000); 125 | } 126 | if(mqttClient.connected()) { 127 | if (debug) { 128 | Serial.println(" DONE"); 129 | Serial.println("\n---------------------------- Logs -----------------------------"); 130 | Serial.println(); 131 | } 132 | mqttClient.subscribe(MQTT_TOPIC); 133 | blinkLED(LED, 40, 8); 134 | digitalWrite(LED, HIGH); 135 | } 136 | else { 137 | if (debug) { 138 | Serial.println(" FAILED!"); 139 | Serial.println("\n----------------------------------------------------------------"); 140 | Serial.println(); 141 | } 142 | } 143 | } 144 | else { 145 | if (debug) { 146 | Serial.println(" WiFi FAILED!"); 147 | Serial.println("\n----------------------------------------------------------------"); 148 | Serial.println(); 149 | } 150 | } 151 | } 152 | 153 | void loop() { 154 | mqttClient.loop(); 155 | yield(); 156 | timedTasks1(); 157 | yield(); 158 | timedTasks2(); 159 | yield(); 160 | checkStatus(); 161 | yield(); 162 | } 163 | 164 | void blinkLED(int pin, int duration, int n) { 165 | for(int i=0; i 1 && count <= 40) { 179 | digitalWrite(RELAY, !digitalRead(RELAY)); 180 | sendStatus = true; 181 | } 182 | else if (count >40){ 183 | if (debug) { 184 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 185 | } 186 | requestRestart = true; 187 | } 188 | count=0; 189 | } 190 | } 191 | 192 | void checkConnection() { 193 | if (WiFi.status() == WL_CONNECTED) { 194 | if (mqttClient.connected()) { 195 | if (debug) { 196 | Serial.println("mqtt broker connection . . . . . . . . . . . . . . . . . . . OK"); 197 | } 198 | } 199 | else { 200 | if (debug) { 201 | Serial.println("mqtt broker connection . . . . . . . . . . . . . . . . . . . LOST"); 202 | } 203 | requestRestart = true; 204 | } 205 | } 206 | else { 207 | if (debug) { 208 | Serial.println("WiFi connection . . . . . . . . . . . . . . . . . . . LOST"); 209 | } 210 | requestRestart = true; 211 | } 212 | } 213 | 214 | void checkStatus() { 215 | if (sendStatus) { 216 | if(digitalRead(RELAY) == LOW) { 217 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 218 | if (debug) { 219 | Serial.println("Relay . . . . . . . . . . . . . . . . . . . . . . . . . . . . OFF"); 220 | } 221 | } else { 222 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 223 | if (debug) { 224 | Serial.println("Relay . . . . . . . . . . . . . . . . . . . . . . . . . . . . ON"); 225 | } 226 | } 227 | sendStatus = false; 228 | } 229 | if (requestRestart) { 230 | blinkLED(LED, 400, 4); 231 | ESP.restart(); 232 | } 233 | } 234 | 235 | void getPower() { 236 | double power = power_read.getPower(); 237 | yield(); 238 | double voltage = power_read.getVoltage(); 239 | yield(); 240 | if (debug) { 241 | Serial.print("Reading Power . . . . . . . . . . . . . . . . . . . . . . . . "); 242 | } 243 | if (isnan(power_read.getPower() || power_read.getVoltage())) { 244 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug","\"Power Read Error\"").set_retain().set_qos(1)); 245 | if (debug) { 246 | Serial.println("ERROR"); 247 | } 248 | return; 249 | } 250 | String pubString = "{\"Power\": "+String(power)+", "+"\"Voltage\": "+String(voltage) + "}"; 251 | pubString.toCharArray(message_buff, pubString.length()+1); 252 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/power", message_buff).set_retain().set_qos(1)); 253 | } 254 | 255 | void timedTasks1() { 256 | if ((millis() > TTasks1 + (kUpdFreq*60000)) || (millis() < TTasks1)) { 257 | TTasks1 = millis(); 258 | checkConnection(); 259 | } 260 | } 261 | 262 | void timedTasks2() { 263 | if ((millis() > TTasks2 + (kPwrUpdFreq*1000)) || (millis() < TTasks2)) { 264 | TTasks2 = millis(); 265 | getPower(); 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_POW-v1.0/power.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This libary is an enhanced version of the ITEAD.cc library 3 | 4 | It reads the values from the Sonoff POW HLW8012 chip and calculates the respective 5 | Power, current, and voltage values. Only voltage or current reading can be chosen. 6 | 7 | Copyright (c) [2016] [Iteand.cc and Andreas Spiess] 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | */ 27 | 28 | #include "power.h" 29 | #include 30 | 31 | uint32_t ESP8266PowerClass::power_freq_cnt = 0; 32 | uint32_t ESP8266PowerClass::current_freq_cnt = 0; 33 | uint32_t ESP8266PowerClass::voltage_freq_cnt = 0; 34 | uint8_t ESP8266PowerClass::power_test_mode = IOTGO_HLW8012_TEST_MODE_REPEAT; 35 | uint8_t ESP8266PowerClass::current_test_mode = IOTGO_HLW8012_TEST_MODE_REPEAT; 36 | uint8_t ESP8266PowerClass::voltage_test_mode = IOTGO_HLW8012_TEST_MODE_REPEAT; 37 | bool ESP8266PowerClass::power_flag = false; 38 | bool ESP8266PowerClass::current_flag = false; 39 | bool ESP8266PowerClass::voltage_flag = false; 40 | uint32_t ESP8266PowerClass::power_freq= 0; 41 | uint32_t ESP8266PowerClass::voltage_freq= 0; 42 | uint32_t ESP8266PowerClass::current_freq= 0; 43 | 44 | void ESP8266PowerClass::measurePowerFreq(void) 45 | { 46 | power_freq_cnt++; 47 | } 48 | void ESP8266PowerClass::measureCurrenFreq(void) // counts number of interrupts CF1 pin 49 | { 50 | current_freq_cnt++; 51 | if(voltage_freq_cnt != 0) 52 | { 53 | voltage_freq_cnt = 0; 54 | } 55 | } 56 | void ESP8266PowerClass::measureVoltageFreq(void) // counts number of interrupts CF1 pin 57 | { 58 | voltage_freq_cnt++; 59 | if(current_freq_cnt != 0) 60 | { 61 | current_freq_cnt = 0; 62 | } 63 | } 64 | void ESP8266PowerClass::getAverageFreq(uint32_t (&history_queue)[10],uint32_t &freq) 65 | { 66 | uint8_t i = 0; 67 | for (i = 9; i >= 1; i--) 68 | { 69 | history_queue[i] = history_queue[i - 1]; 70 | } 71 | history_queue[0] = freq; 72 | for (i = 1; i < 10; i++) 73 | { 74 | freq += history_queue[i]; 75 | } 76 | freq = (uint32_t)((freq*1.0)/i + 0.5); 77 | } 78 | 79 | void ESP8266PowerClass::getFreq(uint32_t &cnt,uint32_t &freq_cnt,uint8_t &test_mode,uint32_t &freq, 80 | uint8_t &hlw8012_bad_once_cnt,uint8_t &hlw8012_bad_repeat_cnt,uint32_t (&history_queue)[10]) 81 | { 82 | 83 | if (IOTGO_HLW8012_TEST_MODE_REPEAT == test_mode) 84 | { 85 | if (cnt >= 1000) 86 | { 87 | if (freq_cnt > 10) 88 | { 89 | hlw8012_bad_repeat_cnt = 0; 90 | freq = freq_cnt * 100; 91 | getAverageFreq(history_queue,freq); 92 | } 93 | else 94 | { 95 | hlw8012_bad_repeat_cnt++; 96 | if (hlw8012_bad_repeat_cnt >= 2) 97 | { 98 | hlw8012_bad_repeat_cnt = 0; 99 | test_mode = IOTGO_HLW8012_TEST_MODE_ONCE; 100 | } 101 | } 102 | freq_cnt = 0; 103 | cnt = 0; 104 | 105 | } 106 | } 107 | else if (IOTGO_HLW8012_TEST_MODE_ONCE == test_mode) 108 | { 109 | if (1 == freq_cnt) 110 | { 111 | if (cnt >= 100) 112 | { 113 | hlw8012_bad_once_cnt = 0; 114 | freq = (uint32_t)(100000.0/(cnt) + 0.5); 115 | getAverageFreq(history_queue,freq); 116 | } 117 | else 118 | { 119 | hlw8012_bad_once_cnt++; 120 | if (hlw8012_bad_once_cnt >= 2) 121 | { 122 | hlw8012_bad_once_cnt = 0; 123 | test_mode = IOTGO_HLW8012_TEST_MODE_REPEAT; 124 | } 125 | } 126 | cnt = 0; 127 | freq_cnt = 0; 128 | 129 | } 130 | 131 | if (cnt >= (10*1000 + 1000)) 132 | { 133 | test_mode = IOTGO_HLW8012_TEST_MODE_REPEAT; 134 | cnt = 0; 135 | freq_cnt = 0; 136 | freq = 0; 137 | os_memset(history_queue,0,10); 138 | 139 | } 140 | } 141 | } 142 | 143 | void ESP8266PowerClass::timerCallback(void) 144 | { 145 | static uint32_t power_1ms_cnt = 0; 146 | static uint32_t curent_1ms_cnt = 0; 147 | static uint32_t voltage_1ms_cnt = 0; 148 | static uint8_t power_bad_once_cnt = 0; 149 | static uint8_t power_bad_repeat_cnt = 0; 150 | static uint8_t current_bad_once_cnt = 0; 151 | static uint8_t current_bad_repeat_cnt = 0; 152 | static uint8_t voltage_bad_once_cnt = 0; 153 | static uint8_t voltage_bad_repeat_cnt = 0; 154 | static uint32_t power_history_queue[10] = {0}; 155 | static uint32_t current_history_queue[10] = {0}; 156 | static uint32_t voltage_history_queue[10] = {0}; 157 | power_1ms_cnt++; 158 | curent_1ms_cnt++; 159 | voltage_1ms_cnt++; 160 | if(power_flag) 161 | { 162 | getFreq(power_1ms_cnt,power_freq_cnt,power_test_mode,power_freq, 163 | power_bad_once_cnt,power_bad_repeat_cnt,power_history_queue); // fills all these variables with numbers, either continuous or once 164 | } 165 | if(current_flag) 166 | { 167 | getFreq(curent_1ms_cnt,current_freq_cnt,current_test_mode,current_freq, 168 | current_bad_once_cnt,current_bad_repeat_cnt,current_history_queue); 169 | } 170 | if(voltage_flag) 171 | { 172 | getFreq(voltage_1ms_cnt,voltage_freq_cnt,voltage_test_mode,voltage_freq, 173 | voltage_bad_once_cnt,voltage_bad_repeat_cnt,voltage_history_queue); 174 | 175 | } 176 | } 177 | 178 | ESP8266PowerClass::ESP8266PowerClass() // Constructor 179 | { 180 | this->power_param = {12.286,0}; 181 | this->current_param = {14.818,0}; 182 | this->voltage_param = {0.435,0}; 183 | 184 | this->power_pin = 14; // CF 185 | this->current_voltage_pin = 13; //CF1 186 | this->sel_pin = 5; // Chip select 187 | } 188 | ESP8266PowerClass::ESP8266PowerClass(int8_t power_pin,int8_t current_voltage_pin,int8_t sel_pin) 189 | { 190 | ESP8266PowerClass(); 191 | this->power_pin = power_pin; 192 | this->current_voltage_pin = current_voltage_pin; 193 | this->sel_pin = sel_pin; 194 | } 195 | 196 | void ESP8266PowerClass::enableMeasurePower(void) 197 | { 198 | this->power_flag = true; 199 | pinMode(this->power_pin,INPUT_PULLUP); 200 | attachInterrupt(this->power_pin,measurePowerFreq,FALLING); // interrupt on CF 201 | } 202 | void ESP8266PowerClass::selectMeasureCurrentOrVoltage(MEASURETYPE dev_type) 203 | { 204 | 205 | #if 1 206 | pinMode(this->sel_pin,OUTPUT); // CF1 207 | detachInterrupt(this->current_voltage_pin); 208 | voltage_freq = 0; 209 | current_freq = 0; 210 | pinMode(this->current_voltage_pin,INPUT_PULLUP); 211 | switch(dev_type) 212 | { 213 | case CURRENT: 214 | { 215 | this->current_flag = true; 216 | this->voltage_flag = false; 217 | digitalWrite(this->sel_pin,HIGH); 218 | attachInterrupt(this->current_voltage_pin,measureCurrenFreq,FALLING); 219 | }break; 220 | case VOLTAGE: 221 | { 222 | this->current_flag = false; 223 | this->voltage_flag = true; 224 | digitalWrite(this->sel_pin,LOW); 225 | attachInterrupt(this->current_voltage_pin,measureVoltageFreq,FALLING); 226 | }break; 227 | default: 228 | { 229 | /* 230 | do nothing 231 | */ 232 | } 233 | } 234 | #endif 235 | } 236 | void ESP8266PowerClass::setPowerParam(double param_a,double param_b) 237 | { 238 | this->power_param.param_a = param_a; 239 | this->power_param.param_b = param_b; 240 | } 241 | 242 | void ESP8266PowerClass::setCurrentParam(double param_a,double param_b) 243 | { 244 | this->current_param.param_a = param_a; 245 | this->current_param.param_b = param_b; 246 | } 247 | 248 | void ESP8266PowerClass::setVoltageParam(double param_a,double param_b) 249 | { 250 | this->voltage_param.param_a = param_a; 251 | this->voltage_param.param_b = param_b; 252 | } 253 | 254 | DEVPARAM ESP8266PowerClass::getPowerParam(void) 255 | { 256 | return power_param; 257 | } 258 | DEVPARAM ESP8266PowerClass::getCurrentParam(void) 259 | { 260 | return current_param; 261 | } 262 | 263 | DEVPARAM ESP8266PowerClass::getvoltageParam(void) 264 | { 265 | return voltage_param; 266 | } 267 | void ESP8266PowerClass::startMeasure(void) 268 | { 269 | os_timer_setfn(&myTimer, (os_timer_func_t *)&ESP8266PowerClass::timerCallback, NULL); 270 | os_timer_arm(&myTimer, 1, true); // every ms 271 | } 272 | 273 | double ESP8266PowerClass::getPower(void) 274 | { 275 | uint32_t power = 0; 276 | power = power_param.param_a * power_freq + power_param.param_b * 100; 277 | return power / 100.0; 278 | } 279 | double ESP8266PowerClass::getCurrent(void) 280 | { 281 | double current = (current_param.param_a * current_freq + current_param.param_b*100.0); 282 | 283 | return current/100.0; 284 | } 285 | 286 | double ESP8266PowerClass::getCurrFrequency(void) 287 | { 288 | uint32_t frequency = 0; 289 | frequency = current_freq ; 290 | return frequency; 291 | } 292 | 293 | 294 | double ESP8266PowerClass::getVoltage(void) 295 | { 296 | uint32_t voltage = 0; 297 | voltage = voltage_param.param_a * voltage_freq + voltage_param.param_b * 100; 298 | return voltage / 100.0; 299 | } 300 | 301 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_POW-v1.0/power.h: -------------------------------------------------------------------------------- 1 | /* 2 | This libary is an enhanced version of the ITEAD.cc library 3 | 4 | It reads the values from the Sonoff POW HLW8012 chip and calculates the respective 5 | Power, current, and voltage values. Only voltage or current reading can be chosen. 6 | 7 | Copyright (c) [2016] [Iteand.cc and Andreas Spiess] 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | */ 27 | 28 | #ifndef __POWER__H_ 29 | #define __POWER__H_ 30 | 31 | #include 32 | 33 | extern "C" { 34 | #include "user_interface.h" 35 | } 36 | 37 | typedef struct _DEVPARAM{ 38 | double param_a; 39 | double param_b; 40 | }DEVPARAM; 41 | 42 | typedef enum{ 43 | CURRENT, 44 | VOLTAGE, 45 | }MEASURETYPE; 46 | 47 | typedef enum 48 | { 49 | IOTGO_HLW8012_TEST_MODE_REPEAT, 50 | IOTGO_HLW8012_TEST_MODE_ONCE, 51 | }TESTMODE; 52 | 53 | class ESP8266PowerClass{ 54 | public: 55 | ESP8266PowerClass(); 56 | ESP8266PowerClass(int8_t power_pin,int8_t current_voltage_pin,int8_t sel_pin); 57 | void enableMeasurePower(void); 58 | void selectMeasureCurrentOrVoltage(MEASURETYPE dev_type); 59 | void setPowerParam(double param_a,double param_b); 60 | void setCurrentParam(double param_a,double param_b); 61 | void setVoltageParam(double param_a,double param_b); 62 | DEVPARAM getPowerParam(void); 63 | DEVPARAM getCurrentParam(void); 64 | DEVPARAM getvoltageParam(void); 65 | void startMeasure(void); 66 | double getPower(void); 67 | double getCurrent(void); 68 | double getVoltage(void); 69 | double getCurrFrequency(void); 70 | private: 71 | static void measurePowerFreq(void); 72 | static void measureCurrenFreq(void); 73 | static void measureVoltageFreq(void); 74 | static void timerCallback(void); 75 | static void getFreq(uint32_t &cnt,uint32_t &freq_cnt,uint8_t &test_mode,uint32_t &freq, 76 | uint8_t &hlw8012_bad_once_cnt,uint8_t &hlw8012_bad_repeat_cnt,uint32_t (&history_queue)[10]); 77 | static void getAverageFreq(uint32_t (&history_queue)[10],uint32_t &freq); 78 | static uint32_t power_freq_cnt; 79 | static uint32_t voltage_freq_cnt; 80 | static uint32_t current_freq_cnt; 81 | static uint8_t power_test_mode; 82 | static uint8_t current_test_mode; 83 | static uint8_t voltage_test_mode; 84 | static bool power_flag; 85 | static bool current_flag; 86 | static bool voltage_flag; 87 | static uint32_t power_freq; 88 | static uint32_t voltage_freq; 89 | static uint32_t current_freq; 90 | DEVPARAM power_param; 91 | DEVPARAM current_param; 92 | DEVPARAM voltage_param; 93 | int8_t power_pin; 94 | int8_t current_voltage_pin; 95 | int8_t sel_pin; 96 | 97 | os_timer_t myTimer; 98 | 99 | }; 100 | 101 | #endif 102 | 103 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_POW-v1.01/ESPsonoff_POW-v1.01.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2017 @KmanOz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | ============================================================================== 24 | Changes in v1.01 25 | 26 | - Relay state now stored in EEPROM and will power up with last relay state 27 | ============================================================================== 28 | 29 | **** USE THIS Firmware for: Sonof POW **** 30 | 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include "power.h" 38 | 39 | #define BUTTON 0 // (Don't Change for Sonoff POW) 40 | #define RELAY 12 // (Don't Change for Sonoff POW) 41 | #define LED 15 // (Don't Change for Sonoff POW) 42 | 43 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.0pow" // mqtt client_id (Must be unique for each Sonoff) 44 | #define MQTT_SERVER "192.168.0.100" // mqtt server 45 | #define MQTT_PORT 1883 // mqtt port 46 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 47 | #define MQTT_USER "user" // mqtt user 48 | #define MQTT_PASS "pass" // mqtt password 49 | 50 | #define WIFI_SSID "homewifi" // wifi ssid 51 | #define WIFI_PASS "homepass" // wifi password 52 | 53 | #define VERSION "\n\n---------------- Sonoff POW Powerpoint v1.01 -----------------" 54 | 55 | bool debug = false; // If 'true' enables serial output at console for debug messages 56 | bool rememberRelayState = true; // If 'true' remembers the state of the relay before power loss. 57 | bool requestRestart = false; // (Do not Change) 58 | bool sendStatus = false; // (Do not Change) 59 | 60 | char message_buff[60]; // (Do not Change) 61 | 62 | int kUpdFreq = 1; // Update frequency in Mintes to check mqtt connection 63 | int kPwrUpdFreq = 15; // Update frequency in Seconds to publish power usage 64 | int kRetries = 10; // WiFi retry count. Increase if not connecting to router. 65 | int lastRelayState; // (Do not Change) 66 | 67 | unsigned long TTasks1; // (Do not Change) 68 | unsigned long TTasks2; // (Do not Change) 69 | unsigned long count = 0; // (Do not Change) 70 | 71 | extern "C" { 72 | #include "user_interface.h" 73 | } 74 | 75 | WiFiClient wifiClient; 76 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 77 | ESP8266PowerClass power_read; 78 | Ticker btn_timer; 79 | 80 | void callback(const MQTT::Publish& pub) { 81 | if (pub.payload_string() == "on") { 82 | digitalWrite(RELAY, HIGH); 83 | } 84 | else if (pub.payload_string() == "off") { 85 | digitalWrite(RELAY, LOW); 86 | } 87 | else if (pub.payload_string() == "reset") { 88 | requestRestart = true; 89 | } 90 | sendStatus = true; 91 | } 92 | 93 | void setup() { 94 | pinMode(LED, OUTPUT); 95 | pinMode(RELAY, OUTPUT); 96 | pinMode(BUTTON, INPUT); 97 | digitalWrite(LED, LOW); 98 | digitalWrite(RELAY, LOW); 99 | power_read.enableMeasurePower(); 100 | power_read.selectMeasureCurrentOrVoltage(VOLTAGE); 101 | power_read.startMeasure(); 102 | EEPROM.begin(8); 103 | lastRelayState = EEPROM.read(0); 104 | if (rememberRelayState && lastRelayState == 1) { 105 | digitalWrite(RELAY, HIGH); 106 | } 107 | btn_timer.attach(0.05, button); 108 | mqttClient.set_callback(callback); 109 | WiFi.mode(WIFI_STA); 110 | WiFi.begin(WIFI_SSID, WIFI_PASS); 111 | delay(500); 112 | if (debug) { 113 | Serial.begin(115200); 114 | blinkLED(LED, 25, 120); 115 | Serial.println(VERSION); 116 | Serial.print("\nESP ChipID: "); 117 | Serial.print(ESP.getChipId(), HEX); 118 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 119 | } 120 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 121 | delay(500); 122 | if (debug) { 123 | Serial.print(" ."); 124 | } 125 | } 126 | if (WiFi.status() == WL_CONNECTED) { 127 | if (debug) { 128 | Serial.println(" DONE"); 129 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 130 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 131 | } 132 | delay(500); 133 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(120).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 134 | if (debug) { 135 | Serial.print(" ."); 136 | } 137 | delay(1000); 138 | } 139 | if(mqttClient.connected()) { 140 | if (debug) { 141 | Serial.println(" DONE"); 142 | Serial.println("\n---------------------------- Logs -----------------------------"); 143 | Serial.println(); 144 | } 145 | mqttClient.subscribe(MQTT_TOPIC); 146 | blinkLED(LED, 40, 8); 147 | digitalWrite(LED, HIGH); 148 | } 149 | else { 150 | if (debug) { 151 | Serial.println(" FAILED!"); 152 | Serial.println("\n----------------------------------------------------------------"); 153 | Serial.println(); 154 | } 155 | } 156 | } 157 | else { 158 | if (debug) { 159 | Serial.println(" WiFi FAILED!"); 160 | Serial.println("\n----------------------------------------------------------------"); 161 | Serial.println(); 162 | } 163 | } 164 | } 165 | 166 | void loop() { 167 | mqttClient.loop(); 168 | yield(); 169 | timedTasks1(); 170 | yield(); 171 | timedTasks2(); 172 | yield(); 173 | checkStatus(); 174 | yield(); 175 | } 176 | 177 | void blinkLED(int pin, int duration, int n) { 178 | for(int i=0; i 1 && count <= 40) { 192 | digitalWrite(RELAY, !digitalRead(RELAY)); 193 | sendStatus = true; 194 | } 195 | else if (count >40){ 196 | if (debug) { 197 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 198 | } 199 | requestRestart = true; 200 | } 201 | count=0; 202 | } 203 | } 204 | 205 | void checkConnection() { 206 | if (WiFi.status() == WL_CONNECTED) { 207 | if (mqttClient.connected()) { 208 | if (debug) { 209 | Serial.println("mqtt broker connection . . . . . . . . . . . . . . . . . . . OK"); 210 | } 211 | } 212 | else { 213 | if (debug) { 214 | Serial.println("mqtt broker connection . . . . . . . . . . . . . . . . . . . LOST"); 215 | } 216 | requestRestart = true; 217 | } 218 | } 219 | else { 220 | if (debug) { 221 | Serial.println("WiFi connection . . . . . . . . . . . . . . . . . . . LOST"); 222 | } 223 | requestRestart = true; 224 | } 225 | } 226 | 227 | void checkStatus() { 228 | if (sendStatus) { 229 | if(digitalRead(RELAY) == LOW) { 230 | if (rememberRelayState) { 231 | EEPROM.write(0, 0); 232 | } 233 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 234 | if (debug) { 235 | Serial.println("Relay . . . . . . . . . . . . . . . . . . . . . . . . . . . . OFF"); 236 | } 237 | } else { 238 | if (rememberRelayState) { 239 | EEPROM.write(0, 1); 240 | } 241 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 242 | if (debug) { 243 | Serial.println("Relay . . . . . . . . . . . . . . . . . . . . . . . . . . . . ON"); 244 | } 245 | } 246 | if (rememberRelayState) { 247 | EEPROM.commit(); 248 | } 249 | sendStatus = false; 250 | } 251 | if (requestRestart) { 252 | blinkLED(LED, 400, 4); 253 | ESP.restart(); 254 | } 255 | } 256 | 257 | void getPower() { 258 | double power = power_read.getPower(); 259 | yield(); 260 | double voltage = power_read.getVoltage(); 261 | yield(); 262 | if (debug) { 263 | Serial.print("Reading Power . . . . . . . . . . . . . . . . . . . . . . . . "); 264 | } 265 | if (isnan(power_read.getPower() || power_read.getVoltage())) { 266 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug","\"Power Read Error\"").set_retain().set_qos(1)); 267 | if (debug) { 268 | Serial.println("ERROR"); 269 | } 270 | return; 271 | } 272 | String pubString = "{\"Power\": "+String(power)+", "+"\"Voltage\": "+String(voltage) + "}"; 273 | pubString.toCharArray(message_buff, pubString.length()+1); 274 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/power", message_buff).set_retain().set_qos(1)); 275 | } 276 | 277 | void timedTasks1() { 278 | if ((millis() > TTasks1 + (kUpdFreq*60000)) || (millis() < TTasks1)) { 279 | TTasks1 = millis(); 280 | checkConnection(); 281 | } 282 | } 283 | 284 | void timedTasks2() { 285 | if ((millis() > TTasks2 + (kPwrUpdFreq*1000)) || (millis() < TTasks2)) { 286 | TTasks2 = millis(); 287 | getPower(); 288 | } 289 | } 290 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_POW-v1.01/power.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This libary is an enhanced version of the ITEAD.cc library 3 | 4 | It reads the values from the Sonoff POW HLW8012 chip and calculates the respective 5 | Power, current, and voltage values. Only voltage or current reading can be chosen. 6 | 7 | Copyright (c) [2016] [Iteand.cc and Andreas Spiess] 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | */ 27 | 28 | #include "power.h" 29 | #include 30 | 31 | uint32_t ESP8266PowerClass::power_freq_cnt = 0; 32 | uint32_t ESP8266PowerClass::current_freq_cnt = 0; 33 | uint32_t ESP8266PowerClass::voltage_freq_cnt = 0; 34 | uint8_t ESP8266PowerClass::power_test_mode = IOTGO_HLW8012_TEST_MODE_REPEAT; 35 | uint8_t ESP8266PowerClass::current_test_mode = IOTGO_HLW8012_TEST_MODE_REPEAT; 36 | uint8_t ESP8266PowerClass::voltage_test_mode = IOTGO_HLW8012_TEST_MODE_REPEAT; 37 | bool ESP8266PowerClass::power_flag = false; 38 | bool ESP8266PowerClass::current_flag = false; 39 | bool ESP8266PowerClass::voltage_flag = false; 40 | uint32_t ESP8266PowerClass::power_freq= 0; 41 | uint32_t ESP8266PowerClass::voltage_freq= 0; 42 | uint32_t ESP8266PowerClass::current_freq= 0; 43 | 44 | void ESP8266PowerClass::measurePowerFreq(void) 45 | { 46 | power_freq_cnt++; 47 | } 48 | void ESP8266PowerClass::measureCurrenFreq(void) // counts number of interrupts CF1 pin 49 | { 50 | current_freq_cnt++; 51 | if(voltage_freq_cnt != 0) 52 | { 53 | voltage_freq_cnt = 0; 54 | } 55 | } 56 | void ESP8266PowerClass::measureVoltageFreq(void) // counts number of interrupts CF1 pin 57 | { 58 | voltage_freq_cnt++; 59 | if(current_freq_cnt != 0) 60 | { 61 | current_freq_cnt = 0; 62 | } 63 | } 64 | void ESP8266PowerClass::getAverageFreq(uint32_t (&history_queue)[10],uint32_t &freq) 65 | { 66 | uint8_t i = 0; 67 | for (i = 9; i >= 1; i--) 68 | { 69 | history_queue[i] = history_queue[i - 1]; 70 | } 71 | history_queue[0] = freq; 72 | for (i = 1; i < 10; i++) 73 | { 74 | freq += history_queue[i]; 75 | } 76 | freq = (uint32_t)((freq*1.0)/i + 0.5); 77 | } 78 | 79 | void ESP8266PowerClass::getFreq(uint32_t &cnt,uint32_t &freq_cnt,uint8_t &test_mode,uint32_t &freq, 80 | uint8_t &hlw8012_bad_once_cnt,uint8_t &hlw8012_bad_repeat_cnt,uint32_t (&history_queue)[10]) 81 | { 82 | 83 | if (IOTGO_HLW8012_TEST_MODE_REPEAT == test_mode) 84 | { 85 | if (cnt >= 1000) 86 | { 87 | if (freq_cnt > 10) 88 | { 89 | hlw8012_bad_repeat_cnt = 0; 90 | freq = freq_cnt * 100; 91 | getAverageFreq(history_queue,freq); 92 | } 93 | else 94 | { 95 | hlw8012_bad_repeat_cnt++; 96 | if (hlw8012_bad_repeat_cnt >= 2) 97 | { 98 | hlw8012_bad_repeat_cnt = 0; 99 | test_mode = IOTGO_HLW8012_TEST_MODE_ONCE; 100 | } 101 | } 102 | freq_cnt = 0; 103 | cnt = 0; 104 | 105 | } 106 | } 107 | else if (IOTGO_HLW8012_TEST_MODE_ONCE == test_mode) 108 | { 109 | if (1 == freq_cnt) 110 | { 111 | if (cnt >= 100) 112 | { 113 | hlw8012_bad_once_cnt = 0; 114 | freq = (uint32_t)(100000.0/(cnt) + 0.5); 115 | getAverageFreq(history_queue,freq); 116 | } 117 | else 118 | { 119 | hlw8012_bad_once_cnt++; 120 | if (hlw8012_bad_once_cnt >= 2) 121 | { 122 | hlw8012_bad_once_cnt = 0; 123 | test_mode = IOTGO_HLW8012_TEST_MODE_REPEAT; 124 | } 125 | } 126 | cnt = 0; 127 | freq_cnt = 0; 128 | 129 | } 130 | 131 | if (cnt >= (10*1000 + 1000)) 132 | { 133 | test_mode = IOTGO_HLW8012_TEST_MODE_REPEAT; 134 | cnt = 0; 135 | freq_cnt = 0; 136 | freq = 0; 137 | os_memset(history_queue,0,10); 138 | 139 | } 140 | } 141 | } 142 | 143 | void ESP8266PowerClass::timerCallback(void) 144 | { 145 | static uint32_t power_1ms_cnt = 0; 146 | static uint32_t curent_1ms_cnt = 0; 147 | static uint32_t voltage_1ms_cnt = 0; 148 | static uint8_t power_bad_once_cnt = 0; 149 | static uint8_t power_bad_repeat_cnt = 0; 150 | static uint8_t current_bad_once_cnt = 0; 151 | static uint8_t current_bad_repeat_cnt = 0; 152 | static uint8_t voltage_bad_once_cnt = 0; 153 | static uint8_t voltage_bad_repeat_cnt = 0; 154 | static uint32_t power_history_queue[10] = {0}; 155 | static uint32_t current_history_queue[10] = {0}; 156 | static uint32_t voltage_history_queue[10] = {0}; 157 | power_1ms_cnt++; 158 | curent_1ms_cnt++; 159 | voltage_1ms_cnt++; 160 | if(power_flag) 161 | { 162 | getFreq(power_1ms_cnt,power_freq_cnt,power_test_mode,power_freq, 163 | power_bad_once_cnt,power_bad_repeat_cnt,power_history_queue); // fills all these variables with numbers, either continuous or once 164 | } 165 | if(current_flag) 166 | { 167 | getFreq(curent_1ms_cnt,current_freq_cnt,current_test_mode,current_freq, 168 | current_bad_once_cnt,current_bad_repeat_cnt,current_history_queue); 169 | } 170 | if(voltage_flag) 171 | { 172 | getFreq(voltage_1ms_cnt,voltage_freq_cnt,voltage_test_mode,voltage_freq, 173 | voltage_bad_once_cnt,voltage_bad_repeat_cnt,voltage_history_queue); 174 | 175 | } 176 | } 177 | 178 | ESP8266PowerClass::ESP8266PowerClass() // Constructor 179 | { 180 | this->power_param = {12.286,0}; 181 | this->current_param = {14.818,0}; 182 | this->voltage_param = {0.435,0}; 183 | 184 | this->power_pin = 14; // CF 185 | this->current_voltage_pin = 13; //CF1 186 | this->sel_pin = 5; // Chip select 187 | } 188 | ESP8266PowerClass::ESP8266PowerClass(int8_t power_pin,int8_t current_voltage_pin,int8_t sel_pin) 189 | { 190 | ESP8266PowerClass(); 191 | this->power_pin = power_pin; 192 | this->current_voltage_pin = current_voltage_pin; 193 | this->sel_pin = sel_pin; 194 | } 195 | 196 | void ESP8266PowerClass::enableMeasurePower(void) 197 | { 198 | this->power_flag = true; 199 | pinMode(this->power_pin,INPUT_PULLUP); 200 | attachInterrupt(this->power_pin,measurePowerFreq,FALLING); // interrupt on CF 201 | } 202 | void ESP8266PowerClass::selectMeasureCurrentOrVoltage(MEASURETYPE dev_type) 203 | { 204 | 205 | #if 1 206 | pinMode(this->sel_pin,OUTPUT); // CF1 207 | detachInterrupt(this->current_voltage_pin); 208 | voltage_freq = 0; 209 | current_freq = 0; 210 | pinMode(this->current_voltage_pin,INPUT_PULLUP); 211 | switch(dev_type) 212 | { 213 | case CURRENT: 214 | { 215 | this->current_flag = true; 216 | this->voltage_flag = false; 217 | digitalWrite(this->sel_pin,HIGH); 218 | attachInterrupt(this->current_voltage_pin,measureCurrenFreq,FALLING); 219 | }break; 220 | case VOLTAGE: 221 | { 222 | this->current_flag = false; 223 | this->voltage_flag = true; 224 | digitalWrite(this->sel_pin,LOW); 225 | attachInterrupt(this->current_voltage_pin,measureVoltageFreq,FALLING); 226 | }break; 227 | default: 228 | { 229 | /* 230 | do nothing 231 | */ 232 | } 233 | } 234 | #endif 235 | } 236 | void ESP8266PowerClass::setPowerParam(double param_a,double param_b) 237 | { 238 | this->power_param.param_a = param_a; 239 | this->power_param.param_b = param_b; 240 | } 241 | 242 | void ESP8266PowerClass::setCurrentParam(double param_a,double param_b) 243 | { 244 | this->current_param.param_a = param_a; 245 | this->current_param.param_b = param_b; 246 | } 247 | 248 | void ESP8266PowerClass::setVoltageParam(double param_a,double param_b) 249 | { 250 | this->voltage_param.param_a = param_a; 251 | this->voltage_param.param_b = param_b; 252 | } 253 | 254 | DEVPARAM ESP8266PowerClass::getPowerParam(void) 255 | { 256 | return power_param; 257 | } 258 | DEVPARAM ESP8266PowerClass::getCurrentParam(void) 259 | { 260 | return current_param; 261 | } 262 | 263 | DEVPARAM ESP8266PowerClass::getvoltageParam(void) 264 | { 265 | return voltage_param; 266 | } 267 | void ESP8266PowerClass::startMeasure(void) 268 | { 269 | os_timer_setfn(&myTimer, (os_timer_func_t *)&ESP8266PowerClass::timerCallback, NULL); 270 | os_timer_arm(&myTimer, 1, true); // every ms 271 | } 272 | 273 | double ESP8266PowerClass::getPower(void) 274 | { 275 | uint32_t power = 0; 276 | power = power_param.param_a * power_freq + power_param.param_b * 100; 277 | return power / 100.0; 278 | } 279 | double ESP8266PowerClass::getCurrent(void) 280 | { 281 | double current = (current_param.param_a * current_freq + current_param.param_b*100.0); 282 | 283 | return current/100.0; 284 | } 285 | 286 | double ESP8266PowerClass::getCurrFrequency(void) 287 | { 288 | uint32_t frequency = 0; 289 | frequency = current_freq ; 290 | return frequency; 291 | } 292 | 293 | 294 | double ESP8266PowerClass::getVoltage(void) 295 | { 296 | uint32_t voltage = 0; 297 | voltage = voltage_param.param_a * voltage_freq + voltage_param.param_b * 100; 298 | return voltage / 100.0; 299 | } 300 | 301 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_POW-v1.01/power.h: -------------------------------------------------------------------------------- 1 | /* 2 | This libary is an enhanced version of the ITEAD.cc library 3 | 4 | It reads the values from the Sonoff POW HLW8012 chip and calculates the respective 5 | Power, current, and voltage values. Only voltage or current reading can be chosen. 6 | 7 | Copyright (c) [2016] [Iteand.cc and Andreas Spiess] 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | */ 27 | 28 | #ifndef __POWER__H_ 29 | #define __POWER__H_ 30 | 31 | #include 32 | 33 | extern "C" { 34 | #include "user_interface.h" 35 | } 36 | 37 | typedef struct _DEVPARAM{ 38 | double param_a; 39 | double param_b; 40 | }DEVPARAM; 41 | 42 | typedef enum{ 43 | CURRENT, 44 | VOLTAGE, 45 | }MEASURETYPE; 46 | 47 | typedef enum 48 | { 49 | IOTGO_HLW8012_TEST_MODE_REPEAT, 50 | IOTGO_HLW8012_TEST_MODE_ONCE, 51 | }TESTMODE; 52 | 53 | class ESP8266PowerClass{ 54 | public: 55 | ESP8266PowerClass(); 56 | ESP8266PowerClass(int8_t power_pin,int8_t current_voltage_pin,int8_t sel_pin); 57 | void enableMeasurePower(void); 58 | void selectMeasureCurrentOrVoltage(MEASURETYPE dev_type); 59 | void setPowerParam(double param_a,double param_b); 60 | void setCurrentParam(double param_a,double param_b); 61 | void setVoltageParam(double param_a,double param_b); 62 | DEVPARAM getPowerParam(void); 63 | DEVPARAM getCurrentParam(void); 64 | DEVPARAM getvoltageParam(void); 65 | void startMeasure(void); 66 | double getPower(void); 67 | double getCurrent(void); 68 | double getVoltage(void); 69 | double getCurrFrequency(void); 70 | private: 71 | static void measurePowerFreq(void); 72 | static void measureCurrenFreq(void); 73 | static void measureVoltageFreq(void); 74 | static void timerCallback(void); 75 | static void getFreq(uint32_t &cnt,uint32_t &freq_cnt,uint8_t &test_mode,uint32_t &freq, 76 | uint8_t &hlw8012_bad_once_cnt,uint8_t &hlw8012_bad_repeat_cnt,uint32_t (&history_queue)[10]); 77 | static void getAverageFreq(uint32_t (&history_queue)[10],uint32_t &freq); 78 | static uint32_t power_freq_cnt; 79 | static uint32_t voltage_freq_cnt; 80 | static uint32_t current_freq_cnt; 81 | static uint8_t power_test_mode; 82 | static uint8_t current_test_mode; 83 | static uint8_t voltage_test_mode; 84 | static bool power_flag; 85 | static bool current_flag; 86 | static bool voltage_flag; 87 | static uint32_t power_freq; 88 | static uint32_t voltage_freq; 89 | static uint32_t current_freq; 90 | DEVPARAM power_param; 91 | DEVPARAM current_param; 92 | DEVPARAM voltage_param; 93 | int8_t power_pin; 94 | int8_t current_voltage_pin; 95 | int8_t sel_pin; 96 | 97 | os_timer_t myTimer; 98 | 99 | }; 100 | 101 | #endif 102 | 103 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_TH-v1.01p/ESPsonoff_TH-v1.01p.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2017 @KmanOz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | ============================================================================== 24 | Changes in v1.01 25 | 26 | - Relay state now stored in EEPROM and will power up with last relay state 27 | - Remote ON & OFF via Wallswitch on pin 14. No debounce provided. Assumes 28 | operation via proper electrical wallswitch which has mechanical debounce. 29 | ============================================================================== 30 | 31 | **** USE THIS Firmware for: Sonof TH10/16 and additional wallswitch **** 32 | 33 | */ 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #define BUTTON 0 // (Don't Change for Sonoff TH Series) 41 | #define RELAY 12 // (Don't Change for Sonoff TH Series) 42 | #define LED 13 // (Don't Change for Sonoff TH Series) 43 | #define WALLSWITCH 14 // (Don't Change for Sonoff TH Series) 44 | 45 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.0p" // mqtt client_id (Must be unique for each Sonoff) 46 | #define MQTT_SERVER "192.168.0.100" // mqtt server 47 | #define MQTT_PORT 1883 // mqtt port 48 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 49 | #define MQTT_USER "user" // mqtt user 50 | #define MQTT_PASS "pass" // mqtt password 51 | 52 | #define WIFI_SSID "homewifi" // wifi ssid 53 | #define WIFI_PASS "homepass" // wifi password 54 | 55 | #define VERSION "\n\n---------------- Sonoff TH Powerpoint v1.01p -----------------" 56 | 57 | bool rememberRelayState = true; // If 'true' remembers the state of the relay before power loss. 58 | bool requestRestart = false; // (Do not Change) 59 | bool sendStatus = false; // (Do not Change) 60 | 61 | int kUpdFreq = 1; // Update frequency in Mintes to check for mqtt connection 62 | int kRetries = 10; // WiFi retry count. Increase if not connecting to router. 63 | int wallSwitch = 1; // (Do not Change) 64 | int lastWallSwitch = 1; // (Do not Change) 65 | int lastRelayState; // (Do not Change) 66 | 67 | unsigned long TTasks; // (Do not Change) 68 | unsigned long count = 0; // (Do not Change) 69 | 70 | extern "C" { 71 | #include "user_interface.h" 72 | } 73 | 74 | WiFiClient wifiClient; 75 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 76 | Ticker btn_timer; 77 | 78 | void callback(const MQTT::Publish& pub) { 79 | if (pub.payload_string() == "stat") { 80 | } 81 | else if (pub.payload_string() == "on") { 82 | digitalWrite(RELAY, HIGH); 83 | } 84 | else if (pub.payload_string() == "off") { 85 | digitalWrite(RELAY, LOW); 86 | } 87 | else if (pub.payload_string() == "reset") { 88 | requestRestart = true; 89 | } 90 | sendStatus = true; 91 | } 92 | 93 | void setup() { 94 | pinMode(LED, OUTPUT); 95 | pinMode(RELAY, OUTPUT); 96 | pinMode(BUTTON, INPUT); 97 | pinMode(WALLSWITCH, INPUT); 98 | digitalWrite(LED, HIGH); 99 | digitalWrite(RELAY, LOW); 100 | Serial.begin(115200); 101 | EEPROM.begin(8); 102 | lastRelayState = EEPROM.read(0); 103 | if (rememberRelayState && lastRelayState == 1) { 104 | digitalWrite(RELAY, HIGH); 105 | } 106 | btn_timer.attach(0.05, button); 107 | mqttClient.set_callback(callback); 108 | WiFi.mode(WIFI_STA); 109 | WiFi.begin(WIFI_SSID, WIFI_PASS); 110 | Serial.println(VERSION); 111 | Serial.print("\nUnit ID: "); 112 | Serial.print("esp8266-"); 113 | Serial.print(ESP.getChipId(), HEX); 114 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 115 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 116 | delay(500); 117 | Serial.print(" ."); 118 | } 119 | if (WiFi.status() == WL_CONNECTED) { 120 | Serial.println(" DONE"); 121 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 122 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 123 | delay(500); 124 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 125 | Serial.print(" ."); 126 | delay(1000); 127 | } 128 | if(mqttClient.connected()) { 129 | Serial.println(" DONE"); 130 | Serial.println("\n---------------------------- Logs ----------------------------"); 131 | Serial.println(); 132 | mqttClient.subscribe(MQTT_TOPIC); 133 | blinkLED(LED, 40, 8); 134 | digitalWrite(LED, LOW); 135 | } 136 | else { 137 | Serial.println(" FAILED!"); 138 | Serial.println("\n----------------------------------------------------------------"); 139 | Serial.println(); 140 | } 141 | } 142 | else { 143 | Serial.println(" WiFi FAILED!"); 144 | Serial.println("\n----------------------------------------------------------------"); 145 | Serial.println(); 146 | } 147 | } 148 | 149 | void loop() { 150 | mqttClient.loop(); 151 | timedTasks(); 152 | checkStatus(); 153 | checkWallSwitch(); 154 | } 155 | 156 | void blinkLED(int pin, int duration, int n) { 157 | for(int i=0; i 1 && count <= 40) { 171 | digitalWrite(RELAY, !digitalRead(RELAY)); 172 | sendStatus = true; 173 | } 174 | else if (count >40){ 175 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 176 | requestRestart = true; 177 | } 178 | count=0; 179 | } 180 | } 181 | 182 | void checkConnection() { 183 | if (WiFi.status() == WL_CONNECTED) { 184 | if (mqttClient.connected()) { 185 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 186 | } 187 | else { 188 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 189 | requestRestart = true; 190 | } 191 | } 192 | else { 193 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 194 | requestRestart = true; 195 | } 196 | } 197 | 198 | void checkStatus() { 199 | if (sendStatus) { 200 | if(digitalRead(RELAY) == LOW) { 201 | if (rememberRelayState) { 202 | EEPROM.write(0, 0); 203 | } 204 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 205 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 206 | } else { 207 | if (rememberRelayState) { 208 | EEPROM.write(0, 1); 209 | } 210 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 211 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 212 | } 213 | if (rememberRelayState) { 214 | EEPROM.commit(); 215 | } 216 | sendStatus = false; 217 | } 218 | if (requestRestart) { 219 | blinkLED(LED, 400, 4); 220 | ESP.restart(); 221 | } 222 | } 223 | 224 | void checkWallSwitch() { 225 | wallSwitch = digitalRead(WALLSWITCH); 226 | if (wallSwitch != lastWallSwitch) { 227 | digitalWrite(RELAY, !digitalRead(RELAY)); 228 | sendStatus = true; 229 | } 230 | lastWallSwitch = wallSwitch; 231 | } 232 | 233 | void timedTasks() { 234 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 235 | TTasks = millis(); 236 | checkConnection(); 237 | } 238 | } 239 | 240 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_TH-v1.01pOTA/ESPsonoff_TH-v1.01pOTA.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 @KmanOz 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | 22 | ============================================================================== 23 | Changes in v1.01pOTA 24 | 25 | - Relay state now stored in EEPROM and will power up with last relay state 26 | - Support for Wallswitch to turn the Sonoff ON & OFF on Pin 14. 27 | - OTA Firmware Upgradable 28 | ============================================================================== 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #define BUTTON 0 // (Don't Change for Sonoff TH Series) 40 | #define RELAY 12 // (Don't Change for Sonoff TH Series) 41 | #define LED 13 // (Don't Change for Sonoff TH Series) 42 | #define WALLSWITCH 14 // (Don't Change for Sonoff TH Series) 43 | 44 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.01pOTA" // mqtt client_id (Must be unique for each Sonoff) 45 | #define MQTT_SERVER "192.168.0.100" // mqtt server 46 | #define MQTT_PORT 1883 // mqtt port 47 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 48 | #define MQTT_USER "user" // mqtt user 49 | #define MQTT_PASS "pass" // mqtt password 50 | 51 | #define WIFI_SSID "homewifi" // wifi ssid 52 | #define WIFI_PASS "homepass" // wifi password 53 | 54 | #define VERSION "\n\n--------------- Sonoff TH Powerpoint v1.01pOTA ---------------" 55 | 56 | bool rememberRelayState = true; // If 'true' remembers the state of the relay before power loss. 57 | bool OTAupdate = false; // (Do not Change) 58 | bool requestRestart = false; // (Do not Change) 59 | bool sendStatus = false; // (Do not Change) 60 | 61 | int kUpdFreq = 1; // Update frequency in Mintes to check for mqtt connection 62 | int kRetries = 10; // WiFi retry count. Increase if not connecting to router. 63 | int wallSwitch = 1; // (Do not Change) 64 | int lastWallSwitch = 1; // (Do not Change) 65 | int lastRelayState; // (Do not Change) 66 | 67 | unsigned long TTasks; // (Do not Change) 68 | unsigned long count = 0; // (Do not Change) 69 | 70 | extern "C" { 71 | #include "user_interface.h" 72 | } 73 | 74 | WiFiClient wifiClient; 75 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 76 | Ticker btn_timer; 77 | 78 | void callback(const MQTT::Publish& pub) { 79 | if (pub.payload_string() == "stat") { 80 | } 81 | else if (pub.payload_string() == "on") { 82 | digitalWrite(RELAY, HIGH); 83 | } 84 | else if (pub.payload_string() == "off") { 85 | digitalWrite(RELAY, LOW); 86 | } 87 | else if (pub.payload_string() == "reset") { 88 | requestRestart = true; 89 | } 90 | sendStatus = true; 91 | } 92 | 93 | void setup() { 94 | pinMode(LED, OUTPUT); 95 | pinMode(RELAY, OUTPUT); 96 | pinMode(BUTTON, INPUT); 97 | pinMode(WALLSWITCH, INPUT); 98 | digitalWrite(LED, HIGH); 99 | digitalWrite(RELAY, LOW); 100 | Serial.begin(115200); 101 | EEPROM.begin(8); 102 | lastRelayState = EEPROM.read(0); 103 | if (rememberRelayState && lastRelayState == 1) { 104 | digitalWrite(RELAY, HIGH); 105 | } 106 | btn_timer.attach(0.05, button); 107 | mqttClient.set_callback(callback); 108 | WiFi.mode(WIFI_STA); 109 | WiFi.begin(WIFI_SSID, WIFI_PASS); 110 | ArduinoOTA.onStart([]() { 111 | OTAupdate = true; 112 | blinkLED(LED, 400, 2); 113 | digitalWrite(LED, HIGH); 114 | Serial.println("OTA Update Initiated . . ."); 115 | }); 116 | ArduinoOTA.onEnd([]() { 117 | Serial.println("\nOTA Update Ended . . .s"); 118 | OTAupdate = false; 119 | requestRestart = true; 120 | }); 121 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { 122 | digitalWrite(LED, LOW); 123 | delay(5); 124 | digitalWrite(LED, HIGH); 125 | Serial.printf("Progress: %u%%\r", (progress / (total / 100))); 126 | }); 127 | ArduinoOTA.onError([](ota_error_t error) { 128 | blinkLED(LED, 40, 2); 129 | OTAupdate = false; 130 | Serial.printf("OTA Error [%u] ", error); 131 | if (error == OTA_AUTH_ERROR) Serial.println(". . . . . . . . . . . . . . . Auth Failed"); 132 | else if (error == OTA_BEGIN_ERROR) Serial.println(". . . . . . . . . . . . . . . Begin Failed"); 133 | else if (error == OTA_CONNECT_ERROR) Serial.println(". . . . . . . . . . . . . . . Connect Failed"); 134 | else if (error == OTA_RECEIVE_ERROR) Serial.println(". . . . . . . . . . . . . . . Receive Failed"); 135 | else if (error == OTA_END_ERROR) Serial.println(". . . . . . . . . . . . . . . End Failed"); 136 | }); 137 | ArduinoOTA.begin(); 138 | Serial.println(VERSION); 139 | Serial.print("\nUnit ID: "); 140 | Serial.print("esp8266-"); 141 | Serial.print(ESP.getChipId(), HEX);; 142 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 143 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 144 | delay(500); 145 | Serial.print(" ."); 146 | } 147 | if (WiFi.status() == WL_CONNECTED) { 148 | Serial.println(" DONE"); 149 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 150 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 151 | delay(500); 152 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 153 | Serial.print(" ."); 154 | delay(1000); 155 | } 156 | if(mqttClient.connected()) { 157 | Serial.println(" DONE"); 158 | Serial.println("\n---------------------------- Logs ----------------------------"); 159 | Serial.println(); 160 | mqttClient.subscribe(MQTT_TOPIC); 161 | blinkLED(LED, 40, 8); 162 | digitalWrite(LED, LOW); 163 | } 164 | else { 165 | Serial.println(" FAILED!"); 166 | Serial.println("\n----------------------------------------------------------------"); 167 | Serial.println(); 168 | } 169 | } 170 | else { 171 | Serial.println(" WiFi FAILED!"); 172 | Serial.println("\n----------------------------------------------------------------"); 173 | Serial.println(); 174 | } 175 | } 176 | 177 | void loop() { 178 | ArduinoOTA.handle(); 179 | if (OTAupdate == false) { 180 | mqttClient.loop(); 181 | timedTasks(); 182 | checkStatus(); 183 | } 184 | } 185 | 186 | void blinkLED(int pin, int duration, int n) { 187 | for(int i=0; i 1 && count <= 40) { 201 | digitalWrite(RELAY, !digitalRead(RELAY)); 202 | sendStatus = true; 203 | } 204 | else if (count >40){ 205 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 206 | requestRestart = true; 207 | } 208 | count=0; 209 | } 210 | } 211 | 212 | void checkConnection() { 213 | if (WiFi.status() == WL_CONNECTED) { 214 | if (mqttClient.connected()) { 215 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 216 | } 217 | else { 218 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 219 | requestRestart = true; 220 | } 221 | } 222 | else { 223 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 224 | requestRestart = true; 225 | } 226 | } 227 | 228 | void checkStatus() { 229 | if (sendStatus) { 230 | if(digitalRead(RELAY) == LOW) { 231 | if (rememberRelayState) { 232 | EEPROM.write(0, 0); 233 | } 234 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 235 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 236 | } else { 237 | if (rememberRelayState) { 238 | EEPROM.write(0, 1); 239 | } 240 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 241 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 242 | } 243 | if (rememberRelayState) { 244 | EEPROM.commit(); 245 | } 246 | sendStatus = false; 247 | } 248 | if (requestRestart) { 249 | blinkLED(LED, 400, 4); 250 | ESP.restart(); 251 | } 252 | } 253 | 254 | void checkWallSwitch() { 255 | wallSwitch = digitalRead(WALLSWITCH); 256 | if (wallSwitch != lastWallSwitch) { 257 | digitalWrite(RELAY, !digitalRead(RELAY)); 258 | sendStatus = true; 259 | } 260 | lastWallSwitch = wallSwitch; 261 | } 262 | 263 | void timedTasks() { 264 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 265 | TTasks = millis(); 266 | checkConnection(); 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_TH-v1.01pt/ESPsonoff_TH-v1.01pt.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2017 @KmanOz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | ============================================================================== 24 | Changes in v1.01 25 | 26 | - Relay state now stored in EEPROM and will power up with last relay state 27 | - Remote ON & OFF via Wallswitch on pin 4. No debounce provided. Assumes 28 | operation via proper electrical wallswitch which has mechanical debounce. 29 | Sonoff needs to be modified to expose Pin 4 onto 2.5mm socket. 30 | ============================================================================== 31 | 32 | **** USE THIS Firmware for: Sonof TH10/16 fitted with AM2303 / DHT22 supplied by ITEAD **** 33 | 34 | */ 35 | 36 | #include 37 | #include "DHT.h" 38 | #include 39 | #include 40 | #include 41 | 42 | #define BUTTON 0 // (Don't Change for Sonoff TH Series) 43 | #define RELAY 12 // (Don't Change for Sonoff TH Series) 44 | #define LED 13 // (Don't Change for Sonoff TH Series) 45 | #define DHTPIN 14 // (Don't Change for Sonoff TH Series) 46 | #define WALLSWITCH 4 // (Don't Change for Sonoff TH Series) 47 | 48 | #define DHTTYPE DHT22 // (11 or 22) DHT Type 49 | 50 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.01t" // mqtt client_id (Must be unique for each Sonoff) 51 | #define MQTT_SERVER "192.168.0.100" // mqtt server 52 | #define MQTT_PORT 1883 // mqtt port 53 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 54 | #define MQTT_USER "user" // mqtt user 55 | #define MQTT_PASS "pass" // mqtt password 56 | 57 | #define WIFI_SSID "homewifi" // wifi ssid 58 | #define WIFI_PASS "homepass" // wifi password 59 | 60 | #define VERSION "\n\n---------------- Sonoff TH Powerpoint v1.01t -----------------" 61 | 62 | DHT dht(DHTPIN, DHTTYPE, 11); // (Don't Change for Sonoff TH Series) 63 | 64 | bool rememberRelayState = true; // If 'true' remembers the state of the relay before power loss. 65 | bool requestRestart = false; // (Do not Change) 66 | bool sendStatus = false; // (Do not Change) 67 | bool tempReport = false; // (Do not Change) 68 | 69 | int kUpdFreq = 1; // Update frequency in Mintes to check for mqtt connection 70 | int kRetries = 10; // WiFi retry count. Increase if not connecting to router. 71 | int wallSwitch = 1; // (Do not Change) 72 | int lastWallSwitch = 1; // (Do not Change) 73 | int lastRelayState; // (Do not Change) 74 | 75 | unsigned long TTasks; // (Do not Change) 76 | unsigned long count = 0; // (Do not Change) 77 | 78 | extern "C" { 79 | #include "user_interface.h" 80 | } 81 | 82 | WiFiClient wifiClient; 83 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 84 | Ticker btn_timer; 85 | 86 | void callback(const MQTT::Publish& pub) { 87 | if (pub.payload_string() == "stat") { 88 | } 89 | else if (pub.payload_string() == "on") { 90 | digitalWrite(RELAY, HIGH); 91 | } 92 | else if (pub.payload_string() == "off") { 93 | digitalWrite(RELAY, LOW); 94 | } 95 | else if (pub.payload_string() == "reset") { 96 | requestRestart = true; 97 | } 98 | else if (pub.payload_string() == "temp") { 99 | tempReport = true; 100 | } 101 | sendStatus = true; 102 | } 103 | 104 | void setup() { 105 | pinMode(LED, OUTPUT); 106 | pinMode(RELAY, OUTPUT); 107 | pinMode(BUTTON, INPUT); 108 | pinMode(WALLSWITCH, INPUT); 109 | digitalWrite(LED, HIGH); 110 | digitalWrite(RELAY, LOW); 111 | Serial.begin(115200); 112 | EEPROM.begin(8); 113 | lastRelayState = EEPROM.read(0); 114 | if (rememberRelayState && lastRelayState == 1) { 115 | digitalWrite(RELAY, HIGH); 116 | } 117 | btn_timer.attach(0.05, button); 118 | mqttClient.set_callback(callback); 119 | WiFi.mode(WIFI_STA); 120 | WiFi.begin(WIFI_SSID, WIFI_PASS); 121 | Serial.println(VERSION); 122 | Serial.print("\nUnit ID: "); 123 | Serial.print("esp8266-"); 124 | Serial.print(ESP.getChipId(), HEX); 125 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 126 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 127 | delay(500); 128 | Serial.print(" ."); 129 | } 130 | if (WiFi.status() == WL_CONNECTED) { 131 | Serial.println(" DONE"); 132 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 133 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 134 | delay(500); 135 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 136 | Serial.print(" ."); 137 | delay(1000); 138 | } 139 | if(mqttClient.connected()) { 140 | Serial.println(" DONE"); 141 | Serial.println("\n---------------------------- Logs ----------------------------"); 142 | Serial.println(); 143 | mqttClient.subscribe(MQTT_TOPIC); 144 | blinkLED(LED, 40, 8); 145 | digitalWrite(LED, LOW); 146 | } 147 | else { 148 | Serial.println(" FAILED!"); 149 | Serial.println("\n----------------------------------------------------------------"); 150 | Serial.println(); 151 | } 152 | } 153 | else { 154 | Serial.println(" WiFi FAILED!"); 155 | Serial.println("\n----------------------------------------------------------------"); 156 | Serial.println(); 157 | } 158 | getTemp(); 159 | } 160 | 161 | void loop() { 162 | mqttClient.loop(); 163 | timedTasks(); 164 | checkStatus(); 165 | checkWallSwitch(); 166 | if (tempReport) { 167 | getTemp(); 168 | } 169 | } 170 | 171 | void blinkLED(int pin, int duration, int n) { 172 | for(int i=0; i 1 && count <= 40) { 186 | digitalWrite(RELAY, !digitalRead(RELAY)); 187 | sendStatus = true; 188 | } 189 | else if (count >40){ 190 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 191 | requestRestart = true; 192 | } 193 | count=0; 194 | } 195 | } 196 | 197 | void checkConnection() { 198 | if (WiFi.status() == WL_CONNECTED) { 199 | if (mqttClient.connected()) { 200 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 201 | } 202 | else { 203 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 204 | requestRestart = true; 205 | } 206 | } 207 | else { 208 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 209 | requestRestart = true; 210 | } 211 | } 212 | 213 | void checkStatus() { 214 | if (sendStatus) { 215 | if(digitalRead(RELAY) == LOW) { 216 | if (rememberRelayState) { 217 | EEPROM.write(0, 0); 218 | } 219 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 220 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 221 | } else { 222 | if (rememberRelayState) { 223 | EEPROM.write(0, 1); 224 | } 225 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 226 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 227 | } 228 | if (rememberRelayState) { 229 | EEPROM.commit(); 230 | } 231 | sendStatus = false; 232 | } 233 | if (requestRestart) { 234 | blinkLED(LED, 400, 4); 235 | ESP.restart(); 236 | } 237 | } 238 | 239 | void checkWallSwitch() { 240 | wallSwitch = digitalRead(WALLSWITCH); 241 | if (wallSwitch != lastWallSwitch) { 242 | digitalWrite(RELAY, !digitalRead(RELAY)); 243 | sendStatus = true; 244 | } 245 | lastWallSwitch = wallSwitch; 246 | } 247 | 248 | void getTemp() { 249 | Serial.print("DHT read . . . . . . . . . . . . . . . . . "); 250 | float dhtH, dhtT; 251 | char message_buff[60]; 252 | dhtH = dht.readHumidity(); 253 | dhtT = dht.readTemperature(); 254 | if(digitalRead(LED) == LOW) { 255 | blinkLED(LED, 100, 1); 256 | } else { 257 | blinkLED(LED, 100, 1); 258 | digitalWrite(LED, HIGH); 259 | } 260 | if (isnan(dhtH) || isnan(dhtT)) { 261 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug","\"DHT Read Error\"").set_retain().set_qos(1)); 262 | Serial.println("ERROR"); 263 | tempReport = false; 264 | return; 265 | } 266 | String pubString = "{\"Temp\": "+String(dhtT)+", "+"\"Humidity\": "+String(dhtH) + "}"; 267 | pubString.toCharArray(message_buff, pubString.length()+1); 268 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/temp", message_buff).set_retain().set_qos(1)); 269 | Serial.println("OK"); 270 | tempReport = false; 271 | } 272 | 273 | void timedTasks() { 274 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 275 | TTasks = millis(); 276 | checkConnection(); 277 | tempReport = true; 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_TH-v1.01ptOTA/ESPsonoff_TH-v1.01ptOTA.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2017 @KmanOz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | ============================================================================== 24 | Changes in v1.01ptOTA 25 | 26 | - Relay state now stored in EEPROM and will power up with last relay state 27 | - Remote ON & OFF via Wallswitch on pin 4. No debounce provided. Assumes 28 | operation via proper electrical wallswitch which has mechanical debounce. 29 | Sonoff needs to be modified to expose Pin 4 onto 2.5mm socket. 30 | - OTA Firmware Upgradable 31 | ============================================================================== 32 | 33 | **** USE THIS Firmware for: Sonof TH10/16 fitted with AM2303 / DHT22 supplied by ITEAD **** 34 | 35 | */ 36 | 37 | #include 38 | #include "DHT.h" 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #define BUTTON 0 // (Don't Change for Sonoff TH Series) 47 | #define RELAY 12 // (Don't Change for Sonoff TH Series) 48 | #define LED 13 // (Don't Change for Sonoff TH Series) 49 | #define DHTPIN 14 // (Don't Change for Sonoff TH Series) 50 | #define WALLSWITCH 4 // (Don't Change for Sonoff TH Series) 51 | 52 | #define DHTTYPE DHT22 // (11 or 22) DHT Type 53 | 54 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.01ptOTA" // mqtt client_id (Must be unique for each Sonoff) 55 | #define MQTT_SERVER "192.168.0.100" // mqtt server 56 | #define MQTT_PORT 1883 // mqtt port 57 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 58 | #define MQTT_USER "user" // mqtt user 59 | #define MQTT_PASS "pass" // mqtt password 60 | 61 | #define WIFI_SSID "homewifi" // wifi ssid 62 | #define WIFI_PASS "homepass" // wifi password 63 | 64 | #define VERSION "\n\n-------------- Sonoff TH Powerpoint v1.01ptOTA ---------------" 65 | 66 | DHT dht(DHTPIN, DHTTYPE, 11); // (Don't Change for Sonoff TH Series) 67 | 68 | bool rememberRelayState = true; // If 'true' remembers the state of the relay before power loss. 69 | bool OTAupdate = false; // (Do not Change) 70 | bool requestRestart = false; // (Do not Change) 71 | bool sendStatus = false; // (Do not Change) 72 | bool tempReport = false; // (Do not Change) 73 | 74 | int kUpdFreq = 1; // Update frequency in Mintes to check for mqtt connection 75 | int kRetries = 10; // WiFi retry count. Increase if not connecting to router. 76 | int wallSwitch = 1; // (Do not Change) 77 | int lastWallSwitch = 1; // (Do not Change) 78 | int lastRelayState; // (Do not Change) 79 | 80 | unsigned long TTasks; // (Do not Change) 81 | unsigned long count = 0; // (Do not Change) 82 | 83 | extern "C" { 84 | #include "user_interface.h" 85 | } 86 | 87 | WiFiClient wifiClient; 88 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 89 | Ticker btn_timer; 90 | 91 | void callback(const MQTT::Publish& pub) { 92 | if (pub.payload_string() == "stat") { 93 | } 94 | else if (pub.payload_string() == "on") { 95 | digitalWrite(RELAY, HIGH); 96 | } 97 | else if (pub.payload_string() == "off") { 98 | digitalWrite(RELAY, LOW); 99 | } 100 | else if (pub.payload_string() == "reset") { 101 | requestRestart = true; 102 | } 103 | else if (pub.payload_string() == "temp") { 104 | tempReport = true; 105 | } 106 | sendStatus = true; 107 | } 108 | 109 | void setup() { 110 | pinMode(LED, OUTPUT); 111 | pinMode(RELAY, OUTPUT); 112 | pinMode(BUTTON, INPUT); 113 | pinMode(WALLSWITCH, INPUT); 114 | digitalWrite(LED, HIGH); 115 | digitalWrite(RELAY, LOW); 116 | Serial.begin(115200); 117 | EEPROM.begin(8); 118 | lastRelayState = EEPROM.read(0); 119 | if (rememberRelayState && lastRelayState == 1) { 120 | digitalWrite(RELAY, HIGH); 121 | } 122 | btn_timer.attach(0.05, button); 123 | mqttClient.set_callback(callback); 124 | WiFi.mode(WIFI_STA); 125 | WiFi.begin(WIFI_SSID, WIFI_PASS); 126 | ArduinoOTA.onStart([]() { 127 | OTAupdate = true; 128 | blinkLED(LED, 400, 2); 129 | digitalWrite(LED, HIGH); 130 | Serial.println("OTA Update Initiated . . ."); 131 | }); 132 | ArduinoOTA.onEnd([]() { 133 | Serial.println("\nOTA Update Ended . . .s"); 134 | ESP.restart(); 135 | }); 136 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { 137 | digitalWrite(LED, LOW); 138 | delay(5); 139 | digitalWrite(LED, HIGH); 140 | Serial.printf("Progress: %u%%\r", (progress / (total / 100))); 141 | }); 142 | ArduinoOTA.onError([](ota_error_t error) { 143 | blinkLED(LED, 40, 2); 144 | OTAupdate = false; 145 | Serial.printf("OTA Error [%u] ", error); 146 | if (error == OTA_AUTH_ERROR) Serial.println(". . . . . . . . . . . . . . . Auth Failed"); 147 | else if (error == OTA_BEGIN_ERROR) Serial.println(". . . . . . . . . . . . . . . Begin Failed"); 148 | else if (error == OTA_CONNECT_ERROR) Serial.println(". . . . . . . . . . . . . . . Connect Failed"); 149 | else if (error == OTA_RECEIVE_ERROR) Serial.println(". . . . . . . . . . . . . . . Receive Failed"); 150 | else if (error == OTA_END_ERROR) Serial.println(". . . . . . . . . . . . . . . End Failed"); 151 | }); 152 | ArduinoOTA.begin(); 153 | Serial.println(VERSION); 154 | Serial.print("\nUnit ID: "); 155 | Serial.print("esp8266-"); 156 | Serial.print(ESP.getChipId(), HEX); 157 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 158 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 159 | delay(500); 160 | Serial.print(" ."); 161 | } 162 | if (WiFi.status() == WL_CONNECTED) { 163 | Serial.println(" DONE"); 164 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 165 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 166 | delay(500); 167 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 168 | Serial.print(" ."); 169 | delay(1000); 170 | } 171 | if(mqttClient.connected()) { 172 | Serial.println(" DONE"); 173 | Serial.println("\n---------------------------- Logs ----------------------------"); 174 | Serial.println(); 175 | mqttClient.subscribe(MQTT_TOPIC); 176 | blinkLED(LED, 40, 8); 177 | digitalWrite(LED, LOW); 178 | } 179 | else { 180 | Serial.println(" FAILED!"); 181 | Serial.println("\n----------------------------------------------------------------"); 182 | Serial.println(); 183 | } 184 | } 185 | else { 186 | Serial.println(" WiFi FAILED!"); 187 | Serial.println("\n----------------------------------------------------------------"); 188 | Serial.println(); 189 | } 190 | getTemp(); 191 | } 192 | 193 | void loop() { 194 | ArduinoOTA.handle(); 195 | if (OTAupdate == false) { 196 | mqttClient.loop(); 197 | timedTasks(); 198 | checkStatus(); 199 | checkWallSwitch(); 200 | if (tempReport) { 201 | getTemp(); 202 | } 203 | } 204 | } 205 | 206 | void blinkLED(int pin, int duration, int n) { 207 | for(int i=0; i 1 && count <= 40) { 221 | digitalWrite(RELAY, !digitalRead(RELAY)); 222 | sendStatus = true; 223 | } 224 | else if (count >40){ 225 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 226 | requestRestart = true; 227 | } 228 | count=0; 229 | } 230 | } 231 | 232 | void checkConnection() { 233 | if (WiFi.status() == WL_CONNECTED) { 234 | if (mqttClient.connected()) { 235 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 236 | } 237 | else { 238 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 239 | requestRestart = true; 240 | } 241 | } 242 | else { 243 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 244 | requestRestart = true; 245 | } 246 | } 247 | 248 | void checkStatus() { 249 | if (sendStatus) { 250 | if(digitalRead(RELAY) == LOW) { 251 | if (rememberRelayState) { 252 | EEPROM.write(0, 0); 253 | } 254 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 255 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 256 | } else { 257 | if (rememberRelayState) { 258 | EEPROM.write(0, 1); 259 | } 260 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 261 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 262 | } 263 | if (rememberRelayState) { 264 | EEPROM.commit(); 265 | } 266 | sendStatus = false; 267 | } 268 | if (requestRestart) { 269 | blinkLED(LED, 400, 4); 270 | ESP.restart(); 271 | } 272 | } 273 | 274 | void checkWallSwitch() { 275 | wallSwitch = digitalRead(WALLSWITCH); 276 | if (wallSwitch != lastWallSwitch) { 277 | digitalWrite(RELAY, !digitalRead(RELAY)); 278 | sendStatus = true; 279 | } 280 | lastWallSwitch = wallSwitch; 281 | } 282 | 283 | void getTemp() { 284 | Serial.print("DHT read . . . . . . . . . . . . . . . . . "); 285 | float dhtH, dhtT; 286 | char message_buff[60]; 287 | dhtH = dht.readHumidity(); 288 | dhtT = dht.readTemperature(); 289 | if(digitalRead(LED) == LOW) { 290 | blinkLED(LED, 100, 1); 291 | } else { 292 | blinkLED(LED, 100, 1); 293 | digitalWrite(LED, HIGH); 294 | } 295 | if (isnan(dhtH) || isnan(dhtT)) { 296 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug","\"DHT Read Error\"").set_retain().set_qos(1)); 297 | Serial.println("ERROR"); 298 | tempReport = false; 299 | return; 300 | } 301 | String pubString = "{\"Temp\": "+String(dhtT)+", "+"\"Humidity\": "+String(dhtH) + "}"; 302 | pubString.toCharArray(message_buff, pubString.length()+1); 303 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/temp", message_buff).set_retain().set_qos(1)); 304 | Serial.println("OK"); 305 | tempReport = false; 306 | } 307 | 308 | void timedTasks() { 309 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 310 | TTasks = millis(); 311 | checkConnection(); 312 | tempReport = true; 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_TH-v1.01t/ESPsonoff_TH-v1.01t.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2017 @KmanOz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | ============================================================================== 24 | Changes in v1.01 25 | 26 | - Relay state now stored in EEPROM and will power up with last relay state 27 | ============================================================================== 28 | 29 | **** USE THIS Firmware for: Sonof TH10/16 fitted with AM2303 / DHT22 supplied by ITEAD **** 30 | 31 | */ 32 | 33 | #include 34 | #include "DHT.h" 35 | #include 36 | #include 37 | #include 38 | 39 | #define BUTTON 0 // (Don't Change for Sonoff TH Series) 40 | #define RELAY 12 // (Don't Change for Sonoff TH Series) 41 | #define LED 13 // (Don't Change for Sonoff TH Series) 42 | #define DHTPIN 14 // (Don't Change for Sonoff TH Series) 43 | 44 | #define DHTTYPE DHT22 // (11 or 22) DHT Type 45 | 46 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.01t" // mqtt client_id (Must be unique for each Sonoff) 47 | #define MQTT_SERVER "192.168.0.100" // mqtt server 48 | #define MQTT_PORT 1883 // mqtt port 49 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 50 | #define MQTT_USER "user" // mqtt user 51 | #define MQTT_PASS "pass" // mqtt password 52 | 53 | #define WIFI_SSID "homewifi" // wifi ssid 54 | #define WIFI_PASS "homepass" // wifi password 55 | 56 | #define VERSION "\n\n---------------- Sonoff TH Powerpoint v1.01t -----------------" 57 | 58 | DHT dht(DHTPIN, DHTTYPE, 11); // (Don't Change for Sonoff TH Series) 59 | 60 | bool rememberRelayState = true; // If 'true' remembers the state of the relay before power loss. 61 | bool requestRestart = false; // (Do not Change) 62 | bool sendStatus = false; // (Do not Change) 63 | bool tempReport = false; // (Do not Change) 64 | 65 | int kUpdFreq = 1; // Update frequency in Mintes to check for mqtt connection 66 | int kRetries = 10; // WiFi retry count. Increase if not connecting to router. 67 | int lastRelayState; // (Do not Change) 68 | 69 | unsigned long TTasks; // (Do not Change) 70 | unsigned long count = 0; // (Do not Change) 71 | 72 | extern "C" { 73 | #include "user_interface.h" 74 | } 75 | 76 | WiFiClient wifiClient; 77 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 78 | Ticker btn_timer; 79 | 80 | void callback(const MQTT::Publish& pub) { 81 | if (pub.payload_string() == "stat") { 82 | } 83 | else if (pub.payload_string() == "on") { 84 | digitalWrite(RELAY, HIGH); 85 | } 86 | else if (pub.payload_string() == "off") { 87 | digitalWrite(RELAY, LOW); 88 | } 89 | else if (pub.payload_string() == "reset") { 90 | requestRestart = true; 91 | } 92 | else if (pub.payload_string() == "temp") { 93 | tempReport = true; 94 | } 95 | sendStatus = true; 96 | } 97 | 98 | void setup() { 99 | pinMode(LED, OUTPUT); 100 | pinMode(RELAY, OUTPUT); 101 | pinMode(BUTTON, INPUT); 102 | digitalWrite(LED, HIGH); 103 | digitalWrite(RELAY, LOW); 104 | Serial.begin(115200); 105 | EEPROM.begin(8); 106 | lastRelayState = EEPROM.read(0); 107 | if (rememberRelayState && lastRelayState == 1) { 108 | digitalWrite(RELAY, HIGH); 109 | } 110 | btn_timer.attach(0.05, button); 111 | mqttClient.set_callback(callback); 112 | WiFi.mode(WIFI_STA); 113 | WiFi.begin(WIFI_SSID, WIFI_PASS); 114 | Serial.println(VERSION); 115 | Serial.print("\nUnit ID: "); 116 | Serial.print("esp8266-"); 117 | Serial.print(ESP.getChipId(), HEX); 118 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 119 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 120 | delay(500); 121 | Serial.print(" ."); 122 | } 123 | if (WiFi.status() == WL_CONNECTED) { 124 | Serial.println(" DONE"); 125 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 126 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 127 | delay(500); 128 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 129 | Serial.print(" ."); 130 | delay(1000); 131 | } 132 | if(mqttClient.connected()) { 133 | Serial.println(" DONE"); 134 | Serial.println("\n---------------------------- Logs ----------------------------"); 135 | Serial.println(); 136 | mqttClient.subscribe(MQTT_TOPIC); 137 | blinkLED(LED, 40, 8); 138 | digitalWrite(LED, LOW); 139 | } 140 | else { 141 | Serial.println(" FAILED!"); 142 | Serial.println("\n----------------------------------------------------------------"); 143 | Serial.println(); 144 | } 145 | } 146 | else { 147 | Serial.println(" WiFi FAILED!"); 148 | Serial.println("\n----------------------------------------------------------------"); 149 | Serial.println(); 150 | } 151 | getTemp(); 152 | } 153 | 154 | void loop() { 155 | mqttClient.loop(); 156 | timedTasks(); 157 | checkStatus(); 158 | if (tempReport) { 159 | getTemp(); 160 | } 161 | } 162 | 163 | void blinkLED(int pin, int duration, int n) { 164 | for(int i=0; i 1 && count <= 40) { 178 | digitalWrite(RELAY, !digitalRead(RELAY)); 179 | sendStatus = true; 180 | } 181 | else if (count >40){ 182 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 183 | requestRestart = true; 184 | } 185 | count=0; 186 | } 187 | } 188 | 189 | void checkConnection() { 190 | if (WiFi.status() == WL_CONNECTED) { 191 | if (mqttClient.connected()) { 192 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 193 | } 194 | else { 195 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 196 | requestRestart = true; 197 | } 198 | } 199 | else { 200 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 201 | requestRestart = true; 202 | } 203 | } 204 | 205 | void checkStatus() { 206 | if (sendStatus) { 207 | if(digitalRead(RELAY) == LOW) { 208 | if (rememberRelayState) { 209 | EEPROM.write(0, 0); 210 | } 211 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 212 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 213 | } else { 214 | if (rememberRelayState) { 215 | EEPROM.write(0, 1); 216 | } 217 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 218 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 219 | } 220 | if (rememberRelayState) { 221 | EEPROM.commit(); 222 | } 223 | sendStatus = false; 224 | } 225 | if (requestRestart) { 226 | blinkLED(LED, 400, 4); 227 | ESP.restart(); 228 | } 229 | } 230 | 231 | void getTemp() { 232 | Serial.print("DHT read . . . . . . . . . . . . . . . . . "); 233 | float dhtH, dhtT; 234 | char message_buff[60]; 235 | dhtH = dht.readHumidity(); 236 | dhtT = dht.readTemperature(); 237 | if(digitalRead(LED) == LOW) { 238 | blinkLED(LED, 100, 1); 239 | } else { 240 | blinkLED(LED, 100, 1); 241 | digitalWrite(LED, HIGH); 242 | } 243 | if (isnan(dhtH) || isnan(dhtT)) { 244 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug","\"DHT Read Error\"").set_retain().set_qos(1)); 245 | Serial.println("ERROR"); 246 | tempReport = false; 247 | return; 248 | } 249 | String pubString = "{\"Temp\": "+String(dhtT)+", "+"\"Humidity\": "+String(dhtH) + "}"; 250 | pubString.toCharArray(message_buff, pubString.length()+1); 251 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/temp", message_buff).set_retain().set_qos(1)); 252 | Serial.println("OK"); 253 | tempReport = false; 254 | } 255 | 256 | void timedTasks() { 257 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 258 | TTasks = millis(); 259 | checkConnection(); 260 | tempReport = true; 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_TH-v1.01tOTA/ESPsonoff_TH-v1.01tOTA.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2017 @KmanOz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | ============================================================================== 24 | Changes in v1.01tOTA 25 | 26 | - Relay state now stored in EEPROM and will power up with last relay state 27 | - OTA Firmware Upgradable 28 | ============================================================================== 29 | 30 | **** USE THIS Firmware for: Sonof TH10/16 fitted with AM2303 / DHT22 supplied by ITEAD **** 31 | 32 | */ 33 | 34 | #include 35 | #include "DHT.h" 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #define BUTTON 0 // (Don't Change for Sonoff TH Series) 44 | #define RELAY 12 // (Don't Change for Sonoff TH Series) 45 | #define LED 13 // (Don't Change for Sonoff TH Series) 46 | #define DHTPIN 14 // (Don't Change for Sonoff TH Series) 47 | 48 | #define DHTTYPE DHT22 // (11 or 22) DHT Type 49 | 50 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.01tOTA" // mqtt client_id (Must be unique for each Sonoff) 51 | #define MQTT_SERVER "192.168.0.100" // mqtt server 52 | #define MQTT_PORT 1883 // mqtt port 53 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 54 | #define MQTT_USER "user" // mqtt user 55 | #define MQTT_PASS "pass" // mqtt password 56 | 57 | #define WIFI_SSID "homewifi" // wifi ssid 58 | #define WIFI_PASS "homepass" // wifi password 59 | 60 | #define VERSION "\n\n--------------- Sonoff TH Powerpoint v1.01tOTA ---------------" 61 | 62 | DHT dht(DHTPIN, DHTTYPE, 11); // (Don't Change for Sonoff TH Series) 63 | 64 | bool rememberRelayState = true; // If 'true' remembers the state of the relay before power loss. 65 | bool OTAupdate = false; // (Do not Change) 66 | bool requestRestart = false; // (Do not Change) 67 | bool sendStatus = false; // (Do not Change) 68 | bool tempReport = false; // (Do not Change) 69 | 70 | int kUpdFreq = 1; // Update frequency in Mintes to check for mqtt connection 71 | int kRetries = 10; // WiFi retry count. Increase if not connecting to router. 72 | int lastRelayState; // (Do not Change) 73 | 74 | unsigned long TTasks; // (Do not Change) 75 | unsigned long count = 0; // (Do not Change) 76 | 77 | extern "C" { 78 | #include "user_interface.h" 79 | } 80 | 81 | WiFiClient wifiClient; 82 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 83 | Ticker btn_timer; 84 | 85 | void callback(const MQTT::Publish& pub) { 86 | if (pub.payload_string() == "stat") { 87 | } 88 | else if (pub.payload_string() == "on") { 89 | digitalWrite(RELAY, HIGH); 90 | } 91 | else if (pub.payload_string() == "off") { 92 | digitalWrite(RELAY, LOW); 93 | } 94 | else if (pub.payload_string() == "reset") { 95 | requestRestart = true; 96 | } 97 | else if (pub.payload_string() == "temp") { 98 | tempReport = true; 99 | } 100 | sendStatus = true; 101 | } 102 | 103 | void setup() { 104 | pinMode(LED, OUTPUT); 105 | pinMode(RELAY, OUTPUT); 106 | pinMode(BUTTON, INPUT); 107 | digitalWrite(LED, HIGH); 108 | digitalWrite(RELAY, LOW); 109 | Serial.begin(115200); 110 | EEPROM.begin(8); 111 | lastRelayState = EEPROM.read(0); 112 | if (rememberRelayState && lastRelayState == 1) { 113 | digitalWrite(RELAY, HIGH); 114 | } 115 | btn_timer.attach(0.05, button); 116 | mqttClient.set_callback(callback); 117 | WiFi.mode(WIFI_STA); 118 | WiFi.begin(WIFI_SSID, WIFI_PASS); 119 | ArduinoOTA.onStart([]() { 120 | OTAupdate = true; 121 | blinkLED(LED, 400, 2); 122 | digitalWrite(LED, HIGH); 123 | Serial.println("OTA Update Initiated . . ."); 124 | }); 125 | ArduinoOTA.onEnd([]() { 126 | Serial.println("\nOTA Update Ended . . .s"); 127 | ESP.restart(); 128 | }); 129 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { 130 | digitalWrite(LED, LOW); 131 | delay(5); 132 | digitalWrite(LED, HIGH); 133 | Serial.printf("Progress: %u%%\r", (progress / (total / 100))); 134 | }); 135 | ArduinoOTA.onError([](ota_error_t error) { 136 | blinkLED(LED, 40, 2); 137 | OTAupdate = false; 138 | Serial.printf("OTA Error [%u] ", error); 139 | if (error == OTA_AUTH_ERROR) Serial.println(". . . . . . . . . . . . . . . Auth Failed"); 140 | else if (error == OTA_BEGIN_ERROR) Serial.println(". . . . . . . . . . . . . . . Begin Failed"); 141 | else if (error == OTA_CONNECT_ERROR) Serial.println(". . . . . . . . . . . . . . . Connect Failed"); 142 | else if (error == OTA_RECEIVE_ERROR) Serial.println(". . . . . . . . . . . . . . . Receive Failed"); 143 | else if (error == OTA_END_ERROR) Serial.println(". . . . . . . . . . . . . . . End Failed"); 144 | }); 145 | ArduinoOTA.begin(); 146 | Serial.println(VERSION); 147 | Serial.print("\nUnit ID: "); 148 | Serial.print("esp8266-"); 149 | Serial.print(ESP.getChipId(), HEX); 150 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 151 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 152 | delay(500); 153 | Serial.print(" ."); 154 | } 155 | if (WiFi.status() == WL_CONNECTED) { 156 | Serial.println(" DONE"); 157 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 158 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 159 | delay(500); 160 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 161 | Serial.print(" ."); 162 | delay(1000); 163 | } 164 | if(mqttClient.connected()) { 165 | Serial.println(" DONE"); 166 | Serial.println("\n---------------------------- Logs ----------------------------"); 167 | Serial.println(); 168 | mqttClient.subscribe(MQTT_TOPIC); 169 | blinkLED(LED, 40, 8); 170 | digitalWrite(LED, LOW); 171 | } 172 | else { 173 | Serial.println(" FAILED!"); 174 | Serial.println("\n----------------------------------------------------------------"); 175 | Serial.println(); 176 | } 177 | } 178 | else { 179 | Serial.println(" WiFi FAILED!"); 180 | Serial.println("\n----------------------------------------------------------------"); 181 | Serial.println(); 182 | } 183 | getTemp(); 184 | } 185 | 186 | void loop() { 187 | ArduinoOTA.handle(); 188 | if (OTAupdate == false) { 189 | mqttClient.loop(); 190 | timedTasks(); 191 | checkStatus(); 192 | if (tempReport) { 193 | getTemp(); 194 | } 195 | } 196 | } 197 | 198 | void blinkLED(int pin, int duration, int n) { 199 | for(int i=0; i 1 && count <= 40) { 213 | digitalWrite(RELAY, !digitalRead(RELAY)); 214 | sendStatus = true; 215 | } 216 | else if (count >40){ 217 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 218 | requestRestart = true; 219 | } 220 | count=0; 221 | } 222 | } 223 | 224 | void checkConnection() { 225 | if (WiFi.status() == WL_CONNECTED) { 226 | if (mqttClient.connected()) { 227 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 228 | } 229 | else { 230 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 231 | requestRestart = true; 232 | } 233 | } 234 | else { 235 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 236 | requestRestart = true; 237 | } 238 | } 239 | 240 | void checkStatus() { 241 | if (sendStatus) { 242 | if(digitalRead(RELAY) == LOW) { 243 | if (rememberRelayState) { 244 | EEPROM.write(0, 0); 245 | } 246 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 247 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 248 | } else { 249 | if (rememberRelayState) { 250 | EEPROM.write(0, 1); 251 | } 252 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 253 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 254 | } 255 | if (rememberRelayState) { 256 | EEPROM.commit(); 257 | } 258 | sendStatus = false; 259 | } 260 | if (requestRestart) { 261 | blinkLED(LED, 400, 4); 262 | ESP.restart(); 263 | } 264 | } 265 | 266 | void getTemp() { 267 | Serial.print("DHT read . . . . . . . . . . . . . . . . . "); 268 | float dhtH, dhtT; 269 | char message_buff[60]; 270 | dhtH = dht.readHumidity(); 271 | dhtT = dht.readTemperature(); 272 | if(digitalRead(LED) == LOW) { 273 | blinkLED(LED, 100, 1); 274 | } else { 275 | blinkLED(LED, 100, 1); 276 | digitalWrite(LED, HIGH); 277 | } 278 | if (isnan(dhtH) || isnan(dhtT)) { 279 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug","\"DHT Read Error\"").set_retain().set_qos(1)); 280 | Serial.println("ERROR"); 281 | tempReport = false; 282 | return; 283 | } 284 | String pubString = "{\"Temp\": "+String(dhtT)+", "+"\"Humidity\": "+String(dhtH) + "}"; 285 | pubString.toCharArray(message_buff, pubString.length()+1); 286 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/temp", message_buff).set_retain().set_qos(1)); 287 | Serial.println("OK"); 288 | tempReport = false; 289 | } 290 | 291 | void timedTasks() { 292 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 293 | TTasks = millis(); 294 | checkConnection(); 295 | tempReport = true; 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_TH-v1.0p/ESPsonoff_TH-v1.0p.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define BUTTON 0 // (Don't Change for Sonoff) 6 | #define RELAY 12 // (Don't Change for Sonoff) 7 | #define LED 13 // (Don't Change for Sonoff) 8 | 9 | #define MQTT_CLIENT "Sonoff_Living_Room_v1.0p" // mqtt client_id (Must be unique for each Sonoff) 10 | #define MQTT_SERVER "192.168.0.100" // mqtt server 11 | #define MQTT_PORT 1883 // mqtt port 12 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 13 | #define MQTT_USER "user" // mqtt user 14 | #define MQTT_PASS "pass" // mqtt password 15 | 16 | #define WIFI_SSID "homewifi" // wifi ssid 17 | #define WIFI_PASS "homepass" // wifi password 18 | 19 | #define VERSION "\n\n----------------- Sonoff TH Powerpoint v1.0p -----------------" 20 | 21 | extern "C" { 22 | #include "user_interface.h" 23 | } 24 | 25 | bool sendStatus = false; 26 | bool requestRestart = false; 27 | 28 | int kUpdFreq = 1; 29 | int kRetries = 10; 30 | 31 | unsigned long TTasks; 32 | unsigned long count = 0; 33 | 34 | WiFiClient wifiClient; 35 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 36 | Ticker btn_timer; 37 | 38 | void callback(const MQTT::Publish& pub) { 39 | if (pub.payload_string() == "stat") { 40 | } 41 | else if (pub.payload_string() == "on") { 42 | digitalWrite(RELAY, HIGH); 43 | } 44 | else if (pub.payload_string() == "off") { 45 | digitalWrite(RELAY, LOW); 46 | } 47 | else if (pub.payload_string() == "reset") { 48 | requestRestart = true; 49 | } 50 | sendStatus = true; 51 | } 52 | 53 | void setup() { 54 | pinMode(LED, OUTPUT); 55 | pinMode(RELAY, OUTPUT); 56 | pinMode(BUTTON, INPUT); 57 | 58 | digitalWrite(LED, HIGH); 59 | digitalWrite(RELAY, LOW); 60 | 61 | btn_timer.attach(0.05, button); 62 | 63 | mqttClient.set_callback(callback); 64 | 65 | WiFi.mode(WIFI_STA); 66 | WiFi.begin(WIFI_SSID, WIFI_PASS); 67 | Serial.begin(115200); 68 | Serial.println(VERSION); 69 | Serial.print("\nESP ChipID: "); 70 | Serial.print(ESP.getChipId(), HEX); 71 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 72 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 73 | delay(500); 74 | Serial.print(" ."); 75 | } 76 | if (WiFi.status() == WL_CONNECTED) { 77 | Serial.println(" DONE"); 78 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 79 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 80 | delay(500); 81 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 82 | Serial.print(" ."); 83 | delay(1000); 84 | } 85 | if(mqttClient.connected()) { 86 | Serial.println(" DONE"); 87 | Serial.println("\n---------------------------- Logs ----------------------------"); 88 | Serial.println(); 89 | mqttClient.subscribe(MQTT_TOPIC); 90 | blinkLED(LED, 40, 8); 91 | digitalWrite(LED, LOW); 92 | } 93 | else { 94 | Serial.println(" FAILED!"); 95 | Serial.println("\n----------------------------------------------------------------"); 96 | Serial.println(); 97 | } 98 | } 99 | else { 100 | Serial.println(" WiFi FAILED!"); 101 | Serial.println("\n----------------------------------------------------------------"); 102 | Serial.println(); 103 | } 104 | } 105 | 106 | void loop() { 107 | mqttClient.loop(); 108 | timedTasks(); 109 | checkStatus(); 110 | } 111 | 112 | void blinkLED(int pin, int duration, int n) { 113 | for(int i=0; i 1 && count <= 40) { 127 | digitalWrite(RELAY, !digitalRead(RELAY)); 128 | sendStatus = true; 129 | } 130 | else if (count >40){ 131 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 132 | requestRestart = true; 133 | } 134 | count=0; 135 | } 136 | } 137 | 138 | void checkConnection() { 139 | if (WiFi.status() == WL_CONNECTED) { 140 | if (mqttClient.connected()) { 141 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 142 | } 143 | else { 144 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 145 | requestRestart = true; 146 | } 147 | } 148 | else { 149 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 150 | requestRestart = true; 151 | } 152 | } 153 | 154 | void checkStatus() { 155 | if (sendStatus) { 156 | if(digitalRead(RELAY) == LOW) { 157 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 158 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 159 | } else { 160 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 161 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 162 | } 163 | sendStatus = false; 164 | } 165 | if (requestRestart) { 166 | blinkLED(LED, 400, 4); 167 | ESP.restart(); 168 | } 169 | } 170 | 171 | void timedTasks() { 172 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 173 | TTasks = millis(); 174 | checkConnection(); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /arduino/ESPsonoff_TH-v1.0t/ESPsonof_TH-v1.0t.ino: -------------------------------------------------------------------------------- 1 | #include "DHT.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #define BUTTON 0 // (Don't Change for Sonoff) 7 | #define RELAY 12 // (Don't Change for Sonoff) 8 | #define LED 13 // (Don't Change for Sonoff) 9 | #define DHTPIN 14 // (Don't Change for Sonoff) 10 | 11 | #define DHTTYPE DHT22 // (Don't Change for Sonoff TH10/16) 12 | 13 | #define MQTT_CLIENT "Sonoff_Living_Room_v2.0t" // mqtt client_id (Must be unique for each Sonoff) 14 | #define MQTT_SERVER "192.168.0.100" // mqtt server 15 | #define MQTT_PORT 1883 // mqtt port 16 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 17 | #define MQTT_USER "user" // mqtt user 18 | #define MQTT_PASS "pass" // mqtt password 19 | 20 | #define WIFI_SSID "homewifi" // wifi ssid 21 | #define WIFI_PASS "homepass" // wifi password 22 | 23 | #define VERSION "\n\n----------------- Sonoff TH Powerpoint v1.0t -----------------" 24 | 25 | DHT dht(DHTPIN, DHTTYPE, 11); // (Don't Change for Sonoff) 26 | 27 | extern "C" { 28 | #include "user_interface.h" 29 | } 30 | 31 | bool sendStatus = false; 32 | bool requestRestart = false; 33 | bool tempReport = false; 34 | 35 | int kUpdFreq = 1; 36 | int kRetries = 10; 37 | 38 | unsigned long TTasks; 39 | unsigned long count = 0; 40 | 41 | WiFiClient wifiClient; 42 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 43 | Ticker btn_timer; 44 | 45 | void callback(const MQTT::Publish& pub) { 46 | if (pub.payload_string() == "stat") { 47 | } 48 | else if (pub.payload_string() == "on") { 49 | digitalWrite(RELAY, HIGH); 50 | } 51 | else if (pub.payload_string() == "off") { 52 | digitalWrite(RELAY, LOW); 53 | } 54 | else if (pub.payload_string() == "reset") { 55 | requestRestart = true; 56 | } 57 | else if (pub.payload_string() == "temp") { 58 | tempReport = true; 59 | } 60 | sendStatus = true; 61 | } 62 | 63 | void setup() { 64 | pinMode(LED, OUTPUT); 65 | pinMode(RELAY, OUTPUT); 66 | pinMode(BUTTON, INPUT); 67 | 68 | digitalWrite(LED, HIGH); 69 | digitalWrite(RELAY, LOW); 70 | 71 | btn_timer.attach(0.05, button); 72 | 73 | mqttClient.set_callback(callback); 74 | 75 | WiFi.mode(WIFI_STA); 76 | WiFi.begin(WIFI_SSID, WIFI_PASS); 77 | Serial.begin(115200); 78 | Serial.println(VERSION); 79 | Serial.print("\nESP ChipID: "); 80 | Serial.print(ESP.getChipId(), HEX); 81 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 82 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 83 | delay(500); 84 | Serial.print(" ."); 85 | } 86 | if (WiFi.status() == WL_CONNECTED) { 87 | Serial.println(" DONE"); 88 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 89 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 90 | delay(500); 91 | while (!mqttClient.connect(MQTT::Connect(MQTT_CLIENT).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 92 | Serial.print(" ."); 93 | delay(1000); 94 | } 95 | if(mqttClient.connected()) { 96 | Serial.println(" DONE"); 97 | Serial.println("\n---------------------------- Logs ----------------------------"); 98 | Serial.println(); 99 | mqttClient.subscribe(MQTT_TOPIC); 100 | blinkLED(LED, 40, 8); 101 | digitalWrite(LED, LOW); 102 | } 103 | else { 104 | Serial.println(" FAILED!"); 105 | Serial.println("\n----------------------------------------------------------------"); 106 | Serial.println(); 107 | } 108 | } 109 | else { 110 | Serial.println(" WiFi FAILED!"); 111 | Serial.println("\n----------------------------------------------------------------"); 112 | Serial.println(); 113 | } 114 | getTemp(); 115 | } 116 | 117 | void loop() { 118 | mqttClient.loop(); 119 | timedTasks(); 120 | checkStatus(); 121 | if (tempReport) { 122 | getTemp(); 123 | } 124 | } 125 | 126 | void blinkLED(int pin, int duration, int n) { 127 | for(int i=0; i 1 && count <= 40) { 141 | digitalWrite(RELAY, !digitalRead(RELAY)); 142 | sendStatus = true; 143 | } 144 | else if (count >40){ 145 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 146 | requestRestart = true; 147 | } 148 | count=0; 149 | } 150 | } 151 | 152 | void checkConnection() { 153 | if (WiFi.status() == WL_CONNECTED) { 154 | if (mqttClient.connected()) { 155 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 156 | } 157 | else { 158 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 159 | requestRestart = true; 160 | } 161 | } 162 | else { 163 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 164 | requestRestart = true; 165 | } 166 | } 167 | 168 | void checkStatus() { 169 | if (sendStatus) { 170 | if(digitalRead(RELAY) == LOW) { 171 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(1)); 172 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 173 | } else { 174 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(1)); 175 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 176 | } 177 | sendStatus = false; 178 | } 179 | if (requestRestart) { 180 | blinkLED(LED, 400, 4); 181 | ESP.restart(); 182 | } 183 | } 184 | 185 | void getTemp() { 186 | Serial.print("DHT read . . . . . . . . . . . . . . . . . "); 187 | float dhtH, dhtT; 188 | char message_buff[60]; 189 | dhtH = dht.readHumidity(); 190 | dhtT = dht.readTemperature(); 191 | if(digitalRead(LED) == LOW) { 192 | blinkLED(LED, 100, 1); 193 | } else { 194 | blinkLED(LED, 100, 1); 195 | digitalWrite(LED, HIGH); 196 | } 197 | if (isnan(dhtH) || isnan(dhtT)) { 198 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug","\"DHT Read Error\"").set_retain().set_qos(1)); 199 | Serial.println("ERROR"); 200 | tempReport = false; 201 | return; 202 | } 203 | String pubString = "{\"Temp\": "+String(dhtT)+", "+"\"Humidity\": "+String(dhtH) + "}"; 204 | pubString.toCharArray(message_buff, pubString.length()+1); 205 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/temp", message_buff).set_retain().set_qos(1)); 206 | Serial.println("OK"); 207 | tempReport = false; 208 | } 209 | 210 | void timedTasks() { 211 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 212 | TTasks = millis(); 213 | checkConnection(); 214 | tempReport = true; 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /home-assistant/living_room_switch.yaml: -------------------------------------------------------------------------------- 1 | switch: 2 | platform: mqtt 3 | name: "Living Room" 4 | state_topic: "home/sonoff/living_room/1/stat" 5 | command_topic: "home/sonoff/living_room/1" 6 | qos: 1 7 | payload_on: "on" 8 | payload_off: "off" 9 | retain: true 10 | -------------------------------------------------------------------------------- /home-assistant/sensors.yaml: -------------------------------------------------------------------------------- 1 | Sonoff TH 10/16 ------------------------------- 2 | 3 | - platform: mqtt 4 | name: "Living Room Temp" 5 | state_topic: "home/sonoff/living_room/1/temp" 6 | qos: 1 7 | unit_of_measurement: "°C" 8 | value_template: "{{ value_json.Temp }}" 9 | 10 | - platform: mqtt 11 | name: "Living Room Humidity" 12 | state_topic: "home/sonoff/living_room/1/temp" 13 | qos: 1 14 | unit_of_measurement: "%" 15 | value_template: "{{ value_json.Humidity }}" 16 | 17 | Sonoff Pow ------------------------------------- 18 | 19 | - platform: mqtt 20 | name: "Living Room Power" 21 | state_topic: "home/sonoff/living_room/1/power" 22 | qos: 1 23 | unit_of_measurement: "W" 24 | value_template: "{{ value_json.Power }}" 25 | 26 | - platform: mqtt 27 | name: "Living Room Voltage" 28 | state_topic: "home/sonoff/living_room/1/power" 29 | qos: 1 30 | unit_of_measurement: "V" 31 | value_template: "{{ value_json.Voltage }}" -------------------------------------------------------------------------------- /images/sensor_wiring.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KmanOz/Sonoff-HomeAssistant/fab22f9f34c21079a11811ac2c256a1e8c3b353c/images/sensor_wiring.jpg -------------------------------------------------------------------------------- /images/sonoff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KmanOz/Sonoff-HomeAssistant/fab22f9f34c21079a11811ac2c256a1e8c3b353c/images/sonoff.png -------------------------------------------------------------------------------- /images/sonoff_temp.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KmanOz/Sonoff-HomeAssistant/fab22f9f34c21079a11811ac2c256a1e8c3b353c/images/sonoff_temp.JPG -------------------------------------------------------------------------------- /images/th10.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KmanOz/Sonoff-HomeAssistant/fab22f9f34c21079a11811ac2c256a1e8c3b353c/images/th10.JPG -------------------------------------------------------------------------------- /images/th10ftdi.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KmanOz/Sonoff-HomeAssistant/fab22f9f34c21079a11811ac2c256a1e8c3b353c/images/th10ftdi.JPG --------------------------------------------------------------------------------