diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino
index 86387a041..9b6207e39 100644
--- a/sonoff/_releasenotes.ino
+++ b/sonoff/_releasenotes.ino
@@ -1,9 +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;