diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md
index ffefbd0fa..ab7e9aad6 100644
--- a/CHANGELOG_LATEST.md
+++ b/CHANGELOG_LATEST.md
@@ -13,11 +13,12 @@ For more details go to [emsesp.org](https://emsesp.org/).
- boiler pumpkick [#2965](https://github.com/emsesp/EMS-ESP32/discussions/2965)
- heatpump reset [#2933](https://github.com/emsesp/EMS-ESP32/issues/2933)
- e-mail notification using ReadyMail Client
-- 2.nd freshwater module (dhw4) [#2991](https://github.com/emsesp/EMS-ESP32/issues/2991)
+- 2.nd freshwater module (dhw4, dhw5) [#2991](https://github.com/emsesp/EMS-ESP32/issues/2991)
## Fixed
- SRC climate creation [#2936](https://github.com/emsesp/EMS-ESP32/issues/2936) and [#2960](https://github.com/emsesp/EMS-ESP32/issues/2960)
+- missing translations [#3015](https://github.com/emsesp/EMS-ESP32/issues/3015)
## Changed
@@ -31,3 +32,5 @@ For more details go to [emsesp.org](https://emsesp.org/).
- device class for % values [#2980](https://github.com/emsesp/EMS-ESP32/issues/2980)
- use tasmota core 2026.03.30
- secure mqtt uses ESP_SSLClient
+- fetch telegrams: set length to fetch [#3017](https://github.com/emsesp/EMS-ESP32/issues/3017)
+- move http client from stack to heap
diff --git a/docs/Modbus-Entity-Registers.md b/docs/Modbus-Entity-Registers.md
index e9fefdfb6..739350265 100644
--- a/docs/Modbus-Entity-Registers.md
+++ b/docs/Modbus-Entity-Registers.md
@@ -7654,7 +7654,7 @@ uint8
| cylmaxtemp | maximum cylinder temperature | uint8 (>=0<=0) | C | true | DEVICE_DATA | 5 | 1 | 1 |
| collectorshutdown | collector shutdown | boolean | | false | DEVICE_DATA | 6 | 1 | 1 |
| cylheated | cyl heated | boolean | | false | DEVICE_DATA | 7 | 1 | 1 |
-| cylmiddletemp | cylinder middle temperature (TS3) | int16 | C | false | DEVICE_DATA | 17 | 1 | 1/10 |
+| cylmiddletemp | cylinder middle temperature (TS14) | int16 | C | false | DEVICE_DATA | 17 | 1 | 1/10 |
| retheatassist | return temperature heat assistance (TS4) | int16 | C | false | DEVICE_DATA | 18 | 1 | 1/10 |
| heatassistvalve | heat assistance valve (M1) | boolean | | false | DEVICE_DATA | 19 | 1 | 1 |
| energylasthour | energy last hour | uint24 | Wh | false | DEVICE_DATA | 13 | 2 | 1/10 |
@@ -7671,7 +7671,7 @@ uint8
| cylmaxtemp | maximum cylinder temperature | uint8 (>=0<=0) | C | true | DEVICE_DATA | 5 | 1 | 1 |
| collectorshutdown | collector shutdown | boolean | | false | DEVICE_DATA | 6 | 1 | 1 |
| cylheated | cyl heated | boolean | | false | DEVICE_DATA | 7 | 1 | 1 |
-| cylmiddletemp | cylinder middle temperature (TS3) | int16 | C | false | DEVICE_DATA | 17 | 1 | 1/10 |
+| cylmiddletemp | cylinder middle temperature (TS14) | int16 | C | false | DEVICE_DATA | 17 | 1 | 1/10 |
| retheatassist | return temperature heat assistance (TS4) | int16 | C | false | DEVICE_DATA | 18 | 1 | 1/10 |
| heatassistvalve | heat assistance valve (M1) | boolean | | false | DEVICE_DATA | 19 | 1 | 1 |
| energylasthour | energy last hour | uint24 | Wh | false | DEVICE_DATA | 13 | 2 | 1/10 |
@@ -7696,67 +7696,68 @@ uint8
uint8
| turnoffdiff | pump turn off difference | uint8 (>=0<=0) | C | true | DEVICE_DATA | 11 | 1 | 1/10 |
| collector2temp | collector 2 temperature (TS7) | int16 | C | false | DEVICE_DATA | 20 | 1 | 1/10 |
-| cylmiddletemp | cylinder middle temperature (TS3) | int16 | C | false | DEVICE_DATA | 17 | 1 | 1/10 |
+| cylmiddletemp | cylinder middle temperature (TS14) | int16 | C | false | DEVICE_DATA | 17 | 1 | 1/10 |
+| ts3 | cylinder middle temperature (TS3) | int16 | C | false | DEVICE_DATA | 21 | 1 | 1/10 |
| retheatassist | return temperature heat assistance (TS4) | int16 | C | false | DEVICE_DATA | 18 | 1 | 1/10 |
-| ts8 | (TS8) | int16 | C | false | DEVICE_DATA | 21 | 1 | 1/10 |
-| ts16 | (TS16) | int16 | C | false | DEVICE_DATA | 22 | 1 | 1/10 |
+| ts8 | (TS8) | int16 | C | false | DEVICE_DATA | 22 | 1 | 1/10 |
+| ts16 | (TS16) | int16 | C | false | DEVICE_DATA | 23 | 1 | 1/10 |
| heatassistvalve | heat assistance valve (M1) | boolean | | false | DEVICE_DATA | 19 | 1 | 1 |
-| heatassistpower | heat assistance valve power (M1) | uint8 | % | false | DEVICE_DATA | 23 | 1 | 1 |
-| solarpump2 | pump 2 (PS4) | boolean | | false | DEVICE_DATA | 24 | 1 | 1 |
-| solarpump2mod | pump 2 modulation (PS4) | uint8 | % | false | DEVICE_DATA | 25 | 1 | 1 |
-| cyl2bottomtemp | second cylinder bottom temperature (TS5) | int16 | C | false | DEVICE_DATA | 26 | 1 | 1/10 |
-| cyl3bottomtemp | third cylinder bottom temperature (TS11) | int16 | C | false | DEVICE_DATA | 27 | 1 | 1/10 |
-| cyltoptemp | cylinder top temperature (TS10) | int16 | C | false | DEVICE_DATA | 28 | 1 | 1/10 |
-| heatexchangertemp | heat exchanger temperature (TS6) | int16 | C | false | DEVICE_DATA | 29 | 1 | 1/10 |
-| cylpumpmod | cylinder pump modulation (PS5) | uint8 | % | false | DEVICE_DATA | 30 | 1 | 1 |
-| valvestatus | valve status | boolean | | false | DEVICE_DATA | 31 | 1 | 1 |
-| vs1status | valve status VS1 | boolean | | false | DEVICE_DATA | 32 | 1 | 1 |
-| vs3status | valve status VS3 | boolean | | false | DEVICE_DATA | 33 | 1 | 1 |
-| transferpump | transfer pump | boolean | | false | DEVICE_DATA | 34 | 1 | 1 |
-| transferpumpmod | transfer pump modulation | uint8 | % | false | DEVICE_DATA | 35 | 1 | 1 |
+| heatassistpower | heat assistance valve power (M1) | uint8 | % | false | DEVICE_DATA | 24 | 1 | 1 |
+| solarpump2 | pump 2 (PS4) | boolean | | false | DEVICE_DATA | 25 | 1 | 1 |
+| solarpump2mod | pump 2 modulation (PS4) | uint8 | % | false | DEVICE_DATA | 26 | 1 | 1 |
+| cyl2bottomtemp | second cylinder bottom temperature (TS5) | int16 | C | false | DEVICE_DATA | 27 | 1 | 1/10 |
+| cyl3bottomtemp | third cylinder bottom temperature (TS11) | int16 | C | false | DEVICE_DATA | 28 | 1 | 1/10 |
+| cyltoptemp | cylinder top temperature (TS10) | int16 | C | false | DEVICE_DATA | 29 | 1 | 1/10 |
+| heatexchangertemp | heat exchanger temperature (TS6) | int16 | C | false | DEVICE_DATA | 30 | 1 | 1/10 |
+| cylpumpmod | cylinder pump modulation (PS5) | uint8 | % | false | DEVICE_DATA | 31 | 1 | 1 |
+| valvestatus | valve status | boolean | | false | DEVICE_DATA | 32 | 1 | 1 |
+| vs1status | valve status VS1 | boolean | | false | DEVICE_DATA | 33 | 1 | 1 |
+| vs3status | valve status VS3 | boolean | | false | DEVICE_DATA | 34 | 1 | 1 |
+| transferpump | transfer pump | boolean | | false | DEVICE_DATA | 35 | 1 | 1 |
+| transferpumpmod | transfer pump modulation | uint8 | % | false | DEVICE_DATA | 36 | 1 | 1 |
uint8
-| collectormaxtemp | maximum collector temperature | uint8 (>=0<=0) | C | true | DEVICE_DATA | 36 | 1 | 1 |
+| collectormaxtemp | maximum collector temperature | uint8 (>=0<=0) | C | true | DEVICE_DATA | 37 | 1 | 1 |
uint8
-| collectormintemp | minimum collector temperature | uint8 (>=0<=0) | C | true | DEVICE_DATA | 37 | 1 | 1 |
+| collectormintemp | minimum collector temperature | uint8 (>=0<=0) | C | true | DEVICE_DATA | 38 | 1 | 1 |
| energylasthour | energy last hour | uint24 | Wh | false | DEVICE_DATA | 13 | 2 | 1/10 |
-| energytoday | total energy today | uint24 | Wh | false | DEVICE_DATA | 38 | 2 | 1 |
-| energytotal | total energy | uint24 | kWh | false | DEVICE_DATA | 40 | 2 | 1/10 |
-| pump2worktime | pump 2 working time | time | minutes | false | DEVICE_DATA | 42 | 2 | 1 |
-| m1worktime | differential control working time | time | minutes | false | DEVICE_DATA | 44 | 2 | 1 |
-| heattransfersystem | heattransfer system | boolean | | true | DEVICE_DATA | 46 | 1 | 1 |
-| externalcyl | external cylinder | boolean | | true | DEVICE_DATA | 47 | 1 | 1 |
-| thermaldisinfect | thermal disinfection | boolean | | true | DEVICE_DATA | 48 | 1 | 1 |
-| heatmetering | heatmetering | boolean | | true | DEVICE_DATA | 49 | 1 | 1 |
-| activated | activated | boolean | | true | DEVICE_DATA | 50 | 1 | 1 |
-| solarpumpmode | solar pump mode | enum | | true | DEVICE_DATA | 51 | 1 | 1 |
-| solarpumpkick | solar pump kick | boolean | | true | DEVICE_DATA | 52 | 1 | 1 |
-| plainwatermode | plain water mode | boolean | | true | DEVICE_DATA | 53 | 1 | 1 |
-| doublematchflow | doublematchflow | boolean | | true | DEVICE_DATA | 54 | 1 | 1 |
+| energytoday | total energy today | uint24 | Wh | false | DEVICE_DATA | 39 | 2 | 1 |
+| energytotal | total energy | uint24 | kWh | false | DEVICE_DATA | 41 | 2 | 1/10 |
+| pump2worktime | pump 2 working time | time | minutes | false | DEVICE_DATA | 43 | 2 | 1 |
+| m1worktime | differential control working time | time | minutes | false | DEVICE_DATA | 45 | 2 | 1 |
+| heattransfersystem | heattransfer system | boolean | | true | DEVICE_DATA | 47 | 1 | 1 |
+| externalcyl | external cylinder | boolean | | true | DEVICE_DATA | 48 | 1 | 1 |
+| thermaldisinfect | thermal disinfection | boolean | | true | DEVICE_DATA | 49 | 1 | 1 |
+| heatmetering | heatmetering | boolean | | true | DEVICE_DATA | 50 | 1 | 1 |
+| activated | activated | boolean | | true | DEVICE_DATA | 51 | 1 | 1 |
+| solarpumpmode | solar pump mode | enum | | true | DEVICE_DATA | 52 | 1 | 1 |
+| solarpumpkick | solar pump kick | boolean | | true | DEVICE_DATA | 53 | 1 | 1 |
+| plainwatermode | plain water mode | boolean | | true | DEVICE_DATA | 54 | 1 | 1 |
+| doublematchflow | doublematchflow | boolean | | true | DEVICE_DATA | 55 | 1 | 1 |
uint8
-| pump2minmod | minimum pump 2 modulation | uint8 (>=0<=0) | % | true | DEVICE_DATA | 55 | 1 | 1 |
+| pump2minmod | minimum pump 2 modulation | uint8 (>=0<=0) | % | true | DEVICE_DATA | 56 | 1 | 1 |
uint8
-| turnondiff2 | pump 2 turn on difference | uint8 (>=0<=0) | C | true | DEVICE_DATA | 56 | 1 | 1/10 |
+| turnondiff2 | pump 2 turn on difference | uint8 (>=0<=0) | C | true | DEVICE_DATA | 57 | 1 | 1/10 |
uint8
-| turnoffdiff2 | pump 2 turn off difference | uint8 (>=0<=0) | C | true | DEVICE_DATA | 57 | 1 | 1/10 |
-| pump2kick | pump kick 2 | boolean | | true | DEVICE_DATA | 58 | 1 | 1 |
+| turnoffdiff2 | pump 2 turn off difference | uint8 (>=0<=0) | C | true | DEVICE_DATA | 58 | 1 | 1/10 |
+| pump2kick | pump kick 2 | boolean | | true | DEVICE_DATA | 59 | 1 | 1 |
uint8
-| climatezone | climate zone | uint8 (>=0<=0) | | true | DEVICE_DATA | 59 | 1 | 1 |
+| climatezone | climate zone | uint8 (>=0<=0) | | true | DEVICE_DATA | 60 | 1 | 1 |
uint16
-| collector1area | collector 1 area | uint16 (>=0<=0) | m² | true | DEVICE_DATA | 60 | 1 | 1/10 |
-| collector1type | collector 1 type | enum | | true | DEVICE_DATA | 61 | 1 | 1 |
+| collector1area | collector 1 area | uint16 (>=0<=0) | m² | true | DEVICE_DATA | 61 | 1 | 1/10 |
+| collector1type | collector 1 type | enum | | true | DEVICE_DATA | 62 | 1 | 1 |
uint16
-| collector2area | collector 2 area | uint16 (>=0<=0) | m² | true | DEVICE_DATA | 62 | 1 | 1/10 |
-| collector2type | collector 2 type | enum | | true | DEVICE_DATA | 63 | 1 | 1 |
-| cylpriority | cylinder priority | enum | | true | DEVICE_DATA | 64 | 1 | 1 |
-| heatcntflowtemp | heat counter flow temperature | uint16 | C | false | DEVICE_DATA | 65 | 1 | 1/10 |
-| heatcntrettemp | heat counter return temperature | uint16 | C | false | DEVICE_DATA | 66 | 1 | 1/10 |
-| heatcnt | heat counter impulses | uint8 | | false | DEVICE_DATA | 67 | 1 | 1 |
-| swapflowtemp | swap flow temperature (TS14) | uint16 | C | false | DEVICE_DATA | 68 | 1 | 1/10 |
-| swaprettemp | swap return temperature (TS15) | uint16 | C | false | DEVICE_DATA | 69 | 1 | 1/10 |
+| collector2area | collector 2 area | uint16 (>=0<=0) | m² | true | DEVICE_DATA | 63 | 1 | 1/10 |
+| collector2type | collector 2 type | enum | | true | DEVICE_DATA | 64 | 1 | 1 |
+| cylpriority | cylinder priority | enum | | true | DEVICE_DATA | 65 | 1 | 1 |
+| heatcntflowtemp | heat counter flow temperature | uint16 | C | false | DEVICE_DATA | 66 | 1 | 1/10 |
+| heatcntrettemp | heat counter return temperature | uint16 | C | false | DEVICE_DATA | 67 | 1 | 1/10 |
+| heatcnt | heat counter impulses | uint8 | | false | DEVICE_DATA | 68 | 1 | 1 |
+| swapflowtemp | swap flow temperature (TS14) | uint16 | C | false | DEVICE_DATA | 69 | 1 | 1/10 |
+| swaprettemp | swap return temperature (TS15) | uint16 | C | false | DEVICE_DATA | 70 | 1 | 1/10 |
int8
-| heatassiston | heat assistance on | int8 (>=0<=0) | K | true | DEVICE_DATA | 70 | 1 | 1/10 |
+| heatassiston | heat assistance on | int8 (>=0<=0) | K | true | DEVICE_DATA | 71 | 1 | 1/10 |
int8
-| heatassistoff | heat assistance off | int8 (>=0<=0) | K | true | DEVICE_DATA | 71 | 1 | 1/10 |
+| heatassistoff | heat assistance off | int8 (>=0<=0) | K | true | DEVICE_DATA | 72 | 1 | 1/10 |
### SM100, MS100
@@ -7778,67 +7779,68 @@ uint8
uint8
| turnoffdiff | pump turn off difference | uint8 (>=0<=0) | C | true | DEVICE_DATA | 11 | 1 | 1/10 |
| collector2temp | collector 2 temperature (TS7) | int16 | C | false | DEVICE_DATA | 20 | 1 | 1/10 |
-| cylmiddletemp | cylinder middle temperature (TS3) | int16 | C | false | DEVICE_DATA | 17 | 1 | 1/10 |
+| cylmiddletemp | cylinder middle temperature (TS14) | int16 | C | false | DEVICE_DATA | 17 | 1 | 1/10 |
+| ts3 | cylinder middle temperature (TS3) | int16 | C | false | DEVICE_DATA | 21 | 1 | 1/10 |
| retheatassist | return temperature heat assistance (TS4) | int16 | C | false | DEVICE_DATA | 18 | 1 | 1/10 |
-| ts8 | (TS8) | int16 | C | false | DEVICE_DATA | 21 | 1 | 1/10 |
-| ts16 | (TS16) | int16 | C | false | DEVICE_DATA | 22 | 1 | 1/10 |
+| ts8 | (TS8) | int16 | C | false | DEVICE_DATA | 22 | 1 | 1/10 |
+| ts16 | (TS16) | int16 | C | false | DEVICE_DATA | 23 | 1 | 1/10 |
| heatassistvalve | heat assistance valve (M1) | boolean | | false | DEVICE_DATA | 19 | 1 | 1 |
-| heatassistpower | heat assistance valve power (M1) | uint8 | % | false | DEVICE_DATA | 23 | 1 | 1 |
-| solarpump2 | pump 2 (PS4) | boolean | | false | DEVICE_DATA | 24 | 1 | 1 |
-| solarpump2mod | pump 2 modulation (PS4) | uint8 | % | false | DEVICE_DATA | 25 | 1 | 1 |
-| cyl2bottomtemp | second cylinder bottom temperature (TS5) | int16 | C | false | DEVICE_DATA | 26 | 1 | 1/10 |
-| cyl3bottomtemp | third cylinder bottom temperature (TS11) | int16 | C | false | DEVICE_DATA | 27 | 1 | 1/10 |
-| cyltoptemp | cylinder top temperature (TS10) | int16 | C | false | DEVICE_DATA | 28 | 1 | 1/10 |
-| heatexchangertemp | heat exchanger temperature (TS6) | int16 | C | false | DEVICE_DATA | 29 | 1 | 1/10 |
-| cylpumpmod | cylinder pump modulation (PS5) | uint8 | % | false | DEVICE_DATA | 30 | 1 | 1 |
-| valvestatus | valve status | boolean | | false | DEVICE_DATA | 31 | 1 | 1 |
-| vs1status | valve status VS1 | boolean | | false | DEVICE_DATA | 32 | 1 | 1 |
-| vs3status | valve status VS3 | boolean | | false | DEVICE_DATA | 33 | 1 | 1 |
-| transferpump | transfer pump | boolean | | false | DEVICE_DATA | 34 | 1 | 1 |
-| transferpumpmod | transfer pump modulation | uint8 | % | false | DEVICE_DATA | 35 | 1 | 1 |
+| heatassistpower | heat assistance valve power (M1) | uint8 | % | false | DEVICE_DATA | 24 | 1 | 1 |
+| solarpump2 | pump 2 (PS4) | boolean | | false | DEVICE_DATA | 25 | 1 | 1 |
+| solarpump2mod | pump 2 modulation (PS4) | uint8 | % | false | DEVICE_DATA | 26 | 1 | 1 |
+| cyl2bottomtemp | second cylinder bottom temperature (TS5) | int16 | C | false | DEVICE_DATA | 27 | 1 | 1/10 |
+| cyl3bottomtemp | third cylinder bottom temperature (TS11) | int16 | C | false | DEVICE_DATA | 28 | 1 | 1/10 |
+| cyltoptemp | cylinder top temperature (TS10) | int16 | C | false | DEVICE_DATA | 29 | 1 | 1/10 |
+| heatexchangertemp | heat exchanger temperature (TS6) | int16 | C | false | DEVICE_DATA | 30 | 1 | 1/10 |
+| cylpumpmod | cylinder pump modulation (PS5) | uint8 | % | false | DEVICE_DATA | 31 | 1 | 1 |
+| valvestatus | valve status | boolean | | false | DEVICE_DATA | 32 | 1 | 1 |
+| vs1status | valve status VS1 | boolean | | false | DEVICE_DATA | 33 | 1 | 1 |
+| vs3status | valve status VS3 | boolean | | false | DEVICE_DATA | 34 | 1 | 1 |
+| transferpump | transfer pump | boolean | | false | DEVICE_DATA | 35 | 1 | 1 |
+| transferpumpmod | transfer pump modulation | uint8 | % | false | DEVICE_DATA | 36 | 1 | 1 |
uint8
-| collectormaxtemp | maximum collector temperature | uint8 (>=0<=0) | C | true | DEVICE_DATA | 36 | 1 | 1 |
+| collectormaxtemp | maximum collector temperature | uint8 (>=0<=0) | C | true | DEVICE_DATA | 37 | 1 | 1 |
uint8
-| collectormintemp | minimum collector temperature | uint8 (>=0<=0) | C | true | DEVICE_DATA | 37 | 1 | 1 |
+| collectormintemp | minimum collector temperature | uint8 (>=0<=0) | C | true | DEVICE_DATA | 38 | 1 | 1 |
| energylasthour | energy last hour | uint24 | Wh | false | DEVICE_DATA | 13 | 2 | 1/10 |
-| energytoday | total energy today | uint24 | Wh | false | DEVICE_DATA | 38 | 2 | 1 |
-| energytotal | total energy | uint24 | kWh | false | DEVICE_DATA | 40 | 2 | 1/10 |
-| pump2worktime | pump 2 working time | time | minutes | false | DEVICE_DATA | 42 | 2 | 1 |
-| m1worktime | differential control working time | time | minutes | false | DEVICE_DATA | 44 | 2 | 1 |
-| heattransfersystem | heattransfer system | boolean | | true | DEVICE_DATA | 46 | 1 | 1 |
-| externalcyl | external cylinder | boolean | | true | DEVICE_DATA | 47 | 1 | 1 |
-| thermaldisinfect | thermal disinfection | boolean | | true | DEVICE_DATA | 48 | 1 | 1 |
-| heatmetering | heatmetering | boolean | | true | DEVICE_DATA | 49 | 1 | 1 |
-| activated | activated | boolean | | true | DEVICE_DATA | 50 | 1 | 1 |
-| solarpumpmode | solar pump mode | enum | | true | DEVICE_DATA | 51 | 1 | 1 |
-| solarpumpkick | solar pump kick | boolean | | true | DEVICE_DATA | 52 | 1 | 1 |
-| plainwatermode | plain water mode | boolean | | true | DEVICE_DATA | 53 | 1 | 1 |
-| doublematchflow | doublematchflow | boolean | | true | DEVICE_DATA | 54 | 1 | 1 |
+| energytoday | total energy today | uint24 | Wh | false | DEVICE_DATA | 39 | 2 | 1 |
+| energytotal | total energy | uint24 | kWh | false | DEVICE_DATA | 41 | 2 | 1/10 |
+| pump2worktime | pump 2 working time | time | minutes | false | DEVICE_DATA | 43 | 2 | 1 |
+| m1worktime | differential control working time | time | minutes | false | DEVICE_DATA | 45 | 2 | 1 |
+| heattransfersystem | heattransfer system | boolean | | true | DEVICE_DATA | 47 | 1 | 1 |
+| externalcyl | external cylinder | boolean | | true | DEVICE_DATA | 48 | 1 | 1 |
+| thermaldisinfect | thermal disinfection | boolean | | true | DEVICE_DATA | 49 | 1 | 1 |
+| heatmetering | heatmetering | boolean | | true | DEVICE_DATA | 50 | 1 | 1 |
+| activated | activated | boolean | | true | DEVICE_DATA | 51 | 1 | 1 |
+| solarpumpmode | solar pump mode | enum | | true | DEVICE_DATA | 52 | 1 | 1 |
+| solarpumpkick | solar pump kick | boolean | | true | DEVICE_DATA | 53 | 1 | 1 |
+| plainwatermode | plain water mode | boolean | | true | DEVICE_DATA | 54 | 1 | 1 |
+| doublematchflow | doublematchflow | boolean | | true | DEVICE_DATA | 55 | 1 | 1 |
uint8
-| pump2minmod | minimum pump 2 modulation | uint8 (>=0<=0) | % | true | DEVICE_DATA | 55 | 1 | 1 |
+| pump2minmod | minimum pump 2 modulation | uint8 (>=0<=0) | % | true | DEVICE_DATA | 56 | 1 | 1 |
uint8
-| turnondiff2 | pump 2 turn on difference | uint8 (>=0<=0) | C | true | DEVICE_DATA | 56 | 1 | 1/10 |
+| turnondiff2 | pump 2 turn on difference | uint8 (>=0<=0) | C | true | DEVICE_DATA | 57 | 1 | 1/10 |
uint8
-| turnoffdiff2 | pump 2 turn off difference | uint8 (>=0<=0) | C | true | DEVICE_DATA | 57 | 1 | 1/10 |
-| pump2kick | pump kick 2 | boolean | | true | DEVICE_DATA | 58 | 1 | 1 |
+| turnoffdiff2 | pump 2 turn off difference | uint8 (>=0<=0) | C | true | DEVICE_DATA | 58 | 1 | 1/10 |
+| pump2kick | pump kick 2 | boolean | | true | DEVICE_DATA | 59 | 1 | 1 |
uint8
-| climatezone | climate zone | uint8 (>=0<=0) | | true | DEVICE_DATA | 59 | 1 | 1 |
+| climatezone | climate zone | uint8 (>=0<=0) | | true | DEVICE_DATA | 60 | 1 | 1 |
uint16
-| collector1area | collector 1 area | uint16 (>=0<=0) | m² | true | DEVICE_DATA | 60 | 1 | 1/10 |
-| collector1type | collector 1 type | enum | | true | DEVICE_DATA | 61 | 1 | 1 |
+| collector1area | collector 1 area | uint16 (>=0<=0) | m² | true | DEVICE_DATA | 61 | 1 | 1/10 |
+| collector1type | collector 1 type | enum | | true | DEVICE_DATA | 62 | 1 | 1 |
uint16
-| collector2area | collector 2 area | uint16 (>=0<=0) | m² | true | DEVICE_DATA | 62 | 1 | 1/10 |
-| collector2type | collector 2 type | enum | | true | DEVICE_DATA | 63 | 1 | 1 |
-| cylpriority | cylinder priority | enum | | true | DEVICE_DATA | 64 | 1 | 1 |
-| heatcntflowtemp | heat counter flow temperature | uint16 | C | false | DEVICE_DATA | 65 | 1 | 1/10 |
-| heatcntrettemp | heat counter return temperature | uint16 | C | false | DEVICE_DATA | 66 | 1 | 1/10 |
-| heatcnt | heat counter impulses | uint8 | | false | DEVICE_DATA | 67 | 1 | 1 |
-| swapflowtemp | swap flow temperature (TS14) | uint16 | C | false | DEVICE_DATA | 68 | 1 | 1/10 |
-| swaprettemp | swap return temperature (TS15) | uint16 | C | false | DEVICE_DATA | 69 | 1 | 1/10 |
+| collector2area | collector 2 area | uint16 (>=0<=0) | m² | true | DEVICE_DATA | 63 | 1 | 1/10 |
+| collector2type | collector 2 type | enum | | true | DEVICE_DATA | 64 | 1 | 1 |
+| cylpriority | cylinder priority | enum | | true | DEVICE_DATA | 65 | 1 | 1 |
+| heatcntflowtemp | heat counter flow temperature | uint16 | C | false | DEVICE_DATA | 66 | 1 | 1/10 |
+| heatcntrettemp | heat counter return temperature | uint16 | C | false | DEVICE_DATA | 67 | 1 | 1/10 |
+| heatcnt | heat counter impulses | uint8 | | false | DEVICE_DATA | 68 | 1 | 1 |
+| swapflowtemp | swap flow temperature (TS14) | uint16 | C | false | DEVICE_DATA | 69 | 1 | 1/10 |
+| swaprettemp | swap return temperature (TS15) | uint16 | C | false | DEVICE_DATA | 70 | 1 | 1/10 |
int8
-| heatassiston | heat assistance on | int8 (>=0<=0) | K | true | DEVICE_DATA | 70 | 1 | 1/10 |
+| heatassiston | heat assistance on | int8 (>=0<=0) | K | true | DEVICE_DATA | 71 | 1 | 1/10 |
int8
-| heatassistoff | heat assistance off | int8 (>=0<=0) | K | true | DEVICE_DATA | 71 | 1 | 1/10 |
+| heatassistoff | heat assistance off | int8 (>=0<=0) | K | true | DEVICE_DATA | 72 | 1 | 1/10 |
### SM200, MS200
@@ -7860,67 +7862,68 @@ uint8
uint8
| turnoffdiff | pump turn off difference | uint8 (>=0<=0) | C | true | DEVICE_DATA | 11 | 1 | 1/10 |
| collector2temp | collector 2 temperature (TS7) | int16 | C | false | DEVICE_DATA | 20 | 1 | 1/10 |
-| cylmiddletemp | cylinder middle temperature (TS3) | int16 | C | false | DEVICE_DATA | 17 | 1 | 1/10 |
+| cylmiddletemp | cylinder middle temperature (TS14) | int16 | C | false | DEVICE_DATA | 17 | 1 | 1/10 |
+| ts3 | cylinder middle temperature (TS3) | int16 | C | false | DEVICE_DATA | 21 | 1 | 1/10 |
| retheatassist | return temperature heat assistance (TS4) | int16 | C | false | DEVICE_DATA | 18 | 1 | 1/10 |
-| ts8 | (TS8) | int16 | C | false | DEVICE_DATA | 21 | 1 | 1/10 |
-| ts16 | (TS16) | int16 | C | false | DEVICE_DATA | 22 | 1 | 1/10 |
+| ts8 | (TS8) | int16 | C | false | DEVICE_DATA | 22 | 1 | 1/10 |
+| ts16 | (TS16) | int16 | C | false | DEVICE_DATA | 23 | 1 | 1/10 |
| heatassistvalve | heat assistance valve (M1) | boolean | | false | DEVICE_DATA | 19 | 1 | 1 |
-| heatassistpower | heat assistance valve power (M1) | uint8 | % | false | DEVICE_DATA | 23 | 1 | 1 |
-| solarpump2 | pump 2 (PS4) | boolean | | false | DEVICE_DATA | 24 | 1 | 1 |
-| solarpump2mod | pump 2 modulation (PS4) | uint8 | % | false | DEVICE_DATA | 25 | 1 | 1 |
-| cyl2bottomtemp | second cylinder bottom temperature (TS5) | int16 | C | false | DEVICE_DATA | 26 | 1 | 1/10 |
-| cyl3bottomtemp | third cylinder bottom temperature (TS11) | int16 | C | false | DEVICE_DATA | 27 | 1 | 1/10 |
-| cyltoptemp | cylinder top temperature (TS10) | int16 | C | false | DEVICE_DATA | 28 | 1 | 1/10 |
-| heatexchangertemp | heat exchanger temperature (TS6) | int16 | C | false | DEVICE_DATA | 29 | 1 | 1/10 |
-| cylpumpmod | cylinder pump modulation (PS5) | uint8 | % | false | DEVICE_DATA | 30 | 1 | 1 |
-| valvestatus | valve status | boolean | | false | DEVICE_DATA | 31 | 1 | 1 |
-| vs1status | valve status VS1 | boolean | | false | DEVICE_DATA | 32 | 1 | 1 |
-| vs3status | valve status VS3 | boolean | | false | DEVICE_DATA | 33 | 1 | 1 |
-| transferpump | transfer pump | boolean | | false | DEVICE_DATA | 34 | 1 | 1 |
-| transferpumpmod | transfer pump modulation | uint8 | % | false | DEVICE_DATA | 35 | 1 | 1 |
+| heatassistpower | heat assistance valve power (M1) | uint8 | % | false | DEVICE_DATA | 24 | 1 | 1 |
+| solarpump2 | pump 2 (PS4) | boolean | | false | DEVICE_DATA | 25 | 1 | 1 |
+| solarpump2mod | pump 2 modulation (PS4) | uint8 | % | false | DEVICE_DATA | 26 | 1 | 1 |
+| cyl2bottomtemp | second cylinder bottom temperature (TS5) | int16 | C | false | DEVICE_DATA | 27 | 1 | 1/10 |
+| cyl3bottomtemp | third cylinder bottom temperature (TS11) | int16 | C | false | DEVICE_DATA | 28 | 1 | 1/10 |
+| cyltoptemp | cylinder top temperature (TS10) | int16 | C | false | DEVICE_DATA | 29 | 1 | 1/10 |
+| heatexchangertemp | heat exchanger temperature (TS6) | int16 | C | false | DEVICE_DATA | 30 | 1 | 1/10 |
+| cylpumpmod | cylinder pump modulation (PS5) | uint8 | % | false | DEVICE_DATA | 31 | 1 | 1 |
+| valvestatus | valve status | boolean | | false | DEVICE_DATA | 32 | 1 | 1 |
+| vs1status | valve status VS1 | boolean | | false | DEVICE_DATA | 33 | 1 | 1 |
+| vs3status | valve status VS3 | boolean | | false | DEVICE_DATA | 34 | 1 | 1 |
+| transferpump | transfer pump | boolean | | false | DEVICE_DATA | 35 | 1 | 1 |
+| transferpumpmod | transfer pump modulation | uint8 | % | false | DEVICE_DATA | 36 | 1 | 1 |
uint8
-| collectormaxtemp | maximum collector temperature | uint8 (>=0<=0) | C | true | DEVICE_DATA | 36 | 1 | 1 |
+| collectormaxtemp | maximum collector temperature | uint8 (>=0<=0) | C | true | DEVICE_DATA | 37 | 1 | 1 |
uint8
-| collectormintemp | minimum collector temperature | uint8 (>=0<=0) | C | true | DEVICE_DATA | 37 | 1 | 1 |
+| collectormintemp | minimum collector temperature | uint8 (>=0<=0) | C | true | DEVICE_DATA | 38 | 1 | 1 |
| energylasthour | energy last hour | uint24 | Wh | false | DEVICE_DATA | 13 | 2 | 1/10 |
-| energytoday | total energy today | uint24 | Wh | false | DEVICE_DATA | 38 | 2 | 1 |
-| energytotal | total energy | uint24 | kWh | false | DEVICE_DATA | 40 | 2 | 1/10 |
-| pump2worktime | pump 2 working time | time | minutes | false | DEVICE_DATA | 42 | 2 | 1 |
-| m1worktime | differential control working time | time | minutes | false | DEVICE_DATA | 44 | 2 | 1 |
-| heattransfersystem | heattransfer system | boolean | | true | DEVICE_DATA | 46 | 1 | 1 |
-| externalcyl | external cylinder | boolean | | true | DEVICE_DATA | 47 | 1 | 1 |
-| thermaldisinfect | thermal disinfection | boolean | | true | DEVICE_DATA | 48 | 1 | 1 |
-| heatmetering | heatmetering | boolean | | true | DEVICE_DATA | 49 | 1 | 1 |
-| activated | activated | boolean | | true | DEVICE_DATA | 50 | 1 | 1 |
-| solarpumpmode | solar pump mode | enum | | true | DEVICE_DATA | 51 | 1 | 1 |
-| solarpumpkick | solar pump kick | boolean | | true | DEVICE_DATA | 52 | 1 | 1 |
-| plainwatermode | plain water mode | boolean | | true | DEVICE_DATA | 53 | 1 | 1 |
-| doublematchflow | doublematchflow | boolean | | true | DEVICE_DATA | 54 | 1 | 1 |
+| energytoday | total energy today | uint24 | Wh | false | DEVICE_DATA | 39 | 2 | 1 |
+| energytotal | total energy | uint24 | kWh | false | DEVICE_DATA | 41 | 2 | 1/10 |
+| pump2worktime | pump 2 working time | time | minutes | false | DEVICE_DATA | 43 | 2 | 1 |
+| m1worktime | differential control working time | time | minutes | false | DEVICE_DATA | 45 | 2 | 1 |
+| heattransfersystem | heattransfer system | boolean | | true | DEVICE_DATA | 47 | 1 | 1 |
+| externalcyl | external cylinder | boolean | | true | DEVICE_DATA | 48 | 1 | 1 |
+| thermaldisinfect | thermal disinfection | boolean | | true | DEVICE_DATA | 49 | 1 | 1 |
+| heatmetering | heatmetering | boolean | | true | DEVICE_DATA | 50 | 1 | 1 |
+| activated | activated | boolean | | true | DEVICE_DATA | 51 | 1 | 1 |
+| solarpumpmode | solar pump mode | enum | | true | DEVICE_DATA | 52 | 1 | 1 |
+| solarpumpkick | solar pump kick | boolean | | true | DEVICE_DATA | 53 | 1 | 1 |
+| plainwatermode | plain water mode | boolean | | true | DEVICE_DATA | 54 | 1 | 1 |
+| doublematchflow | doublematchflow | boolean | | true | DEVICE_DATA | 55 | 1 | 1 |
uint8
-| pump2minmod | minimum pump 2 modulation | uint8 (>=0<=0) | % | true | DEVICE_DATA | 55 | 1 | 1 |
+| pump2minmod | minimum pump 2 modulation | uint8 (>=0<=0) | % | true | DEVICE_DATA | 56 | 1 | 1 |
uint8
-| turnondiff2 | pump 2 turn on difference | uint8 (>=0<=0) | C | true | DEVICE_DATA | 56 | 1 | 1/10 |
+| turnondiff2 | pump 2 turn on difference | uint8 (>=0<=0) | C | true | DEVICE_DATA | 57 | 1 | 1/10 |
uint8
-| turnoffdiff2 | pump 2 turn off difference | uint8 (>=0<=0) | C | true | DEVICE_DATA | 57 | 1 | 1/10 |
-| pump2kick | pump kick 2 | boolean | | true | DEVICE_DATA | 58 | 1 | 1 |
+| turnoffdiff2 | pump 2 turn off difference | uint8 (>=0<=0) | C | true | DEVICE_DATA | 58 | 1 | 1/10 |
+| pump2kick | pump kick 2 | boolean | | true | DEVICE_DATA | 59 | 1 | 1 |
uint8
-| climatezone | climate zone | uint8 (>=0<=0) | | true | DEVICE_DATA | 59 | 1 | 1 |
+| climatezone | climate zone | uint8 (>=0<=0) | | true | DEVICE_DATA | 60 | 1 | 1 |
uint16
-| collector1area | collector 1 area | uint16 (>=0<=0) | m² | true | DEVICE_DATA | 60 | 1 | 1/10 |
-| collector1type | collector 1 type | enum | | true | DEVICE_DATA | 61 | 1 | 1 |
+| collector1area | collector 1 area | uint16 (>=0<=0) | m² | true | DEVICE_DATA | 61 | 1 | 1/10 |
+| collector1type | collector 1 type | enum | | true | DEVICE_DATA | 62 | 1 | 1 |
uint16
-| collector2area | collector 2 area | uint16 (>=0<=0) | m² | true | DEVICE_DATA | 62 | 1 | 1/10 |
-| collector2type | collector 2 type | enum | | true | DEVICE_DATA | 63 | 1 | 1 |
-| cylpriority | cylinder priority | enum | | true | DEVICE_DATA | 64 | 1 | 1 |
-| heatcntflowtemp | heat counter flow temperature | uint16 | C | false | DEVICE_DATA | 65 | 1 | 1/10 |
-| heatcntrettemp | heat counter return temperature | uint16 | C | false | DEVICE_DATA | 66 | 1 | 1/10 |
-| heatcnt | heat counter impulses | uint8 | | false | DEVICE_DATA | 67 | 1 | 1 |
-| swapflowtemp | swap flow temperature (TS14) | uint16 | C | false | DEVICE_DATA | 68 | 1 | 1/10 |
-| swaprettemp | swap return temperature (TS15) | uint16 | C | false | DEVICE_DATA | 69 | 1 | 1/10 |
+| collector2area | collector 2 area | uint16 (>=0<=0) | m² | true | DEVICE_DATA | 63 | 1 | 1/10 |
+| collector2type | collector 2 type | enum | | true | DEVICE_DATA | 64 | 1 | 1 |
+| cylpriority | cylinder priority | enum | | true | DEVICE_DATA | 65 | 1 | 1 |
+| heatcntflowtemp | heat counter flow temperature | uint16 | C | false | DEVICE_DATA | 66 | 1 | 1/10 |
+| heatcntrettemp | heat counter return temperature | uint16 | C | false | DEVICE_DATA | 67 | 1 | 1/10 |
+| heatcnt | heat counter impulses | uint8 | | false | DEVICE_DATA | 68 | 1 | 1 |
+| swapflowtemp | swap flow temperature (TS14) | uint16 | C | false | DEVICE_DATA | 69 | 1 | 1/10 |
+| swaprettemp | swap return temperature (TS15) | uint16 | C | false | DEVICE_DATA | 70 | 1 | 1/10 |
int8
-| heatassiston | heat assistance on | int8 (>=0<=0) | K | true | DEVICE_DATA | 70 | 1 | 1/10 |
+| heatassiston | heat assistance on | int8 (>=0<=0) | K | true | DEVICE_DATA | 71 | 1 | 1/10 |
int8
-| heatassistoff | heat assistance off | int8 (>=0<=0) | K | true | DEVICE_DATA | 71 | 1 | 1/10 |
+| heatassistoff | heat assistance off | int8 (>=0<=0) | K | true | DEVICE_DATA | 72 | 1 | 1/10 |
## Devices of type \_heatpump
diff --git a/docs/dump_entities.csv b/docs/dump_entities.csv
index 943b1d5ef..0bd4e604b 100644
--- a/docs/dump_entities.csv
+++ b/docs/dump_entities.csv
@@ -5495,7 +5495,7 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"ISM1",solar,101,cylmaxtemp,maximum cylinder temperature,uint8 (>=0<=0),C,true,number.solar_maximum_cylinder_temperature,number.solar_cylmaxtemp,8,0,1,5,1
"ISM1",solar,101,collectorshutdown,collector shutdown,boolean, ,false,binary_sensor.solar_collector_shutdown,binary_sensor.solar_collectorshutdown,8,0,1,6,1
"ISM1",solar,101,cylheated,cyl heated,boolean, ,false,binary_sensor.solar_cyl_heated,binary_sensor.solar_cylheated,8,0,1,7,1
-"ISM1",solar,101,cylmiddletemp,cylinder middle temperature (TS3),int16,C,false,sensor.solar_cylinder_middle_temperature_(TS3),sensor.solar_cylmiddletemp,8,0,1/10,17,1
+"ISM1",solar,101,cylmiddletemp,cylinder middle temperature (TS14),int16,C,false,sensor.solar_cylinder_middle_temperature_(TS14),sensor.solar_cylmiddletemp,8,0,1/10,17,1
"ISM1",solar,101,retheatassist,return temperature heat assistance (TS4),int16,C,false,sensor.solar_return_temperature_heat_assistance_(TS4),sensor.solar_retheatassist,8,0,1/10,18,1
"ISM1",solar,101,heatassistvalve,heat assistance valve (M1),boolean, ,false,binary_sensor.solar_heat_assistance_valve_(M1),binary_sensor.solar_heatassistvalve,8,0,1,19,1
"ISM1",solar,101,energylasthour,energy last hour,uint24,Wh,false,sensor.solar_energy_last_hour,sensor.solar_energylasthour,8,0,1/10,13,2
@@ -5506,7 +5506,7 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"ISM2",solar,103,cylmaxtemp,maximum cylinder temperature,uint8 (>=0<=0),C,true,number.solar_maximum_cylinder_temperature,number.solar_cylmaxtemp,8,0,1,5,1
"ISM2",solar,103,collectorshutdown,collector shutdown,boolean, ,false,binary_sensor.solar_collector_shutdown,binary_sensor.solar_collectorshutdown,8,0,1,6,1
"ISM2",solar,103,cylheated,cyl heated,boolean, ,false,binary_sensor.solar_cyl_heated,binary_sensor.solar_cylheated,8,0,1,7,1
-"ISM2",solar,103,cylmiddletemp,cylinder middle temperature (TS3),int16,C,false,sensor.solar_cylinder_middle_temperature_(TS3),sensor.solar_cylmiddletemp,8,0,1/10,17,1
+"ISM2",solar,103,cylmiddletemp,cylinder middle temperature (TS14),int16,C,false,sensor.solar_cylinder_middle_temperature_(TS14),sensor.solar_cylmiddletemp,8,0,1/10,17,1
"ISM2",solar,103,retheatassist,return temperature heat assistance (TS4),int16,C,false,sensor.solar_return_temperature_heat_assistance_(TS4),sensor.solar_retheatassist,8,0,1/10,18,1
"ISM2",solar,103,heatassistvalve,heat assistance valve (M1),boolean, ,false,binary_sensor.solar_heat_assistance_valve_(M1),binary_sensor.solar_heatassistvalve,8,0,1,19,1
"ISM2",solar,103,energylasthour,energy last hour,uint24,Wh,false,sensor.solar_energy_last_hour,sensor.solar_energylasthour,8,0,1/10,13,2
@@ -5522,57 +5522,58 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"SM50",solar,162,turnondiff,pump turn on difference,uint8 (>=0<=0),C,true,number.solar_pump_turn_on_difference,number.solar_turnondiff,8,0,1/10,10,1
"SM50",solar,162,turnoffdiff,pump turn off difference,uint8 (>=0<=0),C,true,number.solar_pump_turn_off_difference,number.solar_turnoffdiff,8,0,1/10,11,1
"SM50",solar,162,collector2temp,collector 2 temperature (TS7),int16,C,false,sensor.solar_collector_2_temperature_(TS7),sensor.solar_collector2temp,8,0,1/10,20,1
-"SM50",solar,162,cylmiddletemp,cylinder middle temperature (TS3),int16,C,false,sensor.solar_cylinder_middle_temperature_(TS3),sensor.solar_cylmiddletemp,8,0,1/10,17,1
+"SM50",solar,162,cylmiddletemp,cylinder middle temperature (TS14),int16,C,false,sensor.solar_cylinder_middle_temperature_(TS14),sensor.solar_cylmiddletemp,8,0,1/10,17,1
+"SM50",solar,162,ts3,cylinder middle temperature (TS3),int16,C,false,sensor.solar_cylinder_middle_temperature_(TS3),sensor.solar_ts3,8,0,1/10,21,1
"SM50",solar,162,retheatassist,return temperature heat assistance (TS4),int16,C,false,sensor.solar_return_temperature_heat_assistance_(TS4),sensor.solar_retheatassist,8,0,1/10,18,1
-"SM50",solar,162,ts8,(TS8),int16,C,false,sensor.solar_(TS8),sensor.solar_ts8,8,0,1/10,21,1
-"SM50",solar,162,ts16,(TS16),int16,C,false,sensor.solar_(TS16),sensor.solar_ts16,8,0,1/10,22,1
+"SM50",solar,162,ts8,(TS8),int16,C,false,sensor.solar_(TS8),sensor.solar_ts8,8,0,1/10,22,1
+"SM50",solar,162,ts16,(TS16),int16,C,false,sensor.solar_(TS16),sensor.solar_ts16,8,0,1/10,23,1
"SM50",solar,162,heatassistvalve,heat assistance valve (M1),boolean, ,false,binary_sensor.solar_heat_assistance_valve_(M1),binary_sensor.solar_heatassistvalve,8,0,1,19,1
-"SM50",solar,162,heatassistpower,heat assistance valve power (M1),uint8,%,false,sensor.solar_heat_assistance_valve_power_(M1),sensor.solar_heatassistpower,8,0,1,23,1
-"SM50",solar,162,solarpump2,pump 2 (PS4),boolean, ,false,binary_sensor.solar_pump_2_(PS4),binary_sensor.solar_solarpump2,8,0,1,24,1
-"SM50",solar,162,solarpump2mod,pump 2 modulation (PS4),uint8,%,false,sensor.solar_pump_2_modulation_(PS4),sensor.solar_solarpump2mod,8,0,1,25,1
-"SM50",solar,162,cyl2bottomtemp,second cylinder bottom temperature (TS5),int16,C,false,sensor.solar_second_cylinder_bottom_temperature_(TS5),sensor.solar_cyl2bottomtemp,8,0,1/10,26,1
-"SM50",solar,162,cyl3bottomtemp,third cylinder bottom temperature (TS11),int16,C,false,sensor.solar_third_cylinder_bottom_temperature_(TS11),sensor.solar_cyl3bottomtemp,8,0,1/10,27,1
-"SM50",solar,162,cyltoptemp,cylinder top temperature (TS10),int16,C,false,sensor.solar_cylinder_top_temperature_(TS10),sensor.solar_cyltoptemp,8,0,1/10,28,1
-"SM50",solar,162,heatexchangertemp,heat exchanger temperature (TS6),int16,C,false,sensor.solar_heat_exchanger_temperature_(TS6),sensor.solar_heatexchangertemp,8,0,1/10,29,1
-"SM50",solar,162,cylpumpmod,cylinder pump modulation (PS5),uint8,%,false,sensor.solar_cylinder_pump_modulation_(PS5),sensor.solar_cylpumpmod,8,0,1,30,1
-"SM50",solar,162,valvestatus,valve status,boolean, ,false,binary_sensor.solar_valve_status,binary_sensor.solar_valvestatus,8,0,1,31,1
-"SM50",solar,162,vs1status,valve status VS1,boolean, ,false,binary_sensor.solar_valve_status_VS1,binary_sensor.solar_vs1status,8,0,1,32,1
-"SM50",solar,162,vs3status,valve status VS3,boolean, ,false,binary_sensor.solar_valve_status_VS3,binary_sensor.solar_vs3status,8,0,1,33,1
-"SM50",solar,162,transferpump,transfer pump,boolean, ,false,binary_sensor.solar_transfer_pump,binary_sensor.solar_transferpump,8,0,1,34,1
-"SM50",solar,162,transferpumpmod,transfer pump modulation,uint8,%,false,sensor.solar_transfer_pump_modulation,sensor.solar_transferpumpmod,8,0,1,35,1
-"SM50",solar,162,collectormaxtemp,maximum collector temperature,uint8 (>=0<=0),C,true,number.solar_maximum_collector_temperature,number.solar_collectormaxtemp,8,0,1,36,1
-"SM50",solar,162,collectormintemp,minimum collector temperature,uint8 (>=0<=0),C,true,number.solar_minimum_collector_temperature,number.solar_collectormintemp,8,0,1,37,1
+"SM50",solar,162,heatassistpower,heat assistance valve power (M1),uint8,%,false,sensor.solar_heat_assistance_valve_power_(M1),sensor.solar_heatassistpower,8,0,1,24,1
+"SM50",solar,162,solarpump2,pump 2 (PS4),boolean, ,false,binary_sensor.solar_pump_2_(PS4),binary_sensor.solar_solarpump2,8,0,1,25,1
+"SM50",solar,162,solarpump2mod,pump 2 modulation (PS4),uint8,%,false,sensor.solar_pump_2_modulation_(PS4),sensor.solar_solarpump2mod,8,0,1,26,1
+"SM50",solar,162,cyl2bottomtemp,second cylinder bottom temperature (TS5),int16,C,false,sensor.solar_second_cylinder_bottom_temperature_(TS5),sensor.solar_cyl2bottomtemp,8,0,1/10,27,1
+"SM50",solar,162,cyl3bottomtemp,third cylinder bottom temperature (TS11),int16,C,false,sensor.solar_third_cylinder_bottom_temperature_(TS11),sensor.solar_cyl3bottomtemp,8,0,1/10,28,1
+"SM50",solar,162,cyltoptemp,cylinder top temperature (TS10),int16,C,false,sensor.solar_cylinder_top_temperature_(TS10),sensor.solar_cyltoptemp,8,0,1/10,29,1
+"SM50",solar,162,heatexchangertemp,heat exchanger temperature (TS6),int16,C,false,sensor.solar_heat_exchanger_temperature_(TS6),sensor.solar_heatexchangertemp,8,0,1/10,30,1
+"SM50",solar,162,cylpumpmod,cylinder pump modulation (PS5),uint8,%,false,sensor.solar_cylinder_pump_modulation_(PS5),sensor.solar_cylpumpmod,8,0,1,31,1
+"SM50",solar,162,valvestatus,valve status,boolean, ,false,binary_sensor.solar_valve_status,binary_sensor.solar_valvestatus,8,0,1,32,1
+"SM50",solar,162,vs1status,valve status VS1,boolean, ,false,binary_sensor.solar_valve_status_VS1,binary_sensor.solar_vs1status,8,0,1,33,1
+"SM50",solar,162,vs3status,valve status VS3,boolean, ,false,binary_sensor.solar_valve_status_VS3,binary_sensor.solar_vs3status,8,0,1,34,1
+"SM50",solar,162,transferpump,transfer pump,boolean, ,false,binary_sensor.solar_transfer_pump,binary_sensor.solar_transferpump,8,0,1,35,1
+"SM50",solar,162,transferpumpmod,transfer pump modulation,uint8,%,false,sensor.solar_transfer_pump_modulation,sensor.solar_transferpumpmod,8,0,1,36,1
+"SM50",solar,162,collectormaxtemp,maximum collector temperature,uint8 (>=0<=0),C,true,number.solar_maximum_collector_temperature,number.solar_collectormaxtemp,8,0,1,37,1
+"SM50",solar,162,collectormintemp,minimum collector temperature,uint8 (>=0<=0),C,true,number.solar_minimum_collector_temperature,number.solar_collectormintemp,8,0,1,38,1
"SM50",solar,162,energylasthour,energy last hour,uint24,Wh,false,sensor.solar_energy_last_hour,sensor.solar_energylasthour,8,0,1/10,13,2
-"SM50",solar,162,energytoday,total energy today,uint24,Wh,false,sensor.solar_total_energy_today,sensor.solar_energytoday,8,0,1,38,2
-"SM50",solar,162,energytotal,total energy,uint24,kWh,false,sensor.solar_total_energy,sensor.solar_energytotal,8,0,1/10,40,2
-"SM50",solar,162,pump2worktime,pump 2 working time,time,minutes,false,sensor.solar_pump_2_working_time,sensor.solar_pump2worktime,8,0,1,42,2
-"SM50",solar,162,m1worktime,differential control working time,time,minutes,false,sensor.solar_differential_control_working_time,sensor.solar_m1worktime,8,0,1,44,2
-"SM50",solar,162,heattransfersystem,heattransfer system,boolean (>=0<=0), ,true,switch.solar_heattransfer_system,switch.solar_heattransfersystem,8,0,1,46,1
-"SM50",solar,162,externalcyl,external cylinder,boolean (>=0<=0), ,true,switch.solar_external_cylinder,switch.solar_externalcyl,8,0,1,47,1
-"SM50",solar,162,thermaldisinfect,thermal disinfection,boolean (>=0<=0), ,true,switch.solar_thermal_disinfection,switch.solar_thermaldisinfect,8,0,1,48,1
-"SM50",solar,162,heatmetering,heatmetering,boolean (>=0<=0), ,true,switch.solar_heatmetering,switch.solar_heatmetering,8,0,1,49,1
-"SM50",solar,162,activated,activated,boolean (>=0<=0), ,true,switch.solar_activated,switch.solar_activated,8,0,1,50,1
-"SM50",solar,162,solarpumpmode,solar pump mode,enum [constant\|pwm\|analog] (>=0<=0), ,true,select.solar_solar_pump_mode,select.solar_solarpumpmode,8,0,1,51,1
-"SM50",solar,162,solarpumpkick,solar pump kick,boolean (>=0<=0), ,true,switch.solar_solar_pump_kick,switch.solar_solarpumpkick,8,0,1,52,1
-"SM50",solar,162,plainwatermode,plain water mode,boolean (>=0<=0), ,true,switch.solar_plain_water_mode,switch.solar_plainwatermode,8,0,1,53,1
-"SM50",solar,162,doublematchflow,doublematchflow,boolean (>=0<=0), ,true,switch.solar_doublematchflow,switch.solar_doublematchflow,8,0,1,54,1
-"SM50",solar,162,pump2minmod,minimum pump 2 modulation,uint8 (>=0<=0),%,true,number.solar_minimum_pump_2_modulation,number.solar_pump2minmod,8,0,1,55,1
-"SM50",solar,162,turnondiff2,pump 2 turn on difference,uint8 (>=0<=0),C,true,number.solar_pump_2_turn_on_difference,number.solar_turnondiff2,8,0,1/10,56,1
-"SM50",solar,162,turnoffdiff2,pump 2 turn off difference,uint8 (>=0<=0),C,true,number.solar_pump_2_turn_off_difference,number.solar_turnoffdiff2,8,0,1/10,57,1
-"SM50",solar,162,pump2kick,pump kick 2,boolean (>=0<=0), ,true,switch.solar_pump_kick_2,switch.solar_pump2kick,8,0,1,58,1
-"SM50",solar,162,climatezone,climate zone,uint8 (>=0<=0), ,true,number.solar_climate_zone,number.solar_climatezone,8,0,1,59,1
-"SM50",solar,162,collector1area,collector 1 area,uint16 (>=0<=0),m²,true,number.solar_collector_1_area,number.solar_collector1area,8,0,1/10,60,1
-"SM50",solar,162,collector1type,collector 1 type,enum [flat\|vacuum] (>=0<=0), ,true,select.solar_collector_1_type,select.solar_collector1type,8,0,1,61,1
-"SM50",solar,162,collector2area,collector 2 area,uint16 (>=0<=0),m²,true,number.solar_collector_2_area,number.solar_collector2area,8,0,1/10,62,1
-"SM50",solar,162,collector2type,collector 2 type,enum [flat\|vacuum] (>=0<=0), ,true,select.solar_collector_2_type,select.solar_collector2type,8,0,1,63,1
-"SM50",solar,162,cylpriority,cylinder priority,enum [cyl 1\|cyl 2] (>=0<=0), ,true,select.solar_cylinder_priority,select.solar_cylpriority,8,0,1,64,1
-"SM50",solar,162,heatcntflowtemp,heat counter flow temperature,uint16,C,false,sensor.solar_heat_counter_flow_temperature,sensor.solar_heatcntflowtemp,8,0,1/10,65,1
-"SM50",solar,162,heatcntrettemp,heat counter return temperature,uint16,C,false,sensor.solar_heat_counter_return_temperature,sensor.solar_heatcntrettemp,8,0,1/10,66,1
-"SM50",solar,162,heatcnt,heat counter impulses,uint8, ,false,sensor.solar_heat_counter_impulses,sensor.solar_heatcnt,8,0,1,67,1
-"SM50",solar,162,swapflowtemp,swap flow temperature (TS14),uint16,C,false,sensor.solar_swap_flow_temperature_(TS14),sensor.solar_swapflowtemp,8,0,1/10,68,1
-"SM50",solar,162,swaprettemp,swap return temperature (TS15),uint16,C,false,sensor.solar_swap_return_temperature_(TS15),sensor.solar_swaprettemp,8,0,1/10,69,1
-"SM50",solar,162,heatassiston,heat assistance on,int8 (>=0<=0),K,true,number.solar_heat_assistance_on,number.solar_heatassiston,8,0,1/10,70,1
-"SM50",solar,162,heatassistoff,heat assistance off,int8 (>=0<=0),K,true,number.solar_heat_assistance_off,number.solar_heatassistoff,8,0,1/10,71,1
+"SM50",solar,162,energytoday,total energy today,uint24,Wh,false,sensor.solar_total_energy_today,sensor.solar_energytoday,8,0,1,39,2
+"SM50",solar,162,energytotal,total energy,uint24,kWh,false,sensor.solar_total_energy,sensor.solar_energytotal,8,0,1/10,41,2
+"SM50",solar,162,pump2worktime,pump 2 working time,time,minutes,false,sensor.solar_pump_2_working_time,sensor.solar_pump2worktime,8,0,1,43,2
+"SM50",solar,162,m1worktime,differential control working time,time,minutes,false,sensor.solar_differential_control_working_time,sensor.solar_m1worktime,8,0,1,45,2
+"SM50",solar,162,heattransfersystem,heattransfer system,boolean (>=0<=0), ,true,switch.solar_heattransfer_system,switch.solar_heattransfersystem,8,0,1,47,1
+"SM50",solar,162,externalcyl,external cylinder,boolean (>=0<=0), ,true,switch.solar_external_cylinder,switch.solar_externalcyl,8,0,1,48,1
+"SM50",solar,162,thermaldisinfect,thermal disinfection,boolean (>=0<=0), ,true,switch.solar_thermal_disinfection,switch.solar_thermaldisinfect,8,0,1,49,1
+"SM50",solar,162,heatmetering,heatmetering,boolean (>=0<=0), ,true,switch.solar_heatmetering,switch.solar_heatmetering,8,0,1,50,1
+"SM50",solar,162,activated,activated,boolean (>=0<=0), ,true,switch.solar_activated,switch.solar_activated,8,0,1,51,1
+"SM50",solar,162,solarpumpmode,solar pump mode,enum [constant\|pwm\|analog] (>=0<=0), ,true,select.solar_solar_pump_mode,select.solar_solarpumpmode,8,0,1,52,1
+"SM50",solar,162,solarpumpkick,solar pump kick,boolean (>=0<=0), ,true,switch.solar_solar_pump_kick,switch.solar_solarpumpkick,8,0,1,53,1
+"SM50",solar,162,plainwatermode,plain water mode,boolean (>=0<=0), ,true,switch.solar_plain_water_mode,switch.solar_plainwatermode,8,0,1,54,1
+"SM50",solar,162,doublematchflow,doublematchflow,boolean (>=0<=0), ,true,switch.solar_doublematchflow,switch.solar_doublematchflow,8,0,1,55,1
+"SM50",solar,162,pump2minmod,minimum pump 2 modulation,uint8 (>=0<=0),%,true,number.solar_minimum_pump_2_modulation,number.solar_pump2minmod,8,0,1,56,1
+"SM50",solar,162,turnondiff2,pump 2 turn on difference,uint8 (>=0<=0),C,true,number.solar_pump_2_turn_on_difference,number.solar_turnondiff2,8,0,1/10,57,1
+"SM50",solar,162,turnoffdiff2,pump 2 turn off difference,uint8 (>=0<=0),C,true,number.solar_pump_2_turn_off_difference,number.solar_turnoffdiff2,8,0,1/10,58,1
+"SM50",solar,162,pump2kick,pump kick 2,boolean (>=0<=0), ,true,switch.solar_pump_kick_2,switch.solar_pump2kick,8,0,1,59,1
+"SM50",solar,162,climatezone,climate zone,uint8 (>=0<=0), ,true,number.solar_climate_zone,number.solar_climatezone,8,0,1,60,1
+"SM50",solar,162,collector1area,collector 1 area,uint16 (>=0<=0),m²,true,number.solar_collector_1_area,number.solar_collector1area,8,0,1/10,61,1
+"SM50",solar,162,collector1type,collector 1 type,enum [flat\|vacuum] (>=0<=0), ,true,select.solar_collector_1_type,select.solar_collector1type,8,0,1,62,1
+"SM50",solar,162,collector2area,collector 2 area,uint16 (>=0<=0),m²,true,number.solar_collector_2_area,number.solar_collector2area,8,0,1/10,63,1
+"SM50",solar,162,collector2type,collector 2 type,enum [flat\|vacuum] (>=0<=0), ,true,select.solar_collector_2_type,select.solar_collector2type,8,0,1,64,1
+"SM50",solar,162,cylpriority,cylinder priority,enum [cyl 1\|cyl 2] (>=0<=0), ,true,select.solar_cylinder_priority,select.solar_cylpriority,8,0,1,65,1
+"SM50",solar,162,heatcntflowtemp,heat counter flow temperature,uint16,C,false,sensor.solar_heat_counter_flow_temperature,sensor.solar_heatcntflowtemp,8,0,1/10,66,1
+"SM50",solar,162,heatcntrettemp,heat counter return temperature,uint16,C,false,sensor.solar_heat_counter_return_temperature,sensor.solar_heatcntrettemp,8,0,1/10,67,1
+"SM50",solar,162,heatcnt,heat counter impulses,uint8, ,false,sensor.solar_heat_counter_impulses,sensor.solar_heatcnt,8,0,1,68,1
+"SM50",solar,162,swapflowtemp,swap flow temperature (TS14),uint16,C,false,sensor.solar_swap_flow_temperature_(TS14),sensor.solar_swapflowtemp,8,0,1/10,69,1
+"SM50",solar,162,swaprettemp,swap return temperature (TS15),uint16,C,false,sensor.solar_swap_return_temperature_(TS15),sensor.solar_swaprettemp,8,0,1/10,70,1
+"SM50",solar,162,heatassiston,heat assistance on,int8 (>=0<=0),K,true,number.solar_heat_assistance_on,number.solar_heatassiston,8,0,1/10,71,1
+"SM50",solar,162,heatassistoff,heat assistance off,int8 (>=0<=0),K,true,number.solar_heat_assistance_off,number.solar_heatassistoff,8,0,1/10,72,1
"SM100, MS100",solar,163,collectortemp,collector temperature (TS1),int16,C,false,sensor.solar_collector_temperature_(TS1),sensor.solar_collectortemp,8,0,1/10,0,1
"SM100, MS100",solar,163,cylbottomtemp,cylinder bottom temperature (TS2),int16,C,false,sensor.solar_cylinder_bottom_temperature_(TS2),sensor.solar_cylbottomtemp,8,0,1/10,1,1
"SM100, MS100",solar,163,solarpump,pump (PS1),boolean, ,false,binary_sensor.solar_pump_(PS1),binary_sensor.solar_solarpump,8,0,1,2,1
@@ -5585,57 +5586,58 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"SM100, MS100",solar,163,turnondiff,pump turn on difference,uint8 (>=0<=0),C,true,number.solar_pump_turn_on_difference,number.solar_turnondiff,8,0,1/10,10,1
"SM100, MS100",solar,163,turnoffdiff,pump turn off difference,uint8 (>=0<=0),C,true,number.solar_pump_turn_off_difference,number.solar_turnoffdiff,8,0,1/10,11,1
"SM100, MS100",solar,163,collector2temp,collector 2 temperature (TS7),int16,C,false,sensor.solar_collector_2_temperature_(TS7),sensor.solar_collector2temp,8,0,1/10,20,1
-"SM100, MS100",solar,163,cylmiddletemp,cylinder middle temperature (TS3),int16,C,false,sensor.solar_cylinder_middle_temperature_(TS3),sensor.solar_cylmiddletemp,8,0,1/10,17,1
+"SM100, MS100",solar,163,cylmiddletemp,cylinder middle temperature (TS14),int16,C,false,sensor.solar_cylinder_middle_temperature_(TS14),sensor.solar_cylmiddletemp,8,0,1/10,17,1
+"SM100, MS100",solar,163,ts3,cylinder middle temperature (TS3),int16,C,false,sensor.solar_cylinder_middle_temperature_(TS3),sensor.solar_ts3,8,0,1/10,21,1
"SM100, MS100",solar,163,retheatassist,return temperature heat assistance (TS4),int16,C,false,sensor.solar_return_temperature_heat_assistance_(TS4),sensor.solar_retheatassist,8,0,1/10,18,1
-"SM100, MS100",solar,163,ts8,(TS8),int16,C,false,sensor.solar_(TS8),sensor.solar_ts8,8,0,1/10,21,1
-"SM100, MS100",solar,163,ts16,(TS16),int16,C,false,sensor.solar_(TS16),sensor.solar_ts16,8,0,1/10,22,1
+"SM100, MS100",solar,163,ts8,(TS8),int16,C,false,sensor.solar_(TS8),sensor.solar_ts8,8,0,1/10,22,1
+"SM100, MS100",solar,163,ts16,(TS16),int16,C,false,sensor.solar_(TS16),sensor.solar_ts16,8,0,1/10,23,1
"SM100, MS100",solar,163,heatassistvalve,heat assistance valve (M1),boolean, ,false,binary_sensor.solar_heat_assistance_valve_(M1),binary_sensor.solar_heatassistvalve,8,0,1,19,1
-"SM100, MS100",solar,163,heatassistpower,heat assistance valve power (M1),uint8,%,false,sensor.solar_heat_assistance_valve_power_(M1),sensor.solar_heatassistpower,8,0,1,23,1
-"SM100, MS100",solar,163,solarpump2,pump 2 (PS4),boolean, ,false,binary_sensor.solar_pump_2_(PS4),binary_sensor.solar_solarpump2,8,0,1,24,1
-"SM100, MS100",solar,163,solarpump2mod,pump 2 modulation (PS4),uint8,%,false,sensor.solar_pump_2_modulation_(PS4),sensor.solar_solarpump2mod,8,0,1,25,1
-"SM100, MS100",solar,163,cyl2bottomtemp,second cylinder bottom temperature (TS5),int16,C,false,sensor.solar_second_cylinder_bottom_temperature_(TS5),sensor.solar_cyl2bottomtemp,8,0,1/10,26,1
-"SM100, MS100",solar,163,cyl3bottomtemp,third cylinder bottom temperature (TS11),int16,C,false,sensor.solar_third_cylinder_bottom_temperature_(TS11),sensor.solar_cyl3bottomtemp,8,0,1/10,27,1
-"SM100, MS100",solar,163,cyltoptemp,cylinder top temperature (TS10),int16,C,false,sensor.solar_cylinder_top_temperature_(TS10),sensor.solar_cyltoptemp,8,0,1/10,28,1
-"SM100, MS100",solar,163,heatexchangertemp,heat exchanger temperature (TS6),int16,C,false,sensor.solar_heat_exchanger_temperature_(TS6),sensor.solar_heatexchangertemp,8,0,1/10,29,1
-"SM100, MS100",solar,163,cylpumpmod,cylinder pump modulation (PS5),uint8,%,false,sensor.solar_cylinder_pump_modulation_(PS5),sensor.solar_cylpumpmod,8,0,1,30,1
-"SM100, MS100",solar,163,valvestatus,valve status,boolean, ,false,binary_sensor.solar_valve_status,binary_sensor.solar_valvestatus,8,0,1,31,1
-"SM100, MS100",solar,163,vs1status,valve status VS1,boolean, ,false,binary_sensor.solar_valve_status_VS1,binary_sensor.solar_vs1status,8,0,1,32,1
-"SM100, MS100",solar,163,vs3status,valve status VS3,boolean, ,false,binary_sensor.solar_valve_status_VS3,binary_sensor.solar_vs3status,8,0,1,33,1
-"SM100, MS100",solar,163,transferpump,transfer pump,boolean, ,false,binary_sensor.solar_transfer_pump,binary_sensor.solar_transferpump,8,0,1,34,1
-"SM100, MS100",solar,163,transferpumpmod,transfer pump modulation,uint8,%,false,sensor.solar_transfer_pump_modulation,sensor.solar_transferpumpmod,8,0,1,35,1
-"SM100, MS100",solar,163,collectormaxtemp,maximum collector temperature,uint8 (>=0<=0),C,true,number.solar_maximum_collector_temperature,number.solar_collectormaxtemp,8,0,1,36,1
-"SM100, MS100",solar,163,collectormintemp,minimum collector temperature,uint8 (>=0<=0),C,true,number.solar_minimum_collector_temperature,number.solar_collectormintemp,8,0,1,37,1
+"SM100, MS100",solar,163,heatassistpower,heat assistance valve power (M1),uint8,%,false,sensor.solar_heat_assistance_valve_power_(M1),sensor.solar_heatassistpower,8,0,1,24,1
+"SM100, MS100",solar,163,solarpump2,pump 2 (PS4),boolean, ,false,binary_sensor.solar_pump_2_(PS4),binary_sensor.solar_solarpump2,8,0,1,25,1
+"SM100, MS100",solar,163,solarpump2mod,pump 2 modulation (PS4),uint8,%,false,sensor.solar_pump_2_modulation_(PS4),sensor.solar_solarpump2mod,8,0,1,26,1
+"SM100, MS100",solar,163,cyl2bottomtemp,second cylinder bottom temperature (TS5),int16,C,false,sensor.solar_second_cylinder_bottom_temperature_(TS5),sensor.solar_cyl2bottomtemp,8,0,1/10,27,1
+"SM100, MS100",solar,163,cyl3bottomtemp,third cylinder bottom temperature (TS11),int16,C,false,sensor.solar_third_cylinder_bottom_temperature_(TS11),sensor.solar_cyl3bottomtemp,8,0,1/10,28,1
+"SM100, MS100",solar,163,cyltoptemp,cylinder top temperature (TS10),int16,C,false,sensor.solar_cylinder_top_temperature_(TS10),sensor.solar_cyltoptemp,8,0,1/10,29,1
+"SM100, MS100",solar,163,heatexchangertemp,heat exchanger temperature (TS6),int16,C,false,sensor.solar_heat_exchanger_temperature_(TS6),sensor.solar_heatexchangertemp,8,0,1/10,30,1
+"SM100, MS100",solar,163,cylpumpmod,cylinder pump modulation (PS5),uint8,%,false,sensor.solar_cylinder_pump_modulation_(PS5),sensor.solar_cylpumpmod,8,0,1,31,1
+"SM100, MS100",solar,163,valvestatus,valve status,boolean, ,false,binary_sensor.solar_valve_status,binary_sensor.solar_valvestatus,8,0,1,32,1
+"SM100, MS100",solar,163,vs1status,valve status VS1,boolean, ,false,binary_sensor.solar_valve_status_VS1,binary_sensor.solar_vs1status,8,0,1,33,1
+"SM100, MS100",solar,163,vs3status,valve status VS3,boolean, ,false,binary_sensor.solar_valve_status_VS3,binary_sensor.solar_vs3status,8,0,1,34,1
+"SM100, MS100",solar,163,transferpump,transfer pump,boolean, ,false,binary_sensor.solar_transfer_pump,binary_sensor.solar_transferpump,8,0,1,35,1
+"SM100, MS100",solar,163,transferpumpmod,transfer pump modulation,uint8,%,false,sensor.solar_transfer_pump_modulation,sensor.solar_transferpumpmod,8,0,1,36,1
+"SM100, MS100",solar,163,collectormaxtemp,maximum collector temperature,uint8 (>=0<=0),C,true,number.solar_maximum_collector_temperature,number.solar_collectormaxtemp,8,0,1,37,1
+"SM100, MS100",solar,163,collectormintemp,minimum collector temperature,uint8 (>=0<=0),C,true,number.solar_minimum_collector_temperature,number.solar_collectormintemp,8,0,1,38,1
"SM100, MS100",solar,163,energylasthour,energy last hour,uint24,Wh,false,sensor.solar_energy_last_hour,sensor.solar_energylasthour,8,0,1/10,13,2
-"SM100, MS100",solar,163,energytoday,total energy today,uint24,Wh,false,sensor.solar_total_energy_today,sensor.solar_energytoday,8,0,1,38,2
-"SM100, MS100",solar,163,energytotal,total energy,uint24,kWh,false,sensor.solar_total_energy,sensor.solar_energytotal,8,0,1/10,40,2
-"SM100, MS100",solar,163,pump2worktime,pump 2 working time,time,minutes,false,sensor.solar_pump_2_working_time,sensor.solar_pump2worktime,8,0,1,42,2
-"SM100, MS100",solar,163,m1worktime,differential control working time,time,minutes,false,sensor.solar_differential_control_working_time,sensor.solar_m1worktime,8,0,1,44,2
-"SM100, MS100",solar,163,heattransfersystem,heattransfer system,boolean (>=0<=0), ,true,switch.solar_heattransfer_system,switch.solar_heattransfersystem,8,0,1,46,1
-"SM100, MS100",solar,163,externalcyl,external cylinder,boolean (>=0<=0), ,true,switch.solar_external_cylinder,switch.solar_externalcyl,8,0,1,47,1
-"SM100, MS100",solar,163,thermaldisinfect,thermal disinfection,boolean (>=0<=0), ,true,switch.solar_thermal_disinfection,switch.solar_thermaldisinfect,8,0,1,48,1
-"SM100, MS100",solar,163,heatmetering,heatmetering,boolean (>=0<=0), ,true,switch.solar_heatmetering,switch.solar_heatmetering,8,0,1,49,1
-"SM100, MS100",solar,163,activated,activated,boolean (>=0<=0), ,true,switch.solar_activated,switch.solar_activated,8,0,1,50,1
-"SM100, MS100",solar,163,solarpumpmode,solar pump mode,enum [constant\|pwm\|analog] (>=0<=0), ,true,select.solar_solar_pump_mode,select.solar_solarpumpmode,8,0,1,51,1
-"SM100, MS100",solar,163,solarpumpkick,solar pump kick,boolean (>=0<=0), ,true,switch.solar_solar_pump_kick,switch.solar_solarpumpkick,8,0,1,52,1
-"SM100, MS100",solar,163,plainwatermode,plain water mode,boolean (>=0<=0), ,true,switch.solar_plain_water_mode,switch.solar_plainwatermode,8,0,1,53,1
-"SM100, MS100",solar,163,doublematchflow,doublematchflow,boolean (>=0<=0), ,true,switch.solar_doublematchflow,switch.solar_doublematchflow,8,0,1,54,1
-"SM100, MS100",solar,163,pump2minmod,minimum pump 2 modulation,uint8 (>=0<=0),%,true,number.solar_minimum_pump_2_modulation,number.solar_pump2minmod,8,0,1,55,1
-"SM100, MS100",solar,163,turnondiff2,pump 2 turn on difference,uint8 (>=0<=0),C,true,number.solar_pump_2_turn_on_difference,number.solar_turnondiff2,8,0,1/10,56,1
-"SM100, MS100",solar,163,turnoffdiff2,pump 2 turn off difference,uint8 (>=0<=0),C,true,number.solar_pump_2_turn_off_difference,number.solar_turnoffdiff2,8,0,1/10,57,1
-"SM100, MS100",solar,163,pump2kick,pump kick 2,boolean (>=0<=0), ,true,switch.solar_pump_kick_2,switch.solar_pump2kick,8,0,1,58,1
-"SM100, MS100",solar,163,climatezone,climate zone,uint8 (>=0<=0), ,true,number.solar_climate_zone,number.solar_climatezone,8,0,1,59,1
-"SM100, MS100",solar,163,collector1area,collector 1 area,uint16 (>=0<=0),m²,true,number.solar_collector_1_area,number.solar_collector1area,8,0,1/10,60,1
-"SM100, MS100",solar,163,collector1type,collector 1 type,enum [flat\|vacuum] (>=0<=0), ,true,select.solar_collector_1_type,select.solar_collector1type,8,0,1,61,1
-"SM100, MS100",solar,163,collector2area,collector 2 area,uint16 (>=0<=0),m²,true,number.solar_collector_2_area,number.solar_collector2area,8,0,1/10,62,1
-"SM100, MS100",solar,163,collector2type,collector 2 type,enum [flat\|vacuum] (>=0<=0), ,true,select.solar_collector_2_type,select.solar_collector2type,8,0,1,63,1
-"SM100, MS100",solar,163,cylpriority,cylinder priority,enum [cyl 1\|cyl 2] (>=0<=0), ,true,select.solar_cylinder_priority,select.solar_cylpriority,8,0,1,64,1
-"SM100, MS100",solar,163,heatcntflowtemp,heat counter flow temperature,uint16,C,false,sensor.solar_heat_counter_flow_temperature,sensor.solar_heatcntflowtemp,8,0,1/10,65,1
-"SM100, MS100",solar,163,heatcntrettemp,heat counter return temperature,uint16,C,false,sensor.solar_heat_counter_return_temperature,sensor.solar_heatcntrettemp,8,0,1/10,66,1
-"SM100, MS100",solar,163,heatcnt,heat counter impulses,uint8, ,false,sensor.solar_heat_counter_impulses,sensor.solar_heatcnt,8,0,1,67,1
-"SM100, MS100",solar,163,swapflowtemp,swap flow temperature (TS14),uint16,C,false,sensor.solar_swap_flow_temperature_(TS14),sensor.solar_swapflowtemp,8,0,1/10,68,1
-"SM100, MS100",solar,163,swaprettemp,swap return temperature (TS15),uint16,C,false,sensor.solar_swap_return_temperature_(TS15),sensor.solar_swaprettemp,8,0,1/10,69,1
-"SM100, MS100",solar,163,heatassiston,heat assistance on,int8 (>=0<=0),K,true,number.solar_heat_assistance_on,number.solar_heatassiston,8,0,1/10,70,1
-"SM100, MS100",solar,163,heatassistoff,heat assistance off,int8 (>=0<=0),K,true,number.solar_heat_assistance_off,number.solar_heatassistoff,8,0,1/10,71,1
+"SM100, MS100",solar,163,energytoday,total energy today,uint24,Wh,false,sensor.solar_total_energy_today,sensor.solar_energytoday,8,0,1,39,2
+"SM100, MS100",solar,163,energytotal,total energy,uint24,kWh,false,sensor.solar_total_energy,sensor.solar_energytotal,8,0,1/10,41,2
+"SM100, MS100",solar,163,pump2worktime,pump 2 working time,time,minutes,false,sensor.solar_pump_2_working_time,sensor.solar_pump2worktime,8,0,1,43,2
+"SM100, MS100",solar,163,m1worktime,differential control working time,time,minutes,false,sensor.solar_differential_control_working_time,sensor.solar_m1worktime,8,0,1,45,2
+"SM100, MS100",solar,163,heattransfersystem,heattransfer system,boolean (>=0<=0), ,true,switch.solar_heattransfer_system,switch.solar_heattransfersystem,8,0,1,47,1
+"SM100, MS100",solar,163,externalcyl,external cylinder,boolean (>=0<=0), ,true,switch.solar_external_cylinder,switch.solar_externalcyl,8,0,1,48,1
+"SM100, MS100",solar,163,thermaldisinfect,thermal disinfection,boolean (>=0<=0), ,true,switch.solar_thermal_disinfection,switch.solar_thermaldisinfect,8,0,1,49,1
+"SM100, MS100",solar,163,heatmetering,heatmetering,boolean (>=0<=0), ,true,switch.solar_heatmetering,switch.solar_heatmetering,8,0,1,50,1
+"SM100, MS100",solar,163,activated,activated,boolean (>=0<=0), ,true,switch.solar_activated,switch.solar_activated,8,0,1,51,1
+"SM100, MS100",solar,163,solarpumpmode,solar pump mode,enum [constant\|pwm\|analog] (>=0<=0), ,true,select.solar_solar_pump_mode,select.solar_solarpumpmode,8,0,1,52,1
+"SM100, MS100",solar,163,solarpumpkick,solar pump kick,boolean (>=0<=0), ,true,switch.solar_solar_pump_kick,switch.solar_solarpumpkick,8,0,1,53,1
+"SM100, MS100",solar,163,plainwatermode,plain water mode,boolean (>=0<=0), ,true,switch.solar_plain_water_mode,switch.solar_plainwatermode,8,0,1,54,1
+"SM100, MS100",solar,163,doublematchflow,doublematchflow,boolean (>=0<=0), ,true,switch.solar_doublematchflow,switch.solar_doublematchflow,8,0,1,55,1
+"SM100, MS100",solar,163,pump2minmod,minimum pump 2 modulation,uint8 (>=0<=0),%,true,number.solar_minimum_pump_2_modulation,number.solar_pump2minmod,8,0,1,56,1
+"SM100, MS100",solar,163,turnondiff2,pump 2 turn on difference,uint8 (>=0<=0),C,true,number.solar_pump_2_turn_on_difference,number.solar_turnondiff2,8,0,1/10,57,1
+"SM100, MS100",solar,163,turnoffdiff2,pump 2 turn off difference,uint8 (>=0<=0),C,true,number.solar_pump_2_turn_off_difference,number.solar_turnoffdiff2,8,0,1/10,58,1
+"SM100, MS100",solar,163,pump2kick,pump kick 2,boolean (>=0<=0), ,true,switch.solar_pump_kick_2,switch.solar_pump2kick,8,0,1,59,1
+"SM100, MS100",solar,163,climatezone,climate zone,uint8 (>=0<=0), ,true,number.solar_climate_zone,number.solar_climatezone,8,0,1,60,1
+"SM100, MS100",solar,163,collector1area,collector 1 area,uint16 (>=0<=0),m²,true,number.solar_collector_1_area,number.solar_collector1area,8,0,1/10,61,1
+"SM100, MS100",solar,163,collector1type,collector 1 type,enum [flat\|vacuum] (>=0<=0), ,true,select.solar_collector_1_type,select.solar_collector1type,8,0,1,62,1
+"SM100, MS100",solar,163,collector2area,collector 2 area,uint16 (>=0<=0),m²,true,number.solar_collector_2_area,number.solar_collector2area,8,0,1/10,63,1
+"SM100, MS100",solar,163,collector2type,collector 2 type,enum [flat\|vacuum] (>=0<=0), ,true,select.solar_collector_2_type,select.solar_collector2type,8,0,1,64,1
+"SM100, MS100",solar,163,cylpriority,cylinder priority,enum [cyl 1\|cyl 2] (>=0<=0), ,true,select.solar_cylinder_priority,select.solar_cylpriority,8,0,1,65,1
+"SM100, MS100",solar,163,heatcntflowtemp,heat counter flow temperature,uint16,C,false,sensor.solar_heat_counter_flow_temperature,sensor.solar_heatcntflowtemp,8,0,1/10,66,1
+"SM100, MS100",solar,163,heatcntrettemp,heat counter return temperature,uint16,C,false,sensor.solar_heat_counter_return_temperature,sensor.solar_heatcntrettemp,8,0,1/10,67,1
+"SM100, MS100",solar,163,heatcnt,heat counter impulses,uint8, ,false,sensor.solar_heat_counter_impulses,sensor.solar_heatcnt,8,0,1,68,1
+"SM100, MS100",solar,163,swapflowtemp,swap flow temperature (TS14),uint16,C,false,sensor.solar_swap_flow_temperature_(TS14),sensor.solar_swapflowtemp,8,0,1/10,69,1
+"SM100, MS100",solar,163,swaprettemp,swap return temperature (TS15),uint16,C,false,sensor.solar_swap_return_temperature_(TS15),sensor.solar_swaprettemp,8,0,1/10,70,1
+"SM100, MS100",solar,163,heatassiston,heat assistance on,int8 (>=0<=0),K,true,number.solar_heat_assistance_on,number.solar_heatassiston,8,0,1/10,71,1
+"SM100, MS100",solar,163,heatassistoff,heat assistance off,int8 (>=0<=0),K,true,number.solar_heat_assistance_off,number.solar_heatassistoff,8,0,1/10,72,1
"SM200, MS200",solar,164,collectortemp,collector temperature (TS1),int16,C,false,sensor.solar_collector_temperature_(TS1),sensor.solar_collectortemp,8,0,1/10,0,1
"SM200, MS200",solar,164,cylbottomtemp,cylinder bottom temperature (TS2),int16,C,false,sensor.solar_cylinder_bottom_temperature_(TS2),sensor.solar_cylbottomtemp,8,0,1/10,1,1
"SM200, MS200",solar,164,solarpump,pump (PS1),boolean, ,false,binary_sensor.solar_pump_(PS1),binary_sensor.solar_solarpump,8,0,1,2,1
@@ -5648,57 +5650,58 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"SM200, MS200",solar,164,turnondiff,pump turn on difference,uint8 (>=0<=0),C,true,number.solar_pump_turn_on_difference,number.solar_turnondiff,8,0,1/10,10,1
"SM200, MS200",solar,164,turnoffdiff,pump turn off difference,uint8 (>=0<=0),C,true,number.solar_pump_turn_off_difference,number.solar_turnoffdiff,8,0,1/10,11,1
"SM200, MS200",solar,164,collector2temp,collector 2 temperature (TS7),int16,C,false,sensor.solar_collector_2_temperature_(TS7),sensor.solar_collector2temp,8,0,1/10,20,1
-"SM200, MS200",solar,164,cylmiddletemp,cylinder middle temperature (TS3),int16,C,false,sensor.solar_cylinder_middle_temperature_(TS3),sensor.solar_cylmiddletemp,8,0,1/10,17,1
+"SM200, MS200",solar,164,cylmiddletemp,cylinder middle temperature (TS14),int16,C,false,sensor.solar_cylinder_middle_temperature_(TS14),sensor.solar_cylmiddletemp,8,0,1/10,17,1
+"SM200, MS200",solar,164,ts3,cylinder middle temperature (TS3),int16,C,false,sensor.solar_cylinder_middle_temperature_(TS3),sensor.solar_ts3,8,0,1/10,21,1
"SM200, MS200",solar,164,retheatassist,return temperature heat assistance (TS4),int16,C,false,sensor.solar_return_temperature_heat_assistance_(TS4),sensor.solar_retheatassist,8,0,1/10,18,1
-"SM200, MS200",solar,164,ts8,(TS8),int16,C,false,sensor.solar_(TS8),sensor.solar_ts8,8,0,1/10,21,1
-"SM200, MS200",solar,164,ts16,(TS16),int16,C,false,sensor.solar_(TS16),sensor.solar_ts16,8,0,1/10,22,1
+"SM200, MS200",solar,164,ts8,(TS8),int16,C,false,sensor.solar_(TS8),sensor.solar_ts8,8,0,1/10,22,1
+"SM200, MS200",solar,164,ts16,(TS16),int16,C,false,sensor.solar_(TS16),sensor.solar_ts16,8,0,1/10,23,1
"SM200, MS200",solar,164,heatassistvalve,heat assistance valve (M1),boolean, ,false,binary_sensor.solar_heat_assistance_valve_(M1),binary_sensor.solar_heatassistvalve,8,0,1,19,1
-"SM200, MS200",solar,164,heatassistpower,heat assistance valve power (M1),uint8,%,false,sensor.solar_heat_assistance_valve_power_(M1),sensor.solar_heatassistpower,8,0,1,23,1
-"SM200, MS200",solar,164,solarpump2,pump 2 (PS4),boolean, ,false,binary_sensor.solar_pump_2_(PS4),binary_sensor.solar_solarpump2,8,0,1,24,1
-"SM200, MS200",solar,164,solarpump2mod,pump 2 modulation (PS4),uint8,%,false,sensor.solar_pump_2_modulation_(PS4),sensor.solar_solarpump2mod,8,0,1,25,1
-"SM200, MS200",solar,164,cyl2bottomtemp,second cylinder bottom temperature (TS5),int16,C,false,sensor.solar_second_cylinder_bottom_temperature_(TS5),sensor.solar_cyl2bottomtemp,8,0,1/10,26,1
-"SM200, MS200",solar,164,cyl3bottomtemp,third cylinder bottom temperature (TS11),int16,C,false,sensor.solar_third_cylinder_bottom_temperature_(TS11),sensor.solar_cyl3bottomtemp,8,0,1/10,27,1
-"SM200, MS200",solar,164,cyltoptemp,cylinder top temperature (TS10),int16,C,false,sensor.solar_cylinder_top_temperature_(TS10),sensor.solar_cyltoptemp,8,0,1/10,28,1
-"SM200, MS200",solar,164,heatexchangertemp,heat exchanger temperature (TS6),int16,C,false,sensor.solar_heat_exchanger_temperature_(TS6),sensor.solar_heatexchangertemp,8,0,1/10,29,1
-"SM200, MS200",solar,164,cylpumpmod,cylinder pump modulation (PS5),uint8,%,false,sensor.solar_cylinder_pump_modulation_(PS5),sensor.solar_cylpumpmod,8,0,1,30,1
-"SM200, MS200",solar,164,valvestatus,valve status,boolean, ,false,binary_sensor.solar_valve_status,binary_sensor.solar_valvestatus,8,0,1,31,1
-"SM200, MS200",solar,164,vs1status,valve status VS1,boolean, ,false,binary_sensor.solar_valve_status_VS1,binary_sensor.solar_vs1status,8,0,1,32,1
-"SM200, MS200",solar,164,vs3status,valve status VS3,boolean, ,false,binary_sensor.solar_valve_status_VS3,binary_sensor.solar_vs3status,8,0,1,33,1
-"SM200, MS200",solar,164,transferpump,transfer pump,boolean, ,false,binary_sensor.solar_transfer_pump,binary_sensor.solar_transferpump,8,0,1,34,1
-"SM200, MS200",solar,164,transferpumpmod,transfer pump modulation,uint8,%,false,sensor.solar_transfer_pump_modulation,sensor.solar_transferpumpmod,8,0,1,35,1
-"SM200, MS200",solar,164,collectormaxtemp,maximum collector temperature,uint8 (>=0<=0),C,true,number.solar_maximum_collector_temperature,number.solar_collectormaxtemp,8,0,1,36,1
-"SM200, MS200",solar,164,collectormintemp,minimum collector temperature,uint8 (>=0<=0),C,true,number.solar_minimum_collector_temperature,number.solar_collectormintemp,8,0,1,37,1
+"SM200, MS200",solar,164,heatassistpower,heat assistance valve power (M1),uint8,%,false,sensor.solar_heat_assistance_valve_power_(M1),sensor.solar_heatassistpower,8,0,1,24,1
+"SM200, MS200",solar,164,solarpump2,pump 2 (PS4),boolean, ,false,binary_sensor.solar_pump_2_(PS4),binary_sensor.solar_solarpump2,8,0,1,25,1
+"SM200, MS200",solar,164,solarpump2mod,pump 2 modulation (PS4),uint8,%,false,sensor.solar_pump_2_modulation_(PS4),sensor.solar_solarpump2mod,8,0,1,26,1
+"SM200, MS200",solar,164,cyl2bottomtemp,second cylinder bottom temperature (TS5),int16,C,false,sensor.solar_second_cylinder_bottom_temperature_(TS5),sensor.solar_cyl2bottomtemp,8,0,1/10,27,1
+"SM200, MS200",solar,164,cyl3bottomtemp,third cylinder bottom temperature (TS11),int16,C,false,sensor.solar_third_cylinder_bottom_temperature_(TS11),sensor.solar_cyl3bottomtemp,8,0,1/10,28,1
+"SM200, MS200",solar,164,cyltoptemp,cylinder top temperature (TS10),int16,C,false,sensor.solar_cylinder_top_temperature_(TS10),sensor.solar_cyltoptemp,8,0,1/10,29,1
+"SM200, MS200",solar,164,heatexchangertemp,heat exchanger temperature (TS6),int16,C,false,sensor.solar_heat_exchanger_temperature_(TS6),sensor.solar_heatexchangertemp,8,0,1/10,30,1
+"SM200, MS200",solar,164,cylpumpmod,cylinder pump modulation (PS5),uint8,%,false,sensor.solar_cylinder_pump_modulation_(PS5),sensor.solar_cylpumpmod,8,0,1,31,1
+"SM200, MS200",solar,164,valvestatus,valve status,boolean, ,false,binary_sensor.solar_valve_status,binary_sensor.solar_valvestatus,8,0,1,32,1
+"SM200, MS200",solar,164,vs1status,valve status VS1,boolean, ,false,binary_sensor.solar_valve_status_VS1,binary_sensor.solar_vs1status,8,0,1,33,1
+"SM200, MS200",solar,164,vs3status,valve status VS3,boolean, ,false,binary_sensor.solar_valve_status_VS3,binary_sensor.solar_vs3status,8,0,1,34,1
+"SM200, MS200",solar,164,transferpump,transfer pump,boolean, ,false,binary_sensor.solar_transfer_pump,binary_sensor.solar_transferpump,8,0,1,35,1
+"SM200, MS200",solar,164,transferpumpmod,transfer pump modulation,uint8,%,false,sensor.solar_transfer_pump_modulation,sensor.solar_transferpumpmod,8,0,1,36,1
+"SM200, MS200",solar,164,collectormaxtemp,maximum collector temperature,uint8 (>=0<=0),C,true,number.solar_maximum_collector_temperature,number.solar_collectormaxtemp,8,0,1,37,1
+"SM200, MS200",solar,164,collectormintemp,minimum collector temperature,uint8 (>=0<=0),C,true,number.solar_minimum_collector_temperature,number.solar_collectormintemp,8,0,1,38,1
"SM200, MS200",solar,164,energylasthour,energy last hour,uint24,Wh,false,sensor.solar_energy_last_hour,sensor.solar_energylasthour,8,0,1/10,13,2
-"SM200, MS200",solar,164,energytoday,total energy today,uint24,Wh,false,sensor.solar_total_energy_today,sensor.solar_energytoday,8,0,1,38,2
-"SM200, MS200",solar,164,energytotal,total energy,uint24,kWh,false,sensor.solar_total_energy,sensor.solar_energytotal,8,0,1/10,40,2
-"SM200, MS200",solar,164,pump2worktime,pump 2 working time,time,minutes,false,sensor.solar_pump_2_working_time,sensor.solar_pump2worktime,8,0,1,42,2
-"SM200, MS200",solar,164,m1worktime,differential control working time,time,minutes,false,sensor.solar_differential_control_working_time,sensor.solar_m1worktime,8,0,1,44,2
-"SM200, MS200",solar,164,heattransfersystem,heattransfer system,boolean (>=0<=0), ,true,switch.solar_heattransfer_system,switch.solar_heattransfersystem,8,0,1,46,1
-"SM200, MS200",solar,164,externalcyl,external cylinder,boolean (>=0<=0), ,true,switch.solar_external_cylinder,switch.solar_externalcyl,8,0,1,47,1
-"SM200, MS200",solar,164,thermaldisinfect,thermal disinfection,boolean (>=0<=0), ,true,switch.solar_thermal_disinfection,switch.solar_thermaldisinfect,8,0,1,48,1
-"SM200, MS200",solar,164,heatmetering,heatmetering,boolean (>=0<=0), ,true,switch.solar_heatmetering,switch.solar_heatmetering,8,0,1,49,1
-"SM200, MS200",solar,164,activated,activated,boolean (>=0<=0), ,true,switch.solar_activated,switch.solar_activated,8,0,1,50,1
-"SM200, MS200",solar,164,solarpumpmode,solar pump mode,enum [constant\|pwm\|analog] (>=0<=0), ,true,select.solar_solar_pump_mode,select.solar_solarpumpmode,8,0,1,51,1
-"SM200, MS200",solar,164,solarpumpkick,solar pump kick,boolean (>=0<=0), ,true,switch.solar_solar_pump_kick,switch.solar_solarpumpkick,8,0,1,52,1
-"SM200, MS200",solar,164,plainwatermode,plain water mode,boolean (>=0<=0), ,true,switch.solar_plain_water_mode,switch.solar_plainwatermode,8,0,1,53,1
-"SM200, MS200",solar,164,doublematchflow,doublematchflow,boolean (>=0<=0), ,true,switch.solar_doublematchflow,switch.solar_doublematchflow,8,0,1,54,1
-"SM200, MS200",solar,164,pump2minmod,minimum pump 2 modulation,uint8 (>=0<=0),%,true,number.solar_minimum_pump_2_modulation,number.solar_pump2minmod,8,0,1,55,1
-"SM200, MS200",solar,164,turnondiff2,pump 2 turn on difference,uint8 (>=0<=0),C,true,number.solar_pump_2_turn_on_difference,number.solar_turnondiff2,8,0,1/10,56,1
-"SM200, MS200",solar,164,turnoffdiff2,pump 2 turn off difference,uint8 (>=0<=0),C,true,number.solar_pump_2_turn_off_difference,number.solar_turnoffdiff2,8,0,1/10,57,1
-"SM200, MS200",solar,164,pump2kick,pump kick 2,boolean (>=0<=0), ,true,switch.solar_pump_kick_2,switch.solar_pump2kick,8,0,1,58,1
-"SM200, MS200",solar,164,climatezone,climate zone,uint8 (>=0<=0), ,true,number.solar_climate_zone,number.solar_climatezone,8,0,1,59,1
-"SM200, MS200",solar,164,collector1area,collector 1 area,uint16 (>=0<=0),m²,true,number.solar_collector_1_area,number.solar_collector1area,8,0,1/10,60,1
-"SM200, MS200",solar,164,collector1type,collector 1 type,enum [flat\|vacuum] (>=0<=0), ,true,select.solar_collector_1_type,select.solar_collector1type,8,0,1,61,1
-"SM200, MS200",solar,164,collector2area,collector 2 area,uint16 (>=0<=0),m²,true,number.solar_collector_2_area,number.solar_collector2area,8,0,1/10,62,1
-"SM200, MS200",solar,164,collector2type,collector 2 type,enum [flat\|vacuum] (>=0<=0), ,true,select.solar_collector_2_type,select.solar_collector2type,8,0,1,63,1
-"SM200, MS200",solar,164,cylpriority,cylinder priority,enum [cyl 1\|cyl 2] (>=0<=0), ,true,select.solar_cylinder_priority,select.solar_cylpriority,8,0,1,64,1
-"SM200, MS200",solar,164,heatcntflowtemp,heat counter flow temperature,uint16,C,false,sensor.solar_heat_counter_flow_temperature,sensor.solar_heatcntflowtemp,8,0,1/10,65,1
-"SM200, MS200",solar,164,heatcntrettemp,heat counter return temperature,uint16,C,false,sensor.solar_heat_counter_return_temperature,sensor.solar_heatcntrettemp,8,0,1/10,66,1
-"SM200, MS200",solar,164,heatcnt,heat counter impulses,uint8, ,false,sensor.solar_heat_counter_impulses,sensor.solar_heatcnt,8,0,1,67,1
-"SM200, MS200",solar,164,swapflowtemp,swap flow temperature (TS14),uint16,C,false,sensor.solar_swap_flow_temperature_(TS14),sensor.solar_swapflowtemp,8,0,1/10,68,1
-"SM200, MS200",solar,164,swaprettemp,swap return temperature (TS15),uint16,C,false,sensor.solar_swap_return_temperature_(TS15),sensor.solar_swaprettemp,8,0,1/10,69,1
-"SM200, MS200",solar,164,heatassiston,heat assistance on,int8 (>=0<=0),K,true,number.solar_heat_assistance_on,number.solar_heatassiston,8,0,1/10,70,1
-"SM200, MS200",solar,164,heatassistoff,heat assistance off,int8 (>=0<=0),K,true,number.solar_heat_assistance_off,number.solar_heatassistoff,8,0,1/10,71,1
+"SM200, MS200",solar,164,energytoday,total energy today,uint24,Wh,false,sensor.solar_total_energy_today,sensor.solar_energytoday,8,0,1,39,2
+"SM200, MS200",solar,164,energytotal,total energy,uint24,kWh,false,sensor.solar_total_energy,sensor.solar_energytotal,8,0,1/10,41,2
+"SM200, MS200",solar,164,pump2worktime,pump 2 working time,time,minutes,false,sensor.solar_pump_2_working_time,sensor.solar_pump2worktime,8,0,1,43,2
+"SM200, MS200",solar,164,m1worktime,differential control working time,time,minutes,false,sensor.solar_differential_control_working_time,sensor.solar_m1worktime,8,0,1,45,2
+"SM200, MS200",solar,164,heattransfersystem,heattransfer system,boolean (>=0<=0), ,true,switch.solar_heattransfer_system,switch.solar_heattransfersystem,8,0,1,47,1
+"SM200, MS200",solar,164,externalcyl,external cylinder,boolean (>=0<=0), ,true,switch.solar_external_cylinder,switch.solar_externalcyl,8,0,1,48,1
+"SM200, MS200",solar,164,thermaldisinfect,thermal disinfection,boolean (>=0<=0), ,true,switch.solar_thermal_disinfection,switch.solar_thermaldisinfect,8,0,1,49,1
+"SM200, MS200",solar,164,heatmetering,heatmetering,boolean (>=0<=0), ,true,switch.solar_heatmetering,switch.solar_heatmetering,8,0,1,50,1
+"SM200, MS200",solar,164,activated,activated,boolean (>=0<=0), ,true,switch.solar_activated,switch.solar_activated,8,0,1,51,1
+"SM200, MS200",solar,164,solarpumpmode,solar pump mode,enum [constant\|pwm\|analog] (>=0<=0), ,true,select.solar_solar_pump_mode,select.solar_solarpumpmode,8,0,1,52,1
+"SM200, MS200",solar,164,solarpumpkick,solar pump kick,boolean (>=0<=0), ,true,switch.solar_solar_pump_kick,switch.solar_solarpumpkick,8,0,1,53,1
+"SM200, MS200",solar,164,plainwatermode,plain water mode,boolean (>=0<=0), ,true,switch.solar_plain_water_mode,switch.solar_plainwatermode,8,0,1,54,1
+"SM200, MS200",solar,164,doublematchflow,doublematchflow,boolean (>=0<=0), ,true,switch.solar_doublematchflow,switch.solar_doublematchflow,8,0,1,55,1
+"SM200, MS200",solar,164,pump2minmod,minimum pump 2 modulation,uint8 (>=0<=0),%,true,number.solar_minimum_pump_2_modulation,number.solar_pump2minmod,8,0,1,56,1
+"SM200, MS200",solar,164,turnondiff2,pump 2 turn on difference,uint8 (>=0<=0),C,true,number.solar_pump_2_turn_on_difference,number.solar_turnondiff2,8,0,1/10,57,1
+"SM200, MS200",solar,164,turnoffdiff2,pump 2 turn off difference,uint8 (>=0<=0),C,true,number.solar_pump_2_turn_off_difference,number.solar_turnoffdiff2,8,0,1/10,58,1
+"SM200, MS200",solar,164,pump2kick,pump kick 2,boolean (>=0<=0), ,true,switch.solar_pump_kick_2,switch.solar_pump2kick,8,0,1,59,1
+"SM200, MS200",solar,164,climatezone,climate zone,uint8 (>=0<=0), ,true,number.solar_climate_zone,number.solar_climatezone,8,0,1,60,1
+"SM200, MS200",solar,164,collector1area,collector 1 area,uint16 (>=0<=0),m²,true,number.solar_collector_1_area,number.solar_collector1area,8,0,1/10,61,1
+"SM200, MS200",solar,164,collector1type,collector 1 type,enum [flat\|vacuum] (>=0<=0), ,true,select.solar_collector_1_type,select.solar_collector1type,8,0,1,62,1
+"SM200, MS200",solar,164,collector2area,collector 2 area,uint16 (>=0<=0),m²,true,number.solar_collector_2_area,number.solar_collector2area,8,0,1/10,63,1
+"SM200, MS200",solar,164,collector2type,collector 2 type,enum [flat\|vacuum] (>=0<=0), ,true,select.solar_collector_2_type,select.solar_collector2type,8,0,1,64,1
+"SM200, MS200",solar,164,cylpriority,cylinder priority,enum [cyl 1\|cyl 2] (>=0<=0), ,true,select.solar_cylinder_priority,select.solar_cylpriority,8,0,1,65,1
+"SM200, MS200",solar,164,heatcntflowtemp,heat counter flow temperature,uint16,C,false,sensor.solar_heat_counter_flow_temperature,sensor.solar_heatcntflowtemp,8,0,1/10,66,1
+"SM200, MS200",solar,164,heatcntrettemp,heat counter return temperature,uint16,C,false,sensor.solar_heat_counter_return_temperature,sensor.solar_heatcntrettemp,8,0,1/10,67,1
+"SM200, MS200",solar,164,heatcnt,heat counter impulses,uint8, ,false,sensor.solar_heat_counter_impulses,sensor.solar_heatcnt,8,0,1,68,1
+"SM200, MS200",solar,164,swapflowtemp,swap flow temperature (TS14),uint16,C,false,sensor.solar_swap_flow_temperature_(TS14),sensor.solar_swapflowtemp,8,0,1/10,69,1
+"SM200, MS200",solar,164,swaprettemp,swap return temperature (TS15),uint16,C,false,sensor.solar_swap_return_temperature_(TS15),sensor.solar_swaprettemp,8,0,1/10,70,1
+"SM200, MS200",solar,164,heatassiston,heat assistance on,int8 (>=0<=0),K,true,number.solar_heat_assistance_on,number.solar_heatassiston,8,0,1/10,71,1
+"SM200, MS200",solar,164,heatassistoff,heat assistance off,int8 (>=0<=0),K,true,number.solar_heat_assistance_off,number.solar_heatassistoff,8,0,1/10,72,1
"HP Module",heatpump,252,airhumidity,relative air humidity,uint8,%,false,sensor.heatpump_relative_air_humidity,sensor.heatpump_airhumidity,9,0,1,0,1
"HP Module",heatpump,252,dewtemperature,dew point temperature,uint8,C,false,sensor.heatpump_dew_point_temperature,sensor.heatpump_dewtemperature,9,0,1,1,1
"HP Module",heatpump,252,curflowtemp,current flow temperature,int16,C,false,sensor.heatpump_current_flow_temperature,sensor.heatpump_curflowtemp,9,0,1/10,2,1
diff --git a/interface/package.json b/interface/package.json
index 07dcf3af2..f2a1dea0b 100644
--- a/interface/package.json
+++ b/interface/package.json
@@ -1,6 +1,6 @@
{
"name": "EMS-ESP",
- "version": "3.8.0",
+ "version": "3.8.2",
"description": "EMS-ESP WebUI",
"homepage": "https://emsesp.org",
"author": "proddy, emsesp.org",
@@ -44,7 +44,7 @@
"react-router": "^7.14.1",
"react-toastify": "^11.0.5",
"typesafe-i18n": "^5.27.1",
- "typescript": "^6.0.2"
+ "typescript": "^6.0.3"
},
"devDependencies": {
"@babel/core": "^7.29.0",
diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml
index 4ff491e52..9b6c0b7c5 100644
--- a/interface/pnpm-lock.yaml
+++ b/interface/pnpm-lock.yaml
@@ -70,10 +70,10 @@ importers:
version: 11.0.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
typesafe-i18n:
specifier: ^5.27.1
- version: 5.27.1(typescript@6.0.2)
+ version: 5.27.1(typescript@6.0.3)
typescript:
- specifier: ^6.0.2
- version: 6.0.2
+ specifier: ^6.0.3
+ version: 6.0.3
devDependencies:
'@babel/core':
specifier: ^7.29.0
@@ -119,7 +119,7 @@ importers:
version: 5.46.1
typescript-eslint:
specifier: ^8.58.2
- version: 8.58.2(eslint@10.2.0)(typescript@6.0.2)
+ version: 8.58.2(eslint@10.2.0)(typescript@6.0.3)
vite:
specifier: ^8.0.8
version: 8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1)
@@ -624,8 +624,8 @@ packages:
'@types/react':
optional: true
- '@napi-rs/wasm-runtime@1.1.3':
- resolution: {integrity: sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==}
+ '@napi-rs/wasm-runtime@1.1.4':
+ resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==}
peerDependencies:
'@emnapi/core': ^1.7.1
'@emnapi/runtime': ^1.7.1
@@ -1516,8 +1516,8 @@ packages:
duplexer3@0.1.5:
resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==}
- electron-to-chromium@1.5.336:
- resolution: {integrity: sha512-AbH9q9J455r/nLmdNZes0G0ZKcRX73FicwowalLs6ijwOmCJSRRrLX63lcAlzy9ux3dWK1w1+1nsBJEWN11hcQ==}
+ electron-to-chromium@1.5.340:
+ resolution: {integrity: sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==}
emoji-regex@10.6.0:
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
@@ -2711,8 +2711,8 @@ packages:
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
engines: {node: '>= 0.4'}
- postcss@8.5.9:
- resolution: {integrity: sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==}
+ postcss@8.5.10:
+ resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==}
engines: {node: ^10 || ^12 || >=14}
powershell-utils@0.1.0:
@@ -3197,8 +3197,8 @@ packages:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0'
- typescript@6.0.2:
- resolution: {integrity: sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==}
+ typescript@6.0.3:
+ resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==}
engines: {node: '>=14.17'}
hasBin: true
@@ -3849,7 +3849,7 @@ snapshots:
optionalDependencies:
'@types/react': 19.2.14
- '@napi-rs/wasm-runtime@1.1.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)':
+ '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)':
dependencies:
'@emnapi/core': 1.9.2
'@emnapi/runtime': 1.9.2
@@ -3961,7 +3961,7 @@ snapshots:
dependencies:
'@emnapi/core': 1.9.2
'@emnapi/runtime': 1.9.2
- '@napi-rs/wasm-runtime': 1.1.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)
+ '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)
optional: true
'@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15':
@@ -4166,40 +4166,40 @@ snapshots:
dependencies:
'@types/node': 25.6.0
- '@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2)':
+ '@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.3))(eslint@10.2.0)(typescript@6.0.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
- '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.2)
+ '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.3)
'@typescript-eslint/scope-manager': 8.58.2
- '@typescript-eslint/type-utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2)
- '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2)
+ '@typescript-eslint/type-utils': 8.58.2(eslint@10.2.0)(typescript@6.0.3)
+ '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.3)
'@typescript-eslint/visitor-keys': 8.58.2
eslint: 10.2.0
ignore: 7.0.5
natural-compare: 1.4.0
- ts-api-utils: 2.5.0(typescript@6.0.2)
- typescript: 6.0.2
+ ts-api-utils: 2.5.0(typescript@6.0.3)
+ typescript: 6.0.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2)':
+ '@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.58.2
'@typescript-eslint/types': 8.58.2
- '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2)
+ '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3)
'@typescript-eslint/visitor-keys': 8.58.2
debug: 4.4.3
eslint: 10.2.0
- typescript: 6.0.2
+ typescript: 6.0.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/project-service@8.58.2(typescript@6.0.2)':
+ '@typescript-eslint/project-service@8.58.2(typescript@6.0.3)':
dependencies:
- '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.2)
+ '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.3)
'@typescript-eslint/types': 8.58.2
debug: 4.4.3
- typescript: 6.0.2
+ typescript: 6.0.3
transitivePeerDependencies:
- supports-color
@@ -4208,47 +4208,47 @@ snapshots:
'@typescript-eslint/types': 8.58.2
'@typescript-eslint/visitor-keys': 8.58.2
- '@typescript-eslint/tsconfig-utils@8.58.2(typescript@6.0.2)':
+ '@typescript-eslint/tsconfig-utils@8.58.2(typescript@6.0.3)':
dependencies:
- typescript: 6.0.2
+ typescript: 6.0.3
- '@typescript-eslint/type-utils@8.58.2(eslint@10.2.0)(typescript@6.0.2)':
+ '@typescript-eslint/type-utils@8.58.2(eslint@10.2.0)(typescript@6.0.3)':
dependencies:
'@typescript-eslint/types': 8.58.2
- '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2)
- '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2)
+ '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3)
+ '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.3)
debug: 4.4.3
eslint: 10.2.0
- ts-api-utils: 2.5.0(typescript@6.0.2)
- typescript: 6.0.2
+ ts-api-utils: 2.5.0(typescript@6.0.3)
+ typescript: 6.0.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/types@8.58.2': {}
- '@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.2)':
+ '@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.3)':
dependencies:
- '@typescript-eslint/project-service': 8.58.2(typescript@6.0.2)
- '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.2)
+ '@typescript-eslint/project-service': 8.58.2(typescript@6.0.3)
+ '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.3)
'@typescript-eslint/types': 8.58.2
'@typescript-eslint/visitor-keys': 8.58.2
debug: 4.4.3
minimatch: 10.2.5
semver: 7.7.4
tinyglobby: 0.2.16
- ts-api-utils: 2.5.0(typescript@6.0.2)
- typescript: 6.0.2
+ ts-api-utils: 2.5.0(typescript@6.0.3)
+ typescript: 6.0.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/utils@8.58.2(eslint@10.2.0)(typescript@6.0.2)':
+ '@typescript-eslint/utils@8.58.2(eslint@10.2.0)(typescript@6.0.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0)
'@typescript-eslint/scope-manager': 8.58.2
'@typescript-eslint/types': 8.58.2
- '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2)
+ '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3)
eslint: 10.2.0
- typescript: 6.0.2
+ typescript: 6.0.3
transitivePeerDependencies:
- supports-color
@@ -4388,7 +4388,7 @@ snapshots:
dependencies:
baseline-browser-mapping: 2.10.19
caniuse-lite: 1.0.30001788
- electron-to-chromium: 1.5.336
+ electron-to-chromium: 1.5.340
node-releases: 2.0.37
update-browserslist-db: 1.2.3(browserslist@4.28.2)
@@ -4752,7 +4752,7 @@ snapshots:
duplexer3@0.1.5: {}
- electron-to-chromium@1.5.336: {}
+ electron-to-chromium@1.5.340: {}
emoji-regex@10.6.0: {}
@@ -5908,7 +5908,7 @@ snapshots:
possible-typed-array-names@1.1.0: {}
- postcss@8.5.9:
+ postcss@8.5.10:
dependencies:
nanoid: 3.3.11
picocolors: 1.1.1
@@ -6364,9 +6364,9 @@ snapshots:
dependencies:
escape-string-regexp: 1.0.5
- ts-api-utils@2.5.0(typescript@6.0.2):
+ ts-api-utils@2.5.0(typescript@6.0.3):
dependencies:
- typescript: 6.0.2
+ typescript: 6.0.3
tslib@2.8.1: {}
@@ -6386,22 +6386,22 @@ snapshots:
es-errors: 1.3.0
is-typed-array: 1.1.15
- typesafe-i18n@5.27.1(typescript@6.0.2):
+ typesafe-i18n@5.27.1(typescript@6.0.3):
dependencies:
- typescript: 6.0.2
+ typescript: 6.0.3
- typescript-eslint@8.58.2(eslint@10.2.0)(typescript@6.0.2):
+ typescript-eslint@8.58.2(eslint@10.2.0)(typescript@6.0.3):
dependencies:
- '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2)
- '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.2)
- '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2)
- '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2)
+ '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.3))(eslint@10.2.0)(typescript@6.0.3)
+ '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.3)
+ '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3)
+ '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.3)
eslint: 10.2.0
- typescript: 6.0.2
+ typescript: 6.0.3
transitivePeerDependencies:
- supports-color
- typescript@6.0.2: {}
+ typescript@6.0.3: {}
unbzip2-stream@1.4.3:
dependencies:
@@ -6484,7 +6484,7 @@ snapshots:
dependencies:
lightningcss: 1.32.0
picomatch: 4.0.4
- postcss: 8.5.9
+ postcss: 8.5.10
rolldown: 1.0.0-rc.15
tinyglobby: 0.2.16
optionalDependencies:
diff --git a/interface/src/app/main/Sensors.tsx b/interface/src/app/main/Sensors.tsx
index 578140a43..028c362fc 100644
--- a/interface/src/app/main/Sensors.tsx
+++ b/interface/src/app/main/Sensors.tsx
@@ -348,7 +348,7 @@ const Sensors = () => {
const addAnalogSensor = useCallback(() => {
if (firstAvailableGPIO.current === undefined) {
- toast.error('No available GPIO found');
+ toast.error(LL.NO_GPIO());
return;
}
setCreating(true);
diff --git a/interface/src/app/main/types.ts b/interface/src/app/main/types.ts
index 492ccc532..d33301dc4 100644
--- a/interface/src/app/main/types.ts
+++ b/interface/src/app/main/types.ts
@@ -43,6 +43,16 @@ export interface Settings {
modbus_port: number;
modbus_max_clients: number;
modbus_timeout: number;
+ email_enabled: boolean;
+ email_ssl?: boolean;
+ email_starttls?: boolean;
+ email_server: string;
+ email_port: number;
+ email_login: string;
+ email_pass: string;
+ email_sender: string;
+ email_recp: string;
+ email_subject: string;
developer_mode: boolean;
}
diff --git a/interface/src/app/settings/ApplicationSettings.tsx b/interface/src/app/settings/ApplicationSettings.tsx
index 247db2d45..68519d7b5 100644
--- a/interface/src/app/settings/ApplicationSettings.tsx
+++ b/interface/src/app/settings/ApplicationSettings.tsx
@@ -28,6 +28,7 @@ import {
FormLoader,
MessageBox,
SectionContent,
+ ValidatedPasswordField,
ValidatedTextField,
useLayoutTitle
} from 'components';
@@ -351,6 +352,156 @@ const ApplicationSettings = () => {
)}
+ eMail
+
+ }
+ label={
+
+ Enable eMail notification
+ {!hardwareData.psram && (
+
+ ({LL.IS_REQUIRED('PSRAM')})
+
+ )}
+
+ }
+ />
+ {data.email_enabled && (
+ <>
+
+
+
+
+
+
+
+
+ {!data.email_starttls && (
+
+ }
+ label="SSL/TLS"
+ />
+ )}
+ {!data.email_ssl && (
+
+ }
+ label="STARTTLS"
+ />
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
{LL.SENSORS()}
diff --git a/interface/src/app/status/Version.tsx b/interface/src/app/status/Version.tsx
index 0930fbcc5..81494858c 100644
--- a/interface/src/app/status/Version.tsx
+++ b/interface/src/app/status/Version.tsx
@@ -7,6 +7,7 @@ import {
useRef,
useState
} from 'react';
+import { Link } from 'react-router';
import { toast } from 'react-toastify';
import CancelIcon from '@mui/icons-material/Cancel';
@@ -24,7 +25,6 @@ import {
DialogTitle,
Grid,
IconButton,
- Link,
Table,
TableBody,
TableCell,
@@ -343,7 +343,12 @@ const InstallDialog = memo(
onClick={onClose}
color="primary"
>
-
+
{LL.DOWNLOAD(0)}
diff --git a/interface/src/i18n/cz/index.ts b/interface/src/i18n/cz/index.ts
index 9bc067dfb..158655f96 100644
--- a/interface/src/i18n/cz/index.ts
+++ b/interface/src/i18n/cz/index.ts
@@ -350,13 +350,14 @@ const cz: Translation = {
NO_DATA_1: 'Nebyly nalezeny žádné oblíbené entity. Použijte modul',
NO_DATA_2: 'pro jejich výběr.',
NO_DATA_3: 'Pro zobrazení všech dostupných entit navštivte stránku',
+ NO_GPIO:'Nebylo nalezeno žádné volné GPIO',
THIS_VERSION: 'Tato verze',
PLATFORM: 'Platforma',
RELEASE_TYPE: 'Typ sestavení',
INTERNET_CONNECTION_REQUIRED: 'Pro automatickou kontrolu a instalaci aktualizací je třeba internetové připojení',
SWITCH_RELEASE_TYPE: 'Přepnout na {0} verzi',
FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru',
- NO_DATA: 'Žádná data',
+ NO_DATA: 'Žádné údaje',
USER_PROFILE: 'Uživatelský profil',
STORED_VERSIONS: 'Uložené verze',
ONLINE_HELP: 'online nápověda',
diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts
index 12c1e6ed7..e8d17c01b 100644
--- a/interface/src/i18n/de/index.ts
+++ b/interface/src/i18n/de/index.ts
@@ -350,6 +350,7 @@ const de: Translation = {
NO_DATA_1: 'Keine favorisierten EMS-Entitäten gefunden! Verwenden Sie das Modul',
NO_DATA_2: ', um sie zu markieren.',
NO_DATA_3: 'Um alle verfügbaren Entitäten anzuzeigen, gehen Sie zu',
+ NO_GPIO:'Keine freien GPIO gefunden',
THIS_VERSION: 'Diese Version',
PLATFORM: 'Plattform',
RELEASE_TYPE: 'Release Typ',
diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts
index 8c8f8dcbd..0c116d399 100644
--- a/interface/src/i18n/en/index.ts
+++ b/interface/src/i18n/en/index.ts
@@ -350,6 +350,7 @@ const en: Translation = {
NO_DATA_1: 'No favorite EMS entities found yet. Use the',
NO_DATA_2: 'module to mark them.',
NO_DATA_3: 'To see all available entities go to',
+ NO_GPIO:'No available GPIO found',
THIS_VERSION: 'This Version',
PLATFORM: 'Platform',
RELEASE_TYPE: 'Release Type',
diff --git a/interface/src/i18n/fr/index.ts b/interface/src/i18n/fr/index.ts
index e576a5950..528c83bd9 100644
--- a/interface/src/i18n/fr/index.ts
+++ b/interface/src/i18n/fr/index.ts
@@ -350,6 +350,7 @@ const fr: Translation = {
NO_DATA_1: 'Aucune entité EMS favorite trouvée. Utilisez le',
NO_DATA_2: 'module pour les marquer.',
NO_DATA_3: 'Pour voir toutes les entités disponibles, aller à',
+ NO_GPIO:"Aucun GPIO disponible n'a été détecté",
THIS_VERSION: 'Cette version',
PLATFORM: 'Plateforme',
RELEASE_TYPE: 'Type de version',
diff --git a/interface/src/i18n/it/index.ts b/interface/src/i18n/it/index.ts
index 4e86cbc03..04fe977d2 100644
--- a/interface/src/i18n/it/index.ts
+++ b/interface/src/i18n/it/index.ts
@@ -350,6 +350,7 @@ const it: Translation = {
NO_DATA_1: 'Nessuna entità EMS preferita trovata. Usa il',
NO_DATA_2: 'modulo per marcarle.',
NO_DATA_3: 'Per vedere tutte le entità disponibili vai a',
+ NO_GPIO:'Non è stato trovato alcun GPIO disponibile',
THIS_VERSION: 'Questa versione',
PLATFORM: 'Piattaforma',
RELEASE_TYPE: 'Tipo di rilascio',
diff --git a/interface/src/i18n/nl/index.ts b/interface/src/i18n/nl/index.ts
index f246aa684..70176a084 100644
--- a/interface/src/i18n/nl/index.ts
+++ b/interface/src/i18n/nl/index.ts
@@ -350,6 +350,7 @@ const nl: Translation = {
NO_DATA_1: 'Er zijn nog geen favoriete EMS-entiteiten gevonden. Gebruik de',
NO_DATA_2: 'module om ze te markeren.',
NO_DATA_3: 'Om alle beschikbare entiteiten te zien, ga naar',
+ NO_GPIO:'Er is geen beschikbare GPIO gevonden',
THIS_VERSION: 'Deze Versie',
PLATFORM: 'Platform',
RELEASE_TYPE: 'Release Typ',
diff --git a/interface/src/i18n/no/index.ts b/interface/src/i18n/no/index.ts
index 84f56b6ae..f37f87d99 100644
--- a/interface/src/i18n/no/index.ts
+++ b/interface/src/i18n/no/index.ts
@@ -350,6 +350,7 @@ const no: Translation = {
NO_DATA_1: 'Ingen favoritte EMS enheter funnet enda. Bruk',
NO_DATA_2: 'modul for å markere dem.',
NO_DATA_3: 'For å se alle tilgjengelige enheter, gå til',
+ NO_GPIO:'Det ble ikke funnet noen tilgjengelige GPIO-porter',
THIS_VERSION: 'Denne versjonen',
PLATFORM: 'Plattform',
RELEASE_TYPE: 'Utgivelses type',
diff --git a/interface/src/i18n/pl/index.ts b/interface/src/i18n/pl/index.ts
index da445c469..5a279ba93 100644
--- a/interface/src/i18n/pl/index.ts
+++ b/interface/src/i18n/pl/index.ts
@@ -350,6 +350,7 @@ const pl: BaseTranslation = {
NO_DATA_1: 'Brak ulubionych encji EMS. Użyj',
NO_DATA_2: 'moduł do ich oznaczenia.',
NO_DATA_3: 'Aby zobaczyć wszystkie dostępne encje przejdź do',
+ NO_GPIO:'Nie znaleziono dostępnych pinów GPIO',
THIS_VERSION: 'Ta wersja',
PLATFORM: 'Platforma',
RELEASE_TYPE: 'Typ wydania',
diff --git a/interface/src/i18n/sk/index.ts b/interface/src/i18n/sk/index.ts
index 0f4697fe0..be742048f 100644
--- a/interface/src/i18n/sk/index.ts
+++ b/interface/src/i18n/sk/index.ts
@@ -350,6 +350,7 @@ const sk: Translation = {
NO_DATA_1: 'Nenašli sa žiadne obľúbené entity EMS. Použite',
NO_DATA_2: 'modul na ich označenie.',
NO_DATA_3: 'Ak chcete zobraziť všetky dostupné entity, prejdite na',
+ NO_GPIO:'Nebol nájdený žiadny dostupný GPIO',
THIS_VERSION: 'Táto verzia',
PLATFORM: 'Platforma',
RELEASE_TYPE: 'Typ vydania',
diff --git a/interface/src/i18n/sv/index.ts b/interface/src/i18n/sv/index.ts
index 3cff59b90..c980a54fd 100644
--- a/interface/src/i18n/sv/index.ts
+++ b/interface/src/i18n/sv/index.ts
@@ -350,6 +350,7 @@ const sv: Translation = {
NO_DATA_1: 'Inga favorit EMS enheter hittade än. Använd',
NO_DATA_2: 'modul för att markera dem.',
NO_DATA_3: 'För att se alla tillgängliga enheter, gå till',
+ NO_GPIO:'Inga tillgängliga GPIO-portar hittades',
THIS_VERSION: 'Denna version',
PLATFORM: 'Plattform',
RELEASE_TYPE: 'Utgivelsestyp',
diff --git a/interface/src/i18n/tr/index.ts b/interface/src/i18n/tr/index.ts
index 4661b0b2f..154115d6a 100644
--- a/interface/src/i18n/tr/index.ts
+++ b/interface/src/i18n/tr/index.ts
@@ -350,6 +350,7 @@ const tr: Translation = {
NO_DATA_1: 'Henüz bir favori EMS varlığı bulunamadı. Kullanın',
NO_DATA_2: 'modülünü kullanın.',
NO_DATA_3: 'Tüm kullanılabilir varlıkları görmek için git',
+ NO_GPIO:'Kullanılabilir GPIO bulunamadı',
THIS_VERSION: 'Bu Sürüm',
PLATFORM: 'Platforma',
RELEASE_TYPE: 'Sürüm Tipi',
diff --git a/mock-api/package.json b/mock-api/package.json
index 4ba91519e..c90493509 100644
--- a/mock-api/package.json
+++ b/mock-api/package.json
@@ -1,6 +1,6 @@
{
"name": "mock-api",
- "version": "3.8.0",
+ "version": "3.8.2",
"description": "mock api for EMS-ESP",
"author": "proddy, emsesp.org",
"license": "MIT",
diff --git a/mock-api/restServer.ts b/mock-api/restServer.ts
index e7e924c33..1e3a7afae 100644
--- a/mock-api/restServer.ts
+++ b/mock-api/restServer.ts
@@ -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.0';
-let LATEST_DEV_VERSION = '3.8.1-dev.2';
+let LATEST_STABLE_VERSION = '3.8.2';
+let LATEST_DEV_VERSION = '3.8.3-dev.2';
// scenarios for testing versioning
let version_test = 0; // on latest stable, or switch to dev
diff --git a/sonar-project.properties b/sonar-project.properties
index cee91ae32..563719c80 100644
--- a/sonar-project.properties
+++ b/sonar-project.properties
@@ -1,7 +1,7 @@
sonar.organization=emsesp
sonar.projectKey=emsesp_EMS-ESP32
sonar.projectName=EMS-ESP32
-sonar.projectVersion=3.8.0
+sonar.projectVersion=3.8.2
sonar.sources=./src
sonar.cfamily.compile-commands=bw-output/compile_commands.json
sonar.sourceEncoding=UTF-8
diff --git a/src/core/emsdevice.cpp b/src/core/emsdevice.cpp
index 20d338584..d5c18839d 100644
--- a/src/core/emsdevice.cpp
+++ b/src/core/emsdevice.cpp
@@ -368,7 +368,7 @@ void EMSdevice::fetch_values() {
for (const auto & tf : telegram_functions_) {
if (tf.fetch_) {
- read_command(tf.telegram_type_id_);
+ read_command(tf.telegram_type_id_, 0, tf.length_);
}
}
}
@@ -547,8 +547,8 @@ void EMSdevice::show_mqtt_handlers(uuid::console::Shell & shell) const {
}
// register a callback function for a specific telegram type
-void EMSdevice::register_telegram_type(const uint16_t telegram_type_id, const char * telegram_type_name, bool fetch, const process_function_p f) {
- telegram_functions_.emplace_back(telegram_type_id, telegram_type_name, fetch, false, f);
+void EMSdevice::register_telegram_type(const uint16_t telegram_type_id, const char * telegram_type_name, bool fetch, const process_function_p f, uint8_t length) {
+ telegram_functions_.emplace_back(telegram_type_id, telegram_type_name, fetch, false, length, f);
}
// add to device value library, also know now as a "device entity"
diff --git a/src/core/emsdevice.h b/src/core/emsdevice.h
index f584e9b58..366f76a2e 100644
--- a/src/core/emsdevice.h
+++ b/src/core/emsdevice.h
@@ -259,7 +259,7 @@ class EMSdevice {
void setCustomizationEntity(const std::string & entity_id);
void getCustomizationEntities(std::vector & entity_ids);
- void register_telegram_type(const uint16_t telegram_type_id, const char * telegram_type_name, bool fetch, const process_function_p cb);
+ void register_telegram_type(const uint16_t telegram_type_id, const char * telegram_type_name, bool fetch, const process_function_p cb, uint8_t length = 0);
bool handle_telegram(std::shared_ptr telegram);
std::string get_value_uom(const std::string & shortname) const;
@@ -555,13 +555,15 @@ class EMSdevice {
const char * telegram_type_name_; // e.g. RC20Message
bool fetch_; // if this type_id be queried automatically
bool received_;
+ uint8_t length_;
const process_function_p process_function_;
- TelegramFunction(uint16_t telegram_type_id, const char * telegram_type_name, bool fetch, bool received, const process_function_p process_function)
+ TelegramFunction(uint16_t telegram_type_id, const char * telegram_type_name, bool fetch, bool received, uint8_t length, const process_function_p process_function)
: telegram_type_id_(telegram_type_id)
, telegram_type_name_(telegram_type_name)
, fetch_(fetch)
, received_(received)
+ , length_(length)
, process_function_(process_function) {
}
};
diff --git a/src/core/locale_translations.h b/src/core/locale_translations.h
index a56633592..110238bfc 100644
--- a/src/core/locale_translations.h
+++ b/src/core/locale_translations.h
@@ -860,8 +860,9 @@ MAKE_TRANSLATION(poolShunt, "poolshunt", "pool shunt open/close (0% = pool / 100
MAKE_TRANSLATION(hydrTemp, "hydrTemp", "hydraulic header temperature", "Verteilertemperatur", "Temperatuur open verdeler", "Fördelartemperatur", "temperatura kolektora hydraulicznego", "Fordelertemperatur", "température collecteur hydraulique", "hidrolik başlık sıcaklığı", "temperatura del collettore", "teplota hydraulickej hlavice", "teplota hydraulické hlavice")
// solar
-MAKE_TRANSLATION(cylMiddleTemp, "cylmiddletemp", "cylinder middle temperature (TS3)", "Speichertemperatur Mitte (TS3)", "Zonneboilertemperatuur midden (TS3)", "Cylindertemperatur Mitten (TS3)", "temperatura w środku zasobnika (TS3)", "beredertemperatur i midten (TS3)", "température moyenne cylindre (TS3)", "orta depolama sıcaklığı (TS3)", "temperatura di conservazione media accumulo (TS3)", "stredná teplota valca (TS3)", "teplota středu válce (TS3)")
+MAKE_TRANSLATION(cylMiddleTemp, "cylmiddletemp", "cylinder middle temperature (TS14)", "Speichertemperatur Mitte (TS14)", "Zonneboilertemperatuur midden (TS14)", "Cylindertemperatur Mitten (TS14)", "temperatura w środku zasobnika (TS14)", "beredertemperatur i midten (TS14)", "température moyenne cylindre (TS14)", "orta depolama sıcaklığı (TS14)", "temperatura di conservazione media accumulo (TS14)", "stredná teplota valca (TS14)", "teplota středu válce (TS14)")
MAKE_TRANSLATION(retHeatAssist, "retheatassist", "return temperature heat assistance (TS4)", "Anhebung Rücklauftemp. (TS4)", "Retourtemperatuur verwarmingsassistentie (TS4)", "Returtemperatur värmestöd (TS4)", "temperatura powrotu wspomagania grzania (TS4)", "returtemperatur varmestøtte (TS4)", "température retour de assistance thermique (TS4)", "geri dönüş sıcaklığı artışı (TS4)", "temperatura ritorno scambiatore (TS4)", "pomoc pri teplote spiatočky (TS4)", "teplota zpátečky pomocného topení (TS4)")
+MAKE_TRANSLATION(ts3, "ts3", "cylinder middle temperature (TS3)", "Speichertemperatur Mitte (TS3)", "Zonneboilertemperatuur midden (TS3)", "Cylindertemperatur Mitten (TS3)", "temperatura w środku zasobnika (TS3)", "beredertemperatur i midten (TS3)", "température moyenne cylindre (TS3)", "orta depolama sıcaklığı (TS3)", "temperatura di conservazione media accumulo (TS3)", "stredná teplota valca (TS3)", "teplota středu válce (TS3)")
MAKE_TRANSLATION(ts8, "ts8", "(TS8)", "(TS8)")
MAKE_TRANSLATION(ts16, "ts16", "(TS16)","(TS16)")
MAKE_TRANSLATION(m1Valve, "heatassistvalve", "heat assistance valve (M1)", "Ventil Heizungsunterstützung (M1)", "Klep verwarmingsassistentie (M1)", "Uppvärmningsstöd Ventil (M1)", "zawór wspomagania grzania (M1)", "varmehjelpsventil (M1)", "vanne assistance thermique (M1)", "ısıtma yardım vanası (M1)", "valvola scambiatore (M1)", "tepelný asistenčný ventil (M1)", "ventil pomocného topení (M1)")
diff --git a/src/core/modbus_entity_parameters.hpp b/src/core/modbus_entity_parameters.hpp
index 0d222517a..63755c639 100644
--- a/src/core/modbus_entity_parameters.hpp
+++ b/src/core/modbus_entity_parameters.hpp
@@ -446,53 +446,54 @@ const std::initializer_list Modbus::modbus_register_ma
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(retHeatAssist), 18, 1), // retheatassist
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(m1Valve), 19, 1), // heatassistvalve
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collector2Temp), 20, 1), // collector2temp
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(ts8), 21, 1), // ts8
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(ts16), 22, 1), // ts16
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(m1Power), 23, 1), // heatassistpower
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump2), 24, 1), // solarpump2
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump2Mod), 25, 1), // solarpump2mod
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cyl2BottomTemp), 26, 1), // cyl2bottomtemp
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cyl3BottomTemp), 27, 1), // cyl3bottomtemp
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cylTopTemp), 28, 1), // cyltoptemp
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatExchangerTemp), 29, 1), // heatexchangertemp
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cylPumpMod), 30, 1), // cylpumpmod
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(valveStatus), 31, 1), // valvestatus
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(vs1Status), 32, 1), // vs1status
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(vs3Status), 33, 1), // vs3status
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(transferPump), 34, 1), // transferpump
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(transferPumpMod), 35, 1), // transferpumpmod
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collectorMaxTemp), 36, 1), // collectormaxtemp
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collectorMinTemp), 37, 1), // collectormintemp
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(energyToday), 38, 2), // energytoday
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(energyTotal), 40, 2), // energytotal
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(pump2WorkTime), 42, 2), // pump2worktime
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(m1WorkTime), 44, 2), // m1worktime
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatTransferSystem), 46, 1), // heattransfersystem
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(externalCyl), 47, 1), // externalcyl
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(thermalDisinfect), 48, 1), // thermaldisinfect
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatMetering), 49, 1), // heatmetering
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(activated), 50, 1), // activated
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPumpMode), 51, 1), // solarpumpmode
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPumpKick), 52, 1), // solarpumpkick
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(plainWaterMode), 53, 1), // plainwatermode
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(doubleMatchFlow), 54, 1), // doublematchflow
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(pump2MinMod), 55, 1), // pump2minmod
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump2TurnonDiff), 56, 1), // turnondiff2
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump2TurnoffDiff), 57, 1), // turnoffdiff2
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump2Kick), 58, 1), // pump2kick
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(climateZone), 59, 1), // climatezone
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collector1Area), 60, 1), // collector1area
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collector1Type), 61, 1), // collector1type
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collector2Area), 62, 1), // collector2area
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collector2Type), 63, 1), // collector2type
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cylPriority), 64, 1), // cylpriority
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatCntFlowTemp), 65, 1), // heatcntflowtemp
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatCntRetTemp), 66, 1), // heatcntrettemp
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatCnt), 67, 1), // heatcnt
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(swapFlowTemp), 68, 1), // swapflowtemp
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(swapRetTemp), 69, 1), // swaprettemp
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatAssistOn), 70, 1), // heatassiston
- REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatAssistOff), 71, 1), // heatassistoff
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(ts3), 21, 1), // ts3
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(ts8), 22, 1), // ts8
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(ts16), 23, 1), // ts16
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(m1Power), 24, 1), // heatassistpower
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump2), 25, 1), // solarpump2
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump2Mod), 26, 1), // solarpump2mod
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cyl2BottomTemp), 27, 1), // cyl2bottomtemp
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cyl3BottomTemp), 28, 1), // cyl3bottomtemp
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cylTopTemp), 29, 1), // cyltoptemp
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatExchangerTemp), 30, 1), // heatexchangertemp
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cylPumpMod), 31, 1), // cylpumpmod
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(valveStatus), 32, 1), // valvestatus
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(vs1Status), 33, 1), // vs1status
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(vs3Status), 34, 1), // vs3status
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(transferPump), 35, 1), // transferpump
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(transferPumpMod), 36, 1), // transferpumpmod
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collectorMaxTemp), 37, 1), // collectormaxtemp
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collectorMinTemp), 38, 1), // collectormintemp
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(energyToday), 39, 2), // energytoday
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(energyTotal), 41, 2), // energytotal
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(pump2WorkTime), 43, 2), // pump2worktime
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(m1WorkTime), 45, 2), // m1worktime
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatTransferSystem), 47, 1), // heattransfersystem
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(externalCyl), 48, 1), // externalcyl
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(thermalDisinfect), 49, 1), // thermaldisinfect
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatMetering), 50, 1), // heatmetering
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(activated), 51, 1), // activated
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPumpMode), 52, 1), // solarpumpmode
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPumpKick), 53, 1), // solarpumpkick
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(plainWaterMode), 54, 1), // plainwatermode
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(doubleMatchFlow), 55, 1), // doublematchflow
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(pump2MinMod), 56, 1), // pump2minmod
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump2TurnonDiff), 57, 1), // turnondiff2
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump2TurnoffDiff), 58, 1), // turnoffdiff2
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPump2Kick), 59, 1), // pump2kick
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(climateZone), 60, 1), // climatezone
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collector1Area), 61, 1), // collector1area
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collector1Type), 62, 1), // collector1type
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collector2Area), 63, 1), // collector2area
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(collector2Type), 64, 1), // collector2type
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(cylPriority), 65, 1), // cylpriority
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatCntFlowTemp), 66, 1), // heatcntflowtemp
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatCntRetTemp), 67, 1), // heatcntrettemp
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatCnt), 68, 1), // heatcnt
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(swapFlowTemp), 69, 1), // swapflowtemp
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(swapRetTemp), 70, 1), // swaprettemp
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatAssistOn), 71, 1), // heatassiston
+ REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatAssistOff), 72, 1), // heatassistoff
REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DHW, FL_(wwMinTemp), 0, 1), // mintemp
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(airHumidity), 0, 1), // airhumidity
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(dewTemperature), 1, 1), // dewtemperature
diff --git a/src/core/system.cpp b/src/core/system.cpp
index 7a5b8863a..82fba4144 100644
--- a/src/core/system.cpp
+++ b/src/core/system.cpp
@@ -1789,7 +1789,7 @@ void System::exportSystemBackup(JsonObject output) {
output["version"] = EMSESP_APP_VERSION; // add the version to the output
#ifndef EMSESP_STANDALONE
- // add date/time if NTP enabled and active
+ // add date/time if NTP enabled and active
if ((esp_sntp_enabled()) && (EMSESP::system_.ntp_connected())) {
time_t now = time(nullptr);
if (now > 1500000000L) {
@@ -1854,18 +1854,16 @@ void System::exportSystemBackup(JsonObject output) {
nvs_entry_info_t info;
nvs_entry_info(it, &info);
JsonObject entry = entries.add();
- entry["type"] = info.type; // e.g. NVS_TYPE_U32 or NVS_TYPE_STR etc
+ entry["type"] = info.type;
entry["key"] = info.key;
LOG_DEBUG("Exporting NVS value: %s = %d", info.key, info.type);
- // serialize based on the type. We use putString, putChar, putUChar, putDouble, putBool, putULong only
switch (info.type) {
case NVS_TYPE_I8:
entry["value"] = EMSESP::nvs_.getChar(info.key);
break;
case NVS_TYPE_U8:
- // also used for bool
entry["value"] = EMSESP::nvs_.getUChar(info.key);
break;
case NVS_TYPE_I32:
@@ -1881,17 +1879,14 @@ void System::exportSystemBackup(JsonObject output) {
entry["value"] = EMSESP::nvs_.getULong64(info.key);
break;
case NVS_TYPE_BLOB:
- // used for double (e.g. sensor values, nrgheat, nrgww), and stored as bytes in NVS
- entry["value"] = EMSESP::nvs_.getDouble(info.key);
+ entry["value"] = EMSESP::nvs_.getDouble(info.key); // bytes used for double values
break;
case NVS_TYPE_STR:
case NVS_TYPE_ANY:
default:
- // any other value we store as a string
entry["value"] = EMSESP::nvs_.getString(info.key);
break;
}
-
err = nvs_entry_next(&it);
}
diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp
index 0f8e60970..1c40b9ff3 100644
--- a/src/devices/boiler.cpp
+++ b/src/devices/boiler.cpp
@@ -35,7 +35,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_telegram_type(0x11, "UBAErrorMessage2", false, MAKE_PF_CB(process_UBAErrorMessage));
register_telegram_type(0xC2, "UBAErrorMessage3", false, MAKE_PF_CB(process_UBAErrorMessage2));
register_telegram_type(0xC6, "UBAErrorMessage3", false, MAKE_PF_CB(process_UBAErrorMessage3));
- register_telegram_type(0x14, "UBATotalUptime", true, MAKE_PF_CB(process_UBATotalUptime));
+ register_telegram_type(0x14, "UBATotalUptime", true, MAKE_PF_CB(process_UBATotalUptime), 3);
register_telegram_type(0x15, "UBAMaintenanceData", false, MAKE_PF_CB(process_UBAMaintenanceData));
register_telegram_type(0x1C, "UBAMaintenanceStatus", false, MAKE_PF_CB(process_UBAMaintenanceStatus));
@@ -46,13 +46,13 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_telegram_type(0x35, "UBAFlags", false, MAKE_PF_CB(process_UBAFlags));
// only EMS 1.0
- register_telegram_type(0x16, "UBAParameters", true, MAKE_PF_CB(process_UBAParameters));
- register_telegram_type(0x33, "UBAParameterWW", true, MAKE_PF_CB(process_UBAParameterWW));
+ register_telegram_type(0x16, "UBAParameters", true, MAKE_PF_CB(process_UBAParameters), 27);
+ register_telegram_type(0x33, "UBAParameterWW", true, MAKE_PF_CB(process_UBAParameterWW), 11);
register_telegram_type(0x34, "UBAMonitorWW", false, MAKE_PF_CB(process_UBAMonitorWW));
// not ems1.0, but HT3
if (model() != EMSdevice::EMS_DEVICE_FLAG_EMS) {
- register_telegram_type(0x27, "UBASettingsWW", true, MAKE_PF_CB(process_UBASettingsWW));
+ register_telegram_type(0x27, "UBASettingsWW", true, MAKE_PF_CB(process_UBASettingsWW), 11);
register_telegram_type(0x2A, "MC110Status", false, MAKE_PF_CB(process_MC110Status));
}
@@ -62,39 +62,39 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_telegram_type(0xE3, "UBAMonitorSlowPlus2", false, MAKE_PF_CB(process_UBAMonitorSlowPlus2));
register_telegram_type(0xE4, "UBAMonitorFastPlus", false, MAKE_PF_CB(process_UBAMonitorFastPlus));
register_telegram_type(0xE5, "UBAMonitorSlowPlus", false, MAKE_PF_CB(process_UBAMonitorSlowPlus));
- register_telegram_type(0xE6, "UBAParametersPlus", true, MAKE_PF_CB(process_UBAParametersPlus));
+ register_telegram_type(0xE6, "UBAParametersPlus", true, MAKE_PF_CB(process_UBAParametersPlus), 25);
register_telegram_type(0xE9, "UBAMonitorWWPlus", false, MAKE_PF_CB(process_UBAMonitorWWPlus));
- register_telegram_type(0xEA, "UBAParameterWWPlus", true, MAKE_PF_CB(process_UBAParameterWWPlus));
- register_telegram_type(0xEB, "PumpKick", true, MAKE_PF_CB(process_PumpKick));
- register_telegram_type(0x28, "WeatherComp", true, MAKE_PF_CB(process_WeatherComp));
+ register_telegram_type(0xEA, "UBAParameterWWPlus", true, MAKE_PF_CB(process_UBAParameterWWPlus), 28);
+ register_telegram_type(0xEB, "PumpKick", true, MAKE_PF_CB(process_PumpKick), 4);
+ register_telegram_type(0x28, "WeatherComp", true, MAKE_PF_CB(process_WeatherComp), 6);
register_telegram_type(0x2E0, "UBASetPoints", false, MAKE_PF_CB(process_UBASetPoints2));
- register_telegram_type(0x2CC, "HPPressure", true, MAKE_PF_CB(process_HpPressure));
+ register_telegram_type(0x2CC, "HPPressure", true, MAKE_PF_CB(process_HpPressure), 10);
}
if (isHeatPump()) {
register_telegram_type(0x494, "UBAEnergySupplied", false, MAKE_PF_CB(process_UBAEnergySupplied));
register_telegram_type(0x495, "UBAInformation", false, MAKE_PF_CB(process_UBAInformation));
- register_telegram_type(0x48D, "HpPower", true, MAKE_PF_CB(process_HpPower));
+ register_telegram_type(0x48D, "HpPower", true, MAKE_PF_CB(process_HpPower), 20);
register_telegram_type(0x48F, "HpTemperatures", false, MAKE_PF_CB(process_HpTemperatures));
- register_telegram_type(0x48A, "HpPool", true, MAKE_PF_CB(process_HpPool));
+ register_telegram_type(0x48A, "HpPool", true, MAKE_PF_CB(process_HpPool), 2);
register_telegram_type(0x4A2, "HpInput", true, MAKE_PF_CB(process_HpInput));
- register_telegram_type(0x485, "HpCooling", true, MAKE_PF_CB(process_HpCooling));
- register_telegram_type(0x486, "HpInConfig", true, MAKE_PF_CB(process_HpInConfig));
+ register_telegram_type(0x485, "HpCooling", true, MAKE_PF_CB(process_HpCooling), 22);
+ register_telegram_type(0x486, "HpInConfig", true, MAKE_PF_CB(process_HpInConfig), 53);
- register_telegram_type(0x492, "HpHeaterConfig", true, MAKE_PF_CB(process_HpHeaterConfig));
- register_telegram_type(0x488, "HPValve", true, MAKE_PF_CB(process_HpValve));
- register_telegram_type(0x484, "HPSilentMode", true, MAKE_PF_CB(process_HpSilentMode));
- register_telegram_type(0x48B, "HPPumps", true, MAKE_PF_CB(process_HpPumps));
- register_telegram_type(0x491, "HPAdditionalHeater", true, MAKE_PF_CB(process_HpAdditionalHeater));
- register_telegram_type(0x499, "HPDhwSettings", true, MAKE_PF_CB(process_HpDhwSettings));
- register_telegram_type(0x49C, "HPSettings2", true, MAKE_PF_CB(process_HpSettings2));
- register_telegram_type(0x49D, "HPSettings3", true, MAKE_PF_CB(process_HpSettings3));
- register_telegram_type(0x4AE, "HPEnergy", true, MAKE_PF_CB(process_HpEnergy));
- register_telegram_type(0x4AF, "HPMeters", true, MAKE_PF_CB(process_HpMeters));
- register_telegram_type(0x4A5, "HPFan", true, MAKE_PF_CB(process_HpFan));
- register_telegram_type(0x4AA, "HPPower2", true, MAKE_PF_CB(process_HpPower2));
- register_telegram_type(0x4A7, "HPPowerLimit", true, MAKE_PF_CB(process_HpPowerLimit));
- register_telegram_type(0x2D6, "HPPump2", true, MAKE_PF_CB(process_HpPump2));
+ register_telegram_type(0x492, "HpHeaterConfig", true, MAKE_PF_CB(process_HpHeaterConfig), 5);
+ register_telegram_type(0x488, "HPValve", true, MAKE_PF_CB(process_HpValve), 14);
+ register_telegram_type(0x484, "HPSilentMode", true, MAKE_PF_CB(process_HpSilentMode), 65);
+ register_telegram_type(0x48B, "HPPumps", true, MAKE_PF_CB(process_HpPumps), 19);
+ register_telegram_type(0x491, "HPAdditionalHeater", true, MAKE_PF_CB(process_HpAdditionalHeater), 18);
+ register_telegram_type(0x499, "HPDhwSettings", true, MAKE_PF_CB(process_HpDhwSettings), 15);
+ register_telegram_type(0x49C, "HPSettings2", true, MAKE_PF_CB(process_HpSettings2), 4);
+ register_telegram_type(0x49D, "HPSettings3", true, MAKE_PF_CB(process_HpSettings3), 12);
+ register_telegram_type(0x4AE, "HPEnergy", true, MAKE_PF_CB(process_HpEnergy), 32);
+ register_telegram_type(0x4AF, "HPMeters", true, MAKE_PF_CB(process_HpMeters), 56);
+ register_telegram_type(0x4A5, "HPFan", true, MAKE_PF_CB(process_HpFan), 15);
+ register_telegram_type(0x4AA, "HPPower2", true, MAKE_PF_CB(process_HpPower2), 2);
+ register_telegram_type(0x4A7, "HPPowerLimit", true, MAKE_PF_CB(process_HpPowerLimit), 2);
+ register_telegram_type(0x2D6, "HPPump2", true, MAKE_PF_CB(process_HpPump2), 11);
}
// some gas boilers, see #1701
@@ -1139,7 +1139,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
if (!isHeatPump() && model() != EMSdevice::EMS_DEVICE_FLAG_HIU) {
- register_telegram_type(0x04, "UBAFactory", true, MAKE_PF_CB(process_UBAFactory));
+ register_telegram_type(0x04, "UBAFactory", true, MAKE_PF_CB(process_UBAFactory), 21);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nomPower_, DeviceValueType::UINT8, FL_(nomPower), DeviceValueUOM::KW, MAKE_CF_CB(set_nomPower));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&nrgTotal_,
diff --git a/src/devices/connect.cpp b/src/devices/connect.cpp
index a3e22af38..1b87a695e 100644
--- a/src/devices/connect.cpp
+++ b/src/devices/connect.cpp
@@ -39,11 +39,11 @@ Connect::Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, con
DeviceValueUOM::DEGREES);
// Roomthermostats
for (uint8_t i = 0; i < 16; i++) {
- register_telegram_type(0x0BDD + i, "Room", false, MAKE_PF_CB(process_roomThermostat)); // broadcasted
- register_telegram_type(0x0B3D + i, "Roomname", false, MAKE_PF_CB(process_roomThermostatName)); // fetch for active circuits
- register_telegram_type(0x0BB5 + i, "Roomsettings", false, MAKE_PF_CB(process_roomThermostatSettings)); // fetch for active circuits
- 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(0x0BDD + i, "Room", false, MAKE_PF_CB(process_roomThermostat)); // broadcasted
+ register_telegram_type(0x0B3D + i, "Roomname", false, MAKE_PF_CB(process_roomThermostatName), 100); // fetch for active circuits
+ register_telegram_type(0x0BB5 + i, "Roomsettings", false, MAKE_PF_CB(process_roomThermostatSettings), 8); // fetch for active circuits
+ 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));
// 0x2040, broadcast 36 bytes:
diff --git a/src/devices/extension.cpp b/src/devices/extension.cpp
index f3475759b..be0f0c2e6 100644
--- a/src/devices/extension.cpp
+++ b/src/devices/extension.cpp
@@ -29,7 +29,7 @@ Extension::Extension(uint8_t device_type, uint8_t device_id, uint8_t product_id,
return;
}
// Extension module EM100 device_id 0x12
- register_telegram_type(0x935, "EM100SetMessage", true, MAKE_PF_CB(process_EM100SetMessage));
+ register_telegram_type(0x935, "EM100SetMessage", true, MAKE_PF_CB(process_EM100SetMessage), 5);
register_telegram_type(0x936, "EM100OutMessage", false, MAKE_PF_CB(process_EM100OutMessage));
register_telegram_type(0x937, "EM100TempMessage", false, MAKE_PF_CB(process_EM100TempMessage));
register_telegram_type(0x938, "EM100InputMessage", false, MAKE_PF_CB(process_EM100InputMessage));
diff --git a/src/devices/heatpump.cpp b/src/devices/heatpump.cpp
index 76dc4c1be..aa59ff97a 100644
--- a/src/devices/heatpump.cpp
+++ b/src/devices/heatpump.cpp
@@ -28,13 +28,13 @@ Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, c
// register_telegram_type(0x042B, "HP1", false, MAKE_PF_CB(process_HPMonitor1));
register_telegram_type(0x047B, "HP2", false, MAKE_PF_CB(process_HPMonitor2));
- register_telegram_type(0x998, "HPSettings", true, MAKE_PF_CB(process_HPSettings));
- register_telegram_type(0x999, "HPFunctionTest", true, MAKE_PF_CB(process_HPFunctionTest));
+ register_telegram_type(0x998, "HPSettings", true, MAKE_PF_CB(process_HPSettings), 20);
+ register_telegram_type(0x999, "HPFunctionTest", true, MAKE_PF_CB(process_HPFunctionTest), 11);
register_telegram_type(0x9A0, "HPTemperature", false, MAKE_PF_CB(process_HPTemperature));
register_telegram_type(0x99B, "HPFlowTemp", false, MAKE_PF_CB(process_HPFlowTemp));
register_telegram_type(0x99C, "HPComp", false, MAKE_PF_CB(process_HPComp));
- register_telegram_type(0x4AE, "HPEnergy", true, MAKE_PF_CB(process_HpEnergy));
- register_telegram_type(0x4AF, "HPMeters", true, MAKE_PF_CB(process_HpMeters));
+ register_telegram_type(0x4AE, "HPEnergy", true, MAKE_PF_CB(process_HpEnergy), 32);
+ register_telegram_type(0x4AF, "HPMeters", true, MAKE_PF_CB(process_HpMeters), 56);
register_telegram_type(0x99A, "HPStarts", false, MAKE_PF_CB(process_HpStarts));
register_telegram_type(0x12E, "HPEnergy1", false, MAKE_PF_CB(process_HpEnergy1));
register_telegram_type(0x13B, "HPEnergy2", false, MAKE_PF_CB(process_HpEnergy2));
diff --git a/src/devices/heatsource.cpp b/src/devices/heatsource.cpp
index 292846da3..1487b5406 100644
--- a/src/devices/heatsource.cpp
+++ b/src/devices/heatsource.cpp
@@ -33,7 +33,7 @@ Heatsource::Heatsource(uint8_t device_type, uint8_t device_id, uint8_t product_i
register_telegram_type(0x54E, "AmStatus", false, MAKE_PF_CB(process_amStatusMessage));
register_telegram_type(0x54F, "AmCommand", false, MAKE_PF_CB(process_amCommandMessage)); // not broadcasted, but actually not used
register_telegram_type(0x550, "AmExtra", false, MAKE_PF_CB(process_amExtraMessage));
- register_telegram_type(0x54C, "AmSettings", true, MAKE_PF_CB(process_amSettingMessage)); // not broadcasted
+ register_telegram_type(0x54C, "AmSettings", true, MAKE_PF_CB(process_amSettingMessage), 23); // not broadcasted
register_device_value(tag, &curFlowTemp_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(sysFlowTemp), DeviceValueUOM::DEGREES);
register_device_value(tag, &retTemp_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(sysRetTemp), DeviceValueUOM::DEGREES);
diff --git a/src/devices/mixer.cpp b/src/devices/mixer.cpp
index 4dccb32c8..4d521f90b 100644
--- a/src/devices/mixer.cpp
+++ b/src/devices/mixer.cpp
@@ -56,7 +56,7 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
// EMS 1.0
if (flags == EMSdevice::EMS_DEVICE_FLAG_MM10) {
- register_telegram_type(0x00AA, "MMConfigMessage", true, MAKE_PF_CB(process_MMConfigMessage));
+ register_telegram_type(0x00AA, "MMConfigMessage", true, MAKE_PF_CB(process_MMConfigMessage), 10);
register_telegram_type(0x00AB, "MMStatusMessage", false, MAKE_PF_CB(process_MMStatusMessage));
register_telegram_type(0x00AC, "MMSetMessage", false, MAKE_PF_CB(process_MMSetMessage));
register_device_value(tag, &flowTempHc_, DeviceValueType::UINT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(flowTempHc), DeviceValueUOM::DEGREES);
diff --git a/src/devices/pool.cpp b/src/devices/pool.cpp
index 0cfc559fb..f3dc95e17 100644
--- a/src/devices/pool.cpp
+++ b/src/devices/pool.cpp
@@ -27,7 +27,7 @@ uuid::log::Logger Pool::logger_{F_(pool), uuid::log::Facility::CONSOLE};
Pool::Pool(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// Pool module
- register_telegram_type(0x5BA, "HpPoolStatus", true, MAKE_PF_CB(process_HpPoolStatus));
+ register_telegram_type(0x5BA, "HpPoolStatus", true, MAKE_PF_CB(process_HpPoolStatus), 4);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&poolTemp_,
DeviceValueType::INT16,
diff --git a/src/devices/solar.cpp b/src/devices/solar.cpp
index 2aa874869..8d40ca5ed 100644
--- a/src/devices/solar.cpp
+++ b/src/devices/solar.cpp
@@ -29,32 +29,32 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
// telegram handlers
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM10) {
register_telegram_type(0x97, "SM10Monitor", false, MAKE_PF_CB(process_SM10Monitor));
- register_telegram_type(0x96, "SM10Config", true, MAKE_PF_CB(process_SM10Config));
+ register_telegram_type(0x96, "SM10Config", true, MAKE_PF_CB(process_SM10Config), 15);
EMSESP::send_read_request(0x97, device_id);
}
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) {
// F9 is not a telegram type, it's a flag for configure
// register_telegram_type(0xF9, "ParamCfg", false, MAKE_PF_CB(process_SM100ParamCfg));
- register_telegram_type(0x0358, "SM100SystemConfig", true, MAKE_PF_CB(process_SM100SystemConfig));
- register_telegram_type(0x035A, "SM100CircuitConfig", true, MAKE_PF_CB(process_SM100CircuitConfig));
- register_telegram_type(0x035D, "SM100Circuit2Config", true, MAKE_PF_CB(process_SM100Circuit2Config));
+ register_telegram_type(0x0358, "SM100SystemConfig", true, MAKE_PF_CB(process_SM100SystemConfig), 32);
+ register_telegram_type(0x035A, "SM100CircuitConfig", true, MAKE_PF_CB(process_SM100CircuitConfig), 14);
+ register_telegram_type(0x035D, "SM100Circuit2Config", true, MAKE_PF_CB(process_SM100Circuit2Config), 12);
register_telegram_type(0x0362, "SM100Monitor", false, MAKE_PF_CB(process_SM100Monitor));
register_telegram_type(0x0363, "SM100Monitor2", false, MAKE_PF_CB(process_SM100Monitor2));
register_telegram_type(0x0366, "SM100Config", false, MAKE_PF_CB(process_SM100Config));
register_telegram_type(0x0364, "SM100Status", false, MAKE_PF_CB(process_SM100Status));
register_telegram_type(0x036A, "SM100Status2", false, MAKE_PF_CB(process_SM100Status2));
- register_telegram_type(0x0380, "SM100CollectorConfig", true, MAKE_PF_CB(process_SM100CollectorConfig));
- register_telegram_type(0x038E, "SM100Energy", true, MAKE_PF_CB(process_SM100Energy));
- register_telegram_type(0x0391, "SM100Time", true, MAKE_PF_CB(process_SM100Time));
- register_telegram_type(0x035F, "SM100Config1", true, MAKE_PF_CB(process_SM100Config1));
- register_telegram_type(0x035C, "SM100HeatAssist", true, MAKE_PF_CB(process_SM100HeatAssist));
- register_telegram_type(0x0361, "SM100Differential", true, MAKE_PF_CB(process_SM100Differential));
+ register_telegram_type(0x0380, "SM100CollectorConfig", true, MAKE_PF_CB(process_SM100CollectorConfig), 9);
+ register_telegram_type(0x038E, "SM100Energy", true, MAKE_PF_CB(process_SM100Energy), 12);
+ register_telegram_type(0x0391, "SM100Time", true, MAKE_PF_CB(process_SM100Time), 48);
+ register_telegram_type(0x035F, "SM100Config1", true, MAKE_PF_CB(process_SM100Config1), 11);
+ register_telegram_type(0x035C, "SM100HeatAssist", true, MAKE_PF_CB(process_SM100HeatAssist), 2);
+ register_telegram_type(0x0361, "SM100Differential", true, MAKE_PF_CB(process_SM100Differential), 1);
}
if (flags == EMSdevice::EMS_DEVICE_FLAG_ISM) {
- register_telegram_type(0x0103, "ISM1StatusMessage", true, MAKE_PF_CB(process_ISM1StatusMessage));
- register_telegram_type(0x0101, "ISM1Set", true, MAKE_PF_CB(process_ISM1Set));
+ register_telegram_type(0x0103, "ISM1StatusMessage", true, MAKE_PF_CB(process_ISM1StatusMessage), 14);
+ register_telegram_type(0x0101, "ISM1Set", true, MAKE_PF_CB(process_ISM1Set), 7);
register_telegram_type(0x0104, "ISM2StatusMessage", false, MAKE_PF_CB(process_ISM2StatusMessage));
}
@@ -190,6 +190,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
DeviceValueNumOp::DV_NUMOP_DIV10,
FL_(cylMiddleTemp),
DeviceValueUOM::DEGREES);
+ register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ts3_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(ts3), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&retHeatAssist_,
DeviceValueType::INT16,
@@ -613,6 +614,7 @@ void Solar::process_SM100Monitor(std::shared_ptr telegram) {
has_update(telegram, collector2Temp_, 6); // is *10 - TS7: Temperature sensor for collector array 2
has_update(telegram, cylMiddleTemp_, 8); // is *10 - TS14: cylinder middle temperature
has_update(telegram, retHeatAssist_, 10); // is *10 - TS15: return temperature heating assistance
+ has_update(telegram, ts3_, 14); // is *10 - TS3: cylinder middle temperature, see discord
has_update(telegram, ts8_, 22); // is *10 - TS8: ?
has_update(telegram, cylBottomTemp3_, 24); // is *10 - TS5: Temperature sensor cylinder 3, bottom
}
diff --git a/src/devices/solar.h b/src/devices/solar.h
index 39617655a..0fc30918b 100644
--- a/src/devices/solar.h
+++ b/src/devices/solar.h
@@ -37,6 +37,7 @@ class Solar : public EMSdevice {
int16_t cylTopTemp_; // TS10: Temperature sensor 1 cylinder, Top
int16_t heatExchangerTemp_; // TS6: Heat exchanger temperature sensor
int16_t collector2Temp_; // TS7: Temperature sensor for collector array 2
+ int16_t ts3_; // TS3: Temperature sensor cylinder middle
int16_t ts8_; // TS8: Temperature sensor for ?
int16_t ts16_; // TS16: Temperature sensor for ?
int16_t cylMiddleTemp_; // TS14: Cylinder middle temp
diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp
index 95170fbb7..e27b08e5c 100644
--- a/src/devices/thermostat.cpp
+++ b/src/devices/thermostat.cpp
@@ -36,11 +36,11 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
register_telegram_type(0x042B + device_id - 0x38, "RemoteTemp", false, MAKE_PF_CB(process_RemoteTemp));
if (product_id != Roomctrl::RC200) {
register_telegram_type(0x047B + device_id - 0x38, "RemoteHumidity", false, MAKE_PF_CB(process_RemoteHumidity));
- register_telegram_type(0x0273 + device_id - 0x38, "RemoteCorrection", true, MAKE_PF_CB(process_RemoteCorrection));
- register_telegram_type(0x0A6A + device_id - 0x38, "RemoteBattery", true, MAKE_PF_CB(process_RemoteBattery));
+ register_telegram_type(0x0273 + device_id - 0x38, "RemoteCorrection", true, MAKE_PF_CB(process_RemoteCorrection), 1);
+ register_telegram_type(0x0A6A + device_id - 0x38, "RemoteBattery", true, MAKE_PF_CB(process_RemoteBattery), 2);
// maybe fixed type for these telegrams?
- // register_telegram_type(0x0273, "RemoteCorrection", true, MAKE_PF_CB(process_RemoteCorrection));
- // register_telegram_type(0x0A6B, "RemoteBattery", true, MAKE_PF_CB(process_RemoteBattery));
+ // register_telegram_type(0x0273, "RemoteCorrection", true, MAKE_PF_CB(process_RemoteCorrection), 1);
+ // register_telegram_type(0x0A6B, "RemoteBattery", true, MAKE_PF_CB(process_RemoteBattery), 2);
}
register_device_values(); // register device values for common values (not heating circuit)
return; // no values to add
@@ -73,15 +73,15 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
timer2_typeids = {0x42, 0x4C, 0x56, 0x60};
const size_t size = monitor_typeids.size();
for (uint8_t i = 0; i < size; i++) {
- register_telegram_type(monitor_typeids[i], "RC35Monitor", false, MAKE_PF_CB(process_RC35Monitor));
- register_telegram_type(set_typeids[i], "RC35Set", false, MAKE_PF_CB(process_RC35Set));
- register_telegram_type(timer_typeids[i], "RC35Timer", false, MAKE_PF_CB(process_RC35Timer));
- register_telegram_type(timer2_typeids[i], "RC35Timer2", false, MAKE_PF_CB(process_RC35Timer));
+ register_telegram_type(monitor_typeids[i], "RC35Monitor", false, MAKE_PF_CB(process_RC35Monitor), 15);
+ register_telegram_type(set_typeids[i], "RC35Set", false, MAKE_PF_CB(process_RC35Set), 42);
+ register_telegram_type(timer_typeids[i], "RC35Timer", false, MAKE_PF_CB(process_RC35Timer), 99);
+ register_telegram_type(timer2_typeids[i], "RC35Timer2", false, MAKE_PF_CB(process_RC35Timer), 99);
}
- register_telegram_type(EMS_TYPE_IBASettings, "IBASettings", true, MAKE_PF_CB(process_IBASettings));
- register_telegram_type(EMS_TYPE_wwSettings, "WWSettings", true, MAKE_PF_CB(process_RC35wwSettings));
- register_telegram_type(0x38, "WWTimer", true, MAKE_PF_CB(process_RC35wwTimer));
- register_telegram_type(0x39, "WWCircTimer", true, MAKE_PF_CB(process_RC35wwTimer));
+ register_telegram_type(EMS_TYPE_IBASettings, "IBASettings", true, MAKE_PF_CB(process_IBASettings), 22);
+ register_telegram_type(EMS_TYPE_wwSettings, "WWSettings", true, MAKE_PF_CB(process_RC35wwSettings), 10);
+ register_telegram_type(0x38, "WWTimer", true, MAKE_PF_CB(process_RC35wwTimer), 99);
+ register_telegram_type(0x39, "WWCircTimer", true, MAKE_PF_CB(process_RC35wwTimer), 99);
// RC20
} else if (model == EMSdevice::EMS_DEVICE_FLAG_RC20) {
@@ -92,10 +92,10 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
timer_typeids = {0x8F};
const size_t size = monitor_typeids.size();
for (uint8_t i = 0; i < size; i++) {
- register_telegram_type(monitor_typeids[i], "RC20Monitor", false, MAKE_PF_CB(process_RC20Monitor));
- register_telegram_type(set_typeids[i], "RC20Set", false, MAKE_PF_CB(process_RC20Set));
- register_telegram_type(curve_typeids[i], "RC20Temp", false, MAKE_PF_CB(process_RC20Temp));
- register_telegram_type(timer_typeids[i], "RC20Timer", false, MAKE_PF_CB(process_RC20Timer));
+ register_telegram_type(monitor_typeids[i], "RC20Monitor", false, MAKE_PF_CB(process_RC20Monitor), 14);
+ register_telegram_type(set_typeids[i], "RC20Set", false, MAKE_PF_CB(process_RC20Set), 30);
+ register_telegram_type(curve_typeids[i], "RC20Temp", false, MAKE_PF_CB(process_RC20Temp), 7);
+ register_telegram_type(timer_typeids[i], "RC20Timer", false, MAKE_PF_CB(process_RC20Timer), 99);
}
} else {
// remote thermostat uses only 0xAF
@@ -108,8 +108,8 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
set_typeids = {0xAD};
const size_t size = monitor_typeids.size();
for (uint8_t i = 0; i < size; i++) {
- register_telegram_type(monitor_typeids[i], "RC20Monitor", false, MAKE_PF_CB(process_RC20Monitor_2));
- register_telegram_type(set_typeids[i], "RC20Set", false, MAKE_PF_CB(process_RC20Set_2));
+ register_telegram_type(monitor_typeids[i], "RC20Monitor", false, MAKE_PF_CB(process_RC20Monitor_2), 8);
+ register_telegram_type(set_typeids[i], "RC20Set", false, MAKE_PF_CB(process_RC20Set_2), 22);
}
} else {
// remote thermostat uses only 0xAF
@@ -123,22 +123,22 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
timer_typeids = {0x3F};
const size_t size = monitor_typeids.size();
for (uint8_t i = 0; i < size; i++) {
- register_telegram_type(monitor_typeids[i], "RC30Monitor", false, MAKE_PF_CB(process_RC30Monitor));
- register_telegram_type(set_typeids[i], "RC30Set", false, MAKE_PF_CB(process_RC30Set));
- register_telegram_type(curve_typeids[i], "RC30Temp", false, MAKE_PF_CB(process_RC30Temp));
- register_telegram_type(timer_typeids[i], "RC30Timer", false, MAKE_PF_CB(process_RC35Timer));
+ register_telegram_type(monitor_typeids[i], "RC30Monitor", false, MAKE_PF_CB(process_RC30Monitor), 14);
+ register_telegram_type(set_typeids[i], "RC30Set", false, MAKE_PF_CB(process_RC30Set), 31);
+ register_telegram_type(curve_typeids[i], "RC30Temp", false, MAKE_PF_CB(process_RC30Temp), 25);
+ register_telegram_type(timer_typeids[i], "RC30Timer", false, MAKE_PF_CB(process_RC35Timer), 99);
}
- register_telegram_type(0xA9, "RC30Vacation", true, MAKE_PF_CB(process_RC30Vacation));
- register_telegram_type(EMS_TYPE_RC30wwSettings, "RC30WWSettings", true, MAKE_PF_CB(process_RC30wwSettings));
- register_telegram_type(0x38, "WWTimer", true, MAKE_PF_CB(process_RC35wwTimer));
- register_telegram_type(0x39, "WWCircTimer", true, MAKE_PF_CB(process_RC35wwTimer));
+ register_telegram_type(0xA9, "RC30Vacation", true, MAKE_PF_CB(process_RC30Vacation), 57);
+ register_telegram_type(EMS_TYPE_RC30wwSettings, "RC30WWSettings", true, MAKE_PF_CB(process_RC30wwSettings), 5);
+ register_telegram_type(0x38, "WWTimer", true, MAKE_PF_CB(process_RC35wwTimer), 99);
+ register_telegram_type(0x39, "WWCircTimer", true, MAKE_PF_CB(process_RC35wwTimer), 99);
// EASY
} else if (model == EMSdevice::EMS_DEVICE_FLAG_EASY) {
monitor_typeids = {0x0A};
set_typeids.clear();
- register_telegram_type(monitor_typeids[0], "EasyMonitor", true, MAKE_PF_CB(process_EasyMonitor));
- register_telegram_type(0x02A5, "EasyMonitor", false, MAKE_PF_CB(process_EasyMonitor));
+ register_telegram_type(monitor_typeids[0], "EasyMonitor", true, MAKE_PF_CB(process_EasyMonitor), 12);
+ register_telegram_type(0x02A5, "EasyMonitor", false, MAKE_PF_CB(process_EasyMonitor), 7);
// CRF
} else if (model == EMSdevice::EMS_DEVICE_FLAG_CRF) {
@@ -146,16 +146,16 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
set_typeids.clear();
const size_t size = monitor_typeids.size();
for (uint8_t i = 0; i < size; i++) {
- register_telegram_type(monitor_typeids[i], "CRFMonitor", false, MAKE_PF_CB(process_CRFMonitor));
+ register_telegram_type(monitor_typeids[i], "CRFMonitor", false, MAKE_PF_CB(process_CRFMonitor), 7);
}
} else if (model == EMSdevice::EMS_DEVICE_FLAG_CR11) {
monitor_typeids = {0x02A5};
set_typeids = {0x02B9};
curve_typeids = {0x029B};
- register_telegram_type(monitor_typeids[0], "RC300Monitor", true, MAKE_PF_CB(process_CR11Monitor));
- register_telegram_type(set_typeids[0], "RC300Set", false, MAKE_PF_CB(process_RC300Set));
- register_telegram_type(curve_typeids[0], "RC300Curves", true, MAKE_PF_CB(process_RC300Curve));
+ register_telegram_type(monitor_typeids[0], "RC300Monitor", true, MAKE_PF_CB(process_CR11Monitor), 7);
+ register_telegram_type(set_typeids[0], "RC300Set", false, MAKE_PF_CB(process_RC300Set), 29);
+ register_telegram_type(curve_typeids[0], "RC300Curves", true, MAKE_PF_CB(process_RC300Curve), 9);
// RC300/RC100 variants
} else if (isRC300() || (model == EMSdevice::EMS_DEVICE_FLAG_RC100)) {
@@ -171,40 +171,40 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
hpmode_typeids = {0x0291, 0x0292, 0x0293, 0x0294};
const size_t monitor_size = monitor_typeids.size();
for (uint8_t i = 0; i < monitor_size; i++) {
- register_telegram_type(monitor_typeids[i], "RC300Monitor", false, MAKE_PF_CB(process_RC300Monitor));
- register_telegram_type(set_typeids[i], "RC300Set", false, MAKE_PF_CB(process_RC300Set));
- register_telegram_type(summer_typeids[i], "RC300Summer", false, MAKE_PF_CB(process_RC300Summer));
- register_telegram_type(curve_typeids[i], "RC300Curves", false, MAKE_PF_CB(process_RC300Curve));
- register_telegram_type(summer2_typeids[i], "RC300Summer2", false, MAKE_PF_CB(process_RC300Summer2));
+ register_telegram_type(monitor_typeids[i], "RC300Monitor", false, MAKE_PF_CB(process_RC300Monitor), 33);
+ 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), 13);
+ 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);
}
const size_t set2_size = set2_typeids.size();
for (uint8_t i = 0; i < set2_size; i++) {
// register_telegram_type(set2_typeids[i], "RC300Set2", false, MAKE_PF_CB(process_RC300Set2));
- register_telegram_type(set2_typeids[i], "RC300Set2", false, MAKE_PF_CB(process_PID));
- register_telegram_type(hp_typeids[i], "HPSet", false, MAKE_PF_CB(process_HPSet));
- register_telegram_type(hpmode_typeids[i], "HPMode", true, MAKE_PF_CB(process_HPMode));
+ register_telegram_type(set2_typeids[i], "RC300Set2", false, MAKE_PF_CB(process_PID), 4);
+ register_telegram_type(hp_typeids[i], "HPSet", false, MAKE_PF_CB(process_HPSet), 5);
+ register_telegram_type(hpmode_typeids[i], "HPMode", true, MAKE_PF_CB(process_HPMode), 6);
}
- register_telegram_type(0x2F5, "RC300WWmode", true, MAKE_PF_CB(process_RC300WWmode));
- register_telegram_type(0x2F6, "RC300WW2mode", true, MAKE_PF_CB(process_RC300WWmode));
- register_telegram_type(0x31B, "RC300WWtemp", true, MAKE_PF_CB(process_RC300WWtemp));
- register_telegram_type(0x31D, "RC300WWmode2", false, MAKE_PF_CB(process_RC300WWmode2));
- register_telegram_type(0x31E, "RC300WWmode2", false, MAKE_PF_CB(process_RC300WWmode2));
- register_telegram_type(0x23A, "RC300OutdoorTemp", true, MAKE_PF_CB(process_RC300OutdoorTemp));
- register_telegram_type(0x267, "RC300Floordry", false, MAKE_PF_CB(process_RC300Floordry));
+ register_telegram_type(0x2F5, "RC300WWmode", true, MAKE_PF_CB(process_RC300WWmode), 21);
+ register_telegram_type(0x2F6, "RC300WW2mode", true, MAKE_PF_CB(process_RC300WWmode), 21);
+ register_telegram_type(0x31B, "RC300WWtemp", true, MAKE_PF_CB(process_RC300WWtemp), 2);
+ register_telegram_type(0x31D, "RC300WWmode2", false, MAKE_PF_CB(process_RC300WWmode2), 9);
+ register_telegram_type(0x31E, "RC300WWmode2", false, MAKE_PF_CB(process_RC300WWmode2), 9);
+ register_telegram_type(0x23A, "RC300OutdoorTemp", true, MAKE_PF_CB(process_RC300OutdoorTemp), 2);
+ register_telegram_type(0x267, "RC300Floordry", false, MAKE_PF_CB(process_RC300Floordry), 2);
if (model == EMSdevice::EMS_DEVICE_FLAG_RC100) {
- register_telegram_type(0x241, "RC300Settings", true, MAKE_PF_CB(process_RC300Settings));
+ register_telegram_type(0x241, "RC300Settings", true, MAKE_PF_CB(process_RC300Settings), 23);
} else {
- register_telegram_type(0x240, "RC300Settings", true, MAKE_PF_CB(process_RC300Settings));
+ register_telegram_type(0x240, "RC300Settings", true, MAKE_PF_CB(process_RC300Settings), 23);
}
- register_telegram_type(0xBB, "HybridSettings", true, MAKE_PF_CB(process_HybridSettings));
- register_telegram_type(0x23E, "PVSettings", true, MAKE_PF_CB(process_PVSettings));
+ register_telegram_type(0xBB, "HybridSettings", true, MAKE_PF_CB(process_HybridSettings), 20);
+ register_telegram_type(0x23E, "PVSettings", true, MAKE_PF_CB(process_PVSettings), 6);
if (model == EMSdevice::EMS_DEVICE_FLAG_RC100) {
- register_telegram_type(0x43F, "CRHolidays", true, MAKE_PF_CB(process_RC300Holiday));
+ register_telegram_type(0x43F, "CRHolidays", true, MAKE_PF_CB(process_RC300Holiday), 6);
} else {
- register_telegram_type(0x269, "RC300Holiday", true, MAKE_PF_CB(process_RC300Holiday));
+ register_telegram_type(0x269, "RC300Holiday", true, MAKE_PF_CB(process_RC300Holiday), 6);
}
- register_telegram_type(0x16E, "Absent", true, MAKE_PF_CB(process_Absent));
+ 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));
EMSESP::send_read_request(0xC0, device_id, 0, 20); // read last errorcode on start (only published on errors)
@@ -220,25 +220,25 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
monitor_typeids = {0x016F, 0x0170, 0x0171, 0x0172};
const size_t junkers_size = monitor_typeids.size();
for (uint8_t i = 0; i < junkers_size; i++) {
- register_telegram_type(monitor_typeids[i], "JunkersMonitor", false, MAKE_PF_CB(process_JunkersMonitor));
+ register_telegram_type(monitor_typeids[i], "JunkersMonitor", false, MAKE_PF_CB(process_JunkersMonitor), 8);
}
if (has_flags(EMSdevice::EMS_DEVICE_FLAG_JUNKERS_OLD)) {
// FR120, FR100
set_typeids = {0x0179, 0x017A, 0x017B, 0x017C};
for (uint8_t i = 0; i < junkers_size; i++) {
- register_telegram_type(set_typeids[i], "JunkersSet", false, MAKE_PF_CB(process_JunkersSet2));
+ register_telegram_type(set_typeids[i], "JunkersSet", false, MAKE_PF_CB(process_JunkersSet2), 11);
}
} else {
set_typeids = {0x0165, 0x0166, 0x0167, 0x0168};
for (uint8_t i = 0; i < junkers_size; i++) {
- register_telegram_type(set_typeids[i], "JunkersSet", false, MAKE_PF_CB(process_JunkersSet));
+ register_telegram_type(set_typeids[i], "JunkersSet", false, MAKE_PF_CB(process_JunkersSet), 20);
}
}
- register_telegram_type(0xBB, "HybridSettings", true, MAKE_PF_CB(process_HybridSettings));
- register_telegram_type(0x23, "JunkersSetMixer", true, MAKE_PF_CB(process_JunkersSetMixer));
- register_telegram_type(0x1D3, "JunkersDhw", true, MAKE_PF_CB(process_JunkersWW));
- register_telegram_type(0x11E, "JunkersDisp", true, MAKE_PF_CB(process_JunkersDisp));
+ register_telegram_type(0xBB, "HybridSettings", true, MAKE_PF_CB(process_HybridSettings), 20);
+ register_telegram_type(0x23, "JunkersSetMixer", true, MAKE_PF_CB(process_JunkersSetMixer), 1);
+ register_telegram_type(0x1D3, "JunkersDhw", true, MAKE_PF_CB(process_JunkersWW), 3);
+ register_telegram_type(0x11E, "JunkersDisp", true, MAKE_PF_CB(process_JunkersDisp), 18);
}
// register device values for common values (not heating circuit)
diff --git a/src/devices/ventilation.cpp b/src/devices/ventilation.cpp
index 9d3a142da..8473b123d 100644
--- a/src/devices/ventilation.cpp
+++ b/src/devices/ventilation.cpp
@@ -25,12 +25,12 @@ REGISTER_FACTORY(Ventilation, EMSdevice::DeviceType::VENTILATION);
Ventilation::Ventilation(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// HRV176 module, device_id 0x51
- register_telegram_type(0x56B, "VentilationMode", true, MAKE_PF_CB(process_ModeMessage));
+ register_telegram_type(0x56B, "VentilationMode", true, MAKE_PF_CB(process_ModeMessage), 1);
register_telegram_type(0x585, "Blowerspeed", false, MAKE_PF_CB(process_BlowerMessage));
register_telegram_type(0x583, "VentilationMonitor", false, MAKE_PF_CB(process_MonitorMessage));
register_telegram_type(0x5D9, "Airquality", false, MAKE_PF_CB(process_VOCMessage));
register_telegram_type(0x587, "Bypass", false, MAKE_PF_CB(process_BypassMessage));
- register_telegram_type(0x55C, "VentilationSet", true, MAKE_PF_CB(process_SetMessage));
+ register_telegram_type(0x55C, "VentilationSet", true, MAKE_PF_CB(process_SetMessage), 2);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&outFresh_,
diff --git a/src/devices/water.cpp b/src/devices/water.cpp
index 22f198289..17bcdf75f 100644
--- a/src/devices/water.cpp
+++ b/src/devices/water.cpp
@@ -32,13 +32,13 @@ Water::Water(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
// telegram handlers
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));
- register_telegram_type(0x07A6, "SM100wwParam", true, MAKE_PF_CB(process_SM100wwParam)); // same telegram for all circuits
+ 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
if (tag == DeviceValueTAG::TAG_DHW3) {
register_telegram_type(0x07AA, "SM100wwStatus", false, MAKE_PF_CB(process_SM100wwStatus));
register_telegram_type(0x07AC, "SM100wwParam1", false, MAKE_PF_CB(process_SM100wwParam2));
- register_telegram_type(0x07A5, "SM100wwCirc", true, MAKE_PF_CB(process_SM100wwCirc));
- register_telegram_type(0x07AE, "SM100wwKeepWarm", true, MAKE_PF_CB(process_SM100wwKeepWarm));
+ register_telegram_type(0x07A5, "SM100wwCirc", true, MAKE_PF_CB(process_SM100wwCirc), 5);
+ register_telegram_type(0x07AE, "SM100wwKeepWarm", true, MAKE_PF_CB(process_SM100wwKeepWarm), 1);
register_telegram_type(0x07AD, "SM100ValveStatus", false, MAKE_PF_CB(process_SM100ValveStatus));
register_telegram_type(0x07AB, "SM100wwCommand", false, MAKE_PF_CB(process_SM100wwCommand)); // command from thermostat
} else if (tag == DeviceValueTAG::TAG_DHW4) {
@@ -70,7 +70,7 @@ Water::Water(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
} 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));
+ 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);
@@ -88,7 +88,7 @@ Water::Water(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
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));
+ 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));
diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp
index 1f47d70b2..b14fef8f7 100644
--- a/src/uart/emsuart_esp32.cpp
+++ b/src/uart/emsuart_esp32.cpp
@@ -39,21 +39,19 @@ uint32_t inverse_mask = 0;
// receive task, wait for break and call incoming_telegram
void EMSuart::uart_event_task(void * pvParameters) {
uart_event_t event;
- uint8_t telegram[EMS_MAXBUFFERSIZE];
+ uint8_t telegram[UART_FIFO_LEN + 1]; // same size as in driver_install
uint8_t length = 0;
while (1) {
- //Waiting for UART event.
+ // Waiting for UART event.
if (xQueueReceive(uart_queue, (void *)&event, portMAX_DELAY)) {
if (event.type == UART_DATA) {
length += event.size;
} else if (event.type == UART_BREAK) {
+ // read buffer up to break
+ uart_read_bytes(EMSUART_NUM, telegram, length, portMAX_DELAY);
if (length == 2 || (length >= 6 && length <= EMS_MAXBUFFERSIZE)) {
- uart_read_bytes(EMSUART_NUM, telegram, length, portMAX_DELAY);
EMSESP::incoming_telegram(telegram, (uint8_t)(length - 1));
- } else { // flush buffer up to break
- uint8_t buf[SOC_UART_FIFO_LEN];
- uart_read_bytes(EMSUART_NUM, buf, length, portMAX_DELAY);
}
length = 0;
} else if (event.type == UART_BUFFER_FULL) {
@@ -94,7 +92,7 @@ void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t
uart_param_config(EMSUART_NUM, &uart_config);
uart_set_pin(EMSUART_NUM, tx_gpio, rx_gpio, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
uart_set_line_inverse(EMSUART_NUM, inverse_mask);
- uart_driver_install(EMSUART_NUM, SOC_UART_FIFO_LEN + 1, 0, (EMS_MAXBUFFERSIZE + 1) * 2, &uart_queue, 0); // buffer must be > fifo
+ uart_driver_install(EMSUART_NUM, UART_FIFO_LEN + 1, 0, UART_FIFO_LEN + 3, &uart_queue, 0); // buffer must be > fifo, queue can hold data+break+overflow message
uart_set_rx_full_threshold(EMSUART_NUM, 1);
uart_set_rx_timeout(EMSUART_NUM, 0); // disable
diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp
index 392bb36bd..54473a128 100644
--- a/src/web/WebSchedulerService.cpp
+++ b/src/web/WebSchedulerService.cpp
@@ -352,7 +352,6 @@ bool WebSchedulerService::command(const char * name, const std::string & command
// parse json
JsonDocument doc;
if (deserializeJson(doc, cmd) == DeserializationError::Ok) {
- // HTTPClient http;
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
diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp
index 121b75d82..1fee94c64 100644
--- a/src/web/WebSettingsService.cpp
+++ b/src/web/WebSettingsService.cpp
@@ -16,554 +16,553 @@
* along with this program. If not, see .
*/
- #include "emsesp.h"
+#include "emsesp.h"
- namespace emsesp {
-
- uint8_t WebSettings::flags_ = 0;
-
- WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
- : _httpEndpoint(WebSettings::read, WebSettings::update, this, server, EMSESP_SETTINGS_SERVICE_PATH, securityManager)
- , _fsPersistence(WebSettings::read, WebSettings::update, this, fs, EMSESP_SETTINGS_FILE) {
- securityManager->addEndpoint(server, EMSESP_BOARD_PROFILE_SERVICE_PATH, AuthenticationPredicates::IS_AUTHENTICATED, [this](AsyncWebServerRequest * request) {
- board_profile(request);
- });
-
- addUpdateHandler([this] { onUpdate(); }, false);
- }
-
- void WebSettings::read(WebSettings & settings, JsonObject root) {
- root["version"] = settings.version;
- root["board_profile"] = settings.board_profile;
- root["platform"] = EMSESP_PLATFORM;
- root["locale"] = settings.locale;
- root["tx_mode"] = settings.tx_mode;
- root["ems_bus_id"] = settings.ems_bus_id;
- root["syslog_enabled"] = settings.syslog_enabled;
- root["syslog_level"] = settings.syslog_level;
- root["trace_raw"] = settings.trace_raw;
- root["syslog_mark_interval"] = settings.syslog_mark_interval;
- root["syslog_host"] = settings.syslog_host;
- root["syslog_port"] = settings.syslog_port;
- root["boiler_heatingoff"] = settings.boiler_heatingoff;
- root["remote_timeout"] = settings.remote_timeout;
- root["remote_timeout_en"] = settings.remote_timeout_enabled;
- root["shower_timer"] = settings.shower_timer;
- root["shower_alert"] = settings.shower_alert;
- root["shower_alert_coldshot"] = settings.shower_alert_coldshot;
- root["shower_alert_trigger"] = settings.shower_alert_trigger;
- root["shower_min_duration"] = settings.shower_min_duration;
- root["rx_gpio"] = settings.rx_gpio;
- root["tx_gpio"] = settings.tx_gpio;
- root["dallas_gpio"] = settings.dallas_gpio;
- root["dallas_parasite"] = settings.dallas_parasite;
- root["led_gpio"] = settings.led_gpio;
- root["hide_led"] = settings.hide_led;
- root["led_type"] = settings.led_type;
- root["low_clock"] = settings.low_clock;
- root["telnet_enabled"] = settings.telnet_enabled;
- root["notoken_api"] = settings.notoken_api;
- root["readonly_mode"] = settings.readonly_mode;
- root["analog_enabled"] = settings.analog_enabled;
- root["pbutton_gpio"] = settings.pbutton_gpio;
- root["solar_maxflow"] = settings.solar_maxflow;
- root["fahrenheit"] = settings.fahrenheit;
- root["bool_format"] = settings.bool_format;
- root["bool_dashboard"] = settings.bool_dashboard;
- root["enum_format"] = settings.enum_format;
- root["weblog_level"] = settings.weblog_level;
- root["weblog_buffer"] = settings.weblog_buffer;
- root["weblog_compact"] = settings.weblog_compact;
- root["phy_type"] = settings.phy_type;
- root["eth_power"] = settings.eth_power;
- root["eth_phy_addr"] = settings.eth_phy_addr;
- root["eth_clock_mode"] = settings.eth_clock_mode;
- root["modbus_enabled"] = settings.modbus_enabled;
- root["modbus_port"] = settings.modbus_port;
- root["modbus_max_clients"] = settings.modbus_max_clients;
- root["modbus_timeout"] = settings.modbus_timeout;
- root["developer_mode"] = settings.developer_mode;
- #ifndef NO_TLS_SUPPORT
- root["email_enabled"] = settings.email_enabled;
- #else
- root["email_enabled"] = false;
- #endif
- root["email_ssl"] = settings.email_ssl;
- root["email_starttls"] = settings.email_starttls;
- root["email_server"] = settings.email_server;
- root["email_port"] = settings.email_port;
- root["email_login"] = settings.email_login;
- root["email_pass"] = settings.email_pass;
- root["email_sender"] = settings.email_sender;
- root["email_recp"] = settings.email_recp;
- root["email_subject"] = settings.email_subject;
- }
-
- // call on initialization and also when settings are updated/saved via web or console
- // note, settings is empty when the service starts
- StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
- // make a copy of the settings to compare to later
- const WebSettings original_settings(settings);
-
- // make a snapshot of the current GPIOs
- std::vector used_gpios;
- std::vector system_gpios;
- EMSESP::system_.make_snapshot_gpios(used_gpios, system_gpios);
-
- settings.version = root["version"] | EMSESP_APP_VERSION; // save the version, we use it later in System::check_upgrade()
- settings.board_profile = root["board_profile"] | EMSESP_DEFAULT_BOARD_PROFILE;
-
- // get current values that are related to the board profile
- settings.led_gpio = root["led_gpio"];
- settings.dallas_gpio = root["dallas_gpio"];
- settings.rx_gpio = root["rx_gpio"];
- settings.tx_gpio = root["tx_gpio"];
- settings.pbutton_gpio = root["pbutton_gpio"];
- settings.phy_type = root["phy_type"];
- settings.eth_power = root["eth_power"];
- settings.eth_phy_addr = root["eth_phy_addr"];
- settings.eth_clock_mode = root["eth_clock_mode"];
- settings.led_type = root["led_type"]; // 1 = RGB-LED
-
- reset_flags();
-
- // before loading new board profile free old gpios from used list to allow remapping
- EMSESP::system_.remove_gpio(original_settings.led_gpio);
- EMSESP::system_.remove_gpio(original_settings.dallas_gpio);
- EMSESP::system_.remove_gpio(original_settings.pbutton_gpio);
- EMSESP::system_.remove_gpio(original_settings.rx_gpio);
- EMSESP::system_.remove_gpio(original_settings.tx_gpio);
-
- // see if the user has changed the board profile
- // this will set: led_gpio, dallas_gpio, rx_gpio, tx_gpio, pbutton_gpio, phy_type, eth_power, eth_phy_addr, eth_clock_mode, led_type
- // this will always run when EMS-ESP starts since original_settings{} is empty
- if (original_settings.board_profile != settings.board_profile || original_settings.board_profile == "default"
- || original_settings.board_profile.length() == 0) {
- set_board_profile(settings);
- add_flags(ChangeFlags::RESTART);
- }
-
- check_flag(original_settings.phy_type, settings.phy_type, ChangeFlags::RESTART);
- // ETH has changed, so we need to check the ethernet pins. Only if ETH is being used.
- if (settings.phy_type != PHY_type::PHY_TYPE_NONE) {
- check_flag(original_settings.eth_power, settings.eth_power, ChangeFlags::RESTART);
- check_flag(original_settings.eth_clock_mode, settings.eth_clock_mode, ChangeFlags::RESTART);
- if (settings.eth_power != -1) { // Ethernet Power -1 means disabled
- EMSESP::system_.remove_gpio(settings.eth_power, true);
- }
- // remove the ethernet pins from valid list, regardless of whether the GPIOs are valid or not
- EMSESP::system_.remove_gpio(23, true); // MDC
- EMSESP::system_.remove_gpio(18, true); // MDIO
- EMSESP::system_.remove_gpio(19, true); // TXD0
- EMSESP::system_.remove_gpio(22, true); // TXD1
- EMSESP::system_.remove_gpio(21, true); // TXEN
- EMSESP::system_.remove_gpio(25, true); // RXD0
- EMSESP::system_.remove_gpio(26, true); // RXD1
- EMSESP::system_.remove_gpio(27, true); // CRS
-
- if (settings.eth_clock_mode < 2) {
- EMSESP::system_.remove_gpio(0, true); // ETH.clock input
- } else if (settings.eth_clock_mode == 2) {
- EMSESP::system_.remove_gpio(16, true); // ETH.clock output
- } else if (settings.eth_clock_mode == 3) {
- EMSESP::system_.remove_gpio(17, true); // ETH.clock output
- }
- }
-
- // if any of the GPIOs have changed and re-validate them
- bool have_valid_gpios = true;
-
- // Helper lambda for optional GPIOs (can be 0 to disable)
- auto add_optional_gpio = [&have_valid_gpios](uint8_t & gpio, const char * name) {
- if (gpio != 0 && !EMSESP::system_.add_gpio(gpio, name)) {
- gpio = 0; // 0 means disabled
- have_valid_gpios = false;
- }
- };
-
- // add new gpio assignment
- check_flag(original_settings.rx_gpio, settings.rx_gpio, ChangeFlags::UART);
- have_valid_gpios &= EMSESP::system_.add_gpio(settings.rx_gpio, "UART Rx");
-
- check_flag(original_settings.tx_gpio, settings.tx_gpio, ChangeFlags::UART);
- have_valid_gpios &= EMSESP::system_.add_gpio(settings.tx_gpio, "UART Tx");
-
- check_flag(original_settings.led_gpio, settings.led_gpio, ChangeFlags::LED);
- add_optional_gpio(settings.led_gpio, "LED");
-
- check_flag(original_settings.dallas_gpio, settings.dallas_gpio, ChangeFlags::TEMPERATURE_SENSOR);
- add_optional_gpio(settings.dallas_gpio, "Dallas");
-
- check_flag(original_settings.pbutton_gpio, settings.pbutton_gpio, ChangeFlags::BUTTON);
- have_valid_gpios &= EMSESP::system_.add_gpio(settings.pbutton_gpio, "Button");
-
- // check if the LED type, eth_phy_addr or eth_clock_mode have changed
- check_flag(original_settings.led_type, settings.led_type, ChangeFlags::LED);
- check_flag(original_settings.eth_phy_addr, settings.eth_phy_addr, ChangeFlags::RESTART);
- check_flag(original_settings.eth_clock_mode, settings.eth_clock_mode, ChangeFlags::RESTART);
-
- // tx_mode
- settings.tx_mode = root["tx_mode"] | EMSESP_DEFAULT_TX_MODE;
- check_flag(original_settings.tx_mode, settings.tx_mode, ChangeFlags::UART);
-
- // syslog
- settings.syslog_enabled = root["syslog_enabled"] | EMSESP_DEFAULT_SYSLOG_ENABLED;
- check_flag(original_settings.syslog_enabled, settings.syslog_enabled, ChangeFlags::SYSLOG);
- settings.syslog_level = root["syslog_level"] | EMSESP_DEFAULT_SYSLOG_LEVEL;
- check_flag(original_settings.syslog_level, settings.syslog_level, ChangeFlags::SYSLOG);
- settings.syslog_mark_interval = root["syslog_mark_interval"] | EMSESP_DEFAULT_SYSLOG_MARK_INTERVAL;
- check_flag(original_settings.syslog_mark_interval, settings.syslog_mark_interval, ChangeFlags::SYSLOG);
- settings.syslog_port = root["syslog_port"] | EMSESP_DEFAULT_SYSLOG_PORT;
- check_flag(original_settings.syslog_port, settings.syslog_port, ChangeFlags::SYSLOG);
-
- #ifndef EMSESP_STANDALONE
- settings.syslog_host = root["syslog_host"] | EMSESP_DEFAULT_SYSLOG_HOST;
- if (original_settings.syslog_host != settings.syslog_host) {
- add_flags(ChangeFlags::SYSLOG);
- }
- #endif
-
- // temperature sensor
- settings.dallas_parasite = root["dallas_parasite"] | EMSESP_DEFAULT_DALLAS_PARASITE;
- check_flag(original_settings.dallas_parasite, settings.dallas_parasite, ChangeFlags::TEMPERATURE_SENSOR);
-
- // shower
- settings.shower_timer = root["shower_timer"] | EMSESP_DEFAULT_SHOWER_TIMER;
- check_flag(original_settings.shower_timer, settings.shower_timer, ChangeFlags::SHOWER);
- settings.shower_alert = root["shower_alert"] | EMSESP_DEFAULT_SHOWER_ALERT;
- check_flag(original_settings.shower_alert, settings.shower_alert, ChangeFlags::SHOWER);
- settings.shower_alert_trigger = root["shower_alert_trigger"] | EMSESP_DEFAULT_SHOWER_ALERT_TRIGGER;
- check_flag(original_settings.shower_alert_trigger, settings.shower_alert_trigger, ChangeFlags::SHOWER);
- settings.shower_min_duration = root["shower_min_duration"] | EMSESP_DEFAULT_SHOWER_MIN_DURATION;
- check_flag(original_settings.shower_min_duration, settings.shower_min_duration, ChangeFlags::SHOWER);
- settings.shower_alert_coldshot = root["shower_alert_coldshot"] | EMSESP_DEFAULT_SHOWER_ALERT_COLDSHOT;
- check_flag(original_settings.shower_alert_coldshot, settings.shower_alert_coldshot, ChangeFlags::SHOWER);
-
- // LED
- settings.hide_led = root["hide_led"] | EMSESP_DEFAULT_HIDE_LED;
- check_flag(original_settings.hide_led, settings.hide_led, ChangeFlags::LED);
-
- // adc
- settings.analog_enabled = root["analog_enabled"] | EMSESP_DEFAULT_ANALOG_ENABLED;
- check_flag(original_settings.analog_enabled, settings.analog_enabled, ChangeFlags::ANALOG_SENSOR);
-
- // telnet, ems bus id and low clock
- settings.telnet_enabled = root["telnet_enabled"] | EMSESP_DEFAULT_TELNET_ENABLED;
- check_flag(original_settings.telnet_enabled, settings.telnet_enabled, ChangeFlags::RESTART);
- settings.ems_bus_id = root["ems_bus_id"] | EMSESP_DEFAULT_EMS_BUS_ID;
- check_flag(original_settings.ems_bus_id, settings.ems_bus_id, ChangeFlags::RESTART);
- settings.low_clock = root["low_clock"];
- check_flag(original_settings.low_clock, settings.low_clock, ChangeFlags::RESTART);
-
- // Modbus settings
- settings.modbus_enabled = root["modbus_enabled"] | EMSESP_DEFAULT_MODBUS_ENABLED;
- settings.modbus_port = root["modbus_port"] | EMSESP_DEFAULT_MODBUS_PORT;
- settings.modbus_max_clients = root["modbus_max_clients"] | EMSESP_DEFAULT_MODBUS_MAX_CLIENTS;
- settings.modbus_timeout = root["modbus_timeout"] | EMSESP_DEFAULT_MODBUS_TIMEOUT;
-
- //
- // these may need mqtt restart to rebuild HA discovery topics
- //
- settings.bool_format = root["bool_format"] | EMSESP_DEFAULT_BOOL_FORMAT;
- EMSESP::system_.bool_format(settings.bool_format);
- if (Mqtt::ha_enabled()) {
- check_flag(original_settings.bool_format, settings.bool_format, ChangeFlags::MQTT);
- }
-
- settings.enum_format = root["enum_format"] | EMSESP_DEFAULT_ENUM_FORMAT;
- EMSESP::system_.enum_format(settings.enum_format);
- if (Mqtt::ha_enabled()) {
- check_flag(original_settings.enum_format, settings.enum_format, ChangeFlags::MQTT);
- }
-
- settings.locale = root["locale"] | EMSESP_DEFAULT_LOCALE;
- EMSESP::system_.locale(settings.locale);
- if (Mqtt::ha_enabled() && original_settings.locale != settings.locale) {
- add_flags(ChangeFlags::MQTT);
- }
-
- //
- // without checks or necessary restarts...
- //
- settings.trace_raw = root["trace_raw"] | EMSESP_DEFAULT_TRACELOG_RAW;
- EMSESP::trace_raw(settings.trace_raw);
-
- settings.notoken_api = root["notoken_api"] | EMSESP_DEFAULT_NOTOKEN_API;
- settings.solar_maxflow = root["solar_maxflow"] | EMSESP_DEFAULT_SOLAR_MAXFLOW;
- settings.boiler_heatingoff = root["boiler_heatingoff"] | EMSESP_DEFAULT_BOILER_HEATINGOFF;
- settings.remote_timeout = root["remote_timeout"] | EMSESP_DEFAULT_REMOTE_TIMEOUT;
- settings.remote_timeout_enabled = root["remote_timeout_en"] | EMSESP_DEFAULT_REMOTE_TIMEOUT_EN;
- Roomctrl::set_timeout(settings.remote_timeout_enabled ? settings.remote_timeout : 0);
-
- settings.fahrenheit = root["fahrenheit"];
- EMSESP::system_.fahrenheit(settings.fahrenheit);
-
- settings.readonly_mode = root["readonly_mode"];
- EMSESP::system_.readonly_mode(settings.readonly_mode);
-
- settings.developer_mode = root["developer_mode"];
- EMSESP::system_.developer_mode(settings.developer_mode);
-
- settings.bool_dashboard = root["bool_dashboard"] | EMSESP_DEFAULT_BOOL_FORMAT;
- EMSESP::system_.bool_dashboard(settings.bool_dashboard);
-
- settings.weblog_level = root["weblog_level"] | EMSESP_DEFAULT_WEBLOG_LEVEL;
- settings.weblog_compact = root["weblog_compact"] | EMSESP_DEFAULT_WEBLOG_COMPACT;
-
- settings.email_enabled = root["email_enabled"] | FACTORY_EMAIL_ENABLE;
- settings.email_ssl = root["email_ssl"] | FACTORY_EMAIL_SSL;
- settings.email_starttls = root["email_starttls"] | FACTORY_EMAIL_STARTTLS;
- settings.email_server = root["email_server"] | FACTORY_EMAIL_SERVER;
- settings.email_port = root["email_port"] | FACTORY_EMAIL_PORT;
- settings.email_login = root["email_login"] | FACTORY_EMAIL_LOGIN;
- settings.email_pass = root["email_pass"] | FACTORY_EMAIL_PASSWORD;
- settings.email_sender = root["email_sender"] | FACTORY_EMAIL_FROM;
- settings.email_recp = root["email_recp"] | FACTORY_EMAIL_TO;
- settings.email_subject = root["email_subject"] | FACTORY_EMAIL_SUBJECT;
-
- if (settings.email_ssl && settings.email_starttls) {
- settings.email_ssl = false;
- }
- // if no psram limit weblog buffer to 25 messages
- if (EMSESP::system_.PSram() > 0) {
- settings.weblog_buffer = root["weblog_buffer"] | EMSESP_DEFAULT_WEBLOG_BUFFER;
- } else {
- settings.weblog_buffer = root["weblog_buffer"] | 25; // limit to 25 messages if no psram
- }
-
- // save the settings if changed from the webUI
- // if we encountered an invalid GPIO, rollback changes and don't save settings,
- // and report the error to WebUI without a restart
- if (!have_valid_gpios) {
- // replace settings with original settings
- settings = original_settings;
- EMSESP::system_.restore_snapshot_gpios(used_gpios, system_gpios);
-
- // report the error to WebUI
- EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_INVALID_GPIO);
- return StateUpdateResult::ERROR; // don't save the settings if the GPIOs are invalid
- }
-
- // save the setting internally, for reference later
- EMSESP::system_.store_settings(settings);
-
- // and finally always write to the settings file
- if (has_flags(ChangeFlags::RESTART)) {
- return StateUpdateResult::CHANGED_RESTART;
- }
-
- return StateUpdateResult::CHANGED;
- }
-
- // this is called after any of the settings have been persisted to the filesystem
- // either via the Web UI or via the Console
- void WebSettingsService::onUpdate() {
- // skip if we're restarting anyway
-
- if (WebSettings::has_flags(WebSettings::ChangeFlags::RESTART)) {
- return;
- }
-
- if (WebSettings::has_flags(WebSettings::ChangeFlags::SHOWER)) {
- EMSESP::shower_.start();
- }
-
- if (WebSettings::has_flags(WebSettings::ChangeFlags::TEMPERATURE_SENSOR)) {
- EMSESP::temperaturesensor_.start();
- }
-
- if (WebSettings::has_flags(WebSettings::ChangeFlags::UART)) {
- EMSESP::system_.uart_init();
- }
-
- if (WebSettings::has_flags(WebSettings::ChangeFlags::SYSLOG)) {
- EMSESP::system_.syslog_init(); // re-start (or stop)
- }
-
- if (WebSettings::has_flags(WebSettings::ChangeFlags::ANALOG_SENSOR)) {
- EMSESP::analogsensor_.start();
- }
-
- if (WebSettings::has_flags(WebSettings::ChangeFlags::BUTTON)) {
- EMSESP::system_.button_init();
- }
-
- if (WebSettings::has_flags(WebSettings::ChangeFlags::LED)) {
- EMSESP::system_.led_init();
- }
-
- if (WebSettings::has_flags(WebSettings::ChangeFlags::MQTT)) {
- Mqtt::reset_mqtt(); // reload MQTT, init HA etc
- }
-
- WebSettings::reset_flags();
- }
-
- void WebSettingsService::begin() {
- _fsPersistence.readFromFS();
- }
-
- void WebSettingsService::save() {
- _fsPersistence.writeToFS();
- }
-
- // send the board profile as JSON
- void WebSettingsService::board_profile(AsyncWebServerRequest * request) {
- if (request->hasParam("boardProfile")) {
- std::string board_profile = request->getParam("boardProfile")->value().c_str();
-
- auto * response = new AsyncJsonResponse(false);
- JsonObject root = response->getRoot();
-
- // 0=led, 1=dallas, 2=rx, 3=tx, 4=button, 5=phy_type, 6=eth_power, 7=eth_phy_addr, 8=eth_clock_mode, 9=led_type
- std::vector data;
- (void)System::load_board_profile(data, board_profile);
- root["board_profile"] = board_profile;
- root["led_gpio"] = data[0];
- root["dallas_gpio"] = data[1];
- root["rx_gpio"] = data[2];
- root["tx_gpio"] = data[3];
- root["pbutton_gpio"] = data[4];
- root["phy_type"] = data[5];
- root["eth_power"] = data[6];
- root["eth_phy_addr"] = data[7];
- root["eth_clock_mode"] = data[8];
- root["led_type"] = data[9];
-
- response->setLength();
- request->send(response);
- return;
- }
-
- AsyncWebServerResponse * response = request->beginResponse(200);
- request->send(response);
- }
-
- // loads the board profile to set the gpios
- // if the board profile is not found, or default, it will try to autodetect the board profile
- void WebSettings::set_board_profile(WebSettings & settings) {
- // The optional NVS boot value has priority and overrides any board_profile setting.
- // This is only done for BBQKees boards
- // Note 1: we never set the NVS boot value in the code - this is done on initial pre-loading
- // Note 2: The board profile is dynamically changed for the session, but the value in the settings file on the FS remains untouched
- if (EMSESP::system_.getBBQKeesGatewayDetails(FUSE_VALUE::MFG).startsWith("BBQKees")) {
- String bbq_board = EMSESP::system_.getBBQKeesGatewayDetails(FUSE_VALUE::BOARD);
- if (!bbq_board.isEmpty() && settings.board_profile != "CUSTOM") {
- #if defined(EMSESP_DEBUG)
- EMSESP::logger().info("Overriding board profile with fuse value %s", bbq_board.c_str());
- #endif
- settings.board_profile = bbq_board;
- }
- }
-
- // if it's CUSTOM no need to load the board profile from the settings
- // as it's already set
- if (settings.board_profile == "CUSTOM") {
- EMSESP::logger().info("Using CUSTOM board profile");
- EMSESP::system_.set_valid_system_gpios();
- return;
- }
-
- // load the board profile into the data vector
- // 0=led, 1=dallas, 2=rx, 3=tx, 4=button, 5=phy_type, 6=eth_power, 7=eth_phy_addr, 8=eth_clock_mode, 9=led_type
- std::vector data(10, 99); // initialize with 99 for all values, just as a safe guard to catch bad gpios
- if (settings.board_profile != "default") {
- if (!System::load_board_profile(data, settings.board_profile.c_str())) {
- #if defined(EMSESP_DEBUG)
- EMSESP::logger().debug("Unable to identify board profile %s", settings.board_profile.c_str());
- #endif
- settings.board_profile = "default"; // can't find profile, fallback to "default"
- }
- }
-
- // we still don't have a valid board profile. Let's see if we can determine one from the build config or hardware
- if (settings.board_profile == "default") {
- EMSESP::logger().info("Autodetecting board profile");
- #if CONFIG_IDF_TARGET_ESP32
- // check for no PSRAM, could be a E32 or S32?
- if (!ESP.getPsramSize()) {
- if (ETH.begin(ETH_PHY_LAN8720, 1, 23, 18, 16, ETH_CLOCK_GPIO0_IN)) {
- settings.board_profile = "E32"; // Ethernet without PSRAM
- } else {
- settings.board_profile = "S32"; // ESP32 standard WiFi without PSRAM
- }
- } else {
- // check for boards with PSRAM, could be a E32V2 otherwise default back to the S32
- if (ETH.begin(ETH_PHY_LAN8720, 0, 23, 18, 15, ETH_CLOCK_GPIO0_OUT)) {
- if (analogReadMilliVolts(39) > 700) { // core voltage > 2.6V
- settings.board_profile = "E32V2_2"; // Ethernet, PSRAM, internal sensors
- } else {
- settings.board_profile = "E32V2"; // Ethernet and PSRAM
- }
- } else {
- settings.board_profile = "S32"; // ESP32 standard WiFi with PSRAM
- }
- }
- // override if we know the target from the build config like C3, S2, S3 etc..
- #elif CONFIG_IDF_TARGET_ESP32C3
- settings.board_profile = "C3MINI";
- #elif CONFIG_IDF_TARGET_ESP32S2
- settings.board_profile = "S2MINI";
- #elif CONFIG_IDF_TARGET_ESP32S3
- settings.board_profile = "S32S3"; // BBQKees Gateway S3
- #elif CONFIG_IDF_TARGET_ESP32C6
- settings.board_profile = "CUSTOM";
- #endif
- // apply the new board profile setting
- System::load_board_profile(data, settings.board_profile.c_str());
- }
-
- // log board profile and PSRAM info
- #ifndef EMSESP_STANDALONE
- uint32_t psram_size = ESP.getPsramSize() / 1024; // in KB
- if (psram_size > 0) {
- EMSESP::logger().info("Loaded board profile %s (PSRAM: %lu KB)", settings.board_profile.c_str(), psram_size);
- } else {
- EMSESP::logger().info("Loaded board profile %s (PSRAM: not available)", settings.board_profile.c_str());
- }
- #endif
-
- // apply the new board profile settings
- // 0=led, 1=dallas, 2=rx, 3=tx, 4=button, 5=phy_type, 6=eth_power, 7=eth_phy_addr, 8=eth_clock_mode, 9=led_type
- settings.led_gpio = data[0]; // LED GPIO
- settings.dallas_gpio = data[1]; // Dallas GPIO
- settings.rx_gpio = data[2]; // UART Rx GPIO
- settings.tx_gpio = data[3]; // UART Tx GPIO
- settings.pbutton_gpio = data[4]; // Button GPIO
- settings.phy_type = data[5]; // PHY Type
- settings.eth_power = data[6]; // Ethernet Power GPIO
- settings.eth_phy_addr = data[7]; // Ethernet PHY Address
- settings.eth_clock_mode = data[8]; // Ethernet Clock Mode
- settings.led_type = data[9]; // LED Type
- }
-
- // returns true if the value was changed
- bool WebSettings::check_flag(int prev_v, int new_v, uint8_t flag) {
- if (prev_v != new_v) {
- add_flags(flag);
- #if defined(EMSESP_DEBUG)
- // EMSESP::logger().debug("check_flag: flag %d, prev_v=%d, new_v=%d", flag, prev_v, new_v);
- #endif
- return true;
- }
- return false;
- }
-
- void WebSettings::add_flags(uint8_t flags) {
- flags_ |= flags;
- }
-
- bool WebSettings::has_flags(uint8_t flags) {
- return (flags_ & flags) == flags;
- }
-
- void WebSettings::reset_flags() {
- flags_ = ChangeFlags::NONE;
- }
-
- uint8_t WebSettings::get_flags() {
- return flags_;
- }
-
- } // namespace emsesp
-
\ No newline at end of file
+namespace emsesp {
+
+uint8_t WebSettings::flags_ = 0;
+
+WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
+ : _httpEndpoint(WebSettings::read, WebSettings::update, this, server, EMSESP_SETTINGS_SERVICE_PATH, securityManager)
+ , _fsPersistence(WebSettings::read, WebSettings::update, this, fs, EMSESP_SETTINGS_FILE) {
+ securityManager->addEndpoint(server, EMSESP_BOARD_PROFILE_SERVICE_PATH, AuthenticationPredicates::IS_AUTHENTICATED, [this](AsyncWebServerRequest * request) {
+ board_profile(request);
+ });
+
+ addUpdateHandler([this] { onUpdate(); }, false);
+}
+
+void WebSettings::read(WebSettings & settings, JsonObject root) {
+ root["version"] = settings.version;
+ root["board_profile"] = settings.board_profile;
+ root["platform"] = EMSESP_PLATFORM;
+ root["locale"] = settings.locale;
+ root["tx_mode"] = settings.tx_mode;
+ root["ems_bus_id"] = settings.ems_bus_id;
+ root["syslog_enabled"] = settings.syslog_enabled;
+ root["syslog_level"] = settings.syslog_level;
+ root["trace_raw"] = settings.trace_raw;
+ root["syslog_mark_interval"] = settings.syslog_mark_interval;
+ root["syslog_host"] = settings.syslog_host;
+ root["syslog_port"] = settings.syslog_port;
+ root["boiler_heatingoff"] = settings.boiler_heatingoff;
+ root["remote_timeout"] = settings.remote_timeout;
+ root["remote_timeout_en"] = settings.remote_timeout_enabled;
+ root["shower_timer"] = settings.shower_timer;
+ root["shower_alert"] = settings.shower_alert;
+ root["shower_alert_coldshot"] = settings.shower_alert_coldshot;
+ root["shower_alert_trigger"] = settings.shower_alert_trigger;
+ root["shower_min_duration"] = settings.shower_min_duration;
+ root["rx_gpio"] = settings.rx_gpio;
+ root["tx_gpio"] = settings.tx_gpio;
+ root["dallas_gpio"] = settings.dallas_gpio;
+ root["dallas_parasite"] = settings.dallas_parasite;
+ root["led_gpio"] = settings.led_gpio;
+ root["hide_led"] = settings.hide_led;
+ root["led_type"] = settings.led_type;
+ root["low_clock"] = settings.low_clock;
+ root["telnet_enabled"] = settings.telnet_enabled;
+ root["notoken_api"] = settings.notoken_api;
+ root["readonly_mode"] = settings.readonly_mode;
+ root["analog_enabled"] = settings.analog_enabled;
+ root["pbutton_gpio"] = settings.pbutton_gpio;
+ root["solar_maxflow"] = settings.solar_maxflow;
+ root["fahrenheit"] = settings.fahrenheit;
+ root["bool_format"] = settings.bool_format;
+ root["bool_dashboard"] = settings.bool_dashboard;
+ root["enum_format"] = settings.enum_format;
+ root["weblog_level"] = settings.weblog_level;
+ root["weblog_buffer"] = settings.weblog_buffer;
+ root["weblog_compact"] = settings.weblog_compact;
+ root["phy_type"] = settings.phy_type;
+ root["eth_power"] = settings.eth_power;
+ root["eth_phy_addr"] = settings.eth_phy_addr;
+ root["eth_clock_mode"] = settings.eth_clock_mode;
+ root["modbus_enabled"] = settings.modbus_enabled;
+ root["modbus_port"] = settings.modbus_port;
+ root["modbus_max_clients"] = settings.modbus_max_clients;
+ root["modbus_timeout"] = settings.modbus_timeout;
+ root["developer_mode"] = settings.developer_mode;
+#ifndef NO_TLS_SUPPORT
+ root["email_enabled"] = settings.email_enabled;
+#else
+ root["email_enabled"] = false;
+#endif
+ root["email_ssl"] = settings.email_ssl;
+ root["email_starttls"] = settings.email_starttls;
+ root["email_server"] = settings.email_server;
+ root["email_port"] = settings.email_port;
+ root["email_login"] = settings.email_login;
+ root["email_pass"] = settings.email_pass;
+ root["email_sender"] = settings.email_sender;
+ root["email_recp"] = settings.email_recp;
+ root["email_subject"] = settings.email_subject;
+}
+
+// call on initialization and also when settings are updated/saved via web or console
+// note, settings is empty when the service starts
+StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
+ // make a copy of the settings to compare to later
+ const WebSettings original_settings(settings);
+
+ // make a snapshot of the current GPIOs
+ std::vector used_gpios;
+ std::vector system_gpios;
+ EMSESP::system_.make_snapshot_gpios(used_gpios, system_gpios);
+
+ settings.version = root["version"] | EMSESP_APP_VERSION; // save the version, we use it later in System::check_upgrade()
+ settings.board_profile = root["board_profile"] | EMSESP_DEFAULT_BOARD_PROFILE;
+
+ // get current values that are related to the board profile
+ settings.led_gpio = root["led_gpio"];
+ settings.dallas_gpio = root["dallas_gpio"];
+ settings.rx_gpio = root["rx_gpio"];
+ settings.tx_gpio = root["tx_gpio"];
+ settings.pbutton_gpio = root["pbutton_gpio"];
+ settings.phy_type = root["phy_type"];
+ settings.eth_power = root["eth_power"];
+ settings.eth_phy_addr = root["eth_phy_addr"];
+ settings.eth_clock_mode = root["eth_clock_mode"];
+ settings.led_type = root["led_type"]; // 1 = RGB-LED
+
+ reset_flags();
+
+ // before loading new board profile free old gpios from used list to allow remapping
+ EMSESP::system_.remove_gpio(original_settings.led_gpio);
+ EMSESP::system_.remove_gpio(original_settings.dallas_gpio);
+ EMSESP::system_.remove_gpio(original_settings.pbutton_gpio);
+ EMSESP::system_.remove_gpio(original_settings.rx_gpio);
+ EMSESP::system_.remove_gpio(original_settings.tx_gpio);
+
+ // see if the user has changed the board profile
+ // this will set: led_gpio, dallas_gpio, rx_gpio, tx_gpio, pbutton_gpio, phy_type, eth_power, eth_phy_addr, eth_clock_mode, led_type
+ // this will always run when EMS-ESP starts since original_settings{} is empty
+ if (original_settings.board_profile != settings.board_profile || original_settings.board_profile == "default"
+ || original_settings.board_profile.length() == 0) {
+ set_board_profile(settings);
+ add_flags(ChangeFlags::RESTART);
+ }
+
+ check_flag(original_settings.phy_type, settings.phy_type, ChangeFlags::RESTART);
+ // ETH has changed, so we need to check the ethernet pins. Only if ETH is being used.
+ if (settings.phy_type != PHY_type::PHY_TYPE_NONE) {
+ check_flag(original_settings.eth_power, settings.eth_power, ChangeFlags::RESTART);
+ check_flag(original_settings.eth_clock_mode, settings.eth_clock_mode, ChangeFlags::RESTART);
+ if (settings.eth_power != -1) { // Ethernet Power -1 means disabled
+ EMSESP::system_.remove_gpio(settings.eth_power, true);
+ }
+ // remove the ethernet pins from valid list, regardless of whether the GPIOs are valid or not
+ EMSESP::system_.remove_gpio(23, true); // MDC
+ EMSESP::system_.remove_gpio(18, true); // MDIO
+ EMSESP::system_.remove_gpio(19, true); // TXD0
+ EMSESP::system_.remove_gpio(22, true); // TXD1
+ EMSESP::system_.remove_gpio(21, true); // TXEN
+ EMSESP::system_.remove_gpio(25, true); // RXD0
+ EMSESP::system_.remove_gpio(26, true); // RXD1
+ EMSESP::system_.remove_gpio(27, true); // CRS
+
+ if (settings.eth_clock_mode < 2) {
+ EMSESP::system_.remove_gpio(0, true); // ETH.clock input
+ } else if (settings.eth_clock_mode == 2) {
+ EMSESP::system_.remove_gpio(16, true); // ETH.clock output
+ } else if (settings.eth_clock_mode == 3) {
+ EMSESP::system_.remove_gpio(17, true); // ETH.clock output
+ }
+ }
+
+ // if any of the GPIOs have changed and re-validate them
+ bool have_valid_gpios = true;
+
+ // Helper lambda for optional GPIOs (can be 0 to disable)
+ auto add_optional_gpio = [&have_valid_gpios](uint8_t & gpio, const char * name) {
+ if (gpio != 0 && !EMSESP::system_.add_gpio(gpio, name)) {
+ gpio = 0; // 0 means disabled
+ have_valid_gpios = false;
+ }
+ };
+
+ // add new gpio assignment
+ check_flag(original_settings.rx_gpio, settings.rx_gpio, ChangeFlags::UART);
+ have_valid_gpios &= EMSESP::system_.add_gpio(settings.rx_gpio, "UART Rx");
+
+ check_flag(original_settings.tx_gpio, settings.tx_gpio, ChangeFlags::UART);
+ have_valid_gpios &= EMSESP::system_.add_gpio(settings.tx_gpio, "UART Tx");
+
+ check_flag(original_settings.led_gpio, settings.led_gpio, ChangeFlags::LED);
+ add_optional_gpio(settings.led_gpio, "LED");
+
+ check_flag(original_settings.dallas_gpio, settings.dallas_gpio, ChangeFlags::TEMPERATURE_SENSOR);
+ add_optional_gpio(settings.dallas_gpio, "Dallas");
+
+ check_flag(original_settings.pbutton_gpio, settings.pbutton_gpio, ChangeFlags::BUTTON);
+ have_valid_gpios &= EMSESP::system_.add_gpio(settings.pbutton_gpio, "Button");
+
+ // check if the LED type, eth_phy_addr or eth_clock_mode have changed
+ check_flag(original_settings.led_type, settings.led_type, ChangeFlags::LED);
+ check_flag(original_settings.eth_phy_addr, settings.eth_phy_addr, ChangeFlags::RESTART);
+ check_flag(original_settings.eth_clock_mode, settings.eth_clock_mode, ChangeFlags::RESTART);
+
+ // tx_mode
+ settings.tx_mode = root["tx_mode"] | EMSESP_DEFAULT_TX_MODE;
+ check_flag(original_settings.tx_mode, settings.tx_mode, ChangeFlags::UART);
+
+ // syslog
+ settings.syslog_enabled = root["syslog_enabled"] | EMSESP_DEFAULT_SYSLOG_ENABLED;
+ check_flag(original_settings.syslog_enabled, settings.syslog_enabled, ChangeFlags::SYSLOG);
+ settings.syslog_level = root["syslog_level"] | EMSESP_DEFAULT_SYSLOG_LEVEL;
+ check_flag(original_settings.syslog_level, settings.syslog_level, ChangeFlags::SYSLOG);
+ settings.syslog_mark_interval = root["syslog_mark_interval"] | EMSESP_DEFAULT_SYSLOG_MARK_INTERVAL;
+ check_flag(original_settings.syslog_mark_interval, settings.syslog_mark_interval, ChangeFlags::SYSLOG);
+ settings.syslog_port = root["syslog_port"] | EMSESP_DEFAULT_SYSLOG_PORT;
+ check_flag(original_settings.syslog_port, settings.syslog_port, ChangeFlags::SYSLOG);
+
+#ifndef EMSESP_STANDALONE
+ settings.syslog_host = root["syslog_host"] | EMSESP_DEFAULT_SYSLOG_HOST;
+ if (original_settings.syslog_host != settings.syslog_host) {
+ add_flags(ChangeFlags::SYSLOG);
+ }
+#endif
+
+ // temperature sensor
+ settings.dallas_parasite = root["dallas_parasite"] | EMSESP_DEFAULT_DALLAS_PARASITE;
+ check_flag(original_settings.dallas_parasite, settings.dallas_parasite, ChangeFlags::TEMPERATURE_SENSOR);
+
+ // shower
+ settings.shower_timer = root["shower_timer"] | EMSESP_DEFAULT_SHOWER_TIMER;
+ check_flag(original_settings.shower_timer, settings.shower_timer, ChangeFlags::SHOWER);
+ settings.shower_alert = root["shower_alert"] | EMSESP_DEFAULT_SHOWER_ALERT;
+ check_flag(original_settings.shower_alert, settings.shower_alert, ChangeFlags::SHOWER);
+ settings.shower_alert_trigger = root["shower_alert_trigger"] | EMSESP_DEFAULT_SHOWER_ALERT_TRIGGER;
+ check_flag(original_settings.shower_alert_trigger, settings.shower_alert_trigger, ChangeFlags::SHOWER);
+ settings.shower_min_duration = root["shower_min_duration"] | EMSESP_DEFAULT_SHOWER_MIN_DURATION;
+ check_flag(original_settings.shower_min_duration, settings.shower_min_duration, ChangeFlags::SHOWER);
+ settings.shower_alert_coldshot = root["shower_alert_coldshot"] | EMSESP_DEFAULT_SHOWER_ALERT_COLDSHOT;
+ check_flag(original_settings.shower_alert_coldshot, settings.shower_alert_coldshot, ChangeFlags::SHOWER);
+
+ // LED
+ settings.hide_led = root["hide_led"] | EMSESP_DEFAULT_HIDE_LED;
+ check_flag(original_settings.hide_led, settings.hide_led, ChangeFlags::LED);
+
+ // adc
+ settings.analog_enabled = root["analog_enabled"] | EMSESP_DEFAULT_ANALOG_ENABLED;
+ check_flag(original_settings.analog_enabled, settings.analog_enabled, ChangeFlags::ANALOG_SENSOR);
+
+ // telnet, ems bus id and low clock
+ settings.telnet_enabled = root["telnet_enabled"] | EMSESP_DEFAULT_TELNET_ENABLED;
+ check_flag(original_settings.telnet_enabled, settings.telnet_enabled, ChangeFlags::RESTART);
+ settings.ems_bus_id = root["ems_bus_id"] | EMSESP_DEFAULT_EMS_BUS_ID;
+ check_flag(original_settings.ems_bus_id, settings.ems_bus_id, ChangeFlags::RESTART);
+ settings.low_clock = root["low_clock"];
+ check_flag(original_settings.low_clock, settings.low_clock, ChangeFlags::RESTART);
+
+ // Modbus settings
+ settings.modbus_enabled = root["modbus_enabled"] | EMSESP_DEFAULT_MODBUS_ENABLED;
+ settings.modbus_port = root["modbus_port"] | EMSESP_DEFAULT_MODBUS_PORT;
+ settings.modbus_max_clients = root["modbus_max_clients"] | EMSESP_DEFAULT_MODBUS_MAX_CLIENTS;
+ settings.modbus_timeout = root["modbus_timeout"] | EMSESP_DEFAULT_MODBUS_TIMEOUT;
+
+ //
+ // these may need mqtt restart to rebuild HA discovery topics
+ //
+ settings.bool_format = root["bool_format"] | EMSESP_DEFAULT_BOOL_FORMAT;
+ EMSESP::system_.bool_format(settings.bool_format);
+ if (Mqtt::ha_enabled()) {
+ check_flag(original_settings.bool_format, settings.bool_format, ChangeFlags::MQTT);
+ }
+
+ settings.enum_format = root["enum_format"] | EMSESP_DEFAULT_ENUM_FORMAT;
+ EMSESP::system_.enum_format(settings.enum_format);
+ if (Mqtt::ha_enabled()) {
+ check_flag(original_settings.enum_format, settings.enum_format, ChangeFlags::MQTT);
+ }
+
+ settings.locale = root["locale"] | EMSESP_DEFAULT_LOCALE;
+ EMSESP::system_.locale(settings.locale);
+ if (Mqtt::ha_enabled() && original_settings.locale != settings.locale) {
+ add_flags(ChangeFlags::MQTT);
+ }
+
+ //
+ // without checks or necessary restarts...
+ //
+ settings.trace_raw = root["trace_raw"] | EMSESP_DEFAULT_TRACELOG_RAW;
+ EMSESP::trace_raw(settings.trace_raw);
+
+ settings.notoken_api = root["notoken_api"] | EMSESP_DEFAULT_NOTOKEN_API;
+ settings.solar_maxflow = root["solar_maxflow"] | EMSESP_DEFAULT_SOLAR_MAXFLOW;
+ settings.boiler_heatingoff = root["boiler_heatingoff"] | EMSESP_DEFAULT_BOILER_HEATINGOFF;
+ settings.remote_timeout = root["remote_timeout"] | EMSESP_DEFAULT_REMOTE_TIMEOUT;
+ settings.remote_timeout_enabled = root["remote_timeout_en"] | EMSESP_DEFAULT_REMOTE_TIMEOUT_EN;
+ Roomctrl::set_timeout(settings.remote_timeout_enabled ? settings.remote_timeout : 0);
+
+ settings.fahrenheit = root["fahrenheit"];
+ EMSESP::system_.fahrenheit(settings.fahrenheit);
+
+ settings.readonly_mode = root["readonly_mode"];
+ EMSESP::system_.readonly_mode(settings.readonly_mode);
+
+ settings.developer_mode = root["developer_mode"];
+ EMSESP::system_.developer_mode(settings.developer_mode);
+
+ settings.bool_dashboard = root["bool_dashboard"] | EMSESP_DEFAULT_BOOL_FORMAT;
+ EMSESP::system_.bool_dashboard(settings.bool_dashboard);
+
+ settings.weblog_level = root["weblog_level"] | EMSESP_DEFAULT_WEBLOG_LEVEL;
+ settings.weblog_compact = root["weblog_compact"] | EMSESP_DEFAULT_WEBLOG_COMPACT;
+
+ settings.email_enabled = root["email_enabled"] | FACTORY_EMAIL_ENABLE;
+ settings.email_ssl = root["email_ssl"] | FACTORY_EMAIL_SSL;
+ settings.email_starttls = root["email_starttls"] | FACTORY_EMAIL_STARTTLS;
+ settings.email_server = root["email_server"] | FACTORY_EMAIL_SERVER;
+ settings.email_port = root["email_port"] | FACTORY_EMAIL_PORT;
+ settings.email_login = root["email_login"] | FACTORY_EMAIL_LOGIN;
+ settings.email_pass = root["email_pass"] | FACTORY_EMAIL_PASSWORD;
+ settings.email_sender = root["email_sender"] | FACTORY_EMAIL_FROM;
+ settings.email_recp = root["email_recp"] | FACTORY_EMAIL_TO;
+ settings.email_subject = root["email_subject"] | FACTORY_EMAIL_SUBJECT;
+
+ if (settings.email_ssl && settings.email_starttls) {
+ settings.email_ssl = false;
+ }
+ // if no psram limit weblog buffer to 25 messages
+ if (EMSESP::system_.PSram() > 0) {
+ settings.weblog_buffer = root["weblog_buffer"] | EMSESP_DEFAULT_WEBLOG_BUFFER;
+ } else {
+ settings.weblog_buffer = root["weblog_buffer"] | 25; // limit to 25 messages if no psram
+ }
+
+ // save the settings if changed from the webUI
+ // if we encountered an invalid GPIO, rollback changes and don't save settings,
+ // and report the error to WebUI without a restart
+ if (!have_valid_gpios) {
+ // replace settings with original settings
+ settings = original_settings;
+ EMSESP::system_.restore_snapshot_gpios(used_gpios, system_gpios);
+
+ // report the error to WebUI
+ EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_INVALID_GPIO);
+ return StateUpdateResult::ERROR; // don't save the settings if the GPIOs are invalid
+ }
+
+ // save the setting internally, for reference later
+ EMSESP::system_.store_settings(settings);
+
+ // and finally always write to the settings file
+ if (has_flags(ChangeFlags::RESTART)) {
+ return StateUpdateResult::CHANGED_RESTART;
+ }
+
+ return StateUpdateResult::CHANGED;
+}
+
+// this is called after any of the settings have been persisted to the filesystem
+// either via the Web UI or via the Console
+void WebSettingsService::onUpdate() {
+ // skip if we're restarting anyway
+
+ if (WebSettings::has_flags(WebSettings::ChangeFlags::RESTART)) {
+ return;
+ }
+
+ if (WebSettings::has_flags(WebSettings::ChangeFlags::SHOWER)) {
+ EMSESP::shower_.start();
+ }
+
+ if (WebSettings::has_flags(WebSettings::ChangeFlags::TEMPERATURE_SENSOR)) {
+ EMSESP::temperaturesensor_.start();
+ }
+
+ if (WebSettings::has_flags(WebSettings::ChangeFlags::UART)) {
+ EMSESP::system_.uart_init();
+ }
+
+ if (WebSettings::has_flags(WebSettings::ChangeFlags::SYSLOG)) {
+ EMSESP::system_.syslog_init(); // re-start (or stop)
+ }
+
+ if (WebSettings::has_flags(WebSettings::ChangeFlags::ANALOG_SENSOR)) {
+ EMSESP::analogsensor_.start();
+ }
+
+ if (WebSettings::has_flags(WebSettings::ChangeFlags::BUTTON)) {
+ EMSESP::system_.button_init();
+ }
+
+ if (WebSettings::has_flags(WebSettings::ChangeFlags::LED)) {
+ EMSESP::system_.led_init();
+ }
+
+ if (WebSettings::has_flags(WebSettings::ChangeFlags::MQTT)) {
+ Mqtt::reset_mqtt(); // reload MQTT, init HA etc
+ }
+
+ WebSettings::reset_flags();
+}
+
+void WebSettingsService::begin() {
+ _fsPersistence.readFromFS();
+}
+
+void WebSettingsService::save() {
+ _fsPersistence.writeToFS();
+}
+
+// send the board profile as JSON
+void WebSettingsService::board_profile(AsyncWebServerRequest * request) {
+ if (request->hasParam("boardProfile")) {
+ std::string board_profile = request->getParam("boardProfile")->value().c_str();
+
+ auto * response = new AsyncJsonResponse(false);
+ JsonObject root = response->getRoot();
+
+ // 0=led, 1=dallas, 2=rx, 3=tx, 4=button, 5=phy_type, 6=eth_power, 7=eth_phy_addr, 8=eth_clock_mode, 9=led_type
+ std::vector data;
+ (void)System::load_board_profile(data, board_profile);
+ root["board_profile"] = board_profile;
+ root["led_gpio"] = data[0];
+ root["dallas_gpio"] = data[1];
+ root["rx_gpio"] = data[2];
+ root["tx_gpio"] = data[3];
+ root["pbutton_gpio"] = data[4];
+ root["phy_type"] = data[5];
+ root["eth_power"] = data[6];
+ root["eth_phy_addr"] = data[7];
+ root["eth_clock_mode"] = data[8];
+ root["led_type"] = data[9];
+
+ response->setLength();
+ request->send(response);
+ return;
+ }
+
+ AsyncWebServerResponse * response = request->beginResponse(200);
+ request->send(response);
+}
+
+// loads the board profile to set the gpios
+// if the board profile is not found, or default, it will try to autodetect the board profile
+void WebSettings::set_board_profile(WebSettings & settings) {
+ // The optional NVS boot value has priority and overrides any board_profile setting.
+ // This is only done for BBQKees boards
+ // Note 1: we never set the NVS boot value in the code - this is done on initial pre-loading
+ // Note 2: The board profile is dynamically changed for the session, but the value in the settings file on the FS remains untouched
+ if (EMSESP::system_.getBBQKeesGatewayDetails(FUSE_VALUE::MFG).startsWith("BBQKees")) {
+ String bbq_board = EMSESP::system_.getBBQKeesGatewayDetails(FUSE_VALUE::BOARD);
+ if (!bbq_board.isEmpty() && settings.board_profile != "CUSTOM") {
+#if defined(EMSESP_DEBUG)
+ EMSESP::logger().info("Overriding board profile with fuse value %s", bbq_board.c_str());
+#endif
+ settings.board_profile = bbq_board;
+ }
+ }
+
+ // if it's CUSTOM no need to load the board profile from the settings
+ // as it's already set
+ if (settings.board_profile == "CUSTOM") {
+ EMSESP::logger().info("Using CUSTOM board profile");
+ EMSESP::system_.set_valid_system_gpios();
+ return;
+ }
+
+ // load the board profile into the data vector
+ // 0=led, 1=dallas, 2=rx, 3=tx, 4=button, 5=phy_type, 6=eth_power, 7=eth_phy_addr, 8=eth_clock_mode, 9=led_type
+ std::vector data(10, 99); // initialize with 99 for all values, just as a safe guard to catch bad gpios
+ if (settings.board_profile != "default") {
+ if (!System::load_board_profile(data, settings.board_profile.c_str())) {
+#if defined(EMSESP_DEBUG)
+ EMSESP::logger().debug("Unable to identify board profile %s", settings.board_profile.c_str());
+#endif
+ settings.board_profile = "default"; // can't find profile, fallback to "default"
+ }
+ }
+
+ // we still don't have a valid board profile. Let's see if we can determine one from the build config or hardware
+ if (settings.board_profile == "default") {
+ EMSESP::logger().info("Autodetecting board profile");
+#if CONFIG_IDF_TARGET_ESP32
+ // check for no PSRAM, could be a E32 or S32?
+ if (!ESP.getPsramSize()) {
+ if (ETH.begin(ETH_PHY_LAN8720, 1, 23, 18, 16, ETH_CLOCK_GPIO0_IN)) {
+ settings.board_profile = "E32"; // Ethernet without PSRAM
+ } else {
+ settings.board_profile = "S32"; // ESP32 standard WiFi without PSRAM
+ }
+ } else {
+ // check for boards with PSRAM, could be a E32V2 otherwise default back to the S32
+ if (ETH.begin(ETH_PHY_LAN8720, 0, 23, 18, 15, ETH_CLOCK_GPIO0_OUT)) {
+ if (analogReadMilliVolts(39) > 700) { // core voltage > 2.6V
+ settings.board_profile = "E32V2_2"; // Ethernet, PSRAM, internal sensors
+ } else {
+ settings.board_profile = "E32V2"; // Ethernet and PSRAM
+ }
+ } else {
+ settings.board_profile = "S32"; // ESP32 standard WiFi with PSRAM
+ }
+ }
+// override if we know the target from the build config like C3, S2, S3 etc..
+#elif CONFIG_IDF_TARGET_ESP32C3
+ settings.board_profile = "C3MINI";
+#elif CONFIG_IDF_TARGET_ESP32S2
+ settings.board_profile = "S2MINI";
+#elif CONFIG_IDF_TARGET_ESP32S3
+ settings.board_profile = "S32S3"; // BBQKees Gateway S3
+#elif CONFIG_IDF_TARGET_ESP32C6
+ settings.board_profile = "CUSTOM";
+#endif
+ // apply the new board profile setting
+ System::load_board_profile(data, settings.board_profile.c_str());
+ }
+
+// log board profile and PSRAM info
+#ifndef EMSESP_STANDALONE
+ uint32_t psram_size = ESP.getPsramSize() / 1024; // in KB
+ if (psram_size > 0) {
+ EMSESP::logger().info("Loaded board profile %s (PSRAM: %lu KB)", settings.board_profile.c_str(), psram_size);
+ } else {
+ EMSESP::logger().info("Loaded board profile %s (PSRAM: not available)", settings.board_profile.c_str());
+ }
+#endif
+
+ // apply the new board profile settings
+ // 0=led, 1=dallas, 2=rx, 3=tx, 4=button, 5=phy_type, 6=eth_power, 7=eth_phy_addr, 8=eth_clock_mode, 9=led_type
+ settings.led_gpio = data[0]; // LED GPIO
+ settings.dallas_gpio = data[1]; // Dallas GPIO
+ settings.rx_gpio = data[2]; // UART Rx GPIO
+ settings.tx_gpio = data[3]; // UART Tx GPIO
+ settings.pbutton_gpio = data[4]; // Button GPIO
+ settings.phy_type = data[5]; // PHY Type
+ settings.eth_power = data[6]; // Ethernet Power GPIO
+ settings.eth_phy_addr = data[7]; // Ethernet PHY Address
+ settings.eth_clock_mode = data[8]; // Ethernet Clock Mode
+ settings.led_type = data[9]; // LED Type
+}
+
+// returns true if the value was changed
+bool WebSettings::check_flag(int prev_v, int new_v, uint8_t flag) {
+ if (prev_v != new_v) {
+ add_flags(flag);
+#if defined(EMSESP_DEBUG)
+ // EMSESP::logger().debug("check_flag: flag %d, prev_v=%d, new_v=%d", flag, prev_v, new_v);
+#endif
+ return true;
+ }
+ return false;
+}
+
+void WebSettings::add_flags(uint8_t flags) {
+ flags_ |= flags;
+}
+
+bool WebSettings::has_flags(uint8_t flags) {
+ return (flags_ & flags) == flags;
+}
+
+void WebSettings::reset_flags() {
+ flags_ = ChangeFlags::NONE;
+}
+
+uint8_t WebSettings::get_flags() {
+ return flags_;
+}
+
+} // namespace emsesp