diff --git a/lib/HomeAssistantHelper/HomeAssistantHelper.h b/lib/HomeAssistantHelper/HomeAssistantHelper.h index d92bb76..a370e6d 100644 --- a/lib/HomeAssistantHelper/HomeAssistantHelper.h +++ b/lib/HomeAssistantHelper/HomeAssistantHelper.h @@ -5,133 +5,130 @@ class HomeAssistantHelper { public: HomeAssistantHelper() {} - HomeAssistantHelper(PubSubClient* client) { - this->setClient(client); + void setWriter() { + this->writer = nullptr; } - void setClient() { - this->client = nullptr; + void setWriter(MqttWriter* writer) { + this->writer = writer; } - void setClient(PubSubClient* client) { - this->client = client; + void setEventPublishCallback(std::function callback) { + this->eventPublishCallback = callback; } - void setYieldCallback(void(*yieldCallback)(void*)) { - this->yieldCallback = yieldCallback; - this->yieldArg = nullptr; + void setEventPublishCallback() { + this->eventPublishCallback = nullptr; } - void setYieldCallback(void(*yieldCallback)(void*), void* arg) { - this->yieldCallback = yieldCallback; - this->yieldArg = arg; + void setDevicePrefix(const char* value) { + this->devicePrefix = value; } - void setDevicePrefix(String value) { - devicePrefix = value; + void setDeviceVersion(const char* value) { + this->deviceVersion = value; } - void setDeviceVersion(String value) { - deviceVersion = value; + void setDeviceManufacturer(const char* value) { + this->deviceManufacturer = value; } - void setDeviceManufacturer(String value) { - deviceManufacturer = value; + void setDeviceModel(const char* value) { + this->deviceModel = value; } - void setDeviceModel(String value) { - deviceModel = value; + void setDeviceName(const char* value) { + this->deviceName = value; } - void setDeviceName(String value) { - deviceName = value; - } - - void setDeviceConfigUrl(String value) { - deviceConfigUrl = value; + void setDeviceConfigUrl(const char* value) { + this->deviceConfigUrl = value; } bool publish(const char* topic, JsonDocument& doc) { - if (this->client == nullptr) { + if (this->writer == nullptr) { + this->eventPublishCallback(topic, false); return false; } - doc[FPSTR(HA_DEVICE)][FPSTR(HA_IDENTIFIERS)][0] = devicePrefix; - doc[FPSTR(HA_DEVICE)][FPSTR(HA_SW_VERSION)] = deviceVersion; + doc[FPSTR(HA_DEVICE)][FPSTR(HA_IDENTIFIERS)][0] = this->devicePrefix; + doc[FPSTR(HA_DEVICE)][FPSTR(HA_SW_VERSION)] = this->deviceVersion; - if (deviceManufacturer) { - doc[FPSTR(HA_DEVICE)][FPSTR(HA_MANUFACTURER)] = deviceManufacturer; + if (this->deviceManufacturer != nullptr) { + doc[FPSTR(HA_DEVICE)][FPSTR(HA_MANUFACTURER)] = this->deviceManufacturer; } - if (deviceModel) { - doc[FPSTR(HA_DEVICE)][FPSTR(HA_MODEL)] = deviceModel; + if (this->deviceModel != nullptr) { + doc[FPSTR(HA_DEVICE)][FPSTR(HA_MODEL)] = this->deviceModel; } - if (deviceName) { - doc[FPSTR(HA_DEVICE)][FPSTR(HA_NAME)] = deviceName; + if (this->deviceName != nullptr) { + doc[FPSTR(HA_DEVICE)][FPSTR(HA_NAME)] = this->deviceName; } - if (deviceConfigUrl) { - doc[FPSTR(HA_DEVICE)][FPSTR(HA_CONF_URL)] = deviceConfigUrl; + if (this->deviceConfigUrl != nullptr) { + doc[FPSTR(HA_DEVICE)][FPSTR(HA_CONF_URL)] = this->deviceConfigUrl; } - - size_t docSize = measureJson(doc); - uint8_t* buffer = (uint8_t*) malloc(docSize * sizeof(*buffer)); - size_t length = serializeJson(doc, buffer, docSize); - - size_t written = 0; - if (length != 0) { - if (this->client->beginPublish(topic, docSize, true)) { - for (size_t offset = 0; offset < docSize; offset += 128) { - size_t packetSize = offset + 128 <= docSize ? 128 : docSize - offset; - written += this->client->write(buffer + offset, packetSize); - } - - this->client->flush(); - } - } - free(buffer); - - Log.straceln("MQTT", "Publish %u of %u bytes to topic: %s", written, docSize, topic); - - if (this->yieldCallback != nullptr) { - this->yieldCallback(yieldArg); + bool result = this->writer->publish(topic, doc, true); + if (this->eventPublishCallback) { + this->eventPublishCallback(topic, result); } - return docSize == written; + return result; } bool publish(const char* topic) { - if (this->client == nullptr) { + if (this->writer == nullptr) { + this->eventPublishCallback(topic, false); return false; } - return client->publish(topic, NULL, true); + bool result = writer->publish(topic, nullptr, 0, true); + if (this->eventPublishCallback) { + this->eventPublishCallback(topic, result); + } + + return result; } - String getTopic(const char* category, const char* name, const char* nameSeparator = "/") { + String getTopic(const char* category, const char* name, char nameSeparator = '/') { String topic = ""; - topic.concat(prefix); - topic.concat("/"); + topic.concat(this->prefix); + topic.concat('/'); topic.concat(category); - topic.concat("/"); - topic.concat(devicePrefix); + topic.concat('/'); + topic.concat(this->devicePrefix); topic.concat(nameSeparator); topic.concat(name); topic.concat("/config"); return topic; } + + template String getDeviceTopic(T value, char separator = '/') { + String topic = ""; + topic.concat(this->devicePrefix); + topic.concat(separator); + topic.concat(value); + return topic; + } + + template String getObjectId(T value, char separator = '_') { + String topic = ""; + topic.concat(this->devicePrefix); + topic.concat(separator); + topic.concat(value); + return topic; + } protected: - void(*yieldCallback)(void*) = nullptr; - void* yieldArg = nullptr; - PubSubClient* client = nullptr; - String prefix = "homeassistant"; - String devicePrefix = ""; - String deviceVersion = "1.0"; - String deviceManufacturer = "Community"; - String deviceModel = ""; - String deviceName = ""; - String deviceConfigUrl = ""; + std::function eventPublishCallback = nullptr; + MqttWriter* writer = nullptr; + const char* prefix = "homeassistant"; + const char* devicePrefix = ""; + const char* deviceVersion = "1.0"; + const char* deviceManufacturer = nullptr; + const char* deviceModel = nullptr; + const char* deviceName = nullptr; + const char* deviceConfigUrl = nullptr; }; diff --git a/lib/MqttWriter/MqttWiFiClient.h b/lib/MqttWriter/MqttWiFiClient.h new file mode 100644 index 0000000..843e51a --- /dev/null +++ b/lib/MqttWriter/MqttWiFiClient.h @@ -0,0 +1,24 @@ +#include + +class MqttWiFiClient : public WiFiClient { +public: +#ifdef ARDUINO_ARCH_ESP8266 + void flush() override { + if (this->connected()) { + WiFiClient::flush(0); + } + } + + void stop() override { + this->abort(); + } +#endif + +#ifdef ARDUINO_ARCH_ESP32 + void setSync(bool) {} + + bool getSync() { + return false; + } +#endif +}; \ No newline at end of file diff --git a/lib/MqttWriter/MqttWriter.h b/lib/MqttWriter/MqttWriter.h new file mode 100644 index 0000000..280a83c --- /dev/null +++ b/lib/MqttWriter/MqttWriter.h @@ -0,0 +1,221 @@ +#pragma once +#include +#include +#ifdef ARDUINO_ARCH_ESP32 +#include +#endif + + +class MqttWriter { +public: + MqttWriter(PubSubClient* client, size_t bufferSize = 64) { + this->client = client; + this->bufferSize = bufferSize; + this->buffer = (uint8_t*) malloc(bufferSize * sizeof(*this->buffer)); + +#ifdef ARDUINO_ARCH_ESP32 + this->mutex = new std::mutex(); +#endif + } + + ~MqttWriter() { + free(this->buffer); + +#ifdef ARDUINO_ARCH_ESP32 + delete this->mutex; +#endif + } + + void setYieldCallback(std::function callback) { + this->yieldCallback = callback; + } + + void setYieldCallback() { + this->yieldCallback = nullptr; + } + + void setEventPublishCallback(std::function callback) { + this->eventPublishCallback = callback; + } + + void setEventPublishCallback() { + this->eventPublishCallback = nullptr; + } + + void setEventFlushCallback(std::function callback) { + this->eventFlushCallback = callback; + } + + void setEventFlushCallback() { + this->eventFlushCallback = nullptr; + } + + bool lock() { +#ifdef ARDUINO_ARCH_ESP32 + if (!this->mutex->try_lock()) { + return false; + } +#else + if (this->isLocked()) { + return false; + } +#endif + + this->locked = true; + this->writeAfterLock = 0; + this->lockedTime = millis(); + + return true; + } + + bool isLocked() { + return this->locked; + } + + void unlock() { + this->locked = false; +#if defined(ARDUINO_ARCH_ESP32) + this->mutex->unlock(); +#endif + } + + bool publish(const char* topic, JsonDocument& doc, bool retained = false) { + if (!this->client->connected()) { + this->bufferPos = 0; + return false; + } + + while (!this->lock()) { + if (this->yieldCallback) { + this->yieldCallback(); + } + } + + this->bufferPos = 0; + size_t docSize = measureJson(doc); + size_t written = 0; + if (this->client->beginPublish(topic, docSize, retained)) { + serializeJson(doc, *this); + doc.clear(); + this->flush(); + + written = this->writeAfterLock; + } + this->unlock(); + + if (this->eventPublishCallback) { + this->eventPublishCallback(topic, written, docSize, written == docSize); + } + + return written == docSize; + } + + bool publish(const char* topic, const char* buffer, bool retained = false) { + return this->publish(topic, (uint8_t*) buffer, strlen(buffer), retained); + } + + bool publish(const char* topic, const uint8_t* buffer, size_t length, bool retained = false) { + if (!this->client->connected()) { + this->bufferPos = 0; + return false; + } + + while (!this->lock()) { + if (this->yieldCallback) { + this->yieldCallback(); + } + } + + this->bufferPos = 0; + size_t written = 0; + bool result = false; + if (length == 0) { + result = this->client->publish(topic, nullptr, 0, retained); + + } else if (this->client->beginPublish(topic, length, retained)) { + this->write(buffer, length); + this->flush(); + + written = this->writeAfterLock; + result = written == length; + } + this->unlock(); + + if (this->eventPublishCallback) { + this->eventPublishCallback(topic, written, length, result); + } + + return result; + } + + size_t write(uint8_t c) { + this->buffer[this->bufferPos++] = c; + + if (this->bufferPos >= this->bufferSize) { + this->flush(); + } + + return 1; + } + + size_t write(const uint8_t* buffer, size_t length) { + size_t written = 0; + while (written < length) { + size_t copySize = this->bufferSize - this->bufferPos; + if (written + copySize > length) { + copySize = length - written; + } + + memcpy(this->buffer + this->bufferPos, buffer + written, copySize); + this->bufferPos += copySize; + + if (this->bufferPos >= this->bufferSize) { + this->flush(); + } + + written += copySize; + } + + return written; + } + + bool flush() { + if (this->bufferPos == 0) { + return false; + } + + if (!this->client->connected()) { + this->bufferPos = 0; + } + + size_t length = this->bufferPos; + size_t written = this->client->write(this->buffer, length); + this->client->flush(); + this->bufferPos = 0; + + if (this->isLocked()) { + this->writeAfterLock += written; + } + + if (this->eventFlushCallback) { + this->eventFlushCallback(written, length); + } + + return written == length; + } + +protected: + PubSubClient* client; + uint8_t* buffer; + size_t bufferSize = 64; + size_t bufferPos = 0; + bool locked = false; +#ifdef ARDUINO_ARCH_ESP32 + mutable std::mutex* mutex; +#endif + unsigned long lockedTime = 0; + size_t writeAfterLock = 0; + std::function yieldCallback = nullptr; + std::function eventPublishCallback = nullptr; + std::function eventFlushCallback = nullptr; +}; diff --git a/platformio.ini b/platformio.ini index 8bd4bda..b2c9237 100644 --- a/platformio.ini +++ b/platformio.ini @@ -32,7 +32,7 @@ build_flags = -D USE_TELNET=1 upload_speed = 921600 monitor_speed = 115200 -version = 1.4.0 +version = 1.4.0-rc.1 ; Defaults [esp8266_defaults] diff --git a/src/HaHelper.h b/src/HaHelper.h index 5c5a7b6..9d9762f 100644 --- a/src/HaHelper.h +++ b/src/HaHelper.h @@ -8,37 +8,37 @@ public: bool publishSelectOutdoorSensorType(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"sensors\": {\"outdoor\": {\"type\": {% if value == 'Boiler' %}0{% elif value == 'Manual' %}1{% elif value == 'External' %}2{% endif %}}}}"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_outdoor_sensor_type"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_outdoor_sensor_type"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("outdoor_sensor_type").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("outdoor_sensor_type").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("Outdoor temperature source"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{% if value_json.sensors.outdoor.type == 0 %}Boiler{% elif value_json.sensors.outdoor.type == 1 %}Manual{% elif value_json.sensors.outdoor.type == 2 %}External{% endif %}"); doc[FPSTR(HA_OPTIONS)][0] = F("Boiler"); doc[FPSTR(HA_OPTIONS)][1] = F("Manual"); doc[FPSTR(HA_OPTIONS)][2] = F("External"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("select", "outdoor_sensor_type").c_str(), doc); + return this->publish(this->getTopic("select", "outdoor_sensor_type").c_str(), doc); } bool publishSelectIndoorSensorType(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); #if USE_BLE doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"sensors\": {\"indoor\": {\"type\": {% if value == 'Manual' %}1{% elif value == 'External' %}2{% elif value == 'Bluetooth' %}3{% endif %}}}}"); #else doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"sensors\": {\"indoor\": {\"type\": {% if value == 'Manual' %}1{% elif value == 'External' %}2{% endif %}}}}"); #endif doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_indoor_sensor_type"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_indoor_sensor_type"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("indoor_sensor_type").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("indoor_sensor_type").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("Indoor temperature source"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); #if USE_BLE doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{% if value_json.sensors.indoor.type == 1 %}Manual{% elif value_json.sensors.indoor.type == 2 %}External{% elif value_json.sensors.indoor.type == 3 %}Bluetooth{% endif %}"); #else @@ -51,24 +51,24 @@ public: #endif doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("select", "indoor_sensor_type").c_str(), doc); + return this->publish(this->getTopic("select", "indoor_sensor_type").c_str(), doc); } bool publishNumberOutdoorSensorOffset(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.sensors.outdoor.type != 1, 'online', 'offline') }}"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_outdoor_sensor_offset"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_outdoor_sensor_offset"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("outdoor_sensor_offset").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("outdoor_sensor_offset").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Outdoor sensor offset"); doc[FPSTR(HA_ICON)] = F("mdi:altimeter"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.sensors.outdoor.offset|float(0)|round(2) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"sensors\": {\"outdoor\" : {\"offset\" : {{ value }}}}}"); doc[FPSTR(HA_MIN)] = -10; doc[FPSTR(HA_MAX)] = 10; @@ -76,24 +76,24 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "outdoor_sensor_offset").c_str(), doc); + return this->publish(this->getTopic("number", "outdoor_sensor_offset").c_str(), doc); } bool publishNumberIndoorSensorOffset(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.sensors.indoor.type != 1, 'online', 'offline') }}"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_indoor_sensor_offset"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_indoor_sensor_offset"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("indoor_sensor_offset").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("indoor_sensor_offset").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Indoor sensor offset"); doc[FPSTR(HA_ICON)] = F("mdi:altimeter"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.sensors.indoor.offset|float(0)|round(2) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"sensors\": {\"indoor\" : {\"offset\" : {{ value }}}}}"); doc[FPSTR(HA_MIN)] = -10; doc[FPSTR(HA_MAX)] = 10; @@ -101,64 +101,64 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "indoor_sensor_offset").c_str(), doc); + return this->publish(this->getTopic("number", "indoor_sensor_offset").c_str(), doc); } bool publishSwitchDebug(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_debug"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_debug"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("debug").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("debug").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("Debug"); doc[FPSTR(HA_ICON)] = F("mdi:code-braces"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_STATE_ON)] = true; doc[FPSTR(HA_STATE_OFF)] = false; doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.debug }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"debug\": true}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"debug\": false}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("switch", "debug").c_str(), doc); + return this->publish(this->getTopic("switch", "debug").c_str(), doc); } bool publishSwitchEmergency(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_emergency"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_emergency"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("emergency").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("emergency").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("Use emergency"); doc[FPSTR(HA_ICON)] = F("mdi:sun-snowflake-variant"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_STATE_ON)] = true; doc[FPSTR(HA_STATE_OFF)] = false; doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.emergency.enable }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"emergency\": {\"enable\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"emergency\": {\"enable\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("switch", "emergency").c_str(), doc); + return this->publish(this->getTopic("switch", "emergency").c_str(), doc); } bool publishNumberEmergencyTarget(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_emergency_target"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_emergency_target"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("emergency_target").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("emergency_target").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Emergency target temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-alert"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.emergency.target|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"emergency\": {\"target\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 5; doc[FPSTR(HA_MAX)] = 50; @@ -166,88 +166,88 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "emergency_target").c_str(), doc); + return this->publish(this->getTopic("number", "emergency_target").c_str(), doc); } bool publishSwitchEmergencyUseEquitherm(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.sensors.outdoor.type != 1, 'online', 'offline') }}"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_emergency_use_equitherm"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_emergency_use_equitherm"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("emergency_use_equitherm").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("emergency_use_equitherm").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("Use equitherm in emergency"); doc[FPSTR(HA_ICON)] = F("mdi:snowflake-alert"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_STATE_ON)] = true; doc[FPSTR(HA_STATE_OFF)] = false; doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.emergency.useEquitherm }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"emergency\": {\"useEquitherm\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"emergency\": {\"useEquitherm\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("switch", "emergency_use_equitherm").c_str(), doc); + return this->publish(this->getTopic("switch", "emergency_use_equitherm").c_str(), doc); } bool publishSwitchHeating(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_heating"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("heating").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("heating").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("Heating"); doc[FPSTR(HA_ICON)] = F("mdi:radiator"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_STATE_ON)] = true; doc[FPSTR(HA_STATE_OFF)] = false; doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.enable }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"heating\": {\"enable\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"heating\": {\"enable\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("switch", "heating").c_str(), doc); + return this->publish(this->getTopic("switch", "heating").c_str(), doc); } bool publishSwitchHeatingTurbo(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating_turbo"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_heating_turbo"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("heating_turbo").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("heating_turbo").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("Turbo heating"); doc[FPSTR(HA_ICON)] = F("mdi:rocket-launch-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").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)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").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)] = 120; - return publish(getTopic("switch", "heating_turbo").c_str(), doc); + return this->publish(this->getTopic("switch", "heating_turbo").c_str(), doc); } bool publishNumberHeatingTarget(byte minTemp = 20, byte maxTemp = 90, bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating_target"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_heating_target"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("heating_target").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("heating_target").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Heating target"); doc[FPSTR(HA_ICON)] = F("mdi:radiator"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.target|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"target\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = minTemp; doc[FPSTR(HA_MAX)] = maxTemp; @@ -255,22 +255,22 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "heating_target").c_str(), doc); + return this->publish(this->getTopic("number", "heating_target").c_str(), doc); } bool publishNumberHeatingHysteresis(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating_hysteresis"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_heating_hysteresis"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("heating_hysteresis").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("heating_hysteresis").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Heating hysteresis"); doc[FPSTR(HA_ICON)] = F("mdi:altimeter"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.hysteresis|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"hysteresis\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0; doc[FPSTR(HA_MAX)] = 5; @@ -278,79 +278,79 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "heating_hysteresis").c_str(), doc); + return this->publish(this->getTopic("number", "heating_hysteresis").c_str(), doc); } bool publishSensorHeatingSetpoint(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating_setpoint"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_heating_setpoint"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("heating_setpoint").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("heating_setpoint").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_STATE_CLASS)] = F("measurement"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Heating setpoint"); doc[FPSTR(HA_ICON)] = F("mdi:coolant-temperature"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.parameters.heatingSetpoint|int(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("sensor", "heating_setpoint").c_str(), doc); + return this->publish(this->getTopic("sensor", "heating_setpoint").c_str(), doc); } bool publishSensorCurrentHeatingMinTemp(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_current_heating_min_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_current_heating_min_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("current_heating_min_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("current_heating_min_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_STATE_CLASS)] = F("measurement"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Current heating min temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.parameters.heatingMinTemp|int(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("sensor", "current_heating_min_temp").c_str(), doc); + return this->publish(this->getTopic("sensor", "current_heating_min_temp").c_str(), doc); } bool publishSensorCurrentHeatingMaxTemp(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_current_heating_max_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_current_heating_max_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("current_heating_max_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("current_heating_max_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_STATE_CLASS)] = F("measurement"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Current heating max temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.parameters.heatingMaxTemp|int(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("sensor", "current_heating_max_temp").c_str(), doc); + return this->publish(this->getTopic("sensor", "current_heating_max_temp").c_str(), doc); } bool publishNumberHeatingMinTemp(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating_min_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_heating_min_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("heating_min_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("heating_min_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Heating min temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.minTemp|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"minTemp\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0; doc[FPSTR(HA_MAX)] = 99; @@ -358,22 +358,22 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "heating_min_temp").c_str(), doc); + return this->publish(this->getTopic("number", "heating_min_temp").c_str(), doc); } bool publishNumberHeatingMaxTemp(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating_max_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_heating_max_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("heating_max_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("heating_max_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Heating max temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.maxTemp|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"maxTemp\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 1; doc[FPSTR(HA_MAX)] = 100; @@ -381,22 +381,22 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "heating_max_temp").c_str(), doc); + return this->publish(this->getTopic("number", "heating_max_temp").c_str(), doc); } bool publishNumberHeatingMaxModulation(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating_max_modulation"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_heating_max_modulation"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("heating_max_modulation").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("heating_max_modulation").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("power_factor"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("%"); doc[FPSTR(HA_NAME)] = F("Max modulation"); doc[FPSTR(HA_ICON)] = F("mdi:speedometer"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.maxModulation|int(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"maxModulation\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 1; doc[FPSTR(HA_MAX)] = 100; @@ -404,45 +404,45 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "heating_max_modulation").c_str(), doc); + return this->publish(this->getTopic("number", "heating_max_modulation").c_str(), doc); } bool publishSwitchDhw(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_dhw"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_dhw"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("dhw").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("dhw").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("DHW"); doc[FPSTR(HA_ICON)] = F("mdi:water-pump"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_STATE_ON)] = true; doc[FPSTR(HA_STATE_OFF)] = false; doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.dhw.enable }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"dhw\": {\"enable\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"dhw\": {\"enable\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("switch", "dhw").c_str(), doc); + return this->publish(this->getTopic("switch", "dhw").c_str(), doc); } bool publishNumberDhwTarget(byte minTemp = 40, byte maxTemp = 60, bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_dhw_target"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_dhw_target"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("dhw_target").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("dhw_target").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("DHW target"); doc[FPSTR(HA_ICON)] = F("mdi:water-pump"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.dhw.target|int(0) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"target\" : {{ value|int(0) }}}}"); doc[FPSTR(HA_MIN)] = minTemp; doc[FPSTR(HA_MAX)] = maxTemp <= minTemp ? maxTemp : maxTemp; @@ -450,60 +450,60 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "dhw_target").c_str(), doc); + return this->publish(this->getTopic("number", "dhw_target").c_str(), doc); } bool publishSensorCurrentDhwMinTemp(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_current_dhw_min_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_current_dhw_min_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("current_dhw_min_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("current_dhw_min_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_STATE_CLASS)] = F("measurement"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Current DHW min temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.parameters.dhwMinTemp|int(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("sensor", "current_dhw_min_temp").c_str(), doc); + return this->publish(this->getTopic("sensor", "current_dhw_min_temp").c_str(), doc); } bool publishSensorCurrentDhwMaxTemp(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_current_dhw_max_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_current_dhw_max_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("current_dhw_max_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("current_dhw_max_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_STATE_CLASS)] = F("measurement"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Current DHW max temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.parameters.dhwMaxTemp|int(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("sensor", "current_dhw_max_temp").c_str(), doc); + return this->publish(this->getTopic("sensor", "current_dhw_max_temp").c_str(), doc); } bool publishNumberDhwMinTemp(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_dhw_min_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_dhw_min_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("dhw_min_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("dhw_min_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("DHW min temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.dhw.minTemp|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"minTemp\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0; doc[FPSTR(HA_MAX)] = 99; @@ -511,22 +511,22 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "dhw_min_temp").c_str(), doc); + return this->publish(this->getTopic("number", "dhw_min_temp").c_str(), doc); } bool publishNumberDhwMaxTemp(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_dhw_max_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_dhw_max_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("dhw_max_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("dhw_max_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("DHW max temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.dhw.maxTemp|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"maxTemp\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 1; doc[FPSTR(HA_MAX)] = 100; @@ -534,40 +534,40 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "dhw_max_temp").c_str(), doc); + return this->publish(this->getTopic("number", "dhw_max_temp").c_str(), doc); } bool publishSwitchPID(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_pid"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_pid"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("pid").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("pid").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("PID"); doc[FPSTR(HA_ICON)] = F("mdi:chart-bar-stacked"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_STATE_ON)] = true; doc[FPSTR(HA_STATE_OFF)] = false; doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.enable }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"pid\": {\"enable\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"pid\": {\"enable\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("switch", "pid").c_str(), doc); + return this->publish(this->getTopic("switch", "pid").c_str(), doc); } bool publishNumberPIDFactorP(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_pid_p"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_pid_p"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("pid_p").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("pid_p").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("PID factor P"); doc[FPSTR(HA_ICON)] = F("mdi:alpha-p-circle-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.p_factor|float(0)|round(3) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"p_factor\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0.001; doc[FPSTR(HA_MAX)] = 10; @@ -575,19 +575,19 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "pid_p_factor").c_str(), doc); + return this->publish(this->getTopic("number", "pid_p_factor").c_str(), doc); } bool publishNumberPIDFactorI(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_pid_i"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_pid_i"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("pid_i").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("pid_i").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("PID factor I"); doc[FPSTR(HA_ICON)] = F("mdi:alpha-i-circle-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.i_factor|float(0)|round(3) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"i_factor\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0; doc[FPSTR(HA_MAX)] = 10; @@ -595,19 +595,19 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "pid_i_factor").c_str(), doc); + return this->publish(this->getTopic("number", "pid_i_factor").c_str(), doc); } bool publishNumberPIDFactorD(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_pid_d"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_pid_d"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("pid_d").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("pid_d").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("PID factor D"); doc[FPSTR(HA_ICON)] = F("mdi:alpha-d-circle-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.d_factor|float(0)|round(3) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"d_factor\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0; doc[FPSTR(HA_MAX)] = 10; @@ -615,22 +615,22 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "pid_d_factor").c_str(), doc); + return this->publish(this->getTopic("number", "pid_d_factor").c_str(), doc); } bool publishNumberPIDMinTemp(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_pid_min_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_pid_min_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("pid_min_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("pid_min_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("PID min temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.minTemp|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"minTemp\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0; doc[FPSTR(HA_MAX)] = 99; @@ -638,22 +638,22 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "pid_min_temp").c_str(), doc); + return this->publish(this->getTopic("number", "pid_min_temp").c_str(), doc); } bool publishNumberPIDMaxTemp(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_pid_max_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_pid_max_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("pid_max_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("pid_max_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("PID max temp"); doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.maxTemp|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"maxTemp\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 1; doc[FPSTR(HA_MAX)] = 100; @@ -661,40 +661,40 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "pid_max_temp").c_str(), doc); + return this->publish(this->getTopic("number", "pid_max_temp").c_str(), doc); } bool publishSwitchEquitherm(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_equitherm"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_equitherm"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("equitherm").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("equitherm").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("Equitherm"); doc[FPSTR(HA_ICON)] = F("mdi:sun-snowflake-variant"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_STATE_ON)] = true; doc[FPSTR(HA_STATE_OFF)] = false; doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.equitherm.enable }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"equitherm\": {\"enable\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"equitherm\": {\"enable\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("switch", "equitherm").c_str(), doc); + return this->publish(this->getTopic("switch", "equitherm").c_str(), doc); } bool publishNumberEquithermFactorN(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_equitherm_n"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_equitherm_n"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("equitherm_n").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("equitherm_n").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("Equitherm factor N"); doc[FPSTR(HA_ICON)] = F("mdi:alpha-n-circle-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.equitherm.n_factor|float(0)|round(3) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"n_factor\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0.001; doc[FPSTR(HA_MAX)] = 10; @@ -702,19 +702,19 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "equitherm_n_factor").c_str(), doc); + return this->publish(this->getTopic("number", "equitherm_n_factor").c_str(), doc); } bool publishNumberEquithermFactorK(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_equitherm_k"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_equitherm_k"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("equitherm_k").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("equitherm_k").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("Equitherm factor K"); doc[FPSTR(HA_ICON)] = F("mdi:alpha-k-circle-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.equitherm.k_factor|float(0)|round(2) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"k_factor\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0; doc[FPSTR(HA_MAX)] = 10; @@ -722,21 +722,21 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "equitherm_k_factor").c_str(), doc); + return this->publish(this->getTopic("number", "equitherm_k_factor").c_str(), doc); } bool publishNumberEquithermFactorT(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.pid.enable, 'offline', 'online') }}"); - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_equitherm_t"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_equitherm_t"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("equitherm_t").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("equitherm_t").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("Equitherm factor T"); doc[FPSTR(HA_ICON)] = F("mdi:alpha-t-circle-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.equitherm.t_factor|float(0)|round(2) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"t_factor\" : {{ value }}}}"); doc[FPSTR(HA_MIN)] = 0; doc[FPSTR(HA_MAX)] = 10; @@ -744,295 +744,295 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "equitherm_t_factor").c_str(), doc); + return this->publish(this->getTopic("number", "equitherm_t_factor").c_str(), doc); } bool publishSwitchTuning(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_tuning"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_tuning"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("tuning").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("tuning").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("Tuning"); doc[FPSTR(HA_ICON)] = F("mdi:tune-vertical"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_STATE_ON)] = true; doc[FPSTR(HA_STATE_OFF)] = false; doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.tuning.enable }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/state/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("state/set").c_str(); doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"tuning\": {\"enable\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"tuning\": {\"enable\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("switch", "tuning").c_str(), doc); + return this->publish(this->getTopic("switch", "tuning").c_str(), doc); } bool publishSelectTuningRegulator(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/state/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("state/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"tuning\": {\"regulator\": {% if value == 'Equitherm' %}0{% elif value == 'PID' %}1{% endif %}}}"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_tuning_regulator"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_tuning_regulator"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("tuning_regulator").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("tuning_regulator").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_NAME)] = F("Tuning regulator"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{% if value_json.tuning.regulator == 0 %}Equitherm{% elif value_json.tuning.regulator == 1 %}PID{% endif %}"); doc[FPSTR(HA_OPTIONS)][0] = F("Equitherm"); doc[FPSTR(HA_OPTIONS)][1] = F("PID"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("select", "tuning_regulator").c_str(), doc); + return this->publish(this->getTopic("select", "tuning_regulator").c_str(), doc); } bool publishBinSensorStatus(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_status"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_status"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("status").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("status").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("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)] = devicePrefix + F("/status"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value == 'online', 'OFF', 'ON') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 60; - return publish(getTopic("binary_sensor", "status").c_str(), doc); + return this->publish(this->getTopic("binary_sensor", "status").c_str(), doc); } bool publishBinSensorOtStatus(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_ot_status"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_ot_status"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("ot_status").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("ot_status").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("problem"); doc[FPSTR(HA_NAME)] = F("Opentherm status"); doc[FPSTR(HA_ICON)] = F("mdi:list-status"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'OFF', 'ON') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("binary_sensor", "ot_status").c_str(), doc); + return this->publish(this->getTopic("binary_sensor", "ot_status").c_str(), doc); } bool publishBinSensorHeating(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_heating"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("heating").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("heating").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("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)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.heating, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("binary_sensor", "heating").c_str(), doc); + return this->publish(this->getTopic("binary_sensor", "heating").c_str(), doc); } bool publishBinSensorDhw(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_dhw"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_dhw"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("dhw").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("dhw").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("running"); doc[FPSTR(HA_NAME)] = F("DHW"); doc[FPSTR(HA_ICON)] = F("mdi:water-pump"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.dhw, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("binary_sensor", "dhw").c_str(), doc); + return this->publish(this->getTopic("binary_sensor", "dhw").c_str(), doc); } bool publishBinSensorFlame(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_flame"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_flame"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("flame").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("flame").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("running"); doc[FPSTR(HA_NAME)] = F("Flame"); doc[FPSTR(HA_ICON)] = F("mdi:fire"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.flame, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("binary_sensor", "flame").c_str(), doc); + return this->publish(this->getTopic("binary_sensor", "flame").c_str(), doc); } bool publishBinSensorFault(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_fault"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_fault"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("fault").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("fault").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("problem"); doc[FPSTR(HA_NAME)] = F("Fault"); doc[FPSTR(HA_ICON)] = F("mdi:water-boiler-alert"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.fault, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("binary_sensor", "fault").c_str(), doc); + return this->publish(this->getTopic("binary_sensor", "fault").c_str(), doc); } bool publishBinSensorDiagnostic(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_diagnostic"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_diagnostic"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("diagnostic").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("diagnostic").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("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)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.diagnostic, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("binary_sensor", "diagnostic").c_str(), doc); + return this->publish(this->getTopic("binary_sensor", "diagnostic").c_str(), doc); } bool publishSensorFaultCode(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.fault, 'online', 'offline') }}"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_fault_code"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_fault_code"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("fault_code").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("fault_code").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_NAME)] = F("Fault code"); doc[FPSTR(HA_ICON)] = F("mdi:chat-alert-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ \"E%02d\"|format(value_json.sensors.faultCode) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("sensor", "fault_code").c_str(), doc); + return this->publish(this->getTopic("sensor", "fault_code").c_str(), doc); } bool publishSensorRssi(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_rssi"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_rssi"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("rssi").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("rssi").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("signal_strength"); doc[FPSTR(HA_STATE_CLASS)] = F("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)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.sensors.rssi|float(0)|round(1) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("sensor", "rssi").c_str(), doc); + return this->publish(this->getTopic("sensor", "rssi").c_str(), doc); } bool publishSensorUptime(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_uptime"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_uptime"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("uptime").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("uptime").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("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)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.sensors.uptime|int(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("sensor", "uptime").c_str(), doc); + return this->publish(this->getTopic("sensor", "uptime").c_str(), doc); } bool publishSensorModulation(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_modulation_level"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_modulation_level"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("modulation_level").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("modulation_level").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("power_factor"); doc[FPSTR(HA_STATE_CLASS)] = F("measurement"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("%"); doc[FPSTR(HA_NAME)] = F("Modulation level"); doc[FPSTR(HA_ICON)] = F("mdi:fire-circle"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.sensors.modulation|float(0)|round(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("sensor", "modulation").c_str(), doc); + return this->publish(this->getTopic("sensor", "modulation").c_str(), doc); } bool publishSensorPressure(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_pressure"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_pressure"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("pressure").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("pressure").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("pressure"); doc[FPSTR(HA_STATE_CLASS)] = F("measurement"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("bar"); doc[FPSTR(HA_NAME)] = F("Pressure"); doc[FPSTR(HA_ICON)] = F("mdi:gauge"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.sensors.pressure|float(0)|round(2) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("sensor", "pressure").c_str(), doc); + return this->publish(this->getTopic("sensor", "pressure").c_str(), doc); } bool publishSensorDhwFlowRate(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_dhw_flow_rate"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_dhw_flow_rate"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("dhw_flow_rate").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("dhw_flow_rate").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("volume"); doc[FPSTR(HA_STATE_CLASS)] = F("measurement"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("L/min"); doc[FPSTR(HA_NAME)] = F("DHW flow rate"); doc[FPSTR(HA_ICON)] = F("mdi:water-pump"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.sensors.dhwFlowRate|float(0)|round(2) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("sensor", "dhw_flow_rate").c_str(), doc); + return this->publish(this->getTopic("sensor", "dhw_flow_rate").c_str(), doc); } bool publishNumberIndoorTemp(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_indoor_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_indoor_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("indoor_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("indoor_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Indoor temperature"); doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.indoor|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/state/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("state/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"temperatures\": {\"indoor\":{{ value }}}}"); doc[FPSTR(HA_MIN)] = -99; doc[FPSTR(HA_MAX)] = 99; @@ -1040,41 +1040,41 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "indoor_temp").c_str(), doc); + return this->publish(this->getTopic("number", "indoor_temp").c_str(), doc); } bool publishSensorIndoorTemp(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_AVAILABILITY_MODE)] = F("any"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_indoor_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_indoor_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("indoor_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("indoor_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_STATE_CLASS)] = F("measurement"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Indoor temperature"); doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.indoor|float(0)|round(1) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("sensor", "indoor_temp").c_str(), doc); + return this->publish(this->getTopic("sensor", "indoor_temp").c_str(), doc); } bool publishNumberOutdoorTemp(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_outdoor_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_outdoor_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("outdoor_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("outdoor_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Outdoor temperature"); doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.outdoor|float(0)|round(1) }}"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/state/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("state/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"temperatures\": {\"outdoor\":{{ value }}}}"); doc[FPSTR(HA_MIN)] = -99; doc[FPSTR(HA_MAX)] = 99; @@ -1082,79 +1082,79 @@ public: doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("number", "outdoor_temp").c_str(), doc); + return this->publish(this->getTopic("number", "outdoor_temp").c_str(), doc); } bool publishSensorOutdoorTemp(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_AVAILABILITY_MODE)] = F("any"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_outdoor_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_outdoor_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("outdoor_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("outdoor_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_STATE_CLASS)] = F("measurement"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Outdoor temperature"); doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer-outline"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.outdoor|float(0)|round(1) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("sensor", "outdoor_temp").c_str(), doc); + return this->publish(this->getTopic("sensor", "outdoor_temp").c_str(), doc); } bool publishSensorHeatingTemp(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_heating_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("heating_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("heating_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_STATE_CLASS)] = F("measurement"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("Heating temperature"); doc[FPSTR(HA_ICON)] = F("mdi:radiator"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.heating|float(0)|round(2) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("sensor", "heating_temp").c_str(), doc); + return this->publish(this->getTopic("sensor", "heating_temp").c_str(), doc); } bool publishSensorDhwTemp(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_dhw_temp"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_dhw_temp"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("dhw_temp").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("dhw_temp").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic"); doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature"); doc[FPSTR(HA_STATE_CLASS)] = F("measurement"); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C"); doc[FPSTR(HA_NAME)] = F("DHW temperature"); doc[FPSTR(HA_ICON)] = F("mdi:water-pump"); - doc[FPSTR(HA_STATE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.dhw|float(0)|round(2) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("sensor", "dhw_temp").c_str(), doc); + return this->publish(this->getTopic("sensor", "dhw_temp").c_str(), doc); } bool publishClimateHeating(byte minTemp = 20, byte maxTemp = 90, byte currentTempSource = HaHelper::TEMP_SOURCE_HEATING, bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_heating"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("heating").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("heating").c_str(); doc[FPSTR(HA_NAME)] = F("Heating"); doc[FPSTR(HA_ICON)] = F("mdi:radiator"); if (currentTempSource == HaHelper::TEMP_SOURCE_HEATING || currentTempSource == HaHelper::TEMP_SOURCE_INDOOR) { - doc[FPSTR(HA_CURRENT_TEMPERATURE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_CURRENT_TEMPERATURE_TOPIC)] = this->getDeviceTopic("state").c_str(); } if (currentTempSource == HaHelper::TEMP_SOURCE_HEATING) { @@ -1164,27 +1164,27 @@ public: doc[FPSTR(HA_CURRENT_TEMPERATURE_TEMPLATE)] = F("{{ value_json.temperatures.indoor|float(0)|round(2) }}"); } - doc[FPSTR(HA_TEMPERATURE_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_TEMPERATURE_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_TEMPERATURE_COMMAND_TEMPLATE)] = F("{\"heating\": {\"target\" : {{ value }}}}"); - doc[FPSTR(HA_TEMPERATURE_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_TEMPERATURE_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_TEMPERATURE_STATE_TEMPLATE)] = F("{{ value_json.heating.target|float(0)|round(1) }}"); - doc[FPSTR(HA_MODE_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_MODE_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); 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)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_MODE_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_MODE_STATE_TEMPLATE)] = F("{{ iif(value_json.heating.enable, 'heat', 'off') }}"); doc[FPSTR(HA_MODES)][0] = F("off"); doc[FPSTR(HA_MODES)][1] = F("heat"); - doc[FPSTR(HA_ACTION_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_ACTION_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_ACTION_TEMPLATE)] = F("{{ iif(value_json.states.heating, 'heating', 'idle') }}"); - doc[FPSTR(HA_PRESET_MODE_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_PRESET_MODE_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").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)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_PRESET_MODE_STATE_TOPIC)] = this->getDeviceTopic("settings").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"); @@ -1193,150 +1193,149 @@ public: doc[FPSTR(HA_TEMP_STEP)] = 0.5; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("climate", "heating", "_").c_str(), doc); + return this->publish(this->getTopic("climate", "heating", '_').c_str(), doc); } bool publishClimateDhw(byte minTemp = 40, byte maxTemp = 60, bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status"); - + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("status").c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_dhw"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_dhw"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("dhw").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("dhw").c_str(); doc[FPSTR(HA_NAME)] = F("DHW"); doc[FPSTR(HA_ICON)] = F("mdi:water-pump"); - doc[FPSTR(HA_CURRENT_TEMPERATURE_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_CURRENT_TEMPERATURE_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_CURRENT_TEMPERATURE_TEMPLATE)] = F("{{ value_json.temperatures.dhw|float(0)|round(1) }}"); - doc[FPSTR(HA_TEMPERATURE_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_TEMPERATURE_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); doc[FPSTR(HA_TEMPERATURE_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"target\" : {{ value|int(0) }}}}"); - doc[FPSTR(HA_TEMPERATURE_STATE_TOPIC)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_TEMPERATURE_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_TEMPERATURE_STATE_TEMPLATE)] = F("{{ value_json.dhw.target|int(0) }}"); - doc[FPSTR(HA_MODE_COMMAND_TOPIC)] = devicePrefix + F("/settings/set"); + doc[FPSTR(HA_MODE_COMMAND_TOPIC)] = this->getDeviceTopic("settings/set").c_str(); 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)] = devicePrefix + F("/settings"); + doc[FPSTR(HA_MODE_STATE_TOPIC)] = this->getDeviceTopic("settings").c_str(); doc[FPSTR(HA_MODE_STATE_TEMPLATE)] = F("{{ iif(value_json.dhw.enable, 'heat', 'off') }}"); doc[FPSTR(HA_MODES)][0] = F("off"); doc[FPSTR(HA_MODES)][1] = F("heat"); - doc[FPSTR(HA_ACTION_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_ACTION_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_ACTION_TEMPLATE)] = F("{{ iif(value_json.states.dhw, 'heating', 'idle') }}"); doc[FPSTR(HA_MIN_TEMP)] = minTemp; doc[FPSTR(HA_MAX_TEMP)] = maxTemp; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("climate", "dhw", "_").c_str(), doc); + return this->publish(this->getTopic("climate", "dhw", '_').c_str(), doc); } bool publishButtonRestart(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_restart"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_restart"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("restart").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("restart").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("restart"); doc[FPSTR(HA_NAME)] = F("Restart"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/state/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("state/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"actions\": {\"restart\": true}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("button", "restart").c_str(), doc); + return this->publish(this->getTopic("button", "restart").c_str(), doc); } bool publishButtonResetFault(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.fault, 'online', 'offline') }}"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_reset_fault"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_reset_fault"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("reset_fault").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("reset_fault").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("restart"); doc[FPSTR(HA_NAME)] = F("Reset fault"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/state/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("state/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"actions\": {\"resetFault\": true}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("button", "reset_fault").c_str(), doc); + return this->publish(this->getTopic("button", "reset_fault").c_str(), doc); } bool publishButtonResetDiagnostic(bool enabledByDefault = true) { JsonDocument doc; - doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/state"); + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic("state").c_str(); doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.diagnostic, 'online', 'offline') }}"); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; - doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_reset_diagnostic"); - doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_reset_diagnostic"); + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId("reset_diagnostic").c_str(); + doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId("reset_diagnostic").c_str(); doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config"); doc[FPSTR(HA_DEVICE_CLASS)] = F("restart"); doc[FPSTR(HA_NAME)] = F("Reset diagnostic"); - doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/state/set"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("state/set").c_str(); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"actions\": {\"resetDiagnostic\": true}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; - return publish(getTopic("button", "reset_diagnostic").c_str(), doc); + return this->publish(this->getTopic("button", "reset_diagnostic").c_str(), doc); } bool deleteNumberOutdoorTemp() { - return publish(getTopic("number", "outdoor_temp").c_str()); + return this->publish(this->getTopic("number", "outdoor_temp").c_str()); } bool deleteSensorOutdoorTemp() { - return publish(getTopic("sensor", "outdoor_temp").c_str()); + return this->publish(this->getTopic("sensor", "outdoor_temp").c_str()); } bool deleteNumberIndoorTemp() { - return publish(getTopic("number", "indoor_temp").c_str()); + return this->publish(this->getTopic("number", "indoor_temp").c_str()); } bool deleteSensorIndoorTemp() { - return publish(getTopic("sensor", "indoor_temp").c_str()); + return this->publish(this->getTopic("sensor", "indoor_temp").c_str()); } bool deleteSwitchDhw() { - return publish(getTopic("switch", "dhw").c_str()); + return this->publish(this->getTopic("switch", "dhw").c_str()); } bool deleteSensorCurrentDhwMinTemp() { - return publish(getTopic("sensor", "current_dhw_min_temp").c_str()); + return this->publish(this->getTopic("sensor", "current_dhw_min_temp").c_str()); } bool deleteSensorCurrentDhwMaxTemp() { - return publish(getTopic("sensor", "current_dhw_max_temp").c_str()); + return this->publish(this->getTopic("sensor", "current_dhw_max_temp").c_str()); } bool deleteNumberDhwMinTemp() { - return publish(getTopic("number", "dhw_min_temp").c_str()); + return this->publish(this->getTopic("number", "dhw_min_temp").c_str()); } bool deleteNumberDhwMaxTemp() { - return publish(getTopic("number", "dhw_max_temp").c_str()); + return this->publish(this->getTopic("number", "dhw_max_temp").c_str()); } bool deleteBinSensorDhw() { - return publish(getTopic("binary_sensor", "dhw").c_str()); + return this->publish(this->getTopic("binary_sensor", "dhw").c_str()); } bool deleteSensorDhwTemp() { - return publish(getTopic("sensor", "dhw_temp").c_str()); + return this->publish(this->getTopic("sensor", "dhw_temp").c_str()); } bool deleteNumberDhwTarget() { - return publish(getTopic("number", "dhw_target").c_str()); + return this->publish(this->getTopic("number", "dhw_target").c_str()); } bool deleteSensorDhwFlowRate() { - return publish(getTopic("sensor", "dhw_flow_rate").c_str()); + return this->publish(this->getTopic("sensor", "dhw_flow_rate").c_str()); } bool deleteClimateDhw() { - return publish(getTopic("climate", "dhw", "_").c_str()); + return this->publish(this->getTopic("climate", "dhw", '_').c_str()); } }; diff --git a/src/MqttTask.h b/src/MqttTask.h index 2f0094a..89106ee 100644 --- a/src/MqttTask.h +++ b/src/MqttTask.h @@ -1,5 +1,7 @@ #include #include +#include +#include #include "HaHelper.h" @@ -20,15 +22,20 @@ public: delete this->client; } + if (this->writer != nullptr) { + delete this->writer; + } + if (this->wifiClient != nullptr) { delete this->wifiClient; } } protected: - WiFiClient* wifiClient = nullptr; + MqttWiFiClient* wifiClient = nullptr; PubSubClient* client = nullptr; HaHelper* haHelper = nullptr; + MqttWriter* writer = nullptr; unsigned short readyForSendTime = 15000; unsigned long lastReconnectTime = 0; unsigned long connectedTime = 0; @@ -57,12 +64,39 @@ protected: void setup() { Log.sinfoln("MQTT", F("Started")); + this->wifiClient = new MqttWiFiClient(); + this->wifiClient->setSync(true); + // client settings this->client = new PubSubClient(); - this->client->setSocketTimeout(2); - this->client->setKeepAlive(5); + this->client->setClient(*this->wifiClient); + this->client->setSocketTimeout(3); + this->client->setKeepAlive(15); this->client->setBufferSize(768); - this->client->setCallback(std::bind(&MqttTask::onMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + this->client->setCallback([this] (char* topic, uint8_t* payload, unsigned int length) { + this->onMessage(topic, payload, length); + }); + + // writer + this->writer = new MqttWriter(this->client, 256); + this->writer->setYieldCallback([this] { + this->delay(10); + }); + this->writer->setEventPublishCallback([this] (const char* topic, size_t written, size_t length, bool result) { + Log.straceln("MQTT", F("%s publish %u of %u bytes to topic: %s"), result ? F("Successfully") : F("Failed"), written, length, topic); + + this->client->loop(); + this->delay(100); + }); + this->writer->setEventFlushCallback([this] (size_t, size_t) { + if (!this->wifiClient->getSync() && this->wifiClient->connected()) { + this->wifiClient->flush(); + } + + #ifdef ARDUINO_ARCH_ESP8266 + ::yield(); + #endif + }); // ha helper settings this->haHelper = new HaHelper(); @@ -70,44 +104,29 @@ protected: this->haHelper->setDeviceVersion(PROJECT_VERSION); this->haHelper->setDeviceModel(PROJECT_NAME); this->haHelper->setDeviceName(PROJECT_NAME); - this->haHelper->setClient(this->client); - this->haHelper->setYieldCallback([](void* self) { - MqttTask* task = static_cast(self); - task->client->loop(); - task->delay(100); - }, this); + this->haHelper->setWriter(this->writer); sprintf(buffer, CONFIG_URL, WiFi.localIP().toString().c_str()); this->haHelper->setDeviceConfigUrl(buffer); } void loop() { - if (this->wifiClient == nullptr || (!this->client->connected() && millis() - this->lastReconnectTime >= MQTT_RECONNECT_INTERVAL)) { - Log.sinfoln("MQTT", F("Not connected, state: %d"), this->client->state()); - - // bug? - // memory leak at random times if this is not done - if (this->wifiClient != nullptr) { - delete this->wifiClient; - this->wifiClient = nullptr; - } - - this->wifiClient = new WiFiClient(); - this->client->setClient(*this->wifiClient); - this->client->setServer(settings.mqtt.server, settings.mqtt.port); - - Log.sinfoln("MQTT", F("Connecting to %s:%u..."), settings.mqtt.server, settings.mqtt.port); - this->client->connect(settings.hostname, settings.mqtt.user, settings.mqtt.password); - - this->lastReconnectTime = millis(); - return; - } - if (!this->client->connected() && this->connected) { this->connected = false; this->onDisconnect(); + } - } else if (this->client->connected() && !this->connected) { + if (this->wifiClient == nullptr || (!this->client->connected() && millis() - this->lastReconnectTime >= MQTT_RECONNECT_INTERVAL)) { + Log.sinfoln("MQTT", F("Not connected, state: %d"), this->client->state()); + Log.sinfoln("MQTT", F("Connecting to %s:%u..."), settings.mqtt.server, settings.mqtt.port); + + this->client->setServer(settings.mqtt.server, settings.mqtt.port); + this->client->connect(settings.hostname, settings.mqtt.user, settings.mqtt.password); + + this->lastReconnectTime = millis(); + } + + if (this->client->connected() && !this->connected) { this->connected = true; this->onConnect(); } @@ -132,21 +151,19 @@ protected: // publish variables and status if (this->newConnection || millis() - this->prevPubVarsTime > settings.mqtt.interval) { - this->client->publish( - this->getTopicPath("status").c_str(), - !vars.states.otStatus ? "offline" : vars.states.fault ? "fault" : "online" + this->writer->publish( + this->haHelper->getDeviceTopic("status").c_str(), + !vars.states.otStatus ? "offline" : vars.states.fault ? "fault" : "online", + true ); - this->client->loop(); - this->publishVariables(this->getTopicPath("state").c_str()); - this->client->loop(); + this->publishVariables(this->haHelper->getDeviceTopic("state").c_str()); this->prevPubVarsTime = millis(); } // publish settings if (this->newConnection || millis() - this->prevPubSettingsTime > settings.mqtt.interval * 10) { - this->publishSettings(this->getTopicPath("settings").c_str()); - this->client->loop(); + this->publishSettings(this->haHelper->getDeviceTopic("settings").c_str()); this->prevPubSettingsTime = millis(); } @@ -173,8 +190,8 @@ protected: Log.sinfoln("MQTT", F("Emergency mode disabled")); } - this->client->subscribe(this->getTopicPath("settings/set").c_str()); - this->client->subscribe(this->getTopicPath("state/set").c_str()); + this->client->subscribe(this->haHelper->getDeviceTopic("settings/set").c_str()); + this->client->subscribe(this->haHelper->getDeviceTopic("state/set").c_str()); } void onDisconnect() { @@ -184,7 +201,7 @@ protected: Log.swarningln("MQTT", F("Disconnected (reason: %d uptime: %u s.)"), this->client->state(), uptime); } - void onMessage(char* topic, byte* payload, unsigned int length) { + void onMessage(char* topic, uint8_t* payload, unsigned int length) { if (!length) { return; } @@ -212,37 +229,16 @@ protected: JsonDocument doc; DeserializationError dErr = deserializeJson(doc, payload, length); if (dErr != DeserializationError::Ok || doc.isNull()) { - const char* errMsg; - switch (dErr.code()) { - case DeserializationError::EmptyInput: - case DeserializationError::IncompleteInput: - case DeserializationError::InvalidInput: - errMsg = "invalid input"; - break; - - case DeserializationError::NoMemory: - errMsg = "no memory"; - break; - - case DeserializationError::TooDeep: - errMsg = "too deep"; - break; - - default: - errMsg = "failed"; - break; - } - Log.swarningln("MQTT.MSG", F("No deserialization: %s"), errMsg); - + Log.swarningln("MQTT.MSG", F("Error on deserialization: %s"), dErr.f_str()); return; } - if (this->getTopicPath("state/set").compare(topic) == 0) { - this->client->publish(this->getTopicPath("state/set").c_str(), NULL, true); + if (this->haHelper->getDeviceTopic("state/set").equals(topic)) { + this->writer->publish(this->haHelper->getDeviceTopic("state/set").c_str(), nullptr, 0, true); this->updateVariables(doc); - } else if (this->getTopicPath("settings/set").compare(topic) == 0) { - this->client->publish(this->getTopicPath("settings/set").c_str(), NULL, true); + } else if (this->haHelper->getDeviceTopic("settings/set").equals(topic)) { + this->writer->publish(this->haHelper->getDeviceTopic("settings/set").c_str(), nullptr, 0, true); this->updateSettings(doc); } } @@ -727,27 +723,7 @@ protected: doc["sensors"]["indoor"]["type"] = settings.sensors.indoor.type; doc["sensors"]["indoor"]["offset"] = settings.sensors.indoor.offset; - - size_t docSize = measureJson(doc); - uint8_t* buffer = (uint8_t*) malloc(docSize * sizeof(*buffer)); - size_t length = serializeJson(doc, buffer, docSize); - - size_t written = 0; - if (length != 0) { - if (this->client->beginPublish(topic, docSize, true)) { - for (size_t offset = 0; offset < docSize; offset += 128) { - size_t packetSize = offset + 128 <= docSize ? 128 : docSize - offset; - written += this->client->write(buffer + offset, packetSize); - } - - this->client->flush(); - } - } - free(buffer); - - Log.straceln("MQTT", "Publish %u of %u bytes to topic: %s", written, docSize, topic); - - return docSize == written; + return this->writer->publish(topic, doc, true); } bool publishVariables(const char* topic) { @@ -782,30 +758,6 @@ protected: doc["parameters"]["dhwMinTemp"] = vars.parameters.dhwMinTemp; doc["parameters"]["dhwMaxTemp"] = vars.parameters.dhwMaxTemp; - - size_t docSize = measureJson(doc); - uint8_t* buffer = (uint8_t*) malloc(docSize * sizeof(*buffer)); - size_t length = serializeJson(doc, buffer, docSize); - - size_t written = 0; - if (length != 0) { - if (this->client->beginPublish(topic, docSize, true)) { - for (size_t offset = 0; offset < docSize; offset += 128) { - size_t packetSize = offset + 128 <= docSize ? 128 : docSize - offset; - written += this->client->write(buffer + offset, packetSize); - } - - this->client->flush(); - } - } - free(buffer); - - Log.straceln("MQTT", "Publish %u of %u bytes to topic: %s", written, docSize, topic); - - return docSize == written; - } - - static std::string getTopicPath(const char* topic) { - return std::string(settings.mqtt.prefix) + "/" + std::string(topic); + return this->writer->publish(topic, doc, true); } }; \ No newline at end of file diff --git a/src/defines.h b/src/defines.h index cef6a62..4a1aea5 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,5 +1,5 @@ #define PROJECT_NAME "OpenTherm Gateway" -#define PROJECT_VERSION "1.4.0" +#define PROJECT_VERSION "1.4.0-rc.1" #define PROJECT_REPO "https://github.com/Laxilef/OTGateway" #define AP_SSID "OpenTherm Gateway" #define AP_PASSWORD "otgateway123456"