From fda18cdb130ddda4d1427f6df4d09ed34d87ab67 Mon Sep 17 00:00:00 2001 From: Yurii Date: Mon, 11 Nov 2024 02:41:39 +0300 Subject: [PATCH] refactor: memory optimization for esp8266 --- lib/BufferedWebServer/BufferedWebServer.h | 3 +- lib/HomeAssistantHelper/HomeAssistantHelper.h | 2 +- lib/HomeAssistantHelper/strings.h | 2 + lib/WebServerHandlers/DynamicPage.h | 2 +- lib/WebServerHandlers/StaticPage.h | 9 +- lib/WebServerHandlers/UpgradeHandler.h | 6 +- platformio.ini | 4 +- src/HaHelper.h | 381 ++++----- src/MainTask.h | 10 +- src/MqttTask.h | 40 +- src/OpenThermTask.h | 4 +- src/PortalTask.h | 364 +++++---- src/SensorsTask.h | 12 +- src/Settings.h | 2 +- src/main.cpp | 3 + src/strings.h | 217 ++++- src/utils.h | 771 +++++++++--------- 17 files changed, 1044 insertions(+), 788 deletions(-) diff --git a/lib/BufferedWebServer/BufferedWebServer.h b/lib/BufferedWebServer/BufferedWebServer.h index 1ba3881..a991556 100644 --- a/lib/BufferedWebServer/BufferedWebServer.h +++ b/lib/BufferedWebServer/BufferedWebServer.h @@ -10,7 +10,8 @@ public: free(this->buffer); } - void send(int code, const char* contentType, const JsonVariantConst content, bool pretty = false) { + template + void send(int code, T contentType, const JsonVariantConst content, bool pretty = false) { #ifdef ARDUINO_ARCH_ESP8266 if (!this->webServer->chunkedResponseModeStart(code, contentType)) { this->webServer->send(505, F("text/html"), F("HTTP1.1 required")); diff --git a/lib/HomeAssistantHelper/HomeAssistantHelper.h b/lib/HomeAssistantHelper/HomeAssistantHelper.h index b18fe6d..c7417c8 100644 --- a/lib/HomeAssistantHelper/HomeAssistantHelper.h +++ b/lib/HomeAssistantHelper/HomeAssistantHelper.h @@ -110,7 +110,7 @@ public: topic.concat(this->devicePrefix); topic.concat(nameSeparator); topic.concat(name); - topic.concat("/config"); + topic.concat(F("/config")); return topic; } diff --git a/lib/HomeAssistantHelper/strings.h b/lib/HomeAssistantHelper/strings.h index e98237d..8ac68da 100644 --- a/lib/HomeAssistantHelper/strings.h +++ b/lib/HomeAssistantHelper/strings.h @@ -37,11 +37,13 @@ const char HA_DEVICE_CLASS[] PROGMEM = "device_class"; const char HA_UNIT_OF_MEASUREMENT[] PROGMEM = "unit_of_measurement"; const char HA_UNIT_OF_MEASUREMENT_C[] PROGMEM = "°C"; const char HA_UNIT_OF_MEASUREMENT_F[] PROGMEM = "°F"; +const char HA_UNIT_OF_MEASUREMENT_PERCENT[] PROGMEM = "%"; const char HA_ICON[] PROGMEM = "icon"; const char HA_MIN[] PROGMEM = "min"; const char HA_MAX[] PROGMEM = "max"; const char HA_STEP[] PROGMEM = "step"; const char HA_MODE[] PROGMEM = "mode"; +const char HA_MODE_BOX[] PROGMEM = "box"; const char HA_STATE_ON[] PROGMEM = "state_on"; const char HA_STATE_OFF[] PROGMEM = "state_off"; const char HA_PAYLOAD_ON[] PROGMEM = "payload_on"; diff --git a/lib/WebServerHandlers/DynamicPage.h b/lib/WebServerHandlers/DynamicPage.h index 4ad7182..8553a0d 100644 --- a/lib/WebServerHandlers/DynamicPage.h +++ b/lib/WebServerHandlers/DynamicPage.h @@ -61,7 +61,7 @@ public: } if (this->cacheHeader != nullptr) { - server.sendHeader("Cache-Control", this->cacheHeader); + server.sendHeader(F("Cache-Control"), this->cacheHeader); } #ifdef ARDUINO_ARCH_ESP8266 diff --git a/lib/WebServerHandlers/StaticPage.h b/lib/WebServerHandlers/StaticPage.h index 095635c..8b09721 100644 --- a/lib/WebServerHandlers/StaticPage.h +++ b/lib/WebServerHandlers/StaticPage.h @@ -8,7 +8,8 @@ public: typedef std::function CanHandleCallback; typedef std::function BeforeSendCallback; - StaticPage(const char* uri, FS* fs, const char* path, const char* cacheHeader = nullptr) { + template + StaticPage(const char* uri, FS* fs, T path, const char* cacheHeader = nullptr) { this->uri = uri; this->fs = fs; this->path = path; @@ -55,7 +56,7 @@ public: this->eTag = esp8266webserver::calcETag(*this->fs, this->path); } - if (server.header("If-None-Match").equals(this->eTag.c_str())) { + if (server.header(F("If-None-Match")).equals(this->eTag.c_str())) { server.send(304); return true; } @@ -80,12 +81,12 @@ public: } if (this->cacheHeader != nullptr) { - server.sendHeader("Cache-Control", this->cacheHeader); + server.sendHeader(F("Cache-Control"), this->cacheHeader); } #if defined(ARDUINO_ARCH_ESP8266) if (server._eTagEnabled && this->eTag.length() > 0) { - server.sendHeader("ETag", this->eTag); + server.sendHeader(F("ETag"), this->eTag); } server.streamFile(file, F("text/html"), method); diff --git a/lib/WebServerHandlers/UpgradeHandler.h b/lib/WebServerHandlers/UpgradeHandler.h index 13012cf..14c7f93 100644 --- a/lib/WebServerHandlers/UpgradeHandler.h +++ b/lib/WebServerHandlers/UpgradeHandler.h @@ -93,10 +93,12 @@ public: void upload(WebServer& server, const String& uri, HTTPUpload& upload) override { UpgradeResult* result; - if (upload.name.equals("firmware")) { + if (upload.name.equals(F("firmware"))) { result = &this->firmwareResult; - } else if (upload.name.equals("filesystem")) { + + } else if (upload.name.equals(F("filesystem"))) { result = &this->filesystemResult; + } else { return; } diff --git a/platformio.ini b/platformio.ini index 835d884..9da4d56 100644 --- a/platformio.ini +++ b/platformio.ini @@ -59,7 +59,9 @@ build_flags = upload_speed = 921600 monitor_speed = 115200 ;monitor_filters = direct -monitor_filters = esp32_exception_decoder +monitor_filters = + esp32_exception_decoder + esp8266_exception_decoder board_build.flash_mode = dio board_build.filesystem = littlefs diff --git a/src/HaHelper.h b/src/HaHelper.h index 50755e6..149ebb4 100644 --- a/src/HaHelper.h +++ b/src/HaHelper.h @@ -8,6 +8,14 @@ public: static const char AVAILABILITY_OT_CONN[]; static const char AVAILABILITY_SENSOR_CONN[]; + void updateCachedTopics() { + this->statusTopic = this->getDeviceTopic(F("status")); + this->stateTopic = this->getDeviceTopic(F("state")); + this->setStateTopic = this->getDeviceTopic(F("state/set")); + this->settingsTopic = this->getDeviceTopic(F("settings")); + this->setSettingsTopic = this->getDeviceTopic(F("settings/set")); + } + void setExpireAfter(unsigned short value) { this->expireAfter = value; } @@ -60,7 +68,7 @@ public: case Sensors::Purpose::MODULATION_LEVEL: doc[FPSTR(HA_DEVICE_CLASS)] = F("power_factor"); - doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("%"); + doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_PERCENT); break; case Sensors::Purpose::CURRENT_POWER: @@ -80,7 +88,7 @@ public: case Sensors::Purpose::HUMIDITY: doc[FPSTR(HA_DEVICE_CLASS)] = F("humidity"); - doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = "%"; + doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_PERCENT); break; default: @@ -180,7 +188,7 @@ public: sName += F(" humidity"); doc[FPSTR(HA_DEVICE_CLASS)] = F("humidity"); - doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = "%"; + doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_PERCENT); doc[FPSTR(HA_NAME)] = sName; doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.humidity|float(0)|round(2) }}"); break; @@ -191,7 +199,7 @@ public: doc[FPSTR(HA_DEVICE_CLASS)] = F("battery"); doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); - doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = "%"; + doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_PERCENT); doc[FPSTR(HA_NAME)] = sName; doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.battery|float(0)|round(2) }}"); break; @@ -213,7 +221,7 @@ public: } else if (sSensor.type == Sensors::Type::MANUAL) { doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("sensors"), objId.c_str(), F("set")); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"value\": {{ value }}}"); @@ -245,7 +253,7 @@ public: ); objId.clear(); - doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all"); doc[FPSTR(HA_STATE_CLASS)] = FPSTR(HA_STATE_CLASS_MEASUREMENT); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; @@ -321,7 +329,7 @@ public: objId.clear(); - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); doc[FPSTR(HA_DEVICE_CLASS)] = F("connectivity"); @@ -371,12 +379,12 @@ public: objId.clear(); - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); doc[FPSTR(HA_DEVICE_CLASS)] = F("signal_strength"); doc[FPSTR(HA_STATE_CLASS)] = FPSTR(HA_STATE_CLASS_MEASUREMENT); - doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("%"); + doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_PERCENT); doc[FPSTR(HA_ICON)] = F("mdi:signal"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.signalQuality|float(0)|round(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; @@ -397,18 +405,18 @@ public: bool publishSwitchHeatingTurbo(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("heating_turbo")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("heating_turbo")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_NAME)] = F("Turbo heating"); doc[FPSTR(HA_ICON)] = F("mdi:rocket-launch-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_STATE_ON)] = true; doc[FPSTR(HA_STATE_OFF)] = false; doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.turbo }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"heating\": {\"turbo\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"heating\": {\"turbo\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; @@ -419,10 +427,10 @@ public: bool publishInputHeatingHysteresis(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("heating_hysteresis")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("heating_hysteresis")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); @@ -435,14 +443,14 @@ public: doc[FPSTR(HA_NAME)] = F("Heating hysteresis"); doc[FPSTR(HA_ICON)] = F("mdi:altimeter"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.hysteresis|float(0)|round(2) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"hysteresis\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0; doc[FPSTR(HA_MAX)] = 15; doc[FPSTR(HA_STEP)] = 0.01f; - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -451,22 +459,22 @@ public: bool publishInputHeatingTurboFactor(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("heating_turbo_factor")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("heating_turbo_factor")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_DEVICE_CLASS)] = F("power_factor"); doc[FPSTR(HA_NAME)] = F("Heating turbo factor"); doc[FPSTR(HA_ICON)] = F("mdi:multiplication-box"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.turboFactor|float(0)|round(2) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"turboFactor\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 1.5; doc[FPSTR(HA_MAX)] = 10; doc[FPSTR(HA_STEP)] = 0.01f; - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -475,10 +483,10 @@ public: bool publishInputHeatingMinTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("heating_min_temp")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("heating_min_temp")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); @@ -495,12 +503,12 @@ public: doc[FPSTR(HA_NAME)] = F("Heating min temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.minTemp|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"minTemp\" : {{ value }}}}"); doc[FPSTR(HA_STEP)] = 1; - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -509,10 +517,10 @@ public: bool publishInputHeatingMaxTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("heating_max_temp")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("heating_max_temp")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); @@ -529,12 +537,12 @@ public: doc[FPSTR(HA_NAME)] = F("Heating max temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.maxTemp|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"maxTemp\" : {{ value }}}}"); doc[FPSTR(HA_STEP)] = 1; - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -544,10 +552,10 @@ public: bool publishInputDhwMinTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("dhw_min_temp")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("dhw_min_temp")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); @@ -564,12 +572,12 @@ public: doc[FPSTR(HA_NAME)] = F("DHW min temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.dhw.minTemp|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"minTemp\" : {{ value }}}}"); doc[FPSTR(HA_STEP)] = 1; - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -578,10 +586,10 @@ public: bool publishInputDhwMaxTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("dhw_max_temp")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("dhw_max_temp")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); @@ -598,12 +606,12 @@ public: doc[FPSTR(HA_NAME)] = F("DHW max temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.dhw.maxTemp|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"maxTemp\" : {{ value }}}}"); doc[FPSTR(HA_STEP)] = 1; - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -613,20 +621,20 @@ public: bool publishSwitchPid(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("pid")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("pid")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_NAME)] = F("PID"); doc[FPSTR(HA_ICON)] = F("mdi:chart-bar-stacked"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_STATE_ON)] = true; doc[FPSTR(HA_STATE_OFF)] = false; doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.enabled }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); - doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"pid\": {\"enable\" : true}}"); - doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"pid\": {\"enable\" : false}}"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); + doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"pid\": {\"enabled\" : true}}"); + doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"pid\": {\"enabled\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -635,21 +643,21 @@ public: bool publishInputPidFactorP(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("pid_p")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("pid_p")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_NAME)] = F("PID factor P"); doc[FPSTR(HA_ICON)] = F("mdi:alpha-p-circle-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.p_factor|float(0)|round(3) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"p_factor\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0.1f; doc[FPSTR(HA_MAX)] = 1000; doc[FPSTR(HA_STEP)] = 0.1f; - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -658,21 +666,21 @@ public: bool publishInputPidFactorI(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("pid_i")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("pid_i")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_NAME)] = F("PID factor I"); doc[FPSTR(HA_ICON)] = F("mdi:alpha-i-circle-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.i_factor|float(0)|round(4) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"i_factor\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0; doc[FPSTR(HA_MAX)] = 100; doc[FPSTR(HA_STEP)] = 0.001f; - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -681,21 +689,21 @@ public: bool publishInputPidFactorD(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("pid_d")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("pid_d")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_NAME)] = F("PID factor D"); doc[FPSTR(HA_ICON)] = F("mdi:alpha-d-circle-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.d_factor|float(0)|round(3) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"d_factor\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0; doc[FPSTR(HA_MAX)] = 100000; doc[FPSTR(HA_STEP)] = 1; - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -704,23 +712,23 @@ public: bool publishInputPidDt(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("pid_dt")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("pid_dt")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_DEVICE_CLASS)] = F("duration"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("s"); doc[FPSTR(HA_NAME)] = F("PID DT"); doc[FPSTR(HA_ICON)] = F("mdi:timer-cog-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.dt|int(0) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"dt\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 30; doc[FPSTR(HA_MAX)] = 1800; doc[FPSTR(HA_STEP)] = 1; - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -729,10 +737,10 @@ public: bool publishInputPidMinTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("pid_min_temp")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("pid_min_temp")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); @@ -749,12 +757,12 @@ public: doc[FPSTR(HA_NAME)] = F("PID min temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.minTemp|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"minTemp\" : {{ value }}}}"); doc[FPSTR(HA_STEP)] = 1; - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -763,10 +771,10 @@ public: bool publishInputPidMaxTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("pid_max_temp")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("pid_max_temp")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); @@ -783,12 +791,12 @@ public: doc[FPSTR(HA_NAME)] = F("PID max temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.maxTemp|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"maxTemp\" : {{ value }}}}"); doc[FPSTR(HA_STEP)] = 1; - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -798,20 +806,20 @@ public: bool publishSwitchEquitherm(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("equitherm")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("equitherm")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_NAME)] = F("Equitherm"); doc[FPSTR(HA_ICON)] = F("mdi:sun-snowflake-variant"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_STATE_ON)] = true; doc[FPSTR(HA_STATE_OFF)] = false; doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.equitherm.enabled }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); - doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"equitherm\": {\"enable\" : true}}"); - doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"equitherm\": {\"enable\" : false}}"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); + doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"equitherm\": {\"enabled\" : true}}"); + doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"equitherm\": {\"enabled\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -820,21 +828,21 @@ public: bool publishInputEquithermFactorN(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("equitherm_n")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("equitherm_n")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_NAME)] = F("Equitherm factor N"); doc[FPSTR(HA_ICON)] = F("mdi:alpha-n-circle-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.equitherm.n_factor|float(0)|round(3) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"n_factor\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0.001f; doc[FPSTR(HA_MAX)] = 10; doc[FPSTR(HA_STEP)] = 0.001f; - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -843,21 +851,21 @@ public: bool publishInputEquithermFactorK(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("equitherm_k")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("equitherm_k")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_NAME)] = F("Equitherm factor K"); doc[FPSTR(HA_ICON)] = F("mdi:alpha-k-circle-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.equitherm.k_factor|float(0)|round(2) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"k_factor\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0; doc[FPSTR(HA_MAX)] = 10; doc[FPSTR(HA_STEP)] = 0.01f; - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -866,24 +874,24 @@ public: bool publishInputEquithermFactorT(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); - doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("settings")); - doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.pid.enable, 'offline', 'online') }}"); + doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); + doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->settingsTopic.c_str(); + doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.pid.enabled, 'offline', 'online') }}"); doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("equitherm_t")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("equitherm_t")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_NAME)] = F("Equitherm factor T"); doc[FPSTR(HA_ICON)] = F("mdi:alpha-t-circle-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.equitherm.t_factor|float(0)|round(2) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"t_factor\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0; doc[FPSTR(HA_MAX)] = 10; doc[FPSTR(HA_STEP)] = 0.01f; - doc[FPSTR(HA_MODE)] = "box"; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -895,12 +903,12 @@ public: JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("status")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("status")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); doc[FPSTR(HA_DEVICE_CLASS)] = F("problem"); doc[FPSTR(HA_NAME)] = F("Status"); doc[FPSTR(HA_ICON)] = F("mdi:list-status"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_STATE_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value == 'online', 'OFF', 'ON') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 60; doc.shrinkToFit(); @@ -910,15 +918,15 @@ public: bool publishEmergencyState(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("emergency")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("emergency")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); doc[FPSTR(HA_DEVICE_CLASS)] = F("problem"); doc[FPSTR(HA_NAME)] = F("Emergency"); doc[FPSTR(HA_ICON)] = F("mdi:alert-rhombus-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.master.emergency.state, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -928,15 +936,15 @@ public: bool publishOpenthermConnectedState(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("ot_status")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("ot_status")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); doc[FPSTR(HA_DEVICE_CLASS)] = F("connectivity"); doc[FPSTR(HA_NAME)] = F("Opentherm status"); doc[FPSTR(HA_ICON)] = F("mdi:list-status"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.slave.connected, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -946,18 +954,18 @@ public: bool publishHeatingState(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); - doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); + doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = AVAILABILITY_OT_CONN; doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("heating")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("heating")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; //doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); doc[FPSTR(HA_DEVICE_CLASS)] = F("running"); doc[FPSTR(HA_NAME)] = F("Heating"); doc[FPSTR(HA_ICON)] = F("mdi:radiator"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.slave.heating.active, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -967,18 +975,18 @@ public: bool publishDhwState(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); - doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); + doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = AVAILABILITY_OT_CONN; doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("dhw")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("dhw")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; //doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); doc[FPSTR(HA_DEVICE_CLASS)] = F("running"); doc[FPSTR(HA_NAME)] = F("DHW"); doc[FPSTR(HA_ICON)] = F("mdi:faucet"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.slave.dhw.active, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -988,18 +996,18 @@ public: bool publishFlameState(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); - doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); + doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = AVAILABILITY_OT_CONN; doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("flame")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("flame")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; //doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); doc[FPSTR(HA_DEVICE_CLASS)] = F("running"); doc[FPSTR(HA_NAME)] = F("Flame"); doc[FPSTR(HA_ICON)] = F("mdi:gas-burner"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.slave.flame, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -1009,18 +1017,18 @@ public: bool publishFaultState(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); - doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); + doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = AVAILABILITY_OT_CONN; doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("fault")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("fault")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); doc[FPSTR(HA_DEVICE_CLASS)] = F("problem"); doc[FPSTR(HA_NAME)] = F("Fault"); doc[FPSTR(HA_ICON)] = F("mdi:alert-remove-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.slave.fault.active, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -1030,18 +1038,18 @@ public: bool publishDiagState(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); - doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); + doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = AVAILABILITY_OT_CONN; doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC)); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC)); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); doc[FPSTR(HA_DEVICE_CLASS)] = F("problem"); doc[FPSTR(HA_NAME)] = F("Diagnostic"); doc[FPSTR(HA_ICON)] = F("mdi:account-wrench"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.slave.diag.active, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -1051,15 +1059,15 @@ public: bool publishExternalPumpState(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("ext_pump")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("ext_pump")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); doc[FPSTR(HA_DEVICE_CLASS)] = F("running"); doc[FPSTR(HA_NAME)] = F("External pump"); doc[FPSTR(HA_ICON)] = F("mdi:pump"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.master.externalPump.state, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -1069,17 +1077,17 @@ public: bool publishFaultCode(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); - doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state")); - doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.opentherm.connected and value_json.fault.active, 'online', 'offline') }}"); + doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); + doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->stateTopic.c_str(); + doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.slave.connected and value_json.slave.fault.active, 'online', 'offline') }}"); doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("fault_code")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("fault_code")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); doc[FPSTR(HA_NAME)] = F("Fault code"); doc[FPSTR(HA_ICON)] = F("mdi:cog-box"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ \"%02d (0x%02X)\"|format(value_json.slave.fault.code, value_json.slave.fault.code) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -1089,17 +1097,17 @@ public: bool publishDiagCode(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); - doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state")); - doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.opentherm.connected and value_json.fault.active or value_json.diag.active, 'online', 'offline') }}"); + doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); + doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->stateTopic.c_str(); + doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.slave.connected and value_json.slave.fault.active or value_json.slave.diag.active, 'online', 'offline') }}"); doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("diagnostic_code")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("diagnostic_code")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); doc[FPSTR(HA_NAME)] = F("Diagnostic code"); doc[FPSTR(HA_ICON)] = F("mdi:information-box"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ \"%02d (0x%02X)\"|format(value_json.slave.diag.code, value_json.slave.diag.code) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -1109,17 +1117,17 @@ public: bool publishNetworkRssi(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("rssi")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("rssi")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); doc[FPSTR(HA_DEVICE_CLASS)] = F("signal_strength"); doc[FPSTR(HA_STATE_CLASS)] = FPSTR(HA_STATE_CLASS_MEASUREMENT); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("dBm"); doc[FPSTR(HA_NAME)] = F("RSSI"); doc[FPSTR(HA_ICON)] = F("mdi:signal"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.master.network.rssi|float(0)|round(1) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -1129,17 +1137,17 @@ public: bool publishUptime(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("uptime")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("uptime")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); doc[FPSTR(HA_DEVICE_CLASS)] = F("duration"); doc[FPSTR(HA_STATE_CLASS)] = F("total_increasing"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("s"); doc[FPSTR(HA_NAME)] = F("Uptime"); doc[FPSTR(HA_ICON)] = F("mdi:clock-start"); - doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_STATE_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.master.uptime|int(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -1150,20 +1158,20 @@ public: bool publishClimateHeating(UnitSystem unit = UnitSystem::METRIC, byte minTemp = 20, byte maxTemp = 90, bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("heating")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("heating")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_NAME)] = F("Heating"); doc[FPSTR(HA_ICON)] = F("mdi:radiator"); - doc[FPSTR(HA_CURRENT_TEMPERATURE_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_CURRENT_TEMPERATURE_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_CURRENT_TEMPERATURE_TEMPLATE)] = F("{{ iif(value_json.master.heating.indoorTempControl, value_json.master.heating.indoorTemp, value_json.master.heating.currentTemp, 0)|float(0)|round(2) }}"); - doc[FPSTR(HA_TEMPERATURE_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_TEMPERATURE_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_TEMPERATURE_COMMAND_TEMPLATE)] = F("{\"heating\": {\"target\" : {{ value }}}}"); - doc[FPSTR(HA_TEMPERATURE_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_TEMPERATURE_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_TEMPERATURE_STATE_TEMPLATE)] = F("{{ value_json.heating.target|float(0)|round(1) }}"); if (unit == UnitSystem::METRIC) { @@ -1173,21 +1181,21 @@ public: doc[FPSTR(HA_TEMPERATURE_UNIT)] = "F"; } - doc[FPSTR(HA_MODE_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); - doc[FPSTR(HA_MODE_COMMAND_TEMPLATE)] = F("{% if value == 'heat' %}{\"heating\": {\"enable\" : true}}" - "{% elif value == 'off' %}{\"heating\": {\"enable\" : false}}{% endif %}"); - doc[FPSTR(HA_MODE_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); - doc[FPSTR(HA_MODE_STATE_TEMPLATE)] = F("{{ iif(value_json.heating.enable, 'heat', 'off') }}"); + doc[FPSTR(HA_MODE_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); + doc[FPSTR(HA_MODE_COMMAND_TEMPLATE)] = F("{% if value == 'heat' %}{\"heating\": {\"enabled\" : true}}" + "{% elif value == 'off' %}{\"heating\": {\"enabled\" : false}}{% endif %}"); + doc[FPSTR(HA_MODE_STATE_TOPIC)] = this->settingsTopic.c_str(); + doc[FPSTR(HA_MODE_STATE_TEMPLATE)] = F("{{ iif(value_json.heating.enabled, 'heat', 'off') }}"); doc[FPSTR(HA_MODES)][0] = F("off"); doc[FPSTR(HA_MODES)][1] = F("heat"); - doc[FPSTR(HA_ACTION_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_ACTION_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_ACTION_TEMPLATE)] = F("{{ iif(value_json.master.heating.enabled, iif(value_json.slave.heating.active, 'heating', 'idle'), 'off') }}"); - doc[FPSTR(HA_PRESET_MODE_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_PRESET_MODE_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_PRESET_MODE_COMMAND_TEMPLATE)] = F("{% if value == 'boost' %}{\"heating\": {\"turbo\" : true}}" "{% elif value == 'none' %}{\"heating\": {\"turbo\" : false}}{% endif %}"); - doc[FPSTR(HA_PRESET_MODE_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_PRESET_MODE_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_PRESET_MODE_VALUE_TEMPLATE)] = F("{{ iif(value_json.heating.turbo, 'boost', 'none') }}"); doc[FPSTR(HA_PRESET_MODES)][0] = F("boost"); @@ -1202,20 +1210,20 @@ public: bool publishClimateDhw(UnitSystem unit = UnitSystem::METRIC, byte minTemp = 40, byte maxTemp = 60, bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("dhw")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("dhw")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_NAME)] = F("DHW"); doc[FPSTR(HA_ICON)] = F("mdi:faucet"); - doc[FPSTR(HA_CURRENT_TEMPERATURE_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_CURRENT_TEMPERATURE_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_CURRENT_TEMPERATURE_TEMPLATE)] = F("{{ value_json.master.dhw.currentTemp|float(0)|round(1) }}"); - doc[FPSTR(HA_TEMPERATURE_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); + doc[FPSTR(HA_TEMPERATURE_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); doc[FPSTR(HA_TEMPERATURE_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"target\" : {{ value|int(0) }}}}"); - doc[FPSTR(HA_TEMPERATURE_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); + doc[FPSTR(HA_TEMPERATURE_STATE_TOPIC)] = this->settingsTopic.c_str(); doc[FPSTR(HA_TEMPERATURE_STATE_TEMPLATE)] = F("{{ value_json.dhw.target|float(0)|round(1) }}"); if (unit == UnitSystem::METRIC) { @@ -1225,15 +1233,15 @@ public: doc[FPSTR(HA_TEMPERATURE_UNIT)] = "F"; } - doc[FPSTR(HA_MODE_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set")); - doc[FPSTR(HA_MODE_COMMAND_TEMPLATE)] = F("{% if value == 'heat' %}{\"dhw\": {\"enable\" : true}}" - "{% elif value == 'off' %}{\"dhw\": {\"enable\" : false}}{% endif %}"); - doc[FPSTR(HA_MODE_STATE_TOPIC)] = this->getDeviceTopic(F("settings")); - doc[FPSTR(HA_MODE_STATE_TEMPLATE)] = F("{{ iif(value_json.dhw.enable, 'heat', 'off') }}"); + doc[FPSTR(HA_MODE_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); + doc[FPSTR(HA_MODE_COMMAND_TEMPLATE)] = F("{% if value == 'heat' %}{\"dhw\": {\"enabled\" : true}}" + "{% elif value == 'off' %}{\"dhw\": {\"enabled\" : false}}{% endif %}"); + doc[FPSTR(HA_MODE_STATE_TOPIC)] = this->settingsTopic.c_str(); + doc[FPSTR(HA_MODE_STATE_TEMPLATE)] = F("{{ iif(value_json.dhw.enabled, 'heat', 'off') }}"); doc[FPSTR(HA_MODES)][0] = F("off"); doc[FPSTR(HA_MODES)][1] = F("heat"); - doc[FPSTR(HA_ACTION_TOPIC)] = this->getDeviceTopic(F("state")); + doc[FPSTR(HA_ACTION_TOPIC)] = this->stateTopic.c_str(); doc[FPSTR(HA_ACTION_TEMPLATE)] = F("{{ iif(value_json.master.dhw.enabled, iif(value_json.slave.dhw.active, 'heating', 'idle'), 'off') }}"); doc[FPSTR(HA_MIN_TEMP)] = minTemp; @@ -1247,14 +1255,14 @@ public: bool publishRestartButton(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("restart")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("restart")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_DEVICE_CLASS)] = F("restart"); doc[FPSTR(HA_NAME)] = F("Restart"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setStateTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"actions\": {\"restart\": true}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -1264,17 +1272,17 @@ public: bool publishResetFaultButton(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); - doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state")); - doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.fault.active, 'online', 'offline') }}"); + doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); + doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->stateTopic.c_str(); + doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.slave.fault.active, 'online', 'offline') }}"); doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("reset_fault")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("reset_fault")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_DEVICE_CLASS)] = F("restart"); doc[FPSTR(HA_NAME)] = F("Reset fault"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setStateTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"actions\": {\"resetFault\": true}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -1284,17 +1292,17 @@ public: bool publishResetDiagButton(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); - doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state")); - doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.diag.active, 'online', 'offline') }}"); + doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); + doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->stateTopic.c_str(); + doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.slave.diag.active, 'online', 'offline') }}"); doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("reset_diagnostic")); - doc[FPSTR(HA_OBJECT_ID)] = this->getObjectIdWithPrefix(F("reset_diagnostic")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); doc[FPSTR(HA_DEVICE_CLASS)] = F("restart"); doc[FPSTR(HA_NAME)] = F("Reset diagnostic"); - doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set")); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setStateTopic.c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"actions\": {\"resetDiagnostic\": true}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; doc.shrinkToFit(); @@ -1334,6 +1342,7 @@ public: protected: unsigned short expireAfter = 300u; + String statusTopic, stateTopic, setStateTopic, settingsTopic, setSettingsTopic; }; const char HaHelper::AVAILABILITY_OT_CONN[] = "{{ iif(value_json.slave.connected, 'online', 'offline') }}"; diff --git a/src/MainTask.h b/src/MainTask.h index 08314b7..7c238f6 100644 --- a/src/MainTask.h +++ b/src/MainTask.h @@ -517,7 +517,7 @@ protected: if (configuredGpio == GPIO_IS_NOT_CONFIGURED) { if (vars.externalPump.state) { vars.externalPump.state = false; - vars.externalPump.lastEnableTime = millis(); + vars.externalPump.lastEnabledTime = millis(); Log.sinfoln(FPSTR(L_EXTPUMP), F("Disabled: use = off")); } @@ -538,7 +538,7 @@ protected: digitalWrite(configuredGpio, LOW); vars.externalPump.state = false; - vars.externalPump.lastEnableTime = millis(); + vars.externalPump.lastEnabledTime = millis(); Log.sinfoln(FPSTR(L_EXTPUMP), F("Disabled: use = off")); } @@ -551,7 +551,7 @@ protected: digitalWrite(configuredGpio, LOW); vars.externalPump.state = false; - vars.externalPump.lastEnableTime = millis(); + vars.externalPump.lastEnabledTime = millis(); Log.sinfoln(FPSTR(L_EXTPUMP), F("Disabled: expired post circulation time")); @@ -559,7 +559,7 @@ protected: digitalWrite(configuredGpio, LOW); vars.externalPump.state = false; - vars.externalPump.lastEnableTime = millis(); + vars.externalPump.lastEnabledTime = millis(); Log.sinfoln(FPSTR(L_EXTPUMP), F("Disabled: expired anti stuck time")); } @@ -576,7 +576,7 @@ protected: Log.sinfoln(FPSTR(L_EXTPUMP), F("Enabled: heating on")); - } else if (!vars.externalPump.state && (vars.externalPump.lastEnableTime == 0 || millis() - vars.externalPump.lastEnableTime >= (settings.externalPump.antiStuckInterval * 1000ul))) { + } else if (!vars.externalPump.state && (vars.externalPump.lastEnabledTime == 0 || millis() - vars.externalPump.lastEnabledTime >= (settings.externalPump.antiStuckInterval * 1000lu))) { vars.externalPump.state = true; this->externalPumpStartTime = millis(); this->extPumpStartReason = MainTask::PumpStartReason::ANTISTUCK; diff --git a/src/MqttTask.h b/src/MqttTask.h index c910f14..f42e26c 100644 --- a/src/MqttTask.h +++ b/src/MqttTask.h @@ -192,6 +192,7 @@ protected: Log.sinfoln(FPSTR(L_MQTT), F("Connecting to %s:%u..."), settings.mqtt.server, settings.mqtt.port); this->haHelper->setDevicePrefix(settings.mqtt.prefix); + this->haHelper->updateCachedTopics(); this->client->stop(); this->client->setId(networkSettings.hostname); this->client->setUsernamePassword(settings.mqtt.user, settings.mqtt.password); @@ -221,14 +222,14 @@ protected: // publish variables and status if (this->newConnection || millis() - this->prevPubVarsTime > (settings.mqtt.interval * 1000u)) { - this->writer->publish(this->haHelper->getDeviceTopic("status").c_str(), "online", false); - this->publishVariables(this->haHelper->getDeviceTopic("state").c_str()); + this->writer->publish(this->haHelper->getDeviceTopic(F("status")).c_str(), "online", false); + this->publishVariables(this->haHelper->getDeviceTopic(F("state")).c_str()); this->prevPubVarsTime = millis(); } // publish settings if (this->newConnection || millis() - this->prevPubSettingsTime > (settings.mqtt.interval * 10000u)) { - this->publishSettings(this->haHelper->getDeviceTopic("settings").c_str()); + this->publishSettings(this->haHelper->getDeviceTopic(F("settings")).c_str()); this->prevPubSettingsTime = millis(); } @@ -292,7 +293,7 @@ protected: case Sensors::Type::MANUAL: { String topic = this->haHelper->getDeviceTopic( F("sensors"), - Sensors::makeObjectId(prevSettings.name), + Sensors::makeObjectId(prevSettings.name).c_str(), F("set") ); this->client->unsubscribe(topic.c_str()); @@ -328,7 +329,7 @@ protected: case Sensors::Type::MANUAL: { String topic = this->haHelper->getDeviceTopic( F("sensors"), - Sensors::makeObjectId(prevSettings.name), + Sensors::makeObjectId(prevSettings.name).c_str(), F("set") ); this->client->subscribe(topic.c_str()); @@ -355,15 +356,15 @@ protected: unsigned long downtime = (millis() - this->disconnectedTime) / 1000; Log.sinfoln(FPSTR(L_MQTT), F("Connected (downtime: %u s.)"), downtime); - this->client->subscribe(this->haHelper->getDeviceTopic("settings/set").c_str()); - this->client->subscribe(this->haHelper->getDeviceTopic("state/set").c_str()); + this->client->subscribe(this->haHelper->getDeviceTopic(F("settings/set")).c_str()); + this->client->subscribe(this->haHelper->getDeviceTopic(F("state/set")).c_str()); } void onDisconnect() { this->disconnectedTime = millis(); unsigned long uptime = (millis() - this->connectedTime) / 1000; - Log.swarningln(FPSTR(L_MQTT), F("Disconnected (reason: %d uptime: %u s.)"), this->client->connectError(), uptime); + Log.swarningln(FPSTR(L_MQTT), F("Disconnected (reason: %d uptime: %lu s.)"), this->client->connectError(), uptime); } void onMessage(const char* topic, uint8_t* payload, size_t length) { @@ -380,12 +381,12 @@ protected: } else if (payload[i] == 13) { continue; } else if (payload[i] == 10) { - Log.print("\r\n> "); + Log.print(F("\r\n> ")); } else { Log.print((char) payload[i]); } } - Log.print("\r\n\n"); + Log.print(F("\r\n\n")); Log.flush(); Log.unlock(); } @@ -403,14 +404,14 @@ protected: } doc.shrinkToFit(); - if (this->haHelper->getDeviceTopic("state/set").equals(topic)) { + if (this->haHelper->getDeviceTopic(F("state/set")).equals(topic)) { this->writer->publish(topic, nullptr, 0, true); if (jsonToVars(doc, vars)) { this->resetPublishedVarsTime(); } - } else if (this->haHelper->getDeviceTopic("settings/set").equals(topic)) { + } else if (this->haHelper->getDeviceTopic(F("settings/set")).equals(topic)) { this->writer->publish(topic, nullptr, 0, true); if (safeJsonToSettings(doc, settings)) { @@ -422,10 +423,10 @@ protected: this->writer->publish(topic, nullptr, 0, true); String _topic = topic; - String sensorsTopic = this->haHelper->getDeviceTopic("sensors/"); - unsigned short stLength = sensorsTopic.length(); + String sensorsTopic = this->haHelper->getDeviceTopic(F("sensors/")); + auto stLength = sensorsTopic.length(); - if (_topic.startsWith(sensorsTopic) && _topic.endsWith("/set")) { + if (_topic.startsWith(sensorsTopic) && _topic.endsWith(F("/set"))) { if (_topic.length() > stLength + 4) { String name = _topic.substring(stLength, _topic.indexOf('/', stLength)); int16_t id = Sensors::getIdByObjectId(name.c_str()); @@ -512,7 +513,7 @@ protected: case Sensors::Type::MANUAL: { String topic = this->haHelper->getDeviceTopic( F("sensors"), - Sensors::makeObjectId(sSettings.name), + Sensors::makeObjectId(sSettings.name).c_str(), F("set") ); this->client->subscribe(topic.c_str()); @@ -597,8 +598,11 @@ protected: sensorResultToJson(sensorId, doc); doc.shrinkToFit(); - String objId = Sensors::makeObjectId(sSettings.name); - String topic = this->haHelper->getDeviceTopic(F("sensors"), objId); + String topic = this->haHelper->getDeviceTopic( + F("sensors"), + Sensors::makeObjectId(sSettings.name).c_str() + ); + return this->writer->publish(topic.c_str(), doc, true); } diff --git a/src/OpenThermTask.h b/src/OpenThermTask.h index 3c4c484..6a66c81 100644 --- a/src/OpenThermTask.h +++ b/src/OpenThermTask.h @@ -244,13 +244,13 @@ protected: if (vars.master.heating.enabled != vars.slave.heating.enabled) { this->prevUpdateNonEssentialVars = 0; vars.slave.heating.enabled = vars.master.heating.enabled; - Log.sinfoln(FPSTR(L_OT_HEATING), "%s", vars.master.heating.enabled ? F("Enabled") : F("Disabled")); + Log.sinfoln(FPSTR(L_OT_HEATING), vars.master.heating.enabled ? F("Enabled") : F("Disabled")); } if (vars.master.dhw.enabled != vars.slave.dhw.enabled) { this->prevUpdateNonEssentialVars = 0; vars.slave.dhw.enabled = vars.master.heating.enabled; - Log.sinfoln(FPSTR(L_OT_DHW), "%s", vars.master.heating.enabled ? F("Enabled") : F("Disabled")); + Log.sinfoln(FPSTR(L_OT_DHW), vars.master.heating.enabled ? F("Enabled") : F("Disabled")); } vars.slave.heating.active = CustomOpenTherm::isCentralHeatingActive(response); diff --git a/src/PortalTask.h b/src/PortalTask.h index 323885e..baed4de 100644 --- a/src/PortalTask.h +++ b/src/PortalTask.h @@ -88,10 +88,10 @@ protected: return result; }); this->webServer->addHandler(indexPage);*/ - this->webServer->addHandler(new StaticPage("/", &LittleFS, "/pages/index.html", PORTAL_CACHE)); + this->webServer->addHandler(new StaticPage("/", &LittleFS, F("/pages/index.html"), PORTAL_CACHE)); // dashboard page - auto dashboardPage = (new StaticPage("/dashboard.html", &LittleFS, "/pages/dashboard.html", PORTAL_CACHE)) + auto dashboardPage = (new StaticPage("/dashboard.html", &LittleFS, F("/pages/dashboard.html"), PORTAL_CACHE)) ->setBeforeSendCallback([this]() { if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) { this->webServer->requestAuthentication(DIGEST_AUTH); @@ -103,7 +103,7 @@ protected: this->webServer->addHandler(dashboardPage); // restart - this->webServer->on("/restart.html", HTTP_GET, [this]() { + this->webServer->on(F("/restart.html"), HTTP_GET, [this]() { if (this->isAuthRequired()) { if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) { this->webServer->send(401); @@ -112,12 +112,12 @@ protected: } vars.actions.restart = true; - this->webServer->sendHeader("Location", "/"); + this->webServer->sendHeader(F("Location"), "/"); this->webServer->send(302); }); // network settings page - auto networkPage = (new StaticPage("/network.html", &LittleFS, "/pages/network.html", PORTAL_CACHE)) + auto networkPage = (new StaticPage("/network.html", &LittleFS, F("/pages/network.html"), PORTAL_CACHE)) ->setBeforeSendCallback([this]() { if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) { this->webServer->requestAuthentication(DIGEST_AUTH); @@ -129,7 +129,7 @@ protected: this->webServer->addHandler(networkPage); // settings page - auto settingsPage = (new StaticPage("/settings.html", &LittleFS, "/pages/settings.html", PORTAL_CACHE)) + auto settingsPage = (new StaticPage("/settings.html", &LittleFS, F("/pages/settings.html"), PORTAL_CACHE)) ->setBeforeSendCallback([this]() { if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) { this->webServer->requestAuthentication(DIGEST_AUTH); @@ -141,7 +141,7 @@ protected: this->webServer->addHandler(settingsPage); // sensors page - auto sensorsPage = (new StaticPage("/sensors.html", &LittleFS, "/pages/sensors.html", PORTAL_CACHE)) + auto sensorsPage = (new StaticPage("/sensors.html", &LittleFS, F("/pages/sensors.html"), PORTAL_CACHE)) ->setBeforeSendCallback([this]() { if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) { this->webServer->requestAuthentication(DIGEST_AUTH); @@ -153,7 +153,7 @@ protected: this->webServer->addHandler(sensorsPage); // upgrade page - auto upgradePage = (new StaticPage("/upgrade.html", &LittleFS, "/pages/upgrade.html", PORTAL_CACHE)) + auto upgradePage = (new StaticPage("/upgrade.html", &LittleFS, F("/pages/upgrade.html"), PORTAL_CACHE)) ->setBeforeSendCallback([this]() { if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) { this->webServer->requestAuthentication(DIGEST_AUTH); @@ -167,7 +167,7 @@ protected: // OTA auto upgradeHandler = (new UpgradeHandler("/api/upgrade"))->setCanUploadCallback([this](const String& uri) { if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) { - this->webServer->sendHeader("Connection", "close"); + this->webServer->sendHeader(F("Connection"), F("close")); this->webServer->send(401); return false; } @@ -184,22 +184,22 @@ protected: status = 400; } - String response = "{\"firmware\": {\"status\": "; + String response = F("{\"firmware\": {\"status\": "); response.concat((short int) fwResult.status); - response.concat(", \"error\": \""); + response.concat(F(", \"error\": \"")); response.concat(fwResult.error); - response.concat("\"}, \"filesystem\": {\"status\": "); + response.concat(F("\"}, \"filesystem\": {\"status\": ")); response.concat((short int) fsResult.status); - response.concat(", \"error\": \""); + response.concat(F(", \"error\": \"")); response.concat(fsResult.error); - response.concat("\"}}"); - this->webServer->send(status, "application/json", response); + response.concat(F("\"}}")); + this->webServer->send(status, F("application/json"), response); }); this->webServer->addHandler(upgradeHandler); // backup - this->webServer->on("/api/backup/save", HTTP_GET, [this]() { + this->webServer->on(F("/api/backup/save"), HTTP_GET, [this]() { if (this->isAuthRequired()) { if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) { return this->webServer->send(401); @@ -208,24 +208,24 @@ protected: JsonDocument doc; - auto networkDoc = doc["network"].to(); + auto networkDoc = doc[FPSTR(S_NETWORK)].to(); networkSettingsToJson(networkSettings, networkDoc); - auto settingskDoc = doc["settings"].to(); - settingsToJson(settings, settingskDoc); + auto settingsDoc = doc[FPSTR(S_SETTINGS)].to(); + settingsToJson(settings, settingsDoc); for (uint8_t sensorId = 0; sensorId <= Sensors::getMaxSensorId(); sensorId++) { - auto sensorSettingskDoc = doc["sensors"][sensorId].to(); - sensorSettingsToJson(sensorId, Sensors::settings[sensorId], sensorSettingskDoc); + auto sensorsettingsDoc = doc[FPSTR(S_SENSORS)][sensorId].to(); + sensorSettingsToJson(sensorId, Sensors::settings[sensorId], sensorsettingsDoc); } doc.shrinkToFit(); this->webServer->sendHeader(F("Content-Disposition"), F("attachment; filename=\"backup.json\"")); - this->bufferedWebServer->send(200, "application/json", doc); + this->bufferedWebServer->send(200, F("application/json"), doc); }); - this->webServer->on("/api/backup/restore", HTTP_POST, [this]() { + this->webServer->on(F("/api/backup/restore"), HTTP_POST, [this]() { if (this->isAuthRequired()) { if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) { return this->webServer->send(401); @@ -254,13 +254,13 @@ protected: } bool changed = false; - if (!doc["settings"].isNull() && jsonToSettings(doc["settings"], settings)) { + if (!doc[FPSTR(S_SETTINGS)].isNull() && jsonToSettings(doc[FPSTR(S_SETTINGS)], settings)) { vars.actions.restart = true; fsSettings.update(); changed = true; } - if (!doc["network"].isNull() && jsonToNetworkSettings(doc["network"], networkSettings)) { + if (!doc[FPSTR(S_NETWORK)].isNull() && jsonToNetworkSettings(doc[FPSTR(S_NETWORK)], networkSettings)) { fsNetworkSettings.update(); network->setHostname(networkSettings.hostname) ->setStaCredentials(networkSettings.sta.ssid, networkSettings.sta.password, networkSettings.sta.channel) @@ -276,13 +276,13 @@ protected: changed = true; } - if (!doc["sensors"].isNull()) { + if (!doc[FPSTR(S_SENSORS)].isNull()) { for (uint8_t sensorId = 0; sensorId <= Sensors::getMaxSensorId(); sensorId++) { - if (doc["sensors"][sensorId].isNull()) { + if (doc[FPSTR(S_SENSORS)][sensorId].isNull()) { continue; } - auto sensorSettingsDoc = doc["sensors"][sensorId].to(); + auto sensorSettingsDoc = doc[FPSTR(S_SENSORS)][sensorId].to(); if (jsonToSensorSettings(sensorId, sensorSettingsDoc, Sensors::settings[sensorId])){ changed = true; } @@ -296,7 +296,7 @@ protected: }); // network - this->webServer->on("/api/network/settings", HTTP_GET, [this]() { + this->webServer->on(F("/api/network/settings"), HTTP_GET, [this]() { if (this->isAuthRequired()) { if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) { return this->webServer->send(401); @@ -307,10 +307,10 @@ protected: networkSettingsToJson(networkSettings, doc); doc.shrinkToFit(); - this->bufferedWebServer->send(200, "application/json", doc); + this->bufferedWebServer->send(200, F("application/json"), doc); }); - this->webServer->on("/api/network/settings", HTTP_POST, [this]() { + this->webServer->on(F("/api/network/settings"), HTTP_POST, [this]() { if (this->isAuthRequired()) { if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) { return this->webServer->send(401); @@ -345,7 +345,7 @@ protected: networkSettingsToJson(networkSettings, doc); doc.shrinkToFit(); - this->bufferedWebServer->send(changed ? 201 : 200, "application/json", doc); + this->bufferedWebServer->send(changed ? 201 : 200, F("application/json"), doc); if (changed) { doc.clear(); @@ -366,7 +366,7 @@ protected: } }); - this->webServer->on("/api/network/scan", HTTP_GET, [this]() { + this->webServer->on(F("/api/network/scan"), HTTP_GET, [this]() { if (this->isAuthRequired()) { if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) { this->webServer->send(401); @@ -391,28 +391,28 @@ protected: JsonDocument doc; for (short int i = 0; i < apCount; i++) { String ssid = WiFi.SSID(i); - doc[i]["ssid"] = ssid; - doc[i]["bssid"] = WiFi.BSSIDstr(i); - doc[i]["signalQuality"] = NetworkMgr::rssiToSignalQuality(WiFi.RSSI(i)); - doc[i]["channel"] = WiFi.channel(i); - doc[i]["hidden"] = !ssid.length(); + doc[i][FPSTR(S_SSID)] = ssid; + doc[i][FPSTR(S_BSSID)] = WiFi.BSSIDstr(i); + doc[i][FPSTR(S_SIGNAL_QUALITY)] = NetworkMgr::rssiToSignalQuality(WiFi.RSSI(i)); + doc[i][FPSTR(S_CHANNEL)] = WiFi.channel(i); + doc[i][FPSTR(S_HIDDEN)] = !ssid.length(); #ifdef ARDUINO_ARCH_ESP8266 const bss_info* info = WiFi.getScanInfoByIndex(i); - doc[i]["auth"] = info->authmode; + doc[i][FPSTR(S_AUTH)] = info->authmode; #else - doc[i]["auth"] = WiFi.encryptionType(i); + doc[i][FPSTR(S_AUTH)] = WiFi.encryptionType(i); #endif } doc.shrinkToFit(); - this->bufferedWebServer->send(200, "application/json", doc); + this->bufferedWebServer->send(200, F("application/json"), doc); WiFi.scanDelete(); }); // settings - this->webServer->on("/api/settings", HTTP_GET, [this]() { + this->webServer->on(F("/api/settings"), HTTP_GET, [this]() { if (this->isAuthRequired()) { if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) { return this->webServer->send(401); @@ -423,10 +423,10 @@ protected: settingsToJson(settings, doc); doc.shrinkToFit(); - this->bufferedWebServer->send(200, "application/json", doc); + this->bufferedWebServer->send(200, F("application/json"), doc); }); - this->webServer->on("/api/settings", HTTP_POST, [this]() { + this->webServer->on(F("/api/settings"), HTTP_POST, [this]() { if (this->isAuthRequired()) { if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) { return this->webServer->send(401); @@ -461,7 +461,7 @@ protected: settingsToJson(settings, doc); doc.shrinkToFit(); - this->bufferedWebServer->send(changed ? 201 : 200, "application/json", doc); + this->bufferedWebServer->send(changed ? 201 : 200, F("application/json"), doc); if (changed) { doc.clear(); @@ -474,7 +474,7 @@ protected: // sensors list - this->webServer->on("/api/sensors", HTTP_GET, [this]() { + this->webServer->on(F("/api/sensors"), HTTP_GET, [this]() { if (this->isAuthRequired()) { if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) { return this->webServer->send(401); @@ -482,16 +482,16 @@ protected: } bool detailed = false; - if (this->webServer->hasArg("detailed")) { - detailed = this->webServer->arg("detailed").toInt() > 0; + if (this->webServer->hasArg(F("detailed"))) { + detailed = this->webServer->arg(F("detailed")).toInt() > 0; } JsonDocument doc; for (uint8_t sensorId = 0; sensorId <= Sensors::getMaxSensorId(); sensorId++) { if (detailed) { auto& sSensor = Sensors::settings[sensorId]; - doc[sensorId]["name"] = sSensor.name; - doc[sensorId]["purpose"] = static_cast(sSensor.purpose); + doc[sensorId][FPSTR(S_NAME)] = sSensor.name; + doc[sensorId][FPSTR(S_PURPOSE)] = static_cast(sSensor.purpose); sensorResultToJson(sensorId, doc[sensorId]); } else { @@ -500,22 +500,22 @@ protected: } doc.shrinkToFit(); - this->bufferedWebServer->send(200, "application/json", doc); + this->bufferedWebServer->send(200, F("application/json"), doc); }); // sensor settings - this->webServer->on("/api/sensor", HTTP_GET, [this]() { + this->webServer->on(F("/api/sensor"), HTTP_GET, [this]() { if (this->isAuthRequired()) { if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) { return this->webServer->send(401); } } - if (!this->webServer->hasArg("id")) { + if (!this->webServer->hasArg(F("id"))) { return this->webServer->send(400); } - auto id = this->webServer->arg("id"); + auto id = this->webServer->arg(F("id")); if (!isDigit(id.c_str())) { return this->webServer->send(400); } @@ -529,10 +529,10 @@ protected: JsonDocument doc; sensorSettingsToJson(sensorId, Sensors::settings[sensorId], doc); doc.shrinkToFit(); - this->bufferedWebServer->send(200, "application/json", doc); + this->bufferedWebServer->send(200, F("application/json"), doc); }); - this->webServer->on("/api/sensor", HTTP_POST, [this]() { + this->webServer->on(F("/api/sensor"), HTTP_POST, [this]() { if (this->isAuthRequired()) { if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) { return this->webServer->send(401); @@ -540,16 +540,16 @@ protected: } #ifdef ARDUINO_ARCH_ESP8266 - if (!this->webServer->hasArg("id") || this->webServer->args() != 1) { + if (!this->webServer->hasArg(F("id")) || this->webServer->args() != 1) { return this->webServer->send(400); } #else - if (!this->webServer->hasArg("id") || this->webServer->args() != 2) { + if (!this->webServer->hasArg(F("id")) || this->webServer->args() != 2) { return this->webServer->send(400); } #endif - auto id = this->webServer->arg("id"); + auto id = this->webServer->arg(F("id")); if (!isDigit(id.c_str())) { return this->webServer->send(400); } @@ -592,7 +592,7 @@ protected: sensorSettingsToJson(sensorId, sSettings, doc); doc.shrinkToFit(); - this->bufferedWebServer->send(changed ? 201 : 200, "application/json", doc); + this->bufferedWebServer->send(changed ? 201 : 200, F("application/json"), doc); } if (changed) { @@ -603,15 +603,15 @@ protected: // vars - this->webServer->on("/api/vars", HTTP_GET, [this]() { + this->webServer->on(F("/api/vars"), HTTP_GET, [this]() { JsonDocument doc; varsToJson(vars, doc); doc.shrinkToFit(); - this->bufferedWebServer->send(200, "application/json", doc); + this->bufferedWebServer->send(200, F("application/json"), doc); }); - this->webServer->on("/api/vars", HTTP_POST, [this]() { + this->webServer->on(F("/api/vars"), HTTP_POST, [this]() { if (this->isAuthRequired()) { if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) { return this->webServer->send(401); @@ -646,7 +646,7 @@ protected: varsToJson(vars, doc); doc.shrinkToFit(); - this->bufferedWebServer->send(changed ? 201 : 200, "application/json", doc); + this->bufferedWebServer->send(changed ? 201 : 200, F("application/json"), doc); if (changed) { doc.clear(); @@ -656,78 +656,138 @@ protected: } }); - this->webServer->on("/api/info", HTTP_GET, [this]() { + this->webServer->on(F("/api/info"), HTTP_GET, [this]() { bool isConnected = network->isConnected(); JsonDocument doc; - doc["system"]["resetReason"] = getResetReason(); - doc["system"]["uptime"] = millis() / 1000ul; - doc["network"]["hostname"] = networkSettings.hostname; - doc["network"]["mac"] = network->getStaMac(); - doc["network"]["connected"] = isConnected; - doc["network"]["ssid"] = network->getStaSsid(); - doc["network"]["signalQuality"] = isConnected ? NetworkMgr::rssiToSignalQuality(network->getRssi()) : 0; - doc["network"]["channel"] = isConnected ? network->getStaChannel() : 0; - doc["network"]["ip"] = isConnected ? network->getStaIp().toString() : ""; - doc["network"]["subnet"] = isConnected ? network->getStaSubnet().toString() : ""; - doc["network"]["gateway"] = isConnected ? network->getStaGateway().toString() : ""; - doc["network"]["dns"] = isConnected ? network->getStaDns().toString() : ""; + auto docSystem = doc[FPSTR(S_SYSTEM)].to(); + docSystem[FPSTR(S_RESET_REASON)] = getResetReason(); + docSystem[FPSTR(S_UPTIME)] = millis() / 1000; - doc["build"]["version"] = BUILD_VERSION; - doc["build"]["date"] = __DATE__ " " __TIME__; - doc["build"]["env"] = BUILD_ENV; + auto docNetwork = doc[FPSTR(S_NETWORK)].to(); + docNetwork[FPSTR(S_HOSTNAME)] = networkSettings.hostname; + docNetwork[FPSTR(S_MAC)] = network->getStaMac(); + docNetwork[FPSTR(S_CONNECTED)] = isConnected; + docNetwork[FPSTR(S_SSID)] = network->getStaSsid(); + docNetwork[FPSTR(S_SIGNAL_QUALITY)] = isConnected ? NetworkMgr::rssiToSignalQuality(network->getRssi()) : 0; + docNetwork[FPSTR(S_CHANNEL)] = isConnected ? network->getStaChannel() : 0; + docNetwork[FPSTR(S_IP)] = isConnected ? network->getStaIp().toString() : ""; + docNetwork[FPSTR(S_SUBNET)] = isConnected ? network->getStaSubnet().toString() : ""; + docNetwork[FPSTR(S_GATEWAY)] = isConnected ? network->getStaGateway().toString() : ""; + docNetwork[FPSTR(S_DNS)] = isConnected ? network->getStaDns().toString() : ""; - doc["heap"]["total"] = getTotalHeap(); - doc["heap"]["free"] = getFreeHeap(); - doc["heap"]["minFree"] = getFreeHeap(true); - doc["heap"]["maxFreeBlock"] = getMaxFreeBlockHeap(); - doc["heap"]["minMaxFreeBlock"] = getMaxFreeBlockHeap(true); - + auto docBuild = doc[FPSTR(S_BUILD)].to(); + docBuild[FPSTR(S_VERSION)] = BUILD_VERSION; + docBuild[FPSTR(S_DATE)] = __DATE__ " " __TIME__; + docBuild[FPSTR(S_ENV)] = BUILD_ENV; #ifdef ARDUINO_ARCH_ESP8266 - doc["build"]["core"] = ESP.getCoreVersion(); - doc["build"]["sdk"] = ESP.getSdkVersion(); - doc["chip"]["model"] = esp_is_8285() ? "ESP8285" : "ESP8266"; - doc["chip"]["rev"] = 0; - doc["chip"]["cores"] = 1; - doc["chip"]["freq"] = ESP.getCpuFreqMHz(); - doc["flash"]["size"] = ESP.getFlashChipSize(); - doc["flash"]["realSize"] = ESP.getFlashChipRealSize(); + docBuild[FPSTR(S_CORE)] = ESP.getCoreVersion(); + docBuild[FPSTR(S_SDK)] = ESP.getSdkVersion(); #elif ARDUINO_ARCH_ESP32 - doc["build"]["core"] = ESP.getCoreVersion(); - doc["build"]["sdk"] = ESP.getSdkVersion(); - doc["chip"]["model"] = ESP.getChipModel(); - doc["chip"]["rev"] = ESP.getChipRevision(); - doc["chip"]["cores"] = ESP.getChipCores(); - doc["chip"]["freq"] = ESP.getCpuFreqMHz(); - doc["flash"]["size"] = ESP.getFlashChipSize(); - doc["flash"]["realSize"] = doc["flash"]["size"]; + docBuild[FPSTR(S_CORE)] = ESP.getCoreVersion(); + docBuild[FPSTR(S_SDK)] = ESP.getSdkVersion(); #else - doc["build"]["core"] = 0; - doc["build"]["sdk"] = 0; - doc["chip"]["model"] = 0; - doc["chip"]["rev"] = 0; - doc["chip"]["cores"] = 0; - doc["chip"]["freq"] = 0; - doc["flash"]["size"] = 0; - doc["flash"]["realSize"] = 0; + docBuild[FPSTR(S_CORE)] = 0; + docBuild[FPSTR(S_SDK)] = 0; + #endif + + auto docHeap = doc[FPSTR(S_HEAP)].to(); + docHeap[FPSTR(S_TOTAL)] = getTotalHeap(); + docHeap[FPSTR(S_FREE)] = getFreeHeap(); + docHeap[FPSTR(S_MIN_FREE)] = getFreeHeap(true); + docHeap[FPSTR(S_MAX_FREE_BLOCK)] = getMaxFreeBlockHeap(); + docHeap[FPSTR(S_MIN_MAX_FREE_BLOCK)] = getMaxFreeBlockHeap(true); + + auto docChip = doc[FPSTR(S_CHIP)].to(); + #ifdef ARDUINO_ARCH_ESP8266 + docChip[FPSTR(S_MODEL)] = esp_is_8285() ? F("ESP8285") : F("ESP8266"); + docChip[FPSTR(S_REV)] = 0; + docChip[FPSTR(S_CORES)] = 1; + docChip[FPSTR(S_FREQ)] = ESP.getCpuFreqMHz(); + #elif ARDUINO_ARCH_ESP32 + docChip[FPSTR(S_MODEL)] = ESP.getChipModel(); + docChip[FPSTR(S_REV)] = ESP.getChipRevision(); + docChip[FPSTR(S_CORES)] = ESP.getChipCores(); + docChip[FPSTR(S_FREQ)] = ESP.getCpuFreqMHz(); + #else + docChip[FPSTR(S_MODEL)] = 0; + docChip[FPSTR(S_REV)] = 0; + docChip[FPSTR(S_CORES)] = 0; + docChip[FPSTR(S_FREQ)] = 0; + #endif + + auto docFlash = doc[FPSTR(S_FLASH)].to(); + #ifdef ARDUINO_ARCH_ESP8266 + docFlash[FPSTR(S_SIZE)] = ESP.getFlashChipSize(); + docFlash[FPSTR(S_REAL_SIZE)] = ESP.getFlashChipRealSize(); + #elif ARDUINO_ARCH_ESP32 + docFlash[FPSTR(S_SIZE)] = ESP.getFlashChipSize(); + docFlash[FPSTR(S_REAL_SIZE)] = docFlash[FPSTR(S_SIZE)]; + #else + docFlash[FPSTR(S_SIZE)] = 0; + docFlash[FPSTR(S_REAL_SIZE)] = 0; #endif doc.shrinkToFit(); - this->bufferedWebServer->send(200, "application/json", doc); + this->bufferedWebServer->send(200, F("application/json"), doc); }); - this->webServer->on("/api/debug", HTTP_GET, [this]() { + this->webServer->on(F("/api/debug"), HTTP_GET, [this]() { JsonDocument doc; - doc["build"]["version"] = BUILD_VERSION; - doc["build"]["date"] = __DATE__ " " __TIME__; - doc["build"]["env"] = BUILD_ENV; - doc["heap"]["total"] = getTotalHeap(); - doc["heap"]["free"] = getFreeHeap(); - doc["heap"]["minFree"] = getFreeHeap(true); - doc["heap"]["maxFreeBlock"] = getMaxFreeBlockHeap(); - doc["heap"]["minMaxFreeBlock"] = getMaxFreeBlockHeap(true); + + auto docBuild = doc[FPSTR(S_BUILD)].to(); + docBuild[FPSTR(S_VERSION)] = BUILD_VERSION; + docBuild[FPSTR(S_DATE)] = __DATE__ " " __TIME__; + docBuild[FPSTR(S_ENV)] = BUILD_ENV; + #ifdef ARDUINO_ARCH_ESP8266 + docBuild[FPSTR(S_CORE)] = ESP.getCoreVersion(); + docBuild[FPSTR(S_SDK)] = ESP.getSdkVersion(); + #elif ARDUINO_ARCH_ESP32 + docBuild[FPSTR(S_CORE)] = ESP.getCoreVersion(); + docBuild[FPSTR(S_SDK)] = ESP.getSdkVersion(); + #else + docBuild[FPSTR(S_CORE)] = 0; + docBuild[FPSTR(S_SDK)] = 0; + #endif + + auto docHeap = doc[FPSTR(S_HEAP)].to(); + docHeap[FPSTR(S_TOTAL)] = getTotalHeap(); + docHeap[FPSTR(S_FREE)] = getFreeHeap(); + docHeap[FPSTR(S_MIN_FREE)] = getFreeHeap(true); + docHeap[FPSTR(S_MAX_FREE_BLOCK)] = getMaxFreeBlockHeap(); + docHeap[FPSTR(S_MIN_MAX_FREE_BLOCK)] = getMaxFreeBlockHeap(true); + + auto docChip = doc[FPSTR(S_CHIP)].to(); + #ifdef ARDUINO_ARCH_ESP8266 + docChip[FPSTR(S_MODEL)] = esp_is_8285() ? F("ESP8285") : F("ESP8266"); + docChip[FPSTR(S_REV)] = 0; + docChip[FPSTR(S_CORES)] = 1; + docChip[FPSTR(S_FREQ)] = ESP.getCpuFreqMHz(); + #elif ARDUINO_ARCH_ESP32 + docChip[FPSTR(S_MODEL)] = ESP.getChipModel(); + docChip[FPSTR(S_REV)] = ESP.getChipRevision(); + docChip[FPSTR(S_CORES)] = ESP.getChipCores(); + docChip[FPSTR(S_FREQ)] = ESP.getCpuFreqMHz(); + #else + docChip[FPSTR(S_MODEL)] = 0; + docChip[FPSTR(S_REV)] = 0; + docChip[FPSTR(S_CORES)] = 0; + docChip[FPSTR(S_FREQ)] = 0; + #endif + + auto docFlash = doc[FPSTR(S_FLASH)].to(); + #ifdef ARDUINO_ARCH_ESP8266 + docFlash[FPSTR(S_SIZE)] = ESP.getFlashChipSize(); + docFlash[FPSTR(S_REAL_SIZE)] = ESP.getFlashChipRealSize(); + #elif ARDUINO_ARCH_ESP32 + docFlash[FPSTR(S_SIZE)] = ESP.getFlashChipSize(); + docFlash[FPSTR(S_REAL_SIZE)] = docFlash[FPSTR(S_SIZE)]; + #else + docFlash[FPSTR(S_SIZE)] = 0; + docFlash[FPSTR(S_REAL_SIZE)] = 0; + #endif #if defined(ARDUINO_ARCH_ESP32) auto reason = esp_reset_reason(); @@ -738,58 +798,30 @@ protected: #else if (false) { #endif - doc["crash"]["reason"] = getResetReason(); - doc["crash"]["core"] = CrashRecorder::ext.core; - doc["crash"]["heap"] = CrashRecorder::ext.heap; - doc["crash"]["uptime"] = CrashRecorder::ext.uptime; + auto docCrash = doc[FPSTR(S_CRASH)].to(); + docCrash[FPSTR(S_REASON)] = getResetReason(); + docCrash[FPSTR(S_CORE)] = CrashRecorder::ext.core; + docCrash[FPSTR(S_HEAP)] = CrashRecorder::ext.heap; + docCrash[FPSTR(S_UPTIME)] = CrashRecorder::ext.uptime; if (CrashRecorder::backtrace.length > 0 && CrashRecorder::backtrace.length <= CrashRecorder::backtraceMaxLength) { String backtraceStr; arr2str(backtraceStr, CrashRecorder::backtrace.data, CrashRecorder::backtrace.length); - doc["crash"]["backtrace"]["data"] = backtraceStr; - doc["crash"]["backtrace"]["continues"] = CrashRecorder::backtrace.continues; + docCrash[FPSTR(S_BACKTRACE)][FPSTR(S_DATA)] = backtraceStr; + docCrash[FPSTR(S_BACKTRACE)][FPSTR(S_CONTINUES)] = CrashRecorder::backtrace.continues; } if (CrashRecorder::epc.length > 0 && CrashRecorder::epc.length <= CrashRecorder::epcMaxLength) { String epcStr; arr2str(epcStr, CrashRecorder::epc.data, CrashRecorder::epc.length); - doc["crash"]["epc"] = epcStr; + docCrash[FPSTR(S_EPC)] = epcStr; } } - #ifdef ARDUINO_ARCH_ESP8266 - doc["build"]["core"] = ESP.getCoreVersion(); - doc["build"]["sdk"] = ESP.getSdkVersion(); - doc["chip"]["model"] = esp_is_8285() ? "ESP8285" : "ESP8266"; - doc["chip"]["rev"] = 0; - doc["chip"]["cores"] = 1; - doc["chip"]["freq"] = ESP.getCpuFreqMHz(); - doc["flash"]["size"] = ESP.getFlashChipSize(); - doc["flash"]["realSize"] = ESP.getFlashChipRealSize(); - #elif ARDUINO_ARCH_ESP32 - doc["build"]["core"] = ESP.getCoreVersion(); - doc["build"]["sdk"] = ESP.getSdkVersion(); - doc["chip"]["model"] = ESP.getChipModel(); - doc["chip"]["rev"] = ESP.getChipRevision(); - doc["chip"]["cores"] = ESP.getChipCores(); - doc["chip"]["freq"] = ESP.getCpuFreqMHz(); - doc["flash"]["size"] = ESP.getFlashChipSize(); - doc["flash"]["realSize"] = doc["flash"]["size"]; - #else - doc["build"]["core"] = 0; - doc["build"]["sdk"] = 0; - doc["chip"]["model"] = 0; - doc["chip"]["rev"] = 0; - doc["chip"]["cores"] = 0; - doc["chip"]["freq"] = 0; - doc["flash"]["size"] = 0; - doc["flash"]["realSize"] = 0; - #endif - doc.shrinkToFit(); this->webServer->sendHeader(F("Content-Disposition"), F("attachment; filename=\"debug.json\"")); - this->bufferedWebServer->send(200, "application/json", doc, true); + this->bufferedWebServer->send(200, F("application/json"), doc, true); }); @@ -798,14 +830,14 @@ protected: Log.straceln(FPSTR(L_PORTAL_WEBSERVER), F("Page not found, uri: %s"), this->webServer->uri().c_str()); const String uri = this->webServer->uri(); - if (uri.equals("/")) { - this->webServer->send(200, "text/plain", F("The file system is not flashed!")); + if (uri.equals(F("/"))) { + this->webServer->send(200, F("text/plain"), F("The file system is not flashed!")); } else if (network->isApEnabled()) { this->onCaptivePortal(); } else { - this->webServer->send(404, "text/plain", F("Page not found")); + this->webServer->send(404, F("text/plain"), F("Page not found")); } }); @@ -877,26 +909,28 @@ protected: void onCaptivePortal() { const String uri = this->webServer->uri(); - if (uri.equals("/connecttest.txt")) { + if (uri.equals(F("/connecttest.txt"))) { this->webServer->sendHeader(F("Location"), F("http://logout.net")); this->webServer->send(302); Log.straceln(FPSTR(L_PORTAL_CAPTIVE), F("Redirect to http://logout.net with 302 code")); - } else if (uri.equals("/wpad.dat")) { + } else if (uri.equals(F("/wpad.dat"))) { this->webServer->send(404); Log.straceln(FPSTR(L_PORTAL_CAPTIVE), F("Send empty page with 404 code")); - } else if (uri.equals("/success.txt")) { + } else if (uri.equals(F("/success.txt"))) { this->webServer->send(200); Log.straceln(FPSTR(L_PORTAL_CAPTIVE), F("Send empty page with 200 code")); } else { - String portalUrl = "http://" + network->getApIp().toString() + '/'; + String portalUrl = F("http://"); + portalUrl += network->getApIp().toString(); + portalUrl += '/'; - this->webServer->sendHeader("Location", portalUrl.c_str()); + this->webServer->sendHeader(F("Location"), portalUrl.c_str()); this->webServer->send(302); Log.straceln(FPSTR(L_PORTAL_CAPTIVE), F("Redirect to portal page with 302 code")); diff --git a/src/SensorsTask.h b/src/SensorsTask.h index 6eef520..432adfa 100644 --- a/src/SensorsTask.h +++ b/src/SensorsTask.h @@ -61,16 +61,26 @@ protected: void loop() { if (isPollingDallasSensors()) { pollingDallasSensors(false); + this->yield(); } if (millis() - this->globalLastPollingTime > this->globalPollingInterval) { - makeDallasInstances(); cleanDallasInstances(); + makeDallasInstances(); + this->yield(); + searchDallasSensors(); fillingAddressesDallasSensors(); + this->yield(); + pollingDallasSensors(); + this->yield(); + pollingNtcSensors(); + this->yield(); + pollingBleSensors(); + this->yield(); this->globalLastPollingTime = millis(); } diff --git a/src/Settings.h b/src/Settings.h index 35fcf36..7b3f59b 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -236,7 +236,7 @@ struct Variables { struct { bool state = false; - unsigned long lastEnableTime = 0; + unsigned long lastEnabledTime = 0; } externalPump; struct { diff --git a/src/main.cpp b/src/main.cpp index 6e2663d..b504948 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,6 @@ +#define ARDUINOJSON_USE_DOUBLE 0 +#define ARDUINOJSON_USE_LONG_LONG 0 + #include #include #include diff --git a/src/strings.h b/src/strings.h index 60776c6..54c874d 100644 --- a/src/strings.h +++ b/src/strings.h @@ -3,32 +3,191 @@ #define PROGMEM #endif -const char L_SETTINGS[] PROGMEM = "SETTINGS"; -const char L_SETTINGS_OT[] PROGMEM = "SETTINGS.OT"; -const char L_SETTINGS_DHW[] PROGMEM = "SETTINGS.DHW"; -const char L_SETTINGS_HEATING[] PROGMEM = "SETTINGS.HEATING"; -const char L_NETWORK[] PROGMEM = "NETWORK"; -const char L_NETWORK_SETTINGS[] PROGMEM = "NETWORK.SETTINGS"; -const char L_PORTAL_WEBSERVER[] PROGMEM = "PORTAL.WEBSERVER"; -const char L_PORTAL_DNSSERVER[] PROGMEM = "PORTAL.DNSSERVER"; -const char L_PORTAL_CAPTIVE[] PROGMEM = "PORTAL.CAPTIVE"; -const char L_PORTAL_OTA[] PROGMEM = "PORTAL.OTA"; -const char L_MAIN[] PROGMEM = "MAIN"; -const char L_MQTT[] PROGMEM = "MQTT"; -const char L_MQTT_HA[] PROGMEM = "MQTT.HA"; -const char L_MQTT_MSG[] PROGMEM = "MQTT.MSG"; -const char L_OT[] PROGMEM = "OT"; -const char L_OT_DHW[] PROGMEM = "OT.DHW"; -const char L_OT_HEATING[] PROGMEM = "OT.HEATING"; -const char L_OT_CH2[] PROGMEM = "OT.CH2"; -const char L_SENSORS[] PROGMEM = "SENSORS"; -const char L_SENSORS_SETTINGS[] PROGMEM = "SENSORS.SETTINGS"; -const char L_SENSORS_DALLAS[] PROGMEM = "SENSORS.DALLAS"; -const char L_SENSORS_NTC[] PROGMEM = "SENSORS.NTC"; -const char L_SENSORS_BLE[] PROGMEM = "SENSORS.BLE"; -const char L_REGULATOR[] PROGMEM = "REGULATOR"; -const char L_REGULATOR_PID[] PROGMEM = "REGULATOR.PID"; -const char L_REGULATOR_EQUITHERM[] PROGMEM = "REGULATOR.EQUITHERM"; -const char L_CASCADE_INPUT[] PROGMEM = "CASCADE.INPUT"; -const char L_CASCADE_OUTPUT[] PROGMEM = "CASCADE.OUTPUT"; -const char L_EXTPUMP[] PROGMEM = "EXTPUMP"; \ No newline at end of file +const char L_SETTINGS[] PROGMEM = "SETTINGS"; +const char L_SETTINGS_OT[] PROGMEM = "SETTINGS.OT"; +const char L_SETTINGS_DHW[] PROGMEM = "SETTINGS.DHW"; +const char L_SETTINGS_HEATING[] PROGMEM = "SETTINGS.HEATING"; +const char L_NETWORK[] PROGMEM = "NETWORK"; +const char L_NETWORK_SETTINGS[] PROGMEM = "NETWORK.SETTINGS"; +const char L_PORTAL_WEBSERVER[] PROGMEM = "PORTAL.WEBSERVER"; +const char L_PORTAL_DNSSERVER[] PROGMEM = "PORTAL.DNSSERVER"; +const char L_PORTAL_CAPTIVE[] PROGMEM = "PORTAL.CAPTIVE"; +const char L_PORTAL_OTA[] PROGMEM = "PORTAL.OTA"; +const char L_MAIN[] PROGMEM = "MAIN"; +const char L_MQTT[] PROGMEM = "MQTT"; +const char L_MQTT_HA[] PROGMEM = "MQTT.HA"; +const char L_MQTT_MSG[] PROGMEM = "MQTT.MSG"; +const char L_OT[] PROGMEM = "OT"; +const char L_OT_DHW[] PROGMEM = "OT.DHW"; +const char L_OT_HEATING[] PROGMEM = "OT.HEATING"; +const char L_OT_CH2[] PROGMEM = "OT.CH2"; +const char L_SENSORS[] PROGMEM = "SENSORS"; +const char L_SENSORS_SETTINGS[] PROGMEM = "SENSORS.SETTINGS"; +const char L_SENSORS_DALLAS[] PROGMEM = "SENSORS.DALLAS"; +const char L_SENSORS_NTC[] PROGMEM = "SENSORS.NTC"; +const char L_SENSORS_BLE[] PROGMEM = "SENSORS.BLE"; +const char L_REGULATOR[] PROGMEM = "REGULATOR"; +const char L_REGULATOR_PID[] PROGMEM = "REGULATOR.PID"; +const char L_REGULATOR_EQUITHERM[] PROGMEM = "REGULATOR.EQUITHERM"; +const char L_CASCADE_INPUT[] PROGMEM = "CASCADE.INPUT"; +const char L_CASCADE_OUTPUT[] PROGMEM = "CASCADE.OUTPUT"; +const char L_EXTPUMP[] PROGMEM = "EXTPUMP"; + + +const char S_ACTIONS[] PROGMEM = "actions"; +const char S_ACTIVE[] PROGMEM = "active"; +const char S_ADDRESS[] PROGMEM = "address"; +const char S_ANTI_STUCK_INTERVAL[] PROGMEM = "antiStuckInterval"; +const char S_ANTI_STUCK_TIME[] PROGMEM = "antiStuckTime"; +const char S_AP[] PROGMEM = "ap"; +const char S_APP_VERSION[] PROGMEM = "appVersion"; +const char S_AUTH[] PROGMEM = "auth"; +const char S_BACKTRACE[] PROGMEM = "backtrace"; +const char S_BATTERY[] PROGMEM = "battery"; +const char S_BAUDRATE[] PROGMEM = "baudrate"; +const char S_BLOCKING[] PROGMEM = "blocking"; +const char S_BSSID[] PROGMEM = "bssid"; +const char S_BUILD[] PROGMEM = "build"; +const char S_CASCADE_CONTROL[] PROGMEM = "cascadeControl"; +const char S_CHANNEL[] PROGMEM = "channel"; +const char S_CHIP[] PROGMEM = "chip"; +const char S_CODE[] PROGMEM = "code"; +const char S_CONNECTED[] PROGMEM = "connected"; +const char S_CONTINUES[] PROGMEM = "continues"; +const char S_CORE[] PROGMEM = "core"; +const char S_CORES[] PROGMEM = "cores"; +const char S_CRASH[] PROGMEM = "crash"; +const char S_CURRENT_TEMP[] PROGMEM = "currentTemp"; +const char S_DATA[] PROGMEM = "data"; +const char S_DATE[] PROGMEM = "date"; +const char S_DHW[] PROGMEM = "dhw"; +const char S_DHW_BLOCKING[] PROGMEM = "dhwBlocking"; +const char S_DHW_PRESENT[] PROGMEM = "dhwPresent"; +const char S_DHW_TO_CH2[] PROGMEM = "dhwToCh2"; +const char S_DIAG[] PROGMEM = "diag"; +const char S_DNS[] PROGMEM = "dns"; +const char S_DT[] PROGMEM = "dt"; +const char S_D_FACTOR[] PROGMEM = "d_factor"; +const char S_EMERGENCY[] PROGMEM = "emergency"; +const char S_ENABLED[] PROGMEM = "enabled"; +const char S_ENV[] PROGMEM = "env"; +const char S_EPC[] PROGMEM = "epc"; +const char S_EQUITHERM[] PROGMEM = "equitherm"; +const char S_EXTERNAL_PUMP[] PROGMEM = "externalPump"; +const char S_FACTOR[] PROGMEM = "factor"; +const char S_FAULT[] PROGMEM = "fault"; +const char S_FILTERING[] PROGMEM = "filtering"; +const char S_FILTERING_FACTOR[] PROGMEM = "filteringFactor"; +const char S_FLAGS[] PROGMEM = "flags"; +const char S_FLAME[] PROGMEM = "flame"; +const char S_FLASH[] PROGMEM = "flash"; +const char S_FREE[] PROGMEM = "free"; +const char S_FREQ[] PROGMEM = "freq"; +const char S_GATEWAY[] PROGMEM = "gateway"; +const char S_GET_MIN_MAX_TEMP[] PROGMEM = "getMinMaxTemp"; +const char S_GPIO[] PROGMEM = "gpio"; +const char S_HEAP[] PROGMEM = "heap"; +const char S_HEATING[] PROGMEM = "heating"; +const char S_HEATING_CH1_TO_CH2[] PROGMEM = "heatingCh1ToCh2"; +const char S_HEATING_CH2_ENABLED[] PROGMEM = "heatingCh2Enabled"; +const char S_HIDDEN[] PROGMEM = "hidden"; +const char S_HOME_ASSISTANT_DISCOVERY[] PROGMEM = "homeAssistantDiscovery"; +const char S_HOSTNAME[] PROGMEM = "hostname"; +const char S_HUMIDITY[] PROGMEM = "humidity"; +const char S_HYSTERESIS[] PROGMEM = "hysteresis"; +const char S_ID[] PROGMEM = "id"; +const char S_IMMERGAS_FIX[] PROGMEM = "immergasFix"; +const char S_INDOOR_TEMP[] PROGMEM = "indoorTemp"; +const char S_INDOOR_TEMP_CONTROL[] PROGMEM = "indoorTempControl"; +const char S_IN_GPIO[] PROGMEM = "inGpio"; +const char S_INPUT[] PROGMEM = "input"; +const char S_INTERVAL[] PROGMEM = "interval"; +const char S_INVERT_STATE[] PROGMEM = "invertState"; +const char S_IP[] PROGMEM = "ip"; +const char S_I_FACTOR[] PROGMEM = "i_factor"; +const char S_K_FACTOR[] PROGMEM = "k_factor"; +const char S_LOGIN[] PROGMEM = "login"; +const char S_LOG_LEVEL[] PROGMEM = "logLevel"; +const char S_MAC[] PROGMEM = "mac"; +const char S_MASTER[] PROGMEM = "master"; +const char S_MAX[] PROGMEM = "max"; +const char S_MAX_FREE_BLOCK[] PROGMEM = "maxFreeBlock"; +const char S_MAX_MODULATION[] PROGMEM = "maxModulation"; +const char S_MAX_POWER[] PROGMEM = "maxPower"; +const char S_MAX_TEMP[] PROGMEM = "maxTemp"; +const char S_MEMBER_ID[] PROGMEM = "memberId"; +const char S_MIN[] PROGMEM = "min"; +const char S_MIN_FREE[] PROGMEM = "minFree"; +const char S_MIN_MAX_FREE_BLOCK[] PROGMEM = "minMaxFreeBlock"; +const char S_MIN_POWER[] PROGMEM = "minPower"; +const char S_MIN_TEMP[] PROGMEM = "minTemp"; +const char S_MODEL[] PROGMEM = "model"; +const char S_MODULATION[] PROGMEM = "modulation"; +const char S_MODULATION_SYNC_WITH_HEATING[] PROGMEM = "modulationSyncWithHeating"; +const char S_MQTT[] PROGMEM = "mqtt"; +const char S_NAME[] PROGMEM = "name"; +const char S_NATIVE_HEATING_CONTROL[] PROGMEM = "nativeHeatingControl"; +const char S_NETWORK[] PROGMEM = "network"; +const char S_N_FACTOR[] PROGMEM = "n_factor"; +const char S_OFFSET[] PROGMEM = "offset"; +const char S_ON_ENABLED_HEATING[] PROGMEM = "onEnabledHeating"; +const char S_ON_FAULT[] PROGMEM = "onFault"; +const char S_ON_LOSS_CONNECTION[] PROGMEM = "onLossConnection"; +const char S_OPENTHERM[] PROGMEM = "opentherm"; +const char S_OUTDOOR_TEMP[] PROGMEM = "outdoorTemp"; +const char S_OUT_GPIO[] PROGMEM = "outGpio"; +const char S_OUTPUT[] PROGMEM = "output"; +const char S_PASSWORD[] PROGMEM = "password"; +const char S_PID[] PROGMEM = "pid"; +const char S_PORT[] PROGMEM = "port"; +const char S_PORTAL[] PROGMEM = "portal"; +const char S_POST_CIRCULATION_TIME[] PROGMEM = "postCirculationTime"; +const char S_POWER[] PROGMEM = "power"; +const char S_PREFIX[] PROGMEM = "prefix"; +const char S_PROTOCOL_VERSION[] PROGMEM = "protocolVersion"; +const char S_PURPOSE[] PROGMEM = "purpose"; +const char S_P_FACTOR[] PROGMEM = "p_factor"; +const char S_REAL_SIZE[] PROGMEM = "realSize"; +const char S_REASON[] PROGMEM = "reason"; +const char S_RESET_DIAGNOSTIC[] PROGMEM = "resetDiagnostic"; +const char S_RESET_FAULT[] PROGMEM = "resetFault"; +const char S_RESET_REASON[] PROGMEM = "resetReason"; +const char S_RESTART[] PROGMEM = "restart"; +const char S_RETURN_TEMP[] PROGMEM = "returnTemp"; +const char S_REV[] PROGMEM = "rev"; +const char S_RSSI[] PROGMEM = "rssi"; +const char S_RX_LED_GPIO[] PROGMEM = "rxLedGpio"; +const char S_SDK[] PROGMEM = "sdk"; +const char S_SENSORS[] PROGMEM = "sensors"; +const char S_SERIAL[] PROGMEM = "serial"; +const char S_SERVER[] PROGMEM = "server"; +const char S_SETTINGS[] PROGMEM = "settings"; +const char S_SIGNAL_QUALITY[] PROGMEM = "signalQuality"; +const char S_SIZE[] PROGMEM = "size"; +const char S_SLAVE[] PROGMEM = "slave"; +const char S_SSID[] PROGMEM = "ssid"; +const char S_STA[] PROGMEM = "sta"; +const char S_STATE[] PROGMEM = "state"; +const char S_STATIC_CONFIG[] PROGMEM = "staticConfig"; +const char S_STATUS_LED_GPIO[] PROGMEM = "statusLedGpio"; +const char S_SUBNET[] PROGMEM = "subnet"; +const char S_SUMMER_WINTER_MODE[] PROGMEM = "summerWinterMode"; +const char S_SYSTEM[] PROGMEM = "system"; +const char S_TARGET[] PROGMEM = "target"; +const char S_TARGET_TEMP[] PROGMEM = "targetTemp"; +const char S_TELNET[] PROGMEM = "telnet"; +const char S_TEMPERATURE[] PROGMEM = "temperature"; +const char S_THRESHOLD_TIME[] PROGMEM = "thresholdTime"; +const char S_TOTAL[] PROGMEM = "total"; +const char S_TRESHOLD_TIME[] PROGMEM = "tresholdTime"; +const char S_TURBO[] PROGMEM = "turbo"; +const char S_TURBO_FACTOR[] PROGMEM = "turboFactor"; +const char S_TYPE[] PROGMEM = "type"; +const char S_T_FACTOR[] PROGMEM = "t_factor"; +const char S_UNIT_SYSTEM[] PROGMEM = "unitSystem"; +const char S_UPTIME[] PROGMEM = "uptime"; +const char S_USE[] PROGMEM = "use"; +const char S_USE_DHCP[] PROGMEM = "useDhcp"; +const char S_USER[] PROGMEM = "user"; +const char S_VALUE[] PROGMEM = "value"; +const char S_VERSION[] PROGMEM = "version"; diff --git a/src/utils.h b/src/utils.h index 9f7f700..0eac8c7 100644 --- a/src/utils.h +++ b/src/utils.h @@ -69,14 +69,14 @@ inline bool isValidTemp(const float value, UnitSystem unit, const float min = 0. float roundf(float value, uint8_t decimals = 2) { if (decimals == 0) { - return (int)(value + 0.5); + return (int)(value + 0.5f); - } else if (abs(value) < 0.00000001) { - return 0.0; + } else if (abs(value) < 0.00000001f) { + return 0.0f; } float multiplier = pow10(decimals); - value += 0.5 / multiplier * (value < 0 ? -1 : 1); + value += 0.5f / multiplier * (value < 0.0f ? -1.0f : 1.0f); return (int)(value * multiplier) / multiplier; } @@ -211,29 +211,29 @@ void arr2str(String& str, T arr[], size_t length) { } void networkSettingsToJson(const NetworkSettings& src, JsonVariant dst) { - dst["hostname"] = src.hostname; + dst[FPSTR(S_HOSTNAME)] = src.hostname; - dst["useDhcp"] = src.useDhcp; - dst["staticConfig"]["ip"] = src.staticConfig.ip; - dst["staticConfig"]["gateway"] = src.staticConfig.gateway; - dst["staticConfig"]["subnet"] = src.staticConfig.subnet; - dst["staticConfig"]["dns"] = src.staticConfig.dns; + dst[FPSTR(S_USE_DHCP)] = src.useDhcp; + dst[FPSTR(S_STATIC_CONFIG)][FPSTR(S_IP)] = src.staticConfig.ip; + dst[FPSTR(S_STATIC_CONFIG)][FPSTR(S_GATEWAY)] = src.staticConfig.gateway; + dst[FPSTR(S_STATIC_CONFIG)][FPSTR(S_SUBNET)] = src.staticConfig.subnet; + dst[FPSTR(S_STATIC_CONFIG)][FPSTR(S_DNS)] = src.staticConfig.dns; - dst["ap"]["ssid"] = src.ap.ssid; - dst["ap"]["password"] = src.ap.password; - dst["ap"]["channel"] = src.ap.channel; + dst[FPSTR(S_AP)][FPSTR(S_SSID)] = src.ap.ssid; + dst[FPSTR(S_AP)][FPSTR(S_PASSWORD)] = src.ap.password; + dst[FPSTR(S_AP)][FPSTR(S_CHANNEL)] = src.ap.channel; - dst["sta"]["ssid"] = src.sta.ssid; - dst["sta"]["password"] = src.sta.password; - dst["sta"]["channel"] = src.sta.channel; + dst[FPSTR(S_STA)][FPSTR(S_SSID)] = src.sta.ssid; + dst[FPSTR(S_STA)][FPSTR(S_PASSWORD)] = src.sta.password; + dst[FPSTR(S_STA)][FPSTR(S_CHANNEL)] = src.sta.channel; } bool jsonToNetworkSettings(const JsonVariantConst src, NetworkSettings& dst) { bool changed = false; // hostname - if (!src["hostname"].isNull()) { - String value = src["hostname"].as(); + if (!src[FPSTR(S_HOSTNAME)].isNull()) { + String value = src[FPSTR(S_HOSTNAME)].as(); if (value.length() < sizeof(dst.hostname) && !value.equals(dst.hostname)) { strcpy(dst.hostname, value.c_str()); @@ -242,15 +242,15 @@ bool jsonToNetworkSettings(const JsonVariantConst src, NetworkSettings& dst) { } // use dhcp - if (src["useDhcp"].is()) { - dst.useDhcp = src["useDhcp"].as(); + if (src[FPSTR(S_USE_DHCP)].is()) { + dst.useDhcp = src[FPSTR(S_USE_DHCP)].as(); changed = true; } // static config - if (!src["staticConfig"]["ip"].isNull()) { - String value = src["staticConfig"]["ip"].as(); + if (!src[FPSTR(S_STATIC_CONFIG)][FPSTR(S_IP)].isNull()) { + String value = src[FPSTR(S_STATIC_CONFIG)][FPSTR(S_IP)].as(); if (value.length() < sizeof(dst.staticConfig.ip) && !value.equals(dst.staticConfig.ip)) { strcpy(dst.staticConfig.ip, value.c_str()); @@ -258,8 +258,8 @@ bool jsonToNetworkSettings(const JsonVariantConst src, NetworkSettings& dst) { } } - if (!src["staticConfig"]["gateway"].isNull()) { - String value = src["staticConfig"]["gateway"].as(); + if (!src[FPSTR(S_STATIC_CONFIG)][FPSTR(S_GATEWAY)].isNull()) { + String value = src[FPSTR(S_STATIC_CONFIG)][FPSTR(S_GATEWAY)].as(); if (value.length() < sizeof(dst.staticConfig.gateway) && !value.equals(dst.staticConfig.gateway)) { strcpy(dst.staticConfig.gateway, value.c_str()); @@ -267,8 +267,8 @@ bool jsonToNetworkSettings(const JsonVariantConst src, NetworkSettings& dst) { } } - if (!src["staticConfig"]["subnet"].isNull()) { - String value = src["staticConfig"]["subnet"].as(); + if (!src[FPSTR(S_STATIC_CONFIG)][FPSTR(S_SUBNET)].isNull()) { + String value = src[FPSTR(S_STATIC_CONFIG)][FPSTR(S_SUBNET)].as(); if (value.length() < sizeof(dst.staticConfig.subnet) && !value.equals(dst.staticConfig.subnet)) { strcpy(dst.staticConfig.subnet, value.c_str()); @@ -276,8 +276,8 @@ bool jsonToNetworkSettings(const JsonVariantConst src, NetworkSettings& dst) { } } - if (!src["staticConfig"]["dns"].isNull()) { - String value = src["staticConfig"]["dns"].as(); + if (!src[FPSTR(S_STATIC_CONFIG)][FPSTR(S_DNS)].isNull()) { + String value = src[FPSTR(S_STATIC_CONFIG)][FPSTR(S_DNS)].as(); if (value.length() < sizeof(dst.staticConfig.dns) && !value.equals(dst.staticConfig.dns)) { strcpy(dst.staticConfig.dns, value.c_str()); @@ -287,8 +287,8 @@ bool jsonToNetworkSettings(const JsonVariantConst src, NetworkSettings& dst) { // ap - if (!src["ap"]["ssid"].isNull()) { - String value = src["ap"]["ssid"].as(); + if (!src[FPSTR(S_AP)][FPSTR(S_SSID)].isNull()) { + String value = src[FPSTR(S_AP)][FPSTR(S_SSID)].as(); if (value.length() < sizeof(dst.ap.ssid) && !value.equals(dst.ap.ssid)) { strcpy(dst.ap.ssid, value.c_str()); @@ -296,8 +296,8 @@ bool jsonToNetworkSettings(const JsonVariantConst src, NetworkSettings& dst) { } } - if (!src["ap"]["password"].isNull()) { - String value = src["ap"]["password"].as(); + if (!src[FPSTR(S_AP)][FPSTR(S_PASSWORD)].isNull()) { + String value = src[FPSTR(S_AP)][FPSTR(S_PASSWORD)].as(); if (value.length() < sizeof(dst.ap.password) && !value.equals(dst.ap.password)) { strcpy(dst.ap.password, value.c_str()); @@ -305,8 +305,8 @@ bool jsonToNetworkSettings(const JsonVariantConst src, NetworkSettings& dst) { } } - if (!src["ap"]["channel"].isNull()) { - unsigned char value = src["ap"]["channel"].as(); + if (!src[FPSTR(S_AP)][FPSTR(S_CHANNEL)].isNull()) { + unsigned char value = src[FPSTR(S_AP)][FPSTR(S_CHANNEL)].as(); if (value >= 0 && value < 12) { dst.ap.channel = value; @@ -316,8 +316,8 @@ bool jsonToNetworkSettings(const JsonVariantConst src, NetworkSettings& dst) { // sta - if (!src["sta"]["ssid"].isNull()) { - String value = src["sta"]["ssid"].as(); + if (!src[FPSTR(S_STA)][FPSTR(S_SSID)].isNull()) { + String value = src[FPSTR(S_STA)][FPSTR(S_SSID)].as(); if (value.length() < sizeof(dst.sta.ssid) && !value.equals(dst.sta.ssid)) { strcpy(dst.sta.ssid, value.c_str()); @@ -325,8 +325,8 @@ bool jsonToNetworkSettings(const JsonVariantConst src, NetworkSettings& dst) { } } - if (!src["sta"]["password"].isNull()) { - String value = src["sta"]["password"].as(); + if (!src[FPSTR(S_STA)][FPSTR(S_PASSWORD)].isNull()) { + String value = src[FPSTR(S_STA)][FPSTR(S_PASSWORD)].as(); if (value.length() < sizeof(dst.sta.password) && !value.equals(dst.sta.password)) { strcpy(dst.sta.password, value.c_str()); @@ -334,8 +334,8 @@ bool jsonToNetworkSettings(const JsonVariantConst src, NetworkSettings& dst) { } } - if (!src["sta"]["channel"].isNull()) { - unsigned char value = src["sta"]["channel"].as(); + if (!src[FPSTR(S_STA)][FPSTR(S_CHANNEL)].isNull()) { + unsigned char value = src[FPSTR(S_STA)][FPSTR(S_CHANNEL)].as(); if (value >= 0 && value < 12) { dst.sta.channel = value; @@ -348,96 +348,113 @@ bool jsonToNetworkSettings(const JsonVariantConst src, NetworkSettings& dst) { void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) { if (!safe) { - dst["system"]["logLevel"] = static_cast(src.system.logLevel); - dst["system"]["serial"]["enable"] = src.system.serial.enabled; - dst["system"]["serial"]["baudrate"] = src.system.serial.baudrate; - dst["system"]["telnet"]["enable"] = src.system.telnet.enabled; - dst["system"]["telnet"]["port"] = src.system.telnet.port; - dst["system"]["unitSystem"] = static_cast(src.system.unitSystem); - dst["system"]["statusLedGpio"] = src.system.statusLedGpio; + auto system = dst[FPSTR(S_SYSTEM)].to(); + system[FPSTR(S_LOG_LEVEL)] = static_cast(src.system.logLevel); - dst["portal"]["auth"] = src.portal.auth; - dst["portal"]["login"] = src.portal.login; - dst["portal"]["password"] = src.portal.password; + auto serial = system[FPSTR(S_SERIAL)].to(); + serial[FPSTR(S_ENABLED)] = src.system.serial.enabled; + serial[FPSTR(S_BAUDRATE)] = src.system.serial.baudrate; - dst["opentherm"]["unitSystem"] = static_cast(src.opentherm.unitSystem); - dst["opentherm"]["inGpio"] = src.opentherm.inGpio; - dst["opentherm"]["outGpio"] = src.opentherm.outGpio; - dst["opentherm"]["rxLedGpio"] = src.opentherm.rxLedGpio; - dst["opentherm"]["memberId"] = src.opentherm.memberId; - dst["opentherm"]["flags"] = src.opentherm.flags; - dst["opentherm"]["maxModulation"] = src.opentherm.maxModulation; - dst["opentherm"]["minPower"] = roundf(src.opentherm.minPower, 2); - dst["opentherm"]["maxPower"] = roundf(src.opentherm.maxPower, 2); - dst["opentherm"]["dhwPresent"] = src.opentherm.dhwPresent; - dst["opentherm"]["summerWinterMode"] = src.opentherm.summerWinterMode; - dst["opentherm"]["heatingCh2Enabled"] = src.opentherm.heatingCh2Enabled; - dst["opentherm"]["heatingCh1ToCh2"] = src.opentherm.heatingCh1ToCh2; - dst["opentherm"]["dhwToCh2"] = src.opentherm.dhwToCh2; - dst["opentherm"]["dhwBlocking"] = src.opentherm.dhwBlocking; - dst["opentherm"]["modulationSyncWithHeating"] = src.opentherm.modulationSyncWithHeating; - dst["opentherm"]["getMinMaxTemp"] = src.opentherm.getMinMaxTemp; - dst["opentherm"]["nativeHeatingControl"] = src.opentherm.nativeHeatingControl; - dst["opentherm"]["immergasFix"] = src.opentherm.immergasFix; + auto telnet = system[FPSTR(S_TELNET)].to(); + telnet[FPSTR(S_ENABLED)] = src.system.telnet.enabled; + telnet[FPSTR(S_PORT)] = src.system.telnet.port; - dst["mqtt"]["enable"] = src.mqtt.enabled; - dst["mqtt"]["server"] = src.mqtt.server; - dst["mqtt"]["port"] = src.mqtt.port; - dst["mqtt"]["user"] = src.mqtt.user; - dst["mqtt"]["password"] = src.mqtt.password; - dst["mqtt"]["prefix"] = src.mqtt.prefix; - dst["mqtt"]["interval"] = src.mqtt.interval; - dst["mqtt"]["homeAssistantDiscovery"] = src.mqtt.homeAssistantDiscovery; + system[FPSTR(S_UNIT_SYSTEM)] = static_cast(src.system.unitSystem); + system[FPSTR(S_STATUS_LED_GPIO)] = src.system.statusLedGpio; - dst["emergency"]["target"] = roundf(src.emergency.target, 2); - dst["emergency"]["tresholdTime"] = src.emergency.tresholdTime; + auto portal = dst[FPSTR(S_PORTAL)].to(); + portal[FPSTR(S_AUTH)] = src.portal.auth; + portal[FPSTR(S_LOGIN)] = src.portal.login; + portal[FPSTR(S_PASSWORD)] = src.portal.password; + + auto opentherm = dst[FPSTR(S_OPENTHERM)].to(); + opentherm[FPSTR(S_UNIT_SYSTEM)] = static_cast(src.opentherm.unitSystem); + opentherm[FPSTR(S_IN_GPIO)] = src.opentherm.inGpio; + opentherm[FPSTR(S_OUT_GPIO)] = src.opentherm.outGpio; + opentherm[FPSTR(S_RX_LED_GPIO)] = src.opentherm.rxLedGpio; + opentherm[FPSTR(S_MEMBER_ID)] = src.opentherm.memberId; + opentherm[FPSTR(S_FLAGS)] = src.opentherm.flags; + opentherm[FPSTR(S_MAX_MODULATION)] = src.opentherm.maxModulation; + opentherm[FPSTR(S_MIN_POWER)] = roundf(src.opentherm.minPower, 2); + opentherm[FPSTR(S_MAX_POWER)] = roundf(src.opentherm.maxPower, 2); + opentherm[FPSTR(S_DHW_PRESENT)] = src.opentherm.dhwPresent; + opentherm[FPSTR(S_SUMMER_WINTER_MODE)] = src.opentherm.summerWinterMode; + opentherm[FPSTR(S_HEATING_CH2_ENABLED)] = src.opentherm.heatingCh2Enabled; + opentherm[FPSTR(S_HEATING_CH1_TO_CH2)] = src.opentherm.heatingCh1ToCh2; + opentherm[FPSTR(S_DHW_TO_CH2)] = src.opentherm.dhwToCh2; + opentherm[FPSTR(S_DHW_BLOCKING)] = src.opentherm.dhwBlocking; + opentherm[FPSTR(S_MODULATION_SYNC_WITH_HEATING)] = src.opentherm.modulationSyncWithHeating; + opentherm[FPSTR(S_GET_MIN_MAX_TEMP)] = src.opentherm.getMinMaxTemp; + opentherm[FPSTR(S_NATIVE_HEATING_CONTROL)] = src.opentherm.nativeHeatingControl; + opentherm[FPSTR(S_IMMERGAS_FIX)] = src.opentherm.immergasFix; + + auto mqtt = dst[FPSTR(S_MQTT)].to(); + mqtt[FPSTR(S_ENABLED)] = src.mqtt.enabled; + mqtt[FPSTR(S_SERVER)] = src.mqtt.server; + mqtt[FPSTR(S_PORT)] = src.mqtt.port; + mqtt[FPSTR(S_USER)] = src.mqtt.user; + mqtt[FPSTR(S_PASSWORD)] = src.mqtt.password; + mqtt[FPSTR(S_PREFIX)] = src.mqtt.prefix; + mqtt[FPSTR(S_INTERVAL)] = src.mqtt.interval; + mqtt[FPSTR(S_HOME_ASSISTANT_DISCOVERY)] = src.mqtt.homeAssistantDiscovery; + + auto emergency = dst[FPSTR(S_EMERGENCY)].to(); + emergency[FPSTR(S_TARGET)] = roundf(src.emergency.target, 2); + emergency[FPSTR(S_TRESHOLD_TIME)] = src.emergency.tresholdTime; } + + auto heating = dst[FPSTR(S_HEATING)].to(); + heating[FPSTR(S_ENABLED)] = src.heating.enabled; + heating[FPSTR(S_TURBO)] = src.heating.turbo; + heating[FPSTR(S_TARGET)] = roundf(src.heating.target, 2); + heating[FPSTR(S_HYSTERESIS)] = roundf(src.heating.hysteresis, 3); + heating[FPSTR(S_TURBO_FACTOR)] = roundf(src.heating.turboFactor, 3); + heating[FPSTR(S_MIN_TEMP)] = src.heating.minTemp; + heating[FPSTR(S_MAX_TEMP)] = src.heating.maxTemp; - dst["heating"]["enable"] = src.heating.enabled; - dst["heating"]["turbo"] = src.heating.turbo; - dst["heating"]["target"] = roundf(src.heating.target, 2); - dst["heating"]["hysteresis"] = roundf(src.heating.hysteresis, 3); - dst["heating"]["turboFactor"] = roundf(src.heating.turboFactor, 3); - dst["heating"]["minTemp"] = src.heating.minTemp; - dst["heating"]["maxTemp"] = src.heating.maxTemp; + auto dhw = dst[FPSTR(S_DHW)].to(); + dhw[FPSTR(S_ENABLED)] = src.dhw.enabled; + dhw[FPSTR(S_TARGET)] = roundf(src.dhw.target, 1); + dhw[FPSTR(S_MIN_TEMP)] = src.dhw.minTemp; + dhw[FPSTR(S_MAX_TEMP)] = src.dhw.maxTemp; - dst["dhw"]["enable"] = src.dhw.enabled; - dst["dhw"]["target"] = roundf(src.dhw.target, 1); - dst["dhw"]["minTemp"] = src.dhw.minTemp; - dst["dhw"]["maxTemp"] = src.dhw.maxTemp; + auto equitherm = dst[FPSTR(S_EQUITHERM)].to(); + equitherm[FPSTR(S_ENABLED)] = src.equitherm.enabled; + equitherm[FPSTR(S_N_FACTOR)] = roundf(src.equitherm.n_factor, 3); + equitherm[FPSTR(S_K_FACTOR)] = roundf(src.equitherm.k_factor, 3); + equitherm[FPSTR(S_T_FACTOR)] = roundf(src.equitherm.t_factor, 3); - dst["equitherm"]["enable"] = src.equitherm.enabled; - dst["equitherm"]["n_factor"] = roundf(src.equitherm.n_factor, 3); - dst["equitherm"]["k_factor"] = roundf(src.equitherm.k_factor, 3); - dst["equitherm"]["t_factor"] = roundf(src.equitherm.t_factor, 3); - - dst["pid"]["enable"] = src.pid.enabled; - dst["pid"]["p_factor"] = roundf(src.pid.p_factor, 3); - dst["pid"]["i_factor"] = roundf(src.pid.i_factor, 4); - dst["pid"]["d_factor"] = roundf(src.pid.d_factor, 1); - dst["pid"]["dt"] = src.pid.dt; - dst["pid"]["minTemp"] = src.pid.minTemp; - dst["pid"]["maxTemp"] = src.pid.maxTemp; + auto pid = dst[FPSTR(S_PID)].to(); + pid[FPSTR(S_ENABLED)] = src.pid.enabled; + pid[FPSTR(S_P_FACTOR)] = roundf(src.pid.p_factor, 3); + pid[FPSTR(S_I_FACTOR)] = roundf(src.pid.i_factor, 4); + pid[FPSTR(S_D_FACTOR)] = roundf(src.pid.d_factor, 1); + pid[FPSTR(S_DT)] = src.pid.dt; + pid[FPSTR(S_MIN_TEMP)] = src.pid.minTemp; + pid[FPSTR(S_MAX_TEMP)] = src.pid.maxTemp; if (!safe) { - dst["externalPump"]["use"] = src.externalPump.use; - dst["externalPump"]["gpio"] = src.externalPump.gpio; - dst["externalPump"]["postCirculationTime"] = roundf(src.externalPump.postCirculationTime / 60, 0); - dst["externalPump"]["antiStuckInterval"] = roundf(src.externalPump.antiStuckInterval / 86400, 0); - dst["externalPump"]["antiStuckTime"] = roundf(src.externalPump.antiStuckTime / 60, 0); + auto externalPump = dst[FPSTR(S_EXTERNAL_PUMP)].to(); + externalPump[FPSTR(S_USE)] = src.externalPump.use; + externalPump[FPSTR(S_GPIO)] = src.externalPump.gpio; + externalPump[FPSTR(S_POST_CIRCULATION_TIME)] = roundf(src.externalPump.postCirculationTime / 60, 0); + externalPump[FPSTR(S_ANTI_STUCK_INTERVAL)] = roundf(src.externalPump.antiStuckInterval / 86400, 0); + externalPump[FPSTR(S_ANTI_STUCK_TIME)] = roundf(src.externalPump.antiStuckTime / 60, 0); - dst["cascadeControl"]["input"]["enable"] = src.cascadeControl.input.enabled; - dst["cascadeControl"]["input"]["gpio"] = src.cascadeControl.input.gpio; - dst["cascadeControl"]["input"]["invertState"] = src.cascadeControl.input.invertState; - dst["cascadeControl"]["input"]["thresholdTime"] = src.cascadeControl.input.thresholdTime; + auto cascadeControlInput = dst[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_INPUT)].to(); + cascadeControlInput[FPSTR(S_ENABLED)] = src.cascadeControl.input.enabled; + cascadeControlInput[FPSTR(S_GPIO)] = src.cascadeControl.input.gpio; + cascadeControlInput[FPSTR(S_INVERT_STATE)] = src.cascadeControl.input.invertState; + cascadeControlInput[FPSTR(S_THRESHOLD_TIME)] = src.cascadeControl.input.thresholdTime; - dst["cascadeControl"]["output"]["enable"] = src.cascadeControl.output.enabled; - dst["cascadeControl"]["output"]["gpio"] = src.cascadeControl.output.gpio; - dst["cascadeControl"]["output"]["invertState"] = src.cascadeControl.output.invertState; - dst["cascadeControl"]["output"]["thresholdTime"] = src.cascadeControl.output.thresholdTime; - dst["cascadeControl"]["output"]["onFault"] = src.cascadeControl.output.onFault; - dst["cascadeControl"]["output"]["onLossConnection"] = src.cascadeControl.output.onLossConnection; - dst["cascadeControl"]["output"]["onEnabledHeating"] = src.cascadeControl.output.onEnabledHeating; + auto cascadeControlOutput = dst[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)].to(); + cascadeControlOutput[FPSTR(S_ENABLED)] = src.cascadeControl.output.enabled; + cascadeControlOutput[FPSTR(S_GPIO)] = src.cascadeControl.output.gpio; + cascadeControlOutput[FPSTR(S_INVERT_STATE)] = src.cascadeControl.output.invertState; + cascadeControlOutput[FPSTR(S_THRESHOLD_TIME)] = src.cascadeControl.output.thresholdTime; + cascadeControlOutput[FPSTR(S_ON_FAULT)] = src.cascadeControl.output.onFault; + cascadeControlOutput[FPSTR(S_ON_LOSS_CONNECTION)] = src.cascadeControl.output.onLossConnection; + cascadeControlOutput[FPSTR(S_ON_ENABLED_HEATING)] = src.cascadeControl.output.onEnabledHeating; } } @@ -450,8 +467,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false if (!safe) { // system - if (!src["system"]["logLevel"].isNull()) { - uint8_t value = src["system"]["logLevel"].as(); + if (!src[FPSTR(S_SYSTEM)][FPSTR(S_LOG_LEVEL)].isNull()) { + uint8_t value = src[FPSTR(S_SYSTEM)][FPSTR(S_LOG_LEVEL)].as(); if (value != dst.system.logLevel && value >= TinyLogger::Level::SILENT && value <= TinyLogger::Level::VERBOSE) { dst.system.logLevel = value; @@ -459,8 +476,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["system"]["serial"]["enable"].is()) { - bool value = src["system"]["serial"]["enable"].as(); + if (src[FPSTR(S_SYSTEM)][FPSTR(S_SERIAL)][FPSTR(S_ENABLED)].is()) { + bool value = src[FPSTR(S_SYSTEM)][FPSTR(S_SERIAL)][FPSTR(S_ENABLED)].as(); if (value != dst.system.serial.enabled) { dst.system.serial.enabled = value; @@ -468,8 +485,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["system"]["serial"]["baudrate"].isNull()) { - unsigned int value = src["system"]["serial"]["baudrate"].as(); + if (!src[FPSTR(S_SYSTEM)][FPSTR(S_SERIAL)][FPSTR(S_BAUDRATE)].isNull()) { + unsigned int value = src[FPSTR(S_SYSTEM)][FPSTR(S_SERIAL)][FPSTR(S_BAUDRATE)].as(); if (value == 9600 || value == 19200 || value == 38400 || value == 57600 || value == 74880 || value == 115200) { if (value != dst.system.serial.baudrate) { @@ -479,8 +496,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["system"]["telnet"]["enable"].is()) { - bool value = src["system"]["telnet"]["enable"].as(); + if (src[FPSTR(S_SYSTEM)][FPSTR(S_TELNET)][FPSTR(S_ENABLED)].is()) { + bool value = src[FPSTR(S_SYSTEM)][FPSTR(S_TELNET)][FPSTR(S_ENABLED)].as(); if (value != dst.system.telnet.enabled) { dst.system.telnet.enabled = value; @@ -488,8 +505,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["system"]["telnet"]["port"].isNull()) { - unsigned short value = src["system"]["telnet"]["port"].as(); + if (!src[FPSTR(S_SYSTEM)][FPSTR(S_TELNET)][FPSTR(S_PORT)].isNull()) { + unsigned short value = src[FPSTR(S_SYSTEM)][FPSTR(S_TELNET)][FPSTR(S_PORT)].as(); if (value > 0 && value <= 65535 && value != dst.system.telnet.port) { dst.system.telnet.port = value; @@ -497,8 +514,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["system"]["unitSystem"].isNull()) { - uint8_t value = src["system"]["unitSystem"].as(); + if (!src[FPSTR(S_SYSTEM)][FPSTR(S_UNIT_SYSTEM)].isNull()) { + uint8_t value = src[FPSTR(S_SYSTEM)][FPSTR(S_UNIT_SYSTEM)].as(); UnitSystem prevUnitSystem = dst.system.unitSystem; switch (value) { @@ -534,15 +551,15 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["system"]["statusLedGpio"].isNull()) { - if (src["system"]["statusLedGpio"].is() && src["system"]["statusLedGpio"].as().size() == 0) { + if (!src[FPSTR(S_SYSTEM)][FPSTR(S_STATUS_LED_GPIO)].isNull()) { + if (src[FPSTR(S_SYSTEM)][FPSTR(S_STATUS_LED_GPIO)].is() && src[FPSTR(S_SYSTEM)][FPSTR(S_STATUS_LED_GPIO)].as().size() == 0) { if (dst.system.statusLedGpio != GPIO_IS_NOT_CONFIGURED) { dst.system.statusLedGpio = GPIO_IS_NOT_CONFIGURED; changed = true; } } else { - unsigned char value = src["system"]["statusLedGpio"].as(); + unsigned char value = src[FPSTR(S_SYSTEM)][FPSTR(S_STATUS_LED_GPIO)].as(); if (GPIO_IS_VALID(value) && value != dst.system.statusLedGpio) { dst.system.statusLedGpio = value; @@ -553,8 +570,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false // portal - if (src["portal"]["auth"].is()) { - bool value = src["portal"]["auth"].as(); + if (src[FPSTR(S_PORTAL)][FPSTR(S_AUTH)].is()) { + bool value = src[FPSTR(S_PORTAL)][FPSTR(S_AUTH)].as(); if (value != dst.portal.auth) { dst.portal.auth = value; @@ -562,8 +579,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["portal"]["login"].isNull()) { - String value = src["portal"]["login"].as(); + if (!src[FPSTR(S_PORTAL)][FPSTR(S_LOGIN)].isNull()) { + String value = src[FPSTR(S_PORTAL)][FPSTR(S_LOGIN)].as(); if (value.length() < sizeof(dst.portal.login) && !value.equals(dst.portal.login)) { strcpy(dst.portal.login, value.c_str()); @@ -571,8 +588,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["portal"]["password"].isNull()) { - String value = src["portal"]["password"].as(); + if (!src[FPSTR(S_PORTAL)][FPSTR(S_PASSWORD)].isNull()) { + String value = src[FPSTR(S_PORTAL)][FPSTR(S_PASSWORD)].as(); if (value.length() < sizeof(dst.portal.password) && !value.equals(dst.portal.password)) { strcpy(dst.portal.password, value.c_str()); @@ -582,8 +599,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false // opentherm - if (!src["opentherm"]["unitSystem"].isNull()) { - uint8_t value = src["opentherm"]["unitSystem"].as(); + if (!src[FPSTR(S_OPENTHERM)][FPSTR(S_UNIT_SYSTEM)].isNull()) { + uint8_t value = src[FPSTR(S_OPENTHERM)][FPSTR(S_UNIT_SYSTEM)].as(); switch (value) { case static_cast(UnitSystem::METRIC): @@ -605,15 +622,15 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["opentherm"]["inGpio"].isNull()) { - if (src["opentherm"]["inGpio"].is() && src["opentherm"]["inGpio"].as().size() == 0) { + if (!src[FPSTR(S_OPENTHERM)][FPSTR(S_IN_GPIO)].isNull()) { + if (src[FPSTR(S_OPENTHERM)][FPSTR(S_IN_GPIO)].is() && src[FPSTR(S_OPENTHERM)][FPSTR(S_IN_GPIO)].as().size() == 0) { if (dst.opentherm.inGpio != GPIO_IS_NOT_CONFIGURED) { dst.opentherm.inGpio = GPIO_IS_NOT_CONFIGURED; changed = true; } } else { - unsigned char value = src["opentherm"]["inGpio"].as(); + unsigned char value = src[FPSTR(S_OPENTHERM)][FPSTR(S_IN_GPIO)].as(); if (GPIO_IS_VALID(value) && value != dst.opentherm.inGpio) { dst.opentherm.inGpio = value; @@ -622,15 +639,15 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["opentherm"]["outGpio"].isNull()) { - if (src["opentherm"]["outGpio"].is() && src["opentherm"]["outGpio"].as().size() == 0) { + if (!src[FPSTR(S_OPENTHERM)][FPSTR(S_OUT_GPIO)].isNull()) { + if (src[FPSTR(S_OPENTHERM)][FPSTR(S_OUT_GPIO)].is() && src[FPSTR(S_OPENTHERM)][FPSTR(S_OUT_GPIO)].as().size() == 0) { if (dst.opentherm.outGpio != GPIO_IS_NOT_CONFIGURED) { dst.opentherm.outGpio = GPIO_IS_NOT_CONFIGURED; changed = true; } } else { - unsigned char value = src["opentherm"]["outGpio"].as(); + unsigned char value = src[FPSTR(S_OPENTHERM)][FPSTR(S_OUT_GPIO)].as(); if (GPIO_IS_VALID(value) && value != dst.opentherm.outGpio) { dst.opentherm.outGpio = value; @@ -639,15 +656,15 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["opentherm"]["rxLedGpio"].isNull()) { - if (src["opentherm"]["rxLedGpio"].is() && src["opentherm"]["rxLedGpio"].as().size() == 0) { + if (!src[FPSTR(S_OPENTHERM)][FPSTR(S_RX_LED_GPIO)].isNull()) { + if (src[FPSTR(S_OPENTHERM)][FPSTR(S_RX_LED_GPIO)].is() && src[FPSTR(S_OPENTHERM)][FPSTR(S_RX_LED_GPIO)].as().size() == 0) { if (dst.opentherm.rxLedGpio != GPIO_IS_NOT_CONFIGURED) { dst.opentherm.rxLedGpio = GPIO_IS_NOT_CONFIGURED; changed = true; } } else { - unsigned char value = src["opentherm"]["rxLedGpio"].as(); + unsigned char value = src[FPSTR(S_OPENTHERM)][FPSTR(S_RX_LED_GPIO)].as(); if (GPIO_IS_VALID(value) && value != dst.opentherm.rxLedGpio) { dst.opentherm.rxLedGpio = value; @@ -656,8 +673,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["opentherm"]["memberId"].isNull()) { - auto value = src["opentherm"]["memberId"].as(); + if (!src[FPSTR(S_OPENTHERM)][FPSTR(S_MEMBER_ID)].isNull()) { + auto value = src[FPSTR(S_OPENTHERM)][FPSTR(S_MEMBER_ID)].as(); if (value != dst.opentherm.memberId) { dst.opentherm.memberId = value; @@ -665,8 +682,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["opentherm"]["flags"].isNull()) { - auto value = src["opentherm"]["flags"].as(); + if (!src[FPSTR(S_OPENTHERM)][FPSTR(S_FLAGS)].isNull()) { + auto value = src[FPSTR(S_OPENTHERM)][FPSTR(S_FLAGS)].as(); if (value != dst.opentherm.flags) { dst.opentherm.flags = value; @@ -674,8 +691,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["opentherm"]["maxModulation"].isNull()) { - unsigned char value = src["opentherm"]["maxModulation"].as(); + if (!src[FPSTR(S_OPENTHERM)][FPSTR(S_MAX_MODULATION)].isNull()) { + unsigned char value = src[FPSTR(S_OPENTHERM)][FPSTR(S_MAX_MODULATION)].as(); if (value > 0 && value <= 100 && value != dst.opentherm.maxModulation) { dst.opentherm.maxModulation = value; @@ -683,8 +700,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["opentherm"]["minPower"].isNull()) { - float value = src["opentherm"]["minPower"].as(); + if (!src[FPSTR(S_OPENTHERM)][FPSTR(S_MIN_POWER)].isNull()) { + float value = src[FPSTR(S_OPENTHERM)][FPSTR(S_MIN_POWER)].as(); if (value >= 0 && value <= 1000 && fabsf(value - dst.opentherm.minPower) > 0.0001f) { dst.opentherm.minPower = roundf(value, 2); @@ -692,8 +709,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["opentherm"]["maxPower"].isNull()) { - float value = src["opentherm"]["maxPower"].as(); + if (!src[FPSTR(S_OPENTHERM)][FPSTR(S_MAX_POWER)].isNull()) { + float value = src[FPSTR(S_OPENTHERM)][FPSTR(S_MAX_POWER)].as(); if (value >= 0 && value <= 1000 && fabsf(value - dst.opentherm.maxPower) > 0.0001f) { dst.opentherm.maxPower = roundf(value, 2); @@ -701,8 +718,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["opentherm"]["dhwPresent"].is()) { - bool value = src["opentherm"]["dhwPresent"].as(); + if (src[FPSTR(S_OPENTHERM)][FPSTR(S_DHW_PRESENT)].is()) { + bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_DHW_PRESENT)].as(); if (value != dst.opentherm.dhwPresent) { dst.opentherm.dhwPresent = value; @@ -710,8 +727,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["opentherm"]["summerWinterMode"].is()) { - bool value = src["opentherm"]["summerWinterMode"].as(); + if (src[FPSTR(S_OPENTHERM)][FPSTR(S_SUMMER_WINTER_MODE)].is()) { + bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_SUMMER_WINTER_MODE)].as(); if (value != dst.opentherm.summerWinterMode) { dst.opentherm.summerWinterMode = value; @@ -719,8 +736,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["opentherm"]["heatingCh2Enabled"].is()) { - bool value = src["opentherm"]["heatingCh2Enabled"].as(); + if (src[FPSTR(S_OPENTHERM)][FPSTR(S_HEATING_CH2_ENABLED)].is()) { + bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_HEATING_CH2_ENABLED)].as(); if (value != dst.opentherm.heatingCh2Enabled) { dst.opentherm.heatingCh2Enabled = value; @@ -734,8 +751,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["opentherm"]["heatingCh1ToCh2"].is()) { - bool value = src["opentherm"]["heatingCh1ToCh2"].as(); + if (src[FPSTR(S_OPENTHERM)][FPSTR(S_HEATING_CH1_TO_CH2)].is()) { + bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_HEATING_CH1_TO_CH2)].as(); if (value != dst.opentherm.heatingCh1ToCh2) { dst.opentherm.heatingCh1ToCh2 = value; @@ -749,8 +766,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["opentherm"]["dhwToCh2"].is()) { - bool value = src["opentherm"]["dhwToCh2"].as(); + if (src[FPSTR(S_OPENTHERM)][FPSTR(S_DHW_TO_CH2)].is()) { + bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_DHW_TO_CH2)].as(); if (value != dst.opentherm.dhwToCh2) { dst.opentherm.dhwToCh2 = value; @@ -764,8 +781,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["opentherm"]["dhwBlocking"].is()) { - bool value = src["opentherm"]["dhwBlocking"].as(); + if (src[FPSTR(S_OPENTHERM)][FPSTR(S_DHW_BLOCKING)].is()) { + bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_DHW_BLOCKING)].as(); if (value != dst.opentherm.dhwBlocking) { dst.opentherm.dhwBlocking = value; @@ -773,8 +790,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["opentherm"]["modulationSyncWithHeating"].is()) { - bool value = src["opentherm"]["modulationSyncWithHeating"].as(); + if (src[FPSTR(S_OPENTHERM)][FPSTR(S_MODULATION_SYNC_WITH_HEATING)].is()) { + bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_MODULATION_SYNC_WITH_HEATING)].as(); if (value != dst.opentherm.modulationSyncWithHeating) { dst.opentherm.modulationSyncWithHeating = value; @@ -782,8 +799,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["opentherm"]["getMinMaxTemp"].is()) { - bool value = src["opentherm"]["getMinMaxTemp"].as(); + if (src[FPSTR(S_OPENTHERM)][FPSTR(S_GET_MIN_MAX_TEMP)].is()) { + bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_GET_MIN_MAX_TEMP)].as(); if (value != dst.opentherm.getMinMaxTemp) { dst.opentherm.getMinMaxTemp = value; @@ -791,8 +808,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["opentherm"]["nativeHeatingControl"].is()) { - bool value = src["opentherm"]["nativeHeatingControl"].as(); + if (src[FPSTR(S_OPENTHERM)][FPSTR(S_NATIVE_HEATING_CONTROL)].is()) { + bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_NATIVE_HEATING_CONTROL)].as(); if (value != dst.opentherm.nativeHeatingControl) { dst.opentherm.nativeHeatingControl = value; @@ -806,8 +823,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["opentherm"]["immergasFix"].is()) { - bool value = src["opentherm"]["immergasFix"].as(); + if (src[FPSTR(S_OPENTHERM)][FPSTR(S_IMMERGAS_FIX)].is()) { + bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_IMMERGAS_FIX)].as(); if (value != dst.opentherm.immergasFix) { dst.opentherm.immergasFix = value; @@ -817,8 +834,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false // mqtt - if (src["mqtt"]["enable"].is()) { - bool value = src["mqtt"]["enable"].as(); + if (src[FPSTR(S_MQTT)][FPSTR(S_ENABLED)].is()) { + bool value = src[FPSTR(S_MQTT)][FPSTR(S_ENABLED)].as(); if (value != dst.mqtt.enabled) { dst.mqtt.enabled = value; @@ -826,8 +843,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["mqtt"]["server"].isNull()) { - String value = src["mqtt"]["server"].as(); + if (!src[FPSTR(S_MQTT)][FPSTR(S_SERVER)].isNull()) { + String value = src[FPSTR(S_MQTT)][FPSTR(S_SERVER)].as(); if (value.length() < sizeof(dst.mqtt.server) && !value.equals(dst.mqtt.server)) { strcpy(dst.mqtt.server, value.c_str()); @@ -835,8 +852,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["mqtt"]["port"].isNull()) { - unsigned short value = src["mqtt"]["port"].as(); + if (!src[FPSTR(S_MQTT)][FPSTR(S_PORT)].isNull()) { + unsigned short value = src[FPSTR(S_MQTT)][FPSTR(S_PORT)].as(); if (value > 0 && value <= 65535 && value != dst.mqtt.port) { dst.mqtt.port = value; @@ -844,8 +861,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["mqtt"]["user"].isNull()) { - String value = src["mqtt"]["user"].as(); + if (!src[FPSTR(S_MQTT)][FPSTR(S_USER)].isNull()) { + String value = src[FPSTR(S_MQTT)][FPSTR(S_USER)].as(); if (value.length() < sizeof(dst.mqtt.user) && !value.equals(dst.mqtt.user)) { strcpy(dst.mqtt.user, value.c_str()); @@ -853,8 +870,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["mqtt"]["password"].isNull()) { - String value = src["mqtt"]["password"].as(); + if (!src[FPSTR(S_MQTT)][FPSTR(S_PASSWORD)].isNull()) { + String value = src[FPSTR(S_MQTT)][FPSTR(S_PASSWORD)].as(); if (value.length() < sizeof(dst.mqtt.password) && !value.equals(dst.mqtt.password)) { strcpy(dst.mqtt.password, value.c_str()); @@ -862,8 +879,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["mqtt"]["prefix"].isNull()) { - String value = src["mqtt"]["prefix"].as(); + if (!src[FPSTR(S_MQTT)][FPSTR(S_PREFIX)].isNull()) { + String value = src[FPSTR(S_MQTT)][FPSTR(S_PREFIX)].as(); if (value.length() < sizeof(dst.mqtt.prefix) && !value.equals(dst.mqtt.prefix)) { strcpy(dst.mqtt.prefix, value.c_str()); @@ -871,8 +888,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["mqtt"]["interval"].isNull()) { - unsigned short value = src["mqtt"]["interval"].as(); + if (!src[FPSTR(S_MQTT)][FPSTR(S_INTERVAL)].isNull()) { + unsigned short value = src[FPSTR(S_MQTT)][FPSTR(S_INTERVAL)].as(); if (value >= 3 && value <= 60 && value != dst.mqtt.interval) { dst.mqtt.interval = value; @@ -880,8 +897,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["mqtt"]["homeAssistantDiscovery"].is()) { - bool value = src["mqtt"]["homeAssistantDiscovery"].as(); + if (src[FPSTR(S_MQTT)][FPSTR(S_HOME_ASSISTANT_DISCOVERY)].is()) { + bool value = src[FPSTR(S_MQTT)][FPSTR(S_HOME_ASSISTANT_DISCOVERY)].as(); if (value != dst.mqtt.homeAssistantDiscovery) { dst.mqtt.homeAssistantDiscovery = value; @@ -891,8 +908,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false // emergency - if (!src["emergency"]["tresholdTime"].isNull()) { - unsigned short value = src["emergency"]["tresholdTime"].as(); + if (!src[FPSTR(S_EMERGENCY)][FPSTR(S_TRESHOLD_TIME)].isNull()) { + unsigned short value = src[FPSTR(S_EMERGENCY)][FPSTR(S_TRESHOLD_TIME)].as(); if (value >= 60 && value <= 1800 && value != dst.emergency.tresholdTime) { dst.emergency.tresholdTime = value; @@ -903,8 +920,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false // equitherm - if (src["equitherm"]["enable"].is()) { - bool value = src["equitherm"]["enable"].as(); + if (src[FPSTR(S_EQUITHERM)][FPSTR(S_ENABLED)].is()) { + bool value = src[FPSTR(S_EQUITHERM)][FPSTR(S_ENABLED)].as(); if (!dst.opentherm.nativeHeatingControl) { if (value != dst.equitherm.enabled) { @@ -918,8 +935,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["equitherm"]["n_factor"].isNull()) { - float value = src["equitherm"]["n_factor"].as(); + if (!src[FPSTR(S_EQUITHERM)][FPSTR(S_N_FACTOR)].isNull()) { + float value = src[FPSTR(S_EQUITHERM)][FPSTR(S_N_FACTOR)].as(); if (value > 0 && value <= 10 && fabsf(value - dst.equitherm.n_factor) > 0.0001f) { dst.equitherm.n_factor = roundf(value, 3); @@ -927,8 +944,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["equitherm"]["k_factor"].isNull()) { - float value = src["equitherm"]["k_factor"].as(); + if (!src[FPSTR(S_EQUITHERM)][FPSTR(S_K_FACTOR)].isNull()) { + float value = src[FPSTR(S_EQUITHERM)][FPSTR(S_K_FACTOR)].as(); if (value >= 0 && value <= 10 && fabsf(value - dst.equitherm.k_factor) > 0.0001f) { dst.equitherm.k_factor = roundf(value, 3); @@ -936,8 +953,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["equitherm"]["t_factor"].isNull()) { - float value = src["equitherm"]["t_factor"].as(); + if (!src[FPSTR(S_EQUITHERM)][FPSTR(S_T_FACTOR)].isNull()) { + float value = src[FPSTR(S_EQUITHERM)][FPSTR(S_T_FACTOR)].as(); if (value >= 0 && value <= 10 && fabsf(value - dst.equitherm.t_factor) > 0.0001f) { dst.equitherm.t_factor = roundf(value, 3); @@ -947,8 +964,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false // pid - if (src["pid"]["enable"].is()) { - bool value = src["pid"]["enable"].as(); + if (src[FPSTR(S_PID)][FPSTR(S_ENABLED)].is()) { + bool value = src[FPSTR(S_PID)][FPSTR(S_ENABLED)].as(); if (!dst.opentherm.nativeHeatingControl) { if (value != dst.pid.enabled) { @@ -962,8 +979,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["pid"]["p_factor"].isNull()) { - float value = src["pid"]["p_factor"].as(); + if (!src[FPSTR(S_PID)][FPSTR(S_P_FACTOR)].isNull()) { + float value = src[FPSTR(S_PID)][FPSTR(S_P_FACTOR)].as(); if (value > 0 && value <= 1000 && fabsf(value - dst.pid.p_factor) > 0.0001f) { dst.pid.p_factor = roundf(value, 3); @@ -971,8 +988,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["pid"]["i_factor"].isNull()) { - float value = src["pid"]["i_factor"].as(); + if (!src[FPSTR(S_PID)][FPSTR(S_I_FACTOR)].isNull()) { + float value = src[FPSTR(S_PID)][FPSTR(S_I_FACTOR)].as(); if (value >= 0 && value <= 100 && fabsf(value - dst.pid.i_factor) > 0.0001f) { dst.pid.i_factor = roundf(value, 4); @@ -980,8 +997,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["pid"]["d_factor"].isNull()) { - float value = src["pid"]["d_factor"].as(); + if (!src[FPSTR(S_PID)][FPSTR(S_D_FACTOR)].isNull()) { + float value = src[FPSTR(S_PID)][FPSTR(S_D_FACTOR)].as(); if (value >= 0 && value <= 100000 && fabsf(value - dst.pid.d_factor) > 0.0001f) { dst.pid.d_factor = roundf(value, 1); @@ -989,8 +1006,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["pid"]["dt"].isNull()) { - unsigned short value = src["pid"]["dt"].as(); + if (!src[FPSTR(S_PID)][FPSTR(S_DT)].isNull()) { + unsigned short value = src[FPSTR(S_PID)][FPSTR(S_DT)].as(); if (value >= 30 && value <= 1800 && value != dst.pid.dt) { dst.pid.dt = value; @@ -998,8 +1015,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["pid"]["minTemp"].isNull()) { - short value = src["pid"]["minTemp"].as(); + if (!src[FPSTR(S_PID)][FPSTR(S_MIN_TEMP)].isNull()) { + short value = src[FPSTR(S_PID)][FPSTR(S_MIN_TEMP)].as(); if (isValidTemp(value, dst.system.unitSystem, dst.equitherm.enabled ? -99.9f : 0.0f) && value != dst.pid.minTemp) { dst.pid.minTemp = value; @@ -1007,8 +1024,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["pid"]["maxTemp"].isNull()) { - short value = src["pid"]["maxTemp"].as(); + if (!src[FPSTR(S_PID)][FPSTR(S_MAX_TEMP)].isNull()) { + short value = src[FPSTR(S_PID)][FPSTR(S_MAX_TEMP)].as(); if (isValidTemp(value, dst.system.unitSystem) && value != dst.pid.maxTemp) { dst.pid.maxTemp = value; @@ -1023,8 +1040,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false // heating - if (src["heating"]["enable"].is()) { - bool value = src["heating"]["enable"].as(); + if (src[FPSTR(S_HEATING)][FPSTR(S_ENABLED)].is()) { + bool value = src[FPSTR(S_HEATING)][FPSTR(S_ENABLED)].as(); if (value != dst.heating.enabled) { dst.heating.enabled = value; @@ -1032,8 +1049,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["heating"]["turbo"].is()) { - bool value = src["heating"]["turbo"].as(); + if (src[FPSTR(S_HEATING)][FPSTR(S_TURBO)].is()) { + bool value = src[FPSTR(S_HEATING)][FPSTR(S_TURBO)].as(); if (value != dst.heating.turbo) { dst.heating.turbo = value; @@ -1041,8 +1058,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["heating"]["hysteresis"].isNull()) { - float value = src["heating"]["hysteresis"].as(); + if (!src[FPSTR(S_HEATING)][FPSTR(S_HYSTERESIS)].isNull()) { + float value = src[FPSTR(S_HEATING)][FPSTR(S_HYSTERESIS)].as(); if (value >= 0.0f && value <= 15.0f && fabsf(value - dst.heating.hysteresis) > 0.0001f) { dst.heating.hysteresis = roundf(value, 2); @@ -1050,8 +1067,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["heating"]["turboFactor"].isNull()) { - float value = src["heating"]["turboFactor"].as(); + if (!src[FPSTR(S_HEATING)][FPSTR(S_TURBO_FACTOR)].isNull()) { + float value = src[FPSTR(S_HEATING)][FPSTR(S_TURBO_FACTOR)].as(); if (value >= 1.5f && value <= 10.0f && fabsf(value - dst.heating.turboFactor) > 0.0001f) { dst.heating.turboFactor = roundf(value, 3); @@ -1059,8 +1076,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["heating"]["minTemp"].isNull()) { - unsigned char value = src["heating"]["minTemp"].as(); + if (!src[FPSTR(S_HEATING)][FPSTR(S_MIN_TEMP)].isNull()) { + unsigned char value = src[FPSTR(S_HEATING)][FPSTR(S_MIN_TEMP)].as(); if (value != dst.heating.minTemp && value >= vars.slave.heating.minTemp && value < vars.slave.heating.maxTemp && value != dst.heating.minTemp) { dst.heating.minTemp = value; @@ -1068,8 +1085,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["heating"]["maxTemp"].isNull()) { - unsigned char value = src["heating"]["maxTemp"].as(); + if (!src[FPSTR(S_HEATING)][FPSTR(S_MAX_TEMP)].isNull()) { + unsigned char value = src[FPSTR(S_HEATING)][FPSTR(S_MAX_TEMP)].as(); if (value != dst.heating.maxTemp && value > vars.slave.heating.minTemp && value <= vars.slave.heating.maxTemp && value != dst.heating.maxTemp) { dst.heating.maxTemp = value; @@ -1084,8 +1101,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false // dhw - if (src["dhw"]["enable"].is()) { - bool value = src["dhw"]["enable"].as(); + if (src[FPSTR(S_DHW)][FPSTR(S_ENABLED)].is()) { + bool value = src[FPSTR(S_DHW)][FPSTR(S_ENABLED)].as(); if (value != dst.dhw.enabled) { dst.dhw.enabled = value; @@ -1093,8 +1110,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["dhw"]["minTemp"].isNull()) { - unsigned char value = src["dhw"]["minTemp"].as(); + if (!src[FPSTR(S_DHW)][FPSTR(S_MIN_TEMP)].isNull()) { + unsigned char value = src[FPSTR(S_DHW)][FPSTR(S_MIN_TEMP)].as(); if (value >= vars.slave.dhw.minTemp && value < vars.slave.dhw.maxTemp && value != dst.dhw.minTemp) { dst.dhw.minTemp = value; @@ -1102,8 +1119,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["dhw"]["maxTemp"].isNull()) { - unsigned char value = src["dhw"]["maxTemp"].as(); + if (!src[FPSTR(S_DHW)][FPSTR(S_MAX_TEMP)].isNull()) { + unsigned char value = src[FPSTR(S_DHW)][FPSTR(S_MAX_TEMP)].as(); if (value > vars.slave.dhw.minTemp && value <= vars.slave.dhw.maxTemp && value != dst.dhw.maxTemp) { dst.dhw.maxTemp = value; @@ -1119,8 +1136,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false if (!safe) { // external pump - if (src["externalPump"]["use"].is()) { - bool value = src["externalPump"]["use"].as(); + if (src[FPSTR(S_EXTERNAL_PUMP)][FPSTR(S_USE)].is()) { + bool value = src[FPSTR(S_EXTERNAL_PUMP)][FPSTR(S_USE)].as(); if (value != dst.externalPump.use) { dst.externalPump.use = value; @@ -1128,15 +1145,15 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["externalPump"]["gpio"].isNull()) { - if (src["externalPump"]["gpio"].is() && src["externalPump"]["gpio"].as().size() == 0) { + if (!src[FPSTR(S_EXTERNAL_PUMP)][FPSTR(S_GPIO)].isNull()) { + if (src[FPSTR(S_EXTERNAL_PUMP)][FPSTR(S_GPIO)].is() && src[FPSTR(S_EXTERNAL_PUMP)][FPSTR(S_GPIO)].as().size() == 0) { if (dst.externalPump.gpio != GPIO_IS_NOT_CONFIGURED) { dst.externalPump.gpio = GPIO_IS_NOT_CONFIGURED; changed = true; } } else { - unsigned char value = src["externalPump"]["gpio"].as(); + unsigned char value = src[FPSTR(S_EXTERNAL_PUMP)][FPSTR(S_GPIO)].as(); if (GPIO_IS_VALID(value) && value != dst.externalPump.gpio) { dst.externalPump.gpio = value; @@ -1145,8 +1162,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["externalPump"]["postCirculationTime"].isNull()) { - unsigned short value = src["externalPump"]["postCirculationTime"].as(); + if (!src[FPSTR(S_EXTERNAL_PUMP)][FPSTR(S_POST_CIRCULATION_TIME)].isNull()) { + unsigned short value = src[FPSTR(S_EXTERNAL_PUMP)][FPSTR(S_POST_CIRCULATION_TIME)].as(); if (value >= 0 && value <= 120) { value = value * 60; @@ -1158,8 +1175,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["externalPump"]["antiStuckInterval"].isNull()) { - unsigned int value = src["externalPump"]["antiStuckInterval"].as(); + if (!src[FPSTR(S_EXTERNAL_PUMP)][FPSTR(S_ANTI_STUCK_INTERVAL)].isNull()) { + unsigned int value = src[FPSTR(S_EXTERNAL_PUMP)][FPSTR(S_ANTI_STUCK_INTERVAL)].as(); if (value >= 0 && value <= 366) { value = value * 86400; @@ -1171,8 +1188,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["externalPump"]["antiStuckTime"].isNull()) { - unsigned short value = src["externalPump"]["antiStuckTime"].as(); + if (!src[FPSTR(S_EXTERNAL_PUMP)][FPSTR(S_ANTI_STUCK_TIME)].isNull()) { + unsigned short value = src[FPSTR(S_EXTERNAL_PUMP)][FPSTR(S_ANTI_STUCK_TIME)].as(); if (value >= 0 && value <= 20) { value = value * 60; @@ -1186,8 +1203,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false // cascade control - if (src["cascadeControl"]["input"]["enable"].is()) { - bool value = src["cascadeControl"]["input"]["enable"].as(); + if (src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_INPUT)][FPSTR(S_ENABLED)].is()) { + bool value = src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_INPUT)][FPSTR(S_ENABLED)].as(); if (value != dst.cascadeControl.input.enabled) { dst.cascadeControl.input.enabled = value; @@ -1195,15 +1212,15 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["cascadeControl"]["input"]["gpio"].isNull()) { - if (src["cascadeControl"]["input"]["gpio"].is() && src["cascadeControl"]["input"]["gpio"].as().size() == 0) { + if (!src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_INPUT)][FPSTR(S_GPIO)].isNull()) { + if (src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_INPUT)][FPSTR(S_GPIO)].is() && src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_INPUT)][FPSTR(S_GPIO)].as().size() == 0) { if (dst.cascadeControl.input.gpio != GPIO_IS_NOT_CONFIGURED) { dst.cascadeControl.input.gpio = GPIO_IS_NOT_CONFIGURED; changed = true; } } else { - unsigned char value = src["cascadeControl"]["input"]["gpio"].as(); + unsigned char value = src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_INPUT)][FPSTR(S_GPIO)].as(); if (GPIO_IS_VALID(value) && value != dst.cascadeControl.input.gpio) { dst.cascadeControl.input.gpio = value; @@ -1212,8 +1229,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["cascadeControl"]["input"]["invertState"].is()) { - bool value = src["cascadeControl"]["input"]["invertState"].as(); + if (src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_INPUT)][FPSTR(S_INVERT_STATE)].is()) { + bool value = src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_INPUT)][FPSTR(S_INVERT_STATE)].as(); if (value != dst.cascadeControl.input.invertState) { dst.cascadeControl.input.invertState = value; @@ -1221,8 +1238,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["cascadeControl"]["input"]["thresholdTime"].isNull()) { - unsigned short value = src["cascadeControl"]["input"]["thresholdTime"].as(); + if (!src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_INPUT)][FPSTR(S_THRESHOLD_TIME)].isNull()) { + unsigned short value = src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_INPUT)][FPSTR(S_THRESHOLD_TIME)].as(); if (value >= 5 && value <= 600) { if (value != dst.cascadeControl.input.thresholdTime) { @@ -1232,8 +1249,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["cascadeControl"]["output"]["enable"].is()) { - bool value = src["cascadeControl"]["output"]["enable"].as(); + if (src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_ENABLED)].is()) { + bool value = src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_ENABLED)].as(); if (value != dst.cascadeControl.output.enabled) { dst.cascadeControl.output.enabled = value; @@ -1241,15 +1258,15 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["cascadeControl"]["output"]["gpio"].isNull()) { - if (src["cascadeControl"]["output"]["gpio"].is() && src["cascadeControl"]["output"]["gpio"].as().size() == 0) { + if (!src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_GPIO)].isNull()) { + if (src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_GPIO)].is() && src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_GPIO)].as().size() == 0) { if (dst.cascadeControl.output.gpio != GPIO_IS_NOT_CONFIGURED) { dst.cascadeControl.output.gpio = GPIO_IS_NOT_CONFIGURED; changed = true; } } else { - unsigned char value = src["cascadeControl"]["output"]["gpio"].as(); + unsigned char value = src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_GPIO)].as(); if (GPIO_IS_VALID(value) && value != dst.cascadeControl.output.gpio) { dst.cascadeControl.output.gpio = value; @@ -1258,8 +1275,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["cascadeControl"]["output"]["invertState"].is()) { - bool value = src["cascadeControl"]["output"]["invertState"].as(); + if (src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_INVERT_STATE)].is()) { + bool value = src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_INVERT_STATE)].as(); if (value != dst.cascadeControl.output.invertState) { dst.cascadeControl.output.invertState = value; @@ -1267,8 +1284,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src["cascadeControl"]["output"]["thresholdTime"].isNull()) { - unsigned short value = src["cascadeControl"]["output"]["thresholdTime"].as(); + if (!src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_THRESHOLD_TIME)].isNull()) { + unsigned short value = src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_THRESHOLD_TIME)].as(); if (value >= 5 && value <= 600) { if (value != dst.cascadeControl.output.thresholdTime) { @@ -1278,8 +1295,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["cascadeControl"]["output"]["onFault"].is()) { - bool value = src["cascadeControl"]["output"]["onFault"].as(); + if (src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_ON_FAULT)].is()) { + bool value = src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_ON_FAULT)].as(); if (value != dst.cascadeControl.output.onFault) { dst.cascadeControl.output.onFault = value; @@ -1287,8 +1304,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["cascadeControl"]["output"]["onLossConnection"].is()) { - bool value = src["cascadeControl"]["output"]["onLossConnection"].as(); + if (src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_ON_LOSS_CONNECTION)].is()) { + bool value = src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_ON_LOSS_CONNECTION)].as(); if (value != dst.cascadeControl.output.onLossConnection) { dst.cascadeControl.output.onLossConnection = value; @@ -1296,8 +1313,8 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src["cascadeControl"]["output"]["onEnabledHeating"].is()) { - bool value = src["cascadeControl"]["output"]["onEnabledHeating"].as(); + if (src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_ON_ENABLED_HEATING)].is()) { + bool value = src[FPSTR(S_CASCADE_CONTROL)][FPSTR(S_OUTPUT)][FPSTR(S_ON_ENABLED_HEATING)].as(); if (value != dst.cascadeControl.output.onEnabledHeating) { dst.cascadeControl.output.onEnabledHeating = value; @@ -1308,7 +1325,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false // force check emergency target { - float value = !src["emergency"]["target"].isNull() ? src["emergency"]["target"].as() : dst.emergency.target; + float value = !src[FPSTR(S_EMERGENCY)][FPSTR(S_TARGET)].isNull() ? src[FPSTR(S_EMERGENCY)][FPSTR(S_TARGET)].as() : dst.emergency.target; bool noRegulators = !dst.opentherm.nativeHeatingControl; bool valid = isValidTemp( value, @@ -1334,7 +1351,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false // force check heating target { - float value = !src["heating"]["target"].isNull() ? src["heating"]["target"].as() : dst.heating.target; + float value = !src[FPSTR(S_HEATING)][FPSTR(S_TARGET)].isNull() ? src[FPSTR(S_HEATING)][FPSTR(S_TARGET)].as() : dst.heating.target; bool valid = isValidTemp( value, dst.system.unitSystem, @@ -1361,7 +1378,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false // force check dhw target { - float value = !src["dhw"]["target"].isNull() ? src["dhw"]["target"].as() : dst.dhw.target; + float value = !src[FPSTR(S_DHW)][FPSTR(S_TARGET)].isNull() ? src[FPSTR(S_DHW)][FPSTR(S_TARGET)].as() : dst.dhw.target; bool valid = isValidTemp( value, dst.system.unitSystem, @@ -1388,41 +1405,41 @@ inline bool safeJsonToSettings(const JsonVariantConst src, Settings& dst) { } void sensorSettingsToJson(const uint8_t sensorId, const Sensors::Settings& src, JsonVariant dst) { - dst["id"] = sensorId; - dst["enabled"] = src.enabled; - dst["name"] = src.name; - dst["purpose"] = static_cast(src.purpose); - dst["type"] = static_cast(src.type); - dst["gpio"] = src.gpio; + dst[FPSTR(S_ID)] = sensorId; + dst[FPSTR(S_ENABLED)] = src.enabled; + dst[FPSTR(S_NAME)] = src.name; + dst[FPSTR(S_PURPOSE)] = static_cast(src.purpose); + dst[FPSTR(S_TYPE)] = static_cast(src.type); + dst[FPSTR(S_GPIO)] = src.gpio; if (src.type == Sensors::Type::DALLAS_TEMP) { char addr[24]; - sprintf( + sprintf_P( addr, - "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + PSTR("%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"), src.address[0], src.address[1], src.address[2], src.address[3], src.address[4], src.address[5], src.address[6], src.address[7] ); - dst["address"] = String(addr); + dst[FPSTR(S_ADDRESS)] = String(addr); } else if (src.type == Sensors::Type::BLUETOOTH) { char addr[18]; - sprintf( + sprintf_P( addr, - "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + PSTR("%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"), src.address[0], src.address[1], src.address[2], src.address[3], src.address[4], src.address[5] ); - dst["address"] = String(addr); + dst[FPSTR(S_ADDRESS)] = String(addr); } else { - dst["address"] = ""; + dst[FPSTR(S_ADDRESS)] = ""; } - dst["offset"] = roundf(src.offset, 3); - dst["factor"] = roundf(src.factor, 3); - dst["filtering"] = src.filtering; - dst["filteringFactor"] = roundf(src.filteringFactor, 3); + dst[FPSTR(S_OFFSET)] = roundf(src.offset, 3); + dst[FPSTR(S_FACTOR)] = roundf(src.factor, 3); + dst[FPSTR(S_FILTERING)] = src.filtering; + dst[FPSTR(S_FILTERING_FACTOR)] = roundf(src.filteringFactor, 3); } bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Sensors::Settings& dst) { @@ -1433,8 +1450,8 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se bool changed = false; // enabled - if (src["enabled"].is()) { - auto value = src["enabled"].as(); + if (src[FPSTR(S_ENABLED)].is()) { + auto value = src[FPSTR(S_ENABLED)].as(); if (value != dst.enabled) { dst.enabled = value; @@ -1443,8 +1460,8 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se } // name - if (!src["name"].isNull()) { - String value = Sensors::cleanName(src["name"].as()); + if (!src[FPSTR(S_NAME)].isNull()) { + String value = Sensors::cleanName(src[FPSTR(S_NAME)].as()); if (value.length() < sizeof(dst.name) && !value.equals(dst.name)) { strcpy(dst.name, value.c_str()); @@ -1453,8 +1470,8 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se } // purpose - if (!src["purpose"].isNull()) { - uint8_t value = src["purpose"].as(); + if (!src[FPSTR(S_PURPOSE)].isNull()) { + uint8_t value = src[FPSTR(S_PURPOSE)].as(); switch (value) { case static_cast(Sensors::Purpose::OUTDOOR_TEMP): @@ -1483,8 +1500,8 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se } // type - if (!src["type"].isNull()) { - uint8_t value = src["type"].as(); + if (!src[FPSTR(S_TYPE)].isNull()) { + uint8_t value = src[FPSTR(S_TYPE)].as(); switch (value) { case static_cast(Sensors::Type::OT_OUTDOOR_TEMP): @@ -1517,21 +1534,21 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se } // gpio - if (!src["gpio"].isNull()) { + if (!src[FPSTR(S_GPIO)].isNull()) { if (dst.type != Sensors::Type::DALLAS_TEMP && dst.type == Sensors::Type::BLUETOOTH && dst.type == Sensors::Type::NTC_10K_TEMP) { if (dst.gpio != GPIO_IS_NOT_CONFIGURED) { dst.gpio = GPIO_IS_NOT_CONFIGURED; changed = true; } - } else if (src["gpio"].is() && src["gpio"].as().size() == 0) { + } else if (src[FPSTR(S_GPIO)].is() && src[FPSTR(S_GPIO)].as().size() == 0) { if (dst.gpio != GPIO_IS_NOT_CONFIGURED) { dst.gpio = GPIO_IS_NOT_CONFIGURED; changed = true; } } else { - unsigned char value = src["gpio"].as(); + unsigned char value = src[FPSTR(S_GPIO)].as(); if (GPIO_IS_VALID(value) && value != dst.gpio) { dst.gpio = value; @@ -1541,8 +1558,8 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se } // address - if (!src["address"].isNull()) { - String value = src["address"].as(); + if (!src[FPSTR(S_ADDRESS)].isNull()) { + String value = src[FPSTR(S_ADDRESS)].as(); if (dst.type == Sensors::Type::DALLAS_TEMP) { uint8_t tmp[8]; @@ -1583,8 +1600,8 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se } // offset - if (!src["offset"].isNull()) { - float value = src["offset"].as(); + if (!src[FPSTR(S_OFFSET)].isNull()) { + float value = src[FPSTR(S_OFFSET)].as(); if (value >= -20.0f && value <= 20.0f && fabsf(value - dst.offset) > 0.0001f) { dst.offset = roundf(value, 2); @@ -1593,8 +1610,8 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se } // factor - if (!src["factor"].isNull()) { - float value = src["factor"].as(); + if (!src[FPSTR(S_FACTOR)].isNull()) { + float value = src[FPSTR(S_FACTOR)].as(); if (value > 0.09f && value <= 10.0f && fabsf(value - dst.factor) > 0.0001f) { dst.factor = roundf(value, 3); @@ -1603,8 +1620,8 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se } // filtering - if (src["filtering"].is()) { - auto value = src["filtering"].as(); + if (src[FPSTR(S_FILTERING)].is()) { + auto value = src[FPSTR(S_FILTERING)].as(); if (value != dst.filtering) { dst.filtering = value; @@ -1613,8 +1630,8 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se } // filtering factor - if (!src["filteringFactor"].isNull()) { - float value = src["filteringFactor"].as(); + if (!src[FPSTR(S_FILTERING_FACTOR)].isNull()) { + float value = src[FPSTR(S_FILTERING_FACTOR)].as(); if (value > 0 && value <= 1 && fabsf(value - dst.filteringFactor) > 0.0001f) { dst.filteringFactor = roundf(value, 3); @@ -1633,18 +1650,18 @@ void sensorResultToJson(const uint8_t sensorId, JsonVariant dst) { auto& sSensor = Sensors::settings[sensorId]; auto& rSensor = Sensors::results[sensorId]; - //dst["id"] = sensorId; - dst["connected"] = rSensor.connected; - dst["signalQuality"] = rSensor.signalQuality; + //dst[FPSTR(S_ID)] = sensorId; + dst[FPSTR(S_CONNECTED)] = rSensor.connected; + dst[FPSTR(S_SIGNAL_QUALITY)] = rSensor.signalQuality; if (sSensor.type == Sensors::Type::BLUETOOTH) { - dst["temperature"] = rSensor.values[static_cast(Sensors::ValueType::TEMPERATURE)]; - dst["humidity"] = rSensor.values[static_cast(Sensors::ValueType::HUMIDITY)]; - dst["battery"] = rSensor.values[static_cast(Sensors::ValueType::BATTERY)]; - dst["rssi"] = rSensor.values[static_cast(Sensors::ValueType::RSSI)]; + dst[FPSTR(S_TEMPERATURE)] = rSensor.values[static_cast(Sensors::ValueType::TEMPERATURE)]; + dst[FPSTR(S_HUMIDITY)] = rSensor.values[static_cast(Sensors::ValueType::HUMIDITY)]; + dst[FPSTR(S_BATTERY)] = rSensor.values[static_cast(Sensors::ValueType::BATTERY)]; + dst[FPSTR(S_RSSI)] = rSensor.values[static_cast(Sensors::ValueType::RSSI)]; } else { - dst["value"] = rSensor.values[static_cast(Sensors::ValueType::PRIMARY)]; + dst[FPSTR(S_VALUE)] = rSensor.values[static_cast(Sensors::ValueType::PRIMARY)]; } } @@ -1662,8 +1679,8 @@ bool jsonToSensorResult(const uint8_t sensorId, const JsonVariantConst src) { bool changed = false; // value - if (!src["value"].isNull()) { - float value = src["value"].as(); + if (!src[FPSTR(S_VALUE)].isNull()) { + float value = src[FPSTR(S_VALUE)].as(); uint8_t vType = static_cast(Sensors::ValueType::PRIMARY); if (fabsf(value - dst.values[vType]) > 0.0001f) { @@ -1676,76 +1693,88 @@ bool jsonToSensorResult(const uint8_t sensorId, const JsonVariantConst src) { } void varsToJson(const Variables& src, JsonVariant dst) { - dst["slave"]["memberId"] = src.slave.memberId; - dst["slave"]["flags"] = src.slave.flags; - dst["slave"]["type"] = src.slave.type; - dst["slave"]["appVersion"] = src.slave.appVersion; - dst["slave"]["protocolVersion"] = src.slave.appVersion; - dst["slave"]["connected"] = src.slave.connected; - dst["slave"]["flame"] = src.slave.flame; + auto slave = dst[FPSTR(S_SLAVE)].to(); + slave[FPSTR(S_MEMBER_ID)] = src.slave.memberId; + slave[FPSTR(S_FLAGS)] = src.slave.flags; + slave[FPSTR(S_TYPE)] = src.slave.type; + slave[FPSTR(S_APP_VERSION)] = src.slave.appVersion; + slave[FPSTR(S_PROTOCOL_VERSION)] = src.slave.appVersion; + slave[FPSTR(S_CONNECTED)] = src.slave.connected; + slave[FPSTR(S_FLAME)] = src.slave.flame; - dst["slave"]["modulation"]["min"] = src.slave.modulation.min; - dst["slave"]["modulation"]["max"] = src.slave.modulation.max; + auto sModulation = slave[FPSTR(S_MODULATION)].to(); + sModulation[FPSTR(S_MIN)] = src.slave.modulation.min; + sModulation[FPSTR(S_MAX)] = src.slave.modulation.max; - dst["slave"]["power"]["min"] = roundf(src.slave.power.min, 2); - dst["slave"]["power"]["max"] = roundf(src.slave.power.max, 2); + auto sPower = slave[FPSTR(S_POWER)].to(); + sPower[FPSTR(S_MIN)] = roundf(src.slave.power.min, 2); + sPower[FPSTR(S_MAX)] = roundf(src.slave.power.max, 2); - dst["slave"]["heating"]["active"] = src.slave.heating.active; - dst["slave"]["heating"]["minTemp"] = src.slave.heating.minTemp; - dst["slave"]["heating"]["maxTemp"] = src.slave.heating.maxTemp; + auto sHeating = slave[FPSTR(S_HEATING)].to(); + sHeating[FPSTR(S_ACTIVE)] = src.slave.heating.active; + sHeating[FPSTR(S_MIN_TEMP)] = src.slave.heating.minTemp; + sHeating[FPSTR(S_MAX_TEMP)] = src.slave.heating.maxTemp; - dst["slave"]["dhw"]["active"] = src.slave.dhw.active; - dst["slave"]["dhw"]["minTemp"] = src.slave.dhw.minTemp; - dst["slave"]["dhw"]["maxTemp"] = src.slave.dhw.maxTemp; + auto sDhw = slave[FPSTR(S_DHW)].to(); + sDhw[FPSTR(S_ACTIVE)] = src.slave.dhw.active; + sDhw[FPSTR(S_MIN_TEMP)] = src.slave.dhw.minTemp; + sDhw[FPSTR(S_MAX_TEMP)] = src.slave.dhw.maxTemp; - dst["slave"]["fault"]["active"] = src.slave.fault.active; - dst["slave"]["fault"]["code"] = src.slave.fault.code; + auto sFault = slave[FPSTR(S_FAULT)].to(); + sFault[FPSTR(S_ACTIVE)] = src.slave.fault.active; + sFault[FPSTR(S_CODE)] = src.slave.fault.code; - dst["slave"]["diag"]["active"] = src.slave.diag.active; - dst["slave"]["diag"]["code"] = src.slave.diag.code; + auto sDiag = slave[FPSTR(S_DIAG)].to(); + sDiag[FPSTR(S_ACTIVE)] = src.slave.diag.active; + sDiag[FPSTR(S_CODE)] = src.slave.diag.code; - dst["master"]["heating"]["enabled"] = src.master.heating.enabled; - dst["master"]["heating"]["blocking"] = src.master.heating.blocking; - dst["master"]["heating"]["indoorTempControl"] = src.master.heating.indoorTempControl; - dst["master"]["heating"]["targetTemp"] = roundf(src.master.heating.targetTemp, 2); - dst["master"]["heating"]["currentTemp"] = roundf(src.master.heating.currentTemp, 2); - dst["master"]["heating"]["returnTemp"] = roundf(src.master.heating.returnTemp, 2); - dst["master"]["heating"]["indoorTemp"] = roundf(src.master.heating.indoorTemp, 2); - dst["master"]["heating"]["outdoorTemp"] = roundf(src.master.heating.outdoorTemp, 2); - dst["master"]["heating"]["minTemp"] = roundf(src.master.heating.minTemp, 2); - dst["master"]["heating"]["maxTemp"] = roundf(src.master.heating.maxTemp, 2); - dst["master"]["dhw"]["enabled"] = src.master.dhw.enabled; - dst["master"]["dhw"]["targetTemp"] = roundf(src.master.dhw.targetTemp, 2); - dst["master"]["dhw"]["currentTemp"] = roundf(src.master.dhw.currentTemp, 2); - dst["master"]["dhw"]["returnTemp"] = roundf(src.master.dhw.returnTemp, 2); - dst["master"]["dhw"]["minTemp"] = settings.dhw.minTemp; - dst["master"]["dhw"]["maxTemp"] = settings.dhw.maxTemp; + auto master = dst[FPSTR(S_MASTER)].to(); + auto mHeating = master[FPSTR(S_HEATING)].to(); + mHeating[FPSTR(S_ENABLED)] = src.master.heating.enabled; + mHeating[FPSTR(S_BLOCKING)] = src.master.heating.blocking; + mHeating[FPSTR(S_INDOOR_TEMP_CONTROL)] = src.master.heating.indoorTempControl; + mHeating[FPSTR(S_TARGET_TEMP)] = roundf(src.master.heating.targetTemp, 2); + mHeating[FPSTR(S_CURRENT_TEMP)] = roundf(src.master.heating.currentTemp, 2); + mHeating[FPSTR(S_RETURN_TEMP)] = roundf(src.master.heating.returnTemp, 2); + mHeating[FPSTR(S_INDOOR_TEMP)] = roundf(src.master.heating.indoorTemp, 2); + mHeating[FPSTR(S_OUTDOOR_TEMP)] = roundf(src.master.heating.outdoorTemp, 2); + mHeating[FPSTR(S_MIN_TEMP)] = roundf(src.master.heating.minTemp, 2); + mHeating[FPSTR(S_MAX_TEMP)] = roundf(src.master.heating.maxTemp, 2); - dst["master"]["network"]["connected"] = src.network.connected; - dst["master"]["mqtt"]["connected"] = src.mqtt.connected; - dst["master"]["emergency"]["state"] = src.emergency.state; - dst["master"]["externalPump"]["state"] = src.externalPump.state; + auto mDhw = master[FPSTR(S_DHW)].to(); + mDhw[FPSTR(S_ENABLED)] = src.master.dhw.enabled; + mDhw[FPSTR(S_TARGET_TEMP)] = roundf(src.master.dhw.targetTemp, 2); + mDhw[FPSTR(S_CURRENT_TEMP)] = roundf(src.master.dhw.currentTemp, 2); + mDhw[FPSTR(S_RETURN_TEMP)] = roundf(src.master.dhw.returnTemp, 2); + mDhw[FPSTR(S_MIN_TEMP)] = settings.dhw.minTemp; + mDhw[FPSTR(S_MAX_TEMP)] = settings.dhw.maxTemp; - dst["master"]["cascadeControl"]["input"] = src.cascadeControl.input; - dst["master"]["cascadeControl"]["output"] = src.cascadeControl.output; + master[FPSTR(S_NETWORK)][FPSTR(S_CONNECTED)] = src.network.connected; + master[FPSTR(S_MQTT)][FPSTR(S_CONNECTED)] = src.mqtt.connected; + master[FPSTR(S_EMERGENCY)][FPSTR(S_STATE)] = src.emergency.state; + master[FPSTR(S_EXTERNAL_PUMP)][FPSTR(S_STATE)] = src.externalPump.state; - dst["master"]["uptime"] = millis() / 1000ul; + auto mCascadeControl = master[FPSTR(S_CASCADE_CONTROL)].to(); + mCascadeControl[FPSTR(S_INPUT)] = src.cascadeControl.input; + mCascadeControl[FPSTR(S_OUTPUT)] = src.cascadeControl.output; + + master[FPSTR(S_UPTIME)] = millis() / 1000; } bool jsonToVars(const JsonVariantConst src, Variables& dst) { bool changed = false; // actions - if (src["actions"]["restart"].is() && src["actions"]["restart"].as()) { + if (src[FPSTR(S_ACTIONS)][FPSTR(S_RESTART)].is() && src[FPSTR(S_ACTIONS)][FPSTR(S_RESTART)].as()) { dst.actions.restart = true; } - if (src["actions"]["resetFault"].is() && src["actions"]["resetFault"].as()) { + if (src[FPSTR(S_ACTIONS)][FPSTR(S_RESET_FAULT)].is() && src[FPSTR(S_ACTIONS)][FPSTR(S_RESET_FAULT)].as()) { dst.actions.resetFault = true; } - if (src["actions"]["resetDiagnostic"].is() && src["actions"]["resetDiagnostic"].as()) { + if (src[FPSTR(S_ACTIONS)][FPSTR(S_RESET_DIAGNOSTIC)].is() && src[FPSTR(S_ACTIONS)][FPSTR(S_RESET_DIAGNOSTIC)].as()) { dst.actions.resetDiagnostic = true; }