From 84bc0afeb7f0661fcff014e10417ed4a284cac89 Mon Sep 17 00:00:00 2001 From: gnakh Date: Sat, 10 Oct 2026 11:09:03 +0200 Subject: [PATCH] add heat pump dhw/disinfectduration (0xEA offset 15), #3278 The DHW thermal disinfection duration (time allowed to reach the disinfection temperature; on timeout HPC4x0 reports A01(5284)) is sent in UBAParameterWWPlus 0xEA offset 15 in steps of 10 min, but was not decoded. Add boiler/dhw/disinfectduration for heat pumps, readable and writeable, range 120-240 min as on the HPC410 menu. Tested on a Bosch Compress 3400AW with HPC410: changing the duration on the controller writes 0xEA offset 15 (150 min -> 0F, 180 -> 12), and writing 0B 08 EA 0F 11 from EMS-ESP made the HPC410 menu show 170 min without errors. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG_LATEST.md | 1 + src/core/locale_translations.h | 1 + src/devices/boiler.cpp | 23 +++++++++++++++++++++++ src/devices/boiler.h | 2 ++ 4 files changed, 27 insertions(+) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index d25e66f90..9b2aa95cc 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -20,6 +20,7 @@ This release is based on the latest Espressif/Arduino core version 3. It brings - new Application Setting "Automatically check for firmware updates", off by default. When enabled EMS-ESP asks emsesp.org for the latest version once a day on its own, otherwise it only asks when the WebUI wants to show it, so an unattended system never contacts emsesp.org - Automatically check and convert older 3.8.x filesystem to the new 3.9.0 format - heatpump pool: `poolon` (switch, 0x48A), `hppoolon` (pool heating active, 0x488), MP100 `poolshuntset` (0x5C4) and `poolrequest` (0x5BA), shorter pool names +- heat pump `dhw/disinfectduration`, the time allowed to reach the thermal disinfection temperature (0xEA offset 15, 120-240 min) [#3278](https://github.com/emsesp/EMS-ESP32/issues/3278) ## Fixed diff --git a/src/core/locale_translations.h b/src/core/locale_translations.h index f25b86f79..1269a0b6e 100644 --- a/src/core/locale_translations.h +++ b/src/core/locale_translations.h @@ -755,6 +755,7 @@ MAKE_TRANSLATION(wwDisinfect, "disinfect", "disinfection", "Desinfektion", "Desi MAKE_TRANSLATION(wwDisinfectDay, "disinfectday", "disinfection day", "Desinfektionstag", "Desinfectiedag", "Desinfektionsdag", "dzień dezynfekcji termicznej", "desinfeksjonsdag", "jour désinfection", "dezenfeksiyon günü", "giorno disinfezione", "deň dezinfekcie", "den dezinfekce") MAKE_TRANSLATION(wwDisinfectHour, "disinfecthour", "disinfection hour", "Desinfektionsstunde", "Desinfectieuur", "Desinfektionstimme", "godzina dezynfekcji termicznej", "desinfeksjonstime", "heure désinfection", "dezenfeksiyon saati", "ora disinfezione", "hodina dezinfekcie", "hodina dezinfekce") MAKE_TRANSLATION(wwDisinfectTime, "disinfecttime", "disinfection time", "Desinfektionszeit", "Desinfectietijd", "Desinfektionstid", "maksymalny czas trwania dezynfekcji termicznej", "desinfeksjonstid", "durée désinfection", "dezenfeksiyon zamanı", "orario disinfezione", "čas na dezinfekciu", "čas dezinfekce") +MAKE_TRANSLATION(wwDisinfectDuration, "disinfectduration", "disinfection duration", "Desinfektionsdauer", "Desinfectieduur", "Desinfektionsvaraktighet", "czas trwania dezynfekcji termicznej", "desinfeksjonsvarighet", "durée désinfection", "dezenfeksiyon süresi", "durata disinfezione", "trvanie dezinfekcie", "doba dezinfekce") MAKE_TRANSLATION(wwDailyHeating, "dailyheating", "daily heating", "täglich Heizen", "Dagelijks opwarmen", "Daglig Uppvärmning", "codzienne nagrzewanie", "daglig oppvarming", "chauffage quotidien", "günlük ısıtma", "riscaldamento giornaliero", "denné kúrenie", "denní ohřev") MAKE_TRANSLATION(wwDailyHeatTime, "dailyheattime", "daily heating time", "tägliche Heizzeit", "Tijd dagelijkse opwarming", "Daglig Uppvärmningstid", "czas trwania codziennego nagrzewania", "daglig oppvarmingstid", "heure chauffage quotidien", "günlük ısıtma süresi", "orario riscaldamento giornaliero", "denný čas vykurovania", "čas denního ohřevu") diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index 029ac0d6d..d6a91c148 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -1090,6 +1090,18 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const MAKE_CF_CB(set_ww_disinfect_temp), 60, 80); + if (isHeatPump()) { + // time allowed to reach the disinfection temperature (120-240 min, steps of 10), on timeout HPC4x0 reports A01(5284), #3278 + register_device_value(DeviceValueTAG::TAG_DHW1, + &wwDisinfectDuration_, + DeviceValueType::UINT8, + DeviceValueNumOp::DV_NUMOP_MUL10, + FL_(wwDisinfectDuration), + DeviceValueUOM::MINUTES, + MAKE_CF_CB(set_ww_disinfect_duration), + 120, + 240); + } register_device_value(DeviceValueTAG::TAG_DHW1, &wwCircMode_, DeviceValueType::ENUM, @@ -1651,6 +1663,7 @@ void Boiler::process_UBAParameterWWPlus(const std::shared_ptr & has_update(telegram, wwCircMode_, 11); // 0=off, 1=1x3min... 6=6x3min, 7=continuous has_update(telegram, wwDisinfectionTemp_, 12); // setting here, status in E9 has_update(telegram, wwAlternatingOper_, 14); // 0x01 means enabled + has_update(telegram, wwDisinfectDuration_, 15); // heat pumps: disinfection duration in steps of 10 min, #3278 has_update(telegram, wwSelTempSingle_, 16); has_update(telegram, wwSelTempLow_, 18); has_update(telegram, wwMaxTemp_, 20); @@ -2506,6 +2519,16 @@ bool Boiler::set_ww_disinfect_temp(const char * value, const int8_t id) { return true; } +// Set the dhw disinfection duration (heat pumps), 0xEA offset 15 in steps of 10 min, #3278 +bool Boiler::set_ww_disinfect_duration(const char * value, const int8_t id) { + int v; + if (!Helpers::value2number(value, v, 120, 240)) { // HPC410 menu: 120-240 min in steps of 10 + return false; + } + write_command(EMS_TYPE_UBAParameterWWPlus, 15, (v + 5) / 10, EMS_TYPE_UBAParameterWWPlus); + return true; +} + // Set the dhw priority bool Boiler::set_ww_prio(const char * value, const int8_t) { bool b; diff --git a/src/devices/boiler.h b/src/devices/boiler.h index 281718dd7..165b2e245 100644 --- a/src/devices/boiler.h +++ b/src/devices/boiler.h @@ -70,6 +70,7 @@ class Boiler : public EMSdevice { uint8_t wwChargeType_; // DHW charge type (pump or 3-way-valve) uint8_t wwChargeOptimization_; // DHW charge optimization uint8_t wwDisinfectionTemp_; // DHW disinfection temperature to prevent infection + uint8_t wwDisinfectDuration_; // DHW disinfection duration, heat pumps (0xEA offset 15, steps of 10 min) uint8_t wwCircMode_; // DHW circulation pump mode uint8_t wwCirc_; // DHW circulation on/off uint16_t wwCurTemp_; // DHW current temperature @@ -431,6 +432,7 @@ class Boiler : public EMSdevice { bool set_ww_temp_eco(const char * value, const int8_t id); bool set_ww_temp_single(const char * value, const int8_t id); bool set_ww_disinfect_temp(const char * value, const int8_t id); + bool set_ww_disinfect_duration(const char * value, const int8_t id); bool set_ww_maxpower(const char * value, const int8_t id); bool set_ww_maxtemp(const char * value, const int8_t id); bool set_ww_flowTempOffset(const char * value, const int8_t id);