Skip to content

Commit

Permalink
Merge pull request #8724 from effelle/development
Browse files Browse the repository at this point in the history
Discovery Update
  • Loading branch information
arendst authored Jun 18, 2020
2 parents f9c0364 + 0d6aaa6 commit 2a87fa4
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 51 deletions.
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

0 comments on commit 2a87fa4

Please sign in to comment.