diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index 62c28b7ed..17df37b0c 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -12,6 +12,7 @@ * Change default CFG_HOLDER from 0x20161209 to 4617 (=0x1209) - no impact on default upgrades * Fix Pzem004T checksum error * Fix KNX bug when doing reply of sensors values + * Fix rules induced LWT message * * 5.14.0b * Add Console Commands to send KNX Commands diff --git a/sonoff/settings.h b/sonoff/settings.h index 4704d598c..31d139b44 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -318,6 +318,29 @@ struct XDRVMAILBOX { char *data; } XdrvMailbox; +#define MAX_RULES_FLAG 5 // Number of bits used in RulesBitfield (tricky I know...) +typedef union { // Restricted by MISRA-C Rule 18.4 but so usefull... + uint16_t data; // Allow bit manipulation + struct { + uint16_t system_boot : 1; + uint16_t time_init : 1; + uint16_t time_set : 1; + uint16_t mqtt_connected : 1; + uint16_t mqtt_disconnected : 1; + uint16_t spare05 : 1; + uint16_t spare06 : 1; + uint16_t spare07 : 1; + uint16_t spare08 : 1; + uint16_t spare09 : 1; + uint16_t spare10 : 1; + uint16_t spare11 : 1; + uint16_t spare12 : 1; + uint16_t spare13 : 1; + uint16_t spare14 : 1; + uint16_t spare15 : 1; + }; +} RulesBitfield; + // See issue https://github.com/esp8266/Arduino/issues/2913 #ifdef USE_ADC_VCC ADC_MODE(ADC_VCC); // Set ADC input for Power Supply Voltage usage diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index e5ad17e7a..0f56d1492 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -181,6 +181,7 @@ uint8_t light_type = 0; // Light types bool pwm_present = false; // Any PWM channel configured with SetOption15 0 boolean mdns_begun = false; uint8_t ntp_force_sync = 0; // Force NTP sync +RulesBitfield rules_flag; char my_version[33]; // Composed version string char my_hostname[33]; // Composed Wifi hostname diff --git a/sonoff/support.ino b/sonoff/support.ino index 8e874f210..9eb808553 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -1754,11 +1754,10 @@ void RtcSecond() GetTime(0).c_str(), GetTime(2).c_str(), GetTime(3).c_str()); AddLog(LOG_LEVEL_DEBUG); if (local_time < 1451602800) { // 2016-01-01 - strncpy_P(mqtt_data, PSTR("{\"Time\":{\"Initialized\":1}}"), sizeof(mqtt_data)); + rules_flag.time_init = 1; } else { - strncpy_P(mqtt_data, PSTR("{\"Time\":{\"Set\":1}}"), sizeof(mqtt_data)); + rules_flag.time_set = 1; } - XdrvRulesProcess(); } else { ntp_sync_minute++; // Try again in next minute } diff --git a/sonoff/xdrv_01_mqtt.ino b/sonoff/xdrv_01_mqtt.ino index 7a2c5e666..a860e6717 100644 --- a/sonoff/xdrv_01_mqtt.ino +++ b/sonoff/xdrv_01_mqtt.ino @@ -315,8 +315,7 @@ void MqttDisconnected(int state) snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CONNECT_FAILED_TO " %s:%d, rc %d. " D_RETRY_IN " %d " D_UNIT_SECOND), Settings.mqtt_host, Settings.mqtt_port, state, mqtt_retry_counter); AddLog(LOG_LEVEL_INFO); - strncpy_P(mqtt_data, PSTR("{\"MQTT\":{\"Disconnected\":1}}"), sizeof(mqtt_data)); - XdrvRulesProcess(); + rules_flag.mqtt_disconnected = 1; } void MqttConnected() @@ -368,13 +367,11 @@ void MqttConnected() tele_period = Settings.tele_period -9; } status_update_timer = 2; - strncpy_P(mqtt_data, PSTR("{\"System\":{\"Boot\":1}}"), sizeof(mqtt_data)); - XdrvRulesProcess(); + rules_flag.system_boot = 1; XdrvCall(FUNC_MQTT_INIT); } mqtt_initial_connection_state = 0; - strncpy_P(mqtt_data, PSTR("{\"MQTT\":{\"Connected\":1}}"), sizeof(mqtt_data)); - XdrvRulesProcess(); + rules_flag.mqtt_connected = 1; } #ifdef USE_MQTT_TLS diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index dd46e32d5..ed849011d 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -339,11 +339,11 @@ bool RuleSetProcess(byte rule_set, String &event_saved) /*******************************************************************************************/ -bool RulesProcess() +bool RulesProcessEvent(char *json_event) { bool serviced = false; - String event_saved = mqtt_data; + String event_saved = json_event; event_saved.toUpperCase(); for (byte i = 0; i < MAX_RULE_SETS; i++) { @@ -354,8 +354,14 @@ bool RulesProcess() return serviced; } +bool RulesProcess() +{ + return RulesProcessEvent(mqtt_data); +} + void RulesInit() { + rules_flag.data = 0; for (byte i = 0; i < MAX_RULE_SETS; i++) { if (Settings.rules[i][0] == '\0') { bitWrite(Settings.rule_enabled, i, 0); @@ -368,19 +374,21 @@ void RulesInit() void RulesEvery50ms() { if (Settings.rule_enabled) { // Any rule enabled + char json_event[120]; + 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(); + snprintf_P(json_event, sizeof(json_event), PSTR("{\"Power%d\":{\"State\":%d}}"), i +1, new_state); + RulesProcessEvent(json_event); } } } rules_old_power = rules_new_power; } - else if(event_data[0]) { + else if (event_data[0]) { char *event; char *parameter; event = strtok_r(event_data, "=", ¶meter); // event_data = fanspeed=10 @@ -391,13 +399,34 @@ void RulesEvery50ms() } else { parameter = event + strlen(event); // '\0' } - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"Event\":{\"%s\":\"%s\"}}"), event, parameter); + snprintf_P(json_event, sizeof(json_event), PSTR("{\"Event\":{\"%s\":\"%s\"}}"), event, parameter); event_data[0] ='\0'; - RulesProcess(); + RulesProcessEvent(json_event); } else { event_data[0] ='\0'; } } + else if (rules_flag.data) { + uint16_t mask = 1; + for (byte i = 0; i < MAX_RULES_FLAG; i++) { + if (rules_flag.data & mask) { + rules_flag.data ^= mask; + json_event[0] = '\0'; + switch (i) { + case 0: strncpy_P(json_event, PSTR("{\"System\":{\"Boot\":1}}"), sizeof(json_event)); break; + case 1: strncpy_P(json_event, PSTR("{\"Time\":{\"Initialized\":1}}"), sizeof(json_event)); break; + case 2: strncpy_P(json_event, PSTR("{\"Time\":{\"Set\":1}}"), sizeof(json_event)); break; + case 3: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Connected\":1}}"), sizeof(json_event)); break; + case 4: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Disconnected\":1}}"), sizeof(json_event)); break; + } + if (json_event[0]) { + RulesProcessEvent(json_event); + break; // Only service one event within 50mS + } + } + mask <<= 1; + } + } else { rules_quota++; if (rules_quota &1) { // Every 100 ms @@ -419,12 +448,14 @@ void RulesEvery50ms() void RulesEverySecond() { if (Settings.rule_enabled) { // Any rule enabled + char json_event[120]; + for (byte i = 0; i < MAX_RULE_TIMERS; i++) { if (rules_timer[i] != 0L) { // Timer active? if (TimeReached(rules_timer[i])) { // Timer finished? rules_timer[i] = 0L; // Turn off this timer - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"Rules\":{\"Timer\":%d}}"), i +1); - RulesProcess(); + snprintf_P(json_event, sizeof(json_event), PSTR("{\"Rules\":{\"Timer\":%d}}"), i +1); + RulesProcessEvent(json_event); } } }