HA integration - add devices as HA devices - HomeAssistant Discovery #288

This commit is contained in:
proddy
2020-09-30 18:40:29 +02:00
parent a285a2c546
commit 0fae2c6b90
7 changed files with 80 additions and 24 deletions

View File

@@ -85,8 +85,24 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
// create the config topics for Home Assistant MQTT Discovery // create the config topics for Home Assistant MQTT Discovery
// for each of the main elements // for each of the main elements
void Boiler::register_mqtt_ha_config() { void Boiler::register_mqtt_ha_config() {
Mqtt::register_mqtt_ha_binary_sensor(F("Boiler DHW"), "tapwater_active"); // Create the Master device
Mqtt::register_mqtt_ha_binary_sensor(F("Boiler Heating"), "heating_active"); StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
doc["name"] = F("EMS-ESP");
doc["uniq_id"] = F("boiler");
doc["ic"] = F("mdi:home-thermometer-outline");
doc["stat_t"] = F("ems-esp/boiler_data");
doc["val_tpl"] = F("{{value_json.serviceCode}}");
JsonObject dev = doc.createNestedObject("dev");
dev["name"] = F("EMS-ESP Boiler");
dev["sw"] = EMSESP_APP_VERSION;
dev["mf"] = this->brand_to_string();
dev["mdl"] = this->name();
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp-boiler");
Mqtt::publish_retain(F("homeassistant/sensor/ems-esp/boiler/config"), doc.as<JsonObject>(), true); // publish the config payload with retain flag
Mqtt::register_mqtt_ha_binary_sensor(F("Boiler DHW"), this->device_type(), "tapwater_active");
Mqtt::register_mqtt_ha_binary_sensor(F("Boiler Heating"), this->device_type(), "heating_active");
Mqtt::register_mqtt_ha_sensor(F("Service Code"), this->device_type(), "serviceCode", "", ""); Mqtt::register_mqtt_ha_sensor(F("Service Code"), this->device_type(), "serviceCode", "", "");
Mqtt::register_mqtt_ha_sensor(F("Service Code number"), this->device_type(), "serviceCodeNumber", "", ""); Mqtt::register_mqtt_ha_sensor(F("Service Code number"), this->device_type(), "serviceCodeNumber", "", "");

View File

@@ -139,6 +139,22 @@ void Mixing::publish_values() {
// publish config topic for HA MQTT Discovery // publish config topic for HA MQTT Discovery
void Mixing::register_mqtt_ha_config() { void Mixing::register_mqtt_ha_config() {
// Create the Master device
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
doc["name"] = F("EMS-ESP");
doc["uniq_id"] = F("mixing");
doc["ic"] = F("mdi:home-thermometer-outline");
doc["stat_t"] = F("ems-esp/mixing_data");
doc["val_tpl"] = F("{{value_json.pumpStatus}}");
JsonObject dev = doc.createNestedObject("dev");
dev["name"] = F("EMS-ESP Mixing");
dev["sw"] = EMSESP_APP_VERSION;
dev["mf"] = this->brand_to_string();
dev["mdl"] = this->name();
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp-mixing");
Mqtt::publish_retain(F("homeassistant/sensor/ems-esp/mixing/config"), doc.as<JsonObject>(), true); // publish the config payload with retain flag
if (this->type() == Type::HC) { if (this->type() == Type::HC) {
Mqtt::register_mqtt_ha_sensor(F("Current flow temperature"), this->device_type(), "flowTemp", "°C", ""); Mqtt::register_mqtt_ha_sensor(F("Current flow temperature"), this->device_type(), "flowTemp", "°C", "");
Mqtt::register_mqtt_ha_sensor(F("Setpoint flow temperature"), this->device_type(), "flowSetTemp", "°C", ""); Mqtt::register_mqtt_ha_sensor(F("Setpoint flow temperature"), this->device_type(), "flowSetTemp", "°C", "");

View File

@@ -127,6 +127,22 @@ void Solar::publish_values() {
// publish config topic for HA MQTT Discovery // publish config topic for HA MQTT Discovery
void Solar::register_mqtt_ha_config() { void Solar::register_mqtt_ha_config() {
// Create the Master device
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
doc["name"] = F("EMS-ESP");
doc["uniq_id"] = F("solar");
doc["ic"] = F("mdi:home-thermometer-outline");
doc["stat_t"] = F("ems-esp/solar_data");
doc["val_tpl"] = F("{{value_json.solarPump}}");
JsonObject dev = doc.createNestedObject("dev");
dev["name"] = F("EMS-ESP Solar");
dev["sw"] = EMSESP_APP_VERSION;
dev["mf"] = this->brand_to_string();
dev["mdl"] = this->name();
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp-solar");
Mqtt::publish_retain(F("homeassistant/sensor/ems-esp/solar/config"), doc.as<JsonObject>(), true); // publish the config payload with retain flag
Mqtt::register_mqtt_ha_sensor(F("Collector temperature (TS1)"), this->device_type(), "collectorTemp", "°C", ""); Mqtt::register_mqtt_ha_sensor(F("Collector temperature (TS1)"), this->device_type(), "collectorTemp", "°C", "");
Mqtt::register_mqtt_ha_sensor(F("Bottom temperature (TS2)"), this->device_type(), "tankBottomTemp", "°C", ""); Mqtt::register_mqtt_ha_sensor(F("Bottom temperature (TS2)"), this->device_type(), "tankBottomTemp", "°C", "");
Mqtt::register_mqtt_ha_sensor(F("Bottom temperature (TS5)"), this->device_type(), "tankBottomTemp2", "°C", ""); Mqtt::register_mqtt_ha_sensor(F("Bottom temperature (TS5)"), this->device_type(), "tankBottomTemp2", "°C", "");

View File

@@ -412,7 +412,7 @@ bool Thermostat::export_values(uint8_t mqtt_format, JsonObject & rootThermostat)
dataThermostat["summermode"] = "auto"; dataThermostat["summermode"] = "auto";
} else { } else {
char s[7]; char s[7];
rootThermostat["summermode"] = Helpers::render_boolean(s, (hc->summer_setmode == 0)); rootThermostat["summermode"] = Helpers::render_boolean(s, (hc->summer_setmode == 0));
} }
} }
@@ -599,10 +599,14 @@ void Thermostat::register_mqtt_ha_config(uint8_t hc_num) {
} }
JsonObject dev = doc.createNestedObject(F("dev")); JsonObject dev = doc.createNestedObject(F("dev"));
JsonArray ids = dev.createNestedArray(F("ids")); dev["name"] = F("EMS-ESP Thermostat");
ids.add(F("ems-esp")); dev["sw"] = EMSESP_APP_VERSION;
dev["mf"] = this->brand_to_string();
dev["mdl"] = this->name();
JsonArray ids = dev.createNestedArray(F("ids"));
ids.add(F("ems-esp-thermostat"));
std::string topic(100, '\0'); // e.g homeassistant/climate/hc1/thermostat/config std::string topic(100, '\0');
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/climate/ems-esp/thermostat_hc%d/config"), hc_num); snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/climate/ems-esp/thermostat_hc%d/config"), hc_num);
// Mqtt::publish(topic); // empty payload, this remove any previous config sent to HA // Mqtt::publish(topic); // empty payload, this remove any previous config sent to HA
Mqtt::publish_retain(topic, doc.as<JsonObject>(), true); // publish the config payload with retain flag Mqtt::publish_retain(topic, doc.as<JsonObject>(), true); // publish the config payload with retain flag
@@ -926,7 +930,7 @@ void Thermostat::show_values(uuid::console::Shell & shell) {
print_value(shell, 4, F("Summer mode"), F("auto")); print_value(shell, 4, F("Summer mode"), F("auto"));
} else { } else {
char s[7]; char s[7];
print_value(shell, 4, F("Summer mode"), Helpers::render_boolean(s, (hc->summer_setmode == 0))); print_value(shell, 4, F("Summer mode"), Helpers::render_boolean(s, (hc->summer_setmode == 0)));
} }
} }
if (Helpers::hasValue(hc->targetflowtemp)) { if (Helpers::hasValue(hc->targetflowtemp)) {
@@ -1646,21 +1650,21 @@ bool Thermostat::set_mode_n(const uint8_t mode, const uint8_t hc_num) {
} }
bool Thermostat::set_summermode(const char * value, const int8_t id) { bool Thermostat::set_summermode(const char * value, const int8_t id) {
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id; uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
std::string v(10, '\0'); std::string v(10, '\0');
if (!Helpers::value2string(value, v)) { if (!Helpers::value2string(value, v)) {
return false; return false;
} }
uint8_t set = 0xFF; // some dummy value uint8_t set = 0xFF; // some dummy value
if (v == "on" || v == "1" || v == "true") { if (v == "on" || v == "1" || v == "true") {
LOG_INFO(F("Setting summer mode to always on for heating circuit %d"), hc->hc_num()); LOG_INFO(F("Setting summer mode to always on for heating circuit %d"), hc->hc_num());
set = 0; set = 0;
} else if (v == "auto" || v == "2") { } else if (v == "auto" || v == "2") {
LOG_INFO(F("Setting summer mode to auto for heating circuit %d"), hc->hc_num()); LOG_INFO(F("Setting summer mode to auto for heating circuit %d"), hc->hc_num());
set = 1; set = 1;
} else if (v == "off" || v == "0" || v == "false") { } else if (v == "off" || v == "0" || v == "false") {
LOG_INFO(F("Setting summer mode to always off for heating circuit %d"), hc->hc_num()); LOG_INFO(F("Setting summer mode to always off for heating circuit %d"), hc->hc_num());
set = 2; set = 2;
} else { } else {

View File

@@ -474,7 +474,7 @@ void Mqtt::on_connect() {
LOG_INFO(F("MQTT connected")); LOG_INFO(F("MQTT connected"));
} }
// Home Assistant Discovery // Home Assistant Discovery - the main master Device
// homeassistant/sensor/ems-esp/status/config // homeassistant/sensor/ems-esp/status/config
void Mqtt::ha_status() { void Mqtt::ha_status() {
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
@@ -681,7 +681,7 @@ void Mqtt::process_queue() {
} }
// HA config for a binary_sensor // HA config for a binary_sensor
void Mqtt::register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, const char * entity) { void Mqtt::register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, const uint8_t device_type, const char * entity) {
if (mqtt_format() != Format::HA) { if (mqtt_format() != Format::HA) {
return; return;
} }
@@ -708,9 +708,11 @@ void Mqtt::register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, cons
} }
}); });
JsonObject dev = doc.createNestedObject(F("dev")); JsonObject dev = doc.createNestedObject(F("dev"));
JsonArray ids = dev.createNestedArray(F("ids")); JsonArray ids = dev.createNestedArray(F("ids"));
ids.add(F("ems-esp")); std::string ha_device(40, '\0');
snprintf_P(&ha_device[0], ha_device.capacity() + 1, PSTR("ems-esp-%s"), EMSdevice::device_type_2_device_name(device_type).c_str());
ids.add(ha_device);
std::string topic(100, '\0'); std::string topic(100, '\0');
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/binary_sensor/ems-esp/%s/config"), entity); snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/binary_sensor/ems-esp/%s/config"), entity);
@@ -718,7 +720,7 @@ void Mqtt::register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, cons
Mqtt::publish_retain(topic, doc.as<JsonObject>(), true); // publish the config payload with retain flag Mqtt::publish_retain(topic, doc.as<JsonObject>(), true); // publish the config payload with retain flag
} }
// HA config for a normal sensor // HA config for a normal 'sensor' type
void Mqtt::register_mqtt_ha_sensor(const __FlashStringHelper * name, const uint8_t device_type, const char * entity, const char * uom, const char * icon) { void Mqtt::register_mqtt_ha_sensor(const __FlashStringHelper * name, const uint8_t device_type, const char * entity, const char * uom, const char * icon) {
if (mqtt_format() != Format::HA) { if (mqtt_format() != Format::HA) {
return; return;
@@ -746,9 +748,11 @@ void Mqtt::register_mqtt_ha_sensor(const __FlashStringHelper * name, const uint8
doc["ic"] = icon; doc["ic"] = icon;
} }
JsonObject dev = doc.createNestedObject(F("dev")); JsonObject dev = doc.createNestedObject(F("dev"));
JsonArray ids = dev.createNestedArray(F("ids")); JsonArray ids = dev.createNestedArray(F("ids"));
ids.add(F("ems-esp")); std::string ha_device(40, '\0');
snprintf_P(&ha_device[0], ha_device.capacity() + 1, PSTR("ems-esp-%s"), EMSdevice::device_type_2_device_name(device_type).c_str());
ids.add(ha_device);
std::string topic(100, '\0'); std::string topic(100, '\0');
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/sensor/ems-esp/%s/config"), entity); snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/sensor/ems-esp/%s/config"), entity);

View File

@@ -104,7 +104,7 @@ class Mqtt {
static void publish_retain(const __FlashStringHelper * topic, const std::string & payload, bool retain); static void publish_retain(const __FlashStringHelper * topic, const std::string & payload, bool retain);
static void publish_retain(const __FlashStringHelper * topic, const JsonObject & payload, bool retain); static void publish_retain(const __FlashStringHelper * topic, const JsonObject & payload, bool retain);
static void register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, const char * entity); static void register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, const uint8_t device_type, const char * entity);
static void register_mqtt_ha_sensor(const __FlashStringHelper * name, const uint8_t device_type, const char * entity, const char * uom, const char * icon); static void register_mqtt_ha_sensor(const __FlashStringHelper * name, const uint8_t device_type, const char * entity, const char * uom, const char * icon);
static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type); static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type);
@@ -162,7 +162,7 @@ class Mqtt {
static size_t maximum_mqtt_messages_; static size_t maximum_mqtt_messages_;
static uint16_t mqtt_message_id_; static uint16_t mqtt_message_id_;
static constexpr size_t MAX_MQTT_MESSAGES = 30; // size of queue static constexpr size_t MAX_MQTT_MESSAGES = 70; // size of queue
static constexpr uint32_t MQTT_PUBLISH_WAIT = 200; // delay between sending publishes, to account for large payloads static constexpr uint32_t MQTT_PUBLISH_WAIT = 200; // delay between sending publishes, to account for large payloads
static constexpr uint8_t MQTT_PUBLISH_MAX_RETRY = 3; // max retries for giving up on publishing static constexpr uint8_t MQTT_PUBLISH_MAX_RETRY = 3; // max retries for giving up on publishing

View File

@@ -29,7 +29,7 @@ void Shower::start() {
}); });
if (Mqtt::mqtt_format() == Mqtt::Format::HA) { if (Mqtt::mqtt_format() == Mqtt::Format::HA) {
Mqtt::register_mqtt_ha_binary_sensor(F("Shower Active"), "shower_active"); Mqtt::register_mqtt_ha_binary_sensor(F("Shower Active"), EMSdevice::DeviceType::BOILER, "shower_active");
} }
} }