Merge pull request #4380 from emontnemery/hass_announce_dht_sensor

Add support for sensor discovery
This commit is contained in:
Theo Arends 2018-11-22 12:16:41 +01:00 committed by GitHub
commit 29f46c5804
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 139 additions and 10 deletions

View File

@ -455,16 +455,18 @@ void RulesEvery50ms(void)
}
}
uint8_t rules_xsns_index = 0;
void RulesEvery100ms(void)
{
if (Settings.rule_enabled && (uptime > 4)) { // Any rule enabled and allow 4 seconds start-up time for sensors (#3811)
mqtt_data[0] = '\0';
int tele_period_save = tele_period;
tele_period = 2; // Do not allow HA updates during next function call
XsnsNextCall(FUNC_JSON_APPEND); // ,"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}
tele_period = 2; // Do not allow HA updates during next function call
XsnsNextCall(FUNC_JSON_APPEND, rules_xsns_index); // ,"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}
tele_period = tele_period_save;
if (strlen(mqtt_data)) {
mqtt_data[0] = '{'; // {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}
mqtt_data[0] = '{'; // {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
RulesProcess();
}

View File

@ -62,6 +62,25 @@ const char HASS_DISCOVER_LIGHT_CT[] PROGMEM =
"\"color_temp_state_topic\":\"%s\"," // stat/led2/RESULT
"\"color_temp_value_template\":\"{{value_json." D_CMND_COLORTEMPERATURE "}}\"";
const char HASS_DISCOVER_SENSOR[] PROGMEM =
"{\"name\":\"%s\"," // dualr2 1 BTN
"\"state_topic\":\"%s\"," // cmnd/dualr2/POWER (implies "\"optimistic\":\"false\",")
"\"availability_topic\":\"%s\"," // tele/dualr2/LWT
"\"payload_available\":\"" D_ONLINE "\"," // Online
"\"payload_not_available\":\"" D_OFFLINE "\""; // Offline
const char HASS_DISCOVER_SENSOR_TEMP[] PROGMEM =
"%s,\"unit_of_measurement\":\"°%c\"," // °C / °F
"\"value_template\":\"{{value_json['%s'].Temperature}}\""; // "SI7021-14":{"Temperature":null,"Humidity":null} -> {{ value_json['SI7021-14'].Temperature }}
const char HASS_DISCOVER_SENSOR_HUM[] PROGMEM =
"%s,\"unit_of_measurement\":\"%%\"," // %
"\"value_template\":\"{{value_json['%s'].Humidity}}\"," // "SI7021-14":{"Temperature":null,"Humidity":null} -> {{ value_json['SI7021-14'].Humidity }}
"\"device_class\":\"humidity\""; // temperature / humidity
const char HASS_DISCOVER_SENSOR_ANY[] PROGMEM =
"%s,\"value_template\":\"{{value_json['%s'].%s}}\""; // "COUNTER":{"C1":0} -> {{ value_json['COUNTER'].C1 }}
const char HASS_DISCOVER_RELAY_SHORT[] PROGMEM =
"{\"name\":\"%s\"," // dualr2 1
"\"cmd_t\":\"%s\"," // cmnd/dualr2/POWER2
@ -109,6 +128,26 @@ const char HASS_DISCOVER_LIGHT_SCHEME[] PROGMEM =
"\"effect_value_template\":\"{{value_json." D_CMND_SCHEME "}}\","
"\"effect_list\":[\"0\",\"1\",\"2\",\"3\",\"4\"]"; // string list with reference to scheme parameter. Currently only supports numbers 0 to 11 as it make the mqtt string too long
*/
const char HASS_DISCOVER_SENSOR_SHORT[] PROGMEM =
"{\"name\":\"%s\"," // dualr2 1 BTN
"\"stat_t\":\"%s\"," // cmnd/dualr2/POWER (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_TEMP_SHORT[] PROGMEM =
"%s,\"unit_of_meas\":\"°%c\"," // °C / °F
"\"val_tpl\":\"{{value_json['%s'].Temperature}}\""; // "SI7021-14":{"Temperature":null,"Humidity":null} -> {{ value_json['SI7021-14'].Temperature }}
const char HASS_DISCOVER_SENSOR_HUM_SHORT[] PROGMEM =
"%s,\"unit_of_meas\":\"%%\"," // %
"\"val_tpl\":\"{{value_json['%s'].Humidity}}\"," // "SI7021-14":{"Temperature":null,"Humidity":null} -> {{ value_json['SI7021-14'].Humidity }}
"\"dev_cla\":\"humidity\""; // humidity
const char HASS_DISCOVER_SENSOR_ANY_SHORT[] PROGMEM =
"%s,\"val_tpl\":\"{{value_json['%s'].%s}}\""; // "COUNTER":{"C1":0} -> {{ value_json['COUNTER'].C1 }}
const char HASS_DISCOVER_TOPIC_PREFIX[] PROGMEM =
"%s, \"~\":\"%s\"";
@ -132,7 +171,7 @@ static void Shorten(char** s, char *prefix)
}
}
void HAssDiscoverRelay(void)
void HAssAnnounceRelayLight(void)
{
char sidx[8];
char stopic[TOPSZ];
@ -226,7 +265,7 @@ void HAssDiscoverRelay(void)
}
}
void HAssDiscoverButton(void)
void HAssAnnounceButton(void)
{
char sidx[8];
char stopic[TOPSZ];
@ -287,6 +326,92 @@ void HAssDiscoverButton(void)
}
}
void HAssAnnounceSensor(const char* sensorname, const char* subsensortype)
{
char stopic[TOPSZ];
// Announce sensor, special handling of temperature and humidity sensors
mqtt_data[0] = '\0'; // Clear retained message
// Clear or Set topic
snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/sensor/%s_%s_%s/config"),
mqtt_topic, sensorname, subsensortype);
if (Settings.flag.hass_discovery) {
char name[33];
char _state_topic[TOPSZ];
char _availability_topic[TOPSZ];
char prefix[TOPSZ];
char *state_topic = _state_topic;
char *availability_topic = _availability_topic;
snprintf_P(name, sizeof(name), PSTR("%s %s %s"), Settings.friendlyname[0], sensorname, subsensortype);
GetTopic_P(state_topic, TELE, mqtt_topic, PSTR(D_RSLT_SENSOR));
GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT);
FindPrefix(state_topic, availability_topic, prefix);
if (Settings.flag3.hass_short_discovery_msg) {
Shorten(&state_topic, prefix);
Shorten(&availability_topic, prefix);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), Settings.flag3.hass_short_discovery_msg?HASS_DISCOVER_SENSOR_SHORT:HASS_DISCOVER_SENSOR,
name, state_topic, availability_topic);
if (!strcmp(subsensortype, "Temperature")) {
snprintf_P(mqtt_data, sizeof(mqtt_data), Settings.flag3.hass_short_discovery_msg?HASS_DISCOVER_SENSOR_TEMP_SHORT:HASS_DISCOVER_SENSOR_TEMP,
mqtt_data, TempUnit(), sensorname);
} else if (!strcmp(subsensortype, "Humidity")) {
snprintf_P(mqtt_data, sizeof(mqtt_data), Settings.flag3.hass_short_discovery_msg?HASS_DISCOVER_SENSOR_HUM_SHORT:HASS_DISCOVER_SENSOR_HUM,
mqtt_data, sensorname);
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), Settings.flag3.hass_short_discovery_msg?HASS_DISCOVER_SENSOR_ANY_SHORT:HASS_DISCOVER_SENSOR_ANY,
mqtt_data, sensorname, subsensortype);
}
if (Settings.flag3.hass_short_discovery_msg)
snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_TOPIC_PREFIX, mqtt_data, prefix);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
}
MqttPublish(stopic, true);
}
void HAssAnnounceSensors(void)
{
uint8_t hass_xsns_index = 0;
do {
mqtt_data[0] = '\0';
int tele_period_save = tele_period;
tele_period = 2; // Do not allow HA updates during next function call
XsnsNextCall(FUNC_JSON_APPEND, hass_xsns_index); // ,"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}
tele_period = tele_period_save;
char sensordata[256]; // Copy because we need to write to mqtt_data
strlcpy(sensordata, mqtt_data, sizeof(sensordata));
if (strlen(sensordata)) {
sensordata[0] = '{'; // {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}
snprintf_P(sensordata, sizeof(sensordata), PSTR("%s}"), sensordata);
StaticJsonBuffer<256> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(sensordata);
if (!root.success()) {
snprintf_P(log_data, sizeof(log_data), PSTR("HASS: failed to parse '%s'"), sensordata);
AddLog(LOG_LEVEL_ERROR);
continue;
}
for (auto sensor : root) {
const char* sensorname = sensor.key;
JsonObject& sensors = sensor.value.as<JsonObject>();
if (!sensors.success()) {
snprintf_P(log_data, sizeof(log_data), PSTR("HASS: failed to parse '%s'"), sensordata);
AddLog(LOG_LEVEL_ERROR);
continue;
}
for (auto subsensor : sensors) {
HAssAnnounceSensor(sensorname, subsensor.key);
}
}
}
} while (hass_xsns_index != 0);
}
static int string_ends_with(const char * str, const char * suffix)
{
int str_len = strlen(str);
@ -308,12 +433,15 @@ void HAssDiscovery(uint8_t mode)
if (Settings.flag.hass_discovery || (1 == mode)) {
// Send info about relays and lights
HAssDiscoverRelay();
HAssAnnounceRelayLight();
// Send info about buttons
HAssDiscoverButton();
HAssAnnounceButton();
// TODO: Send info about switches
// TODO: Send info about sensors
// Send info about sensors
HAssAnnounceSensors();
}
}

View File

@ -263,13 +263,12 @@ boolean (* const xsns_func_ptr[])(byte) = { // Sensor Function Pointers for sim
};
const uint8_t xsns_present = sizeof(xsns_func_ptr) / sizeof(xsns_func_ptr[0]); // Number of External Sensors found
uint8_t xsns_index = 0;
/*********************************************************************************************\
* Function call to all xsns
\*********************************************************************************************/
boolean XsnsNextCall(byte Function)
boolean XsnsNextCall(byte Function, uint8_t &xsns_index)
{
xsns_index++;