From 2cab0d053958c72ef55867df3fa22a515fb76ba7 Mon Sep 17 00:00:00 2001 From: Matteo Albinola Date: Tue, 10 Mar 2020 08:41:37 +0100 Subject: [PATCH 1/5] New command ShutterInvertWebButtons --- tasmota/i18n.h | 1 + tasmota/xdrv_01_webserver.ino | 2 +- tasmota/xdrv_27_shutter.ino | 22 +++++++++++++++++----- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/tasmota/i18n.h b/tasmota/i18n.h index f36f37977..8a0b210a8 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -542,6 +542,7 @@ #define D_CMND_SHUTTER_BUTTON "Button" #define D_CMND_SHUTTER_LOCK "Lock" #define D_CMND_SHUTTER_ENABLEENDSTOPTIME "EnableEndStopTime" +#define D_CMND_SHUTTER_INVERTWEBBUTTONS "InvertWebButtons" // Commands xdrv_32_hotplug.ino #define D_CMND_HOTPLUG "HotPlug" diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index 2dff240ad..7ca14894a 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -1164,7 +1164,7 @@ void HandleRoot(void) int32_t ShutterWebButton; if (ShutterWebButton = IsShutterWebButton(idx)) { WSContentSend_P(HTTP_DEVICE_CONTROL, 100 / devices_present, idx, - (set_button) ? SettingsText(SET_BUTTON1 + idx -1) : ((Settings.shutter_options[abs(ShutterWebButton)-1] & 2) /* is locked */ ? "-" : ((ShutterWebButton>0) ? "▲" : "▼")), + (set_button) ? SettingsText(SET_BUTTON1 + idx -1) : ((Settings.shutter_options[abs(ShutterWebButton)-1] & 2) /* is locked */ ? "-" : ((Settings.shutter_options[abs(ShutterWebButton)-1] & 8) /* invert web buttons */ ? ((ShutterWebButton>0) ? "▼" : "▲") : ((ShutterWebButton>0) ? "▲" : "▼"))), ""); continue; } diff --git a/tasmota/xdrv_27_shutter.ino b/tasmota/xdrv_27_shutter.ino index 9fa2f6589..cedf93e28 100644 --- a/tasmota/xdrv_27_shutter.ino +++ b/tasmota/xdrv_27_shutter.ino @@ -40,13 +40,13 @@ const char kShutterCommands[] PROGMEM = D_PRFX_SHUTTER "|" D_CMND_SHUTTER_OPEN "|" D_CMND_SHUTTER_CLOSE "|" D_CMND_SHUTTER_STOP "|" D_CMND_SHUTTER_POSITION "|" D_CMND_SHUTTER_OPENTIME "|" D_CMND_SHUTTER_CLOSETIME "|" D_CMND_SHUTTER_RELAY "|" D_CMND_SHUTTER_SETHALFWAY "|" D_CMND_SHUTTER_SETCLOSE "|" D_CMND_SHUTTER_INVERT "|" D_CMND_SHUTTER_CLIBRATION "|" - D_CMND_SHUTTER_MOTORDELAY "|" D_CMND_SHUTTER_FREQUENCY "|" D_CMND_SHUTTER_BUTTON "|" D_CMND_SHUTTER_LOCK "|" D_CMND_SHUTTER_ENABLEENDSTOPTIME; + D_CMND_SHUTTER_MOTORDELAY "|" D_CMND_SHUTTER_FREQUENCY "|" D_CMND_SHUTTER_BUTTON "|" D_CMND_SHUTTER_LOCK "|" D_CMND_SHUTTER_ENABLEENDSTOPTIME "|" D_CMND_SHUTTER_INVERTWEBBUTTONS; void (* const ShutterCommand[])(void) PROGMEM = { &CmndShutterOpen, &CmndShutterClose, &CmndShutterStop, &CmndShutterPosition, &CmndShutterOpenTime, &CmndShutterCloseTime, &CmndShutterRelay, &CmndShutterSetHalfway, &CmndShutterSetClose, &CmndShutterInvert, &CmndShutterCalibration , &CmndShutterMotorDelay, - &CmndShutterFrequency, &CmndShutterButton, &CmndShutterLock, &CmndShutterEnableEndStopTime}; + &CmndShutterFrequency, &CmndShutterButton, &CmndShutterLock, &CmndShutterEnableEndStopTime, &CmndShutterInvertWebButtons}; const char JSON_SHUTTER_POS[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Position\":%d,\"Direction\":%d,\"Target\":%d}"; const char JSON_SHUTTER_BUTTON[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Button%d\":%d}"; @@ -239,10 +239,10 @@ void ShutterInit(void) dtostrfd((float)Shutter.open_time[i] / 10 , 1, shutter_open_chr); char shutter_close_chr[10]; dtostrfd((float)Shutter.close_time[i] / 10, 1, shutter_close_chr); - AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Shutter %d (Relay:%d): Init. Pos: %d [%d %%], Open Vel.: 100, Close Vel.: %d , Max Way: %d, Opentime %s [s], Closetime %s [s], CoeffCalc: c0: %d, c1 %d, c2: %d, c3: %d, c4: %d, binmask %d, is inverted %d, is locked %d, end stop time enabled %d, shuttermode %d, motordelay %d"), + AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Shutter %d (Relay:%d): Init. Pos: %d [%d %%], Open Vel.: 100, Close Vel.: %d , Max Way: %d, Opentime %s [s], Closetime %s [s], CoeffCalc: c0: %d, c1 %d, c2: %d, c3: %d, c4: %d, binmask %d, is inverted %d, is locked %d, end stop time enabled %d, webButtons inverted %d, shuttermode %d, motordelay %d"), i+1, Settings.shutter_startrelay[i], Shutter.real_position[i], Settings.shutter_position[i], Shutter.close_velocity[i], Shutter.open_max[i], shutter_open_chr, shutter_close_chr, Settings.shuttercoeff[0][i], Settings.shuttercoeff[1][i], Settings.shuttercoeff[2][i], Settings.shuttercoeff[3][i], Settings.shuttercoeff[4][i], - Shutter.mask, (Settings.shutter_options[i]&1) ? 1 : 0, (Settings.shutter_options[i]&2) ? 1 : 0, (Settings.shutter_options[i]&4) ? 1 : 0, Shutter.mode, Shutter.motordelay[i]); + Shutter.mask, (Settings.shutter_options[i]&1) ? 1 : 0, (Settings.shutter_options[i]&2) ? 1 : 0, (Settings.shutter_options[i]&4) ? 1 : 0, (Settings.shutter_options[i]&8) ? 1 : 0, Shutter.mode, Shutter.motordelay[i]); } else { // terminate loop at first INVALID shutter. @@ -549,7 +549,7 @@ void ShutterButtonHandler(void) } else { Button.press_counter[button_index] = (Button.window_timer[button_index]) ? Button.press_counter[button_index] +1 : 1; // Button.window_timer[button_index] = (Button.press_counter[button_index]==1) ? loops_per_second / 2 : loops_per_second; // 0.5 second multi press window after 1st press, 1s afterwards - Button.window_timer[button_index] = (loops_per_second >> 2) * 3; // 0.75 second multi press window + Button.window_timer[button_index] = (loops_per_second >> 2) * 3; // 0.75 second multi press window } } blinks = 201; @@ -1143,6 +1143,18 @@ void CmndShutterEnableEndStopTime(void) { } } +void CmndShutterInvertWebButtons(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { + if (XdrvMailbox.payload == 0) { + Settings.shutter_options[XdrvMailbox.index -1] &= ~(8); + } else if (XdrvMailbox.payload == 1) { + Settings.shutter_options[XdrvMailbox.index -1] |= (8); + } + ResponseCmndIdxNumber((Settings.shutter_options[XdrvMailbox.index -1] & 8) ? 1 : 0); + } +} + /*********************************************************************************************\ * Interface \*********************************************************************************************/ From fc29e31d208174645030e814f97b1f4091d7bdb1 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 12 Mar 2020 09:14:30 +0100 Subject: [PATCH 2/5] Change to Tasmota freeze stage for development... solving issue https://github.com/arendst/Tasmota/issues/7879 Tests of the freezed stage core shows (so far) no issues. With regard to the new release version 8.2. with gzip support a good test in advance to verify the stability of the upcoming core 2.7. The core 2.7. will no longer change significantly to the one used here. --- platformio.ini | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/platformio.ini b/platformio.ini index 198e47264..6b9459388 100755 --- a/platformio.ini +++ b/platformio.ini @@ -101,16 +101,15 @@ build_flags = -DUSE_IR_REMOTE_FULL -DDECODE_PRONTO=false -DSEND_PRONTO=false [core_active] -platform = ${core_2_6_1.platform} -platform_packages = ${core_2_6_1.platform_packages} -build_flags = ${core_2_6_1.build_flags} +platform = ${tasmota_core_stage.platform} +platform_packages = ${tasmota_core_stage.platform_packages} +build_flags = ${tasmota_core_stage.build_flags} -[core_2_6_1] -; *** Esp8266 core for Arduino version 2.6.1 -platform = espressif8266@2.3.0 -platform_packages = +[tasmota_core_stage] +; *** Esp8266 core for Arduino version stable beta +platform = espressif8266@2.3.3 +platform_packages = framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#372a3ec297dfe8501bed1ec4552244695b5e8ced build_flags = ${esp82xx_defaults.build_flags} - -Wl,-Teagle.flash.1m.ld -DBEARSSL_SSL_BASIC ; NONOSDK22x_190703 = 2.2.2-dev(38a443e) -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703 From 057ff372638b4d9723ec0e7ccda1bfa6d52ce989 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 12 Mar 2020 12:11:33 +0100 Subject: [PATCH 3/5] Add function KeyTopicActive(key) Add function KeyTopicActive(key) --- tasmota/xdrv_02_mqtt.ino | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tasmota/xdrv_02_mqtt.ino b/tasmota/xdrv_02_mqtt.ino index c766ab247..2a15c33df 100644 --- a/tasmota/xdrv_02_mqtt.ino +++ b/tasmota/xdrv_02_mqtt.ino @@ -719,6 +719,16 @@ bool ButtonTopicActive(void) return ((strlen(key_topic) != 0) && strcmp(key_topic, "0")); } +bool KeyTopicActive(uint32_t key) +{ + // key = 0 - Button topic + // key = 1 - Switch topic + key &= 1; + char key_topic[TOPSZ]; + Format(key_topic, SettingsText(SET_MQTT_BUTTON_TOPIC + key), sizeof(key_topic)); + return ((strlen(key_topic) != 0) && strcmp(key_topic, "0")); +} + /*********************************************************************************************\ * Commands \*********************************************************************************************/ From 4eaec27124356ba475d2a0e020e53f3a7a66d766 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 12 Mar 2020 19:44:46 +0100 Subject: [PATCH 4/5] Change PR template to core tasmota_core_stage --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a2fa5648e..2839ba02b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,6 +6,6 @@ - [ ] The pull request is done against the latest dev branch - [ ] Only relevant files were touched - [ ] Only one feature/fix was added per PR. - - [ ] The code change is tested and works on core 2.6.1 + - [ ] The code change is tested and works on core Tasmota_core_stage - [ ] The code change pass travis tests. **Your PR cannot be merged unless tests pass** - [ ] I accept the [CLA](https://github.com/arendst/Tasmota/blob/development/CONTRIBUTING.md#contributor-license-agreement-cla). From 956f56e0e17f89c79455d1ebcd4c45f477799501 Mon Sep 17 00:00:00 2001 From: Federico Leoni Date: Thu, 12 Mar 2020 16:48:44 -0300 Subject: [PATCH 5/5] Update xdrv_12_home_assistant.ino --- tasmota/xdrv_12_home_assistant.ino | 425 ++++++++++++++++++----------- 1 file changed, 265 insertions(+), 160 deletions(-) diff --git a/tasmota/xdrv_12_home_assistant.ino b/tasmota/xdrv_12_home_assistant.ino index 7da0ad380..900df6541 100644 --- a/tasmota/xdrv_12_home_assistant.ino +++ b/tasmota/xdrv_12_home_assistant.ino @@ -26,96 +26,104 @@ const char kHAssJsonSensorTypes[] PROGMEM = D_JSON_TEMPERATURE "|" D_JSON_PRESSURE "|" D_JSON_PRESSUREATSEALEVEL "|" D_JSON_APPARENT_POWERUSAGE "|Battery|" D_JSON_CURRENT "|" D_JSON_DISTANCE "|" D_JSON_FREQUENCY "|" D_JSON_HUMIDITY "|" D_JSON_ILLUMINANCE "|" D_JSON_MOISTURE "|PB0.3|PB0.5|PB1|PB2.5|PB5|PB10|PM1|PM2.5|PM10|" D_JSON_POWERFACTOR "|" D_JSON_POWERUSAGE "|" - D_JSON_REACTIVE_POWERUSAGE "|" D_JSON_TODAY "|" D_JSON_TOTAL "|" D_JSON_VOLTAGE "|" D_JSON_WEIGHT "|" D_JSON_YESTERDAY; + D_JSON_REACTIVE_POWERUSAGE "|" D_JSON_TODAY "|" D_JSON_TOTAL "|" D_JSON_VOLTAGE "|" D_JSON_WEIGHT "|" D_JSON_YESTERDAY + D_JSON_CO2 "|" D_JSON_ECO2 "|" D_JSON_TVOC; const char kHAssJsonSensorUnits[] PROGMEM = "|||" - "W|%|A|Cm|Hz|%|LX|" - "%|ppd|ppd|ppd|ppd|ppd|ppd|µg/m³|µg/m³|µg/m³||W|" - "W|KWh|KWh|V|Kg|KWh"; + "VA|%|A|Cm|Hz|%|LX|" + "%|ppd|ppd|ppd|ppd|ppd|ppd|µg/m³|µg/m³|µg/m³|Cos φ|W|" + "VAr|kWh|kWh|V|Kg|kWh|" + "ppm|ppm|ppb|"; const char kHAssJsonSensorDevCla[] PROGMEM = "dev_cla\":\"temperature|dev_cla\":\"pressure|dev_cla\":\"pressure|" "dev_cla\":\"power|dev_cla\":\"battery|ic\":\"mdi:alpha-a-circle-outline|ic\":\"mdi:leak|ic\":\"mdi:current-ac|dev_cla\":\"humidity|dev_cla\":\"illuminance|" "ic\":\"mdi:cup-water|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|" "ic\":\"mdi:air-filter|ic\":\"mdi:air-filter|ic\":\"mdi:air-filter|ic\":\"mdi:alpha-f-circle-outline|dev_cla\":\"power|" - "dev_cla\":\"power|dev_cla\":\"power|dev_cla\":\"power|ic\":\"mdi:alpha-v-circle-outline|ic\":\"mdi:scale|dev_cla\":\"power"; + "dev_cla\":\"power|dev_cla\":\"power|dev_cla\":\"power|ic\":\"mdi:alpha-v-circle-outline|ic\":\"mdi:scale|dev_cla\":\"power" + "ic\":\"mdi:periodic-table-co2|ic\":\"mdi:air-filter|ic\":\"mdi:periodic-table-co2"; // List of sensors ready for discovery const char HASS_DISCOVER_SENSOR[] PROGMEM = - ",\"unit_of_meas\":\"%s\",\"%s\"," // unit of measure and class (or icon) - "\"frc_upd\":true," // force update for better graph representation - "\"val_tpl\":\"{{value_json['%s']['%s']"; // "COUNTER":{"C1":0} -> {{ value_json['COUNTER'].['C1'] + ",\"unit_of_meas\":\"%s\",\"%s\"," // unit of measure and class (or icon) + "\"frc_upd\":true," // force update for better graph representation + "\"val_tpl\":\"{{value_json['%s']['%s']"; // "COUNTER":{"C1":0} -> {{ value_json['COUNTER'].['C1'] const char HASS_DISCOVER_BASE[] PROGMEM = - "{\"name\":\"%s\"," // dualr2 1 - "\"stat_t\":\"%s\"," // stat/dualr2/RESULT (implies "\"optimistic\":\"false\",") - "\"avty_t\":\"%s\"," // tele/dualr2/LWT - "\"pl_avail\":\"" D_ONLINE "\"," // Online - "\"pl_not_avail\":\"" D_OFFLINE "\""; // Offline + "{\"name\":\"%s\"," // dualr2 1 + "\"stat_t\":\"%s\"," // stat/dualr2/RESULT (implies "\"optimistic\":\"false\",") + "\"avty_t\":\"%s\"," // tele/dualr2/LWT + "\"pl_avail\":\"" D_ONLINE "\"," // Online + "\"pl_not_avail\":\"" D_OFFLINE "\""; // Offline const char HASS_DISCOVER_RELAY[] PROGMEM = - ",\"cmd_t\":\"%s\"," // cmnd/dualr2/POWER2 - "\"val_tpl\":\"{{value_json.%s}}\"," // POWER2 - "\"pl_off\":\"%s\"," // OFF - "\"pl_on\":\"%s\""; // ON + ",\"cmd_t\":\"%s\"," // cmnd/dualr2/POWER2 + "\"val_tpl\":\"{{value_json.%s}}\"," // POWER2 + "\"pl_off\":\"%s\"," // OFF + "\"pl_on\":\"%s\""; // ON -const char HASS_DISCOVER_BUTTON_TOGGLE[] PROGMEM = - ",\"value_template\":\"{%%if is_state(entity_id,\\\"off\\\")-%%}ON{%%-endif%%}\"," // STATE - "\"off_delay\":1"; // HAss has no support for TOGGLE, fake it by resetting to OFF after 1s - -const char HASS_DISCOVER_BUTTON_SWITCH_ONOFF[] PROGMEM = - ",\"value_template\":\"{{value_json.%s}}\"," // STATE - "\"frc_upd\":true," // In ON/OFF case, enable force_update to make automations work - "\"pl_on\":\"%s\"," // ON - "\"pl_off\":\"%s\""; // OFF +const char HASS_DISCOVER_BIN_SWITCH[] PROGMEM = + ",\"val_tpl\":\"{{value_json.%s}}\"," // STATE + "\"frc_upd\":true," // In ON/OFF case, enable force_update to make automations work + "\"pl_on\":\"%s\"," // ON + "\"pl_off\":\"%s\""; // OFF const char HASS_DISCOVER_LIGHT_DIMMER[] PROGMEM = - ",\"bri_cmd_t\":\"%s\"," // cmnd/led2/Dimmer - "\"bri_stat_t\":\"%s\"," // stat/led2/RESULT - "\"bri_scl\":100," // 100% - "\"on_cmd_type\":\"%s\"," // power on (first), power on (last), no power on (brightness) - "\"bri_val_tpl\":\"{{value_json." D_CMND_DIMMER "}}\""; + ",\"bri_cmd_t\":\"%s\"," // cmnd/led2/Dimmer + "\"bri_stat_t\":\"%s\"," // stat/led2/RESULT + "\"bri_scl\":100," // 100% + "\"on_cmd_type\":\"%s\"," // power on (first), power on (last), no power on (brightness) + "\"bri_val_tpl\":\"{{value_json." D_CMND_DIMMER "}}\""; const char HASS_DISCOVER_LIGHT_COLOR[] PROGMEM = - ",\"rgb_cmd_t\":\"%s2\"," // cmnd/led2/Color2 - "\"rgb_stat_t\":\"%s\"," // stat/led2/RESULT - "\"rgb_val_tpl\":\"{{value_json." D_CMND_COLOR ".split(',')[0:3]|join(',')}}\""; + ",\"rgb_cmd_t\":\"%s2\"," // cmnd/led2/Color2 + "\"rgb_stat_t\":\"%s\"," // stat/led2/RESULT + "\"rgb_val_tpl\":\"{{value_json." D_CMND_COLOR ".split(',')[0:3]|join(',')}}\""; const char HASS_DISCOVER_LIGHT_WHITE[] PROGMEM = - ",\"whit_val_cmd_t\":\"%s\"," // cmnd/led2/White - "\"whit_val_stat_t\":\"%s\"," // stat/led2/RESULT - "\"white_value_scale\":100," // (No abbreviation defined) - "\"whit_val_tpl\":\"{{value_json.Channel[3]}}\""; + ",\"whit_val_cmd_t\":\"%s\"," // cmnd/led2/White + "\"whit_val_stat_t\":\"%s\"," // stat/led2/RESULT + "\"whit_val_scl\":100," + "\"whit_val_tpl\":\"{{value_json.Channel[3]}}\""; const char HASS_DISCOVER_LIGHT_CT[] PROGMEM = - ",\"clr_temp_cmd_t\":\"%s\"," // cmnd/led2/CT - "\"clr_temp_stat_t\":\"%s\"," // stat/led2/RESULT - "\"clr_temp_val_tpl\":\"{{value_json." D_CMND_COLORTEMPERATURE "}}\""; + ",\"clr_temp_cmd_t\":\"%s\"," // cmnd/led2/CT + "\"clr_temp_stat_t\":\"%s\"," // stat/led2/RESULT + "\"clr_temp_val_tpl\":\"{{value_json." D_CMND_COLORTEMPERATURE "}}\""; const char HASS_DISCOVER_LIGHT_SCHEME[] PROGMEM = - ",\"fx_cmd_t\":\"%s\"," // cmnd/led2/Scheme - "\"fx_stat_t\":\"%s\"," // stat/led2/RESULT - "\"fx_val_tpl\":\"{{value_json." D_CMND_SCHEME "}}\"," - "\"fx_list\":[\"0\",\"1\",\"2\",\"3\",\"4\"]"; // string list with reference to scheme parameter. + ",\"fx_cmd_t\":\"%s\"," // cmnd/led2/Scheme + "\"fx_stat_t\":\"%s\"," // stat/led2/RESULT + "\"fx_val_tpl\":\"{{value_json." D_CMND_SCHEME "}}\"," + "\"fx_list\":[\"0\",\"1\",\"2\",\"3\",\"4\"]"; // string list with reference to scheme parameter. const char HASS_DISCOVER_SENSOR_HASS_STATUS[] PROGMEM = - ",\"json_attributes_topic\":\"%s\"," - "\"unit_of_meas\":\" \"," // " " As unit of measurement to get a value graph in HAss - "\"val_tpl\":\"{{value_json['" D_JSON_RSSI "']}}\"," - "\"ic\":\"mdi:information-outline\""; + ",\"json_attr_t\":\"%s\"," + "\"unit_of_meas\":\"%%\"," + "\"val_tpl\":\"{{value_json['" D_JSON_RSSI "']}}\"," + "\"ic\":\"mdi:information-outline\""; const char HASS_DISCOVER_DEVICE_INFO[] PROGMEM = - ",\"uniq_id\":\"%s\"," - "\"device\":{\"identifiers\":[\"%06X\"]," - "\"connections\":[[\"mac\",\"%s\"]]," - "\"name\":\"%s\"," - "\"model\":\"%s\"," - "\"sw_version\":\"%s%s\"," - "\"manufacturer\":\"Tasmota\"}"; + ",\"uniq_id\":\"%s\"," + "\"dev\":{\"ids\":[\"%06X\"]," + "\"name\":\"%s\"," + "\"mdl\":\"%s\"," + "\"sw\":\"%s%s\"," + "\"mf\":\"Tasmota\"}"; const char HASS_DISCOVER_DEVICE_INFO_SHORT[] PROGMEM = - ",\"uniq_id\":\"%s\"," - "\"device\":{\"identifiers\":[\"%06X\"]," - "\"connections\":[[\"mac\",\"%s\"]]}"; + ",\"uniq_id\":\"%s\"," + "\"dev\":{\"ids\":[\"%06X\"]}"; + +const char HASS_TRIGGER_TYPE[] PROGMEM = + "{\"atype\":\"trigger\"," + "\"t\":\"%sT\"," + "\"pl\":\"{\\\"TRIG\\\":\\\"%s\\\"}\"," + "\"type\":\"%s\"," + "\"stype\":\"%s\"," + "\"dev\":{\"ids\":[\"%06X\"]}}"; + +const char kHAssTriggerType[] PROGMEM = + "none|button_short_press|button_long_press|button_double_press"; uint8_t hass_init_step = 0; uint8_t hass_mode = 0; @@ -183,12 +191,9 @@ void HAssAnnounceRelayLight(void) char *state_topic = stemp2; char *availability_topic = stemp3; - if (i > MAX_FRIENDLYNAMES) - { + if (i > MAX_FRIENDLYNAMES) { snprintf_P(name, sizeof(name), PSTR("%s %d"), SettingsText(SET_FRIENDLYNAME1), i); - } - else - { + } else { snprintf_P(name, sizeof(name), SettingsText(SET_FRIENDLYNAME1 + i - 1)); } GetPowerDevice(value_template, i, sizeof(value_template), Settings.flag.device_index_enable); // SetOption26 - Switch between POWER or POWER1 @@ -198,7 +203,7 @@ void HAssAnnounceRelayLight(void) Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic); TryResponseAppend_P(HASS_DISCOVER_RELAY, command_topic, value_template, SettingsText(SET_STATE_TXT1), SettingsText(SET_STATE_TXT2)); - TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP.getChipId(), WiFi.macAddress().c_str()); + TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP.getChipId()); #if defined(USE_LIGHT) || defined(USE_PWM_DIMMER) if (is_light || PWM_DIMMER == my_module_type) @@ -244,7 +249,7 @@ void HAssAnnounceRelayLight(void) } } -void HAssAnnounceButtonSwitch(uint8_t device, char *topic, uint8_t present, uint8_t key, uint8_t toggle) +void HAssAnnouncerTriggers(uint8_t device, uint8_t present, uint8_t key, uint8_t toggle, uint8_t hold) { // key 0 = button // key 1 = switch @@ -255,108 +260,199 @@ void HAssAnnounceButtonSwitch(uint8_t device, char *topic, uint8_t present, uint mqtt_data[0] = '\0'; // Clear retained message - // Clear or Set topic - snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_%s_%d"), ESP.getChipId(), key ? "SW" : "BTN", device + 1); + for (uint8_t i = 2; i <= 3; i++) { + snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_%s_%d_%s"), ESP.getChipId(), key ? "SW" : "BTN", device + 1, GetStateText(i)); + snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/device_automation/%s/config"), unique_id); + + if (Settings.flag.hass_discovery && present) { // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59) + char name[33 + 6]; // friendlyname(33) + " " + "BTN" + " " + index + char value_template[33]; + char prefix[TOPSZ]; + char *state_topic = stemp1; + char *availability_topic = stemp2; + char jsoname[8]; + + GetPowerDevice(value_template, device + 1, sizeof(value_template), key + Settings.flag.device_index_enable); // Force index for Switch 1, Index on Button1 is controlled by SetOption26 - Switch between POWER or POWER1 + snprintf_P(jsoname, sizeof(jsoname), PSTR("%s%d"), key ? "SWITCH" : "BUTTON", device + 1); + GetTopic_P(state_topic, STAT, mqtt_topic, jsoname); + GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT); + + char param[21]; + char subtype[9]; + uint8_t pload = toggle; + + if ((i == 2 && toggle != 0) || (i == 3 && hold != 0)) { + if (i == 3) { pload = hold; } + GetTextIndexed(param, sizeof(param), pload, kHAssTriggerType); + snprintf_P(subtype, sizeof(subtype), PSTR("%s_%d"), key ? "switch" : "button", device + 1); + Response_P(HASS_TRIGGER_TYPE, state_topic, GetStateText(i), param, subtype, ESP.getChipId()); + } else { mqtt_data[0] = '\0'; } // Need to be cleaned again to avoid duplicate. + } + MqttPublish(stopic, true); + } +} + +void HAssAnnouncerBinSensors(uint8_t device, uint8_t present, uint8_t dual, uint8_t toggle) +{ + char stopic[TOPSZ]; + char stemp1[TOPSZ]; + char stemp2[TOPSZ]; + char unique_id[30]; + + mqtt_data[0] = '\0'; // Clear retained message + + snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_SW_%d"), ESP.getChipId(), device + 1); snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/binary_sensor/%s/config"), unique_id); - if (Settings.flag.hass_discovery && present) - { // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59) - char name[33 + 6]; // friendlyname(33) + " " + "BTN" + " " + index - char value_template[33]; - char prefix[TOPSZ]; - char *state_topic = stemp1; - char *availability_topic = stemp2; - char jsoname[8]; - snprintf_P(name, sizeof(name), PSTR("%s %s%d"), SettingsText(SET_FRIENDLYNAME1), key ? "Switch" : "Button", device + 1); - snprintf_P(jsoname, sizeof(jsoname), PSTR("%s%d"), key ? "SWITCH" : "BUTTON", device + 1); - GetPowerDevice(value_template, device + 1, sizeof(value_template), - key + Settings.flag.device_index_enable); // Force index for Switch 1, Index on Button1 is controlled by SetOption26 - Switch between POWER or POWER1 - GetTopic_P(state_topic, STAT, mqtt_topic, (PSTR("/'%s'"), jsoname)); - GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT); + if (Settings.flag.hass_discovery && present ) { // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59) + if (!toggle || dual) { + char name[33 + 6]; // friendlyname(33) + " " + "BTN" + " " + index + char value_template[33]; + char prefix[TOPSZ]; + char *state_topic = stemp1; + char *availability_topic = stemp2; + char jsoname[8]; - Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic); - TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP.getChipId(), WiFi.macAddress().c_str()); + GetPowerDevice(value_template, device + 1, sizeof(value_template), 1 + Settings.flag.device_index_enable); // Force index for Switch 1, Index on Button1 is controlled by SetOption26 - Switch between POWER or POWER1 + snprintf_P(jsoname, sizeof(jsoname), PSTR("SWITCH%d"), device + 1); + GetTopic_P(state_topic, STAT, mqtt_topic, jsoname); + GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT); - if (toggle) { - if (!key) { - TryResponseAppend_P(HASS_DISCOVER_BUTTON_TOGGLE); - } else { // A switch must maintain his state until the next update - TryResponseAppend_P(",\"value_template\":\"{%%if is_state(entity_id,\\\"on\\\")-%%}OFF{%%-else-%%}ON{%%-endif%%}\""); - } - } else { - TryResponseAppend_P(HASS_DISCOVER_BUTTON_SWITCH_ONOFF, PSTR(D_RSLT_STATE), SettingsText(SET_STATE_TXT2), SettingsText(SET_STATE_TXT1)); + snprintf_P(name, sizeof(name), PSTR("%s Switch%d"), SettingsText(SET_FRIENDLYNAME1), device + 1); + Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic); + TryResponseAppend_P(HASS_DISCOVER_BIN_SWITCH, PSTR(D_RSLT_STATE), SettingsText(SET_STATE_TXT2), SettingsText(SET_STATE_TXT1)); + TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP.getChipId()); + TryResponseAppend_P(PSTR("}")); } - TryResponseAppend_P(PSTR("}")); } MqttPublish(stopic, true); } void HAssAnnounceSwitches(void) { - char sw_topic[TOPSZ]; - - // Send info about buttons - char *tmp = SettingsText(SET_MQTT_SWITCH_TOPIC); - Format(sw_topic, tmp, sizeof(sw_topic)); - if (!strcmp_P(sw_topic, "0") || strlen(sw_topic) == 0) + for (uint32_t switch_index = 0; switch_index < MAX_SWITCHES; switch_index++) { - for (uint32_t switch_index = 0; switch_index < MAX_SWITCHES; switch_index++) + uint8_t switch_present = 0; + uint8_t dual = 0; + uint8_t toggle = 1; + uint8_t hold = 0; + + if (pin[GPIO_SWT1 + switch_index] < 99) { switch_present = 1; } + + if (KeyTopicActive(1) && strcmp(SettingsText(SET_MQTT_SWITCH_TOPIC), mqtt_topic)) // Enable Discovery for Switches only if Switchtopic is set to a custom name { - uint8_t switch_present = 0; - uint8_t toggle = 1; - if (pin[GPIO_SWT1 + switch_index] < 99) - { - switch_present = 1; - } + // switch matrix for triggers and binary sensor generation when switchtopic is set as custom (default index is 0,0 - TOGGLE, TOGGLE): + // SWITCHMODE INTERNAL BINARY PRESS DOUBLE PRESS HOLD T,H + // 0 TOGGLE NO TOGGLE (button_short_press) NONE NONE 1,0 + // 1 FOLLOW YES NONE NONE NONE 0,0 + // 2 FOLLOW_INV YES NONE NONE NONE 0,0 + // 3 PUSHBUTTON YES TOGGLE (button_short_press) NONE NONE 1,0 + // 4 PUSHBUTTON_INV YES TOGGLE (button_short_press) NONE NONE 1,0 + // 5 PUSHBUTTONHOLD YES TOGGLE (button_short_press) NONE HOLD (button_long_press) 1,2 + // 6 PUSHBUTTONHOLD_INV YES TOGGLE (button_short_press) NONE HOLD (button_long_press) 1,2 + // 7 PUSHBUTTON_TOGGLE NO TOGGLE (button_short_press) NONE NONE 1,0 + // 8 TOGGLEMULTI NO TOGGLE (button_short_press) HOLD (button_double_press) NONE 1,3 + // 9 FOLLOWMULTI YES NONE HOLD (button_double_press) NONE 0,3 + // 10 FOLLOWMULTI_INV YES NONE HOLD (button_double_press) NONE 0,3 + // 11 PUSHHOLDMULTI NO TOGGLE (button_short_press) NONE INC_DEC (button_long_press) 1,0 + // INV (not available) CLEAR (not available) + // 12 PUSHHOLDMULTI_INV NO TOGGLE (button_short_press) NONE CLEAR (button_long_press) 1,0 + // INV (not available) INC_DEC (not available) + // Please note: SwitchMode11 and 12 will register just TOGGLE (button_short_press) + + // Trigger types: "0 = none | 1 = button_short_press | 2 = button_long_press | 3 = button_double_press"; - // Check if MQTT message will be ON/OFF or TOGGLE - if (Settings.switchmode[switch_index] == FOLLOW || Settings.switchmode[switch_index] == FOLLOW_INV || - Settings.flag3.button_switch_force_local || // SetOption61 - Force local operation when button/switch topic is set - !strcmp(mqtt_topic, sw_topic) || !strcmp(SettingsText(SET_MQTT_GRP_TOPIC), sw_topic)) - { - toggle = 0; // MQTT message will be ON/OFF + uint8_t swmode = Settings.switchmode[switch_index]; + + switch (swmode) { + case 1: + case 2: + toggle = 0; // Binary sensor and no triggers + break; + case 3: + case 4: + dual = 1; // Binary sensor and TOGGLE (button_short_press) trigger + break; + case 5: + case 6: + dual = 1; // Binary sensor, TOGGLE (button_short_press) and HOLD (button_long_press) triggers + hold = 2; + break; + case 8: + hold = 3; // TOGGLE (button_short_press) and HOLD (button_double_press) triggers + break; + case 9: + case 10: + dual = 1; // Binary sensor and HOLD (button_long_press) trigger + toggle = 0; + hold = 3; + break; } - HAssAnnounceButtonSwitch(switch_index, sw_topic, switch_present, 1, toggle); - } + + } else { switch_present = 0;} + + HAssAnnouncerTriggers(switch_index, switch_present, 1, toggle, hold); + HAssAnnouncerBinSensors(switch_index, switch_present, dual, toggle); } } + void HAssAnnounceButtons(void) { - char key_topic[TOPSZ]; - - // Send info about buttons - char *tmp = SettingsText(SET_MQTT_BUTTON_TOPIC); - Format(key_topic, tmp, sizeof(key_topic)); - if (!strcmp_P(key_topic, "0") || strlen(key_topic) == 0) + for (uint32_t button_index = 0; button_index < MAX_KEYS; button_index++) { - for (uint32_t button_index = 0; button_index < MAX_KEYS; button_index++) - { - uint8_t button_present = 0; - uint8_t toggle = 1; + uint8_t button_present = 0; + uint8_t toggle = 1; + uint8_t hold = 0; - if (!button_index && ((SONOFF_DUAL == my_module_type) || (CH4 == my_module_type))) - { + if (!button_index && ((SONOFF_DUAL == my_module_type) || (CH4 == my_module_type))) + { + button_present = 1; + } else { + if (pin[GPIO_KEY1 + button_index] < 99) { button_present = 1; } - else - { - if (pin[GPIO_KEY1 + button_index] < 99) - { - button_present = 1; - } - } - - // Check if MQTT message will be ON/OFF or TOGGLE - if (Settings.flag3.button_switch_force_local || // SetOption61 - Force local operation when button/switch topic is set - !strcmp(mqtt_topic, key_topic) || !strcmp(SettingsText(SET_MQTT_GRP_TOPIC), key_topic)) - { - toggle = 0; // MQTT message will be ON/OFF - } - HAssAnnounceButtonSwitch(button_index, key_topic, button_present, 0, toggle); } + + // button matrix for triggers generation when buttontopic is set as custom (default TOGGLE = 1 HOLD = 0): + // N SetOption1 SetOption11 SetOption13 PRESS DOUBLE PRESS HOLD T,H + // 1 0 0 0 TOGGLE (button_short_press) NONE (toggle real relay) NONE (reset device) 1,0 + // 2 1 0 0 TOGGLE (button_short_press) NONE (toggle real relay) HOLD (button_long_press) 1,2 + // 3 0 1 0 NONE (toggle real relay) TOGGLE (button_double_press) NONE (reset device) 3,0 + // 4 1 1 0 NONE (toggle real relay) TOGGLE (button_double_press) HOLD (button_long_press) 3,2 + // 5 0 0 1 TOGGLE (button_short_press) NONE (toggle real relay) NONE (reset device) 1,0 + // 6 1 0 1 TOGGLE (button_short_press) NONE (toggle real relay) NONE (MQTT HOLD) 1,0 + // 7 0 1 1 NONE (toggle real relay) NONE (toggle real relay) NONE (reset device) 0,0 + // 8 1 1 1 NONE (toggle real relay) NONE (toggle real relay) NONE (MQTT HOLD) 0.0 + + // Trigger types: "0 = none | 1 = button_short_press | 2 = button_long_press | 3 = button_double_press"; + + if (Settings.flag.button_restrict) { // [SetOption1] Enable/Disable button multipress + if (!Settings.flag.button_single) { + hold = 2; // Default TOGGLE (button_short_press) + HOLD (button_long_press) trigger if [SetOption13] is OFF + } + } + + if (Settings.flag.button_swap) { // [SetOption11] Swap button single and double press functionality + if (!Settings.flag.button_single) { + if (!Settings.flag.button_restrict) { + hold = 0; // TOGGLE (button_double_press) and remove HOLD (button_long_press) trigger if [SetOption1] is OFF + } + toggle = 3; // TOGGLE (button_double_press) + } else {toggle = 0; hold = 0;} // [SetOption13] Immediate action on button press, no TOGGLE or HOLD triggers + } + + if (KeyTopicActive(0)) { // Enable Discovery for Buttons only if Buttontopic is set to 1 or a custom name + + if (!strcmp(SettingsText(SET_MQTT_BUTTON_TOPIC), mqtt_topic)) { + toggle = 0; // When ButtonTopic is set to 1, TOGGLE is not allowed but an HOLD trigger can be generated. + } + + } else { button_present = 0; } + + HAssAnnouncerTriggers(button_index, button_present, 0, toggle, hold); } } @@ -369,9 +465,7 @@ void HAssAnnounceSensor(const char *sensorname, const char *subsensortype, const mqtt_data[0] = '\0'; // Clear retained message // Clear or Set topic - char subname[20]; - NoAlNumToUnderscore(subname, MultiSubName); //Replace all non alphaumeric characters to '_' to avoid topic name issues - snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_%s_%s"), ESP.getChipId(), sensorname, subname); + snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_%s_%s"), ESP.getChipId(), sensorname, MultiSubName); snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/sensor/%s/config"), unique_id);; if (Settings.flag.hass_discovery) @@ -381,13 +475,13 @@ void HAssAnnounceSensor(const char *sensorname, const char *subsensortype, const char *state_topic = stemp1; char *availability_topic = stemp2; - snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/sensor/%s/config"), unique_id); GetTopic_P(state_topic, TELE, mqtt_topic, PSTR(D_RSLT_SENSOR)); snprintf_P(name, sizeof(name), PSTR("%s %s %s"), SettingsText(SET_FRIENDLYNAME1), sensorname, MultiSubName); GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT); Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic); - TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP.getChipId(), WiFi.macAddress().c_str()); + TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP.getChipId()); + char jname[32]; int sensor_index = GetCommandCode(jname, sizeof(jname), subsensortype, kHAssJsonSensorTypes); @@ -398,7 +492,7 @@ void HAssAnnounceSensor(const char *sensorname, const char *subsensortype, const case 0: // Temperature snprintf_P(param1, sizeof(param1), PSTR("°%c"),TempUnit()); // C or F break; - case 1: + case 1: // Pressure case 2: snprintf_P(param1, sizeof(param1), PSTR("%s"), PressureUnit().c_str()); break; @@ -439,7 +533,6 @@ void HAssAnnounceSensors(void) snprintf_P(sensordata, sizeof(sensordata), PSTR("%s}"), sensordata); // {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}} // USE THE FOLLOWING LINE TO TEST JSON //snprintf_P(sensordata, sizeof(sensordata), PSTR("{\"HX711\":{\"Weight\":[22,34,1023.4], \"Battery\":25}}")); - StaticJsonBuffer<500> jsonBuffer; JsonObject &root = jsonBuffer.parseObject(sensordata); if (!root.success()) @@ -464,8 +557,9 @@ void HAssAnnounceSensors(void) subqty = subsensors.size(); char MultiSubName[20]; for (int i = 1; i <= subqty; i++) { - snprintf_P(MultiSubName, sizeof(MultiSubName), PSTR("%s %d"), subsensor.key, i); + snprintf_P(MultiSubName, sizeof(MultiSubName), PSTR("%s_%d"), subsensor.key, i); HAssAnnounceSensor(sensorname, subsensor.key, MultiSubName, i, 1); + } } else { HAssAnnounceSensor(sensorname, subsensor.key, subsensor.key, 0, 0);} } @@ -504,7 +598,6 @@ void HAssAnnounceStatusSensor(void) TryResponseAppend_P(HASS_DISCOVER_SENSOR_HASS_STATUS, state_topic); TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO, unique_id, ESP.getChipId(), WiFi.macAddress().c_str(), SettingsText(SET_FRIENDLYNAME1), ModuleName().c_str(), my_version, my_image); - TryResponseAppend_P(PSTR("}")); } MqttPublish(stopic, true); @@ -529,11 +622,13 @@ void HAssDiscovery(void) { // Configure Tasmota for default Home Assistant parameters to keep discovery message as short as possible if (Settings.flag.hass_discovery) - { // SetOption19 - Control Home Assistant automatic discovery (See SetOption59) - Settings.flag.mqtt_response = 0; // SetOption4 - Switch between MQTT RESULT or COMMAND - Response always as RESULT and not as uppercase command - Settings.flag.decimal_text = 1; // SetOption17 - Switch between decimal or hexadecimal output - Respond with decimal color values - Settings.flag3.hass_tele_on_power = 1; // SetOption59 - Send tele/%topic%/STATE in addition to stat/%topic%/RESULT - send tele/STATE message as stat/RESULT - Settings.light_scheme = 0; // To just control color it needs to be Scheme 0 + { // SetOption19 - Control Home Assistant automatic discovery (See SetOption59) + Settings.flag.mqtt_response = 0; // SetOption4 - Switch between MQTT RESULT or COMMAND - Response always as RESULT and not as uppercase command + Settings.flag.decimal_text = 1; // SetOption17 - Switch between decimal or hexadecimal output - Respond with decimal color values + Settings.flag3.hass_tele_on_power = 1; // SetOption59 - Send tele/%topic%/STATE in addition to stat/%topic%/RESULT - send tele/STATE message as stat/RESULT + // the purpose of that is so that if HA is restarted, state in HA will be correct within one teleperiod otherwise state + // will not be correct until the device state is changed this is why in the patterns for switch and light, we tell HA to trigger on STATE, not RESULT. + Settings.light_scheme = 0; // To just control color it needs to be Scheme 0 } if (Settings.flag.hass_discovery || (1 == hass_mode)) @@ -570,18 +665,28 @@ void HAssAnyKey(void) uint32_t key = (XdrvMailbox.payload >> 16) & 0xFF; // 0 = Button, 1 = Switch uint32_t device = XdrvMailbox.payload & 0xFF; // Device number or 1 if more Buttons than Devices - uint32_t state = (XdrvMailbox.payload >> 8) & 0xFF; // 0 = Off, 1 = On, 2 = Toggle + uint32_t state = (XdrvMailbox.payload >> 8) & 0xFF; // 0 = Off, 1 = On, 2 = Toggle, 3 = Hold - if (!key && ButtonTopicActive()) { // Button and ButtonTopic is active + if (!key && KeyTopicActive(0)) { // Button and ButtonTopic is active device = (XdrvMailbox.payload >> 24) & 0xFF; // Button number } char scommand[CMDSZ]; - snprintf_P(scommand, sizeof(scommand), PSTR("%s%d"), (key) ? "SWITCH" : "BUTTON", device); + char sw_topic[TOPSZ]; + char key_topic[TOPSZ]; + char *tmpbtn = SettingsText(SET_MQTT_BUTTON_TOPIC); + char *tmpsw = SettingsText(SET_MQTT_SWITCH_TOPIC); + uint8_t evkey = 0; // Flag to select the correct topic for a trigger or a binary_sensor + Format(sw_topic, tmpsw, sizeof(sw_topic)); + Format(key_topic, tmpbtn, sizeof(key_topic)); + + if (state == 2 || state == 3 ) { evkey = 1;} + snprintf_P(scommand, sizeof(scommand), PSTR("%s%d%s"), (key) ? "SWITCH" : "BUTTON", device, (evkey) ? "T" : ""); + char stopic[TOPSZ]; GetTopic_P(stopic, STAT, mqtt_topic, scommand); - Response_P(S_JSON_COMMAND_SVALUE, PSTR(D_RSLT_STATE), GetStateText(state)); + Response_P(S_JSON_COMMAND_SVALUE, (evkey) ? "TRIG" : PSTR(D_RSLT_STATE), GetStateText(state)); MqttPublish(stopic); } @@ -630,4 +735,4 @@ bool Xdrv12(uint8_t function) return result; } -#endif // USE_HOME_ASSISTANT +#endif // USE_HOME_ASSISTANT \ No newline at end of file