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 && ( - - )} {readOpen ? ( @@ -315,6 +305,19 @@ const SystemLog = () => { )} )} + + {dirtyFlags && dirtyFlags.length !== 0 && ( + + + + )} =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