From 6d12fff4fef2248799cff876284883845ec4db47 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 20 Sep 2021 21:41:29 +0200 Subject: [PATCH 01/21] add API test --- src/test/test.cpp | 13 +++++++++++-- src/test/test.h | 4 ++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/test/test.cpp b/src/test/test.cpp index 66b367ce5..00114c4c0 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -948,11 +948,20 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) { if (command == "api") { #if defined(EMSESP_STANDALONE) shell.printfln(F("Testing RESTful API...")); - Mqtt::ha_enabled(false); + Mqtt::ha_enabled(true); Mqtt::enabled(false); run_test("general"); AsyncWebServerRequest request; + request.url("/api/boiler/id"); + EMSESP::webAPIService.webAPIService_get(&request); + + request.url("/api/thermostat"); + EMSESP::webAPIService.webAPIService_get(&request); + + request.url("/api/thermostat/hamode"); + EMSESP::webAPIService.webAPIService_get(&request); + // GET request.method(HTTP_GET); request.url("/api/thermostat/seltemp"); @@ -994,7 +1003,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) { EMSESP::webAPIService.webAPIService_post(&request, json); // 3 - char data3[] = "{\"device\":\"thermostat\", \"name\":\"temp\",\"value\":11}"; + char data3[] = "{\"device\":\"thermostat\", \"name\":\"temp\",\"value\":13}"; deserializeJson(doc, data3); json = doc.as(); request.url("/api"); diff --git a/src/test/test.h b/src/test/test.h index 5e4e29ffc..d9ca69ca7 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -34,12 +34,12 @@ namespace emsesp { // #define EMSESP_DEBUG_DEFAULT "boiler" // #define EMSESP_DEBUG_DEFAULT "mqtt2" // #define EMSESP_DEBUG_DEFAULT "mqtt_nested" -#define EMSESP_DEBUG_DEFAULT "ha" +// #define EMSESP_DEBUG_DEFAULT "ha" // #define EMSESP_DEBUG_DEFAULT "board_profile" // #define EMSESP_DEBUG_DEFAULT "shower_alert" // #define EMSESP_DEBUG_DEFAULT "310" // #define EMSESP_DEBUG_DEFAULT "render" -// #define EMSESP_DEBUG_DEFAULT "api" +#define EMSESP_DEBUG_DEFAULT "api" // #define EMSESP_DEBUG_DEFAULT "crash" class Test { From 1a71921fd6dd7180f190db4c01bea91b9f52ce6c Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 20 Sep 2021 21:41:48 +0200 Subject: [PATCH 02/21] remove debug --- src/console.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/console.cpp b/src/console.cpp index 21b5aa161..2825a74b5 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -404,8 +404,6 @@ void EMSESPShell::add_console_commands() { cmd_return = Command::call(device_type, cmd, arguments[2].c_str(), true, atoi(arguments[3].c_str()), json); } - shell.printfln("size=%d measure=%d overflowed=%d", doc.size(), measureJson(doc), doc.overflowed()); // TODO remove debug - if (cmd_return == CommandRet::OK && json.size()) { serializeJsonPretty(doc, shell); shell.println(); From d8add7edcbf5b9ced72a1d21f3e6c14689447a26 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 20 Sep 2021 21:42:24 +0200 Subject: [PATCH 03/21] rename DeviceValueType::TEXT to STRING and ignore UOM if its NONE --- src/emsdevice.cpp | 25 ++++++++++++++----------- src/emsdevice.h | 5 +++-- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 44f79d914..5cf77a670 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -125,7 +125,7 @@ const std::string EMSdevice::tag_to_mqtt(uint8_t tag) { } const std::string EMSdevice::uom_to_string(uint8_t uom) { - if (uom == DeviceValueUOM::NONE) { + if ((uom == DeviceValueUOM::NONE) || (uom == DeviceValueUOM::TEXT)) { return std::string{}; } return uuid::read_flash_string(DeviceValueUOM_s[uom - 1]); // offset by 1 to account for NONE @@ -484,7 +484,7 @@ void EMSdevice::register_device_value(uint8_t tag, int32_t min, uint32_t max) { // init the value depending on it's type - if (type == DeviceValueType::TEXT) { + if (type == DeviceValueType::STRING) { *(char *)(value_p) = {'\0'}; } else if (type == DeviceValueType::INT) { *(int8_t *)(value_p) = EMS_VALUE_INT_NOTSET; @@ -577,7 +577,7 @@ const std::string EMSdevice::get_value_uom(const char * key) { if (dv.full_name != nullptr) { if (uuid::read_flash_string(dv.full_name) == p) { // ignore TIME since "minutes" is already added to the string value - if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) { + if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::TEXT) || (dv.uom == DeviceValueUOM::MINUTES)) { break; } return EMSdevice::uom_to_string(dv.uom); @@ -606,7 +606,7 @@ void EMSdevice::generate_values_json_web(JsonObject & json) { } // handle TEXT strings - else if ((dv.type == DeviceValueType::TEXT) && (Helpers::hasValue((char *)(dv.value_p)))) { + else if ((dv.type == DeviceValueType::STRING) && (Helpers::hasValue((char *)(dv.value_p)))) { obj = data.createNestedObject(); obj["v"] = (char *)(dv.value_p); } @@ -633,7 +633,7 @@ void EMSdevice::generate_values_json_web(JsonObject & json) { uint8_t divider = 0; uint8_t factor = 1; if (dv.options_size == 1) { - const char * s = uuid::read_flash_string(dv.options[0]).c_str(); + const char * s = uuid::read_flash_string(dv.options[0]).c_str(); if (s[0] == '*') { factor = Helpers::atoint(&s[1]); } else { @@ -719,11 +719,13 @@ bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t // search device value with this tag for (auto & dv : devicevalues_) { - if (strcmp(cmd, Helpers::toLower(uuid::read_flash_string(dv.short_name)).c_str()) == 0 && (tag <= 0 || tag == dv.tag)) { + // ignore any device values which have a uom of NONE as we use this to hide them + if ((dv.uom != DeviceValueUOM::NONE) + && (strcmp(cmd, Helpers::toLower(uuid::read_flash_string(dv.short_name)).c_str()) == 0 && (tag <= 0 || tag == dv.tag))) { uint8_t divider = 0; uint8_t factor = 1; if (dv.options_size == 1) { - const char * s = uuid::read_flash_string(dv.options[0]).c_str(); + const char * s = uuid::read_flash_string(dv.options[0]).c_str(); if (s[0] == '*') { factor = Helpers::atoint(&s[1]); } else { @@ -849,7 +851,7 @@ bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t json[max] = divider ? EMS_VALUE_ULONG_NOTSET / divider : EMS_VALUE_ULONG_NOTSET; break; - case DeviceValueType::TEXT: + case DeviceValueType::STRING: if (Helpers::hasValue((char *)(dv.value_p))) { json[value] = (char *)(dv.value_p); } @@ -906,9 +908,10 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter bool has_value = false; // only show if tag is either empty (TAG_NONE) or matches a value // and don't show if full_name is empty unless we're outputing for mqtt payloads + // and ignore anything that has an UOM of "NONE" as these are hidden values (e.g. id and hamode) // for nested we use all values, dont show command only (have_cmd and no fullname) if (((nested) || tag_filter == DeviceValueTAG::TAG_NONE || (tag_filter == dv.tag)) && (dv.full_name != nullptr || !console) - && !(dv.full_name == nullptr && dv.has_cmd)) { + && !(dv.full_name == nullptr && dv.has_cmd) && (dv.uom != DeviceValueUOM::NONE)) { // we have a tag if it matches the filter given, and that the tag name is not empty/"" bool have_tag = ((dv.tag != tag_filter) && !tag_to_string(dv.tag).empty()); @@ -950,7 +953,7 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter } // handle TEXT strings - else if ((dv.type == DeviceValueType::TEXT) && (Helpers::hasValue((char *)(dv.value_p)))) { + else if ((dv.type == DeviceValueType::STRING) && (Helpers::hasValue((char *)(dv.value_p)))) { json[name] = (char *)(dv.value_p); has_value = true; } @@ -976,7 +979,7 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter uint8_t divider = 0; uint8_t factor = 1; if (dv.options_size == 1) { - const char * s = uuid::read_flash_string(dv.options[0]).c_str(); + const char * s = uuid::read_flash_string(dv.options[0]).c_str(); if (s[0] == '*') { factor = Helpers::atoint(&s[1]); } else { diff --git a/src/emsdevice.h b/src/emsdevice.h index 4bcfe914b..b13b52d1f 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -39,7 +39,7 @@ enum DeviceValueType : uint8_t { ULONG, TIME, // same as ULONG (32 bits) ENUM, - TEXT, + STRING, CMD // special for commands only }; @@ -66,7 +66,8 @@ enum DeviceValueUOM : uint8_t { DBM, // 14 NUM, // 15 BOOLEAN, // 16 - LIST // 17 + LIST, // 17 + TEXT // 18 }; From b1f59d4727e7a0f2ab25b733c2e14e0773c34f8b Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 20 Sep 2021 21:42:45 +0200 Subject: [PATCH 04/21] ignore UOM if its TEXT --- src/mqtt.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 54fb0e809..43acf6894 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -1010,7 +1010,7 @@ void Mqtt::publish_ha_sensor(uint8_t type, // EMSdevice::Dev bool set_state_class = false; // unit of measure and map the HA icon - if (uom != DeviceValueUOM::NONE) { + if ((uom != DeviceValueUOM::NONE) && (uom != DeviceValueUOM::TEXT)) { doc["unit_of_meas"] = EMSdevice::uom_to_string(uom); } @@ -1060,6 +1060,7 @@ void Mqtt::publish_ha_sensor(uint8_t type, // EMSdevice::Dev doc["ic"] = F_(iconnum); break; case DeviceValueUOM::NONE: + case DeviceValueUOM::TEXT: default: break; } From 09d8a6360bb38dc99520b6df616cd3073f0b590a Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 20 Sep 2021 21:43:05 +0200 Subject: [PATCH 05/21] only use UOM of NONE for hidden Device Values --- src/devices/boiler.cpp | 14 +++++++------- src/devices/mixer.cpp | 2 +- src/devices/solar.cpp | 6 +++--- src/devices/switch.cpp | 2 +- src/devices/thermostat.cpp | 34 +++++++++++++++++----------------- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index 97c0f34f1..e2e00ffa8 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -142,10 +142,10 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value(TAG_BOILER_DATA, &burnWorkMin_, DeviceValueType::TIME, nullptr, FL_(burnWorkMin), DeviceValueUOM::MINUTES); register_device_value(TAG_BOILER_DATA, &heatWorkMin_, DeviceValueType::TIME, nullptr, FL_(heatWorkMin), DeviceValueUOM::MINUTES); register_device_value(TAG_BOILER_DATA, &UBAuptime_, DeviceValueType::TIME, nullptr, FL_(UBAuptime), DeviceValueUOM::MINUTES); - register_device_value(TAG_BOILER_DATA, &lastCode_, DeviceValueType::TEXT, nullptr, FL_(lastCode), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &serviceCode_, DeviceValueType::TEXT, nullptr, FL_(serviceCode), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &serviceCodeNumber_, DeviceValueType::USHORT, nullptr, FL_(serviceCodeNumber), DeviceValueUOM::NONE); - register_device_value(TAG_BOILER_DATA, &maintenanceMessage_, DeviceValueType::TEXT, nullptr, FL_(maintenanceMessage), DeviceValueUOM::NONE); + register_device_value(TAG_BOILER_DATA, &lastCode_, DeviceValueType::STRING, nullptr, FL_(lastCode), DeviceValueUOM::TEXT); + register_device_value(TAG_BOILER_DATA, &serviceCode_, DeviceValueType::STRING, nullptr, FL_(serviceCode), DeviceValueUOM::TEXT); + register_device_value(TAG_BOILER_DATA, &serviceCodeNumber_, DeviceValueType::USHORT, nullptr, FL_(serviceCodeNumber), DeviceValueUOM::NUM); + register_device_value(TAG_BOILER_DATA, &maintenanceMessage_, DeviceValueType::STRING, nullptr, FL_(maintenanceMessage), DeviceValueUOM::TEXT); register_device_value(TAG_BOILER_DATA, &maintenanceType_, DeviceValueType::ENUM, @@ -156,7 +156,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value( TAG_BOILER_DATA, &maintenanceTime_, DeviceValueType::USHORT, nullptr, FL_(maintenanceTime), DeviceValueUOM::HOURS, MAKE_CF_CB(set_maintenancetime)); register_device_value( - TAG_BOILER_DATA, &maintenanceDate_, DeviceValueType::TEXT, nullptr, FL_(maintenanceDate), DeviceValueUOM::NONE, MAKE_CF_CB(set_maintenancedate)); + TAG_BOILER_DATA, &maintenanceDate_, DeviceValueType::STRING, nullptr, FL_(maintenanceDate), DeviceValueUOM::TEXT, MAKE_CF_CB(set_maintenancedate)); // heatpump info if (model() == EMS_DEVICE_FLAG_HEATPUMP) { register_device_value(TAG_BOILER_DATA, &upTimeControl_, DeviceValueType::TIME, FL_(div60), FL_(upTimeControl), DeviceValueUOM::MINUTES); @@ -226,11 +226,11 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const FL_(wwSelTempSingle), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_warmwater_temp_single)); - register_device_value(TAG_BOILER_DATA_WW, &wwType_, DeviceValueType::ENUM, FL_(enum_flow), FL_(wwType), DeviceValueUOM::NONE); + register_device_value(TAG_BOILER_DATA_WW, &wwType_, DeviceValueType::ENUM, FL_(enum_flow), FL_(wwType), DeviceValueUOM::TEXT); register_device_value( TAG_BOILER_DATA_WW, &wwComfort_, DeviceValueType::ENUM, FL_(enum_comfort), FL_(wwComfort), DeviceValueUOM::LIST, MAKE_CF_CB(set_warmwater_mode)); register_device_value( - TAG_BOILER_DATA_WW, &wwFlowTempOffset_, DeviceValueType::UINT, nullptr, FL_(wwFlowTempOffset), DeviceValueUOM::NONE, MAKE_CF_CB(set_wWFlowTempOffset)); + TAG_BOILER_DATA_WW, &wwFlowTempOffset_, DeviceValueType::UINT, nullptr, FL_(wwFlowTempOffset), DeviceValueUOM::NUM, MAKE_CF_CB(set_wWFlowTempOffset)); register_device_value( TAG_BOILER_DATA_WW, &wwMaxPower_, DeviceValueType::UINT, nullptr, FL_(wwMaxPower), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_warmwater_maxpower)); register_device_value( diff --git a/src/devices/mixer.cpp b/src/devices/mixer.cpp index f009ab606..0f6a34ad7 100644 --- a/src/devices/mixer.cpp +++ b/src/devices/mixer.cpp @@ -60,7 +60,7 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s register_device_value(tag, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE); register_device_value(tag, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(wwTemp), DeviceValueUOM::DEGREES); register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, FL_(wwPumpStatus), DeviceValueUOM::BOOLEAN); - register_device_value(tag, &status_, DeviceValueType::INT, nullptr, FL_(wwTempStatus), DeviceValueUOM::NONE); + register_device_value(tag, &status_, DeviceValueType::INT, nullptr, FL_(wwTempStatus), DeviceValueUOM::NUM); } } diff --git a/src/devices/solar.cpp b/src/devices/solar.cpp index b235d723e..6ab6dcec5 100644 --- a/src/devices/solar.cpp +++ b/src/devices/solar.cpp @@ -64,7 +64,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s // special case for a device_id with 0x2A where it's not actual a solar module if (device_id == 0x2A) { - register_device_value(TAG_NONE, &type_, DeviceValueType::TEXT, nullptr, FL_(type), DeviceValueUOM::NONE); + register_device_value(TAG_NONE, &type_, DeviceValueType::STRING, nullptr, FL_(type), DeviceValueUOM::TEXT); strlcpy(type_, "warm water circuit", sizeof(type_)); register_device_value(TAG_NONE, &wwTemp_1_, DeviceValueType::UINT, nullptr, FL_(wwTemp1), DeviceValueUOM::DEGREES); register_device_value(TAG_NONE, &wwTemp_3_, DeviceValueType::UINT, nullptr, FL_(wwTemp3), DeviceValueUOM::DEGREES); @@ -169,13 +169,13 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s MAKE_CF_CB(set_doubleMatchFlow)); // double Match Flow, 00=off // telegram 0x380 - register_device_value(TAG_NONE, &climateZone_, DeviceValueType::UINT, nullptr, FL_(climateZone), DeviceValueUOM::NONE, MAKE_CF_CB(set_climateZone)); // climate zone identifier + register_device_value(TAG_NONE, &climateZone_, DeviceValueType::UINT, nullptr, FL_(climateZone), DeviceValueUOM::NUM, MAKE_CF_CB(set_climateZone)); // climate zone identifier register_device_value(TAG_NONE, &collector1Area_, DeviceValueType::USHORT, FL_(div10), FL_(collector1Area), - DeviceValueUOM::NONE, + DeviceValueUOM::NUM, MAKE_CF_CB(set_collector1Area)); // Area of collector field 1 register_device_value(TAG_NONE, &collector1Type_, diff --git a/src/devices/switch.cpp b/src/devices/switch.cpp index 06b91a945..4a00c4233 100644 --- a/src/devices/switch.cpp +++ b/src/devices/switch.cpp @@ -37,7 +37,7 @@ Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const register_device_value(TAG_NONE, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE); register_device_value(TAG_NONE, &activated_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::BOOLEAN); register_device_value(TAG_NONE, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempHc), DeviceValueUOM::DEGREES); - register_device_value(TAG_NONE, &status_, DeviceValueType::INT, nullptr, FL_(status), DeviceValueUOM::NONE); + register_device_value(TAG_NONE, &status_, DeviceValueType::INT, nullptr, FL_(status), DeviceValueUOM::NUM); id_ = product_id; } diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 3f39e4c9a..ffb866353 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -2389,13 +2389,13 @@ bool Thermostat::set_roominfluence(const char * value, const int8_t id) { void Thermostat::register_device_values() { // Common for all thermostats register_device_value(TAG_THERMOSTAT_DATA, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE); - register_device_value(TAG_THERMOSTAT_DATA, &errorCode_, DeviceValueType::TEXT, nullptr, FL_(errorCode), DeviceValueUOM::NONE); - register_device_value(TAG_THERMOSTAT_DATA, &lastCode_, DeviceValueType::TEXT, nullptr, FL_(lastCode), DeviceValueUOM::NONE); + register_device_value(TAG_THERMOSTAT_DATA, &errorCode_, DeviceValueType::STRING, nullptr, FL_(errorCode), DeviceValueUOM::TEXT); + register_device_value(TAG_THERMOSTAT_DATA, &lastCode_, DeviceValueType::STRING, nullptr, FL_(lastCode), DeviceValueUOM::TEXT); switch (this->model()) { case EMS_DEVICE_FLAG_RC100: case EMS_DEVICE_FLAG_RC300: - register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime)); + register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::TEXT, MAKE_CF_CB(set_datetime)); register_device_value(TAG_THERMOSTAT_DATA, &floordrystatus_, DeviceValueType::ENUM, FL_(enum_floordrystatus), FL_(floordrystatus), DeviceValueUOM::LIST); register_device_value(TAG_THERMOSTAT_DATA, &dampedoutdoortemp2_, DeviceValueType::SHORT, FL_(div10), FL_(dampedoutdoortemp), DeviceValueUOM::DEGREES); register_device_value(TAG_THERMOSTAT_DATA, &floordrytemp_, DeviceValueType::UINT, nullptr, FL_(floordrytemp), DeviceValueUOM::DEGREES); @@ -2432,10 +2432,10 @@ void Thermostat::register_device_values() { break; case EMS_DEVICE_FLAG_RC20_N: case EMS_DEVICE_FLAG_RC20: - register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime + register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::TEXT); // can't set datetime break; case EMS_DEVICE_FLAG_RC30_N: - register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime + register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::TEXT); // can't set datetime register_device_value(TAG_THERMOSTAT_DATA, &ibaMainDisplay_, DeviceValueType::ENUM, FL_(enum_ibaMainDisplay), FL_(ibaMainDisplay), DeviceValueUOM::LIST); register_device_value(TAG_THERMOSTAT_DATA, &ibaLanguage_, DeviceValueType::ENUM, FL_(enum_ibaLanguage), FL_(ibaLanguage), DeviceValueUOM::LIST); register_device_value(TAG_THERMOSTAT_DATA, @@ -2443,7 +2443,7 @@ void Thermostat::register_device_values() { DeviceValueType::UINT, nullptr, FL_(ibaClockOffset), - DeviceValueUOM::NONE); // offset (in sec) to clock, 0xff=-1s, 0x02=2s + DeviceValueUOM::NUM); // offset (in sec) to clock, 0xff=-1s, 0x02=2s register_device_value(TAG_THERMOSTAT_DATA, &ibaCalIntTemperature_, DeviceValueType::INT, @@ -2471,7 +2471,7 @@ void Thermostat::register_device_values() { TAG_THERMOSTAT_DATA, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode2), FL_(wwCircMode), DeviceValueUOM::LIST, MAKE_CF_CB(set_wwcircmode)); break; case EMS_DEVICE_FLAG_RC35: - register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime)); + register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::TEXT, MAKE_CF_CB(set_datetime)); register_device_value(TAG_THERMOSTAT_DATA, &ibaCalIntTemperature_, DeviceValueType::INT, @@ -2518,7 +2518,7 @@ void Thermostat::register_device_values() { DeviceValueType::UINT, nullptr, FL_(wwDisinfectHour), - DeviceValueUOM::NONE, + DeviceValueUOM::NUM, MAKE_CF_CB(set_wwDisinfectHour), 0, 23); @@ -2527,14 +2527,14 @@ void Thermostat::register_device_values() { TAG_THERMOSTAT_DATA, &wwOneTimeKey_, DeviceValueType::BOOL, nullptr, FL_(wwOneTimeKey), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_wwOneTimeKey)); break; case EMS_DEVICE_FLAG_JUNKERS: - register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime)); + register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::TEXT, MAKE_CF_CB(set_datetime)); break; case EMS_DEVICE_FLAG_EASY: // Easy TC100 have no date/time, see issue #100, not sure about CT200, so leave it. - register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime + register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::TEXT); // can't set datetime break; default: - register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime + register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::TEXT); // can't set datetime break; } } @@ -2613,7 +2613,7 @@ void Thermostat::register_device_values_hc(std::shared_ptroffsettemp, DeviceValueType::INT, nullptr, FL_(offsettemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_offsettemp)); register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, nullptr, FL_(minflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minflowtemp)); register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, nullptr, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp)); - register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT, nullptr, FL_(roominfluence), DeviceValueUOM::NONE, MAKE_CF_CB(set_roominfluence)); + register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT, nullptr, FL_(roominfluence), DeviceValueUOM::NUM, MAKE_CF_CB(set_roominfluence)); register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT, nullptr, FL_(nofrosttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nofrosttemp)); register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT, nullptr, FL_(targetflowtemp), DeviceValueUOM::DEGREES); register_device_value(tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::LIST); @@ -2622,10 +2622,10 @@ void Thermostat::register_device_values_hc(std::shared_ptrsummermode, DeviceValueType::BOOL, nullptr, FL_(summermode), DeviceValueUOM::BOOLEAN); register_device_value( tag, &hc->controlmode, DeviceValueType::ENUM, FL_(enum_controlmode), FL_(controlmode), DeviceValueUOM::LIST, MAKE_CF_CB(set_controlmode)); - register_device_value(tag, &hc->program, DeviceValueType::UINT, nullptr, FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program)); + register_device_value(tag, &hc->program, DeviceValueType::UINT, nullptr, FL_(program), DeviceValueUOM::NUM, MAKE_CF_CB(set_program)); register_device_value(tag, &hc->tempautotemp, DeviceValueType::UINT, FL_(div2), FL_(tempautotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_tempautotemp)); register_device_value( - tag, &hc->fastHeatupFactor, DeviceValueType::UINT, nullptr, FL_(fastheatupfactor), DeviceValueUOM::NONE, MAKE_CF_CB(set_fastheatupfactor)); + tag, &hc->fastHeatupFactor, DeviceValueType::UINT, nullptr, FL_(fastheatupfactor), DeviceValueUOM::NUM, MAKE_CF_CB(set_fastheatupfactor)); break; case EMS_DEVICE_FLAG_CRF: register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode5), FL_(mode), DeviceValueUOM::LIST); @@ -2640,7 +2640,7 @@ void Thermostat::register_device_values_hc(std::shared_ptrmodetype, DeviceValueType::ENUM, FL_(enum_modetype2), FL_(modetype), DeviceValueUOM::LIST); register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), FL_(daytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(nighttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); - register_device_value(tag, &hc->program, DeviceValueType::UINT, nullptr, FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program)); + register_device_value(tag, &hc->program, DeviceValueType::UINT, nullptr, FL_(program), DeviceValueUOM::NUM, MAKE_CF_CB(set_program)); // RC25 additions, guess, not validated by users, see:https://github.com/emsesp/EMS-ESP32/issues/106 register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, nullptr, FL_(minflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minflowtemp)); register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, nullptr, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp)); @@ -2664,7 +2664,7 @@ void Thermostat::register_device_values_hc(std::shared_ptrsummermode, DeviceValueType::BOOL, nullptr, FL_(summermode), DeviceValueUOM::BOOLEAN); register_device_value(tag, &hc->holidaymode, DeviceValueType::BOOL, nullptr, FL_(holidaymode), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_holiday)); register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT, nullptr, FL_(nofrosttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nofrosttemp)); - register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT, nullptr, FL_(roominfluence), DeviceValueUOM::NONE, MAKE_CF_CB(set_roominfluence)); + register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT, nullptr, FL_(roominfluence), DeviceValueUOM::NUM, MAKE_CF_CB(set_roominfluence)); register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, nullptr, FL_(minflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minflowtemp)); register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, nullptr, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp)); register_device_value(tag, &hc->flowtempoffset, DeviceValueType::UINT, nullptr, FL_(flowtempoffset), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_flowtempoffset)); @@ -2674,7 +2674,7 @@ void Thermostat::register_device_values_hc(std::shared_ptrcontrolmode, DeviceValueType::ENUM, FL_(enum_controlmode2), FL_(controlmode), DeviceValueUOM::LIST, MAKE_CF_CB(set_controlmode)); register_device_value(tag, &hc->control, DeviceValueType::ENUM, FL_(enum_control), FL_(control), DeviceValueUOM::LIST, MAKE_CF_CB(set_control)); - register_device_value(tag, &hc->program, DeviceValueType::UINT, nullptr, FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program)); + register_device_value(tag, &hc->program, DeviceValueType::UINT, nullptr, FL_(program), DeviceValueUOM::NUM, MAKE_CF_CB(set_program)); register_device_value(tag, &hc->pause, DeviceValueType::UINT, nullptr, FL_(pause), DeviceValueUOM::HOURS, MAKE_CF_CB(set_pause)); register_device_value(tag, &hc->party, DeviceValueType::UINT, nullptr, FL_(party), DeviceValueUOM::HOURS, MAKE_CF_CB(set_party)); register_device_value(tag, &hc->tempautotemp, DeviceValueType::UINT, FL_(div2), FL_(tempautotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_tempautotemp)); From a31cf5386359cd922a0c5fc990587fae9332f101 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 20 Sep 2021 21:43:56 +0200 Subject: [PATCH 06/21] replace class components (HOCs) with React Hooks --- interface/package.json | 12 +-- .../authentication/UnauthenticatedRoute.tsx | 22 ++---- interface/src/components/FormLoader.tsx | 56 +++++++++++++ interface/src/components/index.ts | 1 + interface/src/features/FeaturesWrapper.tsx | 65 +++++---------- interface/src/hooks/index.ts | 2 + interface/src/hooks/useAuthorizedRest.ts | 12 +++ interface/src/hooks/useRest.ts | 79 +++++++++++++++++++ interface/src/utils/binding.ts | 33 ++++++++ interface/src/utils/index.ts | 1 + 10 files changed, 214 insertions(+), 69 deletions(-) create mode 100644 interface/src/components/FormLoader.tsx create mode 100644 interface/src/hooks/index.ts create mode 100644 interface/src/hooks/useAuthorizedRest.ts create mode 100644 interface/src/hooks/useRest.ts create mode 100644 interface/src/utils/binding.ts create mode 100644 interface/src/utils/index.ts diff --git a/interface/package.json b/interface/package.json index fd3d99c94..abd7f4a96 100644 --- a/interface/package.json +++ b/interface/package.json @@ -3,13 +3,13 @@ "version": "0.1.0", "private": true, "dependencies": { - "@material-ui/core": "^4.11.4", + "@material-ui/core": "^4.12.3", "@material-ui/icons": "^4.11.2", "@msgpack/msgpack": "^2.7.0", - "@types/lodash": "^4.14.168", - "@types/node": "^15.0.1", - "@types/react": "^17.0.4", - "@types/react-dom": "^17.0.3", + "@types/lodash": "^4.14.172", + "@types/node": "^12.20.20", + "@types/react": "^17.0.19", + "@types/react-dom": "^17.0.9", "@types/react-material-ui-form-validator": "^2.1.0", "@types/react-router": "^5.1.13", "@types/react-router-dom": "^5.1.7", @@ -30,7 +30,7 @@ "react-router-dom": "^5.2.0", "react-scripts": "4.0.3", "sockette": "^2.0.6", - "typescript": "4.2.4", + "typescript": "4.3.5", "zlib": "^1.0.5" }, "scripts": { diff --git a/interface/src/authentication/UnauthenticatedRoute.tsx b/interface/src/authentication/UnauthenticatedRoute.tsx index ca6512b7d..9396c44b3 100644 --- a/interface/src/authentication/UnauthenticatedRoute.tsx +++ b/interface/src/authentication/UnauthenticatedRoute.tsx @@ -22,25 +22,13 @@ interface UnauthenticatedRouteProps | React.ComponentType; } -type RenderComponent = (props: RouteComponentProps) => React.ReactNode; - class UnauthenticatedRoute extends Route { public render() { - const { - authenticationContext, - component: Component, - features, - ...rest - } = this.props; - const renderComponent: RenderComponent = (props) => { - if (authenticationContext.me) { - return ; - } - if (Component) { - return ; - } - }; - return ; + const { authenticationContext, features, ...rest } = this.props; + if (authenticationContext.me) { + return ; + } + return ; } } diff --git a/interface/src/components/FormLoader.tsx b/interface/src/components/FormLoader.tsx new file mode 100644 index 000000000..3efeeb663 --- /dev/null +++ b/interface/src/components/FormLoader.tsx @@ -0,0 +1,56 @@ +import { FC } from 'react'; + +import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'; +import { Button, LinearProgress, Typography } from '@material-ui/core'; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + loadingSettings: { + margin: theme.spacing(0.5) + }, + loadingSettingsDetails: { + margin: theme.spacing(4), + textAlign: 'center' + }, + button: { + marginRight: theme.spacing(2), + marginTop: theme.spacing(2) + } + }) +); + +interface FormLoaderProps { + errorMessage?: string; + loadData: () => void; +} + +const FormLoader: FC = ({ errorMessage, loadData }) => { + const classes = useStyles(); + if (errorMessage) { + return ( +
+ + {errorMessage} + + +
+ ); + } + return ( +
+ + + Loading… + +
+ ); +}; + +export default FormLoader; diff --git a/interface/src/components/index.ts b/interface/src/components/index.ts index 47348a94d..e98047039 100644 --- a/interface/src/components/index.ts +++ b/interface/src/components/index.ts @@ -5,6 +5,7 @@ export { default as HighlightAvatar } from './HighlightAvatar'; export { default as MenuAppBar } from './MenuAppBar'; export { default as PasswordValidator } from './PasswordValidator'; export { default as RestFormLoader } from './RestFormLoader'; +export { default as FormLoader } from './FormLoader'; export { default as SectionContent } from './SectionContent'; export { default as WebSocketFormLoader } from './WebSocketFormLoader'; export { default as ErrorButton } from './ErrorButton'; diff --git a/interface/src/features/FeaturesWrapper.tsx b/interface/src/features/FeaturesWrapper.tsx index 4742a4bcc..e5c762f23 100644 --- a/interface/src/features/FeaturesWrapper.tsx +++ b/interface/src/features/FeaturesWrapper.tsx @@ -1,58 +1,31 @@ -import { Component } from 'react'; +import { FC } from 'react'; -import { Features } from './types'; -import { FeaturesContext } from './FeaturesContext'; import FullScreenLoading from '../components/FullScreenLoading'; import ApplicationError from '../components/ApplicationError'; import { FEATURES_ENDPOINT } from '../api'; +import { useRest } from '../hooks'; -interface FeaturesWrapperState { - features?: Features; - error?: string; -} +import { Features } from './types'; +import { FeaturesContext } from './FeaturesContext'; -class FeaturesWrapper extends Component<{}, FeaturesWrapperState> { - state: FeaturesWrapperState = {}; +const FeaturesWrapper: FC = ({ children }) => { + const { data: features, errorMessage: error } = useRest({ + endpoint: FEATURES_ENDPOINT + }); - componentDidMount() { - this.fetchFeaturesDetails(); + if (features) { + return ( + + {children} + + ); } - fetchFeaturesDetails = () => { - fetch(FEATURES_ENDPOINT) - .then((response) => { - if (response.status === 200) { - return response.json(); - } else { - throw Error('Unexpected status code: ' + response.status); - } - }) - .then((features) => { - this.setState({ features }); - }) - .catch((error) => { - this.setState({ error: error.message }); - }); - }; - - render() { - const { features, error } = this.state; - if (features) { - return ( - - {this.props.children} - - ); - } - if (error) { - return ; - } - return ; + if (error) { + return ; } -} + + return ; +}; export default FeaturesWrapper; diff --git a/interface/src/hooks/index.ts b/interface/src/hooks/index.ts new file mode 100644 index 000000000..94897b22a --- /dev/null +++ b/interface/src/hooks/index.ts @@ -0,0 +1,2 @@ +export { default as useRest } from './useRest'; +export { default as useAuthorizedRest } from './useAuthorizedRest'; diff --git a/interface/src/hooks/useAuthorizedRest.ts b/interface/src/hooks/useAuthorizedRest.ts new file mode 100644 index 000000000..78fa7ce56 --- /dev/null +++ b/interface/src/hooks/useAuthorizedRest.ts @@ -0,0 +1,12 @@ +import { redirectingAuthorizedFetch } from '../authentication'; +import useRest, { RestRequestOptions } from './useRest'; + +const useAuthorizedRest = ({ + endpoint +}: Omit) => + useRest({ + endpoint, + fetchFunction: redirectingAuthorizedFetch + }); + +export default useAuthorizedRest; diff --git a/interface/src/hooks/useRest.ts b/interface/src/hooks/useRest.ts new file mode 100644 index 000000000..0d6b30743 --- /dev/null +++ b/interface/src/hooks/useRest.ts @@ -0,0 +1,79 @@ +import { useCallback, useEffect, useState } from 'react'; +import { useSnackbar } from 'notistack'; + +export interface RestRequestOptions { + endpoint: string; + fetchFunction?: typeof fetch; +} + +const useRest = ({ + endpoint, + fetchFunction = fetch +}: RestRequestOptions) => { + const { enqueueSnackbar } = useSnackbar(); + + const [saving, setSaving] = useState(false); + const [data, setData] = useState(); + const [errorMessage, setErrorMessage] = useState(); + + const handleError = useCallback( + (error: any) => { + const errorMessage = error.message || 'Unknown error'; + enqueueSnackbar('Problem fetching: ' + errorMessage, { + variant: 'error' + }); + setErrorMessage(errorMessage); + }, + [enqueueSnackbar] + ); + + const loadData = useCallback(async () => { + setData(undefined); + setErrorMessage(undefined); + try { + const response = await fetchFunction(endpoint); + if (response.status !== 200) { + throw Error('Invalid status code: ' + response.status); + } + setData(await response.json()); + } catch (error) { + handleError(error); + } + }, [handleError, fetchFunction, endpoint]); + + const save = useCallback( + async (data: D) => { + setSaving(true); + setErrorMessage(undefined); + try { + const response = await fetchFunction(endpoint, { + method: 'POST', + body: JSON.stringify(data), + headers: { + 'Content-Type': 'application/json' + } + }); + if (response.status !== 200) { + throw Error('Invalid status code: ' + response.status); + } + enqueueSnackbar('Update successful.', { variant: 'success' }); + setData(await response.json()); + } catch (error) { + handleError(error); + } finally { + setSaving(false); + } + }, + [enqueueSnackbar, handleError, fetchFunction, endpoint] + ); + + const saveData = () => data && save(data); + + useEffect(() => { + loadData(); + }, [loadData]); + + return { loadData, saveData, saving, setData, data, errorMessage } as const; +}; + +export default useRest; diff --git a/interface/src/utils/binding.ts b/interface/src/utils/binding.ts new file mode 100644 index 000000000..dac942044 --- /dev/null +++ b/interface/src/utils/binding.ts @@ -0,0 +1,33 @@ +type UpdateEntity = (state: (prevState: Readonly) => S) => void; + +export const extractEventValue = ( + event: React.ChangeEvent +) => { + switch (event.target.type) { + case 'number': + return event.target.valueAsNumber; + case 'checkbox': + return event.target.checked; + default: + return event.target.value; + } +}; + +export const updateValue = (updateEntity: UpdateEntity) => ( + event: React.ChangeEvent +) => { + updateEntity((prevState) => ({ + ...prevState, + [event.target.name]: extractEventValue(event) + })); +}; + +export const updateBooleanValue = (updateEntity: UpdateEntity) => ( + name: string, + value?: boolean +) => { + updateEntity((prevState) => ({ + ...prevState, + [name]: value + })); +}; diff --git a/interface/src/utils/index.ts b/interface/src/utils/index.ts new file mode 100644 index 000000000..1ad877297 --- /dev/null +++ b/interface/src/utils/index.ts @@ -0,0 +1 @@ +export * from './binding'; From 16e390f8496479ae4cf453ea6ca399f9168ffc10 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 20 Sep 2021 21:44:23 +0200 Subject: [PATCH 07/21] v3.3 --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index ccad8f1db..ddd6dc8fb 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.2.2b6" +#define EMSESP_APP_VERSION "3.3" From 6ef8ff757abe72c70ef67ca43f7e25731c9a0451 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 21 Sep 2021 18:02:14 +0200 Subject: [PATCH 08/21] add check to prevent crash on null strings --- lib/uuid-common/src/read_flash_string.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/uuid-common/src/read_flash_string.cpp b/lib/uuid-common/src/read_flash_string.cpp index a5d6b78fe..94fccb6b1 100644 --- a/lib/uuid-common/src/read_flash_string.cpp +++ b/lib/uuid-common/src/read_flash_string.cpp @@ -25,6 +25,10 @@ namespace uuid { std::string read_flash_string(const __FlashStringHelper * flash_str) { + if (flash_str == nullptr) { + return std::string(""); // prevent crash + } + std::string str(::strlen_P(reinterpret_cast(flash_str)), '\0'); ::strncpy_P(&str[0], reinterpret_cast(flash_str), str.capacity() + 1); From ba3d49172c5be86309e7baacc2aba6544ee72828 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 21 Sep 2021 18:02:40 +0200 Subject: [PATCH 09/21] updated packages --- interface/package-lock.json | 114 ++++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 50 deletions(-) diff --git a/interface/package-lock.json b/interface/package-lock.json index a9ca3a7a6..62b4fd527 100644 --- a/interface/package-lock.json +++ b/interface/package-lock.json @@ -8,13 +8,13 @@ "name": "emsesp-react", "version": "0.1.0", "dependencies": { - "@material-ui/core": "^4.11.4", + "@material-ui/core": "^4.12.3", "@material-ui/icons": "^4.11.2", "@msgpack/msgpack": "^2.7.0", - "@types/lodash": "^4.14.168", - "@types/node": "^15.0.1", - "@types/react": "^17.0.4", - "@types/react-dom": "^17.0.3", + "@types/lodash": "^4.14.172", + "@types/node": "^12.20.20", + "@types/react": "^17.0.19", + "@types/react-dom": "^17.0.9", "@types/react-material-ui-form-validator": "^2.1.0", "@types/react-router": "^5.1.13", "@types/react-router-dom": "^5.1.7", @@ -35,7 +35,7 @@ "react-router-dom": "^5.2.0", "react-scripts": "4.0.3", "sockette": "^2.0.6", - "typescript": "4.2.4", + "typescript": "4.3.5", "zlib": "^1.0.5" }, "devDependencies": { @@ -2050,13 +2050,13 @@ } }, "node_modules/@material-ui/core": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.4.tgz", - "integrity": "sha512-oqb+lJ2Dl9HXI9orc6/aN8ZIAMkeThufA5iZELf2LQeBn2NtjVilF5D2w7e9RpntAzDb4jK5DsVhkfOvFY/8fg==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz", + "integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==", "dependencies": { "@babel/runtime": "^7.4.4", "@material-ui/styles": "^4.11.4", - "@material-ui/system": "^4.11.3", + "@material-ui/system": "^4.12.1", "@material-ui/types": "5.1.0", "@material-ui/utils": "^4.11.2", "@types/react-transition-group": "^4.2.0", @@ -2137,9 +2137,9 @@ } }, "node_modules/@material-ui/system": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.11.3.tgz", - "integrity": "sha512-SY7otguNGol41Mu2Sg6KbBP1ZRFIbFLHGK81y4KYbsV2yIcaEPOmsCK6zwWlp+2yTV3J/VwT6oSBARtGIVdXPw==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz", + "integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==", "dependencies": { "@babel/runtime": "^7.4.4", "@material-ui/utils": "^4.11.2", @@ -2148,6 +2148,20 @@ }, "engines": { "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/@material-ui/types": { @@ -2639,9 +2653,9 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" }, "node_modules/@types/lodash": { - "version": "4.14.168", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.168.tgz", - "integrity": "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==" + "version": "4.14.173", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.173.tgz", + "integrity": "sha512-vv0CAYoaEjCw/mLy96GBTnRoZrSxkGE0BKzKimdR8P3OzrNYNvBgtW7p055A+E8C31vXNUhWKoFCbhq7gbyhFg==" }, "node_modules/@types/material-ui": { "version": "0.21.8", @@ -2658,9 +2672,9 @@ "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==" }, "node_modules/@types/node": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.1.tgz", - "integrity": "sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA==" + "version": "12.20.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.25.tgz", + "integrity": "sha512-hcTWqk7DR/HrN9Xe7AlJwuCaL13Vcd9/g/T54YrJz4Q3ESM5mr33YCzW2bOfzSIc3aZMeGBvbLGvgN6mIJ0I5Q==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.0", @@ -2688,9 +2702,9 @@ "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==" }, "node_modules/@types/react": { - "version": "17.0.4", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.4.tgz", - "integrity": "sha512-onz2BqScSFMoTRdJUZUDD/7xrusM8hBA2Fktk2qgaTYPCgPvWnDEgkrOs8hhPUf2jfcIXkJ5yK6VfYormJS3Jw==", + "version": "17.0.22", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.22.tgz", + "integrity": "sha512-kq/BMeaAVLJM6Pynh8C2rnr/drCK+/5ksH0ch9asz+8FW3DscYCIEFtCeYTFeIx/ubvOsMXmRfy7qEJ76gM96A==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2706,9 +2720,9 @@ } }, "node_modules/@types/react-dom": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.3.tgz", - "integrity": "sha512-4NnJbCeWE+8YBzupn/YrJxZ8VnjcJq5iR1laqQ1vkpQgBiA7bwk0Rp24fxsdNinzJY2U+HHS4dJJDPdoMjdJ7w==", + "version": "17.0.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz", + "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==", "dependencies": { "@types/react": "*" } @@ -19249,9 +19263,9 @@ } }, "node_modules/typescript": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", - "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -23150,13 +23164,13 @@ } }, "@material-ui/core": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.4.tgz", - "integrity": "sha512-oqb+lJ2Dl9HXI9orc6/aN8ZIAMkeThufA5iZELf2LQeBn2NtjVilF5D2w7e9RpntAzDb4jK5DsVhkfOvFY/8fg==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz", + "integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==", "requires": { "@babel/runtime": "^7.4.4", "@material-ui/styles": "^4.11.4", - "@material-ui/system": "^4.11.3", + "@material-ui/system": "^4.12.1", "@material-ui/types": "5.1.0", "@material-ui/utils": "^4.11.2", "@types/react-transition-group": "^4.2.0", @@ -23200,9 +23214,9 @@ } }, "@material-ui/system": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.11.3.tgz", - "integrity": "sha512-SY7otguNGol41Mu2Sg6KbBP1ZRFIbFLHGK81y4KYbsV2yIcaEPOmsCK6zwWlp+2yTV3J/VwT6oSBARtGIVdXPw==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz", + "integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==", "requires": { "@babel/runtime": "^7.4.4", "@material-ui/utils": "^4.11.2", @@ -23611,9 +23625,9 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" }, "@types/lodash": { - "version": "4.14.168", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.168.tgz", - "integrity": "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==" + "version": "4.14.173", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.173.tgz", + "integrity": "sha512-vv0CAYoaEjCw/mLy96GBTnRoZrSxkGE0BKzKimdR8P3OzrNYNvBgtW7p055A+E8C31vXNUhWKoFCbhq7gbyhFg==" }, "@types/material-ui": { "version": "0.21.8", @@ -23630,9 +23644,9 @@ "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==" }, "@types/node": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.1.tgz", - "integrity": "sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA==" + "version": "12.20.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.25.tgz", + "integrity": "sha512-hcTWqk7DR/HrN9Xe7AlJwuCaL13Vcd9/g/T54YrJz4Q3ESM5mr33YCzW2bOfzSIc3aZMeGBvbLGvgN6mIJ0I5Q==" }, "@types/normalize-package-data": { "version": "2.4.0", @@ -23660,9 +23674,9 @@ "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==" }, "@types/react": { - "version": "17.0.4", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.4.tgz", - "integrity": "sha512-onz2BqScSFMoTRdJUZUDD/7xrusM8hBA2Fktk2qgaTYPCgPvWnDEgkrOs8hhPUf2jfcIXkJ5yK6VfYormJS3Jw==", + "version": "17.0.22", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.22.tgz", + "integrity": "sha512-kq/BMeaAVLJM6Pynh8C2rnr/drCK+/5ksH0ch9asz+8FW3DscYCIEFtCeYTFeIx/ubvOsMXmRfy7qEJ76gM96A==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -23685,9 +23699,9 @@ } }, "@types/react-dom": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.3.tgz", - "integrity": "sha512-4NnJbCeWE+8YBzupn/YrJxZ8VnjcJq5iR1laqQ1vkpQgBiA7bwk0Rp24fxsdNinzJY2U+HHS4dJJDPdoMjdJ7w==", + "version": "17.0.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz", + "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==", "requires": { "@types/react": "*" } @@ -37376,9 +37390,9 @@ } }, "typescript": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", - "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==" + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==" }, "unbox-primitive": { "version": "1.0.1", From 252554ea8732e6ecfc4b7f50804907bd262d9fe2 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 21 Sep 2021 18:02:52 +0200 Subject: [PATCH 10/21] added comment about nesting --- lib_standalone/ESP8266React.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_standalone/ESP8266React.h b/lib_standalone/ESP8266React.h index 908b776b6..fcea74c55 100644 --- a/lib_standalone/ESP8266React.h +++ b/lib_standalone/ESP8266React.h @@ -35,7 +35,7 @@ class DummySettings { uint8_t mqtt_qos = 0; bool mqtt_retain = false; bool enabled = true; - uint8_t nested_format = 1; + uint8_t nested_format = 1; // 1=nested 2=single uint8_t ha_climate_format = 1; bool ha_enabled = true; String base = "ems-esp"; From 8fab4e29bf3ecfaa9d4aa8523050c4a6466b6cff Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 21 Sep 2021 18:03:05 +0200 Subject: [PATCH 11/21] use float instead of double --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4b611b114..114d15fa0 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ CXX_STANDARD := -std=c++11 #---------------------------------------------------------------------- # Defined Symbols #---------------------------------------------------------------------- -DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_DEFAULT_BOARD_PROFILE=\"LOLIN\" +DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_DEFAULT_BOARD_PROFILE=\"LOLIN\" #---------------------------------------------------------------------- # Sources & Files From 30d1e7ecb40f93ee19c97b7825981aa30dca4921 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 21 Sep 2021 18:03:14 +0200 Subject: [PATCH 12/21] bump version --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index ddd6dc8fb..9ad2c5671 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.3" +#define EMSESP_APP_VERSION "v3.2.2b7" From 906813b8f55371549f58f50bd49673fd1c60a45c Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 21 Sep 2021 18:03:30 +0200 Subject: [PATCH 13/21] don't show handlers if there arn't any --- src/system.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/system.cpp b/src/system.cpp index a220827b7..fed00e290 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -981,7 +981,10 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & json obj["type"] = emsdevice->device_type_name(); obj["name"] = emsdevice->to_string(); char result[200]; - obj["handlers"] = emsdevice->show_telegram_handlers(result); + (void)emsdevice->show_telegram_handlers(result); + if (result[0] != '\0') { + obj["handlers"] = result; // don't show hanlders if there aren't any + } } } } From 4d88c6a90b0366b5b86c96371eec2985d0bf929e Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 21 Sep 2021 18:03:43 +0200 Subject: [PATCH 14/21] add comments about nesting --- src/mqtt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mqtt.h b/src/mqtt.h index dc9bfc246..b964be7c8 100644 --- a/src/mqtt.h +++ b/src/mqtt.h @@ -174,11 +174,11 @@ class Mqtt { } static uint8_t nested_format() { - return nested_format_; + return nested_format_; // nested_format is 1 if nested, otherwise 2 for single topics } static void nested_format(uint8_t nested_format) { - nested_format_ = nested_format; + nested_format_ = nested_format; // nested_format is 1 if nested, otherwise 2 for single topics } static bool ha_enabled() { From 54199affc1261efd8407867ce9aa37779d07236f Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 21 Sep 2021 18:04:07 +0200 Subject: [PATCH 15/21] removed DeviceValueUOM::TEXT --- src/mqtt.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 43acf6894..54fb0e809 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -1010,7 +1010,7 @@ void Mqtt::publish_ha_sensor(uint8_t type, // EMSdevice::Dev bool set_state_class = false; // unit of measure and map the HA icon - if ((uom != DeviceValueUOM::NONE) && (uom != DeviceValueUOM::TEXT)) { + if (uom != DeviceValueUOM::NONE) { doc["unit_of_meas"] = EMSdevice::uom_to_string(uom); } @@ -1060,7 +1060,6 @@ void Mqtt::publish_ha_sensor(uint8_t type, // EMSdevice::Dev doc["ic"] = F_(iconnum); break; case DeviceValueUOM::NONE: - case DeviceValueUOM::TEXT: default: break; } From d4b06cf0c0500ec7be5ec3c5e6f943a1b683fb65 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 21 Sep 2021 18:04:25 +0200 Subject: [PATCH 16/21] formatting --- src/locale_EN.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/locale_EN.h b/src/locale_EN.h index 425e6563e..a85fd6ec3 100644 --- a/src/locale_EN.h +++ b/src/locale_EN.h @@ -301,9 +301,9 @@ MAKE_PSTR_WORD(design) MAKE_PSTR_WORD(tempauto) MAKE_PSTR_WORD(minflow) MAKE_PSTR_WORD(maxflow) - MAKE_PSTR_WORD(rc3x) MAKE_PSTR_WORD(rc20) + MAKE_PSTR(internal_temperature, "internal temperature") MAKE_PSTR(internal_setpoint, "internal setpoint") MAKE_PSTR(external_temperature, "external temperature") @@ -365,12 +365,11 @@ MAKE_PSTR_LIST(enum_collectortype, F("flat"), F("vacuum")) // MQTT topics and full text for values and commands MAKE_PSTR(homeassistant, "homeassistant/") -// id used to store the device ID, goes into MQTT payload -// empty full name to prevent being shown in web or console +// id used to store the device ID. empty full name so only gets displayed in the MQTT payload MAKE_PSTR_LIST(ID, F_(id)) // Boiler -// extra commands, no output +// extra commands, with no json output MAKE_PSTR_LIST(wwtapactivated, F("wwtapactivated"), F("turn on/off DHW by going into maintenance mode")) MAKE_PSTR_LIST(reset, F("reset"), F("reset messages")) @@ -523,14 +522,13 @@ MAKE_PSTR_LIST(wwMaxTemp, F("wwmaxtemp"), F("maximum temperature")) MAKE_PSTR_LIST(wwOneTimeKey, F("wwonetimekey"), F("one time key function")) // thermostat -// extra commands -MAKE_PSTR_LIST(switchtime, F("switchtime"), F("single program switchtime")) -// extra commands, with no long name so they don't show up in WebUI +// commands, with no long name so they only appear in the MQTT payloads MAKE_PSTR_LIST(temp, F("temp")) MAKE_PSTR_LIST(hatemp, F("hatemp")) MAKE_PSTR_LIST(hamode, F("hamode")) // mqtt values / commands +MAKE_PSTR_LIST(switchtime, F("switchtime"), F("single program switchtime")) MAKE_PSTR_LIST(dateTime, F("datetime"), F("date/time")) MAKE_PSTR_LIST(errorCode, F("errorcode"), F("error code")) MAKE_PSTR_LIST(ibaMainDisplay, F("display"), F("display")) From f836209249e5c9237bcd2f652c9e72921d892722 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 21 Sep 2021 18:04:48 +0200 Subject: [PATCH 17/21] added output target when rendering json --- src/emsesp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emsesp.h b/src/emsesp.h index 37e1b6150..b64a6eb01 100644 --- a/src/emsesp.h +++ b/src/emsesp.h @@ -249,7 +249,7 @@ class EMSESP { 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, const int8_t id, bool verbose = true); + static bool command_info(uint8_t device_type, JsonObject & json, const int8_t id, const uint8_t output_target); static bool command_commands(uint8_t device_type, JsonObject & json, const int8_t id); static bool command_entities(uint8_t device_type, JsonObject & json, const int8_t id); From 3086342d2bb6cbee93240140d4902acbe2a686ef Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 21 Sep 2021 18:05:36 +0200 Subject: [PATCH 18/21] fix bug in nested json and added output targets --- src/emsesp.cpp | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 5f3171ba1..759c3cdfd 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -299,7 +299,7 @@ void EMSESP::show_ems(uuid::console::Shell & shell) { } // show EMS device values to the shell console -// generate_values_json is called in verbose mode (set to true) +// generate_values_json is called in verbose mode void EMSESP::show_device_values(uuid::console::Shell & shell) { if (emsdevices.empty()) { shell.printfln(F("No EMS devices detected. Try using 'scan devices' from the ems menu.")); @@ -316,7 +316,7 @@ void EMSESP::show_device_values(uuid::console::Shell & shell) { DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE_DYN); // use max size JsonObject json = doc.to(); - emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true, true); // console mode and nested + emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::API_VERBOSE); // verbose mode and nested // print line uint8_t id = 0; @@ -451,7 +451,7 @@ void EMSESP::publish_device_values(uint8_t device_type) { JsonObject json = doc.to(); bool need_publish = false; - uint8_t nested = Mqtt::nested_format(); + bool nested = (Mqtt::nested_format() == 1); // 1 is nested, 2 is single // group by device type for (const auto & emsdevice : emsdevices) { @@ -461,13 +461,13 @@ void EMSESP::publish_device_values(uint8_t device_type) { emsdevice->publish_mqtt_ha_sensor(); // create the configs for each value as a sensor } - // if its a boiler, generate json for each group and publish it directly + // if its a boiler, generate json for each group and publish it directly. not nested if (device_type == DeviceType::BOILER) { - if (emsdevice->generate_values_json(json, DeviceValueTAG::TAG_BOILER_DATA, false)) { + if (emsdevice->generate_values_json(json, DeviceValueTAG::TAG_BOILER_DATA, false, EMSdevice::OUTPUT_TARGET::MQTT)) { Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_BOILER_DATA), json); } doc.clear(); - if (emsdevice->generate_values_json(json, DeviceValueTAG::TAG_BOILER_DATA_WW, false)) { + if (emsdevice->generate_values_json(json, DeviceValueTAG::TAG_BOILER_DATA_WW, false, EMSdevice::OUTPUT_TARGET::MQTT)) { Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_BOILER_DATA_WW), json); } need_publish = false; @@ -478,15 +478,15 @@ void EMSESP::publish_device_values(uint8_t device_type) { // only publish the single master thermostat if (emsdevice->device_id() == EMSESP::actual_master_thermostat()) { if (nested) { - need_publish |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true); // nested + need_publish |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::MQTT); // nested } else { - if (emsdevice->generate_values_json(json, DeviceValueTAG::TAG_THERMOSTAT_DATA, false)) { // not nested + if (emsdevice->generate_values_json(json, DeviceValueTAG::TAG_THERMOSTAT_DATA, false, EMSdevice::OUTPUT_TARGET::MQTT)) { // not nested Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_NONE), json); } doc.clear(); for (uint8_t hc_tag = TAG_HC1; hc_tag <= DeviceValueTAG::TAG_HC4; hc_tag++) { - if (emsdevice->generate_values_json(json, hc_tag, false)) { // not nested + if (emsdevice->generate_values_json(json, hc_tag, false, EMSdevice::OUTPUT_TARGET::MQTT)) { // not nested Mqtt::publish(Mqtt::tag_to_topic(device_type, hc_tag), json); } doc.clear(); @@ -499,10 +499,10 @@ void EMSESP::publish_device_values(uint8_t device_type) { // Mixer else if (device_type == DeviceType::MIXER) { if (nested) { - need_publish |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true); // nested + need_publish |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::MQTT); // nested } else { for (uint8_t hc_tag = TAG_HC1; hc_tag <= DeviceValueTAG::TAG_WWC4; hc_tag++) { - if (emsdevice->generate_values_json(json, hc_tag, false)) { // not nested + if (emsdevice->generate_values_json(json, hc_tag, false, EMSdevice::OUTPUT_TARGET::MQTT)) { // not nested Mqtt::publish(Mqtt::tag_to_topic(device_type, hc_tag), json); } doc.clear(); @@ -512,7 +512,7 @@ void EMSESP::publish_device_values(uint8_t device_type) { } else { // for all other devices add the values to the json - need_publish |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true); // nested + need_publish |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::MQTT); // nested } } } @@ -992,12 +992,14 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, std:: Command::add_json( device_type, F_(info), - [device_type](const char * value, const int8_t id, JsonObject & json) { return command_info(device_type, json, id, true); }, + [device_type](const char * value, const int8_t id, JsonObject & json) { + return command_info(device_type, json, id, EMSdevice::OUTPUT_TARGET::API_VERBOSE); + }, F_(info_cmd)); Command::add_json( device_type, F("info_short"), - [device_type](const char * value, const int8_t id, JsonObject & json) { return command_info(device_type, json, id, false); }, + [device_type](const char * value, const int8_t id, JsonObject & json) { return command_info(device_type, json, id, EMSdevice::OUTPUT_TARGET::API); }, nullptr, CommandFlag::HIDDEN); // this command is hidden Command::add_json( @@ -1036,7 +1038,7 @@ bool EMSESP::command_commands(uint8_t device_type, JsonObject & json, const int8 // export all values to info command // value is ignored here // info command always shows in verbose mode, so full names are displayed -bool EMSESP::command_info(uint8_t device_type, JsonObject & json, const int8_t id, bool verbose) { +bool EMSESP::command_info(uint8_t device_type, JsonObject & json, const int8_t id, const uint8_t output_target) { bool has_value = false; uint8_t tag; if (id >= 1 && id <= 4) { @@ -1049,10 +1051,13 @@ bool EMSESP::command_info(uint8_t device_type, JsonObject & json, const int8_t i return false; } + // if id=-1 it means we have no endpoint so default to API + uint8_t target = (id == -1) ? EMSdevice::OUTPUT_TARGET::API_VERBOSE : EMSdevice::OUTPUT_TARGET::API; + for (const auto & emsdevice : emsdevices) { if (emsdevice && (emsdevice->device_type() == device_type) && ((device_type != DeviceType::THERMOSTAT) || (emsdevice->device_id() == EMSESP::actual_master_thermostat()))) { - has_value |= emsdevice->generate_values_json(json, tag, (id < 1), verbose && (id == -1)); // nested for id -1,0 & console for id -1 + has_value |= emsdevice->generate_values_json(json, tag, (id < 1), target); // nested for id -1 and 0 } } From c3874d7c95913b7926bbb6062cfa507151bef431 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 21 Sep 2021 18:06:25 +0200 Subject: [PATCH 19/21] remove DeviceValueUOM::TEXT --- src/emsdevice.cpp | 39 +++++++++++++++++++++------------------ src/emsdevice.h | 27 +++++++++++++++++---------- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 5cf77a670..56ae8923e 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -125,7 +125,7 @@ const std::string EMSdevice::tag_to_mqtt(uint8_t tag) { } const std::string EMSdevice::uom_to_string(uint8_t uom) { - if ((uom == DeviceValueUOM::NONE) || (uom == DeviceValueUOM::TEXT)) { + if (uom == DeviceValueUOM::NONE) { return std::string{}; } return uuid::read_flash_string(DeviceValueUOM_s[uom - 1]); // offset by 1 to account for NONE @@ -370,7 +370,7 @@ bool EMSdevice::is_fetch(uint16_t telegram_id) { // list of registered device entries, adding the HA entity if it exists void EMSdevice::list_device_entries(JsonObject & json) { for (const auto & dv : devicevalues_) { - if (dv.full_name && dv.type != DeviceValueType::CMD) { + if (dv_is_visible(dv) && dv.type != DeviceValueType::CMD) { // if we have a tag prefix it char key[50]; if (!EMSdevice::tag_to_string(dv.tag).empty()) { @@ -574,10 +574,10 @@ const std::string EMSdevice::get_value_uom(const char * key) { // find the key (p) in the name for (const auto & dv : devicevalues_) { - if (dv.full_name != nullptr) { + if (dv_is_visible(dv)) { if (uuid::read_flash_string(dv.full_name) == p) { // ignore TIME since "minutes" is already added to the string value - if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::TEXT) || (dv.uom == DeviceValueUOM::MINUTES)) { + if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) { break; } return EMSdevice::uom_to_string(dv.uom); @@ -596,7 +596,7 @@ void EMSdevice::generate_values_json_web(JsonObject & json) { for (const auto & dv : devicevalues_) { // ignore if full_name empty and also commands - if ((dv.full_name != nullptr) && (dv.type != DeviceValueType::CMD)) { + if (dv_is_visible(dv) && dv.type != DeviceValueType::CMD) { JsonObject obj; // create the object, if needed // handle Booleans (true, false) @@ -739,7 +739,7 @@ bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t json["name"] = dv.short_name; // prefix tag if it's included - if (dv.full_name != nullptr) { + if (dv_is_visible(dv)) { if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) { json["fullname"] = dv.full_name; } else { @@ -898,25 +898,29 @@ bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t // For each value in the device create the json object pair and add it to given json // return false if empty -// this is used to create both the MQTT payloads and Console messages (console = true) -bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter, const bool nested, const bool console) { +// this is used to create both the MQTT payloads, Console messages and Web API calls +bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter, const bool nested, const uint8_t output_target) { bool has_values = false; // to see if we've added a value. it's faster than doing a json.size() at the end uint8_t old_tag = 255; // NAN JsonObject json = root; for (auto & dv : devicevalues_) { + // conditions + bool condition; + condition = (tag_filter == DeviceValueTAG::TAG_NONE) || (tag_filter == dv.tag); // tag must be either empty or match a tag passed to this function + + if (output_target != OUTPUT_TARGET::MQTT) { + condition &= dv_is_visible(dv); // value must be visible if outputting to API (web or console). This is for ID, hamode, hatemp etc + } + bool has_value = false; - // only show if tag is either empty (TAG_NONE) or matches a value - // and don't show if full_name is empty unless we're outputing for mqtt payloads - // and ignore anything that has an UOM of "NONE" as these are hidden values (e.g. id and hamode) - // for nested we use all values, dont show command only (have_cmd and no fullname) - if (((nested) || tag_filter == DeviceValueTAG::TAG_NONE || (tag_filter == dv.tag)) && (dv.full_name != nullptr || !console) - && !(dv.full_name == nullptr && dv.has_cmd) && (dv.uom != DeviceValueUOM::NONE)) { + + if (condition) { // we have a tag if it matches the filter given, and that the tag name is not empty/"" bool have_tag = ((dv.tag != tag_filter) && !tag_to_string(dv.tag).empty()); char name[80]; - if (console) { + if (output_target == OUTPUT_TARGET::API_VERBOSE) { // prefix the tag in brackets, unless it's Boiler because we're naughty and use tag for the MQTT topic if (have_tag) { snprintf(name, 80, "%s %s", tag_to_string(dv.tag).c_str(), uuid::read_flash_string(dv.full_name).c_str()); @@ -938,9 +942,8 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter // handle Booleans (true, false) if ((dv.type == DeviceValueType::BOOL) && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) { // see how to render the value depending on the setting - // when in console mode we always use on and off uint8_t bool_format = EMSESP::bool_format(); - if ((bool_format == BOOL_FORMAT_ONOFF) || console) { + if (bool_format == BOOL_FORMAT_ONOFF) { json[name] = *(uint8_t *)(dv.value_p) ? F_(on) : F_(off); } else if (bool_format == BOOL_FORMAT_ONOFF_CAP) { json[name] = *(uint8_t *)(dv.value_p) ? F_(ON) : F_(OFF); @@ -1026,7 +1029,7 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter } else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { uint32_t time_value = *(uint32_t *)(dv.value_p); time_value = (divider) ? time_value / divider : time_value * factor; // sometimes we need to divide by 60 - if (console) { + if (output_target == EMSdevice::OUTPUT_TARGET::API_VERBOSE) { char time_s[40]; snprintf(time_s, sizeof(time_s), "%d days %d hours %d minutes", (time_value / 1440), ((time_value % 1440) / 60), (time_value % 60)); json[name] = time_s; diff --git a/src/emsdevice.h b/src/emsdevice.h index b13b52d1f..2be6b7d18 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -66,8 +66,7 @@ enum DeviceValueUOM : uint8_t { DBM, // 14 NUM, // 15 BOOLEAN, // 16 - LIST, // 17 - TEXT // 18 + LIST // 17 }; @@ -149,10 +148,6 @@ class EMSdevice { , brand_(brand) { } - inline uint8_t device_id() const { - return device_id_; - } - const std::string device_type_name() const; static const std::string device_type_2_device_name(const uint8_t device_type); static uint8_t device_name_2_device_type(const char * topic); @@ -161,6 +156,10 @@ class EMSdevice { static const std::string tag_to_string(uint8_t tag); static const std::string tag_to_mqtt(uint8_t tag); + inline uint8_t device_id() const { + return device_id_; + } + inline uint8_t product_id() const { return product_id_; } @@ -187,9 +186,8 @@ class EMSdevice { return flags_; } - // see enum DeviceType below inline uint8_t device_type() const { - return device_type_; + return device_type_; // see enum DeviceType below } inline void version(std::string & version) { @@ -250,8 +248,11 @@ class EMSdevice { const std::string get_value_uom(const char * key); bool get_value_info(JsonObject & root, const char * cmd, const int8_t id); - bool generate_values_json(JsonObject & json, const uint8_t tag_filter, const bool nested, const bool console = false); - void generate_values_json_web(JsonObject & json); + + enum OUTPUT_TARGET : uint8_t { API_VERBOSE, API, MQTT }; + bool generate_values_json(JsonObject & json, const uint8_t tag_filter, const bool nested, const uint8_t output_target); + + void generate_values_json_web(JsonObject & json); void register_device_value(uint8_t tag, void * value_p, @@ -418,6 +419,8 @@ class EMSdevice { } }; + + // DeviceValue holds all the attributes for a device value (also a device parameter) struct DeviceValue { uint8_t device_type; // EMSdevice::DeviceType uint8_t tag; // DeviceValueTAG::* @@ -471,6 +474,10 @@ class EMSdevice { void init_devicevalues(uint8_t size) { devicevalues_.reserve(size); } + + inline bool dv_is_visible(DeviceValue dv) { + return (dv.full_name); + } }; } // namespace emsesp From eba6324d18b567b594504b72fae602b457171b29 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 21 Sep 2021 18:06:36 +0200 Subject: [PATCH 20/21] more API tests --- src/test/test.cpp | 26 +++++++++++++++++--------- src/test/test.h | 4 ++-- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/test/test.cpp b/src/test/test.cpp index 00114c4c0..876efec0e 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -482,8 +482,9 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) { // first with nested Mqtt::nested_format(1); shell.invoke_command("call system publish"); + shell.invoke_command("show mqtt"); - // then without nested + // then without nested - single mode Mqtt::nested_format(2); shell.invoke_command("call system publish"); shell.invoke_command("show mqtt"); @@ -829,6 +830,9 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) { if (command == "mqtt") { shell.printfln(F("Testing MQTT...")); + Mqtt::ha_enabled(false); + Mqtt::enabled(true); + // add a boiler add_device(0x08, 123); // Nefit Trendline @@ -841,6 +845,8 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) { uart_telegram("98 00 FF 00 01 A5 00 CF 21 2E 00 00 2E 24 03 25 03 03 01 03 25 00 C8 00 00 11 01 03"); // without CRC uart_telegram_withCRC("98 00 FF 00 01 A5 00 CF 21 2E 00 00 2E 24 03 25 03 03 01 03 25 00 C8 00 00 11 01 03 13"); // with CRC + shell.invoke_command("call system publish"); + shell.invoke_command("show mqtt"); shell.loop_all(); char boiler_topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; @@ -853,11 +859,11 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) { strcpy(thermostat_topic, "ems-esp/thermostat"); strcpy(system_topic, "ems-esp/system"); - EMSESP::mqtt_.incoming(boiler_topic, ""); // test if ignore empty payloads // invalid format + EMSESP::mqtt_.incoming(boiler_topic, ""); // test if ignore empty payloads - EMSESP::mqtt_.incoming(boiler_topic, "12345"); // invalid format - EMSESP::mqtt_.incoming("bad_topic", "12345"); // no matching topic - EMSESP::mqtt_.incoming(boiler_topic, "{\"cmd\":\"garbage\",\"data\":22.52}"); // should report error + EMSESP::mqtt_.incoming(boiler_topic, "12345"); // error: invalid format + EMSESP::mqtt_.incoming("bad_topic", "12345"); // error: no matching topic + EMSESP::mqtt_.incoming(boiler_topic, "{\"cmd\":\"garbage\",\"data\":22.52}"); // error: should report error EMSESP::mqtt_.incoming(boiler_topic, "{\"cmd\":\"comfort\",\"data\":\"eco\"}"); EMSESP::mqtt_.incoming(boiler_topic, "{\"cmd\":\"wwactivated\",\"data\":\"1\"}"); // with quotes @@ -953,16 +959,18 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) { run_test("general"); AsyncWebServerRequest request; - request.url("/api/boiler/id"); - EMSESP::webAPIService.webAPIService_get(&request); - + // GET request.url("/api/thermostat"); EMSESP::webAPIService.webAPIService_get(&request); + request.url("/api/thermostat/info"); + EMSESP::webAPIService.webAPIService_get(&request); + // these next 2 should fail + request.url("/api/boiler/id"); + EMSESP::webAPIService.webAPIService_get(&request); request.url("/api/thermostat/hamode"); EMSESP::webAPIService.webAPIService_get(&request); - // GET request.method(HTTP_GET); request.url("/api/thermostat/seltemp"); EMSESP::webAPIService.webAPIService_get(&request); diff --git a/src/test/test.h b/src/test/test.h index d9ca69ca7..120e3060f 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -33,13 +33,13 @@ namespace emsesp { // #define EMSESP_DEBUG_DEFAULT "general" // #define EMSESP_DEBUG_DEFAULT "boiler" // #define EMSESP_DEBUG_DEFAULT "mqtt2" -// #define EMSESP_DEBUG_DEFAULT "mqtt_nested" +#define EMSESP_DEBUG_DEFAULT "mqtt_nested" // #define EMSESP_DEBUG_DEFAULT "ha" // #define EMSESP_DEBUG_DEFAULT "board_profile" // #define EMSESP_DEBUG_DEFAULT "shower_alert" // #define EMSESP_DEBUG_DEFAULT "310" // #define EMSESP_DEBUG_DEFAULT "render" -#define EMSESP_DEBUG_DEFAULT "api" +// #define EMSESP_DEBUG_DEFAULT "api" // #define EMSESP_DEBUG_DEFAULT "crash" class Test { From 29f2335935c664c5c6cd292ba63e2912013ce506 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 21 Sep 2021 18:06:55 +0200 Subject: [PATCH 21/21] remove DeviceValueUOM::TEXT --- src/devices/boiler.cpp | 13 +++++++------ src/devices/solar.cpp | 2 +- src/devices/thermostat.cpp | 22 ++++++++++++---------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index e2e00ffa8..5aa803a49 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -142,10 +142,10 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value(TAG_BOILER_DATA, &burnWorkMin_, DeviceValueType::TIME, nullptr, FL_(burnWorkMin), DeviceValueUOM::MINUTES); register_device_value(TAG_BOILER_DATA, &heatWorkMin_, DeviceValueType::TIME, nullptr, FL_(heatWorkMin), DeviceValueUOM::MINUTES); register_device_value(TAG_BOILER_DATA, &UBAuptime_, DeviceValueType::TIME, nullptr, FL_(UBAuptime), DeviceValueUOM::MINUTES); - register_device_value(TAG_BOILER_DATA, &lastCode_, DeviceValueType::STRING, nullptr, FL_(lastCode), DeviceValueUOM::TEXT); - register_device_value(TAG_BOILER_DATA, &serviceCode_, DeviceValueType::STRING, nullptr, FL_(serviceCode), DeviceValueUOM::TEXT); + register_device_value(TAG_BOILER_DATA, &lastCode_, DeviceValueType::STRING, nullptr, FL_(lastCode), DeviceValueUOM::NONE); + register_device_value(TAG_BOILER_DATA, &serviceCode_, DeviceValueType::STRING, nullptr, FL_(serviceCode), DeviceValueUOM::NONE); register_device_value(TAG_BOILER_DATA, &serviceCodeNumber_, DeviceValueType::USHORT, nullptr, FL_(serviceCodeNumber), DeviceValueUOM::NUM); - register_device_value(TAG_BOILER_DATA, &maintenanceMessage_, DeviceValueType::STRING, nullptr, FL_(maintenanceMessage), DeviceValueUOM::TEXT); + register_device_value(TAG_BOILER_DATA, &maintenanceMessage_, DeviceValueType::STRING, nullptr, FL_(maintenanceMessage), DeviceValueUOM::NONE); register_device_value(TAG_BOILER_DATA, &maintenanceType_, DeviceValueType::ENUM, @@ -156,7 +156,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value( TAG_BOILER_DATA, &maintenanceTime_, DeviceValueType::USHORT, nullptr, FL_(maintenanceTime), DeviceValueUOM::HOURS, MAKE_CF_CB(set_maintenancetime)); register_device_value( - TAG_BOILER_DATA, &maintenanceDate_, DeviceValueType::STRING, nullptr, FL_(maintenanceDate), DeviceValueUOM::TEXT, MAKE_CF_CB(set_maintenancedate)); + TAG_BOILER_DATA, &maintenanceDate_, DeviceValueType::STRING, nullptr, FL_(maintenanceDate), DeviceValueUOM::NONE, MAKE_CF_CB(set_maintenancedate)); // heatpump info if (model() == EMS_DEVICE_FLAG_HEATPUMP) { register_device_value(TAG_BOILER_DATA, &upTimeControl_, DeviceValueType::TIME, FL_(div60), FL_(upTimeControl), DeviceValueUOM::MINUTES); @@ -226,7 +226,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const FL_(wwSelTempSingle), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_warmwater_temp_single)); - register_device_value(TAG_BOILER_DATA_WW, &wwType_, DeviceValueType::ENUM, FL_(enum_flow), FL_(wwType), DeviceValueUOM::TEXT); + register_device_value(TAG_BOILER_DATA_WW, &wwType_, DeviceValueType::ENUM, FL_(enum_flow), FL_(wwType), DeviceValueUOM::NONE); register_device_value( TAG_BOILER_DATA_WW, &wwComfort_, DeviceValueType::ENUM, FL_(enum_comfort), FL_(wwComfort), DeviceValueUOM::LIST, MAKE_CF_CB(set_warmwater_mode)); register_device_value( @@ -261,7 +261,8 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value( TAG_BOILER_DATA_WW, &wwActivated_, DeviceValueType::BOOL, nullptr, FL_(wwActivated), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_activated)); register_device_value(TAG_BOILER_DATA_WW, &wwOneTime_, DeviceValueType::BOOL, nullptr, FL_(wwOneTime), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_onetime)); - register_device_value(TAG_BOILER_DATA_WW, &wwDisinfect_, DeviceValueType::BOOL, nullptr, FL_(wwDisinfect), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_disinfect)); + register_device_value( + TAG_BOILER_DATA_WW, &wwDisinfect_, DeviceValueType::BOOL, nullptr, FL_(wwDisinfect), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_disinfect)); register_device_value(TAG_BOILER_DATA_WW, &wwCharging_, DeviceValueType::BOOL, nullptr, FL_(wwCharging), DeviceValueUOM::BOOLEAN); register_device_value(TAG_BOILER_DATA_WW, &wwRecharging_, DeviceValueType::BOOL, nullptr, FL_(wwRecharging), DeviceValueUOM::BOOLEAN); register_device_value(TAG_BOILER_DATA_WW, &wwTempOK_, DeviceValueType::BOOL, nullptr, FL_(wwTempOK), DeviceValueUOM::BOOLEAN); diff --git a/src/devices/solar.cpp b/src/devices/solar.cpp index 6ab6dcec5..235594a5d 100644 --- a/src/devices/solar.cpp +++ b/src/devices/solar.cpp @@ -64,7 +64,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s // special case for a device_id with 0x2A where it's not actual a solar module if (device_id == 0x2A) { - register_device_value(TAG_NONE, &type_, DeviceValueType::STRING, nullptr, FL_(type), DeviceValueUOM::TEXT); + register_device_value(TAG_NONE, &type_, DeviceValueType::STRING, nullptr, FL_(type), DeviceValueUOM::NONE); strlcpy(type_, "warm water circuit", sizeof(type_)); register_device_value(TAG_NONE, &wwTemp_1_, DeviceValueType::UINT, nullptr, FL_(wwTemp1), DeviceValueUOM::DEGREES); register_device_value(TAG_NONE, &wwTemp_3_, DeviceValueType::UINT, nullptr, FL_(wwTemp3), DeviceValueUOM::DEGREES); diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index ffb866353..9ae163168 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -2389,13 +2389,13 @@ bool Thermostat::set_roominfluence(const char * value, const int8_t id) { void Thermostat::register_device_values() { // Common for all thermostats register_device_value(TAG_THERMOSTAT_DATA, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE); - register_device_value(TAG_THERMOSTAT_DATA, &errorCode_, DeviceValueType::STRING, nullptr, FL_(errorCode), DeviceValueUOM::TEXT); - register_device_value(TAG_THERMOSTAT_DATA, &lastCode_, DeviceValueType::STRING, nullptr, FL_(lastCode), DeviceValueUOM::TEXT); + register_device_value(TAG_THERMOSTAT_DATA, &errorCode_, DeviceValueType::STRING, nullptr, FL_(errorCode), DeviceValueUOM::NONE); + register_device_value(TAG_THERMOSTAT_DATA, &lastCode_, DeviceValueType::STRING, nullptr, FL_(lastCode), DeviceValueUOM::NONE); switch (this->model()) { case EMS_DEVICE_FLAG_RC100: case EMS_DEVICE_FLAG_RC300: - register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::TEXT, MAKE_CF_CB(set_datetime)); + register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime)); register_device_value(TAG_THERMOSTAT_DATA, &floordrystatus_, DeviceValueType::ENUM, FL_(enum_floordrystatus), FL_(floordrystatus), DeviceValueUOM::LIST); register_device_value(TAG_THERMOSTAT_DATA, &dampedoutdoortemp2_, DeviceValueType::SHORT, FL_(div10), FL_(dampedoutdoortemp), DeviceValueUOM::DEGREES); register_device_value(TAG_THERMOSTAT_DATA, &floordrytemp_, DeviceValueType::UINT, nullptr, FL_(floordrytemp), DeviceValueUOM::DEGREES); @@ -2432,10 +2432,10 @@ void Thermostat::register_device_values() { break; case EMS_DEVICE_FLAG_RC20_N: case EMS_DEVICE_FLAG_RC20: - register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::TEXT); // can't set datetime + register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime break; case EMS_DEVICE_FLAG_RC30_N: - register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::TEXT); // can't set datetime + register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime register_device_value(TAG_THERMOSTAT_DATA, &ibaMainDisplay_, DeviceValueType::ENUM, FL_(enum_ibaMainDisplay), FL_(ibaMainDisplay), DeviceValueUOM::LIST); register_device_value(TAG_THERMOSTAT_DATA, &ibaLanguage_, DeviceValueType::ENUM, FL_(enum_ibaLanguage), FL_(ibaLanguage), DeviceValueUOM::LIST); register_device_value(TAG_THERMOSTAT_DATA, @@ -2471,7 +2471,7 @@ void Thermostat::register_device_values() { TAG_THERMOSTAT_DATA, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode2), FL_(wwCircMode), DeviceValueUOM::LIST, MAKE_CF_CB(set_wwcircmode)); break; case EMS_DEVICE_FLAG_RC35: - register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::TEXT, MAKE_CF_CB(set_datetime)); + register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime)); register_device_value(TAG_THERMOSTAT_DATA, &ibaCalIntTemperature_, DeviceValueType::INT, @@ -2527,14 +2527,14 @@ void Thermostat::register_device_values() { TAG_THERMOSTAT_DATA, &wwOneTimeKey_, DeviceValueType::BOOL, nullptr, FL_(wwOneTimeKey), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_wwOneTimeKey)); break; case EMS_DEVICE_FLAG_JUNKERS: - register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::TEXT, MAKE_CF_CB(set_datetime)); + register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime)); break; case EMS_DEVICE_FLAG_EASY: // Easy TC100 have no date/time, see issue #100, not sure about CT200, so leave it. - register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::TEXT); // can't set datetime + register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime break; default: - register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::TEXT); // can't set datetime + register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime break; } } @@ -2572,6 +2572,8 @@ void Thermostat::register_device_values_hc(std::shared_ptrsetpoint_roomTemp, DeviceValueType::SHORT, setpoint_temp_divider, FL_(temp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_temp), 5, 29); } @@ -2625,7 +2627,7 @@ void Thermostat::register_device_values_hc(std::shared_ptrprogram, DeviceValueType::UINT, nullptr, FL_(program), DeviceValueUOM::NUM, MAKE_CF_CB(set_program)); register_device_value(tag, &hc->tempautotemp, DeviceValueType::UINT, FL_(div2), FL_(tempautotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_tempautotemp)); register_device_value( - tag, &hc->fastHeatupFactor, DeviceValueType::UINT, nullptr, FL_(fastheatupfactor), DeviceValueUOM::NUM, MAKE_CF_CB(set_fastheatupfactor)); + tag, &hc->fastHeatupFactor, DeviceValueType::UINT, nullptr, FL_(fastheatupfactor), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_fastheatupfactor)); break; case EMS_DEVICE_FLAG_CRF: register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode5), FL_(mode), DeviceValueUOM::LIST);