From 39a435cec3be8f91230cda6f026387cab82648f7 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 6 Oct 2020 22:30:20 +0200 Subject: [PATCH] fix for MQTT from HA for different heating circuits - #536 --- src/devices/thermostat.cpp | 49 +++++++++++++++++++------------------- src/devices/thermostat.h | 2 +- src/mqtt.cpp | 8 +++++++ src/test/test.cpp | 8 +++++-- 4 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 2d982122c..987f2b0a4 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -317,32 +317,21 @@ void Thermostat::publish_values() { JsonObject output = 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(output); if (Mqtt::mqtt_format() == Mqtt::Format::SINGLE && has_data) { Mqtt::publish(F("thermostat_data"), output); output.clear(); } + + // get the thermostat data. + // if we're in Single mode this function will also have published each of the heating circuits has_data |= export_values_hc(Mqtt::mqtt_format(), output); - // if we're in SINGLE mode the MQTT would have been published on the export_values() function for each hc + + // 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) { Mqtt::publish(F("thermostat_data"), output); } - /* - StaticJsonDocument doc_main; - JsonObject output_main = doc_main.to(); - if (export_values_main(output_main)) { - Mqtt::publish(F("thermostat_system_data"), output_main); - } - - StaticJsonDocument doc_hc; - JsonObject output_hc = doc_hc.to(); - if (export_values_hc(Mqtt::mqtt_format(), output_hc)) { - // if we're in SINGLE mode the MQTT would have been published on the export_values() function for each hc - if (Mqtt::mqtt_format() != Mqtt::Format::SINGLE) { - Mqtt::publish(F("thermostat_data"), output_hc); - } - } - */ } bool Thermostat::export_values_main(JsonObject & rootThermostat) { @@ -724,9 +713,13 @@ void Thermostat::register_mqtt_ha_config(uint8_t hc_num) { snprintf_P(str2, sizeof(str2), PSTR("thermostat_hc%d"), hc_num); doc["uniq_id"] = str2; + char str3[40]; + snprintf_P(str3, sizeof(str3), PSTR("~/%s"), str2); + + doc["uniq_id"] = str2; doc["~"] = F("ems-esp"); - doc["mode_cmd_t"] = F("~/thermostat"); - doc["temp_cmd_t"] = F("~/thermostat"); + doc["mode_cmd_t"] = str3; + doc["temp_cmd_t"] = str3; doc["mode_stat_t"] = F("~/thermostat_data"); doc["temp_stat_t"] = F("~/thermostat_data"); doc["curr_temp_t"] = F("~/thermostat_data"); @@ -752,7 +745,7 @@ void Thermostat::register_mqtt_ha_config(uint8_t hc_num) { modes.add(F("heat")); modes.add(F("off")); -/* + /* uint8_t model = this->model(); if (model == EMSdevice::EMS_DEVICE_FLAG_RC20_2) { modes.add(F("night")); @@ -786,7 +779,10 @@ void Thermostat::register_mqtt_ha_config(uint8_t hc_num) { Mqtt::publish_retain(topic, doc.as(), true); // publish the config payload with retain flag // enable the thermostat topic to take both mode strings and floats - register_mqtt_topic("thermostat", [&](const char * m) { return thermostat_ha_cmd(m); }); + // for each of the heating circuits + std::string topic2(100, '\0'); + snprintf_P(&topic2[0], topic2.capacity() + 1, PSTR("thermostat_hc%d"), hc_num); + register_mqtt_topic(topic2, [=](const char * m) { return thermostat_ha_cmd(m, hc_num); }); char hc_name[10]; // hc{1-4} strlcpy(hc_name, "hc", 10); @@ -835,17 +831,17 @@ void Thermostat::register_mqtt_ha_config(uint8_t hc_num) { // for HA specifically when receiving over MQTT in the thermostat topic // it could be either a 'mode' or a float value // return true if it parses the message correctly -bool Thermostat::thermostat_ha_cmd(const char * message) { +bool Thermostat::thermostat_ha_cmd(const char * message, uint8_t hc_num) { // check if it's json. We know the message isn't empty if (message[0] == '{') { return false; } // check for mode first - if (!set_mode(message, AUTO_HEATING_CIRCUIT)) { + if (!set_mode(message, hc_num)) { // handle as a numerical temperature value float f = strtof((char *)message, 0); - set_temperature(f, HeatingCircuit::Mode::AUTO, AUTO_HEATING_CIRCUIT); + set_temperature(f, HeatingCircuit::Mode::AUTO, hc_num); } return true; @@ -1567,6 +1563,11 @@ bool Thermostat::set_datetime(const char * value, const int8_t id) { // sets the thermostat working mode, where mode is a string // converts string mode to HeatingCircuit::Mode bool Thermostat::set_mode(const char * value, const int8_t id) { + // quit if its numerical, as it could be mistaken as a temperature value + if (value[0] <= 'A') { + return false; + } + std::string mode(10, '\0'); if (!Helpers::value2string(value, mode)) { LOG_WARNING(F("Set mode: Invalid mode")); diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index 6ba055872..265041d02 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -225,7 +225,7 @@ class Thermostat : public EMSdevice { std::shared_ptr heating_circuit(const uint8_t hc_num); void register_mqtt_ha_config(uint8_t hc_num); - bool thermostat_ha_cmd(const char * message); + bool thermostat_ha_cmd(const char * message, uint8_t hc_num); bool command_info(const char * value, const int8_t id, JsonObject & output); diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 912c83a53..05dc282e7 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -722,11 +722,15 @@ void Mqtt::register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, cons std::string payload_text; serializeJson(doc, payload_text); // convert json to string uint16_t packet_id = mqttClient_->publish(topic, 0, true, payload_text.c_str(), payload_text.size()); +#if defined(EMSESP_STANDALONE) + LOG_DEBUG(F("Publishing topic %s"), topic); +#else if (packet_id == 0) { LOG_ERROR(F("Failed to publish topic %s"), topic); } else { LOG_DEBUG(F("Publishing topic %s"), topic); } +#endif delay(MQTT_PUBLISH_WAIT); } @@ -794,11 +798,15 @@ void Mqtt::register_mqtt_ha_sensor(const char * prefix, std::string payload_text; serializeJson(doc, payload_text); // convert json to string uint16_t packet_id = mqttClient_->publish(topic, 0, true, payload_text.c_str(), payload_text.size()); +#if defined(EMSESP_STANDALONE) + LOG_DEBUG(F("Publishing topic %s"), topic); +#else if (packet_id == 0) { LOG_ERROR(F("Failed to publish topic %s"), topic); } else { LOG_DEBUG(F("Publishing topic %s"), topic); } +#endif delay(MQTT_PUBLISH_WAIT); } diff --git a/src/test/test.cpp b/src/test/test.cpp index 5f26a24d3..7aa10b60a 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -28,7 +28,7 @@ namespace emsesp { // used with the 'test' command, under su/admin void Test::run_test(uuid::console::Shell & shell, const std::string & command) { if (command == "default") { - run_test(shell, "fr120"); // add the default test case here + run_test(shell, "thermostat"); // add the default test case here } if (command.empty()) { @@ -252,7 +252,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) { shell.invoke_command("show"); } - if (command == "fr120") { + if (command == "fr120") { shell.printfln(F("Testing adding a thermostat FR120...")); // add_device(0x10, 165, version, EMSdevice::Brand::BUDERUS); @@ -307,6 +307,10 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) { uart_telegram({0x90, 0x00, 0xFF, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); shell.invoke_command("show"); + + EMSESP::mqtt_.incoming("ems-esp/thermostat_hc1", "heat"); + EMSESP::mqtt_.incoming("ems-esp/thermostat_hc2", "28.8"); + EMSESP::mqtt_.incoming("ems-esp/thermostat", "{\"cmd\":\"temp\",\"id\":2,\"data\":22}"); } if (command == "tc100") {