mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
split HA-config in smaller blocks, add publish command
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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<EMSESP_MAX_JSON_SIZE_MEDIUM> config;
|
||||
config["dev_cla"] = F("temperature");
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ class DallasSensor {
|
||||
|
||||
void start();
|
||||
void loop();
|
||||
void publish_values();
|
||||
void publish_values(const bool force);
|
||||
void reload();
|
||||
bool updated_values();
|
||||
|
||||
|
||||
@@ -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<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> 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<JsonObject>();
|
||||
// DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE);
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
|
||||
JsonObject json = doc.to<JsonObject>();
|
||||
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<JsonObject>();
|
||||
if (export_values_main(json_main)) {
|
||||
Mqtt::publish(F("boiler_data"), doc_main.as<JsonObject>());
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
|
||||
JsonObject json_data = doc.to<JsonObject>();
|
||||
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<JsonObject>();
|
||||
if (export_values_ww(json_ww)) {
|
||||
Mqtt::publish(F("boiler_data_ww"), doc_ww.as<JsonObject>());
|
||||
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<JsonObject>();
|
||||
// DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE);
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
|
||||
JsonObject json = doc.to<JsonObject>();
|
||||
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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
|
||||
JsonObject json = doc.to<JsonObject>();
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
|
||||
JsonObject json = doc.to<JsonObject>();
|
||||
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<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
|
||||
JsonObject json = doc.to<JsonObject>();
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
|
||||
JsonObject json = doc.to<JsonObject>();
|
||||
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<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
|
||||
JsonObject json_data = doc.to<JsonObject>();
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
|
||||
JsonObject json_data = doc.to<JsonObject>();
|
||||
if (export_values(json_data)) {
|
||||
Mqtt::publish(F("heatpump_data"), doc.as<JsonObject>());
|
||||
}
|
||||
}
|
||||
|
||||
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<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
|
||||
doc["name"] = F_(EMSESP);
|
||||
doc["uniq_id"] = F_(heatpump);
|
||||
doc["ic"] = F_(iconheatpump);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -62,7 +62,7 @@ void Mixer::device_info_web(JsonArray & root) {
|
||||
}
|
||||
|
||||
// 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>();
|
||||
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<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
|
||||
JsonObject json = doc.to<JsonObject>();
|
||||
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<EMSESP_MAX_JSON_SIZE_SMALL> doc;
|
||||
JsonObject json = doc.to<JsonObject>();
|
||||
if (export_values_format(Mqtt::mqtt_format(), json)) {
|
||||
JsonObject json_data = doc.to<JsonObject>();
|
||||
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<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
|
||||
|
||||
char name[20];
|
||||
snprintf_P(name, sizeof(name), PSTR("Mixer %02X"), device_id() - 0x20 + 1);
|
||||
|
||||
@@ -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<const Telegram> telegram);
|
||||
void process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
@@ -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<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
|
||||
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<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
|
||||
doc["name"] = F_(EMSESP);
|
||||
doc["uniq_id"] = F_(solar);
|
||||
doc["ic"] = F_(iconthermostat);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<EMSESP_MAX_JSON_SIZE_SMALL> doc_main;
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc_main;
|
||||
JsonObject json_main = doc_main.to<JsonObject>();
|
||||
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<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
|
||||
JsonObject json_data = doc.to<JsonObject>();
|
||||
bool has_data = false;
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
|
||||
JsonObject json_data = doc.to<JsonObject>();
|
||||
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::HeatingCircuit> 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<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> 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<EMSESP_MAX_JSON_SIZE_MEDIUM> 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;
|
||||
|
||||
@@ -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<const Telegram> telegram);
|
||||
|
||||
@@ -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<JsonObject>();
|
||||
// DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE);
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
|
||||
JsonObject json = doc.to<JsonObject>();
|
||||
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<JsonObject>());
|
||||
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
|
||||
|
||||
@@ -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<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_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
|
||||
|
||||
36
src/mqtt.cpp
36
src/mqtt.cpp
@@ -40,7 +40,7 @@ bool Mqtt::mqtt_enabled_;
|
||||
std::vector<Mqtt::MQTTSubFunction> 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::QueuedMqttMessage> 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<const MqttMessage> 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<EMSESP_MAX_JSON_SIZE_SMALL> doc;
|
||||
DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_SMALL);
|
||||
// StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> 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<EMSESP_MAX_JSON_SIZE_SMALL> doc;
|
||||
|
||||
// DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_SMALL);
|
||||
DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_SMALL);
|
||||
// StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> 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<JsonObject>(), 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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user