diff --git a/.github/workflows/github-releases-to-discord.yml b/.github/workflows/github-releases-to-discord.yml index 54bf9702e..140d6a63e 100644 --- a/.github/workflows/github-releases-to-discord.yml +++ b/.github/workflows/github-releases-to-discord.yml @@ -10,6 +10,7 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: GitHub Releases To Discord uses: SethCohen/github-releases-to-discord@v1.13.1 with: diff --git a/.github/workflows/pre_release.yml b/.github/workflows/pre_release.yml index 9fdc19c13..ca1fac59b 100644 --- a/.github/workflows/pre_release.yml +++ b/.github/workflows/pre_release.yml @@ -11,25 +11,33 @@ jobs: name: 'Automatic pre-release build' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 + - name: Enable Corepack run: corepack enable - - uses: actions/setup-python@v5 + + - name: Install python 3.11 + uses: actions/setup-python@v5 with: python-version: '3.11' - - name: Use Node.js 20.x + + - name: Install Node.js 20 uses: actions/setup-node@v4 with: node-version: '20.x' - - name: Get EMS-ESP source code and version + + - name: Get EMS-ESP version id: build_info run: | version=`grep -E '^#define EMSESP_APP_VERSION' ./src/version.h | awk -F'"' '{print $2}'` echo "VERSION=$version" >> $GITHUB_OUTPUT + - name: Install PlatformIO run: | python -m pip install --upgrade pip pip install -U platformio + - name: Build WebUI run: | cd interface @@ -38,9 +46,11 @@ jobs: sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts yarn build yarn webUI - - name: Build all target environments from default_envs + + - name: Build all PIO target environments from default_envs run: | platformio run + - name: Create GitHub Release id: 'automatic_releases' uses: emsesp/action-automatic-releases@v1.0.0 diff --git a/.github/workflows/sonar_check.yml b/.github/workflows/sonar_check.yml index 9d983fc09..6c8da39e3 100644 --- a/.github/workflows/sonar_check.yml +++ b/.github/workflows/sonar_check.yml @@ -16,13 +16,17 @@ jobs: env: BUILD_WRAPPER_OUT_DIR: bw-output steps: - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Install sonar-scanner and build-wrapper uses: SonarSource/sonarcloud-github-c-cpp@v2 + - name: Run build-wrapper run: build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} make all + - name: Run sonar-scanner env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/tagged_release.yml b/.github/workflows/tagged_release.yml index 147cf97a2..2f3916aa6 100644 --- a/.github/workflows/tagged_release.yml +++ b/.github/workflows/tagged_release.yml @@ -11,22 +11,27 @@ jobs: name: 'Tagged Release' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 + - name: Enable Corepack run: corepack enable - - uses: actions/setup-python@v5 + + - name: Install python 3.11 + uses: actions/setup-python@v5 with: python-version: '3.11' - - name: Use Node.js 20.x + + - name: Install Node.js 20 uses: actions/setup-node@v4 with: node-version: '20.x' + - name: Install PlatformIO run: | python -m pip install --upgrade pip pip install -U platformio - platformio upgrade - pio pkg update + - name: Build WebUI run: | cd interface @@ -35,9 +40,11 @@ jobs: sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts yarn build yarn webUI - - name: Build all target environments from default_envs + + - name: Build all PIO target environments from default_envs run: | platformio run + - name: Create GitHub Release uses: emsesp/action-automatic-releases@v1.0.0 with: diff --git a/.gitignore b/.gitignore index 8eef96223..f7be0a8b2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ .vscode/c_cpp_properties.json .vscode/extensions.json .vscode/launch.json -#.vscode/settings.json +.vscode/settings.json # c++ compiling .clang_complete diff --git a/.vscode/settings.json b/.vscode/settings.json index 0eaa9d107..ab21de54e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -89,7 +89,8 @@ "**/ArduinoJson/**" ], "cSpell.enableFiletypes": [ - "!typescript" + "ini", + "makefile" ], "typescript.preferences.preferTypeOnlyAutoImports": true } \ No newline at end of file diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 5a5e0a2bb..92ffba0d3 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -35,12 +35,17 @@ - RC310 cooling parameters [#1857](https://github.com/emsesp/EMS-ESP32/issues/1857) - command `api/device/entities` [#1897](https://github.com/emsesp/EMS-ESP32/issues/1897) - switchprogmode [#1903] -- Autodetect and download firmware upgrades +- Autodetect and download firmware upgrades via the WebUI +- command 'show log' that lists out the current weblog buffer, showing last messages. +- default web log buffer to 25 lines for ESP32s with no PSRAM +- Try and determine correct board profile if none is set ## Fixed - remote thermostat emulation for RC200 on Rego2000/3000 thermostats [#1691](https://github.com/emsesp/EMS-ESP32/discussions/1691) - log shows data for F7/F9 requests +- Detection of LittleFS for factory setting wasn't working +- Check for bad GPIOs with Ethernet before the ethernet is initialized ## Changed @@ -58,4 +63,5 @@ - Change key-names in JSON to be compliant and consistent [#1860](https://github.com/emsesp/EMS-ESP32/issues/1860) - Updates to webUI [#1920](https://github.com/emsesp/EMS-ESP32/issues/1920) - Correct firmware naming #1933 [#1933](https://github.com/emsesp/EMS-ESP32/issues/1933) - \ No newline at end of file +- Don't start Serial console if not connected to a Serial port. Will initiate manually after a CTRL-C +- WebLog UI matches color schema of the terminal console correctly diff --git a/Makefile b/Makefile index bf03a0f72..54137f214 100644 --- a/Makefile +++ b/Makefile @@ -81,8 +81,8 @@ CPPFLAGS += -g3 CPPFLAGS += -Os CFLAGS += $(CPPFLAGS) -CFLAGS += -Wall -Wextra -Werror -Wswitch-enum -Wno-unused-parameter -Wno-inconsistent-missing-override -Wno-missing-braces -Wno-unused-lambda-capture -Wno-sign-compare - +CFLAGS += -Wall -Wextra -Werror -Wswitch-enum +CFLAGS += -Wno-tautological-constant-out-of-range-compare -Wno-unused-parameter -Wno-inconsistent-missing-override -Wno-missing-braces -Wno-unused-lambda-capture -Wno-sign-compare CXXFLAGS += $(CFLAGS) -MMD #---------------------------------------------------------------------- diff --git a/README.md b/README.md index 90a64e624..b157e14a9 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,13 @@ - Easy first-time configuration via a web Captive Portal - Support for more than [120+ EMS devices](https://emsesp.org/All-Devices/) (boilers, thermostats, solar modules, mixer modules, heat pumps, gateways, switches, heat sources) +## **Installing** + +Go to [install.emsesp.org](https://install.emsesp.org) or look at the documentation link below on the different ways to install EMS-ESP. + ## **Documentation** -For the complete documentation on how to install, configure and get support visit the [EMS-ESP Wiki](https://emsesp.org). +For the complete documentation on how to install, configure and get support visit the [documentation at emsesp.org](https://emsesp.org). ## **Support** @@ -35,7 +39,7 @@ If you like **EMS-ESP**, please give it a star, or fork it and contribute or off ## **Demo** -For a live demo of the Web UI click [here](https://demo.emsesp.org) and log in with any username/password. +For a live demo of the Web UI click [demo.emsesp.org](https://demo.emsesp.org) and log in with any username/password, and change the language to English. ## **Contributors ✨** @@ -67,6 +71,6 @@ This program is licensed under GPL-3.0 ![Console](media/console0.png) -### In Home Assistant +### Home Assistant ![Home Assistant](media/ha_lovelace.png) diff --git a/dump_entities.csv b/dump_entities.csv index 4eca57e4d..a1db027ef 100644 --- a/dump_entities.csv +++ b/dump_entities.csv @@ -40,12 +40,12 @@ CS6800i/WLW176i,boiler,8,emergencytemp,emergency temperature,uint8 (>=15<=70),C, CS6800i/WLW176i,boiler,8,nrgtotal,total energy,uint24 (>=0<=167772),kWh,false,sensor.boiler_total_energy,sensor.boiler_nrgtotal,5,0,1/100,80,2 CS6800i/WLW176i,boiler,8,nrg,energy,uint24 (>=0<=167772),kWh,false,sensor.boiler_dhw_energy,sensor.boiler_dhw_nrg,5,9,1/100,0,2 CS6800i/WLW176i,boiler,8,nrgheat,energy heating,uint24 (>=0<=167772),kWh,false,sensor.boiler_energy_heating,sensor.boiler_nrgheat,5,0,1/100,82,2 -CS6800i/WLW176i,boiler,8,nrgcool,energy cooling,uint24 (>=0<=167772),kWh,false,sensor.boiler_energy_cooling,sensor.boiler_nrgcool,5,0,1/100,-1,2 +CS6800i/WLW176i,boiler,8,nrgcool,energy cooling,uint24 (>=0<=167772),kWh,false,sensor.boiler_energy_cooling,sensor.boiler_nrgcool,5,0,1/100,264,2 CS6800i/WLW176i,boiler,8,metertotal,meter total,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_total,sensor.boiler_metertotal,5,0,1/100,84,2 CS6800i/WLW176i,boiler,8,metercomp,meter compressor,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_compressor,sensor.boiler_metercomp,5,0,1/100,86,2 CS6800i/WLW176i,boiler,8,metereheat,meter e-heater,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_e-heater,sensor.boiler_metereheat,5,0,1/100,88,2 CS6800i/WLW176i,boiler,8,meterheat,meter heating,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_heating,sensor.boiler_meterheat,5,0,1/100,90,2 -CS6800i/WLW176i,boiler,8,metercool,meter cooling,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_cooling,sensor.boiler_metercool,5,0,1/100,-1,2 +CS6800i/WLW176i,boiler,8,metercool,meter cooling,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_cooling,sensor.boiler_metercool,5,0,1/100,266,2 CS6800i/WLW176i,boiler,8,meter,meter,uint24 (>=0<=167772),kWh,false,sensor.boiler_dhw_meter,sensor.boiler_dhw_meter,5,9,1/100,2,2 CS6800i/WLW176i,boiler,8,uptimetotal,heatpump total uptime,time (>=0<=279620),minutes,false,sensor.boiler_heatpump_total_uptime,sensor.boiler_uptimetotal,5,0,1/60,92,2 CS6800i/WLW176i,boiler,8,uptimecontrol,total operating time heat,time (>=0<=279620),minutes,false,sensor.boiler_total_operating_time_heat,sensor.boiler_uptimecontrol,5,0,1/60,94,2 @@ -2090,12 +2090,12 @@ Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i,bo Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i,boiler,172,nrgtotal,total energy,uint24 (>=0<=167772),kWh,false,sensor.boiler_total_energy,sensor.boiler_nrgtotal,5,0,1/100,80,2 Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i,boiler,172,nrg,energy,uint24 (>=0<=167772),kWh,false,sensor.boiler_dhw_energy,sensor.boiler_dhw_nrg,5,9,1/100,0,2 Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i,boiler,172,nrgheat,energy heating,uint24 (>=0<=167772),kWh,false,sensor.boiler_energy_heating,sensor.boiler_nrgheat,5,0,1/100,82,2 -Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i,boiler,172,nrgcool,energy cooling,uint24 (>=0<=167772),kWh,false,sensor.boiler_energy_cooling,sensor.boiler_nrgcool,5,0,1/100,-1,2 +Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i,boiler,172,nrgcool,energy cooling,uint24 (>=0<=167772),kWh,false,sensor.boiler_energy_cooling,sensor.boiler_nrgcool,5,0,1/100,264,2 Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i,boiler,172,metertotal,meter total,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_total,sensor.boiler_metertotal,5,0,1/100,84,2 Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i,boiler,172,metercomp,meter compressor,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_compressor,sensor.boiler_metercomp,5,0,1/100,86,2 Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i,boiler,172,metereheat,meter e-heater,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_e-heater,sensor.boiler_metereheat,5,0,1/100,88,2 Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i,boiler,172,meterheat,meter heating,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_heating,sensor.boiler_meterheat,5,0,1/100,90,2 -Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i,boiler,172,metercool,meter cooling,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_cooling,sensor.boiler_metercool,5,0,1/100,-1,2 +Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i,boiler,172,metercool,meter cooling,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_cooling,sensor.boiler_metercool,5,0,1/100,266,2 Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i,boiler,172,meter,meter,uint24 (>=0<=167772),kWh,false,sensor.boiler_dhw_meter,sensor.boiler_dhw_meter,5,9,1/100,2,2 Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i,boiler,172,uptimetotal,heatpump total uptime,time (>=0<=279620),minutes,false,sensor.boiler_heatpump_total_uptime,sensor.boiler_uptimetotal,5,0,1/60,92,2 Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i,boiler,172,uptimecontrol,total operating time heat,time (>=0<=279620),minutes,false,sensor.boiler_total_operating_time_heat,sensor.boiler_uptimecontrol,5,0,1/60,94,2 @@ -2287,12 +2287,12 @@ Geo 5xx,boiler,173,emergencytemp,emergency temperature,uint8 (>=15<=70),C,true,n Geo 5xx,boiler,173,nrgtotal,total energy,uint24 (>=0<=167772),kWh,false,sensor.boiler_total_energy,sensor.boiler_nrgtotal,5,0,1/100,80,2 Geo 5xx,boiler,173,nrg,energy,uint24 (>=0<=167772),kWh,false,sensor.boiler_dhw_energy,sensor.boiler_dhw_nrg,5,9,1/100,0,2 Geo 5xx,boiler,173,nrgheat,energy heating,uint24 (>=0<=167772),kWh,false,sensor.boiler_energy_heating,sensor.boiler_nrgheat,5,0,1/100,82,2 -Geo 5xx,boiler,173,nrgcool,energy cooling,uint24 (>=0<=167772),kWh,false,sensor.boiler_energy_cooling,sensor.boiler_nrgcool,5,0,1/100,-1,2 +Geo 5xx,boiler,173,nrgcool,energy cooling,uint24 (>=0<=167772),kWh,false,sensor.boiler_energy_cooling,sensor.boiler_nrgcool,5,0,1/100,264,2 Geo 5xx,boiler,173,metertotal,meter total,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_total,sensor.boiler_metertotal,5,0,1/100,84,2 Geo 5xx,boiler,173,metercomp,meter compressor,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_compressor,sensor.boiler_metercomp,5,0,1/100,86,2 Geo 5xx,boiler,173,metereheat,meter e-heater,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_e-heater,sensor.boiler_metereheat,5,0,1/100,88,2 Geo 5xx,boiler,173,meterheat,meter heating,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_heating,sensor.boiler_meterheat,5,0,1/100,90,2 -Geo 5xx,boiler,173,metercool,meter cooling,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_cooling,sensor.boiler_metercool,5,0,1/100,-1,2 +Geo 5xx,boiler,173,metercool,meter cooling,uint24 (>=0<=167772),kWh,false,sensor.boiler_meter_cooling,sensor.boiler_metercool,5,0,1/100,266,2 Geo 5xx,boiler,173,meter,meter,uint24 (>=0<=167772),kWh,false,sensor.boiler_dhw_meter,sensor.boiler_dhw_meter,5,9,1/100,2,2 Geo 5xx,boiler,173,uptimetotal,heatpump total uptime,time (>=0<=279620),minutes,false,sensor.boiler_heatpump_total_uptime,sensor.boiler_uptimetotal,5,0,1/60,92,2 Geo 5xx,boiler,173,uptimecontrol,total operating time heat,time (>=0<=279620),minutes,false,sensor.boiler_total_operating_time_heat,sensor.boiler_uptimecontrol,5,0,1/60,94,2 @@ -3355,16 +3355,16 @@ UI800/BC400,thermostat,4,hpoperatingstate,heatpump operating state,enum [heating UI800/BC400,thermostat,4,controlmode,control mode,enum [weather compensated\|outside basepoint\|n/a\|room\|power\|constant], ,true,select.thermostat_hc1_control_mode,select.thermostat_hc1_controlmode,6,1,1,24,1 UI800/BC400,thermostat,4,program,program,enum [prog 1\|prog 2], ,true,select.thermostat_hc1_program,select.thermostat_hc1_program,6,1,1,25,1 UI800/BC400,thermostat,4,tempautotemp,temporary set temperature automode,int8 (>=-1<=30),C,true,number.thermostat_hc1_temporary_set_temperature_automode,number.thermostat_hc1_tempautotemp,6,1,1/2,26,1 -UI800/BC400,thermostat,4,remoteseltemp,temporary set temperature from remote,int8 (>=-63<=63),C,false,sensor.thermostat_hc1_temporary_set_temperature_from_remote,sensor.thermostat_hc1_remoteseltemp,6,1,1/2,27,1 +UI800/BC400,thermostat,4,remoteseltemp,temporary set temperature from remote,int8 (>=-1<=30),C,true,number.thermostat_hc1_temporary_set_temperature_from_remote,number.thermostat_hc1_remoteseltemp,6,1,1/2,27,1 UI800/BC400,thermostat,4,fastheatup,fast heatup,uint8 (>=0<=100),%,true,number.thermostat_hc1_fast_heatup,number.thermostat_hc1_fastheatup,6,1,1,28,1 UI800/BC400,thermostat,4,switchonoptimization,switch-on optimization,boolean, ,true,switch.thermostat_hc1_switch-on_optimization,switch.thermostat_hc1_switchonoptimization,6,1,1,29,1 UI800/BC400,thermostat,4,reducemode,reduce mode,enum [outdoor\|room\|reduce], ,true,select.thermostat_hc1_reduce_mode,select.thermostat_hc1_reducemode,6,1,1,30,1 UI800/BC400,thermostat,4,noreducetemp,no reduce below temperature,int8 (>=-126<=126),C,true,number.thermostat_hc1_no_reduce_below_temperature,number.thermostat_hc1_noreducetemp,6,1,1,31,1 UI800/BC400,thermostat,4,reducetemp,off/reduce switch temperature,int8 (>=-126<=126),C,true,number.thermostat_hc1_off/reduce_switch_temperature,number.thermostat_hc1_reducetemp,6,1,1,32,1 UI800/BC400,thermostat,4,dhwprio,dhw priority,boolean, ,true,switch.thermostat_hc1_dhw_priority,switch.thermostat_hc1_dhwprio,6,1,1,33,1 -UI800/BC400,thermostat,4,cooling,cooling,boolean, ,true,switch.thermostat_hc1_cooling,switch.thermostat_hc1_cooling,6,1,1,34,1 -UI800/BC400,thermostat,4,coolingon,cooling,boolean, ,false,binary_sensor.thermostat_hc1_cooling,binary_sensor.thermostat_hc1_coolingon,6,1,1,35,1 -UI800/BC400,thermostat,4,hpmode,HP Mode,enum [heating\|cooling\|heating&cooling], ,true,select.thermostat_hc1_HP_Mode,select.thermostat_hc1_hpmode,6,1,1,36,1 +UI800/BC400,thermostat,4,hpcooling,hp cooling,boolean, ,true,switch.thermostat_hc1_hp_cooling,switch.thermostat_hc1_hpcooling,6,1,1,34,1 +UI800/BC400,thermostat,4,coolingon,cooling on,boolean, ,false,binary_sensor.thermostat_hc1_cooling_on,binary_sensor.thermostat_hc1_coolingon,6,1,1,35,1 +UI800/BC400,thermostat,4,hpmode,HP Mode,enum [heating\|cooling\|heating & cooling], ,true,select.thermostat_hc1_HP_Mode,select.thermostat_hc1_hpmode,6,1,1,36,1 UI800/BC400,thermostat,4,dewoffset,dew point offset,uint8 (>=2<=10),K,true,number.thermostat_hc1_dew_point_offset,number.thermostat_hc1_dewoffset,6,1,1,37,1 UI800/BC400,thermostat,4,roomtempdiff,room temp difference,uint8 (>=0<=254),K,true,number.thermostat_hc1_room_temp_difference,number.thermostat_hc1_roomtempdiff,6,1,1,38,1 UI800/BC400,thermostat,4,hpminflowtemp,HP min. flow temp.,uint8 (>=0<=254),C,true,number.thermostat_hc1_HP_min._flow_temp.,number.thermostat_hc1_hpminflowtemp,6,1,1,39,1 @@ -3376,10 +3376,10 @@ UI800/BC400,thermostat,4,heatoffdelay,heat-off delay,uint8 (>=1<=48),hours,true, UI800/BC400,thermostat,4,instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_hc1_instant_start,number.thermostat_hc1_instantstart,6,1,1,45,1 UI800/BC400,thermostat,4,boost,boost mode,boolean, ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,46,1 UI800/BC400,thermostat,4,boosttime,boost time,uint8 (>=0<=254),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,47,1 -UI800/BC400,thermostat,4,coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,-1,1 -UI800/BC400,thermostat,4,coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,-1,1 -UI800/BC400,thermostat,4,cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,-1,1 -UI800/BC400,thermostat,4,switchprogmode,switch program mode,enum [level\|absolute], ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,-1,1 +UI800/BC400,thermostat,4,coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,193,1 +UI800/BC400,thermostat,4,coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,194,1 +UI800/BC400,thermostat,4,cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,195,1 +UI800/BC400,thermostat,4,switchprogmode,switch program mode,enum [level\|absolute], ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,196,1 UI800/BC400,thermostat,4,mode,mode,enum [off\|eco+\|eco\|comfort\|auto], ,true,select.thermostat_dhw_mode,select.thermostat_dhw_mode,6,9,1,0,1 UI800/BC400,thermostat,4,settemp,set temperature,uint8 (>=0<=254),C,true,number.thermostat_dhw_set_temperature,number.thermostat_dhw_settemp,6,9,1,1,1 UI800/BC400,thermostat,4,settemplow,set low temperature,uint8 (>=0<=254),C,true,number.thermostat_dhw_set_low_temperature,number.thermostat_dhw_settemplow,6,9,1,2,1 @@ -3471,7 +3471,7 @@ RC30,thermostat,67,disinfectday,disinfection day,enum [mo\|tu\|we\|th\|fr\|sa\|s RC30,thermostat,67,disinfecthour,disinfection hour,uint8 (>=0<=23), ,true,number.thermostat_dhw_disinfection_hour,number.thermostat_dhw_disinfecthour,6,9,1,14,1 RC30,thermostat,67,maxtemp,maximum temperature,uint8 (>=0<=254),C,true,number.thermostat_dhw_maximum_temperature,number.thermostat_dhw_maxtemp,6,9,1,15,1 RC30,thermostat,67,onetimekey,one time key function,boolean, ,true,switch.thermostat_dhw_one_time_key_function,switch.thermostat_dhw_onetimekey,6,9,1,16,1 -RC30,thermostat,67,switchtime,program switchtime,string, ,true,sensor.thermostat_dhw_program_switchtime,sensor.thermostat_dhw_switchtime,6,9,1,17,8 +RC30,thermostat,67,switchtimeWW,program switchtime warm water,string, ,true,sensor.thermostat_dhw_program_switchtime_warm_water,sensor.thermostat_dhw_switchtimeWW,6,9,1,17,8 RC30,thermostat,67,circswitchtime,circulation program switchtime,string, ,true,sensor.thermostat_dhw_circulation_program_switchtime,sensor.thermostat_dhw_circswitchtime,6,9,1,25,8 RC30,thermostat,67,holidays,holiday dates,string, ,true,sensor.thermostat_dhw_holiday_dates,sensor.thermostat_dhw_holidays,6,9,1,33,13 RC30,thermostat,67,vacations,vacation dates,string, ,true,sensor.thermostat_dhw_vacation_dates,sensor.thermostat_dhw_vacations,6,9,1,46,13 @@ -3488,7 +3488,7 @@ RC20/Moduline 300,thermostat,77,daytemp2,day temperature T2,uint8 (>=0<=127),C,t RC20/Moduline 300,thermostat,77,daytemp3,day temperature T3,uint8 (>=0<=127),C,true,number.thermostat_hc1_day_temperature_T3,number.thermostat_hc1_daytemp3,6,1,1/2,101,1 RC20/Moduline 300,thermostat,77,daytemp4,day temperature T4,uint8 (>=0<=127),C,true,number.thermostat_hc1_day_temperature_T4,number.thermostat_hc1_daytemp4,6,1,1/2,102,1 RC20/Moduline 300,thermostat,77,nighttemp,night temperature T1,uint8 (>=0<=127),C,true,number.thermostat_hc1_night_temperature_T1,number.thermostat_hc1_nighttemp,6,1,1/2,49,1 -RC20/Moduline 300,thermostat,77,switchtime,program switchtime,string, ,true,sensor.thermostat_hc1_program_switchtime,sensor.thermostat_hc1_switchtime,6,1,1,103,8 +RC20/Moduline 300,thermostat,77,switchtime,program switchtime,string, ,true,sensor.thermostat_hc1_program_switchtime,sensor.thermostat_hc1_switchtime,6,1,1,197,8 Moduline 400,thermostat,78,errorcode,error code,string, ,false,sensor.thermostat_error_code,sensor.thermostat_errorcode,6,0,1,0,8 Moduline 400,thermostat,78,lastcode,last error code,string, ,false,sensor.thermostat_last_error_code,sensor.thermostat_lastcode,6,0,1,8,25 Moduline 400,thermostat,78,datetime,date/time,string, ,false,sensor.thermostat_date/time,sensor.thermostat_datetime,6,0,1,33,13 @@ -3617,7 +3617,7 @@ RC35,thermostat,86,disinfectday,disinfection day,enum [mo\|tu\|we\|th\|fr\|sa\|s RC35,thermostat,86,disinfecthour,disinfection hour,uint8 (>=0<=23), ,true,number.thermostat_dhw_disinfection_hour,number.thermostat_dhw_disinfecthour,6,9,1,14,1 RC35,thermostat,86,maxtemp,maximum temperature,uint8 (>=60<=80),C,true,number.thermostat_dhw_maximum_temperature,number.thermostat_dhw_maxtemp,6,9,1,15,1 RC35,thermostat,86,onetimekey,one time key function,boolean, ,true,switch.thermostat_dhw_one_time_key_function,switch.thermostat_dhw_onetimekey,6,9,1,16,1 -RC35,thermostat,86,switchtime,program switchtime,string, ,true,sensor.thermostat_dhw_program_switchtime,sensor.thermostat_dhw_switchtime,6,9,1,17,8 +RC35,thermostat,86,switchtimeWW,program switchtime warm water,string, ,true,sensor.thermostat_dhw_program_switchtime_warm_water,sensor.thermostat_dhw_switchtimeWW,6,9,1,17,8 RC35,thermostat,86,circswitchtime,circulation program switchtime,string, ,true,sensor.thermostat_dhw_circulation_program_switchtime,sensor.thermostat_dhw_circswitchtime,6,9,1,25,8 RC35,thermostat,86,holidays,holiday dates,string, ,true,sensor.thermostat_dhw_holiday_dates,sensor.thermostat_dhw_holidays,6,9,1,33,13 RC35,thermostat,86,vacations,vacation dates,string, ,true,sensor.thermostat_dhw_vacation_dates,sensor.thermostat_dhw_vacations,6,9,1,46,13 @@ -3652,7 +3652,7 @@ RC20RF,thermostat,93,daytemp2,day temperature T2,uint8 (>=0<=127),C,true,number. RC20RF,thermostat,93,daytemp3,day temperature T3,uint8 (>=0<=127),C,true,number.thermostat_hc1_day_temperature_T3,number.thermostat_hc1_daytemp3,6,1,1/2,101,1 RC20RF,thermostat,93,daytemp4,day temperature T4,uint8 (>=0<=127),C,true,number.thermostat_hc1_day_temperature_T4,number.thermostat_hc1_daytemp4,6,1,1/2,102,1 RC20RF,thermostat,93,nighttemp,night temperature T1,uint8 (>=0<=127),C,true,number.thermostat_hc1_night_temperature_T1,number.thermostat_hc1_nighttemp,6,1,1/2,49,1 -RC20RF,thermostat,93,switchtime,program switchtime,string, ,true,sensor.thermostat_hc1_program_switchtime,sensor.thermostat_hc1_switchtime,6,1,1,103,8 +RC20RF,thermostat,93,switchtime,program switchtime,string, ,true,sensor.thermostat_hc1_program_switchtime,sensor.thermostat_hc1_switchtime,6,1,1,197,8 RFM20 Remote,thermostat,94,errorcode,error code,string, ,false,sensor.thermostat_error_code,sensor.thermostat_errorcode,6,0,1,0,8 RFM20 Remote,thermostat,94,lastcode,last error code,string, ,false,sensor.thermostat_last_error_code,sensor.thermostat_lastcode,6,0,1,8,25 RFM20 Remote,thermostat,94,datetime,date/time,string, ,false,sensor.thermostat_date/time,sensor.thermostat_datetime,6,0,1,33,13 @@ -3724,16 +3724,16 @@ RC200/CW100/CR120,thermostat,157,hpoperatingstate,heatpump operating state,enum RC200/CW100/CR120,thermostat,157,controlmode,control mode,enum [optimized\|simple\|n/a\|room\|power], ,true,select.thermostat_hc1_control_mode,select.thermostat_hc1_controlmode,6,1,1,24,1 RC200/CW100/CR120,thermostat,157,program,program,enum [prog 1\|prog 2], ,true,select.thermostat_hc1_program,select.thermostat_hc1_program,6,1,1,25,1 RC200/CW100/CR120,thermostat,157,tempautotemp,temporary set temperature automode,int8 (>=-1<=30),C,true,number.thermostat_hc1_temporary_set_temperature_automode,number.thermostat_hc1_tempautotemp,6,1,1/2,26,1 -RC200/CW100/CR120,thermostat,157,remoteseltemp,temporary set temperature from remote,int8 (>=-63<=63),C,false,sensor.thermostat_hc1_temporary_set_temperature_from_remote,sensor.thermostat_hc1_remoteseltemp,6,1,1/2,27,1 +RC200/CW100/CR120,thermostat,157,remoteseltemp,temporary set temperature from remote,int8 (>=-1<=30),C,true,number.thermostat_hc1_temporary_set_temperature_from_remote,number.thermostat_hc1_remoteseltemp,6,1,1/2,27,1 RC200/CW100/CR120,thermostat,157,fastheatup,fast heatup,uint8 (>=0<=100),%,true,number.thermostat_hc1_fast_heatup,number.thermostat_hc1_fastheatup,6,1,1,28,1 RC200/CW100/CR120,thermostat,157,switchonoptimization,switch-on optimization,boolean, ,true,switch.thermostat_hc1_switch-on_optimization,switch.thermostat_hc1_switchonoptimization,6,1,1,29,1 RC200/CW100/CR120,thermostat,157,reducemode,reduce mode,enum [outdoor\|room\|reduce], ,true,select.thermostat_hc1_reduce_mode,select.thermostat_hc1_reducemode,6,1,1,30,1 RC200/CW100/CR120,thermostat,157,noreducetemp,no reduce below temperature,int8 (>=-126<=126),C,true,number.thermostat_hc1_no_reduce_below_temperature,number.thermostat_hc1_noreducetemp,6,1,1,31,1 RC200/CW100/CR120,thermostat,157,reducetemp,off/reduce switch temperature,int8 (>=-126<=126),C,true,number.thermostat_hc1_off/reduce_switch_temperature,number.thermostat_hc1_reducetemp,6,1,1,32,1 RC200/CW100/CR120,thermostat,157,dhwprio,dhw priority,boolean, ,true,switch.thermostat_hc1_dhw_priority,switch.thermostat_hc1_dhwprio,6,1,1,33,1 -RC200/CW100/CR120,thermostat,157,cooling,cooling,boolean, ,true,switch.thermostat_hc1_cooling,switch.thermostat_hc1_cooling,6,1,1,34,1 -RC200/CW100/CR120,thermostat,157,coolingon,cooling,boolean, ,false,binary_sensor.thermostat_hc1_cooling,binary_sensor.thermostat_hc1_coolingon,6,1,1,35,1 -RC200/CW100/CR120,thermostat,157,hpmode,HP Mode,enum [heating\|cooling\|heating&cooling], ,true,select.thermostat_hc1_HP_Mode,select.thermostat_hc1_hpmode,6,1,1,36,1 +RC200/CW100/CR120,thermostat,157,hpcooling,hp cooling,boolean, ,true,switch.thermostat_hc1_hp_cooling,switch.thermostat_hc1_hpcooling,6,1,1,34,1 +RC200/CW100/CR120,thermostat,157,coolingon,cooling on,boolean, ,false,binary_sensor.thermostat_hc1_cooling_on,binary_sensor.thermostat_hc1_coolingon,6,1,1,35,1 +RC200/CW100/CR120,thermostat,157,hpmode,HP Mode,enum [heating\|cooling\|heating & cooling], ,true,select.thermostat_hc1_HP_Mode,select.thermostat_hc1_hpmode,6,1,1,36,1 RC200/CW100/CR120,thermostat,157,dewoffset,dew point offset,uint8 (>=2<=10),K,true,number.thermostat_hc1_dew_point_offset,number.thermostat_hc1_dewoffset,6,1,1,37,1 RC200/CW100/CR120,thermostat,157,roomtempdiff,room temp difference,uint8 (>=0<=254),K,true,number.thermostat_hc1_room_temp_difference,number.thermostat_hc1_roomtempdiff,6,1,1,38,1 RC200/CW100/CR120,thermostat,157,hpminflowtemp,HP min. flow temp.,uint8 (>=0<=254),C,true,number.thermostat_hc1_HP_min._flow_temp.,number.thermostat_hc1_hpminflowtemp,6,1,1,39,1 @@ -3745,10 +3745,10 @@ RC200/CW100/CR120,thermostat,157,heatoffdelay,heat-off delay,uint8 (>=1<=48),hou RC200/CW100/CR120,thermostat,157,instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_hc1_instant_start,number.thermostat_hc1_instantstart,6,1,1,45,1 RC200/CW100/CR120,thermostat,157,boost,boost mode,boolean, ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,46,1 RC200/CW100/CR120,thermostat,157,boosttime,boost time,uint8 (>=0<=254),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,47,1 -RC200/CW100/CR120,thermostat,157,coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,-1,1 -RC200/CW100/CR120,thermostat,157,coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,-1,1 -RC200/CW100/CR120,thermostat,157,cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,-1,1 -RC200/CW100/CR120,thermostat,157,switchprogmode,switch program mode,enum [level\|absolute], ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,-1,1 +RC200/CW100/CR120,thermostat,157,coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,193,1 +RC200/CW100/CR120,thermostat,157,coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,194,1 +RC200/CW100/CR120,thermostat,157,cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,195,1 +RC200/CW100/CR120,thermostat,157,switchprogmode,switch program mode,enum [level\|absolute], ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,196,1 RC200/CW100/CR120,thermostat,157,mode,mode,enum [off\|normal\|comfort\|auto\|own prog], ,true,select.thermostat_dhw_mode,select.thermostat_dhw_mode,6,9,1,0,1 RC200/CW100/CR120,thermostat,157,settemp,set temperature,uint8 (>=0<=254),C,true,number.thermostat_dhw_set_temperature,number.thermostat_dhw_settemp,6,9,1,1,1 RC200/CW100/CR120,thermostat,157,settemplow,set low temperature,uint8 (>=0<=254),C,true,number.thermostat_dhw_set_low_temperature,number.thermostat_dhw_settemplow,6,9,1,2,1 @@ -3808,16 +3808,16 @@ RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,hpoperating RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,controlmode,control mode,enum [weather compensated\|outside basepoint\|n/a\|room\|power\|constant], ,true,select.thermostat_hc1_control_mode,select.thermostat_hc1_controlmode,6,1,1,24,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,program,program,enum [prog 1\|prog 2], ,true,select.thermostat_hc1_program,select.thermostat_hc1_program,6,1,1,25,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,tempautotemp,temporary set temperature automode,int8 (>=-1<=30),C,true,number.thermostat_hc1_temporary_set_temperature_automode,number.thermostat_hc1_tempautotemp,6,1,1/2,26,1 -RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,remoteseltemp,temporary set temperature from remote,int8 (>=-63<=63),C,false,sensor.thermostat_hc1_temporary_set_temperature_from_remote,sensor.thermostat_hc1_remoteseltemp,6,1,1/2,27,1 +RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,remoteseltemp,temporary set temperature from remote,int8 (>=-1<=30),C,true,number.thermostat_hc1_temporary_set_temperature_from_remote,number.thermostat_hc1_remoteseltemp,6,1,1/2,27,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,fastheatup,fast heatup,uint8 (>=0<=100),%,true,number.thermostat_hc1_fast_heatup,number.thermostat_hc1_fastheatup,6,1,1,28,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,switchonoptimization,switch-on optimization,boolean, ,true,switch.thermostat_hc1_switch-on_optimization,switch.thermostat_hc1_switchonoptimization,6,1,1,29,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,reducemode,reduce mode,enum [outdoor\|room\|reduce], ,true,select.thermostat_hc1_reduce_mode,select.thermostat_hc1_reducemode,6,1,1,30,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,noreducetemp,no reduce below temperature,int8 (>=-126<=126),C,true,number.thermostat_hc1_no_reduce_below_temperature,number.thermostat_hc1_noreducetemp,6,1,1,31,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,reducetemp,off/reduce switch temperature,int8 (>=-126<=126),C,true,number.thermostat_hc1_off/reduce_switch_temperature,number.thermostat_hc1_reducetemp,6,1,1,32,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,dhwprio,dhw priority,boolean, ,true,switch.thermostat_hc1_dhw_priority,switch.thermostat_hc1_dhwprio,6,1,1,33,1 -RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,cooling,cooling,boolean, ,true,switch.thermostat_hc1_cooling,switch.thermostat_hc1_cooling,6,1,1,34,1 -RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,coolingon,cooling,boolean, ,false,binary_sensor.thermostat_hc1_cooling,binary_sensor.thermostat_hc1_coolingon,6,1,1,35,1 -RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,hpmode,HP Mode,enum [heating\|cooling\|heating&cooling], ,true,select.thermostat_hc1_HP_Mode,select.thermostat_hc1_hpmode,6,1,1,36,1 +RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,hpcooling,hp cooling,boolean, ,true,switch.thermostat_hc1_hp_cooling,switch.thermostat_hc1_hpcooling,6,1,1,34,1 +RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,coolingon,cooling on,boolean, ,false,binary_sensor.thermostat_hc1_cooling_on,binary_sensor.thermostat_hc1_coolingon,6,1,1,35,1 +RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,hpmode,HP Mode,enum [heating\|cooling\|heating & cooling], ,true,select.thermostat_hc1_HP_Mode,select.thermostat_hc1_hpmode,6,1,1,36,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,dewoffset,dew point offset,uint8 (>=2<=10),K,true,number.thermostat_hc1_dew_point_offset,number.thermostat_hc1_dewoffset,6,1,1,37,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,roomtempdiff,room temp difference,uint8 (>=0<=254),K,true,number.thermostat_hc1_room_temp_difference,number.thermostat_hc1_roomtempdiff,6,1,1,38,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,hpminflowtemp,HP min. flow temp.,uint8 (>=0<=254),C,true,number.thermostat_hc1_HP_min._flow_temp.,number.thermostat_hc1_hpminflowtemp,6,1,1,39,1 @@ -3829,10 +3829,10 @@ RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,heatoffdela RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_hc1_instant_start,number.thermostat_hc1_instantstart,6,1,1,45,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,boost,boost mode,boolean, ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,46,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,boosttime,boost time,uint8 (>=0<=254),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,47,1 -RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,-1,1 -RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,-1,1 -RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,-1,1 -RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,switchprogmode,switch program mode,enum [level\|absolute], ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,-1,1 +RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,193,1 +RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,194,1 +RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,195,1 +RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,switchprogmode,switch program mode,enum [level\|absolute], ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,196,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,mode,mode,enum [off\|normal\|comfort\|auto\|own prog], ,true,select.thermostat_dhw_mode,select.thermostat_dhw_mode,6,9,1,0,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,settemp,set temperature,uint8 (>=0<=254),C,true,number.thermostat_dhw_set_temperature,number.thermostat_dhw_settemp,6,9,1,1,1 RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410,thermostat,158,settemplow,set low temperature,uint8 (>=0<=254),C,true,number.thermostat_dhw_set_low_temperature,number.thermostat_dhw_settemplow,6,9,1,2,1 @@ -3892,16 +3892,16 @@ RC100/Moduline 1000/1010,thermostat,165,hpoperatingstate,heatpump operating stat RC100/Moduline 1000/1010,thermostat,165,controlmode,control mode,enum [optimized\|simple\|n/a\|room\|power], ,true,select.thermostat_hc1_control_mode,select.thermostat_hc1_controlmode,6,1,1,24,1 RC100/Moduline 1000/1010,thermostat,165,program,program,enum [prog 1\|prog 2], ,true,select.thermostat_hc1_program,select.thermostat_hc1_program,6,1,1,25,1 RC100/Moduline 1000/1010,thermostat,165,tempautotemp,temporary set temperature automode,int8 (>=-1<=30),C,true,number.thermostat_hc1_temporary_set_temperature_automode,number.thermostat_hc1_tempautotemp,6,1,1/2,26,1 -RC100/Moduline 1000/1010,thermostat,165,remoteseltemp,temporary set temperature from remote,int8 (>=-63<=63),C,false,sensor.thermostat_hc1_temporary_set_temperature_from_remote,sensor.thermostat_hc1_remoteseltemp,6,1,1/2,27,1 +RC100/Moduline 1000/1010,thermostat,165,remoteseltemp,temporary set temperature from remote,int8 (>=-1<=30),C,true,number.thermostat_hc1_temporary_set_temperature_from_remote,number.thermostat_hc1_remoteseltemp,6,1,1/2,27,1 RC100/Moduline 1000/1010,thermostat,165,fastheatup,fast heatup,uint8 (>=0<=100),%,true,number.thermostat_hc1_fast_heatup,number.thermostat_hc1_fastheatup,6,1,1,28,1 RC100/Moduline 1000/1010,thermostat,165,switchonoptimization,switch-on optimization,boolean, ,true,switch.thermostat_hc1_switch-on_optimization,switch.thermostat_hc1_switchonoptimization,6,1,1,29,1 RC100/Moduline 1000/1010,thermostat,165,reducemode,reduce mode,enum [outdoor\|room\|reduce], ,true,select.thermostat_hc1_reduce_mode,select.thermostat_hc1_reducemode,6,1,1,30,1 RC100/Moduline 1000/1010,thermostat,165,noreducetemp,no reduce below temperature,int8 (>=-126<=126),C,true,number.thermostat_hc1_no_reduce_below_temperature,number.thermostat_hc1_noreducetemp,6,1,1,31,1 RC100/Moduline 1000/1010,thermostat,165,reducetemp,off/reduce switch temperature,int8 (>=-126<=126),C,true,number.thermostat_hc1_off/reduce_switch_temperature,number.thermostat_hc1_reducetemp,6,1,1,32,1 RC100/Moduline 1000/1010,thermostat,165,dhwprio,dhw priority,boolean, ,true,switch.thermostat_hc1_dhw_priority,switch.thermostat_hc1_dhwprio,6,1,1,33,1 -RC100/Moduline 1000/1010,thermostat,165,cooling,cooling,boolean, ,true,switch.thermostat_hc1_cooling,switch.thermostat_hc1_cooling,6,1,1,34,1 -RC100/Moduline 1000/1010,thermostat,165,coolingon,cooling,boolean, ,false,binary_sensor.thermostat_hc1_cooling,binary_sensor.thermostat_hc1_coolingon,6,1,1,35,1 -RC100/Moduline 1000/1010,thermostat,165,hpmode,HP Mode,enum [heating\|cooling\|heating&cooling], ,true,select.thermostat_hc1_HP_Mode,select.thermostat_hc1_hpmode,6,1,1,36,1 +RC100/Moduline 1000/1010,thermostat,165,hpcooling,hp cooling,boolean, ,true,switch.thermostat_hc1_hp_cooling,switch.thermostat_hc1_hpcooling,6,1,1,34,1 +RC100/Moduline 1000/1010,thermostat,165,coolingon,cooling on,boolean, ,false,binary_sensor.thermostat_hc1_cooling_on,binary_sensor.thermostat_hc1_coolingon,6,1,1,35,1 +RC100/Moduline 1000/1010,thermostat,165,hpmode,HP Mode,enum [heating\|cooling\|heating & cooling], ,true,select.thermostat_hc1_HP_Mode,select.thermostat_hc1_hpmode,6,1,1,36,1 RC100/Moduline 1000/1010,thermostat,165,dewoffset,dew point offset,uint8 (>=2<=10),K,true,number.thermostat_hc1_dew_point_offset,number.thermostat_hc1_dewoffset,6,1,1,37,1 RC100/Moduline 1000/1010,thermostat,165,roomtempdiff,room temp difference,uint8 (>=0<=254),K,true,number.thermostat_hc1_room_temp_difference,number.thermostat_hc1_roomtempdiff,6,1,1,38,1 RC100/Moduline 1000/1010,thermostat,165,hpminflowtemp,HP min. flow temp.,uint8 (>=0<=254),C,true,number.thermostat_hc1_HP_min._flow_temp.,number.thermostat_hc1_hpminflowtemp,6,1,1,39,1 @@ -3913,10 +3913,10 @@ RC100/Moduline 1000/1010,thermostat,165,heatoffdelay,heat-off delay,uint8 (>=1<= RC100/Moduline 1000/1010,thermostat,165,instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_hc1_instant_start,number.thermostat_hc1_instantstart,6,1,1,45,1 RC100/Moduline 1000/1010,thermostat,165,boost,boost mode,boolean, ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,46,1 RC100/Moduline 1000/1010,thermostat,165,boosttime,boost time,uint8 (>=0<=254),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,47,1 -RC100/Moduline 1000/1010,thermostat,165,coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,-1,1 -RC100/Moduline 1000/1010,thermostat,165,coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,-1,1 -RC100/Moduline 1000/1010,thermostat,165,cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,-1,1 -RC100/Moduline 1000/1010,thermostat,165,switchprogmode,switch program mode,enum [level\|absolute], ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,-1,1 +RC100/Moduline 1000/1010,thermostat,165,coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,193,1 +RC100/Moduline 1000/1010,thermostat,165,coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,194,1 +RC100/Moduline 1000/1010,thermostat,165,cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,195,1 +RC100/Moduline 1000/1010,thermostat,165,switchprogmode,switch program mode,enum [level\|absolute], ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,196,1 RC100/Moduline 1000/1010,thermostat,165,mode,mode,enum [off\|normal\|comfort\|auto\|own prog], ,true,select.thermostat_dhw_mode,select.thermostat_dhw_mode,6,9,1,0,1 RC100/Moduline 1000/1010,thermostat,165,settemp,set temperature,uint8 (>=0<=254),C,true,number.thermostat_dhw_set_temperature,number.thermostat_dhw_settemp,6,9,1,1,1 RC100/Moduline 1000/1010,thermostat,165,settemplow,set low temperature,uint8 (>=0<=254),C,true,number.thermostat_dhw_set_low_temperature,number.thermostat_dhw_settemplow,6,9,1,2,1 @@ -3977,16 +3977,16 @@ Rego 2000/3000,thermostat,172,hpoperatingstate,heatpump operating state,enum [he Rego 2000/3000,thermostat,172,controlmode,control mode,enum [weather compensated\|outside basepoint\|n/a\|room\|power\|constant], ,true,select.thermostat_hc1_control_mode,select.thermostat_hc1_controlmode,6,1,1,24,1 Rego 2000/3000,thermostat,172,program,program,enum [prog 1\|prog 2], ,true,select.thermostat_hc1_program,select.thermostat_hc1_program,6,1,1,25,1 Rego 2000/3000,thermostat,172,tempautotemp,temporary set temperature automode,int8 (>=-1<=30),C,true,number.thermostat_hc1_temporary_set_temperature_automode,number.thermostat_hc1_tempautotemp,6,1,1/2,26,1 -Rego 2000/3000,thermostat,172,remoteseltemp,temporary set temperature from remote,int8 (>=-63<=63),C,false,sensor.thermostat_hc1_temporary_set_temperature_from_remote,sensor.thermostat_hc1_remoteseltemp,6,1,1/2,27,1 +Rego 2000/3000,thermostat,172,remoteseltemp,temporary set temperature from remote,int8 (>=-1<=30),C,true,number.thermostat_hc1_temporary_set_temperature_from_remote,number.thermostat_hc1_remoteseltemp,6,1,1/2,27,1 Rego 2000/3000,thermostat,172,fastheatup,fast heatup,uint8 (>=0<=100),%,true,number.thermostat_hc1_fast_heatup,number.thermostat_hc1_fastheatup,6,1,1,28,1 Rego 2000/3000,thermostat,172,switchonoptimization,switch-on optimization,boolean, ,true,switch.thermostat_hc1_switch-on_optimization,switch.thermostat_hc1_switchonoptimization,6,1,1,29,1 Rego 2000/3000,thermostat,172,reducemode,reduce mode,enum [outdoor\|room\|reduce], ,true,select.thermostat_hc1_reduce_mode,select.thermostat_hc1_reducemode,6,1,1,30,1 Rego 2000/3000,thermostat,172,noreducetemp,no reduce below temperature,int8 (>=-126<=126),C,true,number.thermostat_hc1_no_reduce_below_temperature,number.thermostat_hc1_noreducetemp,6,1,1,31,1 Rego 2000/3000,thermostat,172,reducetemp,off/reduce switch temperature,int8 (>=-126<=126),C,true,number.thermostat_hc1_off/reduce_switch_temperature,number.thermostat_hc1_reducetemp,6,1,1,32,1 Rego 2000/3000,thermostat,172,dhwprio,dhw priority,boolean, ,true,switch.thermostat_hc1_dhw_priority,switch.thermostat_hc1_dhwprio,6,1,1,33,1 -Rego 2000/3000,thermostat,172,cooling,cooling,boolean, ,true,switch.thermostat_hc1_cooling,switch.thermostat_hc1_cooling,6,1,1,34,1 -Rego 2000/3000,thermostat,172,coolingon,cooling,boolean, ,false,binary_sensor.thermostat_hc1_cooling,binary_sensor.thermostat_hc1_coolingon,6,1,1,35,1 -Rego 2000/3000,thermostat,172,hpmode,HP Mode,enum [heating\|cooling\|heating&cooling], ,true,select.thermostat_hc1_HP_Mode,select.thermostat_hc1_hpmode,6,1,1,36,1 +Rego 2000/3000,thermostat,172,hpcooling,hp cooling,boolean, ,true,switch.thermostat_hc1_hp_cooling,switch.thermostat_hc1_hpcooling,6,1,1,34,1 +Rego 2000/3000,thermostat,172,coolingon,cooling on,boolean, ,false,binary_sensor.thermostat_hc1_cooling_on,binary_sensor.thermostat_hc1_coolingon,6,1,1,35,1 +Rego 2000/3000,thermostat,172,hpmode,HP Mode,enum [heating\|cooling\|heating & cooling], ,true,select.thermostat_hc1_HP_Mode,select.thermostat_hc1_hpmode,6,1,1,36,1 Rego 2000/3000,thermostat,172,dewoffset,dew point offset,uint8 (>=2<=10),K,true,number.thermostat_hc1_dew_point_offset,number.thermostat_hc1_dewoffset,6,1,1,37,1 Rego 2000/3000,thermostat,172,roomtempdiff,room temp difference,uint8 (>=0<=254),K,true,number.thermostat_hc1_room_temp_difference,number.thermostat_hc1_roomtempdiff,6,1,1,38,1 Rego 2000/3000,thermostat,172,hpminflowtemp,HP min. flow temp.,uint8 (>=0<=254),C,true,number.thermostat_hc1_HP_min._flow_temp.,number.thermostat_hc1_hpminflowtemp,6,1,1,39,1 @@ -3998,10 +3998,10 @@ Rego 2000/3000,thermostat,172,heatoffdelay,heat-off delay,uint8 (>=1<=48),hours, Rego 2000/3000,thermostat,172,instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_hc1_instant_start,number.thermostat_hc1_instantstart,6,1,1,45,1 Rego 2000/3000,thermostat,172,boost,boost mode,boolean, ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,46,1 Rego 2000/3000,thermostat,172,boosttime,boost time,uint8 (>=0<=254),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,47,1 -Rego 2000/3000,thermostat,172,coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,-1,1 -Rego 2000/3000,thermostat,172,coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,-1,1 -Rego 2000/3000,thermostat,172,cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,-1,1 -Rego 2000/3000,thermostat,172,switchprogmode,switch program mode,enum [level\|absolute], ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,-1,1 +Rego 2000/3000,thermostat,172,coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,193,1 +Rego 2000/3000,thermostat,172,coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,194,1 +Rego 2000/3000,thermostat,172,cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,195,1 +Rego 2000/3000,thermostat,172,switchprogmode,switch program mode,enum [level\|absolute], ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,196,1 Rego 2000/3000,thermostat,172,mode,mode,enum [normal\|comfort\|eco+], ,true,select.thermostat_dhw_mode,select.thermostat_dhw_mode,6,9,1,0,1 Rego 2000/3000,thermostat,172,settemp,set temperature,uint8 (>=0<=254),C,true,number.thermostat_dhw_set_temperature,number.thermostat_dhw_settemp,6,9,1,1,1 Rego 2000/3000,thermostat,172,settemplow,set low temperature,uint8 (>=0<=254),C,true,number.thermostat_dhw_set_low_temperature,number.thermostat_dhw_settemplow,6,9,1,2,1 @@ -4088,16 +4088,16 @@ Rego 3000/UI800/WSW196i/BC400,thermostat,253,hpoperatingstate,heatpump operating Rego 3000/UI800/WSW196i/BC400,thermostat,253,controlmode,control mode,enum [weather compensated\|outside basepoint\|n/a\|room\|power\|constant], ,true,select.thermostat_hc1_control_mode,select.thermostat_hc1_controlmode,6,1,1,24,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,program,program,enum [prog 1\|prog 2], ,true,select.thermostat_hc1_program,select.thermostat_hc1_program,6,1,1,25,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,tempautotemp,temporary set temperature automode,int8 (>=-1<=30),C,true,number.thermostat_hc1_temporary_set_temperature_automode,number.thermostat_hc1_tempautotemp,6,1,1/2,26,1 -Rego 3000/UI800/WSW196i/BC400,thermostat,253,remoteseltemp,temporary set temperature from remote,int8 (>=-63<=63),C,false,sensor.thermostat_hc1_temporary_set_temperature_from_remote,sensor.thermostat_hc1_remoteseltemp,6,1,1/2,27,1 +Rego 3000/UI800/WSW196i/BC400,thermostat,253,remoteseltemp,temporary set temperature from remote,int8 (>=-1<=30),C,true,number.thermostat_hc1_temporary_set_temperature_from_remote,number.thermostat_hc1_remoteseltemp,6,1,1/2,27,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,fastheatup,fast heatup,uint8 (>=0<=100),%,true,number.thermostat_hc1_fast_heatup,number.thermostat_hc1_fastheatup,6,1,1,28,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,switchonoptimization,switch-on optimization,boolean, ,true,switch.thermostat_hc1_switch-on_optimization,switch.thermostat_hc1_switchonoptimization,6,1,1,29,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,reducemode,reduce mode,enum [outdoor\|room\|reduce], ,true,select.thermostat_hc1_reduce_mode,select.thermostat_hc1_reducemode,6,1,1,30,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,noreducetemp,no reduce below temperature,int8 (>=-126<=126),C,true,number.thermostat_hc1_no_reduce_below_temperature,number.thermostat_hc1_noreducetemp,6,1,1,31,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,reducetemp,off/reduce switch temperature,int8 (>=-126<=126),C,true,number.thermostat_hc1_off/reduce_switch_temperature,number.thermostat_hc1_reducetemp,6,1,1,32,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,dhwprio,dhw priority,boolean, ,true,switch.thermostat_hc1_dhw_priority,switch.thermostat_hc1_dhwprio,6,1,1,33,1 -Rego 3000/UI800/WSW196i/BC400,thermostat,253,cooling,cooling,boolean, ,true,switch.thermostat_hc1_cooling,switch.thermostat_hc1_cooling,6,1,1,34,1 -Rego 3000/UI800/WSW196i/BC400,thermostat,253,coolingon,cooling,boolean, ,false,binary_sensor.thermostat_hc1_cooling,binary_sensor.thermostat_hc1_coolingon,6,1,1,35,1 -Rego 3000/UI800/WSW196i/BC400,thermostat,253,hpmode,HP Mode,enum [heating\|cooling\|heating&cooling], ,true,select.thermostat_hc1_HP_Mode,select.thermostat_hc1_hpmode,6,1,1,36,1 +Rego 3000/UI800/WSW196i/BC400,thermostat,253,hpcooling,hp cooling,boolean, ,true,switch.thermostat_hc1_hp_cooling,switch.thermostat_hc1_hpcooling,6,1,1,34,1 +Rego 3000/UI800/WSW196i/BC400,thermostat,253,coolingon,cooling on,boolean, ,false,binary_sensor.thermostat_hc1_cooling_on,binary_sensor.thermostat_hc1_coolingon,6,1,1,35,1 +Rego 3000/UI800/WSW196i/BC400,thermostat,253,hpmode,HP Mode,enum [heating\|cooling\|heating & cooling], ,true,select.thermostat_hc1_HP_Mode,select.thermostat_hc1_hpmode,6,1,1,36,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,dewoffset,dew point offset,uint8 (>=2<=10),K,true,number.thermostat_hc1_dew_point_offset,number.thermostat_hc1_dewoffset,6,1,1,37,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,roomtempdiff,room temp difference,uint8 (>=0<=254),K,true,number.thermostat_hc1_room_temp_difference,number.thermostat_hc1_roomtempdiff,6,1,1,38,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,hpminflowtemp,HP min. flow temp.,uint8 (>=0<=254),C,true,number.thermostat_hc1_HP_min._flow_temp.,number.thermostat_hc1_hpminflowtemp,6,1,1,39,1 @@ -4109,10 +4109,10 @@ Rego 3000/UI800/WSW196i/BC400,thermostat,253,heatoffdelay,heat-off delay,uint8 ( Rego 3000/UI800/WSW196i/BC400,thermostat,253,instantstart,instant start,uint8 (>=1<=10),K,true,number.thermostat_hc1_instant_start,number.thermostat_hc1_instantstart,6,1,1,45,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,boost,boost mode,boolean, ,true,switch.thermostat_hc1_boost_mode,switch.thermostat_hc1_boost,6,1,1,46,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,boosttime,boost time,uint8 (>=0<=254),hours,true,number.thermostat_hc1_boost_time,number.thermostat_hc1_boosttime,6,1,1,47,1 -Rego 3000/UI800/WSW196i/BC400,thermostat,253,coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,-1,1 -Rego 3000/UI800/WSW196i/BC400,thermostat,253,coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,-1,1 -Rego 3000/UI800/WSW196i/BC400,thermostat,253,cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,-1,1 -Rego 3000/UI800/WSW196i/BC400,thermostat,253,switchprogmode,switch program mode,enum [level\|absolute], ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,-1,1 +Rego 3000/UI800/WSW196i/BC400,thermostat,253,coolstart,cooling starttemp,uint8 (>=20<=35),C,true,number.thermostat_hc1_cooling_starttemp,number.thermostat_hc1_coolstart,6,1,1,193,1 +Rego 3000/UI800/WSW196i/BC400,thermostat,253,coolondelay,cooling on delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_on_delay,number.thermostat_hc1_coolondelay,6,1,1,194,1 +Rego 3000/UI800/WSW196i/BC400,thermostat,253,cooloffdelay,cooling off delay,uint8 (>=1<=48),hours,true,number.thermostat_hc1_cooling_off_delay,number.thermostat_hc1_cooloffdelay,6,1,1,195,1 +Rego 3000/UI800/WSW196i/BC400,thermostat,253,switchprogmode,switch program mode,enum [level\|absolute], ,true,select.thermostat_hc1_switch_program_mode,select.thermostat_hc1_switchprogmode,6,1,1,196,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,mode,mode,enum [off\|eco+\|eco\|comfort\|auto], ,true,select.thermostat_dhw_mode,select.thermostat_dhw_mode,6,9,1,0,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,settemp,set temperature,uint8 (>=0<=254),C,true,number.thermostat_dhw_set_temperature,number.thermostat_dhw_settemp,6,9,1,1,1 Rego 3000/UI800/WSW196i/BC400,thermostat,253,settemplow,set low temperature,uint8 (>=0<=254),C,true,number.thermostat_dhw_set_low_temperature,number.thermostat_dhw_settemplow,6,9,1,2,1 @@ -4204,7 +4204,7 @@ ES73,thermostat,76,disinfectday,disinfection day,enum [mo\|tu\|we\|th\|fr\|sa\|s ES73,thermostat,76,disinfecthour,disinfection hour,uint8 (>=0<=23), ,true,number.thermostat_dhw_disinfection_hour,number.thermostat_dhw_disinfecthour,6,9,1,14,1 ES73,thermostat,76,maxtemp,maximum temperature,uint8 (>=0<=254),C,true,number.thermostat_dhw_maximum_temperature,number.thermostat_dhw_maxtemp,6,9,1,15,1 ES73,thermostat,76,onetimekey,one time key function,boolean, ,true,switch.thermostat_dhw_one_time_key_function,switch.thermostat_dhw_onetimekey,6,9,1,16,1 -ES73,thermostat,76,switchtime,program switchtime,string, ,true,sensor.thermostat_dhw_program_switchtime,sensor.thermostat_dhw_switchtime,6,9,1,17,8 +ES73,thermostat,76,switchtimeWW,program switchtime warm water,string, ,true,sensor.thermostat_dhw_program_switchtime_warm_water,sensor.thermostat_dhw_switchtimeWW,6,9,1,17,8 ES73,thermostat,76,circswitchtime,circulation program switchtime,string, ,true,sensor.thermostat_dhw_circulation_program_switchtime,sensor.thermostat_dhw_circswitchtime,6,9,1,25,8 ES73,thermostat,76,holidays,holiday dates,string, ,true,sensor.thermostat_dhw_holiday_dates,sensor.thermostat_dhw_holidays,6,9,1,33,13 ES73,thermostat,76,vacations,vacation dates,string, ,true,sensor.thermostat_dhw_vacation_dates,sensor.thermostat_dhw_vacations,6,9,1,46,13 @@ -4284,7 +4284,7 @@ ES79,thermostat,156,disinfectday,disinfection day,enum [mo\|tu\|we\|th\|fr\|sa\| ES79,thermostat,156,disinfecthour,disinfection hour,uint8 (>=0<=23), ,true,number.thermostat_dhw_disinfection_hour,number.thermostat_dhw_disinfecthour,6,9,1,14,1 ES79,thermostat,156,maxtemp,maximum temperature,uint8 (>=60<=80),C,true,number.thermostat_dhw_maximum_temperature,number.thermostat_dhw_maxtemp,6,9,1,15,1 ES79,thermostat,156,onetimekey,one time key function,boolean, ,true,switch.thermostat_dhw_one_time_key_function,switch.thermostat_dhw_onetimekey,6,9,1,16,1 -ES79,thermostat,156,switchtime,program switchtime,string, ,true,sensor.thermostat_dhw_program_switchtime,sensor.thermostat_dhw_switchtime,6,9,1,17,8 +ES79,thermostat,156,switchtimeWW,program switchtime warm water,string, ,true,sensor.thermostat_dhw_program_switchtime_warm_water,sensor.thermostat_dhw_switchtimeWW,6,9,1,17,8 ES79,thermostat,156,circswitchtime,circulation program switchtime,string, ,true,sensor.thermostat_dhw_circulation_program_switchtime,sensor.thermostat_dhw_circswitchtime,6,9,1,25,8 ES79,thermostat,156,holidays,holiday dates,string, ,true,sensor.thermostat_dhw_holiday_dates,sensor.thermostat_dhw_holidays,6,9,1,33,13 ES79,thermostat,156,vacations,vacation dates,string, ,true,sensor.thermostat_dhw_vacation_dates,sensor.thermostat_dhw_vacations,6,9,1,46,13 @@ -4808,8 +4808,8 @@ SM50,solar,162,externalcyl,external cylinder,boolean, ,true,switch.solar_externa SM50,solar,162,thermaldisinfect,thermal disinfection,boolean, ,true,switch.solar_thermal_disinfection,switch.solar_thermaldisinfect,8,0,1,41,1 SM50,solar,162,heatmetering,heatmetering,boolean, ,true,switch.solar_heatmetering,switch.solar_heatmetering,8,0,1,42,1 SM50,solar,162,activated,activated,boolean, ,true,switch.solar_activated,switch.solar_activated,8,0,1,43,1 -SM50,solar,162,solarpumpmode,pump mode,enum [constant\|pwm\|analog], ,true,select.solar_pump_mode,select.solar_solarpumpmode,8,0,1,44,1 -SM50,solar,162,pumpkick,pump kick,boolean, ,true,switch.solar_pump_kick,switch.solar_pumpkick,8,0,1,45,1 +SM50,solar,162,solarpumpmode,solar pump mode,enum [constant\|pwm\|analog], ,true,select.solar_solar_pump_mode,select.solar_solarpumpmode,8,0,1,44,1 +SM50,solar,162,solarpumpkick,solar pump kick,boolean, ,true,switch.solar_solar_pump_kick,switch.solar_solarpumpkick,8,0,1,45,1 SM50,solar,162,plainwatermode,plain water mode,boolean, ,true,switch.solar_plain_water_mode,switch.solar_plainwatermode,8,0,1,46,1 SM50,solar,162,doublematchflow,doublematchflow,boolean, ,true,switch.solar_doublematchflow,switch.solar_doublematchflow,8,0,1,47,1 SM50,solar,162,pump2minmod,minimum pump 2 modulation,uint8 (>=0<=100),%,true,number.solar_minimum_pump_2_modulation,number.solar_pump2minmod,8,0,1,48,1 @@ -4862,8 +4862,8 @@ SM100/MS100,solar,163,externalcyl,external cylinder,boolean, ,true,switch.solar_ SM100/MS100,solar,163,thermaldisinfect,thermal disinfection,boolean, ,true,switch.solar_thermal_disinfection,switch.solar_thermaldisinfect,8,0,1,41,1 SM100/MS100,solar,163,heatmetering,heatmetering,boolean, ,true,switch.solar_heatmetering,switch.solar_heatmetering,8,0,1,42,1 SM100/MS100,solar,163,activated,activated,boolean, ,true,switch.solar_activated,switch.solar_activated,8,0,1,43,1 -SM100/MS100,solar,163,solarpumpmode,pump mode,enum [constant\|pwm\|analog], ,true,select.solar_pump_mode,select.solar_solarpumpmode,8,0,1,44,1 -SM100/MS100,solar,163,pumpkick,pump kick,boolean, ,true,switch.solar_pump_kick,switch.solar_pumpkick,8,0,1,45,1 +SM100/MS100,solar,163,solarpumpmode,solar pump mode,enum [constant\|pwm\|analog], ,true,select.solar_solar_pump_mode,select.solar_solarpumpmode,8,0,1,44,1 +SM100/MS100,solar,163,solarpumpkick,solar pump kick,boolean, ,true,switch.solar_solar_pump_kick,switch.solar_solarpumpkick,8,0,1,45,1 SM100/MS100,solar,163,plainwatermode,plain water mode,boolean, ,true,switch.solar_plain_water_mode,switch.solar_plainwatermode,8,0,1,46,1 SM100/MS100,solar,163,doublematchflow,doublematchflow,boolean, ,true,switch.solar_doublematchflow,switch.solar_doublematchflow,8,0,1,47,1 SM100/MS100,solar,163,pump2minmod,minimum pump 2 modulation,uint8 (>=0<=100),%,true,number.solar_minimum_pump_2_modulation,number.solar_pump2minmod,8,0,1,48,1 @@ -4916,8 +4916,8 @@ SM200/MS200,solar,164,externalcyl,external cylinder,boolean, ,true,switch.solar_ SM200/MS200,solar,164,thermaldisinfect,thermal disinfection,boolean, ,true,switch.solar_thermal_disinfection,switch.solar_thermaldisinfect,8,0,1,41,1 SM200/MS200,solar,164,heatmetering,heatmetering,boolean, ,true,switch.solar_heatmetering,switch.solar_heatmetering,8,0,1,42,1 SM200/MS200,solar,164,activated,activated,boolean, ,true,switch.solar_activated,switch.solar_activated,8,0,1,43,1 -SM200/MS200,solar,164,solarpumpmode,pump mode,enum [constant\|pwm\|analog], ,true,select.solar_pump_mode,select.solar_solarpumpmode,8,0,1,44,1 -SM200/MS200,solar,164,pumpkick,pump kick,boolean, ,true,switch.solar_pump_kick,switch.solar_pumpkick,8,0,1,45,1 +SM200/MS200,solar,164,solarpumpmode,solar pump mode,enum [constant\|pwm\|analog], ,true,select.solar_solar_pump_mode,select.solar_solarpumpmode,8,0,1,44,1 +SM200/MS200,solar,164,solarpumpkick,solar pump kick,boolean, ,true,switch.solar_solar_pump_kick,switch.solar_solarpumpkick,8,0,1,45,1 SM200/MS200,solar,164,plainwatermode,plain water mode,boolean, ,true,switch.solar_plain_water_mode,switch.solar_plainwatermode,8,0,1,46,1 SM200/MS200,solar,164,doublematchflow,doublematchflow,boolean, ,true,switch.solar_doublematchflow,switch.solar_doublematchflow,8,0,1,47,1 SM200/MS200,solar,164,pump2minmod,minimum pump 2 modulation,uint8 (>=0<=100),%,true,number.solar_minimum_pump_2_modulation,number.solar_pump2minmod,8,0,1,48,1 diff --git a/dump_telegrams.csv b/dump_telegrams.csv index d07246469..2e3aa9b9a 100644 --- a/dump_telegrams.csv +++ b/dump_telegrams.csv @@ -105,10 +105,10 @@ telegram_type_id,name,is_fetched,is_cmd 0x02A0,RC300Curves, ,cmd 0x02A1,RC300Curves, ,cmd 0x02A2,RC300Curves, ,cmd -0x02A5,CRFMonitor, ,cmd +0x02A5,RC300Monitor, ,cmd 0x02A6,RC300Monitor, ,cmd 0x02A7,RC300Monitor, ,cmd -0x02A8,RC300Monitor, ,cmd +0x02A8,CRFMonitor, ,cmd 0x02A9,RC300Monitor, ,cmd 0x02AA,RC300Monitor, ,cmd 0x02AB,RC300Monitor, ,cmd @@ -129,7 +129,7 @@ telegram_type_id,name,is_fetched,is_cmd 0x02BE,RC300Set, ,cmd 0x02BF,RC300Set, ,cmd 0x02C0,RC300Set, ,cmd -0x02CC,RC300Set2, ,cmd +0x02CC,HPPressure,fetched,cmd 0x02CD,MMPLUSConfigMessage,fetched,cmd 0x02CE,RC300Set2, ,cmd 0x02D0,RC300Set2, ,cmd diff --git a/interface/package.json b/interface/package.json index bb5058464..13e7ee4bd 100644 --- a/interface/package.json +++ b/interface/package.json @@ -35,10 +35,10 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-icons": "^5.3.0", - "react-router-dom": "^6.26.1", + "react-router-dom": "^6.26.2", "react-toastify": "^10.0.5", "typesafe-i18n": "^5.26.2", - "typescript": "^5.5.4" + "typescript": "^5.6.2" }, "devDependencies": { "@babel/core": "^7.25.2", @@ -52,15 +52,15 @@ "@types/react": "^18.3.5", "@types/react-dom": "^18.3.0", "@types/react-router-dom": "^5.3.3", - "concurrently": "^8.2.2", + "concurrently": "^9.0.0", "eslint": "^9.10.0", "eslint-config-prettier": "^9.1.0", "formidable": "^3.5.1", "prettier": "^3.3.3", "rollup-plugin-visualizer": "^5.12.0", - "terser": "^5.31.6", - "typescript-eslint": "8.4.0", - "vite": "^5.4.3", + "terser": "^5.32.0", + "typescript-eslint": "8.5.0", + "vite": "^5.4.4", "vite-plugin-imagemin": "^0.6.1", "vite-tsconfig-paths": "^5.0.1" }, diff --git a/interface/src/app/main/Help.tsx b/interface/src/app/main/Help.tsx index 369619319..3518a892a 100644 --- a/interface/src/app/main/Help.tsx +++ b/interface/src/app/main/Help.tsx @@ -102,7 +102,7 @@ const Help = () => { color="primary" onClick={() => callAPI('system', 'info')} > - {LL.SUPPORT_INFORMATION(0)} + {LL.DOWNLOAD(1)} {LL.SUPPORT_INFORMATION(0)} @@ -113,24 +113,24 @@ const Help = () => { color="primary" onClick={() => callAPI('system', 'allvalues')} > - {LL.ALLVALUES()} + {LL.DOWNLOAD(1)} {LL.ALLVALUES()} - - - {LL.HELP_INFORMATION_5()} + + + {LL.HELP_INFORMATION_5()} - + - {'github.com/emsesp/EMS-ESP32'} + {'https://github.com/emsesp/EMS-ESP32'} - - @proddy @MichaelDvP + + © emsesp.org diff --git a/interface/src/app/settings/ApplicationSettings.tsx b/interface/src/app/settings/ApplicationSettings.tsx index b6ef0cc23..9daf45b74 100644 --- a/interface/src/app/settings/ApplicationSettings.tsx +++ b/interface/src/app/settings/ApplicationSettings.tsx @@ -613,10 +613,10 @@ const ApplicationSettings = () => { name="tx_mode" label={LL.TX_MODE()} value={data.tx_mode} - fullWidth variant="outlined" onChange={updateFormValue} margin="normal" + sx={{ width: '15ch' }} select > EMS diff --git a/interface/src/app/settings/DownloadUpload.tsx b/interface/src/app/settings/DownloadUpload.tsx index e41251917..c2365e51a 100644 --- a/interface/src/app/settings/DownloadUpload.tsx +++ b/interface/src/app/settings/DownloadUpload.tsx @@ -15,6 +15,7 @@ import { Link, Typography } from '@mui/material'; +import Grid from '@mui/material/Grid2'; import * as SystemApi from 'api/system'; import { @@ -291,34 +292,11 @@ const DownloadUpload = () => { {LL.DOWNLOAD(0)} - - - {LL.HELP_INFORMATION_4()} - - - - - - - {LL.DOWNLOAD_SETTINGS_TEXT()} - + + {LL.DOWNLOAD_SETTINGS_TEXT()} + + - - - - {LL.DOWNLOAD_CUSTOMIZATION_TEXT()} - - - - {LL.DOWNLOAD_SCHEDULE_TEXT()} - - + + + + {LL.UPLOAD()} + + + + {LL.UPLOAD_TEXT()} - - - {LL.EMS_ESP_VER()} - - + + + + {LL.EMS_ESP_VER()} + + {LL.VERSION() + ':'} {data.emsesp_version} @@ -430,16 +407,6 @@ const DownloadUpload = () => { {renderUploadDialog()} - - - {LL.UPLOAD()} - - - - {LL.UPLOAD_TEXT()} - - - ); }; diff --git a/interface/src/app/status/RestartMonitor.tsx b/interface/src/app/status/RestartMonitor.tsx index 83377d1ee..9e813eebe 100644 --- a/interface/src/app/status/RestartMonitor.tsx +++ b/interface/src/app/status/RestartMonitor.tsx @@ -59,9 +59,10 @@ const RestartMonitor = () => { : data?.status === 'ready' ? LL.RESTARTING_PRE() : LL.RESTARTING_POST()} + … - {LL.PLEASE_WAIT()}… + {LL.PLEASE_WAIT()} {errorMessage ? ( diff --git a/interface/src/app/status/SystemLog.tsx b/interface/src/app/status/SystemLog.tsx index 561a7e342..436bbb323 100644 --- a/interface/src/app/status/SystemLog.tsx +++ b/interface/src/app/status/SystemLog.tsx @@ -6,8 +6,12 @@ import WarningIcon from '@mui/icons-material/Warning'; import { Box, Button, Checkbox, MenuItem, TextField, styled } from '@mui/material'; import Grid from '@mui/material/Grid2'; -import * as SystemApi from 'api/system'; -import { fetchLogES } from 'api/system'; +import { + fetchLog, + fetchLogES, + readLogSettings, + updateLogSettings +} from 'api/system'; import { useRequest, useSSE } from 'alova/client'; import { @@ -22,20 +26,18 @@ import type { LogEntry, LogSettings } from 'types'; import { LogLevel } from 'types'; import { updateValueDirty, useRest } from 'utils'; -const ButtonTextColors = { +const TextColors = { [LogLevel.ERROR]: '#ff0000', // red - [LogLevel.WARNING]: '#ffcc00', // yellow + [LogLevel.WARNING]: '#ff0000', // red [LogLevel.NOTICE]: '#ffffff', // white - [LogLevel.INFO]: '#ffffff', // yellow + [LogLevel.INFO]: '#ffcc00', // yellow [LogLevel.DEBUG]: '#00ffff', // cyan [LogLevel.TRACE]: '#00ffff' // cyan }; -const LogEntryLine = styled('div')( +const LogEntryLine = styled('span')( ({ details: { level } }: { details: { level: LogLevel } }) => ({ - color: ButtonTextColors[level], - font: '14px monospace', - whiteSpace: 'nowrap' + color: TextColors[level] }) ); @@ -79,8 +81,8 @@ const SystemLog = () => { saveData, errorMessage } = useRest({ - read: SystemApi.readLogSettings, - update: SystemApi.updateLogSettings + read: readLogSettings, + update: updateLogSettings }); const [logEntries, setLogEntries] = useState([]); @@ -114,7 +116,7 @@ const SystemLog = () => { }); // called on page load to reset pointer and fetch all log entries - useRequest(SystemApi.fetchLog()); + useRequest(fetchLog()); const paddedLevelLabel = (level: LogLevel) => { const label = levelLabel(level); @@ -190,23 +192,25 @@ const SystemLog = () => { ALL - - - 25 - 50 - 75 - 100 - - + {data.psram && ( + + + 25 + 50 + 75 + 100 + + + )} { }} > {logEntries.map((e) => ( - +
{e.t} {paddedLevelLabel(e.l)}  {paddedIDLabel(e.i)} {paddedNameLabel(e.n)} - {e.m} - + + {e.m} + +
))} +
diff --git a/interface/src/components/upload/SingleUpload.tsx b/interface/src/components/upload/SingleUpload.tsx index 9c425e2a3..78f29e465 100644 --- a/interface/src/components/upload/SingleUpload.tsx +++ b/interface/src/components/upload/SingleUpload.tsx @@ -44,7 +44,7 @@ const SingleUpload = ({ doRestart }) => { abort: cancelUpload } = useRequest(SystemApi.uploadFile, { immediate: false - }).onComplete(({ data }) => { + }).onSuccess(({ data }) => { if (data) { setMd5(data.md5 as string); toast.success(LL.UPLOAD() + ' MD5 ' + LL.SUCCESSFUL()); @@ -59,10 +59,8 @@ const SingleUpload = ({ doRestart }) => { await sendUpload(file).catch((error: Error) => { if (error.message === 'The user aborted a request') { toast.warning(LL.UPLOAD() + ' ' + LL.ABORTED()); - } else if (error.message === 'Network Error') { - toast.warning('Invalid file extension or incompatible bin file'); } else { - toast.error(error.message); + toast.warning('Invalid file extension or incompatible bin file'); } }); } diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts index 027288e4b..78eb19d3a 100644 --- a/interface/src/i18n/de/index.ts +++ b/interface/src/i18n/de/index.ts @@ -177,7 +177,7 @@ const de: Translation = { STABLE: 'Stabil', DEVELOPMENT: 'Entwicklung', RELEASE_NOTES: 'Versionshinweise', - EMS_ESP_VER: 'EMS-ESP Version', + EMS_ESP_VER: 'Firmware Version', // TODO translate UPTIME: 'Systembetriebszeit', FREE_MEMORY: 'Freier RAM Speicher', PSRAM: 'PSRAM (Größe / Frei)', @@ -186,10 +186,8 @@ const de: Translation = { FILESYSTEM: 'Dateisystem (Genutzt / Frei)', BUFFER_SIZE: 'max. Puffergröße', COMPACT: 'Kompakte Darstellung', - DOWNLOAD_CUSTOMIZATION_TEXT: 'Herunterladen der individuellen Entitätsanpassungen', - DOWNLOAD_SCHEDULE_TEXT: 'Herunterladen geplanter Befehle', - DOWNLOAD_SETTINGS_TEXT: 'Herunterladen der Anwendungseinstellungen. Vorsicht beim Teilen der Einstellungen, da sie Passwörter und andere sensible Daten enthalten', - UPLOAD_TEXT: 'Hochladen von neuer Firmware (.bin), Geräte- oder Entitätseinstellungen (.json), zur optionalen Validitätsprüfung zuerst die (.md5) Datei hochladen', + DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate + UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_DROP_TEXT: 'Klicken Sie hier, oder ziehen Sie eine Datei hierher', ERROR: 'Unerwarteter Fehler, bitte versuchen Sie es erneut', TIME_SET: 'Zeit gesetzt', @@ -340,7 +338,7 @@ const de: Translation = { LATEST_VERSION: 'Sie verwenden die neueste Firmware-Version.', PLEASE_WAIT: 'Bitte warten', RESTARTING_PRE: 'Initialisierung', - RESTARTING_POST: 'Neuladen' + RESTARTING_POST: 'Vorbereitung' }; export default de; diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts index 796cbaccf..08b3f0f08 100644 --- a/interface/src/i18n/en/index.ts +++ b/interface/src/i18n/en/index.ts @@ -177,7 +177,7 @@ const en: Translation = { STABLE: 'Stable', DEVELOPMENT: 'Development', RELEASE_NOTES: 'release notes', - EMS_ESP_VER: 'EMS-ESP Version', + EMS_ESP_VER: 'Firmware Version', // TODO translate UPTIME: 'System Uptime', FREE_MEMORY: 'Free Memory', PSRAM: 'PSRAM (Size / Free)', @@ -186,10 +186,8 @@ const en: Translation = { FILESYSTEM: 'File System (Used / Free)', BUFFER_SIZE: 'Max Buffer Size', COMPACT: 'Compact', - DOWNLOAD_CUSTOMIZATION_TEXT: 'Download the entity customizations', - DOWNLOAD_SCHEDULE_TEXT: 'Download Scheduler Events', - DOWNLOAD_SETTINGS_TEXT: 'Download the application settings. Be careful when sharing your settings as this file contains passwords and other sensitive system information', - UPLOAD_TEXT: 'Upload a new firmware (.bin) file, settings or customizations (.json) file below, for optional validation upload (.md5) first', + DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate + UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', UPLOAD_DROP_TEXT: 'Drop file or click here', ERROR: 'Unexpected Error, please try again', TIME_SET: 'Time set', @@ -334,13 +332,13 @@ const en: Translation = { ALLVALUES: 'All Values', SPECIAL_FUNCTIONS: 'Special Functions', WAIT_FIRMWARE: 'Firmware is uploading and installing', - INSTALL_VERSION: 'This will install vesion {0}. Are you sure?', + INSTALL_VERSION: 'This will install version {0}. Are you sure?', SWITCH_DEV: 'switch to the development version', UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', LATEST_VERSION: 'You are using the latest firmware version.', PLEASE_WAIT: 'Please wait', RESTARTING_PRE: 'Initializing', - RESTARTING_POST: 'Reloading' + RESTARTING_POST: 'Preparing' }; export default en; diff --git a/interface/src/i18n/fr/index.ts b/interface/src/i18n/fr/index.ts index f7465ccdc..9a3ee8f09 100644 --- a/interface/src/i18n/fr/index.ts +++ b/interface/src/i18n/fr/index.ts @@ -177,7 +177,7 @@ const fr: Translation = { STABLE: 'Stable', // TODO translate DEVELOPMENT: 'Développement', RELEASE_NOTES: 'notes de version', - EMS_ESP_VER: 'Version EMS-ESP', + EMS_ESP_VER: 'Firmware Version', // TODO translate UPTIME: 'Durée de fonctionnement du système', FREE_MEMORY: 'Libre Memory', PSRAM: 'PSRAM (Taille / Libre)', @@ -186,10 +186,8 @@ const fr: Translation = { FILESYSTEM: 'File System (Utilisée / Libre)', BUFFER_SIZE: 'Max taille du buffer', COMPACT: 'Compact', - DOWNLOAD_CUSTOMIZATION_TEXT: "Télécharger les personnalisations d'entités", - DOWNLOAD_SCHEDULE_TEXT: 'Download Scheduler Events', // TODO translate - DOWNLOAD_SETTINGS_TEXT: "Téléchargez les paramètres de l'application. Soyez prudent lorsque vous partagez vos paramètres car ce fichier contient des mots de passe et d'autres informations système sensibles.", - UPLOAD_TEXT: "Téléchargez un nouveau fichier de firmware (.bin), un fichier de paramètres ou de personnalisations (.json) ci-dessous, pour une validation optionnelle téléchargez d'abord un fichier (.md5)", + DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate + UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_DROP_TEXT: 'Déposer le fichier ou cliquer ici', ERROR: 'Erreur inattendue, veuillez réessayer', TIME_SET: 'Time set', @@ -334,13 +332,13 @@ const fr: Translation = { ALLVALUES: 'All Values', // TODO translate SPECIAL_FUNCTIONS: 'Special Functions', WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate - INSTALL_VERSION: 'This will install vesion {0}. Are you sure?', // TODO translate + INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate SWITCH_DEV: 'switch to the development version', // TODO translate UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate LATEST_VERSION: 'You are using the latest firmware version.', // TODO translate // TODO translate PLEASE_WAIT: 'Please wait', // TODO translate RESTARTING_PRE: 'Initializing', // TODO translate - RESTARTING_POST: 'Reloading' // TODO translate + RESTARTING_POST: 'Preparing' // TODO translate }; export default fr; diff --git a/interface/src/i18n/it/index.ts b/interface/src/i18n/it/index.ts index b0d07c848..e8dd6ba9a 100644 --- a/interface/src/i18n/it/index.ts +++ b/interface/src/i18n/it/index.ts @@ -177,7 +177,7 @@ const it: Translation = { STABLE: 'Stable', // TODO translate DEVELOPMENT: 'Sviluppo', RELEASE_NOTES: 'note rilascio', - EMS_ESP_VER: 'Versione EMS-ESP', + EMS_ESP_VER: 'Versione Firmware', UPTIME: 'Tempo di attività del sistema', FREE_MEMORY: 'Free Memory', PSRAM: 'PSRAM (Size / Free)', @@ -186,10 +186,8 @@ const it: Translation = { FILESYSTEM: 'Memoria Sistema (Usata / Libera)', BUFFER_SIZE: 'Max Buffer Size', COMPACT: 'Compact', - DOWNLOAD_CUSTOMIZATION_TEXT: 'Scarica personalizzazioni entità', - DOWNLOAD_SCHEDULE_TEXT: 'Download Scheduler Events', - DOWNLOAD_SETTINGS_TEXT: 'Scarica le impostazioni dell applicazione. Fai attenzione quando condividi le tue impostazioni poiché questo file contiene password e altre informazioni di sistema riservate', - UPLOAD_TEXT: 'Carica un nuovo file firmware (.bin) , file delle impostazioni o delle personalizzazioni (.json) di seguito, per un opzione di convalida scaricare dapprima un file "*.MD5" ', + DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate + UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_DROP_TEXT: 'Trascina il file o clicca qui', ERROR: 'Errore Inaspettato, prego tenta ancora', TIME_SET: 'Imposta Ora', @@ -334,13 +332,13 @@ const it: Translation = { ALLVALUES: 'All Values', // TODO translate SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate - INSTALL_VERSION: 'This will install vesion {0}. Are you sure?', // TODO translate + INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate SWITCH_DEV: 'switch to the development version', // TODO translate UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate LATEST_VERSION: 'You are using the latest firmware version.', // TODO translate PLEASE_WAIT: 'Please wait', // TODO translate RESTARTING_PRE: 'Initializing', // TODO translate - RESTARTING_POST: 'Reloading' // TODO translate + RESTARTING_POST: 'Preparing' // TODO translate }; export default it; diff --git a/interface/src/i18n/nl/index.ts b/interface/src/i18n/nl/index.ts index 76f5c6789..420d6ac57 100644 --- a/interface/src/i18n/nl/index.ts +++ b/interface/src/i18n/nl/index.ts @@ -177,7 +177,7 @@ const nl: Translation = { STABLE: 'Stable', DEVELOPMENT: 'Development', RELEASE_NOTES: 'release notes', - EMS_ESP_VER: 'EMS-ESP Versie', + EMS_ESP_VER: 'Firmware Versie', UPTIME: 'Systeem Uptime', FREE_MEMORY: 'Free Memory', PSRAM: 'PSRAM (Size / Free)', @@ -186,10 +186,8 @@ const nl: Translation = { FILESYSTEM: 'File System (Used / Free)', BUFFER_SIZE: 'Max Buffer Size', COMPACT: 'Compact', - DOWNLOAD_CUSTOMIZATION_TEXT: 'Download alle custom instellingen', - DOWNLOAD_SCHEDULE_TEXT: 'Download Scheduler Events', - DOWNLOAD_SETTINGS_TEXT: 'Download de applicatie settings. Wees voorzichting met het delen van dit bestand want het bevat o.a. de wachtwoorden in plain text', - UPLOAD_TEXT: 'Upload een nieuwe firmware (.bin) file, instellingen of custom instellingen (.json) bestand hieronder', + DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate + UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_DROP_TEXT: 'Sleep bestand hierheen of klik hier', ERROR: 'Onverwachte fout, probeer opnieuw', TIME_SET: 'Tijd ingesteld', @@ -334,13 +332,13 @@ const nl: Translation = { ALLVALUES: 'All Values', // TODO translate SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate - INSTALL_VERSION: 'This will install vesion {0}. Are you sure?', // TODO translate + INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate SWITCH_DEV: 'switch to the development version', // TODO translate UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate LATEST_VERSION: 'You are using the latest firmware version.', // TODO translate PLEASE_WAIT: 'Please wait', // TODO translate RESTARTING_PRE: 'Initializing', // TODO translate - RESTARTING_POST: 'Reloading' // TODO translate + RESTARTING_POST: 'Preparing' // TODO translate }; export default nl; diff --git a/interface/src/i18n/no/index.ts b/interface/src/i18n/no/index.ts index bd77cd0eb..c91fad680 100644 --- a/interface/src/i18n/no/index.ts +++ b/interface/src/i18n/no/index.ts @@ -177,7 +177,7 @@ const no: Translation = { STABLE: 'Stable', // TODO translate DEVELOPMENT: 'Development', RELEASE_NOTES: 'release notes', - EMS_ESP_VER: 'EMS-ESP Version', + EMS_ESP_VER: 'Firmware Version', // TODO translate UPTIME: 'System Oppetid', FREE_MEMORY: 'Ledig Memory', PSRAM: 'PSRAM (Størrelse / Ledig)', @@ -186,10 +186,8 @@ const no: Translation = { FILESYSTEM: 'File System (Brukt / Ledig)', BUFFER_SIZE: 'Max Buffer Størrelse', COMPACT: 'Komprimere', - DOWNLOAD_CUSTOMIZATION_TEXT: 'Last ned objektstilpasninger', - DOWNLOAD_SCHEDULE_TEXT: 'Last ned planlagte oppgaver', - DOWNLOAD_SETTINGS_TEXT: 'Last ned applikasjonskonfigurasjon. Vær varsom med å dele fila da den inneholder passord og annen sensitiv system informasjon', - UPLOAD_TEXT: 'Last opp en ny firmware (.bin) fil, innstillinger eller tilpassninger (.json) fil nedenfor', + DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate + UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_DROP_TEXT: 'Slipp fil eller klikk her', ERROR: 'Ukjent feil, prøv igjen', TIME_SET: 'Still in tid', @@ -334,13 +332,13 @@ const no: Translation = { ALLVALUES: 'All Values', // TODO translate SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate - INSTALL_VERSION: 'This will install vesion {0}. Are you sure?', // TODO translate + INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate SWITCH_DEV: 'switch to the development version', // TODO translate UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate LATEST_VERSION: 'You are using the latest firmware version.', // TODO translate PLEASE_WAIT: 'Please wait', // TODO translate RESTARTING_PRE: 'Initializing', // TODO translate - RESTARTING_POST: 'Reloading' // TODO translate + RESTARTING_POST: 'Preparing' // TODO translate }; export default no; diff --git a/interface/src/i18n/pl/index.ts b/interface/src/i18n/pl/index.ts index 062fca421..85c54584d 100644 --- a/interface/src/i18n/pl/index.ts +++ b/interface/src/i18n/pl/index.ts @@ -177,7 +177,7 @@ const pl: BaseTranslation = { STABLE: 'Stable', // TODO translate DEVELOPMENT: 'Testowe', RELEASE_NOTES: 'lista zmian', - EMS_ESP_VER: 'Wersja EMS-ESP', + EMS_ESP_VER: 'Wersja Firmware', UPTIME: 'Czas działania systemu', FREE_MEMORY: 'Wolne Memory', // TODO translate PSRAM: 'PSRAM (rozmiar / wolne)', @@ -186,10 +186,8 @@ const pl: BaseTranslation = { FILESYSTEM: 'System plików (wykorzystane / wolne)', BUFFER_SIZE: 'Maksymalna pojemność bufora (ilość wpisów)', COMPACT: 'Kompaktowy', - DOWNLOAD_CUSTOMIZATION_TEXT: 'Pobierz personalizacje.', - DOWNLOAD_SCHEDULE_TEXT: 'Pobierz harmonogram zdarzeń.', - DOWNLOAD_SETTINGS_TEXT: 'Pobierz ustawienia aplikacji. Uwaga! Plik z ustawieniami zawiera hasła oraz inne wrażliwe informacje systemowe! Nie udostepniaj go pochopnie!', - UPLOAD_TEXT: 'Wyślij firmware (.bin), ustawienia lub personalizacje (.json). Opcjonalnie, wyślij wcześniej plik walidacji z sumą kontrolną (.md5).', + DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate + UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_DROP_TEXT: 'Przeciągnij tutaj plik lub kliknij', ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!', TIME_SET: 'Zegar został ustawiony.', @@ -334,13 +332,13 @@ const pl: BaseTranslation = { ALLVALUES: 'All Values', // TODO translate SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate - INSTALL_VERSION: 'This will install vesion {0}. Are you sure?', // TODO translate + INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate SWITCH_DEV: 'switch to the development version', // TODO translate UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate LATEST_VERSION: 'You are using the latest firmware version.', // TODO translate PLEASE_WAIT: 'Please wait', // TODO translate RESTARTING_PRE: 'Initializing', // TODO translate - RESTARTING_POST: 'Reloading' // TODO translate + RESTARTING_POST: 'Preparing' // TODO translate }; export default pl; diff --git a/interface/src/i18n/sk/index.ts b/interface/src/i18n/sk/index.ts index dcb68804b..fda468557 100644 --- a/interface/src/i18n/sk/index.ts +++ b/interface/src/i18n/sk/index.ts @@ -177,19 +177,17 @@ const sk: Translation = { STABLE: 'Stabilná', // TODO translate DEVELOPMENT: 'Vývojárska', RELEASE_NOTES: 'poznámky k verzii', - EMS_ESP_VER: 'EMS-ESP verzia', + EMS_ESP_VER: 'Firmware verzia', UPTIME: 'Beh systému', - FREE_MEMORY: 'Voľná pamäť', // TODO translate + FREE_MEMORY: 'Voľné Memory', PSRAM: 'PSRAM (Veľkosť / Voľné)', FLASH: 'Flash chip (Veľkosť , Rýchlosť)', APPSIZE: 'Applikácia (Oddiel: Použité / Voľné)', FILESYSTEM: 'Súborový systém (Použité / Voľné)', BUFFER_SIZE: 'Buffer-max.veľkosť', COMPACT: 'Kompaktné', - DOWNLOAD_CUSTOMIZATION_TEXT: 'Stiahnutie prispôsobení entity', - DOWNLOAD_SCHEDULE_TEXT: 'Stiahnutie plánovača udalostí', - DOWNLOAD_SETTINGS_TEXT: 'Stiahnite si nastavenia aplikácie. Pri zdieľaní nastavení buďte opatrní, pretože tento súbor obsahuje heslá a iné citlivé systémové informácie.', - UPLOAD_TEXT: 'Najskôr nahrajte nový súbor firmvéru (.bin), nastavenia alebo prispôsobenia (.json), pre voliteľné overenie nahrajte súbor (.md5)', + DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate + UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_DROP_TEXT: 'Potiahnúť a pripnúť súbor alebo kliknúť sem', ERROR: 'Neočakávaná chyba, prosím skúste to znova', TIME_SET: 'Nastavený čas', diff --git a/interface/src/i18n/sv/index.ts b/interface/src/i18n/sv/index.ts index d18e34d66..79494dd45 100644 --- a/interface/src/i18n/sv/index.ts +++ b/interface/src/i18n/sv/index.ts @@ -177,7 +177,7 @@ const sv: Translation = { STABLE: 'Stable', // TODO translate DEVELOPMENT: 'Utveckling', RELEASE_NOTES: 'release-logg', - EMS_ESP_VER: 'EMS-ESP Version', + EMS_ESP_VER: 'Firmware Version', // TODO translate UPTIME: 'Systemets Upptid', FREE_MEMORY: 'Ledigt Memory', PSRAM: 'PSRAM (Storlek / Ledigt)', @@ -186,10 +186,8 @@ const sv: Translation = { FILESYSTEM: 'Filsystem (Använt / Ledigt)', BUFFER_SIZE: 'Max Bufferstorlek', COMPACT: 'Komprimera', - DOWNLOAD_CUSTOMIZATION_TEXT: 'Ladda ner entitetsanpassningar', - DOWNLOAD_SCHEDULE_TEXT: 'Download Scheduler Events', // TODO translate - DOWNLOAD_SETTINGS_TEXT: 'Ladda ner applikationsinställningar. Var försiktig om du delar dina iställlningar då de innehåller lösenord och annan känslig systeminformation', - UPLOAD_TEXT: 'Ladda upp ett nytt firmware (.bin), inställningar eller anpassningar (.json) nedan', + DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate + UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_DROP_TEXT: 'Släpp fil eller klicka här', ERROR: 'Okänt Fel, var god försök igen', TIME_SET: 'Ställ in tid', @@ -334,13 +332,13 @@ const sv: Translation = { ALLVALUES: 'All Values', // TODO translate SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate - INSTALL_VERSION: 'This will install vesion {0}. Are you sure?', // TODO translate + INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate SWITCH_DEV: 'switch to the development version', // TODO translate UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate LATEST_VERSION: 'You are using the latest firmware version.', // TODO translate PLEASE_WAIT: 'Please wait', // TODO translate RESTARTING_PRE: 'Initializing', // TODO translate - RESTARTING_POST: 'Reloading' // TODO translate + RESTARTING_POST: 'Preparing' // TODO translate }; export default sv; diff --git a/interface/src/i18n/tr/index.ts b/interface/src/i18n/tr/index.ts index f82467641..aef0043f0 100644 --- a/interface/src/i18n/tr/index.ts +++ b/interface/src/i18n/tr/index.ts @@ -177,19 +177,17 @@ const tr: Translation = { STABLE: 'Stable', // TODO translate DEVELOPMENT: 'Geliştirme', RELEASE_NOTES: 'yayınlanma notları', - EMS_ESP_VER: 'EMS-ESP Sürümü', + EMS_ESP_VER: 'Firmware Sürümü', UPTIME: 'Sistem Çalışma Süresi', - FREE_MEMORY: 'Yığın Memory', // TODO translate + FREE_MEMORY: 'Yığın Memory', PSRAM: 'PSRAM (Boyut / Boş)', FLASH: 'Flash Çipi (Boyut , Hız)', APPSIZE: 'Uygulama (Bölme: Kullanılmış / Boş)', FILESYSTEM: 'Dosya Sistemi (Kullanılmış / Boş)', BUFFER_SIZE: 'En fazla bellek boyutu', COMPACT: 'Sıkışık', - DOWNLOAD_CUSTOMIZATION_TEXT: 'Varlık özelleştirmelerini indir', - DOWNLOAD_SCHEDULE_TEXT: 'Download Scheduler Events', // TODO translate - DOWNLOAD_SETTINGS_TEXT: 'Uygulama ayarlarını indir. Bu dosya hassas sistem bilgileri ve şifrelerinizi içerdiğinden ayarlarınızı paylaşırken dikkatli olun', - UPLOAD_TEXT: 'Yeni bir bellenim(.bin) dosyası yükleyin, ayarlar ve özelleştirmeler(.json) dosyası aşağıda, sçenekli denetim yüklemesi(.md5) için önce', + DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate + UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_DROP_TEXT: 'Buraya tıklayın yada dosyayı sürükleyip bırakın', ERROR: 'Beklenemedik hata, lütfen tekrar deneyin.', TIME_SET: 'Zaman ayarı', @@ -334,13 +332,13 @@ const tr: Translation = { ALLVALUES: 'All Values', // TODO translate SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate - INSTALL_VERSION: 'This will install vesion {0}. Are you sure?', // TODO translate + INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate SWITCH_DEV: 'switch to the development version', // TODO translate UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate LATEST_VERSION: 'You are using the latest firmware version.', // TODO translate PLEASE_WAIT: 'Please wait', // TODO translate RESTARTING_PRE: 'Initializing', // TODO translate - RESTARTING_POST: 'Reloading' // TODO translate + RESTARTING_POST: 'Preparing' // TODO translate }; export default tr; diff --git a/interface/src/types/system.ts b/interface/src/types/system.ts index 9cfa528d1..768813dda 100644 --- a/interface/src/types/system.ts +++ b/interface/src/types/system.ts @@ -70,4 +70,5 @@ export interface LogSettings { level: number; max_messages: number; compact: boolean; + psram: boolean; } diff --git a/interface/yarn.lock b/interface/yarn.lock index 7a2992365..41414e0e6 100644 --- a/interface/yarn.lock +++ b/interface/yarn.lock @@ -287,7 +287,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7": +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7": version: 7.25.0 resolution: "@babel/runtime@npm:7.25.0" dependencies: @@ -1145,10 +1145,10 @@ __metadata: languageName: node linkType: hard -"@remix-run/router@npm:1.19.1": - version: 1.19.1 - resolution: "@remix-run/router@npm:1.19.1" - checksum: 10c0/9101fc96646e5107b6b0ef248d4c93bd965590c37ac02d35bcc57d1902467db7fc6eeec0a1fb97d0ce5bc96fae58e75239555e44a983239a61badba18e82d3b8 +"@remix-run/router@npm:1.19.2": + version: 1.19.2 + resolution: "@remix-run/router@npm:1.19.2" + checksum: 10c0/ac7fc813350686705f2c29219e70e1e299d9a8e3b301e9e81f7e84f578c40c6462b590cf0d78863bac40dbc325b68c71ae070f4a1465793d1d1971b619618295 languageName: node linkType: hard @@ -1595,15 +1595,15 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:8.4.0": - version: 8.4.0 - resolution: "@typescript-eslint/eslint-plugin@npm:8.4.0" +"@typescript-eslint/eslint-plugin@npm:8.5.0": + version: 8.5.0 + resolution: "@typescript-eslint/eslint-plugin@npm:8.5.0" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:8.4.0" - "@typescript-eslint/type-utils": "npm:8.4.0" - "@typescript-eslint/utils": "npm:8.4.0" - "@typescript-eslint/visitor-keys": "npm:8.4.0" + "@typescript-eslint/scope-manager": "npm:8.5.0" + "@typescript-eslint/type-utils": "npm:8.5.0" + "@typescript-eslint/utils": "npm:8.5.0" + "@typescript-eslint/visitor-keys": "npm:8.5.0" graphemer: "npm:^1.4.0" ignore: "npm:^5.3.1" natural-compare: "npm:^1.4.0" @@ -1614,66 +1614,66 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/c75e9bb176e9e0277c9f9c4c006bc2c31ac91984e555de1390a9bbe876e3b6787d59d96015b3f0cd083fd22c814aea4ed4858910d3afdd24d64ab79815da31e5 + checksum: 10c0/69ae7067e03d2d8d442e69d668235bdafd63b07229d0be27025eaad8aa468b5af8ac54627021e0e3a060df04ed1c39d1327a0b11469ac72405b52b74a79f402b languageName: node linkType: hard -"@typescript-eslint/parser@npm:8.4.0": - version: 8.4.0 - resolution: "@typescript-eslint/parser@npm:8.4.0" +"@typescript-eslint/parser@npm:8.5.0": + version: 8.5.0 + resolution: "@typescript-eslint/parser@npm:8.5.0" dependencies: - "@typescript-eslint/scope-manager": "npm:8.4.0" - "@typescript-eslint/types": "npm:8.4.0" - "@typescript-eslint/typescript-estree": "npm:8.4.0" - "@typescript-eslint/visitor-keys": "npm:8.4.0" + "@typescript-eslint/scope-manager": "npm:8.5.0" + "@typescript-eslint/types": "npm:8.5.0" + "@typescript-eslint/typescript-estree": "npm:8.5.0" + "@typescript-eslint/visitor-keys": "npm:8.5.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.57.0 || ^9.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/19f3358e5bc4bbad693183eefe1a90ea64be054a934bc2c8a972ff4738b94580b55ad4955af5797db42298628caa59b3ba3f9fd960582b5fc2c836da3a4578a5 + checksum: 10c0/509fdd605b86c7d025928f20e1035712c2fc268c34b1af84248ed0b53d699034f19caf98e085c5c758d3025e29939dd12eea427c72cae9e5ea79274364851f0a languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.4.0": - version: 8.4.0 - resolution: "@typescript-eslint/scope-manager@npm:8.4.0" +"@typescript-eslint/scope-manager@npm:8.5.0": + version: 8.5.0 + resolution: "@typescript-eslint/scope-manager@npm:8.5.0" dependencies: - "@typescript-eslint/types": "npm:8.4.0" - "@typescript-eslint/visitor-keys": "npm:8.4.0" - checksum: 10c0/95188c663df7db106529c6b93c4c7c61647ed34ab6dd48114e41ddf49140ff606c5501ce2ae451a988ec49b5d3874ea96ff212fc102802327b10affd2ff80a37 + "@typescript-eslint/types": "npm:8.5.0" + "@typescript-eslint/visitor-keys": "npm:8.5.0" + checksum: 10c0/868602f9324a6e15fcae017acd3b0832e9f2c8c8cd315667df37c2e7c765cda5fba7c4bede931f32cc04819ba97cf74a5fddb085c6f1c7993f1fb085ba126422 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:8.4.0": - version: 8.4.0 - resolution: "@typescript-eslint/type-utils@npm:8.4.0" +"@typescript-eslint/type-utils@npm:8.5.0": + version: 8.5.0 + resolution: "@typescript-eslint/type-utils@npm:8.5.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:8.4.0" - "@typescript-eslint/utils": "npm:8.4.0" + "@typescript-eslint/typescript-estree": "npm:8.5.0" + "@typescript-eslint/utils": "npm:8.5.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.3.0" peerDependenciesMeta: typescript: optional: true - checksum: 10c0/ae51100594d9ca61c7577b5aed0bd10c1959725df5c38cd9653eed1fd3dbdfff9146b6e48f3409994b4c8d781b9d95025c36b30f73a5a1b3dbdee6d142cecc87 + checksum: 10c0/675d3e41f938d16e9268fd33764a4e16b12a4a9817e61d5e2508a07fe6783c69ce9d05facc61822b5647c71d767929618ed37b8b93f423f7c2ccb62cfeb4343b languageName: node linkType: hard -"@typescript-eslint/types@npm:8.4.0": - version: 8.4.0 - resolution: "@typescript-eslint/types@npm:8.4.0" - checksum: 10c0/15e09ced84827c349553530a31822f06ae5bad456c03d561b7d0c64b6ad9b5d7ca795e030bd93e65d5a2cd41bfde36ed08dcd2ff9feaa8b60a67080827f47ecb +"@typescript-eslint/types@npm:8.5.0": + version: 8.5.0 + resolution: "@typescript-eslint/types@npm:8.5.0" + checksum: 10c0/f0b666b5c001b9779bfd9e4c7d031843d07264429d5bcf5d636f26f96cd5d949a33f5d6a645b8d74b93daf565a468476a6a4935dd7135a200250fb03acbe4988 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:8.4.0": - version: 8.4.0 - resolution: "@typescript-eslint/typescript-estree@npm:8.4.0" +"@typescript-eslint/typescript-estree@npm:8.5.0": + version: 8.5.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.5.0" dependencies: - "@typescript-eslint/types": "npm:8.4.0" - "@typescript-eslint/visitor-keys": "npm:8.4.0" + "@typescript-eslint/types": "npm:8.5.0" + "@typescript-eslint/visitor-keys": "npm:8.5.0" debug: "npm:^4.3.4" fast-glob: "npm:^3.3.2" is-glob: "npm:^4.0.3" @@ -1683,31 +1683,31 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/170702b024121cff9268f53de8054796b0ce025f9a78d6f2bc850a360e5f3f7032ba3ee9d4b7392726308273a5f3ade5ab31b1788b504b514bc15afc07302b37 + checksum: 10c0/f62f03d0c5dc57b2b54dbe1cbd027966f774f241279655f46c64145abb54b765176a0cd40447583ba56ada306181da9a82e39b777c78128e105e4ea98c609350 languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.4.0": - version: 8.4.0 - resolution: "@typescript-eslint/utils@npm:8.4.0" +"@typescript-eslint/utils@npm:8.5.0": + version: 8.5.0 + resolution: "@typescript-eslint/utils@npm:8.5.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" - "@typescript-eslint/scope-manager": "npm:8.4.0" - "@typescript-eslint/types": "npm:8.4.0" - "@typescript-eslint/typescript-estree": "npm:8.4.0" + "@typescript-eslint/scope-manager": "npm:8.5.0" + "@typescript-eslint/types": "npm:8.5.0" + "@typescript-eslint/typescript-estree": "npm:8.5.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 - checksum: 10c0/8c9c36b3aa23f9bcc28cc4b10f0fa2996f1bc6cdd75135f08c2ef734baa30dbd2a8b92f344b90518e1fd07a486936734789fc7e90b780221a7707dad8e9c9364 + checksum: 10c0/0cb0bfdaf0da79d13c0d0379478eb14b5825d235873bc7181e70c4f6297fa1c74431ef730cbc2912fe1814dd8d46c6515ce22b39c57e8f03c337aa152fd49a4e languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.4.0": - version: 8.4.0 - resolution: "@typescript-eslint/visitor-keys@npm:8.4.0" +"@typescript-eslint/visitor-keys@npm:8.5.0": + version: 8.5.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.5.0" dependencies: - "@typescript-eslint/types": "npm:8.4.0" + "@typescript-eslint/types": "npm:8.5.0" eslint-visitor-keys: "npm:^3.4.3" - checksum: 10c0/339199b7fbb9ac83b530d03ab25f6bc5ceb688c9cd0ae460112cd14ee78ca7284a845aef5620cdf70170980123475ec875e85ebf595c60255ba3c0d6fe48c714 + checksum: 10c0/8b9e81968ad36e8af18ac17b63c4e0764612451ca085676c939b723549052243f63577d2706bc2da48174f11bf47587ab47e6e0b7c5b28d9f3c1ef7b9aad322d languageName: node linkType: hard @@ -1734,7 +1734,7 @@ __metadata: "@types/react-router-dom": "npm:^5.3.3" alova: "npm:3.0.16" async-validator: "npm:^4.2.5" - concurrently: "npm:^8.2.2" + concurrently: "npm:^9.0.0" eslint: "npm:^9.10.0" eslint-config-prettier: "npm:^9.1.0" formidable: "npm:^3.5.1" @@ -1745,14 +1745,14 @@ __metadata: react: "npm:^18.3.1" react-dom: "npm:^18.3.1" react-icons: "npm:^5.3.0" - react-router-dom: "npm:^6.26.1" + react-router-dom: "npm:^6.26.2" react-toastify: "npm:^10.0.5" rollup-plugin-visualizer: "npm:^5.12.0" - terser: "npm:^5.31.6" + terser: "npm:^5.32.0" typesafe-i18n: "npm:^5.26.2" - typescript: "npm:^5.5.4" - typescript-eslint: "npm:8.4.0" - vite: "npm:^5.4.3" + typescript: "npm:^5.6.2" + typescript-eslint: "npm:8.5.0" + vite: "npm:^5.4.4" vite-plugin-imagemin: "npm:^0.6.1" vite-tsconfig-paths: "npm:^5.0.1" languageName: unknown @@ -2340,23 +2340,21 @@ __metadata: languageName: node linkType: hard -"concurrently@npm:^8.2.2": - version: 8.2.2 - resolution: "concurrently@npm:8.2.2" +"concurrently@npm:^9.0.0": + version: 9.0.0 + resolution: "concurrently@npm:9.0.0" dependencies: chalk: "npm:^4.1.2" - date-fns: "npm:^2.30.0" lodash: "npm:^4.17.21" rxjs: "npm:^7.8.1" shell-quote: "npm:^1.8.1" - spawn-command: "npm:0.0.2" supports-color: "npm:^8.1.1" tree-kill: "npm:^1.2.2" yargs: "npm:^17.7.2" bin: conc: dist/bin/concurrently.js concurrently: dist/bin/concurrently.js - checksum: 10c0/0e9683196fe9c071d944345d21d8f34aa6c0cc50c0dd897e95619f2f1c9eb4871dca851b2569da17888235b7335b4c821ca19deed35bebcd9a131ee5d247f34c + checksum: 10c0/65251009f4540c25eda0d5b2f367ba8755eac83db2ce562802132160e9241c5cd755228b18c330ea29ccd5b0a033302da8a670d724e89fe462c26253e3046f2e languageName: node linkType: hard @@ -2535,15 +2533,6 @@ __metadata: languageName: node linkType: hard -"date-fns@npm:^2.30.0": - version: 2.30.0 - resolution: "date-fns@npm:2.30.0" - dependencies: - "@babel/runtime": "npm:^7.21.0" - checksum: 10c0/e4b521fbf22bc8c3db332bbfb7b094fd3e7627de0259a9d17c7551e2d2702608a7307a449206065916538e384f37b181565447ce2637ae09828427aed9cb5581 - languageName: node - linkType: hard - "debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": version: 4.3.6 resolution: "debug@npm:4.3.6" @@ -5831,27 +5820,27 @@ __metadata: languageName: node linkType: hard -"react-router-dom@npm:^6.26.1": - version: 6.26.1 - resolution: "react-router-dom@npm:6.26.1" +"react-router-dom@npm:^6.26.2": + version: 6.26.2 + resolution: "react-router-dom@npm:6.26.2" dependencies: - "@remix-run/router": "npm:1.19.1" - react-router: "npm:6.26.1" + "@remix-run/router": "npm:1.19.2" + react-router: "npm:6.26.2" peerDependencies: react: ">=16.8" react-dom: ">=16.8" - checksum: 10c0/9d9d8ed54d1c95497c6fa35a6ab46992efeccf1cfc6f0f6089c6c9b040af3eae09568fbb80c690bae08051a955d92d7aa3a0e730f626eb69285114993d31d430 + checksum: 10c0/7515128a98eef0a6b2bf354ef9dfefad03556a06be00fa9220eda6526aaada8a42f294911083473d7ced6d7128c3088bd193218bbb3d62593f9f4f7053781c23 languageName: node linkType: hard -"react-router@npm:6.26.1": - version: 6.26.1 - resolution: "react-router@npm:6.26.1" +"react-router@npm:6.26.2": + version: 6.26.2 + resolution: "react-router@npm:6.26.2" dependencies: - "@remix-run/router": "npm:1.19.1" + "@remix-run/router": "npm:1.19.2" peerDependencies: react: ">=16.8" - checksum: 10c0/463078e740462b42bb5ba8004448f33fc9e63778f432a4ed55c57b93c5b519e25fb17913ee8435b0fda33c6b9f75df8ef6fcb2c3a4f8db84fb546d202e29aa51 + checksum: 10c0/0d15a39b419c99fb5ccad76388bfc4ee2b01323b3b1b694595a9f9ea28e1fbeea25486b5398f5d3d93922f5c6a9aa751b6bb27419488d85279f6ca5ff9e0a6bb languageName: node linkType: hard @@ -6395,13 +6384,6 @@ __metadata: languageName: node linkType: hard -"spawn-command@npm:0.0.2": - version: 0.0.2 - resolution: "spawn-command@npm:0.0.2" - checksum: 10c0/b22f2d71239e6e628a400831861ba747750bbb40c0a53323754cf7b84330b73d81e40ff1f9055e6d1971818679510208a9302e13d9ff3b32feb67e74d7a1b3ef - languageName: node - linkType: hard - "spdx-correct@npm:^3.0.0": version: 3.2.0 resolution: "spdx-correct@npm:3.2.0" @@ -6719,9 +6701,9 @@ __metadata: languageName: node linkType: hard -"terser@npm:^5.31.6": - version: 5.31.6 - resolution: "terser@npm:5.31.6" +"terser@npm:^5.32.0": + version: 5.32.0 + resolution: "terser@npm:5.32.0" dependencies: "@jridgewell/source-map": "npm:^0.3.3" acorn: "npm:^8.8.2" @@ -6729,7 +6711,7 @@ __metadata: source-map-support: "npm:~0.5.20" bin: terser: bin/terser - checksum: 10c0/b17d02b65a52a5041430572b3c514475820f5e7590fa93773c0f5b4be601ccf3f6d745bf5a79f3ee58187cf85edf61c24ddf4345783839fccb44c9c8fa9b427e + checksum: 10c0/94daae4881258eb7d09abd46378e23d11ee46caa507b2fb26c5595c7e490914be734e0de38c50041dc38fae5fca24de11badf042dfbbfc1d336ed117335c420a languageName: node linkType: hard @@ -6868,37 +6850,37 @@ __metadata: languageName: node linkType: hard -"typescript-eslint@npm:8.4.0": - version: 8.4.0 - resolution: "typescript-eslint@npm:8.4.0" +"typescript-eslint@npm:8.5.0": + version: 8.5.0 + resolution: "typescript-eslint@npm:8.5.0" dependencies: - "@typescript-eslint/eslint-plugin": "npm:8.4.0" - "@typescript-eslint/parser": "npm:8.4.0" - "@typescript-eslint/utils": "npm:8.4.0" + "@typescript-eslint/eslint-plugin": "npm:8.5.0" + "@typescript-eslint/parser": "npm:8.5.0" + "@typescript-eslint/utils": "npm:8.5.0" peerDependenciesMeta: typescript: optional: true - checksum: 10c0/266ef73fdc1f7fa19228b8653d61ad143261ccd35f7d5d647092ed0e1512de2d4e3d1b9e1f2520658708cc0c1d7925c4ec97f23440c180a3bf1716e81d65123f + checksum: 10c0/dd92e8f5fb50bb05810a1a37a4bbb6f60761295b121f6118bc027686ebc1b3ba9e4248ab5223ed4753e1320ef6329dd2e53e8160fa4463264277f307fefefd62 languageName: node linkType: hard -"typescript@npm:^5.5.4": - version: 5.5.4 - resolution: "typescript@npm:5.5.4" +"typescript@npm:^5.6.2": + version: 5.6.2 + resolution: "typescript@npm:5.6.2" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/422be60f89e661eab29ac488c974b6cc0a660fb2228003b297c3d10c32c90f3bcffc1009b43876a082515a3c376b1eefcce823d6e78982e6878408b9a923199c + checksum: 10c0/3ed8297a8c7c56b7fec282532503d1ac795239d06e7c4966b42d4330c6cf433a170b53bcf93a130a7f14ccc5235de5560df4f1045eb7f3550b46ebed16d3c5e5 languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^5.5.4#optional!builtin": - version: 5.5.4 - resolution: "typescript@patch:typescript@npm%3A5.5.4#optional!builtin::version=5.5.4&hash=379a07" +"typescript@patch:typescript@npm%3A^5.6.2#optional!builtin": + version: 5.6.2 + resolution: "typescript@patch:typescript@npm%3A5.6.2#optional!builtin::version=5.6.2&hash=74658d" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/73409d7b9196a5a1217b3aaad929bf76294d3ce7d6e9766dd880ece296ee91cf7d7db6b16c6c6c630ee5096eccde726c0ef17c7dfa52b01a243e57ae1f09ef07 + checksum: 10c0/e6c1662e4852e22fe4bbdca471dca3e3edc74f6f1df043135c44a18a7902037023ccb0abdfb754595ca9028df8920f2f8492c00fc3cbb4309079aae8b7de71cd languageName: node linkType: hard @@ -7074,9 +7056,9 @@ __metadata: languageName: node linkType: hard -"vite@npm:^5.4.3": - version: 5.4.3 - resolution: "vite@npm:5.4.3" +"vite@npm:^5.4.4": + version: 5.4.4 + resolution: "vite@npm:5.4.4" dependencies: esbuild: "npm:^0.21.3" fsevents: "npm:~2.3.3" @@ -7113,7 +7095,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10c0/7afe601bcba82f81980c718fc171ba8f0c45e3bffaeb7ef831b64b84e396f963c3c87818b74da4c8e817d1bce1c179f1efae3bcb14d2e94b4eb635071722c8f2 + checksum: 10c0/2752e7dd5584ea7cc057742e8f5cbf2f2bd3a2bceb8794fbd3d52f1e88d362b5ac7f1c70be7a3d01b3d768320c8a8ad0df287fd72f253bf040423c36c67a3e89 languageName: node linkType: hard diff --git a/lib/eModbus/src/ModbusClientTCPasync.cpp b/lib/eModbus/src/ModbusClientTCPasync.cpp index 163d552a0..463820fb2 100644 --- a/lib/eModbus/src/ModbusClientTCPasync.cpp +++ b/lib/eModbus/src/ModbusClientTCPasync.cpp @@ -7,210 +7,213 @@ // #undef LOCAL_LOG_LEVEL #include "Logging.h" -ModbusClientTCPasync::ModbusClientTCPasync(IPAddress address, uint16_t port, uint16_t queueLimit) : - ModbusClient(), - txQueue(), - rxQueue(), - MTA_client(), - MTA_timeout(DEFAULTTIMEOUT), - MTA_idleTimeout(DEFAULTIDLETIME), - MTA_qLimit(queueLimit), - MTA_maxInflightRequests(queueLimit), - MTA_lastActivity(0), - MTA_state(DISCONNECTED), - MTA_host(address), - MTA_port(port) - { - // attach all handlers on async tcp events - MTA_client.onConnect([](void* i, AsyncClient* c) { (static_cast(i))->onConnected(); }, this); - MTA_client.onDisconnect([](void* i, AsyncClient* c) { (static_cast(i))->onDisconnected(); }, this); - MTA_client.onError([](void* i, AsyncClient* c, int8_t error) { (static_cast(i))->onACError(c, error); }, this); - // MTA_client.onTimeout([](void* i, AsyncClient* c, uint32_t time) { (static_cast(i))->onTimeout(time); }, this); - // MTA_client.onAck([](void* i, AsyncClient* c, size_t len, uint32_t time) { (static_cast(i))->onAck(len, time); }, this); - MTA_client.onData([](void* i, AsyncClient* c, void* data, size_t len) { (static_cast(i))->onPacket(static_cast(data), len); }, this); - MTA_client.onPoll([](void* i, AsyncClient* c) { (static_cast(i))->onPoll(); }, this); +ModbusClientTCPasync::ModbusClientTCPasync(IPAddress address, uint16_t port, uint16_t queueLimit) + : ModbusClient() + , txQueue() + , rxQueue() + , MTA_client() + , MTA_timeout(DEFAULTTIMEOUT) + , MTA_idleTimeout(DEFAULTIDLETIME) + , MTA_qLimit(queueLimit) + , MTA_maxInflightRequests(queueLimit) + , MTA_lastActivity(0) + , MTA_state(DISCONNECTED) + , MTA_host(address) + , MTA_port(port) { + // attach all handlers on async tcp events + MTA_client.onConnect([](void * i, AsyncClient * c) { (static_cast(i))->onConnected(); }, this); + MTA_client.onDisconnect([](void * i, AsyncClient * c) { (static_cast(i))->onDisconnected(); }, this); + MTA_client.onError([](void * i, AsyncClient * c, int8_t error) { (static_cast(i))->onACError(c, error); }, this); + // MTA_client.onTimeout([](void* i, AsyncClient* c, uint32_t time) { (static_cast(i))->onTimeout(time); }, this); + // MTA_client.onAck([](void* i, AsyncClient* c, size_t len, uint32_t time) { (static_cast(i))->onAck(len, time); }, this); + MTA_client.onData([](void * i, + AsyncClient * c, + void * data, + size_t len) { (static_cast(i))->onPacket(static_cast(data), len); }, + this); + MTA_client.onPoll([](void * i, AsyncClient * c) { (static_cast(i))->onPoll(); }, this); - // disable nagle algorithm ref Modbus spec - MTA_client.setNoDelay(true); - } + // disable nagle algorithm ref Modbus spec + MTA_client.setNoDelay(true); +} // Destructor: clean up queue, task etc. ModbusClientTCPasync::~ModbusClientTCPasync() { - // Clean up queue - { - // Safely lock access - LOCK_GUARD(lock1, qLock); - LOCK_GUARD(lock2, sLock); - // Delete all elements from queues - while (!txQueue.empty()) { - delete txQueue.front(); - txQueue.pop_front(); + // Clean up queue + { + // Safely lock access + LOCK_GUARD(lock1, qLock); + LOCK_GUARD(lock2, sLock); + // Delete all elements from queues + while (!txQueue.empty()) { + delete txQueue.front(); + txQueue.pop_front(); + } + for (auto it = rxQueue.cbegin(); it != rxQueue.cend(); /* no increment */) { + delete it->second; + it = rxQueue.erase(it); + } } - for (auto it = rxQueue.cbegin(); it != rxQueue.cend();/* no increment */) { - delete it->second; - it = rxQueue.erase(it); - } - } - // force close client - MTA_client.close(true); + // force close client + MTA_client.close(true); } // optionally manually connect to modbus server. Otherwise connection will be made upon first request void ModbusClientTCPasync::connect() { - LOG_D("connecting\n"); - LOCK_GUARD(lock1, sLock); - // only connect if disconnected - if (MTA_state == DISCONNECTED) { - MTA_state = CONNECTING; - MTA_client.connect(MTA_host, MTA_port); - } + LOG_D("connecting\n"); + LOCK_GUARD(lock1, sLock); + // only connect if disconnected + if (MTA_state == DISCONNECTED) { + MTA_state = CONNECTING; + MTA_client.connect(MTA_host, MTA_port); + } } // connect to another modbus server. void ModbusClientTCPasync::connect(IPAddress host, uint16_t port) { - // First disconnect, if connected - disconnect(true); - // Set new host and port - MTA_host = host; - MTA_port = port; - connect(); + // First disconnect, if connected + disconnect(true); + // Set new host and port + MTA_host = host; + MTA_port = port; + connect(); } // manually disconnect from modbus server. Connection will also auto close after idle time void ModbusClientTCPasync::disconnect(bool force) { - LOG_D("disconnecting\n"); - MTA_client.close(force); + LOG_D("disconnecting\n"); + MTA_client.close(force); } // Set timeout value void ModbusClientTCPasync::setTimeout(uint32_t timeout) { - MTA_timeout = timeout; + MTA_timeout = timeout; } // Set idle timeout value (time before connection auto closes after being idle) void ModbusClientTCPasync::setIdleTimeout(uint32_t timeout) { - MTA_idleTimeout = timeout; + MTA_idleTimeout = timeout; } void ModbusClientTCPasync::setMaxInflightRequests(uint32_t maxInflightRequests) { - MTA_maxInflightRequests = maxInflightRequests; + MTA_maxInflightRequests = maxInflightRequests; } // Remove all pending request from queue -void ModbusClientTCPasync::clearQueue() -{ - LOCK_GUARD(lock1, qLock); - LOCK_GUARD(lock2, sLock); - // Delete all elements from queues - while (!txQueue.empty()) { - delete txQueue.front(); - txQueue.pop_front(); - } +void ModbusClientTCPasync::clearQueue() { + LOCK_GUARD(lock1, qLock); + LOCK_GUARD(lock2, sLock); + // Delete all elements from queues + while (!txQueue.empty()) { + delete txQueue.front(); + txQueue.pop_front(); + } } // Base addRequest for preformatted ModbusMessage and last set target Error ModbusClientTCPasync::addRequestM(ModbusMessage msg, uint32_t token) { - Error rc = SUCCESS; // Return value + Error rc = SUCCESS; // Return value - // Add it to the queue, if valid - if (msg) { - // Queue add successful? - if (!addToQueue(token, msg)) { - // No. Return error after deleting the allocated request. - rc = REQUEST_QUEUE_FULL; + // Add it to the queue, if valid + if (msg) { + // Queue add successful? + if (!addToQueue(token, msg)) { + // No. Return error after deleting the allocated request. + rc = REQUEST_QUEUE_FULL; + } } - } - LOG_D("Add TCP request result: %02X\n", rc); - return rc; + LOG_D("Add TCP request result: %02X\n", rc); + return rc; } // Base syncRequest follows the same pattern ModbusMessage ModbusClientTCPasync::syncRequestM(ModbusMessage msg, uint32_t token) { - ModbusMessage response; + ModbusMessage response; - if (msg) { - // Queue add successful? - if (!addToQueue(token, msg, true)) { - // No. Return error after deleting the allocated request. - response.setError(msg.getServerID(), msg.getFunctionCode(), REQUEST_QUEUE_FULL); + if (msg) { + // Queue add successful? + if (!addToQueue(token, msg, true)) { + // No. Return error after deleting the allocated request. + response.setError(msg.getServerID(), msg.getFunctionCode(), REQUEST_QUEUE_FULL); + } else { + // Request is queued - wait for the result. + response = waitSync(msg.getServerID(), msg.getFunctionCode(), token); + } } else { - // Request is queued - wait for the result. - response = waitSync(msg.getServerID(), msg.getFunctionCode(), token); + response.setError(msg.getServerID(), msg.getFunctionCode(), EMPTY_MESSAGE); } - } else { - response.setError(msg.getServerID(), msg.getFunctionCode(), EMPTY_MESSAGE); - } - return response; + return response; } // addToQueue: send freshly created request to queue bool ModbusClientTCPasync::addToQueue(int32_t token, ModbusMessage request, bool syncReq) { - // Did we get one? - if (request) { - LOCK_GUARD(lock1, qLock); - if (txQueue.size() + rxQueue.size() < MTA_qLimit) { - HEXDUMP_V("Enqueue", request.data(), request.size()); - RequestEntry *re = new RequestEntry(token, request, syncReq); - if (!re) return false; //TODO: proper error returning in case allocation fails - // inject proper transactionID - re->head.transactionID = messageCount++; - re->head.len = request.size(); - // if we're already connected, try to send and push to rxQueue - // or else push to txQueue and (re)connect - if (MTA_state == CONNECTED && send(re)) { - re->sentTime = millis(); - rxQueue[re->head.transactionID] = re; - } else { - txQueue.push_back(re); - if (MTA_state == DISCONNECTED) { - connect(); + // Did we get one? + if (request) { + LOCK_GUARD(lock1, qLock); + if (txQueue.size() + rxQueue.size() < MTA_qLimit) { + HEXDUMP_V("Enqueue", request.data(), request.size()); + RequestEntry * re = new RequestEntry(token, request, syncReq); + if (!re) + return false; // TODO proper error returning in case allocation fails + // inject proper transactionID + re->head.transactionID = messageCount++; + re->head.len = request.size(); + // if we're already connected, try to send and push to rxQueue + // or else push to txQueue and (re)connect + if (MTA_state == CONNECTED && send(re)) { + re->sentTime = millis(); + rxQueue[re->head.transactionID] = re; + } else { + txQueue.push_back(re); + if (MTA_state == DISCONNECTED) { + connect(); + } + } + return true; } - } - return true; + LOG_E("queue is full\n"); } - LOG_E("queue is full\n"); - } - return false; + return false; } void ModbusClientTCPasync::onConnected() { - LOG_D("connected\n"); - LOCK_GUARD(lock1, sLock); - MTA_state = CONNECTED; - MTA_lastActivity = millis(); - // from now on onPoll will be called every 500 msec + LOG_D("connected\n"); + LOCK_GUARD(lock1, sLock); + MTA_state = CONNECTED; + MTA_lastActivity = millis(); + // from now on onPoll will be called every 500 msec } void ModbusClientTCPasync::onDisconnected() { - LOG_D("disconnected\n"); - LOCK_GUARD(lock1, sLock); - MTA_state = DISCONNECTED; + LOG_D("disconnected\n"); + LOCK_GUARD(lock1, sLock); + MTA_state = DISCONNECTED; - // empty queue on disconnect, calling errorcode on every waiting request - LOCK_GUARD(lock2, qLock); - while (!txQueue.empty()) { - RequestEntry* r = txQueue.front(); - if (onError) { - onError(IP_CONNECTION_FAILED, r->token); + // empty queue on disconnect, calling errorcode on every waiting request + LOCK_GUARD(lock2, qLock); + while (!txQueue.empty()) { + RequestEntry * r = txQueue.front(); + if (onError) { + onError(IP_CONNECTION_FAILED, r->token); + } + delete r; + txQueue.pop_front(); } - delete r; - txQueue.pop_front(); - } - while (!rxQueue.empty()) { - RequestEntry *r = rxQueue.begin()->second; - if (onError) { - onError(IP_CONNECTION_FAILED, r->token); + while (!rxQueue.empty()) { + RequestEntry * r = rxQueue.begin()->second; + if (onError) { + onError(IP_CONNECTION_FAILED, r->token); + } + delete r; + rxQueue.erase(rxQueue.begin()); } - delete r; - rxQueue.erase(rxQueue.begin()); - } } -void ModbusClientTCPasync::onACError(AsyncClient* c, int8_t error) { - // onDisconnect will alse be called, so nothing to do here - LOG_W("TCP error: %s\n", c->errorToString(error)); +void ModbusClientTCPasync::onACError(AsyncClient * c, int8_t error) { + // onDisconnect will alse be called, so nothing to do here + LOG_W("TCP error: %s\n", c->errorToString(error)); } /* @@ -222,180 +225,178 @@ void onAck(size_t len, uint32_t time) { // assuming we don't need this } */ -void ModbusClientTCPasync::onPacket(uint8_t* data, size_t length) { - LOG_D("packet received (len:%d)\n", length); - // reset idle timeout - MTA_lastActivity = millis(); +void ModbusClientTCPasync::onPacket(uint8_t * data, size_t length) { + LOG_D("packet received (len:%d)\n", length); + // reset idle timeout + MTA_lastActivity = millis(); - if (length) { - LOG_D("parsing (len:%d)\n", length + 1); - } - while (length > 0) { - RequestEntry* request = nullptr; - ModbusMessage* response = nullptr; - uint16_t transactionID = 0; - uint16_t protocolID = 0; - uint16_t messageLength = 0; - bool isOkay = false; - - // 1. Check for valid modbus message - - // MBAP header is 6 bytes, we can't do anything with less - // total message should fit MBAP plus remaining bytes (in data[4], data[5]) - if (length > 6) { - transactionID = (data[0] << 8) | data[1]; - protocolID = (data[2] << 8) | data[3]; - messageLength = (data[4] << 8) | data[5]; - if (protocolID == 0 && - length >= (uint32_t)messageLength + 6 && - messageLength < 256) { - response = new ModbusMessage(messageLength); - response->add(&data[6], messageLength); - LOG_D("packet validated (len:%d)\n", messageLength); - - // on next iteration: adjust remaining length and pointer to data - length -= 6 + messageLength; - data += 6 + messageLength; - isOkay = true; - } + if (length) { + LOG_D("parsing (len:%d)\n", length + 1); } + while (length > 0) { + RequestEntry * request = nullptr; + ModbusMessage * response = nullptr; + uint16_t transactionID = 0; + uint16_t protocolID = 0; + uint16_t messageLength = 0; + bool isOkay = false; - if (!isOkay) { - // invalid packet, abort function - LOG_W("packet invalid\n"); - return; - } else { - // 2. we got a valid response, match with a request - LOCK_GUARD(lock1, qLock); - auto i = rxQueue.find(transactionID); - if (i != rxQueue.end()) { - // found it, handle it and stop iterating - request = i->second; - i = rxQueue.erase(i); - LOG_D("matched request\n"); - } else { - // TCP packet did not yield valid modbus response, abort function - LOG_W("no matching request found\n"); - return; - } - } + // 1. Check for valid modbus message - // 3. we have a valid request and a valid response, call appropriate callback - if (request) { - // compare request with response - Error error = SUCCESS; - if (request->msg.getFunctionCode() != (response->getFunctionCode() & 0x7F)) { - error = FC_MISMATCH; - } else if (request->msg.getServerID() != response->getServerID()) { - error = SERVER_ID_MISMATCH; - } else { - error = response->getError(); - } + // MBAP header is 6 bytes, we can't do anything with less + // total message should fit MBAP plus remaining bytes (in data[4], data[5]) + if (length > 6) { + transactionID = (data[0] << 8) | data[1]; + protocolID = (data[2] << 8) | data[3]; + messageLength = (data[4] << 8) | data[5]; + if (protocolID == 0 && length >= (uint32_t)messageLength + 6 && messageLength < 256) { + response = new ModbusMessage(messageLength); + response->add(&data[6], messageLength); + LOG_D("packet validated (len:%d)\n", messageLength); - if (error != SUCCESS) { - LOCK_GUARD(errorCntLock, countAccessM); - errorCount++; - } - - if (request->isSyncRequest) { - { - LOCK_GUARD(sL ,syncRespM); - syncResponse[request->token] = *response; + // on next iteration: adjust remaining length and pointer to data + length -= 6 + messageLength; + data += 6 + messageLength; + isOkay = true; + } } - } else if (onResponse) { - onResponse(*response, request->token); - } else { - if (error == SUCCESS) { - if (onData) { - onData(*response, request->token); - } + + if (!isOkay) { + // invalid packet, abort function + LOG_W("packet invalid\n"); + return; } else { - if (onError) { - onError(response->getError(), request->token); - } + // 2. we got a valid response, match with a request + LOCK_GUARD(lock1, qLock); + auto i = rxQueue.find(transactionID); + if (i != rxQueue.end()) { + // found it, handle it and stop iterating + request = i->second; + i = rxQueue.erase(i); + LOG_D("matched request\n"); + } else { + // TCP packet did not yield valid modbus response, abort function + LOG_W("no matching request found\n"); + return; + } } - } - delete request; - } - delete response; - } // end processing of incoming data + // 3. we have a valid request and a valid response, call appropriate callback + if (request) { + // compare request with response + Error error = SUCCESS; + if (request->msg.getFunctionCode() != (response->getFunctionCode() & 0x7F)) { + error = FC_MISMATCH; + } else if (request->msg.getServerID() != response->getServerID()) { + error = SERVER_ID_MISMATCH; + } else { + error = response->getError(); + } - // check if we have to send the next request - LOCK_GUARD(lock1, qLock); - handleSendingQueue(); + if (error != SUCCESS) { + LOCK_GUARD(errorCntLock, countAccessM); + errorCount++; + } + + if (request->isSyncRequest) { + { + LOCK_GUARD(sL, syncRespM); + syncResponse[request->token] = *response; + } + } else if (onResponse) { + onResponse(*response, request->token); + } else { + if (error == SUCCESS) { + if (onData) { + onData(*response, request->token); + } + } else { + if (onError) { + onError(response->getError(), request->token); + } + } + } + delete request; + } + delete response; + + } // end processing of incoming data + + // check if we have to send the next request + LOCK_GUARD(lock1, qLock); + handleSendingQueue(); } void ModbusClientTCPasync::onPoll() { - { - LOCK_GUARD(lock1, qLock); + { + LOCK_GUARD(lock1, qLock); - // try to send whatever is waiting - handleSendingQueue(); + // try to send whatever is waiting + handleSendingQueue(); - // next check if timeout has struck for oldest request - if (!rxQueue.empty()) { - RequestEntry* request = rxQueue.begin()->second; - if (millis() - request->sentTime > MTA_timeout) { - LOG_D("request timeouts (now:%lu-sent:%u)\n", millis(), request->sentTime); - // oldest element timeouts, call onError and clean up - if (onError) { - // Handle timeout error - onError(TIMEOUT, request->token); - } - delete request; - rxQueue.erase(rxQueue.begin()); + // next check if timeout has struck for oldest request + if (!rxQueue.empty()) { + RequestEntry * request = rxQueue.begin()->second; + if (millis() - request->sentTime > MTA_timeout) { + LOG_D("request timeouts (now:%lu-sent:%u)\n", millis(), request->sentTime); + // oldest element timeouts, call onError and clean up + if (onError) { + // Handle timeout error + onError(TIMEOUT, request->token); + } + delete request; + rxQueue.erase(rxQueue.begin()); + } + } + + } // end lockguard scope + + // if nothing happened during idle timeout, gracefully close connection + if (millis() - MTA_lastActivity > MTA_idleTimeout) { + disconnect(); } - } - - } // end lockguard scope - - // if nothing happened during idle timeout, gracefully close connection - if (millis() - MTA_lastActivity > MTA_idleTimeout) { - disconnect(); - } } void ModbusClientTCPasync::handleSendingQueue() { - // ATTENTION: This method does not have a lock guard. - // Calling sites must assure shared resources are protected - // by mutex. + // ATTENTION: This method does not have a lock guard. + // Calling sites must assure shared resources are protected + // by mutex. - // try to send everything we have waiting - std::list::iterator it = txQueue.begin(); - while (it != txQueue.end()) { - // get the actual element - if (send(*it)) { - // after sending, update timeout value, add to other queue and remove from this queue - (*it)->sentTime = millis(); - rxQueue[(*it)->head.transactionID] = (*it); // push request to other queue - it = txQueue.erase(it); // remove from toSend queue and point i to next request - } else { - // sending didn't succeed, try next request - ++it; + // try to send everything we have waiting + std::list::iterator it = txQueue.begin(); + while (it != txQueue.end()) { + // get the actual element + if (send(*it)) { + // after sending, update timeout value, add to other queue and remove from this queue + (*it)->sentTime = millis(); + rxQueue[(*it)->head.transactionID] = (*it); // push request to other queue + it = txQueue.erase(it); // remove from toSend queue and point i to next request + } else { + // sending didn't succeed, try next request + ++it; + } } - } } -bool ModbusClientTCPasync::send(RequestEntry* re) { - // ATTENTION: This method does not have a lock guard. - // Calling sites must assure shared resources are protected - // by mutex. +bool ModbusClientTCPasync::send(RequestEntry * re) { + // ATTENTION: This method does not have a lock guard. + // Calling sites must assure shared resources are protected + // by mutex. - if (rxQueue.size() >= MTA_maxInflightRequests) { + if (rxQueue.size() >= MTA_maxInflightRequests) { + return false; + } + + // check if TCP client is able to send + if (MTA_client.space() > ((uint32_t)re->msg.size() + 6)) { + // Write TCP header first + MTA_client.add(reinterpret_cast((const uint8_t *)(re->head)), 6, ASYNC_WRITE_FLAG_COPY); + // Request comes next + MTA_client.add(reinterpret_cast(re->msg.data()), re->msg.size(), ASYNC_WRITE_FLAG_COPY); + // done + MTA_client.send(); + LOG_D("request sent (msgid:%d)\n", re->head.transactionID); + return true; + } return false; - } - - // check if TCP client is able to send - if (MTA_client.space() > ((uint32_t)re->msg.size() + 6)) { - // Write TCP header first - MTA_client.add(reinterpret_cast((const uint8_t *)(re->head)), 6, ASYNC_WRITE_FLAG_COPY); - // Request comes next - MTA_client.add(reinterpret_cast(re->msg.data()), re->msg.size(), ASYNC_WRITE_FLAG_COPY); - // done - MTA_client.send(); - LOG_D("request sent (msgid:%d)\n", re->head.transactionID); - return true; - } - return false; } diff --git a/lib/framework/FSPersistence.h b/lib/framework/FSPersistence.h index 712ed1cb2..7478e4886 100644 --- a/lib/framework/FSPersistence.h +++ b/lib/framework/FSPersistence.h @@ -42,7 +42,7 @@ class FSPersistence { // hard-coded emergency defaults are now applied. #ifdef EMSESP_DEBUG Serial.println(); - Serial.printf("Applying defaults to %s ", _filePath); + Serial.printf("Applying defaults to %s", _filePath); Serial.println(); #endif applyDefaults(); diff --git a/lib/framework/NetworkSettingsService.cpp b/lib/framework/NetworkSettingsService.cpp index 9f9ce28d7..48c779217 100644 --- a/lib/framework/NetworkSettingsService.cpp +++ b/lib/framework/NetworkSettingsService.cpp @@ -354,31 +354,39 @@ void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) setWiFiPowerOnRSSI(); } #if ESP_IDF_VERSION_MAJOR < 5 - WiFi.enableIpV6(); + WiFi.enableIpV6(); // force ipv6 #endif break; case ARDUINO_EVENT_ETH_CONNECTED: #if ESP_IDF_VERSION_MAJOR < 5 - ETH.enableIpV6(); + ETH.enableIpV6(); // force ipv6 #endif break; // IPv6 specific case ARDUINO_EVENT_WIFI_STA_GOT_IP6: - case ARDUINO_EVENT_ETH_GOT_IP6: #if !TASMOTA_SDK && ESP_IDF_VERSION_MAJOR < 5 - if (emsesp::EMSESP::system_.ethernet_connected()) { - emsesp::EMSESP::logger().info("Local IPv6=%s", ETH.localIPv6().toString().c_str()); - } else { - emsesp::EMSESP::logger().info("Local IPv6=%s", WiFi.localIPv6().toString().c_str()); - } + emsesp::EMSESP::logger().info("Local IPv6 (WiFi)=%s", WiFi.localIPv6().toString().c_str()); #else emsesp::EMSESP::logger().info("Local IPv6=%s", IPAddress(IPv6, (uint8_t *)info.got_ip6.ip6_info.ip.addr, 0).toString().c_str()); #endif emsesp::EMSESP::system_.has_ipv6(true); break; + // IPv6 specific + // This a bug in arduino where this is triggered twice, so we prevent it + case ARDUINO_EVENT_ETH_GOT_IP6: + if (!emsesp::EMSESP::system_.has_ipv6()) { +#if !TASMOTA_SDK && ESP_IDF_VERSION_MAJOR < 5 + emsesp::EMSESP::logger().info("Local IPv6 (Eth)=%s", ETH.localIPv6().toString().c_str()); +#else + emsesp::EMSESP::logger().info("Local IPv6=%s", IPAddress(IPv6, (uint8_t *)info.got_ip6.ip6_info.ip.addr, 0).toString().c_str()); +#endif + emsesp::EMSESP::system_.has_ipv6(true); + } + break; + default: break; } diff --git a/lib/uuid-console/src/shell.cpp b/lib/uuid-console/src/shell.cpp index 94b27887d..8005913c1 100644 --- a/lib/uuid-console/src/shell.cpp +++ b/lib/uuid-console/src/shell.cpp @@ -85,11 +85,7 @@ void Shell::stop() { blocking_data->stop_ = true; } else { -#if defined(EMSESP_STANDALONE) if (running()) { -#else - if (running() && !has_flags(CommandFlags::LOCAL)) { // do not close local shell -#endif stopped_ = true; stopped(); } diff --git a/media/ha_lovelace.png b/media/ha_lovelace.png index 3c493d3f2..bb0788648 100644 Binary files a/media/ha_lovelace.png and b/media/ha_lovelace.png differ diff --git a/media/web_customizations.png b/media/web_customizations.png index 4602338df..61edfecf4 100644 Binary files a/media/web_customizations.png and b/media/web_customizations.png differ diff --git a/media/web_devices.png b/media/web_devices.png index e54c0fd2b..0708379b6 100644 Binary files a/media/web_devices.png and b/media/web_devices.png differ diff --git a/media/web_edit.png b/media/web_edit.png index 54851b5e2..3df3e5a6f 100644 Binary files a/media/web_edit.png and b/media/web_edit.png differ diff --git a/media/web_log.png b/media/web_log.png index cbf34c331..37c46ca83 100644 Binary files a/media/web_log.png and b/media/web_log.png differ diff --git a/media/web_mqtt.png b/media/web_mqtt.png index 738fb91f9..32b2fe1ce 100644 Binary files a/media/web_mqtt.png and b/media/web_mqtt.png differ diff --git a/media/web_settings.png b/media/web_settings.png index bd57cd1a5..20561b1c4 100644 Binary files a/media/web_settings.png and b/media/web_settings.png differ diff --git a/media/web_status.png b/media/web_status.png index 010054221..410a52e27 100644 Binary files a/media/web_status.png and b/media/web_status.png differ diff --git a/mock-api/mockServer.js b/mock-api/mockServer.js index 0ff53bca4..d1b41d15c 100644 --- a/mock-api/mockServer.js +++ b/mock-api/mockServer.js @@ -1,3 +1,6 @@ +// used to simulate +// - file uploads +// - EventSource (SSE) for log messages import formidable from 'formidable'; function pad(number) { @@ -81,7 +84,7 @@ export default () => { }) ); } else { - res.statusCode = 400; + res.statusCode = 406; console.log('Invalid file extension!'); } } @@ -99,15 +102,21 @@ export default () => { let count = 0; const interval = setInterval(() => { + let message = 'message #' + count; + if (count % 6 === 1) { + message += + ' with a long message that will be wrapped, to see if it stays one a single line'; + } const data = { t: new Date().toISOString(), l: 3 + (count % 6), i: count, n: 'system', - m: 'message #' + count++ + m: message }; + count++; res.write(`data: ${JSON.stringify(data)}\n\n`); - }, 1000); + }, 800); // if client closes connection res.on('close', () => { diff --git a/mock-api/rest_server.ts b/mock-api/rest_server.ts index f184475ff..a11b46a4a 100644 --- a/mock-api/rest_server.ts +++ b/mock-api/rest_server.ts @@ -124,7 +124,8 @@ const LOG_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'logSettings'; let log_settings = { level: 6, max_messages: 50, - compact: true + compact: true, + psram: true }; const FETCH_LOG_ENDPOINT = REST_ENDPOINT_ROOT + 'fetchLog'; diff --git a/platformio.ini b/platformio.ini index 70de8b6ea..44306203e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -33,11 +33,12 @@ build_flags = -D CONFIG_ASYNC_TCP_STACK_SIZE=6144 -D CONFIG_ASYNC_TCP_QUEUE=32 -D CONFIG_ASYNC_TCP_TASK_PRIORITY=10 + -D CORE_DEBUG_LEVEL=0 unbuild_flags = ${common.core_unbuild_flags} -[espressi32_base] +[espressif32_base] platform = espressif32@6.8.1 framework = arduino board_build.filesystem = littlefs @@ -49,7 +50,7 @@ extra_scripts = pre:scripts/build_interface.py scripts/rename_fw.py -[espressi32_base_tasmota] +[espressif32_base_tasmota] ; use Tasmota's library for 4MB variants ; it removes some unused libs (like mbedtsl, so no WiFi_secure.h) and increases available heap ; Tasmota Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8 @@ -81,75 +82,72 @@ lib_deps = ; ; builds for GitHub Actions CI +; We don't set EMSESP_DEFAULT_BOARD_PROFILE and let the code determine the board type. e.g. with board_build.extra_flags = '-DEMSESP_DEFAULT_BOARD_PROFILE="S32"' ; -; the Web interface is built seperately during the GH Action so is skipped (not included in extra_scripts) +; the Web interface is built separately during the GH Action script, so skipped on these targets ; [env:ci_s_4M] -; 4MB ESP32 - using Tasmota - no SSL, no PSRAM - like the BBQKees older S32 models -extends = espressi32_base_tasmota +; 4MB ESP32 - using Tasmota - no SSL, no PSRAM - like the BBQKees older S32 and E32 models +extends = espressif32_base_tasmota extra_scripts = scripts/rename_fw.py board = esp32dev board_upload.flash_size = 4MB board_build.partitions = esp32_partition_4M.csv -board_build.extra_flags = '-DEMSESP_DEFAULT_BOARD_PROFILE="S32"' [env:ci_s_16M] -; 16MB ESP32 - using Tasmota - no SSL, no PSRAM - like the BBQKees older S32 models -extends = espressi32_base_tasmota +; 16MB ESP32 - using Tasmota - no SSL, no PSRAM - like the BBQKees some later S32 models +extends = espressif32_base_tasmota extra_scripts = scripts/rename_fw.py board = esp32dev board_upload.flash_size = 16MB board_build.partitions = esp32_partition_16M.csv -board_build.extra_flags = '-DEMSESP_DEFAULT_BOARD_PROFILE="S32"' [env:ci_s_16M_P] ; 16MB ESP32 - with PSRAM - like BBQKees E32V2 -extends = espressi32_base +extends = espressif32_base extra_scripts = scripts/rename_fw.py board = esp32dev board_upload.flash_size = 16MB board_build.partitions = esp32_partition_16M.csv -board_build.extra_flags = -DBOARD_HAS_PSRAM '-DEMSESP_DEFAULT_BOARD_PROFILE="E32V2"' +board_build.extra_flags = -DBOARD_HAS_PSRAM [env:ci_s3_16M_P] ; 16MB ESP32-S3 - with PSRAM - like BBQKees S3 -extends = espressi32_base +extends = espressif32_base extra_scripts = scripts/rename_fw.py board = lolin_s3 board_build.f_cpu = 240000000L board_upload.flash_size = 16MB board_build.partitions = esp32_partition_16M.csv -board_build.extra_flags = -DBOARD_HAS_PSRAM '-DEMSESP_DEFAULT_BOARD_PROFILE="S32S3"' +board_build.extra_flags = -DBOARD_HAS_PSRAM ; ; Direct builds ; -; For board params see jsonb files in https://github.com/platformio/platform-espressif32/tree/master/boards +; For board params see json files in https://github.com/platformio/platform-espressif32/tree/master/boards ; [env:s_4M] -extends = espressi32_base_tasmota +extends = espressif32_base_tasmota board = esp32dev board_upload.flash_size = 4MB board_build.partitions = esp32_partition_4M.csv -board_build.extra_flags = '-DEMSESP_DEFAULT_BOARD_PROFILE="S32"' [env:s_asym_4M] -extends = espressi32_base_tasmota +extends = espressif32_base_tasmota board = esp32dev board_upload.flash_size = 4MB board_build.partitions = esp32_asym_partition_4M.csv -board_build.extra_flags = '-DEMSESP_DEFAULT_BOARD_PROFILE="S32"' [env:s_16M_P] -extends = espressi32_base +extends = espressif32_base board = esp32dev board_upload.flash_size = 16MB board_build.partitions = esp32_partition_16M.csv -board_build.extra_flags = -DBOARD_HAS_PSRAM '-DEMSESP_DEFAULT_BOARD_PROFILE="S32"' +board_build.extra_flags = -DBOARD_HAS_PSRAM [env:c3_mini_4M] -extends = espressi32_base_tasmota +extends = espressif32_base_tasmota board = lolin_c3_mini board_upload.flash_size = 4MB board_build.partitions = esp32_partition_4M.csv @@ -158,14 +156,14 @@ board_build.extra_flags = '-DEMSESP_DEFAULT_BOARD_PROFILE="C3MINI"' ; lolin C3 mini v1 needs special wifi init. ; https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi [env:c3_miniv1_4M] -extends = espressi32_base_tasmota +extends = espressif32_base_tasmota board = lolin_c3_mini board_upload.flash_size = 4MB board_build.partitions = esp32_partition_4M.csv board_build.extra_flags = -DBOARD_C3_MINI_V1 '-DEMSESP_DEFAULT_BOARD_PROFILE="C3MINI"' [env:s2_4M] -extends = espressi32_base_tasmota +extends = espressif32_base_tasmota board = lolin_s2_mini board_upload.flash_size = 4MB board_build.partitions = esp32_partition_4M.csv @@ -173,28 +171,28 @@ board_build.extra_flags = '-DEMSESP_DEFAULT_BOARD_PROFILE="S2MINI"' ; https://github.com/platformio/platform-espressif32/blob/master/boards/lolin_s3.json [env:s3_16M_P] -extends = espressi32_base +extends = espressif32_base board = lolin_s3 board_upload.use_1200bps_touch = false board_upload.wait_for_upload_port = false board_upload.flash_size = 16MB board_build.partitions = esp32_partition_16M.csv -board_build.extra_flags = -DBOARD_HAS_PSRAM '-DEMSESP_DEFAULT_BOARD_PROFILE="S32S3"' +board_build.extra_flags = -DBOARD_HAS_PSRAM [env:s3_32M_P] -extends = espressi32_base +extends = espressif32_base board = lolin_s3 board_build.arduino.memory_type: opi_opi board_build.flash_mode = opi board_upload.flash_size = 32MB board_build.partitions = esp32_partition_32M.csv -board_build.extra_flags = -DBOARD_HAS_PSRAM '-DEMSESP_DEFAULT_BOARD_PROFILE="S32S3"' +board_build.extra_flags = -DBOARD_HAS_PSRAM ; ; Building and testing natively, standalone without an ESP32. ; See https://docs.platformio.org/en/latest/platforms/native.html ; -; It will generate an executbale which when run will show the EMS-ESP Console where you can run tests using the `test` command. +; It will generate an executable which when run will show the EMS-ESP Console where you can run tests using the `test` command. ; ; See https://docs.platformio.org/en/latest/core/installation/shell-commands.html#piocore-install-shell-commands ; @@ -203,8 +201,8 @@ board_build.extra_flags = -DBOARD_HAS_PSRAM '-DEMSESP_DEFAULT_BOARD_PROFILE="S32 ; to build and run on Windows, it needs winsock for the console input so: ; - For the first time, install Msys2 (https://www.msys2.org/) and the GCC compiler with `run pacman -S mingw-w64-ucrt-x86_64-gcc` ; - Then, build with `pio run -e native` to create the program.exe file -; - run by calling the executable from the Mysys shell e.g. `C:/msys64/msys2_shell.cmd -defterm -here -no-start -ucrt64 -c /d/dev/proddy/EMS-ESP32/.pio/build/native/program.exe` -; - or integrate into Windows Terminal https://www.msys2.org/docs/terminals/ +; - run by calling the executable from the Mysys shell e.g. `C:/msys64/msys2_shell.cmd -defterm -here -no-start -ucrt64 -c /.pio/build/native/program.exe` +; - or use with Windows Terminal https://www.msys2.org/docs/terminals/ ; [env:native] platform = native @@ -243,7 +241,7 @@ lib_ignore = Module EMS-ESP-Modules ; unit tests ; pio run -e native-test -t exec ; works on Linux, Windows, and MacOS -; to auto generate the API exepected test results, compile with -DEMSESP_UNITY_CREATE and capture the output, and paste into the test_api.cpp file +; to update the test results, compile with -DEMSESP_UNITY_CREATE, run and capture the output and then paste this into the test_api.cpp file [env:native-test] platform = native test_build_src = true diff --git a/src/analogsensor.cpp b/src/analogsensor.cpp index 942c6e0e5..9af4e5a51 100644 --- a/src/analogsensor.cpp +++ b/src/analogsensor.cpp @@ -29,6 +29,7 @@ void AnalogSensor::start() { if (!analog_enabled_) { return; } + analogSetAttenuation(ADC_2_5db); // for all channels 1.5V LOG_INFO("Starting Analog Sensor service"); @@ -135,9 +136,9 @@ void AnalogSensor::reload(bool get_nvs) { // first check if the GPIO is valid. If not, force set it to disabled if (!System::is_valid_gpio(sensor.gpio())) { - LOG_WARNING("Bad GPIO %d for Sensor %s", sensor.gpio(), sensor.name().c_str()); + LOG_WARNING("Bad GPIO %d for Sensor %s. Disabling.", sensor.gpio(), sensor.name().c_str()); sensor.set_type(AnalogType::NOTUSED); - continue; + continue; // skip this loop pass } if (sensor.type() == AnalogType::ADC) { @@ -260,6 +261,7 @@ void AnalogSensor::measure() { sensor.sum_ = (sensor.sum_ * 511) / 512 + a; sensor.analog_ = sensor.sum_ / 512; } + // detect change with little hysteresis on raw mV value if (sensor.last_reading_ + 1 < sensor.analog_ || sensor.last_reading_ > sensor.analog_ + 1) { sensor.set_value(((int32_t)sensor.analog_ - sensor.offset()) * sensor.factor()); @@ -300,6 +302,7 @@ void AnalogSensor::measure() { sensor.last_polltime_ = sensor.polltime_; } } + // see if there is a change and increment # reads if (old_value != sensor.value()) { sensorreads_++; @@ -308,6 +311,7 @@ void AnalogSensor::measure() { } } } + // store counter-values only every hour to reduce flash wear static uint8_t lastSaveHour = 0; time_t now = time(nullptr); diff --git a/src/console.cpp b/src/console.cpp index 67b7ade63..cd3dccbbd 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -68,7 +68,7 @@ static std::vector log_level_autocomplete(Shell & shell, const std: } static void setup_commands(std::shared_ptr & commands) { - // log, exit, help + // exit, help, log commands->add_command(ShellContext::MAIN, CommandFlags::USER, {F_(exit)}, EMSESPShell::main_exit_function); commands->add_command(ShellContext::MAIN, CommandFlags::USER, {F_(help)}, EMSESPShell::main_help_function); commands->add_command(ShellContext::MAIN, CommandFlags::USER, {F_(log)}, {F_(log_level_optional)}, console_log_level, log_level_autocomplete); @@ -91,6 +91,10 @@ static void setup_commands(std::shared_ptr & commands) { string_vector{F_(show), F_(devices)}, [](Shell & shell, const std::vector & arguments) { to_app(shell).show_devices(shell); }); + commands->add_command(ShellContext::MAIN, CommandFlags::USER, string_vector{F_(show), F_(log)}, [](Shell & shell, const std::vector & arguments) { + to_app(shell).webLogService.show(shell); + }); + commands->add_command(ShellContext::MAIN, CommandFlags::USER, string_vector{F_(show), F_(ems)}, [](Shell & shell, const std::vector & arguments) { to_app(shell).show_ems(shell); @@ -269,7 +273,7 @@ static void setup_commands(std::shared_ptr & commands) { ShellContext::MAIN, CommandFlags::ADMIN, string_vector{F_(set), F_(board_profile)}, - string_vector{F_(name_mandatory), F_(nvs_optional)}, + string_vector{F_(name_mandatory)}, [](Shell & shell, const std::vector & arguments) { std::vector data; // led, dallas, rx, tx, button, phy_type, eth_power, eth_phy_addr, eth_clock_mode std::string board_profile = Helpers::toUpper(arguments.front()); @@ -277,9 +281,7 @@ static void setup_commands(std::shared_ptr & commands) { shell.println("Invalid board profile (S32, E32, E32V2, MH-ET, NODEMCU, LOLIN, OLIMEX, OLIMEXPOE, C3MINI, S2MINI, S3MINI, S32S3, CUSTOM)"); return; } - if (arguments.size() == 2 && Helpers::toLower(arguments.back()) == "nvs") { - to_app(shell).nvs_.putString("boot", board_profile.c_str()); - } + to_app(shell).webSettingsService.update([&](WebSettings & settings) { settings.board_profile = board_profile.c_str(); settings.led_gpio = data[0]; @@ -686,7 +688,11 @@ void EMSESPShell::end_of_transmission() { void EMSESPShell::main_help_function(Shell & shell, const std::vector & arguments) { shell.println(); +#ifndef EMSESP_DEBUG shell.printfln("%s%sEMS-ESP version %s%s", COLOR_BRIGHT_GREEN, COLOR_BOLD_ON, EMSESP_APP_VERSION, COLOR_RESET); +#else + shell.printfln("%s%sEMS-ESP version %s%s (DEBUG)", COLOR_BRIGHT_GREEN, COLOR_BOLD_ON, EMSESP_APP_VERSION, COLOR_RESET); +#endif shell.println(); shell.print_all_available_commands(); } @@ -695,7 +701,7 @@ void EMSESPShell::main_exit_function(Shell & shell, const std::vector EMSESPConsole::ptys_; diff --git a/src/emsesp.cpp b/src/emsesp.cpp index bcb020c94..bf9438311 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -1341,7 +1341,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const fetch_device_values(device_id); // go and fetch its device entity data // Print to LOG showing we've added a new device - LOG_INFO("Recognized new %s with deviceID 0x%02X", EMSdevice::device_type_2_device_name(device_type), device_id); + LOG_INFO("Detected EMS device: %s (0x%02X)", EMSdevice::device_type_2_device_name(device_type), device_id); // register the MQTT subscribe topic for this device // except for connect, controller and gateway @@ -1541,68 +1541,69 @@ void EMSESP::start() { #ifndef EMSESP_STANDALONE system_.PSram(ESP.getPsramSize()); #endif -// don't need shell if running unit tests -#ifndef EMSESP_UNITY - // Serial console's shell + serial_console_.begin(SERIAL_CONSOLE_BAUD_RATE); - shell_ = std::make_shared(*this, serial_console_, true); - shell_->maximum_log_messages(100); - shell_->start(); -#if defined(EMSESP_DEBUG) - shell_->log_level(uuid::log::Level::DEBUG); -#else - shell_->log_level(uuid::log::Level::TRACE); -#endif -#if defined(EMSESP_STANDALONE) - shell_->add_flags(CommandFlags::ADMIN); // always start in su/admin mode when running tests + + // always start a serial console if we're running standalone, except if we're running unit tests +#if defined(EMSESP_STANDALONE) || defined(EMSESP_DEBUG) +#ifndef EMSESP_UNITY + start_serial_console(); #endif #endif // start the file system #ifndef EMSESP_STANDALONE if (!LittleFS.begin(true)) { - LOG_INFO("LittleFS Mount Failed. Using default settings."); + LOG_ERROR("LittleFS Mount Failed"); return; } #endif -// do a quick scan of the filesystem to see if we have a /config folder -// so we know if this is a new install or not +// do a quick scan of the filesystem to see if we a settings file in the /config folder +// so we know if this is a new factory install or not #ifndef EMSESP_STANDALONE - File root = LittleFS.open(EMSESP_FS_CONFIG_DIRECTORY); + File root = LittleFS.open(EMSESP_SETTINGS_FILE); bool factory_settings = !root; if (!root) { - LOG_INFO("No config found, assuming factory settings"); + LOG_WARNING("No settings found on filesystem. Using factory settings."); } root.close(); #else bool factory_settings = false; #endif - webLogService.begin(); // start web log service. now we can start capturing logs to the web log + // start web log service. now we can start capturing logs to the web log + webLogService.begin(); - esp8266React.begin(); // loads core system services settings (network, mqtt, ap, ntp etc) - - if (!nvs_.begin("ems-esp", false, "nvs1")) { // try bigger nvs partition on 16M flash first - nvs_.begin("ems-esp", false, "nvs"); // fallback to small nvs - } - LOG_DEBUG("NVS device information: %s", system_.getBBQKeesGatewayDetails().c_str()); + // loads core system services settings (network, mqtt, ap, ntp etc) + esp8266React.begin(); #ifndef EMSESP_STANDALONE - LOG_INFO("Booting EMS-ESP version %s from %s partition", EMSESP_APP_VERSION, esp_ota_get_running_partition()->label); // welcome message + LOG_INFO("Booting EMS-ESP version %s from %s/%s partition", + EMSESP_APP_VERSION, + esp_ota_get_boot_partition()->label, + esp_ota_get_running_partition()->label); // welcome message #else LOG_INFO("Booting EMS-ESP version %s", EMSESP_APP_VERSION); // welcome message #endif LOG_DEBUG("System is running in Debug mode"); LOG_INFO("Last system reset reason Core0: %s, Core1: %s", system_.reset_reason(0).c_str(), system_.reset_reason(1).c_str()); - // see if we're restoring a settings file +// see if we're restoring a settings file +#ifndef EMSESP_STANDALONE if (system_.check_restore()) { - LOG_WARNING("System needs a restart to apply new settings. Please wait."); + LOG_WARNING("EMS-ESP will restart to apply new settings. Please wait."); system_.system_restart(); }; +#endif - webSettingsService.begin(); // load EMS-ESP Application settings... + if (!nvs_.begin("ems-esp", false, "nvs1")) { // try bigger nvs partition on 16M flash first + nvs_.begin("ems-esp", false, "nvs"); // fallback to small nvs + } + + LOG_DEBUG("NVS device information: %s", system_.getBBQKeesGatewayDetails().isEmpty() ? "not set" : system_.getBBQKeesGatewayDetails().c_str()); + + webSettingsService.begin(); // load EMS-ESP Application settings // do any system upgrades if (system_.check_upgrade(factory_settings)) { @@ -1653,11 +1654,11 @@ void EMSESP::start() { // main loop calling all services void EMSESP::loop() { - esp8266React.loop(); // web services - system_.loop(); // does LED and checks system health, and syslog service - static bool upload_status = true; // ready for any OTA uploads + esp8266React.loop(); // web services + system_.loop(); // does LED and checks system health, and syslog service // if we're doing an OTA upload, skip everything except from console refresh + static bool upload_status = true; // ready for any OTA uploads if (!system_.upload_isrunning()) { // service loops webLogService.loop(); // log in Web UI @@ -1688,13 +1689,54 @@ void EMSESP::loop() { if (system_.telnet_enabled()) { telnet_.loop(); } -#else - if (!shell_->running()) { - ::exit(0); - } #endif Shell::loop_all(); + + static bool show_prompt = true; + + // user has to ctrl-c to create a serial console stream, exit command will close it + // this is to save around 2kb of heap memory + if (shell_) { + if (!shell_->running()) { + shell_.reset(); +#ifdef EMSESP_STANDALONE + ::exit(0); // kill session +#endif + shell_prompt(); + } + } else { + if (show_prompt) { + shell_prompt(); + show_prompt = false; // only show it once + } + int c = serial_console_.read(); + if (c != -1) { + show_prompt = true; + } + if (c == '\x03' || c == '\x0C') { + start_serial_console(); + } + } +} + +void EMSESP::start_serial_console() { + shell_ = std::make_shared(*this, serial_console_, true); + shell_->maximum_log_messages(100); + shell_->add_flags(CommandFlags::ADMIN); // always start in su/admin mode when running tests + shell_->start(); +#if defined(EMSESP_DEBUG) + shell_->log_level(uuid::log::Level::DEBUG); +#else + shell_->log_level(uuid::log::Level::TRACE); +#endif +} + +void EMSESP::shell_prompt() { +#ifndef EMSESP_STANDALONE + serial_console_.println(); + serial_console_.println("Press CTRL-C to activate this serial console"); +#endif } } // namespace emsesp diff --git a/src/emsesp.h b/src/emsesp.h index 8afc2b4b8..9f1ba1efd 100644 --- a/src/emsesp.h +++ b/src/emsesp.h @@ -252,6 +252,9 @@ class EMSESP { static void publish_response(std::shared_ptr telegram); static void publish_all_loop(); + void shell_prompt(); + void start_serial_console(); + static constexpr uint32_t EMS_FETCH_FREQUENCY = 60000; // check every minute static constexpr uint8_t EMS_WAIT_KM_TIMEOUT = 60; // wait one minute diff --git a/src/locale_common.h b/src/locale_common.h index ea2977bc8..b2de59dd1 100644 --- a/src/locale_common.h +++ b/src/locale_common.h @@ -147,7 +147,6 @@ MAKE_WORD_CUSTOM(sensorid_optional, "[sensor ID]") MAKE_WORD_CUSTOM(id_optional, "[id|hc]") MAKE_WORD_CUSTOM(partitionname_optional, "[partitionname]") MAKE_WORD_CUSTOM(data_optional, "[data]") -MAKE_WORD_CUSTOM(nvs_optional, "[nvs]") MAKE_WORD_CUSTOM(offset_optional, "[offset]") MAKE_WORD_CUSTOM(length_optional, "[length]") MAKE_WORD_CUSTOM(typeid_mandatory, "") diff --git a/src/modbus.cpp b/src/modbus.cpp index e949e8009..22e1ceb2f 100644 --- a/src/modbus.cpp +++ b/src/modbus.cpp @@ -1,6 +1,5 @@ /** - * TODO: - * - verwendete libs in readme hinzufügen + * TODO: verwendete libs in readme hinzufügen */ #include "modbus.h" #include "modbus_entity_parameters.hpp" diff --git a/src/modbus_entity_parameters.hpp b/src/modbus_entity_parameters.hpp index 9a22fd2ea..d9b345a7f 100644 --- a/src/modbus_entity_parameters.hpp +++ b/src/modbus_entity_parameters.hpp @@ -37,8 +37,6 @@ const std::initializer_list Modbus::modbus_register_ma REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pumpMode), 18, 1), // pumpmode REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pumpCharacter), 19, 1), // pumpcharacter REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pumpDelay), 20, 1), // pumpdelay - // REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(setFlowTemp), 21, 1), // setflowtemp - // REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(setBurnPow), 22, 1), // setburnpow REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(selBurnPow), 23, 1), // selburnpow REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curBurnPow), 24, 1), // curburnpow REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnStarts), 25, 2), // burnstarts @@ -183,6 +181,8 @@ const std::initializer_list Modbus::modbus_register_ma REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(keepWarmTemp), 261, 1), // keepwarmtemp REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(setReturnTemp), 262, 1), // setreturntemp REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingOn), 263, 1), // heating + REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgCool), 264, 2), // nrgcool + REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(meterCool), 266, 2), // metercool REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(nrgWw), 0, 2), // nrg REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(meterWw), 2, 2), // meter REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(upTimeCompWw), 4, 2), // uptimecomp @@ -239,7 +239,6 @@ const std::initializer_list Modbus::modbus_register_ma REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwTempOK), 60, 1), // tempok REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwActive), 61, 1), // active REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(ww3wayValve), 62, 1), // 3wayvalve - // REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwSetPumpPower), 63, 1), // setpumppower REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwMixerTemp), 64, 1), // mixertemp REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(cylMiddleTemp), 65, 1), // cylmiddletemp REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(wwStarts), 66, 2), // starts @@ -313,7 +312,7 @@ const std::initializer_list Modbus::modbus_register_ma REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(noreducetemp), 31, 1), // noreducetemp REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(reducetemp), 32, 1), // reducetemp REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(wwprio), 33, 1), // dhwprio - REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpcooling), 34, 1), // cooling + REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpcooling), 34, 1), // hpcooling REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(coolingOn), 35, 1), // coolingon REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(hpmode), 36, 1), // hpmode REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(dewoffset), 37, 1), // dewoffset @@ -344,7 +343,6 @@ const std::initializer_list Modbus::modbus_register_ma REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(daylowtemp), 100, 1), // daytemp2 REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(daymidtemp), 101, 1), // daytemp3 REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(dayhightemp), 102, 1), // daytemp4 - REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(wwswitchtime), 103, 8), // switchtime REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations1), 111, 11), // vacations1 REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations2), 122, 11), // vacations2 REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(vacations3), 133, 11), // vacations3 @@ -357,6 +355,11 @@ const std::initializer_list Modbus::modbus_register_ma REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heattemp), 190, 1), // heattemp REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(roomsensor), 191, 1), // roomsensor REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(heatup), 192, 1), // heatup + REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(coolstart), 193, 1), // coolstart + REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(coolondelay), 194, 1), // coolondelay + REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(cooloffdelay), 195, 1), // cooloffdelay + REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchProgMode), 196, 1), // switchprogmode + REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_HC, FL_(switchtime), 197, 8), // switchtime REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(mode), 0, 1), // mode REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwSetTemp), 1, 1), // settemp REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwSetTempLow), 2, 1), // settemplow @@ -374,7 +377,7 @@ const std::initializer_list Modbus::modbus_register_ma REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwDisinfectHour), 14, 1), // disinfecthour REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwMaxTemp), 15, 1), // maxtemp REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwOneTimeKey), 16, 1), // onetimekey - REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwswitchtime), 17, 8), // switchtime + REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwswitchtime), 17, 8), // switchtimeWW REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(wwcircswitchtime), 25, 8), // circswitchtime REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(holidays), 33, 13), // holidays REGISTER_MAPPING(dt::THERMOSTAT, TAG_TYPE_DHW, FL_(vacations), 46, 13), // vacations @@ -433,7 +436,7 @@ const std::initializer_list Modbus::modbus_register_ma REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(heatMetering), 42, 1), // heatmetering REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(activated), 43, 1), // activated REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPumpMode), 44, 1), // solarpumpmode - REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPumpKick), 45, 1), // pumpkick + REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(solarPumpKick), 45, 1), // solarpumpkick REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(plainWaterMode), 46, 1), // plainwatermode REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(doubleMatchFlow), 47, 1), // doublematchflow REGISTER_MAPPING(dt::SOLAR, TAG_TYPE_DEVICE_DATA, FL_(pump2MinMod), 48, 1), // pump2minmod diff --git a/src/shower.cpp b/src/shower.cpp index 194e45d08..cc8210740 100644 --- a/src/shower.cpp +++ b/src/shower.cpp @@ -106,18 +106,19 @@ void Shower::loop() { // duration in seconds doc["duration"] = duration_; // seconds - time_t now = time(nullptr); - // if NTP enabled, publish timestamp - if (now > 1576800000) { // year 2020 - // doc["timestamp_s"] = now; // if needed, in seconds - tm * tm_ = localtime(&now); - char dt[25]; - strftime(dt, sizeof(dt), "%FT%T%z", tm_); - doc["timestamp"] = dt; - LOG_INFO("shower finished %s (duration %lu s)", dt, duration_); - } else { - LOG_INFO("shower finished (duration %lu s)", duration_); - } + // time_t now = time(nullptr); + // // if NTP enabled, publish timestamp + // if (now > 1576800000) { // year 2020 + // // doc["timestamp_s"] = now; // if needed, in seconds + // tm * tm_ = localtime(&now); + // char dt[25]; + // strftime(dt, sizeof(dt), "%FT%T%z", tm_); + // doc["timestamp"] = dt; + // LOG_INFO("Shower finished %s (duration %lus)", dt, duration_); + // } else { + // LOG_INFO("Shower finished (duration %lus)", duration_); + // } + LOG_INFO("Shower finished (duration %lus)", duration_); Mqtt::queue_publish("shower_data", doc.as()); } } @@ -210,7 +211,7 @@ void Shower::set_shower_state(bool state, bool force) { ha_configdone_ = Mqtt::queue_ha(topic, doc.as()); // publish the config payload with retain flag // - // shower duaration + // shower duration // doc.clear(); diff --git a/src/system.cpp b/src/system.cpp index 500199724..ed1bb39e4 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -466,8 +466,8 @@ bool System::is_valid_gpio(uint8_t pin, bool has_psram) { return false; // bad pin } - // extra check for pins 21 and 22 (I2C) when ethernet is enabled - if ((EMSESP::system_.ethernet_connected()) && (pin >= 21 && pin <= 22)) { + // extra check for pins 21 and 22 (I2C) when ethernet is onboard + if ((EMSESP::system_.ethernet_connected() || EMSESP::system_.phy_type_ != PHY_type::PHY_TYPE_NONE) && (pin >= 21 && pin <= 22)) { return false; // bad pin } return true; @@ -540,6 +540,7 @@ void System::button_init(bool refresh) { reload_settings(); } +#ifndef EMSESP_STANDALONE if (!is_valid_gpio(pbutton_gpio_)) { LOG_WARNING("Invalid button GPIO. Check config."); myPButton_.init(255, HIGH); // disable @@ -555,6 +556,7 @@ void System::button_init(bool refresh) { myPButton_.onDblClick(BUTTON_DblClickDelay, button_OnDblClick); myPButton_.onLongPress(BUTTON_LongPressDelay, button_OnLongPress); myPButton_.onVLongPress(BUTTON_VLongPressDelay, button_OnVLongPress); +#endif } // set the LED to on or off when in normal operating mode @@ -997,7 +999,7 @@ void System::show_system(uuid::console::Shell & shell) { #ifndef EMSESP_STANDALONE shell.printfln(" Platform: %s (%s)", EMSESP_PLATFORM, ESP.getChipModel()); shell.printfln(" Model: %s", getBBQKeesGatewayDetails().c_str()); - shell.printfln(" Partition Boot/Running: %s/%s", esp_ota_get_boot_partition()->label, esp_ota_get_running_partition()->label); + shell.printfln(" Partition boot/running: %s/%s", esp_ota_get_boot_partition()->label, esp_ota_get_running_partition()->label); #endif shell.printfln(" Language: %s", locale().c_str()); shell.printfln(" Board profile: %s", board_profile().c_str()); @@ -1022,11 +1024,6 @@ void System::show_system(uuid::console::Shell & shell) { shell.println(); shell.println("Network:"); - // show ethernet mac address if we have an eth controller present - if (eth_present_) { - shell.printfln(" Ethernet MAC address: %s", ETH.macAddress().c_str()); - } - switch (WiFi.status()) { case WL_IDLE_STATUS: shell.printfln(" Status: Idle"); @@ -1086,7 +1083,7 @@ void System::show_system(uuid::console::Shell & shell) { // show Ethernet if connected if (ethernet_connected_) { shell.println(); - shell.printfln(" Status: Ethernet connected"); + shell.printfln(" Ethernet Status: connected"); shell.printfln(" Ethernet MAC address: %s", ETH.macAddress().c_str()); shell.printfln(" Hostname: %s", ETH.getHostname()); shell.printfln(" IPv4 address: %s/%s", uuid::printable_to_string(ETH.localIP()).c_str(), uuid::printable_to_string(ETH.subnetMask()).c_str()); @@ -1196,7 +1193,7 @@ bool System::check_upgrade(bool factory_settings) { version::Semver200_version settings_version(settingsVersion); if (!missing_version) { - LOG_DEBUG("Checking version upgrade (settings file is v%d.%d.%d-%s)", + LOG_DEBUG("Checking for version upgrades (settings file has v%d.%d.%d-%s)", settings_version.major(), settings_version.minor(), settings_version.patch(), @@ -1213,46 +1210,69 @@ bool System::check_upgrade(bool factory_settings) { // compare versions if (this_version > settings_version) { - // need upgrade - LOG_NOTICE("Upgrading to version %d.%d.%d-%s", this_version.major(), this_version.minor(), this_version.patch(), this_version.prerelease().c_str()); + // we need to do an upgrade + if (missing_version) { + LOG_NOTICE("Upgrading to version %d.%d.%d-%s", this_version.major(), this_version.minor(), this_version.patch(), this_version.prerelease().c_str()); + } else { + LOG_NOTICE("Upgrading from version %d.%d.%d-%s to %d.%d.%d-%s", + settings_version.major(), + settings_version.minor(), + settings_version.patch(), + settings_version.prerelease().c_str(), + this_version.major(), + this_version.minor(), + this_version.patch(), + this_version.prerelease().c_str()); + } // if we're coming from 3.4.4 or 3.5.0b14 which had no version stored then we need to apply new settings if (missing_version) { - LOG_INFO("Upgrade: Setting MQTT Entity ID format to older v3.4 format"); + LOG_INFO("Upgrade: Setting MQTT Entity ID format to older v3.4 format (0)"); EMSESP::esp8266React.getMqttSettingsService()->update([&](MqttSettings & mqttSettings) { mqttSettings.entity_format = Mqtt::entityFormat::SINGLE_LONG; // use old Entity ID format from v3.4 return StateUpdateResult::CHANGED; }); } else if (settings_version.major() == 3 && settings_version.minor() <= 6) { - LOG_INFO("Upgrade: Setting MQTT Entity ID format to v3.6 format"); EMSESP::esp8266React.getMqttSettingsService()->update([&](MqttSettings & mqttSettings) { if (mqttSettings.entity_format == 1) { mqttSettings.entity_format = Mqtt::entityFormat::SINGLE_OLD; // use old Entity ID format from v3.6 + LOG_INFO("Upgrade: Setting MQTT Entity ID format to v3.6 format (3)"); return StateUpdateResult::CHANGED; } else if (mqttSettings.entity_format == 2) { mqttSettings.entity_format = Mqtt::entityFormat::MULTI_OLD; // use old Entity ID format from v3.6 + LOG_INFO("Upgrade: Setting MQTT Entity ID format to v3.6 format (4)"); return StateUpdateResult::CHANGED; } return StateUpdateResult::UNCHANGED; }); } - // force WiFi sleep to off (was default on < 3.7.0-dev-33) - EMSESP::esp8266React.getNetworkSettingsService()->update([&](NetworkSettings & networkSettings) { - networkSettings.nosleep = true; - return StateUpdateResult::CHANGED; - }); - - // Network Settings Wifi tx_power is now using the value * 4. + // changes to Network EMSESP::esp8266React.getNetworkSettingsService()->update([&](NetworkSettings & networkSettings) { + // Network Settings Wifi tx_power is now using the value * 4. if (networkSettings.tx_power == 20) { networkSettings.tx_power = WIFI_POWER_19_5dBm; // use 19.5 as we don't have 20 anymore LOG_INFO("Upgrade: Setting WiFi TX Power to Auto"); + } + + // force WiFi sleep to off (was default on < 3.7.0-dev-33) + networkSettings.nosleep = true; + LOG_INFO("Upgrade: Disabling WiFi nosleep"); + + return StateUpdateResult::CHANGED; + }); + + // changes to application settings + EMSESP::webSettingsService.update([&](WebSettings & settings) { + // force web buffer to 25 for those boards without psram + if (EMSESP::system_.PSram() == 0) { + settings.weblog_buffer = 25; return StateUpdateResult::CHANGED; } return StateUpdateResult::UNCHANGED; }); + } else if (this_version < settings_version) { // need downgrade LOG_NOTICE("Downgrading to version %d.%d.%d-%s", this_version.major(), this_version.minor(), this_version.patch(), this_version.prerelease().c_str()); @@ -1267,7 +1287,7 @@ bool System::check_upgrade(bool factory_settings) { settings.version = EMSESP_APP_VERSION; return StateUpdateResult::CHANGED; }); - LOG_INFO("Upgrade: Setting version to %s", EMSESP_APP_VERSION); + // LOG_INFO("Upgrade: Setting version to %s", EMSESP_APP_VERSION); return true; // need reboot } @@ -1300,7 +1320,7 @@ bool System::saveSettings(const char * filename, const char * section, JsonObjec if (section_json) { File section_file = LittleFS.open(filename, "w"); if (section_file) { - LOG_INFO("Applying new %s", section); + LOG_INFO("Applying new uploaded %s data", section); serializeJson(section_json, section_file); section_file.close(); return true; // reboot required @@ -1438,7 +1458,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output #endif node["resetReason"] = EMSESP::system_.reset_reason(0) + " / " + EMSESP::system_.reset_reason(1); #ifndef EMSESP_STANDALONE - node["psram"] = (EMSESP::system_.PSram() > 0); // boolean + node["psram"] = (EMSESP::system_.PSram() > 0); // make boolean if (EMSESP::system_.PSram()) { node["psramSize"] = EMSESP::system_.PSram(); node["freePsram"] = ESP.getFreePsram() / 1024; @@ -1756,10 +1776,11 @@ bool System::load_board_profile(std::vector & data, const std::string & (int8_t)EMSESP::system_.eth_phy_addr_, (int8_t)EMSESP::system_.eth_clock_mode_}; } else { - // unknown, return false - return false; + LOG_DEBUG("Couldn't identify board profile %s", board_profile.c_str()); + return false; // unknown, return false } + // LOG_DEBUG("Found data for board profile %s", board_profile.c_str()); return true; } diff --git a/src/system.h b/src/system.h index 8c42a8a1a..23b223acf 100644 --- a/src/system.h +++ b/src/system.h @@ -217,6 +217,10 @@ class System { has_ipv6_ = b; } + bool has_ipv6() { + return has_ipv6_; + } + void ntp_connected(bool b); bool ntp_connected(); diff --git a/src/version.h b/src/version.h index e21a13fc9..7bdf3ef51 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.7.0-dev.34" +#define EMSESP_APP_VERSION "3.7.0-dev.35" diff --git a/src/web/WebLogService.cpp b/src/web/WebLogService.cpp index e563400f8..89dd66ec8 100644 --- a/src/web/WebLogService.cpp +++ b/src/web/WebLogService.cpp @@ -18,6 +18,8 @@ #include "emsesp.h" +using ::uuid::console::Shell; + namespace emsesp { WebLogService::WebLogService(AsyncWebServer * server, SecurityManager * securityManager) @@ -75,12 +77,15 @@ size_t WebLogService::maximum_log_messages() const { void WebLogService::maximum_log_messages(size_t count) { maximum_log_messages_ = std::max((size_t)1, count); + if (limit_log_messages_ > maximum_log_messages_) { limit_log_messages_ = maximum_log_messages_; } + while (log_messages_.size() > maximum_log_messages_) { log_messages_.pop_front(); } + EMSESP::webSettingsService.update([&](WebSettings & settings) { settings.weblog_buffer = count; return StateUpdateResult::CHANGED; @@ -132,6 +137,42 @@ void WebLogService::operator<<(std::shared_ptr message) { }); } +// dumps out the contents of log buffer to shell console +void WebLogService::show(Shell & shell) { + if (log_messages_.empty()) { + return; + } + + shell.println(); + shell.printfln("Last Log (filtered by WebLog's level %s & buffer %d):", format_level_uppercase(log_level()), maximum_log_messages()); + shell.println(); + + for (const auto & message : log_messages_) { + log_message_id_tail_ = message.id_; + + shell.print(uuid::log::format_timestamp_ms(message.content_->uptime_ms, 3)); + shell.printf(" %c %lu: [%s] ", uuid::log::format_level_char(message.content_->level), message.id_, message.content_->name); + + if ((message.content_->level == uuid::log::Level::ERR) || (message.content_->level == uuid::log::Level::WARNING)) { + shell.print(COLOR_RED); + shell.println(message.content_->text); + shell.print(COLOR_RESET); + } else if (message.content_->level == uuid::log::Level::INFO) { + shell.print(COLOR_YELLOW); + shell.println(message.content_->text); + shell.print(COLOR_RESET); + } else if (message.content_->level == uuid::log::Level::DEBUG) { + shell.print(COLOR_CYAN); + shell.println(message.content_->text); + shell.print(COLOR_RESET); + } else { + shell.println(message.content_->text); + } + } + + shell.println(); +} + void WebLogService::loop() { if (!events_.count() || log_messages_.empty()) { return; @@ -200,7 +241,7 @@ void WebLogService::fetchLog(AsyncWebServerRequest * request) { request->send(200); } -// sets the values like level after a POST +// sets the values after a POST void WebLogService::getSetValues(AsyncWebServerRequest * request, JsonVariant json) { if ((request->method() == HTTP_GET) || (!json.is())) { // GET - return the values @@ -209,12 +250,13 @@ void WebLogService::getSetValues(AsyncWebServerRequest * request, JsonVariant js root["level"] = log_level(); root["max_messages"] = maximum_log_messages(); root["compact"] = compact(); + root["psram"] = (EMSESP::system_.PSram() > 0); + response->setLength(); request->send(response); return; } - // POST - write the settings auto && body = json.as(); uuid::log::Level level = body["level"]; diff --git a/src/web/WebLogService.h b/src/web/WebLogService.h index 900c1ef59..222b159d0 100644 --- a/src/web/WebLogService.h +++ b/src/web/WebLogService.h @@ -23,6 +23,8 @@ #define EMSESP_FETCH_LOG_PATH "/rest/fetchLog" #define EMSESP_LOG_SETTINGS_PATH "/rest/logSettings" +using ::uuid::console::Shell; + namespace emsesp { class WebLogService : public uuid::log::Handler { @@ -42,6 +44,7 @@ class WebLogService : public uuid::log::Handler { bool compact() const; void compact(bool compact); void loop(); + void show(Shell & shell); virtual void operator<<(std::shared_ptr message); diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index e41f0f36e..16983ab47 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -28,15 +28,16 @@ WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, Securit server->on(EMSESP_BOARD_PROFILE_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest([this](AsyncWebServerRequest * request) { board_profile(request); }, AuthenticationPredicates::IS_AUTHENTICATED)); - addUpdateHandler([this] { onUpdate(); }, false); - server->on(EMSESP_GET_SETTINGS_PATH, HTTP_GET, securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getSettings(request); }, AuthenticationPredicates::IS_ADMIN)); + 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; @@ -67,7 +68,6 @@ void WebSettings::read(WebSettings & settings, JsonObject root) { root["analog_enabled"] = settings.analog_enabled; root["pbutton_gpio"] = settings.pbutton_gpio; root["solar_maxflow"] = settings.solar_maxflow; - root["board_profile"] = settings.board_profile; root["fahrenheit"] = settings.fahrenheit; root["bool_format"] = settings.bool_format; root["bool_dashboard"] = settings.bool_dashboard; @@ -79,7 +79,6 @@ void WebSettings::read(WebSettings & settings, JsonObject root) { root["eth_power"] = settings.eth_power; root["eth_phy_addr"] = settings.eth_phy_addr; root["eth_clock_mode"] = settings.eth_clock_mode; - root["platform"] = EMSESP_PLATFORM; root["modbus_enabled"] = settings.modbus_enabled; root["modbus_port"] = settings.modbus_port; root["modbus_max_clients"] = settings.modbus_max_clients; @@ -88,90 +87,116 @@ void WebSettings::read(WebSettings & settings, JsonObject root) { // call on initialization and also when settings are updated via web or console StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { - // load the version of the settings - // will be picked up in System::check_upgrade() + // load the version from the settings config. This can be blank and later used in System::check_upgrade() settings.version = root["version"] | EMSESP_DEFAULT_VERSION; - // load default GPIO configuration based on board profile - std::vector data; // // led, dallas, rx, tx, button, phy_type, eth_power, eth_phy_addr, eth_clock_mode - settings.board_profile = root["board_profile"] | EMSESP_DEFAULT_BOARD_PROFILE; - // for -D compile setting store it in NVS - if ((String)EMSESP_DEFAULT_BOARD_PROFILE != "default" && EMSESP::nvs_.getString("boot") == "") { - EMSESP::nvs_.putString("boot", (const char *)EMSESP_DEFAULT_BOARD_PROFILE); - } - #ifndef EMSESP_STANDALONE bool psram = ESP.getPsramSize() > 0; // System::PSram() is initialized later #else bool psram = false; #endif - if (System::load_board_profile(data, settings.board_profile.c_str())) { - if (settings.board_profile == "CUSTOM") { //read pins, fallback to S32 - data = {(int8_t)(root["led_gpio"] | 2), - (int8_t)(root["dallas_gpio"] | 18), - (int8_t)(root["rx_gpio"] | 23), - (int8_t)(root["tx_gpio"] | 5), - (int8_t)(root["pbutton_gpio"] | 0), - (int8_t)(root["phy_type"] | PHY_type::PHY_TYPE_NONE), - (int8_t)(root["eth_power"] | 0), - (int8_t)(root["eth_phy_addr"] | 0), - (int8_t)(root["eth_clock_mode"] | 0)}; +#ifdef EMSESP_DEBUG + EMSESP::logger().debug("NVS boot value=[%s], board profile=[%s], EMSESP_DEFAULT_BOARD_PROFILE=[%s]", + EMSESP::nvs_.getString("boot").c_str(), + root["board_profile"] | "", + EMSESP_DEFAULT_BOARD_PROFILE); +#endif + + // get the current board profile saved in the settings file + settings.board_profile = root["board_profile"] | EMSESP_DEFAULT_BOARD_PROFILE; // this is set at compile time in platformio.ini, other it's "default" + String old_board_profile = settings.board_profile; + + // The optional NVS boot value has priority and overrides any board_profile setting. + // We only do this 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().isEmpty()) { + String nvs_boot = EMSESP::nvs_.getString("boot"); + if (!nvs_boot.isEmpty()) { +#ifdef EMSESP_DEBUG + EMSESP::logger().debug("Overriding board profile with NVS boot value %s"); +#endif + settings.board_profile = nvs_boot; } - // check valid pins in this board profile - if (!System::is_valid_gpio(data[0], psram) || !System::is_valid_gpio(data[1], psram) || !System::is_valid_gpio(data[2], psram) - || !System::is_valid_gpio(data[3], psram) || !System::is_valid_gpio(data[4], psram) || !System::is_valid_gpio(data[6], psram)) { - settings.board_profile = ""; // reset to factory default - } - } else { - settings.board_profile = ""; // reset to factory default } - if (settings.board_profile == "") { - // unknown, check for NVS or scan for ethernet, use default E32/E32V2/S32 - settings.board_profile = EMSESP::nvs_.getString("boot"); - if (!System::load_board_profile(data, settings.board_profile.c_str())) { -#if defined(EMSESP_STANDALONE) - settings.board_profile = "S32"; -#elif CONFIG_IDF_TARGET_ESP32 - if (settings.board_profile == "" && !psram) { // empty: new test for E32 -#if ESP_ARDUINO_VERSION_MAJOR < 3 - if (ETH.begin(1, 16, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_IN)) { -#else - if (ETH.begin(ETH_PHY_LAN8720, 1, 23, 18, 16, ETH_CLOCK_GPIO0_IN)) { -#endif - EMSESP::nvs_.putString("boot", "E32"); - } else { - EMSESP::nvs_.putString("boot", "Test"); - } - } else if (settings.board_profile == "Test" || psram) { // test E32V2 -#if ESP_ARDUINO_VERSION_MAJOR < 3 - if (ETH.begin(0, 15, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_OUT)) { -#else - if (ETH.begin(ETH_PHY_LAN8720, 0, 23, 18, 15, ETH_CLOCK_GPIO0_OUT)) { -#endif - EMSESP::nvs_.putString("boot", "E32V2"); - } else { - EMSESP::nvs_.putString("boot", "S32"); - } - } else { - EMSESP::nvs_.putString("boot", "S32"); + + // load the board profile from the settings, if it's not "default" + std::vector data; // // led, dallas, rx, tx, button, phy_type, eth_power, eth_phy_addr, eth_clock_mode + if (settings.board_profile != "default") { + if (System::load_board_profile(data, settings.board_profile.c_str())) { + if (settings.board_profile == "CUSTOM") { // read pins, fallback to S32 values + data = {(int8_t)(root["led_gpio"] | 2), + (int8_t)(root["dallas_gpio"] | 18), + (int8_t)(root["rx_gpio"] | 23), + (int8_t)(root["tx_gpio"] | 5), + (int8_t)(root["pbutton_gpio"] | 0), + (int8_t)(root["phy_type"] | PHY_type::PHY_TYPE_NONE), + (int8_t)(root["eth_power"] | 0), + (int8_t)(root["eth_phy_addr"] | 0), + (int8_t)(root["eth_clock_mode"] | 0)}; } - // ESP.restart(); - EMSESP::system_.restart_requested(true); -#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 -#else - settings.board_profile = "S32"; -#endif - System::load_board_profile(data, settings.board_profile.c_str()); + // check valid pins in this board profile + if (!System::is_valid_gpio(data[0], psram) || !System::is_valid_gpio(data[1], psram) || !System::is_valid_gpio(data[2], psram) + || !System::is_valid_gpio(data[3], psram) || !System::is_valid_gpio(data[4], psram) || !System::is_valid_gpio(data[6], psram)) { + settings.board_profile = "default"; // reset to factory default + } + } else { + settings.board_profile = "default"; // can't find profile, use "default" } - EMSESP::logger().info("No board profile found. Re-setting to %s", settings.board_profile.c_str()); + } + + // still don't have a valid board profile. Let's see if we can determine one + if (settings.board_profile == "default") { +#ifdef EMSESP_DEBUG + EMSESP::logger().debug("Trying to detect board and set board profile..."); +#endif + +#if defined(EMSESP_STANDALONE) + settings.board_profile = "S32"; +#elif CONFIG_IDF_TARGET_ESP32 + // check for no PSRAM, could be a E32 or S32 + if (!psram) { +#if ESP_ARDUINO_VERSION_MAJOR < 3 + if (ETH.begin(1, 16, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_IN)) { +#else + if (ETH.begin(ETH_PHY_LAN8720, 1, 23, 18, 16, ETH_CLOCK_GPIO0_IN)) { +#endif + 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 ESP_ARDUINO_VERSION_MAJOR < 3 + if (ETH.begin(0, 15, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_OUT)) { +#else + if (ETH.begin(ETH_PHY_LAN8720, 0, 23, 18, 15, ETH_CLOCK_GPIO0_OUT)) { +#endif + 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 +#endif + + // apply the new board profile setting + System::load_board_profile(data, settings.board_profile.c_str()); + } + + if (old_board_profile != settings.board_profile) { + // see if need to override the set board profile (e.g. forced by NVS boot string) + EMSESP::logger().info("Setting new Board profile %s (was %s)", settings.board_profile.c_str(), old_board_profile.c_str()); } else { - EMSESP::logger().info("Loading board profile %s", settings.board_profile.c_str()); + EMSESP::logger().info("Board profile set to %s", settings.board_profile.c_str()); } int prev; @@ -233,7 +258,7 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { } #endif - // temperaturesensor + // temperature sensor prev = settings.dallas_parasite; settings.dallas_parasite = root["dallas_parasite"] | EMSESP_DEFAULT_DALLAS_PARASITE; check_flag(prev, settings.dallas_parasite, ChangeFlags::SENSOR); @@ -343,13 +368,20 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { EMSESP::system_.bool_dashboard(settings.bool_dashboard); settings.weblog_level = root["weblog_level"] | EMSESP_DEFAULT_WEBLOG_LEVEL; - settings.weblog_buffer = root["weblog_buffer"] | EMSESP_DEFAULT_WEBLOG_BUFFER; settings.weblog_compact = root["weblog_compact"] | EMSESP_DEFAULT_WEBLOG_COMPACT; + // 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; + } + // save the settings - if (flags_ == WebSettings::ChangeFlags::RESTART) { + if (get_flags() == WebSettings::ChangeFlags::RESTART) { return StateUpdateResult::CHANGED_RESTART; // tell WebUI that a restart is needed } + return StateUpdateResult::CHANGED; } @@ -377,11 +409,11 @@ void WebSettingsService::onUpdate() { } if (WebSettings::has_flags(WebSettings::ChangeFlags::BUTTON)) { - EMSESP::system_.button_init(true); // reload settings + EMSESP::system_.button_init(true); } if (WebSettings::has_flags(WebSettings::ChangeFlags::LED)) { - EMSESP::system_.led_init(true); // reload settings + EMSESP::system_.led_init(true); } if (WebSettings::has_flags(WebSettings::ChangeFlags::MQTT)) { @@ -393,6 +425,7 @@ void WebSettingsService::onUpdate() { void WebSettingsService::begin() { _fsPersistence.readFromFS(); + WebSettings::reset_flags(); } diff --git a/test/test_api/test_api.h b/test/test_api/test_api.h index 21ec835b3..4cfd9e8b1 100644 --- a/test/test_api/test_api.h +++ b/test/test_api/test_api.h @@ -3,7 +3,7 @@ // Compile with -DEMSESP_UNITY_CREATE to generate the test functions // and copy the output and paste below. // -// TODO: convert output to JSON and compare, showing differences +// TODO convert output to JSON and compare, showing differences // // You can also manually compare the differences using https://www.diffchecker.com/text-compare/ //