From 8ba73093afc7fc4dc55ec3b5e6db12b5a6b43322 Mon Sep 17 00:00:00 2001 From: P43YM Date: Thu, 27 Feb 2025 02:50:19 +0300 Subject: [PATCH 1/2] Chart and new algorithm for equitherm --- build/.gitkeep | 0 data/static/.gitkeep | 0 lib/Equitherm/Equitherm.h | 38 ++++--- platformio.ini | 8 +- src/HaHelper.h | 23 +++++ src/RegulatorTask.h | 1 + src/Settings.h | 1 + src/strings.h | 1 + src/utils.h | 9 ++ src_data/locales/en.json | 5 + src_data/locales/it.json | 5 + src_data/locales/ru.json | 5 + src_data/pages/settings.html | 190 ++++++++++++++++++++++++++++++++++- 13 files changed, 267 insertions(+), 19 deletions(-) delete mode 100644 build/.gitkeep delete mode 100644 data/static/.gitkeep diff --git a/build/.gitkeep b/build/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/data/static/.gitkeep b/data/static/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/lib/Equitherm/Equitherm.h b/lib/Equitherm/Equitherm.h index 287b4f2..6890465 100644 --- a/lib/Equitherm/Equitherm.h +++ b/lib/Equitherm/Equitherm.h @@ -14,16 +14,19 @@ public: datatype indoorTemp = 0; datatype outdoorTemp = 0; float Kn = 0.0; + float Kntemp = 0.0; float Kk = 0.0; float Kt = 0.0; + float Ke = 1.3; Equitherm() = default; - // kn, kk, kt - Equitherm(float new_kn, float new_kk, float new_kt) { + // kn, kk, kt, Ke + Equitherm(float new_kn, float new_kk, float new_kt, float new_ke) { Kn = new_kn; Kk = new_kk; Kt = new_kt; + Ke = new_ke; } // лимит выходной величины @@ -34,7 +37,7 @@ public: // возвращает новое значение при вызове datatype getResult() { - datatype output = getResultN() + getResultK() + getResultT(); + datatype output = getResultN() + Kk + getResultT(); output = constrain(output, _minOut, _maxOut); // ограничиваем выход return output; } @@ -43,18 +46,27 @@ private: unsigned short _minOut = 20, _maxOut = 90; // температура контура отопления в зависимости от наружной температуры + // datatype getResultN() { + // Kntemp = Kn*3.3; //Подгонка под типовые кривые + // float tempDiff = targetTemp - outdoorTemp; + // if (tempDiff < 0) tempDiff = 0; + // float T_rad = targetTemp + pow(Kntemp * tempDiff, 1.0 / Ke); + // return T_rad; + // } datatype getResultN() { - float a = (-0.21 * Kn) - 0.06; // a = -0,21k — 0,06 - float b = (6.04 * Kn) + 1.98; // b = 6,04k + 1,98 - float c = (-5.06 * Kn) + 18.06; // с = -5,06k + 18,06 - float x = (-0.2 * outdoorTemp) + 5; // x = -0.2*t1 + 5 - return (a * x * x) + (b * x) + c; // Tn = ax2 + bx + c - } + float tempDiff = targetTemp - outdoorTemp; + if (tempDiff < 0) { + tempDiff = 0; + } + float minOutside = targetTemp - (_maxOut - targetTemp) / Kn; + float c1 = (_maxOut - targetTemp) / pow(targetTemp - minOutside, 1.0 / Ke); + float T_rad = targetTemp + c1 * pow(tempDiff, 1.0 / Ke) ; + if (T_rad > _maxOut) { + T_rad = _maxOut; + } - // поправка на желаемую комнатную температуру - datatype getResultK() { - return (targetTemp - 20) * Kk; - } + return T_rad; +} // Расчет поправки (ошибки) термостата datatype getResultT() { diff --git a/platformio.ini b/platformio.ini index 2a82211..1e5905b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -84,7 +84,7 @@ board_build.ldscript = eagle.flash.4m1m.ld ;platform_packages = ; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.5 ; framework-arduinoespressif32-libs @ https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip -platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.13/platform-espressif32.zip +platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.12/platform-espressif32.zip platform_packages = board_build.partitions = esp32_partitions.csv lib_deps = @@ -164,10 +164,10 @@ board_build.ldscript = ${esp8266_defaults.board_build.ldscript} build_type = ${esp8266_defaults.build_type} build_flags = ${esp8266_defaults.build_flags} - -D DEFAULT_OT_IN_GPIO=13 - -D DEFAULT_OT_OUT_GPIO=15 + -D DEFAULT_OT_IN_GPIO=4 + -D DEFAULT_OT_OUT_GPIO=5 -D DEFAULT_SENSOR_OUTDOOR_GPIO=12 - -D DEFAULT_SENSOR_INDOOR_GPIO=4 + -D DEFAULT_SENSOR_INDOOR_GPIO=14 -D DEFAULT_STATUS_LED_GPIO=2 -D DEFAULT_OT_RX_LED_GPIO=16 diff --git a/src/HaHelper.h b/src/HaHelper.h index 3864783..432ffb4 100644 --- a/src/HaHelper.h +++ b/src/HaHelper.h @@ -886,6 +886,29 @@ public: return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_NUMBER), F("equitherm_k_factor")).c_str(), doc); } + bool publishInputEquithermFactorK(bool enabledByDefault = true) { + JsonDocument doc; + doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); + doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; + doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectIdWithPrefix(F("equitherm_e")); + doc[FPSTR(HA_OBJECT_ID)] = doc[FPSTR(HA_UNIQUE_ID)]; + doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_CONFIG); + doc[FPSTR(HA_NAME)] = F("Equitherm Exponent E"); + doc[FPSTR(HA_ICON)] = F("mdi:alpha-e-circle-outline"); + doc[FPSTR(HA_STATE_TOPIC)] = this->settingsTopic.c_str(); + doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.equitherm.e_factor|float(0)|round(2) }}"); + doc[FPSTR(HA_COMMAND_TOPIC)] = this->setSettingsTopic.c_str(); + doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"e_factor\" : {{ value }}}}"); + doc[FPSTR(HA_MIN)] = 1; + doc[FPSTR(HA_MAX)] = 2; + doc[FPSTR(HA_STEP)] = 0.01f; + doc[FPSTR(HA_MODE)] = FPSTR(HA_MODE_BOX); + doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter; + doc.shrinkToFit(); + + return this->publish(this->makeConfigTopic(FPSTR(HA_ENTITY_NUMBER), F("equitherm_k_factor")).c_str(), doc); + } + bool publishInputEquithermFactorT(bool enabledByDefault = true) { JsonDocument doc; doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); diff --git a/src/RegulatorTask.h b/src/RegulatorTask.h index cc67d39..109f289 100644 --- a/src/RegulatorTask.h +++ b/src/RegulatorTask.h @@ -172,6 +172,7 @@ protected: etRegulator.setLimits(minTemp, maxTemp); etRegulator.Kn = settings.equitherm.n_factor; etRegulator.Kk = settings.equitherm.k_factor; + etRegulator.Ke = settings.equitherm.e_factor; etRegulator.targetTemp = targetTemp; etRegulator.outdoorTemp = outdoorTemp; float etResult = etRegulator.getResult(); diff --git a/src/Settings.h b/src/Settings.h index 5a493e2..2deb5ca 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -137,6 +137,7 @@ struct Settings { float n_factor = 0.7f; float k_factor = 3.0f; float t_factor = 2.0f; + float e_factor = 1.3f; } equitherm; struct { diff --git a/src/strings.h b/src/strings.h index 32ad73a..6da8e30 100644 --- a/src/strings.h +++ b/src/strings.h @@ -73,6 +73,7 @@ const char S_DNS[] PROGMEM = "dns"; const char S_DT[] PROGMEM = "dt"; const char S_D_FACTOR[] PROGMEM = "d_factor"; const char S_D_MULTIPLIER[] PROGMEM = "d_multiplier"; +const char S_E_FACTOR[] PROGMEM = "e_factor"; const char S_EMERGENCY[] PROGMEM = "emergency"; const char S_ENABLED[] PROGMEM = "enabled"; const char S_ENV[] PROGMEM = "env"; diff --git a/src/utils.h b/src/utils.h index 261d2d2..3a8cb1d 100644 --- a/src/utils.h +++ b/src/utils.h @@ -502,6 +502,7 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) { equitherm[FPSTR(S_ENABLED)] = src.equitherm.enabled; equitherm[FPSTR(S_N_FACTOR)] = roundf(src.equitherm.n_factor, 3); equitherm[FPSTR(S_K_FACTOR)] = roundf(src.equitherm.k_factor, 3); + equitherm[FPSTR(S_E_FACTOR)] = roundf(src.equitherm.e_factor, 3); equitherm[FPSTR(S_T_FACTOR)] = roundf(src.equitherm.t_factor, 3); auto pid = dst[FPSTR(S_PID)].to(); @@ -1100,6 +1101,14 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } + if (!src[FPSTR(S_EQUITHERM)][FPSTR(S_E_FACTOR)].isNull()) { + float value = src[FPSTR(S_EQUITHERM)][FPSTR(S_E_FACTOR)].as(); + + if (value >= 1 && value <= 2 && fabsf(value - dst.equitherm.e_factor) > 0.0001f) { + dst.equitherm.e_factor = roundf(value, 3); + changed = true; + } + } if (!src[FPSTR(S_EQUITHERM)][FPSTR(S_T_FACTOR)].isNull()) { float value = src[FPSTR(S_EQUITHERM)][FPSTR(S_T_FACTOR)].as(); diff --git a/src_data/locales/en.json b/src_data/locales/en.json index 8dcbf79..3eb3469 100644 --- a/src_data/locales/en.json +++ b/src_data/locales/en.json @@ -342,9 +342,14 @@ "equitherm": { "n": "N factor", "k": "K factor", + "e": "Exponent E", "t": { "title": "T factor", "note": "Not used if PID is enabled" + }, + "chart": { + "radiatorTemp": "Radiator Temperature (°C)", + "outdoorTemp": "Outdoor Temperature (°C)" } }, diff --git a/src_data/locales/it.json b/src_data/locales/it.json index a0b8e05..643a6df 100644 --- a/src_data/locales/it.json +++ b/src_data/locales/it.json @@ -342,9 +342,14 @@ "equitherm": { "n": "Fattore N", "k": "Fattore K", + "e": "Esponente E", "t": { "title": "Fattore T", "note": "Non usato se PID è attivato" + }, + "chart": { + "radiatorTemp": "Temperatura Del Radiatore (°C)", + "outdoorTemp": "Outdoor Temperature (°C)" } }, diff --git a/src_data/locales/ru.json b/src_data/locales/ru.json index fa1daa8..6f98b81 100644 --- a/src_data/locales/ru.json +++ b/src_data/locales/ru.json @@ -342,9 +342,14 @@ "equitherm": { "n": "Коэффициент N", "k": "Коэффициент K", + "e": "Экспонента E", "t": { "title": "Коэффициент T", "note": "Не используется, если ПИД включен" + }, + "chart": { + "radiatorTemp": "Температура радиатора (°C)", + "outdoorTemp": "Наружная температура (°C)" } }, diff --git a/src_data/pages/settings.html b/src_data/pages/settings.html index 2b9d7d7..12f53d0 100644 --- a/src_data/pages/settings.html +++ b/src_data/pages/settings.html @@ -261,9 +261,10 @@
- +
settings.section.equitherm +