diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 868159566..996a1f35a 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -2,7 +2,7 @@ ### Added - 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 ### Fixed @@ -11,6 +11,7 @@ ### Changed - optimized MQTT for HA to reduce mem fragmentation issues - change syslog settings without reboot +- HA-config split in smaller blocks ### Removed - old scripts diff --git a/src/dallassensor.cpp b/src/dallassensor.cpp index b1a0bf53c..b83297489 100644 --- a/src/dallassensor.cpp +++ b/src/dallassensor.cpp @@ -309,7 +309,7 @@ bool DallasSensor::export_values(JsonObject & json) { } // 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(); if (num_sensors == 0) { @@ -340,7 +340,7 @@ void DallasSensor::publish_values() { // create the HA MQTT config // to e.g. homeassistant/sensor/ems-esp/dallas_28-233D-9497-0C03/config if (mqtt_format_ == Mqtt::Format::HA) { - if (!(registered_ha_[sensor_no - 1])) { + if (!(registered_ha_[sensor_no - 1]) || force) { StaticJsonDocument config; config["dev_cla"] = F("temperature"); diff --git a/src/dallassensor.h b/src/dallassensor.h index bcc4e8e0d..0f4ebddb2 100644 --- a/src/dallassensor.h +++ b/src/dallassensor.h @@ -58,7 +58,7 @@ class DallasSensor { void start(); void loop(); - void publish_values(); + void publish_values(const bool force); void reload(); bool updated_values(); diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index 3cb34e0c1..e4558e64f 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -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 // for each of the main elements -void Boiler::register_mqtt_ha_config(bool force) { - if ((mqtt_ha_config_ && !force)) { - return; - } - +void Boiler::register_mqtt_ha_config() { if (!Mqtt::connected()) { return; } // Create the Master device - StaticJsonDocument doc; + StaticJsonDocument doc; doc["name"] = F("Service Code"); doc["uniq_id"] = F("boiler"); doc["ic"] = F("mdi:home-thermometer-outline"); @@ -141,8 +137,17 @@ 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_(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_ha_config_ = true; // done +} - // ww +// 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 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_(wWDisinfectionTemp), this->device_type(), "wWDisinfectionTemp", F_(degrees), F_(icontemperature)); @@ -170,14 +175,15 @@ 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_(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 void Boiler::device_info_web(JsonArray & root) { // fetch the values into a JSON document - DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE); - JsonObject json = doc.to(); + // DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE); + StaticJsonDocument doc; + JsonObject json = doc.to(); if (!export_values_main(json)) { return; // empty } @@ -618,19 +624,29 @@ bool Boiler::export_values_main(JsonObject & json) { void Boiler::publish_values(JsonObject & json, bool force) { // handle HA first 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); - JsonObject json_main = doc_main.to(); - if (export_values_main(json_main)) { - Mqtt::publish(F("boiler_data"), doc_main.as()); + StaticJsonDocument doc; + JsonObject json_data = doc.to(); + if (export_values_main(json_data)) { + Mqtt::publish(F("boiler_data"), json_data); } + json_data.clear(); - DynamicJsonDocument doc_ww(EMSESP_MAX_JSON_SIZE_LARGE); - JsonObject json_ww = doc_ww.to(); - if (export_values_ww(json_ww)) { - Mqtt::publish(F("boiler_data_ww"), doc_ww.as()); + if (export_values_ww(json_data)) { + Mqtt::publish(F("boiler_data_ww"), json_data); } // 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 // fetch the values into a JSON document - DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE); - JsonObject json = doc.to(); + // DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE); + StaticJsonDocument doc; + JsonObject json = doc.to(); if (!export_values_main(json)) { return; // empty } 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("tapwaterActive"), nullptr, F_(tapwaterActive), nullptr, json); diff --git a/src/devices/boiler.h b/src/devices/boiler.h index 3fe2f0fc1..173882080 100644 --- a/src/devices/boiler.h +++ b/src/devices/boiler.h @@ -47,13 +47,15 @@ class Boiler : public EMSdevice { private: 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(); bool export_values_main(JsonObject & doc); bool export_values_ww(JsonObject & doc); - bool changed_ = false; - bool mqtt_ha_config_ = false; // HA MQTT Discovery + bool changed_ = false; + 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_UBAFunctionTest = 0x1D; diff --git a/src/devices/heatpump.cpp b/src/devices/heatpump.cpp index ef4adf175..463a4cd7d 100644 --- a/src/devices/heatpump.cpp +++ b/src/devices/heatpump.cpp @@ -49,8 +49,8 @@ bool Heatpump::export_values(JsonObject & json) { void Heatpump::device_info_web(JsonArray & root) { // fetch the values into a JSON document - StaticJsonDocument doc; - JsonObject json = doc.to(); + StaticJsonDocument doc; + JsonObject json = doc.to(); if (!export_values(json)) { return; // empty } @@ -64,8 +64,8 @@ void Heatpump::show_values(uuid::console::Shell & shell) { EMSdevice::show_values(shell); // always call this to show header // fetch the values into a JSON document - StaticJsonDocument doc; - JsonObject json = doc.to(); + StaticJsonDocument doc; + JsonObject json = doc.to(); if (!export_values(json)) { return; // empty } @@ -78,27 +78,26 @@ void Heatpump::show_values(uuid::console::Shell & shell) { void Heatpump::publish_values(JsonObject & json, bool force) { // handle HA first if (Mqtt::mqtt_format() == Mqtt::Format::HA) { - register_mqtt_ha_config(force); + if (!mqtt_ha_config_ || force) { + register_mqtt_ha_config(); + return; + } } - StaticJsonDocument doc; - JsonObject json_data = doc.to(); + StaticJsonDocument doc; + JsonObject json_data = doc.to(); if (export_values(json_data)) { Mqtt::publish(F("heatpump_data"), doc.as()); } } -void Heatpump::register_mqtt_ha_config(bool force) { - if ((mqtt_ha_config_ && !force)) { - return; - } - +void Heatpump::register_mqtt_ha_config() { if (!Mqtt::connected()) { return; } // Create the Master device - StaticJsonDocument doc; + StaticJsonDocument doc; doc["name"] = F_(EMSESP); doc["uniq_id"] = F_(heatpump); doc["ic"] = F_(iconheatpump); diff --git a/src/devices/heatpump.h b/src/devices/heatpump.h index a1b641cc6..2f453523c 100644 --- a/src/devices/heatpump.h +++ b/src/devices/heatpump.h @@ -45,7 +45,7 @@ class Heatpump : public EMSdevice { private: 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 dewTemperature_ = EMS_VALUE_UINT_NOTSET; diff --git a/src/devices/mixer.cpp b/src/devices/mixer.cpp index 43354768d..41c636c51 100644 --- a/src/devices/mixer.cpp +++ b/src/devices/mixer.cpp @@ -62,7 +62,7 @@ void Mixer::device_info_web(JsonArray & root) { } // fetch the values into a JSON document - StaticJsonDocument doc; + StaticJsonDocument doc; JsonObject json = doc.to(); if (!export_values_format(Mqtt::Format::SINGLE, json)) { return; // empty @@ -101,7 +101,7 @@ void Mixer::show_values(uuid::console::Shell & shell) { } // fetch the values into a JSON document - StaticJsonDocument doc; + StaticJsonDocument doc; JsonObject json = doc.to(); if (!export_values_format(Mqtt::Format::SINGLE, json)) { return; // empty @@ -128,13 +128,16 @@ void Mixer::show_values(uuid::console::Shell & shell) { void Mixer::publish_values(JsonObject & json, bool force) { // handle HA first 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) { StaticJsonDocument doc; - JsonObject json = doc.to(); - if (export_values_format(Mqtt::mqtt_format(), json)) { + JsonObject json_data = doc.to(); + if (export_values_format(Mqtt::mqtt_format(), json_data)) { char topic[30]; if (type() == Type::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 -void Mixer::register_mqtt_ha_config(bool force) { - if ((mqtt_ha_config_ && !force)) { - return; - } - +void Mixer::register_mqtt_ha_config() { if (!Mqtt::connected()) { return; } // if we don't have valid values for this HC don't add it ever again - if (!Helpers::hasValue(status_)) { - mqtt_ha_config_ = true; + if (!Helpers::hasValue(pumpStatus_)) { return; } // Create the Master device - StaticJsonDocument doc; + StaticJsonDocument doc; char name[20]; snprintf_P(name, sizeof(name), PSTR("Mixer %02X"), device_id() - 0x20 + 1); diff --git a/src/devices/mixer.h b/src/devices/mixer.h index bdf3b98b3..4341b214c 100644 --- a/src/devices/mixer.h +++ b/src/devices/mixer.h @@ -46,7 +46,7 @@ class Mixer : public EMSdevice { static uuid::log::Logger logger_; 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 telegram); void process_MMPLUSStatusMessage_WWC(std::shared_ptr telegram); diff --git a/src/devices/solar.cpp b/src/devices/solar.cpp index f865945d2..900cfdd2c 100644 --- a/src/devices/solar.cpp +++ b/src/devices/solar.cpp @@ -127,7 +127,10 @@ void Solar::show_values(uuid::console::Shell & shell) { void Solar::publish_values(JsonObject & json, bool force) { // handle HA first if (Mqtt::mqtt_format() == Mqtt::Format::HA) { - register_mqtt_ha_config(force); + if ((!mqtt_ha_config_ || force)) { + register_mqtt_ha_config(); + return; + } } StaticJsonDocument doc; @@ -142,17 +145,13 @@ void Solar::publish_values(JsonObject & json, bool force) { } // publish config topic for HA MQTT Discovery -void Solar::register_mqtt_ha_config(bool force) { - if ((mqtt_ha_config_ && !force)) { - return; - } - +void Solar::register_mqtt_ha_config() { if (!Mqtt::connected()) { return; } // Create the Master device - StaticJsonDocument doc; + StaticJsonDocument doc; doc["name"] = F_(EMSESP); doc["uniq_id"] = F_(solar); doc["ic"] = F_(iconthermostat); diff --git a/src/devices/solar.h b/src/devices/solar.h index dcc649a12..3054b912b 100644 --- a/src/devices/solar.h +++ b/src/devices/solar.h @@ -44,7 +44,7 @@ class Solar : public EMSdevice { private: 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 tankBottomTemp_ = EMS_VALUE_SHORT_NOTSET; // TS2: Temperature sensor 1 cylinder, bottom (solar thermal system) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index cdaf6f7e9..3a8605632 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -180,7 +180,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i // prepare data for Web UI void Thermostat::device_info_web(JsonArray & root) { - StaticJsonDocument doc_main; + StaticJsonDocument doc_main; JsonObject json_main = doc_main.to(); if (export_values_main(json_main)) { print_value_json(root, F("time"), nullptr, F_(time), nullptr, json_main); @@ -336,10 +336,16 @@ void Thermostat::publish_values(JsonObject & json, bool force) { if (EMSESP::actual_master_thermostat() != this->device_id()) { 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 doc; - JsonObject json_data = doc.to(); - bool has_data = false; + StaticJsonDocument doc; + JsonObject json_data = doc.to(); + bool has_data = false; // if MQTT is in single mode send out the main data to the thermostat_data topic has_data |= export_values_main(json_data); @@ -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 (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); } } @@ -685,23 +687,32 @@ bool Thermostat::export_values_hc(uint8_t mqtt_format, JsonObject & rootThermost } // set up HA MQTT Discovery -void Thermostat::ha_config(bool force) { +bool Thermostat::ha_config(bool force) { 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(); ha_registered(true); + return false; } // check to see which heating circuits need publishing 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()); hc->ha_registered(true); + return false; } } + return true; } // returns the heating circuit object based on the hc number @@ -809,7 +820,7 @@ std::shared_ptr Thermostat::heating_circuit(std::sha // publish config topic for HA MQTT Discovery // homeassistant/climate/ems-esp/thermostat/config void Thermostat::register_mqtt_ha_config() { - StaticJsonDocument doc; + StaticJsonDocument doc; doc["uniq_id"] = F("thermostat"); 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) { StaticJsonDocument doc; - char str1[40]; + char str1[20]; 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); - char str3[40]; + char str3[25]; snprintf_P(str3, sizeof(str3), PSTR("~/%s"), str2); doc["mode_cmd_t"] = str3; doc["temp_cmd_t"] = str3; diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index 2366674a6..2e8999a1b 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -248,7 +248,7 @@ class Thermostat : public EMSdevice { void register_mqtt_ha_config(); 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); void process_RCOutdoorTemp(std::shared_ptr telegram); diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 91b30df71..117f1f706 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -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() uint32_t EMSESP::last_fetch_ = 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 // 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 void EMSESP::publish_all(bool force) { + if (force) { + publish_all_idx_ = 1; + return; + } if (Mqtt::connected()) { - publish_device_values(EMSdevice::DeviceType::BOILER, force); - publish_device_values(EMSdevice::DeviceType::THERMOSTAT, force); - publish_device_values(EMSdevice::DeviceType::SOLAR, force); - publish_device_values(EMSdevice::DeviceType::MIXER, force); + publish_device_values(EMSdevice::DeviceType::BOILER, false); + publish_device_values(EMSdevice::DeviceType::THERMOSTAT, false); + publish_device_values(EMSdevice::DeviceType::SOLAR, false); + publish_device_values(EMSdevice::DeviceType::MIXER, false); publish_other_values(); - publish_sensor_values(true); + publish_sensor_values(true, false); 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 // 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) { if (device_type == EMSdevice::DeviceType::MIXER && Mqtt::mqtt_format() != Mqtt::Format::SINGLE) { - DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE); - JsonObject json = doc.to(); + // DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE); + StaticJsonDocument doc; + JsonObject json = doc.to(); for (const auto & emsdevice : emsdevices) { if (emsdevice && (emsdevice->device_type() == device_type)) { emsdevice->publish_values(json, force); } } - doc.shrinkToFit(); + // doc.shrinkToFit(); Mqtt::publish("mixer_data", doc.as()); return; } @@ -335,9 +381,9 @@ void EMSESP::publish_other_values() { } } -void EMSESP::publish_sensor_values(const bool force) { - if (dallassensor_.updated_values() || force) { - dallassensor_.publish_values(); +void EMSESP::publish_sensor_values(const bool time, const bool force) { + if (dallassensor_.updated_values() || time || force) { + dallassensor_.publish_values(force); } } @@ -936,6 +982,7 @@ void EMSESP::loop() { system_.loop(); // does LED and checks system health, and syslog service shower_.loop(); // check for shower on/off dallassensor_.loop(); // this will also send out via MQTT + publish_all_loop(); mqtt_.loop(); // sends out anything in the queue via MQTT console_.loop(); // telnet/serial console rxservice_.loop(); // process any incoming Rx telegrams diff --git a/src/emsesp.h b/src/emsesp.h index 0fd6d976a..dbcdb6a04 100644 --- a/src/emsesp.h +++ b/src/emsesp.h @@ -63,7 +63,7 @@ class EMSESP { static void publish_device_values(uint8_t device_type, bool force = false); 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); #ifdef EMSESP_STANDALONE @@ -184,6 +184,7 @@ class EMSESP { static void process_UBADevices(std::shared_ptr telegram); static void process_version(std::shared_ptr telegram); static void publish_response(std::shared_ptr telegram); + static void publish_all_loop(); static bool command_info(uint8_t device_type, JsonObject & json); @@ -207,6 +208,7 @@ class EMSESP { static uint16_t publish_id_; static bool tap_water_active_; static uint8_t unique_id_count_; + static uint8_t publish_all_idx_; }; } // namespace emsesp diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 09febd6fc..7dc881187 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -40,7 +40,7 @@ bool Mqtt::mqtt_enabled_; std::vector Mqtt::mqtt_subfunctions_; 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; std::list Mqtt::mqtt_messages_; char will_topic_[Mqtt::MQTT_TOPIC_MAX_SIZE]; // because MQTT library keeps only char pointer @@ -527,7 +527,7 @@ std::shared_ptr Mqtt::queue_message(const uint8_t operation, } // 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_.emplace_back(mqtt_message_id_++, std::move(message)); @@ -695,7 +695,8 @@ void Mqtt::register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, cons return; } - StaticJsonDocument doc; + DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_SMALL); + // StaticJsonDocument doc; doc["name"] = name; 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()); ids.add(ha_device); + doc.shrinkToFit(); + char topic[MQTT_TOPIC_MAX_SIZE]; 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 - char payload_text[300]; + char payload_text[256]; serializeJson(doc, payload_text); // convert json to string uint16_t packet_id = mqttClient_->publish(topic, 0, true, payload_text); #if defined(EMSESP_STANDALONE) @@ -740,7 +743,9 @@ void Mqtt::register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, cons } #endif - delay(MQTT_PUBLISH_WAIT); + // delay(MQTT_PUBLISH_WAIT); + delay(50); + } // HA config for a normal 'sensor' type @@ -761,11 +766,11 @@ void Mqtt::register_mqtt_ha_sensor(const char * prefix, if (prefix != nullptr) { snprintf_P(new_entity, sizeof(new_entity), PSTR("%s.%s"), prefix, entity); } else { - strcpy(new_entity, entity); + strncpy(new_entity, entity, sizeof(new_entity)); } 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 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 - StaticJsonDocument doc; - - // DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_SMALL); + DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_SMALL); + // StaticJsonDocument doc; doc["name"] = new_name; doc["uniq_id"] = uniq.c_str(); @@ -819,13 +823,10 @@ void Mqtt::register_mqtt_ha_sensor(const char * prefix, JsonArray ids = dev.createNestedArray("ids"); ids.add(ha_device); + doc.shrinkToFit(); // convert json to string and publish immediately with retain forced to true - // std::string payload_text; - char payload_text[300]; + char payload_text[256]; serializeJson(doc, payload_text); // convert json to string - // queue_publish_message(topic, payload_text, true); - - // publish_retain(topic, doc.as(), true); uint16_t packet_id = mqttClient_->publish(topic, 0, true, payload_text); if (!packet_id) { @@ -838,7 +839,8 @@ void Mqtt::register_mqtt_ha_sensor(const char * prefix, #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 diff --git a/src/mqtt.h b/src/mqtt.h index ed1970cb6..8b987dbb4 100644 --- a/src/mqtt.h +++ b/src/mqtt.h @@ -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_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 { @@ -170,10 +172,10 @@ class Mqtt { static AsyncMqttClient * mqttClient_; - static size_t maximum_mqtt_messages_; + // static size_t maximum_mqtt_messages_; 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 uint8_t MQTT_PUBLISH_MAX_RETRY = 3; // max retries for giving up on publishing diff --git a/src/system.cpp b/src/system.cpp index dde28449d..524561998 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -65,6 +65,12 @@ bool System::command_send(const char * value, const int8_t id) { 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 void System::restart() { LOG_NOTICE(F("Restarting system...")); @@ -165,6 +171,7 @@ void System::start() { 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_(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_(report), System::command_report); }); diff --git a/src/system.h b/src/system.h index 808b189fa..a5f5c44e7 100644 --- a/src/system.h +++ b/src/system.h @@ -50,6 +50,7 @@ class System { 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_publish(const char * value, const int8_t id); 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);