From d763fd52ebc9e9c3e5143b39c22df43bf6408c36 Mon Sep 17 00:00:00 2001 From: arendst Date: Fri, 16 Jun 2017 14:33:49 +0200 Subject: [PATCH] v5.1.7 5.1.7 20170616 * Prep removal of SetOptions alternatives * Restore webpage upgrade error messages removed in 5.1.5 * Add hold button functionality to buttons 2 to 4 * Add command SetOption32 1..100 to set Key Hold Time from 0.1 seconds to 10 seconds (#200) * Allow slashes in Topic, GroupTopic, ButtonTopic and SwitchTopic (#507) * Changed webpage form actions from post to get and use relative path url (#434, #522) --- README.md | 2 +- sonoff/_releasenotes.ino | 10 ++- sonoff/settings.h | 7 +- sonoff/settings.ino | 9 +- sonoff/sonoff.ino | 186 ++++++++++++++++++++++----------------- sonoff/support.ino | 23 +++++ sonoff/user_config.h | 2 +- sonoff/webserver.ino | 67 +++++++------- 8 files changed, 185 insertions(+), 121 deletions(-) diff --git a/README.md b/README.md index 2583d3ca3..e4bf0dcaf 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Sonoff-Tasmota Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE. -Current version is **5.1.6** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information. +Current version is **5.1.7** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information. ### **** ATTENTION Version 5.x.x specific information **** diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index 991eea9f7..ce5456f8b 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,4 +1,12 @@ -/* 5.1.6 20170606 +/* 5.1.7 20170616 + * Prep removal of SetOptions alternatives + * Restore webpage upgrade error messages removed in 5.1.5 + * Add hold button functionality to buttons 2 to 4 + * Add command SetOption32 1..100 to set Key Hold Time from 0.1 seconds to 10 seconds (#200) + * Allow slashes in Topic, GroupTopic, ButtonTopic and SwitchTopic (#507) + * Changed webpage form actions from post to get and use relative path url (#434, #522) + * + * 5.1.6 20170606 * Shrink code * Removed online configuration of Domoticz In and Domoticz Out MQTT strings * Removed commands DomoticzInTopic and DomoticzOutTopic diff --git a/sonoff/settings.h b/sonoff/settings.h index 43d04996b..c85818be5 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -17,13 +17,15 @@ along with this program. If not, see . */ +#define PARAM8_SIZE 23 // Number of param bytes + typedef union { // Restricted by MISRA-C Rule 18.4 but so usefull... uint32_t data; // Allow bit manipulation using SetOption struct { uint32_t savestate : 1; // bit 0 uint32_t button_restrict : 1; // bit 1 uint32_t value_units : 1; // bit 2 - uint32_t mqtt_enabled : 1; + uint32_t mqtt_enabled : 1; // bit 3 uint32_t mqtt_response : 1; // bit 4 uint32_t mqtt_power_retain : 1; uint32_t mqtt_button_retain : 1; @@ -93,9 +95,8 @@ struct SYSCFG { uint8_t power; uint8_t ledstate; - uint8_t ex_switchmode; // Not used since 3.9.21 - char ex_domoticz_in_topic[22]; // Not used since 5.1.6 + uint8_t param[PARAM8_SIZE]; // was domoticz_in_topic until 5.1.6 char state_text[4][11]; // was domoticz_out_topic until 5.1.6 uint16_t domoticz_update_timer; diff --git a/sonoff/settings.ino b/sonoff/settings.ino index fa1da628a..9b060631c 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -456,6 +456,10 @@ void CFG_DefaultSet2() // 5.0.6 sysCfg.mqtt_retry = MQTT_RETRY_SECS; + + // 5.1.7 + sysCfg.param[P_HOLD_TIME] = KEY_HOLD_TIME; // Default 4 seconds hold time + } /********************************************************************************************/ @@ -589,7 +593,7 @@ void CFG_Delta() strlcpy(sysCfg.web_password, WEB_PASSWORD, sizeof(sysCfg.web_password)); } if (sysCfg.version < 0x03091500) { - for (byte i = 0; i < 4; i++) sysCfg.switchmode[i] = sysCfg.ex_switchmode; + for (byte i = 0; i < 4; i++) sysCfg.switchmode[i] = SWITCH_MODE; } if (sysCfg.version < 0x04000200) { sysCfg.ex_button_restrict = 0; @@ -650,6 +654,9 @@ void CFG_Delta() memcpy(sysCfg.state_text, sysCfg.ex_state_text, 33); strlcpy(sysCfg.state_text[3], MQTT_CMND_HOLD, sizeof(sysCfg.state_text[3])); } + if (sysCfg.version < 0x05010700) { + sysCfg.param[P_HOLD_TIME] = KEY_HOLD_TIME; // Default 4 seconds hold time + } sysCfg.version = VERSION; } diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index f7890f5eb..704161dd0 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -24,7 +24,7 @@ - Select IDE Tools - Flash size: "1M (no SPIFFS)" ====================================================*/ -#define VERSION 0x05010600 // 5.1.6 +#define VERSION 0x05010700 // 5.1.7 enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; enum week_t {Last, First, Second, Third, Fourth}; @@ -148,7 +148,8 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX}; #define APP_BAUDRATE 115200 // Default serial baudrate #define MAX_STATUS 11 // Max number of status lines -enum butt_t {PRESSED, NOT_PRESSED}; +enum butt_t {PRESSED, NOT_PRESSED}; +enum opt_t {P_HOLD_TIME, P_MAX_PARAM8}; // Index in sysCfg.param #include "support.h" // Global support @@ -274,11 +275,11 @@ int blinks = 201; // Number of LED blinks uint8_t blinkstate = 0; // LED state uint8_t lastbutton[4] = { NOT_PRESSED, NOT_PRESSED, NOT_PRESSED, NOT_PRESSED }; // Last button states -uint8_t holdcount = 0; // Timer recording button hold +uint8_t holdbutton[4] = { 0 }; // Timer for button hold uint8_t multiwindow = 0; // Max time between button presses to record press count uint8_t multipress = 0; // Number of button presses within multiwindow uint8_t lastwallswitch[4]; // Last wall switch states -uint8_t wallswitchtimer[4] = { 0 }; // Timer for wallswitch push button hold +uint8_t holdwallswitch[4] = { 0 }; // Timer for wallswitch push button hold uint8_t blockgpio0 = 4; // Block GPIO0 for 4 seconds after poweron to workaround Wemos D1 RTS circuit mytmplt my_module; // Active copy of GPIOs @@ -660,12 +661,6 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, } snprintf_P(svalue, ssvalue, PSTR("{\"MqttRetry\":%d}"), sysCfg.mqtt_retry); } - else if (!strcmp_P(type,PSTR("MQTTRESPONSE"))) { - if ((payload >= 0) && (payload <= 1)) { - sysCfg.flag.mqtt_response = payload; - } - snprintf_P(svalue, ssvalue, PSTR("{\"MqttResponse\":\"%s\"}"), getStateText(sysCfg.flag.mqtt_response)); - } else if (!strcmp_P(type,PSTR("STATETEXT")) && (index > 0) && (index <= 4)) { if ((data_len > 0) && (data_len < sizeof(sysCfg.state_text[0]))) { for(i = 0; i <= data_len; i++) { @@ -709,13 +704,7 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, } else if (!strcmp_P(type,PSTR("FULLTOPIC"))) { if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_fulltopic))) { - for (i = 0; i <= data_len; i++) { - if ((dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) { - for (byte j = i; j <= data_len; j++) { - dataBuf[j] = dataBuf[j +1]; - } - } - } + mqttfy(1, dataBuf); if (!strcmp(dataBuf, MQTTClient)) { payload = 1; } @@ -730,11 +719,7 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, } else if (!strcmp_P(type,PSTR("PREFIX")) && (index > 0) && (index <= 3)) { if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_prefix[0]))) { - for(i = 0; i <= data_len; i++) { - if ((dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) { - dataBuf[i] = '_'; - } - } + mqttfy(0, dataBuf); strlcpy(sysCfg.mqtt_prefix[index -1], (1 == payload) ? (1==index)?SUB_PREFIX:(2==index)?PUB_PREFIX:PUB_PREFIX2 : dataBuf, sizeof(sysCfg.mqtt_prefix[0])); // if (sysCfg.mqtt_prefix[index -1][strlen(sysCfg.mqtt_prefix[index -1])] == '/') sysCfg.mqtt_prefix[index -1][strlen(sysCfg.mqtt_prefix[index -1])] = 0; restartflag = 2; @@ -743,11 +728,7 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, } else if (!strcmp_P(type,PSTR("GROUPTOPIC"))) { if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_grptopic))) { - for(i = 0; i <= data_len; i++) { - if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#')) { - dataBuf[i] = '_'; - } - } + mqttfy(0, dataBuf); if (!strcmp(dataBuf, MQTTClient)) { payload = 1; } @@ -758,11 +739,7 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, } else if (!grpflg && !strcmp_P(type,PSTR("TOPIC"))) { if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_topic))) { - for(i = 0; i <= data_len; i++) { - if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) { - dataBuf[i] = '_'; - } - } + mqttfy(0, dataBuf); if (!strcmp(dataBuf, MQTTClient)) { payload = 1; } @@ -777,11 +754,7 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, } else if (!grpflg && !strcmp_P(type,PSTR("BUTTONTOPIC"))) { if ((data_len > 0) && (data_len < sizeof(sysCfg.button_topic))) { - for(i = 0; i <= data_len; i++) { - if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) { - dataBuf[i] = '_'; - } - } + mqttfy(0, dataBuf); if (!strcmp(dataBuf, MQTTClient)) { payload = 1; } @@ -791,11 +764,7 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, } else if (!grpflg && !strcmp_P(type,PSTR("SWITCHTOPIC"))) { if ((data_len > 0) && (data_len < sizeof(sysCfg.switch_topic))) { - for(i = 0; i <= data_len; i++) { - if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) { - dataBuf[i] = '_'; - } - } + mqttfy(0, dataBuf); if (!strcmp(dataBuf, MQTTClient)) { payload = 1; } @@ -832,12 +801,8 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, if (!payload) { for(i = 1; i <= Maxdevice; i++) { // Clear MQTT retain in broker snprintf_P(stemp2, sizeof(stemp2), PSTR("%d"), i); - snprintf_P(scommand, sizeof(scommand), PSTR("POWER%s"), (Maxdevice > 1) ? stemp2 : ""); getTopic_P(stemp1, 1, sysCfg.mqtt_topic, scommand); - -// snprintf_P(stemp1, sizeof(stemp1), PSTR("%s/%s/POWER%s"), sysCfg.mqtt_prefix[1], sysCfg.mqtt_topic, (Maxdevice > 1) ? stemp2 : ""); - mqtt_publish(stemp1, "", sysCfg.flag.mqtt_power_retain); } } @@ -893,6 +858,8 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) char *p; char *mtopic = NULL; char *type = NULL; + byte otype = 0; + byte ptype = 0; uint16_t i = 0; uint16_t grpflg = 0; uint16_t index; @@ -915,7 +882,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) #endif // USE_DOMOTICZ grpflg = (strstr(topicBuf, sysCfg.mqtt_grptopic) != NULL); - type = strrchr(topicBuf, '/') +1; + type = strrchr(topicBuf, '/') +1; // Last part of received topic is always the command (type) index = 1; if (type != NULL) { @@ -939,7 +906,6 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) grpflg, index, type, dataBuf, dataBufUc); addLog(LOG_LEVEL_DEBUG, svalue); -// snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/RESULT"), PUB_PREFIX, sysCfg.mqtt_topic); if (type != NULL) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"Command\":\"Error\"}")); if (sysCfg.ledstate &0x02) { @@ -949,9 +915,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) if (!strcmp(dataBufUc,"?")) { data_len = 0; } - int16_t payload = -1; + int16_t payload = -1; // No payload if (data_len && isdigit(dataBuf[0])) { - payload = atoi(dataBuf); // -32766 - 32767 + payload = atoi(dataBuf); // -32766 - 32767 } uint16_t payload16 = atoi(dataBuf); // 0 - 65535 @@ -1041,21 +1007,47 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } snprintf_P(svalue, sizeof(svalue), PSTR("{\"SaveData\":\"%s\"}"), (sysCfg.savedata > 1) ? stemp1 : getStateText(sysCfg.savedata)); } - else if (!strcmp_P(type,PSTR("SETOPTION")) && (index >= 0) && (index <= 11)) { - if ((payload >= 0) && (payload <= 1)) { - switch (index) { - case 0: // savestate - case 1: // button_restrict - case 2: // value_units - case 4: // mqtt_response - case 8: // temperature_conversion - case 10: // mqtt_offline - case 11: // button_swap - bitWrite(sysCfg.flag.data, index, payload); + else if (!strcmp_P(type,PSTR("SETOPTION")) && ((index >= 0) && (index <= 11)) || ((index > 31) && (index <= P_MAX_PARAM8 +31))) { + if (index <= 31) { + ptype = 0; // SetOption0 .. 31 + } else { + ptype = 1; // SetOption32 .. + index = index -32; + } + if (payload >= 0) { + if (0 == ptype) { // SetOption0 .. 31 + if (payload <= 1) { + switch (index) { + case 3: // mqtt + restartflag = 2; + case 0: // savestate + case 1: // button_restrict + case 2: // value_units + case 4: // mqtt_response + case 8: // temperature_conversion + case 10: // mqtt_offline + case 11: // button_swap + bitWrite(sysCfg.flag.data, index, payload); + } + } + } + else { // SetOption32 .. + switch (index) { + case P_HOLD_TIME: + if ((payload >= 1) && (payload <= 100)) { + sysCfg.param[P_HOLD_TIME] = payload; + } + break; + } } } - snprintf_P(svalue, sizeof(svalue), PSTR("{\"SetOption%d\":\"%s\"}"), index, getStateText(bitRead(sysCfg.flag.data, index))); + if (ptype) { + snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), sysCfg.param[index]); + } + snprintf_P(svalue, sizeof(svalue), PSTR("{\"SetOption%d\":\"%s\"}"), (ptype) ? index +32 : index, (ptype) ? stemp1 : getStateText(bitRead(sysCfg.flag.data, index))); } + +// To be removed in near future else if (!strcmp_P(type,PSTR("SAVESTATE"))) { if ((payload >= 0) && (payload <= 1)) { sysCfg.flag.savestate = payload; @@ -1074,6 +1066,12 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } snprintf_P(svalue, sizeof(svalue), PSTR("{\"Units\":\"%s\"}"), getStateText(sysCfg.flag.value_units)); } + else if (!strcmp_P(type,PSTR("TEMPUNIT"))) { + if ((payload >= 0) && (payload <= 1)) { + sysCfg.flag.temperature_conversion = payload; + } + snprintf_P(svalue, sizeof(svalue), PSTR("{\"TempUnit\":\"%s\"}"), (sysCfg.flag.temperature_conversion) ? "Fahrenheit" : "Celsius"); + } else if (!strcmp_P(type,PSTR("MQTT"))) { if ((payload >= 0) && (payload <= 1)) { sysCfg.flag.mqtt_enabled = payload; @@ -1081,12 +1079,14 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } snprintf_P(svalue, sizeof(svalue), PSTR("{\"Mqtt\":\"%s\"}"), getStateText(sysCfg.flag.mqtt_enabled)); } - else if (!strcmp_P(type,PSTR("TEMPUNIT"))) { + else if (!strcmp_P(type,PSTR("MQTTRESPONSE"))) { if ((payload >= 0) && (payload <= 1)) { - sysCfg.flag.temperature_conversion = payload; + sysCfg.flag.mqtt_response = payload; } - snprintf_P(svalue, sizeof(svalue), PSTR("{\"TempUnit\":\"%s\"}"), (sysCfg.flag.temperature_conversion) ? "Fahrenheit" : "Celsius"); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"MqttResponse\":\"%s\"}"), getStateText(sysCfg.flag.mqtt_response)); } +// Until here + else if (!strcmp_P(type,PSTR("TEMPRES"))) { if ((payload >= 0) && (payload <= 3)) { sysCfg.flag.temperature_resolution = payload; @@ -2059,7 +2059,7 @@ void stateloop() addLog(LOG_LEVEL_DEBUG, log); button = PRESSED; if (0xF500 == ButtonCode) { - holdcount = (STATES *4) -1; + holdbutton[0] = (STATES *4) -1; } ButtonCode = 0; } else { @@ -2079,10 +2079,10 @@ void stateloop() } lastbutton[0] = button; if (NOT_PRESSED == button) { - holdcount = 0; + holdbutton[0] = 0; } else { - holdcount++; - if (KEY_HOLD_TIME == holdcount) { // 4 seconds button hold + holdbutton[0]++; + if (holdbutton[0] == sysCfg.param[P_HOLD_TIME]) { // 4 seconds button hold multipress = 0; if (!sysCfg.flag.button_restrict) { // no restriction (OPTION snprintf_P(scmnd, sizeof(scmnd), PSTR("reset 1")); @@ -2095,7 +2095,7 @@ void stateloop() if (multiwindow) { multiwindow--; } else { - if ((!restartflag) && (!holdcount) && (multipress > 0) && (multipress < MAX_BUTTON_COMMANDS +3)) { + if ((!restartflag) && (!holdbutton[0]) && (multipress > 0) && (multipress < MAX_BUTTON_COMMANDS +3)) { if ((SONOFF_DUAL == sysCfg.module) || (CH4 == sysCfg.module)) { flag = ((1 == multipress) || (2 == multipress)); } else { @@ -2124,12 +2124,32 @@ void stateloop() for (byte i = 1; i < Maxdevice; i++) { if (pin[GPIO_KEY1 +i] < 99) { + + if (holdbutton[i]) { + holdbutton[i]--; + if (0 == holdbutton[i]) { + send_button_power(0, i +1, 3); // Execute command via MQTT + } + } + button = digitalRead(pin[GPIO_KEY1 +i]); +/* if ((PRESSED == button) && (NOT_PRESSED == lastbutton[i])) { if (!send_button_power(0, i +1, 2)) { // Execute command via MQTT do_cmnd_power(i +1, 2); // Execute command internally } } +*/ + if ((PRESSED == button) && (NOT_PRESSED == lastbutton[i])) { + holdbutton[i] = sysCfg.param[P_HOLD_TIME]; + } + if ((NOT_PRESSED == button) && (PRESSED == lastbutton[i]) && (holdbutton[i])) { + holdbutton[i] = 0; + if (!send_button_power(0, i +1, 2)) { // Execute command via MQTT + do_cmnd_power(i +1, 2); // Execute command internally + } + } + lastbutton[i] = button; } } @@ -2137,9 +2157,9 @@ void stateloop() for (byte i = 0; i < 4; i++) { if (pin[GPIO_SWT1 +i] < 99) { - if (wallswitchtimer[i]) { - wallswitchtimer[i]--; - if (0 == wallswitchtimer[i]) { + if (holdwallswitch[i]) { + holdwallswitch[i]--; + if (0 == holdwallswitch[i]) { send_button_power(1, i +1, 3); // Execute command via MQTT } } @@ -2159,30 +2179,30 @@ void stateloop() break; case PUSHBUTTON: if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i])) { - switchflag = 2; // Toggle with pushbutton to Gnd + switchflag = 2; // Toggle with pushbutton to Gnd } break; case PUSHBUTTON_INV: if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i])) { - switchflag = 2; // Toggle with releasing pushbutton from Gnd + switchflag = 2; // Toggle with releasing pushbutton from Gnd } break; case PUSHBUTTONHOLD: if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i])) { - wallswitchtimer[i] = KEY_HOLD_TIME; + holdwallswitch[i] = sysCfg.param[P_HOLD_TIME]; } - if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i]) && (wallswitchtimer[i])) { - wallswitchtimer[i] = 0; - switchflag = 2; // Toggle with pushbutton to Gnd + if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i]) && (holdwallswitch[i])) { + holdwallswitch[i] = 0; + switchflag = 2; // Toggle with pushbutton to Gnd } break; case PUSHBUTTONHOLD_INV: if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i])) { - wallswitchtimer[i] = KEY_HOLD_TIME; + holdwallswitch[i] = sysCfg.param[P_HOLD_TIME]; } - if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i]) && (wallswitchtimer[i])) { - wallswitchtimer[i] = 0; - switchflag = 2; // Toggle with pushbutton to Gnd + if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i]) && (holdwallswitch[i])) { + holdwallswitch[i] = 0; + switchflag = 2; // Toggle with pushbutton to Gnd } break; } diff --git a/sonoff/support.ino b/sonoff/support.ino index 529d3efcc..464b15c3c 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -166,6 +166,29 @@ boolean parseIP(uint32_t* addr, const char* str) return (3 == i); } +void mqttfy(byte option, char* str) +{ +// option 0 = replace by underscore +// option 1 = delete character + uint16_t i = 0; + while (str[i] > 0) { +// if ((str[i] == '/') || (str[i] == '+') || (str[i] == '#') || (str[i] == ' ')) { + if ((str[i] == '+') || (str[i] == '#') || (str[i] == ' ')) { + if (option) { + uint16_t j = i; + while (str[j] > 0) { + str[j] = str[j +1]; + j++; + } + i--; + } else { + str[i] = '_'; + } + } + i++; + } +} + /*********************************************************************************************\ * Wifi \*********************************************************************************************/ diff --git a/sonoff/user_config.h b/sonoff/user_config.h index fe39a53a3..093b1b491 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -141,7 +141,7 @@ #define APP_BLINKCOUNT 10 // [BlinkCount] Number of blinks (0 = 32000) #define APP_SLEEP 0 // [Sleep] Sleep time to lower energy consumption (0 = Off, 1 - 250 mSec) -#define KEY_HOLD_TIME 40 // Number of 0.1 seconds to hold Button or external Pushbutton before sending HOLD message +#define KEY_HOLD_TIME 40 // [SetOption32] Number of 0.1 seconds to hold Button or external Pushbutton before sending HOLD message #define SWITCH_MODE TOGGLE // [SwitchMode] TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD or PUSHBUTTONHOLD_INV (the wall switch state) #define WS2812_LEDS 30 // [Pixels] Number of WS2812 LEDs to start with diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino index 1f62a2987..55238b838 100644 --- a/sonoff/webserver.ino +++ b/sonoff/webserver.ino @@ -135,33 +135,33 @@ const char HTTP_SCRIPT_MODULE[] PROGMEM = const char HTTP_MSG_RSTRT[] PROGMEM = "
Device will restart in a few seconds

"; const char HTTP_BTN_MENU1[] PROGMEM = - "
" - "
" - "
" - "
"; + "
" + "
" + "
" + "
"; const char HTTP_BTN_RSTRT[] PROGMEM = - "
"; + "
"; const char HTTP_BTN_MENU2[] PROGMEM = - "
" - "
"; + "
" + "
"; const char HTTP_BTN_MENU3[] PROGMEM = - "
" + "
" #ifdef USE_DOMOTICZ - "
" + "
" #endif // USE_DOMOTICZ ""; const char HTTP_BTN_MENU4[] PROGMEM = - "
" - "
" - "
" - "
" - "
"; + "
" + "
" + "
" + "
" + "
"; const char HTTP_BTN_MAIN[] PROGMEM = - "

"; + "

"; const char HTTP_BTN_CONF[] PROGMEM = - "

"; + "

"; const char HTTP_FORM_MODULE[] PROGMEM = - "
 Module parameters 
" + "
 Module parameters " "" "
Module type ({mt})
" "
AP1 SSId (" STA_SSID1 ")

" "
AP1 Password

" @@ -177,7 +177,7 @@ const char HTTP_FORM_WIFI[] PROGMEM = "
AP2 Password

" "
Hostname (" WIFI_HOSTNAME ")

"; const char HTTP_FORM_MQTT[] PROGMEM = - "
 MQTT parameters " + "
 MQTT parameters " "" "
Host (" MQTT_HOST ")

" "
Port (" STR(MQTT_PORT) ")

" @@ -187,7 +187,7 @@ const char HTTP_FORM_MQTT[] PROGMEM = "
Topic = %topic% (" MQTT_TOPIC ")

" "
Full Topic (" MQTT_FULLTOPIC ")

"; const char HTTP_FORM_LOG1[] PROGMEM = - "
 Logging parameters " + "
 Logging parameters " ""; const char HTTP_FORM_LOG2[] PROGMEM = "
{b0}log level ({b1})

" "
Telemetric period (" STR(TELE_PERIOD) ")

"; const char HTTP_FORM_OTHER[] PROGMEM = - "
 Other parameters " + "
 Other parameters " "" "
Web Admin Password

" "
MQTT enable
"; @@ -222,7 +222,7 @@ const char HTTP_FORM_RST[] PROGMEM = const char HTTP_FORM_UPG[] PROGMEM = "
" "
 Upgrade by web server " - "" + "" "
OTA Url

" "
" "


" @@ -929,7 +929,9 @@ void handleSave() break; case 2: strlcpy(stemp, (!strlen(webServer->arg("mt").c_str())) ? MQTT_TOPIC : webServer->arg("mt").c_str(), sizeof(stemp)); + mqttfy(0, stemp); strlcpy(stemp2, (!strlen(webServer->arg("mf").c_str())) ? MQTT_FULLTOPIC : webServer->arg("mf").c_str(), sizeof(stemp2)); + mqttfy(1,stemp2); if ((strcmp(stemp, sysCfg.mqtt_topic)) || (strcmp(stemp2, sysCfg.mqtt_fulltopic))) { mqtt_publish_topic_P(2, PSTR("LWT"), (sysCfg.flag.mqtt_offline) ? "Offline" : "", true); // Offline or remove previous retained topic } @@ -1126,18 +1128,18 @@ void handleUploadDone() page += F("
Upload "); if (_uploaderror) { page += F("failed

"); - if (!_uploadfiletype && Update.hasError()) { - StreamString str; - Update.printError(str); - snprintf_P(error, sizeof(error), str.c_str()); - } else { - snprintf_P(error, sizeof(error), PSTR("Upload error code %d"), _uploaderror); - } switch (_uploaderror) { case 1: strcpy_P(error, PSTR("No file selected")); break; + case 2: strcpy_P(error, PSTR("Not enough space")); break; + case 3: strcpy_P(error, PSTR("Magic byte is not 0xE9")); break; + case 4: strcpy_P(error, PSTR("IDE flash size larger than device flash size")); break; + case 5: strcpy_P(error, PSTR("Upload buffer miscompare")); break; + case 6: strcpy_P(error, PSTR("Upload failed. Enable logging 3")); break; case 7: strcpy_P(error, PSTR("Upload aborted")); break; - case 8: strcpy_P(error, PSTR("Invalid configuration file")); break; - case 9: strcpy_P(error, PSTR("Configuration file too large")); break; + case 8: strcpy_P(error, PSTR("File invalid")); break; + case 9: strcpy_P(error, PSTR("File too large")); break; + default: + snprintf_P(error, sizeof(error), PSTR("Upload error code %d"), _uploaderror); } page += error; snprintf_P(log, sizeof(log), PSTR("Upload: %s"), error); @@ -1249,6 +1251,9 @@ void handleUploadLoop() } if (!_uploadfiletype) { if (!Update.end(true)) { // true to set the size to the current progress + if (_serialoutput) { + Update.printError(Serial); + } _uploaderror = 6; return; }