2018-01-18 15:19:28 +00:00
/*
2019-10-27 10:13:24 +00:00
xdrv_12_home_assistant . ino - home assistant support for Tasmota
2022-06-10 09:43:36 +01:00
2021-01-01 12:44:04 +00:00
Copyright ( C ) 2021 Erik Montnemery , Federico Leoni and Theo Arends
2022-06-10 09:43:36 +01:00
2018-01-18 15:19:28 +00:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
2022-06-10 09:43:36 +01:00
2018-01-18 15:19:28 +00:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2022-06-10 09:43:36 +01:00
2018-01-18 15:19:28 +00:00
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# ifdef USE_HOME_ASSISTANT
2021-04-10 17:20:15 +01:00
# undef USE_TASMOTA_DISCOVERY
2022-06-10 09:43:36 +01:00
/*********************************************************************************************\
* Legacy Home Assistant discovery now replaced by Tasmota Discovery and hatasmota in HASS
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-01-18 15:19:28 +00:00
2020-02-06 02:29:44 +00:00
# define XDRV_12 12
2022-06-10 09:43:36 +01:00
# ifndef HOME_ASSISTANT_DISCOVERY_PREFIX
# define HOME_ASSISTANT_DISCOVERY_PREFIX "homeassistant" // Home Assistant discovery prefix
# endif
# ifndef HOME_ASSISTANT_LWT_TOPIC
# define HOME_ASSISTANT_LWT_TOPIC "homeassistant / status" // home Assistant Birth and Last Will Topic (default = homeassistant/status)
# endif
# ifndef HOME_ASSISTANT_LWT_SUBSCRIBE
# define HOME_ASSISTANT_LWT_SUBSCRIBE true // Subscribe to Home Assistant Birth and Last Will Topic (default = true)
# endif
2020-02-06 02:29:44 +00:00
// List of sensors ready for discovery
2020-02-06 16:32:54 +00:00
const char kHAssJsonSensorTypes [ ] PROGMEM =
2020-03-18 14:02:20 +00:00
D_JSON_TEMPERATURE " | " D_JSON_DEWPOINT " | " D_JSON_PRESSURE " | " D_JSON_PRESSUREATSEALEVEL " | "
2020-02-06 02:29:44 +00:00
D_JSON_APPARENT_POWERUSAGE " |Battery| " D_JSON_CURRENT " | " D_JSON_DISTANCE " | " D_JSON_FREQUENCY " | " D_JSON_HUMIDITY " | " D_JSON_ILLUMINANCE " | "
2020-05-12 18:06:35 +01:00
D_JSON_MOISTURE " |PB0.3|PB0.5|PB1|PB2.5|PB5|PB10|PM1|PM2.5|PM10| " D_JSON_POWERFACTOR " | " D_JSON_POWERUSAGE " | " D_JSON_TOTAL_START_TIME " | "
2020-03-18 14:02:20 +00:00
D_JSON_REACTIVE_POWERUSAGE " | " D_JSON_TODAY " | " D_JSON_TOTAL " | " D_JSON_VOLTAGE " | " D_JSON_WEIGHT " | " D_JSON_YESTERDAY " | "
2020-10-01 15:47:01 +01:00
D_JSON_CO2 " | " D_JSON_ECO2 " | " D_JSON_TVOC " |Red|Green|Blue|CCT| " D_PROXIMITY " | " ;
2020-09-25 00:05:36 +01:00
2020-05-06 18:52:08 +01:00
2020-02-06 16:32:54 +00:00
const char kHAssJsonSensorUnits [ ] PROGMEM =
2020-03-18 14:02:20 +00:00
" |||| "
2020-10-01 15:47:01 +01:00
" VA|%|A|cm|Hz|%|lux| "
2020-05-12 18:06:35 +01:00
" %|ppd|ppd|ppd|ppd|ppd|ppd|µg/m³|µg/m³|µg/m³|Cos φ|W| | "
2020-10-01 15:47:01 +01:00
" VAr|kWh|kWh|V|kg|kWh| "
" ppm|ppm|ppb|R|G|B| " D_UNIT_KELVIN " | | " ;
2020-05-06 18:52:08 +01:00
2020-02-06 16:32:54 +00:00
const char kHAssJsonSensorDevCla [ ] PROGMEM =
2021-09-04 00:11:14 +01:00
" dev_cla \" : \" temperature|dev_cla \" : \" temperature|dev_cla \" : \" pressure|dev_cla \" : \" pressure| "
" dev_cla \" : \" power|dev_cla \" : \" battery|dev_cla \" : \" current|ic \" : \" mdi:leak|ic \" : \" mdi:current-ac|dev_cla \" : \" humidity|dev_cla \" : \" illuminance| "
2020-02-06 02:29:44 +00:00
" ic \" : \" mdi:cup-water|ic \" : \" mdi:flask|ic \" : \" mdi:flask|ic \" : \" mdi:flask|ic \" : \" mdi:flask|ic \" : \" mdi:flask|ic \" : \" mdi:flask| "
2021-09-04 00:11:14 +01:00
" dev_cla \" : \" pm1|dev_cla \" : \" pm25|dev_cla \" : \" pm10|dev_cla \" : \" power_factor|dev_cla \" : \" power|ic \" : \" mdi:progress-clock| "
2022-01-12 22:04:47 +00:00
" dev_cla \" : \" power|dev_cla \" : \" energy|dev_cla \" : \" energy \" , \" stat_cla \" : \" total_increasing|dev_cla \" : \" voltage|ic \" : \" mdi:scale|dev_cla \" : \" energy| "
2021-09-04 00:11:14 +01:00
" dev_cla \" : \" carbon_dioxide|dev_cla \" : \" carbon_dioxide|dev_class \" : \" volatile_organic_compounds| "
2020-09-25 00:05:36 +01:00
" ic \" : \" mdi:palette|ic \" : \" mdi:palette|ic \" : \" mdi:palette|ic \" : \" mdi:temperature-kelvin|ic \" : \" mdi:ruler|dev_cla \" : \" illuminance| " ;
2020-02-06 16:32:54 +00:00
// List of sensors ready for discovery
2020-02-06 02:29:44 +00:00
2020-06-18 18:43:18 +01:00
const char HASS_DISCOVER_BASE [ ] PROGMEM =
" { \" name \" : \" %s \" , " // dualr2 1
" \" stat_t \" : \" %s \" " ; // stat/dualr2/RESULT (implies "\"optimistic\":\"false\",")
2020-02-06 02:29:44 +00:00
const char HASS_DISCOVER_SENSOR [ ] PROGMEM =
2020-06-18 18:43:18 +01:00
" , \" 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']
2020-02-06 02:29:44 +00:00
2020-06-18 18:43:18 +01:00
const char HASS_DISCOVER_SENSOR_LWT [ ] PROGMEM =
" , \" avty_t \" : \" %s \" , " // tele/dualr2/LWT
2020-09-27 11:51:50 +01:00
" \" pl_avail \" : \" " MQTT_LWT_ONLINE " \" , " // Online
" \" pl_not_avail \" : \" " MQTT_LWT_OFFLINE " \" " ; // Offline
2018-11-07 09:30:03 +00:00
2020-02-06 16:32:54 +00:00
const char HASS_DISCOVER_RELAY [ ] PROGMEM =
2020-06-18 18:43:18 +01:00
" , \" cmd_t \" : \" %s \" , " // cmnd/dualr2/POWER2
" \" pl_off \" : \" %s \" , " // OFF
" \" pl_on \" : \" %s \" " ; // ON
2018-12-04 20:31:23 +00:00
2021-06-08 15:04:20 +01:00
const char HASS_DISCOVER_RELAY_TEMPLATE [ ] PROGMEM =
" , \" val_tpl \" : \" {{value_json.%s}} \" " ; // POWER2
2020-03-12 19:48:44 +00:00
const char HASS_DISCOVER_BIN_SWITCH [ ] PROGMEM =
2020-06-18 18:43:18 +01:00
" , \" 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
2018-12-04 20:31:23 +00:00
2020-03-14 21:36:19 +00:00
const char HASS_DISCOVER_BIN_PIR [ ] PROGMEM =
2020-06-18 18:43:18 +01:00
" , \" val_tpl \" : \" {{value_json.%s}} \" , " // STATE
" \" frc_upd \" :true, " // In ON/OFF case, enable force_update to make automations work
" \" pl_on \" : \" %s \" , " // ON
" \" off_dly \" :1 " ; // Switchmode13 and Switchmode14 doesn't transmit an OFF state.
2020-03-14 21:36:19 +00:00
2021-06-08 15:04:20 +01:00
const char HASS_DISCOVER_LIGHT_TEMPLATE [ ] PROGMEM =
" , \" stat_val_tpl \" : \" {{value_json.%s}} \" " ; // POWER2
2020-05-06 18:52:08 +01:00
const char HASS_DISCOVER_BASE_LIGHT [ ] PROGMEM =
2020-06-18 18:43:18 +01:00
" , \" 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)
2020-05-06 18:52:08 +01:00
" \" bri_val_tpl \" : \" {{value_json.%s}} \" " ;
2018-01-18 15:19:28 +00:00
2021-07-15 16:51:40 +01:00
const char HASS_DISCOVER_LIGHT_HS_COLOR [ ] PROGMEM =
" , \" hs_cmd_t \" : \" %s \" , " // cmnd/led2/HSBColor
" \" hs_stat_t \" : \" %s \" , " // stat/led2/RESULT
" \" hs_val_tpl \" : \" {{value_json. " D_CMND_HSBCOLOR " .split(',')[0:2]|join(',')}} \" " ;
2018-01-18 15:19:28 +00:00
2018-12-22 12:21:04 +00:00
const char HASS_DISCOVER_LIGHT_WHITE [ ] PROGMEM =
2021-07-15 15:07:30 +01:00
" , \" whit_cmd_t \" : \" %s \" , " // cmnd/led2/White
" \" clrm_stat_t \" : \" %s \" , " // stat/led2/RESULT
" \" whit_scl \" :100, "
2021-07-15 16:51:40 +01:00
" \" clrm_val_tpl \" : \" {%%if value_json.White%%}white{%%else%%}hs{%%endif %%} \" " ;
2018-12-07 20:32:01 +00:00
2018-12-22 12:21:04 +00:00
const char HASS_DISCOVER_LIGHT_CT [ ] PROGMEM =
2020-06-18 18:43:18 +01:00
" , \" clr_temp_cmd_t \" : \" %s \" , " // cmnd/led2/CT
" \" clr_temp_stat_t \" : \" %s \" , " // stat/led2/RESULT
2021-07-15 17:16:59 +01:00
" \" clr_temp_val_tpl \" : \" {{value_json. " D_CMND_COLORTEMPERATURE " }} \" , "
" \" clrm_stat_t \" : \" %s \" , " // stat/led2/RESULT
" \" clrm_val_tpl \" : \" {%%if value_json.White%%}color_temp{%%else%%}hs{%%endif %%} \" " ;
2018-11-28 19:43:36 +00:00
2018-12-22 12:21:04 +00:00
const char HASS_DISCOVER_LIGHT_SCHEME [ ] PROGMEM =
2020-03-12 19:48:44 +00:00
" , \" 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.
2018-11-18 14:33:13 +00:00
2020-06-29 18:44:26 +01:00
const char HASS_DISCOVER_SHUTTER_BASE [ ] PROGMEM =
" , \" cmd_t \" : \" %s \" , " // cmnd/%topic%/Backlog
" \" pl_open \" : \" ShutterOpen%d \" , " // 1
" \" pl_cls \" : \" ShutterClose%d \" , " // 1
" \" pl_stop \" : \" ShutterStop%d \" , " // 1
" \" opt \" :false, "
" \" ret \" :false, "
" \" qos \" :1 " ;
const char HASS_DISCOVER_SHUTTER_POS [ ] PROGMEM =
" , \" pos_t \" : \" %s%d \" , " // stat/%topic%/SHUTTER1
" \" pos_clsd \" :0, "
" \" pos_open \" :100, "
" \" set_pos_t \" : \" %s%d \" " ; // cmnd/%topic%/ShutterPosition1
2021-11-07 13:11:32 +00:00
const char HASS_DISCOVER_SHUTTER_TILT [ ] PROGMEM =
" , \" tilt_cmd_t \" : \" %s%d \" , " // cmnd/%topic%/ShutterTilt1
" \" tilt_opnd_val \" :%d, "
" \" tilt_clsd_val \" :%d " ;
/*
" tilt_clsd_val " : " tilt_closed_value " ,
" tilt_cmd_t " : " tilt_command_topic " ,
" tilt_cmd_tpl " : " tilt_command_template " ,
" tilt_inv_stat " : " tilt_invert_state " ,
" tilt_max " : " tilt_max " ,
" tilt_min " : " tilt_min " ,
" tilt_opnd_val " : " tilt_opened_value " ,
" tilt_opt " : " tilt_optimistic " ,
" tilt_status_t " : " tilt_status_topic " ,
" tilt_status_tpl " : " tilt_status_template " ,
*/
2019-02-06 19:07:28 +00:00
const char HASS_DISCOVER_SENSOR_HASS_STATUS [ ] PROGMEM =
2020-03-12 19:48:44 +00:00
" , \" json_attr_t \" : \" %s \" , "
" \" unit_of_meas \" : \" %% \" , "
" \" val_tpl \" : \" {{value_json[' " D_JSON_RSSI " ']}} \" , "
" \" ic \" : \" mdi:information-outline \" " ;
2019-02-06 19:07:28 +00:00
2018-12-22 12:21:04 +00:00
const char HASS_DISCOVER_DEVICE_INFO [ ] PROGMEM =
2020-03-12 19:48:44 +00:00
" , \" uniq_id \" : \" %s \" , "
" \" dev \" :{ \" ids \" :[ \" %06X \" ], "
" \" name \" : \" %s \" , "
" \" mdl \" : \" %s \" , "
" \" sw \" : \" %s%s \" , "
" \" mf \" : \" Tasmota \" } " ;
2018-12-10 18:51:47 +00:00
2019-02-06 19:07:28 +00:00
const char HASS_DISCOVER_DEVICE_INFO_SHORT [ ] PROGMEM =
2020-03-12 19:48:44 +00:00
" , \" 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 " ;
2019-02-06 19:07:28 +00:00
2020-04-21 13:54:17 +01:00
const char kHAssTriggerTypeButtons [ ] PROGMEM =
" |button_short_press|button_double_press|button_triple_press|button_quadruple_press|button_quintuple_press|button_long_press| " ;
const char kHAssTriggerStringButtons [ ] PROGMEM =
" |SINGLE|DOUBLE|TRIPLE|QUAD|PENTA|HOLD| " ;
2020-10-08 16:04:52 +01:00
const char kHAssRelayType [ ] PROGMEM =
" |RL|LI|SHT|FAN " ;
2020-05-06 18:52:08 +01:00
const char kHAssError1 [ ] PROGMEM =
2020-06-18 18:43:18 +01:00
" HASS: MQTT discovery failed due to too long topic or device/friendly name. Please shorten topic and/or device/friendly name. Failed to format " ;
2020-05-06 18:52:08 +01:00
const char kHAssError2 [ ] PROGMEM =
2020-05-12 18:06:35 +01:00
" HASS: The configuration of the Relays is wrong, there is a Light that is using an index higher than the number of the validated relay. \n "
2020-05-06 18:52:08 +01:00
" The Relays have priority over the Lights, an incorrect order could lead to an erroneous Light control. \n "
" Please update your configuration to avoid inconsistent results. \n "
" Entities for Relays and Lights will not be available in Home Assistant until the configuration will be updated. " ;
2020-05-12 18:06:35 +01:00
const char kHAssError3 [ ] PROGMEM =
" HASS: Unable to create one or more entities from Json data, please check your configuration. Failed to parse " ;
2019-01-22 11:46:55 +00:00
uint8_t hass_mode = 0 ;
2019-02-06 19:07:28 +00:00
int hass_tele_period = 0 ;
2019-01-22 11:46:55 +00:00
2022-06-10 09:43:36 +01:00
/*********************************************************************************************\
* New discovery direct copy of Tasmota discovery
*
* Supported by latest versions of Home Assistant ( with hatasmota ) and TasmoManager .
*
* SetOption19 0 - [ DiscoverOff 0 ] [ Discover 1 ] Enables discovery ( default )
* SetOption19 1 - [ DiscoverOff 1 ] [ Discover 0 ] Disables discovery and removes retained message from MQTT server
* SetOption73 1 - [ DiscoverButton ] Enable discovery for buttons
* SetOption114 1 - [ DiscoverSwitch ] Enable discovery for switches
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2021-08-25 08:41:07 +01:00
void HassDiscoverMessage ( void ) {
2022-02-22 14:42:04 +00:00
uint32_t ip_address = ( uint32_t ) WiFi . localIP ( ) ;
char * hostname = TasmotaGlobal . hostname ;
# if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET)
if ( static_cast < uint32_t > ( EthernetLocalIP ( ) ) ! = 0 ) {
ip_address = ( uint32_t ) EthernetLocalIP ( ) ;
hostname = EthernetHostname ( ) ;
}
# endif
2021-08-25 08:41:07 +01:00
Response_P ( PSTR ( " { \" ip \" : \" %_I \" , " // IP Address
" \" dn \" : \" %s \" , " // Device Name
" \" fn \" :[ " ) , // Friendly Names (start)
2022-02-22 14:42:04 +00:00
ip_address ,
2021-08-25 08:41:07 +01:00
SettingsText ( SET_DEVICENAME ) ) ;
2020-09-18 22:45:20 +01:00
2021-08-25 08:41:07 +01:00
uint32_t maxfn = ( TasmotaGlobal . devices_present > MAX_FRIENDLYNAMES ) ? MAX_FRIENDLYNAMES : ( ! TasmotaGlobal . devices_present ) ? 1 : TasmotaGlobal . devices_present ;
for ( uint32_t i = 0 ; i < MAX_FRIENDLYNAMES ; i + + ) {
char fname [ TOPSZ ] ;
snprintf_P ( fname , sizeof ( fname ) , PSTR ( " \" %s \" " ) , EscapeJSONString ( SettingsText ( SET_FRIENDLYNAME1 + i ) ) . c_str ( ) ) ;
ResponseAppend_P ( PSTR ( " %s%s " ) , ( i > 0 ? " , " : " " ) , ( i < maxfn ) ? fname : PSTR ( " null " ) ) ;
}
2020-10-08 16:04:52 +01:00
2021-08-25 08:41:07 +01:00
bool TuyaMod = false ;
2021-12-19 15:41:10 +00:00
# ifdef USE_TUYA_MCU
TuyaMod = IsModuleTuya ( ) ;
# endif
2021-08-25 08:41:07 +01:00
bool iFanMod = false ;
2020-10-08 16:04:52 +01:00
# ifdef ESP8266
2021-12-19 15:41:10 +00:00
iFanMod = ( ( SONOFF_IFAN02 = = TasmotaGlobal . module_type ) | | ( SONOFF_IFAN03 = = TasmotaGlobal . module_type ) ) ;
2021-08-25 08:41:07 +01:00
# endif // ESP8266
ResponseAppend_P ( PSTR ( " ], " // Friendly Names (end)
" \" hn \" : \" %s \" , " // Host Name
" \" mac \" : \" %s \" , " // Full MAC as Device id
" \" md \" : \" %s \" , " // Module or Template Name
" \" ty \" :%d, \" if \" :%d, " // Flag for TuyaMCU and Ifan devices
" \" ofln \" : \" " MQTT_LWT_OFFLINE " \" , " // Payload Offline
" \" onln \" : \" " MQTT_LWT_ONLINE " \" , " // Payload Online
" \" state \" :[ \" %s \" , \" %s \" , \" %s \" , \" %s \" ], " // State text for "OFF","ON","TOGGLE","HOLD"
" \" sw \" : \" %s \" , " // Software Version
" \" t \" : \" %s \" , " // Topic
" \" ft \" : \" %s \" , " // Full Topic
" \" tp \" :[ \" %s \" , \" %s \" , \" %s \" ], " // Topics for command, stat and tele
" \" rl \" :[ " ) , // Relays (start)
2022-02-22 14:42:04 +00:00
hostname ,
2021-08-25 08:41:07 +01:00
NetworkUniqueId ( ) . c_str ( ) ,
ModuleName ( ) . c_str ( ) ,
TuyaMod , iFanMod ,
GetStateText ( 0 ) , GetStateText ( 1 ) , GetStateText ( 2 ) , GetStateText ( 3 ) ,
TasmotaGlobal . version ,
TasmotaGlobal . mqtt_topic ,
SettingsText ( SET_MQTT_FULLTOPIC ) ,
SettingsText ( SET_MQTTPREFIX1 ) ,
SettingsText ( SET_MQTTPREFIX2 ) ,
SettingsText ( SET_MQTTPREFIX3 ) ) ;
2023-02-09 15:02:06 +00:00
uint8_t light_idx = MAX_RELAYS_SET + 1 ; // Will store the starting position of the lights
2021-08-25 08:41:07 +01:00
uint8_t light_subtype = 0 ;
bool light_controller_isCTRGBLinked = false ;
# ifdef USE_LIGHT
light_subtype = Light . subtype ;
if ( light_subtype > LST_NONE ) {
light_controller_isCTRGBLinked = light_controller . isCTRGBLinked ( ) ;
if ( ! light_controller_isCTRGBLinked ) { // One or two lights present
light_idx = TasmotaGlobal . devices_present - 2 ;
2020-10-08 16:04:52 +01:00
} else {
2021-08-25 08:41:07 +01:00
light_idx = TasmotaGlobal . devices_present - 1 ;
2020-10-08 16:04:52 +01:00
}
}
2021-08-25 08:41:07 +01:00
if ( ( Light . device > 0 ) & & Settings - > flag3 . pwm_multi_channels ) { // How many relays are light devices?
light_idx = TasmotaGlobal . devices_present - light_subtype ;
2020-10-08 16:04:52 +01:00
}
2021-08-25 08:41:07 +01:00
# endif // USE_LIGHT
2020-10-08 16:04:52 +01:00
2023-02-09 15:02:06 +00:00
uint16_t Relay [ MAX_RELAYS_SET ] = { 0 } ; // Base array to store the relay type
uint16_t Shutter [ MAX_RELAYS_SET ] = { 0 } ; // Array to store a temp list for shutters
for ( uint32_t i = 0 ; i < MAX_RELAYS_SET ; i + + ) {
2020-10-30 11:29:48 +00:00
if ( i < TasmotaGlobal . devices_present ) {
2020-10-08 16:04:52 +01:00
# ifdef USE_SHUTTER
2021-06-11 17:14:12 +01:00
if ( Settings - > flag3 . shutter_mode ) {
2020-10-08 16:04:52 +01:00
for ( uint32_t k = 0 ; k < MAX_SHUTTERS ; k + + ) {
2021-11-05 08:02:42 +00:00
if ( Settings - > shutter_startrelay [ k ] > 0 ) {
Shutter [ Settings - > shutter_startrelay [ k ] - 1 ] = Shutter [ Settings - > shutter_startrelay [ k ] ] = 1 ;
2020-10-08 16:04:52 +01:00
} else {
2021-11-05 08:02:42 +00:00
// terminate loop at first INVALID Settings->shutter_startrelay[i].
break ;
2020-10-08 16:04:52 +01:00
}
}
}
2021-08-25 08:41:07 +01:00
# endif // USE_SHUTTER
2020-10-08 16:04:52 +01:00
2021-08-25 08:41:07 +01:00
if ( Shutter [ i ] ! = 0 ) { // Check if there are shutters present
Relay [ i ] = 3 ; // Relay is a shutter
2020-10-08 16:04:52 +01:00
} else {
2021-08-25 08:41:07 +01:00
if ( i > = light_idx | | ( iFanMod & & ( 0 = = i ) ) ) { // First relay on Ifan controls the light
Relay [ i ] = 2 ; // Relay is a light
2020-10-08 16:04:52 +01:00
} else {
2021-08-25 08:41:07 +01:00
if ( ! iFanMod ) { // Relays 2-4 for ifan are controlled by FANSPEED and don't need to be present if TasmotaGlobal.module_type = SONOFF_IFAN02 or SONOFF_IFAN03
Relay [ i ] = 1 ; // Simple Relay
2020-10-08 16:04:52 +01:00
}
}
}
}
2021-08-25 08:41:07 +01:00
ResponseAppend_P ( PSTR ( " %s%d " ) , ( i > 0 ? " , " : " " ) , Relay [ i ] ) ; // Vector for the Official Integration
2020-10-08 16:04:52 +01:00
}
2021-08-25 08:41:07 +01:00
ResponseAppend_P ( PSTR ( " ], " // Relays (end)
" \" swc \" :[ " ) ) ; // Switch modes (start)
2020-10-08 16:04:52 +01:00
2021-08-25 08:41:07 +01:00
// Enable Discovery for Switches only if SetOption114 is enabled
2023-02-06 10:45:28 +00:00
for ( uint32_t i = 0 ; i < MAX_SWITCHES_SET ; i + + ) {
ResponseAppend_P ( PSTR ( " %s%d " ) , ( i > 0 ? " , " : " " ) , ( SwitchUsed ( i ) & & Settings - > flag5 . mqtt_switches ) ? Settings - > switchmode [ i ] : - 1 ) ;
2020-09-18 22:45:20 +01:00
}
2021-08-25 08:41:07 +01:00
ResponseAppend_P ( PSTR ( " ], " // Switch modes (end)
" \" swn \" :[ " ) ) ; // Switch names (start)
2020-11-03 15:50:08 +00:00
// Enable Discovery for Switches only if SetOption114 is enabled
2023-02-06 10:45:28 +00:00
for ( uint32_t i = 0 ; i < MAX_SWITCHES_SET ; i + + ) {
2020-11-03 15:50:08 +00:00
char sname [ TOPSZ ] ;
snprintf_P ( sname , sizeof ( sname ) , PSTR ( " \" %s \" " ) , GetSwitchText ( i ) . c_str ( ) ) ;
2023-02-06 10:45:28 +00:00
ResponseAppend_P ( PSTR ( " %s%s " ) , ( i > 0 ? " , " : " " ) , ( SwitchUsed ( i ) & & Settings - > flag5 . mqtt_switches ) ? sname : PSTR ( " null " ) ) ;
2020-09-18 22:45:20 +01:00
}
2020-09-24 23:16:26 +01:00
2021-08-25 08:41:07 +01:00
ResponseAppend_P ( PSTR ( " ], " // Switch names (end)
" \" btn \" :[ " ) ) ; // Button flag (start)
bool SerialButton = false ;
2020-09-24 23:16:26 +01:00
// Enable Discovery for Buttons only if SetOption73 is enabled
2023-02-06 11:03:32 +00:00
for ( uint32_t i = 0 ; i < MAX_KEYS_SET ; i + + ) {
2020-11-03 16:03:08 +00:00
# ifdef ESP8266
2021-08-25 08:41:07 +01:00
SerialButton = ( ( 0 = = i ) & & ( SONOFF_DUAL = = TasmotaGlobal . module_type ) ) ;
# endif // ESP8266
2023-02-06 11:03:32 +00:00
ResponseAppend_P ( PSTR ( " %s%d " ) , ( i > 0 ? " , " : " " ) , ( SerialButton ? 1 : ( ButtonUsed ( i ) ) & & Settings - > flag3 . mqtt_buttons ) ) ;
2020-09-18 22:45:20 +01:00
}
2021-08-25 08:41:07 +01:00
ResponseAppend_P ( PSTR ( " ], " // Button flag (end)
" \" so \" :{ \" 4 \" :%d, " // SetOptions
" \" 11 \" :%d, "
" \" 13 \" :%d, "
" \" 17 \" :%d, "
" \" 20 \" :%d, "
" \" 30 \" :%d, "
" \" 68 \" :%d, "
" \" 73 \" :%d, "
" \" 82 \" :%d, "
" \" 114 \" :%d, "
" \" 117 \" :%d}, "
" \" lk \" :%d, " // Light CTRGB linked
" \" lt_st \" :%d, " // Light SubType
" \" sho \" :[ " ) , // Shutter Options (start)
Settings - > flag . mqtt_response ,
Settings - > flag . button_swap ,
Settings - > flag . button_single ,
Settings - > flag . decimal_text ,
Settings - > flag . not_power_linked ,
Settings - > flag . hass_light ,
Settings - > flag3 . pwm_multi_channels ,
Settings - > flag3 . mqtt_buttons ,
Settings - > flag4 . alexa_ct_range ,
Settings - > flag5 . mqtt_switches ,
Settings - > flag5 . fade_fixed_duration ,
light_controller_isCTRGBLinked ,
light_subtype ) ;
2020-11-27 12:05:45 +00:00
for ( uint32_t i = 0 ; i < MAX_SHUTTERS ; i + + ) {
2021-08-25 08:41:07 +01:00
# ifdef USE_SHUTTER
ResponseAppend_P ( PSTR ( " %s%d " ) , ( i > 0 ? " , " : " " ) , Settings - > shutter_options [ i ] ) ;
2020-12-03 11:06:52 +00:00
# else
2021-08-25 08:41:07 +01:00
ResponseAppend_P ( PSTR ( " %s0 " ) , ( i > 0 ? " , " : " " ) ) ;
# endif // USE_SHUTTER
}
ResponseAppend_P ( PSTR ( " ], " // Shutter Options (end)
2022-05-13 11:28:48 +01:00
" \" sht \" :[ " ) ) ; // Shutter Tilt (start)
for ( uint32_t i = 0 ; i < MAX_SHUTTERS ; i + + ) {
# ifdef USE_SHUTTER
ResponseAppend_P ( PSTR ( " %s[%d,%d,%d] " ) , ( i > 0 ? " , " : " " ) ,
Settings - > shutter_tilt_config [ 0 ] [ i ] ,
Settings - > shutter_tilt_config [ 1 ] [ i ] ,
Settings - > shutter_tilt_config [ 2 ] [ i ] ) ;
# else
ResponseAppend_P ( PSTR ( " %s[0,0,0] " ) , ( i > 0 ? " , " : " " ) ) ;
# endif // USE_SHUTTER
}
ResponseAppend_P ( PSTR ( " ], " // Shutter Tilt (end)
2021-08-25 08:41:07 +01:00
" \" ver \" :1} " ) ) ; // Discovery version
}
void NewHAssDiscovery ( void ) {
TasmotaGlobal . masterlog_level = LOG_LEVEL_DEBUG_MORE ; // Hide topic on clean and remove use weblog 4 to show it
ResponseClear ( ) ; // Clear retained message
if ( ! Settings - > flag . hass_discovery ) { // SetOption19 - Clear retained message
HassDiscoverMessage ( ) ; // Build discovery message
2020-09-24 23:16:26 +01:00
}
2021-08-25 08:41:07 +01:00
char stopic [ TOPSZ ] ;
snprintf_P ( stopic , sizeof ( stopic ) , PSTR ( " tasmota/discovery/%s/config " ) , NetworkUniqueId ( ) . c_str ( ) ) ;
2020-09-18 22:45:20 +01:00
MqttPublish ( stopic , true ) ;
2020-09-25 00:05:36 +01:00
2021-08-25 08:41:07 +01:00
if ( ! Settings - > flag . hass_discovery ) { // SetOption19 - Clear retained message
2020-10-01 15:47:01 +01:00
Response_P ( PSTR ( " { \" sn \" : " ) ) ;
2021-11-21 17:54:13 +00:00
MqttShowSensor ( true ) ;
2020-09-24 23:16:26 +01:00
ResponseAppend_P ( PSTR ( " , \" ver \" :1} " ) ) ;
}
2021-08-25 08:41:07 +01:00
snprintf_P ( stopic , sizeof ( stopic ) , PSTR ( " tasmota/discovery/%s/sensors " ) , NetworkUniqueId ( ) . c_str ( ) ) ;
MqttPublish ( stopic , true ) ;
2020-09-18 22:45:20 +01:00
2021-08-25 08:41:07 +01:00
TasmotaGlobal . masterlog_level = LOG_LEVEL_NONE ; // Restore WebLog state
}
2022-06-10 09:43:36 +01:00
/*********************************************************************************************\
* Legacy discovery
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-09-18 22:45:20 +01:00
2021-06-06 16:26:01 +01:00
void TryResponseAppend_P ( const char * format , . . . ) {
# ifdef MQTT_DATA_STRING
va_list arg ;
va_start ( arg , format ) ;
char * mqtt_data = ext_vsnprintf_malloc_P ( format , arg ) ;
va_end ( arg ) ;
if ( mqtt_data ! = nullptr ) {
TasmotaGlobal . mqtt_data + = mqtt_data ;
free ( mqtt_data ) ;
}
# else
2019-02-06 19:07:28 +00:00
va_list args ;
va_start ( args , format ) ;
2019-03-11 14:41:06 +00:00
char dummy [ 2 ] ;
2019-03-24 13:23:20 +00:00
int dlen = vsnprintf_P ( dummy , 1 , format , args ) ;
2021-05-23 15:50:17 +01:00
int mlen = ResponseLength ( ) ;
int slen = ResponseSize ( ) - 1 - mlen ;
2020-02-06 02:29:44 +00:00
if ( dlen > = slen )
{
2021-06-05 10:47:09 +01:00
AddLog ( LOG_LEVEL_ERROR , PSTR ( " %s (%u/%u): " ) , kHAssError1 , dlen , slen ) ;
2019-02-07 19:54:30 +00:00
va_start ( args , format ) ;
2021-01-02 15:20:15 +00:00
char log_data [ MAX_LOGSZ ] ;
2020-12-23 17:00:59 +00:00
vsnprintf_P ( log_data , sizeof ( log_data ) , format , args ) ;
AddLogData ( LOG_LEVEL_ERROR , log_data ) ;
2020-02-06 02:29:44 +00:00
}
else
{
2019-02-06 19:07:28 +00:00
va_start ( args , format ) ;
2020-10-30 11:29:48 +00:00
vsnprintf_P ( TasmotaGlobal . mqtt_data + mlen , slen , format , args ) ;
2019-02-06 19:07:28 +00:00
}
va_end ( args ) ;
2021-06-06 16:26:01 +01:00
# endif
2019-02-06 19:07:28 +00:00
}
2018-11-18 14:33:13 +00:00
void HAssAnnounceRelayLight ( void )
2018-01-18 15:19:28 +00:00
{
char stopic [ TOPSZ ] ;
2018-12-10 18:51:47 +00:00
char stemp1 [ TOPSZ ] ;
char stemp2 [ TOPSZ ] ;
char stemp3 [ TOPSZ ] ;
char unique_id [ 30 ] ;
2020-05-06 18:52:08 +01:00
2021-08-28 19:02:06 +01:00
# ifdef USE_LIGHT
2020-05-06 18:52:08 +01:00
bool LightControl = light_controller . isCTRGBLinked ( ) ; // SetOption37 - Color remapping for led channels, also provides an option for allowing independent handling of RGB and white channels
2021-08-28 19:02:06 +01:00
# endif //USE_LIGHT
2021-06-11 17:14:12 +01:00
bool PwmMulti = Settings - > flag3 . pwm_multi_channels ; // SetOption68 - Multi-channel PWM instead of a single light
2020-05-06 18:52:08 +01:00
bool is_topic_light = false ; // Switch HAss domain between Lights and Relays
bool ind_light = false ; // Controls Separated Lights when SetOption37 is >= 128
bool ct_light = false ; // Controls a CT Light when SetOption37 is >= 128
bool err_flag = false ; // When true it blocks the creation of entities if the order of the Relays is not correct to avoid issue with Lights
2020-06-18 18:43:18 +01:00
bool TuyaMod = false ; // Controls Tuya MCU modules
2020-05-21 02:11:07 +01:00
bool PwmMod = false ; // Controls PWM_DIMMER module
2020-06-18 18:43:18 +01:00
bool FanMod = false ; // Controls SONOFF_IFAN0X modules
2020-09-24 23:16:26 +01:00
uint8_t ShowTopic ; // Used to hide/unhide a topic during Discovery to spare some cpu load
2020-05-06 18:52:08 +01:00
uint8_t dimmer = 1 ;
2020-06-18 18:43:18 +01:00
uint8_t valid_relay = 0 ;
2020-05-06 18:52:08 +01:00
uint8_t max_lights = 1 ;
2020-06-18 18:43:18 +01:00
uint8_t TuyaRel = 0 ;
uint8_t TuyaRelInv = 0 ;
uint8_t TuyaDim = 0 ;
2021-11-05 08:02:42 +00:00
power_t shutter_mask = 0 ;
2020-05-06 18:52:08 +01:00
2021-12-19 15:41:10 +00:00
# ifdef ESP8266
PwmMod = ( PWM_DIMMER = = TasmotaGlobal . module_type ) ;
FanMod = ( SONOFF_IFAN02 = = TasmotaGlobal . module_type | | SONOFF_IFAN03 = = TasmotaGlobal . module_type ) ;
if ( SONOFF_DUAL = = TasmotaGlobal . module_type ) { valid_relay = 2 ; }
# endif //ESP8266
# ifdef USE_TUYA_MCU
TuyaMod = IsModuleTuya ( ) ;
# endif
2020-05-21 02:11:07 +01:00
2021-08-28 19:02:06 +01:00
# ifdef USE_LIGHT
2020-05-06 18:52:08 +01:00
// If there is a special Light to be enabled and managed with SetOption68 or SetOption37 >= 128, Discovery calculates the maximum number of entities to be generated in advance
if ( PwmMulti ) { max_lights = Light . subtype ; }
if ( ! LightControl ) {
2020-06-18 18:43:18 +01:00
ind_light = true ;
2020-05-06 18:52:08 +01:00
if ( ! PwmMulti ) { max_lights = 2 ; }
}
2021-08-28 19:02:06 +01:00
# endif //USE_LIGHT
2020-05-06 18:52:08 +01:00
2020-06-29 18:38:50 +01:00
# ifdef USE_SHUTTER
2021-06-11 17:14:12 +01:00
if ( Settings - > flag3 . shutter_mode ) {
2020-06-29 18:38:50 +01:00
for ( uint32_t i = 0 ; i < MAX_SHUTTERS ; i + + ) {
2021-11-05 08:02:42 +00:00
if ( Settings - > shutter_startrelay [ i ] > 0 ) {
2021-06-11 17:14:12 +01:00
bitSet ( shutter_mask , Settings - > shutter_startrelay [ i ] - 1 ) ;
bitSet ( shutter_mask , Settings - > shutter_startrelay [ i ] ) ;
2021-11-05 08:02:42 +00:00
} else {
// terminate loop at first INVALID Settings->shutter_startrelay[i].
break ;
2020-06-29 18:38:50 +01:00
}
}
}
# endif
2020-02-06 02:29:44 +00:00
for ( uint32_t i = 1 ; i < = MAX_RELAYS ; i + + )
{
2018-01-18 15:19:28 +00:00
2020-06-18 18:43:18 +01:00
# ifdef USE_TUYA_MCU
2020-10-29 12:58:50 +00:00
TuyaRel = TuyaGetDpId ( ( TUYA_MCU_FUNC_REL1 + i - 1 ) + TasmotaGlobal . active_device - 1 ) ;
TuyaRelInv = TuyaGetDpId ( ( TUYA_MCU_FUNC_REL1_INV + i - 1 ) + TasmotaGlobal . active_device - 1 ) ;
TuyaDim = TuyaGetDpId ( ( TUYA_MCU_FUNC_DIMMER ) + TasmotaGlobal . active_device - 1 ) ;
2020-06-18 18:43:18 +01:00
# endif //USE_TUYA_MCU
2020-10-30 11:29:48 +00:00
TasmotaGlobal . masterlog_level = ShowTopic = 4 ; // Hide topic on clean and remove use weblog 4 to see it
2020-09-24 23:16:26 +01:00
2020-06-20 14:38:17 +01:00
bool RelayX = PinUsed ( GPIO_REL1 , i - 1 ) | | ( valid_relay > = i ) | | ( TuyaRel > 0 & & TuyaMod ) | | ( TuyaRelInv > 0 & & TuyaMod ) ; // Check if the gpio is configured as Relay or force it for Sonoff DUAL R1 with MCU and Tuya MCU
2021-05-07 14:16:05 +01:00
# ifdef USE_MCP230xx_OUTPUT
if ( i < = TasmotaGlobal . devices_present ) {
RelayX = true ;
}
# endif //USE_MCP230xx_OUTPUT
2021-06-11 17:14:12 +01:00
is_topic_light = Settings - > flag . hass_light & & RelayX | | TasmotaGlobal . light_type & & ! RelayX | | PwmMod | | ( TuyaDim > 0 & & TuyaMod ) ; // SetOption30 - Enforce HAss autodiscovery as light
2020-10-30 11:29:48 +00:00
ResponseClear ( ) ; // Clear retained message
2018-02-16 16:35:51 +00:00
2019-03-08 15:38:36 +00:00
// Clear "other" topic first in case the device has been reconfigured from light to switch or vice versa
2020-04-13 16:45:06 +01:00
snprintf_P ( unique_id , sizeof ( unique_id ) , PSTR ( " %06X_%s_%d " ) , ESP_getChipId ( ) , ( is_topic_light ) ? " RL " : " LI " , i ) ;
2019-02-06 19:07:28 +00:00
snprintf_P ( stopic , sizeof ( stopic ) , PSTR ( HOME_ASSISTANT_DISCOVERY_PREFIX " /%s/%s/config " ) ,
( is_topic_light ) ? " switch " : " light " , unique_id ) ;
2018-02-16 16:35:51 +00:00
MqttPublish ( stopic , true ) ;
2018-03-29 12:03:13 +01:00
// Clear or Set topic
2020-04-13 16:45:06 +01:00
snprintf_P ( unique_id , sizeof ( unique_id ) , PSTR ( " %06X_%s_%d " ) , ESP_getChipId ( ) , ( is_topic_light ) ? " LI " : " RL " , i ) ;
2019-02-06 19:07:28 +00:00
snprintf_P ( stopic , sizeof ( stopic ) , PSTR ( HOME_ASSISTANT_DISCOVERY_PREFIX " /%s/%s/config " ) ,
( is_topic_light ) ? " light " : " switch " , unique_id ) ;
2018-01-18 15:19:28 +00:00
2020-06-29 18:38:50 +01:00
if ( bitRead ( shutter_mask , i - 1 ) ) {
// suppress shutter relays
2021-11-05 08:02:42 +00:00
# ifdef USE_LIGHT
2020-06-29 18:38:50 +01:00
} else if ( ( i < Light . device ) & & ! RelayX ) {
2020-05-06 18:52:08 +01:00
err_flag = true ;
2021-06-05 10:47:09 +01:00
AddLog ( LOG_LEVEL_ERROR , PSTR ( " %s " ) , kHAssError2 ) ;
2020-05-06 18:52:08 +01:00
} else {
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . hass_discovery & & ( RelayX | | ( Light . device > 0 ) & & ( max_lights > 0 ) ) & & ! err_flag )
2021-08-28 21:20:10 +01:00
# else
} else {
if ( Settings - > flag . hass_discovery & & RelayX )
# endif //USE_LIGHT
2020-05-21 16:33:57 +01:00
{ // SetOption19 - Control Home Assistant automatic discovery (See SetOption59)
2020-05-17 17:42:14 +01:00
char name [ TOPSZ ] ; // friendlyname(33) + " " + index
2020-05-06 18:52:08 +01:00
char value_template [ 33 ] ;
char prefix [ TOPSZ ] ;
char * command_topic = stemp1 ;
char * state_topic = stemp2 ;
char * availability_topic = stemp3 ;
2020-09-24 23:16:26 +01:00
ShowTopic = 0 ;
2020-05-06 18:52:08 +01:00
if ( i > MAX_FRIENDLYNAMES ) {
2020-08-13 21:46:13 +01:00
snprintf_P ( name , sizeof ( name ) , PSTR ( " %s %d " ) , SettingsText ( SET_FRIENDLYNAME1 ) , i - 1 ) ;
2020-05-06 18:52:08 +01:00
} else {
2020-08-13 21:46:13 +01:00
snprintf_P ( name , sizeof ( name ) , PSTR ( " %s " ) , SettingsText ( SET_FRIENDLYNAME1 + i - 1 ) ) ;
2020-05-06 18:52:08 +01:00
}
2021-06-11 17:14:12 +01:00
GetPowerDevice ( value_template , i , sizeof ( value_template ) , Settings - > flag . device_index_enable ) ; // SetOption26 - Switch between POWER or POWER1
2020-10-30 11:29:48 +00:00
GetTopic_P ( command_topic , CMND , TasmotaGlobal . mqtt_topic , value_template ) ;
GetTopic_P ( state_topic , TELE , TasmotaGlobal . mqtt_topic , D_RSLT_STATE ) ;
GetTopic_P ( availability_topic , TELE , TasmotaGlobal . mqtt_topic , S_LWT ) ;
2020-06-18 18:43:18 +01:00
Response_P ( HASS_DISCOVER_BASE , name , state_topic ) ;
TryResponseAppend_P ( HASS_DISCOVER_SENSOR_LWT , availability_topic ) ;
2021-06-08 15:04:20 +01:00
TryResponseAppend_P ( HASS_DISCOVER_RELAY , command_topic , SettingsText ( SET_STATE_TXT1 ) , SettingsText ( SET_STATE_TXT2 ) ) ;
if ( is_topic_light ) {
TryResponseAppend_P ( HASS_DISCOVER_LIGHT_TEMPLATE , value_template ) ;
} else {
TryResponseAppend_P ( HASS_DISCOVER_RELAY_TEMPLATE , value_template ) ;
}
2020-05-06 18:52:08 +01:00
TryResponseAppend_P ( HASS_DISCOVER_DEVICE_INFO_SHORT , unique_id , ESP_getChipId ( ) ) ;
# ifdef USE_LIGHT
2020-05-21 16:33:57 +01:00
if ( i > = Light . device ) {
2020-06-18 18:43:18 +01:00
if ( ! RelayX | | PwmMod | | ( TuyaDim > 0 & & TuyaMod ) ) {
2020-05-06 18:52:08 +01:00
char * brightness_command_topic = stemp1 ;
2021-06-11 17:14:12 +01:00
strncpy_P ( stemp3 , Settings - > flag . not_power_linked ? PSTR ( " last " ) : PSTR ( " brightness " ) , sizeof ( stemp3 ) ) ; // SetOption20 - Control power in relation to Dimmer/Color/Ct changes
2020-05-06 18:52:08 +01:00
char channel_num [ 9 ] ;
if ( PwmMulti ) { // SetOption68 - Multi-channel PWM instead of a single light
snprintf_P ( channel_num , sizeof ( channel_num ) , PSTR ( " Channel%d " ) , i ) ;
} else {
2020-05-12 18:06:35 +01:00
if ( ! LightControl ) { // SetOption37 >= 128 - Color remapping for led channels, also provides an option for allowing independent handling of RGB and white channels
2020-05-06 18:52:08 +01:00
snprintf_P ( channel_num , sizeof ( channel_num ) , PSTR ( " " D_CMND_DIMMER " %d " ) , dimmer ) ;
dimmer + + ;
} else {
snprintf_P ( channel_num , sizeof ( channel_num ) , PSTR ( " " D_CMND_DIMMER " " ) ) ;
}
}
2020-10-30 11:29:48 +00:00
GetTopic_P ( brightness_command_topic , CMND , TasmotaGlobal . mqtt_topic , channel_num ) ;
2020-05-06 18:52:08 +01:00
TryResponseAppend_P ( HASS_DISCOVER_BASE_LIGHT , brightness_command_topic , state_topic , stemp3 , channel_num ) ;
}
if ( ( ind_light & & ! PwmMulti ) | | LightControl ) {
2018-01-18 15:19:28 +00:00
2020-05-06 18:52:08 +01:00
if ( Light . subtype > = LST_RGB ) {
2021-07-15 16:51:40 +01:00
char * clr_command_topic = stemp1 ;
2018-12-07 20:32:01 +00:00
2021-07-15 16:51:40 +01:00
GetTopic_P ( clr_command_topic , CMND , TasmotaGlobal . mqtt_topic , D_CMND_HSBCOLOR ) ;
TryResponseAppend_P ( HASS_DISCOVER_LIGHT_HS_COLOR , clr_command_topic , state_topic ) ;
2018-01-18 15:19:28 +00:00
2020-05-06 18:52:08 +01:00
char * effect_command_topic = stemp1 ;
2020-10-30 11:29:48 +00:00
GetTopic_P ( effect_command_topic , CMND , TasmotaGlobal . mqtt_topic , D_CMND_SCHEME ) ;
2020-05-06 18:52:08 +01:00
TryResponseAppend_P ( HASS_DISCOVER_LIGHT_SCHEME , effect_command_topic , state_topic ) ;
}
if ( LST_RGBCW = = Light . subtype ) { ct_light = true ; }
}
if ( ( ! ind_light & & ct_light ) | | ( LST_COLDWARM = = Light . subtype & &
! PwmMulti & & LightControl ) ) {
char * color_temp_command_topic = stemp1 ;
2020-10-30 11:29:48 +00:00
GetTopic_P ( color_temp_command_topic , CMND , TasmotaGlobal . mqtt_topic , D_CMND_COLORTEMPERATURE ) ;
2021-07-15 17:16:59 +01:00
TryResponseAppend_P ( HASS_DISCOVER_LIGHT_CT , color_temp_command_topic , state_topic , state_topic ) ;
2020-05-06 18:52:08 +01:00
ct_light = false ;
}
2021-07-15 16:51:40 +01:00
if ( LST_RGBW = = Light . subtype & & ! PwmMulti & & LightControl ) {
2020-05-06 18:52:08 +01:00
char * white_temp_command_topic = stemp1 ;
2020-10-30 11:29:48 +00:00
GetTopic_P ( white_temp_command_topic , CMND , TasmotaGlobal . mqtt_topic , D_CMND_WHITE ) ;
2020-05-06 18:52:08 +01:00
TryResponseAppend_P ( HASS_DISCOVER_LIGHT_WHITE , white_temp_command_topic , state_topic ) ;
}
ind_light = false ;
max_lights - - ;
2018-01-18 15:19:28 +00:00
}
2020-05-06 18:52:08 +01:00
# endif // USE_LIGHT
TryResponseAppend_P ( PSTR ( " } " ) ) ;
2018-01-18 15:19:28 +00:00
}
}
2020-10-30 11:29:48 +00:00
TasmotaGlobal . masterlog_level = ShowTopic ;
2018-01-18 15:19:28 +00:00
MqttPublish ( stopic , true ) ;
}
}
2020-04-21 13:54:17 +01:00
void HAssAnnouncerTriggers ( uint8_t device , uint8_t present , uint8_t key , uint8_t toggle , uint8_t hold , uint8_t single , uint8_t trg_start , uint8_t trg_end )
2018-03-29 12:03:13 +01:00
{
2020-02-06 02:29:44 +00:00
// key 0 = button
// key 1 = switch
2018-12-04 20:31:23 +00:00
char stopic [ TOPSZ ] ;
2018-12-10 18:51:47 +00:00
char stemp1 [ TOPSZ ] ;
char stemp2 [ TOPSZ ] ;
char unique_id [ 30 ] ;
2020-04-21 13:54:17 +01:00
char trigger2 [ 8 ] ;
2020-09-24 23:16:26 +01:00
uint8_t ShowTopic ; // Used to hide/unhide a topic during Discovery to spare some cpu load
2020-10-30 11:29:48 +00:00
ResponseClear ( ) ; // Clear retained message
2018-12-04 20:31:23 +00:00
2020-04-21 13:54:17 +01:00
for ( uint8_t i = trg_start ; i < = trg_end ; i + + ) {
GetTextIndexed ( trigger2 , sizeof ( trigger2 ) , i , kHAssTriggerStringButtons ) ;
snprintf_P ( unique_id , sizeof ( unique_id ) , PSTR ( " %06X_%s_%d_%s " ) , ESP_getChipId ( ) , key ? " SW " : " BTN " , device + 1 , key ? GetStateText ( i ) : trigger2 ) ;
2020-03-12 19:48:44 +00:00
snprintf_P ( stopic , sizeof ( stopic ) , PSTR ( HOME_ASSISTANT_DISCOVERY_PREFIX " /device_automation/%s/config " ) , unique_id ) ;
2020-10-30 11:29:48 +00:00
TasmotaGlobal . masterlog_level = ShowTopic = 4 ; // Hide topic on clean and remove use weblog 4 to see it
2020-09-24 23:16:26 +01:00
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . hass_discovery & & present ) { // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59)
2020-05-17 17:42:14 +01:00
char name [ TOPSZ ] ; // friendlyname(33) + " " + "BTN" + " " + index
2020-03-12 19:48:44 +00:00
char value_template [ 33 ] ;
char prefix [ TOPSZ ] ;
char * state_topic = stemp1 ;
char * availability_topic = stemp2 ;
char jsoname [ 8 ] ;
2020-09-24 23:16:26 +01:00
ShowTopic = 0 ; // Show the new generated topic
2020-03-12 19:48:44 +00:00
2021-06-11 17:14:12 +01:00
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
2020-03-12 19:48:44 +00:00
snprintf_P ( jsoname , sizeof ( jsoname ) , PSTR ( " %s%d " ) , key ? " SWITCH " : " BUTTON " , device + 1 ) ;
2020-10-30 11:29:48 +00:00
GetTopic_P ( state_topic , STAT , TasmotaGlobal . mqtt_topic , jsoname ) ;
GetTopic_P ( availability_topic , TELE , TasmotaGlobal . mqtt_topic , S_LWT ) ;
2020-03-12 19:48:44 +00:00
char param [ 21 ] ;
char subtype [ 9 ] ;
uint8_t pload = toggle ;
2020-04-21 13:54:17 +01:00
if ( key ) {
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 ( " switch_%d " ) , device + 1 ) ;
Response_P ( HASS_TRIGGER_TYPE , state_topic , GetStateText ( i ) , param , subtype , ESP_getChipId ( ) ) ;
2020-10-30 11:29:48 +00:00
} else { ResponseClear ( ) ; } // Need to be cleaned again to avoid duplicate
2020-04-21 13:54:17 +01:00
} else {
char trigger1 [ 24 ] ;
GetTextIndexed ( trigger1 , sizeof ( trigger1 ) , i , kHAssTriggerTypeButtons ) ;
snprintf_P ( subtype , sizeof ( subtype ) , PSTR ( " button_%d " ) , device + 1 ) ;
if ( i > 1 & & single ) {
2020-10-30 11:29:48 +00:00
ResponseClear ( ) ; // Need to be cleaned again to avoid duplicate
2020-04-21 13:54:17 +01:00
} else {
Response_P ( HASS_TRIGGER_TYPE , state_topic , trigger2 , trigger1 , subtype , ESP_getChipId ( ) ) ;
}
}
2020-03-12 19:48:44 +00:00
}
2020-10-30 11:29:48 +00:00
TasmotaGlobal . masterlog_level = ShowTopic ;
2020-03-12 19:48:44 +00:00
MqttPublish ( stopic , true ) ;
}
}
2020-03-14 21:36:19 +00:00
void HAssAnnouncerBinSensors ( uint8_t device , uint8_t present , uint8_t dual , uint8_t toggle , uint8_t pir )
2020-03-12 19:48:44 +00:00
{
char stopic [ TOPSZ ] ;
char stemp1 [ TOPSZ ] ;
char stemp2 [ TOPSZ ] ;
char unique_id [ 30 ] ;
2020-09-24 23:16:26 +01:00
uint8_t ShowTopic ; // Used to hide/unhide a topic during Discovery to spare some cpu load
2020-10-30 11:29:48 +00:00
ResponseClear ( ) ; // Clear retained message
TasmotaGlobal . masterlog_level = 4 ; // Hide topic on clean and remove use weblog 4 to see it
2020-09-24 23:16:26 +01:00
2020-03-12 19:48:44 +00:00
2020-04-13 16:45:06 +01:00
snprintf_P ( unique_id , sizeof ( unique_id ) , PSTR ( " %06X_SW_%d " ) , ESP_getChipId ( ) , device + 1 ) ;
2018-12-10 18:51:47 +00:00
snprintf_P ( stopic , sizeof ( stopic ) , PSTR ( HOME_ASSISTANT_DISCOVERY_PREFIX " /binary_sensor/%s/config " ) , unique_id ) ;
2018-12-04 20:31:23 +00:00
2020-10-30 11:29:48 +00:00
TasmotaGlobal . masterlog_level = ShowTopic = 4 ; // Hide topic on clean and remove use weblog 4 to see it
2018-12-04 20:31:23 +00:00
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . hass_discovery & & present ) { // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59)
2020-03-12 19:48:44 +00:00
if ( ! toggle | | dual ) {
2020-05-17 17:42:14 +01:00
char name [ TOPSZ ] ; // friendlyname(33) + " " + "BTN" + " " + index
2020-03-12 19:48:44 +00:00
char value_template [ 33 ] ;
char prefix [ TOPSZ ] ;
char * state_topic = stemp1 ;
char * availability_topic = stemp2 ;
char jsoname [ 8 ] ;
2019-10-24 22:29:06 +01:00
2020-09-24 23:16:26 +01:00
ShowTopic = 0 ;
2021-06-11 17:14:12 +01:00
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
2020-03-12 19:48:44 +00:00
snprintf_P ( jsoname , sizeof ( jsoname ) , PSTR ( " SWITCH%d " ) , device + 1 ) ;
2020-10-30 11:29:48 +00:00
GetTopic_P ( state_topic , STAT , TasmotaGlobal . mqtt_topic , jsoname ) ;
GetTopic_P ( availability_topic , TELE , TasmotaGlobal . mqtt_topic , S_LWT ) ;
2020-02-06 16:32:54 +00:00
2020-05-17 17:42:14 +01:00
snprintf_P ( name , sizeof ( name ) , PSTR ( " %s Switch%d " ) , SettingsText ( SET_DEVICENAME ) , device + 1 ) ;
2020-03-12 19:48:44 +00:00
Response_P ( HASS_DISCOVER_BASE , name , state_topic , availability_topic ) ;
2020-03-14 21:36:19 +00:00
if ( ! pir ) {
TryResponseAppend_P ( HASS_DISCOVER_BIN_SWITCH , PSTR ( D_RSLT_STATE ) , SettingsText ( SET_STATE_TXT2 ) , SettingsText ( SET_STATE_TXT1 ) ) ;
} else {
TryResponseAppend_P ( HASS_DISCOVER_BIN_PIR , PSTR ( D_RSLT_STATE ) , SettingsText ( SET_STATE_TXT2 ) ) ;
}
2020-04-13 16:45:06 +01:00
TryResponseAppend_P ( HASS_DISCOVER_DEVICE_INFO_SHORT , unique_id , ESP_getChipId ( ) ) ;
2020-06-18 18:43:18 +01:00
# ifdef DEEPSLEEP_LWT_HA_DISCOVERY
TryResponseAppend_P ( HASS_DISCOVER_SENSOR_LWT , availability_topic ) ;
# else
2021-06-11 17:14:12 +01:00
if ( Settings - > deepsleep = = 0 )
2020-06-18 18:43:18 +01:00
{
TryResponseAppend_P ( HASS_DISCOVER_SENSOR_LWT , availability_topic ) ;
}
# endif //DEEPSLEEP_LWT_HA_DISCOVERY
2020-03-12 19:48:44 +00:00
TryResponseAppend_P ( PSTR ( " } " ) ) ;
2019-11-15 01:37:30 +00:00
}
2018-12-04 20:31:23 +00:00
}
2020-10-30 11:29:48 +00:00
TasmotaGlobal . masterlog_level = ShowTopic ;
2018-12-04 20:31:23 +00:00
MqttPublish ( stopic , true ) ;
2020-09-24 23:16:26 +01:00
2018-12-04 20:31:23 +00:00
}
void HAssAnnounceSwitches ( void )
{
2023-02-06 10:45:28 +00:00
for ( uint32_t switch_index = 0 ; switch_index < MAX_SWITCHES_SET ; switch_index + + )
2020-02-06 02:29:44 +00:00
{
2020-03-12 19:48:44 +00:00
uint8_t switch_present = 0 ;
uint8_t dual = 0 ;
uint8_t toggle = 1 ;
uint8_t hold = 0 ;
2020-03-14 21:36:19 +00:00
uint8_t pir = 0 ;
2020-03-12 19:48:44 +00:00
2023-02-06 10:45:28 +00:00
if ( SwitchUsed ( switch_index ) ) { switch_present = 1 ; }
2020-03-13 11:00:52 +00:00
2020-10-30 11:29:48 +00:00
if ( KeyTopicActive ( 1 ) & & strcmp ( SettingsText ( SET_MQTT_SWITCH_TOPIC ) , TasmotaGlobal . mqtt_topic ) ) // Enable Discovery for Switches only if SwitchTopic is set to a custom name
2020-02-06 02:29:44 +00:00
{
2018-12-04 20:31:23 +00:00
2020-03-12 19:48:44 +00:00
// 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)
2020-03-18 14:02:20 +00:00
// 13 PUSHON YES NONE NONE NONE 0,0
// 14 PUSHON_INV YES NONE NONE NONE 0,0
2020-03-12 19:48:44 +00:00
// Please note: SwitchMode11 and 12 will register just TOGGLE (button_short_press)
2020-03-13 11:00:52 +00:00
2020-03-12 19:48:44 +00:00
// Trigger types: "0 = none | 1 = button_short_press | 2 = button_long_press | 3 = button_double_press";
2021-06-11 17:14:12 +01:00
uint8_t swmode = Settings - > switchmode [ switch_index ] ;
2020-03-12 19:48:44 +00:00
switch ( swmode ) {
2020-03-15 10:41:24 +00:00
case FOLLOW :
case FOLLOW_INV :
2020-03-12 19:48:44 +00:00
toggle = 0 ; // Binary sensor and no triggers
break ;
2020-03-15 10:41:24 +00:00
case PUSHBUTTON :
case PUSHBUTTON_INV :
2020-03-12 19:48:44 +00:00
dual = 1 ; // Binary sensor and TOGGLE (button_short_press) trigger
break ;
2020-03-15 10:41:24 +00:00
case PUSHBUTTONHOLD :
case PUSHBUTTONHOLD_INV :
2020-03-12 19:48:44 +00:00
dual = 1 ; // Binary sensor, TOGGLE (button_short_press) and HOLD (button_long_press) triggers
hold = 2 ;
break ;
2020-03-15 10:41:24 +00:00
case TOGGLEMULTI :
2020-03-12 19:48:44 +00:00
hold = 3 ; // TOGGLE (button_short_press) and HOLD (button_double_press) triggers
break ;
2020-03-15 10:41:24 +00:00
case FOLLOWMULTI :
case FOLLOWMULTI_INV :
2020-03-12 19:48:44 +00:00
dual = 1 ; // Binary sensor and HOLD (button_long_press) trigger
toggle = 0 ;
hold = 3 ;
break ;
2020-03-15 10:41:24 +00:00
case PUSHON :
case PUSHON_INV :
2020-03-14 21:36:19 +00:00
toggle = 0 ;
2020-04-21 13:54:17 +01:00
pir = 1 ; // Binary sensor with only ON state and automatic OFF after 1 second
2018-12-04 20:31:23 +00:00
}
2020-03-13 11:00:52 +00:00
2020-03-12 19:48:44 +00:00
} else { switch_present = 0 ; }
2018-12-04 20:31:23 +00:00
2020-04-21 13:54:17 +01:00
HAssAnnouncerTriggers ( switch_index , switch_present , 1 , toggle , hold , 0 , 2 , 3 ) ;
2020-03-14 21:36:19 +00:00
HAssAnnouncerBinSensors ( switch_index , switch_present , dual , toggle , pir ) ;
2018-12-04 20:31:23 +00:00
}
}
void HAssAnnounceButtons ( void )
{
2023-02-06 11:03:32 +00:00
for ( uint32_t button_index = 0 ; button_index < MAX_KEYS_SET ; button_index + + )
2020-02-06 02:29:44 +00:00
{
2020-03-12 19:48:44 +00:00
uint8_t button_present = 0 ;
2020-04-21 13:54:17 +01:00
uint8_t single = 0 ;
2018-03-29 12:03:13 +01:00
2020-04-10 17:24:08 +01:00
# ifdef ESP8266
2020-10-30 11:29:48 +00:00
if ( ! button_index & & ( ( SONOFF_DUAL = = TasmotaGlobal . module_type ) | | ( CH4 = = TasmotaGlobal . module_type ) ) )
2020-03-12 19:48:44 +00:00
{
button_present = 1 ;
2020-04-10 17:24:08 +01:00
} else
2020-06-18 18:43:18 +01:00
# endif // ESP8266
2020-04-10 17:24:08 +01:00
{
2023-02-06 11:03:32 +00:00
if ( ButtonUsed ( button_index ) ) {
2018-03-29 12:03:13 +01:00
button_present = 1 ;
2020-02-06 02:29:44 +00:00
}
2020-03-12 19:48:44 +00:00
}
2018-03-29 12:03:13 +01:00
2020-04-21 13:54:17 +01:00
// Button matrix for triggers generation when SetOption73 is enabled:
// N SetOption1 SetOption11 SetOption13 PRESS MULTI PRESS HOLD
// 1 0 0 0 SINGLE (10 - button_short_press) DOUBLE to PENTA YES (button_long_press)
// 2 1 0 0 SINGLE (10 - button_short_press) DOUBLE to PENTA YES (button_long_press)
// 3 0 1 0 DOUBLE (11 - button_short_press) SINGLE then TRIPLE TO PENTA YES (button_long_press)
// 4 1 1 0 DOUBLE (11 - button_short_press) SINGLE then TRIPLE TO PENTA YES (button_long_press)
// 5 0 0 1 SINGLE (10 - button_short_press) NONE NONE
// 6 1 0 1 SINGLE (10 - button_short_press) NONE NONE
// 7 0 1 1 SINGLE (10 - button_short_press) NONE NONE
// 8 1 1 1 SINGLE (10 - button_short_press) NONE NONE
// Trigger types: 10 = button_short_press | 11 = button_double_press | 12 = button_triple_press | 13 = button_quadruple_press | 14 = button_quintuple_press | 3 = button_long_press
2021-06-11 17:14:12 +01:00
if ( ! Settings - > flag3 . mqtt_buttons ) { // Enable Buttons for discovery [SetOption73] - Decouple button from relay and send just mqtt topic
2020-04-21 13:54:17 +01:00
button_present = 0 ;
} else {
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . button_single ) { // [SetOption13] Immediate action on button press, just SINGLE trigger
2020-04-21 13:54:17 +01:00
single = 1 ;
}
2020-03-12 19:48:44 +00:00
}
2020-04-21 13:54:17 +01:00
HAssAnnouncerTriggers ( button_index , button_present , 0 , 0 , 0 , single , 1 , 6 ) ;
2018-03-29 12:03:13 +01:00
}
}
2020-09-24 23:16:26 +01:00
void HAssAnnounceSensor ( const char * sensorname , const char * subsensortype , const char * MultiSubName , uint8_t subqty , bool nested , const char * SubKey )
2018-11-18 14:33:13 +00:00
{
char stopic [ TOPSZ ] ;
2018-12-10 18:51:47 +00:00
char stemp1 [ TOPSZ ] ;
char stemp2 [ TOPSZ ] ;
char unique_id [ 30 ] ;
2020-03-18 14:02:20 +00:00
char subname [ 20 ] ;
2018-11-18 14:33:13 +00:00
2020-10-30 11:29:48 +00:00
ResponseClear ( ) ; // Clear retained message
2020-04-10 17:24:08 +01:00
// Clear or Set topic
2020-03-18 14:02:20 +00:00
NoAlNumToUnderscore ( subname , MultiSubName ) ; //Replace all non alphaumeric characters to '_' to avoid topic name issues
2020-04-13 16:45:06 +01:00
snprintf_P ( unique_id , sizeof ( unique_id ) , PSTR ( " %06X_%s_%s " ) , ESP_getChipId ( ) , sensorname , subname ) ;
2020-03-18 14:02:20 +00:00
snprintf_P ( stopic , sizeof ( stopic ) , PSTR ( HOME_ASSISTANT_DISCOVERY_PREFIX " /sensor/%s/config " ) , unique_id ) ;
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . hass_discovery )
2020-02-06 02:29:44 +00:00
{ // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59)
2020-05-17 17:42:14 +01:00
char name [ TOPSZ ] ; // friendlyname(33) + " " + sensorname(20?) + " " + sensortype(20?)
2018-11-18 14:33:13 +00:00
char prefix [ TOPSZ ] ;
2018-12-10 18:51:47 +00:00
char * state_topic = stemp1 ;
char * availability_topic = stemp2 ;
2020-10-30 11:29:48 +00:00
TasmotaGlobal . masterlog_level = 0 ; // Show the new generated topic
2018-11-18 14:33:13 +00:00
2020-10-30 11:29:48 +00:00
GetTopic_P ( state_topic , TELE , TasmotaGlobal . mqtt_topic , PSTR ( D_RSLT_SENSOR ) ) ;
2020-05-17 17:42:14 +01:00
snprintf_P ( name , sizeof ( name ) , PSTR ( " %s %s %s " ) , SettingsText ( SET_DEVICENAME ) , sensorname , MultiSubName ) ;
2020-10-30 11:29:48 +00:00
GetTopic_P ( availability_topic , TELE , TasmotaGlobal . mqtt_topic , S_LWT ) ;
2018-12-22 12:15:55 +00:00
2020-06-18 18:43:18 +01:00
Response_P ( HASS_DISCOVER_BASE , name , state_topic ) ;
2020-09-24 23:16:26 +01:00
# ifdef DEEPSLEEP_LWT_HA_DISCOVERY
2020-06-18 18:43:18 +01:00
TryResponseAppend_P ( HASS_DISCOVER_SENSOR_LWT , availability_topic ) ;
# else
2021-06-11 17:14:12 +01:00
if ( Settings - > deepsleep = = 0 )
2020-06-18 18:43:18 +01:00
{
TryResponseAppend_P ( HASS_DISCOVER_SENSOR_LWT , availability_topic ) ;
}
# endif //DEEPSLEEP_LWT_HA_DISCOVERY
2020-04-13 16:45:06 +01:00
TryResponseAppend_P ( HASS_DISCOVER_DEVICE_INFO_SHORT , unique_id , ESP_getChipId ( ) ) ;
2020-03-12 19:48:44 +00:00
2020-02-06 16:32:54 +00:00
2020-02-06 02:29:44 +00:00
char jname [ 32 ] ;
2020-03-18 14:02:20 +00:00
int sensor_index = GetCommandCode ( jname , sizeof ( jname ) , SubKey , kHAssJsonSensorTypes ) ;
2020-02-06 02:29:44 +00:00
if ( sensor_index > - 1 ) {
2020-03-18 14:02:20 +00:00
2020-02-06 02:29:44 +00:00
char param1 [ 20 ] ;
2020-02-06 16:32:54 +00:00
GetTextIndexed ( param1 , sizeof ( param1 ) , sensor_index , kHAssJsonSensorUnits ) ;
2020-02-06 02:29:44 +00:00
switch ( sensor_index ) {
2020-03-18 14:02:20 +00:00
case 0 : // Temperature and DewPoint
case 1 :
2020-02-06 02:29:44 +00:00
snprintf_P ( param1 , sizeof ( param1 ) , PSTR ( " °%c " ) , TempUnit ( ) ) ; // C or F
break ;
2020-03-18 14:02:20 +00:00
case 2 : // Pressure and Sea Level Pressure
case 3 :
2020-02-06 02:29:44 +00:00
snprintf_P ( param1 , sizeof ( param1 ) , PSTR ( " %s " ) , PressureUnit ( ) . c_str ( ) ) ;
break ;
2020-03-18 14:02:20 +00:00
}
2020-02-06 02:29:44 +00:00
char param2 [ 50 ] ;
2020-02-06 16:32:54 +00:00
GetTextIndexed ( param2 , sizeof ( param2 ) , sensor_index , kHAssJsonSensorDevCla ) ;
2020-02-06 02:29:44 +00:00
TryResponseAppend_P ( HASS_DISCOVER_SENSOR , param1 , param2 , sensorname , subsensortype ) ;
2020-03-18 14:02:20 +00:00
2020-02-06 02:29:44 +00:00
} else {
TryResponseAppend_P ( HASS_DISCOVER_SENSOR , " " , " ic \" : \" mdi:eye " , sensorname , subsensortype ) ;
2018-11-18 14:33:13 +00:00
}
2020-09-24 23:16:26 +01:00
if ( nested ) { TryResponseAppend_P ( PSTR ( " ['%s'] " ) , SubKey ) ; }
if ( subqty ! = 0 ) { TryResponseAppend_P ( PSTR ( " [%d] " ) , subqty - 1 ) ; }
2020-02-06 02:29:44 +00:00
TryResponseAppend_P ( PSTR ( " }} \" } " ) ) ;
2018-11-18 14:33:13 +00:00
}
MqttPublish ( stopic , true ) ;
}
void HAssAnnounceSensors ( void )
{
uint8_t hass_xsns_index = 0 ;
2020-02-06 02:29:44 +00:00
do
{
2020-10-30 11:29:48 +00:00
ResponseClear ( ) ;
2020-10-29 12:37:09 +00:00
int tele_period_save = TasmotaGlobal . tele_period ;
TasmotaGlobal . tele_period = 2 ; // Do not allow HA updates during next function call
2020-02-06 02:29:44 +00:00
XsnsNextCall ( FUNC_JSON_APPEND , hass_xsns_index ) ; // ,"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}
2020-10-29 12:37:09 +00:00
TasmotaGlobal . tele_period = tele_period_save ;
2021-05-24 15:52:59 +01:00
size_t sensordata_len = ResponseLength ( ) ;
2020-09-24 23:16:26 +01:00
char sensordata [ sensordata_len + 2 ] ; // dynamically adjust the size
2021-08-15 16:08:31 +01:00
strcpy ( sensordata , ResponseData ( ) ) ; // we can use strcpy since the buffer has the right size
2018-11-18 14:33:13 +00:00
2020-09-24 23:16:26 +01:00
// ******************* JSON TEST *******************
// char sensordata[512];
// snprintf_P(sensordata, sizeof(sensordata), PSTR("{\"ENERGY\":{\"TotalStartTime\":\"2018-11-23T15:33:47\",\"ExportTariff\":[0.000,0.017],\"Speed\":{\"Act\":\"NE\"}}}"));
// size_t sensordata_len = strlen(sensordata);
// ******************* JSON TEST *******************
2018-11-18 14:33:13 +00:00
2020-09-24 23:16:26 +01:00
if ( sensordata_len > 0 )
2020-02-06 02:29:44 +00:00
{
2020-09-24 23:16:26 +01:00
// // We replace the leader ',' with '{'
2020-02-06 02:29:44 +00:00
sensordata [ 0 ] = ' { ' ;
2020-09-24 23:16:26 +01:00
// // and we add a trailing '}' after the last '}'
sensordata [ sensordata_len ] = ' } ' ;
sensordata [ sensordata_len + 1 ] = ' \0 ' ;
JsonParser parser ( sensordata ) ;
JsonParserObject root = parser . getRootObject ( ) ;
if ( ! root )
2020-02-06 02:29:44 +00:00
{
2021-06-05 10:47:09 +01:00
AddLog ( LOG_LEVEL_ERROR , PSTR ( " %s '%s' (ERR1) " ) , kHAssError3 , sensordata ) ;
2018-11-18 14:33:13 +00:00
continue ;
}
2020-09-24 23:16:26 +01:00
for ( auto sensor_key : root )
2020-02-06 02:29:44 +00:00
{
2020-09-24 23:16:26 +01:00
// sensor is of type JsonParserKey
const char * sensorname = sensor_key . getStr ( ) ;
JsonParserObject sensors = sensor_key . getValue ( ) . getObject ( ) ;
if ( ! sensors )
2020-02-06 02:29:44 +00:00
{
2021-06-05 10:47:09 +01:00
AddLog ( LOG_LEVEL_ERROR , PSTR ( " %s '%s' (ERR2) " ) , kHAssError3 , sensorname ) ;
2018-11-18 14:33:13 +00:00
continue ;
}
2020-03-18 14:02:20 +00:00
2020-09-24 23:16:26 +01:00
for ( auto subsensor_key_token : sensors )
2020-02-06 02:29:44 +00:00
{
2020-09-24 23:16:26 +01:00
const char * subsensor_key = subsensor_key_token . getStr ( ) ;
JsonParserToken subsensor = subsensor_key_token . getValue ( ) ;
if ( subsensor . isObject ( ) ) {
2020-03-18 14:02:20 +00:00
// If there is a nested json on sensor data, second level entitites will be created
2020-09-24 23:16:26 +01:00
JsonParserObject subsensors = subsensor . getObject ( ) ;
2020-03-18 14:02:20 +00:00
char NewSensorName [ 20 ] ;
2020-09-24 23:16:26 +01:00
for ( auto subsensor2_key : subsensors ) {
snprintf_P ( NewSensorName , sizeof ( NewSensorName ) , PSTR ( " %s %s " ) , subsensor_key , subsensor2_key . getStr ( ) ) ;
HAssAnnounceSensor ( sensorname , subsensor_key , NewSensorName , 0 , 1 , subsensor2_key . getStr ( ) ) ;
2020-04-10 17:24:08 +01:00
}
2020-09-24 23:16:26 +01:00
} else if ( subsensor . isArray ( ) ) {
2020-03-18 14:02:20 +00:00
// If there is more than a value on sensor data, 'n' entitites will be created
2020-09-24 23:16:26 +01:00
JsonParserArray subsensors = subsensor . getArray ( ) ;
2020-03-18 14:02:20 +00:00
uint8_t subqty = subsensors . size ( ) ;
2020-02-06 02:29:44 +00:00
char MultiSubName [ 20 ] ;
for ( int i = 1 ; i < = subqty ; i + + ) {
2020-09-24 23:16:26 +01:00
snprintf_P ( MultiSubName , sizeof ( MultiSubName ) , PSTR ( " %s %d " ) , subsensor_key , i ) ;
HAssAnnounceSensor ( sensorname , subsensor_key , MultiSubName , i , 0 , subsensor_key ) ;
2020-02-06 02:29:44 +00:00
}
2020-09-24 23:16:26 +01:00
} else {
HAssAnnounceSensor ( sensorname , subsensor_key , subsensor_key , 0 , 0 , subsensor_key ) ; }
2018-11-18 14:33:13 +00:00
}
}
}
2019-01-08 14:25:12 +00:00
yield ( ) ;
2018-11-18 14:33:13 +00:00
} while ( hass_xsns_index ! = 0 ) ;
}
2020-06-29 18:44:26 +01:00
void HAssAnnounceShutters ( void )
{
# ifdef USE_SHUTTER
char stopic [ TOPSZ ] ;
char stemp1 [ TOPSZ ] ;
char stemp2 [ TOPSZ ] ;
char unique_id [ 30 ] ;
2020-09-24 23:16:26 +01:00
uint8_t ShowTopic ; // Used to hide/unhide a topic during Discovery to spare some cpu load
2020-06-29 18:44:26 +01:00
for ( uint32_t i = 0 ; i < MAX_SHUTTERS ; i + + ) {
2020-10-30 11:29:48 +00:00
ResponseClear ( ) ; // Clear retained message
TasmotaGlobal . masterlog_level = ShowTopic = 4 ; // Hide topic on clean and remove use weblog 4 to see it
2020-09-24 23:16:26 +01:00
2020-06-29 18:44:26 +01:00
snprintf_P ( unique_id , sizeof ( unique_id ) , PSTR ( " %06X_SHT_%d " ) , ESP_getChipId ( ) , i + 1 ) ;
snprintf_P ( stopic , sizeof ( stopic ) , PSTR ( HOME_ASSISTANT_DISCOVERY_PREFIX " /cover/%s/config " ) , unique_id ) ;
2021-11-05 08:02:42 +00:00
if ( Settings - > flag . hass_discovery & & Settings - > flag3 . shutter_mode & & Settings - > shutter_startrelay [ i ] > 0 ) {
2020-09-24 23:16:26 +01:00
ShowTopic = 0 ; // Show the new generated topic
2020-06-29 18:44:26 +01:00
if ( i > MAX_FRIENDLYNAMES ) {
snprintf_P ( stemp1 , sizeof ( stemp1 ) , PSTR ( " %s Shutter %d " ) , SettingsText ( SET_DEVICENAME ) , i + 1 ) ;
} else {
snprintf_P ( stemp1 , sizeof ( stemp1 ) , PSTR ( " %s " ) , SettingsText ( SET_FRIENDLYNAME1 + i ) ) ;
}
2022-01-12 21:50:27 +00:00
Response_P ( PSTR ( " { \" name \" : \" %s \" " ) , stemp1 ) ;
2020-06-29 18:44:26 +01:00
2020-10-30 11:29:48 +00:00
GetTopic_P ( stemp1 , TELE , TasmotaGlobal . mqtt_topic , S_LWT ) ;
2020-06-29 18:44:26 +01:00
TryResponseAppend_P ( HASS_DISCOVER_SENSOR_LWT , stemp1 ) ;
2020-10-30 11:29:48 +00:00
GetTopic_P ( stemp1 , CMND , TasmotaGlobal . mqtt_topic , PSTR ( " Backlog " ) ) ;
2020-06-29 18:44:26 +01:00
TryResponseAppend_P ( HASS_DISCOVER_SHUTTER_BASE , stemp1 , i + 1 , i + 1 , i + 1 ) ;
2020-10-30 11:29:48 +00:00
GetTopic_P ( stemp1 , STAT , TasmotaGlobal . mqtt_topic , PSTR ( " SHUTTER " ) ) ;
GetTopic_P ( stemp2 , CMND , TasmotaGlobal . mqtt_topic , PSTR ( " ShutterPosition " ) ) ;
2020-06-29 18:44:26 +01:00
TryResponseAppend_P ( HASS_DISCOVER_SHUTTER_POS , stemp1 , i + 1 , stemp2 , i + 1 ) ;
2021-12-19 15:41:10 +00:00
2022-01-12 21:54:49 +00:00
if ( Settings - > shutter_tilt_config [ 3 ] [ i ] ! = Settings - > shutter_tilt_config [ 4 ] [ i ] ) {
GetTopic_P ( stemp1 , CMND , TasmotaGlobal . mqtt_topic , PSTR ( " ShutterTilt " ) ) ;
TryResponseAppend_P ( HASS_DISCOVER_SHUTTER_TILT , stemp1 , i + 1 , Settings - > shutter_tilt_config [ 3 ] [ i ] , Settings - > shutter_tilt_config [ 4 ] [ i ] ) ;
}
2021-12-19 15:41:10 +00:00
2020-06-29 18:44:26 +01:00
TryResponseAppend_P ( HASS_DISCOVER_DEVICE_INFO_SHORT , unique_id , ESP_getChipId ( ) ) ;
TryResponseAppend_P ( PSTR ( " } " ) ) ;
2021-11-05 08:02:42 +00:00
} else {
// terminate loop at first INVALID Settings->shutter_startrelay[i].
break ;
2020-06-29 18:44:26 +01:00
}
2020-10-30 11:29:48 +00:00
TasmotaGlobal . masterlog_level = ShowTopic ;
2020-06-29 18:44:26 +01:00
MqttPublish ( stopic , true ) ;
}
# endif
}
2020-04-21 13:54:17 +01:00
void HAssAnnounceDeviceInfoAndStatusSensor ( void )
2019-02-06 19:07:28 +00:00
{
char stopic [ TOPSZ ] ;
char stemp1 [ TOPSZ ] ;
char stemp2 [ TOPSZ ] ;
char unique_id [ 30 ] ;
2020-09-24 23:16:26 +01:00
uint8_t ShowTopic ; // Used to hide/unhide a topic during Discovery to spare some cpu load
2019-02-06 19:07:28 +00:00
// Announce sensor
2020-10-30 11:29:48 +00:00
ResponseClear ( ) ; // Clear retained message
TasmotaGlobal . masterlog_level = ShowTopic = 4 ; // Hide topic on clean and remove use weblog 4 to see it
2019-02-06 19:07:28 +00:00
// Clear or Set topic
2020-04-13 16:45:06 +01:00
snprintf_P ( unique_id , sizeof ( unique_id ) , PSTR ( " %06X_status " ) , ESP_getChipId ( ) ) ;
2019-02-06 19:07:28 +00:00
snprintf_P ( stopic , sizeof ( stopic ) , PSTR ( HOME_ASSISTANT_DISCOVERY_PREFIX " /sensor/%s/config " ) , unique_id ) ;
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . hass_discovery )
2020-02-06 02:29:44 +00:00
{ // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59)
2020-05-17 17:42:14 +01:00
char name [ TOPSZ ] ; // friendlyname(33) + " " + "status"
2019-02-06 19:07:28 +00:00
char prefix [ TOPSZ ] ;
char * state_topic = stemp1 ;
char * availability_topic = stemp2 ;
2020-09-24 23:16:26 +01:00
ShowTopic = 0 ; // Show the new generated topic
2020-05-17 17:42:14 +01:00
snprintf_P ( name , sizeof ( name ) , PSTR ( " %s status " ) , SettingsText ( SET_DEVICENAME ) ) ;
2020-10-30 11:29:48 +00:00
GetTopic_P ( state_topic , TELE , TasmotaGlobal . mqtt_topic , PSTR ( D_RSLT_HASS_STATE ) ) ;
GetTopic_P ( availability_topic , TELE , TasmotaGlobal . mqtt_topic , S_LWT ) ;
2019-02-06 19:07:28 +00:00
2020-06-18 18:43:18 +01:00
Response_P ( HASS_DISCOVER_BASE , name , state_topic ) ;
TryResponseAppend_P ( HASS_DISCOVER_SENSOR_LWT , availability_topic ) ;
2019-03-24 13:23:20 +00:00
TryResponseAppend_P ( HASS_DISCOVER_SENSOR_HASS_STATUS , state_topic ) ;
2020-05-17 17:42:14 +01:00
TryResponseAppend_P ( HASS_DISCOVER_DEVICE_INFO , unique_id , ESP_getChipId ( ) , SettingsText ( SET_DEVICENAME ) ,
2020-10-30 11:29:48 +00:00
ModuleName ( ) . c_str ( ) , TasmotaGlobal . version , TasmotaGlobal . image_name ) ;
2019-03-24 13:23:20 +00:00
TryResponseAppend_P ( PSTR ( " } " ) ) ;
2019-02-06 19:07:28 +00:00
}
2020-10-30 11:29:48 +00:00
TasmotaGlobal . masterlog_level = ShowTopic ;
2019-02-06 19:07:28 +00:00
MqttPublish ( stopic , true ) ;
2020-09-24 23:16:26 +01:00
2021-06-11 17:14:12 +01:00
if ( ! Settings - > flag . hass_discovery ) {
2020-10-30 11:29:48 +00:00
TasmotaGlobal . masterlog_level = 0 ;
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_LOG " Home Assistant MQTT Discovery disabled. " ) ) ;
2020-08-13 21:46:13 +01:00
}
2019-02-06 19:07:28 +00:00
}
void HAssPublishStatus ( void )
{
2020-05-06 18:52:08 +01:00
Response_P ( PSTR ( " { \" " D_JSON_VERSION " \" : \" %s%s \" , \" " D_JSON_BUILDDATETIME " \" : \" %s \" , \" " D_CMND_MODULE " or " D_CMND_TEMPLATE " \" : \" %s \" , "
" \" " D_JSON_RESTARTREASON " \" : \" %s \" , \" " D_JSON_UPTIME " \" : \" %s \" , \" " D_CMND_HOSTNAME " \" : \" %s \" , "
2021-01-27 11:03:20 +00:00
" \" " D_CMND_IPADDRESS " \" : \" %_I \" , \" " D_JSON_RSSI " \" : \" %d \" , \" " D_JSON_SIGNAL " (dBm) " " \" : \" %d \" , "
2020-05-06 18:52:08 +01:00
" \" WiFi " D_JSON_LINK_COUNT " \" :%d, \" WiFi " D_JSON_DOWNTIME " \" : \" %s \" , \" " D_JSON_MQTT_COUNT " \" :%d, \" LoadAvg \" :%lu} " ) ,
2020-10-30 11:29:48 +00:00
TasmotaGlobal . version , TasmotaGlobal . image_name , GetBuildDateAndTime ( ) . c_str ( ) , ModuleName ( ) . c_str ( ) , GetResetReason ( ) . c_str ( ) ,
2021-01-27 11:03:20 +00:00
GetUptime ( ) . c_str ( ) , TasmotaGlobal . hostname , ( uint32_t ) WiFi . localIP ( ) , WifiGetRssiAsQuality ( WiFi . RSSI ( ) ) ,
2020-10-28 16:32:07 +00:00
WiFi . RSSI ( ) , WifiLinkCount ( ) , WifiDowntime ( ) . c_str ( ) , MqttConnectCount ( ) , TasmotaGlobal . loop_load_avg ) ;
2019-02-06 19:07:28 +00:00
MqttPublishPrefixTopic_P ( TELE , PSTR ( D_RSLT_HASS_STATE ) ) ;
}
2019-01-22 11:46:55 +00:00
void HAssDiscovery ( void )
2018-03-29 12:03:13 +01:00
{
// Configure Tasmota for default Home Assistant parameters to keep discovery message as short as possible
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . hass_discovery )
2020-09-18 22:45:20 +01:00
{ // SetOption19 - Control Home Assistant automatic discovery (See SetOption59)
2021-06-11 17:14:12 +01:00
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
2020-09-18 22:45:20 +01:00
// 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.
2021-06-11 17:14:12 +01:00
//Settings->light_scheme = 0; // To just control color it needs to be Scheme 0 (on hold due to new light configuration)
2018-03-29 12:03:13 +01:00
}
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . hass_discovery | | ( 1 = = hass_mode ) )
2020-02-06 02:29:44 +00:00
{ // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59)
2020-10-01 15:47:01 +01:00
hass_mode = 2 ; // Needed for generating bluetooth entities for MI_ESP32
2018-03-29 13:01:38 +01:00
// Send info about buttons
2018-12-04 20:31:23 +00:00
HAssAnnounceButtons ( ) ;
2018-11-18 14:33:13 +00:00
2018-12-04 20:31:23 +00:00
// Send info about switches
HAssAnnounceSwitches ( ) ;
2018-03-29 12:03:13 +01:00
2018-11-18 14:33:13 +00:00
// Send info about sensors
HAssAnnounceSensors ( ) ;
2019-02-06 19:07:28 +00:00
2020-06-29 18:44:26 +01:00
// Send info about shutters
HAssAnnounceShutters ( ) ;
2020-08-13 21:46:13 +01:00
// Send info about relays and lights
HAssAnnounceRelayLight ( ) ;
2019-02-06 19:07:28 +00:00
// Send info about status sensor
2020-04-21 13:54:17 +01:00
HAssAnnounceDeviceInfoAndStatusSensor ( ) ;
2020-10-30 11:29:48 +00:00
TasmotaGlobal . masterlog_level = 0 ; // Restores weblog level
2020-10-01 15:47:01 +01:00
hass_mode = 3 ; // Needed for generating bluetooth entities for MI_ESP32
2018-03-29 13:01:38 +01:00
}
2018-03-29 12:03:13 +01:00
}
2019-01-22 11:46:55 +00:00
void HAssDiscover ( void )
2018-08-23 15:05:51 +01:00
{
2020-02-06 02:29:44 +00:00
hass_mode = 1 ; // Force discovery
2021-05-11 10:01:46 +01:00
TasmotaGlobal . discovery_counter = 1 ; // Delayed discovery
2018-08-23 15:05:51 +01:00
}
2019-10-24 08:47:28 +01:00
void HAssAnyKey ( void )
{
2021-06-11 17:14:12 +01:00
if ( ! Settings - > flag . hass_discovery ) { return ; } // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59)
2020-10-22 15:14:51 +01:00
uint32_t key = ( XdrvMailbox . payload > > 16 ) & 0xFF ; // 0 = KEY_BUTTON, 1 = KEY_SWITCH
2020-03-04 17:02:27 +00:00
uint32_t device = XdrvMailbox . payload & 0xFF ; // Device number or 1 if more Buttons than Devices
2020-04-21 13:54:17 +01:00
uint32_t state = ( XdrvMailbox . payload > > 8 ) & 0xFF ; // 0 = Off, 1 = On, 2 = Toggle, 3 = Hold, 10,11,12,13 and 14 for Button Multipress
2020-03-04 17:02:27 +00:00
2020-03-12 19:48:44 +00:00
if ( ! key & & KeyTopicActive ( 0 ) ) { // Button and ButtonTopic is active
2020-03-04 17:02:27 +00:00
device = ( XdrvMailbox . payload > > 24 ) & 0xFF ; // Button number
}
2019-10-24 08:47:28 +01:00
char scommand [ CMDSZ ] ;
2020-03-12 19:48:44 +00:00
char sw_topic [ TOPSZ ] ;
char key_topic [ TOPSZ ] ;
2020-04-21 13:54:17 +01:00
char trg_state [ 8 ] ;
2020-03-12 19:48:44 +00:00
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 ) ) ;
2020-04-21 13:54:17 +01:00
if ( state > = 2 ) { evkey = 1 ; }
2020-03-12 19:48:44 +00:00
snprintf_P ( scommand , sizeof ( scommand ) , PSTR ( " %s%d%s " ) , ( key ) ? " SWITCH " : " BUTTON " , device , ( evkey ) ? " T " : " " ) ;
2019-10-24 08:47:28 +01:00
char stopic [ TOPSZ ] ;
2020-02-06 16:32:54 +00:00
2020-10-22 15:14:51 +01:00
if ( ! key ) {
if ( state = = 3 ) {
snprintf_P ( trg_state , sizeof ( trg_state ) , GetStateText ( 3 ) ) ;
} else {
if ( state = = 2 ) { state = 10 ; }
GetTextIndexed ( trg_state , sizeof ( trg_state ) , state - 9 , kHAssTriggerStringButtons ) ;
}
2020-04-21 13:54:17 +01:00
}
2020-10-30 11:29:48 +00:00
GetTopic_P ( stopic , STAT , TasmotaGlobal . mqtt_topic , scommand ) ;
2020-04-21 13:54:17 +01:00
Response_P ( S_JSON_COMMAND_SVALUE , ( evkey ) ? " TRIG " : PSTR ( D_RSLT_STATE ) , ( key ) ? GetStateText ( state ) : trg_state ) ;
2019-10-27 10:13:24 +00:00
MqttPublish ( stopic ) ;
2019-10-24 08:47:28 +01:00
}
2020-08-14 21:02:55 +01:00
bool HAssMqttLWT ( void )
{
if ( strncasecmp_P ( XdrvMailbox . topic , PSTR ( HOME_ASSISTANT_LWT_TOPIC ) , strlen ( HOME_ASSISTANT_LWT_TOPIC ) ) ! = 0 ) {
return false ;
}
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . hass_discovery & & ( strncasecmp_P ( XdrvMailbox . data , PSTR ( " online " ) , strlen ( " online " ) ) = = 0 ) & & ( XdrvMailbox . data_len = = 6 ) ) {
2020-08-14 21:02:55 +01:00
MqttPublishTeleState ( ) ;
return true ;
2020-09-24 23:16:26 +01:00
} else { return false ; }
2020-08-14 21:02:55 +01:00
}
2020-08-15 19:23:37 +01:00
void HassLwtSubscribe ( bool hasslwt )
{
char htopic [ TOPSZ ] ;
snprintf_P ( htopic , sizeof ( htopic ) , PSTR ( HOME_ASSISTANT_LWT_TOPIC ) ) ;
2021-06-11 17:14:12 +01:00
if ( hasslwt & & ( Settings - > flag . hass_discovery ) ) {
2020-08-15 19:23:37 +01:00
MqttSubscribe ( htopic ) ;
} else { MqttUnsubscribe ( htopic ) ; }
}
2018-01-18 15:19:28 +00:00
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-11-11 09:44:56 +00:00
bool Xdrv12 ( uint32_t function )
2018-01-18 15:19:28 +00:00
{
2019-01-28 13:08:33 +00:00
bool result = false ;
2020-08-14 21:02:55 +01:00
bool hasslwt = HOME_ASSISTANT_LWT_SUBSCRIBE ;
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . mqtt_enabled )
2020-02-06 02:29:44 +00:00
{ // SetOption3 - Enable MQTT
switch ( function )
{
case FUNC_EVERY_SECOND :
2021-05-11 10:01:46 +01:00
if ( TasmotaGlobal . discovery_counter )
2020-02-06 02:29:44 +00:00
{
2021-05-11 10:01:46 +01:00
TasmotaGlobal . discovery_counter - - ;
if ( ! TasmotaGlobal . discovery_counter )
2020-02-06 02:29:44 +00:00
{
HAssDiscovery ( ) ; // Scheduled discovery using available resources
2020-10-01 15:47:01 +01:00
NewHAssDiscovery ( ) ; // Send the topics for Home Assistant Official Integration
2019-01-22 11:46:55 +00:00
}
2020-02-06 02:29:44 +00:00
}
2021-06-11 17:14:12 +01:00
else if ( Settings - > flag . hass_discovery & & Settings - > tele_period )
2020-02-06 02:29:44 +00:00
{ // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59)
hass_tele_period + + ;
2021-06-11 17:14:12 +01:00
if ( hass_tele_period > = Settings - > tele_period )
2020-02-06 02:29:44 +00:00
{
hass_tele_period = 0 ;
2020-10-30 11:29:48 +00:00
ResponseClear ( ) ;
2020-02-06 02:29:44 +00:00
HAssPublishStatus ( ) ;
}
}
break ;
case FUNC_ANY_KEY :
HAssAnyKey ( ) ;
break ;
2021-05-22 15:25:02 +01:00
/*
2020-02-06 02:29:44 +00:00
case FUNC_MQTT_INIT :
2021-06-11 17:14:12 +01:00
hass_mode = 0 ; // Discovery only if Settings->flag.hass_discovery is set
2021-05-11 10:01:46 +01:00
TasmotaGlobal . discovery_counter = 10 ; // Delayed discovery
2021-06-11 17:14:12 +01:00
// if (!Settings->flag.hass_discovery) {
2020-10-01 15:47:01 +01:00
// NewHAssDiscovery();
// }
2020-08-14 21:02:55 +01:00
break ;
2021-05-22 15:25:02 +01:00
*/
2020-08-14 21:02:55 +01:00
case FUNC_MQTT_SUBSCRIBE :
2020-08-15 19:23:37 +01:00
HassLwtSubscribe ( hasslwt ) ;
2021-06-11 17:14:12 +01:00
hass_mode = 0 ; // Discovery only if Settings->flag.hass_discovery is set
2021-05-22 15:25:02 +01:00
TasmotaGlobal . discovery_counter = ( 0 = = Mqtt . initial_connection_state ) ? 1 : 10 ; // Delayed discovery
2020-02-06 02:29:44 +00:00
break ;
2020-08-14 21:02:55 +01:00
case FUNC_MQTT_DATA :
2020-08-15 19:23:37 +01:00
result = HAssMqttLWT ( ) ;
2020-08-14 21:02:55 +01:00
break ;
2018-01-18 15:19:28 +00:00
}
}
return result ;
}
2020-06-20 14:38:17 +01:00
# endif // USE_HOME_ASSISTANT