split HA-config in smaller blocks, add publish command

This commit is contained in:
MichaelDvP
2020-11-13 13:29:19 +01:00
parent f5b7bad2fb
commit 1578168167
19 changed files with 202 additions and 114 deletions

View File

@@ -2,7 +2,7 @@
### Added ### Added
- function keys in editor: cursor, del, home, end. F1=help, F2=show, and other shortcuts - function keys in editor: cursor, del, home, end. F1=help, F2=show, and other shortcuts
- add sm100 pump working time and energy units - SM100 pump working time and energy units
- heating curve parameters for RC300 - heating curve parameters for RC300
### Fixed ### Fixed
@@ -11,6 +11,7 @@
### Changed ### Changed
- optimized MQTT for HA to reduce mem fragmentation issues - optimized MQTT for HA to reduce mem fragmentation issues
- change syslog settings without reboot - change syslog settings without reboot
- HA-config split in smaller blocks
### Removed ### Removed
- old scripts - old scripts

View File

@@ -309,7 +309,7 @@ bool DallasSensor::export_values(JsonObject & json) {
} }
// send all dallas sensor values as a JSON package to MQTT // send all dallas sensor values as a JSON package to MQTT
void DallasSensor::publish_values() { void DallasSensor::publish_values(const bool force) {
uint8_t num_sensors = sensors_.size(); uint8_t num_sensors = sensors_.size();
if (num_sensors == 0) { if (num_sensors == 0) {
@@ -340,7 +340,7 @@ void DallasSensor::publish_values() {
// create the HA MQTT config // create the HA MQTT config
// to e.g. homeassistant/sensor/ems-esp/dallas_28-233D-9497-0C03/config // to e.g. homeassistant/sensor/ems-esp/dallas_28-233D-9497-0C03/config
if (mqtt_format_ == Mqtt::Format::HA) { if (mqtt_format_ == Mqtt::Format::HA) {
if (!(registered_ha_[sensor_no - 1])) { if (!(registered_ha_[sensor_no - 1]) || force) {
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> config; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> config;
config["dev_cla"] = F("temperature"); config["dev_cla"] = F("temperature");

View File

@@ -58,7 +58,7 @@ class DallasSensor {
void start(); void start();
void loop(); void loop();
void publish_values(); void publish_values(const bool force);
void reload(); void reload();
bool updated_values(); bool updated_values();

View File

@@ -74,17 +74,13 @@ 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(bool force) { void Boiler::register_mqtt_ha_config() {
if ((mqtt_ha_config_ && !force)) {
return;
}
if (!Mqtt::connected()) { if (!Mqtt::connected()) {
return; return;
} }
// Create the Master device // Create the Master device
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
doc["name"] = F("Service Code"); doc["name"] = F("Service Code");
doc["uniq_id"] = F("boiler"); doc["uniq_id"] = F("boiler");
doc["ic"] = F("mdi:home-thermometer-outline"); doc["ic"] = F("mdi:home-thermometer-outline");
@@ -141,7 +137,16 @@ void Boiler::register_mqtt_ha_config(bool force) {
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(burnWorkMin), this->device_type(), "burnWorkMin", F_(min), nullptr); Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(burnWorkMin), this->device_type(), "burnWorkMin", F_(min), nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(heatWorkMin), this->device_type(), "heatWorkMin", F_(min), nullptr); Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(heatWorkMin), this->device_type(), "heatWorkMin", F_(min), nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(UBAuptime), this->device_type(), "UBAuptime", F_(min), nullptr); Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(UBAuptime), this->device_type(), "UBAuptime", F_(min), nullptr);
mqtt_ha_config_ = true; // done
}
// create the config topics for Home Assistant MQTT Discovery
// for each of the ww elements
void Boiler::register_mqtt_ha_config_ww() {
if (!Mqtt::connected()) {
return;
}
// ww // ww
Mqtt::register_mqtt_ha_sensor(nullptr, F_(mqtt_suffix_ww), F_(wWSelTemp), this->device_type(), "wWSelTemp", F_(degrees), F_(iconcruise)); Mqtt::register_mqtt_ha_sensor(nullptr, F_(mqtt_suffix_ww), F_(wWSelTemp), this->device_type(), "wWSelTemp", F_(degrees), F_(iconcruise));
Mqtt::register_mqtt_ha_sensor(nullptr, F_(mqtt_suffix_ww), F_(wWSetTemp), this->device_type(), "wWSetTemp", F_(degrees), F_(icontemperature)); Mqtt::register_mqtt_ha_sensor(nullptr, F_(mqtt_suffix_ww), F_(wWSetTemp), this->device_type(), "wWSetTemp", F_(degrees), F_(icontemperature));
@@ -170,13 +175,14 @@ void Boiler::register_mqtt_ha_config(bool force) {
Mqtt::register_mqtt_ha_sensor(nullptr, F_(mqtt_suffix_ww), F_(wWStarts), this->device_type(), "wWStarts", nullptr, nullptr); Mqtt::register_mqtt_ha_sensor(nullptr, F_(mqtt_suffix_ww), F_(wWStarts), this->device_type(), "wWStarts", nullptr, nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, F_(mqtt_suffix_ww), F_(wWWorkM), this->device_type(), "wWWorkM", F_(min), nullptr); Mqtt::register_mqtt_ha_sensor(nullptr, F_(mqtt_suffix_ww), F_(wWWorkM), this->device_type(), "wWWorkM", F_(min), nullptr);
mqtt_ha_config_ = true; // done mqtt_ha_config_ww_ = true; // done
} }
// send stuff to the Web UI // send stuff to the Web UI
void Boiler::device_info_web(JsonArray & root) { void Boiler::device_info_web(JsonArray & root) {
// fetch the values into a JSON document // fetch the values into a JSON document
DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE); // DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE);
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
JsonObject json = doc.to<JsonObject>(); JsonObject json = doc.to<JsonObject>();
if (!export_values_main(json)) { if (!export_values_main(json)) {
return; // empty return; // empty
@@ -618,19 +624,29 @@ bool Boiler::export_values_main(JsonObject & json) {
void Boiler::publish_values(JsonObject & json, bool force) { void Boiler::publish_values(JsonObject & json, bool force) {
// handle HA first // handle HA first
if (Mqtt::mqtt_format() == Mqtt::Format::HA) { if (Mqtt::mqtt_format() == Mqtt::Format::HA) {
register_mqtt_ha_config(force); if (force) {
mqtt_ha_config_ = false;
mqtt_ha_config_ww_ = false;
}
// register ww in next cycle if both unregistered
if (!mqtt_ha_config_) {
register_mqtt_ha_config();
return;
} else if (!mqtt_ha_config_ww_) {
register_mqtt_ha_config_ww();
return;
}
} }
DynamicJsonDocument doc_main(EMSESP_MAX_JSON_SIZE_LARGE); StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
JsonObject json_main = doc_main.to<JsonObject>(); JsonObject json_data = doc.to<JsonObject>();
if (export_values_main(json_main)) { if (export_values_main(json_data)) {
Mqtt::publish(F("boiler_data"), doc_main.as<JsonObject>()); Mqtt::publish(F("boiler_data"), json_data);
} }
json_data.clear();
DynamicJsonDocument doc_ww(EMSESP_MAX_JSON_SIZE_LARGE); if (export_values_ww(json_data)) {
JsonObject json_ww = doc_ww.to<JsonObject>(); Mqtt::publish(F("boiler_data_ww"), json_data);
if (export_values_ww(json_ww)) {
Mqtt::publish(F("boiler_data_ww"), doc_ww.as<JsonObject>());
} }
// send out heating and tapwater status // send out heating and tapwater status
@@ -651,13 +667,14 @@ void Boiler::show_values(uuid::console::Shell & shell) {
EMSdevice::show_values(shell); // for showing the header EMSdevice::show_values(shell); // for showing the header
// fetch the values into a JSON document // fetch the values into a JSON document
DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE); // DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE);
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
JsonObject json = doc.to<JsonObject>(); JsonObject json = doc.to<JsonObject>();
if (!export_values_main(json)) { if (!export_values_main(json)) {
return; // empty return; // empty
} }
export_values_ww(json); // append ww values export_values_ww(json); // append ww values
doc.shrinkToFit(); // doc.shrinkToFit();
print_value_json(shell, F("heatingActive"), nullptr, F_(heatingActive), nullptr, json); print_value_json(shell, F("heatingActive"), nullptr, F_(heatingActive), nullptr, json);
print_value_json(shell, F("tapwaterActive"), nullptr, F_(tapwaterActive), nullptr, json); print_value_json(shell, F("tapwaterActive"), nullptr, F_(tapwaterActive), nullptr, json);

View File

@@ -47,13 +47,15 @@ class Boiler : public EMSdevice {
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void register_mqtt_ha_config(bool force); void register_mqtt_ha_config();
void register_mqtt_ha_config_ww();
void check_active(); void check_active();
bool export_values_main(JsonObject & doc); bool export_values_main(JsonObject & doc);
bool export_values_ww(JsonObject & doc); bool export_values_ww(JsonObject & doc);
bool changed_ = false; bool changed_ = false;
bool mqtt_ha_config_ = false; // HA MQTT Discovery bool mqtt_ha_config_ = false; // HA MQTT Discovery
bool mqtt_ha_config_ww_ = false; // HA MQTT Discovery
static constexpr uint8_t EMS_TYPE_UBAParameterWW = 0x33; static constexpr uint8_t EMS_TYPE_UBAParameterWW = 0x33;
static constexpr uint8_t EMS_TYPE_UBAFunctionTest = 0x1D; static constexpr uint8_t EMS_TYPE_UBAFunctionTest = 0x1D;

View File

@@ -49,7 +49,7 @@ bool Heatpump::export_values(JsonObject & json) {
void Heatpump::device_info_web(JsonArray & root) { void Heatpump::device_info_web(JsonArray & root) {
// fetch the values into a JSON document // fetch the values into a JSON document
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
JsonObject json = doc.to<JsonObject>(); JsonObject json = doc.to<JsonObject>();
if (!export_values(json)) { if (!export_values(json)) {
return; // empty return; // empty
@@ -64,7 +64,7 @@ void Heatpump::show_values(uuid::console::Shell & shell) {
EMSdevice::show_values(shell); // always call this to show header EMSdevice::show_values(shell); // always call this to show header
// fetch the values into a JSON document // fetch the values into a JSON document
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
JsonObject json = doc.to<JsonObject>(); JsonObject json = doc.to<JsonObject>();
if (!export_values(json)) { if (!export_values(json)) {
return; // empty return; // empty
@@ -78,27 +78,26 @@ void Heatpump::show_values(uuid::console::Shell & shell) {
void Heatpump::publish_values(JsonObject & json, bool force) { void Heatpump::publish_values(JsonObject & json, bool force) {
// handle HA first // handle HA first
if (Mqtt::mqtt_format() == Mqtt::Format::HA) { if (Mqtt::mqtt_format() == Mqtt::Format::HA) {
register_mqtt_ha_config(force); if (!mqtt_ha_config_ || force) {
register_mqtt_ha_config();
return;
}
} }
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
JsonObject json_data = doc.to<JsonObject>(); JsonObject json_data = doc.to<JsonObject>();
if (export_values(json_data)) { if (export_values(json_data)) {
Mqtt::publish(F("heatpump_data"), doc.as<JsonObject>()); Mqtt::publish(F("heatpump_data"), doc.as<JsonObject>());
} }
} }
void Heatpump::register_mqtt_ha_config(bool force) { void Heatpump::register_mqtt_ha_config() {
if ((mqtt_ha_config_ && !force)) {
return;
}
if (!Mqtt::connected()) { if (!Mqtt::connected()) {
return; return;
} }
// Create the Master device // Create the Master device
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
doc["name"] = F_(EMSESP); doc["name"] = F_(EMSESP);
doc["uniq_id"] = F_(heatpump); doc["uniq_id"] = F_(heatpump);
doc["ic"] = F_(iconheatpump); doc["ic"] = F_(iconheatpump);

View File

@@ -45,7 +45,7 @@ class Heatpump : public EMSdevice {
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void register_mqtt_ha_config(bool force); void register_mqtt_ha_config();
uint8_t airHumidity_ = EMS_VALUE_UINT_NOTSET; uint8_t airHumidity_ = EMS_VALUE_UINT_NOTSET;
uint8_t dewTemperature_ = EMS_VALUE_UINT_NOTSET; uint8_t dewTemperature_ = EMS_VALUE_UINT_NOTSET;

View File

@@ -62,7 +62,7 @@ void Mixer::device_info_web(JsonArray & root) {
} }
// fetch the values into a JSON document // fetch the values into a JSON document
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
JsonObject json = doc.to<JsonObject>(); JsonObject json = doc.to<JsonObject>();
if (!export_values_format(Mqtt::Format::SINGLE, json)) { if (!export_values_format(Mqtt::Format::SINGLE, json)) {
return; // empty return; // empty
@@ -101,7 +101,7 @@ void Mixer::show_values(uuid::console::Shell & shell) {
} }
// fetch the values into a JSON document // fetch the values into a JSON document
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
JsonObject json = doc.to<JsonObject>(); JsonObject json = doc.to<JsonObject>();
if (!export_values_format(Mqtt::Format::SINGLE, json)) { if (!export_values_format(Mqtt::Format::SINGLE, json)) {
return; // empty return; // empty
@@ -128,13 +128,16 @@ void Mixer::show_values(uuid::console::Shell & shell) {
void Mixer::publish_values(JsonObject & json, bool force) { void Mixer::publish_values(JsonObject & json, bool force) {
// handle HA first // handle HA first
if (Mqtt::mqtt_format() == Mqtt::Format::HA) { if (Mqtt::mqtt_format() == Mqtt::Format::HA) {
register_mqtt_ha_config(force); if (!mqtt_ha_config_ || force) {
register_mqtt_ha_config();
return;
}
} }
if (Mqtt::mqtt_format() == Mqtt::Format::SINGLE) { if (Mqtt::mqtt_format() == Mqtt::Format::SINGLE) {
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
JsonObject json = doc.to<JsonObject>(); JsonObject json_data = doc.to<JsonObject>();
if (export_values_format(Mqtt::mqtt_format(), json)) { if (export_values_format(Mqtt::mqtt_format(), json_data)) {
char topic[30]; char topic[30];
if (type() == Type::HC) { if (type() == Type::HC) {
snprintf_P(topic, 30, PSTR("mixer_data_hc%d"), hc_); snprintf_P(topic, 30, PSTR("mixer_data_hc%d"), hc_);
@@ -150,23 +153,18 @@ void Mixer::publish_values(JsonObject & json, bool force) {
} }
// publish config topic for HA MQTT Discovery // publish config topic for HA MQTT Discovery
void Mixer::register_mqtt_ha_config(bool force) { void Mixer::register_mqtt_ha_config() {
if ((mqtt_ha_config_ && !force)) {
return;
}
if (!Mqtt::connected()) { if (!Mqtt::connected()) {
return; return;
} }
// if we don't have valid values for this HC don't add it ever again // if we don't have valid values for this HC don't add it ever again
if (!Helpers::hasValue(status_)) { if (!Helpers::hasValue(pumpStatus_)) {
mqtt_ha_config_ = true;
return; return;
} }
// Create the Master device // Create the Master device
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
char name[20]; char name[20];
snprintf_P(name, sizeof(name), PSTR("Mixer %02X"), device_id() - 0x20 + 1); snprintf_P(name, sizeof(name), PSTR("Mixer %02X"), device_id() - 0x20 + 1);

View File

@@ -46,7 +46,7 @@ class Mixer : public EMSdevice {
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
bool export_values_format(uint8_t mqtt_format, JsonObject & doc); bool export_values_format(uint8_t mqtt_format, JsonObject & doc);
void register_mqtt_ha_config(bool force); void register_mqtt_ha_config();
void process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> telegram); void process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> telegram);
void process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> telegram); void process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> telegram);

View File

@@ -127,7 +127,10 @@ void Solar::show_values(uuid::console::Shell & shell) {
void Solar::publish_values(JsonObject & json, bool force) { void Solar::publish_values(JsonObject & json, bool force) {
// handle HA first // handle HA first
if (Mqtt::mqtt_format() == Mqtt::Format::HA) { if (Mqtt::mqtt_format() == Mqtt::Format::HA) {
register_mqtt_ha_config(force); if ((!mqtt_ha_config_ || force)) {
register_mqtt_ha_config();
return;
}
} }
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
@@ -142,17 +145,13 @@ void Solar::publish_values(JsonObject & json, bool force) {
} }
// publish config topic for HA MQTT Discovery // publish config topic for HA MQTT Discovery
void Solar::register_mqtt_ha_config(bool force) { void Solar::register_mqtt_ha_config() {
if ((mqtt_ha_config_ && !force)) {
return;
}
if (!Mqtt::connected()) { if (!Mqtt::connected()) {
return; return;
} }
// Create the Master device // Create the Master device
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
doc["name"] = F_(EMSESP); doc["name"] = F_(EMSESP);
doc["uniq_id"] = F_(solar); doc["uniq_id"] = F_(solar);
doc["ic"] = F_(iconthermostat); doc["ic"] = F_(iconthermostat);

View File

@@ -44,7 +44,7 @@ class Solar : public EMSdevice {
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void register_mqtt_ha_config(bool force); void register_mqtt_ha_config();
int16_t collectorTemp_ = EMS_VALUE_SHORT_NOTSET; // TS1: Temperature sensor for collector array 1 int16_t collectorTemp_ = EMS_VALUE_SHORT_NOTSET; // TS1: Temperature sensor for collector array 1
int16_t tankBottomTemp_ = EMS_VALUE_SHORT_NOTSET; // TS2: Temperature sensor 1 cylinder, bottom (solar thermal system) int16_t tankBottomTemp_ = EMS_VALUE_SHORT_NOTSET; // TS2: Temperature sensor 1 cylinder, bottom (solar thermal system)

View File

@@ -180,7 +180,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
// prepare data for Web UI // prepare data for Web UI
void Thermostat::device_info_web(JsonArray & root) { void Thermostat::device_info_web(JsonArray & root) {
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc_main; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc_main;
JsonObject json_main = doc_main.to<JsonObject>(); JsonObject json_main = doc_main.to<JsonObject>();
if (export_values_main(json_main)) { if (export_values_main(json_main)) {
print_value_json(root, F("time"), nullptr, F_(time), nullptr, json_main); print_value_json(root, F("time"), nullptr, F_(time), nullptr, json_main);
@@ -336,8 +336,14 @@ void Thermostat::publish_values(JsonObject & json, bool force) {
if (EMSESP::actual_master_thermostat() != this->device_id()) { if (EMSESP::actual_master_thermostat() != this->device_id()) {
return; return;
} }
// see if we have already registered this with HA MQTT Discovery, if not send the config
if (Mqtt::mqtt_format() == Mqtt::Format::HA) {
if (!ha_config(force)) {
return;
}
}
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
JsonObject json_data = doc.to<JsonObject>(); JsonObject json_data = doc.to<JsonObject>();
bool has_data = false; bool has_data = false;
@@ -354,10 +360,6 @@ void Thermostat::publish_values(JsonObject & json, bool force) {
// if we're in HA or CUSTOM, send out the complete topic with all the data // if we're in HA or CUSTOM, send out the complete topic with all the data
if (Mqtt::mqtt_format() != Mqtt::Format::SINGLE && has_data) { if (Mqtt::mqtt_format() != Mqtt::Format::SINGLE && has_data) {
// see if we have already registered this with HA MQTT Discovery, if not send the config
if (Mqtt::mqtt_format() == Mqtt::Format::HA) {
ha_config(force);
}
Mqtt::publish(F("thermostat_data"), json_data); Mqtt::publish(F("thermostat_data"), json_data);
} }
} }
@@ -685,23 +687,32 @@ bool Thermostat::export_values_hc(uint8_t mqtt_format, JsonObject & rootThermost
} }
// set up HA MQTT Discovery // set up HA MQTT Discovery
void Thermostat::ha_config(bool force) { bool Thermostat::ha_config(bool force) {
if (!Mqtt::connected()) { if (!Mqtt::connected()) {
return; return false;
}
if (force) {
for (const auto & hc : heating_circuits_) {
hc->ha_registered(false);
}
ha_registered(false);
} }
if (force || !ha_registered()) { if (!ha_registered()) {
register_mqtt_ha_config(); register_mqtt_ha_config();
ha_registered(true); ha_registered(true);
return false;
} }
// check to see which heating circuits need publishing // check to see which heating circuits need publishing
for (const auto & hc : heating_circuits_) { for (const auto & hc : heating_circuits_) {
if (force || (hc->is_active() && !hc->ha_registered())) { if (hc->is_active() && !hc->ha_registered()) {
register_mqtt_ha_config(hc->hc_num()); register_mqtt_ha_config(hc->hc_num());
hc->ha_registered(true); hc->ha_registered(true);
return false;
} }
} }
return true;
} }
// returns the heating circuit object based on the hc number // returns the heating circuit object based on the hc number
@@ -809,7 +820,7 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
// publish config topic for HA MQTT Discovery // publish config topic for HA MQTT Discovery
// homeassistant/climate/ems-esp/thermostat/config // homeassistant/climate/ems-esp/thermostat/config
void Thermostat::register_mqtt_ha_config() { void Thermostat::register_mqtt_ha_config() {
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
doc["uniq_id"] = F("thermostat"); doc["uniq_id"] = F("thermostat");
doc["ic"] = F("mdi:home-thermometer-outline"); doc["ic"] = F("mdi:home-thermometer-outline");
@@ -865,13 +876,13 @@ void Thermostat::register_mqtt_ha_config() {
void Thermostat::register_mqtt_ha_config(uint8_t hc_num) { void Thermostat::register_mqtt_ha_config(uint8_t hc_num) {
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
char str1[40]; char str1[20];
snprintf_P(str1, sizeof(str1), PSTR("Thermostat hc%d"), hc_num); snprintf_P(str1, sizeof(str1), PSTR("Thermostat hc%d"), hc_num);
char str2[40]; char str2[20];
snprintf_P(str2, sizeof(str2), PSTR("thermostat_hc%d"), hc_num); snprintf_P(str2, sizeof(str2), PSTR("thermostat_hc%d"), hc_num);
char str3[40]; char str3[25];
snprintf_P(str3, sizeof(str3), PSTR("~/%s"), str2); snprintf_P(str3, sizeof(str3), PSTR("~/%s"), str2);
doc["mode_cmd_t"] = str3; doc["mode_cmd_t"] = str3;
doc["temp_cmd_t"] = str3; doc["temp_cmd_t"] = str3;

View File

@@ -248,7 +248,7 @@ class Thermostat : public EMSdevice {
void register_mqtt_ha_config(); void register_mqtt_ha_config();
void register_mqtt_ha_config(uint8_t hc_num); void register_mqtt_ha_config(uint8_t hc_num);
void ha_config(bool force = false); bool ha_config(bool force = false);
bool thermostat_ha_cmd(const char * message, uint8_t hc_num); bool thermostat_ha_cmd(const char * message, uint8_t hc_num);
void process_RCOutdoorTemp(std::shared_ptr<const Telegram> telegram); void process_RCOutdoorTemp(std::shared_ptr<const Telegram> telegram);

View File

@@ -64,6 +64,7 @@ uint16_t EMSESP::publish_id_ = 0;
bool EMSESP::tap_water_active_ = false; // for when Boiler states we having running warm water. used in Shower() bool EMSESP::tap_water_active_ = false; // for when Boiler states we having running warm water. used in Shower()
uint32_t EMSESP::last_fetch_ = 0; uint32_t EMSESP::last_fetch_ = 0;
uint8_t EMSESP::unique_id_count_ = 0; uint8_t EMSESP::unique_id_count_ = 0;
uint8_t EMSESP::publish_all_idx_ = 0;
// for a specific EMS device go and request data values // for a specific EMS device go and request data values
// or if device_id is 0 it will fetch from all our known and active devices // or if device_id is 0 it will fetch from all our known and active devices
@@ -290,29 +291,74 @@ void EMSESP::show_sensor_values(uuid::console::Shell & shell) {
// MQTT publish everything, immediately // MQTT publish everything, immediately
void EMSESP::publish_all(bool force) { void EMSESP::publish_all(bool force) {
if (force) {
publish_all_idx_ = 1;
return;
}
if (Mqtt::connected()) { if (Mqtt::connected()) {
publish_device_values(EMSdevice::DeviceType::BOILER, force); publish_device_values(EMSdevice::DeviceType::BOILER, false);
publish_device_values(EMSdevice::DeviceType::THERMOSTAT, force); publish_device_values(EMSdevice::DeviceType::THERMOSTAT, false);
publish_device_values(EMSdevice::DeviceType::SOLAR, force); publish_device_values(EMSdevice::DeviceType::SOLAR, false);
publish_device_values(EMSdevice::DeviceType::MIXER, force); publish_device_values(EMSdevice::DeviceType::MIXER, false);
publish_other_values(); publish_other_values();
publish_sensor_values(true); publish_sensor_values(true, false);
system_.send_heartbeat(); system_.send_heartbeat();
} }
} }
// on command "publish HA" loop and wait between devices for publishing all sensors
void EMSESP::publish_all_loop() {
static uint32_t last = 0;
if (!Mqtt::connected() || !publish_all_idx_) {
return;
}
// every HA-sensor takes 20 ms, wait ~2 sec to finish (boiler have ~70 sensors)
if ((uuid::get_uptime() - last < 2000)) {
return;
}
last = uuid::get_uptime();
switch (publish_all_idx_++) {
case 1:
publish_device_values(EMSdevice::DeviceType::BOILER, true);
break;
case 2:
publish_device_values(EMSdevice::DeviceType::THERMOSTAT, true);
break;
case 3:
publish_device_values(EMSdevice::DeviceType::SOLAR, true);
break;
case 4:
publish_device_values(EMSdevice::DeviceType::MIXER, true);
break;
case 5:
publish_other_values();
break;
case 6:
publish_sensor_values(true, true);
break;
case 7:
system_.send_heartbeat();
break;
default:
// all finished
publish_all_idx_ = 0;
last = 0;
}
}
// create json doc for the devices values and add to MQTT publish queue // create json doc for the devices values and add to MQTT publish queue
// special case for Mixer units, since we want to bundle all devices together into one payload // special case for Mixer units, since we want to bundle all devices together into one payload
void EMSESP::publish_device_values(uint8_t device_type, bool force) { void EMSESP::publish_device_values(uint8_t device_type, bool force) {
if (device_type == EMSdevice::DeviceType::MIXER && Mqtt::mqtt_format() != Mqtt::Format::SINGLE) { if (device_type == EMSdevice::DeviceType::MIXER && Mqtt::mqtt_format() != Mqtt::Format::SINGLE) {
DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE); // DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE);
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
JsonObject json = doc.to<JsonObject>(); JsonObject json = doc.to<JsonObject>();
for (const auto & emsdevice : emsdevices) { for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_type)) { if (emsdevice && (emsdevice->device_type() == device_type)) {
emsdevice->publish_values(json, force); emsdevice->publish_values(json, force);
} }
} }
doc.shrinkToFit(); // doc.shrinkToFit();
Mqtt::publish("mixer_data", doc.as<JsonObject>()); Mqtt::publish("mixer_data", doc.as<JsonObject>());
return; return;
} }
@@ -335,9 +381,9 @@ void EMSESP::publish_other_values() {
} }
} }
void EMSESP::publish_sensor_values(const bool force) { void EMSESP::publish_sensor_values(const bool time, const bool force) {
if (dallassensor_.updated_values() || force) { if (dallassensor_.updated_values() || time || force) {
dallassensor_.publish_values(); dallassensor_.publish_values(force);
} }
} }
@@ -936,6 +982,7 @@ void EMSESP::loop() {
system_.loop(); // does LED and checks system health, and syslog service system_.loop(); // does LED and checks system health, and syslog service
shower_.loop(); // check for shower on/off shower_.loop(); // check for shower on/off
dallassensor_.loop(); // this will also send out via MQTT dallassensor_.loop(); // this will also send out via MQTT
publish_all_loop();
mqtt_.loop(); // sends out anything in the queue via MQTT mqtt_.loop(); // sends out anything in the queue via MQTT
console_.loop(); // telnet/serial console console_.loop(); // telnet/serial console
rxservice_.loop(); // process any incoming Rx telegrams rxservice_.loop(); // process any incoming Rx telegrams

View File

@@ -63,7 +63,7 @@ class EMSESP {
static void publish_device_values(uint8_t device_type, bool force = false); static void publish_device_values(uint8_t device_type, bool force = false);
static void publish_other_values(); static void publish_other_values();
static void publish_sensor_values(const bool force = false); static void publish_sensor_values(const bool time, const bool force = false);
static void publish_all(bool force = false); static void publish_all(bool force = false);
#ifdef EMSESP_STANDALONE #ifdef EMSESP_STANDALONE
@@ -184,6 +184,7 @@ class EMSESP {
static void process_UBADevices(std::shared_ptr<const Telegram> telegram); static void process_UBADevices(std::shared_ptr<const Telegram> telegram);
static void process_version(std::shared_ptr<const Telegram> telegram); static void process_version(std::shared_ptr<const Telegram> telegram);
static void publish_response(std::shared_ptr<const Telegram> telegram); static void publish_response(std::shared_ptr<const Telegram> telegram);
static void publish_all_loop();
static bool command_info(uint8_t device_type, JsonObject & json); static bool command_info(uint8_t device_type, JsonObject & json);
@@ -207,6 +208,7 @@ class EMSESP {
static uint16_t publish_id_; static uint16_t publish_id_;
static bool tap_water_active_; static bool tap_water_active_;
static uint8_t unique_id_count_; static uint8_t unique_id_count_;
static uint8_t publish_all_idx_;
}; };
} // namespace emsesp } // namespace emsesp

View File

@@ -40,7 +40,7 @@ bool Mqtt::mqtt_enabled_;
std::vector<Mqtt::MQTTSubFunction> Mqtt::mqtt_subfunctions_; std::vector<Mqtt::MQTTSubFunction> Mqtt::mqtt_subfunctions_;
uint16_t Mqtt::mqtt_publish_fails_ = 0; uint16_t Mqtt::mqtt_publish_fails_ = 0;
size_t Mqtt::maximum_mqtt_messages_ = Mqtt::MAX_MQTT_MESSAGES; // size_t Mqtt::maximum_mqtt_messages_ = Mqtt::MAX_MQTT_MESSAGES;
uint16_t Mqtt::mqtt_message_id_ = 0; uint16_t Mqtt::mqtt_message_id_ = 0;
std::list<Mqtt::QueuedMqttMessage> Mqtt::mqtt_messages_; std::list<Mqtt::QueuedMqttMessage> Mqtt::mqtt_messages_;
char will_topic_[Mqtt::MQTT_TOPIC_MAX_SIZE]; // because MQTT library keeps only char pointer char will_topic_[Mqtt::MQTT_TOPIC_MAX_SIZE]; // because MQTT library keeps only char pointer
@@ -527,7 +527,7 @@ std::shared_ptr<const MqttMessage> Mqtt::queue_message(const uint8_t operation,
} }
// if the queue is full, make room but removing the last one // if the queue is full, make room but removing the last one
if (mqtt_messages_.size() >= maximum_mqtt_messages_) { if (mqtt_messages_.size() >= MAX_MQTT_MESSAGES) {
mqtt_messages_.pop_front(); mqtt_messages_.pop_front();
} }
mqtt_messages_.emplace_back(mqtt_message_id_++, std::move(message)); mqtt_messages_.emplace_back(mqtt_message_id_++, std::move(message));
@@ -695,7 +695,8 @@ void Mqtt::register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, cons
return; return;
} }
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc; DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_SMALL);
// StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
doc["name"] = name; doc["name"] = name;
doc["uniq_id"] = entity; doc["uniq_id"] = entity;
@@ -723,11 +724,13 @@ void Mqtt::register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, cons
snprintf_P(ha_device, sizeof(ha_device), PSTR("ems-esp-%s"), EMSdevice::device_type_2_device_name(device_type).c_str()); snprintf_P(ha_device, sizeof(ha_device), PSTR("ems-esp-%s"), EMSdevice::device_type_2_device_name(device_type).c_str());
ids.add(ha_device); ids.add(ha_device);
doc.shrinkToFit();
char topic[MQTT_TOPIC_MAX_SIZE]; char topic[MQTT_TOPIC_MAX_SIZE];
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/binary_sensor/ems-esp/%s/config"), entity); snprintf_P(topic, sizeof(topic), PSTR("homeassistant/binary_sensor/ems-esp/%s/config"), entity);
// convert json to string and publish immediately with retain forced to true // convert json to string and publish immediately with retain forced to true
char payload_text[300]; char payload_text[256];
serializeJson(doc, payload_text); // convert json to string serializeJson(doc, payload_text); // convert json to string
uint16_t packet_id = mqttClient_->publish(topic, 0, true, payload_text); uint16_t packet_id = mqttClient_->publish(topic, 0, true, payload_text);
#if defined(EMSESP_STANDALONE) #if defined(EMSESP_STANDALONE)
@@ -740,7 +743,9 @@ void Mqtt::register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, cons
} }
#endif #endif
delay(MQTT_PUBLISH_WAIT); // delay(MQTT_PUBLISH_WAIT);
delay(50);
} }
// HA config for a normal 'sensor' type // HA config for a normal 'sensor' type
@@ -761,11 +766,11 @@ void Mqtt::register_mqtt_ha_sensor(const char * prefix,
if (prefix != nullptr) { if (prefix != nullptr) {
snprintf_P(new_entity, sizeof(new_entity), PSTR("%s.%s"), prefix, entity); snprintf_P(new_entity, sizeof(new_entity), PSTR("%s.%s"), prefix, entity);
} else { } else {
strcpy(new_entity, entity); strncpy(new_entity, entity, sizeof(new_entity));
} }
char device_name[50]; char device_name[50];
strcpy(device_name, EMSdevice::device_type_2_device_name(device_type).c_str()); strncpy(device_name, EMSdevice::device_type_2_device_name(device_type).c_str(), sizeof(device_name));
// build unique identifier, replacing all . with _ as not to break HA // build unique identifier, replacing all . with _ as not to break HA
std::string uniq(50, '\0'); std::string uniq(50, '\0');
@@ -801,9 +806,8 @@ void Mqtt::register_mqtt_ha_sensor(const char * prefix,
} }
new_name[0] = toupper(new_name[0]); // capitalize first letter new_name[0] = toupper(new_name[0]); // capitalize first letter
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc; DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_SMALL);
// StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
// DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_SMALL);
doc["name"] = new_name; doc["name"] = new_name;
doc["uniq_id"] = uniq.c_str(); doc["uniq_id"] = uniq.c_str();
@@ -819,13 +823,10 @@ void Mqtt::register_mqtt_ha_sensor(const char * prefix,
JsonArray ids = dev.createNestedArray("ids"); JsonArray ids = dev.createNestedArray("ids");
ids.add(ha_device); ids.add(ha_device);
doc.shrinkToFit();
// convert json to string and publish immediately with retain forced to true // convert json to string and publish immediately with retain forced to true
// std::string payload_text; char payload_text[256];
char payload_text[300];
serializeJson(doc, payload_text); // convert json to string serializeJson(doc, payload_text); // convert json to string
// queue_publish_message(topic, payload_text, true);
// publish_retain(topic, doc.as<JsonObject>(), true);
uint16_t packet_id = mqttClient_->publish(topic, 0, true, payload_text); uint16_t packet_id = mqttClient_->publish(topic, 0, true, payload_text);
if (!packet_id) { if (!packet_id) {
@@ -838,7 +839,8 @@ void Mqtt::register_mqtt_ha_sensor(const char * prefix,
#endif #endif
} }
delay(MQTT_PUBLISH_WAIT); // don't flood asynctcp // delay(MQTT_PUBLISH_WAIT); // don't flood asynctcp
} delay(50); // enough time to send the short message out
}
} // namespace emsesp } // namespace emsesp

View File

@@ -40,7 +40,9 @@ using uuid::console::Shell;
#define EMSESP_MAX_JSON_SIZE_SMALL 256 // for smaller json docs when using StaticJsonDocument #define EMSESP_MAX_JSON_SIZE_SMALL 256 // for smaller json docs when using StaticJsonDocument
#define EMSESP_MAX_JSON_SIZE_MEDIUM 768 // for smaller json docs from ems devices, when using StaticJsonDocument #define EMSESP_MAX_JSON_SIZE_MEDIUM 768 // for smaller json docs from ems devices, when using StaticJsonDocument
#define EMSESP_MAX_JSON_SIZE_LARGE 2048 // for large json docs from ems devices, like boiler or thermostat data. Using DynamicJsonDocument // #define EMSESP_MAX_JSON_SIZE_LARGE 2048 // for large json docs from ems devices, like boiler or thermostat data. Using DynamicJsonDocument
// mqtt does not publish larger than 1570 on esp8266, boiler message is split and now smaller
#define EMSESP_MAX_JSON_SIZE_LARGE 1536 // for large json docs from ems devices, like boiler or thermostat data. Using StaticJsonDocument
namespace emsesp { namespace emsesp {
@@ -170,10 +172,10 @@ class Mqtt {
static AsyncMqttClient * mqttClient_; static AsyncMqttClient * mqttClient_;
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 = 70; // size of queue static constexpr size_t MAX_MQTT_MESSAGES = 20; // 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

@@ -65,6 +65,12 @@ bool System::command_send(const char * value, const int8_t id) {
return true; return true;
} }
// publish
bool System::command_publish(const char * value, const int8_t id) {
EMSESP::publish_all(); // ignore value and id
return true;
}
// restart EMS-ESP // restart EMS-ESP
void System::restart() { void System::restart() {
LOG_NOTICE(F("Restarting system...")); LOG_NOTICE(F("Restarting system..."));
@@ -165,6 +171,7 @@ void System::start() {
EMSESP::webSettingsService.read([&](WebSettings & settings) { EMSESP::webSettingsService.read([&](WebSettings & settings) {
Command::add(EMSdevice::DeviceType::SYSTEM, settings.ems_bus_id, F_(pin), System::command_pin); Command::add(EMSdevice::DeviceType::SYSTEM, settings.ems_bus_id, F_(pin), System::command_pin);
Command::add(EMSdevice::DeviceType::SYSTEM, settings.ems_bus_id, F_(send), System::command_send); Command::add(EMSdevice::DeviceType::SYSTEM, settings.ems_bus_id, F_(send), System::command_send);
Command::add(EMSdevice::DeviceType::SYSTEM, settings.ems_bus_id, F_(publish), System::command_publish);
Command::add_with_json(EMSdevice::DeviceType::SYSTEM, F_(info), System::command_info); Command::add_with_json(EMSdevice::DeviceType::SYSTEM, F_(info), System::command_info);
Command::add_with_json(EMSdevice::DeviceType::SYSTEM, F_(report), System::command_report); Command::add_with_json(EMSdevice::DeviceType::SYSTEM, F_(report), System::command_report);
}); });

View File

@@ -50,6 +50,7 @@ class System {
static bool command_pin(const char * value, const int8_t id); static bool command_pin(const char * value, const int8_t id);
static bool command_send(const char * value, const int8_t id); static bool command_send(const char * value, const int8_t id);
static bool command_publish(const char * value, const int8_t id);
static bool command_info(const char * value, const int8_t id, JsonObject & json); static bool command_info(const char * value, const int8_t id, JsonObject & json);
static bool command_report(const char * value, const int8_t id, JsonObject & json); static bool command_report(const char * value, const int8_t id, JsonObject & json);