Hass discovery (#1122)

* HASS discovery energy stats fixed except energycounter_clear_date

* HASS: add friendly entity names, remove timestamp class from energycounter_clear_date as workaround for hass-incompatible date format

* HA energycounter_clear_date fixed for correct interpreting as home assistant timestamp sensor

* refactor HA power sensors discovery info

* refactor HA power sensors discovery more

* add apparent power, reactive power, power factor to mqtt + hass discovery, refactor some vars into new energy_sensors[] struct

* amend hass sensor unique_ids due to mqtt topic/channel too long; 'Error:MQTT:Unable to queue! Topic (13), channel (66) or value (437) exceeds size limit'

* hass sensors: add 'energy 2 days ago', 'energy 3 days ago', 'uptime'
web UI: energy sensors apply their rounding setting
drv_bl_shared.c: add enum for daily_stats[], put rearrange energy_sensor[] struct to expose only names via DRV_GetEnergySensorNames()

* -HA energy sensor uniq_id values made consistent with prior builds via .hass_uniq_id_suffix
-Refactor drv_bl_shared sensor/counter vars into energy_sensors[] to simplify mqtt transmissions etc
-Add energy '2 days ago'/'3 days ago' to main web ui, data from vars already being saved to/from flash
-NTP fix html formatting in web ui

* -HA energy sensor uniq_id values made consistent with prior builds via .hass_uniq_id_suffix
-Refactor drv_bl_shared sensor/counter vars into energy_sensors[] to simplify mqtt transmissions etc
-Add energy '2 days ago'/'3 days ago' to main web ui, data from vars already being saved to/from flash
-NTP fix html formatting in web ui

* Update settings.json

ignore vscode settings...

* Update settings.json

* Update settings.json

* minor fix

* fix OBK_CONSUMPTION_LAST_HOUR missing from mqtt

* HASS entity names use channel labels when set, hass discovery excludes unpublished entities (i.e. those set via SetChannelPrivate), hass discovery firmware build info added to diagnostic section, energy sensor discovery bugfix re clear-date

* update submodule sdk

* Fix ch0 label wrongly applied to diagnostic sensors

* update docs

---------

Co-authored-by: Stefan Smith <stefan064>
This commit is contained in:
stefan064
2024-03-24 03:56:44 +11:00
committed by GitHub
parent 1d60854ea9
commit 9987e685e9
5 changed files with 125 additions and 89 deletions

View File

@ -102,6 +102,9 @@ void hass_populate_unique_id(ENTITY_TYPE type, int index, char* uniq_id) {
case HASS_UPTIME:
sprintf(uniq_id, "%s_uptime", longDeviceName);
break;
case HASS_BUILD:
sprintf(uniq_id, "%s_build", longDeviceName);
break;
default:
// TODO: USE type here as well?
// If type is not set, and we use "sensor" naming, we can easily make collision
@ -189,7 +192,8 @@ cJSON* hass_build_device_node(cJSON* ids) {
/// @brief Initializes HomeAssistant device discovery storage with common values.
/// @param type
/// @param index This is used to generate generate unique_id and name.
/// It is ignored for RGB. For energy sensors, index corresponds to energySensor_t. For regular sensor, index can be be the channel.
/// It is ignored for RGB and diagnostic sensors (HASS_RSSI, HASS_UPTIME, HASS_BUILD...).
/// For energy sensors, index corresponds to energySensor_t. For regular sensor, index can be be the channel.
/// @param payload_on The payload that represents enabled state. This is not added for POWER_SENSOR.
/// @param payload_off The payload that represents disabled state. This is not added for POWER_SENSOR.
/// @return
@ -211,85 +215,92 @@ HassDeviceInfo* hass_init_device_info(ENTITY_TYPE type, int index, const char* p
bool isSensor = false; //This does not count binary_sensor
//Build the `name`
switch (type) {
case LIGHT_ON_OFF:
case LIGHT_PWM:
case RELAY:
case BINARY_SENSOR:
if (CHANNEL_HasLabel(index) && type != ENERGY_METER_SENSOR) {
sprintf(g_hassBuffer, "%s", CHANNEL_GetLabel(index));
break;
case LIGHT_PWMCW:
case LIGHT_RGB:
case LIGHT_RGBCW:
//There can only be one RGB so we can skip including index in the name. Do the same
//for 2 PWM case.
sprintf(g_hassBuffer, "Light");
break;
case ENERGY_METER_SENSOR:
isSensor = true;
#ifndef OBK_DISABLE_ALL_DRIVERS
if (index <= OBK__LAST)
sprintf(g_hassBuffer, "%s", DRV_GetEnergySensorNames(index)->name_friendly);
else
sprintf(g_hassBuffer, "Unknown Energy Meter Sensor");
#endif
break;
case POWER_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Power");
break;
case TEMPERATURE_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Temperature");
break;
case HUMIDITY_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Humidity");
break;
case CO2_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "CO2");
break;
case SMOKE_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Smoke");
break;
case PRESSURE_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Pressure");
break;
case TVOC_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Tvoc");
break;
case BATTERY_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Battery");
break;
case BATTERY_VOLTAGE_SENSOR:
case VOLTAGE_SENSOR:
isSensor = (type == BATTERY_VOLTAGE_SENSOR);
sprintf(g_hassBuffer, "Voltage");
break;
case ILLUMINANCE_SENSOR:
sprintf(g_hassBuffer, "Illuminance");
break;
case HASS_RSSI:
sprintf(g_hassBuffer, "RSSI");
break;
case HASS_UPTIME:
sprintf(g_hassBuffer, "Uptime");
break;
case ENERGY_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Energy");
break;
case TIMESTAMP_SENSOR:
sprintf(g_hassBuffer, "Timestamp");
break;
default:
sprintf(g_hassBuffer, "%s", CHANNEL_GetLabel(index));
break;
} else {
switch (type) {
case LIGHT_ON_OFF:
case LIGHT_PWM:
case RELAY:
case BINARY_SENSOR:
sprintf(g_hassBuffer, "%s", CHANNEL_GetLabel(index));
break;
case LIGHT_PWMCW:
case LIGHT_RGB:
case LIGHT_RGBCW:
//There can only be one RGB so we can skip including index in the name. Do the same
//for 2 PWM case.
sprintf(g_hassBuffer, "Light");
break;
case ENERGY_METER_SENSOR:
isSensor = true;
#ifndef OBK_DISABLE_ALL_DRIVERS
if (index <= OBK__LAST)
sprintf(g_hassBuffer, "%s", DRV_GetEnergySensorNames(index)->name_friendly);
else
sprintf(g_hassBuffer, "Unknown Energy Meter Sensor");
#endif
break;
case POWER_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Power");
break;
case TEMPERATURE_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Temperature");
break;
case HUMIDITY_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Humidity");
break;
case CO2_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "CO2");
break;
case SMOKE_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Smoke");
break;
case PRESSURE_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Pressure");
break;
case TVOC_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Tvoc");
break;
case BATTERY_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Battery");
break;
case BATTERY_VOLTAGE_SENSOR:
case VOLTAGE_SENSOR:
isSensor = (type == BATTERY_VOLTAGE_SENSOR);
sprintf(g_hassBuffer, "Voltage");
break;
case ILLUMINANCE_SENSOR:
sprintf(g_hassBuffer, "Illuminance");
break;
case HASS_RSSI:
sprintf(g_hassBuffer, "RSSI");
break;
case HASS_UPTIME:
sprintf(g_hassBuffer, "Uptime");
break;
case HASS_BUILD:
sprintf(g_hassBuffer, "Build");
break;
case ENERGY_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "Energy");
break;
case TIMESTAMP_SENSOR:
sprintf(g_hassBuffer, "Timestamp");
break;
default:
sprintf(g_hassBuffer, "%s", CHANNEL_GetLabel(index));
break;
}
}
cJSON_AddStringToObject(info->root, "name", g_hassBuffer);
cJSON_AddStringToObject(info->root, "~", CFG_GetMQTTClientId()); //base topic
@ -653,13 +664,17 @@ HassDeviceInfo* hass_init_sensor_device_info(ENTITY_TYPE type, int channel, int
cJSON_AddStringToObject(info->root, "entity_category", "diagnostic");
cJSON_AddStringToObject(info->root, "stat_cla", "total_increasing");
break;
case HASS_BUILD:
cJSON_AddStringToObject(info->root, "stat_t", "~/build");
cJSON_AddStringToObject(info->root, "entity_category", "diagnostic");
break;
default:
sprintf(g_hassBuffer, "~/%d/get", channel);
cJSON_AddStringToObject(info->root, "stat_t", g_hassBuffer);
return NULL;
}
if (type != READONLYLOWMIDHIGH_SENSOR && !cJSON_HasObjectItem(info->root, "stat_cla")) {
if (type != READONLYLOWMIDHIGH_SENSOR && type != HASS_BUILD && !cJSON_HasObjectItem(info->root, "stat_cla")) {
cJSON_AddStringToObject(info->root, "stat_cla", "measurement");
}

View File

@ -69,6 +69,8 @@ typedef enum {
HASS_RSSI,
/// @brief Time firmware is alive in secs
HASS_UPTIME,
/// @brief Firmware build info
HASS_BUILD,
/// @brief Wh, kWh
ENERGY_SENSOR,
// hPa

View File

@ -1577,6 +1577,7 @@ void doHomeAssistantDiscovery(const char* topic, http_request_t* request) {
int relayCount;
int pwmCount;
int dInputCount;
int excludedCount = 0;
bool ledDriverChipRunning;
HassDeviceInfo* dev_info = NULL;
bool measuringPower = false;
@ -1592,6 +1593,13 @@ void doHomeAssistantDiscovery(const char* topic, http_request_t* request) {
// no channels published yet
flagsChannelPublished = 0;
for (i = 0; i < CHANNEL_MAX; i++) {
if (CHANNEL_HasNeverPublishFlag(i)) {
BIT_SET(flagsChannelPublished, i);
excludedCount++;
}
}
if (topic == 0 || *topic == 0) {
topic = "homeassistant";
}
@ -1602,7 +1610,7 @@ void doHomeAssistantDiscovery(const char* topic, http_request_t* request) {
#endif
PIN_get_Relay_PWM_Count(&relayCount, &pwmCount, &dInputCount);
addLogAdv(LOG_INFO, LOG_FEATURE_HTTP, "HASS counts: %i rels, %i pwms, %i inps", relayCount, pwmCount, dInputCount);
addLogAdv(LOG_INFO, LOG_FEATURE_HTTP, "HASS counts: %i rels, %i pwms, %i inps, %i excluded", relayCount, pwmCount, dInputCount, excludedCount);
ledDriverChipRunning = LED_IsLedDriverChipRunning();
@ -1739,7 +1747,7 @@ void doHomeAssistantDiscovery(const char* topic, http_request_t* request) {
#ifndef OBK_DISABLE_ALL_DRIVERS
if (measuringPower == true) {
for (i = OBK__FIRST; i < OBK__LAST; i++)
for (i = OBK__FIRST; i <= OBK__LAST; i++)
{
dev_info = hass_init_energy_sensor_device_info(i);
if (dev_info) {
@ -2047,10 +2055,14 @@ void doHomeAssistantDiscovery(const char* topic, http_request_t* request) {
}
#endif
if (1) {
dev_info = hass_init_sensor_device_info(HASS_RSSI, 0, -1, -1, 1);
//use -1 for channel as these don't correspond to channels
dev_info = hass_init_sensor_device_info(HASS_RSSI, -1, -1, -1, 1);
MQTT_QueuePublish(topic, dev_info->channel, hass_build_discovery_json(dev_info), OBK_PUBLISH_FLAG_RETAIN);
hass_free_device_info(dev_info);
dev_info = hass_init_sensor_device_info(HASS_UPTIME, 0, -1, -1, 1);
dev_info = hass_init_sensor_device_info(HASS_UPTIME, -1, -1, -1, 1);
MQTT_QueuePublish(topic, dev_info->channel, hass_build_discovery_json(dev_info), OBK_PUBLISH_FLAG_RETAIN);
hass_free_device_info(dev_info);
dev_info = hass_init_sensor_device_info(HASS_BUILD, -1, -1, -1, 1);
MQTT_QueuePublish(topic, dev_info->channel, hass_build_discovery_json(dev_info), OBK_PUBLISH_FLAG_RETAIN);
hass_free_device_info(dev_info);
discoveryQueued = true;