diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index f534c9bbf..9b6207e39 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,8 +1,11 @@ /* 5.13.1a * Change user_config.h otaurl to http://sonoff.maddox.co.uk/tasmota/sonoff.bin (#2588, #2602) * Fix compile error when ADC is enabled and Rules are disabled (#2608) + * Fix rule power trigger when no backlog command is used (#2613) * Fix several timer data input and output errors (#2597, #2620) + * Fix KNX config error (#2628) * Add Portuguese in Brazil language file + * Add rule state test for On/Off in addition to 0/1 (#2613) * Updated Italian language file (#2618) * * 5.13.1 20180501 diff --git a/sonoff/i18n.h b/sonoff/i18n.h index f50242d86..4bb42331f 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -486,6 +486,12 @@ const char kPrefixes[3][PRFX_MAX_STRING_LENGTH] PROGMEM = { // support.ino static const char kMonthNames[] = D_MONTH3LIST; +const char kOptionOff[] PROGMEM = "OFF|" D_OFF "|" D_FALSE "|" D_STOP "|" D_CELSIUS ; +const char kOptionOn[] PROGMEM = "ON|" D_ON "|" D_TRUE "|" D_START "|" D_FAHRENHEIT "|" D_USER ; +const char kOptionToggle[] PROGMEM = "TOGGLE|" D_TOGGLE "|" D_ADMIN ; +const char kOptionBlink[] PROGMEM = "BLINK|" D_BLINK ; +const char kOptionBlinkOff[] PROGMEM = "BLINKOFF|" D_BLINKOFF ; + // webserver.ino #ifdef USE_WEBSERVER const char HTTP_SNS_TEMP[] PROGMEM = "%s{s}%s " D_TEMPERATURE "{m}%s°%c{e}"; // {s} = , {m} = , {e} = diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index e6565c286..5d70e781e 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -96,12 +96,6 @@ const char kTasmotaCommands[] PROGMEM = D_CMND_TELEPERIOD "|" D_CMND_RESTART "|" D_CMND_RESET "|" D_CMND_TIMEZONE "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|" D_CMND_I2CSCAN "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE "|" D_CMND_SERIALDELIMITER; -const char kOptionOff[] PROGMEM = "OFF|" D_OFF "|" D_FALSE "|" D_STOP "|" D_CELSIUS ; -const char kOptionOn[] PROGMEM = "ON|" D_ON "|" D_TRUE "|" D_START "|" D_FAHRENHEIT "|" D_USER ; -const char kOptionToggle[] PROGMEM = "TOGGLE|" D_TOGGLE "|" D_ADMIN ; -const char kOptionBlink[] PROGMEM = "BLINK|" D_BLINK ; -const char kOptionBlinkOff[] PROGMEM = "BLINKOFF|" D_BLINKOFF ; - // Global variables int baudrate = APP_BAUDRATE; // Serial interface baud rate SerialConfig serial_config = SERIAL_8N1; // Serial interface configuration 8 data bits, No parity, 1 stop bit @@ -436,21 +430,8 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } backlog_delay = MIN_BACKLOG_DELAY; // Reset backlog delay - if ((GetCommandCode(command, sizeof(command), dataBuf, kOptionOff) >= 0) || !strcasecmp(dataBuf, Settings.state_text[0])) { - payload = 0; - } - if ((GetCommandCode(command, sizeof(command), dataBuf, kOptionOn) >= 0) || !strcasecmp(dataBuf, Settings.state_text[1])) { - payload = 1; - } - if ((GetCommandCode(command, sizeof(command), dataBuf, kOptionToggle) >= 0) || !strcasecmp(dataBuf, Settings.state_text[2])) { - payload = 2; - } - if (GetCommandCode(command, sizeof(command), dataBuf, kOptionBlink) >= 0) { - payload = 3; - } - if (GetCommandCode(command, sizeof(command), dataBuf, kOptionBlinkOff) >= 0) { - payload = 4; - } + int temp_payload = GetStateNumber(dataBuf); + if (temp_payload > -1) { payload = temp_payload; } // snprintf_P(log_data, sizeof(log_data), PSTR("RSLT: Payload %d, Payload16 %d"), payload, payload16); // AddLog(LOG_LEVEL_DEBUG); @@ -462,12 +443,23 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) bl_pointer--; char *blcommand = strtok(dataBuf, ";"); while ((blcommand != NULL) && (backlog_index != bl_pointer)) { - backlog[backlog_index] = String(blcommand); - backlog_index++; - if (backlog_index >= MAX_BACKLOG) backlog_index = 0; + while(true) { + while ((*blcommand != '\0') && (isblank(*blcommand))) { blcommand++; } // Trim leading spaces + if (!strncasecmp_P(blcommand, PSTR(D_CMND_BACKLOG), strlen(D_CMND_BACKLOG))) { + blcommand += strlen(D_CMND_BACKLOG); // Skip unnecessary command Backlog + } else { + break; + } + } + if (*blcommand != '\0') { + backlog[backlog_index] = String(blcommand); + backlog_index++; + if (backlog_index >= MAX_BACKLOG) backlog_index = 0; + } blcommand = strtok(NULL, ";"); } - snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_APPENDED); +// snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_APPENDED); + mqtt_data[0] = '\0'; } else { uint8_t blflag = (backlog_pointer == backlog_index); backlog_pointer = backlog_index; diff --git a/sonoff/support.ino b/sonoff/support.ino index d86f9ccce..8f18c5a55 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -447,6 +447,29 @@ int GetCommandCode(char* destination, size_t destination_size, const char* needl return result; } +int GetStateNumber(char *state_text) +{ + char command[CMDSZ]; + int state_number = -1; + + if ((GetCommandCode(command, sizeof(command), state_text, kOptionOff) >= 0) || !strcasecmp(state_text, Settings.state_text[0])) { + state_number = 0; + } + else if ((GetCommandCode(command, sizeof(command), state_text, kOptionOn) >= 0) || !strcasecmp(state_text, Settings.state_text[1])) { + state_number = 1; + } + else if ((GetCommandCode(command, sizeof(command), state_text, kOptionToggle) >= 0) || !strcasecmp(state_text, Settings.state_text[2])) { + state_number = 2; + } + else if (GetCommandCode(command, sizeof(command), state_text, kOptionBlink) >= 0) { + state_number = 3; + } + else if (GetCommandCode(command, sizeof(command), state_text, kOptionBlinkOff) >= 0) { + state_number = 4; + } + return state_number; +} + void SetSerialBaudrate(int baudrate) { Settings.baudrate = baudrate / 1200; diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino index 9c9be2a42..f0c3fc6e6 100644 --- a/sonoff/webserver.ino +++ b/sonoff/webserver.ino @@ -1407,7 +1407,7 @@ void HandlePreflightRequest() void HandleHttpCommand() { if (HttpUser()) { return; } - char svalue[INPUT_BUFFER_SIZE]; // big to serve Backlog + char svalue[INPUT_BUFFER_SIZE]; // Large to serve Backlog AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_COMMAND)); @@ -1477,7 +1477,7 @@ void HandleConsole() void HandleAjaxConsoleRefresh() { if (HttpUser()) { return; } - char svalue[INPUT_BUFFER_SIZE]; // big to serve Backlog + char svalue[INPUT_BUFFER_SIZE]; // Large to serve Backlog byte cflg = 1; byte counter = 0; // Initial start, should never be 0 again diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index b07bea5b7..0690c61b5 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -44,6 +44,7 @@ * on power1#state=1 do color 001000 endon * on button1#state do publish cmnd/ring2/power %value% endon on button2#state do publish cmnd/strip1/power %value% endon * on switch1#state do power2 %value% endon + * on analog#a0div10 do publish cmnd/ring2/dimmer %value% endon * * Notes: * Spaces after , around and before are mandatory @@ -80,7 +81,8 @@ const char kRulesCommands[] PROGMEM = D_CMND_RULE "|" D_CMND_RULETIMER "|" D_CMN String rules_event_value; unsigned long rules_timer[MAX_RULE_TIMERS] = { 0 }; uint8_t rules_quota = 0; -long rules_power = -1; +long rules_new_power = -1; +long rules_old_power = -1; uint32_t rules_triggers = 0; uint8_t rules_trigger_count = 0; @@ -172,11 +174,16 @@ bool RulesRuleMatch(String &event, String &rule) } } - String tmp_value = "none"; + char tmp_value[CMDSZ] = { 0 }; double rule_value = 0; if (pos > 0) { - tmp_value = rule_name.substring(pos + 1); // "0.100" - rule_value = CharToDouble((char*)tmp_value.c_str()); // 0.1 - This saves 9k code over toFLoat()! + snprintf(tmp_value, sizeof(tmp_value), rule_name.substring(pos + 1).c_str()); + int temp_value = GetStateNumber(tmp_value); + if (temp_value > -1) { + rule_value = temp_value; + } else { + rule_value = CharToDouble((char*)tmp_value); // 0.1 - This saves 9k code over toFLoat()! + } rule_name = rule_name.substring(0, pos); // "CURRENT" } @@ -188,9 +195,9 @@ bool RulesRuleMatch(String &event, String &rule) double value = 0; const char* str_value = root[rule_task][rule_name]; -// snprintf_P(log_data, sizeof(log_data), PSTR("RUL: Task %s, Name %s, Value %s, TrigCnt %d, TrigSt %d, Source %s, Json %s"), -// rule_task.c_str(), rule_name.c_str(), tmp_value.c_str(), rules_trigger_count, bitRead(rules_triggers, rules_trigger_count), event.c_str(), (str_value) ? str_value : "none"); -// AddLog(LOG_LEVEL_DEBUG); +//snprintf_P(log_data, sizeof(log_data), PSTR("RUL: Task %s, Name %s, Value |%s|, TrigCnt %d, TrigSt %d, Source %s, Json %s"), +// rule_task.c_str(), rule_name.c_str(), tmp_value, rules_trigger_count, bitRead(rules_triggers, rules_trigger_count), event.c_str(), (str_value) ? str_value : "none"); +//AddLog(LOG_LEVEL_DEBUG); if (!root[rule_task][rule_name].success()) { return false; } // No value but rule_name is ok @@ -239,6 +246,8 @@ bool RulesProcess() char vars[RULES_MAX_VARS][10] = { 0 }; char stemp[10]; + delay(0); // Prohibit possible loop software watchdog + if (!Settings.flag.rules_enabled) { return serviced; } // Not enabled if (!strlen(Settings.rules)) { return serviced; } // No rules @@ -266,8 +275,8 @@ bool RulesProcess() String commands = rules.substring(pevt +4, plen); // "Backlog Dimmer 10;Color 100000" plen += 6; -// snprintf_P(log_data, sizeof(log_data), PSTR("RUL: Trigger |%s|, Commands |%s|"), event_trigger.c_str(), commands.c_str()); -// AddLog(LOG_LEVEL_DEBUG); +//snprintf_P(log_data, sizeof(log_data), PSTR("RUL: Trigger |%s|, Commands |%s|"), event_trigger.c_str(), commands.c_str()); +//AddLog(LOG_LEVEL_DEBUG); rules_event_value = ""; String event = event_saved; @@ -277,9 +286,9 @@ bool RulesProcess() ucommand.toUpperCase(); if (ucommand.startsWith("VAR")) { uint8_t idx = ucommand.charAt(3) - '1'; -// idx -= '1'; if ((idx >= 0) && (idx < RULES_MAX_VARS)) { snprintf(vars[idx], sizeof(vars[idx]), rules_event_value.c_str()); } } else { +// if (!ucommand.startsWith("BACKLOG")) { commands = "backlog " + commands; } // Always use Backlog to prevent power race condition commands.replace(F("%value%"), rules_event_value); for (byte i = 0; i < RULES_MAX_VARS; i++) { if (strlen(vars[i])) { @@ -316,40 +325,33 @@ void RulesInit() rules_teleperiod = 0; } -void RulesSetPower() -{ - if (Settings.flag.rules_enabled) { - uint16_t new_power = XdrvMailbox.index; - if (rules_power == -1) rules_power = new_power; - uint16_t old_power = rules_power; - rules_power = new_power; - for (byte i = 0; i < devices_present; i++) { - uint8_t new_state = new_power &1; - uint8_t old_state = old_power &1; - if (new_state != old_state) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"Power%d\":{\"State\":%d}}"), i +1, new_state); - RulesProcess(); - } - new_power >>= 1; - old_power >>= 1; - } - } -} - void RulesEvery50ms() { if (Settings.flag.rules_enabled) { - rules_quota++; - if (rules_quota &1) { // Every 100 ms - mqtt_data[0] = '\0'; - uint16_t tele_period_save = tele_period; - tele_period = 2; // Do not allow HA updates during next function call - XsnsNextCall(FUNC_JSON_APPEND); // ,"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089} - tele_period = tele_period_save; - if (strlen(mqtt_data)) { - mqtt_data[0] = '{'; // {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089} - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); - RulesProcess(); + if (rules_new_power != rules_old_power) { + if (rules_old_power != -1) { + for (byte i = 0; i < devices_present; i++) { + uint8_t new_state = (rules_new_power >> i) &1; + if (new_state != ((rules_old_power >> i) &1)) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"Power%d\":{\"State\":%d}}"), i +1, new_state); + RulesProcess(); + } + } + } + rules_old_power = rules_new_power; + } else { + rules_quota++; + if (rules_quota &1) { // Every 100 ms + mqtt_data[0] = '\0'; + uint16_t tele_period_save = tele_period; + tele_period = 2; // Do not allow HA updates during next function call + XsnsNextCall(FUNC_JSON_APPEND); // ,"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089} + tele_period = tele_period_save; + if (strlen(mqtt_data)) { + mqtt_data[0] = '{'; // {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089} + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); + RulesProcess(); + } } } } @@ -370,6 +372,11 @@ void RulesEverySecond() } } +void RulesSetPower() +{ + rules_new_power = XdrvMailbox.index; +} + void RulesTeleperiod() { rules_teleperiod = 1; @@ -459,15 +466,15 @@ boolean Xdrv10(byte function) case FUNC_INIT: RulesInit(); break; - case FUNC_SET_POWER: - RulesSetPower(); - break; case FUNC_EVERY_50_MSECOND: RulesEvery50ms(); break; case FUNC_EVERY_SECOND: RulesEverySecond(); break; + case FUNC_SET_POWER: + RulesSetPower(); + break; case FUNC_COMMAND: result = RulesCommand(); break;