bump ArduinoJson to 7.x, refactoring MqttTask

This commit is contained in:
Yurii
2023-12-13 23:23:54 +03:00
parent 8e80cecc22
commit 2a28f664cf
4 changed files with 423 additions and 337 deletions

View File

@@ -4,8 +4,18 @@
class HomeAssistantHelper {
public:
HomeAssistantHelper(PubSubClient& client) {
this->client = &client;
HomeAssistantHelper() {}
HomeAssistantHelper(PubSubClient* client) {
this->setClient(client);
}
void setClient() {
this->client = nullptr;
}
void setClient(PubSubClient* client) {
this->client = client;
}
void setYieldCallback(void(*yieldCallback)(void*)) {
@@ -18,14 +28,6 @@ public:
this->yieldArg = arg;
}
void setBufferedClient() {
this->bClient = nullptr;
}
void setBufferedClient(BufferingPrint* bClient) {
this->bClient = bClient;
}
void setDevicePrefix(String value) {
devicePrefix = value;
}
@@ -51,6 +53,10 @@ public:
}
bool publish(const char* topic, JsonDocument& doc) {
if (this->client == nullptr) {
return false;
}
doc[FPSTR(HA_DEVICE)][FPSTR(HA_IDENTIFIERS)][0] = devicePrefix;
doc[FPSTR(HA_DEVICE)][FPSTR(HA_SW_VERSION)] = deviceVersion;
@@ -70,31 +76,38 @@ public:
doc[FPSTR(HA_DEVICE)][FPSTR(HA_CONF_URL)] = deviceConfigUrl;
}
if (!client->beginPublish(topic, measureJson(doc), true)) {
if (this->yieldCallback != nullptr) {
this->yieldCallback(yieldArg);
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();
}
return false;
}
free(buffer);
if (this->bClient != nullptr) {
serializeJson(doc, *this->bClient);
this->bClient->flush();
Log.straceln("MQTT", "Publish %u of %u bytes to topic: %s", written, docSize, topic);
} else {
serializeJson(doc, *client);
}
int pubResult = client->endPublish();
if (this->yieldCallback != nullptr) {
this->yieldCallback(yieldArg);
}
return pubResult;
return docSize == written;
}
bool publish(const char* topic) {
if (this->client == nullptr) {
return false;
}
return client->publish(topic, NULL, true);
}
@@ -114,8 +127,7 @@ public:
protected:
void(*yieldCallback)(void*) = nullptr;
void* yieldArg = nullptr;
PubSubClient* client;
BufferingPrint* bClient = nullptr;
PubSubClient* client = nullptr;
String prefix = "homeassistant";
String devicePrefix = "";
String deviceVersion = "1.0";

View File

@@ -12,7 +12,8 @@
framework = arduino
lib_deps =
;arduino-libraries/NTPClient@^3.2.1
bblanchon/ArduinoJson@^6.20.0
;bblanchon/ArduinoJson@^6.21.4
https://github.com/bblanchon/ArduinoJson/archive/refs/heads/7.x.zip
;ihormelnyk/OpenTherm Library@^1.1.4
https://github.com/Laxilef/opentherm_library/archive/refs/heads/dev.zip
knolleary/PubSubClient@^2.8

View File

@@ -5,11 +5,9 @@ class HaHelper : public HomeAssistantHelper {
public:
static const byte TEMP_SOURCE_HEATING = 0;
static const byte TEMP_SOURCE_INDOOR = 1;
HaHelper(PubSubClient& client) : HomeAssistantHelper(client) {}
bool publishSelectOutdoorSensorType(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set");
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;
@@ -27,7 +25,7 @@ public:
}
bool publishSelectIndoorSensorType(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/settings/set");
#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 %}}}}");
@@ -55,7 +53,7 @@ public:
}
bool publishNumberOutdoorSensorOffset(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/settings");
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;
@@ -79,7 +77,7 @@ public:
}
bool publishNumberIndoorSensorOffset(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/settings");
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;
@@ -104,7 +102,7 @@ public:
bool publishSwitchDebug(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -124,7 +122,7 @@ public:
bool publishSwitchEmergency(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -143,7 +141,7 @@ public:
}
bool publishNumberEmergencyTarget(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -165,7 +163,7 @@ public:
}
bool publishSwitchEmergencyUseEquitherm(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/settings");
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;
@@ -187,7 +185,7 @@ public:
bool publishSwitchHeating(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating");
@@ -207,7 +205,7 @@ public:
}
bool publishSwitchHeatingTurbo(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating_turbo");
@@ -227,7 +225,7 @@ public:
}
bool publishNumberHeatingTarget(byte minTemp = 20, byte maxTemp = 90, bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating_target");
@@ -250,7 +248,7 @@ public:
}
bool publishNumberHeatingHysteresis(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -272,7 +270,7 @@ public:
}
bool publishSensorHeatingSetpoint(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating_setpoint");
@@ -290,7 +288,7 @@ public:
}
bool publishSensorCurrentHeatingMinTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_current_heating_min_temp");
@@ -308,7 +306,7 @@ public:
}
bool publishSensorCurrentHeatingMaxTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_current_heating_max_temp");
@@ -326,7 +324,7 @@ public:
}
bool publishNumberHeatingMinTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -348,7 +346,7 @@ public:
}
bool publishNumberHeatingMaxTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -370,7 +368,7 @@ public:
}
bool publishNumberHeatingMaxModulation(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -393,7 +391,7 @@ public:
bool publishSwitchDhw(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_dhw");
@@ -413,7 +411,7 @@ public:
}
bool publishNumberDhwTarget(byte minTemp = 40, byte maxTemp = 60, bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_dhw_target");
@@ -436,7 +434,7 @@ public:
}
bool publishSensorCurrentDhwMinTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_current_dhw_min_temp");
@@ -454,7 +452,7 @@ public:
}
bool publishSensorCurrentDhwMaxTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_current_dhw_max_temp");
@@ -472,7 +470,7 @@ public:
}
bool publishNumberDhwMinTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -494,7 +492,7 @@ public:
}
bool publishNumberDhwMaxTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -517,7 +515,7 @@ public:
bool publishSwitchPID(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -536,7 +534,7 @@ public:
}
bool publishNumberPIDFactorP(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_pid_p");
doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_pid_p");
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
@@ -555,7 +553,7 @@ public:
}
bool publishNumberPIDFactorI(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_pid_i");
doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_pid_i");
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
@@ -574,7 +572,7 @@ public:
}
bool publishNumberPIDFactorD(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_pid_d");
doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_pid_d");
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
@@ -593,7 +591,7 @@ public:
}
bool publishNumberPIDMinTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -615,7 +613,7 @@ public:
}
bool publishNumberPIDMaxTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -638,7 +636,7 @@ public:
bool publishSwitchEquitherm(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -657,7 +655,7 @@ public:
}
bool publishNumberEquithermFactorN(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_equitherm_n");
doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_equitherm_n");
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
@@ -676,7 +674,7 @@ public:
}
bool publishNumberEquithermFactorK(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_equitherm_k");
doc[FPSTR(HA_OBJECT_ID)] = devicePrefix + F("_equitherm_k");
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
@@ -695,7 +693,7 @@ public:
}
bool publishNumberEquithermFactorT(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/settings");
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");
@@ -717,7 +715,7 @@ public:
bool publishSwitchTuning(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -736,7 +734,7 @@ public:
}
bool publishSelectTuningRegulator(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_COMMAND_TOPIC)] = devicePrefix + F("/state/set");
@@ -756,7 +754,7 @@ public:
bool publishBinSensorStatus(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -772,7 +770,7 @@ public:
}
bool publishBinSensorOtStatus(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -787,7 +785,7 @@ public:
}
bool publishBinSensorHeating(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating");
@@ -803,7 +801,7 @@ public:
}
bool publishBinSensorDhw(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_dhw");
@@ -819,7 +817,7 @@ public:
}
bool publishBinSensorFlame(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_flame");
@@ -835,7 +833,7 @@ public:
}
bool publishBinSensorFault(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/state");
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
@@ -852,7 +850,7 @@ public:
}
bool publishBinSensorDiagnostic(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_diagnostic");
@@ -868,7 +866,7 @@ public:
}
bool publishSensorFaultCode(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/state");
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.fault, 'online', 'offline') }}");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
@@ -884,7 +882,7 @@ public:
}
bool publishSensorRssi(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_rssi");
@@ -902,7 +900,7 @@ public:
}
bool publishSensorUptime(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_uptime");
@@ -921,7 +919,7 @@ public:
bool publishSensorModulation(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_modulation_level");
@@ -939,7 +937,7 @@ public:
}
bool publishSensorPressure(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_pressure");
@@ -957,7 +955,7 @@ public:
}
bool publishSensorDhwFlowRate(bool enabledByDefault = true) {
StaticJsonDocument<1024> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_dhw_flow_rate");
@@ -976,7 +974,7 @@ public:
bool publishNumberIndoorTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -997,7 +995,7 @@ public:
}
bool publishSensorIndoorTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("any");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
@@ -1016,7 +1014,7 @@ public:
}
bool publishNumberOutdoorTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
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");
@@ -1037,7 +1035,7 @@ public:
}
bool publishSensorOutdoorTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("any");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
@@ -1056,7 +1054,7 @@ public:
}
bool publishSensorHeatingTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating_temp");
@@ -1074,7 +1072,7 @@ public:
}
bool publishSensorDhwTemp(bool enabledByDefault = true) {
StaticJsonDocument<1536> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_dhw_temp");
@@ -1093,7 +1091,7 @@ public:
bool publishClimateHeating(byte minTemp = 20, byte maxTemp = 90, byte currentTempSource = HaHelper::TEMP_SOURCE_HEATING, bool enabledByDefault = true) {
StaticJsonDocument<2560> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = devicePrefix + F("_heating");
@@ -1144,7 +1142,7 @@ public:
}
bool publishClimateDhw(byte minTemp = 40, byte maxTemp = 60, bool enabledByDefault = true) {
StaticJsonDocument<2560> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/status");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
@@ -1181,7 +1179,7 @@ public:
bool publishButtonRestart(bool enabledByDefault = true) {
StaticJsonDocument<1024> doc;
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");
@@ -1195,7 +1193,7 @@ public:
}
bool publishButtonResetFault(bool enabledByDefault = true) {
StaticJsonDocument<1024> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/state");
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.fault, 'online', 'offline') }}");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
@@ -1211,7 +1209,7 @@ public:
}
bool publishButtonResetDiagnostic(bool enabledByDefault = true) {
StaticJsonDocument<1024> doc;
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = devicePrefix + F("/state");
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.diagnostic, 'online', 'offline') }}");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;

View File

@@ -1,27 +1,44 @@
#include <WiFiClient.h>
#include <PubSubClient.h>
#include <StreamUtils.h>
#include "HaHelper.h"
WiFiClient espClient;
PubSubClient client(espClient);
HaHelper haHelper(client);
class MqttTask : public Task {
public:
MqttTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {}
~MqttTask() {
if (this->bClient != nullptr) {
// todo: delete polymorph?
//delete this->bClient;
if (this->haHelper != nullptr) {
delete this->haHelper;
}
if (this->client != nullptr) {
if (this->client->connected()) {
this->client->disconnect();
}
delete this->client;
}
if (this->wifiClient != nullptr) {
delete this->wifiClient;
}
}
protected:
BufferingPrint* bClient = nullptr;
unsigned long lastReconnectAttempt = 0;
unsigned long firstFailConnect = 0;
WiFiClient* wifiClient;
PubSubClient* client = nullptr;
HaHelper* haHelper = nullptr;
unsigned long lastReconnectTime = 0;
unsigned long connectedTime = 0;
unsigned long disconnectedTime = 0;
unsigned long prevPubVars = 0;
unsigned long prevPubSettings = 0;
bool connected = false;
bool newConnection = false;
unsigned short readyForSendTime = 15000;
const char* getTaskName() {
return "Mqtt";
@@ -35,79 +52,199 @@ protected:
return 1;
}
bool isReadyForSend() {
return millis() - this->connectedTime > this->readyForSendTime;
}
void setup() {
Log.sinfoln("MQTT", F("Started"));
this->bClient = new BufferingPrint(client, 64);
// client settings
this->client = new PubSubClient();
this->client->setSocketTimeout(2);
this->client->setKeepAlive(5);
this->client->setBufferSize(768);
this->client->setCallback(std::bind(&MqttTask::onMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
client.setCallback(std::bind(&MqttTask::__callback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
client.setBufferSize(1024);
client.setSocketTimeout(1);
haHelper.setYieldCallback([](void* self) {
// ha helper settings
this->haHelper = new HaHelper();
this->haHelper->setDevicePrefix(settings.mqtt.prefix);
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<MqttTask*>(self);
task->delay(50);
if (client.connected()) {
client.loop();
}
task->client->loop();
task->delay(100);
}, this);
haHelper.setBufferedClient(this->bClient);
haHelper.setDevicePrefix(settings.mqtt.prefix);
haHelper.setDeviceVersion(PROJECT_VERSION);
haHelper.setDeviceModel(PROJECT_NAME);
haHelper.setDeviceName(PROJECT_NAME);
sprintf(buffer, CONFIG_URL, WiFi.localIP().toString().c_str());
haHelper.setDeviceConfigUrl(buffer);
this->haHelper->setDeviceConfigUrl(buffer);
}
void loop() {
if (!client.connected() && millis() - lastReconnectAttempt >= MQTT_RECONNECT_INTERVAL) {
Log.sinfoln("MQTT", F("Not connected, state: %i, connecting to server %s..."), client.state(), settings.mqtt.server);
if (this->wifiClient == nullptr || (!this->client->connected() && millis() - this->lastReconnectTime >= MQTT_RECONNECT_INTERVAL)) {
Log.sinfoln("MQTT", F("Not connected, state: %d"), this->client->state());
client.setServer(settings.mqtt.server, settings.mqtt.port);
if (client.connect(settings.hostname, settings.mqtt.user, settings.mqtt.password)) {
Log.sinfoln("MQTT", F("Connected"));
client.subscribe(getTopicPath("settings/set").c_str());
client.subscribe(getTopicPath("state/set").c_str());
publishHaEntities();
publishNonStaticHaEntities(true);
firstFailConnect = 0;
lastReconnectAttempt = 0;
} else {
Log.swarningln("MQTT", F("Failed to connect to server"));
if (settings.emergency.enable && !vars.states.emergency) {
if (firstFailConnect == 0) {
firstFailConnect = millis();
}
if (millis() - firstFailConnect > EMERGENCY_TIME_TRESHOLD) {
vars.states.emergency = true;
Log.sinfoln("MQTT", F("Emergency mode enabled"));
}
}
lastReconnectAttempt = millis();
// bug?
// memory leak at random times if this is not done
if (this->wifiClient != nullptr) {
delete this->wifiClient;
}
delay(100);
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();
if (client.connected()) {
if (vars.states.emergency) {
vars.states.emergency = false;
} else if (this->client->connected() && !this->connected) {
this->connected = true;
this->onConnect();
}
Log.sinfoln("MQTT", F("Emergency mode disabled"));
if (!this->client->connected()) {
if (settings.emergency.enable && !vars.states.emergency) {
if (millis() - this->disconnectedTime > EMERGENCY_TIME_TRESHOLD) {
vars.states.emergency = true;
Log.sinfoln("MQTT", F("Emergency mode enabled"));
}
}
client.loop();
bool published = publishNonStaticHaEntities();
publish(published);
return;
}
this->client->loop();
// delay for publish data
if (!this->isReadyForSend()) {
return;
}
// publish variables and status
if (this->newConnection || millis() - this->prevPubVars > settings.mqtt.interval) {
this->client->publish(
this->getTopicPath("status").c_str(),
!vars.states.otStatus ? "offline" : vars.states.fault ? "fault" : "online"
);
this->client->loop();
this->publishVariables(this->getTopicPath("state").c_str());
this->client->loop();
this->prevPubVars = millis();
}
// publish settings
if (this->newConnection || millis() - this->prevPubSettings > settings.mqtt.interval * 10) {
this->publishSettings(this->getTopicPath("settings").c_str());
this->client->loop();
this->prevPubSettings = millis();
}
// publish ha entities if not published
if (this->newConnection) {
this->publishHaEntities();
this->publishNonStaticHaEntities(true);
this->newConnection = false;
} else {
// publish non static ha entities
this->publishNonStaticHaEntities();
}
}
void onConnect() {
this->connectedTime = millis();
this->newConnection = true;
unsigned long downtime = (millis() - this->disconnectedTime) / 1000;
Log.sinfoln("MQTT", F("Connected (downtime: %u s.)"), downtime);
if (vars.states.emergency) {
vars.states.emergency = false;
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());
}
void onDisconnect() {
this->disconnectedTime = millis();
unsigned long uptime = (millis() - this->connectedTime) / 1000;
Log.swarningln("MQTT", F("Disconnected (reason: %d uptime: %u s.)"), this->client->state(), uptime);
}
void onMessage(char* topic, byte* payload, unsigned int length) {
if (!length) {
return;
}
if (settings.debug) {
Log.strace("MQTT.MSG", F("Topic: %s\r\n> "), topic);
if (Log.lock()) {
for (size_t i = 0; i < length; i++) {
if (payload[i] == 0) {
break;
} else if (payload[i] == 13) {
continue;
} else if (payload[i] == 10) {
Log.print("\r\n> ");
} else {
Log.print((char) payload[i]);
}
}
Log.print("\r\n\n");
Log.flush();
Log.unlock();
}
}
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);
return;
}
if (this->getTopicPath("state/set").compare(topic) == 0) {
this->client->publish(this->getTopicPath("state/set").c_str(), NULL, true);
this->updateVariables(doc);
} else if (this->getTopicPath("settings/set").compare(topic) == 0) {
this->client->publish(this->getTopicPath("settings/set").c_str(), NULL, true);
this->updateSettings(doc);
}
}
@@ -313,18 +450,16 @@ protected:
}
}
if (flag) {
this->prevPubSettings = 0;
eeSettings.update();
publish(true);
return true;
}
return false;
}
bool updateVariables(const JsonDocument& doc) {
bool updateVariables(JsonDocument& doc) {
bool flag = false;
if (!doc["ping"].isNull() && doc["ping"]) {
@@ -370,108 +505,83 @@ protected:
}
if (flag) {
publish(true);
this->prevPubVars = 0;
return true;
}
return false;
}
void publish(bool force = false) {
static unsigned int prevPubVars = 0;
static unsigned int prevPubSettings = 0;
// publish variables and status
if (force || millis() - prevPubVars > settings.mqtt.interval) {
publishVariables(getTopicPath("state").c_str());
if (vars.states.fault) {
client.publish(getTopicPath("status").c_str(), "fault");
} else {
client.publish(getTopicPath("status").c_str(), vars.states.otStatus ? "online" : "offline");
}
prevPubVars = millis();
}
// publish settings
if (force || millis() - prevPubSettings > settings.mqtt.interval * 10) {
publishSettings(getTopicPath("settings").c_str());
prevPubSettings = millis();
}
}
void publishHaEntities() {
// main
haHelper.publishSelectOutdoorSensorType();
haHelper.publishSelectIndoorSensorType();
haHelper.publishNumberOutdoorSensorOffset(false);
haHelper.publishNumberIndoorSensorOffset(false);
haHelper.publishSwitchDebug(false);
this->haHelper->publishSelectOutdoorSensorType();
this->haHelper->publishSelectIndoorSensorType();
this->haHelper->publishNumberOutdoorSensorOffset(false);
this->haHelper->publishNumberIndoorSensorOffset(false);
this->haHelper->publishSwitchDebug(false);
// emergency
haHelper.publishSwitchEmergency();
haHelper.publishNumberEmergencyTarget();
haHelper.publishSwitchEmergencyUseEquitherm();
this->haHelper->publishSwitchEmergency();
this->haHelper->publishNumberEmergencyTarget();
this->haHelper->publishSwitchEmergencyUseEquitherm();
// heating
haHelper.publishSwitchHeating(false);
haHelper.publishSwitchHeatingTurbo();
haHelper.publishNumberHeatingHysteresis();
haHelper.publishSensorHeatingSetpoint(false);
haHelper.publishSensorCurrentHeatingMinTemp(false);
haHelper.publishSensorCurrentHeatingMaxTemp(false);
haHelper.publishNumberHeatingMinTemp(false);
haHelper.publishNumberHeatingMaxTemp(false);
haHelper.publishNumberHeatingMaxModulation(false);
this->haHelper->publishSwitchHeating(false);
this->haHelper->publishSwitchHeatingTurbo();
this->haHelper->publishNumberHeatingHysteresis();
this->haHelper->publishSensorHeatingSetpoint(false);
this->haHelper->publishSensorCurrentHeatingMinTemp(false);
this->haHelper->publishSensorCurrentHeatingMaxTemp(false);
this->haHelper->publishNumberHeatingMinTemp(false);
this->haHelper->publishNumberHeatingMaxTemp(false);
this->haHelper->publishNumberHeatingMaxModulation(false);
// pid
haHelper.publishSwitchPID();
haHelper.publishNumberPIDFactorP();
haHelper.publishNumberPIDFactorI();
haHelper.publishNumberPIDFactorD();
haHelper.publishNumberPIDMinTemp(false);
haHelper.publishNumberPIDMaxTemp(false);
this->haHelper->publishSwitchPID();
this->haHelper->publishNumberPIDFactorP();
this->haHelper->publishNumberPIDFactorI();
this->haHelper->publishNumberPIDFactorD();
this->haHelper->publishNumberPIDMinTemp(false);
this->haHelper->publishNumberPIDMaxTemp(false);
// equitherm
haHelper.publishSwitchEquitherm();
haHelper.publishNumberEquithermFactorN();
haHelper.publishNumberEquithermFactorK();
haHelper.publishNumberEquithermFactorT();
this->haHelper->publishSwitchEquitherm();
this->haHelper->publishNumberEquithermFactorN();
this->haHelper->publishNumberEquithermFactorK();
this->haHelper->publishNumberEquithermFactorT();
// tuning
haHelper.publishSwitchTuning();
haHelper.publishSelectTuningRegulator();
this->haHelper->publishSwitchTuning();
this->haHelper->publishSelectTuningRegulator();
// states
haHelper.publishBinSensorStatus();
haHelper.publishBinSensorOtStatus();
haHelper.publishBinSensorHeating();
haHelper.publishBinSensorFlame();
haHelper.publishBinSensorFault();
haHelper.publishBinSensorDiagnostic();
this->haHelper->publishBinSensorStatus();
this->haHelper->publishBinSensorOtStatus();
this->haHelper->publishBinSensorHeating();
this->haHelper->publishBinSensorFlame();
this->haHelper->publishBinSensorFault();
this->haHelper->publishBinSensorDiagnostic();
// sensors
haHelper.publishSensorModulation(false);
haHelper.publishSensorPressure(false);
haHelper.publishSensorFaultCode();
haHelper.publishSensorRssi(false);
haHelper.publishSensorUptime(false);
this->haHelper->publishSensorModulation(false);
this->haHelper->publishSensorPressure(false);
this->haHelper->publishSensorFaultCode();
this->haHelper->publishSensorRssi(false);
this->haHelper->publishSensorUptime(false);
// temperatures
haHelper.publishNumberIndoorTemp();
haHelper.publishSensorHeatingTemp();
this->haHelper->publishNumberIndoorTemp();
this->haHelper->publishSensorHeatingTemp();
// buttons
haHelper.publishButtonRestart(false);
haHelper.publishButtonResetFault();
haHelper.publishButtonResetDiagnostic();
this->haHelper->publishButtonRestart(false);
this->haHelper->publishButtonResetFault();
this->haHelper->publishButtonResetDiagnostic();
}
bool publishNonStaticHaEntities(bool force = false) {
static byte _heatingMinTemp, _heatingMaxTemp, _dhwMinTemp, _dhwMaxTemp;
static bool _isStupidMode, _editableOutdoorTemp, _editableIndoorTemp, _dhwPresent;
static byte _heatingMinTemp, _heatingMaxTemp, _dhwMinTemp, _dhwMaxTemp = 0;
static bool _isStupidMode, _editableOutdoorTemp, _editableIndoorTemp, _dhwPresent = false;
bool published = false;
bool isStupidMode = !settings.pid.enable && !settings.equitherm.enable;
@@ -484,26 +594,26 @@ protected:
_dhwPresent = settings.opentherm.dhwPresent;
if (_dhwPresent) {
haHelper.publishSwitchDhw(false);
haHelper.publishSensorCurrentDhwMinTemp(false);
haHelper.publishSensorCurrentDhwMaxTemp(false);
haHelper.publishNumberDhwMinTemp(false);
haHelper.publishNumberDhwMaxTemp(false);
haHelper.publishBinSensorDhw();
haHelper.publishSensorDhwTemp();
haHelper.publishSensorDhwFlowRate(false);
this->haHelper->publishSwitchDhw(false);
this->haHelper->publishSensorCurrentDhwMinTemp(false);
this->haHelper->publishSensorCurrentDhwMaxTemp(false);
this->haHelper->publishNumberDhwMinTemp(false);
this->haHelper->publishNumberDhwMaxTemp(false);
this->haHelper->publishBinSensorDhw();
this->haHelper->publishSensorDhwTemp();
this->haHelper->publishSensorDhwFlowRate(false);
} else {
haHelper.deleteSwitchDhw();
haHelper.deleteSensorCurrentDhwMinTemp();
haHelper.deleteSensorCurrentDhwMaxTemp();
haHelper.deleteNumberDhwMinTemp();
haHelper.deleteNumberDhwMaxTemp();
haHelper.deleteBinSensorDhw();
haHelper.deleteSensorDhwTemp();
haHelper.deleteNumberDhwTarget();
haHelper.deleteClimateDhw();
haHelper.deleteSensorDhwFlowRate();
this->haHelper->deleteSwitchDhw();
this->haHelper->deleteSensorCurrentDhwMinTemp();
this->haHelper->deleteSensorCurrentDhwMaxTemp();
this->haHelper->deleteNumberDhwMinTemp();
this->haHelper->deleteNumberDhwMaxTemp();
this->haHelper->deleteBinSensorDhw();
this->haHelper->deleteSensorDhwTemp();
this->haHelper->deleteNumberDhwTarget();
this->haHelper->deleteClimateDhw();
this->haHelper->deleteSensorDhwFlowRate();
}
published = true;
@@ -518,8 +628,8 @@ protected:
_heatingMaxTemp = heatingMaxTemp;
_isStupidMode = isStupidMode;
haHelper.publishNumberHeatingTarget(heatingMinTemp, heatingMaxTemp, false);
haHelper.publishClimateHeating(
this->haHelper->publishNumberHeatingTarget(heatingMinTemp, heatingMaxTemp, false);
this->haHelper->publishClimateHeating(
heatingMinTemp,
heatingMaxTemp,
isStupidMode ? HaHelper::TEMP_SOURCE_HEATING : HaHelper::TEMP_SOURCE_INDOOR
@@ -529,7 +639,7 @@ protected:
} else if (_isStupidMode != isStupidMode) {
_isStupidMode = isStupidMode;
haHelper.publishClimateHeating(
this->haHelper->publishClimateHeating(
heatingMinTemp,
heatingMaxTemp,
isStupidMode ? HaHelper::TEMP_SOURCE_HEATING : HaHelper::TEMP_SOURCE_INDOOR
@@ -542,8 +652,8 @@ protected:
_dhwMinTemp = settings.dhw.minTemp;
_dhwMaxTemp = settings.dhw.maxTemp;
haHelper.publishNumberDhwTarget(settings.dhw.minTemp, settings.dhw.maxTemp, false);
haHelper.publishClimateDhw(settings.dhw.minTemp, settings.dhw.maxTemp);
this->haHelper->publishNumberDhwTarget(settings.dhw.minTemp, settings.dhw.maxTemp, false);
this->haHelper->publishClimateDhw(settings.dhw.minTemp, settings.dhw.maxTemp);
published = true;
}
@@ -552,11 +662,11 @@ protected:
_editableOutdoorTemp = editableOutdoorTemp;
if (editableOutdoorTemp) {
haHelper.deleteSensorOutdoorTemp();
haHelper.publishNumberOutdoorTemp();
this->haHelper->deleteSensorOutdoorTemp();
this->haHelper->publishNumberOutdoorTemp();
} else {
haHelper.deleteNumberOutdoorTemp();
haHelper.publishSensorOutdoorTemp();
this->haHelper->deleteNumberOutdoorTemp();
this->haHelper->publishSensorOutdoorTemp();
}
published = true;
@@ -566,11 +676,11 @@ protected:
_editableIndoorTemp = editableIndoorTemp;
if (editableIndoorTemp) {
haHelper.deleteSensorIndoorTemp();
haHelper.publishNumberIndoorTemp();
this->haHelper->deleteSensorIndoorTemp();
this->haHelper->publishNumberIndoorTemp();
} else {
haHelper.deleteNumberIndoorTemp();
haHelper.publishSensorIndoorTemp();
this->haHelper->deleteNumberIndoorTemp();
this->haHelper->publishSensorIndoorTemp();
}
published = true;
@@ -580,8 +690,7 @@ protected:
}
bool publishSettings(const char* topic) {
StaticJsonDocument<2048> doc;
JsonDocument doc;
doc["debug"] = settings.debug;
doc["emergency"]["enable"] = settings.emergency.enable;
@@ -619,18 +728,31 @@ protected:
doc["sensors"]["indoor"]["type"] = settings.sensors.indoor.type;
doc["sensors"]["indoor"]["offset"] = settings.sensors.indoor.offset;
if (!client.beginPublish(topic, measureJson(doc), false)) {
return false;
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);
serializeJson(doc, *this->bClient);
this->bClient->flush();
Log.straceln("MQTT", "Publish %u of %u bytes to topic: %s", written, docSize, topic);
return client.endPublish();
return docSize == written;
}
bool publishVariables(const char* topic) {
StaticJsonDocument<2048> doc;
JsonDocument doc;
doc["tuning"]["enable"] = vars.tuning.enable;
doc["tuning"]["regulator"] = vars.tuning.regulator;
@@ -661,77 +783,30 @@ protected:
doc["parameters"]["dhwMinTemp"] = vars.parameters.dhwMinTemp;
doc["parameters"]["dhwMaxTemp"] = vars.parameters.dhwMaxTemp;
if (!client.beginPublish(topic, measureJson(doc), false)) {
return false;
}
serializeJson(doc, *this->bClient);
this->bClient->flush();
return client.endPublish();
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);
}
void __callback(char* topic, byte* payload, unsigned int length) {
if (!length) {
return;
}
if (settings.debug) {
Log.strace("MQTT.MSG", F("Topic: %s\r\n> "), topic);
if (Log.lock()) {
for (unsigned int i = 0; i < length; i++) {
if ( payload[i] == 10 ) {
Log.print("\r\n> ");
} else {
Log.print((char) payload[i]);
}
}
Log.print("\r\n\n");
Log.flush();
Log.unlock();
}
}
StaticJsonDocument<2048> doc;
DeserializationError dErr = deserializeJson(doc, (const byte*) 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);
return;
}
if (getTopicPath("state/set").compare(topic) == 0) {
updateVariables(doc);
client.publish(getTopicPath("state/set").c_str(), NULL, true);
} else if (getTopicPath("settings/set").compare(topic) == 0) {
updateSettings(doc);
client.publish(getTopicPath("settings/set").c_str(), NULL, true);
}
}
};