From ee883bdcb8f9d0a9981fb88f53e0080752c16b55 Mon Sep 17 00:00:00 2001 From: arendst Date: Fri, 30 Jun 2017 17:54:19 +0200 Subject: [PATCH] v5.2.3 5.2.3 20170630 * Change Sonoff Led color conversion code * Fix SetOption12 handling * Simplify auto configuration upgrade * Add option Upgrade to only upgrade to any higher version (Old PR #213) * Change FallbackTopic to cmnd// bypassing FullTopic and Prefix (#538) --- README.md | 2 +- sonoff/_releasenotes.ino | 9 +++++++- sonoff/settings.ino | 37 ++++++++++++++++++++++++++------ sonoff/sonoff.ino | 46 ++++++++++++++++++++++++++++------------ sonoff/support.ino | 44 ++++++++++++++++++++++++++++++++++++++ sonoff/xdrv_snfled.ino | 16 ++++++-------- 6 files changed, 122 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 3a33869bf392..cf89d9f9bd35 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.2.2** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information. +Current version is **5.2.3** - 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 2d095538e701..c993e06d5233 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,4 +1,11 @@ -/* 5.2.2 20170625 +/* 5.2.3 20170630 + * Change Sonoff Led color conversion code + * Fix SetOption12 handling + * Simplify auto configuration upgrade + * Add option Upgrade to only upgrade to any higher version (Old PR #213) + * Change FallbackTopic to cmnd// bypassing FullTopic and Prefix (#538) + * + * 5.2.2 20170625 * Add configuration SaveAddress to Status 1 and Information Page * Change Sonoff Led Color conversion from AtoH to strtol * Fix possible wrong uploads due to configuration overwrites (#542) diff --git a/sonoff/settings.ino b/sonoff/settings.ino index 9149a7ccc960..fcd1aa156ba4 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -200,15 +200,26 @@ uint32_t CFG_Address() return _cfgLocation * SPI_FLASH_SEC_SIZE; } -void CFG_Save(byte no_rotate) +void CFG_Save(byte rotate) { +/* Save configuration in eeprom or one of 7 slots below + * + * rotate 0 = Save in next flash slot + * rotate 1 = Save only in eeprom flash slot until SetOption12 0 or restart + * rotate 2 = Save in eeprom flash slot and continue depending on stop_flash_rotate + * stop_flash_rotate 0 = Allow flash slot rotation (SetOption12 0) + * stop_flash_rotate 1 = Allow only eeprom flash slot use (SetOption12 1) + */ char log[LOGSZ]; #ifndef BE_MINIMAL - if ((getHash() != _cfgHash) || no_rotate) { - if (no_rotate) { + if ((getHash() != _cfgHash) || rotate) { + if (1 == rotate) { stop_flash_rotate = 1; // Disable flash rotate from now on } + if (2 == rotate) { + _cfgLocation = CFG_LOCATION +1; + } if (stop_flash_rotate) { _cfgLocation = CFG_LOCATION; } else { @@ -222,7 +233,7 @@ void CFG_Save(byte no_rotate) spi_flash_erase_sector(_cfgLocation); spi_flash_write(_cfgLocation * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); interrupts(); - if (!stop_flash_rotate && no_rotate) { + if (!stop_flash_rotate && rotate) { for (byte i = 1; i < CFG_ROTATES; i++) { noInterrupts(); spi_flash_erase_sector(_cfgLocation -i); // Delete previous configurations by resetting to 0xFF @@ -240,6 +251,8 @@ void CFG_Save(byte no_rotate) void CFG_Load() { +/* Load configuration from eeprom or one of 7 slots below if first load does not stop_flash_rotate + */ char log[LOGSZ]; struct SYSCFGH { @@ -258,7 +271,7 @@ void CFG_Load() // snprintf_P(log, sizeof(log), PSTR("Cnfg: Check at %X with count %d and holder %X"), _cfgLocation -1, _sysCfgH.saveFlag, _sysCfgH.cfg_holder); // addLog(LOG_LEVEL_DEBUG, log); - if (sysCfg.flag.stop_flash_rotate || (sysCfg.cfg_holder != _sysCfgH.cfg_holder) || (sysCfg.saveFlag > _sysCfgH.saveFlag)) { + if (((sysCfg.version > 0x05000200) && sysCfg.flag.stop_flash_rotate) || (sysCfg.cfg_holder != _sysCfgH.cfg_holder) || (sysCfg.saveFlag > _sysCfgH.saveFlag)) { break; } delay(1); @@ -271,8 +284,9 @@ void CFG_Load() } */ if (sysCfg.cfg_holder != CFG_HOLDER) { +/* // Auto upgrade - if ((sysCfg.version < 0x04020000) || (sysCfg.version > 0x06000000)) { + if ((sysCfg.version < 0x04020000) || (sysCfg.version > VERSION)) { noInterrupts(); spi_flash_read((CFG_LOCATION_3) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); spi_flash_read((CFG_LOCATION_3 + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&_sysCfgH, sizeof(SYSCFGH)); @@ -287,6 +301,17 @@ void CFG_Load() } else { CFG_Default(); } +*/ + // Auto upgrade + noInterrupts(); + spi_flash_read((CFG_LOCATION_3) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); + spi_flash_read((CFG_LOCATION_3 + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&_sysCfgH, sizeof(SYSCFGH)); + if (sysCfg.saveFlag < _sysCfgH.saveFlag) + spi_flash_read((CFG_LOCATION_3 + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); + interrupts(); + if ((sysCfg.cfg_holder != CFG_HOLDER) || (sysCfg.version >= 0x04020000)) { + CFG_Default(); + } } _cfgHash = getHash(); diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 0208a43de656..c3fd71e18f85 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -24,7 +24,7 @@ - Select IDE Tools - Flash size: "1M (no SPIFFS)" ====================================================*/ -#define VERSION 0x05020200 // 5.2.2 +#define VERSION 0x05020300 // 5.2.3 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}; @@ -230,6 +230,7 @@ char Version[16]; // Version string from VERSION define char Hostname[33]; // Composed Wifi hostname char MQTTClient[33]; // Composed MQTT Clientname uint8_t mqttcounter = 0; // MQTT connection retry counter +uint8_t fallbacktopic = 0; // Use Topic or FallbackTopic unsigned long timerxs = 0; // State loop timer int state = 0; // State per second flag int mqttflag = 2; // MQTT connection messages flag @@ -328,19 +329,26 @@ void getClient(char* output, const char* input, byte size) void getTopic_P(char *stopic, byte prefix, char *topic, const char* subtopic) { char romram[CMDSZ]; - + String fulltopic; + snprintf_P(romram, sizeof(romram), subtopic); - String fulltopic = sysCfg.mqtt_fulltopic; - if ((0 == prefix) && (-1 == fulltopic.indexOf(F(MQTT_TOKEN_PREFIX)))) { - fulltopic += F("/" MQTT_TOKEN_PREFIX); // Need prefix for commands to handle mqtt topic loops - } - for (byte i = 0; i < 3; i++) { - if ('\0' == sysCfg.mqtt_prefix[i][0]) { - snprintf_P(sysCfg.mqtt_prefix[i], sizeof(sysCfg.mqtt_prefix[i]), PREFIXES[i]); + if (fallbacktopic) { + fulltopic = FPSTR(PREFIXES[prefix]); + fulltopic += F("/"); + fulltopic += MQTTClient; + } else { + fulltopic = sysCfg.mqtt_fulltopic; + if ((0 == prefix) && (-1 == fulltopic.indexOf(F(MQTT_TOKEN_PREFIX)))) { + fulltopic += F("/" MQTT_TOKEN_PREFIX); // Need prefix for commands to handle mqtt topic loops + } + for (byte i = 0; i < 3; i++) { + if ('\0' == sysCfg.mqtt_prefix[i][0]) { + snprintf_P(sysCfg.mqtt_prefix[i], sizeof(sysCfg.mqtt_prefix[i]), PREFIXES[i]); + } } + fulltopic.replace(F(MQTT_TOKEN_PREFIX), sysCfg.mqtt_prefix[prefix]); + fulltopic.replace(F(MQTT_TOKEN_TOPIC), topic); } - fulltopic.replace(F(MQTT_TOKEN_PREFIX), sysCfg.mqtt_prefix[prefix]); - fulltopic.replace(F(MQTT_TOKEN_TOPIC), topic); fulltopic.replace(F("#"), ""); fulltopic.replace(F("//"), "/"); if (!fulltopic.endsWith("/")) { @@ -536,7 +544,9 @@ void mqtt_connected() getTopic_P(stopic, 0, sysCfg.mqtt_grptopic, PSTR("#")); mqttClient.subscribe(stopic); mqttClient.loop(); // Solve LmacRxBlk:1 messages + fallbacktopic = 1; getTopic_P(stopic, 0, MQTTClient, PSTR("#")); + fallbacktopic = 0; mqttClient.subscribe(stopic); mqttClient.loop(); // Solve LmacRxBlk:1 messages } @@ -883,6 +893,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) #endif // USE_DOMOTICZ grpflg = (strstr(topicBuf, sysCfg.mqtt_grptopic) != NULL); + fallbacktopic = (strstr(topicBuf, MQTTClient) != NULL); type = strrchr(topicBuf, '/') +1; // Last part of received topic is always the command (type) index = 1; @@ -948,6 +959,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) payload = 9; } do_cmnd_power(index, payload); + fallbacktopic = 0; return; } else if (!strcmp_P(type,PSTR("STATUS"))) { @@ -955,6 +967,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) payload = 99; } publish_status(payload); + fallbacktopic = 0; return; } else if ((sysCfg.module != MOTOR) && !strcmp_P(type,PSTR("POWERONSTATE"))) { @@ -1035,7 +1048,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } if (12 == index) { // stop_flash_rotate stop_flash_rotate = payload; - CFG_Save(stop_flash_rotate); + CFG_Save(2); } } } @@ -1275,11 +1288,15 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) snprintf_P(svalue, sizeof(svalue), PSTR("{\"FlashMode\":%d}"), ESP.getFlashChipMode()); } else if (!strcmp_P(type,PSTR("UPGRADE")) || !strcmp_P(type,PSTR("UPLOAD"))) { - if (1 == payload) { + // Check if the payload is numerically 1, and had no trailing chars. + // e.g. "1foo" or "1.2.3" could fool us. + // Check if the version we have been asked to upgrade to is higher than our current version. + // We also need at least 3 chars to make a valid version number string. + if (((1 == data_len) && (1 == payload)) || ((data_len >= 3) && newerVersion(dataBuf))) { otaflag = 3; snprintf_P(svalue, sizeof(svalue), PSTR("{\"Upgrade\":\"Version %s from %s\"}"), Version, sysCfg.otaUrl); } else { - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Upgrade\":\"Option 1 to upgrade\"}")); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"Upgrade\":\"Option 1 or >%s to upgrade\"}"), Version); } } else if (!strcmp_P(type,PSTR("OTAURL"))) { @@ -1573,6 +1590,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) if (svalue[0] != '\0') { mqtt_publish_topic_P(5, type, svalue); } + fallbacktopic = 0; } /********************************************************************************************/ diff --git a/sonoff/support.ino b/sonoff/support.ino index 464b15c3c7f7..3b5894a7b8ff 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -189,6 +189,50 @@ void mqttfy(byte option, char* str) } } +// Function to parse & check if version_str is newer than our currently installed version. +bool newerVersion(char* version_str) +{ + uint32_t version = 0; + uint8_t i = 0; + char *str_ptr; + char* version_dup = strdup(version_str); // Duplicate the version_str as strtok_r will modify it. + + if (!version_dup) { + return false; // Bail if we can't duplicate. Assume bad. + } + // Loop through the version string, splitting on '.' seperators. + for (char *str = strtok_r(version_dup, ".", &str_ptr); str && i < sizeof(VERSION); str = strtok_r(NULL, ".", &str_ptr), i++) { + int field = atoi(str); + // The fields in a version string can only range from 0-255. + if ((field < 0) || (field > 255)) { + free(version_dup); + return false; + } + // Shuffle the accumulated bytes across, and add the new byte. + version = (version << 8) + field; + // Check alpha delimiter after 1.2.3 only + if ((2 == i) && isalpha(str[strlen(str)-1])) { + field = str[strlen(str)-1] & 0x1f; + version = (version << 8) + field; + i++; + } + } + free(version_dup); // We no longer need this. + // A version string should have 2-4 fields. e.g. 1.2, 1.2.3, or 1.2.3a (= 1.2.3.1). + // If not, then don't consider it a valid version string. + if ((i < 2) || (i > sizeof(VERSION))) { + return false; + } + // Keep shifting the parsed version until we hit the maximum number of tokens. + // VERSION stores the major number of the version in the most significant byte of the uint32_t. + while (i < sizeof(VERSION)) { + version <<= 8; + i++; + } + // Now we should have a fully constructed version number in uint32_t form. + return (version > VERSION); +} + /*********************************************************************************************\ * Wifi \*********************************************************************************************/ diff --git a/sonoff/xdrv_snfled.ino b/sonoff/xdrv_snfled.ino index ff098dfeed38..fcb3256b9ccf 100644 --- a/sonoff/xdrv_snfled.ino +++ b/sonoff/xdrv_snfled.ino @@ -152,19 +152,15 @@ boolean sl_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_le { boolean serviced = true; boolean coldim = false; - char *p; if (!strcmp_P(type,PSTR("COLOR"))) { - uint8_t my_color[5]; + uint8_t my_color[2]; + char *p; if (4 == data_len) { - char ccold[3], cwarm[3]; - memcpy(ccold, dataBufUc, 2); - ccold[2] = '\0'; - memcpy(cwarm, dataBufUc + 2, 2); - cwarm[2] = '\0'; - my_color[0] = strtol(ccold, &p, 16); - my_color[1] = strtol(cwarm, &p, 16); - uint16_t temp = my_color[0]; + uint16_t temp = strtol(dataBufUc, &p, 16); + my_color[1] = temp & 0xFF; // Warm + temp >>= 8; + my_color[0] = temp & 0xFF; // Cold if (temp < my_color[1]) { temp = my_color[1]; }