Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discovery Update #8724

Merged
merged 1 commit into from
Jun 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions tasmota/my_user_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@
// -- MQTT - Home Assistant Discovery -------------
#define HOME_ASSISTANT_DISCOVERY_ENABLE false // [SetOption19] Home Assistant Discovery (false = Disable, true = Enable)
#define HASS_AS_LIGHT false // [SetOption30] Enforce HAss autodiscovery as light
//#define DEEPSLEEP_LWT_HA_DISCOVERY // Enable LWT topic and its payloads for read-only sensors (Status sensor not included) and binary_sensors on HAss Discovery (Commented out: all read-only sensors and binary_sensors
// won't be shown as OFFLINE on Home Assistant when the device is DeepSleeping - NOTE: This is only for read-only sensors and binary_sensors, relays will be shown as OFFLINE)

// -- MQTT - Options ------------------------------
#define MQTT_RESULT_COMMAND false // [SetOption4] Switch between MQTT RESULT or COMMAND
Expand Down
139 changes: 88 additions & 51 deletions tasmota/xdrv_12_home_assistant.ino
Original file line number Diff line number Diff line change
Expand Up @@ -27,76 +27,79 @@ const char kHAssJsonSensorTypes[] PROGMEM =
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_TOTAL_START_TIME "|"
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 "|";
D_JSON_CO2 "|" D_JSON_ECO2 "|" D_JSON_TVOC "|" D_COLOR_RED "|" D_COLOR_GREEN "|" D_COLOR_BLUE"|" D_CCT "|" D_PROXIMITY "|Ambient|";

const char kHAssJsonSensorUnits[] PROGMEM =
"||||"
"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|";
"ppm|ppm|ppb|R|G|B|" D_UNIT_KELVIN "| |LX|";

const char kHAssJsonSensorDevCla[] PROGMEM =
"dev_cla\":\"temperature|ic\":\"mdi:weather-rainy|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|ic\":\"mdi:progress-clock|"
"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|";
"ic\":\"mdi:periodic-table-co2|ic\":\"mdi:air-filter|ic\":\"mdi:periodic-table-co2|"
"ic\":\"mdi:palette|ic\":\"mdi:palette|ic\":\"mdi:palette|ic\":\"mdi:temperature-kelvin|ic\":\"mdi:ruler|dev_cla\":\"illuminance|";
//"ic\":\"mdi:weather-windy|ic\":\"mdi:weather-windy|ic\":\"mdi:weather-windy|ic\":\"mdi:weather-windy|"
// List of sensors ready for discovery

const char HASS_DISCOVER_BASE[] PROGMEM =
"{\"name\":\"%s\"," // dualr2 1
"\"stat_t\":\"%s\""; // stat/dualr2/RESULT (implies "\"optimistic\":\"false\",")

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
const char HASS_DISCOVER_SENSOR_LWT[] PROGMEM =
",\"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_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
",\"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_BIN_PIR[] 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
"\"off_dly\":1"; // Switchmode13 and Switchmode14 doesn't transmit an OFF state.
",\"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.

const char HASS_DISCOVER_BASE_LIGHT[] 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_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.%s}}\"";

const char HASS_DISCOVER_LIGHT_COLOR[] PROGMEM =
",\"rgb_cmd_t\":\"%s2\"," // cmnd/led2/Color2
"\"rgb_stat_t\":\"%s\"," // stat/led2/RESULT
",\"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
",\"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_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 =
Expand Down Expand Up @@ -141,7 +144,7 @@ const char kHAssTriggerStringButtons[] PROGMEM =
"|SINGLE|DOUBLE|TRIPLE|QUAD|PENTA|HOLD|";

const char kHAssError1[] PROGMEM =
"HASS: MQTT discovery failed due to too long topic or friendly name. Please shorten topic and/or friendly name. Failed to format";
"HASS: MQTT discovery failed due to too long topic or device/friendly name. Please shorten topic and/or device/friendly name. Failed to format";

const char kHAssError2[] PROGMEM =
"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 "
Expand Down Expand Up @@ -195,31 +198,44 @@ void HAssAnnounceRelayLight(void)
bool ct_light = false; // Controls a CT Light when SetOption37 is >= 128
bool wt_light = false; // Controls a White 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
bool TuyaMod = false; // Controls Tuya MCU modules
bool PwmMod = false; // Controls PWM_DIMMER module
bool FanMod = false; // Controls SONOFF_IFAN0X modules

uint8_t dimmer = 1;
uint8_t valid_relay = 0;
uint8_t max_lights = 1;
uint8_t TuyaRel = 0;
uint8_t TuyaRelInv = 0;
uint8_t TuyaDim = 0;

#ifdef ESP8266
if (PWM_DIMMER == my_module_type) { PwmMod = true; }
if (PWM_DIMMER == my_module_type ) { PwmMod = true; } //
if (SONOFF_IFAN02 == my_module_type || SONOFF_IFAN03 == my_module_type) { FanMod = true; }
if (SONOFF_DUAL == my_module_type) { valid_relay = 2; }
if (TUYA_DIMMER == my_module_type || SK03_TUYA == my_module_type) { TuyaMod = true; }
#endif //ESP8266

// 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) {
ind_light = 1;
ind_light = true;
if (!PwmMulti) { max_lights = 2;}
}

// Lights types: 0 = LST_NONE / 1 = LST_SINGLE / 2 = LST_COLDWARM / 3 = LST_RGB / 4 = LST_RGBW / 5 = LST_RGBCW

for (uint32_t i = 1; i <= MAX_RELAYS; i++)
{
bool RelayX = PinUsed(GPIO_REL1 +i-1);
is_topic_light = Settings.flag.hass_light && RelayX || light_type && !RelayX || PwmMod; // SetOption30 - Enforce HAss autodiscovery as light

#ifdef USE_TUYA_MCU
TuyaRel = TuyaGetDpId((TUYA_MCU_FUNC_REL1+ i-1) + active_device - 1);
TuyaRelInv = TuyaGetDpId((TUYA_MCU_FUNC_REL1_INV+ i-1) + active_device - 1);
TuyaDim = TuyaGetDpId((TUYA_MCU_FUNC_DIMMER) + active_device - 1);
#endif //USE_TUYA_MCU

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
is_topic_light = Settings.flag.hass_light && RelayX || light_type && !RelayX || PwmMod || (TuyaDim > 0 && TuyaMod); // SetOption30 - Enforce HAss autodiscovery as light
mqtt_data[0] = '\0'; // Clear retained message

// Clear "other" topic first in case the device has been reconfigured from light to switch or vice versa
Expand Down Expand Up @@ -255,13 +271,14 @@ void HAssAnnounceRelayLight(void)
GetTopic_P(command_topic, CMND, mqtt_topic, value_template);
GetTopic_P(state_topic, TELE, mqtt_topic, D_RSLT_STATE);
GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT);
Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic);
Response_P(HASS_DISCOVER_BASE, name, state_topic);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, 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());

#ifdef USE_LIGHT
if (i >= Light.device) {
if (!RelayX || PwmMod) {
if (!RelayX || PwmMod || (TuyaDim > 0 && TuyaMod)) {
char *brightness_command_topic = stemp1;
strncpy_P(stemp3, Settings.flag.not_power_linked ? PSTR("last") : PSTR("brightness"), sizeof(stemp3)); // SetOption20 - Control power in relation to Dimmer/Color/Ct changes
char channel_num[9];
Expand Down Expand Up @@ -411,6 +428,14 @@ void HAssAnnouncerBinSensors(uint8_t device, uint8_t present, uint8_t dual, uint
TryResponseAppend_P(HASS_DISCOVER_BIN_PIR, PSTR(D_RSLT_STATE), SettingsText(SET_STATE_TXT2));
}
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP_getChipId());
#ifdef DEEPSLEEP_LWT_HA_DISCOVERY
TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
#else
if (Settings.deepsleep == 0)
{
TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
}
#endif //DEEPSLEEP_LWT_HA_DISCOVERY
TryResponseAppend_P(PSTR("}"));
}
}
Expand Down Expand Up @@ -505,7 +530,7 @@ void HAssAnnounceButtons(void)
{
button_present = 1;
} else
#endif
#endif // ESP8266
{
if (PinUsed(GPIO_KEY1, button_index)) {
button_present = 1;
Expand Down Expand Up @@ -557,12 +582,21 @@ void HAssAnnounceSensor(const char *sensorname, const char *subsensortype, const
char prefix[TOPSZ];
char *state_topic = stemp1;
char *availability_topic = stemp2;
//bool LwtSensor = MQTT_LWT_DISCOVERY;

GetTopic_P(state_topic, TELE, mqtt_topic, PSTR(D_RSLT_SENSOR));
snprintf_P(name, sizeof(name), PSTR("%s %s %s"), SettingsText(SET_DEVICENAME), sensorname, MultiSubName);
GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT);

Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic);
Response_P(HASS_DISCOVER_BASE, name, state_topic);
#ifdef DEEPSLEEP_LWT_HA_DISCOVERY
TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
#else
if (Settings.deepsleep == 0)
{
TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
}
#endif //DEEPSLEEP_LWT_HA_DISCOVERY
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP_getChipId());


Expand Down Expand Up @@ -629,8 +663,8 @@ void HAssAnnounceSensors(void)
sensordata[0] = '{';
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]}}"));

//snprintf_P(sensordata, sizeof(sensordata), PSTR("{\"APDS9960\":{\"Red\":282,\"Green\":252,\"Blue\":196,\"Ambient\":169,\"CCT\":4217,\"Proximity\":9}}"));
//snprintf_P(sensordata, sizeof(sensordata), PSTR("{\"ENERGY\":{\"TotalStartTime\":\"2018-11-23T15:33:47\",\"Total\":0.017,\"TotalTariff\":[0.000,0.017],\"Yesterday\":0.000,\"Today\":0.002,\"ExportActive\":0.000,\"ExportTariff\":[0.000,0.000],\"Period\":0.00,\"Power\":0.00,\"ApparentPower\":7.84,\"ReactivePower\":-7.21,\"Factor\":0.39,\"Frequency\":50.0,\"Voltage\":234.31,\"Current\":0.039,\"ImportActive\":12.580,\"ImportReactive\":0.002,\"ExportReactive\":39.131,\"PhaseAngle\":290.45}}"));

StaticJsonBuffer<500> jsonBuffer;
JsonObject &root = jsonBuffer.parseObject(sensordata);
Expand Down Expand Up @@ -703,7 +737,8 @@ void HAssAnnounceDeviceInfoAndStatusSensor(void)
GetTopic_P(state_topic, TELE, mqtt_topic, PSTR(D_RSLT_HASS_STATE));
GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT);

Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic);
Response_P(HASS_DISCOVER_BASE, name, state_topic);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_HASS_STATUS, state_topic);
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO, unique_id, ESP_getChipId(), SettingsText(SET_DEVICENAME),
ModuleName().c_str(), my_version, my_image);
Expand All @@ -719,7 +754,7 @@ void HAssPublishStatus(void)
"\"" D_CMND_IPADDRESS "\":\"%s\",\"" D_JSON_RSSI "\":\"%d\",\"" D_JSON_SIGNAL " (dBm)""\":\"%d\","
"\"WiFi " D_JSON_LINK_COUNT "\":%d,\"WiFi " D_JSON_DOWNTIME "\":\"%s\",\"" D_JSON_MQTT_COUNT "\":%d,\"LoadAvg\":%lu}"),
my_version, my_image, GetBuildDateAndTime().c_str(), ModuleName().c_str(), GetResetReason().c_str(),
GetUptime().c_str(), NetworkHostname(), WiFi.localIP().toString().c_str(), WifiGetRssiAsQuality(WiFi.RSSI()),
GetUptime().c_str(), my_hostname, WiFi.localIP().toString().c_str(), WifiGetRssiAsQuality(WiFi.RSSI()),
WiFi.RSSI(), WifiLinkCount(), WifiDowntime().c_str(), MqttConnectCount(), loop_load_avg);
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_HASS_STATE));
}
Expand Down Expand Up @@ -812,7 +847,6 @@ void HAssAnyKey(void)
bool Xdrv12(uint8_t function)
{
bool result = false;

if (Settings.flag.mqtt_enabled)
{ // SetOption3 - Enable MQTT
switch (function)
Expand Down Expand Up @@ -844,10 +878,13 @@ bool Xdrv12(uint8_t function)
case FUNC_MQTT_INIT:
hass_mode = 0; // Discovery only if Settings.flag.hass_discovery is set
hass_init_step = 2; // Delayed discovery
// if (!Settings.flag.hass_discovery) {
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MQT: homeassistant/49A3BC/Discovery = {\"dev\":{\"ids\":[\"49A3BC\"]},\"cmd_t\":\"cmnd/test1/\",\"Discovery\":0}"));
// }
break;
}
}
return result;
}

#endif // USE_HOME_ASSISTANT
#endif // USE_HOME_ASSISTANT