├── LICENSE ├── README.md ├── arduino ├── KmanSonoff_v1.00mc │ ├── KmanSonoff_v1.00mc.ino │ └── config_mc.h └── KmanSonoff_v1.00sc │ ├── KmanSonoff_v1.00sc.ino │ └── config_sc.h ├── home-assistant ├── living_room_switch.yaml └── sensors.yaml └── images ├── sonoff.png └── th10ftdi.JPG /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KmanSonoff - Alternative firmware for Sonoff Switches 2 | 3 | ![](images/sonoff.png "Sonoff Range") 4 | 5 | KmanSonoff is the updated version of [KmanOz/Sonoff-HomeAssistant](https://github.com/KmanOz/Sonoff-HomeAssistant) which is alternative firmware for the brilliant & cheap range of ESP-8266 based WiFi controlled power switches. This updated firmware simplifies setup of the switch even more so than the original, yet keeps the firmware and memory footprint basic and lightweight just like it's predecessor. Initial setup is now done in one file "config_sc.h" for the single channel firmware or "config_mc.h" for the multichannel firmware located in the same directory as the sketch. Both versions are OTA upgradable and all naming (mqtt client name & mDNS for OTA) is automatic based on the MAC address of the ESP Wifi radio. 6 | 7 | I realize there are many other mqtt based firmware(s) that have been written for the Sonoff switches, but I found most of them overly complex for my liking. This firmware is basic in operation but ***extremely stable*** and just gets the job done. 8 | 9 | #### Currently Supported Devices (More to come) 10 | 11 | - [Sonoff Basic](https://www.itead.cc/smart-home/sonoff-wifi-wireless-switch.html?acc=70efdf2ec9b086079795c442636b55fb) 12 | - [Sonoff RF](https://www.itead.cc/smart-home/sonoff-rf.html?acc=70efdf2ec9b086079795c442636b55fb) 13 | - [Sonoff Slampher](https://www.itead.cc/slampher.html?acc=70efdf2ec9b086079795c442636b55fb) 14 | - [Sonoff TH10/TH16](https://www.itead.cc/sonoff-th.html?acc=70efdf2ec9b086079795c442636b55fb) 15 | - [Sonoff Touch](https://www.itead.cc/smart-home/sonoff-touch.html?acc=70efdf2ec9b086079795c442636b55fb) 16 | - [Sonoff S20](https://www.itead.cc/smart-home/smart-socket.html?acc=70efdf2ec9b086079795c442636b55fb) 17 | - [Sonoff SV](https://www.itead.cc/smart-home/sonoff-sv.html?acc=70efdf2ec9b086079795c442636b55fb) 18 | - [Sonoff 4CH](https://www.itead.cc/smart-home/sonoff-4ch.html?acc=70efdf2ec9b086079795c442636b55fb) 19 | - [Sonoff 4CH PRO](https://www.itead.cc/sonoff-4ch-pro.html?acc=70efdf2ec9b086079795c442636b55fb) 20 | - [Sonoff T1 (Up to 3 Ch)](https://www.itead.cc/sonoff-t1.html?acc=70efdf2ec9b086079795c442636b55fb) 21 | 22 | You'll need the Arduino IDE and has been tested on 1.8.5 but should be backwards & forwards compatible with other versions. 23 | 24 | ## Configuration 25 | 26 | **1. Clone the Repository** 27 | 28 | Clone the **KmanSonoff** repository to your local machine. Copy the required version for your switch to your Arduino directory. 29 | 30 | ``` bash 31 | $ git clone https://github.com/KmanOz/KmanSonoff 32 | ``` 33 | **2. Clone the LMROY version of the mqtt library** 34 | 35 | I use the [lmroy](https://github.com/Imroy/pubsubclient) version of this excellent mqtt library, mainly because it supports QOS1 and keepalive settings right from within the sketch. No other modifications to library files are necessary. 36 | 37 | It's currently setup to use only v3.1.1 of the mqtt standard and will only work on that version broker unless you modify the code so make sure your broker is setup to use v3.1.1 of the mqtt standard and not v3.1. 38 | 39 | **FOR ALL THE PEOPLE THAT SKIP THIS STEP, DON'T. YOU CANNOT USE OTHER MQTT LIBRARIES** 40 | 41 | ``` bash 42 | $ git clone https://github.com/Imroy/pubsubclient 43 | ``` 44 | **3. Install DHT library (If Temperature reporting is enabled)** 45 | 46 | Uning the Arduino IDE's Library Manager install the DHT library if you plan on enabling Temperature reporting. 47 | 48 | 49 | **3. Modify the details in the Arduino code (config.h) to your specific details and environment. (THIS IS IMPORTANT)** 50 | 51 | To start off, change the "WIFI_SSID, WIFI_PASS, MQTT_SERVER, MQTT_PORT, MQTT_USER, MQTT_PASS in the Arduino code provided to suit your environment. 52 | 53 | ``` bash 54 | #define MQTT_SERVER "192.168.0.100" // mqtt server 55 | #define MQTT_PORT 1883 // mqtt port 56 | #define MQTT_TOPIC "home/sonoff/living_room/1" // mqtt topic (Must be unique for each Sonoff) 57 | #define MQTT_USER "user" // mqtt user 58 | #define MQTT_PASS "pass" // mqtt password 59 | #define WIFI_SSID "homewifi" // wifi ssid 60 | #define WIFI_PASS "homepass" // wifi password 61 | ``` 62 | 63 | Additionally other parameters can be changed in the file at your discretion like whether or not you wish to remember the last relay state, retain mqtt messages, update frequecy for WiFi retries etc. See "config_sc.h or config_mc.h" for all options. 64 | 65 | ## Flashing the Firmware 66 | 67 | I will assume you have the necessary skills to complete this step. As mentioned earlier, you'll need the Arduino IDE and you'll need to move the files you just cloned to the right directories. There are plenty or tutorials that cover all the steps involved already published on the Internet and it's only a Google search away. 68 | 69 | As for the switch modifications, it's simply a matter of opening up the switch, installing a 4 or 5 pin header (depending on switch type) and then holding down the main switch (or installing a jumper on some models) on the unit before you power it up with your FTDI adapter. You are then good to go to re-flash your new firmware. The photo below is for illustration only and different products will require the same basic connection but headers will be located in different positions etc. (If anyone is willing to help, feel free to do a PR and add detailed instructions for other switches. Sorry too busy). 70 | 71 | ![alt FTDI Diagram](images/th10ftdi.JPG "FTDI Diagram") 72 | 73 | ## HomeAssistant Integration 74 | 75 | **1. Modify configuration.yaml in HomeAssistant and add the following to it.** 76 | 77 | ```bash 78 | switch: 79 | - platform: mqtt 80 | name: "Living Room" 81 | state_topic: "home/sonoff/living_room/1/stat" 82 | command_topic: "home/sonoff/living_room/1" 83 | qos: 0 84 | payload_on: "on" 85 | payload_off: "off" 86 | retain: true 87 | ``` 88 | Assuming you make no changes to the topic in the code provided, you should be able to test the switch and be happy that you now have control using Home Assistant. 89 | 90 | If you've the enabled temperature function, you can also setup sensors in HomeAssistant to display both Temperature & Humidity. Modify your configuration.yaml and add the following. 91 | 92 | ```bash 93 | sensor: 94 | - platform: mqtt 95 | name: "Living Room Temp" 96 | state_topic: "home/sonoff/living_room/1/temp" 97 | qos: 1 98 | unit_of_measurement: "°C" 99 | value_template: "{{ value_json.Temp }}" 100 | 101 | - platform: mqtt 102 | name: "Living Room Humidity" 103 | state_topic: "home/sonoff/living_room/1/temp" 104 | qos: 1 105 | unit_of_measurement: "%" 106 | value_template: "{{ value_json.Humidity }}" 107 | ``` 108 | 109 | ## Commands and Operation 110 | 111 | **1. Commands** 112 | 113 | As mentioned earlier, the commands are very basic. In fact the switch will respond to 4 basic mqtt commands and they are :- 114 | 115 | - **on** (Turns the relay and LED on)(For multi channel precede the *on* command by the channel no#. e.g 1on, 3on etc) 116 | - **off** (Turns the relay and LED off)(For multi channel precede the *off* command by the channel no#. e.g 2off, 3off etc) 117 | - **stat** (Returns the status of the switch via mqtt message)(For multi channel the channel no# will precede the status. e.g. 1on, 4off) 118 | - **reset** (Forces a restart of the switch) (4 long flashes of the status LED) 119 | 120 | If you've enabled the temperature function, you have an additional option. 121 | 122 | - **temp** (Forces a temperature & humidity check otherwise it's reported every 1 minute) (1 short flash of the status LED) 123 | 124 | **2. Operation** 125 | 126 | When power is first applied the unit will immediately connect to your WiFi access point / router and your mqtt broker. When it connects the status LED will flash fast 4 times. That's it, your connected. 127 | 128 | If you've enabled the temperature function, you will see a short single flash to indicate that the temperature & humidity has been published as well. 129 | 130 | Press the switch on top to turn on the relay. Press it again to turn it off and watch the status change in HomeAssistant. Toggle the switch in HomeAssistant and the relay & LED will toggle accordingly. If your switch allows for an external wallswitch to be connected and that feature is enable, you should now be able to toggle the status of the Sonoff with the external wallswitch as well. 131 | 132 | To reset the switch manually, press and hold the switch for more than 4 seconds. (4CH press and hold Relay 1 switch) The switch will respond with 4 long flashes and reboot. 133 | 134 | ## OTA Updates 135 | 136 | Assuming you have the correct environment setup for OTA (Python 2.7 installed) you can update the firmware via the Arduino IDE using OTA. The switch will publish it's name in the following format. (Sonoff_XXXXXX) X's will be replaced with the last 6 characters of the WiFi MAC address. 137 | 138 | When the unit enters OTA, the status LED will flash twice. Once entered and firmware is being updated the status LED will flash fast continuously as packets are received. If the upload was successful the status LED will remain ON and in a short amount of time will turn off. The switch will reset and the status LED will flash 4 times fast and reconnect. 139 | 140 | If unsuccessful after it enters OTA upgrade mode, it will exit with 2 fast flashes of the Status LED and either resume normally, or reset depending on the error. 141 | 142 | ## Versions 143 | 144 | **KmanSonoff_v1.00sc** - Single Channel firmware used for original iTead Sonoff Switch, Sonoff Touch, Sonof S20 Smart Socket, Sonoff SV etc 145 | 146 | **KmanSonoff_v1.00mc** - Multichannel firmware (Up to 4 Channels) used for Sonoff 4CH, 4CH Pro, Sonoff T1 (1, 2 & 3 CH), etc 147 | 148 | ## MIT License 149 | 150 | Copyright (c) 2017 151 | 152 | Permission is hereby granted, free of charge, to any person obtaining a copy 153 | of this software and associated documentation files (the "Software"), to deal 154 | in the Software without restriction, including without limitation the rights 155 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 156 | copies of the Software, and to permit persons to whom the Software is 157 | furnished to do so, subject to the following conditions: 158 | 159 | The above copyright notice and this permission notice shall be included in all 160 | copies or substantial portions of the Software. 161 | 162 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 163 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 164 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 165 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 166 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 167 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 168 | SOFTWARE. 169 | 170 | ## Conclusion 171 | 172 | That's about it. Any feature suggestions are welcome and I would be happy to answer any further questions that you may have. Additionally of you would like to contribute to this library please feel free to do a PR. 173 | 174 | 175 | Enjoy! 176 | -------------------------------------------------------------------------------- /arduino/KmanSonoff_v1.00mc/KmanSonoff_v1.00mc.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 | **** Use this Firmware for: Sonoff 4CH, 4CH Pro & T1 (1, 2 and 3 Channel) **** 23 | **** Make sure to select "Generic ESP8285 Module" from the BOARD menu in TOOLS **** 24 | **** Flash Size "1M (64K SPIFFS)" **** 25 | 26 | =============================================================================================== 27 | ATTENTION !!!!!! DO NOT CHANGE ANYTHING IN THIS SECTION. UPDATE YOUR DETAILS IN CONFIG.H 28 | =============================================================================================== 29 | */ 30 | 31 | #include "config_mc.h" 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #define B_1 0 42 | #define B_2 9 43 | #define B_3 10 44 | #define B_4 14 45 | #define L_1 12 46 | #define L_2 5 47 | #define L_3 4 48 | #define L_4 15 49 | #define LED 13 50 | #define HOST_PREFIX "Sonoff_%s" 51 | #define HEADER "\n\n-------------- KmanSonoff_v1.00mc --------------" 52 | #define VER "ksmc_v1.00" 53 | 54 | bool requestRestart = false; 55 | bool OTAupdate = false; 56 | char ESP_CHIP_ID[8]; 57 | char UID[16]; 58 | long rssi; 59 | unsigned long TTasks; 60 | #ifdef CH_1 61 | bool sendStatus1 = false; 62 | int SS1; 63 | unsigned long count1 = 0; 64 | Ticker btn_timer1; 65 | #endif 66 | #ifdef CH_2 67 | bool sendStatus2 = false; 68 | int SS2; 69 | unsigned long count2 = 0; 70 | Ticker btn_timer2; 71 | #endif 72 | #ifdef CH_3 73 | bool sendStatus3 = false; 74 | int SS3; 75 | unsigned long count3 = 0; 76 | Ticker btn_timer3; 77 | #endif 78 | #ifdef CH_4 79 | bool sendStatus4 = false; 80 | int SS4; 81 | unsigned long count4 = 0; 82 | Ticker btn_timer4; 83 | #endif 84 | extern "C" { 85 | #include "user_interface.h" 86 | } 87 | WiFiClient wifiClient; 88 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 89 | 90 | void callback(const MQTT::Publish& pub) { 91 | if (pub.payload_string() == "stat") { 92 | } 93 | #ifdef CH_1 94 | else if (pub.payload_string() == "1on") { 95 | digitalWrite(L_1, HIGH); 96 | sendStatus1 = true; 97 | } 98 | else if (pub.payload_string() == "1off") { 99 | digitalWrite(L_1, LOW); 100 | sendStatus1 = true; 101 | } 102 | #endif 103 | #ifdef CH_2 104 | else if (pub.payload_string() == "2on") { 105 | digitalWrite(L_2, HIGH); 106 | sendStatus2 = true; 107 | } 108 | else if (pub.payload_string() == "2off") { 109 | digitalWrite(L_2, LOW); 110 | sendStatus2 = true; 111 | } 112 | #endif 113 | #ifdef CH_3 114 | else if (pub.payload_string() == "3on") { 115 | digitalWrite(L_3, HIGH); 116 | sendStatus3 = true; 117 | } 118 | else if (pub.payload_string() == "3off") { 119 | digitalWrite(L_3, LOW); 120 | sendStatus3 = true; 121 | } 122 | #endif 123 | #ifdef CH_4 124 | else if (pub.payload_string() == "4on") { 125 | digitalWrite(L_4, HIGH); 126 | sendStatus4 = true; 127 | } 128 | else if (pub.payload_string() == "4off") { 129 | digitalWrite(L_4, LOW); 130 | sendStatus4 = true; 131 | } 132 | #endif 133 | else if (pub.payload_string() == "reset") { 134 | requestRestart = true; 135 | } 136 | } 137 | 138 | void setup() { 139 | pinMode(LED, OUTPUT); 140 | digitalWrite(LED, HIGH);; 141 | Serial.begin(115200); 142 | sprintf(ESP_CHIP_ID, "%06X", ESP.getChipId()); 143 | sprintf(UID, HOST_PREFIX, ESP_CHIP_ID); 144 | EEPROM.begin(8); 145 | #ifdef CH_1 146 | pinMode(B_1, INPUT); 147 | pinMode(L_1, OUTPUT); 148 | digitalWrite(L_1, LOW); 149 | SS1 = EEPROM.read(0); 150 | if (rememberRelayState1 && SS1 == 1) { 151 | digitalWrite(L_1, HIGH); 152 | } 153 | btn_timer1.attach(0.05, button1); 154 | #endif 155 | #ifdef CH_2 156 | pinMode(B_2, INPUT); 157 | pinMode(L_2, OUTPUT); 158 | digitalWrite(L_2, LOW); 159 | SS2 = EEPROM.read(1); 160 | if (rememberRelayState2 && SS2 == 1) { 161 | digitalWrite(L_2, HIGH); 162 | } 163 | btn_timer2.attach(0.05, button2); 164 | #endif 165 | #ifdef CH_3 166 | pinMode(B_3, INPUT); 167 | pinMode(L_3, OUTPUT); 168 | digitalWrite(L_3, LOW); 169 | SS3 = EEPROM.read(2); 170 | if (rememberRelayState3 && SS3 == 1) { 171 | digitalWrite(L_3, HIGH); 172 | } 173 | btn_timer3.attach(0.05, button3); 174 | #endif 175 | #ifdef CH_4 176 | pinMode(B_4, INPUT); 177 | pinMode(L_4, OUTPUT); 178 | digitalWrite(L_4, LOW); 179 | SS4 = EEPROM.read(3); 180 | if (rememberRelayState4 && SS4 == 1) { 181 | digitalWrite(L_4, HIGH); 182 | } 183 | btn_timer4.attach(0.05, button4); 184 | #endif 185 | mqttClient.set_callback(callback); 186 | WiFi.mode(WIFI_STA); 187 | WiFi.hostname(UID); 188 | WiFi.begin(WIFI_SSID, WIFI_PASS); 189 | ArduinoOTA.setHostname(UID); 190 | ArduinoOTA.onStart([]() { 191 | OTAupdate = true; 192 | blinkLED(LED, 400, 2); 193 | digitalWrite(LED, HIGH); 194 | Serial.println("OTA Update Initiated . . ."); 195 | }); 196 | ArduinoOTA.onEnd([]() { 197 | Serial.println("\nOTA Update Ended . . .s"); 198 | OTAupdate = false; 199 | requestRestart = true; 200 | }); 201 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { 202 | digitalWrite(LED, LOW); 203 | delay(5); 204 | digitalWrite(LED, HIGH); 205 | Serial.printf("Progress: %u%%\r", (progress / (total / 100))); 206 | }); 207 | ArduinoOTA.onError([](ota_error_t error) { 208 | blinkLED(LED, 40, 2); 209 | OTAupdate = false; 210 | Serial.printf("OTA Error [%u] ", error); 211 | if (error == OTA_AUTH_ERROR) Serial.println(". . . . . . . . . . . . . . . Auth Failed"); 212 | else if (error == OTA_BEGIN_ERROR) Serial.println(". . . . . . . . . . . . . . . Begin Failed"); 213 | else if (error == OTA_CONNECT_ERROR) Serial.println(". . . . . . . . . . . . . . . Connect Failed"); 214 | else if (error == OTA_RECEIVE_ERROR) Serial.println(". . . . . . . . . . . . . . . Receive Failed"); 215 | else if (error == OTA_END_ERROR) Serial.println(". . . . . . . . . . . . . . . End Failed"); 216 | }); 217 | ArduinoOTA.begin(); 218 | Serial.println(HEADER); 219 | Serial.print("\nUnit ID: "); 220 | Serial.print(UID); 221 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 222 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 223 | delay(500); 224 | Serial.print(" ."); 225 | } 226 | if (WiFi.status() == WL_CONNECTED) { 227 | Serial.println(" DONE"); 228 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 229 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 230 | delay(500); 231 | while (!mqttClient.connect(MQTT::Connect(UID).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 232 | Serial.print(" ."); 233 | delay(1000); 234 | } 235 | if(mqttClient.connected()) { 236 | Serial.println(" DONE"); 237 | Serial.println("\n--------------------- Logs ---------------------"); 238 | Serial.println(); 239 | mqttClient.subscribe(MQTT_TOPIC); 240 | blinkLED(LED, 40, 8); 241 | digitalWrite(LED, LOW); 242 | } 243 | else { 244 | Serial.println(" FAILED!"); 245 | Serial.println("\n--------------------------------------------------"); 246 | Serial.println(); 247 | } 248 | } 249 | else { 250 | Serial.println(" WiFi FAILED!"); 251 | Serial.println("\n--------------------------------------------------"); 252 | Serial.println(); 253 | } 254 | } 255 | 256 | void loop() { 257 | ArduinoOTA.handle(); 258 | if (OTAupdate == false) { 259 | mqttClient.loop(); 260 | timedTasks(); 261 | checkStatus(); 262 | } 263 | } 264 | 265 | void blinkLED(int pin, int duration, int n) { 266 | for(int i=0; i 1 && count1 <= 40) { 281 | digitalWrite(L_1, !digitalRead(L_1)); 282 | sendStatus1 = true; 283 | } 284 | else if (count1 >40){ 285 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 286 | requestRestart = true; 287 | } 288 | count1=0; 289 | } 290 | } 291 | #endif 292 | #ifdef CH_2 293 | void button2() { 294 | if (!digitalRead(B_2)) { 295 | count2++; 296 | } 297 | else { 298 | if (count2 > 1 && count2 <= 40) { 299 | digitalWrite(L_2, !digitalRead(L_2)); 300 | sendStatus2 = true; 301 | } 302 | count2=0; 303 | } 304 | } 305 | #endif 306 | #ifdef CH_3 307 | void button3() { 308 | if (!digitalRead(B_3)) { 309 | count3++; 310 | } 311 | else { 312 | if (count3 > 1 && count3 <= 40) { 313 | digitalWrite(L_3, !digitalRead(L_3)); 314 | sendStatus3 = true; 315 | } 316 | count3=0; 317 | } 318 | } 319 | #endif 320 | #ifdef CH_4 321 | void button4() { 322 | if (!digitalRead(B_4)) { 323 | count4++; 324 | } 325 | else { 326 | if (count4 > 1 && count4 <= 40) { 327 | digitalWrite(L_4, !digitalRead(L_4)); 328 | sendStatus4 = true; 329 | } 330 | count4=0; 331 | } 332 | } 333 | #endif 334 | 335 | void checkConnection() { 336 | if (WiFi.status() == WL_CONNECTED) { 337 | if (mqttClient.connected()) { 338 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 339 | } 340 | else { 341 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 342 | requestRestart = true; 343 | } 344 | } 345 | else { 346 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 347 | requestRestart = true; 348 | } 349 | } 350 | 351 | void checkStatus() { 352 | #ifdef CH_1 353 | if (sendStatus1) { 354 | if(digitalRead(L_1) == LOW) { 355 | if (rememberRelayState1) { 356 | EEPROM.write(0, 0); 357 | EEPROM.commit(); 358 | } 359 | if (kRetain == 0) { 360 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "1off").set_qos(QOS)); 361 | } else { 362 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "1off").set_retain().set_qos(QOS)); 363 | } 364 | Serial.println("Relay 1 . . . . . . . . . . . . . . . . . . OFF"); 365 | } else { 366 | if (rememberRelayState1) { 367 | EEPROM.write(0, 1); 368 | EEPROM.commit(); 369 | } 370 | if (kRetain == 0) { 371 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "1on").set_qos(QOS)); 372 | } else { 373 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "1on").set_retain().set_qos(QOS)); 374 | } 375 | Serial.println("Relay 1 . . . . . . . . . . . . . . . . . . ON"); 376 | } 377 | sendStatus1 = false; 378 | } 379 | #endif 380 | #ifdef CH_2 381 | if (sendStatus2) { 382 | if(digitalRead(L_2) == LOW) { 383 | if (rememberRelayState2) { 384 | EEPROM.write(1, 0); 385 | EEPROM.commit(); 386 | } 387 | if (kRetain == 0) { 388 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "2off").set_qos(QOS)); 389 | } else { 390 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "2off").set_retain().set_qos(QOS)); 391 | } 392 | Serial.println("Relay 2 . . . . . . . . . . . . . . . . . . OFF"); 393 | } else { 394 | if (rememberRelayState2) { 395 | EEPROM.write(1, 1); 396 | EEPROM.commit(); 397 | } 398 | if (kRetain == 0) { 399 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "2on").set_retain().set_qos(QOS)); 400 | } else { 401 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "2on").set_qos(QOS)); 402 | } 403 | Serial.println("Relay 2 . . . . . . . . . . . . . . . . . . ON"); 404 | } 405 | sendStatus2 = false; 406 | } 407 | #endif 408 | #ifdef CH_3 409 | if (sendStatus3) { 410 | if(digitalRead(L_3) == LOW) { 411 | if (rememberRelayState3) { 412 | EEPROM.write(2, 0); 413 | EEPROM.commit(); 414 | } 415 | if (kRetain == 0) { 416 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "3off").set_qos(QOS)); 417 | } else { 418 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "3off").set_retain().set_qos(QOS)); 419 | } 420 | Serial.println("Relay 3 . . . . . . . . . . . . . . . . . . OFF"); 421 | } else { 422 | if (rememberRelayState3) { 423 | EEPROM.write(2, 1); 424 | EEPROM.commit(); 425 | } 426 | if (kRetain == 0) { 427 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "3on").set_qos(QOS)); 428 | } else { 429 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "3on").set_retain().set_qos(QOS)); 430 | } 431 | Serial.println("Relay 3 . . . . . . . . . . . . . . . . . . ON"); 432 | } 433 | sendStatus3 = false; 434 | } 435 | #endif 436 | #ifdef CH_4 437 | if (sendStatus4) { 438 | if(digitalRead(L_4) == LOW) { 439 | if (rememberRelayState4) { 440 | EEPROM.write(3, 0); 441 | EEPROM.commit(); 442 | } 443 | if (kRetain == 0) { 444 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "4off").set_qos(QOS)); 445 | } else { 446 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "4off").set_retain().set_qos(QOS)); 447 | } 448 | Serial.println("Relay 4 . . . . . . . . . . . . . . . . . . OFF"); 449 | } else { 450 | if (rememberRelayState4) { 451 | EEPROM.write(3, 1); 452 | EEPROM.commit(); 453 | } 454 | if (kRetain == 0) { 455 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "4on").set_qos(QOS)); 456 | } else { 457 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "4on").set_retain().set_qos(QOS)); 458 | } 459 | Serial.println("Relay 4 . . . . . . . . . . . . . . . . . . ON"); 460 | } 461 | sendStatus4 = false; 462 | } 463 | #endif 464 | if (requestRestart) { 465 | blinkLED(LED, 400, 4); 466 | ESP.restart(); 467 | } 468 | } 469 | 470 | void doReport() { 471 | rssi = WiFi.RSSI(); 472 | char message_buff[120]; 473 | String pubString = "{\"UID\": "+String(UID)+", "+"\"WiFi RSSI\": "+String(rssi)+"dBM"+", "+"\"Topic\": "+String(MQTT_TOPIC)+", "+"\"Ver\": "+String(VER)+"}"; 474 | pubString.toCharArray(message_buff, pubString.length()+1); 475 | if (kRetain == 0) { 476 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug", message_buff).set_qos(QOS)); 477 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/heartbeat", "OK").set_qos(QOS)); 478 | } else { 479 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug", message_buff).set_retain().set_qos(QOS)); 480 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/heartbeat", "OK").set_retain().set_qos(QOS)); 481 | } 482 | } 483 | 484 | void timedTasks() { 485 | if ((millis() > TTasks + (kUpdFreq*60000)) || (millis() < TTasks)) { 486 | TTasks = millis(); 487 | doReport(); 488 | checkConnection(); 489 | } 490 | } 491 | 492 | -------------------------------------------------------------------------------- /arduino/KmanSonoff_v1.00mc/config_mc.h: -------------------------------------------------------------------------------- 1 | /* 2 | ====================================================================================================================================== 3 | Modify all parameters below to suit you environment 4 | ====================================================================================================================================== 5 | */ 6 | bool rememberRelayState1 = true; // If 'true' remembers the state of relay 1 before power loss. 7 | bool rememberRelayState2 = true; // If 'true' remembers the state of relay 2 before power loss. 8 | bool rememberRelayState3 = true; // If 'true' remembers the state of relay 3 before power loss. 9 | bool rememberRelayState4 = true; // If 'true' remembers the state of relay 4 before power loss. 10 | // Each relay will be OFF evey time power is applied when set to 'false' 11 | 12 | int kRetain = 0; // Retain mqtt messages (0 for off, 1 for on) 13 | int kUpdFreq = 1; // Update frequency in Mintes to check for mqtt connection. Defualt 1 min. 14 | int kRetries = 10; // WiFi retry count (10 default). Increase if not connecting to your WiFi. 15 | int QOS = 0; // QOS level for all mqtt messages. (0 or 1) 16 | 17 | #define CH_1 // Channel 1 (Default single channel. Do not comment out) 18 | //#define CH_2 // Channel 2 (Uncomment to use 2nd Channel) 19 | //#define CH_3 // Channel 3 (Uncomment to use 3rd Channel) 20 | //#define CH_4 // Channel 4 (Uncomment to use 4th Channel) 21 | 22 | #define MQTT_SERVER "192.168.0.100" // Your mqtt server ip address 23 | #define MQTT_PORT 1883 // Your mqtt port 24 | #define MQTT_TOPIC "home/sonoff/living_room/1" // Base mqtt topic 25 | #define MQTT_USER "mqtt_user" // mqtt username 26 | #define MQTT_PASS "mqtt_pass" // mqtt password 27 | 28 | #define WIFI_SSID "wifissid" // Your WiFi ssid 29 | #define WIFI_PASS "wifipass" // Your WiFi password 30 | /* 31 | ====================================================================================================================================== 32 | */ 33 | -------------------------------------------------------------------------------- /arduino/KmanSonoff_v1.00sc/KmanSonoff_v1.00sc.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 | *** USE THIS Firmware for: Original Sonoff, Sonoff SV, Sonoff Touch, Sonoff S20 Smart Socket, Sonof TH Series *** 23 | 24 | ================================================================================================ 25 | ATTENTION !!!!!! DO NOT CHANGE ANYTHING IN THIS SECTION UNLESS YOU KNOW WHAT YOU ARE DOING 26 | ================================================================================================ 27 | */ 28 | 29 | #include "config_sc.h" 30 | #ifdef TEMP 31 | #include "DHT.h" 32 | #endif 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #define B_1 0 42 | #define L_1 12 43 | #define LED 13 44 | #if defined (TEMP) || defined (WS) 45 | #define OPT_PIN 14 46 | #endif 47 | #define HOST_PREFIX "Sonoff_%s" 48 | #define HEADER "\n\n--------------------- KmanSonoff_v1.00sc -------------------" 49 | #define VER "kssc_v1.00" 50 | 51 | bool OTAupdate = false; 52 | bool sendStatus = false; 53 | bool requestRestart = false; 54 | bool tempReport = false; 55 | char ESP_CHIP_ID[8]; 56 | char UID[16]; 57 | #ifdef WS 58 | int wallSwitch = 1; 59 | int lastWallSwitch = 1; 60 | #endif 61 | int lastRelayState; 62 | long rssi; 63 | unsigned long TTasks1; 64 | unsigned long count = 0; 65 | #ifdef TEMP 66 | DHT dht(OPT_PIN, DHTTYPE, 11); 67 | #endif 68 | extern "C" { 69 | #include "user_interface.h" 70 | } 71 | WiFiClient wifiClient; 72 | PubSubClient mqttClient(wifiClient, MQTT_SERVER, MQTT_PORT); 73 | Ticker btn_timer; 74 | 75 | void callback(const MQTT::Publish& pub) { 76 | if (pub.payload_string() == "stat") { 77 | } 78 | else if (pub.payload_string() == "on") { 79 | #ifdef ORIG 80 | digitalWrite(LED, LOW); 81 | #endif 82 | digitalWrite(L_1, HIGH); 83 | } 84 | else if (pub.payload_string() == "off") { 85 | #ifdef ORIG 86 | digitalWrite(LED, HIGH); 87 | #endif 88 | digitalWrite(L_1, LOW); 89 | } 90 | else if (pub.payload_string() == "reset") { 91 | requestRestart = true; 92 | } 93 | sendStatus = true; 94 | } 95 | 96 | void setup() { 97 | pinMode(LED, OUTPUT); 98 | pinMode(L_1, OUTPUT); 99 | pinMode(B_1, INPUT); 100 | #ifdef WS 101 | pinMode(OPT_PIN, INPUT_PULLUP); 102 | #endif 103 | digitalWrite(LED, HIGH); 104 | digitalWrite(L_1, LOW); 105 | Serial.begin(115200); 106 | sprintf(ESP_CHIP_ID, "%06X", ESP.getChipId()); 107 | sprintf(UID, HOST_PREFIX, ESP_CHIP_ID); 108 | EEPROM.begin(8); 109 | lastRelayState = EEPROM.read(0); 110 | if (rememberRelayState && lastRelayState == 1) { 111 | #ifdef ORIG 112 | digitalWrite(LED, LOW); 113 | #endif 114 | digitalWrite(L_1, HIGH); 115 | } 116 | btn_timer.attach(0.05, button); 117 | mqttClient.set_callback(callback); 118 | WiFi.mode(WIFI_STA); 119 | WiFi.hostname(UID); 120 | WiFi.begin(WIFI_SSID, WIFI_PASS); 121 | ArduinoOTA.setHostname(UID); 122 | ArduinoOTA.onStart([]() { 123 | OTAupdate = true; 124 | blinkLED(LED, 400, 2); 125 | digitalWrite(LED, HIGH); 126 | Serial.println("OTA Update Initiated . . ."); 127 | }); 128 | ArduinoOTA.onEnd([]() { 129 | Serial.println("\nOTA Update Ended . . .s"); 130 | ESP.restart(); 131 | }); 132 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { 133 | digitalWrite(LED, LOW); 134 | delay(5); 135 | digitalWrite(LED, HIGH); 136 | Serial.printf("Progress: %u%%\r", (progress / (total / 100))); 137 | }); 138 | ArduinoOTA.onError([](ota_error_t error) { 139 | blinkLED(LED, 40, 2); 140 | OTAupdate = false; 141 | Serial.printf("OTA Error [%u] ", error); 142 | if (error == OTA_AUTH_ERROR) Serial.println(". . . . . . . . . . . . . . . Auth Failed"); 143 | else if (error == OTA_BEGIN_ERROR) Serial.println(". . . . . . . . . . . . . . . Begin Failed"); 144 | else if (error == OTA_CONNECT_ERROR) Serial.println(". . . . . . . . . . . . . . . Connect Failed"); 145 | else if (error == OTA_RECEIVE_ERROR) Serial.println(". . . . . . . . . . . . . . . Receive Failed"); 146 | else if (error == OTA_END_ERROR) Serial.println(". . . . . . . . . . . . . . . End Failed"); 147 | }); 148 | ArduinoOTA.begin(); 149 | Serial.println(HEADER); 150 | Serial.print("\nUID: "); 151 | Serial.print(UID); 152 | Serial.print("\nConnecting to "); Serial.print(WIFI_SSID); Serial.print(" Wifi"); 153 | while ((WiFi.status() != WL_CONNECTED) && kRetries --) { 154 | delay(500); 155 | Serial.print(" ."); 156 | } 157 | if (WiFi.status() == WL_CONNECTED) { 158 | Serial.println(" DONE"); 159 | Serial.print("IP Address is: "); Serial.println(WiFi.localIP()); 160 | Serial.print("Connecting to ");Serial.print(MQTT_SERVER);Serial.print(" Broker . ."); 161 | delay(500); 162 | while (!mqttClient.connect(MQTT::Connect(UID).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASS)) && kRetries --) { 163 | Serial.print(" ."); 164 | delay(1000); 165 | } 166 | if(mqttClient.connected()) { 167 | Serial.println(" DONE"); 168 | Serial.println("\n---------------------------- Logs ----------------------------"); 169 | Serial.println(); 170 | mqttClient.subscribe(MQTT_TOPIC); 171 | blinkLED(LED, 40, 8); 172 | #ifdef ORIG 173 | if(digitalRead(L_1) == HIGH) { 174 | digitalWrite(LED, LOW); 175 | } else { 176 | digitalWrite(LED, HIGH); 177 | } 178 | #endif 179 | #ifdef TH 180 | digitalWrite(LED, LOW); 181 | #endif 182 | } 183 | else { 184 | Serial.println(" FAILED!"); 185 | Serial.println("\n----------------------------------------------------------------"); 186 | Serial.println(); 187 | } 188 | } 189 | else { 190 | Serial.println(" WiFi FAILED!"); 191 | Serial.println("\n----------------------------------------------------------------"); 192 | Serial.println(); 193 | } 194 | } 195 | 196 | void loop() { 197 | ArduinoOTA.handle(); 198 | if (OTAupdate == false) { 199 | mqttClient.loop(); 200 | timedTasks1(); 201 | checkStatus(); 202 | #ifdef TEMP 203 | if (tempReport) { 204 | getTemp(); 205 | } 206 | #endif 207 | #ifdef WS 208 | checkWallSwitch(); 209 | #endif 210 | } 211 | } 212 | 213 | void blinkLED(int pin, int duration, int n) { 214 | for(int i=0; i 1 && count <= 40) { 228 | #ifdef ORIG 229 | digitalWrite(LED, !digitalRead(LED)); 230 | #endif 231 | digitalWrite(L_1, !digitalRead(L_1)); 232 | sendStatus = true; 233 | } 234 | else if (count >40){ 235 | Serial.println("\n\nSonoff Rebooting . . . . . . . . Please Wait"); 236 | requestRestart = true; 237 | } 238 | count=0; 239 | } 240 | } 241 | 242 | void checkConnection() { 243 | if (WiFi.status() == WL_CONNECTED) { 244 | if (mqttClient.connected()) { 245 | Serial.println("mqtt broker connection . . . . . . . . . . OK"); 246 | } 247 | else { 248 | Serial.println("mqtt broker connection . . . . . . . . . . LOST"); 249 | requestRestart = true; 250 | } 251 | } 252 | else { 253 | Serial.println("WiFi connection . . . . . . . . . . LOST"); 254 | requestRestart = true; 255 | } 256 | } 257 | 258 | void checkStatus() { 259 | if (sendStatus) { 260 | #ifdef ORIG 261 | if(digitalRead(LED) == LOW) { 262 | if (rememberRelayState) { 263 | EEPROM.write(0, 1); 264 | } 265 | if (kRetain == 0) { 266 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_qos(QOS)); 267 | } else { 268 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(QOS)); 269 | } 270 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 271 | } else { 272 | if (rememberRelayState) { 273 | EEPROM.write(0, 0); 274 | } 275 | if (kRetain == 0) { 276 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_qos(QOS)); 277 | } else { 278 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(QOS)); 279 | } 280 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 281 | } 282 | #endif 283 | #ifdef TH 284 | if(digitalRead(L_1) == LOW) { 285 | if (rememberRelayState) { 286 | EEPROM.write(0, 0); 287 | } 288 | if (kRetain == 0) { 289 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_qos(QOS)); 290 | } else { 291 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "off").set_retain().set_qos(QOS)); 292 | } 293 | Serial.println("Relay . . . . . . . . . . . . . . . . . . OFF"); 294 | } else { 295 | if (rememberRelayState) { 296 | EEPROM.write(0, 1); 297 | } 298 | if (kRetain == 0) { 299 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_qos(QOS)); 300 | } else { 301 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/stat", "on").set_retain().set_qos(QOS)); 302 | } 303 | Serial.println("Relay . . . . . . . . . . . . . . . . . . ON"); 304 | } 305 | #endif 306 | if (rememberRelayState) { 307 | EEPROM.commit(); 308 | } 309 | sendStatus = false; 310 | } 311 | if (requestRestart) { 312 | blinkLED(LED, 400, 4); 313 | ESP.restart(); 314 | } 315 | } 316 | 317 | #ifdef WS 318 | void checkWallSwitch() { 319 | wallSwitch = digitalRead(OPT_PIN); 320 | if (wallSwitch != lastWallSwitch) { 321 | digitalWrite(L_1, !digitalRead(L_1)); 322 | digitalWrite(LED, !digitalRead(LED)); 323 | sendStatus = true; 324 | } 325 | lastWallSwitch = wallSwitch; 326 | } 327 | #endif 328 | 329 | #ifdef TEMP 330 | void getTemp() { 331 | Serial.print("DHT read . . . . . . . . . . . . . . . . . "); 332 | float dhtH, dhtT, dhtHI; 333 | char message_buff[60]; 334 | dhtH = dht.readHumidity(); 335 | dhtT = dht.readTemperature(UseFahrenheit); 336 | dhtHI = dht.computeHeatIndex(dhtT, dhtH, UseFahrenheit); 337 | if(digitalRead(LED) == LOW) { 338 | blinkLED(LED, 100, 1); 339 | } else { 340 | blinkLED(LED, 100, 1); 341 | digitalWrite(LED, HIGH); 342 | } 343 | if (isnan(dhtH) || isnan(dhtT) || isnan(dhtHI)) { 344 | if (kRetain == 0) { 345 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug","\"DHT Read Error\"").set_qos(QOS)); 346 | } else { 347 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug","\"DHT Read Error\"").set_retain().set_qos(QOS)); 348 | } 349 | Serial.println("ERROR"); 350 | tempReport = false; 351 | return; 352 | } 353 | String pubString = "{\"Temp\": "+String(dhtT)+", "+"\"Humidity\": "+String(dhtH)+", "+"\"HeatIndex\": "+String(dhtHI) + "}"; 354 | pubString.toCharArray(message_buff, pubString.length()+1); 355 | if (kRetain == 0) { 356 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/temp", message_buff).set_qos(QOS)); 357 | } else { 358 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/temp", message_buff).set_retain().set_qos(QOS)); 359 | } 360 | Serial.println("OK"); 361 | tempReport = false; 362 | } 363 | #endif 364 | 365 | void doReport() { 366 | rssi = WiFi.RSSI(); 367 | char message_buff[120]; 368 | String pubString = "{\"UID\": "+String(UID)+", "+"\"WiFi RSSI\": "+String(rssi)+"dBM"+", "+"\"Topic\": "+String(MQTT_TOPIC)+", "+"\"Ver\": "+String(VER)+"}"; 369 | pubString.toCharArray(message_buff, pubString.length()+1); 370 | if (kRetain == 0) { 371 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug", message_buff).set_qos(QOS)); 372 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/heartbeat", "OK").set_qos(QOS)); 373 | } else { 374 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/debug", message_buff).set_retain().set_qos(QOS)); 375 | mqttClient.publish(MQTT::Publish(MQTT_TOPIC"/heartbeat", "OK").set_retain().set_qos(QOS)); 376 | } 377 | } 378 | 379 | void timedTasks1() { 380 | if ((millis() > TTasks1 + (kUpdFreq*60000)) || (millis() < TTasks1)) { 381 | TTasks1 = millis(); 382 | checkConnection(); 383 | doReport(); 384 | #ifdef TEMP 385 | tempReport = true; 386 | #endif 387 | } 388 | } 389 | 390 | -------------------------------------------------------------------------------- /arduino/KmanSonoff_v1.00sc/config_sc.h: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================================================================================== 3 | Modify all parameters below to suit you environment 4 | =========================================================================================================================================== 5 | */ 6 | bool rememberRelayState = true; // If 'true' remembers the state of the relay before power loss otherwise 7 | // load will be OFF evey time power is applied. Set retain below to 0 if true. 8 | 9 | int kRetain = 0; // Retain mqtt messages (0 for off, 1 for on) 10 | int kUpdFreq = 1; // Update frequency in Mintes to check for mqtt connection. Defualt 1 min. 11 | int kRetries = 10; // WiFi retry count (10 default). Increase if not connecting to your WiFi. 12 | int QOS = 0; // QOS level for all mqtt messages. (0 or 1) 13 | 14 | #define NONE // Set to NONE, TEMP, or WS (Cannot be blank) 15 | // NONE for standard Sonoff relay only ON / OFF (default) 16 | // TEMP for DHT11/22 Support on Pin 5 of header (GPIO 14) **Must install 'DHT sensor library' (Adafruit) & 'Adafruit Unified Sensor' library. 17 | // WS for External Wallswitch Support on Pin 5 of header (GPIO 14) 18 | 19 | #define ORIG // ORIG or TH 20 | // ORIG for Basic / Original Sonoff, TH for TH Series 21 | 22 | #define DHTTYPE DHT22 // Set to 'DHT11' or 'DHT22'. (Only applies if using TEMP) **Must connect to the mains power for temperature readings to be sent. 23 | #define UseFahrenheit false // Set to 'true' to use Fahrenheit. (Only applies if using TEMP) 24 | 25 | #define MQTT_SERVER "192.168.0.100" // Your mqtt server ip address 26 | #define MQTT_PORT 1883 // Your mqtt port 27 | #define MQTT_TOPIC "home/sonoff/living_room/1" // Base mqtt topic 28 | #define MQTT_USER "mqtt_user" // mqtt username 29 | #define MQTT_PASS "mqtt_pass" // mqtt password 30 | 31 | #define WIFI_SSID "wifissid" // Your WiFi ssid 32 | #define WIFI_PASS "wifipass" // Your WiFi password 33 | /* 34 | =========================================================================================================================================== 35 | */ 36 | -------------------------------------------------------------------------------- /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: false 10 | -------------------------------------------------------------------------------- /home-assistant/sensors.yaml: -------------------------------------------------------------------------------- 1 | - platform: mqtt 2 | name: "Living Room Temp" 3 | state_topic: "home/sonoff/living_room/1/temp" 4 | qos: 1 5 | # Set unit_of_measurement to "°C" or "°F" to match the temperature scale chosen in config_sc.h 6 | unit_of_measurement: "°C" 7 | value_template: "{{ value_json.Temp | round(1) }}" 8 | 9 | - platform: mqtt 10 | name: "Living Room Humidity" 11 | state_topic: "home/sonoff/living_room/1/temp" 12 | qos: 1 13 | unit_of_measurement: "%" 14 | value_template: "{{ value_json.Humidity | round(1) }}" 15 | 16 | - platform: mqtt 17 | state_topic: "home/sonoff/living_room/1/temp" 18 | name: "Living Room Real Feel" 19 | qos: 1 20 | # Set unit_of_measurement to "°C" or "°F" to match the temperature scale chosen in config_sc.h 21 | unit_of_measurement: "°C" 22 | value_template: "{{ value_json.HeatIndex | round(1) }}" 23 | -------------------------------------------------------------------------------- /images/sonoff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KmanOz/KmanSonoff/d36cff0dafb84060463766d92d386f8beb118732/images/sonoff.png -------------------------------------------------------------------------------- /images/th10ftdi.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KmanOz/KmanSonoff/d36cff0dafb84060463766d92d386f8beb118732/images/th10ftdi.JPG --------------------------------------------------------------------------------