From 7149f52d6210fd89be03abd5e30fcc1b9b97998a Mon Sep 17 00:00:00 2001 From: Yurii Date: Sat, 16 Dec 2023 05:05:37 +0300 Subject: [PATCH] Heap fragmentation optimization Moving object creation to task constructors --- lib/HomeAssistantHelper/HomeAssistantHelper.h | 3 + lib/MqttWriter/MqttWriter.h | 1 - platformio.ini | 2 +- src/HaHelper.h | 60 ++++++++ src/MainTask.h | 16 ++- src/MqttTask.h | 26 +++- src/OpenThermTask.h | 36 ++--- src/SensorsTask.h | 136 ++++++++++-------- src/WifiManagerTask.h | 99 +++++++------ src/defines.h | 2 +- 10 files changed, 244 insertions(+), 137 deletions(-) diff --git a/lib/HomeAssistantHelper/HomeAssistantHelper.h b/lib/HomeAssistantHelper/HomeAssistantHelper.h index a370e6d..cb8bcf8 100644 --- a/lib/HomeAssistantHelper/HomeAssistantHelper.h +++ b/lib/HomeAssistantHelper/HomeAssistantHelper.h @@ -71,6 +71,9 @@ public: } bool result = this->writer->publish(topic, doc, true); + doc.clear(); + doc.shrinkToFit(); + if (this->eventPublishCallback) { this->eventPublishCallback(topic, result); } diff --git a/lib/MqttWriter/MqttWriter.h b/lib/MqttWriter/MqttWriter.h index 280a83c..da2362f 100644 --- a/lib/MqttWriter/MqttWriter.h +++ b/lib/MqttWriter/MqttWriter.h @@ -96,7 +96,6 @@ public: size_t written = 0; if (this->client->beginPublish(topic, docSize, retained)) { serializeJson(doc, *this); - doc.clear(); this->flush(); written = this->writeAfterLock; diff --git a/platformio.ini b/platformio.ini index b2c9237..739a76d 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-rc.1 +version = 1.4.0-rc.2 ; Defaults [esp8266_defaults] diff --git a/src/HaHelper.h b/src/HaHelper.h index ef4c23f..9bc5d10 100644 --- a/src/HaHelper.h +++ b/src/HaHelper.h @@ -21,6 +21,7 @@ public: doc[FPSTR(HA_OPTIONS)][1] = F("Manual"); doc[FPSTR(HA_OPTIONS)][2] = F("External"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("select", "outdoor_sensor_type").c_str(), doc); } @@ -50,6 +51,7 @@ public: doc[FPSTR(HA_OPTIONS)][2] = F("Bluetooth"); #endif doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("select", "indoor_sensor_type").c_str(), doc); } @@ -75,6 +77,7 @@ public: doc[FPSTR(HA_STEP)] = 0.1; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "outdoor_sensor_offset").c_str(), doc); } @@ -100,6 +103,7 @@ public: doc[FPSTR(HA_STEP)] = 0.1; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "indoor_sensor_offset").c_str(), doc); } @@ -121,6 +125,7 @@ public: doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"debug\": true}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"debug\": false}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("switch", "debug").c_str(), doc); } @@ -142,6 +147,7 @@ public: doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"emergency\": {\"enable\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"emergency\": {\"enable\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("switch", "emergency").c_str(), doc); } @@ -165,6 +171,7 @@ public: doc[FPSTR(HA_STEP)] = 0.5; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "emergency_target").c_str(), doc); } @@ -187,6 +194,7 @@ public: doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"emergency\": {\"useEquitherm\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"emergency\": {\"useEquitherm\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("switch", "emergency_use_equitherm").c_str(), doc); } @@ -209,6 +217,7 @@ public: doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"heating\": {\"enable\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"heating\": {\"enable\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("switch", "heating").c_str(), doc); } @@ -230,6 +239,7 @@ public: doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"heating\": {\"turbo\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"heating\": {\"turbo\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("switch", "heating_turbo").c_str(), doc); } @@ -254,6 +264,7 @@ public: doc[FPSTR(HA_STEP)] = 0.5; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "heating_target").c_str(), doc); } @@ -277,6 +288,7 @@ public: doc[FPSTR(HA_STEP)] = 0.1; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "heating_hysteresis").c_str(), doc); } @@ -296,6 +308,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.parameters.heatingSetpoint|int(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("sensor", "heating_setpoint").c_str(), doc); } @@ -315,6 +328,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.parameters.heatingMinTemp|int(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("sensor", "current_heating_min_temp").c_str(), doc); } @@ -334,6 +348,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.parameters.heatingMaxTemp|int(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("sensor", "current_heating_max_temp").c_str(), doc); } @@ -357,6 +372,7 @@ public: doc[FPSTR(HA_STEP)] = 1; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "heating_min_temp").c_str(), doc); } @@ -380,6 +396,7 @@ public: doc[FPSTR(HA_STEP)] = 1; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "heating_max_temp").c_str(), doc); } @@ -403,6 +420,7 @@ public: doc[FPSTR(HA_STEP)] = 1; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "heating_max_modulation").c_str(), doc); } @@ -425,6 +443,7 @@ public: doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"dhw\": {\"enable\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"dhw\": {\"enable\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("switch", "dhw").c_str(), doc); } @@ -449,6 +468,7 @@ public: doc[FPSTR(HA_STEP)] = 1; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "dhw_target").c_str(), doc); } @@ -468,6 +488,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.parameters.dhwMinTemp|int(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("sensor", "current_dhw_min_temp").c_str(), doc); } @@ -487,6 +508,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.parameters.dhwMaxTemp|int(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("sensor", "current_dhw_max_temp").c_str(), doc); } @@ -510,6 +532,7 @@ public: doc[FPSTR(HA_STEP)] = 1; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "dhw_min_temp").c_str(), doc); } @@ -533,6 +556,7 @@ public: doc[FPSTR(HA_STEP)] = 1; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "dhw_max_temp").c_str(), doc); } @@ -554,6 +578,7 @@ public: doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"pid\": {\"enable\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"pid\": {\"enable\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("switch", "pid").c_str(), doc); } @@ -574,6 +599,7 @@ public: doc[FPSTR(HA_STEP)] = 0.001; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "pid_p_factor").c_str(), doc); } @@ -594,6 +620,7 @@ public: doc[FPSTR(HA_STEP)] = 0.001; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "pid_i_factor").c_str(), doc); } @@ -614,6 +641,7 @@ public: doc[FPSTR(HA_STEP)] = 0.001; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "pid_d_factor").c_str(), doc); } @@ -637,6 +665,7 @@ public: doc[FPSTR(HA_STEP)] = 1; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "pid_min_temp").c_str(), doc); } @@ -660,6 +689,7 @@ public: doc[FPSTR(HA_STEP)] = 1; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "pid_max_temp").c_str(), doc); } @@ -681,6 +711,7 @@ public: doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"equitherm\": {\"enable\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"equitherm\": {\"enable\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("switch", "equitherm").c_str(), doc); } @@ -701,6 +732,7 @@ public: doc[FPSTR(HA_STEP)] = 0.001; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "equitherm_n_factor").c_str(), doc); } @@ -721,6 +753,7 @@ public: doc[FPSTR(HA_STEP)] = 0.01; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "equitherm_k_factor").c_str(), doc); } @@ -743,6 +776,7 @@ public: doc[FPSTR(HA_STEP)] = 0.01; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "equitherm_t_factor").c_str(), doc); } @@ -764,6 +798,7 @@ public: doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"tuning\": {\"enable\" : true}}"); doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"tuning\": {\"enable\" : false}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("switch", "tuning").c_str(), doc); } @@ -784,6 +819,7 @@ public: doc[FPSTR(HA_OPTIONS)][0] = F("Equitherm"); doc[FPSTR(HA_OPTIONS)][1] = F("PID"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("select", "tuning_regulator").c_str(), doc); } @@ -801,6 +837,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("status"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value == 'online', 'OFF', 'ON') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 60; + doc.shrinkToFit(); return this->publish(this->getTopic("binary_sensor", "status").c_str(), doc); } @@ -817,6 +854,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'OFF', 'ON') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("binary_sensor", "ot_status").c_str(), doc); } @@ -834,6 +872,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.heating, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("binary_sensor", "heating").c_str(), doc); } @@ -851,6 +890,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.dhw, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("binary_sensor", "dhw").c_str(), doc); } @@ -868,6 +908,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.flame, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("binary_sensor", "flame").c_str(), doc); } @@ -886,6 +927,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.fault, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("binary_sensor", "fault").c_str(), doc); } @@ -903,6 +945,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.diagnostic, 'ON', 'OFF') }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("binary_sensor", "diagnostic").c_str(), doc); } @@ -920,6 +963,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ \"E%02d\"|format(value_json.sensors.faultCode) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("sensor", "fault_code").c_str(), doc); } @@ -939,6 +983,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.sensors.rssi|float(0)|round(1) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("sensor", "rssi").c_str(), doc); } @@ -958,6 +1003,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.sensors.uptime|int(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("sensor", "uptime").c_str(), doc); } @@ -978,6 +1024,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.sensors.modulation|float(0)|round(0) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("sensor", "modulation").c_str(), doc); } @@ -997,6 +1044,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.sensors.pressure|float(0)|round(2) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("sensor", "pressure").c_str(), doc); } @@ -1016,6 +1064,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.sensors.dhwFlowRate|float(0)|round(2) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("sensor", "dhw_flow_rate").c_str(), doc); } @@ -1039,6 +1088,7 @@ public: doc[FPSTR(HA_STEP)] = 0.01; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "indoor_temp").c_str(), doc); } @@ -1059,6 +1109,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.indoor|float(0)|round(1) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("sensor", "indoor_temp").c_str(), doc); } @@ -1081,6 +1132,7 @@ public: doc[FPSTR(HA_STEP)] = 0.01; doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("number", "outdoor_temp").c_str(), doc); } @@ -1101,6 +1153,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.outdoor|float(0)|round(1) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("sensor", "outdoor_temp").c_str(), doc); } @@ -1120,6 +1173,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.heating|float(0)|round(2) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("sensor", "heating_temp").c_str(), doc); } @@ -1139,6 +1193,7 @@ public: doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic("state"); doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.dhw|float(0)|round(2) }}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("sensor", "dhw_temp").c_str(), doc); } @@ -1192,6 +1247,7 @@ public: doc[FPSTR(HA_MAX_TEMP)] = maxTemp; doc[FPSTR(HA_TEMP_STEP)] = 0.5; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("climate", "heating", '_').c_str(), doc); } @@ -1228,6 +1284,7 @@ public: doc[FPSTR(HA_MIN_TEMP)] = minTemp; doc[FPSTR(HA_MAX_TEMP)] = maxTemp; doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("climate", "dhw", '_').c_str(), doc); } @@ -1244,6 +1301,7 @@ public: doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("state/set"); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"actions\": {\"restart\": true}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("button", "restart").c_str(), doc); } @@ -1261,6 +1319,7 @@ public: doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("state/set"); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"actions\": {\"resetFault\": true}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("button", "reset_fault").c_str(), doc); } @@ -1278,6 +1337,7 @@ public: doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic("state/set"); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"actions\": {\"resetDiagnostic\": true}}"); doc[FPSTR(HA_EXPIRE_AFTER)] = 120; + doc.shrinkToFit(); return this->publish(this->getTopic("button", "reset_diagnostic").c_str(), doc); } diff --git a/src/MainTask.h b/src/MainTask.h index d2a9729..a2de4b0 100644 --- a/src/MainTask.h +++ b/src/MainTask.h @@ -11,13 +11,22 @@ extern EEManager eeSettings; class MainTask : public Task { public: - MainTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {} + MainTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) { + this->blinker = new Blinker(); + } + + ~MainTask() { + if (this->blinker != nullptr) { + delete this->blinker; + } + } protected: const static byte REASON_PUMP_START_HEATING = 1; const static byte REASON_PUMP_START_ANTISTUCK = 2; Blinker* blinker = nullptr; + bool blinkerInitialized = false; unsigned long lastHeapInfo = 0; unsigned long firstFailConnect = 0; unsigned int heapSize = 0; @@ -192,8 +201,9 @@ protected: static unsigned long endBlinkTime = 0; static bool ledOn = false; - if (this->blinker == nullptr) { - this->blinker = new Blinker(ledPin); + if (!this->blinkerInitialized) { + this->blinker->init(ledPin); + this->blinkerInitialized = true; } if (WiFi.status() != WL_CONNECTED) { diff --git a/src/MqttTask.h b/src/MqttTask.h index 89106ee..8d913b0 100644 --- a/src/MqttTask.h +++ b/src/MqttTask.h @@ -7,7 +7,12 @@ class MqttTask : public Task { public: - MqttTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {} + MqttTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) { + this->wifiClient = new MqttWiFiClient(); + this->client = new PubSubClient(); + this->writer = new MqttWriter(this->client, 256); + this->haHelper = new HaHelper(); + } ~MqttTask() { if (this->haHelper != nullptr) { @@ -64,11 +69,10 @@ protected: void setup() { Log.sinfoln("MQTT", F("Started")); - this->wifiClient = new MqttWiFiClient(); + // wificlient settings this->wifiClient->setSync(true); // client settings - this->client = new PubSubClient(); this->client->setClient(*this->wifiClient); this->client->setSocketTimeout(3); this->client->setKeepAlive(15); @@ -77,8 +81,7 @@ protected: this->onMessage(topic, payload, length); }); - // writer - this->writer = new MqttWriter(this->client, 256); + // writer settings this->writer->setYieldCallback([this] { this->delay(10); }); @@ -86,7 +89,7 @@ protected: 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->delay(250); }); this->writer->setEventFlushCallback([this] (size_t, size_t) { if (!this->wifiClient->getSync() && this->wifiClient->connected()) { @@ -99,7 +102,6 @@ protected: }); // ha helper settings - this->haHelper = new HaHelper(); this->haHelper->setDevicePrefix(settings.mqtt.prefix); this->haHelper->setDeviceVersion(PROJECT_VERSION); this->haHelper->setDeviceModel(PROJECT_NAME); @@ -445,6 +447,9 @@ protected: } } + doc.clear(); + doc.shrinkToFit(); + if (flag) { this->prevPubSettingsTime = 0; eeSettings.update(); @@ -499,6 +504,9 @@ protected: vars.actions.resetDiagnostic = true; } + doc.clear(); + doc.shrinkToFit(); + if (flag) { this->prevPubVarsTime = 0; return true; @@ -723,6 +731,8 @@ protected: doc["sensors"]["indoor"]["type"] = settings.sensors.indoor.type; doc["sensors"]["indoor"]["offset"] = settings.sensors.indoor.offset; + doc.shrinkToFit(); + return this->writer->publish(topic, doc, true); } @@ -758,6 +768,8 @@ protected: doc["parameters"]["dhwMinTemp"] = vars.parameters.dhwMinTemp; doc["parameters"]["dhwMaxTemp"] = vars.parameters.dhwMaxTemp; + doc.shrinkToFit(); + return this->writer->publish(topic, doc, true); } }; \ No newline at end of file diff --git a/src/OpenThermTask.h b/src/OpenThermTask.h index c1c22d2..1788607 100644 --- a/src/OpenThermTask.h +++ b/src/OpenThermTask.h @@ -11,7 +11,9 @@ const char S_OT_HEATING[] PROGMEM = "OT.HEATING"; class OpenThermTask : public Task { public: - OpenThermTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {} + OpenThermTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) { + ot = new CustomOpenTherm(settings.opentherm.inPin, settings.opentherm.outPin); + } static void IRAM_ATTR handleInterrupt() { ot->handleInterrupt(); @@ -44,8 +46,6 @@ protected: void setup() { Log.sinfoln(FPSTR(S_OT), F("Started. GPIO IN: %hhu, GPIO OUT: %hhu"), settings.opentherm.inPin, settings.opentherm.outPin); - ot = new CustomOpenTherm(settings.opentherm.inPin, settings.opentherm.outPin); - ot->setHandleSendRequestCallback(OpenThermTask::sendRequestCallback); ot->setYieldCallback([](void* self) { static_cast(self)->delay(25); @@ -95,7 +95,7 @@ protected: static byte currentHeatingTemp, currentDhwTemp = 0; unsigned long localResponse; - bool heatingEnabled = (vars.states.emergency || settings.heating.enable) && pump && isReady(); + bool heatingEnabled = (vars.states.emergency || settings.heating.enable) && this->pump && isReady(); bool heatingCh2Enabled = settings.opentherm.heatingCh2Enabled; if (settings.opentherm.heatingCh1ToCh2) { heatingCh2Enabled = heatingEnabled; @@ -135,7 +135,7 @@ protected: } if (vars.parameters.heatingEnabled != heatingEnabled) { - prevUpdateNonEssentialVars = 0; + this->prevUpdateNonEssentialVars = 0; vars.parameters.heatingEnabled = heatingEnabled; Log.sinfoln(FPSTR(S_OT_HEATING), "%s", heatingEnabled ? F("Enabled") : F("Disabled")); } @@ -147,7 +147,7 @@ protected: vars.states.diagnostic = ot->isDiagnostic(localResponse); // These parameters will be updated every minute - if (millis() - prevUpdateNonEssentialVars > 60000) { + if (millis() - this->prevUpdateNonEssentialVars > 60000) { if (!heatingEnabled && settings.opentherm.modulationSyncWithHeating) { if (setMaxModulationLevel(0)) { Log.snoticeln(FPSTR(S_OT_HEATING), F("Set max modulation 0% (off)")); @@ -233,7 +233,7 @@ protected: updatePressure(); - prevUpdateNonEssentialVars = millis(); + this->prevUpdateNonEssentialVars = millis(); //yield(); } @@ -301,7 +301,7 @@ protected: // Записываем заданную температуру ГВС if (ot->setDhwTemp(newDhwTemp)) { currentDhwTemp = newDhwTemp; - dhwSetTempTime = millis(); + this->dhwSetTempTime = millis(); } else { Log.swarningln(FPSTR(S_OT_DHW), F("Failed set temp")); @@ -324,7 +324,7 @@ protected: // Записываем заданную температуру if (ot->setHeatingCh1Temp(vars.parameters.heatingSetpoint)) { currentHeatingTemp = vars.parameters.heatingSetpoint; - heatingSetTempTime = millis(); + this->heatingSetTempTime = millis(); } else { Log.swarningln(FPSTR(S_OT_HEATING), F("Failed set temp")); @@ -343,15 +343,15 @@ protected: // только для pid и/или equitherm if (settings.heating.hysteresis > 0 && !vars.states.emergency && (settings.equitherm.enable || settings.pid.enable)) { float halfHyst = settings.heating.hysteresis / 2; - if (pump && vars.temperatures.indoor - settings.heating.target + 0.0001 >= halfHyst) { - pump = false; + if (this->pump && vars.temperatures.indoor - settings.heating.target + 0.0001 >= halfHyst) { + this->pump = false; - } else if (!pump && vars.temperatures.indoor - settings.heating.target - 0.0001 <= -(halfHyst)) { - pump = true; + } else if (!this->pump && vars.temperatures.indoor - settings.heating.target - 0.0001 <= -(halfHyst)) { + this->pump = true; } - } else if (!pump) { - pump = true; + } else if (!this->pump) { + this->pump = true; } } @@ -392,15 +392,15 @@ protected: } bool isReady() { - return millis() - startupTime > readyTime; + return millis() - this->startupTime > this->readyTime; } bool needSetDhwTemp() { - return millis() - dhwSetTempTime > dhwSetTempInterval; + return millis() - this->dhwSetTempTime > this->dhwSetTempInterval; } bool needSetHeatingTemp() { - return millis() - heatingSetTempTime > heatingSetTempInterval; + return millis() - this->heatingSetTempTime > this->heatingSetTempInterval; } static void printRequestDetail(OpenThermMessageID id, OpenThermResponseStatus status, unsigned long request, unsigned long response, byte attempt) { diff --git a/src/SensorsTask.h b/src/SensorsTask.h index 05fe9c0..6818939 100644 --- a/src/SensorsTask.h +++ b/src/SensorsTask.h @@ -18,20 +18,44 @@ const char S_SENSORS_BLE[] PROGMEM = "SENSORS.BLE"; class SensorsTask : public LeanTask { public: - SensorsTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {} + SensorsTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) { + this->oneWireOutdoorSensor = new OneWire(); + this->outdoorSensor = new DallasTemperature(this->oneWireOutdoorSensor); + + this->oneWireIndoorSensor = new OneWire(); + this->indoorSensor = new DallasTemperature(this->oneWireIndoorSensor); + } + + ~SensorsTask() { + if (this->outdoorSensor != nullptr) { + delete this->outdoorSensor; + } + + if (this->oneWireOutdoorSensor != nullptr) { + delete this->oneWireOutdoorSensor; + } + + if (this->indoorSensor != nullptr) { + delete this->indoorSensor; + } + + if (this->oneWireIndoorSensor != nullptr) { + delete this->oneWireIndoorSensor; + } + } protected: - OneWire* oneWireOutdoorSensor; - OneWire* oneWireIndoorSensor; + OneWire* oneWireOutdoorSensor = nullptr; + OneWire* oneWireIndoorSensor = nullptr; - DallasTemperature* outdoorSensor; - DallasTemperature* indoorSensor; + DallasTemperature* outdoorSensor = nullptr; + DallasTemperature* indoorSensor = nullptr; bool initOutdoorSensor = false; unsigned long startOutdoorConversionTime = 0; float filteredOutdoorTemp = 0; bool emptyOutdoorTemp = true; - + bool initIndoorSensor = false; unsigned long startIndoorConversionTime = 0; float filteredIndoorTemp = 0; @@ -123,27 +147,27 @@ protected: #endif void outdoorTemperatureSensor() { - if (!initOutdoorSensor) { - oneWireOutdoorSensor = new OneWire(settings.sensors.outdoor.pin); - outdoorSensor = new DallasTemperature(oneWireOutdoorSensor); - outdoorSensor->begin(); - outdoorSensor->setResolution(12); - outdoorSensor->setWaitForConversion(false); - outdoorSensor->requestTemperatures(); - startOutdoorConversionTime = millis(); - initOutdoorSensor = true; + if (!this->initOutdoorSensor) { + this->oneWireOutdoorSensor->begin(settings.sensors.outdoor.pin); + this->outdoorSensor->begin(); + this->outdoorSensor->setResolution(12); + this->outdoorSensor->setWaitForConversion(false); + this->outdoorSensor->requestTemperatures(); + this->startOutdoorConversionTime = millis(); + + this->initOutdoorSensor = true; } - unsigned long estimateConversionTime = millis() - startOutdoorConversionTime; - if (estimateConversionTime < outdoorSensor->millisToWaitForConversion()) { + unsigned long estimateConversionTime = millis() - this->startOutdoorConversionTime; + if (estimateConversionTime < this->outdoorSensor->millisToWaitForConversion()) { return; } - bool completed = outdoorSensor->isConversionComplete(); + bool completed = this->outdoorSensor->isConversionComplete(); if (!completed && estimateConversionTime >= 1000) { // fail, retry - outdoorSensor->requestTemperatures(); - startOutdoorConversionTime = millis(); + this->outdoorSensor->requestTemperatures(); + this->startOutdoorConversionTime = millis(); Log.serrorln(FPSTR(S_SENSORS_OUTDOOR), F("Could not read temperature data (no response)")); } @@ -152,55 +176,55 @@ protected: return; } - float rawTemp = outdoorSensor->getTempCByIndex(0); + float rawTemp = this->outdoorSensor->getTempCByIndex(0); if (rawTemp == DEVICE_DISCONNECTED_C) { Log.serrorln(FPSTR(S_SENSORS_OUTDOOR), F("Could not read temperature data (not connected)")); } else { Log.straceln(FPSTR(S_SENSORS_OUTDOOR), F("Raw temp: %f"), rawTemp); - if (emptyOutdoorTemp) { - filteredOutdoorTemp = rawTemp; - emptyOutdoorTemp = false; + if (this->emptyOutdoorTemp) { + this->filteredOutdoorTemp = rawTemp; + this->emptyOutdoorTemp = false; } else { - filteredOutdoorTemp += (rawTemp - filteredOutdoorTemp) * EXT_SENSORS_FILTER_K; + this->filteredOutdoorTemp += (rawTemp - this->filteredOutdoorTemp) * EXT_SENSORS_FILTER_K; } - filteredOutdoorTemp = floor(filteredOutdoorTemp * 100) / 100; + this->filteredOutdoorTemp = floor(this->filteredOutdoorTemp * 100) / 100; - if (fabs(vars.temperatures.outdoor - filteredOutdoorTemp) > 0.099) { - vars.temperatures.outdoor = filteredOutdoorTemp + settings.sensors.outdoor.offset; - Log.sinfoln(FPSTR(S_SENSORS_OUTDOOR), F("New temp: %f"), filteredOutdoorTemp); + if (fabs(vars.temperatures.outdoor - this->filteredOutdoorTemp) > 0.099) { + vars.temperatures.outdoor = this->filteredOutdoorTemp + settings.sensors.outdoor.offset; + Log.sinfoln(FPSTR(S_SENSORS_OUTDOOR), F("New temp: %f"), this->filteredOutdoorTemp); } } - outdoorSensor->requestTemperatures(); - startOutdoorConversionTime = millis(); + this->outdoorSensor->requestTemperatures(); + this->startOutdoorConversionTime = millis(); } void indoorTemperatureSensor() { - if (!initIndoorSensor) { - oneWireIndoorSensor = new OneWire(settings.sensors.indoor.pin); - indoorSensor = new DallasTemperature(oneWireIndoorSensor); - indoorSensor->begin(); - indoorSensor->setResolution(12); - indoorSensor->setWaitForConversion(false); - indoorSensor->requestTemperatures(); - startIndoorConversionTime = millis(); - initIndoorSensor = true; + if (!this->initIndoorSensor) { + this->oneWireIndoorSensor->begin(settings.sensors.indoor.pin); + this->indoorSensor->begin(); + this->indoorSensor->setResolution(12); + this->indoorSensor->setWaitForConversion(false); + this->indoorSensor->requestTemperatures(); + this->startIndoorConversionTime = millis(); + + this->initIndoorSensor = true; } - unsigned long estimateConversionTime = millis() - startIndoorConversionTime; - if (estimateConversionTime < indoorSensor->millisToWaitForConversion()) { + unsigned long estimateConversionTime = millis() - this->startIndoorConversionTime; + if (estimateConversionTime < this->indoorSensor->millisToWaitForConversion()) { return; } - bool completed = indoorSensor->isConversionComplete(); + bool completed = this->indoorSensor->isConversionComplete(); if (!completed && estimateConversionTime >= 1000) { // fail, retry - indoorSensor->requestTemperatures(); - startIndoorConversionTime = millis(); + this->indoorSensor->requestTemperatures(); + this->startIndoorConversionTime = millis(); Log.serrorln(FPSTR(S_SENSORS_INDOOR), F("Could not read temperature data (no response)")); } @@ -209,30 +233,30 @@ protected: return; } - float rawTemp = indoorSensor->getTempCByIndex(0); + float rawTemp = this->indoorSensor->getTempCByIndex(0); if (rawTemp == DEVICE_DISCONNECTED_C) { Log.serrorln(FPSTR(S_SENSORS_INDOOR), F("Could not read temperature data (not connected)")); } else { Log.straceln(FPSTR(S_SENSORS_INDOOR), F("Raw temp: %f"), rawTemp); - if (emptyIndoorTemp) { - filteredIndoorTemp = rawTemp; - emptyIndoorTemp = false; + if (this->emptyIndoorTemp) { + this->filteredIndoorTemp = rawTemp; + this->emptyIndoorTemp = false; } else { - filteredIndoorTemp += (rawTemp - filteredIndoorTemp) * EXT_SENSORS_FILTER_K; + this->filteredIndoorTemp += (rawTemp - this->filteredIndoorTemp) * EXT_SENSORS_FILTER_K; } - filteredIndoorTemp = floor(filteredIndoorTemp * 100) / 100; + this->filteredIndoorTemp = floor(this->filteredIndoorTemp * 100) / 100; - if (fabs(vars.temperatures.indoor - filteredIndoorTemp) > 0.099) { - vars.temperatures.indoor = filteredIndoorTemp + settings.sensors.indoor.offset; - Log.sinfoln(FPSTR(S_SENSORS_INDOOR), F("New temp: %f"), filteredIndoorTemp); + if (fabs(vars.temperatures.indoor - this->filteredIndoorTemp) > 0.099) { + vars.temperatures.indoor = this->filteredIndoorTemp + settings.sensors.indoor.offset; + Log.sinfoln(FPSTR(S_SENSORS_INDOOR), F("New temp: %f"), this->filteredIndoorTemp); } } - indoorSensor->requestTemperatures(); - startIndoorConversionTime = millis(); + this->indoorSensor->requestTemperatures(); + this->startIndoorConversionTime = millis(); } }; \ No newline at end of file diff --git a/src/WifiManagerTask.h b/src/WifiManagerTask.h index cb8c1b7..a20eabe 100644 --- a/src/WifiManagerTask.h +++ b/src/WifiManagerTask.h @@ -56,55 +56,7 @@ const char S_WIFI_SETTINGS[] PROGMEM = "WIFI.SETTINGS"; class WifiManagerTask : public LeanTask { public: - WifiManagerTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {} - - WifiManagerTask* addTaskForDisable(AbstractTask* task) { - this->tasksForDisable.push_back(task); - return this; - } - -protected: - bool connected = false; - unsigned long lastArpGratuitous = 0; - unsigned long lastReconnecting = 0; - std::vector tasksForDisable; - - const char* getTaskName() { - return "WifiManager"; - } - - /*int getTaskCore() { - return 1; - }*/ - - int getTaskPriority() { - return 0; - } - - void setup() { - #ifdef WOKWI - WiFi.begin("Wokwi-GUEST", "", 6); - #endif - - wm.setDebugOutput(settings.debug, (wm_debuglevel_t) WM_DEBUG_MODE); - wm.setTitle(PROJECT_NAME); - wm.setCustomHeadElement(PSTR( - "" - )); - wm.setCustomMenuHTML(PSTR( - "" - "
" - "
" PROJECT_NAME "
" - "
Repo | Issues | Releases | v" PROJECT_VERSION " (" __DATE__ ")
" - "
" - )); - - std::vector menu = {"custom", "wifi", "param", "sep", "info", "update", "restart"}; - wm.setMenu(menu); - + WifiManagerTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) { wmHostname = new WiFiManagerParameter("hostname", "Hostname", settings.hostname, 80); wm.addParameter(wmHostname); @@ -196,10 +148,57 @@ protected: wmExtPumpAntiStuckTime = new UnsignedShortParameter("ext_pump_as_time", "Anti stuck time", settings.externalPump.antiStuckTime, 5); wm.addParameter(wmExtPumpAntiStuckTime); + } + + WifiManagerTask* addTaskForDisable(AbstractTask* task) { + this->tasksForDisable.push_back(task); + return this; + } + +protected: + bool connected = false; + unsigned long lastArpGratuitous = 0; + unsigned long lastReconnecting = 0; + std::vector tasksForDisable; + + const char* getTaskName() { + return "WifiManager"; + } + + /*int getTaskCore() { + return 1; + }*/ + + int getTaskPriority() { + return 0; + } + + void setup() { + #ifdef WOKWI + WiFi.begin("Wokwi-GUEST", "", 6); + #endif + + wm.setDebugOutput(settings.debug, (wm_debuglevel_t) WM_DEBUG_MODE); + wm.setTitle(PROJECT_NAME); + wm.setCustomHeadElement(PSTR( + "" + )); + wm.setCustomMenuHTML(PSTR( + "" + "
" + "
" PROJECT_NAME "
" + "
Repo | Issues | Releases | v" PROJECT_VERSION " (" __DATE__ ")
" + "
" + )); + + std::vector menu = {"custom", "wifi", "param", "sep", "info", "update", "restart"}; + wm.setMenu(menu); //wm.setCleanConnect(true); wm.setRestorePersistent(false); - wm.setHostname(settings.hostname); wm.setWiFiAutoReconnect(false); wm.setAPClientCheck(true); diff --git a/src/defines.h b/src/defines.h index 4a1aea5..43ea107 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,5 +1,5 @@ #define PROJECT_NAME "OpenTherm Gateway" -#define PROJECT_VERSION "1.4.0-rc.1" +#define PROJECT_VERSION "1.4.0-rc.2" #define PROJECT_REPO "https://github.com/Laxilef/OTGateway" #define AP_SSID "OpenTherm Gateway" #define AP_PASSWORD "otgateway123456"