diff --git a/.github/workflows/pr_check.yml b/.github/workflows/pr_check.yml
new file mode 100644
index 000000000..003969d14
--- /dev/null
+++ b/.github/workflows/pr_check.yml
@@ -0,0 +1,37 @@
+name: 'pr_check'
+
+on:
+ workflow_dispatch:
+ pull_request:
+ branches: dev
+ paths:
+ - '**.c'
+ - '**.cpp'
+ - '**.h'
+ - '**.hpp'
+ - '**.json'
+ - '**.py'
+ - '**.md'
+ - '.github/workflows/pr_check.yml'
+
+jobs:
+ pre-release:
+ name: 'Automatic pre-release build'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Install python 3.11
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+
+ - name: Install PlatformIO
+ run: |
+ pip install wheel
+ pip install -U platformio
+
+ - name: Build native
+ run: |
+ platformio run -e native
diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md
index 9feddd546..891f62694 100644
--- a/CHANGELOG_LATEST.md
+++ b/CHANGELOG_LATEST.md
@@ -10,13 +10,13 @@ For more details go to [www.emsesp.org](https://www.emsesp.org/).
- include HA "unit_of_meas", "stat_cla" and "dev_cla" attributes for Number sensors [#2149](https://github.com/emsesp/EMS-ESP32/issues/2149)
- Bosch CS6800i AW - Silent Mode + Electrical Power Reduction (HP) [#2147](https://github.com/emsesp/EMS-ESP32/issues/2147)
-- system commands for showertimer and showeralert [#2168](https://github.com/emsesp/EMS-ESP32/discussions/2168)
+- /api/system/showeralert and /api/system/showertimer [#2182](https://github.com/emsesp/EMS-ESP32/issues/2182)
## Fixed
- Modbus integration in 3.7.0 missing offset [#2148](https://github.com/emsesp/EMS-ESP32/issues/2148)
- fix changing TZ in NTPsettings without clearing enable+server, added DST support [#2142](https://github.com/emsesp/EMS-ESP32/issues/2142)
+- Support MQTT Discovery (AD) with Domoticz [#2177](https://github.com/emsesp/EMS-ESP32/issues/2177)
+- wwExtra (dhw extra) changed from temperature reading to number
## Changed
-
-- MQTT discovery template to support Domoticz [#2138](https://github.com/emsesp/EMS-ESP32/discussions/2138)
diff --git a/Makefile b/Makefile
index 27669c141..8f6fc27a0 100644
--- a/Makefile
+++ b/Makefile
@@ -43,7 +43,7 @@ DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSO
DEFINES += -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_DEBUG -DEMC_RX_BUFFER_SIZE=1500
DEFINES += $(ARGS)
-DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.0-dev\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
+DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.1-dev\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S3\"
#----------------------------------------------------------------------
# Sources & Files
diff --git a/README.md b/README.md
index 0085b5232..e4f09ff2d 100644
--- a/README.md
+++ b/README.md
@@ -54,8 +54,6 @@ For a live demo go to [demo.emsesp.org](https://demo.emsesp.org). Pick a languag
EMS-ESP is a project created by [proddy](https://github.com/proddy) and owned and maintained by both [proddy](https://github.com/proddy) and [MichaelDvP](https://github.com/MichaelDvP) with support from [BBQKees Electronics](https://bbqkees-electronics.nl).
-You can contact us using [this form](https://emsesp.org/Contact/).
-
If you like **EMS-ESP**, please give it a ✨ on GitHub, or even better fork it and contribute. You can also offer a small donation. This is an open-source project maintained by volunteers, and your support is greatly appreciated.
## **Libraries used**
diff --git a/docs/Modbus-Entity-Registers.md b/docs/Modbus-Entity-Registers.md
index 55e513ce1..c416151dd 100644
--- a/docs/Modbus-Entity-Registers.md
+++ b/docs/Modbus-Entity-Registers.md
@@ -4779,7 +4779,7 @@
| circmode | circulation pump mode | enum [off\|on\|auto\|own prog] | | true | DHW | 3 | 1 | 1 |
| chargeduration | charge duration | uint8 (>=0<=3810) | minutes | true | DHW | 4 | 1 | 15 |
| charge | charge | boolean | | true | DHW | 5 | 1 | 1 |
-| extra | extra | uint8 (>=0<=254) | C | false | DHW | 6 | 1 | 1 |
+| extra | extra | uint8 (>=0<=254) | | false | DHW | 6 | 1 | 1 |
| disinfecting | disinfecting | boolean | | true | DHW | 7 | 1 | 1 |
| disinfectday | disinfection day | enum [mo\|tu\|we\|th\|fr\|sa\|su\|all] | | true | DHW | 8 | 1 | 1 |
| disinfecttime | disinfection time | uint8 (>=0<=1431) | minutes | true | DHW | 9 | 1 | 15 |
@@ -4895,7 +4895,7 @@
| circmode | circulation pump mode | enum [off\|on\|auto\|own prog] | | true | DHW | 3 | 1 | 1 |
| chargeduration | charge duration | uint8 (>=0<=3810) | minutes | true | DHW | 4 | 1 | 15 |
| charge | charge | boolean | | true | DHW | 5 | 1 | 1 |
-| extra | extra | uint8 (>=0<=254) | C | false | DHW | 6 | 1 | 1 |
+| extra | extra | uint8 (>=0<=254) | | false | DHW | 6 | 1 | 1 |
| disinfecting | disinfecting | boolean | | true | DHW | 7 | 1 | 1 |
| disinfectday | disinfection day | enum [mo\|tu\|we\|th\|fr\|sa\|su\|all] | | true | DHW | 8 | 1 | 1 |
| disinfecttime | disinfection time | uint8 (>=0<=1431) | minutes | true | DHW | 9 | 1 | 15 |
@@ -5023,7 +5023,7 @@
| circmode | circulation pump mode | enum [off\|on\|auto\|own prog] | | true | DHW | 3 | 1 | 1 |
| chargeduration | charge duration | uint8 (>=0<=3810) | minutes | true | DHW | 4 | 1 | 15 |
| charge | charge | boolean | | true | DHW | 5 | 1 | 1 |
-| extra | extra | uint8 (>=0<=254) | C | false | DHW | 6 | 1 | 1 |
+| extra | extra | uint8 (>=0<=254) | | false | DHW | 6 | 1 | 1 |
| disinfecting | disinfecting | boolean | | true | DHW | 7 | 1 | 1 |
| disinfectday | disinfection day | enum [mo\|tu\|we\|th\|fr\|sa\|su\|all] | | true | DHW | 8 | 1 | 1 |
| disinfecttime | disinfection time | uint8 (>=0<=1431) | minutes | true | DHW | 9 | 1 | 15 |
@@ -5267,7 +5267,7 @@
| circmode | circulation pump mode | enum [off\|on\|auto\|own prog] | | true | DHW | 3 | 1 | 1 |
| chargeduration | charge duration | uint8 (>=0<=3810) | minutes | true | DHW | 4 | 1 | 15 |
| charge | charge | boolean | | true | DHW | 5 | 1 | 1 |
-| extra | extra | uint8 (>=0<=254) | C | false | DHW | 6 | 1 | 1 |
+| extra | extra | uint8 (>=0<=254) | | false | DHW | 6 | 1 | 1 |
| disinfecting | disinfecting | boolean | | true | DHW | 7 | 1 | 1 |
| disinfectday | disinfection day | enum [mo\|tu\|we\|th\|fr\|sa\|su\|all] | | true | DHW | 8 | 1 | 1 |
| disinfecttime | disinfection time | uint8 (>=0<=1431) | minutes | true | DHW | 9 | 1 | 15 |
@@ -5355,7 +5355,7 @@
| circmode | circulation pump mode | enum [off\|on\|auto\|own prog] | | true | DHW | 3 | 1 | 1 |
| chargeduration | charge duration | uint8 (>=0<=3810) | minutes | true | DHW | 4 | 1 | 15 |
| charge | charge | boolean | | true | DHW | 5 | 1 | 1 |
-| extra | extra | uint8 (>=0<=254) | C | false | DHW | 6 | 1 | 1 |
+| extra | extra | uint8 (>=0<=254) | | false | DHW | 6 | 1 | 1 |
| disinfecting | disinfecting | boolean | | true | DHW | 7 | 1 | 1 |
| disinfectday | disinfection day | enum [mo\|tu\|we\|th\|fr\|sa\|su\|all] | | true | DHW | 8 | 1 | 1 |
| disinfecttime | disinfection time | uint8 (>=0<=1431) | minutes | true | DHW | 9 | 1 | 15 |
@@ -5453,7 +5453,7 @@
| circmode | circulation pump mode | enum [off\|on\|auto\|own prog] | | true | DHW | 3 | 1 | 1 |
| chargeduration | charge duration | uint8 (>=0<=3810) | minutes | true | DHW | 4 | 1 | 15 |
| charge | charge | boolean | | true | DHW | 5 | 1 | 1 |
-| extra | extra | uint8 (>=0<=254) | C | false | DHW | 6 | 1 | 1 |
+| extra | extra | uint8 (>=0<=254) | | false | DHW | 6 | 1 | 1 |
| disinfecting | disinfecting | boolean | | true | DHW | 7 | 1 | 1 |
| disinfectday | disinfection day | enum [mo\|tu\|we\|th\|fr\|sa\|su\|all] | | true | DHW | 8 | 1 | 1 |
| disinfecttime | disinfection time | uint8 (>=0<=1431) | minutes | true | DHW | 9 | 1 | 15 |
diff --git a/docs/dump_entities.csv b/docs/dump_entities.csv
index fcf0a5fe5..10ec99089 100644
--- a/docs/dump_entities.csv
+++ b/docs/dump_entities.csv
@@ -3438,7 +3438,7 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"UI800, BC400",thermostat,4,circmode,circulation pump mode,enum [off\|on\|auto\|own prog], ,true,select.thermostat_dhw_circulation_pump_mode,select.thermostat_dhw_circmode,6,9,1,3,1
"UI800, BC400",thermostat,4,chargeduration,charge duration,uint8 (>=0<=3810),minutes,true,number.thermostat_dhw_charge_duration,number.thermostat_dhw_chargeduration,6,9,15,4,1
"UI800, BC400",thermostat,4,charge,charge,boolean, ,true,switch.thermostat_dhw_charge,switch.thermostat_dhw_charge,6,9,1,5,1
-"UI800, BC400",thermostat,4,extra,extra,uint8 (>=0<=254),C,false,sensor.thermostat_dhw_extra,sensor.thermostat_dhw_extra,6,9,1,6,1
+"UI800, BC400",thermostat,4,extra,extra,uint8 (>=0<=254), ,false,sensor.thermostat_dhw_extra,sensor.thermostat_dhw_extra,6,9,1,6,1
"UI800, BC400",thermostat,4,disinfecting,disinfecting,boolean, ,true,switch.thermostat_dhw_disinfecting,switch.thermostat_dhw_disinfecting,6,9,1,7,1
"UI800, BC400",thermostat,4,disinfectday,disinfection day,enum [mo\|tu\|we\|th\|fr\|sa\|su\|all], ,true,select.thermostat_dhw_disinfection_day,select.thermostat_dhw_disinfectday,6,9,1,8,1
"UI800, BC400",thermostat,4,disinfecttime,disinfection time,uint8 (>=0<=1431),minutes,true,number.thermostat_dhw_disinfection_time,number.thermostat_dhw_disinfecttime,6,9,15,9,1
@@ -3807,7 +3807,7 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"RC200, CW100, CR120, CR50",thermostat,157,circmode,circulation pump mode,enum [off\|on\|auto\|own prog], ,true,select.thermostat_dhw_circulation_pump_mode,select.thermostat_dhw_circmode,6,9,1,3,1
"RC200, CW100, CR120, CR50",thermostat,157,chargeduration,charge duration,uint8 (>=0<=3810),minutes,true,number.thermostat_dhw_charge_duration,number.thermostat_dhw_chargeduration,6,9,15,4,1
"RC200, CW100, CR120, CR50",thermostat,157,charge,charge,boolean, ,true,switch.thermostat_dhw_charge,switch.thermostat_dhw_charge,6,9,1,5,1
-"RC200, CW100, CR120, CR50",thermostat,157,extra,extra,uint8 (>=0<=254),C,false,sensor.thermostat_dhw_extra,sensor.thermostat_dhw_extra,6,9,1,6,1
+"RC200, CW100, CR120, CR50",thermostat,157,extra,extra,uint8 (>=0<=254), ,false,sensor.thermostat_dhw_extra,sensor.thermostat_dhw_extra,6,9,1,6,1
"RC200, CW100, CR120, CR50",thermostat,157,disinfecting,disinfecting,boolean, ,true,switch.thermostat_dhw_disinfecting,switch.thermostat_dhw_disinfecting,6,9,1,7,1
"RC200, CW100, CR120, CR50",thermostat,157,disinfectday,disinfection day,enum [mo\|tu\|we\|th\|fr\|sa\|su\|all], ,true,select.thermostat_dhw_disinfection_day,select.thermostat_dhw_disinfectday,6,9,1,8,1
"RC200, CW100, CR120, CR50",thermostat,157,disinfecttime,disinfection time,uint8 (>=0<=1431),minutes,true,number.thermostat_dhw_disinfection_time,number.thermostat_dhw_disinfecttime,6,9,15,9,1
@@ -3891,7 +3891,7 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,circmode,circulation pump mode,enum [off\|on\|auto\|own prog], ,true,select.thermostat_dhw_circulation_pump_mode,select.thermostat_dhw_circmode,6,9,1,3,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,chargeduration,charge duration,uint8 (>=0<=3810),minutes,true,number.thermostat_dhw_charge_duration,number.thermostat_dhw_chargeduration,6,9,15,4,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,charge,charge,boolean, ,true,switch.thermostat_dhw_charge,switch.thermostat_dhw_charge,6,9,1,5,1
-"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,extra,extra,uint8 (>=0<=254),C,false,sensor.thermostat_dhw_extra,sensor.thermostat_dhw_extra,6,9,1,6,1
+"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,extra,extra,uint8 (>=0<=254), ,false,sensor.thermostat_dhw_extra,sensor.thermostat_dhw_extra,6,9,1,6,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,disinfecting,disinfecting,boolean, ,true,switch.thermostat_dhw_disinfecting,switch.thermostat_dhw_disinfecting,6,9,1,7,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,disinfectday,disinfection day,enum [mo\|tu\|we\|th\|fr\|sa\|su\|all], ,true,select.thermostat_dhw_disinfection_day,select.thermostat_dhw_disinfectday,6,9,1,8,1
"RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410",thermostat,158,disinfecttime,disinfection time,uint8 (>=0<=1431),minutes,true,number.thermostat_dhw_disinfection_time,number.thermostat_dhw_disinfecttime,6,9,15,9,1
@@ -3975,7 +3975,7 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"RC100, CR10, Moduline 1000/1010",thermostat,165,circmode,circulation pump mode,enum [off\|on\|auto\|own prog], ,true,select.thermostat_dhw_circulation_pump_mode,select.thermostat_dhw_circmode,6,9,1,3,1
"RC100, CR10, Moduline 1000/1010",thermostat,165,chargeduration,charge duration,uint8 (>=0<=3810),minutes,true,number.thermostat_dhw_charge_duration,number.thermostat_dhw_chargeduration,6,9,15,4,1
"RC100, CR10, Moduline 1000/1010",thermostat,165,charge,charge,boolean, ,true,switch.thermostat_dhw_charge,switch.thermostat_dhw_charge,6,9,1,5,1
-"RC100, CR10, Moduline 1000/1010",thermostat,165,extra,extra,uint8 (>=0<=254),C,false,sensor.thermostat_dhw_extra,sensor.thermostat_dhw_extra,6,9,1,6,1
+"RC100, CR10, Moduline 1000/1010",thermostat,165,extra,extra,uint8 (>=0<=254), ,false,sensor.thermostat_dhw_extra,sensor.thermostat_dhw_extra,6,9,1,6,1
"RC100, CR10, Moduline 1000/1010",thermostat,165,disinfecting,disinfecting,boolean, ,true,switch.thermostat_dhw_disinfecting,switch.thermostat_dhw_disinfecting,6,9,1,7,1
"RC100, CR10, Moduline 1000/1010",thermostat,165,disinfectday,disinfection day,enum [mo\|tu\|we\|th\|fr\|sa\|su\|all], ,true,select.thermostat_dhw_disinfection_day,select.thermostat_dhw_disinfectday,6,9,1,8,1
"RC100, CR10, Moduline 1000/1010",thermostat,165,disinfecttime,disinfection time,uint8 (>=0<=1431),minutes,true,number.thermostat_dhw_disinfection_time,number.thermostat_dhw_disinfecttime,6,9,15,9,1
@@ -4060,7 +4060,7 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"Rego 2000/3000",thermostat,172,circmode,circulation pump mode,enum [off\|on\|auto\|own prog], ,true,select.thermostat_dhw_circulation_pump_mode,select.thermostat_dhw_circmode,6,9,1,3,1
"Rego 2000/3000",thermostat,172,chargeduration,charge duration,uint8 (>=0<=3810),minutes,true,number.thermostat_dhw_charge_duration,number.thermostat_dhw_chargeduration,6,9,15,4,1
"Rego 2000/3000",thermostat,172,charge,charge,boolean, ,true,switch.thermostat_dhw_charge,switch.thermostat_dhw_charge,6,9,1,5,1
-"Rego 2000/3000",thermostat,172,extra,extra,uint8 (>=0<=254),C,false,sensor.thermostat_dhw_extra,sensor.thermostat_dhw_extra,6,9,1,6,1
+"Rego 2000/3000",thermostat,172,extra,extra,uint8 (>=0<=254), ,false,sensor.thermostat_dhw_extra,sensor.thermostat_dhw_extra,6,9,1,6,1
"Rego 2000/3000",thermostat,172,disinfecting,disinfecting,boolean, ,true,switch.thermostat_dhw_disinfecting,switch.thermostat_dhw_disinfecting,6,9,1,7,1
"Rego 2000/3000",thermostat,172,disinfectday,disinfection day,enum [mo\|tu\|we\|th\|fr\|sa\|su\|all], ,true,select.thermostat_dhw_disinfection_day,select.thermostat_dhw_disinfectday,6,9,1,8,1
"Rego 2000/3000",thermostat,172,disinfecttime,disinfection time,uint8 (>=0<=1431),minutes,true,number.thermostat_dhw_disinfection_time,number.thermostat_dhw_disinfecttime,6,9,15,9,1
@@ -4171,7 +4171,7 @@ device name,device type,product id,shortname,fullname,type [options...] \| (min/
"Rego 3000, UI800, Logamatic BC400",thermostat,253,circmode,circulation pump mode,enum [off\|on\|auto\|own prog], ,true,select.thermostat_dhw_circulation_pump_mode,select.thermostat_dhw_circmode,6,9,1,3,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,chargeduration,charge duration,uint8 (>=0<=3810),minutes,true,number.thermostat_dhw_charge_duration,number.thermostat_dhw_chargeduration,6,9,15,4,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,charge,charge,boolean, ,true,switch.thermostat_dhw_charge,switch.thermostat_dhw_charge,6,9,1,5,1
-"Rego 3000, UI800, Logamatic BC400",thermostat,253,extra,extra,uint8 (>=0<=254),C,false,sensor.thermostat_dhw_extra,sensor.thermostat_dhw_extra,6,9,1,6,1
+"Rego 3000, UI800, Logamatic BC400",thermostat,253,extra,extra,uint8 (>=0<=254), ,false,sensor.thermostat_dhw_extra,sensor.thermostat_dhw_extra,6,9,1,6,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,disinfecting,disinfecting,boolean, ,true,switch.thermostat_dhw_disinfecting,switch.thermostat_dhw_disinfecting,6,9,1,7,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,disinfectday,disinfection day,enum [mo\|tu\|we\|th\|fr\|sa\|su\|all], ,true,select.thermostat_dhw_disinfection_day,select.thermostat_dhw_disinfectday,6,9,1,8,1
"Rego 3000, UI800, Logamatic BC400",thermostat,253,disinfecttime,disinfection time,uint8 (>=0<=1431),minutes,true,number.thermostat_dhw_disinfection_time,number.thermostat_dhw_disinfecttime,6,9,15,9,1
diff --git a/interface/package.json b/interface/package.json
index 176eb165f..1fa3a5d6b 100644
--- a/interface/package.json
+++ b/interface/package.json
@@ -27,7 +27,7 @@
"@mui/icons-material": "^6.1.6",
"@mui/material": "^6.1.6",
"@table-library/react-table-library": "4.1.7",
- "alova": "3.2.1",
+ "alova": "3.2.2",
"async-validator": "^4.2.5",
"jwt-decode": "^4.0.0",
"mime-types": "^2.1.35",
@@ -35,7 +35,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.3.0",
- "react-router-dom": "^6.27.0",
+ "react-router-dom": "^6.28.0",
"react-toastify": "^10.0.6",
"typesafe-i18n": "^5.26.2",
"typescript": "^5.6.3"
@@ -47,21 +47,21 @@
"@preact/preset-vite": "^2.9.1",
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/formidable": "^3",
- "@types/node": "^22.8.7",
+ "@types/node": "^22.9.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react-router-dom": "^5.3.3",
- "concurrently": "^9.0.1",
+ "concurrently": "^9.1.0",
"eslint": "^9.14.0",
"eslint-config-prettier": "^9.1.0",
"formidable": "^3.5.2",
"prettier": "^3.3.3",
"rollup-plugin-visualizer": "^5.12.0",
"terser": "^5.36.0",
- "typescript-eslint": "8.12.2",
+ "typescript-eslint": "8.13.0",
"vite": "^5.4.10",
"vite-plugin-imagemin": "^0.6.1",
- "vite-tsconfig-paths": "^5.0.1"
+ "vite-tsconfig-paths": "^5.1.0"
},
"packageManager": "yarn@4.5.1"
}
diff --git a/interface/src/app/main/Dashboard.tsx b/interface/src/app/main/Dashboard.tsx
index eb89f925b..52030b152 100644
--- a/interface/src/app/main/Dashboard.tsx
+++ b/interface/src/app/main/Dashboard.tsx
@@ -107,7 +107,7 @@ const Dashboard = () => {
},
&:hover .td {
background-color: #177ac9;
- }
+ },
`,
BaseCell: `
&:nth-of-type(2) {
@@ -185,18 +185,16 @@ const Dashboard = () => {
// if its a device (parent node) and has entities
if (di.nodes?.length) {
return (
- <>
-
-
- {showType(di.n, di.t)}
-
+
+
+ {showType(di.n, di.t)}
({di.nodes?.length})
- >
+
);
}
}
if (di.dv) {
- return {di.dv.id.slice(2)};
+ return {di.dv.id.slice(2)};
}
};
@@ -250,10 +248,10 @@ const Dashboard = () => {
onChange={handleShowAll}
>
-
+
-
+
@@ -304,9 +302,7 @@ const Dashboard = () => {
title={formatValue(LL, di.dv?.v, di.dv?.u)}
arrow
>
-
- {formatValue(LL, di.dv?.v, di.dv?.u)}
-
+ {formatValue(LL, di.dv?.v, di.dv?.u)}
@@ -314,10 +310,7 @@ const Dashboard = () => {
{me.admin &&
di.dv?.c &&
!hasMask(di.dv.id, DeviceEntityMask.DV_READONLY) && (
- editDashboardValue(di)}
- >
+ editDashboardValue(di)}>
{
}
&.tr.tr-body.row-select.row-select-single-selected {
background-color: #177ac9;
- font-weight: normal;
}
`
});
@@ -169,11 +168,11 @@ const Devices = () => {
HeaderRow: `
.th {
padding: 8px;
- height: 36px;
`,
Row: `
+ font-weight: bold;
&:hover .td {
- background-color: #177ac9;
+ background-color: #177ac9;
`
}
]);
@@ -216,7 +215,7 @@ const Devices = () => {
background-color: #303030;
},
&:hover .td {
- background-color: #177ac9;
+ background-color: #177ac9;
}
`
}
@@ -523,7 +522,7 @@ const Devices = () => {
@@ -574,7 +573,9 @@ const Devices = () => {
const deviceValueDialogClose = () => {
setDeviceValueDialogOpen(false);
- void sendDeviceData(selectedDevice);
+ if (selectedDevice !== undefined) {
+ void sendDeviceData(selectedDevice);
+ }
};
const renderDeviceData = () => {
diff --git a/interface/src/app/status/SystemLog.tsx b/interface/src/app/status/SystemLog.tsx
index b644b48f5..35b11dbf7 100644
--- a/interface/src/app/status/SystemLog.tsx
+++ b/interface/src/app/status/SystemLog.tsx
@@ -261,16 +261,6 @@ const SystemLog = () => {
>
{LL.EXPORT()}
- {dirtyFlags && dirtyFlags.length !== 0 && (
- }
- variant="contained"
- color="info"
- onClick={saveSettings}
- >
- {LL.APPLY_CHANGES(dirtyFlags.length)}
-
- )}
{readOpen ? (
@@ -315,6 +305,19 @@ const SystemLog = () => {
)}
>
)}
+
+ {dirtyFlags && dirtyFlags.length !== 0 && (
+
+ }
+ variant="contained"
+ color="info"
+ onClick={saveSettings}
+ >
+ {LL.APPLY_CHANGES(dirtyFlags.length)}
+
+
+ )}
=16.8"
react-dom: ">=16.8"
- checksum: 10c0/7db48ffd0b387af0eed060ceaf42075d074e63fbd30f4cf60993526b3610883a9ff82615965001165ed69d2bf2f1bce05c594a21c8d0d845e7b9bf203201116e
+ checksum: 10c0/e2930cf83e8c843a932b008c7ce11059fd83390502a433f0e41f192e3cb80081a621d069eeda7af3cf4bf74d7f8029f0141cdce741bca3f0af82d4bbbc7f7f10
languageName: node
linkType: hard
-"react-router@npm:6.27.0":
- version: 6.27.0
- resolution: "react-router@npm:6.27.0"
+"react-router@npm:6.28.0":
+ version: 6.28.0
+ resolution: "react-router@npm:6.28.0"
dependencies:
- "@remix-run/router": "npm:1.20.0"
+ "@remix-run/router": "npm:1.21.0"
peerDependencies:
react: ">=16.8"
- checksum: 10c0/440d6ee00890cec92a0c2183164149fbb96363efccf52bb132a964f44e51aec2f4b5a0520c67f6f17faddaa4097090fd76f7efe58263947532fceeb11dd4cdf3
+ checksum: 10c0/b435510de78fd882bf6ca9800a73cd90cee418bd1d19efd91b8dcaebde36929bbb589e25d9f7eec24ceb84255e8d538bc1fe54e6ddb5c43c32798e2b720fa76d
languageName: node
linkType: hard
@@ -6771,17 +6771,17 @@ __metadata:
languageName: node
linkType: hard
-"typescript-eslint@npm:8.12.2":
- version: 8.12.2
- resolution: "typescript-eslint@npm:8.12.2"
+"typescript-eslint@npm:8.13.0":
+ version: 8.13.0
+ resolution: "typescript-eslint@npm:8.13.0"
dependencies:
- "@typescript-eslint/eslint-plugin": "npm:8.12.2"
- "@typescript-eslint/parser": "npm:8.12.2"
- "@typescript-eslint/utils": "npm:8.12.2"
+ "@typescript-eslint/eslint-plugin": "npm:8.13.0"
+ "@typescript-eslint/parser": "npm:8.13.0"
+ "@typescript-eslint/utils": "npm:8.13.0"
peerDependenciesMeta:
typescript:
optional: true
- checksum: 10c0/8a80916204da1a056fa3776d7c69d3d21b9a242d8d2bea75ca32b25d86a0c0e28711fb185605024e463b311e582f693166950d6fe0f66f0969603214e190cbcc
+ checksum: 10c0/a84958e7602360c4cb2e6227fd9aae19dd18cdf1a2cfd9ece2a81d54098f80454b5707e861e98547d0b2e5dae552b136aa6733b74f0dd743ca7bfe178083c441
languageName: node
linkType: hard
@@ -6954,9 +6954,9 @@ __metadata:
languageName: node
linkType: hard
-"vite-tsconfig-paths@npm:^5.0.1":
- version: 5.0.1
- resolution: "vite-tsconfig-paths@npm:5.0.1"
+"vite-tsconfig-paths@npm:^5.1.0":
+ version: 5.1.0
+ resolution: "vite-tsconfig-paths@npm:5.1.0"
dependencies:
debug: "npm:^4.1.1"
globrex: "npm:^0.1.2"
@@ -6966,7 +6966,7 @@ __metadata:
peerDependenciesMeta:
vite:
optional: true
- checksum: 10c0/3c68a4d5df21ed4ef81749c20e91c5978989ed06bffc01688b3f1a0fe65951b461a68f0c017ad930a088cfe7a8cc04d0c8d955dfb8719d5edc7fb0ba9bf38a73
+ checksum: 10c0/fff3fc7ada55aa4cfd6cad5c6006a8eaf74df0cc1ed5e9282c0c479012c57095d391379cb1742c394711cbb3ee591c66e27838779d8388297bdf033aa6e57719
languageName: node
linkType: hard
diff --git a/mock-api/rest_server.ts b/mock-api/rest_server.ts
index 7d8e58197..9b209bba6 100644
--- a/mock-api/rest_server.ts
+++ b/mock-api/rest_server.ts
@@ -22,10 +22,10 @@ const router = AutoRouter({
const REST_ENDPOINT_ROOT = '/rest/';
const API_ENDPOINT_ROOT = '/api/';
-// HTTP HEADERS
+// HTTP HEADERS for msgpack
const headers = {
'Access-Control-Allow-Origin': '*',
- 'Content-type': 'application/json'
+ 'Content-type': 'application/msgpack'
};
// GLOBAL VARIABLES
diff --git a/project-words.txt b/project-words.txt
index 47b87c788..f0c517484 100644
--- a/project-words.txt
+++ b/project-words.txt
@@ -1363,4 +1363,6 @@ heattransfer
poolshunt
poolshuntstatus
pooltemp
-stoptime
\ No newline at end of file
+stoptime
+showertimer
+showeralert
\ No newline at end of file
diff --git a/src/analogsensor.cpp b/src/analogsensor.cpp
index b791fef3c..1a0e6f39c 100644
--- a/src/analogsensor.cpp
+++ b/src/analogsensor.cpp
@@ -533,7 +533,7 @@ void AnalogSensor::publish_values(const bool force) {
char val_obj[50];
char val_cond[95];
if (Mqtt::is_nested()) {
- snprintf(val_obj, sizeof(val_obj), "value_json['%02d'].value", sensor.gpio()); // TODO change for Domoticz
+ snprintf(val_obj, sizeof(val_obj), "value_json['%02d']['value']", sensor.gpio());
snprintf(val_cond, sizeof(val_cond), "value_json['%02d'] is defined and %s is defined", sensor.gpio(), val_obj);
} else {
snprintf(val_obj, sizeof(val_obj), "value_json['%s']", sensor.name().c_str());
diff --git a/src/command.cpp b/src/command.cpp
index 0604de642..4b92d61ca 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -379,17 +379,6 @@ uint8_t Command::call(const uint8_t device_type, const char * command, const cha
return CommandRet::NOT_ALLOWED; // command not allowed
}
- // build up the log string for reporting back
- // We send the log message as Warning so it appears in the log (debug is only enabled when compiling with DEBUG)
- std::string ro = EMSESP::system_.readonly_mode() ? "[readonly] " : "";
- auto description = Helpers::translated_word(cf->description_);
- char info_s[100];
- if (strlen(description)) {
- snprintf(info_s, sizeof(info_s), "%s/%s (%s)", dname, cmd, description);
- } else {
- snprintf(info_s, sizeof(info_s), "%s/%s", dname, cmd);
- }
-
// call the function based on command function type
// commands return true or false only (bool)
uint8_t return_code = CommandRet::OK;
@@ -406,7 +395,7 @@ uint8_t Command::call(const uint8_t device_type, const char * command, const cha
}
}
- // report back. If not OK show output from error, otherwise return the HTTP code
+ // report back. If not OK show output from error, otherwise return the error code
if (return_code != CommandRet::OK) {
char error[100];
if (single_command) {
@@ -418,6 +407,16 @@ uint8_t Command::call(const uint8_t device_type, const char * command, const cha
output["message"] = error;
LOG_WARNING(error);
} else {
+ // build up the log string for reporting back
+ // We send the log message as Warning so it appears in the log (debug is only enabled when compiling with DEBUG)
+ std::string ro = EMSESP::system_.readonly_mode() ? "[readonly] " : "";
+ auto description = Helpers::translated_word(cf->description_);
+ char info_s[100];
+ if (strlen(description)) {
+ snprintf(info_s, sizeof(info_s), "%s/%s (%s)", dname, cmd, description);
+ } else {
+ snprintf(info_s, sizeof(info_s), "%s/%s", dname, cmd);
+ }
if (single_command) {
// log as DEBUG (TRACE) regardless if compiled with EMSESP_DEBUG
logger_.debug("%sCalled command %s", ro.c_str(), info_s);
diff --git a/src/common.h b/src/common.h
index 696fcc644..608527620 100644
--- a/src/common.h
+++ b/src/common.h
@@ -52,11 +52,16 @@ using string_vector = std::vector;
#define F_(string_name) (__pstr__##string_name)
#define FL_(list_name) (__pstr__L_##list_name)
-#if defined(EMSESP_TEST) || defined(EMSESP_EN_ONLY)
-// In testing just take one language (en) to save on Flash space
+#if defined(EMSESP_TEST)
+// in Test mode use two languages (en & de) to save flash memory needed for the tests
+#define MAKE_WORD_TRANSLATION(list_name, en, de, ...) static const char * const __pstr__L_##list_name[] = {de, nullptr};
+#define MAKE_TRANSLATION(list_name, shortname, en, de, ...) static const char * const __pstr__L_##list_name[] = {shortname, de, nullptr};
+#elif defined(EMSESP_EN_ONLY)
+// EN only
#define MAKE_WORD_TRANSLATION(list_name, en, ...) static const char * const __pstr__L_##list_name[] = {en, nullptr};
#define MAKE_TRANSLATION(list_name, shortname, en, ...) static const char * const __pstr__L_##list_name[] = {shortname, en, nullptr};
#elif defined(EMSESP_DE_ONLY)
+// EN + DE
#define MAKE_WORD_TRANSLATION(list_name, en, de, ...) static const char * const __pstr__L_##list_name[] = {de, nullptr};
#define MAKE_TRANSLATION(list_name, shortname, en, de, ...) static const char * const __pstr__L_##list_name[] = {shortname, de, nullptr};
#else
diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp
index 7e93f60f2..ca05d4b84 100644
--- a/src/devices/thermostat.cpp
+++ b/src/devices/thermostat.cpp
@@ -4912,7 +4912,7 @@ void Thermostat::register_device_values_dhw(std::shared_ptrwwCharge_, DeviceValueType::BOOL, FL_(wwCharge), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwcharge));
- register_device_value(tag, &dhw->wwExtra_, DeviceValueType::UINT8, FL_(wwExtra), DeviceValueUOM::DEGREES);
+ register_device_value(tag, &dhw->wwExtra_, DeviceValueType::BOOL, FL_(wwExtra), DeviceValueUOM::NONE);
register_device_value(tag, &dhw->wwDisinfecting_, DeviceValueType::BOOL, FL_(wwDisinfecting), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwDisinfect));
register_device_value(
tag, &dhw->wwDisinfectDay_, DeviceValueType::ENUM, FL_(enum_dayOfWeek), FL_(wwDisinfectDay), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwDisinfectDay));
diff --git a/src/emsesp.cpp b/src/emsesp.cpp
index a1c69ac4a..b2c826353 100644
--- a/src/emsesp.cpp
+++ b/src/emsesp.cpp
@@ -910,14 +910,14 @@ std::string EMSESP::pretty_telegram(std::shared_ptr telegram) {
std::string str;
str.reserve(200);
if (telegram->operation == Telegram::Operation::RX_READ) {
- str = src_name + "(" + Helpers::hextoa(src) + ") -R-> " + dest_name + "(" + Helpers::hextoa(dest) + "), " + type_name + "("
+ str = src_name + "(" + Helpers::hextoa(src) + ") -> " + dest_name + "(" + Helpers::hextoa(dest) + "), R, " + type_name + "("
+ Helpers::hextoa(telegram->type_id) + "), length: " + Helpers::itoa(telegram->message_data[0])
+ ((telegram->message_length > 1) ? ", data: " + Helpers::data_to_hex(telegram->message_data + 1, telegram->message_length - 1) : "");
} else if (telegram->dest == 0) {
- str = src_name + "(" + Helpers::hextoa(src) + ") -B-> " + dest_name + "(" + Helpers::hextoa(dest) + "), " + type_name + "("
+ str = src_name + "(" + Helpers::hextoa(src) + ") -> " + dest_name + "(" + Helpers::hextoa(dest) + "), B, " + type_name + "("
+ Helpers::hextoa(telegram->type_id) + "), data: " + telegram->to_string_message();
} else {
- str = src_name + "(" + Helpers::hextoa(src) + ") -W-> " + dest_name + "(" + Helpers::hextoa(dest) + "), " + type_name + "("
+ str = src_name + "(" + Helpers::hextoa(src) + ") -> " + dest_name + "(" + Helpers::hextoa(dest) + "), W, " + type_name + "("
+ Helpers::hextoa(telegram->type_id) + "), data: " + telegram->to_string_message();
}
@@ -1016,13 +1016,14 @@ void EMSESP::process_version(std::shared_ptr telegram) {
// some devices store the protocol type (HT3, Buderus) in the last byte
uint8_t brand;
if (telegram->message_length >= 10) {
- brand = EMSdevice::decode_brand(telegram->message_data[9]); // TODO should be offset + 9?
+ brand = EMSdevice::decode_brand(telegram->message_data[9]);
} else {
brand = EMSdevice::Brand::NO_BRAND; // unknown
}
// add it - will be overwritten if device already exists
(void)add_device(device_id, product_id, version, brand);
+
// request the deviceName from telegram 0x01
send_read_request(EMSdevice::EMS_TYPE_NAME, device_id, 27);
}
diff --git a/src/helpers.cpp b/src/helpers.cpp
index dcef19c3b..5429dc5f1 100644
--- a/src/helpers.cpp
+++ b/src/helpers.cpp
@@ -603,6 +603,10 @@ bool Helpers::value2bool(const char * value, bool & value_b) {
return true; // is a bool
}
+#ifdef EMSESP_STANDALONE
+ emsesp::EMSESP::logger().debug("Error. value2bool: %s is not a boolean", value);
+#endif
+
return false; // not a bool
}
@@ -764,7 +768,7 @@ uint8_t Helpers::count_items(const char * const ** list) {
// if force_en is true always take the EN non-translated word
const char * Helpers::translated_word(const char * const * strings, const bool force_en) {
uint8_t language_index = EMSESP::system_.language_index();
- uint8_t index = 0;
+ uint8_t index = 0; // default en
if (!strings) {
return ""; // no translations
@@ -774,6 +778,7 @@ const char * Helpers::translated_word(const char * const * strings, const bool f
if (!force_en && (Helpers::count_items(strings) >= language_index + 1 && strlen(strings[language_index]))) {
index = language_index;
}
+
return strings[index];
}
diff --git a/src/mqtt.cpp b/src/mqtt.cpp
index 86c8db03d..a52e1d5ae 100644
--- a/src/mqtt.cpp
+++ b/src/mqtt.cpp
@@ -934,14 +934,13 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
char config_topic[70];
snprintf(config_topic, sizeof(config_topic), "%s/%s_%s/config", mqtt_basename_.c_str(), device_name, entity_with_tag);
- bool add_ha_classes = true; // default we'll add the "unit_of_meas", "stat_cla" and "dev_cla" attributes
-
// create the topic
- // depending on the type and whether the device entity is writable (a command)
+ // depending on the type and whether the device entity is writable (i.e. a command)
// https://developers.home-assistant.io/docs/core/entity
char topic[MQTT_TOPIC_MAX_SIZE];
- // if it's a command then we can use Number, Switch, Select or Text. Otherwise stick to Sensor
+ topic[0] = '\0'; // nullify, making it empty
if (has_cmd) {
+ // if it's a command then we can use Number, Switch, Select or Text. Otherwise stick to Sensor
switch (type) {
case DeviceValueType::INT8:
case DeviceValueType::UINT8:
@@ -950,45 +949,40 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
case DeviceValueType::UINT24:
case DeviceValueType::UINT32:
// number - https://www.home-assistant.io/integrations/number.mqtt
- // older Domoticz does not support number, use sensor
+ // older Domoticz does not support number, will default to Sensor
if (discovery_type() == discoveryType::HOMEASSISTANT || discovery_type() == discoveryType::DOMOTICZ_LATEST) {
snprintf(topic, sizeof(topic), "number/%s", config_topic);
- } else {
- snprintf(topic, sizeof(topic), "sensor/%s", config_topic);
}
break;
case DeviceValueType::BOOL:
// switch - https://www.home-assistant.io/integrations/switch.mqtt
snprintf(topic, sizeof(topic), "switch/%s", config_topic);
- add_ha_classes = false;
break;
case DeviceValueType::ENUM:
- snprintf(topic, sizeof(topic), "select/%s", config_topic);
- add_ha_classes = false;
- break;
- case DeviceValueType::CMD: // hardcoded commands are always ENUMS
// select - https://www.home-assistant.io/integrations/select.mqtt
+ snprintf(topic, sizeof(topic), "select/%s", config_topic);
+ break;
+ case DeviceValueType::CMD:
if (uom == DeviceValueUOM::NONE) {
- snprintf(topic, sizeof(topic), "select/%s", config_topic);
+ snprintf(topic, sizeof(topic), "select/%s", config_topic); // hardcoded commands are always ENUMS
} else if (discovery_type() == discoveryType::HOMEASSISTANT || discovery_type() == discoveryType::DOMOTICZ_LATEST) {
snprintf(topic, sizeof(topic), "number/%s", config_topic);
- } else {
- snprintf(topic, sizeof(topic), "sensor/%s", config_topic);
}
- add_ha_classes = false;
break;
case DeviceValueType::STRING:
// text - https://www.home-assistant.io/integrations/text.mqtt
- snprintf(topic, sizeof(topic), "text/%s", config_topic); // e.g. set_datetime, set_holiday, set_wwswitchtime
- add_ha_classes = false;
+ // Domoticz does not support text, will default to Sensor
+ if (discovery_type() == discoveryType::HOMEASSISTANT) {
+ snprintf(topic, sizeof(topic), "text/%s", config_topic); // e.g. set_datetime, set_holiday, set_wwswitchtime
+ }
break;
default:
- // plain old sensor
- snprintf(topic, sizeof(topic), "sensor/%s", config_topic);
break;
}
- } else {
- // it is not a command and a read-only sensor. Use then either sensor or binary_sensor
+ }
+
+ // if at this point we don't have a topic created yet, create a default sensor one. We always need a topic.
+ if (!strnlen(topic, sizeof(topic))) {
snprintf(topic, sizeof(topic), (type == DeviceValueType::BOOL) ? "binary_sensor/%s" : "sensor/%s", config_topic); // binary sensor (for booleans)
}
@@ -1054,21 +1048,6 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
doc["max"] = dv_set_max;
snprintf(sample_val, sizeof(sample_val), "%i", dv_set_min);
}
-
- // set icons
- // since these don't have a device class we need to add the icon ourselves
- switch (uom) {
- case DeviceValueUOM::DEGREES:
- case DeviceValueUOM::DEGREES_R:
- case DeviceValueUOM::K:
- doc["ic"] = F_(icondegrees);
- break;
- case DeviceValueUOM::PERCENT:
- doc["ic"] = F_(iconpercent);
- break;
- default:
- break;
- }
}
// friendly name =
@@ -1129,26 +1108,23 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
// Domoticz doesn't support value templates, so we just use the value directly
// Also omit the uom and other state classes
doc["val_tpl"] = (std::string) "{{" + val_obj + "}}";
- // add_ha_classes = false; // don't add the classes, categories of uom (dev_cla, stat_cla)
}
}
- // Add the state class, device class and sometimes the icon.
- // Used only for read-only sensors like Sensor and Binary Sensor but also Numbers
- if (add_ha_classes) {
- // first set the catagory for System entities
- // https://github.com/emsesp/EMS-ESP32/discussions/1459#discussioncomment-7694873
- if (device_type == EMSdevice::DeviceType::SYSTEM) {
- doc["ent_cat"] = "diagnostic";
- }
- add_ha_uom(doc.as(), type, uom, entity); // add the UoM, device and state class
+ // Add the state class, device class and an optional icon based on the uom
+ // first set the catagory for System entities
+ // https://github.com/emsesp/EMS-ESP32/discussions/1459#discussioncomment-7694873
+ if (device_type == EMSdevice::DeviceType::SYSTEM) {
+ doc["ent_cat"] = "diagnostic"; // instead of config
}
+ add_ha_uom(doc.as(), type, uom, entity);
doc["dev"] = dev_json;
return queue_ha(topic, doc.as());
}
+// Add the state class, device class and an optional icon based on the uom
void Mqtt::add_ha_uom(JsonObject doc, const uint8_t type, const uint8_t uom, const char * entity) {
const char * dc_ha = "dev_cla"; // device class
const char * sc_ha = "stat_cla"; // state class
@@ -1169,16 +1145,19 @@ void Mqtt::add_ha_uom(JsonObject doc, const uint8_t type, const uint8_t uom, con
}
// set state and device class
+ // also icon, when there is no device class that sets one
switch (uom) {
case DeviceValueUOM::DEGREES:
case DeviceValueUOM::DEGREES_R:
case DeviceValueUOM::K:
doc[sc_ha] = F_(measurement);
doc[dc_ha] = "temperature";
+ doc["ic"] = F_(icondegrees); // icon
break;
case DeviceValueUOM::PERCENT:
doc[sc_ha] = F_(measurement);
doc[dc_ha] = "power_factor";
+ doc["ic"] = F_(iconpercent); // icon
break;
case DeviceValueUOM::SECONDS:
case DeviceValueUOM::MINUTES:
@@ -1256,8 +1235,6 @@ void Mqtt::add_ha_uom(JsonObject doc, const uint8_t type, const uint8_t uom, con
}
bool Mqtt::publish_ha_climate_config(const int8_t tag, const bool has_roomtemp, const bool remove, const int16_t min, const uint32_t max) {
- // TODO: check if Domoticz supports climate via MQTT discovery, otherwise exit this function if (discovery_type() != discoveryType::HOMEASSISTANT
-
uint8_t hc_num = tag;
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
diff --git a/src/system.cpp b/src/system.cpp
index 7738caf43..fdc19ad6a 100644
--- a/src/system.cpp
+++ b/src/system.cpp
@@ -52,12 +52,17 @@
namespace emsesp {
-// Languages supported. Note: the order is important and must match locale_translations.h
-#if defined(EMSESP_TEST) || defined(EMSESP_EN_ONLY)
-// in Debug mode use one language (en) to save flash memory needed for the tests
+// Languages supported. Note: the order is important
+// and must match locale_translations.h and common.h
+#if defined(EMSESP_TEST)
+// in Test mode use two languages (en & de) to save flash memory needed for the tests
+const char * const languages[] = {EMSESP_LOCALE_EN, EMSESP_LOCALE_DE};
+#elif defined(EMSESP_EN_ONLY)
+// EN only
const char * const languages[] = {EMSESP_LOCALE_EN};
#elif defined(EMSESP_DE_ONLY)
-const char * const languages[] = {EMSESP_LOCALE_DE};
+// EN + DE
+const char * const languages[] = {EMSESP_LOCALE_EN, EMSESP_LOCALE_DE};
#else
const char * const languages[] = {EMSESP_LOCALE_EN,
EMSESP_LOCALE_DE,
@@ -92,7 +97,7 @@ uint8_t System::language_index() {
return i;
}
}
- return 0; // EN
+ return 0; // EN only
}
// send raw to ems
diff --git a/src/temperaturesensor.cpp b/src/temperaturesensor.cpp
index 658f55443..0e67cf291 100644
--- a/src/temperaturesensor.cpp
+++ b/src/temperaturesensor.cpp
@@ -482,7 +482,7 @@ void TemperatureSensor::publish_values(const bool force) {
char val_obj[70];
char val_cond[170];
if (Mqtt::is_nested()) {
- snprintf(val_obj, sizeof(val_obj), "value_json['%s'].temp", sensor.id().c_str()); // TODO change for Domoticz
+ snprintf(val_obj, sizeof(val_obj), "value_json['%s']['temp']", sensor.id().c_str());
snprintf(val_cond, sizeof(val_cond), "value_json['%s'] is defined and %s is defined", sensor.id().c_str(), val_obj);
} else {
snprintf(val_obj, sizeof(val_obj), "value_json['%s']", sensor.name().c_str());
diff --git a/src/test/test.cpp b/src/test/test.cpp
index c71d0bd12..03854c796 100644
--- a/src/test/test.cpp
+++ b/src/test/test.cpp
@@ -307,7 +307,15 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
}
shell.printfln("Testing Adding a device (product_id %d), with all values...", id2);
test("add", id1, id2);
- shell.invoke_command("show values");
+ shell.invoke_command("show devices");
+ ok = true;
+ }
+
+ // set the language
+ if (command == "locale") {
+ shell.printfln("Testing setting locale to %s", id1_s.c_str());
+ EMSESP::system_.locale(id1_s.c_str());
+ shell.invoke_command("show");
ok = true;
}
diff --git a/src/version.h b/src/version.h
index 8117ed7a7..bc1eb86f2 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1 +1 @@
-#define EMSESP_APP_VERSION "3.7.1-dev.3"
\ No newline at end of file
+#define EMSESP_APP_VERSION "3.7.1-dev.4"
\ No newline at end of file