2 * Sonoff and Wkaku by Theo Arends
4 * ---------------------------------------------
5 * >>>> Tools - Flash size: 1M (64K SPIFFS) <<<<
6 * ---------------------------------------------
8 * ESP-12F connections (Wkaku)
10 * |-------------------| |---------|
11 * | | ------------- | |1N4001| |Relay|
12 * | | -| Tx |- | |---------|
14 * |-------------------| En |- |---| 1k|------|< BC547B
16 * | | -| IO00 |------|Switch|------|
17 * | ---| IO12 IO02 |--- LED (ESP-12E/F) |
18 * |---| 1k|---|LED|---| IO13 IO15 |------|10k|---------|
19 * |-------------------| Vcc Gnd |--------------------|
24 #define VERSION 0x01001000 // 1.0.16
26 #define LOG_LEVEL_NONE 0
27 #define LOG_LEVEL_ERROR 1
28 #define LOG_LEVEL_INFO 2
29 #define LOG_LEVEL_DEBUG 3
30 #define LOG_LEVEL_DEBUG_MORE 4
32 #include "user_config.h"
34 #define SERIAL_IO // Enable serial command line
35 #define STATES 10 // loops per second
36 #define MQTT_RETRY_SECS 10 // Seconds to retry MQTT connection
38 //#define LED_PIN 2 // GPIO 2 = Blue Led (0 = On, 1 = Off) - ESP-12
39 #define LED_PIN 13 // GPIO 13 = Green Led (0 = On, 1 = Off) - Sonoff
40 //#define LED_PIN 16 // NodeMCU
41 #define REL_PIN 12 // GPIO 12 = Red Led and Relay (0 = Off, 1 = On)
42 #define KEY_PIN 0 // GPIO 00 = Button
47 #define WIFI_SMARTCONFIG 1
49 #define TOPSZ 40 // Max number of characters in topic string
50 #define MESSZ 200 // Max number of characters in message string (Syntax string)
51 #define LOGSZ 80 // Max number of characters in log string
53 #include <ESP8266WiFi.h>
54 #include <ESP8266HTTPClient.h>
55 #include <ESP8266httpUpdate.h>
56 #include <PubSubClient.h>
58 extern "C" uint32_t _SPIFFS_start;
61 unsigned long cfg_holder;
62 unsigned long saveFlag;
63 unsigned long version;
71 char mqtt_grptopic[32];
74 char mqtt_subtopic[32];
84 uint8_t Wday; // day of week, sunday is day 1
94 uint8_t mqttcounter = 0;
95 unsigned long timerxs = 0, timersec = 0;
99 int smartconfigflag = 0;
100 int heartbeatflag = 0;
103 WiFiClient espClient;
104 PubSubClient mqttClient(espClient);
105 WiFiUDP portUDP; // syslog
108 uint8_t blinkstate = 1;
110 uint8_t lastbutton = NOT_PRESSED;
111 uint8_t holdcount = 0;
112 uint8_t multiwindow = 0;
113 uint8_t multipress = 0;
115 /********************************************************************************************/
117 void mqtt_publish(const char* topic, const char* data)
119 char log[TOPSZ+MESSZ];
121 mqttClient.publish(topic, data);
122 snprintf_P(log, sizeof(log), PSTR("MQTT: %s = %s"), strchr(topic,'/')+1, data); // Skip topic prefix
123 addLog(LOG_LEVEL_INFO, log);
124 mqttClient.loop(); // Solve LmacRxBlk:1 messages
128 void mqtt_connected()
130 char stopic[TOPSZ], svalue[TOPSZ];
132 snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/#"), SUB_PREFIX, sysCfg.mqtt_topic);
133 mqttClient.subscribe(stopic);
134 mqttClient.loop(); // Solve LmacRxBlk:1 messages
135 snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/#"), SUB_PREFIX, sysCfg.mqtt_grptopic);
136 mqttClient.subscribe(stopic);
137 mqttClient.loop(); // Solve LmacRxBlk:1 messages
138 snprintf_P(stopic, sizeof(stopic), PSTR("%s/"MQTT_CLIENT_ID"/#"), SUB_PREFIX, ESP.getChipId()); // Fall back topic
139 mqttClient.subscribe(stopic);
140 mqttClient.loop(); // Solve LmacRxBlk:1 messages
142 snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/NAME"), PUB_PREFIX, sysCfg.mqtt_topic);
143 snprintf_P(svalue, sizeof(svalue), PSTR("Sonoff switch"));
144 mqtt_publish(stopic, svalue);
145 snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/VERSION"), PUB_PREFIX, sysCfg.mqtt_topic);
146 snprintf_P(svalue, sizeof(svalue), PSTR("%s"), Version);
147 mqtt_publish(stopic, svalue);
148 snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/FALLBACKTOPIC"), PUB_PREFIX, sysCfg.mqtt_topic);
149 snprintf_P(svalue, sizeof(svalue), PSTR(MQTT_CLIENT_ID), ESP.getChipId());
150 mqtt_publish(stopic, svalue);
153 void mqtt_reconnect()
155 char stopic[TOPSZ], svalue[TOPSZ], log[LOGSZ];
157 mqttcounter = MQTT_RETRY_SECS;
158 addLog(LOG_LEVEL_INFO, "MQTT: Attempting connection");
159 snprintf(svalue, sizeof(svalue), MQTT_CLIENT_ID, ESP.getChipId());
160 snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/lwt"), PUB_PREFIX, sysCfg.mqtt_topic);
161 if (mqttClient.connect(svalue, MQTT_USER, MQTT_PASS, stopic, 0, 0, "offline")) {
162 addLog(LOG_LEVEL_INFO, "MQTT: Connected");
166 snprintf_P(log, sizeof(log), PSTR("MQTT: Connect failed, rc %d. Retry in %d seconds"), mqttClient.state(), mqttcounter);
167 addLog(LOG_LEVEL_DEBUG, log);
171 void mqttDataCb(char* topic, byte* data, unsigned int data_len)
174 char *str, *p, *mtopic = NULL, *type = NULL;
175 char stopic[TOPSZ], svalue[MESSZ];
177 int topic_len = strlen(topic);
178 char topicBuf[topic_len +1];
179 char dataBuf[data_len +1];
180 char dataBufUc[data_len +1];
182 memcpy(topicBuf, topic, topic_len);
183 topicBuf[topic_len] = 0;
185 memcpy(dataBuf, data, data_len);
186 dataBuf[data_len] = 0;
188 snprintf_P(svalue, sizeof(svalue), PSTR("MQTT: Receive topic %s, data %s"), topicBuf, dataBuf);
189 addLog(LOG_LEVEL_DEBUG, svalue);
192 for (str = strtok_r(topicBuf, "/", &p); str && i < 3; str = strtok_r(NULL, "/", &p)) {
196 case 1: // Topic / GroupTopic / DVES_123456
203 if (!strcmp(mtopic, sysCfg.mqtt_grptopic)) grpflg = 1;
204 if (type != NULL) for(i = 0; i < strlen(type); i++) type[i] = toupper(type[i]);
206 for(i = 0; i <= data_len; i++) dataBufUc[i] = toupper(dataBuf[i]);
208 snprintf_P(svalue, sizeof(svalue), PSTR("MQTT: DataCb Topic %s, Group %d, Type %s, data %s (%s)"),
209 mtopic, grpflg, type, dataBuf, dataBufUc);
210 addLog(LOG_LEVEL_DEBUG, svalue);
213 snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s"), PUB_PREFIX, sysCfg.mqtt_topic, type);
214 strlcpy(svalue, "Error", sizeof(svalue));
216 uint16_t payload = atoi(dataBuf);
217 if (!strcmp(dataBufUc,"OFF")) payload = 0;
218 if (!strcmp(dataBufUc,"ON")) payload = 1;
219 if (!strcmp(dataBufUc,"TOGGLE")) payload = 2;
221 if (!strcmp(type,"STATUS")) {
222 if ((data_len == 0) || (payload < 0) || (payload > 6)) payload = 7;
223 if ((payload == 0) || (payload == 7)) {
224 snprintf_P(svalue, sizeof(svalue), PSTR("%s, %s, %s, %s, %d, %d"),
225 Version, sysCfg.mqtt_topic, sysCfg.mqtt_topic2, sysCfg.mqtt_subtopic, sysCfg.power, sysCfg.timezone);
226 if (payload == 0) mqtt_publish(stopic, svalue);
228 if ((payload == 0) || (payload == 1)) {
229 snprintf_P(svalue, sizeof(svalue), PSTR("PRM: %s, "MQTT_CLIENT_ID", %s, %s, %d, %d"),
230 sysCfg.mqtt_grptopic, ESP.getChipId(), sysCfg.otaUrl, sysCfg.mqtt_host, heartbeat, sysCfg.saveFlag);
231 if (payload == 0) mqtt_publish(stopic, svalue);
233 if ((payload == 0) || (payload == 2)) {
234 snprintf_P(svalue, sizeof(svalue), PSTR("FWR: Version %s, Boot %d, SDK %s"),
235 Version, ESP.getBootVersion(), ESP.getSdkVersion());
236 if (payload == 0) mqtt_publish(stopic, svalue);
238 if ((payload == 0) || (payload == 3)) {
239 snprintf_P(svalue, sizeof(svalue), PSTR("LOG: Seriallog %d, Syslog %d, LogHost %s, SSId %s, Password %s"),
240 sysCfg.seriallog_level, sysCfg.syslog_level, sysCfg.syslog_host, sysCfg.sta_ssid, sysCfg.sta_pwd);
241 if (payload == 0) mqtt_publish(stopic, svalue);
243 if ((payload == 0) || (payload == 4)) {
244 snprintf_P(svalue, sizeof(svalue), PSTR("MEM: Sketch size %d, Free %d (Heap %d), Spiffs start %d, Flash size %d (%d)"),
245 ESP.getSketchSize(), ESP.getFreeSketchSpace(), ESP.getFreeHeap(), (uint32_t)&_SPIFFS_start - 0x40200000,
246 ESP.getFlashChipRealSize(), ESP.getFlashChipSize());
247 if (payload == 0) mqtt_publish(stopic, svalue);
249 if ((payload == 0) || (payload == 5)) {
250 IPAddress ip = WiFi.localIP();
251 IPAddress gw = WiFi.gatewayIP();
252 IPAddress nm = WiFi.subnetMask();
253 snprintf_P(svalue, sizeof(svalue), PSTR("NET: Hostname %s, IP %u.%u.%u.%u, Gateway %u.%u.%u.%u, Subnetmask %u.%u.%u.%u"),
254 Hostname, ip[0], ip[1], ip[2], ip[3], gw[0], gw[1], gw[2], gw[3], nm[0], nm[1], nm[2], nm[3]);
255 if (payload == 0) mqtt_publish(stopic, svalue);
257 if ((payload == 0) || (payload == 6)) {
258 snprintf_P(svalue, sizeof(svalue), PSTR("MQT: Host %s, MAX_PACKET_SIZE %d, KEEPALIVE %d"),
259 sysCfg.mqtt_host, MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE);
262 else if (!grpflg && !strcmp(type,"UPGRADE")) {
263 if ((data_len > 0) && (payload == 1)) {
265 snprintf_P(svalue, sizeof(svalue), PSTR("Upgrade %s"), Version);
268 snprintf_P(svalue, sizeof(svalue), PSTR("1 to upgrade"));
270 else if (!grpflg && !strcmp(type,"OTAURL")) {
271 if ((data_len > 0) && (data_len < 80))
272 strlcpy(sysCfg.otaUrl, (payload == 1) ? OTA_URL : dataBuf, sizeof(sysCfg.otaUrl));
273 snprintf_P(svalue, sizeof(svalue), PSTR("%s"), sysCfg.otaUrl);
275 else if (!strcmp(type,"SERIALLOG")) {
276 if ((data_len > 0) && (payload >= LOG_LEVEL_NONE) && (payload <= LOG_LEVEL_DEBUG_MORE)) {
277 sysCfg.seriallog_level = payload;
279 snprintf_P(svalue, sizeof(svalue), PSTR("%d"), sysCfg.seriallog_level);
281 else if (!strcmp(type,"SYSLOG")) {
282 if ((data_len > 0) && (payload >= LOG_LEVEL_NONE) && (payload <= LOG_LEVEL_DEBUG_MORE)) {
283 sysCfg.syslog_level = payload;
285 snprintf_P(svalue, sizeof(svalue), PSTR("%d"), sysCfg.syslog_level);
287 else if (!strcmp(type,"LOGHOST")) {
288 if ((data_len > 0) && (data_len < 32)) {
289 strlcpy(sysCfg.syslog_host, (payload == 1) ? SYS_LOG_HOST : dataBuf, sizeof(sysCfg.syslog_host));
292 snprintf_P(svalue, sizeof(svalue), PSTR("%s"), sysCfg.syslog_host);
294 else if (!grpflg && !strcmp(type,"SSID")) {
295 if ((data_len > 0) && (data_len < 32)) {
296 strlcpy(sysCfg.sta_ssid, (payload == 1) ? STA_SSID : dataBuf, sizeof(sysCfg.sta_ssid));
299 snprintf_P(svalue, sizeof(svalue), PSTR("%s"), sysCfg.sta_ssid);
301 else if (!grpflg && !strcmp(type,"PASSWORD")) {
302 if ((data_len > 0) && (data_len < 64)) {
303 strlcpy(sysCfg.sta_pwd, (payload == 1) ? STA_PASS : dataBuf, sizeof(sysCfg.sta_pwd));
306 snprintf_P(svalue, sizeof(svalue), PSTR("%s"), sysCfg.sta_pwd);
308 else if (!grpflg && !strcmp(type,"MQTTHOST")) {
309 if ((data_len > 0) && (data_len < 32)) {
310 strlcpy(sysCfg.mqtt_host, (payload == 1) ? MQTT_HOST : dataBuf, sizeof(sysCfg.mqtt_host));
313 snprintf_P(svalue, sizeof(svalue), PSTR("%s"), sysCfg.mqtt_host);
315 else if (!strcmp(type,"GROUPTOPIC")) {
316 if ((data_len > 0) && (data_len < 32)) {
317 for(i = 0; i <= data_len; i++)
318 if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#')) dataBuf[i] = '_';
319 snprintf_P(svalue, sizeof(svalue), PSTR(MQTT_CLIENT_ID), ESP.getChipId());
320 if (!strcmp(dataBuf, svalue)) payload = 1;
321 strlcpy(sysCfg.mqtt_grptopic, (payload == 1) ? MQTT_GRPTOPIC : dataBuf, sizeof(sysCfg.mqtt_grptopic));
324 snprintf_P(svalue, sizeof(svalue), PSTR("%s"), sysCfg.mqtt_grptopic);
326 else if (!grpflg && !strcmp(type,"TOPIC")) {
327 if ((data_len > 0) && (data_len < 32)) {
328 for(i = 0; i <= data_len; i++)
329 if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#')) dataBuf[i] = '_';
330 snprintf_P(svalue, sizeof(svalue), PSTR(MQTT_CLIENT_ID), ESP.getChipId());
331 if (!strcmp(dataBuf, svalue)) payload = 1;
332 strlcpy(sysCfg.mqtt_topic, (payload == 1) ? MQTT_TOPIC : dataBuf, sizeof(sysCfg.mqtt_topic));
335 snprintf_P(svalue, sizeof(svalue), PSTR("%s"), sysCfg.mqtt_topic);
337 else if (!grpflg && !strcmp(type,"BUTTONTOPIC")) {
338 if ((data_len > 0) && (data_len < 32)) {
339 for(i = 0; i <= data_len; i++)
340 if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#')) dataBuf[i] = '_';
341 snprintf_P(svalue, sizeof(svalue), PSTR(MQTT_CLIENT_ID), ESP.getChipId());
342 if (!strcmp(dataBuf, svalue)) payload = 1;
343 strlcpy(sysCfg.mqtt_topic2, (payload == 1) ? MQTT_TOPIC : dataBuf, sizeof(sysCfg.mqtt_topic2));
345 snprintf_P(svalue, sizeof(svalue), PSTR("%s"), sysCfg.mqtt_topic2);
347 else if (!grpflg && !strcmp(type,"SMARTCONFIG")) {
348 if ((data_len > 0) && (payload == 1)) {
351 snprintf_P(svalue, sizeof(svalue), PSTR("Smartconfig started"));
353 snprintf_P(svalue, sizeof(svalue), PSTR("1 to start smartconfig"));
355 else if (!grpflg && !strcmp(type,"RESTART")) {
356 if ((data_len > 0) && (payload == 1)) {
358 snprintf_P(svalue, sizeof(svalue), PSTR("Restarting"));
360 snprintf_P(svalue, sizeof(svalue), PSTR("1 to restart"));
362 else if (!grpflg && !strcmp(type,"RESET")) {
366 snprintf_P(svalue, sizeof(svalue), PSTR("Reset and Restarting"));
370 snprintf_P(svalue, sizeof(svalue), PSTR("Erase, Reset and Restarting"));
373 snprintf_P(svalue, sizeof(svalue), PSTR("1 to reset"));
376 else if (!strcmp(type,"TIMEZONE")) {
377 if ((data_len > 0) && (payload >= -12) && (payload <= 12)) {
378 sysCfg.timezone = payload;
379 rtc_timezone(sysCfg.timezone);
381 snprintf_P(svalue, sizeof(svalue), PSTR("%d"), sysCfg.timezone);
383 else if ((!strcmp(type,"LIGHT")) || (!strcmp(type,"POWER"))) {
384 snprintf_P(sysCfg.mqtt_subtopic, sizeof(sysCfg.mqtt_subtopic), PSTR("%s"), type);
385 if ((data_len > 0) && (payload >= 0) && (payload <= 2)) {
389 sysCfg.power = payload;
395 digitalWrite(REL_PIN, sysCfg.power);
397 strlcpy(svalue, (sysCfg.power) ? "On" : "Off", sizeof(svalue));
399 else if (!strcmp(type,"LEDSTATE")) {
400 if ((data_len > 0) && (payload >= 0) && (payload <= 1)) {
401 sysCfg.ledstate = payload;
403 strlcpy(svalue, (sysCfg.ledstate) ? "On" : "Off", sizeof(svalue));
410 snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/SYNTAX"), PUB_PREFIX, sysCfg.mqtt_topic);
412 // strlcpy(svalue, "Status, Upgrade, Otaurl, Restart, Reset, Smartconfig, Seriallog, Syslog, LogHost, SSId, Password, MqttHost, GroupTopic, Topic, ButtonTopic, Timezone, Light, Power, Ledstate", sizeof(svalue)); // Fails progmem access
413 snprintf_P(svalue, sizeof(svalue), PSTR("Status, Upgrade, Otaurl, Restart, Reset, Smartconfig, Seriallog, Syslog, LogHost, SSId, Password, MqttHost, GroupTopic, Topic, ButtonTopic, Timezone, Light, Power, Ledstate"));
415 // strlcpy(svalue, "Status, GroupTopic, Timezone, Light, Power, Ledstate", sizeof(svalue)); // Fails progmem access
416 snprintf_P(svalue, sizeof(svalue), PSTR("Status, GroupTopic, Timezone, Light, Power, Ledstate"));
418 mqtt_publish(stopic, svalue);
422 /********************************************************************************************/
424 void send_button(char *cmnd)
426 char stopic[128], svalue[128];
429 token = strtok(cmnd, " ");
430 if ((!strcmp(token,"light")) || (!strcmp(token,"power"))) strcpy(token, sysCfg.mqtt_subtopic);
431 snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s"), SUB_PREFIX, sysCfg.mqtt_topic2, token);
432 token = strtok(NULL, "");
433 snprintf_P(svalue, sizeof(svalue), PSTR("%s"), (token == NULL) ? "" : token);
434 mqtt_publish(stopic, svalue);
437 void do_cmnd(char *cmnd)
439 char stopic[128], svalue[128];
442 token = strtok(cmnd, " ");
443 snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s"), SUB_PREFIX, sysCfg.mqtt_topic, token);
444 token = strtok(NULL, "");
445 snprintf_P(svalue, sizeof(svalue), PSTR("%s"), (token == NULL) ? "" : token);
446 mqttDataCb(stopic, (byte*)svalue, strlen(svalue));
451 char stopic[TOPSZ], svalue[TOPSZ];
453 snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s"), PUB_PREFIX, sysCfg.mqtt_topic, sysCfg.mqtt_subtopic);
454 strlcpy(svalue, (sysCfg.power == 0) ? "Off" : "On", sizeof(svalue));
455 mqtt_publish(stopic, svalue);
458 void send_updateStatus(const char* svalue)
462 snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/UPGRADE"), PUB_PREFIX, sysCfg.mqtt_topic);
463 mqtt_publish(stopic, svalue);
468 char stopic[TOPSZ], svalue[TOPSZ];
473 snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/HEARTBEAT"), PUB_PREFIX, sysCfg.mqtt_topic);
474 snprintf_P(svalue, sizeof(svalue), PSTR("%d"), heartbeat);
475 mqtt_publish(stopic, svalue);
479 const char commands[6][14] PROGMEM = {
480 {"reset 1"}, // Hold button for more than 4 seconds
481 {"light 2"}, // Press button once
482 {"light 2"}, // Press button twice
483 {"smartconfig 1"}, // Press button three times
484 {"upgrade 1"}, // Press button four times
485 {"restart 1"}}; // Press button five times
490 char scmnd[20], log[LOGSZ];
492 timerxs = millis() + (1000 / STATES);
494 if (state == STATES) { // Every second
499 button = digitalRead(KEY_PIN);
500 if ((button == PRESSED) && (lastbutton == NOT_PRESSED)) {
501 multipress = (multiwindow) ? multipress +1 : 1;
502 snprintf_P(log, sizeof(log), PSTR("APP: Multipress %d"), multipress);
503 addLog(LOG_LEVEL_DEBUG, log);
505 multiwindow = STATES /2; // 1/2 second multi press window
508 if (button == NOT_PRESSED) {
512 if (holdcount == (STATES *4)) { // 4 seconds button hold
513 // strlcpy(scmnd, commands[0], sizeof(scmnd)); // Fails progmem access
514 snprintf_P(scmnd, sizeof(scmnd), commands[0]);
522 if ((!holdcount) && (multipress >= 1) && (multipress <= 5)) {
523 // strlcpy(scmnd, commands[multipress], sizeof(scmnd)); // Fails progmem access
524 snprintf_P(scmnd, sizeof(scmnd), commands[multipress]);
525 if (strcmp(sysCfg.mqtt_topic2,"0") && (multipress == 1) && mqttClient.connected())
526 send_button(scmnd); // Execute command via MQTT using ButtonTopic to sync external clients
528 do_cmnd(scmnd); // Execute command internally
533 if (!(state % ((STATES/10)*2))) {
534 if (blinks || restartflag || otaflag) {
535 if (restartflag || otaflag)
536 blinkstate = 0; // Stay lit
538 blinkstate ^= 1; // Blink
539 digitalWrite(LED_PIN, blinkstate);
540 if (blinkstate) blinks--;
542 if (sysCfg.ledstate) digitalWrite(LED_PIN, !sysCfg.power);
552 ESPhttpUpdate.update(sysCfg.otaUrl);
553 send_updateStatus(ESPhttpUpdate.getLastErrorString().c_str());
561 if (restartflag == 11) {
565 if (restartflag == 12) {
570 if (restartflag <= 0) ESP.restart();
574 if (smartconfigflag) {
576 WIFI_Check(WIFI_SMARTCONFIG);
578 WIFI_Check(WIFI_STATUS);
582 if ((WiFi.status() == WL_CONNECTED) && (!mqttClient.connected())) {
593 #define INPUT_BUFFER_SIZE 128
596 int SerialInByteCounter = 0;
597 char serialInBuf[INPUT_BUFFER_SIZE + 2];
601 while (Serial.available())
604 SerialInByte = Serial.read();
605 if (SerialInByte > 127) // binary data...
608 SerialInByteCounter = 0;
611 if (isprint(SerialInByte))
613 if (SerialInByteCounter < INPUT_BUFFER_SIZE) // add char to string if it still fits
614 serialInBuf[SerialInByteCounter++] = SerialInByte;
616 SerialInByteCounter = 0;
618 if (SerialInByte == '\n')
620 serialInBuf[SerialInByteCounter] = 0; // serial data completed
621 Serial.println(serialInBuf);
622 SerialInByteCounter = 0;
623 do_cmnd(serialInBuf);
629 /********************************************************************************************/
635 Serial.begin(115200);
639 snprintf_P(Version, sizeof(Version), PSTR("%d.%d.%d"), VERSION >> 24 & 0xff, VERSION >> 16 & 0xff, VERSION >> 8 & 0xff);
640 if (VERSION & 0x1f) {
641 byte idx = strlen(Version);
642 Version[idx] = 96 + (VERSION & 0x1f);
646 if (sysCfg.version != VERSION) { // Fix version dependent changes
647 if (sysCfg.version < 0x01000D00) { // 1.0.13 - Add ledstate
648 sysCfg.ledstate = APP_LEDSTATE;
651 sysCfg.version = VERSION;
654 snprintf_P(Hostname, sizeof(Hostname), PSTR(WIFI_HOSTNAME), ESP.getChipId(), sysCfg.mqtt_topic);
655 WIFI_Connect(Hostname);
657 mqttClient.setServer(sysCfg.mqtt_host, MQTT_PORT);
658 mqttClient.setCallback(mqttDataCb);
660 pinMode(LED_PIN, OUTPUT);
661 digitalWrite(LED_PIN, blinkstate);
663 pinMode(REL_PIN, OUTPUT);
664 digitalWrite(REL_PIN, sysCfg.power);
666 pinMode(KEY_PIN, INPUT_PULLUP);
668 rtc_init(sysCfg.timezone);
670 snprintf_P(log, sizeof(log), PSTR("App: Project %s (Topic %s, Fallback "MQTT_CLIENT_ID", GroupTopic %s) Version %s"),
671 PROJECT, sysCfg.mqtt_topic, ESP.getChipId(), sysCfg.mqtt_grptopic, Version);
672 addLog(LOG_LEVEL_INFO, log);
677 if (millis() >= timersec) {
678 timersec = millis() + 1000;
680 if ((rtcTime.Minute == 2) && (rtcTime.Second == 30)) heartbeatflag = 1;
683 if (millis() >= timerxs) stateloop();
688 if (Serial.available()) serial();