From 6dbb53e5afdda9ddaca40838c9bd750b5f153c18 Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 21 Oct 2026 23:27:01 +0200 Subject: [PATCH] add off to RC300/RC310 nofrostmode #3311 --- CHANGELOG.md | 6 ++++++ docs/dump_entities.csv | 10 +++++----- mock-api/restServer.ts | 2 +- src/core/emsesp.cpp | 14 +++++++------- src/core/emsesp.h | 2 +- src/core/locale_common.h | 2 +- src/devices/thermostat.cpp | 4 ++-- src/emsesp_version.h | 2 +- 8 files changed, 24 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d86d0c8c6..0b11dae9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.9.0] Unreleased + +## Fixed + +- RC300/RC310 `nofrostmode` missing `off` state [#3311](https://github.com/emsesp/EMS-ESP32/issues/3311) + ## [3.8.6] 24 September 2026 ## Added diff --git a/docs/dump_entities.csv b/docs/dump_entities.csv index 5df8ae94c..41203648e 100644 --- a/docs/dump_entities.csv +++ b/docs/dump_entities.csv @@ -4084,7 +4084,7 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/ "UI800, BC400",thermostat,4,hc1.roominfluence,room influence,uint8 (>=0<=0),C,true,number.thermostat_hc1_room_influence,number.thermostat_hc1_roominfluence,7,1,1,14,1 "UI800, BC400",thermostat,4,hc1.roominflfactor,room influence factor,uint8 (>=0<=0), ,true,number.thermostat_hc1_room_influence_factor,number.thermostat_hc1_roominflfactor,7,1,1/10,15,1 "UI800, BC400",thermostat,4,hc1.curroominfl,current room influence,int16,C,false,sensor.thermostat_hc1_current_room_influence,sensor.thermostat_hc1_curroominfl,7,1,1/10,16,1 -"UI800, BC400",thermostat,4,hc1.nofrostmode,nofrost mode,enum [room\|outdoor\|room outdoor] (>=0<=0), ,true,select.thermostat_hc1_nofrost_mode,select.thermostat_hc1_nofrostmode,7,1,1,17,1 +"UI800, BC400",thermostat,4,hc1.nofrostmode,nofrost mode,enum [off\|room\|outdoor\|room outdoor] (>=0<=0), ,true,select.thermostat_hc1_nofrost_mode,select.thermostat_hc1_nofrostmode,7,1,1,17,1 "UI800, BC400",thermostat,4,hc1.nofrosttemp,nofrost temperature,int8 (>=0<=0),C,true,number.thermostat_hc1_nofrost_temperature,number.thermostat_hc1_nofrosttemp,7,1,1,18,1 "UI800, BC400",thermostat,4,hc1.targetflowtemp,target flow temperature,uint8,C,false,sensor.thermostat_hc1_target_flow_temperature,sensor.thermostat_hc1_targetflowtemp,7,1,1,19,1 "UI800, BC400",thermostat,4,hc1.heatingtype,heating type,enum [off\|radiator\|convector\|floor] (>=0<=0), ,true,select.thermostat_hc1_heating_type,select.thermostat_hc1_heatingtype,7,1,1,20,1 @@ -4476,7 +4476,7 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/ "RC200, CW100, CR120, CR50",thermostat,157,hc1.roominfluence,room influence,uint8 (>=0<=0),C,true,number.thermostat_hc1_room_influence,number.thermostat_hc1_roominfluence,7,1,1,14,1 "RC200, CW100, CR120, CR50",thermostat,157,hc1.roominflfactor,room influence factor,uint8 (>=0<=0), ,true,number.thermostat_hc1_room_influence_factor,number.thermostat_hc1_roominflfactor,7,1,1/10,15,1 "RC200, CW100, CR120, CR50",thermostat,157,hc1.curroominfl,current room influence,int16,C,false,sensor.thermostat_hc1_current_room_influence,sensor.thermostat_hc1_curroominfl,7,1,1/10,16,1 -"RC200, CW100, CR120, CR50",thermostat,157,hc1.nofrostmode,nofrost mode,enum [room\|outdoor\|room outdoor] (>=0<=0), ,true,select.thermostat_hc1_nofrost_mode,select.thermostat_hc1_nofrostmode,7,1,1,17,1 +"RC200, CW100, CR120, CR50",thermostat,157,hc1.nofrostmode,nofrost mode,enum [off\|room\|outdoor\|room outdoor] (>=0<=0), ,true,select.thermostat_hc1_nofrost_mode,select.thermostat_hc1_nofrostmode,7,1,1,17,1 "RC200, CW100, CR120, CR50",thermostat,157,hc1.nofrosttemp,nofrost temperature,int8 (>=0<=0),C,true,number.thermostat_hc1_nofrost_temperature,number.thermostat_hc1_nofrosttemp,7,1,1,18,1 "RC200, CW100, CR120, CR50",thermostat,157,hc1.targetflowtemp,target flow temperature,uint8,C,false,sensor.thermostat_hc1_target_flow_temperature,sensor.thermostat_hc1_targetflowtemp,7,1,1,19,1 "RC200, CW100, CR120, CR50",thermostat,157,hc1.heatingtype,heating type,enum [off\|radiator\|convector\|floor] (>=0<=0), ,true,select.thermostat_hc1_heating_type,select.thermostat_hc1_heatingtype,7,1,1,20,1 @@ -4571,7 +4571,7 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/ "RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.roominfluence,room influence,uint8 (>=0<=0),C,true,number.thermostat_hc1_room_influence,number.thermostat_hc1_roominfluence,7,1,1,14,1 "RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.roominflfactor,room influence factor,uint8 (>=0<=0), ,true,number.thermostat_hc1_room_influence_factor,number.thermostat_hc1_roominflfactor,7,1,1/10,15,1 "RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.curroominfl,current room influence,int16,C,false,sensor.thermostat_hc1_current_room_influence,sensor.thermostat_hc1_curroominfl,7,1,1/10,16,1 -"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.nofrostmode,nofrost mode,enum [room\|outdoor\|room outdoor] (>=0<=0), ,true,select.thermostat_hc1_nofrost_mode,select.thermostat_hc1_nofrostmode,7,1,1,17,1 +"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.nofrostmode,nofrost mode,enum [off\|room\|outdoor\|room outdoor] (>=0<=0), ,true,select.thermostat_hc1_nofrost_mode,select.thermostat_hc1_nofrostmode,7,1,1,17,1 "RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.nofrosttemp,nofrost temperature,int8 (>=0<=0),C,true,number.thermostat_hc1_nofrost_temperature,number.thermostat_hc1_nofrosttemp,7,1,1,18,1 "RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.targetflowtemp,target flow temperature,uint8,C,false,sensor.thermostat_hc1_target_flow_temperature,sensor.thermostat_hc1_targetflowtemp,7,1,1,19,1 "RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.heatingtype,heating type,enum [off\|radiator\|convector\|floor] (>=0<=0), ,true,select.thermostat_hc1_heating_type,select.thermostat_hc1_heatingtype,7,1,1,20,1 @@ -4677,7 +4677,7 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/ "Rego 2000/3000",thermostat,172,hc1.roominfluence,room influence,uint8 (>=0<=0),C,true,number.thermostat_hc1_room_influence,number.thermostat_hc1_roominfluence,7,1,1,14,1 "Rego 2000/3000",thermostat,172,hc1.roominflfactor,room influence factor,uint8 (>=0<=0), ,true,number.thermostat_hc1_room_influence_factor,number.thermostat_hc1_roominflfactor,7,1,1/10,15,1 "Rego 2000/3000",thermostat,172,hc1.curroominfl,current room influence,int16,C,false,sensor.thermostat_hc1_current_room_influence,sensor.thermostat_hc1_curroominfl,7,1,1/10,16,1 -"Rego 2000/3000",thermostat,172,hc1.nofrostmode,nofrost mode,enum [room\|outdoor\|room outdoor] (>=0<=0), ,true,select.thermostat_hc1_nofrost_mode,select.thermostat_hc1_nofrostmode,7,1,1,17,1 +"Rego 2000/3000",thermostat,172,hc1.nofrostmode,nofrost mode,enum [off\|room\|outdoor\|room outdoor] (>=0<=0), ,true,select.thermostat_hc1_nofrost_mode,select.thermostat_hc1_nofrostmode,7,1,1,17,1 "Rego 2000/3000",thermostat,172,hc1.nofrosttemp,nofrost temperature,int8 (>=0<=0),C,true,number.thermostat_hc1_nofrost_temperature,number.thermostat_hc1_nofrosttemp,7,1,1,18,1 "Rego 2000/3000",thermostat,172,hc1.targetflowtemp,target flow temperature,uint8,C,false,sensor.thermostat_hc1_target_flow_temperature,sensor.thermostat_hc1_targetflowtemp,7,1,1,19,1 "Rego 2000/3000",thermostat,172,hc1.heatingtype,heating type,enum [off\|radiator\|convector\|floor] (>=0<=0), ,true,select.thermostat_hc1_heating_type,select.thermostat_hc1_heatingtype,7,1,1,20,1 @@ -4809,7 +4809,7 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/ "Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.roominfluence,room influence,uint8 (>=0<=0),C,true,number.thermostat_hc1_room_influence,number.thermostat_hc1_roominfluence,7,1,1,14,1 "Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.roominflfactor,room influence factor,uint8 (>=0<=0), ,true,number.thermostat_hc1_room_influence_factor,number.thermostat_hc1_roominflfactor,7,1,1/10,15,1 "Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.curroominfl,current room influence,int16,C,false,sensor.thermostat_hc1_current_room_influence,sensor.thermostat_hc1_curroominfl,7,1,1/10,16,1 -"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.nofrostmode,nofrost mode,enum [room\|outdoor\|room outdoor] (>=0<=0), ,true,select.thermostat_hc1_nofrost_mode,select.thermostat_hc1_nofrostmode,7,1,1,17,1 +"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.nofrostmode,nofrost mode,enum [off\|room\|outdoor\|room outdoor] (>=0<=0), ,true,select.thermostat_hc1_nofrost_mode,select.thermostat_hc1_nofrostmode,7,1,1,17,1 "Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.nofrosttemp,nofrost temperature,int8 (>=0<=0),C,true,number.thermostat_hc1_nofrost_temperature,number.thermostat_hc1_nofrosttemp,7,1,1,18,1 "Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.targetflowtemp,target flow temperature,uint8,C,false,sensor.thermostat_hc1_target_flow_temperature,sensor.thermostat_hc1_targetflowtemp,7,1,1,19,1 "Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.heatingtype,heating type,enum [off\|radiator\|convector\|floor] (>=0<=0), ,true,select.thermostat_hc1_heating_type,select.thermostat_hc1_heatingtype,7,1,1,20,1 diff --git a/mock-api/restServer.ts b/mock-api/restServer.ts index 4f68a4836..f41bd3ce5 100644 --- a/mock-api/restServer.ts +++ b/mock-api/restServer.ts @@ -3820,7 +3820,7 @@ const emsesp_devicedata_10 = { u: 0, id: '00hc1 nofrost mode', c: 'hc1/nofrostmode', - l: ['room', 'outdoor', 'room outdoor'] + l: ['off', 'room', 'outdoor', 'room outdoor'] }, { v: 2, diff --git a/src/core/emsesp.cpp b/src/core/emsesp.cpp index 50615226d..fa6376bb9 100644 --- a/src/core/emsesp.cpp +++ b/src/core/emsesp.cpp @@ -1803,12 +1803,10 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { #endif // check for poll to us, if so send top message from Tx queue immediately and quit #ifdef EMSESP_GATEWAY_TX_HOLD - // while the gateway is syncing, don't Tx anything (including Roomctrl) — only ack our own poll - // so the master keeps us in 0x07 and the gateway doesn't see the device list change + // while the gateway is syncing, mute ALL Tx including poll ACKs (#3094 19d). + // 19c still A21'd with ACK-only traffic; this tests whether that was enough to break HomeCom. + // risk: master may drop us from 0x07 while held — expect that in the log/status. if (gateway_tx_hold()) { - if (poll_id == EMSbus::ems_bus_id()) { - txservice_.send_poll(); - } return; } #endif @@ -1870,7 +1868,9 @@ void EMSESP::scheduled_fetch_values() { void EMSESP::gateway_note_activity() { uint32_t now = uuid::get_uptime(); if (gateway_last_seen_ && (now - gateway_last_seen_ > GATEWAY_SILENCE_MS)) { - LOG_INFO("Gateway 0x%02X returned after %lu s silence, holding Tx", EMSdevice::EMS_DEVICE_ID_GATEWAY1, (unsigned long)((now - gateway_last_seen_) / 1000)); + LOG_INFO("Gateway 0x%02X returned after %lu s silence, holding Tx (incl. poll ACK)", + EMSdevice::EMS_DEVICE_ID_GATEWAY1, + (unsigned long)((now - gateway_last_seen_) / 1000)); if (!gateway_hold_until_) { gateway_hold_start_ = now; gateway_hold_max_log_ = 0; @@ -1925,7 +1925,7 @@ void EMSESP::gateway_tx_hold_start() { if (!gateway_hold_until_) { gateway_hold_start_ = now; gateway_hold_max_log_ = 0; - LOG_INFO("Gateway 0x%02X is busy, holding Tx", EMSdevice::EMS_DEVICE_ID_GATEWAY1); + LOG_INFO("Gateway 0x%02X is busy, holding Tx (incl. poll ACK)", EMSdevice::EMS_DEVICE_ID_GATEWAY1); } gateway_hold_until_ = (now + GATEWAY_HOLD_TIME) | 1; // 0 means no hold diff --git a/src/core/emsesp.h b/src/core/emsesp.h index 9ee532eee..33b10f200 100644 --- a/src/core/emsesp.h +++ b/src/core/emsesp.h @@ -297,7 +297,7 @@ class EMSESP { static constexpr uint8_t EMS_WAIT_KM_TIMEOUT = 60; // wait one minute #ifdef EMSESP_GATEWAY_TX_HOLD - // hold our Tx while a gateway (K30RF/KM200 on 0x48) is doing its startup sync, see issue #3094 + // hold our Tx (and poll ACKs, since 19d) while a gateway (K30RF/KM200 on 0x48) is syncing — see #3094 // a startup sync is 55-250 read requests/min to other devices, normal operation is <10/min static void gateway_rx_check(const uint8_t * data, const uint8_t length); static void gateway_note_activity(); // poll or telegram from 0x48 — re-arm hold if it was silent diff --git a/src/core/locale_common.h b/src/core/locale_common.h index 9a814e3d1..cbb8cdc29 100644 --- a/src/core/locale_common.h +++ b/src/core/locale_common.h @@ -368,7 +368,7 @@ MAKE_ENUM(enum_modetype5, FL_(off), FL_(on)) MAKE_ENUM(enum_reducemode, FL_(nofrost), FL_(reduce), FL_(room), FL_(outdoor)) MAKE_ENUM(enum_reducemode1, FL_(outdoor), FL_(room), FL_(reduce)) // RC310 values: 1-3 MAKE_ENUM(enum_nofrostmode, FL_(off), FL_(outdoor), FL_(room)) -MAKE_ENUM(enum_nofrostmode1, FL_(room), FL_(outdoor), FL_(room_outdoor)) +MAKE_ENUM(enum_nofrostmode1, FL_(off), FL_(room), FL_(outdoor), FL_(room_outdoor)) // RC300/RC310: 0-3 MAKE_ENUM(enum_controlmode, FL_(optimized), FL_(simple), FL_(na), FL_(room), FL_(power)) MAKE_ENUM(enum_controlmode1, FL_(weather_compensated), FL_(outside_basepoint), FL_(na), FL_(room), FL_(power), FL_(constant)) // RC310 1-4 diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 17f42486b..2a4259742 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -1393,7 +1393,7 @@ void Thermostat::process_RC300Curve(const std::shared_ptr & tele has_enumupdate(telegram, hc->controlmode, 0, 1); // 1-weather_compensated, 2-outside_footpoint,3-n/a, 4-room -- RC310 has_update(telegram, hc->heatingtype, 1); // 1=radiator, 2=convector, 3=floor has_update(telegram, hc->switchonoptimization, 4); - has_enumupdate(telegram, hc->nofrostmode, 5, 1); // 1-room, 2-outdoor, 3- room & outdoor + has_update(telegram, hc->nofrostmode, 5); // 0-off, 1-room, 2-outdoor, 3-room & outdoor has_update(telegram, hc->nofrosttemp, 6); if (hc->heatingtype < 3) { @@ -3925,7 +3925,7 @@ bool Thermostat::set_nofrostmode(const char * value, const int8_t id) { uint8_t set; if (isRC300() || model() == EMSdevice::EMS_DEVICE_FLAG_RC100) { if (Helpers::value2enum(value, set, FL_(enum_nofrostmode1))) { - write_command(curve_typeids[hc->hc()], 5, set + 1, curve_typeids[hc->hc()]); + write_command(curve_typeids[hc->hc()], 5, set, curve_typeids[hc->hc()]); return true; } } else { diff --git a/src/emsesp_version.h b/src/emsesp_version.h index 68976aa71..39dd14b80 100644 --- a/src/emsesp_version.h +++ b/src/emsesp_version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.9.0-dev.20" +#define EMSESP_APP_VERSION "3.9.0-dev.21"