5.2.3 20170630
* Change Sonoff Led color conversion code
* Fix SetOption12 handling
* Simplify auto configuration upgrade
* Add option Upgrade <version_number> to only upgrade to any higher
version (Old PR #213)
* Change FallbackTopic to cmnd/<MQTTClient>/<command> <parameter>
bypassing FullTopic and Prefix (#538)
This commit is contained in:
arendst 2017-06-30 17:54:19 +02:00
parent e914053041
commit ee883bdcb8
6 changed files with 122 additions and 32 deletions

View File

@ -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 ****

View File

@ -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 <version_number> to only upgrade to any higher version (Old PR #213)
* Change FallbackTopic to cmnd/<MQTTClient>/<command> <parameter> 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)

View File

@ -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();

View File

@ -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;
}
/********************************************************************************************/

View File

@ -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
\*********************************************************************************************/

View File

@ -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];
}