Merge remote-tracking branch 'origin/dev'

This commit is contained in:
proddy
2026-08-02 09:55:48 +02:00
54 changed files with 1458 additions and 1111 deletions
-10
View File
@@ -1,13 +1,3 @@
# Changelog
For more details go to [emsesp.org](https://emsesp.org/).
## [3.8.3]
## Added
## Fixed
## Changed
+67 -94
View File
@@ -5363,22 +5363,22 @@ uint8
uint8
| hc1.heatoffdelay | heat-off delay | uint8 (>=1<=48) | hours | true | HC | 48 | 1 | 1 |
uint8
| hc1.instantstart | instant start | uint8 (>=1<=10) | K | true | HC | 49 | 1 | 1 |
| hc1.boost | boost mode | boolean | | true | HC | 50 | 1 | 1 |
| hc1.coolondelay | cooling on delay | uint8 (>=1<=48) | hours | true | HC | 49 | 1 | 1 |
uint8
| hc1.boosttime | boost time | uint8 (>=0<=0) | hours | true | HC | 51 | 1 | 1 |
| hc1.cooloffdelay | cooling off delay | uint8 (>=1<=48) | hours | true | HC | 50 | 1 | 1 |
uint8
| hc1.instantstart | instant start | uint8 (>=1<=10) | K | true | HC | 51 | 1 | 1 |
uint8
| hc1.coolstart | cooling starttemp | uint8 (>=20<=35) | C | true | HC | 52 | 1 | 1 |
| hc1.boost | boost mode | boolean | | true | HC | 53 | 1 | 1 |
uint8
| hc1.coolondelay | cooling on delay | uint8 (>=1<=48) | hours | true | HC | 53 | 1 | 1 |
uint8
| hc1.cooloffdelay | cooling off delay | uint8 (>=1<=48) | hours | true | HC | 54 | 1 | 1 |
| hc1.boosttime | boost time | uint8 (>=0<=0) | hours | true | HC | 54 | 1 | 1 |
| hc1.switchprogmode | switch program mode | enum | | true | HC | 55 | 1 | 1 |
int8
| hc1.redthreshold | reduction threshold | int8 (>=12<=22) | C | true | HC | 56 | 1 | 1/2 |
uint8
| hc1.solarinfl | solar influence | uint8 (>=-5<=4294967295) | C | true | HC | 57 | 1 | 1 |
| hc1.currsolarinfl | current solar influence | uint8 | C | false | HC | 58 | 1 | 1/10 |
int8
| hc1.solarinfl | solar influence | int8 (>=-5<=0) | C | true | HC | 57 | 1 | 1 |
| hc1.currsolarinfl | current solar influence | int8 | C | false | HC | 58 | 1 | 1/10 |
| hc1.heatingpid | heating PID | enum | | true | HC | 59 | 1 | 1 |
| hc1.pumpopt | pump optimization | boolean | | true | HC | 60 | 1 | 1 |
uint8
@@ -5972,22 +5972,22 @@ uint8
uint8
| hc1.heatoffdelay | heat-off delay | uint8 (>=1<=48) | hours | true | HC | 48 | 1 | 1 |
uint8
| hc1.instantstart | instant start | uint8 (>=1<=10) | K | true | HC | 49 | 1 | 1 |
| hc1.boost | boost mode | boolean | | true | HC | 50 | 1 | 1 |
| hc1.coolondelay | cooling on delay | uint8 (>=1<=48) | hours | true | HC | 49 | 1 | 1 |
uint8
| hc1.boosttime | boost time | uint8 (>=0<=0) | hours | true | HC | 51 | 1 | 1 |
| hc1.cooloffdelay | cooling off delay | uint8 (>=1<=48) | hours | true | HC | 50 | 1 | 1 |
uint8
| hc1.instantstart | instant start | uint8 (>=1<=10) | K | true | HC | 51 | 1 | 1 |
uint8
| hc1.coolstart | cooling starttemp | uint8 (>=20<=35) | C | true | HC | 52 | 1 | 1 |
| hc1.boost | boost mode | boolean | | true | HC | 53 | 1 | 1 |
uint8
| hc1.coolondelay | cooling on delay | uint8 (>=1<=48) | hours | true | HC | 53 | 1 | 1 |
uint8
| hc1.cooloffdelay | cooling off delay | uint8 (>=1<=48) | hours | true | HC | 54 | 1 | 1 |
| hc1.boosttime | boost time | uint8 (>=0<=0) | hours | true | HC | 54 | 1 | 1 |
| hc1.switchprogmode | switch program mode | enum | | true | HC | 55 | 1 | 1 |
int8
| hc1.redthreshold | reduction threshold | int8 (>=12<=22) | C | true | HC | 56 | 1 | 1/2 |
uint8
| hc1.solarinfl | solar influence | uint8 (>=-5<=4294967295) | C | true | HC | 57 | 1 | 1 |
| hc1.currsolarinfl | current solar influence | uint8 | C | false | HC | 58 | 1 | 1/10 |
int8
| hc1.solarinfl | solar influence | int8 (>=-5<=0) | C | true | HC | 57 | 1 | 1 |
| hc1.currsolarinfl | current solar influence | int8 | C | false | HC | 58 | 1 | 1/10 |
| hc1.heatingpid | heating PID | enum | | true | HC | 59 | 1 | 1 |
| hc1.pumpopt | pump optimization | boolean | | true | HC | 60 | 1 | 1 |
uint8
@@ -6124,22 +6124,22 @@ uint8
uint8
| hc1.heatoffdelay | heat-off delay | uint8 (>=1<=48) | hours | true | HC | 48 | 1 | 1 |
uint8
| hc1.instantstart | instant start | uint8 (>=1<=10) | K | true | HC | 49 | 1 | 1 |
| hc1.boost | boost mode | boolean | | true | HC | 50 | 1 | 1 |
| hc1.coolondelay | cooling on delay | uint8 (>=1<=48) | hours | true | HC | 49 | 1 | 1 |
uint8
| hc1.boosttime | boost time | uint8 (>=0<=0) | hours | true | HC | 51 | 1 | 1 |
| hc1.cooloffdelay | cooling off delay | uint8 (>=1<=48) | hours | true | HC | 50 | 1 | 1 |
uint8
| hc1.instantstart | instant start | uint8 (>=1<=10) | K | true | HC | 51 | 1 | 1 |
uint8
| hc1.coolstart | cooling starttemp | uint8 (>=20<=35) | C | true | HC | 52 | 1 | 1 |
| hc1.boost | boost mode | boolean | | true | HC | 53 | 1 | 1 |
uint8
| hc1.coolondelay | cooling on delay | uint8 (>=1<=48) | hours | true | HC | 53 | 1 | 1 |
uint8
| hc1.cooloffdelay | cooling off delay | uint8 (>=1<=48) | hours | true | HC | 54 | 1 | 1 |
| hc1.boosttime | boost time | uint8 (>=0<=0) | hours | true | HC | 54 | 1 | 1 |
| hc1.switchprogmode | switch program mode | enum | | true | HC | 55 | 1 | 1 |
int8
| hc1.redthreshold | reduction threshold | int8 (>=12<=22) | C | true | HC | 56 | 1 | 1/2 |
uint8
| hc1.solarinfl | solar influence | uint8 (>=-5<=4294967295) | C | true | HC | 57 | 1 | 1 |
| hc1.currsolarinfl | current solar influence | uint8 | C | false | HC | 58 | 1 | 1/10 |
int8
| hc1.solarinfl | solar influence | int8 (>=-5<=0) | C | true | HC | 57 | 1 | 1 |
| hc1.currsolarinfl | current solar influence | int8 | C | false | HC | 58 | 1 | 1/10 |
| hc1.heatingpid | heating PID | enum | | true | HC | 59 | 1 | 1 |
| hc1.pumpopt | pump optimization | boolean | | true | HC | 60 | 1 | 1 |
uint8
@@ -6291,22 +6291,22 @@ uint8
uint8
| hc1.heatoffdelay | heat-off delay | uint8 (>=1<=48) | hours | true | HC | 48 | 1 | 1 |
uint8
| hc1.instantstart | instant start | uint8 (>=1<=10) | K | true | HC | 49 | 1 | 1 |
| hc1.boost | boost mode | boolean | | true | HC | 50 | 1 | 1 |
| hc1.coolondelay | cooling on delay | uint8 (>=1<=48) | hours | true | HC | 49 | 1 | 1 |
uint8
| hc1.boosttime | boost time | uint8 (>=0<=0) | hours | true | HC | 51 | 1 | 1 |
| hc1.cooloffdelay | cooling off delay | uint8 (>=1<=48) | hours | true | HC | 50 | 1 | 1 |
uint8
| hc1.instantstart | instant start | uint8 (>=1<=10) | K | true | HC | 51 | 1 | 1 |
uint8
| hc1.coolstart | cooling starttemp | uint8 (>=20<=35) | C | true | HC | 52 | 1 | 1 |
| hc1.boost | boost mode | boolean | | true | HC | 53 | 1 | 1 |
uint8
| hc1.coolondelay | cooling on delay | uint8 (>=1<=48) | hours | true | HC | 53 | 1 | 1 |
uint8
| hc1.cooloffdelay | cooling off delay | uint8 (>=1<=48) | hours | true | HC | 54 | 1 | 1 |
| hc1.boosttime | boost time | uint8 (>=0<=0) | hours | true | HC | 54 | 1 | 1 |
| hc1.switchprogmode | switch program mode | enum | | true | HC | 55 | 1 | 1 |
int8
| hc1.redthreshold | reduction threshold | int8 (>=12<=22) | C | true | HC | 56 | 1 | 1/2 |
uint8
| hc1.solarinfl | solar influence | uint8 (>=-5<=4294967295) | C | true | HC | 57 | 1 | 1 |
| hc1.currsolarinfl | current solar influence | uint8 | C | false | HC | 58 | 1 | 1/10 |
int8
| hc1.solarinfl | solar influence | int8 (>=-5<=0) | C | true | HC | 57 | 1 | 1 |
| hc1.currsolarinfl | current solar influence | int8 | C | false | HC | 58 | 1 | 1/10 |
| hc1.heatingpid | heating PID | enum | | true | HC | 59 | 1 | 1 |
| hc1.pumpopt | pump optimization | boolean | | true | HC | 60 | 1 | 1 |
uint8
@@ -6410,6 +6410,21 @@ int8
int8
| pvlowercool | lower cooling with PV | int8 (>=-5<=0) | K | true | DEVICE_DATA | 63 | 1 | 1 |
| absent | absent | boolean | | true | DEVICE_DATA | 64 | 1 | 1 |
| hpoperatingmode | heatpump operating mode | enum | | true | DEVICE_DATA | 89 | 1 | 1 |
uint8
| summertemp | summer temperature | uint8 (>=10<=30) | C | true | DEVICE_DATA | 90 | 1 | 1 |
uint8
| instantstart | instant start | uint8 (>=1<=10) | K | true | DEVICE_DATA | 91 | 1 | 1 |
uint8
| coolstart | cooling starttemp | uint8 (>=20<=35) | C | true | DEVICE_DATA | 92 | 1 | 1 |
uint8
| heatondelay | heat-on delay | uint8 (>=1<=48) | hours | true | DEVICE_DATA | 93 | 1 | 1/4 |
uint8
| heatoffdelay | heat-off delay | uint8 (>=1<=48) | hours | true | DEVICE_DATA | 94 | 1 | 1/4 |
uint8
| coolondelay | cooling on delay | uint8 (>=1<=48) | hours | true | DEVICE_DATA | 95 | 1 | 1/4 |
uint8
| cooloffdelay | cooling off delay | uint8 (>=1<=48) | hours | true | DEVICE_DATA | 96 | 1 | 1/4 |
int16
| hc1.seltemp | selected room temperature | int16 (>=0<=30) | C | true | HC | 0 | 1 | 1/2 |
| hc1.currtemp | current room temperature | int16 | C | false | HC | 1 | 1 | 1/10 |
@@ -6480,27 +6495,15 @@ uint8
| hc1.control | control device | enum | | true | HC | 44 | 1 | 1 |
| hc1.remotetemp | room temperature from remote | cmd | C | true | HC | 45 | 1 | 1/10 |
| hc1.remotehum | room humidity from remote | cmd | % | true | HC | 46 | 1 | 1 |
| hc1.boost | boost mode | boolean | | true | HC | 53 | 1 | 1 |
uint8
| hc1.heatondelay | heat-on delay | uint8 (>=1<=48) | hours | true | HC | 47 | 1 | 1 |
uint8
| hc1.heatoffdelay | heat-off delay | uint8 (>=1<=48) | hours | true | HC | 48 | 1 | 1 |
uint8
| hc1.instantstart | instant start | uint8 (>=1<=10) | K | true | HC | 49 | 1 | 1 |
| hc1.boost | boost mode | boolean | | true | HC | 50 | 1 | 1 |
uint8
| hc1.boosttime | boost time | uint8 (>=0<=0) | hours | true | HC | 51 | 1 | 1 |
uint8
| hc1.coolstart | cooling starttemp | uint8 (>=20<=35) | C | true | HC | 52 | 1 | 1 |
uint8
| hc1.coolondelay | cooling on delay | uint8 (>=1<=48) | hours | true | HC | 53 | 1 | 1 |
uint8
| hc1.cooloffdelay | cooling off delay | uint8 (>=1<=48) | hours | true | HC | 54 | 1 | 1 |
| hc1.boosttime | boost time | uint8 (>=0<=0) | hours | true | HC | 54 | 1 | 1 |
| hc1.switchprogmode | switch program mode | enum | | true | HC | 55 | 1 | 1 |
int8
| hc1.redthreshold | reduction threshold | int8 (>=12<=22) | C | true | HC | 56 | 1 | 1/2 |
uint8
| hc1.solarinfl | solar influence | uint8 (>=-5<=4294967295) | C | true | HC | 57 | 1 | 1 |
| hc1.currsolarinfl | current solar influence | uint8 | C | false | HC | 58 | 1 | 1/10 |
int8
| hc1.solarinfl | solar influence | int8 (>=-5<=0) | C | true | HC | 57 | 1 | 1 |
| hc1.currsolarinfl | current solar influence | int8 | C | false | HC | 58 | 1 | 1/10 |
| hc1.heatingpid | heating PID | enum | | true | HC | 59 | 1 | 1 |
| hc1.pumpopt | pump optimization | boolean | | true | HC | 60 | 1 | 1 |
uint8
@@ -8143,7 +8146,7 @@ uint8
| datetime | date/time | string | | false | DEVICE_DATA | 0 | 13 | 1 |
| outdoortemp | outside temperature | int16 | C | false | DEVICE_DATA | 13 | 1 | 1/10 |
| src1.currtemp | current room temperature | int16 | C | false | SRC | 0 | 1 | 1/10 |
| src1.airhumidity | relative air humidity | int8 | % | false | SRC | 1 | 1 | 1 |
| src1.airhumidity | relative air humidity | uint8 | % | false | SRC | 1 | 1 | 1 |
| src1.dewtemperature | dew point temperature | int16 | C | false | SRC | 2 | 1 | 1/10 |
uint8
| src1.seltemp | selected room temperature | uint8 (>=5<=30) | C | true | SRC | 3 | 1 | 1/2 |
@@ -8353,70 +8356,40 @@ uint8
| shortname | fullname | type | uom | writeable | tag type | register offset | register count | scale factor |
|-|-|-|-|-|-|-|-|-|
| dhw.temp | current temperature | uint16 | C | false | DHW | 1 | 1 | 1/10 |
| dhw.storagetemp1 | storage intern temperature | uint16 | C | false | DHW | 16 | 1 | 1/10 |
| dhw.coldtemp | cold water | uint16 | C | false | DHW | 17 | 1 | 1/10 |
| dhw.temp5 | temperature 5 | uint16 | C | false | DHW | 18 | 1 | 1/10 |
| dhw.rettemp | return temperature | uint16 | C | false | DHW | 19 | 1 | 1/10 |
| dhw.tempstatus | temperature switch in assigned dhw (MC1) | int8 | | false | DHW | 11 | 1 | 1 |
| dhw.pump | pump | boolean | | false | DHW | 4 | 1 | 1 |
uint8
| dhw.maxtemp | maximum temperature | uint8 (>=0<=0) | C | true | DHW | 12 | 1 | 1 |
int8
| dhw.difftemp | start differential temperature | int8 (>=0<=0) | C | true | DHW | 13 | 1 | 1 |
uint8
| dhw.seltemp | selected temperature | uint8 (>=0<=0) | C | true | DHW | 0 | 1 | 1 |
| dhw.disinfectiontemp | disinfection temperature | uint8 (>=0<=0) | C | true | DHW | 8 | 1 | 1 |
uint8
| dhw.redtemp | reduced temperature | uint8 (>=0<=0) | C | true | DHW | 14 | 1 | 1 |
uint8
| dhw.hottemp | extra hot temperature | uint8 (>=0<=0) | C | true | DHW | 20 | 1 | 1 |
uint8
| dhw.dailytemp | daily temperature | uint8 (>=0<=0) | C | true | DHW | 21 | 1 | 1 |
uint8
| dhw.disinfectiontemp | disinfection temperature | uint8 (>=0<=0) | C | true | DHW | 8 | 1 | 1 |
| dhw.requiredtemp | required temperature | uint8 (>=0<=0) | C | true | DHW | 15 | 1 | 1 |
| dhw.circ | circulation active | boolean | | true | DHW | 9 | 1 | 1 |
| dhw.circmode | circulation pump mode | enum | | true | DHW | 10 | 1 | 1 |
| dhw.circtc | circulation time controlled | boolean | | true | DHW | 22 | 1 | 1 |
| dhw.keepwarm | keep warm | boolean | | true | DHW | 23 | 1 | 1 |
| dhw.status2 | status 2 | enum | | false | DHW | 24 | 1 | 1 |
| dhw.pumpmod | pump modulation | uint8 | % | false | DHW | 25 | 1 | 1 |
| dhw.flow | flow rate | uint16 | l/min | false | DHW | 26 | 1 | 1/10 |
uint8
| dhw.valvereturn | return valve | uint8 (>=0<=0) | % | true | DHW | 27 | 1 | 1 |
uint8
| dhw.deltatret | temp. diff. return valve | uint8 (>=0<=0) | K | true | DHW | 28 | 1 | 1 |
| dhw.errordisp | error display | enum | | true | DHW | 29 | 1 | 1 |
### SM200, MS200
| shortname | fullname | type | uom | writeable | tag type | register offset | register count | scale factor |
|-|-|-|-|-|-|-|-|-|
| dhw.temp | current temperature | uint16 | C | false | DHW | 1 | 1 | 1/10 |
| dhw.storagetemp1 | storage intern temperature | uint16 | C | false | DHW | 16 | 1 | 1/10 |
| dhw.coldtemp | cold water | uint16 | C | false | DHW | 17 | 1 | 1/10 |
| dhw.temp5 | temperature 5 | uint16 | C | false | DHW | 18 | 1 | 1/10 |
| dhw.rettemp | return temperature | uint16 | C | false | DHW | 19 | 1 | 1/10 |
| dhw.tempstatus | temperature switch in assigned dhw (MC1) | int8 | | false | DHW | 11 | 1 | 1 |
| dhw.pump | pump | boolean | | false | DHW | 4 | 1 | 1 |
uint8
| dhw.maxtemp | maximum temperature | uint8 (>=0<=0) | C | true | DHW | 12 | 1 | 1 |
int8
| dhw.difftemp | start differential temperature | int8 (>=0<=0) | C | true | DHW | 13 | 1 | 1 |
uint8
| dhw.seltemp | selected temperature | uint8 (>=0<=0) | C | true | DHW | 0 | 1 | 1 |
| dhw.disinfectiontemp | disinfection temperature | uint8 (>=0<=0) | C | true | DHW | 8 | 1 | 1 |
uint8
| dhw.redtemp | reduced temperature | uint8 (>=0<=0) | C | true | DHW | 14 | 1 | 1 |
uint8
| dhw.hottemp | extra hot temperature | uint8 (>=0<=0) | C | true | DHW | 20 | 1 | 1 |
uint8
| dhw.dailytemp | daily temperature | uint8 (>=0<=0) | C | true | DHW | 21 | 1 | 1 |
uint8
| dhw.disinfectiontemp | disinfection temperature | uint8 (>=0<=0) | C | true | DHW | 8 | 1 | 1 |
| dhw.requiredtemp | required temperature | uint8 (>=0<=0) | C | true | DHW | 15 | 1 | 1 |
| dhw.circ | circulation active | boolean | | true | DHW | 9 | 1 | 1 |
| dhw.circmode | circulation pump mode | enum | | true | DHW | 10 | 1 | 1 |
| dhw.circtc | circulation time controlled | boolean | | true | DHW | 22 | 1 | 1 |
| dhw.keepwarm | keep warm | boolean | | true | DHW | 23 | 1 | 1 |
| dhw.status2 | status 2 | enum | | false | DHW | 24 | 1 | 1 |
| dhw.pumpmod | pump modulation | uint8 | % | false | DHW | 25 | 1 | 1 |
| dhw.flow | flow rate | uint16 | l/min | false | DHW | 26 | 1 | 1/10 |
uint8
| dhw.valvereturn | return valve | uint8 (>=0<=0) | % | true | DHW | 27 | 1 | 1 |
uint8
| dhw.deltatret | temp. diff. return valve | uint8 (>=0<=0) | K | true | DHW | 28 | 1 | 1 |
| dhw.errordisp | error display | enum | | true | DHW | 29 | 1 | 1 |
## Devices of type \_pool
+53 -75
View File
@@ -4044,21 +4044,21 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"UI800, BC400",thermostat,4,hc1.dewoffset,dew point offset,uint8 (>=2<=10),K,true,number.thermostat_hc1_dew_point_offset,number.thermostat_hc1_dewoffset,6,1,1,41,1
"UI800, BC400",thermostat,4,hc1.roomtempdiff,room temp difference,uint8 (>=0<=0),K,true,number.thermostat_hc1_room_temp_difference,number.thermostat_hc1_roomtempdiff,6,1,1,42,1
"UI800, BC400",thermostat,4,hc1.hpminflowtemp,HP min. flow temp.,uint8 (>=0<=0),C,true,number.thermostat_hc1_HP_min._flow_temp.,number.thermostat_hc1_hpminflowtemp,6,1,1,43,1
"UI800, BC400",thermostat,4,hc1.control,control device,enum [off\|-\|RC100\|RC100H\|-\|RC120RF\|RC220/RT800\|single] (>=0<=0), ,true,select.thermostat_hc1_control_device,select.thermostat_hc1_control,6,1,1,44,1
"UI800, BC400",thermostat,4,hc1.control,control device,enum [off\|-\|RC100\|RC100H\|-\|RC120RF\|RC220\|single] (>=0<=0), ,true,select.thermostat_hc1_control_device,select.thermostat_hc1_control,6,1,1,44,1
"UI800, BC400",thermostat,4,hc1.remotetemp,room temperature from remote,cmd [] (>=-1<=101),C,true,sensor.thermostat_hc1_room_temperature_from_remote,sensor.thermostat_hc1_remotetemp,6,1,1/10,45,1
"UI800, BC400",thermostat,4,hc1.remotehum,room humidity from remote,cmd [] (>=-1<=101),%,true,sensor.thermostat_hc1_room_humidity_from_remote,sensor.thermostat_hc1_remotehum,6,1,1,46,1
"UI800, BC400",thermostat,4,hc1.heatondelay,heat-on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_heat-on_delay,number.thermostat_hc1_heatondelay,6,1,1,47,1
"UI800, BC400",thermostat,4,hc1.heatoffdelay,heat-off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_heat-off_delay,number.thermostat_hc1_heatoffdelay,6,1,1,48,1
"UI800, BC400",thermostat,4,hc1.instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_hc1_instant_start,number.thermostat_hc1_instantstart,6,1,1,49,1
"UI800, BC400",thermostat,4,hc1.boost,boost mode,boolean (>=0<=0), ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,50,1
"UI800, BC400",thermostat,4,hc1.boosttime,boost time,uint8 (>=0<=0),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,51,1
"UI800, BC400",thermostat,4,hc1.coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,49,1
"UI800, BC400",thermostat,4,hc1.cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,50,1
"UI800, BC400",thermostat,4,hc1.instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_hc1_instant_start,number.thermostat_hc1_instantstart,6,1,1,51,1
"UI800, BC400",thermostat,4,hc1.coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,52,1
"UI800, BC400",thermostat,4,hc1.coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,53,1
"UI800, BC400",thermostat,4,hc1.cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,54,1
"UI800, BC400",thermostat,4,hc1.boost,boost mode,boolean (>=0<=0), ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,53,1
"UI800, BC400",thermostat,4,hc1.boosttime,boost time,uint8 (>=0<=0),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,54,1
"UI800, BC400",thermostat,4,hc1.switchprogmode,switch program mode,enum [level\|absolute] (>=0<=0), ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,55,1
"UI800, BC400",thermostat,4,hc1.redthreshold,reduction threshold,int8 (>=12<=22),C,true,number.thermostat_hc1_reduction_threshold,number.thermostat_hc1_redthreshold,6,1,1/2,56,1
"UI800, BC400",thermostat,4,hc1.solarinfl,solar influence,uint8 (>=-5<=4294967295),C,true,number.thermostat_hc1_solar_influence,number.thermostat_hc1_solarinfl,6,1,1,57,1
"UI800, BC400",thermostat,4,hc1.currsolarinfl,current solar influence,uint8,C,false,sensor.thermostat_hc1_current_solar_influence,sensor.thermostat_hc1_currsolarinfl,6,1,1/10,58,1
"UI800, BC400",thermostat,4,hc1.solarinfl,solar influence,int8 (>=-5<=0),C,true,number.thermostat_hc1_solar_influence,number.thermostat_hc1_solarinfl,6,1,1,57,1
"UI800, BC400",thermostat,4,hc1.currsolarinfl,current solar influence,int8,C,false,sensor.thermostat_hc1_current_solar_influence,sensor.thermostat_hc1_currsolarinfl,6,1,1/10,58,1
"UI800, BC400",thermostat,4,hc1.heatingpid,heating PID,enum [fast\|medium\|slow] (>=0<=0), ,true,select.thermostat_hc1_heating_PID,select.thermostat_hc1_heatingpid,6,1,1,59,1
"UI800, BC400",thermostat,4,hc1.pumpopt,pump optimization,boolean (>=0<=0), ,true,switch.thermostat_hc1_pump_optimization,switch.thermostat_hc1_pumpopt,6,1,1,60,1
"UI800, BC400",thermostat,4,hc1.inttimefloor,integral time floor,uint8 (>=160<=320),minutes,true,number.thermostat_hc1_integral_time_floor,number.thermostat_hc1_inttimefloor,6,1,10,61,1
@@ -4439,16 +4439,16 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"RC200, CW100, CR120, CR50",thermostat,157,hc1.control,control device,enum [RC310\|RC200\|RC100\|RC100H\|TC100] (>=0<=0), ,true,select.thermostat_hc1_control_device,select.thermostat_hc1_control,6,1,1,44,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.heatondelay,heat-on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_heat-on_delay,number.thermostat_hc1_heatondelay,6,1,1,47,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.heatoffdelay,heat-off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_heat-off_delay,number.thermostat_hc1_heatoffdelay,6,1,1,48,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_hc1_instant_start,number.thermostat_hc1_instantstart,6,1,1,49,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.boost,boost mode,boolean (>=0<=0), ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,50,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.boosttime,boost time,uint8 (>=0<=0),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,51,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,49,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,50,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_hc1_instant_start,number.thermostat_hc1_instantstart,6,1,1,51,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,52,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,53,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,54,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.boost,boost mode,boolean (>=0<=0), ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,53,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.boosttime,boost time,uint8 (>=0<=0),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,54,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.switchprogmode,switch program mode,enum [level\|absolute] (>=0<=0), ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,55,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.redthreshold,reduction threshold,int8 (>=12<=22),C,true,number.thermostat_hc1_reduction_threshold,number.thermostat_hc1_redthreshold,6,1,1/2,56,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.solarinfl,solar influence,uint8 (>=-5<=4294967295),C,true,number.thermostat_hc1_solar_influence,number.thermostat_hc1_solarinfl,6,1,1,57,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.currsolarinfl,current solar influence,uint8,C,false,sensor.thermostat_hc1_current_solar_influence,sensor.thermostat_hc1_currsolarinfl,6,1,1/10,58,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.solarinfl,solar influence,int8 (>=-5<=0),C,true,number.thermostat_hc1_solar_influence,number.thermostat_hc1_solarinfl,6,1,1,57,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.currsolarinfl,current solar influence,int8,C,false,sensor.thermostat_hc1_current_solar_influence,sensor.thermostat_hc1_currsolarinfl,6,1,1/10,58,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.heatingpid,heating PID,enum [fast\|medium\|slow] (>=0<=0), ,true,select.thermostat_hc1_heating_PID,select.thermostat_hc1_heatingpid,6,1,1,59,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.pumpopt,pump optimization,boolean (>=0<=0), ,true,switch.thermostat_hc1_pump_optimization,switch.thermostat_hc1_pumpopt,6,1,1,60,1
"RC200, CW100, CR120, CR50",thermostat,157,hc1.inttimefloor,integral time floor,uint8 (>=160<=320),minutes,true,number.thermostat_hc1_integral_time_floor,number.thermostat_hc1_inttimefloor,6,1,10,61,1
@@ -4537,16 +4537,16 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.remotehum,room humidity from remote,cmd [] (>=-1<=101),%,true,sensor.thermostat_hc1_room_humidity_from_remote,sensor.thermostat_hc1_remotehum,6,1,1,46,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.heatondelay,heat-on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_heat-on_delay,number.thermostat_hc1_heatondelay,6,1,1,47,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.heatoffdelay,heat-off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_heat-off_delay,number.thermostat_hc1_heatoffdelay,6,1,1,48,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_hc1_instant_start,number.thermostat_hc1_instantstart,6,1,1,49,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.boost,boost mode,boolean (>=0<=0), ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,50,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.boosttime,boost time,uint8 (>=0<=0),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,51,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,49,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,50,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_hc1_instant_start,number.thermostat_hc1_instantstart,6,1,1,51,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,52,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,53,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,54,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.boost,boost mode,boolean (>=0<=0), ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,53,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.boosttime,boost time,uint8 (>=0<=0),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,54,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.switchprogmode,switch program mode,enum [level\|absolute] (>=0<=0), ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,55,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.redthreshold,reduction threshold,int8 (>=12<=22),C,true,number.thermostat_hc1_reduction_threshold,number.thermostat_hc1_redthreshold,6,1,1/2,56,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.solarinfl,solar influence,uint8 (>=-5<=4294967295),C,true,number.thermostat_hc1_solar_influence,number.thermostat_hc1_solarinfl,6,1,1,57,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.currsolarinfl,current solar influence,uint8,C,false,sensor.thermostat_hc1_current_solar_influence,sensor.thermostat_hc1_currsolarinfl,6,1,1/10,58,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.solarinfl,solar influence,int8 (>=-5<=0),C,true,number.thermostat_hc1_solar_influence,number.thermostat_hc1_solarinfl,6,1,1,57,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.currsolarinfl,current solar influence,int8,C,false,sensor.thermostat_hc1_current_solar_influence,sensor.thermostat_hc1_currsolarinfl,6,1,1/10,58,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.heatingpid,heating PID,enum [fast\|medium\|slow] (>=0<=0), ,true,select.thermostat_hc1_heating_PID,select.thermostat_hc1_heatingpid,6,1,1,59,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.pumpopt,pump optimization,boolean (>=0<=0), ,true,switch.thermostat_hc1_pump_optimization,switch.thermostat_hc1_pumpopt,6,1,1,60,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,hc1.inttimefloor,integral time floor,uint8 (>=160<=320),minutes,true,number.thermostat_hc1_integral_time_floor,number.thermostat_hc1_inttimefloor,6,1,10,61,1
@@ -4644,16 +4644,16 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"Rego 2000/3000",thermostat,172,hc1.remotehum,room humidity from remote,cmd [] (>=-1<=101),%,true,sensor.thermostat_hc1_room_humidity_from_remote,sensor.thermostat_hc1_remotehum,6,1,1,46,1
"Rego 2000/3000",thermostat,172,hc1.heatondelay,heat-on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_heat-on_delay,number.thermostat_hc1_heatondelay,6,1,1,47,1
"Rego 2000/3000",thermostat,172,hc1.heatoffdelay,heat-off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_heat-off_delay,number.thermostat_hc1_heatoffdelay,6,1,1,48,1
"Rego 2000/3000",thermostat,172,hc1.instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_hc1_instant_start,number.thermostat_hc1_instantstart,6,1,1,49,1
"Rego 2000/3000",thermostat,172,hc1.boost,boost mode,boolean (>=0<=0), ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,50,1
"Rego 2000/3000",thermostat,172,hc1.boosttime,boost time,uint8 (>=0<=0),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,51,1
"Rego 2000/3000",thermostat,172,hc1.coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,49,1
"Rego 2000/3000",thermostat,172,hc1.cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,50,1
"Rego 2000/3000",thermostat,172,hc1.instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_hc1_instant_start,number.thermostat_hc1_instantstart,6,1,1,51,1
"Rego 2000/3000",thermostat,172,hc1.coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,52,1
"Rego 2000/3000",thermostat,172,hc1.coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,53,1
"Rego 2000/3000",thermostat,172,hc1.cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,54,1
"Rego 2000/3000",thermostat,172,hc1.boost,boost mode,boolean (>=0<=0), ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,53,1
"Rego 2000/3000",thermostat,172,hc1.boosttime,boost time,uint8 (>=0<=0),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,54,1
"Rego 2000/3000",thermostat,172,hc1.switchprogmode,switch program mode,enum [level\|absolute] (>=0<=0), ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,55,1
"Rego 2000/3000",thermostat,172,hc1.redthreshold,reduction threshold,int8 (>=12<=22),C,true,number.thermostat_hc1_reduction_threshold,number.thermostat_hc1_redthreshold,6,1,1/2,56,1
"Rego 2000/3000",thermostat,172,hc1.solarinfl,solar influence,uint8 (>=-5<=4294967295),C,true,number.thermostat_hc1_solar_influence,number.thermostat_hc1_solarinfl,6,1,1,57,1
"Rego 2000/3000",thermostat,172,hc1.currsolarinfl,current solar influence,uint8,C,false,sensor.thermostat_hc1_current_solar_influence,sensor.thermostat_hc1_currsolarinfl,6,1,1/10,58,1
"Rego 2000/3000",thermostat,172,hc1.solarinfl,solar influence,int8 (>=-5<=0),C,true,number.thermostat_hc1_solar_influence,number.thermostat_hc1_solarinfl,6,1,1,57,1
"Rego 2000/3000",thermostat,172,hc1.currsolarinfl,current solar influence,int8,C,false,sensor.thermostat_hc1_current_solar_influence,sensor.thermostat_hc1_currsolarinfl,6,1,1/10,58,1
"Rego 2000/3000",thermostat,172,hc1.heatingpid,heating PID,enum [fast\|medium\|slow] (>=0<=0), ,true,select.thermostat_hc1_heating_PID,select.thermostat_hc1_heatingpid,6,1,1,59,1
"Rego 2000/3000",thermostat,172,hc1.pumpopt,pump optimization,boolean (>=0<=0), ,true,switch.thermostat_hc1_pump_optimization,switch.thermostat_hc1_pumpopt,6,1,1,60,1
"Rego 2000/3000",thermostat,172,hc1.inttimefloor,integral time floor,uint8 (>=160<=320),minutes,true,number.thermostat_hc1_integral_time_floor,number.thermostat_hc1_inttimefloor,6,1,10,61,1
@@ -4720,6 +4720,14 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"Rego 3000, UI800, Logamatic BC400",thermostat,253,pvraiseheat,raise heating with PV,int8 (>=0<=5),K,true,number.thermostat_raise_heating_with_PV,number.thermostat_pvraiseheat,6,0,1,62,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,pvlowercool,lower cooling with PV,int8 (>=-5<=0),K,true,number.thermostat_lower_cooling_with_PV,number.thermostat_pvlowercool,6,0,1,63,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,absent,absent,boolean (>=0<=0), ,true,switch.thermostat_absent,switch.thermostat_absent,6,0,1,64,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hpoperatingmode,heatpump operating mode,enum [off\|auto\|heating\|cooling] (>=0<=0), ,true,select.thermostat_heatpump_operating_mode,select.thermostat_hpoperatingmode,6,0,1,89,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,summertemp,summer temperature,uint8 (>=10<=30),C,true,number.thermostat_summer_temperature,number.thermostat_summertemp,6,0,1,90,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_instant_start,number.thermostat_instantstart,6,0,1,91,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_cooling_starttemp,number.thermostat_coolstart,6,0,1,92,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,heatondelay,heat-on delay,uint8 (>=1<=48),hours,true,number.thermostat_heat-on_delay,number.thermostat_heatondelay,6,0,1/4,93,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,heatoffdelay,heat-off delay,uint8 (>=1<=48),hours,true,number.thermostat_heat-off_delay,number.thermostat_heatoffdelay,6,0,1/4,94,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_cooling_on_delay,number.thermostat_coolondelay,6,0,1/4,95,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_cooling_off_delay,number.thermostat_cooloffdelay,6,0,1/4,96,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.seltemp,selected room temperature,int16 (>=0<=30),C,true,number.thermostat_hc1_selected_room_temperature,number.thermostat_hc1_seltemp,6,1,1/2,0,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.currtemp,current room temperature,int16,C,false,sensor.thermostat_hc1_current_room_temperature,sensor.thermostat_hc1_currtemp,6,1,1/10,1,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.haclimate,mqtt discovery current room temperature,enum [selTemp\|roomTemp], ,false,sensor.thermostat_hc1_mqtt_discovery_current_room_temperature,sensor.thermostat_hc1_haclimate,6,1,1,2,1
@@ -4764,21 +4772,15 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.dewoffset,dew point offset,uint8 (>=2<=10),K,true,number.thermostat_hc1_dew_point_offset,number.thermostat_hc1_dewoffset,6,1,1,41,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.roomtempdiff,room temp difference,uint8 (>=0<=0),K,true,number.thermostat_hc1_room_temp_difference,number.thermostat_hc1_roomtempdiff,6,1,1,42,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.hpminflowtemp,HP min. flow temp.,uint8 (>=0<=0),C,true,number.thermostat_hc1_HP_min._flow_temp.,number.thermostat_hc1_hpminflowtemp,6,1,1,43,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.control,control device,enum [off\|-\|RC100\|RC100H\|-\|RC120RF\|RC220/RT800\|single] (>=0<=0), ,true,select.thermostat_hc1_control_device,select.thermostat_hc1_control,6,1,1,44,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.control,control device,enum [off\|-\|CR10\|CR10H\|-\|CR20RF\|RT800\|single] (>=0<=0), ,true,select.thermostat_hc1_control_device,select.thermostat_hc1_control,6,1,1,44,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.remotetemp,room temperature from remote,cmd [] (>=-1<=101),C,true,sensor.thermostat_hc1_room_temperature_from_remote,sensor.thermostat_hc1_remotetemp,6,1,1/10,45,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.remotehum,room humidity from remote,cmd [] (>=-1<=101),%,true,sensor.thermostat_hc1_room_humidity_from_remote,sensor.thermostat_hc1_remotehum,6,1,1,46,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.heatondelay,heat-on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_heat-on_delay,number.thermostat_hc1_heatondelay,6,1,1,47,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.heatoffdelay,heat-off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_heat-off_delay,number.thermostat_hc1_heatoffdelay,6,1,1,48,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_hc1_instant_start,number.thermostat_hc1_instantstart,6,1,1,49,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.boost,boost mode,boolean (>=0<=0), ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,50,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.boosttime,boost time,uint8 (>=0<=0),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,51,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,52,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,53,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,54,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.boost,boost mode,boolean (>=0<=0), ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,53,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.boosttime,boost time,uint8 (>=0<=0),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,54,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.switchprogmode,switch program mode,enum [level\|absolute] (>=0<=0), ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,55,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.redthreshold,reduction threshold,int8 (>=12<=22),C,true,number.thermostat_hc1_reduction_threshold,number.thermostat_hc1_redthreshold,6,1,1/2,56,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.solarinfl,solar influence,uint8 (>=-5<=4294967295),C,true,number.thermostat_hc1_solar_influence,number.thermostat_hc1_solarinfl,6,1,1,57,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.currsolarinfl,current solar influence,uint8,C,false,sensor.thermostat_hc1_current_solar_influence,sensor.thermostat_hc1_currsolarinfl,6,1,1/10,58,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.solarinfl,solar influence,int8 (>=-5<=0),C,true,number.thermostat_hc1_solar_influence,number.thermostat_hc1_solarinfl,6,1,1,57,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.currsolarinfl,current solar influence,int8,C,false,sensor.thermostat_hc1_current_solar_influence,sensor.thermostat_hc1_currsolarinfl,6,1,1/10,58,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.heatingpid,heating PID,enum [fast\|medium\|slow] (>=0<=0), ,true,select.thermostat_hc1_heating_PID,select.thermostat_hc1_heatingpid,6,1,1,59,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.pumpopt,pump optimization,boolean (>=0<=0), ,true,switch.thermostat_hc1_pump_optimization,switch.thermostat_hc1_pumpopt,6,1,1,60,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,hc1.inttimefloor,integral time floor,uint8 (>=160<=320),minutes,true,number.thermostat_hc1_integral_time_floor,number.thermostat_hc1_inttimefloor,6,1,10,61,1
@@ -5859,7 +5861,7 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"MX400",connect,17,datetime,date/time,string, ,false,sensor.connect_date/time,sensor.connect_datetime,13,0,1,0,13
"MX400",connect,17,outdoortemp,outside temperature,int16,C,false,sensor.connect_outside_temperature,sensor.connect_outdoortemp,13,0,1/10,13,1
"MX400",connect,17,src1.currtemp,current room temperature,int16,C,false,sensor.connect_src1_current_room_temperature,sensor.connect_src1_currtemp,13,36,1/10,0,1
"MX400",connect,17,src1.airhumidity,relative air humidity,int8,%,false,sensor.connect_src1_relative_air_humidity,sensor.connect_src1_airhumidity,13,36,1,1,1
"MX400",connect,17,src1.airhumidity,relative air humidity,uint8,%,false,sensor.connect_src1_relative_air_humidity,sensor.connect_src1_airhumidity,13,36,1,1,1
"MX400",connect,17,src1.dewtemperature,dew point temperature,int16,C,false,sensor.connect_src1_dew_point_temperature,sensor.connect_src1_dewtemperature,13,36,1/10,2,1
"MX400",connect,17,src1.seltemp,selected room temperature,uint8 (>=5<=30),C,true,number.connect_src1_selected_room_temperature,number.connect_src1_seltemp,13,36,1/2,3,1
"MX400",connect,17,src1.mode,operating mode,enum [off\|manual\|auto] (>=0<=0), ,true,select.connect_src1_operating_mode,select.connect_src1_mode,13,36,1,4,1
@@ -5973,49 +5975,25 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"MM200",water,161,dhw.circ,circulation active,boolean (>=0<=0), ,true,switch.water_dhw_circulation_active,switch.water_dhw_circ,19,9,1,9,1
"MM200",water,161,dhw.circmode,circulation pump mode,enum [off\|on\|auto\|own prog] (>=0<=0), ,true,select.water_dhw_circulation_pump_mode,select.water_dhw_circmode,19,9,1,10,1
"SM100, MS100",water,163,dhw.temp,current temperature,uint16,C,false,sensor.water_dhw_current_temperature,sensor.water_dhw_temp,19,9,1/10,1,1
"SM100, MS100",water,163,dhw.storagetemp1,storage intern temperature,uint16,C,false,sensor.water_dhw_storage_intern_temperature,sensor.water_dhw_storagetemp1,19,9,1/10,16,1
"SM100, MS100",water,163,dhw.coldtemp,cold water,uint16,C,false,sensor.water_dhw_cold_water,sensor.water_dhw_coldtemp,19,9,1/10,17,1
"SM100, MS100",water,163,dhw.temp5,temperature 5,uint16,C,false,sensor.water_dhw_temperature_5,sensor.water_dhw_temp5,19,9,1/10,18,1
"SM100, MS100",water,163,dhw.rettemp,return temperature,uint16,C,false,sensor.water_dhw_return_temperature,sensor.water_dhw_rettemp,19,9,1/10,19,1
"SM100, MS100",water,163,dhw.tempstatus,temperature switch in assigned dhw (MC1),int8, ,false,sensor.water_dhw_temperature_switch_in_assigned_dhw_(MC1),sensor.water_dhw_tempstatus,19,9,1,11,1
"SM100, MS100",water,163,dhw.pump,pump,boolean, ,false,binary_sensor.water_dhw_pump,binary_sensor.water_dhw_pump,19,9,1,4,1
"SM100, MS100",water,163,dhw.maxtemp,maximum temperature,uint8 (>=0<=0),C,true,number.water_dhw_maximum_temperature,number.water_dhw_maxtemp,19,9,1,12,1
"SM100, MS100",water,163,dhw.seltemp,selected temperature,uint8 (>=0<=0),C,true,number.water_dhw_selected_temperature,number.water_dhw_seltemp,19,9,1,0,1
"SM100, MS100",water,163,dhw.redtemp,reduced temperature,uint8 (>=0<=0),C,true,number.water_dhw_reduced_temperature,number.water_dhw_redtemp,19,9,1,14,1
"SM100, MS100",water,163,dhw.hottemp,extra hot temperature,uint8 (>=0<=0),C,true,number.water_dhw_extra_hot_temperature,number.water_dhw_hottemp,19,9,1,20,1
"SM100, MS100",water,163,dhw.dailytemp,daily temperature,uint8 (>=0<=0),C,true,number.water_dhw_daily_temperature,number.water_dhw_dailytemp,19,9,1,21,1
"SM100, MS100",water,163,dhw.difftemp,start differential temperature,int8 (>=0<=0),C,true,number.water_dhw_start_differential_temperature,number.water_dhw_difftemp,19,9,1,13,1
"SM100, MS100",water,163,dhw.disinfectiontemp,disinfection temperature,uint8 (>=0<=0),C,true,number.water_dhw_disinfection_temperature,number.water_dhw_disinfectiontemp,19,9,1,8,1
"SM100, MS100",water,163,dhw.redtemp,reduced temperature,uint8 (>=0<=0),C,true,number.water_dhw_reduced_temperature,number.water_dhw_redtemp,19,9,1,14,1
"SM100, MS100",water,163,dhw.requiredtemp,required temperature,uint8 (>=0<=0),C,true,number.water_dhw_required_temperature,number.water_dhw_requiredtemp,19,9,1,15,1
"SM100, MS100",water,163,dhw.circ,circulation active,boolean (>=0<=0), ,true,switch.water_dhw_circulation_active,switch.water_dhw_circ,19,9,1,9,1
"SM100, MS100",water,163,dhw.circmode,circulation pump mode,enum [off\|1x3min\|2x3min\|3x3min\|4x3min\|5x3min\|6x3min\|continuous] (>=0<=0), ,true,select.water_dhw_circulation_pump_mode,select.water_dhw_circmode,19,9,1,10,1
"SM100, MS100",water,163,dhw.circtc,circulation time controlled,boolean (>=0<=0), ,true,switch.water_dhw_circulation_time_controlled,switch.water_dhw_circtc,19,9,1,22,1
"SM100, MS100",water,163,dhw.keepwarm,keep warm,boolean (>=0<=0), ,true,switch.water_dhw_keep_warm,switch.water_dhw_keepwarm,19,9,1,23,1
"SM100, MS100",water,163,dhw.status2,status 2,enum [\|\|\|no heat\|\|\|heat request\|\|disinfecting\|hold], ,false,sensor.water_dhw_status_2,sensor.water_dhw_status2,19,9,1,24,1
"SM100, MS100",water,163,dhw.pumpmod,pump modulation,uint8,%,false,sensor.water_dhw_pump_modulation,sensor.water_dhw_pumpmod,19,9,1,25,1
"SM100, MS100",water,163,dhw.flow,flow rate,uint16,l/min,false,sensor.water_dhw_flow_rate,sensor.water_dhw_flow,19,9,1/10,26,1
"SM100, MS100",water,163,dhw.valvereturn,return valve,uint8 (>=0<=0),%,true,number.water_dhw_return_valve,number.water_dhw_valvereturn,19,9,1,27,1
"SM100, MS100",water,163,dhw.deltatret,temp. diff. return valve,uint8 (>=0<=0),K,true,number.water_dhw_temp._diff._return_valve,number.water_dhw_deltatret,19,9,1,28,1
"SM100, MS100",water,163,dhw.errordisp,error display,enum [off\|normal\|inverted] (>=0<=0), ,true,select.water_dhw_error_display,select.water_dhw_errordisp,19,9,1,29,1
"SM100, MS100",water,163,dhw.circmode,circulation pump mode,enum [off\|on\|auto\|own prog] (>=0<=0), ,true,select.water_dhw_circulation_pump_mode,select.water_dhw_circmode,19,9,1,10,1
"SM200, MS200",water,164,dhw.temp,current temperature,uint16,C,false,sensor.water_dhw_current_temperature,sensor.water_dhw_temp,19,9,1/10,1,1
"SM200, MS200",water,164,dhw.storagetemp1,storage intern temperature,uint16,C,false,sensor.water_dhw_storage_intern_temperature,sensor.water_dhw_storagetemp1,19,9,1/10,16,1
"SM200, MS200",water,164,dhw.coldtemp,cold water,uint16,C,false,sensor.water_dhw_cold_water,sensor.water_dhw_coldtemp,19,9,1/10,17,1
"SM200, MS200",water,164,dhw.temp5,temperature 5,uint16,C,false,sensor.water_dhw_temperature_5,sensor.water_dhw_temp5,19,9,1/10,18,1
"SM200, MS200",water,164,dhw.rettemp,return temperature,uint16,C,false,sensor.water_dhw_return_temperature,sensor.water_dhw_rettemp,19,9,1/10,19,1
"SM200, MS200",water,164,dhw.tempstatus,temperature switch in assigned dhw (MC1),int8, ,false,sensor.water_dhw_temperature_switch_in_assigned_dhw_(MC1),sensor.water_dhw_tempstatus,19,9,1,11,1
"SM200, MS200",water,164,dhw.pump,pump,boolean, ,false,binary_sensor.water_dhw_pump,binary_sensor.water_dhw_pump,19,9,1,4,1
"SM200, MS200",water,164,dhw.maxtemp,maximum temperature,uint8 (>=0<=0),C,true,number.water_dhw_maximum_temperature,number.water_dhw_maxtemp,19,9,1,12,1
"SM200, MS200",water,164,dhw.seltemp,selected temperature,uint8 (>=0<=0),C,true,number.water_dhw_selected_temperature,number.water_dhw_seltemp,19,9,1,0,1
"SM200, MS200",water,164,dhw.redtemp,reduced temperature,uint8 (>=0<=0),C,true,number.water_dhw_reduced_temperature,number.water_dhw_redtemp,19,9,1,14,1
"SM200, MS200",water,164,dhw.hottemp,extra hot temperature,uint8 (>=0<=0),C,true,number.water_dhw_extra_hot_temperature,number.water_dhw_hottemp,19,9,1,20,1
"SM200, MS200",water,164,dhw.dailytemp,daily temperature,uint8 (>=0<=0),C,true,number.water_dhw_daily_temperature,number.water_dhw_dailytemp,19,9,1,21,1
"SM200, MS200",water,164,dhw.difftemp,start differential temperature,int8 (>=0<=0),C,true,number.water_dhw_start_differential_temperature,number.water_dhw_difftemp,19,9,1,13,1
"SM200, MS200",water,164,dhw.disinfectiontemp,disinfection temperature,uint8 (>=0<=0),C,true,number.water_dhw_disinfection_temperature,number.water_dhw_disinfectiontemp,19,9,1,8,1
"SM200, MS200",water,164,dhw.redtemp,reduced temperature,uint8 (>=0<=0),C,true,number.water_dhw_reduced_temperature,number.water_dhw_redtemp,19,9,1,14,1
"SM200, MS200",water,164,dhw.requiredtemp,required temperature,uint8 (>=0<=0),C,true,number.water_dhw_required_temperature,number.water_dhw_requiredtemp,19,9,1,15,1
"SM200, MS200",water,164,dhw.circ,circulation active,boolean (>=0<=0), ,true,switch.water_dhw_circulation_active,switch.water_dhw_circ,19,9,1,9,1
"SM200, MS200",water,164,dhw.circmode,circulation pump mode,enum [off\|1x3min\|2x3min\|3x3min\|4x3min\|5x3min\|6x3min\|continuous] (>=0<=0), ,true,select.water_dhw_circulation_pump_mode,select.water_dhw_circmode,19,9,1,10,1
"SM200, MS200",water,164,dhw.circtc,circulation time controlled,boolean (>=0<=0), ,true,switch.water_dhw_circulation_time_controlled,switch.water_dhw_circtc,19,9,1,22,1
"SM200, MS200",water,164,dhw.keepwarm,keep warm,boolean (>=0<=0), ,true,switch.water_dhw_keep_warm,switch.water_dhw_keepwarm,19,9,1,23,1
"SM200, MS200",water,164,dhw.status2,status 2,enum [\|\|\|no heat\|\|\|heat request\|\|disinfecting\|hold], ,false,sensor.water_dhw_status_2,sensor.water_dhw_status2,19,9,1,24,1
"SM200, MS200",water,164,dhw.pumpmod,pump modulation,uint8,%,false,sensor.water_dhw_pump_modulation,sensor.water_dhw_pumpmod,19,9,1,25,1
"SM200, MS200",water,164,dhw.flow,flow rate,uint16,l/min,false,sensor.water_dhw_flow_rate,sensor.water_dhw_flow,19,9,1/10,26,1
"SM200, MS200",water,164,dhw.valvereturn,return valve,uint8 (>=0<=0),%,true,number.water_dhw_return_valve,number.water_dhw_valvereturn,19,9,1,27,1
"SM200, MS200",water,164,dhw.deltatret,temp. diff. return valve,uint8 (>=0<=0),K,true,number.water_dhw_temp._diff._return_valve,number.water_dhw_deltatret,19,9,1,28,1
"SM200, MS200",water,164,dhw.errordisp,error display,enum [off\|normal\|inverted] (>=0<=0), ,true,select.water_dhw_error_display,select.water_dhw_errordisp,19,9,1,29,1
"SM200, MS200",water,164,dhw.circmode,circulation pump mode,enum [off\|on\|auto\|own prog] (>=0<=0), ,true,select.water_dhw_circulation_pump_mode,select.water_dhw_circmode,19,9,1,10,1
"MP100",pool,204,pooltemp,pool temperature,int16,C,false,sensor.pool_pool_temperature,sensor.pool_pooltemp,20,0,1/10,-1,1
"MP100",pool,204,poolshuntstatus,pool shunt status opening/closing,enum [stopped\|opening\|closing\|open\|close], ,false,sensor.pool_pool_shunt_status_opening/closing,sensor.pool_poolshuntstatus,20,0,1,-1,1
"MP100",pool,204,poolshunt,pool shunt open/close (0% = pool / 100% = heat),uint8,%,false,sensor.pool_pool_shunt_open/close_(0%_=_pool_/_100%_=_heat),sensor.pool_poolshunt,20,0,1,-1,1
Can't render this file because it is too large.
+14 -14
View File
@@ -13,7 +13,7 @@ telegram_type_id,name,is_fetched
0x19,UBAMonitorSlow,
0x1A,UBASetPoints,
0x1C,UBAMaintenanceStatus,
0x1E,HydrTemp,
0x1E,WM10TempMessage,
0x23,JunkersSetMixer,fetched
0x27,UBASettingsWW,fetched
0x28,WeatherComp,fetched
@@ -77,7 +77,7 @@ telegram_type_id,name,is_fetched
0x0103,ISM1StatusMessage,fetched
0x0104,ISM2StatusMessage,
0x010C,IPMStatusMessage,
0x011E,IPMTempMessage,
0x011E,JunkersDisp,fetched
0x012E,HPEnergy1,
0x013B,HPEnergy2,
0x0165,JunkersSet,
@@ -112,10 +112,10 @@ telegram_type_id,name,is_fetched
0x02A0,RC300Curves,
0x02A1,RC300Curves,
0x02A2,RC300Curves,
0x02A5,RC300Monitor,
0x02A5,CRFMonitor,
0x02A6,RC300Monitor,
0x02A7,RC300Monitor,
0x02A8,RC300Monitor,
0x02A8,CRFMonitor,
0x02A9,RC300Monitor,
0x02AA,RC300Monitor,
0x02AB,RC300Monitor,
@@ -171,15 +171,15 @@ telegram_type_id,name,is_fetched
0x0468,HPSet,
0x0469,HPSet,
0x046A,HPSet,
0x0470,RC300Summer2,fetched
0x0471,RC300Summer2,
0x0472,RC300Summer2,
0x0473,RC300Summer2,
0x0474,RC300Summer2,
0x0475,RC300Summer2,
0x0476,RC300Summer2,
0x0477,RC300Summer2,
0x0478,RC300Summer2,
0x0470,RC300Summer3,fetched
0x0471,RC300Sumr2,
0x0472,RC300Sumr2,
0x0473,RC300Sumr2,
0x0474,RC300Sumr2,
0x0475,RC300Sumr2,
0x0476,RC300Sumr2,
0x0477,RC300Sumr2,
0x0478,RC300Sumr2,
0x047B,HP2,
0x0484,HPSilentMode,fetched
0x0485,HpCooling,fetched
@@ -199,7 +199,7 @@ telegram_type_id,name,is_fetched
0x04A2,HpInput,fetched
0x04A5,HPFan,fetched
0x04A7,HPPowerLimit,fetched
0x04AA,HPPower,
0x04AA,HPPower2,fetched
0x04AE,HPEnergy,fetched
0x04AF,HPMeters,fetched
0x055C,VentilationSet,fetched
1 telegram_type_id name is_fetched
13 0x19 UBAMonitorSlow
14 0x1A UBASetPoints
15 0x1C UBAMaintenanceStatus
16 0x1E HydrTemp WM10TempMessage
17 0x23 JunkersSetMixer fetched
18 0x27 UBASettingsWW fetched
19 0x28 WeatherComp fetched
77 0x0103 ISM1StatusMessage fetched
78 0x0104 ISM2StatusMessage
79 0x010C IPMStatusMessage
80 0x011E IPMTempMessage JunkersDisp fetched
81 0x012E HPEnergy1
82 0x013B HPEnergy2
83 0x0165 JunkersSet
112 0x02A0 RC300Curves
113 0x02A1 RC300Curves
114 0x02A2 RC300Curves
115 0x02A5 RC300Monitor CRFMonitor
116 0x02A6 RC300Monitor
117 0x02A7 RC300Monitor
118 0x02A8 RC300Monitor CRFMonitor
119 0x02A9 RC300Monitor
120 0x02AA RC300Monitor
121 0x02AB RC300Monitor
171 0x0468 HPSet
172 0x0469 HPSet
173 0x046A HPSet
174 0x0470 RC300Summer2 RC300Summer3 fetched
175 0x0471 RC300Summer2 RC300Sumr2
176 0x0472 RC300Summer2 RC300Sumr2
177 0x0473 RC300Summer2 RC300Sumr2
178 0x0474 RC300Summer2 RC300Sumr2
179 0x0475 RC300Summer2 RC300Sumr2
180 0x0476 RC300Summer2 RC300Sumr2
181 0x0477 RC300Summer2 RC300Sumr2
182 0x0478 RC300Summer2 RC300Sumr2
183 0x047B HP2
184 0x0484 HPSilentMode fetched
185 0x0485 HpCooling fetched
199 0x04A2 HpInput fetched
200 0x04A5 HPFan fetched
201 0x04A7 HPPowerLimit fetched
202 0x04AA HPPower HPPower2 fetched
203 0x04AE HPEnergy fetched
204 0x04AF HPMeters fetched
205 0x055C VentilationSet fetched
+1
View File
@@ -24,6 +24,7 @@ build_flags =
-D FACTORY_NTP_TIME_ZONE_LABEL=\"Europe/Amsterdam\"
-D FACTORY_NTP_TIME_ZONE_FORMAT=\"CET-1CEST,M3.5.0,M10.5.0/3\"
-D FACTORY_NTP_SERVER=\"time.google.com\"
-D FACTORY_NTP_THERMOSTAT_SYNC=0
; MQTT settings
-D FACTORY_MQTT_ENABLED=false
+12 -12
View File
@@ -26,8 +26,8 @@
"@alova/adapter-xhr": "2.3.1",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@mui/icons-material": "^9.0.1",
"@mui/material": "^9.0.1",
"@mui/icons-material": "^9.2.0",
"@mui/material": "^9.2.0",
"@preact/compat": "^18.3.2",
"@table-library/react-table-library": "4.1.15",
"alova": "3.5.1",
@@ -37,17 +37,17 @@
"jwt-decode": "^4.0.0",
"magic-string": "^0.30.21",
"mime-types": "^3.0.2",
"preact": "^10.29.1",
"react": "^19.2.6",
"react-dom": "^19.2.6",
"react-icons": "^5.6.0",
"react-router": "^7.15.0",
"preact": "^10.29.7",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"react-icons": "^5.7.0",
"react-router": "^7.18.1",
"react-toastify": "^11.1.0",
"typesafe-i18n": "^5.27.1",
"typescript": "^6.0.3"
},
"devDependencies": {
"@babel/core": "^7.29.0",
"@babel/core": "^7.29.7",
"@eslint/js": "^10.0.1",
"@preact/compat": "^18.3.2",
"@preact/preset-vite": "^2.10.5",
@@ -55,11 +55,11 @@
"@types/node": "^25.7.0",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"axe-core": "^4.11.4",
"concurrently": "^9.2.1",
"eslint": "^10.3.0",
"axe-core": "^4.12.1",
"concurrently": "^9.2.4",
"eslint": "^10.7.0",
"eslint-config-prettier": "^10.1.8",
"prettier": "^3.8.3",
"prettier": "^3.9.5",
"rollup-plugin-visualizer": "^7.0.1",
"terser": "^5.47.1",
"typescript-eslint": "^8.59.3",
+448 -442
View File
File diff suppressed because it is too large Load Diff
+25
View File
@@ -1,3 +1,28 @@
allowBuilds:
cwebp-bin: set this to true or false
esbuild: set this to true or false
gifsicle: set this to true or false
jpegtran-bin: set this to true or false
mozjpeg: set this to true or false
optipng-bin: set this to true or false
pngquant-bin: set this to true or false
minimumReleaseAgeExclude:
- '@babel/code-frame@7.29.7'
- '@babel/compat-data@7.29.7'
- '@babel/core@7.29.7'
- '@babel/generator@7.29.7'
- '@babel/helper-compilation-targets@7.29.7'
- '@babel/helper-globals@7.29.7'
- '@babel/helper-module-imports@7.29.7'
- '@babel/helper-module-transforms@7.29.7'
- '@babel/helper-string-parser@7.29.7'
- '@babel/helper-validator-identifier@7.29.7'
- '@babel/helper-validator-option@7.29.7'
- '@babel/helpers@7.29.7'
- '@babel/parser@7.29.7'
- '@babel/template@7.29.7'
- '@babel/traverse@7.29.7'
- '@babel/types@7.29.7'
onlyBuiltDependencies:
- cwebp-bin
- esbuild
+1 -1
View File
@@ -19,7 +19,7 @@ const AVAILABLE_LOCALES = [
'sk',
'sv',
'tr',
'cz'
'cs'
] as Locales[];
// Static toast configuration - no need to recreate on every render
+1 -5
View File
@@ -13,11 +13,7 @@ import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';
import type { SvgIconProps } from '@mui/material';
export type OptionType =
| 'deleted'
| 'readonly'
| 'web_exclude'
| 'api_mqtt_exclude'
| 'favorite';
'deleted' | 'readonly' | 'web_exclude' | 'api_mqtt_exclude' | 'favorite';
type IconPair = [
React.ComponentType<SvgIconProps>,
@@ -396,7 +396,7 @@ const ApplicationSettings = () => {
margin="normal"
select
>
<MenuItem value="cz">Česky (CZ)</MenuItem>
<MenuItem value="cs">Česky (CS)</MenuItem>
<MenuItem value="de">Deutsch (DE)</MenuItem>
<MenuItem value="en">English (EN)</MenuItem>
<MenuItem value="fr">Français (FR)</MenuItem>
+67 -3
View File
@@ -12,6 +12,7 @@ import {
DialogActions,
DialogContent,
DialogTitle,
Grid,
MenuItem,
TextField,
Typography
@@ -39,7 +40,12 @@ import { formatLocalDateTime, updateValueDirty, useRest } from 'utils';
import { ValidationError, validate } from 'validators';
import { NTP_SETTINGS_VALIDATOR } from 'validators/ntp';
import { TIME_ZONES, selectedTimeZone, useTimeZoneSelectItems } from './TZ';
import {
TIME_ZONES,
selectedTimeZone,
timeZoneSelectItemsT,
useTimeZoneSelectItems
} from './TZ';
const NTPSettings = () => {
const {
@@ -63,13 +69,17 @@ const NTPSettings = () => {
// Memoized timezone select items for better performance
const timeZoneItems = useTimeZoneSelectItems();
const timeZoneItemsT = timeZoneSelectItemsT();
// Memoized selected timezone value
const selectedTzValue = useMemo(
() => (data ? selectedTimeZone(data.tz_label, data.tz_format) : undefined),
[data?.tz_label, data?.tz_format]
);
const selectedTzValueT = useMemo(
() => (data ? selectedTimeZone(data.tz_label_t, data.tz_format_t) : undefined),
[data?.tz_label_t, data?.tz_format_t]
);
const [localTime, setLocalTime] = useState<string>('');
const [settingTime, setSettingTime] = useState<boolean>(false);
const [processing, setProcessing] = useState<boolean>(false);
@@ -150,6 +160,18 @@ const NTPSettings = () => {
[updateFormValue]
);
const changeTimeZoneT = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
void updateState(readNTPSettings(), (settings: NTPSettingsType) => ({
...settings,
tz_label_t: event.target.value,
tz_format_t: TIME_ZONES[event.target.value]
}));
updateFormValue(event);
},
[updateFormValue]
);
// Memoize render content to prevent unnecessary re-renders
const renderContent = useMemo(() => {
if (!data) {
@@ -174,6 +196,7 @@ const NTPSettings = () => {
label={LL.NTP_SERVER()}
fullWidth
variant="outlined"
disabled={!data.enabled}
value={data.server}
onChange={updateFormValue}
margin="normal"
@@ -192,7 +215,47 @@ const NTPSettings = () => {
<MenuItem disabled>{LL.TIME_ZONE()}...</MenuItem>
{timeZoneItems}
</ValidatedTextField>
{data.enabled && (
<Grid container spacing={2} rowSpacing={0}>
<Grid>
<ValidatedTextField
fieldErrors={fieldErrors || {}}
name="thermostat_sync"
label="Sync EMS-Thermostat"
variant="outlined"
sx={{ width: '30ch' }}
value={data.thermostat_sync}
onChange={updateFormValue}
margin="normal"
select
>
<MenuItem value={0}>{LL.OFF()}</MenuItem>
<MenuItem value={1}>{LL.ON()}</MenuItem>
<MenuItem value={2}>
{LL.USE()} {LL.TIME_ZONE()}
</MenuItem>
</ValidatedTextField>
</Grid>
<Grid>
{data.thermostat_sync === 2 && (
<ValidatedTextField
fieldErrors={fieldErrors || {}}
name="tz_label_t"
label={LL.TIME_ZONE() + ' Thermostat'}
sx={{ width: '30ch' }}
variant="outlined"
value={selectedTzValueT}
onChange={changeTimeZoneT}
margin="normal"
select
>
<MenuItem disabled>{LL.TIME_ZONE()}...</MenuItem>
{timeZoneItemsT}
</ValidatedTextField>
)}
</Grid>
</Grid>
)}
<Box sx={{ display: 'flex', flexWrap: 'wrap' }}>
{!data.enabled && !dirtyFlags.length && (
<Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}>
@@ -243,6 +306,7 @@ const NTPSettings = () => {
updateFormValue,
fieldErrors,
selectedTzValue,
selectedTzValueT,
changeTimeZone,
timeZoneItems,
dirtyFlags,
+4
View File
@@ -495,3 +495,7 @@ const precomputedTimeZoneItems = TIME_ZONE_LABELS.map((label) => (
export function timeZoneSelectItems() {
return precomputedTimeZoneItems;
}
export function timeZoneSelectItemsT() {
return precomputedTimeZoneItems;
}
@@ -28,7 +28,7 @@ interface LanguageOption {
}
const LANGUAGE_OPTIONS: LanguageOption[] = [
{ key: 'cz', flag: CZflag, label: 'CZ' },
{ key: 'cs', flag: CZflag, label: 'CS' },
{ key: 'de', flag: DEflag, label: 'DE' },
{ key: 'en', flag: GBflag, label: 'EN' },
{ key: 'fr', flag: FRflag, label: 'FR' },
@@ -1,6 +1,6 @@
import type { Translation } from '../i18n-types';
const cz: Translation = {
const cs: Translation = {
LANGUAGE: 'Jazyk',
RETRY: 'Zkusit znovu',
LOADING: 'Načítání',
@@ -368,4 +368,4 @@ const cz: Translation = {
};
export default cz;
export default cs;
+3
View File
@@ -16,6 +16,9 @@ export interface NTPSettingsType {
server: string;
tz_label: string;
tz_format: string;
thermostat_sync: number;
tz_label_t: string;
tz_format_t: string;
}
export interface Time {
+6 -2
View File
@@ -79,8 +79,12 @@ class DummySettings {
uint8_t provisionMode = 0;
// NTP
String server = "pool.ntp.org";
String tzLabel = "Europe/London";
String server = "pool.ntp.org";
String tzLabel = "Europe/London";
String tzFormat = "GMT0BST,M3.5.0/1,M10.5.0";
String tzLabelT = "Europe/Berlin";
String tzFormatT = "CET-1CEST,M3.5.0,M10.5.0/3";
uint8_t thermostat_sync = 0;
static void read(DummySettings & settings, JsonObject root) {};
static void read(DummySettings & settings) {};
+2 -2
View File
@@ -12,8 +12,8 @@
"@msgpack/msgpack": "^3.1.3",
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
"formidable": "^3.5.4",
"itty-router": "^5.0.23",
"prettier": "^3.8.3"
"itty-router": "^5.0.24",
"prettier": "^3.9.6"
},
"packageManager": "pnpm@10.33.4+sha512.1c67b3b359b2d408119ba1ed289f34b8fc3c6873412bec6fd264fbdc82489e510fcbecb9ce9d22dae7f3b76269d8441046014bdca53b9979cd7a561ad631b800"
}
+63 -63
View File
@@ -13,54 +13,54 @@ importers:
version: 3.1.3
'@trivago/prettier-plugin-sort-imports':
specifier: ^6.0.2
version: 6.0.2(prettier@3.8.3)
version: 6.0.2(prettier@3.9.6)
formidable:
specifier: ^3.5.4
version: 3.5.4
itty-router:
specifier: ^5.0.23
version: 5.0.23
specifier: ^5.0.24
version: 5.0.24
prettier:
specifier: ^3.8.3
version: 3.8.3
specifier: ^3.9.6
version: 3.9.6
packages:
'@babel/code-frame@7.29.0':
resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
'@babel/code-frame@7.29.7':
resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==}
engines: {node: '>=6.9.0'}
'@babel/generator@7.29.1':
resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==}
'@babel/generator@7.29.8':
resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==}
engines: {node: '>=6.9.0'}
'@babel/helper-globals@7.28.0':
resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
'@babel/helper-globals@7.29.7':
resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==}
engines: {node: '>=6.9.0'}
'@babel/helper-string-parser@7.27.1':
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
'@babel/helper-string-parser@7.29.7':
resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==}
engines: {node: '>=6.9.0'}
'@babel/helper-validator-identifier@7.28.5':
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
'@babel/helper-validator-identifier@7.29.7':
resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==}
engines: {node: '>=6.9.0'}
'@babel/parser@7.29.3':
resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==}
'@babel/parser@7.29.8':
resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==}
engines: {node: '>=6.0.0'}
hasBin: true
'@babel/template@7.28.6':
resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
'@babel/template@7.29.7':
resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==}
engines: {node: '>=6.9.0'}
'@babel/traverse@7.29.0':
resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==}
'@babel/traverse@7.29.8':
resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==}
engines: {node: '>=6.9.0'}
'@babel/types@7.29.0':
resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
'@babel/types@7.29.8':
resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==}
engines: {node: '>=6.9.0'}
'@jridgewell/gen-mapping@0.3.13':
@@ -112,8 +112,8 @@ packages:
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
brace-expansion@2.1.0:
resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==}
brace-expansion@2.1.4:
resolution: {integrity: sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==}
debug@4.4.3:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
@@ -131,8 +131,8 @@ packages:
resolution: {integrity: sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==}
engines: {node: '>=14.0.0'}
itty-router@5.0.23:
resolution: {integrity: sha512-i49WU+SNPrwOZA4Z61En1RYd5h2Lcqa+5IvCpMrNi4dxymzJK15ozUUnRrWIUAv95Zamd4eJPAot2UvHRrQg7w==}
itty-router@5.0.24:
resolution: {integrity: sha512-PXij1qGKtE6jg3dLgrTRdh/Frovl5Wc4Av67sD2xfhDPrgNt4u79++/il8/c/OfZGkhD/8uYJub8tjo+H165rA==}
javascript-natural-sort@0.7.1:
resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==}
@@ -167,8 +167,8 @@ packages:
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
prettier@3.8.3:
resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==}
prettier@3.9.6:
resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==}
engines: {node: '>=14'}
hasBin: true
@@ -177,52 +177,52 @@ packages:
snapshots:
'@babel/code-frame@7.29.0':
'@babel/code-frame@7.29.7':
dependencies:
'@babel/helper-validator-identifier': 7.28.5
'@babel/helper-validator-identifier': 7.29.7
js-tokens: 4.0.0
picocolors: 1.1.1
'@babel/generator@7.29.1':
'@babel/generator@7.29.8':
dependencies:
'@babel/parser': 7.29.3
'@babel/types': 7.29.0
'@babel/parser': 7.29.8
'@babel/types': 7.29.8
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
jsesc: 3.1.0
'@babel/helper-globals@7.28.0': {}
'@babel/helper-globals@7.29.7': {}
'@babel/helper-string-parser@7.27.1': {}
'@babel/helper-string-parser@7.29.7': {}
'@babel/helper-validator-identifier@7.28.5': {}
'@babel/helper-validator-identifier@7.29.7': {}
'@babel/parser@7.29.3':
'@babel/parser@7.29.8':
dependencies:
'@babel/types': 7.29.0
'@babel/types': 7.29.8
'@babel/template@7.28.6':
'@babel/template@7.29.7':
dependencies:
'@babel/code-frame': 7.29.0
'@babel/parser': 7.29.3
'@babel/types': 7.29.0
'@babel/code-frame': 7.29.7
'@babel/parser': 7.29.8
'@babel/types': 7.29.8
'@babel/traverse@7.29.0':
'@babel/traverse@7.29.8':
dependencies:
'@babel/code-frame': 7.29.0
'@babel/generator': 7.29.1
'@babel/helper-globals': 7.28.0
'@babel/parser': 7.29.3
'@babel/template': 7.28.6
'@babel/types': 7.29.0
'@babel/code-frame': 7.29.7
'@babel/generator': 7.29.8
'@babel/helper-globals': 7.29.7
'@babel/parser': 7.29.8
'@babel/template': 7.29.7
'@babel/types': 7.29.8
debug: 4.4.3
transitivePeerDependencies:
- supports-color
'@babel/types@7.29.0':
'@babel/types@7.29.8':
dependencies:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
'@babel/helper-string-parser': 7.29.7
'@babel/helper-validator-identifier': 7.29.7
'@jridgewell/gen-mapping@0.3.13':
dependencies:
@@ -246,17 +246,17 @@ snapshots:
dependencies:
'@noble/hashes': 1.8.0
'@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.3)':
'@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.9.6)':
dependencies:
'@babel/generator': 7.29.1
'@babel/parser': 7.29.3
'@babel/traverse': 7.29.0
'@babel/types': 7.29.0
'@babel/generator': 7.29.8
'@babel/parser': 7.29.8
'@babel/traverse': 7.29.8
'@babel/types': 7.29.8
javascript-natural-sort: 0.7.1
lodash-es: 4.18.1
minimatch: 9.0.9
parse-imports-exports: 0.2.4
prettier: 3.8.3
prettier: 3.9.6
transitivePeerDependencies:
- supports-color
@@ -264,7 +264,7 @@ snapshots:
balanced-match@1.0.2: {}
brace-expansion@2.1.0:
brace-expansion@2.1.4:
dependencies:
balanced-match: 1.0.2
@@ -283,7 +283,7 @@ snapshots:
dezalgo: 1.0.4
once: 1.4.0
itty-router@5.0.23: {}
itty-router@5.0.24: {}
javascript-natural-sort@0.7.1: {}
@@ -295,7 +295,7 @@ snapshots:
minimatch@9.0.9:
dependencies:
brace-expansion: 2.1.0
brace-expansion: 2.1.4
ms@2.1.3: {}
@@ -311,6 +311,6 @@ snapshots:
picocolors@1.1.1: {}
prettier@3.8.3: {}
prettier@3.9.6: {}
wrappy@1.0.2: {}
+3 -3
View File
@@ -141,8 +141,8 @@ let system_status = {
let DEV_VERSION_IS_UPGRADEABLE: boolean;
let STABLE_VERSION_IS_UPGRADEABLE: boolean;
let THIS_VERSION: string;
let LATEST_STABLE_VERSION = '3.8.2';
let LATEST_DEV_VERSION = '3.8.3-dev.2';
let LATEST_STABLE_VERSION = '3.8.3';
let LATEST_DEV_VERSION = '3.9.0-dev.0';
// scenarios for testing versioning
let version_test = 0; // on latest stable, or switch to dev
@@ -4139,7 +4139,7 @@ let emsesp_schedule = {
id: 5,
active: false,
flags: 130,
time: 'system/network info/rssi < -70',
time: 'system/network/rssi < -70',
cmd: 'system/restart',
value: '',
name: 'bad_wifi'
+2 -2
View File
@@ -39,7 +39,7 @@ build_flags =
-D CONFIG_ASYNC_TCP_PRIORITY=10 ; default
-D CONFIG_ASYNC_TCP_QUEUE_SIZE=64 ; default
-D CONFIG_ASYNC_TCP_RUNNING_CORE=1 ; force async_tcp task to be on same core as Arduino app (default is any core)
-D CONFIG_ASYNC_TCP_STACK_SIZE=6144 ; default is 16KB/8192*2
-D CONFIG_ASYNC_TCP_STACK_SIZE=8192 ; default is 16KB/8192*2
; ESPAsyncWebServer
; -D WS_MAX_QUEUED_MESSAGES=0 ; not used, default 8
; -D SSE_MAX_QUEUED_MESSAGES=1 ; for log messages, default 32
@@ -105,7 +105,7 @@ board_build.filesystem = littlefs
lib_deps =
bblanchon/ArduinoJson @ 7.4.3
ESP32Async/AsyncTCP @ 3.4.10
ESP32Async/ESPAsyncWebServer @ 3.11.0
ESP32Async/ESPAsyncWebServer @ 3.11.2
; https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
; builds the web interface only, not the firmware
-28
View File
@@ -88,34 +88,6 @@ def bin_copy(source, target, env):
print(f"MD5: {md5_hash}")
md5_file.write_text(md5_hash)
# Make a copy using the old 3.6.x filename format for backwards compatibility
# Note: there is a chance newer E32V2s (which use the 16MB partition table and PSRAM)
# are running a custom build of the 3.6.5 firmware as 3.6.5 was released before
# production of the gateway board. Updating via the WebUI will break the system
# and require a manual update.
pio_env = env.get('PIOENV', '')
extra_variant = None
if pio_env == "s3_16M_P":
extra_variant = f"EMS-ESP-{app_version.replace('.', '_')}-ESP32_S3"
elif pio_env == "s_4M":
extra_variant = f"EMS-ESP-{app_version.replace('.', '_')}-ESP32"
if extra_variant:
extra_bin_file = firmware_dir / f"{extra_variant}.bin"
extra_md5_file = firmware_dir / f"{extra_variant}.md5"
# Remove existing files if they exist
for file_path in [extra_bin_file, extra_md5_file]:
if file_path.exists():
file_path.unlink()
# Copy files
shutil.copy2(str(bin_file), str(extra_bin_file))
shutil.copy2(str(md5_file), str(extra_md5_file))
print(f"Filename copy for 3.6.x: {extra_bin_file}")
print("=" * 90)
+17 -11
View File
@@ -3,28 +3,34 @@
# run from root folder, like `sh ./scripts/update_all.sh`
# as well as GNUMake (make) and python3
# abort on first error so a failed lint/build isn't silently swallowed
set -e
cd interface
rm -rf node_modules
corepack use pnpm@latest-10
pnpm update --latest
corepack use pnpm@latest
pnpm update
pnpm install
pnpm format
pnpm lint
pnpm build-webUI
cd ../mock-api
rm -rf node_modules
corepack use pnpm@latest-10
pnpm update --latest
corepack use pnpm@latest
pnpm update
pnpm install
pnpm format
cd ..
cd interface
pnpm build-webUI
cd ..
npx cspell "**"
# platformio run -e build_modbus
# platformio run -e build_standalone
# platformio run -e native-test -t exec
# build files that go into docs folder
platformio run -e build_modbus -t clean
platformio run -e build_modbus
platformio run -e build_standalone -t clean
platformio run -e build_standalone
# run tests
platformio run -e native-test -t exec
+15 -9
View File
@@ -86,16 +86,22 @@ void NTPSettingsService::ntp_received(struct timeval * tv) {
}
void NTPSettings::read(NTPSettings & settings, JsonObject root) {
root["enabled"] = settings.enabled;
root["server"] = settings.server;
root["tz_label"] = settings.tzLabel;
root["tz_format"] = settings.tzFormat;
root["enabled"] = settings.enabled;
root["server"] = settings.server;
root["tz_label"] = settings.tzLabel;
root["tz_format"] = settings.tzFormat;
root["thermostat_sync"] = settings.thermostat_sync;
root["tz_label_t"] = settings.tzLabelT;
root["tz_format_t"] = settings.tzFormatT;
}
StateUpdateResult NTPSettings::update(JsonObject root, NTPSettings & settings) {
settings.enabled = root["enabled"] | FACTORY_NTP_ENABLED;
settings.server = root["server"] | FACTORY_NTP_SERVER;
settings.tzLabel = root["tz_label"] | FACTORY_NTP_TIME_ZONE_LABEL;
settings.tzFormat = root["tz_format"] | FACTORY_NTP_TIME_ZONE_FORMAT;
settings.enabled = root["enabled"] | FACTORY_NTP_ENABLED;
settings.server = root["server"] | FACTORY_NTP_SERVER;
settings.tzLabel = root["tz_label"] | FACTORY_NTP_TIME_ZONE_LABEL;
settings.tzFormat = root["tz_format"] | FACTORY_NTP_TIME_ZONE_FORMAT;
settings.thermostat_sync = root["thermostat_sync"] | FACTORY_NTP_THERMOSTAT_SYNC;
settings.tzLabelT = root["tz_label_t"] | FACTORY_NTP_TIME_ZONE_LABEL;
settings.tzFormatT = root["tz_format_t"] | FACTORY_NTP_TIME_ZONE_FORMAT;
return StateUpdateResult::CHANGED;
}
}
+11 -4
View File
@@ -19,6 +19,10 @@
#define FACTORY_NTP_TIME_ZONE_FORMAT "GMT0BST,M3.5.0/1,M10.5.0"
#endif
#ifndef FACTORY_NTP_THERMOSTAT_SYNC
#define FACTORY_NTP_THERMOSTAT_SYNC 1
#endif
#ifndef FACTORY_NTP_SERVER
#define FACTORY_NTP_SERVER "time.google.com"
#endif
@@ -30,10 +34,13 @@
class NTPSettings {
public:
bool enabled = FACTORY_NTP_ENABLED;
String tzLabel = FACTORY_NTP_TIME_ZONE_LABEL;
String tzFormat = FACTORY_NTP_TIME_ZONE_FORMAT;
String server = FACTORY_NTP_SERVER;
bool enabled = FACTORY_NTP_ENABLED;
String tzLabel = FACTORY_NTP_TIME_ZONE_LABEL;
String tzFormat = FACTORY_NTP_TIME_ZONE_FORMAT;
String server = FACTORY_NTP_SERVER;
uint8_t thermostat_sync = FACTORY_NTP_THERMOSTAT_SYNC;
String tzLabelT = FACTORY_NTP_TIME_ZONE_LABEL;
String tzFormatT = FACTORY_NTP_TIME_ZONE_FORMAT;
static void read(NTPSettings & settings, JsonObject root);
static StateUpdateResult update(JsonObject root, NTPSettings & settings);
+11 -10
View File
@@ -4,7 +4,6 @@
#include <esp_app_format.h>
#include <esp_ota_ops.h>
// #include <esp_partition.h>
static String getFilenameExtension(const String & filename) {
const auto pos = filename.lastIndexOf('.');
@@ -49,7 +48,7 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
// LittleFS filesystem image
_is_filesystem = true;
_md5[0] = '\0'; // clear any stale md5 so Update.end() doesn't compare against it
} else if ((extension == "bin") && (filesize > 2000000)) {
} else if ((extension == "bin") && (filesize > 1000000)) {
_is_firmware = true;
} else if (extension == "json") {
_md5[0] = '\0'; // clear md5
@@ -133,9 +132,10 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
}
if (_is_firmware || _is_filesystem) {
if (!request->_tempObject) { // if we haven't delt with an error, continue with the OTA update
if (!request->_tempObject) {
//continue with the OTA update
if (Update.write(data, len) != len) {
emsesp::EMSESP::logger().err("Update.write failed at offset %u (chunk %u): %s",
emsesp::EMSESP::logger().err("OTA update failed at offset %u (chunk %u): %s",
static_cast<unsigned>(Update.progress()),
static_cast<unsigned>(len),
Update.errorString());
@@ -144,15 +144,16 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
}
if (final) {
if (!Update.end(true)) {
emsesp::EMSESP::logger().err("Update.end failed: %s", Update.errorString());
handleError(request, 500);
emsesp::EMSESP::logger().err("OTA update failed: %s", Update.errorString());
handleError(request, 500); // internal error, failed
return;
}
}
} else {
if (len && len != request->_tempFile.write(data, len)) { // stream the incoming chunk to the opened file
handleError(request, 507); // 507-Insufficient Storage
}
}
} else {
// stream the incoming chunk to the opened file
if (len && len != request->_tempFile.write(data, len)) {
handleError(request, 507); // 507-Insufficient Storage
}
}
}
+6 -2
View File
@@ -15,7 +15,7 @@ void WiFiScanner::scanNetworks(AsyncWebServerRequest * request) {
if (WiFi.scanComplete() != -1) {
WiFi.scanDelete();
WiFi.scanNetworks(true);
WiFi.scanNetworks(true, false, true, 250);
}
}
@@ -38,6 +38,10 @@ void WiFiScanner::listNetworks(AsyncWebServerRequest * request) {
} else if (numNetworks == -1) {
request->send(202); // special code to indicate scan in progress
} else {
scanNetworks(request);
auto * response = new AsyncJsonResponse(false);
JsonObject root = response->getRoot();
root["networks"].to<JsonArray>();
response->setLength();
request->send(response);
}
}
+4 -2
View File
@@ -546,11 +546,13 @@ bool AnalogSensor::update(uint8_t gpio, const char * org_name, double offset, do
if (deleted) {
LOG_DEBUG("Removing analog sensor GPIO %02d", gpio);
EMSESP::system_.remove_gpio(gpio); // remove from used list only
EMSESP::nvs_.remove(AnalogCustomization.name);
if (EMSESP::nvs_.isKey(AnalogCustomization.name)) {
EMSESP::nvs_.remove(AnalogCustomization.name);
}
settings.analogCustomizations.remove(AnalogCustomization);
} else {
// update existing record
if (!strcmp(name, AnalogCustomization.name)) {
if (!strcmp(name, AnalogCustomization.name) && EMSESP::nvs_.isKey(AnalogCustomization.name)) {
EMSESP::nvs_.remove(AnalogCustomization.name);
}
strlcpy(AnalogCustomization.name, name, sizeof(AnalogCustomization.name));
+4 -3
View File
@@ -105,7 +105,7 @@
{215, DeviceType::THERMOSTAT, "Comfort RF", DeviceFlags::EMS_DEVICE_FLAG_CRF | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18
{216, DeviceType::THERMOSTAT, "CRF200S", DeviceFlags::EMS_DEVICE_FLAG_CRF | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18
{246, DeviceType::THERMOSTAT, "Comfort+2RF", DeviceFlags::EMS_DEVICE_FLAG_CRF | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18
{253, DeviceType::THERMOSTAT, "Rego 3000, UI800, Logamatic BC400", DeviceFlags::EMS_DEVICE_FLAG_BC400}, // 0x10
{253, DeviceType::THERMOSTAT, "Rego 3000, UI800, Logamatic BC400", DeviceFlags::EMS_DEVICE_FLAG_UI800}, // 0x10
// Thermostat - Sieger - 0x10 / 0x17
{ 66, DeviceType::THERMOSTAT, "ES72, RC20", DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17 or remote
@@ -187,8 +187,9 @@
{ 74, DeviceType::ALERT, "EM10", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Gateways - 0x48
{17, DeviceType::GATEWAY, "MX400", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x48 and 0x4B
{189, DeviceType::GATEWAY, "KM200, MB LAN 2", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{17, DeviceType::GATEWAY, "MX400", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x48, 0x4B, or 0x50 as wireless base
{189, DeviceType::GATEWAY, "KM200, MB LAN 2", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x48
{222, DeviceType::GATEWAY, "KM300", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x4A
{252, DeviceType::GATEWAY, "K30RF, MX300", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Generic - 0x40 or other with no product-id and no version
+1
View File
@@ -513,6 +513,7 @@ class EMSdevice {
static constexpr uint8_t EMS_DEVICE_FLAG_CR120 = 16; // mostly like RC300, but some changes
static constexpr uint8_t EMS_DEVICE_FLAG_CR11 = 17; // CRF200 only monitor
static constexpr uint8_t EMS_DEVICE_FLAG_HMC310 = 18;
static constexpr uint8_t EMS_DEVICE_FLAG_UI800 = 19;
uint8_t count_entities();
uint8_t count_entities_fav();
+1
View File
@@ -158,6 +158,7 @@ class DeviceValue {
enum DeviceValueNumOp : int8_t {
DV_NUMOP_NONE = 0, // default
DV_NUMOP_DIV2 = 2,
DV_NUMOP_DIV4 = 4,
DV_NUMOP_DIV10 = 10,
DV_NUMOP_DIV60 = 60,
DV_NUMOP_DIV100 = 100,
+23 -11
View File
@@ -1800,8 +1800,8 @@ void EMSESP::start() {
LOG_INFO("Library loaded: %d EMS devices, %d device entities, %s", device_library_.size(), EMSESP_TRANSLATION_COUNT, system_.languages_string().c_str());
webCustomizationService.begin(); // load the customizations
webSchedulerService.begin(); // load the scheduler events
webCustomEntityService.begin(); // load the custom telegram reads
webSchedulerService.begin(); // load the scheduler events
// start telnet service if it's enabled
// default idle is 10 minutes, default write timeout is 0 (automatic)
@@ -1864,16 +1864,9 @@ void EMSESP::loop() {
webLogService.loop(); // log in Web UI
// run the loop, unless we're in the middle of an OTA upload
if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_NORMAL || EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_INVALID_GPIO) {
// check for GPIO Errors - this is called once when booting
if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_INVALID_GPIO) {
static bool only_once = false;
if (!only_once) {
LOG_ERROR("Invalid GPIOs used. Please check your settings and the system log");
only_once = true;
}
}
// if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_NORMAL || EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_INVALID_GPIO) {
if (EMSESP::system_.systemStatus() != SYSTEM_STATUS::SYSTEM_STATUS_PENDING_UPLOAD
&& EMSESP::system_.systemStatus() != SYSTEM_STATUS::SYSTEM_STATUS_UPLOADING) {
// loop through the services
rxservice_.loop(); // process any incoming Rx telegrams
shower_.loop(); // check for shower on/off
@@ -1887,6 +1880,14 @@ void EMSESP::loop() {
}
scheduled_fetch_values(); // force a query on the EMS devices to fetch latest data at a set interval (1 min)
}
// check for GPIO Errors - this is called once when booting
if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_INVALID_GPIO) {
static bool only_once = false;
if (!only_once) {
LOG_ERROR("Invalid GPIOs used. Please check your settings and the system log");
only_once = true;
}
}
if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_PENDING_UPLOAD) {
// start an upload from a URL, assuming the URL exists and set from a previous pass
@@ -1899,6 +1900,17 @@ void EMSESP::loop() {
}
}
// reset status after 5 Minutes
if (EMSESP::system_.systemStatus() != SYSTEM_STATUS::SYSTEM_STATUS_NORMAL) {
static uint32_t starttime = 0;
if (starttime == 0) {
starttime = uuid::get_uptime_ms();
} else if (uuid::get_uptime_ms() - starttime > 300000) {
starttime = 0;
EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_NORMAL);
}
}
// telnet service
#ifndef EMSESP_STANDALONE
if (system_.telnet_enabled()) {
+14 -1
View File
@@ -817,7 +817,7 @@ std::string Helpers::toUpper(std::string const & s) {
// capitalizes one UTF-8 character in char array
// works with Latin1 (1 byte), Polish and other (2 bytes) characters
// supports special characters for all 11 supported languages: EN, DE, NL, SV, PL, NO, FR, TR, IT, SK, CZ
// supports special characters for all 11 supported languages: EN, DE, NL, SV, PL, NO, FR, TR, IT, SK, CS
#if defined(EMSESP_STANDALONE)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
@@ -1033,4 +1033,17 @@ float Helpers::numericoperator2scalefactor(int8_t numeric_operator) {
return -numeric_operator;
}
int16_t Helpers::calc_dew(int16_t temp, uint8_t humi) {
if (humi == EMS_VALUE_UINT8_NOTSET || temp == EMS_VALUE_INT16_NOTSET) {
return EMS_VALUE_INT16_NOTSET;
}
const float k2 = 17.62;
const float k3 = 243.12;
const float t = (float)temp / 10;
const float h = (float)humi / 100;
int16_t dt = (10 * k3 * (((k2 * t) / (k3 + t)) + log(h)) / (((k2 * k3) / (k3 + t)) - log(h)));
return dt;
}
} // namespace emsesp
+1
View File
@@ -84,6 +84,7 @@ class Helpers {
static uint8_t count_items(const char * const * list);
static const char * translated_word(const char * const * strings, const bool force_en = false);
static int16_t calc_dew(int16_t temp, uint8_t hum);
#ifdef EMSESP_STANDALONE
static char * ultostr(char * ptr, uint32_t value, const uint8_t base);
+6 -1
View File
@@ -190,7 +190,11 @@ MAKE_NOTRANSLATION(rc100, "RC100")
MAKE_NOTRANSLATION(rc100h, "RC100H")
MAKE_NOTRANSLATION(tc100, "TC100")
MAKE_NOTRANSLATION(rc120rf, "RC120RF")
MAKE_NOTRANSLATION(rc220, "RC220/RT800")
MAKE_NOTRANSLATION(rc220, "RC220")
MAKE_NOTRANSLATION(rt800, "RT800")
MAKE_NOTRANSLATION(cr10, "CR10")
MAKE_NOTRANSLATION(cr10h, "CR10H")
MAKE_NOTRANSLATION(cr20rf, "CR20RF")
MAKE_NOTRANSLATION(single, "single")
MAKE_NOTRANSLATION(dash, "-")
MAKE_NOTRANSLATION(BLANK, "")
@@ -370,6 +374,7 @@ MAKE_ENUM(enum_roomsensor, FL_(extern), FL_(intern), FL_(auto))
MAKE_ENUM(enum_roominfluence, FL_(off), FL_(intern), FL_(extern), FL_(auto))
MAKE_ENUM(enum_control1, FL_(rc310), FL_(rc200), FL_(rc100), FL_(rc100h), FL_(tc100))
MAKE_ENUM(enum_control2, FL_(off), FL_(dash), FL_(rc100), FL_(rc100h), FL_(dash), FL_(rc120rf), FL_(rc220), FL_(single)) // BC400
MAKE_ENUM(enum_control3, FL_(off), FL_(dash), FL_(cr10), FL_(cr10h), FL_(dash), FL_(cr20rf), FL_(rt800), FL_(single)) // UI800
MAKE_ENUM(enum_switchmode, FL_(off), FL_(eco), FL_(comfort), FL_(heat))
MAKE_ENUM(enum_switchProgMode, FL_(level), FL_(absolute))
+6 -6
View File
@@ -30,9 +30,9 @@
#define EMSESP_LOCALE_TR "tr"
#define EMSESP_LOCALE_IT "it"
#define EMSESP_LOCALE_SK "sk"
#define EMSESP_LOCALE_CZ "cz"
#define EMSESP_LOCALE_CS "cs"
// IMPORTANT! translations are in the order: en, de, nl, sv, pl, no, fr, tr, it, sk, cz
// IMPORTANT! translations are in the order: en, de, nl, sv, pl, no, fr, tr, it, sk, cs
//
// if there is no translation, it will default to en
@@ -292,7 +292,7 @@ MAKE_WORD_TRANSLATION(curve, "heatingcurve", "Heizkurve", "stookkromme", "värme
MAKE_WORD_TRANSLATION(radiator, "radiator", "Heizkörper", "radiator", "Radiator", "grzejniki", "radiator", "radiateur", "radyatör", "radiatore", "radiátor", "radiátor")
MAKE_WORD_TRANSLATION(convector, "convector", "Konvektor", "convector", "Konvektor", "konwektory", "konvektor", "convecteur", "convector", "convettore", "konvektor", "konvektor")
MAKE_WORD_TRANSLATION(floor, "floor", "Fussboden", "vloer", "Golv", "podłoga", "gulv", "sol", "yer", "pavimento", "podlaha", "podlaha")
MAKE_WORD_TRANSLATION(roomflow, "roomflow", "Raum Fluß", "kamer doorstroming", "Rumsflöde", "przepływ w pomieszczeniu", "romstrøm", "flux de la pièce", "oda akışı", "flusso della stanza", "prúdenie miestnosti", "průtok mistnosti")
MAKE_WORD_TRANSLATION(roomflow, "roomflow", "Raum Fluss", "kamer doorstroming", "Rumsflöde", "przepływ w pomieszczeniu", "romstrøm", "flux de la pièce", "oda akışı", "flusso della stanza", "prúdenie miestnosti", "průtok mistnosti")
MAKE_WORD_TRANSLATION(roomload, "roomload", "Raum Bedarf", "kamer behoefte", "Rumsbehov", "zapotrzebowanie pomieszczenia", "rombelastning", "charge de la pièce", "oda yükü", "carico della stanza", "izbová zaťaž", "zatížení místnosti")
MAKE_WORD_TRANSLATION(summer, "summer", "Sommer", "zomer", "Sommar", "lato", "sommer", "été", "yaz", "estate", "leto", "léto")
MAKE_WORD_TRANSLATION(winter, "winter", "Winter", "winter", "Vinter", "zima", "vinter", "hiver", "kış", "inverno", "zima", "zima")
@@ -367,7 +367,7 @@ MAKE_WORD_TRANSLATION(bookshelf, "mdi:bookshelf", "mdi:bookshelf")
// MQTT Discovery - this is special device entity for 'climate'
MAKE_TRANSLATION(haclimate, "haclimate", "mqtt discovery current room temperature", "Discovery aktuelle Raumtemperatur", "Discovery huidige kamertemperatuur", "MQTT Discovery för aktuell rumstemperatur", "termostat w HA", "HA Avlest temp", "découverte mqtt température actuelle", "Güncel osa sıcaklığı", "verifica temperatura ambiente attuale", "mqtt discovery aktuálna teplota v miestnosti", "mqtt discovery aktuální pokojová teplota")
// Entity translations: tag, mqtt, en, de, nl, sv, pl, no, fr, tr, it, sk, cz
// Entity translations: tag, mqtt, en, de, nl, sv, pl, no, fr, tr, it, sk, cs
// Boiler
MAKE_TRANSLATION(chimneysweeper, "chimneysweeper", "chimney sweeper", "Schornsteinfeger", "schoorsteenveger", "Sotare", "tryb kominiarza", "feier", "ramoneur", "baca temizleyici", "spazzacamino", "kominár", "kominík")
MAKE_TRANSLATION(reset, "reset", "reset", "Reset", "Reset", "Återställ", "kasowanie komunikatu", "nullstill", "reset", "Sıfırla", "Reset", "reset", "reset")
@@ -826,8 +826,8 @@ MAKE_TRANSLATION(vacations7, "vacations7", "vacation dates 7", "Urlaubstage 7",
MAKE_TRANSLATION(vacations8, "vacations8", "vacation dates 8", "Urlaubstage 8", "Vakantiedagen 8", "Semesterdatum 8", "urlop 8", "feriedager 8", "dates vacances 8", "izin günleri 8", "date vacanze 8", "termíny dovolenky 8", "data prázdnin 8")
MAKE_TRANSLATION(absent, "absent", "absent", "Abwesend", "", "Frånvarande", "", "", "", "", "", "chýbajúci", "chybějící")
MAKE_TRANSLATION(redthreshold, "redthreshold", "reduction threshold", "Absenkschwelle", "", "Tröskel för sänkning", "", "", "", "", "", "zníženie tresholdu", "práh snížení")
MAKE_TRANSLATION(solarinfl, "solarinfl", "solar influence", "Solareinfluß", "", "", "", "", "", "", "", "slnečný vplyv", "sluneční vliv")
MAKE_TRANSLATION(currsolarinfl, "currsolarinfl", "current solar influence", "akt. Solareinfluß", "", "", "", "", "", "", "", "aktuálny slnečný vplyv", "aktuální sluneční vliv")
MAKE_TRANSLATION(solarinfl, "solarinfl", "solar influence", "Solareinfluss", "", "", "", "", "", "", "", "slnečný vplyv", "sluneční vliv")
MAKE_TRANSLATION(currsolarinfl, "currsolarinfl", "current solar influence", "akt. Solareinfluss", "", "", "", "", "", "", "", "aktuálny slnečný vplyv", "aktuální sluneční vliv")
MAKE_TRANSLATION(hpmode, "hpmode", "HP Mode", "WP-Modus", "Modus warmtepomp", "Värmepumpsläge", "tryb pracy pompy ciepła", "", "", "yüksek güç modu", "Modalità Termopompa", "Režim TČ", "režim tepelného čerpadla")
MAKE_TRANSLATION(dewoffset, "dewoffset", "dew point offset", "Taupunktdifferenz", "Offset dauwpunt", "Daggpunktsförskjutning", "przesunięcie punktu rosy", "", "", "çiğ noktası göreli", "differenza del punto di rugiada", "posun rosného bodu", "offset rosného bodu")
MAKE_TRANSLATION(roomtempdiff, "roomtempdiff", "room temp difference", "Raumtemperaturdifferenz", "Verschiltemperatuur kamertemp", "Rumstemperaturskillnad", "różnica temp. pomieszczenia", "", "", "oda sıcaklığı farkı", "differenza temperatura ambiente", "rozdiel izbovej teploty", "rozdíl teploty místnosti")
+13 -19
View File
@@ -300,6 +300,14 @@ const std::initializer_list<Modbus::EntityModbusInfo> Modbus::modbus_register_ma
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(heatingPID), 74, 1), // heatingpid
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(preheating), 75, 1), // preheating
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(vacations), 76, 13), // vacations
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(hpoperatingmode), 89, 1), // hpoperatingmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(summertemp), 90, 1), // summertemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(instantstart), 91, 1), // instantstart
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(coolstart), 92, 1), // coolstart
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(heatondelay), 93, 1), // heatondelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(heatoffdelay), 94, 1), // heatoffdelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(coolondelay), 95, 1), // coolondelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DEVICE_DATA, FL_(cooloffdelay), 96, 1), // cooloffdelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(selRoomTemp), 0, 1), // seltemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(roomTemp), 1, 1), // currtemp
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(haclimate), 2, 1), // haclimate
@@ -349,12 +357,12 @@ const std::initializer_list<Modbus::EntityModbusInfo> Modbus::modbus_register_ma
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(remotehum), 46, 1), // remotehum
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatondelay), 47, 1), // heatondelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatoffdelay), 48, 1), // heatoffdelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(instantstart), 49, 1), // instantstart
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(boost), 50, 1), // boost
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(boosttime), 51, 1), // boosttime
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(coolondelay), 49, 1), // coolondelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(cooloffdelay), 50, 1), // cooloffdelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(instantstart), 51, 1), // instantstart
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(coolstart), 52, 1), // coolstart
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(coolondelay), 53, 1), // coolondelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(cooloffdelay), 54, 1), // cooloffdelay
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(boost), 53, 1), // boost
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(boosttime), 54, 1), // boosttime
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchProgMode), 55, 1), // switchprogmode
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(redthreshold), 56, 1), // redthreshold
REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(solarinfl), 57, 1), // solarinfl
@@ -629,20 +637,6 @@ const std::initializer_list<Modbus::EntityModbusInfo> Modbus::modbus_register_ma
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(wwDiffTemp), 13, 1), // difftemp
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(wwRedTemp), 14, 1), // redtemp
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(wwRequiredTemp), 15, 1), // requiredtemp
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(wwStorageTemp1), 16, 1), // storagetemp1
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(wwColdTemp), 17, 1), // coldtemp
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(wwTemp5), 18, 1), // temp5
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(retTemp), 19, 1), // rettemp
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(wwHotTemp), 20, 1), // hottemp
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(wwDailyTemp), 21, 1), // dailytemp
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(wwCircTc), 22, 1), // circtc
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(wwKeepWarm), 23, 1), // keepwarm
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(wwStatus2), 24, 1), // status2
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(wwPumpMod), 25, 1), // pumpmod
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(wwFlow), 26, 1), // flow
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(valveReturn), 27, 1), // valvereturn
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(deltaTRet), 28, 1), // deltatret
REGISTER_MAPPING(dt::WATER, TAG_TYPE_DHW, FL_(errorDisp), 29, 1), // errordisp
};
} // namespace emsesp
+16 -25
View File
@@ -377,19 +377,23 @@ void Roomctrl::temperature(uint8_t addr, uint8_t dst, uint8_t hc) {
// send telegram 0x047B only for RC100H
void Roomctrl::humidity(uint8_t addr, uint8_t dst, uint8_t hc) {
int16_t dew = Helpers::calc_dew(remotetemp_[hc], remotehum_[hc]);
int8_t dew8 = EMS_VALUE_INT8_NOTSET;
if (dew != EMS_VALUE_INT16_NOTSET) {
dew8 = static_cast<int8_t>((dew >= 0 ? dew + 5 : dew - 5) / 10);
}
uint8_t data[11];
data[0] = addr | EMSbus::ems_mask();
data[1] = dst & 0x7F;
uint16_t dew = calc_dew(remotetemp_[hc], remotehum_[hc]);
data[2] = 0xFF;
data[3] = 0;
data[4] = 3;
data[5] = 0x7B + hc;
data[6] = dew == EMS_VALUE_INT16_NOTSET ? EMS_VALUE_INT8_NOTSET : (uint8_t)((dew + 5) / 10);
data[7] = remotehum_[hc];
data[8] = (uint8_t)(dew << 8);
data[9] = (uint8_t)(dew & 0xFF);
data[10] = EMSbus::calculate_crc(data, 10); // append CRC
data[0] = addr | EMSbus::ems_mask();
data[1] = dst & 0x7F;
data[2] = 0xFF;
data[3] = 0;
data[4] = 3;
data[5] = 0x7B + hc;
data[6] = static_cast<uint8_t>(dew8);
data[7] = remotehum_[hc];
data[8] = static_cast<uint8_t>(dew >> 8);
data[9] = static_cast<uint8_t>(dew & 0x00FF);
data[10] = EMSbus::calculate_crc(data, 10); // append CRC
EMSuart::transmit(data, 11);
}
@@ -436,17 +440,4 @@ void Roomctrl::replyF7(uint8_t addr, uint8_t dst, uint8_t offset, uint8_t typehh
EMSuart::transmit(data, 10);
}
int16_t Roomctrl::calc_dew(int16_t temp, uint8_t humi) {
if (humi == EMS_VALUE_UINT8_NOTSET || temp == EMS_VALUE_INT16_NOTSET) {
return EMS_VALUE_INT16_NOTSET;
}
const float k2 = 17.62;
const float k3 = 243.12;
const float t = (float)temp / 10;
const float h = (float)humi / 100;
int16_t dt = (10 * k3 * (((k2 * t) / (k3 + t)) + log(h)) / (((k2 * k3) / (k3 + t)) - log(h)));
return dt;
}
} // namespace emsesp
-1
View File
@@ -50,7 +50,6 @@ class Roomctrl {
static void nack_write();
static void ack_write();
static void replyF7(uint8_t addr, uint8_t dst, uint8_t offset, uint8_t typehh, uint8_t typeh, uint8_t typel, uint8_t hc);
static int16_t calc_dew(int16_t temp, uint8_t hum);
static bool switch_off_[HCS];
static uint32_t send_time_[HCS];
+59 -55
View File
@@ -39,17 +39,8 @@ std::deque<Token> exprToTokens(const std::string & expr) {
i += (*p == '{') ? 1 : (*p == '}') ? -1 : 0;
++p;
}
if (*p) {
++p;
}
// Use string_view to avoid unnecessary string copies
std::string_view s(b, p - b);
auto n = s.find("\"\"");
while (n != std::string_view::npos) {
s.remove_prefix(n + 2);
n = s.find("\"\"");
}
tokens.emplace_back(Token::Type::String, std::string(s), -3);
const auto s = std::string(b, p);
tokens.emplace_back(Token::Type::String, s, -3);
if (*p == '\0') {
--p;
}
@@ -333,7 +324,10 @@ std::deque<Token> shuntingYard(const std::deque<Token> & tokens) {
// check if string is a number
bool isnum(const std::string & s) {
if (!s.empty() && (s.find_first_not_of("0123456789.") == std::string::npos || (s[0] == '-' && s.find_first_not_of("0123456789.", 1) == std::string::npos))) {
if (s.empty() || s.find_first_of("0123456789") == std::string::npos) {
return false;
}
if (s.find_first_not_of("0123456789.") == std::string::npos || (s[0] == '-' && s.find_first_not_of("0123456789.", 1) == std::string::npos)) {
return true;
}
return false;
@@ -636,6 +630,10 @@ std::string calculate(const std::string & expr) {
stack.push_back(lhs + rhs);
break;
}
if (!isnum(rhs) || !isnum(lhs)) {
stack.push_back(lhs + token.str + rhs);
break;
}
auto lhd = std::stod(lhs);
auto rhd = std::stod(rhs);
switch (token.str[0]) {
@@ -700,8 +698,7 @@ std::string compute(const std::string & expr) {
std::string cmd = expr_new.substr(f, e - f).c_str();
JsonDocument doc;
if (DeserializationError::Ok == deserializeJson(doc, cmd)) {
HTTPClient * http = new HTTPClient;
std::string url, header_s, value_s, method_s, key_s, keys_s;
std::string url, header_s, value_s, method_s, key_s, keys_s;
// search keys lower case
for (JsonPair p : doc.as<JsonObject>()) {
if (Helpers::toLower(p.key().c_str()) == "url") {
@@ -720,56 +717,63 @@ std::string compute(const std::string & expr) {
keys_s = p.key().c_str();
}
}
if (http->begin(url.c_str())) {
int httpResult = 0;
for (JsonPair p : doc[header_s].as<JsonObject>()) {
http->addHeader(p.key().c_str(), p.value().as<std::string>().c_str());
}
std::string value = doc[value_s] | "";
std::string method = doc[method_s] | "get";
// if there is data, force a POST
if (value.length() || Helpers::toLower(method) == "post") {
if (value.find_first_of('{') != std::string::npos) {
http->addHeader(asyncsrv::T_Content_Type, asyncsrv::T_application_json, false); // auto-set to JSON
if (url.substr(0, 4) == "http") { // match http and https
HTTPClient * http = new HTTPClient;
#ifndef EMSESP_STANDALONE
http->setConnectTimeout(10000);
http->setTimeout(10000);
#endif
if (http->begin(url.c_str())) {
int httpResult = 0;
for (JsonPair p : doc[header_s].as<JsonObject>()) {
http->addHeader(p.key().c_str(), p.value().as<std::string>().c_str());
}
httpResult = http->POST(value.c_str());
} else {
httpResult = http->GET(); // normal GET
}
std::string value = doc[value_s] | "";
std::string method = doc[method_s] | "get";
if (httpResult > 0) {
std::string result = http->getString().c_str();
std::string key = doc[key_s] | "";
JsonDocument keys_doc; // JsonDocument to hold "keys" after doc is parsed with HTTP body
if (doc[keys_s].is<JsonArray>()) {
keys_doc.set(doc[keys_s].as<JsonArray>());
// if there is data, force a POST
if (value.length() || Helpers::toLower(method) == "post") {
if (value.find_first_of('{') != std::string::npos) {
http->addHeader(asyncsrv::T_Content_Type, asyncsrv::T_application_json, false); // auto-set to JSON
}
httpResult = http->POST(value.c_str());
} else {
httpResult = http->GET(); // normal GET
}
JsonArray keys = keys_doc.as<JsonArray>();
if (key.length() || !keys.isNull()) {
doc.clear();
if (DeserializationError::Ok == deserializeJson(doc, result)) {
if (key.length()) {
result = doc[key.c_str()].as<std::string>();
} else {
JsonVariant json = doc.as<JsonVariant>();
for (JsonVariant keys_key : keys) {
if (keys_key.is<std::string>() && json.is<JsonObject>()) {
json = json[keys_key.as<std::string>()].as<JsonVariant>();
} else if (keys_key.is<int>() && json.is<JsonArray>()) {
json = json[keys_key.as<int>()].as<JsonVariant>();
} else {
break; // type mismatch
if (httpResult > 0) {
std::string result = http->getString().c_str();
std::string key = doc[key_s] | "";
JsonDocument keys_doc; // JsonDocument to hold "keys" after doc is parsed with HTTP body
if (doc[keys_s].is<JsonArray>()) {
keys_doc.set(doc[keys_s].as<JsonArray>());
}
JsonArray keys = keys_doc.as<JsonArray>();
if (key.length() || !keys.isNull()) {
doc.clear();
if (DeserializationError::Ok == deserializeJson(doc, result)) {
if (key.length()) {
result = doc[key.c_str()].as<std::string>();
} else {
JsonVariant json = doc.as<JsonVariant>();
for (JsonVariant keys_key : keys) {
if (keys_key.is<std::string>() && json.is<JsonObject>()) {
json = json[keys_key.as<std::string>()].as<JsonVariant>();
} else if (keys_key.is<int>() && json.is<JsonArray>()) {
json = json[keys_key.as<int>()].as<JsonVariant>();
} else {
break; // type mismatch
}
}
result = json.as<std::string>();
}
result = json.as<std::string>();
}
}
expr_new.replace(f, e - f, result.c_str());
}
expr_new.replace(f, e - f, result.c_str());
http->end();
}
http->end();
delete http;
}
}
@@ -821,4 +825,4 @@ std::string compute(const std::string & expr) {
return calculate(expr_new);
}
} // namespace emsesp
} // namespace emsesp
+9 -19
View File
@@ -30,7 +30,7 @@
#include <HTTPClient.h>
#include <map>
#include "shuntingYard.h" // for compute() used by the message
#include "EMSESP_Version.h"
#if defined(EMSESP_TEST)
@@ -61,7 +61,7 @@ const char * const languages[] = {EMSESP_LOCALE_EN,
EMSESP_LOCALE_TR,
EMSESP_LOCALE_IT,
EMSESP_LOCALE_SK,
EMSESP_LOCALE_CZ};
EMSESP_LOCALE_CS};
#endif
static constexpr uint8_t NUM_LANGUAGES = sizeof(languages) / sizeof(const char *);
@@ -222,22 +222,10 @@ bool System::command_message(const char * value, const int8_t id, JsonObject out
LOG_WARNING("Message is empty");
return false; // must have a string value
}
EMSESP::webSchedulerService.computed_value.clear();
EMSESP::webSchedulerService.raw_value = value;
for (uint16_t wait = 0; wait < 2000 && !EMSESP::webSchedulerService.raw_value.empty(); wait++) {
delay(1);
}
if (EMSESP::webSchedulerService.computed_value.empty()) {
LOG_WARNING("Message result is empty");
return false;
}
LOG_INFO("Message: %s", EMSESP::webSchedulerService.computed_value.c_str()); // send to log
Mqtt::queue_publish(F_(message), EMSESP::webSchedulerService.computed_value); // send to MQTT if enabled
output["api_data"] = EMSESP::webSchedulerService.computed_value; // send to API
std::string computed_value = compute(value);
LOG_INFO("Message: %s", computed_value.c_str()); // send to log
Mqtt::queue_publish(F_(message), computed_value); // send to MQTT if enabled
output["api_data"] = computed_value; // send to API
return true;
}
@@ -1964,7 +1952,9 @@ bool System::get_value_info(JsonObject output, const char * cmd) {
LOG_ERROR("empty system command");
return false;
}
if (!strcmp(cmd, "restart")) { // restart is a command, not an entity
return false;
}
// check for hardcoded "info"/"value"
if (!strcmp(cmd, F_(info)) || !strcmp(cmd, F_(values))) {
return command_info("", 0, output);
+7 -7
View File
@@ -161,9 +161,9 @@ void RxService::add(uint8_t * data, uint8_t length) {
}
if (data[0] != EMSuart::last_tx_src()) { // do not count echos as errors
telegram_error_count_++;
LOG_WARNING("Incomplete Rx: %s", Helpers::data_to_hex(data, length).c_str()); // include CRC
LOG_WARNING("Incomplete Rx: %s (crc: %02X)", Helpers::data_to_hex(data, length).c_str(), crc); // include CRC
} else {
LOG_TRACE("Incomplete Rx: %s", Helpers::data_to_hex(data, length).c_str()); // include CRC
LOG_TRACE("Incomplete Rx: %s (crc: %02X)", Helpers::data_to_hex(data, length).c_str(), crc); // include CRC
}
return;
}
@@ -276,6 +276,7 @@ void TxService::start() {
// sends a 1 byte poll which is our own deviceID
void TxService::send_poll() const {
// LOG_DEBUG("Ack %02X",ems_bus_id() ^ ems_mask());
// if (tx_mode() != EMS_TXMODE_OFF && ems_bus_id() != 0x0D) { // use 0x0D for tests without poll-Ack
if (tx_mode() != EMS_TXMODE_OFF) {
EMSuart::send_poll(ems_bus_id() ^ ems_mask());
}
@@ -572,12 +573,11 @@ bool TxService::send_raw(const char * telegram_data) {
return false;
}
// since the telegram data is a const, make a copy. add 1 to grab the \0 EOS
char telegram[strlen(telegram_data) + 1];
strlcpy(telegram, telegram_data, sizeof(telegram));
// since the telegram data is a const, make a copy
char * telegram = strdup(telegram_data);
uint8_t count = 0;
uint8_t data[2 + strlen(telegram) / 3];
uint8_t data[256]; // max raw telegram length
// get values
char * p = strtok(telegram, " ,"); // delimiter
@@ -585,7 +585,7 @@ bool TxService::send_raw(const char * telegram_data) {
data[count++] = (uint8_t)strtol(p, 0, 16);
p = strtok(nullptr, " ,");
}
free(telegram);
// check valid length
if (count < 4) {
return false;
+95 -16
View File
@@ -45,7 +45,8 @@ Connect::Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, con
register_telegram_type(0x1230 + i, "Roomparams", false, MAKE_PF_CB(process_roomThermostatParam)); // fetch for active circuits
register_telegram_type(0x1244 + i, "Roomdata", false, MAKE_PF_CB(process_roomThermostatData)); // broadcasted
}
register_telegram_type(0xDB65, "Roomschedule", true, MAKE_PF_CB(process_roomSchedule));
register_telegram_type(0x0B65, "Roomschedule", true, MAKE_PF_CB(process_roomSchedule));
register_telegram_type(0xF7, "MenuConfig", false, MAKE_PF_CB(process_roomConfig));
// 0x2040, broadcast 36 bytes:
// data: 0E 60 00 DF 0D AF 0A 46 0A 46 02 9A 1C 53 1C 53 12 AD 12 AD 00 00 13 C2
// data: 1F 37 1F 37 00 00 00 00 18 97 11 27 (offset 24)
@@ -88,11 +89,12 @@ void Connect::process_RCTime(std::shared_ptr<const Telegram> telegram) {
void Connect::register_device_values_room(std::shared_ptr<Connect::RoomCircuit> room) {
auto tag = DeviceValueTAG::TAG_SRC1 + room->room();
register_device_value(tag, &room->temp_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(roomTemp), DeviceValueUOM::DEGREES);
register_device_value(tag, &room->humidity_, DeviceValueType::INT8, FL_(airHumidity), DeviceValueUOM::PERCENT);
register_device_value(tag, &room->humidity_, DeviceValueType::UINT8, FL_(airHumidity), DeviceValueUOM::PERCENT);
register_device_value(tag, &room->dewtemp_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(dewTemperature), DeviceValueUOM::DEGREES);
register_device_value(
tag, &room->seltemp_, DeviceValueType::UINT8, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(selRoomTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_seltemp), 5, 30);
register_device_value(tag, &room->mode_, DeviceValueType::ENUM, FL_(enum_mode2), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode));
// register_device_value(tag, &room->coolmode_, DeviceValueType::BOOL, FL_(coolingOn), DeviceValueUOM::NONE, MAKE_CF_CB(set_coolmode));
register_device_value(tag, &room->name_, DeviceValueType::STRING, FL_(name), DeviceValueUOM::NONE, MAKE_CF_CB(set_name));
register_device_value(tag, &room->childlock_, DeviceValueType::BOOL, FL_(childlock), DeviceValueUOM::NONE, MAKE_CF_CB(set_childlock));
register_device_value(tag, &room->icon_, DeviceValueType::ENUM, FL_(enum_icons), FL_(icon), DeviceValueUOM::NONE, MAKE_CF_CB(set_icon));
@@ -133,16 +135,8 @@ void Connect::process_roomThermostat(std::shared_ptr<const Telegram> telegram) {
if (!Mqtt::ha_enabled() || (Helpers::hasValue(rc->mode_) && Helpers::hasValue(rc->icon_))) {
has_update(telegram, rc->seltemp_, 3);
}
// calculate dew temperature
if (rc->humidity_ >= 0 && rc->humidity_ <= 100) {
const float k2 = 17.62;
const float k3 = 243.12;
const float t = (float)rc->temp_ / 10;
const float h = (float)rc->humidity_ / 100;
int16_t dt = (10 * k3 * (((k2 * t) / (k3 + t)) + log(h)) / (((k2 * k3) / (k3 + t)) - log(h)));
has_update(rc->dewtemp_, dt);
}
has_update(rc->dewtemp_, Helpers::calc_dew(rc->temp_, rc->humidity_));
}
// gateway(0x48) W gateway(0x50), ?(0x0B42), data: 01 // icon in offset 0
@@ -168,11 +162,33 @@ void Connect::process_roomThermostatSettings(std::shared_ptr<const Telegram> tel
if (rc == nullptr) {
return;
}
has_enumupdate(telegram, rc->mode_, 0, {3, 1, 0}); // modes off, manual auto
// has_enumupdate(telegram, rc->mode_, 0, {3, 1, 0}); // modes off, manual auto
// has_update(telegram, rc->mode_, 0); // modes: auto, heat, cool, off
// has_update(telegram, rc->tempautotemp_, 1); // FF means off
// has_update(telegram, rc->manualtemp_, 3);
// has_update(telegram, rc->coolmode_, 4); // 01-cooling, 00-heating
// has_update(telegram, rc->coolautotemp_, 5);
// has_update(telegram, rc->cooltemp_, 6);
has_update(telegram, rc->childlock_, 7);
uint8_t mh = 0xFF;
uint8_t mc = 0xFF;
telegram->read_value(mh, 0);
telegram->read_value(mc, 4);
if (mc == 3) {
rc->coolmode_ = 1;
rc->mode_ = 0;
} else if (mh == 3) {
rc->coolmode_ = 0;
rc->mode_ = 0;
} else if (mc == 1) {
rc->coolmode_ = 1;
rc->mode_ = 1;
} else if (mh == 1) {
rc->coolmode_ = 0;
rc->mode_ = 1;
} else {
rc->mode_ = 2;
}
}
// unknown telegrams, needs fetch
@@ -203,6 +219,53 @@ void Connect::process_roomSchedule(std::shared_ptr<const Telegram> telegram) {
toggle_fetch(telegram->type_id, false); // fetch only once if all is initialized
}
void Connect::process_roomConfig(std::shared_ptr<const Telegram> telegram) {
if (telegram->offset == 0 && telegram->message_length > 3) {
uint16_t t = 0;
telegram->read_value(t, 1);
if (t >= 0x0AB5 && t <= 0x0AB5 + 15) {
auto rc = room_circuit(t - 0x0AB5);
if (rc == nullptr) {
return;
}
uint8_t bits = telegram->message_data[3];
if (rc->mode_ == 2) {
if (bits & 0x02) {
rc->coolmode_ = 0;
} else if (bits & 0x20) {
rc->coolmode_ = 1;
}
}
/*
switch (bits & 0x6A) {
case 0: // cooling off
rc->mode_ = 0;
rc->coolmode_ = 1;
break;
case 0x40: // manual cooling or heating off
rc->mode_ = 1;
rc->coolmode_ = 1;
break;
case 0x20: // auto cooling
rc->mode_ = 2;
rc->coolmode_ = 1;
break;
case 0x48: // manual heating
case 0x08: // manual heating
rc->mode_ = 1;
rc->coolmode_ = 0;
break;
case 0x42: // auto heating
case 0x02: // auto heating
rc->mode_ = 2;
rc->coolmode_ = 0;
break;
}
*/
}
}
}
// Settings:
bool Connect::set_mode(const char * value, const int8_t id) {
@@ -216,7 +279,7 @@ bool Connect::set_mode(const char * value, const int8_t id) {
return false;
}
}
write_command(0xBB5 + rc->room(), 0, v); // no validate, mode change is broadcasted
write_command(0xBB5 + rc->room(), rc->coolmode_ == 1 ? 4 : 0, v); // no validate, mode change is broadcasted
return true;
}
@@ -226,10 +289,13 @@ bool Connect::set_seltemp(const char * value, const int8_t id) {
return false;
}
float v;
if (Helpers::value2float(value, v)) {
if (Helpers::value2temperature(value, v)) {
// depends on mode, auto (2 for enum_mode2, 0 for enum_mode8) set in offset 1
write_command(0xBB5 + rc->room(), rc->mode_ == 2 ? 1 : 3, v == -1 ? 0xFF : uint8_t(v * 2));
// write_command(0xBB5 + rc->room(), rc->mode_ == 0 ? 1 : 3, v == -1 ? 0xFF : uint8_t(v * 2));
if (rc->coolmode_ == 1) {
write_command(0xBB5 + rc->room(), rc->mode_ == 2 ? 5 : 6, v == -1 ? 0xFF : uint8_t(v * 2));
} else {
write_command(0xBB5 + rc->room(), rc->mode_ == 2 ? 1 : 3, v == -1 ? 0xFF : uint8_t(v * 2));
}
return true;
}
return false;
@@ -257,6 +323,19 @@ bool Connect::set_name(const char * value, const int8_t id) {
return true;
}
bool Connect::set_coolmode(const char * value, const int8_t id) {
auto rc = room_circuit(id - DeviceValueTAG::TAG_SRC1);
if (rc == nullptr) {
return false;
}
bool b;
if (Helpers::value2bool(value, b)) {
write_command(0xBB5 + rc->room(), 4, b ? 1 : 0, 0xBB5 + rc->room());
return true;
}
return false;
}
bool Connect::set_childlock(const char * value, const int8_t id) {
auto rc = room_circuit(id - DeviceValueTAG::TAG_SRC1);
if (rc == nullptr) {
+6 -1
View File
@@ -34,15 +34,18 @@ class Connect : public EMSdevice {
}
~RoomCircuit() = default;
int16_t temp_;
int8_t humidity_;
uint8_t humidity_;
uint8_t seltemp_;
uint8_t mode_;
char name_[51];
int16_t dewtemp_;
uint8_t childlock_;
uint8_t icon_;
uint8_t coolmode_;
// uint8_t tempautotemp_;
// uint8_t manualtemp_;
// uint8_t coolautotemp_;
// uint8_t cooltemp_;
uint8_t room() {
return room_;
@@ -62,9 +65,11 @@ class Connect : public EMSdevice {
void process_roomThermostatParam(std::shared_ptr<const Telegram> telegram);
void process_roomThermostatData(std::shared_ptr<const Telegram> telegram);
void process_roomSchedule(std::shared_ptr<const Telegram> telegram);
void process_roomConfig(std::shared_ptr<const Telegram> telegram);
bool set_mode(const char * value, const int8_t id);
bool set_seltemp(const char * value, const int8_t id);
bool set_name(const char * value, const int8_t id);
bool set_coolmode(const char * value, const int8_t id);
bool set_childlock(const char * value, const int8_t id);
bool set_icon(const char * value, const int8_t id);
+264 -90
View File
@@ -175,7 +175,9 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
register_telegram_type(set_typeids[i], "RC300Set", false, MAKE_PF_CB(process_RC300Set), 29);
register_telegram_type(summer_typeids[i], "RC300Summer", false, MAKE_PF_CB(process_RC300Summer), 14);
register_telegram_type(curve_typeids[i], "RC300Curves", false, MAKE_PF_CB(process_RC300Curve), 9);
register_telegram_type(summer2_typeids[i], "RC300Summer2", false, MAKE_PF_CB(process_RC300Summer2), 8);
if (model != EMSdevice::EMS_DEVICE_FLAG_UI800) {
register_telegram_type(summer2_typeids[i], "RC300Sumr2", false, MAKE_PF_CB(process_RC300Summer2), 8);
}
}
const size_t set2_size = set2_typeids.size();
for (uint8_t i = 0; i < set2_size; i++) {
@@ -207,7 +209,9 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
register_telegram_type(0x16E, "Absent", true, MAKE_PF_CB(process_Absent), 1);
register_telegram_type(0xBF, "ErrorMessage", false, MAKE_PF_CB(process_ErrorMessageBF));
register_telegram_type(0xC0, "RCErrorMessage", false, MAKE_PF_CB(process_RCErrorMessage2));
register_telegram_type(0x470, "RC300Summer2", true, MAKE_PF_CB(process_RC300Summer2), 8);
if (model == EMSdevice::EMS_DEVICE_FLAG_UI800) {
register_telegram_type(0x470, "RC300Summer3", true, MAKE_PF_CB(process_RC300Summer3), 8);
}
EMSESP::send_read_request(0xC0, device_id, 0, 20); // read last errorcode on start (only published on errors)
// JUNKERS/HT3
@@ -543,7 +547,7 @@ uint8_t Thermostat::HeatingCircuit::get_mode() const {
} else {
return HeatingCircuit::Mode::OFF;
}
} else if (model == EMSdevice::EMS_DEVICE_FLAG_BC400 || model == EMSdevice::EMS_DEVICE_FLAG_CR120) {
} else if (model == EMSdevice::EMS_DEVICE_FLAG_BC400 || model == EMSdevice::EMS_DEVICE_FLAG_UI800 || model == EMSdevice::EMS_DEVICE_FLAG_CR120) {
if (mode_new == 0) {
return HeatingCircuit::Mode::OFF;
} else if (mode_new == 1) {
@@ -607,7 +611,7 @@ uint8_t Thermostat::HeatingCircuit::get_mode_type() const {
return HeatingCircuit::Mode::ON;
}
} else if (model == EMSdevice::EMS_DEVICE_FLAG_RC300 || model == EMSdevice::EMS_DEVICE_FLAG_R3000 || model == EMSdevice::EMS_DEVICE_FLAG_BC400
|| model == EMSdevice::EMS_DEVICE_FLAG_HMC310) {
|| model == EMSdevice::EMS_DEVICE_FLAG_UI800 || model == EMSdevice::EMS_DEVICE_FLAG_HMC310) {
if (modetype == 0) {
return HeatingCircuit::Mode::ECO;
} else if (modetype == 1) {
@@ -806,16 +810,16 @@ void Thermostat::process_RemoteTemp(std::shared_ptr<const Telegram> telegram) {
// e.g. "38 10 FF 00 03 7B 08 24 00 4B"
void Thermostat::process_RemoteHumidity(std::shared_ptr<const Telegram> telegram) {
// has_update(telegram, dewtemperature_, 0); // this is int8
has_update(telegram, humidity_, 1);
has_update(telegram, dewtemperature_, 2); // this is int16
// some thermostats use short telegram with int8 dewpoint, https://github.com/emsesp/EMS-ESP32/issues/1491
if (telegram->offset == 0 && telegram->message_length < 4) {
int8_t dew = dewtemperature_ / 10;
telegram->read_value(dew, 0);
if (dew != EMS_VALUE_INT8_NOTSET && dewtemperature_ != dew * 10) {
dewtemperature_ = dew * 10;
has_update(dewtemperature_);
}
// but it's not a dewpoint in offset 0, removed, see https://github.com/emsesp/EMS-ESP32/issues/3135
has_update(telegram, humidity_, 1);
// has_update(telegram, dewtemperature_, 2); // this is int16
int16_t dew = EMS_VALUE_INT16_NOTSET;
if (telegram->read_value(dew, 2)) {
has_update(dewtemperature_, dew);
} else if (telegram->offset == 0 && telegram->message_length < 4) {
dew = Helpers::calc_dew(tempsensor1_, humidity_);
has_update(dewtemperature_, dew);
}
}
@@ -1264,18 +1268,25 @@ void Thermostat::process_RC300Summer(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, hc->comfortPointTemp, 12);
}
// type 0x470, only BC400/UI800
// (0x470), data: 01 0E 01 01 02 17 04 48
void Thermostat::process_RC300Summer3(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, hpoperatingmode, 0);
has_update(telegram, summertemp, 1);
has_update(telegram, heatondelay, 2);
has_update(telegram, heatoffdelay, 3);
has_update(telegram, instantstart, 4);
has_update(telegram, coolstart, 5);
has_update(telegram, coolondelay, 6);
has_update(telegram, cooloffdelay, 7);
}
// types 0x471 ff summer2_typeids
// (0x473), data: 00 11 04 01 01 1C 08 04
void Thermostat::process_RC300Summer2(std::shared_ptr<const Telegram> telegram) {
auto hc = heating_circuit(telegram);
if (hc == nullptr) {
// telegram 0x470 see https://github.com/emsesp/EMS-ESP32/issues/2686
if (telegram->type_id == 0x470 && telegram->message_length > 2) {
hc = heating_circuit(1);
summer2_typeids[0] = 0x470;
} else {
return;
}
return;
}
if (hc->statusbyte & 1) {
has_update(telegram, hc->summersetmode, 0);
@@ -1334,7 +1345,7 @@ void Thermostat::process_RC300WWmode(std::shared_ptr<const Telegram> telegram) {
// circulation pump see: https://github.com/Th3M3/buderus_ems-wiki/blob/master/Einstellungen%20der%20Bedieneinheit%20RC310.md
has_update(telegram, dhw->wwCircPump_, 1); // FF=off, 0=on ?
if (model() == EMSdevice::EMS_DEVICE_FLAG_BC400 || model() == EMSdevice::EMS_DEVICE_FLAG_HMC310) {
if (model() == EMSdevice::EMS_DEVICE_FLAG_BC400 || model() == EMSdevice::EMS_DEVICE_FLAG_UI800 || model() == EMSdevice::EMS_DEVICE_FLAG_HMC310) {
has_enumupdate(telegram, dhw->wwMode_, 2, {0, 5, 1, 2, 4});
} else if (model() == EMSdevice::EMS_DEVICE_FLAG_R3000) {
// https://github.com/emsesp/EMS-ESP32/pull/1722#discussion_r1582823521
@@ -1455,14 +1466,21 @@ void Thermostat::process_HPMode(std::shared_ptr<const Telegram> telegram) {
}
// 0x467 ff HP settings
// thermostat(0x10) -W-> Me(0x0B), ?(0x0467), data: 0A 15 00 01 04 (from #1187)
// thermostat(0x10) W me(0x0B), HPSet(0x0467), data: 14 13 02 01 02 (from #3144)
void Thermostat::process_HPSet(std::shared_ptr<const Telegram> telegram) {
auto hc = heating_circuit(telegram);
if (hc == nullptr) {
return;
}
has_update(telegram, hc->dewoffset, 4); // 7-35°C
has_update(telegram, hc->roomtempdiff, 3); // 1-10K
has_update(telegram, hc->hpminflowtemp, 0); // 2-10K
if (hc->control == 3 || hc->control == 6) { // control with humidity
has_update(telegram, hc->hpminflowtemp, 0); // 7-35°C
} else {
has_update(telegram, hc->hpminflowtemp, 1); // 7-35°C
}
// has_update(telegram, hc->roomtempoffset, 2); // 1-10K // not implemented, mentioned in #3144
has_update(telegram, hc->roomtempdiff, 3); // 1-10K
has_update(telegram, hc->dewoffset, 4); // 2-10K
}
// type 0x41 - data from the RC30 thermostat(0x10) - 14 bytes long
@@ -1720,9 +1738,18 @@ void Thermostat::process_RCTime(std::shared_ptr<const Telegram> telegram) {
}
// check clock
time_t now = time(nullptr);
tm * tm_ = localtime(&now);
bool tset_ = tm_->tm_year > 110; // year 2010 and up, time is valid
time_t now = time(nullptr);
bool sync = false;
// change to thermostat timezone if different
EMSESP::esp32React.getNTPSettingsService()->read([&](const NTPSettings & settings) {
sync = settings.thermostat_sync != 0;
if (settings.thermostat_sync == 2) {
setenv("TZ", settings.tzFormatT.c_str(), 1);
tzset();
}
});
tm * tm_ = localtime(&now);
bool tset_ = tm_->tm_year > 110; // year 2010 and up, time is valid
tm_->tm_year = (telegram->message_data[0] & 0x7F) + 100; // IVT
tm_->tm_mon = telegram->message_data[1] - 1;
tm_->tm_mday = telegram->message_data[3];
@@ -1738,20 +1765,27 @@ void Thermostat::process_RCTime(std::shared_ptr<const Telegram> telegram) {
strftime(newdatetime, sizeof(dateTime_), "%d.%m.%Y %H:%M", tm_);
has_update(dateTime_, newdatetime, sizeof(dateTime_));
bool ivtclock = (telegram->message_data[0] & 0x80) == 0x80; // dont sync ivt-clock, #439
bool junkersclock = model() == EMSdevice::EMS_DEVICE_FLAG_JUNKERS;
time_t ttime = mktime(tm_); // thermostat time
bool ivtclock = (telegram->message_data[0] & 0x80) == 0x80; // dont sync ivt-clock, #439
tm_->tm_isdst = -1; // determine dst
time_t ttime = mktime(tm_); // make thermostat time
// change back emsesp timezone
EMSESP::esp32React.getNTPSettingsService()->read([&](const NTPSettings & settings) {
if (settings.thermostat_sync == 2) {
setenv("TZ", settings.tzFormat.c_str(), 1);
tzset();
}
});
// correct thermostat clock if we have valid ntp time, and could write the command
if (!ivtclock && !junkersclock && tset_ && EMSESP::system_.ntp_connected() && !EMSESP::system_.readonly_mode() && has_command(&dateTime_)) {
double difference = difftime(now, ttime);
if (sync && !ivtclock && tset_ && EMSESP::system_.ntp_connected() && !EMSESP::system_.readonly_mode() && has_command(&dateTime_)) {
int difference = difftime(now, ttime);
if (difference > 15 || difference < -15) {
if (setTimeRetry < 3) {
if (!use_dst) {
set_datetime("ntp", 0); // set from NTP without dst
LOG_INFO("thermostat time correction from ntp, ignoring dst");
LOG_INFO("thermostat time correction %d seconds from ntp, ignoring dst", difference);
} else {
set_datetime("ntp", -1); // set from NTP
LOG_INFO("thermostat time correction from ntp");
LOG_INFO("thermostat time correction %d seconds from ntp", difference);
}
setTimeRetry++;
}
@@ -1761,10 +1795,6 @@ void Thermostat::process_RCTime(std::shared_ptr<const Telegram> telegram) {
}
#ifndef EMSESP_STANDALONE
if (!tset_ && tm_->tm_year > 110) { // emsesp clock not set, but thermostat clock
if (ivtclock) {
tm_->tm_isdst = -1; // determine dst
ttime = mktime(tm_); // thermostat time
}
struct timeval newnow = {.tv_sec = ttime, .tv_usec = 0};
#if CONFIG_IDF_TARGET_ESP32C3
// unknown how to set time on C3
@@ -1915,7 +1945,11 @@ bool Thermostat::set_hpminflowtemp(const char * value, const int8_t id) {
}
int v;
if (Helpers::value2temperature(value, v)) {
write_command(hp_typeids[hc->hc()], 0, v, hp_typeids[hc->hc()]);
if (hc->control == 3 || hc->control == 6) { // remotes with humidity
write_command(hp_typeids[hc->hc()], 0, v, hp_typeids[hc->hc()]);
} else {
write_command(hp_typeids[hc->hc()], 1, v, hp_typeids[hc->hc()]);
}
return true;
}
return false;
@@ -2355,7 +2389,7 @@ bool Thermostat::set_control(const char * value, const int8_t id) {
}
// BC400
// 1-RC100, 2-RC100H, 3-RC200
} else if (model() == EMSdevice::EMS_DEVICE_FLAG_BC400) {
} else if (model() == EMSdevice::EMS_DEVICE_FLAG_BC400 || model() == EMSdevice::EMS_DEVICE_FLAG_UI800) {
if (Helpers::value2enum(value, ctrl, FL_(enum_control2))) {
write_command(hpmode_typeids[hc->hc()], 3, ctrl);
hc->control = ctrl; // set in advance, dont wait for verify
@@ -2435,7 +2469,7 @@ bool Thermostat::set_wwmode(const char * value, const int8_t id) {
return false;
}
write_command(0xB0, 2, set, 0xB0);
} else if (model() == EMSdevice::EMS_DEVICE_FLAG_BC400 || model() == EMSdevice::EMS_DEVICE_FLAG_HMC310) {
} else if (model() == EMSdevice::EMS_DEVICE_FLAG_BC400 || model() == EMSdevice::EMS_DEVICE_FLAG_UI800 || model() == EMSdevice::EMS_DEVICE_FLAG_HMC310) {
if (!Helpers::value2enum(value, set, FL_(enum_wwMode4), {0, 5, 1, 2, 4})) { // off, eco+, eco, comfort, auto
return false;
}
@@ -2590,30 +2624,36 @@ bool Thermostat::set_cooling(const char * value, const int8_t id) {
// set cooling delays
bool Thermostat::set_coolondelay(const char * value, const int8_t id) {
float f;
if (!Helpers::value2float(value, f)) {
return false;
}
if (model() == EMSdevice::EMS_DEVICE_FLAG_UI800) {
write_command(0x470, 6, (uint8_t)(f * 4), 0x470);
return true;
}
auto hc = heating_circuit(id);
if (hc == nullptr) {
return false;
}
int v;
if (!Helpers::value2number(value, v)) {
return false;
}
write_command(summer2_typeids[hc->hc()], 6, v, summer2_typeids[hc->hc()]);
write_command(summer2_typeids[hc->hc()], 6, (uint8_t)f, summer2_typeids[hc->hc()]);
return true;
}
bool Thermostat::set_cooloffdelay(const char * value, const int8_t id) {
float f;
if (!Helpers::value2float(value, f)) {
return false;
}
if (model() == EMSdevice::EMS_DEVICE_FLAG_UI800) {
write_command(0x470, 7, (uint8_t)(f * 4), 0x470);
return true;
}
auto hc = heating_circuit(id);
if (hc == nullptr) {
return false;
}
int v;
if (!Helpers::value2number(value, v)) {
return false;
}
write_command(summer2_typeids[hc->hc()], 7, v, summer2_typeids[hc->hc()]);
write_command(summer2_typeids[hc->hc()], 7, (uint8_t)f, summer2_typeids[hc->hc()]);
return true;
}
@@ -3038,6 +3078,15 @@ bool Thermostat::set_datetime(const char * value, const int8_t id) {
if (dt == "ntp") {
time_t now = time(nullptr);
tm * tm_ = localtime(&now);
EMSESP::esp32React.getNTPSettingsService()->read([&](const NTPSettings & settings) {
if (settings.thermostat_sync == 2) {
setenv("TZ", settings.tzFormatT.c_str(), 1);
tzset();
tm_ = localtime(&now);
setenv("TZ", settings.tzFormat.c_str(), 1);
tzset();
}
});
if (tm_->tm_year < 110) { // no valid time
return false;
}
@@ -3053,11 +3102,7 @@ bool Thermostat::set_datetime(const char * value, const int8_t id) {
data[5] = tm_->tm_sec;
data[6] = (tm_->tm_wday + 6) % 7; // Bosch counts from Mo, time from Su
data[7] = (id == 0) ? 2 : tm_->tm_isdst + 2; // set DST and flag for ext. clock
if (model() == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) {
data[6]++; // Junkers use 1-7;
data[7] = 0;
}
} else if (dt.length() == 23) {
} else if (dt.length() == 23 || dt.length() == 21) {
data[0] = (dt[7] - '0') * 100 + (dt[8] - '0') * 10 + (dt[9] - '0'); // year
data[1] = (dt[3] - '0') * 10 + (dt[4] - '0'); // month
data[2] = (dt[11] - '0') * 10 + (dt[12] - '0'); // hour
@@ -3065,10 +3110,35 @@ bool Thermostat::set_datetime(const char * value, const int8_t id) {
data[4] = (dt[14] - '0') * 10 + (dt[15] - '0'); // min
data[5] = (dt[17] - '0') * 10 + (dt[18] - '0'); // sec
data[6] = (dt[20] - '0'); // day of week, Mo:0
data[7] = (dt[22] - '0') + 2; // DST and flag
if (model() == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) {
data[7] = 0;
}
data[7] = dt.length() == 21 ? 2 : (dt[22] - '0') + 2; // DST and flag
} else if (dt.length() == 19 || dt.length() == 16) {
time_t now = time(nullptr);
tm * tm_ = localtime(&now);
data[0] = (dt[7] - '0') * 100 + (dt[8] - '0') * 10 + (dt[9] - '0'); // year
tm_->tm_year = 100 + data[0];
data[1] = (dt[3] - '0') * 10 + (dt[4] - '0'); // month
tm_->tm_mon = data[1] - 1;
tm_->tm_hour = data[2] = (dt[11] - '0') * 10 + (dt[12] - '0'); // hour
tm_->tm_mday = data[3] = (dt[0] - '0') * 10 + (dt[1] - '0'); // day
tm_->tm_min = data[4] = (dt[14] - '0') * 10 + (dt[15] - '0'); // min
tm_->tm_sec = data[5] = dt.length() == 16 ? 0 : (dt[17] - '0') * 10 + (dt[18] - '0'); // sec
tm_->tm_isdst = -1;
// use thermostat time zone to determine day of week and daylight saving
EMSESP::esp32React.getNTPSettingsService()->read([&](const NTPSettings & settings) {
if (settings.thermostat_sync == 2) {
setenv("TZ", settings.tzFormatT.c_str(), 1);
tzset();
auto t = mktime(tm_);
tm_ = localtime(&t);
setenv("TZ", settings.tzFormat.c_str(), 1);
tzset();
} else {
auto t = mktime(tm_);
tm_ = localtime(&t);
}
});
data[6] = (tm_->tm_wday + 6) % 7; // Bosch counts from Mo, time from Su
data[7] = tm_->tm_isdst + 2; // set DST and flag for ext. clock
} else {
LOG_WARNING("Set date: invalid data, wrong length");
return false;
@@ -3078,6 +3148,11 @@ bool Thermostat::set_datetime(const char * value, const int8_t id) {
return false;
}
if (model() == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) {
data[6]++; // Junkers use 1-7 for day of the week
data[7] = 0; // no dst setting
}
// LOG_INFO("Setting date and time: %02d.%02d.2%03d-%02d:%02d:%02d-%d-%d", data[3], data[1], data[0], data[2], data[4], data[5], data[6], data[7]);
write_command(EMS_TYPE_time, 0, data, 8, EMS_TYPE_time);
@@ -3142,6 +3217,7 @@ bool Thermostat::set_mode(const char * value, const int8_t id) {
mode_list = FL_(enum_mode3);
break;
case EMSdevice::EMS_DEVICE_FLAG_BC400:
case EMSdevice::EMS_DEVICE_FLAG_UI800:
case EMSdevice::EMS_DEVICE_FLAG_CR120:
mode_list = FL_(enum_mode2);
break;
@@ -3279,6 +3355,7 @@ bool Thermostat::set_mode_n(const uint8_t mode, const int8_t id) {
offset = EMS_OFFSET_RC35Set_mode;
break;
case EMSdevice::EMS_DEVICE_FLAG_BC400:
case EMSdevice::EMS_DEVICE_FLAG_UI800:
case EMSdevice::EMS_DEVICE_FLAG_CR120:
offset = EMS_OFFSET_RCPLUSSet_mode_new;
break;
@@ -3318,7 +3395,7 @@ bool Thermostat::set_mode_n(const uint8_t mode, const int8_t id) {
// set hc->mode temporary until validate is received
if (model_ == EMSdevice::EMS_DEVICE_FLAG_RC10) {
hc->mode = set_mode_value >> 1;
} else if (model_ == EMSdevice::EMS_DEVICE_FLAG_BC400 || model_ == EMSdevice::EMS_DEVICE_FLAG_CR120) {
} else if (model_ == EMSdevice::EMS_DEVICE_FLAG_BC400 || model_ == EMSdevice::EMS_DEVICE_FLAG_UI800 || model_ == EMSdevice::EMS_DEVICE_FLAG_CR120) {
hc->mode_new = set_mode_value;
} else if (model_ == EMSdevice::EMS_DEVICE_FLAG_RC300 || model_ == EMSdevice::EMS_DEVICE_FLAG_R3000 || model_ == EMSdevice::EMS_DEVICE_FLAG_HMC310
|| model_ == EMSdevice::EMS_DEVICE_FLAG_RC100) {
@@ -3335,13 +3412,19 @@ bool Thermostat::set_mode_n(const uint8_t mode, const int8_t id) {
// sets the thermostat summermode for RC300
bool Thermostat::set_summermode(const char * value, const int8_t id) {
uint8_t set;
if (model() == EMSdevice::EMS_DEVICE_FLAG_UI800) {
if (Helpers::value2enum(value, set, FL_(enum_hpoperatingmode))) {
write_command(0x470, 0, set, 0x470);
return true;
}
return false;
}
auto hc = heating_circuit(id);
if (hc == nullptr) {
return false;
}
uint8_t set;
if (is_received(summer2_typeids[hc->hc()])) {
if ((hc->statusbyte & 1) && Helpers::value2enum(value, set, FL_(enum_summermode))) {
write_command(summer2_typeids[hc->hc()], 0, set, summer2_typeids[hc->hc()]);
@@ -3487,40 +3570,52 @@ bool Thermostat::set_boosttime(const char * value, const int8_t id) {
}
bool Thermostat::set_heatondelay(const char * value, const int8_t id) {
float f;
if (!Helpers::value2float(value, f)) {
return false;
}
if (model() == EMSdevice::EMS_DEVICE_FLAG_UI800) {
write_command(0x470, 2, (uint8_t)(f * 4), 0x470);
return true;
}
auto hc = heating_circuit(id);
if (hc == nullptr) {
return false;
}
int v;
if (!Helpers::value2number(value, v)) {
return false;
}
write_command(summer2_typeids[hc->hc()], 2, (uint8_t)v, summer2_typeids[hc->hc()]);
write_command(summer2_typeids[hc->hc()], 2, (uint8_t)f, summer2_typeids[hc->hc()]);
return true;
}
bool Thermostat::set_heatoffdelay(const char * value, const int8_t id) {
float f;
if (!Helpers::value2float(value, f)) {
return false;
}
if (model() == EMSdevice::EMS_DEVICE_FLAG_UI800) {
write_command(0x470, 3, (uint8_t)(f * 4), 0x470);
return true;
}
auto hc = heating_circuit(id);
if (hc == nullptr) {
return false;
}
int v;
if (!Helpers::value2number(value, v)) {
return false;
}
write_command(summer2_typeids[hc->hc()], 3, (uint8_t)v, summer2_typeids[hc->hc()]);
write_command(summer2_typeids[hc->hc()], 3, (uint8_t)f, summer2_typeids[hc->hc()]);
return true;
}
bool Thermostat::set_instantstart(const char * value, const int8_t id) {
auto hc = heating_circuit(id);
if (hc == nullptr) {
return false;
}
int v;
if (!Helpers::value2number(value, v)) {
return false;
}
if (model() == EMSdevice::EMS_DEVICE_FLAG_UI800) {
write_command(0x470, 4, (uint8_t)v, 0x470);
return true;
}
auto hc = heating_circuit(id);
if (hc == nullptr) {
return false;
}
write_command(summer2_typeids[hc->hc()], 4, (uint8_t)v, summer2_typeids[hc->hc()]);
return true;
}
@@ -4045,6 +4140,10 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
validate_typeid = set_typeids[hc->hc()];
switch (mode) {
case HeatingCircuit::Mode::SUMMER:
if (model == EMSdevice::EMS_DEVICE_FLAG_UI800) {
write_command(0x470, 1, temperature, 0x470);
return true;
}
if (is_received(summer2_typeids[hc->hc()])) {
offset = 0x01;
set_typeid = summer2_typeids[hc->hc()];
@@ -4056,6 +4155,10 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
factor = 1;
break;
case HeatingCircuit::Mode::COOLSTART:
if (model == EMSdevice::EMS_DEVICE_FLAG_UI800) {
write_command(0x470, 5, temperature, 0x470);
return true;
}
offset = 5;
set_typeid = summer2_typeids[hc->hc()];
validate_typeid = set_typeid;
@@ -4144,7 +4247,7 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
if (model == EMSdevice::EMS_DEVICE_FLAG_CR120 && mode_ == HeatingCircuit::Mode::MANUAL) {
offset = 22; // manual offset CR120
} else if (mode_ == HeatingCircuit::Mode::MANUAL) {
offset = 10; // manual offset
offset = hc->hpoperatingstate == 2 ? 17 : 10; // cooling or manual offset
} else {
offset = 8; // auto offset
// special case to reactivate auto temperature, see #737, #746
@@ -4443,6 +4546,7 @@ void Thermostat::register_device_values() {
case EMSdevice::EMS_DEVICE_FLAG_RC300:
case EMSdevice::EMS_DEVICE_FLAG_R3000:
case EMSdevice::EMS_DEVICE_FLAG_BC400:
case EMSdevice::EMS_DEVICE_FLAG_UI800:
case EMSdevice::EMS_DEVICE_FLAG_CR120:
case EMSdevice::EMS_DEVICE_FLAG_HMC310:
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
@@ -4560,6 +4664,70 @@ void Thermostat::register_device_values() {
register_device_value(
DeviceValueTAG::TAG_DEVICE_DATA, &pvLowerCool_, DeviceValueType::INT8, FL_(pvLowerCool), DeviceValueUOM::K, MAKE_CF_CB(set_pvLowerCool), -5, 0);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &absent_, DeviceValueType::BOOL, FL_(absent), DeviceValueUOM::NONE, MAKE_CF_CB(set_absent));
if (model() == EMSdevice::EMS_DEVICE_FLAG_UI800) {
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&hpoperatingmode,
DeviceValueType::ENUM,
FL_(enum_hpoperatingmode),
FL_(hpoperatingmode),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_summermode));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&summertemp,
DeviceValueType::UINT8,
FL_(summertemp),
DeviceValueUOM::DEGREES,
MAKE_CF_CB(set_summertemp),
10,
30);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&instantstart,
DeviceValueType::UINT8,
FL_(instantstart),
DeviceValueUOM::K,
MAKE_CF_CB(set_instantstart),
1,
10);
register_device_value(
DeviceValueTAG::TAG_DEVICE_DATA, &coolstart, DeviceValueType::UINT8, FL_(coolstart), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_coolstart), 20, 35);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&heatondelay,
DeviceValueType::UINT8,
DeviceValueNumOp::DV_NUMOP_DIV4,
FL_(heatondelay),
DeviceValueUOM::HOURS,
MAKE_CF_CB(set_heatondelay),
1,
48);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&heatoffdelay,
DeviceValueType::UINT8,
DeviceValueNumOp::DV_NUMOP_DIV4,
FL_(heatoffdelay),
DeviceValueUOM::HOURS,
MAKE_CF_CB(set_heatoffdelay),
1,
48);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&coolondelay,
DeviceValueType::UINT8,
DeviceValueNumOp::DV_NUMOP_DIV4,
FL_(coolondelay),
DeviceValueUOM::HOURS,
MAKE_CF_CB(set_coolondelay),
1,
48);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&cooloffdelay,
DeviceValueType::UINT8,
DeviceValueNumOp::DV_NUMOP_DIV4,
FL_(cooloffdelay),
DeviceValueUOM::HOURS,
MAKE_CF_CB(set_cooloffdelay),
1,
48);
}
break;
case EMSdevice::EMS_DEVICE_FLAG_RC10:
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
@@ -4902,9 +5070,10 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
case EMSdevice::EMS_DEVICE_FLAG_RC300:
case EMSdevice::EMS_DEVICE_FLAG_R3000:
case EMSdevice::EMS_DEVICE_FLAG_BC400:
case EMSdevice::EMS_DEVICE_FLAG_UI800:
case EMSdevice::EMS_DEVICE_FLAG_CR120:
case EMSdevice::EMS_DEVICE_FLAG_HMC310:
if (model == EMSdevice::EMS_DEVICE_FLAG_BC400 || model == EMSdevice::EMS_DEVICE_FLAG_CR120) {
if (model == EMSdevice::EMS_DEVICE_FLAG_BC400 || model == EMSdevice::EMS_DEVICE_FLAG_UI800 || model == EMSdevice::EMS_DEVICE_FLAG_CR120) {
register_device_value(tag, &hc->mode_new, DeviceValueType::ENUM, FL_(enum_mode2), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode));
} else {
register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode));
@@ -4997,6 +5166,8 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
register_device_value(tag, &hc->hpminflowtemp, DeviceValueType::UINT8, FL_(hpminflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_hpminflowtemp));
if (model == EMSdevice::EMS_DEVICE_FLAG_BC400) {
register_device_value(tag, &hc->control, DeviceValueType::ENUM, FL_(enum_control2), FL_(control), DeviceValueUOM::NONE, MAKE_CF_CB(set_control));
} else if (model == EMSdevice::EMS_DEVICE_FLAG_UI800) {
register_device_value(tag, &hc->control, DeviceValueType::ENUM, FL_(enum_control3), FL_(control), DeviceValueUOM::NONE, MAKE_CF_CB(set_control));
} else {
register_device_value(tag, &hc->control, DeviceValueType::ENUM, FL_(enum_control1), FL_(control), DeviceValueUOM::NONE, MAKE_CF_CB(set_control));
}
@@ -5012,14 +5183,16 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
101);
register_device_value(tag, &hc->remotehum, DeviceValueType::CMD, FL_(remotehum), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_remotehum), -1, 101);
}
register_device_value(tag, &hc->heatondelay, DeviceValueType::UINT8, FL_(heatondelay), DeviceValueUOM::HOURS, MAKE_CF_CB(set_heatondelay), 1, 48);
register_device_value(tag, &hc->heatoffdelay, DeviceValueType::UINT8, FL_(heatoffdelay), DeviceValueUOM::HOURS, MAKE_CF_CB(set_heatoffdelay), 1, 48);
register_device_value(tag, &hc->instantstart, DeviceValueType::UINT8, FL_(instantstart), DeviceValueUOM::K, MAKE_CF_CB(set_instantstart), 1, 10);
if (model != EMSdevice::EMS_DEVICE_FLAG_UI800) {
register_device_value(tag, &hc->heatondelay, DeviceValueType::UINT8, FL_(heatondelay), DeviceValueUOM::HOURS, MAKE_CF_CB(set_heatondelay), 1, 48);
register_device_value(tag, &hc->heatoffdelay, DeviceValueType::UINT8, FL_(heatoffdelay), DeviceValueUOM::HOURS, MAKE_CF_CB(set_heatoffdelay), 1, 48);
register_device_value(tag, &hc->coolondelay, DeviceValueType::UINT8, FL_(coolondelay), DeviceValueUOM::HOURS, MAKE_CF_CB(set_coolondelay), 1, 48);
register_device_value(tag, &hc->cooloffdelay, DeviceValueType::UINT8, FL_(cooloffdelay), DeviceValueUOM::HOURS, MAKE_CF_CB(set_cooloffdelay), 1, 48);
register_device_value(tag, &hc->instantstart, DeviceValueType::UINT8, FL_(instantstart), DeviceValueUOM::K, MAKE_CF_CB(set_instantstart), 1, 10);
register_device_value(tag, &hc->coolstart, DeviceValueType::UINT8, FL_(coolstart), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_coolstart), 20, 35);
}
register_device_value(tag, &hc->boost, DeviceValueType::BOOL, FL_(boost), DeviceValueUOM::NONE, MAKE_CF_CB(set_boost));
register_device_value(tag, &hc->boosttime, DeviceValueType::UINT8, FL_(boosttime), DeviceValueUOM::HOURS, MAKE_CF_CB(set_boosttime));
register_device_value(tag, &hc->coolstart, DeviceValueType::UINT8, FL_(coolstart), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_coolstart), 20, 35);
register_device_value(tag, &hc->coolondelay, DeviceValueType::UINT8, FL_(coolondelay), DeviceValueUOM::HOURS, MAKE_CF_CB(set_coolondelay), 1, 48);
register_device_value(tag, &hc->cooloffdelay, DeviceValueType::UINT8, FL_(cooloffdelay), DeviceValueUOM::HOURS, MAKE_CF_CB(set_cooloffdelay), 1, 48);
register_device_value(tag,
&hc->switchProgMode,
DeviceValueType::ENUM,
@@ -5037,8 +5210,8 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
MAKE_CF_CB(set_redthreshold),
12,
22);
register_device_value(tag, &hc->solarInfl, DeviceValueType::UINT8, FL_(solarinfl), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_solarinfl), -5, -1);
register_device_value(tag, &hc->currSolarInfl, DeviceValueType::UINT8, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(currsolarinfl), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->solarInfl, DeviceValueType::INT8, FL_(solarinfl), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_solarinfl), -5, 0);
register_device_value(tag, &hc->currSolarInfl, DeviceValueType::INT8, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(currsolarinfl), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->heatingpid, DeviceValueType::ENUM, FL_(enum_PID), FL_(heatingPID), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatingpid));
register_device_value(tag, &hc->pumpopt, DeviceValueType::BOOL, FL_(pumpopt), DeviceValueUOM::NONE, MAKE_CF_CB(set_pumpopt));
register_device_value(tag,
@@ -5359,9 +5532,10 @@ void Thermostat::register_device_values_dhw(std::shared_ptr<Thermostat::DhwCircu
case EMSdevice::EMS_DEVICE_FLAG_RC300:
case EMSdevice::EMS_DEVICE_FLAG_R3000:
case EMSdevice::EMS_DEVICE_FLAG_BC400:
case EMSdevice::EMS_DEVICE_FLAG_UI800:
case EMSdevice::EMS_DEVICE_FLAG_CR120:
case EMSdevice::EMS_DEVICE_FLAG_HMC310:
if (model() == EMSdevice::EMS_DEVICE_FLAG_BC400 || model() == EMSdevice::EMS_DEVICE_FLAG_HMC310) {
if (model() == EMSdevice::EMS_DEVICE_FLAG_BC400 || model() == EMSdevice::EMS_DEVICE_FLAG_UI800 || model() == EMSdevice::EMS_DEVICE_FLAG_HMC310) {
register_device_value(tag, &dhw->wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode4), FL_(wwMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwmode));
} else if (model() == EMSdevice::EMS_DEVICE_FLAG_R3000) {
register_device_value(tag, &dhw->wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode5), FL_(wwMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwmode));
+12 -1
View File
@@ -241,7 +241,7 @@ class Thermostat : public EMSdevice {
// check to see if the thermostat is a hybrid of the R300
inline bool isRC300() const {
return (model() == EMSdevice::EMS_DEVICE_FLAG_RC300 || model() == EMSdevice::EMS_DEVICE_FLAG_R3000 || model() == EMSdevice::EMS_DEVICE_FLAG_BC400
|| model() == EMSdevice::EMS_DEVICE_FLAG_CR120 || model() == EMSdevice::EMS_DEVICE_FLAG_HMC310);
|| model() == EMSdevice::EMS_DEVICE_FLAG_CR120 || model() == EMSdevice::EMS_DEVICE_FLAG_HMC310 || model() == EMSdevice::EMS_DEVICE_FLAG_UI800);
}
inline uint8_t id2dhw(const int8_t id) const { // returns telegram offset for TAG(id)
@@ -296,6 +296,16 @@ class Thermostat : public EMSdevice {
uint8_t absent_;
uint8_t hasSolar_;
// BC400/UI800 telegram 0x470
uint8_t hpoperatingmode;
uint8_t summertemp;
uint8_t heatondelay;
uint8_t heatoffdelay;
uint8_t instantstart;
uint8_t coolstart;
uint8_t coolondelay;
uint8_t cooloffdelay;
// HybridHP
uint8_t hybridStrategy_; // co2 = 1, cost = 2, temperature = 3, mix = 4
int8_t switchOverTemp_; // degrees
@@ -451,6 +461,7 @@ class Thermostat : public EMSdevice {
void process_RC300Set2(std::shared_ptr<const Telegram> telegram);
void process_RC300Summer(std::shared_ptr<const Telegram> telegram);
void process_RC300Summer2(std::shared_ptr<const Telegram> telegram);
void process_RC300Summer3(std::shared_ptr<const Telegram> telegram);
void process_RC300WWmode(std::shared_ptr<const Telegram> telegram);
void process_RC300WWmode2(std::shared_ptr<const Telegram> telegram);
void process_RC300WWtemp(std::shared_ptr<const Telegram> telegram);
+40 -39
View File
@@ -28,9 +28,41 @@ Water::Water(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
dhw_ = device_id - EMSdevice::EMS_DEVICE_ID_DHW1;
int8_t tag = DeviceValueTAG::TAG_DHW1 + dhw_;
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) { // device_id 0x2A, DHW3
// telegram handlers
if (flags == EMSdevice::EMS_DEVICE_FLAG_IPM) {
dhw_ = 0;
tag = DeviceValueTAG::TAG_DHW1;
register_telegram_type(0x34, "UBAMonitorWW", false, MAKE_PF_CB(process_IPMMonitorWW));
register_telegram_type(0x1E, "HydrTemp", false, MAKE_PF_CB(process_IPMHydrTemp));
register_telegram_type(0x33, "UBAParameterWW", true, MAKE_PF_CB(process_IPMParameterWW), 12);
// register_telegram_type(0x10D, "wwNTCStatus", false, MAKE_PF_CB(process_wwNTCStatus));
// device values...
register_device_value(tag, &wwSelTemp_, DeviceValueType::UINT8, FL_(wwSelTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwSelTemp));
register_device_value(tag, &wwTemp_, DeviceValueType::UINT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(wwTemp), DeviceValueUOM::DEGREES);
register_device_value(tag, &wwTemp2_, DeviceValueType::UINT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(wwCurTemp2), DeviceValueUOM::DEGREES);
register_device_value(tag, &HydrTemp_, DeviceValueType::UINT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hydrTemp), DeviceValueUOM::DEGREES);
register_device_value(tag, &wwPump_, DeviceValueType::BOOL, FL_(wwPump), DeviceValueUOM::NONE);
register_device_value(tag, &wwFlowTempOffset_, DeviceValueType::UINT8, FL_(wwFlowTempOffset), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwFlowTempOffset));
register_device_value(tag, &wwHystOn_, DeviceValueType::INT8, FL_(wwHystOn), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwHystOn));
register_device_value(tag, &wwHystOff_, DeviceValueType::INT8, FL_(wwHystOff), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwHystOff));
register_device_value(tag, &wwDisinfectionTemp_, DeviceValueType::UINT8, FL_(wwDisinfectionTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwDisinfectionTemp));
register_device_value(tag, &wwCirc_, DeviceValueType::BOOL, FL_(wwCirc), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwCirc));
register_device_value(tag, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode), FL_(wwCircMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwCircMode));
} else if (tag == DeviceValueTAG::TAG_DHW1 || tag == DeviceValueTAG::TAG_DHW2) { // MM100 or SM100
register_telegram_type(0x331 + dhw_, "MMPLUSStatusMessage_WWC", false, MAKE_PF_CB(process_MMPLUSStatusMessage_WWC));
register_telegram_type(0x313 + dhw_, "MMPLUSConfigMessage_WWC", true, MAKE_PF_CB(process_MMPLUSConfigMessage_WWC), 11);
// register_telegram_type(0x33B + type_offset, "MMPLUSSetMessage_WWC", true, MAKE_PF_CB(process_MMPLUSSetMessage_WWC));
// device values...
register_device_value(tag, &wwTemp_, DeviceValueType::UINT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(wwTemp), DeviceValueUOM::DEGREES);
register_device_value(tag, &wwStatus_, DeviceValueType::INT8, FL_(wwTempStatus), DeviceValueUOM::NONE);
register_device_value(tag, &wwPump_, DeviceValueType::BOOL, FL_(wwPump), DeviceValueUOM::NONE);
register_device_value(tag, &wwMaxTemp_, DeviceValueType::UINT8, FL_(wwMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwMaxTemp));
register_device_value(tag, &wwDiffTemp_, DeviceValueType::INT8, FL_(wwDiffTemp), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwDiffTemp));
register_device_value(tag, &wwDisinfectionTemp_, DeviceValueType::UINT8, FL_(wwDisinfectionTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwDisinfectionTemp));
register_device_value(tag, &wwRedTemp_, DeviceValueType::UINT8, FL_(wwRedTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwRedTemp));
register_device_value(tag, &wwRequiredTemp_, DeviceValueType::UINT8, FL_(wwRequiredTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwRequiredTemp));
register_device_value(tag, &wwCirc_, DeviceValueType::BOOL, FL_(wwCirc), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwCirc));
register_device_value(tag, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode), FL_(wwCircMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwCircMode));
} else { // device_id 0x2A, DHW3, SM100
register_telegram_type(0x07D6 + dhw_ - 2, "SM100wwTemperature", false, MAKE_PF_CB(process_SM100wwTemperature));
register_telegram_type(0x07E0 + dhw_ - 2, "SM100wwStatus2", true, MAKE_PF_CB(process_SM100wwStatus2), 10);
register_telegram_type(0x07A6, "SM100wwParam", true, MAKE_PF_CB(process_SM100wwParam), 20); // same telegram for all circuits
@@ -67,41 +99,6 @@ Water::Water(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
register_device_value(tag, &wwRetValve_, DeviceValueType::UINT8, FL_(valveReturn), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_wwRetValve));
register_device_value(tag, &wwDeltaTRet_, DeviceValueType::UINT8, FL_(deltaTRet), DeviceValueUOM::K, MAKE_CF_CB(set_wwDeltaTRet));
register_device_value(tag, &errorDisp_, DeviceValueType::ENUM, FL_(enum_errorDisp), FL_(errorDisp), DeviceValueUOM::NONE, MAKE_CF_CB(set_errorDisp));
} else if (flags == EMSdevice::EMS_DEVICE_FLAG_MMPLUS) { // dhw1 and dhw 2
register_telegram_type(0x331 + dhw_, "MMPLUSStatusMessage_WWC", false, MAKE_PF_CB(process_MMPLUSStatusMessage_WWC));
register_telegram_type(0x313 + dhw_, "MMPLUSConfigMessage_WWC", true, MAKE_PF_CB(process_MMPLUSConfigMessage_WWC), 11);
// register_telegram_type(0x33B + type_offset, "MMPLUSSetMessage_WWC", true, MAKE_PF_CB(process_MMPLUSSetMessage_WWC));
// device values...
register_device_value(tag, &wwTemp_, DeviceValueType::UINT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(wwTemp), DeviceValueUOM::DEGREES);
register_device_value(tag, &wwStatus_, DeviceValueType::INT8, FL_(wwTempStatus), DeviceValueUOM::NONE);
register_device_value(tag, &wwPump_, DeviceValueType::BOOL, FL_(wwPump), DeviceValueUOM::NONE);
register_device_value(tag, &wwMaxTemp_, DeviceValueType::UINT8, FL_(wwMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwMaxTemp));
register_device_value(tag, &wwDiffTemp_, DeviceValueType::INT8, FL_(wwDiffTemp), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwDiffTemp));
register_device_value(tag, &wwDisinfectionTemp_, DeviceValueType::UINT8, FL_(wwDisinfectionTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwDisinfectionTemp));
register_device_value(tag, &wwRedTemp_, DeviceValueType::UINT8, FL_(wwRedTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwRedTemp));
register_device_value(tag, &wwRequiredTemp_, DeviceValueType::UINT8, FL_(wwRequiredTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwRequiredTemp));
register_device_value(tag, &wwCirc_, DeviceValueType::BOOL, FL_(wwCirc), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwCirc));
register_device_value(tag, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode), FL_(wwCircMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwCircMode));
} else if (flags == EMSdevice::EMS_DEVICE_FLAG_IPM) {
dhw_ = 0;
tag = DeviceValueTAG::TAG_DHW1;
register_telegram_type(0x34, "UBAMonitorWW", false, MAKE_PF_CB(process_IPMMonitorWW));
register_telegram_type(0x1E, "HydrTemp", false, MAKE_PF_CB(process_IPMHydrTemp));
register_telegram_type(0x33, "UBAParameterWW", true, MAKE_PF_CB(process_IPMParameterWW), 12);
// register_telegram_type(0x10D, "wwNTCStatus", false, MAKE_PF_CB(process_wwNTCStatus));
// device values...
register_device_value(tag, &wwSelTemp_, DeviceValueType::UINT8, FL_(wwSelTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwSelTemp));
register_device_value(tag, &wwTemp_, DeviceValueType::UINT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(wwTemp), DeviceValueUOM::DEGREES);
register_device_value(tag, &wwTemp2_, DeviceValueType::UINT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(wwCurTemp2), DeviceValueUOM::DEGREES);
register_device_value(tag, &HydrTemp_, DeviceValueType::UINT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hydrTemp), DeviceValueUOM::DEGREES);
register_device_value(tag, &wwPump_, DeviceValueType::BOOL, FL_(wwPump), DeviceValueUOM::NONE);
register_device_value(tag, &wwFlowTempOffset_, DeviceValueType::UINT8, FL_(wwFlowTempOffset), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwFlowTempOffset));
register_device_value(tag, &wwHystOn_, DeviceValueType::INT8, FL_(wwHystOn), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwHystOn));
register_device_value(tag, &wwHystOff_, DeviceValueType::INT8, FL_(wwHystOff), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwHystOff));
register_device_value(tag, &wwDisinfectionTemp_, DeviceValueType::UINT8, FL_(wwDisinfectionTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwDisinfectionTemp));
register_device_value(tag, &wwCirc_, DeviceValueType::BOOL, FL_(wwCirc), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwCirc));
register_device_value(tag, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode), FL_(wwCircMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwCircMode));
}
}
@@ -361,7 +358,11 @@ bool Water::set_wwCircTc(const char * value, const int8_t id) {
if (!Helpers::value2bool(value, b)) {
return false;
}
write_command(0x33B + dhw_, 4, b ? 0x01 : 0x00, 0x33B + dhw_);
if (flags() == EMSdevice::EMS_DEVICE_FLAG_MMPLUS) {
write_command(0x33B + dhw_, 4, b ? 0x01 : 0x00, 0x33B + dhw_);
} else { // SM100
write_command(0x7A5, 4, b ? 0xFF : 0x00, 0x7A5);
}
return true;
}
+1 -1
View File
@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.8.2"
#define EMSESP_APP_VERSION "3.8.3"
+6
View File
@@ -35,6 +35,11 @@ WebAPIService::WebAPIService(AsyncWebServer * server, SecurityManager * security
// POST|GET api/{device}
// POST|GET api/{device}/{entity}
void WebAPIService::webAPIService(AsyncWebServerRequest * request, JsonVariant json) {
static uint64_t lastcall = 0;
if (uuid::get_uptime_ms() - lastcall < 50 && request->method() == HTTP_GET) {
request->send(429); //too many requests
return;
}
JsonDocument input_doc; // has no body JSON so create dummy as empty input object
JsonObject input;
// if no body then treat it as a secure GET
@@ -49,6 +54,7 @@ void WebAPIService::webAPIService(AsyncWebServerRequest * request, JsonVariant j
input["data"] = json.as<std::string>();
}
parse(request, input);
lastcall = uuid::get_uptime_ms();
}
// for POSTS accepting plain text data
+3 -1
View File
@@ -77,7 +77,9 @@ StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & web
if (entityItem.ram == 2) { // NVS
char key[sizeof(entityItem.name) + 2];
snprintf(key, sizeof(key), "c:%s", entityItem.name);
EMSESP::nvs_.remove(key);
if (EMSESP::nvs_.isKey(key)) {
EMSESP::nvs_.remove(key);
}
}
if (entityItem.ram) { // save name/value pairs for change checking
doc[entityItem.name] = entityItem.value;
+23 -13
View File
@@ -76,7 +76,9 @@ StateUpdateResult WebScheduler::update(JsonObject root, WebScheduler & webSchedu
for (ScheduleItem & scheduleItem : webScheduler.scheduleItems) {
char key[sizeof(scheduleItem.name) + 2];
snprintf(key, sizeof(key), "s:%s", scheduleItem.name);
EMSESP::nvs_.remove(key);
if (EMSESP::nvs_.isKey(key)) {
EMSESP::nvs_.remove(key);
}
}
webScheduler.scheduleItems.clear();
EMSESP::webSchedulerService.ha_reset();
@@ -345,7 +347,11 @@ uint8_t WebSchedulerService::count_entities(bool cmd_only) {
// execute scheduled command
bool WebSchedulerService::command(const char * name, const std::string & command, const std::string & data) {
std::string cmd = Helpers::toLower(command);
if (cmd == "system/message") {
EMSESP::logger().info("Message: %s", data.c_str()); // send to log
Mqtt::queue_publish(F_(message), data); // send to MQTT if enabled
return true;
}
// check http commands. e.g.
// tasmota(get): http://<tasmotaIP>/cm?cmnd=power%20ON
// shelly(get): http://<shellyIP>/relais/0?turn=on
@@ -353,7 +359,11 @@ bool WebSchedulerService::command(const char * name, const std::string & command
JsonDocument doc;
if (deserializeJson(doc, cmd) == DeserializationError::Ok) {
HTTPClient * http = new HTTPClient;
std::string url = doc["url"] | "";
#ifndef EMSESP_STANDALONE
http->setConnectTimeout(10000);
http->setTimeout(10000);
#endif
std::string url = doc["url"] | "";
// for a GET with parameters replace commands with values
// don't search the complete url, it may contain a devicename in path
auto q = url.find_first_of('?');
@@ -401,6 +411,7 @@ bool WebSchedulerService::command(const char * name, const std::string & command
return true;
}
// we can add other json tests here
delete http;
}
doc.clear();
@@ -443,8 +454,7 @@ bool WebSchedulerService::command(const char * name, const std::string & command
// queue schedules to be handled executed in scheduler-loop
bool WebSchedulerService::onChange(const char * cmd) {
for (ScheduleItem & scheduleItem : *scheduleItems_) {
if (scheduleItem.active && scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_ONCHANGE
&& Helpers::toLower(scheduleItem.time.c_str()).find(Helpers::toLower(cmd)) != std::string::npos) {
if (scheduleItem.active && scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_ONCHANGE && Helpers::toLower(scheduleItem.time.c_str()) == Helpers::toLower(cmd)) {
cmd_changed_.push_back(&scheduleItem);
return true;
}
@@ -480,15 +490,14 @@ void WebSchedulerService::loop() {
static uint32_t last_uptime_min = 0;
static uint32_t last_uptime_sec = 0;
if (!raw_value.empty()) { // process a value from system/message command
computed_value = compute(raw_value);
raw_value.clear();
}
// get list of scheduler events and exit if it's empty
if (scheduleItems_->empty()) {
return;
}
// do not execute any command in the first 60 secondes
if (uuid::get_uptime_sec() < 60) {
return;
}
// check if we have onChange events
while (!cmd_changed_.empty()) {
@@ -532,7 +541,8 @@ void WebSchedulerService::loop() {
// retry startup commands not yet executed
if (scheduleItem.active && scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_TIMER && scheduleItem.elapsed_min == 0
&& scheduleItem.retry_cnt < MAX_STARTUP_RETRIES) {
scheduleItem.retry_cnt = command(scheduleItem.name, scheduleItem.cmd.c_str(), scheduleItem.value.c_str()) ? 0xFF : scheduleItem.retry_cnt + 1;
scheduleItem.retry_cnt =
command(scheduleItem.name, scheduleItem.cmd.c_str(), compute(scheduleItem.value.c_str())) ? 0xFF : scheduleItem.retry_cnt + 1;
}
// scheduled timer commands
if (scheduleItem.active && scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_TIMER && scheduleItem.elapsed_min > 0
@@ -543,10 +553,10 @@ void WebSchedulerService::loop() {
last_uptime_min = uptime_min;
}
// check calender, sync to RTC, only execute if year is valid
// check calender, sync to RTC, only execute if year is valid and uptime more than a minute
time_t now = time(nullptr);
tm * tm = localtime(&now);
if (tm->tm_min != last_tm_min && tm->tm_year > 120) {
if (tm->tm_min != last_tm_min && tm->tm_year > 120 && uuid::get_uptime_sec() > 60) {
// find the real dow and minute from RTC
uint8_t real_dow = 1 << tm->tm_wday; // 1 is Sunday
uint16_t real_min = tm->tm_hour * 60 + tm->tm_min;
-3
View File
@@ -90,9 +90,6 @@ class WebSchedulerService : public StatefulService<WebScheduler> {
std::string get_metrics_prometheus();
std::string raw_value;
std::string computed_value;
#if defined(EMSESP_TEST)
void load_test_data();
#endif
+3
View File
@@ -267,6 +267,9 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
}
settings.locale = root["locale"] | EMSESP_DEFAULT_LOCALE;
if (settings.locale == "cz") { // convert from older settings file
settings.locale = "cs";
}
EMSESP::system_.locale(settings.locale);
if (Mqtt::ha_enabled() && original_settings.locale != settings.locale) {
add_flags(ChangeFlags::MQTT);
+5
View File
@@ -177,6 +177,10 @@ void WebStatusService::systemStatus(AsyncWebServerRequest * request) {
// we're ready to do the actual restart ASAP
EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_RESTART_REQUESTED);
}
if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_ERROR_UPLOAD) {
// error is reported, back to normal state
EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_NORMAL);
}
#endif
@@ -241,6 +245,7 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json)
if (!ok) {
EMSESP::logger().err("Action '%s' failed", action.c_str());
request->send(400); // bad request
delete response;
return;
}