Merge remote-tracking branch 'emsesp/dev' into dev

This commit is contained in:
MichaelDvP
2026-10-08 07:56:11 +02:00
131 changed files with 2958 additions and 2611 deletions
+4 -3
View File
@@ -14,21 +14,22 @@ permissions:
jobs: jobs:
pre-release: pre-release:
name: 'Build Dev Release' name: 'Build Dev Release'
if: github.event_name == 'workflow_dispatch' || github.repository == 'emsesp/EMS-ESP32'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Install python 3.13 - name: Install python 3.13
uses: actions/setup-python@v6 uses: actions/setup-python@v7
with: with:
python-version: '3.13' python-version: '3.13'
- name: Install Node.js 26 - name: Install Node.js 26
uses: actions/setup-node@v6 uses: actions/setup-node@v7
with: with:
node-version: 26 node-version: 26
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
@@ -11,10 +11,10 @@ jobs:
contents: read contents: read
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: GitHub Releases To Discord - name: GitHub Releases To Discord
uses: SethCohen/github-releases-to-discord@v1.13.1 uses: SethCohen/github-releases-to-discord@v1.20.0
with: with:
webhook_url: ${{ secrets.WEBHOOK_URL }} webhook_url: ${{ secrets.WEBHOOK_URL }}
color: '2105893' color: '2105893'
+2 -2
View File
@@ -15,10 +15,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Install python 3.13 - name: Install python 3.13
uses: actions/setup-python@v6 uses: actions/setup-python@v7
with: with:
python-version: '3.13' python-version: '3.13'
+3 -3
View File
@@ -19,15 +19,15 @@ jobs:
BUILD_WRAPPER_OUT_DIR: bw-output BUILD_WRAPPER_OUT_DIR: bw-output
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Install Build Wrapper - name: Install Build Wrapper
uses: SonarSource/sonarqube-scan-action/install-build-wrapper@master uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v8.2.2
- name: Run Build Wrapper - name: Run Build Wrapper
run: build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} make all run: build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} make all
- name: SonarQube Scan - name: SonarQube Scan
uses: SonarSource/sonarqube-scan-action@master uses: SonarSource/sonarqube-scan-action@v8.2.2
env: env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+3 -3
View File
@@ -16,17 +16,17 @@ jobs:
steps: steps:
- name: Install python 3.13 - name: Install python 3.13
uses: actions/setup-python@v6 uses: actions/setup-python@v7
with: with:
python-version: '3.13' python-version: '3.13'
- name: Install Node.js 26 - name: Install Node.js 26
uses: actions/setup-node@v6 uses: actions/setup-node@v7
with: with:
node-version: 26 node-version: 26
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Install pnpm - name: Install pnpm
run: npm install -g pnpm run: npm install -g pnpm
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
stale: stale:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/stale@v10 - uses: actions/stale@v11
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 30 days-before-stale: 30
+3 -3
View File
@@ -18,17 +18,17 @@ jobs:
steps: steps:
- name: Install python 3.13 - name: Install python 3.13
uses: actions/setup-python@v6 uses: actions/setup-python@v7
with: with:
python-version: '3.13' python-version: '3.13'
- name: Install Node.js 26 - name: Install Node.js 26
uses: actions/setup-node@v6 uses: actions/setup-node@v7
with: with:
node-version: 26 node-version: 26
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Install pnpm - name: Install pnpm
run: npm install -g pnpm run: npm install -g pnpm
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Get and Send EMS-ESP version to Cloudflare - name: Get and Send EMS-ESP version to Cloudflare
env: env:
+18
View File
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [3.8.6] 24 September 2026
## Added
- own rgb_led library supporting WS2812B V5 and the newer V6 RGB LEDs
## [3.8.5] 22 September 2026
## Added
- Change webUI message when upgrading to a major version of the firmware, in preparation for the upcoming 3.9.0 release.
## [3.8.4] 4 August 2026
## Fixed
- Allow auto-download and install of firmware versions which are smaller to allow update to the latest 3.9.0-development version.
## [3.8.3] 1 August 2026 ## [3.8.3] 1 August 2026
## Added ## Added
+3 -1
View File
@@ -4,7 +4,7 @@ For more details go to [emsesp.org](https://emsesp.org/).
## [3.9.0] ## [3.9.0]
This release is based on the latest Espressif/Arduino core version 3. It brings in many memory and performance optimizations. Note it does require the user to manually migrate settings from 3.8.x to 3.9.0. This release is based on the latest Espressif/Arduino core version 3. It brings in many memory and performance optimizations.
## Added ## Added
@@ -19,6 +19,7 @@ This release is based on the latest Espressif/Arduino core version 3. It brings
- `show system` reports the Ethernet status on boards with a PHY, so a failed initialisation or a link that never came up is visible instead of Ethernet being omitted completely. Also shows the loop task's lowest free stack, to help diagnose reboots - `show system` reports the Ethernet status on boards with a PHY, so a failed initialisation or a link that never came up is visible instead of Ethernet being omitted completely. Also shows the loop task's lowest free stack, to help diagnose reboots
- new Application Setting "Automatically check for firmware updates", off by default. When enabled EMS-ESP asks emsesp.org for the latest version once a day on its own, otherwise it only asks when the WebUI wants to show it, so an unattended system never contacts emsesp.org - new Application Setting "Automatically check for firmware updates", off by default. When enabled EMS-ESP asks emsesp.org for the latest version once a day on its own, otherwise it only asks when the WebUI wants to show it, so an unattended system never contacts emsesp.org
- Automatically check and convert older 3.8.x filesystem to the new 3.9.0 format - Automatically check and convert older 3.8.x filesystem to the new 3.9.0 format
- heatpump pool: `poolon` (switch, 0x48A), `hppoolon` (pool heating active, 0x488), MP100 `poolshuntset` (0x5C4) and `poolrequest` (0x5BA), shorter pool names
## Fixed ## Fixed
@@ -56,4 +57,5 @@ This release is based on the latest Espressif/Arduino core version 3. It brings
- multiple optimization in network, power down WiFi when Ethernet and WiFi nosleep is instant when selected [#3213](https://github.com/emsesp/EMS-ESP32/pull/3213) - multiple optimization in network, power down WiFi when Ethernet and WiFi nosleep is instant when selected [#3213](https://github.com/emsesp/EMS-ESP32/pull/3213)
- TLS buffers (~17KB per HTTPS request) are taken from PSRAM on boards that have it, instead of fragmenting the internal heap - TLS buffers (~17KB per HTTPS request) are taken from PSRAM on boards that have it, instead of fragmenting the internal heap
- failed versions.json fetches back off from 5 up to 160 minutes instead of retrying every 5 minutes, as each attempt blocks the main loop for as long as the DNS, connect and read timeouts allow - failed versions.json fetches back off from 5 up to 160 minutes instead of retrying every 5 minutes, as each attempt blocks the main loop for as long as the DNS, connect and read timeouts allow
- optimized the LED library to support WS2812B V5 and the newer V6 RGB LEDs
+1 -1
View File
@@ -27,7 +27,7 @@ ifeq ($(UNAME_S),Linux)
JOBS := $(shell nproc) JOBS := $(shell nproc)
endif endif
ifeq ($(UNAME_S),Darwin) ifeq ($(UNAME_S),Darwin)
EXTRA_CPPFLAGS = -D OSX -Wno-tautological-constant-out-of-range-compare EXTRA_CPPFLAGS = -D OSX -Wno-tautological-constant-out-of-range-compare -Wno-unused-lambda-capture
JOBS := $(shell sysctl -n hw.ncpu) JOBS := $(shell sysctl -n hw.ncpu)
endif endif
File diff suppressed because it is too large Load Diff
+992 -972
View File
File diff suppressed because it is too large Load Diff
+6 -3
View File
@@ -77,7 +77,7 @@ telegram_type_id,name,is_fetched
0x0103,ISM1StatusMessage,fetched 0x0103,ISM1StatusMessage,fetched
0x0104,ISM2StatusMessage, 0x0104,ISM2StatusMessage,
0x010C,IPMStatusMessage, 0x010C,IPMStatusMessage,
0x011E,JunkersDisp,fetched 0x011E,IPMTempMessage,
0x012E,HPEnergy1, 0x012E,HPEnergy1,
0x013B,HPEnergy2, 0x013B,HPEnergy2,
0x0165,JunkersSet, 0x0165,JunkersSet,
@@ -104,7 +104,7 @@ telegram_type_id,name,is_fetched
0x0292,HPMode,fetched 0x0292,HPMode,fetched
0x0293,HPMode,fetched 0x0293,HPMode,fetched
0x0294,HPMode,fetched 0x0294,HPMode,fetched
0x029B,RC300Curves,fetched 0x029B,RC300Curves,
0x029C,RC300Curves, 0x029C,RC300Curves,
0x029D,RC300Curves, 0x029D,RC300Curves,
0x029E,RC300Curves, 0x029E,RC300Curves,
@@ -112,7 +112,7 @@ telegram_type_id,name,is_fetched
0x02A0,RC300Curves, 0x02A0,RC300Curves,
0x02A1,RC300Curves, 0x02A1,RC300Curves,
0x02A2,RC300Curves, 0x02A2,RC300Curves,
0x02A5,RC300Monitor, 0x02A5,EasyMonitor,
0x02A6,RC300Monitor, 0x02A6,RC300Monitor,
0x02A7,RC300Monitor, 0x02A7,RC300Monitor,
0x02A8,RC300Monitor, 0x02A8,RC300Monitor,
@@ -209,6 +209,7 @@ telegram_type_id,name,is_fetched
0x0585,Blowerspeed, 0x0585,Blowerspeed,
0x0587,Bypass, 0x0587,Bypass,
0x05BA,HpPoolStatus,fetched 0x05BA,HpPoolStatus,fetched
0x05C4,HpPoolShunt,
0x05D9,Airquality, 0x05D9,Airquality,
0x0772,HIUSettings, 0x0772,HIUSettings,
0x0779,HIUMonitor, 0x0779,HIUMonitor,
@@ -232,4 +233,6 @@ telegram_type_id,name,is_fetched
0x099A,HPStarts, 0x099A,HPStarts,
0x099B,HPFlowTemp, 0x099B,HPFlowTemp,
0x099C,HPComp, 0x099C,HPComp,
0x099D,HPComp2,
0x09A0,HPTemperature, 0x09A0,HPTemperature,
0x09A8,HPVolume,
1 telegram_type_id name is_fetched
77 0x0103 ISM1StatusMessage fetched
78 0x0104 ISM2StatusMessage
79 0x010C IPMStatusMessage
80 0x011E JunkersDisp IPMTempMessage fetched
81 0x012E HPEnergy1
82 0x013B HPEnergy2
83 0x0165 JunkersSet
104 0x0292 HPMode fetched
105 0x0293 HPMode fetched
106 0x0294 HPMode fetched
107 0x029B RC300Curves fetched
108 0x029C RC300Curves
109 0x029D RC300Curves
110 0x029E RC300Curves
112 0x02A0 RC300Curves
113 0x02A1 RC300Curves
114 0x02A2 RC300Curves
115 0x02A5 RC300Monitor EasyMonitor
116 0x02A6 RC300Monitor
117 0x02A7 RC300Monitor
118 0x02A8 RC300Monitor
209 0x0585 Blowerspeed
210 0x0587 Bypass
211 0x05BA HpPoolStatus fetched
212 0x05C4 HpPoolShunt
213 0x05D9 Airquality
214 0x0772 HIUSettings
215 0x0779 HIUMonitor
233 0x099A HPStarts
234 0x099B HPFlowTemp
235 0x099C HPComp
236 0x099D HPComp2
237 0x09A0 HPTemperature
238 0x09A8 HPVolume
+3 -3
View File
@@ -42,7 +42,7 @@
"@eslint/js": "^10.0.1", "@eslint/js": "^10.0.1",
"@preact/preset-vite": "^2.10.6", "@preact/preset-vite": "^2.10.6",
"@trivago/prettier-plugin-sort-imports": "^6.0.2", "@trivago/prettier-plugin-sort-imports": "^6.0.2",
"@types/node": "^26.6.2", "@types/node": "^26.6.3",
"@types/react": "^19.3.0", "@types/react": "^19.3.0",
"@types/react-dom": "^19.3.0", "@types/react-dom": "^19.3.0",
"concurrently": "^10.0.5", "concurrently": "^10.0.5",
@@ -50,12 +50,12 @@
"eslint-config-prettier": "^10.1.8", "eslint-config-prettier": "^10.1.8",
"etag": "^1.8.1", "etag": "^1.8.1",
"mime-types": "^3.0.2", "mime-types": "^3.0.2",
"prettier": "^3.9.8", "prettier": "^3.9.9",
"rollup-plugin-visualizer": "^7.1.1", "rollup-plugin-visualizer": "^7.1.1",
"terser": "^5.51.2", "terser": "^5.51.2",
"typescript": "^6.0.3", "typescript": "^6.0.3",
"typescript-eslint": "^8.70.1", "typescript-eslint": "^8.70.1",
"vite": "^8.3.0", "vite": "^8.3.1",
"vite-plugin-imagemin": "^0.6.1" "vite-plugin-imagemin": "^0.6.1"
}, },
"packageManager": "pnpm@12.6.0" "packageManager": "pnpm@12.6.0"
+140 -140
View File
@@ -214,13 +214,13 @@ importers:
version: 10.0.1(eslint@10.11.0(supports-color@10.2.2)) version: 10.0.1(eslint@10.11.0(supports-color@10.2.2))
'@preact/preset-vite': '@preact/preset-vite':
specifier: ^2.10.6 specifier: ^2.10.6
version: 2.10.6(@babel/core@7.29.7(supports-color@10.2.2))(preact@10.29.8)(supports-color@10.2.2)(vite@8.3.0(@types/node@26.6.2)(terser@5.51.2)) version: 2.10.6(@babel/core@7.29.7(supports-color@10.2.2))(preact@10.29.8)(supports-color@10.2.2)(vite@8.3.1(@types/node@26.6.3)(terser@5.51.2))
'@trivago/prettier-plugin-sort-imports': '@trivago/prettier-plugin-sort-imports':
specifier: ^6.0.2 specifier: ^6.0.2
version: 6.0.2(prettier@3.9.8)(supports-color@10.2.2) version: 6.0.2(prettier@3.9.9)(supports-color@10.2.2)
'@types/node': '@types/node':
specifier: ^26.6.2 specifier: ^26.6.3
version: 26.6.2 version: 26.6.3
'@types/react': '@types/react':
specifier: ^19.3.0 specifier: ^19.3.0
version: 19.3.0 version: 19.3.0
@@ -243,11 +243,11 @@ importers:
specifier: ^3.0.2 specifier: ^3.0.2
version: 3.0.2 version: 3.0.2
prettier: prettier:
specifier: ^3.9.8 specifier: ^3.9.9
version: 3.9.8 version: 3.9.9
rollup-plugin-visualizer: rollup-plugin-visualizer:
specifier: ^7.1.1 specifier: ^7.1.1
version: 7.1.1(rolldown@1.2.9) version: 7.1.1(rolldown@1.2.11)
terser: terser:
specifier: ^5.51.2 specifier: ^5.51.2
version: 5.51.2 version: 5.51.2
@@ -258,11 +258,11 @@ importers:
specifier: ^8.70.1 specifier: ^8.70.1
version: 8.70.1(eslint@10.11.0(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) version: 8.70.1(eslint@10.11.0(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
vite: vite:
specifier: ^8.3.0 specifier: ^8.3.1
version: 8.3.0(@types/node@26.6.2)(terser@5.51.2) version: 8.3.1(@types/node@26.6.3)(terser@5.51.2)
vite-plugin-imagemin: vite-plugin-imagemin:
specifier: ^0.6.1 specifier: ^0.6.1
version: 0.6.1(supports-color@10.2.2)(vite@8.3.0(@types/node@26.6.2)(terser@5.51.2)) version: 0.6.1(supports-color@10.2.2)(vite@8.3.1(@types/node@26.6.3)(terser@5.51.2))
packages: packages:
@@ -627,8 +627,8 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
'@oxc-project/types@0.150.0': '@oxc-project/types@0.151.0':
resolution: {integrity: sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw==} resolution: {integrity: sha512-J1yXrIlNDZVzE3ada310xeAw7nH8yCAyLPuUIsjKatFPmfn5bS1oW+cM+QsGOtVWd5nhSpbwZWx/rue+r5Z+PA==}
'@popperjs/core@2.11.8': '@popperjs/core@2.11.8':
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
@@ -661,98 +661,98 @@ packages:
'@remix-run/route-pattern@0.22.1': '@remix-run/route-pattern@0.22.1':
resolution: {integrity: sha512-czdGJWh09Lapvcqt7Vb09KlrU2PhRJ8xQaI+AItTuD9aDJ5MAgxnS38lnys6Ll+6RJEqPiaUqTwIQhVLwFvv+w==} resolution: {integrity: sha512-czdGJWh09Lapvcqt7Vb09KlrU2PhRJ8xQaI+AItTuD9aDJ5MAgxnS38lnys6Ll+6RJEqPiaUqTwIQhVLwFvv+w==}
'@rolldown/binding-android-arm-eabi@1.2.9': '@rolldown/binding-android-arm-eabi@1.2.11':
resolution: {integrity: sha512-tNISae1QEf/vkb3xkRcjV5SEdzPE97We5IVaa2Z8jSszQPZ8U60B/YCYpw4QI7VidYsBtKavczXf+DyDs9WGxw==} resolution: {integrity: sha512-A5kXfGKvKWWZE0TtPrfsvT+q4Y5d1QG8gGUzpYjGydM+fARM9MuX90PrXYXe0XbsDVgyxxNzHo6giCj90bsFNw==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm] cpu: [arm]
os: [android] os: [android]
'@rolldown/binding-android-arm64@1.2.9': '@rolldown/binding-android-arm64@1.2.11':
resolution: {integrity: sha512-YC8YsI30o606GTZi0VyzYlsDKFP8W61i/QzayHDkLbNEz/IShqAmTa+hsJRj13xTHA0H+6fk4b2UmGn+Q/cMlg==} resolution: {integrity: sha512-z6cTycz+iJ4PVkuL4HHW4DfTfoeU/2nqYYuSOrTmH7yHK5Y0LCOnA03V4ZNxavyVaU1oOqUgIg2klN/s+USGOA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [android] os: [android]
'@rolldown/binding-darwin-arm64@1.2.9': '@rolldown/binding-darwin-arm64@1.2.11':
resolution: {integrity: sha512-IwhlH3qK5urrY8hZiEgGkHKEFN901p/p2bjxCxJlr4GyNnF7wYpUvK+Y43uaRYuC4hpfjzbR3SJC3arX1jGvmw==} resolution: {integrity: sha512-jShvqNtP6vDC6/A5JOAzbVV+DkgHqhl/ScVCJEbt+TUY6QYz7YnXcrg3sLtFBniro0f/Ld50ZwCWA6f7KYD1nQ==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@rolldown/binding-darwin-x64@1.2.9': '@rolldown/binding-darwin-x64@1.2.11':
resolution: {integrity: sha512-XxpJfVzFh+jilRxIXUqcfYAYcunIc/XEzIizsOL1fcJee5Sf7H3mH8WlLmfHfluz5amqR88QQo9izKtmMlavAw==} resolution: {integrity: sha512-f2i2xiNWq1Z1l2++q2fuhZRdLAT3aqxD6vRNm1RAxpUoBcdqNB3C0s1Bt+K+PbEx2F5F4gQp6hqKkphCY/xF9w==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@rolldown/binding-freebsd-x64@1.2.9': '@rolldown/binding-freebsd-x64@1.2.11':
resolution: {integrity: sha512-kSfvhmgeWyfkbT3p/1s5vSgboogoah2zkm9fX2zjg2hHxSV7T4KhMWRUUaRk4OXNqoD3QAUeRqLcs1aZOK4U1g==} resolution: {integrity: sha512-4Ir5FSOKIAMr4r0kExpt1s3bMgzJU3rA45AYOHtQpls0oNeqcYBKrWMlckrYH4KCfGLfkfn1tN1dmZPMVsdXow==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64] cpu: [x64]
os: [freebsd] os: [freebsd]
'@rolldown/binding-linux-arm-gnueabihf@1.2.9': '@rolldown/binding-linux-arm-gnueabihf@1.2.11':
resolution: {integrity: sha512-1RVzG17pxqbTfYLC352JlLt6kKLG+6Hr30n8DlIJqsnV5luUDd2Qdx9Ayw1Cabfyb1K9k0jXEZ7evxkRoT+uiw==} resolution: {integrity: sha512-/gnRDM+39BROzAN/k1OZjDPnDMcZxB/0EUxKjONO5yVkNEvlsoMDrxGNKgZi/ttFriS2gwlDNzB65pvNbFOXIQ==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@rolldown/binding-linux-arm64-gnu@1.2.9': '@rolldown/binding-linux-arm64-gnu@1.2.11':
resolution: {integrity: sha512-BXqPvZ2drqVD+/Z8UpKwcs4Mp7grM+eGFku4CAEKrEtcbAsUpzREphK1sogCRZGreVPiMkiiBtw0n3TPteuqvw==} resolution: {integrity: sha512-PFaK8HwvAHbaKbBcDNQihjMKYvFnA5hiENx/l5tphTDz1E0WFp32l0A7aq7lyUwGsRw/xSrNIy/gIK4thrSCrw==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc] libc: [glibc]
'@rolldown/binding-linux-arm64-musl@1.2.9': '@rolldown/binding-linux-arm64-musl@1.2.11':
resolution: {integrity: sha512-11vWvo8YDwLzukt27J3aYDWU+gg2P7J+ZOmiJ0hkF5BXZDW7pVya7r40MXDy6ya0i9KamoENSVKIugvJNgFXIA==} resolution: {integrity: sha512-AskzJUIKRLPxkruR1wLKewGbOw+EYfU/9lOrBFj4AFrEA8hPpKFnODWNu2WLaNs0QNkEb9QIJufmVZZIL/bJlg==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl] libc: [musl]
'@rolldown/binding-linux-ppc64-gnu@1.2.9': '@rolldown/binding-linux-ppc64-gnu@1.2.11':
resolution: {integrity: sha512-a1tijMkdwsIARtc0F39ApURROkf3NwqinI6TOiSSWCTR7dT96dffNvMUtDHnq64wKNTIZOIlzKrFvvFUznJiyw==} resolution: {integrity: sha512-qlUGAheh2yh8afH7QBgx0PrRHN85hKnNd78x8MeMhXivuevgd8vgf6/CstOzmNKY/lLTHvNTrPy98cLnAugzJw==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
libc: [glibc] libc: [glibc]
'@rolldown/binding-linux-s390x-gnu@1.2.9': '@rolldown/binding-linux-s390x-gnu@1.2.11':
resolution: {integrity: sha512-x6SQNdAvv4c3hWqTMaWuawzMX9myaCs/yEmlGsxJzkdClnHW7FbrjQuSiRDhuSYzEYoEMhsaJy9qHG/XNemJPQ==} resolution: {integrity: sha512-secpEad+0vCbSfn8upFySkDskv+bGPk3THSDS9Y89yc4rb4kzqHp8Dmyd9BkQW4SnhNXBZCl/6CrO//hZahNJQ==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
libc: [glibc] libc: [glibc]
'@rolldown/binding-linux-x64-gnu@1.2.9': '@rolldown/binding-linux-x64-gnu@1.2.11':
resolution: {integrity: sha512-9s0AZ8BFK5/n7B/TBoa2yJE3gI3KURrbXcPBlsAsvjU4VeJKgE90y1YtNxyEUIcHPQkg6/yfF3qihUrcM/Kf0Q==} resolution: {integrity: sha512-mOVBT3dPpkWm8XBWPmU4bf+U6dYDLeMo/9ojUmis4N0L5uu10qra5vOyngZ7/PSdoE4G9KvRt4bloRxNjLas7A==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc] libc: [glibc]
'@rolldown/binding-linux-x64-musl@1.2.9': '@rolldown/binding-linux-x64-musl@1.2.11':
resolution: {integrity: sha512-P7VWAmV+WdJluH7ovnRGoiv2i8To7GAZ+kGzfGup635cyL7SyYl3lSUaA3Gp5THf0n/Co5EyEqb2zbqq+nMOHQ==} resolution: {integrity: sha512-Is78i9A8Ui4SqcxUwFJ9uMmjDn58IbVTjFWYdQestFEgeuEmHMLGNriXnVJKkwG2YiZjw8cP0zCTyDMdDGtOOg==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl] libc: [musl]
'@rolldown/binding-openharmony-arm64@1.2.9': '@rolldown/binding-openharmony-arm64@1.2.11':
resolution: {integrity: sha512-1qixtsE4BK8h+yS3BfmZ09UhA7O/N4IACva6YBr7EBvCJraByTuRcgOTaiA62Tm0vey3UcKXLOaoGHtYmNGEVg==} resolution: {integrity: sha512-dUCXneZ87INUMyQ0D+C0HrEBNUPNXHaPmU5GTjyKTJEiussw9Kaj5Ln8UztPe4epV/ffvgNBEadksdYhmW6xJA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [openharmony] os: [openharmony]
'@rolldown/binding-win32-arm64-msvc@1.2.9': '@rolldown/binding-win32-arm64-msvc@1.2.11':
resolution: {integrity: sha512-ok8IQjcEPs1AKZfuEUznVBrJw+gK4soq+bx8b1X2XoMqVClarc1q5JDmVtWXY1xfr6ZuHTAsPXHTgTrqKTZeww==} resolution: {integrity: sha512-jByxb6qfd+bH1xUd0qnfFnb17i9sWBPY2tOavJ0l3tdr3OTu+Kvtm8cd/JV5nFt657b1VqGltxg9olOEfofXWw==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@rolldown/binding-win32-x64-msvc@1.2.9': '@rolldown/binding-win32-x64-msvc@1.2.11':
resolution: {integrity: sha512-Ip2mXoU0hM0boq3Rf+ekuT653OROSo6aSYcPT1VHE4q52KvyxgFkQgrgb/IEsxOuvQ2fZZbs8khJAyCEPM24/g==} resolution: {integrity: sha512-/PzKqzAJ03i19oy2ItPvyvaVjOjBCNnfaJs8yvUdGBKmiESgnrJSQ2awd81QzFbbnAmu7YO9ZnJrDCb9VSJPRA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
@@ -842,8 +842,8 @@ packages:
'@types/minimatch@5.1.2': '@types/minimatch@5.1.2':
resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==}
'@types/node@26.6.2': '@types/node@26.6.3':
resolution: {integrity: sha512-X1P21scMv4zGKLYqjdGjaKa7COa0RKVYYZZN/NfvLQ1JegxFhdhpZG/Lyn8AXx6CDUavKAd11v6BvfpkDByK8g==} resolution: {integrity: sha512-dsqMQQoeTLqu9wynDD00q573mNzso3IdQOAfHRJqLCcmCFPoGo9A1bDpUcv/9tnKpErQWv9uKeGfl37EIS02Yg==}
'@types/parse-json@4.0.2': '@types/parse-json@4.0.2':
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
@@ -1004,8 +1004,8 @@ packages:
base64-js@1.5.1: base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
baseline-browser-mapping@2.11.25: baseline-browser-mapping@2.11.26:
resolution: {integrity: sha512-gMmEShwwq7FJqMwvfRwvCl00v4kN+KOfJqXn+f4nrufak5gNHJOksd/60Dvjuz7sI8Y5WiSFBa8FEYr+zoyqCw==} resolution: {integrity: sha512-GLQdD3y6UF8iVuMJl5fHgE4jdn/ua7n+toKfLgNlg3BqQtOZjpy68T8Tup8/wGWZCDlm7KMg7tPb4MPn7oN0TQ==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
hasBin: true hasBin: true
@@ -1049,8 +1049,8 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'} engines: {node: '>=8'}
browserslist@4.29.0: browserslist@4.29.1:
resolution: {integrity: sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==} resolution: {integrity: sha512-AUdjuRyCNGUYtqpqfTmWyM4fXay8yIQhmLnvYe/THMGfT9B/34X7xQd3ifKxwyNPPpowVBjLb+64BN9Rn1mizw==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true hasBin: true
@@ -1072,8 +1072,8 @@ packages:
buffer@5.7.1: buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
bundle-name@4.1.0: bundle-name@4.1.1:
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} resolution: {integrity: sha512-DdH81/zPLVS11EUgWq3tEu/xn+EzljlMYooDNdzWEnFha3R3NBMpMV1UqYIpjYHV/SgpFKMIX1Oh7o06SjM/oA==}
engines: {node: '>=18'} engines: {node: '>=18'}
cacheable-request@2.1.4: cacheable-request@2.1.4:
@@ -1106,8 +1106,8 @@ packages:
resolution: {integrity: sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==} resolution: {integrity: sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
caniuse-lite@1.0.30001810: caniuse-lite@1.0.30001812:
resolution: {integrity: sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==} resolution: {integrity: sha512-qN+QNNBr93TCmFrmte0bBCjSDMuRvt78VlHT99qIGPszm4QsqCX8lnyWUFkHi8B7ZBAPq8SH+UqyXNy/odMdng==}
caw@2.0.1: caw@2.0.1:
resolution: {integrity: sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==} resolution: {integrity: sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==}
@@ -1338,8 +1338,8 @@ packages:
duplexer3@0.1.5: duplexer3@0.1.5:
resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==} resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==}
electron-to-chromium@1.5.437: electron-to-chromium@1.5.439:
resolution: {integrity: sha512-1z60R0Nb+kYPnGUrQ6PvMjTVINDGMfqQZ/mI5FJIHvTotlA6noI+YJWakbjaFM+qhLXg9WnK3RUeYSO5ixSHJA==} resolution: {integrity: sha512-qu6QIPXhsb+CRcAiTMNjR4A1y/7tCYKkKjr5CZXRVih6qkDf79peZ2BpEU3qoDBNCRrcy3Mra3X9nG5oruuA7Q==}
emoji-regex@10.6.0: emoji-regex@10.6.0:
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
@@ -2318,8 +2318,8 @@ packages:
node-html-parser@6.1.13: node-html-parser@6.1.13:
resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==}
node-releases@2.0.56: node-releases@2.0.57:
resolution: {integrity: sha512-x0InOIyzgdk+eyaWaRJFH5snEtiImgBgblZ2CyPrLmqqcuMQkEvcDPHbzqbD8eDsSeJbVOjn+crzyzHaM4D+/A==} resolution: {integrity: sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw==}
engines: {node: '>=18'} engines: {node: '>=18'}
normalize-package-data@2.5.0: normalize-package-data@2.5.0:
@@ -2555,8 +2555,8 @@ packages:
resolution: {integrity: sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==} resolution: {integrity: sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==}
engines: {node: '>=4'} engines: {node: '>=4'}
prettier@3.9.8: prettier@3.9.9:
resolution: {integrity: sha512-WRFq3Wn3WId7LLROfMLdH7xaFr2jR62wU8nLO6rQUOLOxNZUviyJQs1M0iIhLexSFy+L+w0ch66wtoO2jRjG0A==} resolution: {integrity: sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg==}
engines: {node: '>=14'} engines: {node: '>=14'}
hasBin: true hasBin: true
@@ -2686,8 +2686,8 @@ packages:
deprecated: Rimraf versions prior to v4 are no longer supported deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true hasBin: true
rolldown@1.2.9: rolldown@1.2.11:
resolution: {integrity: sha512-hx/Pv0N1haXRb11qkfnK5MXB/iqr7i0yjWQqmO9uHqZpBgQSqzc8UsSnEpalsh+j1I8qQ2CkXAkJC8Br3dKSlg==} resolution: {integrity: sha512-qpSwIyz0jHQq5qXBTNxFmE6664rJ7O+4TvPFOiOaBSrz8IOHc1koKKSqTM2H6u1UG1+TveuC6vaDHKXFOvb1Kw==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true hasBin: true
@@ -2853,8 +2853,8 @@ packages:
resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
string-width@8.2.2: string-width@8.3.0:
resolution: {integrity: sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==} resolution: {integrity: sha512-ZbmZM0JCihQN91dWnxoipT2KOEyHqEyfRXUyjuRhW8b/xnqPDoq4gWEVApTVa9db2wN8mmoikgFBbjh71+cGeQ==}
engines: {node: '>=20'} engines: {node: '>=20'}
string_decoder@1.1.1: string_decoder@1.1.1:
@@ -3056,13 +3056,13 @@ packages:
peerDependencies: peerDependencies:
vite: '>=2.0.0' vite: '>=2.0.0'
vite-prerender-plugin@0.5.13: vite-prerender-plugin@0.5.14:
resolution: {integrity: sha512-IKSpYkzDBsKAxa05naRbj7GvNVMSdww/Z/E89oO3xndz+gWnOBOKOAbEXv7qDhktY/j3vHgJmoV1pPzqU2tx9g==} resolution: {integrity: sha512-X2w9AS1OhwEUec9HSryGAmEnEQJGhW6eFoiCVJv8BfOTVpM8SOjk75cEw/IC28APDHZudeIRbP8Sp7wfABq+Aw==}
peerDependencies: peerDependencies:
vite: 5.x || 6.x || 7.x || 8.x vite: 5.x || 6.x || 7.x || 8.x
vite@8.3.0: vite@8.3.1:
resolution: {integrity: sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==} resolution: {integrity: sha512-/bvH9E9tmCXRGp2uXY3WbOldqpTwFkbha/8ANaEQ6VkxhH60KyqLwgZq6lG2y+4uT55x9+9eUHMpQ7uGnOCKjA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@@ -3225,7 +3225,7 @@ snapshots:
dependencies: dependencies:
'@babel/compat-data': 7.29.7 '@babel/compat-data': 7.29.7
'@babel/helper-validator-option': 7.29.7 '@babel/helper-validator-option': 7.29.7
browserslist: 4.29.0 browserslist: 4.29.1
lru-cache: 5.1.1 lru-cache: 5.1.1
semver: 6.3.1 semver: 6.3.1
@@ -3591,23 +3591,23 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5 '@nodelib/fs.scandir': 2.1.5
fastq: 1.20.3 fastq: 1.20.3
'@oxc-project/types@0.150.0': {} '@oxc-project/types@0.151.0': {}
'@popperjs/core@2.11.8': {} '@popperjs/core@2.11.8': {}
'@preact/preset-vite@2.10.6(@babel/core@7.29.7(supports-color@10.2.2))(preact@10.29.8)(supports-color@10.2.2)(vite@8.3.0(@types/node@26.6.2)(terser@5.51.2))': '@preact/preset-vite@2.10.6(@babel/core@7.29.7(supports-color@10.2.2))(preact@10.29.8)(supports-color@10.2.2)(vite@8.3.1(@types/node@26.6.3)(terser@5.51.2))':
dependencies: dependencies:
'@babel/core': 7.29.7(supports-color@10.2.2) '@babel/core': 7.29.7(supports-color@10.2.2)
'@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)
'@babel/plugin-transform-react-jsx-development': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) '@babel/plugin-transform-react-jsx-development': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)
'@prefresh/vite': 2.4.12(preact@10.29.8)(supports-color@10.2.2)(vite@8.3.0(@types/node@26.6.2)(terser@5.51.2)) '@prefresh/vite': 2.4.12(preact@10.29.8)(supports-color@10.2.2)(vite@8.3.1(@types/node@26.6.3)(terser@5.51.2))
'@rollup/pluginutils': 5.4.0 '@rollup/pluginutils': 5.4.0
babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.29.7(supports-color@10.2.2)) babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.29.7(supports-color@10.2.2))
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@10.2.2)
magic-string: 0.30.21 magic-string: 0.30.21
picocolors: 1.1.1 picocolors: 1.1.1
vite: 8.3.0(@types/node@26.6.2)(terser@5.51.2) vite: 8.3.1(@types/node@26.6.3)(terser@5.51.2)
vite-prerender-plugin: 0.5.13(vite@8.3.0(@types/node@26.6.2)(terser@5.51.2)) vite-prerender-plugin: 0.5.14(vite@8.3.1(@types/node@26.6.3)(terser@5.51.2))
zimmerframe: 1.1.5 zimmerframe: 1.1.5
transitivePeerDependencies: transitivePeerDependencies:
- preact - preact
@@ -3624,7 +3624,7 @@ snapshots:
'@prefresh/utils@1.2.1': {} '@prefresh/utils@1.2.1': {}
'@prefresh/vite@2.4.12(preact@10.29.8)(supports-color@10.2.2)(vite@8.3.0(@types/node@26.6.2)(terser@5.51.2))': '@prefresh/vite@2.4.12(preact@10.29.8)(supports-color@10.2.2)(vite@8.3.1(@types/node@26.6.3)(terser@5.51.2))':
dependencies: dependencies:
'@babel/core': 7.29.7(supports-color@10.2.2) '@babel/core': 7.29.7(supports-color@10.2.2)
'@prefresh/babel-plugin': 0.5.4(@babel/core@7.29.7(supports-color@10.2.2)) '@prefresh/babel-plugin': 0.5.4(@babel/core@7.29.7(supports-color@10.2.2))
@@ -3632,55 +3632,55 @@ snapshots:
'@prefresh/utils': 1.2.1 '@prefresh/utils': 1.2.1
'@rollup/pluginutils': 4.2.1 '@rollup/pluginutils': 4.2.1
preact: 10.29.8 preact: 10.29.8
vite: 8.3.0(@types/node@26.6.2)(terser@5.51.2) vite: 8.3.1(@types/node@26.6.3)(terser@5.51.2)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@remix-run/route-pattern@0.22.1': {} '@remix-run/route-pattern@0.22.1': {}
'@rolldown/binding-android-arm-eabi@1.2.9': '@rolldown/binding-android-arm-eabi@1.2.11':
optional: true optional: true
'@rolldown/binding-android-arm64@1.2.9': '@rolldown/binding-android-arm64@1.2.11':
optional: true optional: true
'@rolldown/binding-darwin-arm64@1.2.9': '@rolldown/binding-darwin-arm64@1.2.11':
optional: true optional: true
'@rolldown/binding-darwin-x64@1.2.9': '@rolldown/binding-darwin-x64@1.2.11':
optional: true optional: true
'@rolldown/binding-freebsd-x64@1.2.9': '@rolldown/binding-freebsd-x64@1.2.11':
optional: true optional: true
'@rolldown/binding-linux-arm-gnueabihf@1.2.9': '@rolldown/binding-linux-arm-gnueabihf@1.2.11':
optional: true optional: true
'@rolldown/binding-linux-arm64-gnu@1.2.9': '@rolldown/binding-linux-arm64-gnu@1.2.11':
optional: true optional: true
'@rolldown/binding-linux-arm64-musl@1.2.9': '@rolldown/binding-linux-arm64-musl@1.2.11':
optional: true optional: true
'@rolldown/binding-linux-ppc64-gnu@1.2.9': '@rolldown/binding-linux-ppc64-gnu@1.2.11':
optional: true optional: true
'@rolldown/binding-linux-s390x-gnu@1.2.9': '@rolldown/binding-linux-s390x-gnu@1.2.11':
optional: true optional: true
'@rolldown/binding-linux-x64-gnu@1.2.9': '@rolldown/binding-linux-x64-gnu@1.2.11':
optional: true optional: true
'@rolldown/binding-linux-x64-musl@1.2.9': '@rolldown/binding-linux-x64-musl@1.2.11':
optional: true optional: true
'@rolldown/binding-openharmony-arm64@1.2.9': '@rolldown/binding-openharmony-arm64@1.2.11':
optional: true optional: true
'@rolldown/binding-win32-arm64-msvc@1.2.9': '@rolldown/binding-win32-arm64-msvc@1.2.11':
optional: true optional: true
'@rolldown/binding-win32-x64-msvc@1.2.9': '@rolldown/binding-win32-x64-msvc@1.2.11':
optional: true optional: true
'@rolldown/pluginutils@1.0.1': {} '@rolldown/pluginutils@1.0.1': {}
@@ -3707,7 +3707,7 @@ snapshots:
react-virtualized-auto-sizer: 1.0.26(react-dom@19.3.0(react@19.3.0))(react@19.3.0) react-virtualized-auto-sizer: 1.0.26(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
react-window: 1.8.11(react-dom@19.3.0(react@19.3.0))(react@19.3.0) react-window: 1.8.11(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
'@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.9.8)(supports-color@10.2.2)': '@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.9.9)(supports-color@10.2.2)':
dependencies: dependencies:
'@babel/generator': 7.29.8 '@babel/generator': 7.29.8
'@babel/parser': 7.29.9 '@babel/parser': 7.29.9
@@ -3717,7 +3717,7 @@ snapshots:
lodash-es: 4.18.1 lodash-es: 4.18.1
minimatch: 9.0.9 minimatch: 9.0.9
parse-imports-exports: 0.2.4 parse-imports-exports: 0.2.4
prettier: 3.9.8 prettier: 3.9.9
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -3728,7 +3728,7 @@ snapshots:
'@types/glob@7.2.0': '@types/glob@7.2.0':
dependencies: dependencies:
'@types/minimatch': 5.1.2 '@types/minimatch': 5.1.2
'@types/node': 26.6.2 '@types/node': 26.6.3
'@types/imagemin-gifsicle@7.0.4': '@types/imagemin-gifsicle@7.0.4':
dependencies: dependencies:
@@ -3757,17 +3757,17 @@ snapshots:
'@types/imagemin@7.0.1': '@types/imagemin@7.0.1':
dependencies: dependencies:
'@types/node': 26.6.2 '@types/node': 26.6.3
'@types/json-schema@7.0.15': {} '@types/json-schema@7.0.15': {}
'@types/keyv@3.1.4': '@types/keyv@3.1.4':
dependencies: dependencies:
'@types/node': 26.6.2 '@types/node': 26.6.3
'@types/minimatch@5.1.2': {} '@types/minimatch@5.1.2': {}
'@types/node@26.6.2': '@types/node@26.6.3':
dependencies: dependencies:
undici-types: 8.9.0 undici-types: 8.9.0
@@ -3789,11 +3789,11 @@ snapshots:
'@types/responselike@1.0.3': '@types/responselike@1.0.3':
dependencies: dependencies:
'@types/node': 26.6.2 '@types/node': 26.6.3
'@types/svgo@2.6.4': '@types/svgo@2.6.4':
dependencies: dependencies:
'@types/node': 26.6.2 '@types/node': 26.6.3
'@typescript-eslint/eslint-plugin@8.70.1(@typescript-eslint/parser@8.70.1(eslint@10.11.0(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.11.0(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': '@typescript-eslint/eslint-plugin@8.70.1(@typescript-eslint/parser@8.70.1(eslint@10.11.0(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.11.0(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)':
dependencies: dependencies:
@@ -3946,7 +3946,7 @@ snapshots:
base64-js@1.5.1: {} base64-js@1.5.1: {}
baseline-browser-mapping@2.11.25: {} baseline-browser-mapping@2.11.26: {}
bin-build@3.0.0: bin-build@3.0.0:
dependencies: dependencies:
@@ -4005,13 +4005,13 @@ snapshots:
dependencies: dependencies:
fill-range: 7.1.1 fill-range: 7.1.1
browserslist@4.29.0: browserslist@4.29.1:
dependencies: dependencies:
baseline-browser-mapping: 2.11.25 baseline-browser-mapping: 2.11.26
caniuse-lite: 1.0.30001810 caniuse-lite: 1.0.30001812
electron-to-chromium: 1.5.437 electron-to-chromium: 1.5.439
node-releases: 2.0.56 node-releases: 2.0.57
update-browserslist-db: 1.3.3(browserslist@4.29.0) update-browserslist-db: 1.3.3(browserslist@4.29.1)
buffer-alloc-unsafe@1.1.0: {} buffer-alloc-unsafe@1.1.0: {}
@@ -4031,7 +4031,7 @@ snapshots:
base64-js: 1.5.1 base64-js: 1.5.1
ieee754: 1.2.1 ieee754: 1.2.1
bundle-name@4.1.0: bundle-name@4.1.1:
dependencies: dependencies:
run-applescript: 7.1.0 run-applescript: 7.1.0
@@ -4079,7 +4079,7 @@ snapshots:
camelcase@2.1.1: {} camelcase@2.1.1: {}
caniuse-lite@1.0.30001810: {} caniuse-lite@1.0.30001812: {}
caw@2.0.1: caw@2.0.1:
dependencies: dependencies:
@@ -4281,7 +4281,7 @@ snapshots:
default-browser@5.5.1: default-browser@5.5.1:
dependencies: dependencies:
bundle-name: 4.1.0 bundle-name: 4.1.1
default-browser-id: 5.0.1 default-browser-id: 5.0.1
define-data-property@1.1.4: define-data-property@1.1.4:
@@ -4374,7 +4374,7 @@ snapshots:
duplexer3@0.1.5: {} duplexer3@0.1.5: {}
electron-to-chromium@1.5.437: {} electron-to-chromium@1.5.439: {}
emoji-regex@10.6.0: {} emoji-regex@10.6.0: {}
@@ -5311,7 +5311,7 @@ snapshots:
css-select: 5.2.2 css-select: 5.2.2
he: 1.2.0 he: 1.2.0
node-releases@2.0.56: {} node-releases@2.0.57: {}
normalize-package-data@2.5.0: normalize-package-data@2.5.0:
dependencies: dependencies:
@@ -5515,7 +5515,7 @@ snapshots:
prepend-http@2.0.0: {} prepend-http@2.0.0: {}
prettier@3.9.8: {} prettier@3.9.9: {}
process-nextick-args@2.0.1: {} process-nextick-args@2.0.1: {}
@@ -5645,35 +5645,35 @@ snapshots:
dependencies: dependencies:
glob: 7.2.3 glob: 7.2.3
rolldown@1.2.9: rolldown@1.2.11:
dependencies: dependencies:
'@oxc-project/types': 0.150.0 '@oxc-project/types': 0.151.0
'@rolldown/pluginutils': 1.0.1 '@rolldown/pluginutils': 1.0.1
optionalDependencies: optionalDependencies:
'@rolldown/binding-android-arm-eabi': 1.2.9 '@rolldown/binding-android-arm-eabi': 1.2.11
'@rolldown/binding-android-arm64': 1.2.9 '@rolldown/binding-android-arm64': 1.2.11
'@rolldown/binding-darwin-arm64': 1.2.9 '@rolldown/binding-darwin-arm64': 1.2.11
'@rolldown/binding-darwin-x64': 1.2.9 '@rolldown/binding-darwin-x64': 1.2.11
'@rolldown/binding-freebsd-x64': 1.2.9 '@rolldown/binding-freebsd-x64': 1.2.11
'@rolldown/binding-linux-arm-gnueabihf': 1.2.9 '@rolldown/binding-linux-arm-gnueabihf': 1.2.11
'@rolldown/binding-linux-arm64-gnu': 1.2.9 '@rolldown/binding-linux-arm64-gnu': 1.2.11
'@rolldown/binding-linux-arm64-musl': 1.2.9 '@rolldown/binding-linux-arm64-musl': 1.2.11
'@rolldown/binding-linux-ppc64-gnu': 1.2.9 '@rolldown/binding-linux-ppc64-gnu': 1.2.11
'@rolldown/binding-linux-s390x-gnu': 1.2.9 '@rolldown/binding-linux-s390x-gnu': 1.2.11
'@rolldown/binding-linux-x64-gnu': 1.2.9 '@rolldown/binding-linux-x64-gnu': 1.2.11
'@rolldown/binding-linux-x64-musl': 1.2.9 '@rolldown/binding-linux-x64-musl': 1.2.11
'@rolldown/binding-openharmony-arm64': 1.2.9 '@rolldown/binding-openharmony-arm64': 1.2.11
'@rolldown/binding-win32-arm64-msvc': 1.2.9 '@rolldown/binding-win32-arm64-msvc': 1.2.11
'@rolldown/binding-win32-x64-msvc': 1.2.9 '@rolldown/binding-win32-x64-msvc': 1.2.11
rollup-plugin-visualizer@7.1.1(rolldown@1.2.9): rollup-plugin-visualizer@7.1.1(rolldown@1.2.11):
dependencies: dependencies:
open: 11.0.4 open: 11.0.4
picomatch: 4.0.7 picomatch: 4.0.7
source-map: 0.8.0 source-map: 0.8.0
yargs: 18.2.0 yargs: 18.2.0
optionalDependencies: optionalDependencies:
rolldown: 1.2.9 rolldown: 1.2.11
run-applescript@7.1.0: {} run-applescript@7.1.0: {}
@@ -5799,7 +5799,7 @@ snapshots:
get-east-asian-width: 1.7.0 get-east-asian-width: 1.7.0
strip-ansi: 7.2.0 strip-ansi: 7.2.0
string-width@8.2.2: string-width@8.3.0:
dependencies: dependencies:
get-east-asian-width: 1.7.0 get-east-asian-width: 1.7.0
strip-ansi: 7.2.0 strip-ansi: 7.2.0
@@ -5959,9 +5959,9 @@ snapshots:
universalify@2.0.1: {} universalify@2.0.1: {}
update-browserslist-db@1.3.3(browserslist@4.29.0): update-browserslist-db@1.3.3(browserslist@4.29.1):
dependencies: dependencies:
browserslist: 4.29.0 browserslist: 4.29.1
escalade: 3.2.0 escalade: 3.2.0
picocolors: 1.1.1 picocolors: 1.1.1
@@ -5988,7 +5988,7 @@ snapshots:
spdx-correct: 3.2.0 spdx-correct: 3.2.0
spdx-expression-parse: 3.0.1 spdx-expression-parse: 3.0.1
vite-plugin-imagemin@0.6.1(supports-color@10.2.2)(vite@8.3.0(@types/node@26.6.2)(terser@5.51.2)): vite-plugin-imagemin@0.6.1(supports-color@10.2.2)(vite@8.3.1(@types/node@26.6.3)(terser@5.51.2)):
dependencies: dependencies:
'@types/imagemin': 7.0.1 '@types/imagemin': 7.0.1
'@types/imagemin-gifsicle': 7.0.4 '@types/imagemin-gifsicle': 7.0.4
@@ -6013,11 +6013,11 @@ snapshots:
imagemin-webp: 6.1.0 imagemin-webp: 6.1.0
jpegtran-bin: 6.0.1 jpegtran-bin: 6.0.1
pathe: 0.2.0 pathe: 0.2.0
vite: 8.3.0(@types/node@26.6.2)(terser@5.51.2) vite: 8.3.1(@types/node@26.6.3)(terser@5.51.2)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
vite-prerender-plugin@0.5.13(vite@8.3.0(@types/node@26.6.2)(terser@5.51.2)): vite-prerender-plugin@0.5.14(vite@8.3.1(@types/node@26.6.3)(terser@5.51.2)):
dependencies: dependencies:
kolorist: 1.8.0 kolorist: 1.8.0
magic-string: 0.30.21 magic-string: 0.30.21
@@ -6025,17 +6025,17 @@ snapshots:
simple-code-frame: 1.3.0 simple-code-frame: 1.3.0
source-map: 0.7.6 source-map: 0.7.6
stack-trace: 1.0.0 stack-trace: 1.0.0
vite: 8.3.0(@types/node@26.6.2)(terser@5.51.2) vite: 8.3.1(@types/node@26.6.3)(terser@5.51.2)
vite@8.3.0(@types/node@26.6.2)(terser@5.51.2): vite@8.3.1(@types/node@26.6.3)(terser@5.51.2):
dependencies: dependencies:
lightningcss: 1.33.0 lightningcss: 1.33.0
picomatch: 4.0.7 picomatch: 4.0.7
postcss: 8.5.28 postcss: 8.5.28
rolldown: 1.2.9 rolldown: 1.2.11
tinyglobby: 0.2.17 tinyglobby: 0.2.17
optionalDependencies: optionalDependencies:
'@types/node': 26.6.2 '@types/node': 26.6.3
fsevents: 2.3.3 fsevents: 2.3.3
terser: 5.51.2 terser: 5.51.2
@@ -6098,7 +6098,7 @@ snapshots:
cliui: 9.0.1 cliui: 9.0.1
escalade: 3.2.0 escalade: 3.2.0
get-caller-file: 2.0.5 get-caller-file: 2.0.5
string-width: 8.2.2 string-width: 8.3.0
y18n: 5.0.8 y18n: 5.0.8
yargs-parser: 22.0.0 yargs-parser: 22.0.0
-2
View File
@@ -148,7 +148,5 @@ double ledcSetup(uint8_t chan, double freq, uint8_t bit_num) {
void ledcAttachPin(uint8_t pin, uint8_t chan) {}; void ledcAttachPin(uint8_t pin, uint8_t chan) {};
void ledcAttach(uint8_t pin, uint8_t chan, uint8_t bit_num) {}; void ledcAttach(uint8_t pin, uint8_t chan, uint8_t bit_num) {};
void ledcWrite(uint8_t chan, uint32_t duty) {}; void ledcWrite(uint8_t chan, uint32_t duty) {};
void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val) {};
void rgbLedWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val) {};
#endif #endif
-2
View File
@@ -83,8 +83,6 @@ double ledcSetup(uint8_t chan, double freq, uint8_t bit_num);
void ledcAttachPin(uint8_t pin, uint8_t chan); void ledcAttachPin(uint8_t pin, uint8_t chan);
void ledcAttach(uint8_t pin, uint8_t chan, uint8_t bit_num); void ledcAttach(uint8_t pin, uint8_t chan, uint8_t bit_num);
void ledcWrite(uint8_t chan, uint32_t duty); void ledcWrite(uint8_t chan, uint32_t duty);
void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val);
void rgbLedWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val);
inline int rtc_get_reset_reason(int cpu_no) { inline int rtc_get_reset_reason(int cpu_no) {
return 0; return 0;
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -15,7 +15,7 @@
}, },
"devDependencies": { "devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^6.0.2", "@trivago/prettier-plugin-sort-imports": "^6.0.2",
"prettier": "^3.9.8" "prettier": "^3.9.9"
}, },
"packageManager": "pnpm@12.6.0" "packageManager": "pnpm@12.6.0"
} }
+8 -8
View File
@@ -175,10 +175,10 @@ importers:
devDependencies: devDependencies:
'@trivago/prettier-plugin-sort-imports': '@trivago/prettier-plugin-sort-imports':
specifier: ^6.0.2 specifier: ^6.0.2
version: 6.0.2(prettier@3.9.8) version: 6.0.2(prettier@3.9.9)
prettier: prettier:
specifier: ^3.9.8 specifier: ^3.9.9
version: 3.9.8 version: 3.9.9
packages: packages:
@@ -303,8 +303,8 @@ packages:
picocolors@1.1.1: picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
prettier@3.9.8: prettier@3.9.9:
resolution: {integrity: sha512-WRFq3Wn3WId7LLROfMLdH7xaFr2jR62wU8nLO6rQUOLOxNZUviyJQs1M0iIhLexSFy+L+w0ch66wtoO2jRjG0A==} resolution: {integrity: sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg==}
engines: {node: '>=14'} engines: {node: '>=14'}
hasBin: true hasBin: true
@@ -373,7 +373,7 @@ snapshots:
'@msgpack/msgpack@3.1.3': {} '@msgpack/msgpack@3.1.3': {}
'@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.9.8)': '@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.9.9)':
dependencies: dependencies:
'@babel/generator': 7.29.8 '@babel/generator': 7.29.8
'@babel/parser': 7.29.9 '@babel/parser': 7.29.9
@@ -383,7 +383,7 @@ snapshots:
lodash-es: 4.18.1 lodash-es: 4.18.1
minimatch: 9.0.9 minimatch: 9.0.9
parse-imports-exports: 0.2.4 parse-imports-exports: 0.2.4
prettier: 3.9.8 prettier: 3.9.9
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -421,4 +421,4 @@ snapshots:
picocolors@1.1.1: {} picocolors@1.1.1: {}
prettier@3.9.8: {} prettier@3.9.9: {}
+3
View File
@@ -61,6 +61,7 @@ board_build.partitions = partitions/esp32_partition_4M.csv
board_upload.flash_size = 4MB board_upload.flash_size = 4MB
board_build.app_partition_name = app0 board_build.app_partition_name = app0
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.05.50/platform-espressif32.zip ; Tasmota Arduino Core 3.3.8 based on IDF 5.5.4.260407 platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.05.50/platform-espressif32.zip ; Tasmota Arduino Core 3.3.8 based on IDF 5.5.4.260407
; platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.09.50/platform-espressif32.zip ; Tasmota Arduino Core 3.3.12 based on IDF 5.5.5
; 16MB Flash variants ; 16MB Flash variants
[espressif32_base_16M] [espressif32_base_16M]
@@ -69,6 +70,7 @@ board_build.partitions = partitions/esp32_partition_16M.csv
board_upload.flash_size = 16MB board_upload.flash_size = 16MB
board_build.app_partition_name = app0 board_build.app_partition_name = app0
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.05.50/platform-espressif32.zip ; Tasmota Arduino Core 3.3.8 based on IDF 5.5.4.260407 platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.05.50/platform-espressif32.zip ; Tasmota Arduino Core 3.3.8 based on IDF 5.5.4.260407
; platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.09.50/platform-espressif32.zip ; Tasmota Arduino Core 3.3.12 based on IDF 5.5.5
; 32MB Flash variants ; 32MB Flash variants
[espressif32_base_32M] [espressif32_base_32M]
@@ -77,6 +79,7 @@ board_build.partitions = partitions/esp32_partition_32M.csv
board_upload.flash_size = 32MB board_upload.flash_size = 32MB
board_build.app_partition_name = app0 board_build.app_partition_name = app0
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.05.50/platform-espressif32.zip ; Tasmota Arduino Core 3.3.8 based on IDF 5.5.4.260407 platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.05.50/platform-espressif32.zip ; Tasmota Arduino Core 3.3.8 based on IDF 5.5.4.260407
; platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.09.50/platform-espressif32.zip ; Tasmota Arduino Core 3.3.12 based on IDF 5.5.5
[env] [env]
build_flags = build_flags =
+1 -1
View File
@@ -786,7 +786,6 @@ negcond
negheat negheat
nein nein
nennvolumentstrom nennvolumentstrom
neopixel
netcmp netcmp
netflowtemp netflowtemp
netif netif
@@ -1352,3 +1351,4 @@ zyxwvutsrqponmlkjihgfedcba
öffnen öffnen
česky česky
živanović živanović
neopixel
+1 -1
View File
@@ -71,7 +71,7 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
_is_filesystem = true; _is_filesystem = true;
_md5[0] = '\0'; // clear any stale md5 so Update.end() doesn't compare against it _md5[0] = '\0'; // clear any stale md5 so Update.end() doesn't compare against it
_md5_applied = false; _md5_applied = false;
} else if ((extension == "bin") && (filesize > 1000000)) { } else if ((extension == "bin") && (filesize >= emsesp::System::MIN_FIRMWARE_SIZE)) {
_is_firmware = true; _is_firmware = true;
} else if (extension == "json") { } else if (extension == "json") {
_md5[0] = '\0'; // clear md5 _md5[0] = '\0'; // clear md5
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+11 -13
View File
@@ -144,8 +144,8 @@ void AnalogSensor::reload(bool get_nvs) {
// load the list of analog sensors from the customization service // load the list of analog sensors from the customization service
// and store them locally and then activate them // and store them locally and then activate them
EMSESP::webCustomizationService.read([&](WebCustomization & settings) { EMSESP::webCustomizationService.read([&](WebCustomization & settings) {
auto it = sensors_.begin(); for (auto it = sensors_.begin(); it != sensors_.end();) {
for (auto & sensor_ : sensors_) { auto & sensor_ = *it;
// update existing sensors // update existing sensors
bool found = false; bool found = false;
for (const auto & sensor : settings.analogCustomizations) { // search customlist for (const auto & sensor : settings.analogCustomizations) { // search customlist
@@ -170,9 +170,10 @@ void AnalogSensor::reload(bool get_nvs) {
} }
} }
if (!found) { if (!found) {
sensors_.erase(it); it = sensors_.erase(it);
} else {
++it;
} }
it++;
} }
// add new sensors from list // add new sensors from list
@@ -307,7 +308,7 @@ void AnalogSensor::reload(bool get_nvs) {
uint8_t r = v / 10000; uint8_t r = v / 10000;
uint8_t g = (v - r * 10000) / 100; uint8_t g = (v - r * 10000) / 100;
uint8_t b = v % 100; uint8_t b = v % 100;
rgbLedWrite(sensor.gpio(), 2 * r, 2 * g, 2 * b); rgb_led::write(sensor.gpio(), 2 * r, 2 * g, 2 * b);
LOG_DEBUG("RGB set to %d, %d, %d", r, g, b); LOG_DEBUG("RGB set to %d, %d, %d", r, g, b);
} else if (sensor.type() == AnalogType::DIGITAL_OUT) { } else if (sensor.type() == AnalogType::DIGITAL_OUT) {
LOG_DEBUG("Digital Write on GPIO %02d", sensor.gpio()); LOG_DEBUG("Digital Write on GPIO %02d", sensor.gpio());
@@ -405,8 +406,9 @@ void AnalogSensor::measure() {
sensor.sum_ = (sensor.sum_ * 15 + a * 16) / 16; sensor.sum_ = (sensor.sum_ * 15 + a * 16) / 16;
sensor.analog_ = sensor.sum_ / 16; sensor.analog_ = sensor.sum_ / 16;
} }
if (sensor.analog_ > 0 && sensor.analog_ < 3300 && (sensor.last_reading_ + 1 < sensor.analog_ || sensor.last_reading_ > sensor.analog_ + 1)) { if (sensor.analog_ > 0 && sensor.analog_ < NTC_VREF_MV
sensor.set_value(sensor.offset() + 1 / (1 / T25 + log((double)sensor.analog_ / (3300 - sensor.analog_) * (Rt / R0)) / Beta) && (sensor.last_reading_ + 1 < sensor.analog_ || sensor.last_reading_ > sensor.analog_ + 1)) {
sensor.set_value(sensor.offset() + 1 / (1 / T25 + log((double)sensor.analog_ / (NTC_VREF_MV - sensor.analog_) * (Rt / R0)) / Beta)
- T0); // Temperature in Celsius - T0); // Temperature in Celsius
sensor.last_reading_ = sensor.analog_; sensor.last_reading_ = sensor.analog_;
sensorreads_++; sensorreads_++;
@@ -424,7 +426,7 @@ void AnalogSensor::measure() {
edgecnt[index] = 0; edgecnt[index] = 0;
portEXIT_CRITICAL_ISR(&mux); portEXIT_CRITICAL_ISR(&mux);
sensor.set_value(sensor.factor() * 1000000.0 / t); sensor.set_value(sensor.factor() * 1000000.0 / t);
} else if (micros() - edge[index] > 10000000ul && sensor.value() > 0) { } else if (micros() - edge[index] > FREQ_ZERO_TIMEOUT_US && sensor.value() > 0) {
sensor.set_value(0); sensor.set_value(0);
} }
if (sensor.value() != oldval) { if (sensor.value() != oldval) {
@@ -533,11 +535,7 @@ bool AnalogSensor::update(uint8_t gpio, const char * org_name, double offset, do
bool found_sensor = false; bool found_sensor = false;
EMSESP::webCustomizationService.update([&](WebCustomization & settings) { EMSESP::webCustomizationService.update([&](WebCustomization & settings) {
for (auto & AnalogCustomization : settings.analogCustomizations) { for (auto & AnalogCustomization : settings.analogCustomizations) {
if (AnalogCustomization.type == AnalogType::COUNTER
|| (AnalogCustomization.type >= AnalogType::DIGITAL_OUT && AnalogCustomization.type <= AnalogType::PWM_2)
|| AnalogCustomization.type == AnalogType::RGB || AnalogCustomization.type == AnalogType::PULSE) {
Command::erase_command(EMSdevice::DeviceType::ANALOGSENSOR, AnalogCustomization.name); Command::erase_command(EMSdevice::DeviceType::ANALOGSENSOR, AnalogCustomization.name);
}
if (AnalogCustomization.gpio == gpio) { if (AnalogCustomization.gpio == gpio) {
found_sensor = true; // found the record found_sensor = true; // found the record
// see if it's marked for deletion // see if it's marked for deletion
@@ -999,7 +997,7 @@ bool AnalogSensor::command_setvalue(const char * value, const int8_t gpio) {
uint8_t r = v / 10000; uint8_t r = v / 10000;
uint8_t g = (v - r * 10000) / 100; uint8_t g = (v - r * 10000) / 100;
uint8_t b = v % 100; uint8_t b = v % 100;
rgbLedWrite(sensor.gpio(), 2 * r, 2 * g, 2 * b); rgb_led::write(sensor.gpio(), 2 * r, 2 * g, 2 * b);
LOG_DEBUG("RGB set to %d, %d, %d", r, g, b); LOG_DEBUG("RGB set to %d, %d, %d", r, g, b);
} else if (sensor.type() == AnalogType::PULSE) { } else if (sensor.type() == AnalogType::PULSE) {
uint8_t v = val; uint8_t v = val;
+3 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -189,8 +189,10 @@ class AnalogSensor {
static constexpr double T25 = 298.15; static constexpr double T25 = 298.15;
static constexpr double R0 = 100000; static constexpr double R0 = 100000;
static constexpr double Rt = 60000; static constexpr double Rt = 60000;
static constexpr uint32_t NTC_VREF_MV = 3300; // NTC voltage divider supply (in mV) - 3.3 V
static constexpr uint8_t MAX_SENSORS = 20; static constexpr uint8_t MAX_SENSORS = 20;
static constexpr uint32_t MEASURE_ANALOG_INTERVAL = 500; static constexpr uint32_t MEASURE_ANALOG_INTERVAL = 500;
static constexpr uint32_t FREQ_ZERO_TIMEOUT_US = 10000000; // report 0 Hz if no edge arrives for this long (in us) - 10 seconds
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void remove_ha_topic(const int8_t type, const uint8_t id) const; void remove_ha_topic(const int8_t type, const uint8_t id) const;
+5 -11
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -542,16 +542,10 @@ Command::CmdFunction * Command::find_command(const uint8_t device_type, const ui
} }
void Command::erase_device_commands(const uint8_t device_type) { void Command::erase_device_commands(const uint8_t device_type) {
if (cmdfunctions_.empty()) { cmdfunctions_.erase(std::remove_if(cmdfunctions_.begin(),
return; cmdfunctions_.end(),
} [device_type](const CmdFunction & cf) { return cf.device_type_ == device_type; }),
auto it = cmdfunctions_.end(); cmdfunctions_.end());
do {
int i = it - cmdfunctions_.begin();
if (cmdfunctions_[i].device_type_ == device_type) {
cmdfunctions_.erase(it);
}
} while (it-- > cmdfunctions_.begin());
} }
void Command::erase_command(const uint8_t device_type, const char * cmd, uint8_t flag) { void Command::erase_command(const uint8_t device_type, const char * cmd, uint8_t flag) {
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+3 -3
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -2281,8 +2281,8 @@ bool EMSdevice::handle_telegram(const std::shared_ptr<const Telegram> & telegram
EMSESP::logger().debug("This telegram (%s) is not recognized by the EMS bus", tf.telegram_type_name_); EMSESP::logger().debug("This telegram (%s) is not recognized by the EMS bus", tf.telegram_type_name_);
#endif #endif
// removing fetch after start causes issue: https://github.com/emsesp/EMS-ESP32/issues/1420 // removing fetch after start causes issue: https://github.com/emsesp/EMS-ESP32/issues/1420
// continue retry the first 5 minutes, then disable (added 15.3.2024) // continue retrying for a while after boot, then disable (added 15.3.2024)
if (uuid::get_uptime_sec() > 600) { if (uuid::get_uptime_sec() > FETCH_RETRY_DURATION_SEC) {
tf.fetch_ = false; tf.fetch_ = false;
} }
return false; return false;
+4 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -441,6 +441,9 @@ class EMSdevice {
static constexpr uint8_t EMS_DEVICES_MAX_TELEGRAMS = 20; static constexpr uint8_t EMS_DEVICES_MAX_TELEGRAMS = 20;
// keep fetching telegrams the bus master doesn't recognise for this long after boot, then give up (in seconds) - 10 minutes
static constexpr uint32_t FETCH_RETRY_DURATION_SEC = 600;
// static device IDs // static device IDs
static constexpr uint8_t EMS_DEVICE_ID_BOILER = 0x08; // fixed device_id for Master Boiler/UBA static constexpr uint8_t EMS_DEVICE_ID_BOILER = 0x08; // fixed device_id for Master Boiler/UBA
static constexpr uint8_t EMS_DEVICE_ID_HS1 = 0x70; // fixed device_id for 1st. Cascade Boiler/UBA static constexpr uint8_t EMS_DEVICE_ID_HS1 = 0x70; // fixed device_id for 1st. Cascade Boiler/UBA
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+15 -12
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -1210,7 +1210,9 @@ bool EMSESP::process_telegram(const std::shared_ptr<const Telegram> & telegram)
// check all conditions in one loop // check all conditions in one loop
for (const auto & emsdevice : emsdevices) { for (const auto & emsdevice : emsdevices) {
if ((emsdevice->is_device_id(telegram->src) && (telegram->dest == 0 || telegram->dest == EMSbus::ems_bus_id() || telegram->dest == 0x10)) if ((emsdevice->is_device_id(telegram->src) && (telegram->dest == 0 || telegram->dest == EMSbus::ems_bus_id() || telegram->dest == 0x10))
|| (emsdevice->is_device_id(telegram->dest) && telegram->src != EMSbus::ems_bus_id())) { || (emsdevice->is_device_id(telegram->dest) && telegram->src != EMSbus::ems_bus_id())
// the MP100 sends its full status only to the heatpump
|| (emsdevice->device_type() == EMSdevice::DeviceType::POOL && emsdevice->is_device_id(telegram->src))) {
found_device = emsdevice.get(); found_device = emsdevice.get();
if (emsdevice->handle_telegram(telegram)) { if (emsdevice->handle_telegram(telegram)) {
telegram_found = true; telegram_found = true;
@@ -1774,6 +1776,15 @@ void EMSESP::start() {
// 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(); webLogService.begin();
#ifndef EMSESP_STANDALONE
// apply any uploaded settings before any service loads them from the filesystem
if (system_.check_restore()) {
root = LittleFS.open(EMSESP_SETTINGS_FILE);
factory_settings = !root;
root.close();
}
#endif
// loads core system services settings (mqtt, ap, ntp etc) // loads core system services settings (mqtt, ap, ntp etc)
esp32React.begin(); esp32React.begin();
@@ -1829,14 +1840,6 @@ void EMSESP::start() {
LOG_INFO("Last system reset reason Core0: %s, Core1: %s", system_.reset_reason(0).c_str(), system_.reset_reason(1).c_str()); LOG_INFO("Last system reset reason Core0: %s, Core1: %s", system_.reset_reason(0).c_str(), system_.reset_reason(1).c_str());
#endif #endif
// see if we're restoring a settings file
#ifndef EMSESP_STANDALONE
if (system_.check_restore()) {
LOG_WARNING("EMS-ESP will restart to apply new settings. Please wait.");
system_.system_restart();
};
#endif
webSettingsService.begin(); // load EMS-ESP Application settings webSettingsService.begin(); // load EMS-ESP Application settings
LOG_DEBUG("System name: %s", system_.system_name().c_str()); LOG_DEBUG("System name: %s", system_.system_name().c_str());
@@ -1978,12 +1981,12 @@ void EMSESP::loop() {
} }
} }
// reset status after 5 Minutes // reset status after a timeout
if (EMSESP::system_.systemStatus() != SYSTEM_STATUS::SYSTEM_STATUS_NORMAL) { if (EMSESP::system_.systemStatus() != SYSTEM_STATUS::SYSTEM_STATUS_NORMAL) {
static uint32_t starttime = 0; static uint32_t starttime = 0;
if (starttime == 0) { if (starttime == 0) {
starttime = uuid::get_uptime_ms(); starttime = uuid::get_uptime_ms();
} else if (uuid::get_uptime_ms() - starttime > 300000) { } else if (uuid::get_uptime_ms() - starttime > SYSTEM_STATUS_RESET_TIMEOUT) {
starttime = 0; starttime = 0;
EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_NORMAL); EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_NORMAL);
} }
+3 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -291,6 +291,8 @@ class EMSESP {
static constexpr uint32_t EMS_FETCH_FREQUENCY = 60000; // check every minute static constexpr uint32_t EMS_FETCH_FREQUENCY = 60000; // check every minute
static constexpr uint8_t EMS_WAIT_KM_TIMEOUT = 60; // wait one minute static constexpr uint8_t EMS_WAIT_KM_TIMEOUT = 60; // wait one minute
static constexpr uint32_t SYSTEM_STATUS_RESET_TIMEOUT = 300000; // return a non-normal system status to normal after this (in ms) - 5 minutes
struct Device_record { struct Device_record {
uint8_t product_id; uint8_t product_id;
EMSdevice::DeviceType device_type; EMSdevice::DeviceType device_type;
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+3 -3
View File
@@ -66,13 +66,13 @@ int HttpClient::request(std::string url, const std::string & method, const std::
ssl_client->setInsecure(); ssl_client->setInsecure();
// Notes: with root CA we should set here: ssl_client->setCACert(rootCACert); // Notes: with root CA we should set here: ssl_client->setCACert(rootCACert);
// 1 KB RX buffer is fine for small JSON-style endpoints used by the scheduler/shunting-yard but it is NOT enough for servers that send full-size TLS records (>1 KB) // 1 KB RX buffer is fine for small JSON-style endpoints used by the scheduler/shunting-yard but it is NOT enough for servers that send full-size TLS records (>1 KB)
ssl_client->setBufferSizes(16384, 1024); ssl_client->setBufferSizes(TLS_RX_BUFFER_SIZE, TLS_TX_BUFFER_SIZE);
ssl_client->setSessionTimeout(120); // Set the timeout in seconds (>=120 seconds) ssl_client->setSessionTimeout(TLS_SESSION_TIMEOUT_S);
} }
// WiFiClient is NetworkClient, which declares no setTimeout() of its own - calling it binds to // WiFiClient is NetworkClient, which declares no setTimeout() of its own - calling it binds to
// Stream::setTimeout() and only affects readBytes(), leaving the socket on the core's 3s default // Stream::setTimeout() and only affects readBytes(), leaving the socket on the core's 3s default
basic_client->setConnectionTimeout(CONNECT_TIMEOUT_MS); basic_client->setConnectionTimeout(CONNECT_TIMEOUT_MS);
ssl_client->setTimeout(5); // seconds, drives BearSSL only - unused on the plain HTTP path ssl_client->setTimeout(TLS_READ_TIMEOUT_S); // drives BearSSL only - unused on the plain HTTP path
ssl_client->setClient(basic_client, is_https); // enableSSL = false for plain HTTP ssl_client->setClient(basic_client, is_https); // enableSSL = false for plain HTTP
const uint16_t port = is_https ? 443 : 80; const uint16_t port = is_https ? 443 : 80;
+8
View File
@@ -29,6 +29,14 @@ class HttpClient {
public: public:
static int request(std::string url, const std::string & method, const std::string & value, JsonObjectConst headers, std::string & result); static int request(std::string url, const std::string & method, const std::string & value, JsonObjectConst headers, std::string & result);
// ESP_SSLClient (BearSSL) settings, shared by every TLS client in the project.
// The RX buffer must hold one full TLS record: servers such as GitHub's CDN send up-to-16 KB
// records and don't negotiate max_fragment_length, so a smaller buffer can't decode the body
static constexpr size_t TLS_RX_BUFFER_SIZE = 16384;
static constexpr size_t TLS_TX_BUFFER_SIZE = 1024;
static constexpr uint32_t TLS_SESSION_TIMEOUT_S = 120; // in seconds, the library minimum
static constexpr uint32_t TLS_READ_TIMEOUT_S = 5; // in seconds, not ms like the socket timeouts
private: private:
static constexpr uint32_t CONNECT_TIMEOUT_MS = 5000; // TCP connect, the core defaults to 3s static constexpr uint32_t CONNECT_TIMEOUT_MS = 5000; // TCP connect, the core defaults to 3s
static constexpr uint32_t FIRST_BYTE_TIMEOUT_MS = 8000; // how long the server may take to start replying static constexpr uint32_t FIRST_BYTE_TIMEOUT_MS = 8000; // how long the server may take to start replying
+152 -70
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -19,19 +19,139 @@
#include "led.h" #include "led.h"
#include "emsesp.h" #include "emsesp.h"
#ifndef EMSESP_STANDALONE
#include <esp32-hal-rmt.h>
#endif
namespace emsesp { namespace emsesp {
namespace rgb_led {
#ifndef EMSESP_STANDALONE
namespace {
// durations in 100 ns ticks
constexpr uint16_t T0H = 3; // 300 ns
constexpr uint16_t T0L = 9; // 900 ns
constexpr uint16_t T1H = 8; // 800 ns
constexpr uint16_t T1L = 6; // 600 ns
// rmt_data_t.val layout: duration0:15, level0:1, duration1:15, level1:1 (high then low)
constexpr uint32_t SYMBOL_0 = T0H | (1UL << 15) | (static_cast<uint32_t>(T0L) << 16);
constexpr uint32_t SYMBOL_1 = T1H | (1UL << 15) | (static_cast<uint32_t>(T1L) << 16);
constexpr uint32_t RMT_FREQ_HZ = 10000000; // 10 MHz
constexpr uint32_t RESET_US = 300;
constexpr uint8_t NO_PIN = 0xFF;
constexpr uint8_t MAX_PINS = 2; // status LED + an RGB analog sensor; the ESP32-C3 only has 2 RMT TX channels
struct Channel {
uint8_t pin = NO_PIN;
uint32_t last_tx_us = 0;
};
Channel channels[MAX_PINS];
Channel * init(uint8_t pin) {
Channel * free_slot = nullptr;
for (auto & ch : channels) {
if (ch.pin == pin) {
return &ch;
}
if (!free_slot && ch.pin == NO_PIN) {
free_slot = &ch;
}
}
if (!free_slot) {
// all slots in use: release the least recently written one
const uint32_t now = micros();
free_slot = &channels[0];
for (auto & ch : channels) {
if (now - ch.last_tx_us > now - free_slot->last_tx_us) {
free_slot = &ch;
}
}
end(free_slot->pin);
}
if (!rmtInit(pin, RMT_TX_MODE, RMT_MEM_NUM_BLOCKS_1, RMT_FREQ_HZ)) {
return nullptr;
}
free_slot->pin = pin;
free_slot->last_tx_us = micros() - RESET_US; // no wait on first write
return free_slot;
}
} // namespace
bool write(uint8_t pin, uint8_t red, uint8_t green, uint8_t blue, Order order) {
Channel * ch = init(pin);
if (!ch) {
return false;
}
// enforce the latch/reset gap since the previous frame (V6 needs > 280 us)
const uint32_t elapsed = micros() - ch->last_tx_us;
if (elapsed < RESET_US) {
delayMicroseconds(RESET_US - elapsed);
}
const uint8_t bytes[3] = {order == Order::GRB ? green : red, order == Order::GRB ? red : green, blue};
rmt_data_t frame[24];
for (uint8_t i = 0; i < 24; i++) {
frame[i].val = (bytes[i >> 3] & (0x80 >> (i & 7))) ? SYMBOL_1 : SYMBOL_0;
}
const bool ok = rmtWrite(pin, frame, 24, RMT_WAIT_FOR_EVER);
ch->last_tx_us = micros();
return ok;
}
void end(uint8_t pin) {
for (auto & ch : channels) {
if (ch.pin == pin && pin != NO_PIN) {
rmtDeinit(pin);
ch.pin = NO_PIN;
}
}
}
#else
bool write(uint8_t, uint8_t, uint8_t, uint8_t, Order) {
return true;
}
void end(uint8_t) {
}
#endif
} // namespace rgb_led
uuid::log::Logger LED::logger_{F_(led), uuid::log::Facility::KERN}; uuid::log::Logger LED::logger_{F_(led), uuid::log::Facility::KERN};
// initialise the LED, fetching the settings from the WebSettingsService // initialise the LED, fetching the settings from the WebSettingsService
// set the LED to on or off when in normal operating mode // set the LED to on or off when in normal operating mode
void LED::init() { void LED::init() {
// settings may have changed: turn off and release the previous pin
if (led_gpio_) {
set_led(Color::OFF);
if (led_type_) {
rgb_led::end(led_gpio_);
}
}
// copy the application settings // copy the application settings
EMSESP::webSettingsService.read([&](WebSettings & settings) { EMSESP::webSettingsService.read([&](WebSettings & settings) {
led_gpio_ = settings.led_gpio; led_gpio_ = settings.led_gpio;
led_type_ = settings.led_type; led_type_ = settings.led_type;
hide_led_ = settings.hide_led; hide_led_ = settings.hide_led;
}); });
last_color_ = COLOR_UNSET;
if (!led_gpio_) { // 0 means disabled if (!led_gpio_) { // 0 means disabled
LOG_INFO("LED disabled"); LOG_INFO("LED disabled");
@@ -74,10 +194,6 @@ bool LED::loop(uint8_t healthcheck, bool button_busy) {
// check the system health. // check the system health.
// Set the sequence accordingly, only if the healthcheck is not 0 and has changed // Set the sequence accordingly, only if the healthcheck is not 0 and has changed
if (healthcheck != previous_healthcheck_) { if (healthcheck != previous_healthcheck_) {
color_steps_[0] = Color::OFF;
color_steps_[1] = Color::OFF;
color_steps_[2] = Color::OFF;
// if the healthcheck is 0, i.e. system is healthy, reset the LED // if the healthcheck is 0, i.e. system is healthy, reset the LED
if (healthcheck == 0) { if (healthcheck == 0) {
reset_led(); reset_led();
@@ -85,25 +201,12 @@ bool LED::loop(uint8_t healthcheck, bool button_busy) {
// 1 flash (blue) is the EMS bus is not connected // 1 flash (blue) is the EMS bus is not connected
// 2 flashes (red, red) if the network (wifi or ethernet) is not connected // 2 flashes (red, red) if the network (wifi or ethernet) is not connected
// 3 flashes (red, red, blue) is both the bus and the network are not connected // 3 flashes (red, red, blue) is both the bus and the network are not connected
bool no_network = (healthcheck & System::HEALTHCHECK_NO_NETWORK) == System::HEALTHCHECK_NO_NETWORK; const bool no_network = (healthcheck & System::HEALTHCHECK_NO_NETWORK) == System::HEALTHCHECK_NO_NETWORK;
bool no_bus = (healthcheck & System::HEALTHCHECK_NO_BUS) == System::HEALTHCHECK_NO_BUS; const bool no_bus = (healthcheck & System::HEALTHCHECK_NO_BUS) == System::HEALTHCHECK_NO_BUS;
// set step 1 color_steps_[0] = no_network ? Color::RED : (no_bus ? Color::BLUE : Color::OFF);
if (no_network) { color_steps_[1] = no_network ? Color::RED : Color::OFF;
color_steps_[0] = Color::RED; // red, no network color_steps_[2] = (no_network && no_bus) ? Color::BLUE : Color::OFF;
} else if (no_bus) {
color_steps_[0] = Color::BLUE; // blue, no bus
}
// set step 2
if (no_network) {
color_steps_[1] = Color::RED; // red, no network
}
// set step 3
if (no_network && no_bus) {
color_steps_[2] = Color::BLUE; // blue, no network and no bus
}
} }
previous_healthcheck_ = healthcheck; // must be set after reset_led(), which invalidates it previous_healthcheck_ = healthcheck; // must be set after reset_led(), which invalidates it
@@ -126,9 +229,7 @@ bool LED::loop(uint8_t healthcheck, bool button_busy) {
void LED::reset_led() { void LED::reset_led() {
is_user_led_blink_ = false; is_user_led_blink_ = false;
set_led(hide_led_ ? Color::OFF : Color::GREEN); // Green set_led(hide_led_ ? Color::OFF : Color::GREEN); // Green
color_steps_[0] = Color::OFF; color_steps_[0] = color_steps_[1] = color_steps_[2] = Color::OFF;
color_steps_[1] = Color::OFF;
color_steps_[2] = Color::OFF;
// invalidate the last health state so the sequence is rebuilt on the next check, // invalidate the last health state so the sequence is rebuilt on the next check,
// needed because the color steps above have been cleared // needed because the color steps above have been cleared
@@ -163,9 +264,10 @@ void LED::led_fast_flash() {
// set LED on/off or RGB color // set LED on/off or RGB color
// ignores whether the LED is hidden or not (if hide_led_ is set) // ignores whether the LED is hidden or not (if hide_led_ is set)
void LED::set_led(Color color) { void LED::set_led(Color color) {
if (!led_gpio_) { if (!led_gpio_ || color == last_color_) {
return; return;
} }
last_color_ = color;
// RGB lookup table indexed by Color enum (must match enum order in led.h) // RGB lookup table indexed by Color enum (must match enum order in led.h)
static constexpr uint8_t B = RGB_LED_BRIGHTNESS; static constexpr uint8_t B = RGB_LED_BRIGHTNESS;
@@ -181,28 +283,26 @@ void LED::set_led(Color color) {
{0, B, B}, // CYAN {0, B, B}, // CYAN
{H, 0, H} // PINK {H, 0, H} // PINK
}; };
static_assert(sizeof(rgb_table) / sizeof(rgb_table[0]) == Color::PINK + 1, "rgb_table must match the Color enum");
const uint8_t color_idx = static_cast<uint8_t>(color); const uint8_t * rgb = rgb_table[color];
const uint8_t idx = (color_idx < sizeof(rgb_table) / sizeof(rgb_table[0])) ? color_idx : static_cast<uint8_t>(Color::OFF);
const uint8_t red = rgb_table[idx][0];
const uint8_t green = rgb_table[idx][1];
const uint8_t blue = rgb_table[idx][2];
if (led_type_) { if (led_type_) {
rgbLedWrite(led_gpio_, red, green, blue); rgb_led::write(led_gpio_, rgb[0], rgb[1], rgb[2]);
} else { } else {
digitalWrite(led_gpio_, (red == 0 && green == 0 && blue == 0) || color == Color::OFF ? !LED_ON : LED_ON); digitalWrite(led_gpio_, color == Color::OFF ? !LED_ON : LED_ON);
} }
} }
// set LED custom routine // set LED custom routine
// For example: /api/system/led?data=red:blink1 // For example: /api/system/led?data=red:blink1
// For older non-RGB models, the colour would default to just being on. // For older non-RGB models, the colour would default to just being on.
bool LED::set_custom_led_routine(std::string color, std::string pattern) { bool LED::set_custom_led_routine(const std::string & color, const std::string & pattern) {
static constexpr struct { static constexpr struct {
const char * name; const char * name;
Color value; Color value;
} color_map[] = { } color_map[] = {
{"", Color::OFF},
{"off", Color::OFF}, {"off", Color::OFF},
{"on", Color::ON}, {"on", Color::ON},
{"white", Color::ON}, {"white", Color::ON},
@@ -228,35 +328,33 @@ bool LED::set_custom_led_routine(std::string color, std::string pattern) {
return false; return false;
} }
// reset the color steps // build the steps locally so an unrecognized pattern leaves the current sequence untouched
color_steps_[0] = Color::OFF; Color steps[3] = {Color::OFF, Color::OFF, Color::OFF};
color_steps_[1] = Color::OFF;
color_steps_[2] = Color::OFF;
// blink patterns // blink patterns
if (pattern == "blink1") { if (pattern == "blink1") {
color_steps_[0] = color_type; steps[0] = color_type;
} else if (pattern == "blink2") { } else if (pattern == "blink2") {
color_steps_[0] = color_type; steps[0] = steps[1] = color_type;
color_steps_[1] = color_type;
} else if (pattern == "blink3") { } else if (pattern == "blink3") {
color_steps_[0] = color_type; steps[0] = steps[1] = steps[2] = color_type;
color_steps_[1] = color_type;
color_steps_[2] = color_type;
// special patterns, ignores the user color // special patterns, ignores the user color
} else if (pattern == "rgb") { } else if (pattern == "rgb") {
color_steps_[0] = Color::RED; steps[0] = Color::RED;
color_steps_[1] = Color::GREEN; steps[1] = Color::GREEN;
color_steps_[2] = Color::BLUE; steps[2] = Color::BLUE;
} else if (pattern == "cpc") { } else if (pattern == "cpc") {
color_steps_[0] = Color::CYAN; steps[0] = Color::CYAN;
color_steps_[1] = Color::PINK; steps[1] = Color::PINK;
color_steps_[2] = Color::CYAN; steps[2] = Color::CYAN;
} else { } else {
return false; // pattern not recognized return false; // pattern not recognized
} }
color_steps_[0] = steps[0];
color_steps_[1] = steps[1];
color_steps_[2] = steps[2];
is_user_led_blink_ = true; // user routine is active is_user_led_blink_ = true; // user routine is active
// when this is called we want the sequence_led to restart immediately and skip the long pause // when this is called we want the sequence_led to restart immediately and skip the long pause
@@ -286,7 +384,7 @@ void LED::sequence_led() {
if (++led_flash_step_ == 8) { if (++led_flash_step_ == 8) {
// finished first iteration, reset the whole sequence, turn off LED // finished first iteration, reset the whole sequence, turn off LED
led_long_timer_ = uuid::get_uptime(); led_long_timer_ = current_time;
led_flash_step_ = 0; led_flash_step_ = 0;
set_led(Color::OFF); // turn off the LED set_led(Color::OFF); // turn off the LED
@@ -298,24 +396,8 @@ void LED::sequence_led() {
return; return;
} }
if (led_flash_step_ % 2) { // odd steps 3, 5 and 7 show the three configured colors, even steps turn the LED off to make it flash
// handle the three step events (on odd numbers 3,5,7 etc). see if we need to set a LED color set_led(led_flash_step_ % 2 ? color_steps_[(led_flash_step_ - 3) / 2] : Color::OFF);
switch (led_flash_step_) {
case 3: // first flash
set_led(color_steps_[0]);
break;
case 5: // second flash
set_led(color_steps_[1]);
break;
case 7: // third flash
set_led(color_steps_[2]);
break;
default:
break;
}
} else {
set_led(Color::OFF); // turn off on even number count, to make it flash
}
} }
} }
+37 -11
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -24,6 +24,29 @@
namespace emsesp { namespace emsesp {
// WS2812B driver replacing arduino-esp32's rgbLedWrite()/neopixelWrite(), which hard-code
// T0H = 400 ns, T1L = 400 ns and have no reset gap. The WS2812B-2020-V6 needs T0H 220-380 ns,
// T1L 580-1000 ns and a reset > 280 us, otherwise it misreads 0-bits as 1-bits (washed-out white).
// Timings used (10 MHz RMT clock, 1 tick = 100 ns) fit both the original WS2812B and the V6:
//
// sent old WS2812B WS2812B-2020-V6
// T0H 300 ns 250-550 ns 220-380 ns
// T0L 900 ns 700-1000 ns 580-1000 ns
// T1H 800 ns 650-950 ns 580-1000 ns
// T1L 600 ns 300-600 ns 580-1000 ns
// Reset >300 us >50 us >280 us
//
// Do not mix with rgbLedWrite()/neopixelWrite() on the same pin, as both claim the pin's RMT channel.
namespace rgb_led {
enum class Order : uint8_t { GRB, RGB }; // WS2812B is GRB
// Blocks ~30 us for the transmit, plus up to the reset gap if called again right after the previous update
bool write(uint8_t pin, uint8_t red, uint8_t green, uint8_t blue, Order order = Order::GRB);
void end(uint8_t pin); // release the pin's RMT channel, e.g. before reusing the pin for something else
} // namespace rgb_led
class LED { class LED {
public: public:
enum Color : uint8_t { enum Color : uint8_t {
@@ -42,7 +65,7 @@ class LED {
bool loop(uint8_t healthcheck, bool button_busy); bool loop(uint8_t healthcheck, bool button_busy);
void start_led_fast_flash(uint8_t duration); // duration in seconds void start_led_fast_flash(uint8_t duration); // duration in seconds
bool set_custom_led_routine(std::string color, std::string pattern); bool set_custom_led_routine(const std::string & color, const std::string & pattern);
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
@@ -59,6 +82,16 @@ class LED {
static constexpr uint32_t LED_FLASH_INTERVAL_MS = 100; // LED toggle period during factory-reset flash static constexpr uint32_t LED_FLASH_INTERVAL_MS = 100; // LED toggle period during factory-reset flash
static constexpr uint8_t RGB_LED_BRIGHTNESS = 20; // 255 is max brightness static constexpr uint8_t RGB_LED_BRIGHTNESS = 20; // 255 is max brightness
static constexpr uint8_t LED_ON = HIGH; // LED on static constexpr uint8_t LED_ON = HIGH; // LED on
static constexpr Color COLOR_UNSET = static_cast<Color>(0xFF); // forces the next set_led() to write
// led_fast_flash() state
uint32_t led_flash_start_time_ = 0;
uint32_t led_flash_duration_ = 0;
uint32_t last_toggle_time_ = 0;
// sequence_led() state
uint32_t led_long_timer_ = 1; // 1 will kick it off immediately
uint32_t led_short_timer_ = 0;
// local copies of the application settings // local copies of the application settings
uint8_t led_gpio_ = 0; uint8_t led_gpio_ = 0;
@@ -66,21 +99,14 @@ class LED {
bool hide_led_ = false; bool hide_led_ = false;
bool led_fast_flash_timer_ = false; bool led_fast_flash_timer_ = false;
uint32_t led_flash_start_time_ = 0;
uint32_t led_flash_duration_ = 0;
// led_flash() state
bool led_flash_state_ = false; bool led_flash_state_ = false;
uint32_t last_toggle_time_ = 0;
// sequence_led() state
bool last_button_busy_ = false; bool last_button_busy_ = false;
uint32_t led_long_timer_ = 1; // 1 will kick it off immediately
uint32_t led_short_timer_ = 0;
uint8_t led_flash_step_ = 0; // 0 means we're not in the short flash timer uint8_t led_flash_step_ = 0; // 0 means we're not in the short flash timer
// set_led_routine() state // set_custom_led_routine() and healthcheck state
Color color_steps_[3] = {Color::OFF, Color::OFF, Color::OFF}; Color color_steps_[3] = {Color::OFF, Color::OFF, Color::OFF};
Color last_color_ = COLOR_UNSET; // last color written, to skip redundant writes
// if true, the user has requested a custom LED blink, this always has preference over the button or showing the system health // if true, the user has requested a custom LED blink, this always has preference over the button or showing the system health
bool is_user_led_blink_ = false; bool is_user_led_blink_ = false;
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+19 -10
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -470,7 +470,7 @@ MAKE_TRANSLATION(coolingOn, "coolingon", "cooling on", "Kühlung an", "koelbedri
// MAKE_TRANSLATION(hpHeatingOn, "hpheatingon", "hp heating", "WP Heizen", "WP verwarmingsbedrijf", "VP Uppvärmning", "pompa ciepła, ogrzewanie", "vp oppvarmning", "hp ısınıyor", "riscaldamento pompa calore", "vykurovanie hp", "topení hp") // MAKE_TRANSLATION(hpHeatingOn, "hpheatingon", "hp heating", "WP Heizen", "WP verwarmingsbedrijf", "VP Uppvärmning", "pompa ciepła, ogrzewanie", "vp oppvarmning", "hp ısınıyor", "riscaldamento pompa calore", "vykurovanie hp", "topení hp")
// MAKE_TRANSLATION(hpCoolingOn, "hpcoolingon", "hp cooling", "WP Kühlen", "WP koelbedrijf", "VP Kyla", "pompa ciepła, chłodzenie", "vp kjøling", "hp soğuyor", "raffreddamento pompa calore", "chladenie hp", "chlazení hp") // MAKE_TRANSLATION(hpCoolingOn, "hpcoolingon", "hp cooling", "WP Kühlen", "WP koelbedrijf", "VP Kyla", "pompa ciepła, chłodzenie", "vp kjøling", "hp soğuyor", "raffreddamento pompa calore", "chladenie hp", "chlazení hp")
// MAKE_TRANSLATION(hpWwOn, "hpdhwon", "hp", "WP", "WP", "VP Varmvatten", "pompa ciepła", "vp", "pompe à chaleur", "hp", "pompa calore", "hp", "hp") // MAKE_TRANSLATION(hpWwOn, "hpdhwon", "hp", "WP", "WP", "VP Varmvatten", "pompa ciepła", "vp", "pompe à chaleur", "hp", "pompa calore", "hp", "hp")
// MAKE_TRANSLATION(hpPoolOn, "hppoolon", "hp pool", "WP Pool", "WP zwembadbedrijf", "VP Pool", "pompa ciepła, podgrzewanie basenu", "vp basseng", "tuzlu su pompası hızı", "pompa calore piscina", "hp bazén", "hp bazén") MAKE_TRANSLATION(hpPoolOn, "hppoolon", "hp pool", "WP Pool", "WP zwembadbedrijf", "VP Pool", "pompa ciepła, podgrzewanie basenu", "vp basseng", "tuzlu su pompası hızı", "pompa calore piscina", "hp bazén", "hp bazén")
MAKE_TRANSLATION(hpBrinePumpSpd, "hpbrinepumpspd", "brine pump speed", "Solepumpendrehzahl", "Snelheid pekelpomp", "Hastighet Brine-pump", "wysterowanie pompy glikolu", "hastighet brine-pumpe", "vitesse pompe à saumure", "ısı pompası hızı", "velocità pompa sbrinamento", "rýchlosť čerpadla soľanky", "rychlost čerpadla solanky") MAKE_TRANSLATION(hpBrinePumpSpd, "hpbrinepumpspd", "brine pump speed", "Solepumpendrehzahl", "Snelheid pekelpomp", "Hastighet Brine-pump", "wysterowanie pompy glikolu", "hastighet brine-pumpe", "vitesse pompe à saumure", "ısı pompası hızı", "velocità pompa sbrinamento", "rýchlosť čerpadla soľanky", "rychlost čerpadla solanky")
MAKE_TRANSLATION(hpCompSpd, "hpcompspd", "compressor speed", "Kompressordrehzahl", "Snelheid compressor", "Kompressorhastighet", "wysterowanie sprężarki", "kompressorhastighet", "vitesse du compresseur", "sirkülasyon pompası hızı", "velocità compressore", "rýchlosť kompresora", "rychlost kompresoru") MAKE_TRANSLATION(hpCompSpd, "hpcompspd", "compressor speed", "Kompressordrehzahl", "Snelheid compressor", "Kompressorhastighet", "wysterowanie sprężarki", "kompressorhastighet", "vitesse du compresseur", "sirkülasyon pompası hızı", "velocità compressore", "rýchlosť kompresora", "rychlost kompresoru")
MAKE_TRANSLATION(hpCircSpd, "hpcircspd", "circulation pump speed", "Zirkulationspumpendrehzahl", "Snelheid circulatiepomp", "Hastighet Cirkulationspump", "wysterowanie pompy obiegu grzewczego", "hastighet sirkulationspumpe", "vitesse pompe à circulation", "evaporatör tuzlu su giişi", "velocità pompa circolazione", "otáčky obehového čerpadla", "rychlost oběhového čerpadla") MAKE_TRANSLATION(hpCircSpd, "hpcircspd", "circulation pump speed", "Zirkulationspumpendrehzahl", "Snelheid circulatiepomp", "Hastighet Cirkulationspump", "wysterowanie pompy obiegu grzewczego", "hastighet sirkulationspumpe", "vitesse pompe à circulation", "evaporatör tuzlu su giişi", "velocità pompa circolazione", "otáčky obehového čerpadla", "rychlost oběhového čerpadla")
@@ -484,9 +484,9 @@ MAKE_TRANSLATION(expansionValveVr1, "expvalve", "expansion valve VR1", "Ausdehnu
MAKE_TRANSLATION(hpMaxPower, "hpmaxpower", "compressor max power", "max. Kompressorleistung", "", "Max. Kompressoreffekt", "maksymalna wydajność sprężarki", "", "", "", "", "max výkon kompresora", "maximální výkon kompresoru") MAKE_TRANSLATION(hpMaxPower, "hpmaxpower", "compressor max power", "max. Kompressorleistung", "", "Max. Kompressoreffekt", "maksymalna wydajność sprężarki", "", "", "", "", "max výkon kompresora", "maximální výkon kompresoru")
MAKE_TRANSLATION(pvMaxComp, "pvmaxcomp", "pv compressor max power", "PV max. Kompressorleistung", "", "PV Max. Kompressoreffekt", "maksymalna wydajność sprężarki", "", "", "", "", "pv max výkon kompresora", "maximální výkon PV kompresoru") MAKE_TRANSLATION(pvMaxComp, "pvmaxcomp", "pv compressor max power", "PV max. Kompressorleistung", "", "PV Max. Kompressoreffekt", "maksymalna wydajność sprężarki", "", "", "", "", "pv max výkon kompresora", "maximální výkon PV kompresoru")
MAKE_TRANSLATION(hpPower, "hppower", "compressor power output", "Kompressorleistung", "Compressorvermogen", "Kompressoreffekt", "moc wyjściowa sprężarki", "kompressoreffekt", "puissance de sortie compresseur", "ısı pompası güç çıkışı", "potenza uscita compressore", "výkon kompresora", "výstupní výkon kompresoru") MAKE_TRANSLATION(hpPower, "hppower", "compressor power output", "Kompressorleistung", "Compressorvermogen", "Kompressoreffekt", "moc wyjściowa sprężarki", "kompressoreffekt", "puissance de sortie compresseur", "ısı pompası güç çıkışı", "potenza uscita compressore", "výkon kompresora", "výstupní výkon kompresoru")
MAKE_TRANSLATION(hpTc0, "hptc0", "heat carrier return (TC0)", "Kältemittelrücklauf (TC0)", "Koudemiddel retour (TC0)", "Värmebärare Retur (TC0)", "temperatura nośnika ciepła na powrocie (TC0)", "kjølemiddel retur (TC0)", "retour caloporteur (TC0)", "sıcak su dönüşü (TC0)", "ritorno del refrigerante (TC0)", "návrat nosiča tepla (TC0)", "návrat teplonosné látky (TC0)") MAKE_TRANSLATION(hpTc0, "hptc0", "heat carrier return (TC0)", "Wärmeträgerrücklauf (TC0)", "Koudemiddel retour (TC0)", "Värmebärare Retur (TC0)", "temperatura nośnika ciepła na powrocie (TC0)", "kjølemiddel retur (TC0)", "retour caloporteur (TC0)", "sıcak su dönüşü (TC0)", "ritorno del refrigerante (TC0)", "návrat nosiča tepla (TC0)", "návrat teplonosné látky (TC0)")
MAKE_TRANSLATION(hpTc1, "hptc1", "heat carrier forward (TC1)", "Kältemittelvorlauf (TC1)", "Koudemiddel aanvoer (TC1)", "Värmebärare Framledning (TC1)", "temperatura nośnika ciepła pierwotna (TC1)", "kjølemiddel tur (TC1)", "avance caloporteur (TC1)", "sıcak su çıkışı (TC1)", "flusso di refrigerante (TC1)", "nosič tepla vpred (TC1)", "předání teplonosné látky (TC1)") MAKE_TRANSLATION(hpTc1, "hptc1", "heat carrier forward (TC1)", "Wärmeträgervorlauf (TC1)", "Koudemiddel aanvoer (TC1)", "Värmebärare Framledning (TC1)", "temperatura nośnika ciepła pierwotna (TC1)", "kjølemiddel tur (TC1)", "avance caloporteur (TC1)", "sıcak su çıkışı (TC1)", "flusso di refrigerante (TC1)", "nosič tepla vpred (TC1)", "předání teplonosné látky (TC1)")
MAKE_TRANSLATION(hpTc3, "hptc3", "condenser temperature (TC3)", "Kondensatortemperatur (TC3)", "Condensortemperatuur (TC3)", "Kondensortemperatur (TC3)", "temperatura skraplacza/na wyjściu sprężarki (TC3)", "kondensortemperatur (TC3)", "température condensateur (TC3)", "kondenser sıcaklığı (TC3)", "temperatura condensatore (TC3)", "teplota kondenzátora (TC3)", "teplota kondenzátoru (TC3)") MAKE_TRANSLATION(hpTc3, "hptc3", "condenser temperature (TC3)", "Wärmeträgerausgang (TC3)", "Condensortemperatuur (TC3)", "Kondensortemperatur (TC3)", "temperatura skraplacza/na wyjściu sprężarki (TC3)", "kondensortemperatur (TC3)", "température condensateur (TC3)", "kondenser sıcaklığı (TC3)", "temperatura condensatore (TC3)", "teplota kondenzátora (TC3)", "teplota kondenzátoru (TC3)")
MAKE_TRANSLATION(hpTr1, "hptr1", "compressor temperature (TR1)", "Kompressortemperatur (TR1)", "Compressor temperatuur (TR1)", "Kompressor temp (TR1)", "temperatura sprężarki (TR1)", "kompressor temperatur (TR1)", "température compresseur (TR1)", "ısı pompası sıcaklığı (TR1)", "temperatura compressore (TR1)", "teplota kompresora (TR1)", "teplota kompresoru (TR1)") MAKE_TRANSLATION(hpTr1, "hptr1", "compressor temperature (TR1)", "Kompressortemperatur (TR1)", "Compressor temperatuur (TR1)", "Kompressor temp (TR1)", "temperatura sprężarki (TR1)", "kompressor temperatur (TR1)", "température compresseur (TR1)", "ısı pompası sıcaklığı (TR1)", "temperatura compressore (TR1)", "teplota kompresora (TR1)", "teplota kompresoru (TR1)")
MAKE_TRANSLATION(hpTr3, "hptr3", "refrigerant temperature liquid side (condenser output) (TR3)", "Kältemittel (flüssig) (TR3)", "Temperatuur koudemiddel vloeibare zijde (TR3)", "Köldmedium temperatur (kondensorutlopp) (TR3)", "temperatura skraplacza ogrzew. (TR3)", "kjølemiddeltemperatur på væskesiden (TR3)", "température réfrigérant côté liquide (sortie condensateur) (TR3)", "ısı pompası çıkışı (TR3)", "temperatura refrigerante lato liquido (uscita condensatore) (TR3)", "teplota chladiva na strane kvapaliny (výstup kondenzátora) (TR3)", "teplota chladiva na kapalné straně (výstup kondenzátoru) (TR3)") MAKE_TRANSLATION(hpTr3, "hptr3", "refrigerant temperature liquid side (condenser output) (TR3)", "Kältemittel (flüssig) (TR3)", "Temperatuur koudemiddel vloeibare zijde (TR3)", "Köldmedium temperatur (kondensorutlopp) (TR3)", "temperatura skraplacza ogrzew. (TR3)", "kjølemiddeltemperatur på væskesiden (TR3)", "température réfrigérant côté liquide (sortie condensateur) (TR3)", "ısı pompası çıkışı (TR3)", "temperatura refrigerante lato liquido (uscita condensatore) (TR3)", "teplota chladiva na strane kvapaliny (výstup kondenzátora) (TR3)", "teplota chladiva na kapalné straně (výstup kondenzátoru) (TR3)")
MAKE_TRANSLATION(hpTr4, "hptr4", "evaporator inlet temperature (TR4)", "Verdampfereingang (TR4)", "Verdamper ingangstemperatuur (TR4)", "Förångare inloppstemp (TR4)", "temperatura na wejściu parownika (TR4)", "innløpstemperatur for fordamperen (TR4)", "température entrée évaporateur (TR4)", "evaporatör giriş sıcaklığı (TR4)", "temperatura di ingresso dell'evaporatore (TR4)", "Vstupná teplota výparníka (TR4)", "teplota vstupu do evaporátoru (TR4)") MAKE_TRANSLATION(hpTr4, "hptr4", "evaporator inlet temperature (TR4)", "Verdampfereingang (TR4)", "Verdamper ingangstemperatuur (TR4)", "Förångare inloppstemp (TR4)", "temperatura na wejściu parownika (TR4)", "innløpstemperatur for fordamperen (TR4)", "température entrée évaporateur (TR4)", "evaporatör giriş sıcaklığı (TR4)", "temperatura di ingresso dell'evaporatore (TR4)", "Vstupná teplota výparníka (TR4)", "teplota vstupu do evaporátoru (TR4)")
@@ -496,7 +496,7 @@ MAKE_TRANSLATION(hpTr7, "hptr7", "refrigerant temperature gas side (condenser in
MAKE_TRANSLATION(hpTl2, "hptl2", "air inlet temperature (TL2)", "Außenlufteintrittstemperatur (TL2)", "Temperatuur luchtinlaat (TL2)", "Luftintagstemperatur (TL2)", "temperatura wlotu powietrza (TL2)", "luftinntakstemperatur (TL2)", "température entrée air (TL2)", "hava giriş sıcaklığı (TL2)", "temperatura ingresso aria (TL2)", "teplota prívodu vzduchu (TL2)", "teplota vzduchu na vstupu (TL2)") MAKE_TRANSLATION(hpTl2, "hptl2", "air inlet temperature (TL2)", "Außenlufteintrittstemperatur (TL2)", "Temperatuur luchtinlaat (TL2)", "Luftintagstemperatur (TL2)", "temperatura wlotu powietrza (TL2)", "luftinntakstemperatur (TL2)", "température entrée air (TL2)", "hava giriş sıcaklığı (TL2)", "temperatura ingresso aria (TL2)", "teplota prívodu vzduchu (TL2)", "teplota vzduchu na vstupu (TL2)")
MAKE_TRANSLATION(hpPl1, "hppl1", "low pressure side temperature (PL1)", "Niederdrucktemperatur (PL1)", "Temperatuur lage drukzijde (PL1)", "Temperatur Lågtryckssidan (PL1)", "temperatura po stronie niskiego ciśnienia (PL1)", "temperatur lavtrykksiden (PL1)", "température côté basse pression (PL1)", "düşük basınç tarafı sıcaklığı (PL1)", "temperatura lato bassa pressione (PL1)", "teplota na strane nízkeho tlaku (PL1)", "teplota na nízkotlaké straně (PL1)") MAKE_TRANSLATION(hpPl1, "hppl1", "low pressure side temperature (PL1)", "Niederdrucktemperatur (PL1)", "Temperatuur lage drukzijde (PL1)", "Temperatur Lågtryckssidan (PL1)", "temperatura po stronie niskiego ciśnienia (PL1)", "temperatur lavtrykksiden (PL1)", "température côté basse pression (PL1)", "düşük basınç tarafı sıcaklığı (PL1)", "temperatura lato bassa pressione (PL1)", "teplota na strane nízkeho tlaku (PL1)", "teplota na nízkotlaké straně (PL1)")
MAKE_TRANSLATION(hpPh1, "hpph1", "high pressure side temperature (PH1)", "Hochdrucktemperatur (PH1)", "Temperatuur hoge drukzijde (PH1)", "Temperatur Högtryckssidan (PH1)", "temperatura po stronie wysokiego ciśnienia (PH1)", "Temperatur Høytrykksiden (PH1)", "température côté bhauteasse pression (PH1)", "yüksek basınç tarafı sıcaklığı (PH1)", "temperatura lato alta pressione (PH1)", "teplota na strane vysokého tlaku (PH1)", "teplota na vysokotlaké straně (PH1)") MAKE_TRANSLATION(hpPh1, "hpph1", "high pressure side temperature (PH1)", "Hochdrucktemperatur (PH1)", "Temperatuur hoge drukzijde (PH1)", "Temperatur Högtryckssidan (PH1)", "temperatura po stronie wysokiego ciśnienia (PH1)", "Temperatur Høytrykksiden (PH1)", "température côté bhauteasse pression (PH1)", "yüksek basınç tarafı sıcaklığı (PH1)", "temperatura lato alta pressione (PH1)", "teplota na strane vysokého tlaku (PH1)", "teplota na vysokotlaké straně (PH1)")
MAKE_TRANSLATION(hpTa4, "hpta4", "drain pan temp (TA4)", "Kondensatorwanne (TA4)", "Temperatuur condensorafvoerbak (TA4)", " (TA4)", "temperatura ociekacza (TA4)", "kondenstråg temperatur (TA4)", " (TA4)", "tahliye sıcaklığı (TA4)", "temperatura condensatore (TA4)", "teplota vypúšťacej misky (TA4)", "teplota odvodňovací vany (TA4)") MAKE_TRANSLATION(hpTa4, "hpta4", "drain pan temp (TA4)", "Auffangwanne (TA4)", "Temperatuur condensorafvoerbak (TA4)", " (TA4)", "temperatura ociekacza (TA4)", "kondenstråg temperatur (TA4)", " (TA4)", "tahliye sıcaklığı (TA4)", "temperatura condensatore (TA4)", "teplota vypúšťacej misky (TA4)", "teplota odvodňovací vany (TA4)")
MAKE_TRANSLATION(hpTw1, "hptw1", "reservoir temp (TW1)", "DHW Reservoir (TW1)", "(TW1)", "Varmvattentank Temperatur (TW1)", "temperatura zbiornika (TW1)", "(TW1)", "(TW1)", "(TW1)", "(TW1)", "teplota zásobníka (TW1)", "teplota v nádrži (TW1)") MAKE_TRANSLATION(hpTw1, "hptw1", "reservoir temp (TW1)", "DHW Reservoir (TW1)", "(TW1)", "Varmvattentank Temperatur (TW1)", "temperatura zbiornika (TW1)", "(TW1)", "(TW1)", "(TW1)", "(TW1)", "teplota zásobníka (TW1)", "teplota v nádrži (TW1)")
MAKE_TRANSLATION(hpInput1, "hpin1", "input 1 state", "Status Eingang 1", "Status input 1", "Status Ingång 1", "stan wejścia 1", "status inggang 1", "état entrée 1", "giriş 1 durumu", "stato ingresso 1", "stav vstupu 1", "stav vstupu 1") MAKE_TRANSLATION(hpInput1, "hpin1", "input 1 state", "Status Eingang 1", "Status input 1", "Status Ingång 1", "stan wejścia 1", "status inggang 1", "état entrée 1", "giriş 1 durumu", "stato ingresso 1", "stav vstupu 1", "stav vstupu 1")
MAKE_TRANSLATION(hpInput2, "hpin2", "input 2 state", "Status Eingang 2", "Status input 2", "Status Ingång 2", "stan wejścia 2", "status inggang 2", "état entrée 2", "giriş 2 durumu", "stato ingresso 2", "stav vstupu 2", "stav vstupu 2") MAKE_TRANSLATION(hpInput2, "hpin2", "input 2 state", "Status Eingang 2", "Status input 2", "Status Ingång 2", "stan wejścia 2", "status inggang 2", "état entrée 2", "giriş 2 durumu", "stato ingresso 2", "stav vstupu 2", "stav vstupu 2")
@@ -653,6 +653,10 @@ MAKE_TRANSLATION(elHeat, "elheat", "el. consumption heating", "el. Verbrauch Hei
MAKE_TRANSLATION(elDhw, "eldhw", "el. consumption", "el. Verbrauch", "", "Elförbrukning varmvatten", "", "", "", "", "", "el. spotreba", "") MAKE_TRANSLATION(elDhw, "eldhw", "el. consumption", "el. Verbrauch", "", "Elförbrukning varmvatten", "", "", "", "", "", "el. spotreba", "")
MAKE_TRANSLATION(elGenHeat, "elgenheat", "el. generation heating", "el. Erzeugung Heizen", "", "Elgenerering värme", "", "", "", "", "", "el. generovanie kúrenia", "") MAKE_TRANSLATION(elGenHeat, "elgenheat", "el. generation heating", "el. Erzeugung Heizen", "", "Elgenerering värme", "", "", "", "", "", "el. generovanie kúrenia", "")
MAKE_TRANSLATION(elGenDhw, "elgendhw", "el generation", "el. Erzeugung", "", "Elgenerering varmvatten", "", "", "", "", "", "el. generovanie", "") MAKE_TRANSLATION(elGenDhw, "elgendhw", "el generation", "el. Erzeugung", "", "Elgenerering varmvatten", "", "", "", "", "", "el. generovanie", "")
MAKE_TRANSLATION(hpPumpFlow, "hppumpflow", "volume flow", "Volumenstrom", "", "Volumenstrom", "", "", "", "", "", "objemový průtok", "objemový průtok")
MAKE_TRANSLATION(hpCompSpdER1, "hpcompspder1", "compressor speed ER1", "Kompressordrehzahl ER1", "", "Kompressordrehzahl ER1", "", "", "", "", "", "otáčky kompresoru ER1", "otáčky kompresoru ER1")
MAKE_TRANSLATION(hpSpeedSetpoint, "hpSpeedSetpoint", "speed setpoint", "Geschwindigkeitsteller", "", "Geschwindigkeitsteller", "", "", "", "", "", "nastavená rychlost", "nastavená rychlost")
MAKE_TRANSLATION(smartGridMode, "smartgridmode", "smart grid mode", "Smart Grid Modus", "", "Smart Grid Modus", "", "", "", "", "", "smart grid modus", "smart grid modus")
// HIU // HIU
MAKE_TRANSLATION(netFlowTemp, "netflowtemp", "heat network flow temp", "Systemvorlauftemperatur", "Netto aanvoertemperatuur", "Temperatur fjärrvärmenät", "temp. zasilania sieci cieplnej", "", "", "ısıtma şebekesi akış derecesi", "temperatura di mandata della rete di riscaldamento", "teplota prívodu tepelnej siete", "teplota přívodu tepelné sítě") MAKE_TRANSLATION(netFlowTemp, "netflowtemp", "heat network flow temp", "Systemvorlauftemperatur", "Netto aanvoertemperatuur", "Temperatur fjärrvärmenät", "temp. zasilania sieci cieplnej", "", "", "ısıtma şebekesi akış derecesi", "temperatura di mandata della rete di riscaldamento", "teplota prívodu tepelnej siete", "teplota přívodu tepelné sítě")
@@ -855,11 +859,16 @@ MAKE_TRANSLATION(flowTempVf, "flowtempvf", "flow temperature in header (T0/Vf)",
MAKE_TRANSLATION(mixerSetTime, "valvesettime", "time to set valve", "Zeit zum einstellen des Ventils", "Inschakeltijd mengklep", "Inställningstid Shuntventil", "czas na ustawienie zaworu", "instillningstid ventil", "délai activation vanne", "vana ayar zamanı", "ritardo attivazione valvola", "čas na nastavenie ventilu", "čas pro nastavení ventilu") MAKE_TRANSLATION(mixerSetTime, "valvesettime", "time to set valve", "Zeit zum einstellen des Ventils", "Inschakeltijd mengklep", "Inställningstid Shuntventil", "czas na ustawienie zaworu", "instillningstid ventil", "délai activation vanne", "vana ayar zamanı", "ritardo attivazione valvola", "čas na nastavenie ventilu", "čas pro nastavení ventilu")
MAKE_TRANSLATION(setDiffPress, "setdiffpress", "set differential pressure", "Pumpensolldruck", "", "Tryckskillnad", "różnica ciśnień", "", "", "", "", "nastaviť diferenčný tlak", "nastavení rozdílového tlaku") MAKE_TRANSLATION(setDiffPress, "setdiffpress", "set differential pressure", "Pumpensolldruck", "", "Tryckskillnad", "różnica ciśnień", "", "", "", "", "nastaviť diferenčný tlak", "nastavení rozdílového tlaku")
// mixer pool // MP100 pool module
MAKE_TRANSLATION(poolSetTemp, "poolsettemp", "pool set temperature", "Sollwert Pooltemperatur", "Streeftemperatuur zwembad", "Pool Temperatur Börvärde", "zadana temperatura basenu", "valgt temp basseng", "température consigne piscine", "hedef havuz sıcaklığı", "temperatura nominale piscina", "nastavená teplota bazéna", "cílová teplota bazénu") MAKE_TRANSLATION(poolOn, "poolon", "pool on", "Pool ein")
MAKE_TRANSLATION(poolSetTemp, "poolsettemp", "pool setpoint", "Pool Soll", "Streeftemperatuur zwembad", "Pool Temperatur Börvärde", "zadana temperatura basenu", "valgt temp basseng", "température consigne piscine", "hedef havuz sıcaklığı", "temperatura nominale piscina", "nastavená teplota bazéna", "cílová teplota bazénu")
MAKE_TRANSLATION(poolTemp, "pooltemp", "pool temperature", "Pooltemperatur", "Zwembadtemperatuur", "Pooltemperatur", "temperatura basenu", "bassengtemperatur", "température piscine", "havuz sıcaklığı", "temperatura piscina", "teplota bazéna", "teplota bazénu") MAKE_TRANSLATION(poolTemp, "pooltemp", "pool temperature", "Pooltemperatur", "Zwembadtemperatuur", "Pooltemperatur", "temperatura basenu", "bassengtemperatur", "température piscine", "havuz sıcaklığı", "temperatura piscina", "teplota bazéna", "teplota bazénu")
MAKE_TRANSLATION(poolShuntStatus, "poolshuntstatus", "pool shunt status opening/closing", "Poolventil öffnen/schließen", "Zwembadklep status openen/sluiten", "Pool Shunt-status öppen/stängd", "status bocznika basenu", "bassengshunt-status åpen/stengt", "état shunt piscine ouvert/fermé", "havuz şant durumu açılıyor/kapanıyor", "aprire/chiudere valvola regolazione piscina", "stav bazénového bočníka otváranie/zatváranie", "stav šoupátka bazénu (otevírání/zavírání)") MAKE_TRANSLATION(poolShuntStatus, "poolshuntstatus", "valve status", "Ventil Status", "Zwembadklep status openen/sluiten", "Pool Shunt-status öppen/stängd", "status bocznika basenu", "bassengshunt-status åpen/stengt", "état shunt piscine ouvert/fermé", "havuz şant durumu açılıyor/kapanıyor", "aprire/chiudere valvola regolazione piscina", "stav bazénového bočníka otváranie/zatváranie", "stav šoupátka bazénu (otevírání/zavírání)")
MAKE_TRANSLATION(poolShunt, "poolshunt", "pool shunt open/close (0% = pool / 100% = heat)", "Poolventil Öffnung", "Mengklep zwembad stand", "Pool Shunt Öppen/Stängd", "bocznik basenu (0% = basen / 100% = grzanie)", "bassengshunt åpen/stengt (0% = basseng / 100% = varme)", "ouverture/fermeture shunt piscine (0% = piscine / 100% = chaleur).", "havuz şant açık/kapalı (0% = havuz / 100% = ısıtma)", "valvola regolazione piscina (0% = piscina / 100% = caldo)", "pohyb bazéna otvoriť/zatvoriť (0 % = bazén / 100 % = teplo)", "šoupátko bazénu (0% = bazén / 100% = vytápění)") MAKE_TRANSLATION(poolShunt, "poolshunt", "valve actual", "Ventil Ist", "Mengklep zwembad stand", "Pool Shunt Öppen/Stängd", "bocznik basenu", "bassengshunt åpen/stengt", "ouverture/fermeture shunt piscine", "havuz şant açık/kapalı", "valvola regolazione piscina", "pohyb bazéna otvoriť/zatvoriť", "šoupátko bazénu")
MAKE_TRANSLATION(poolShuntSet, "poolshuntset", "valve setpoint", "Ventil Soll")
MAKE_TRANSLATION(poolRequest, "poolrequest", "pool request", "Pool Anforderung")
// water
MAKE_TRANSLATION(hydrTemp, "hydrTemp", "hydraulic header temperature", "Verteilertemperatur", "Temperatuur open verdeler", "Fördelartemperatur", "temperatura kolektora hydraulicznego", "Fordelertemperatur", "température collecteur hydraulique", "hidrolik başlık sıcaklığı", "temperatura del collettore", "teplota hydraulickej hlavice", "teplota hydraulické hlavice") MAKE_TRANSLATION(hydrTemp, "hydrTemp", "hydraulic header temperature", "Verteilertemperatur", "Temperatuur open verdeler", "Fördelartemperatur", "temperatura kolektora hydraulicznego", "Fordelertemperatur", "température collecteur hydraulique", "hidrolik başlık sıcaklığı", "temperatura del collettore", "teplota hydraulickej hlavice", "teplota hydraulické hlavice")
// solar // solar
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+132 -126
View File
@@ -101,108 +101,110 @@ const std::initializer_list<Modbus::EntityModbusInfo> Modbus::modbus_register_ma
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpSetDiffPress), 151, 1), // hpsetdiffpress REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpSetDiffPress), 151, 1), // hpsetdiffpress
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCompOn), 152, 1), // hpcompon REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCompOn), 152, 1), // hpcompon
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpActivity), 153, 1), // hpactivity REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpActivity), 153, 1), // hpactivity
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpBrinePumpSpd), 154, 1), // hpbrinepumpspd REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPoolOn), 154, 1), // hppoolon
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpSwitchValve), 155, 1), // hpswitchvalve REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpBrinePumpSpd), 155, 1), // hpbrinepumpspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCompSpd), 156, 1), // hpcompspd REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpSwitchValve), 156, 1), // hpswitchvalve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTargetSpd), 157, 1), // hptargetspd REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCompSpd), 157, 1), // hpcompspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCircSpd), 158, 1), // hpcircspd REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTargetSpd), 158, 1), // hptargetspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(receiverValveVr0), 159, 1), // recvalve REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCircSpd), 159, 1), // hpcircspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(expansionValveVr1), 160, 1), // expvalve REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(receiverValveVr0), 160, 1), // recvalve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpBrineIn), 161, 1), // hpbrinein REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(expansionValveVr1), 161, 1), // expvalve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpBrineOut), 162, 1), // hpbrineout REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpBrineIn), 162, 1), // hpbrinein
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTc0), 163, 1), // hptc0 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpBrineOut), 163, 1), // hpbrineout
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTc1), 164, 1), // hptc1 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTc0), 164, 1), // hptc0
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTc3), 165, 1), // hptc3 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTc1), 165, 1), // hptc1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr1), 166, 1), // hptr1 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTc3), 166, 1), // hptc3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr3), 167, 1), // hptr3 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr1), 167, 1), // hptr1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr4), 168, 1), // hptr4 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr3), 168, 1), // hptr3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr5), 169, 1), // hptr5 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr4), 169, 1), // hptr4
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr6), 170, 1), // hptr6 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr5), 170, 1), // hptr5
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr7), 171, 1), // hptr7 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr6), 171, 1), // hptr6
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTl2), 172, 1), // hptl2 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTr7), 172, 1), // hptr7
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPl1), 173, 1), // hppl1 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTl2), 173, 1), // hptl2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPh1), 174, 1), // hpph1 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPl1), 174, 1), // hppl1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTa4), 175, 1), // hpta4 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPh1), 175, 1), // hpph1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTw1), 176, 1), // hptw1 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTa4), 176, 1), // hpta4
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(poolSetTemp), 177, 1), // poolsettemp REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTw1), 177, 1), // hptw1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hp4wayValve), 178, 1), // hp4way REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(poolOn), 178, 1), // poolon
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput1), 179, 1), // hpin1 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(poolSetTemp), 179, 1), // poolsettemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn1Opt), 180, 8), // hpin1opt REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hp4wayValve), 180, 1), // hp4way
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput2), 188, 1), // hpin2 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput1), 181, 1), // hpin1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn2Opt), 189, 8), // hpin2opt REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn1Opt), 182, 8), // hpin1opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput3), 197, 1), // hpin3 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput2), 190, 1), // hpin2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn3Opt), 198, 8), // hpin3opt REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn2Opt), 191, 8), // hpin2opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput4), 206, 1), // hpin4 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput3), 199, 1), // hpin3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn4Opt), 207, 8), // hpin4opt REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn3Opt), 200, 8), // hpin3opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maxHeatComp), 215, 1), // maxheatcomp REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput4), 208, 1), // hpin4
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maxHeatHeat), 216, 1), // maxheatheat REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn4Opt), 209, 8), // hpin4opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterSource), 217, 1), // auxheatersource REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maxHeatComp), 217, 1), // maxheatcomp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pvCooling), 218, 1), // pvcooling REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maxHeatHeat), 218, 1), // maxheatheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterOnly), 219, 1), // auxheateronly REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterSource), 219, 1), // auxheatersource
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterOff), 220, 1), // auxheateroff REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pvCooling), 220, 1), // pvcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterStatus), 221, 1), // auxheaterstatus REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterOnly), 221, 1), // auxheateronly
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterLevel), 222, 1), // auxheaterlevel REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterOff), 222, 1), // auxheateroff
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterDelay), 223, 1), // auxheaterdelay REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterStatus), 223, 1), // auxheaterstatus
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxMaxLimit), 224, 1), // auxmaxlimit REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterLevel), 224, 1), // auxheaterlevel
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxLimitStart), 225, 1), // auxlimitstart REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterDelay), 225, 1), // auxheaterdelay
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeatMode), 226, 1), // auxheatrmode REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxMaxLimit), 226, 1), // auxmaxlimit
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystHeat), 227, 1), // hphystheat REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxLimitStart), 227, 1), // auxlimitstart
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystCool), 228, 1), // hphystcool REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeatMode), 228, 1), // auxheatrmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystPool), 229, 1), // hphystpool REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystHeat), 229, 1), // hphystheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentMode), 230, 1), // silentmode REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystCool), 230, 1), // hphystcool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentFrom), 231, 1), // silentfrom REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystPool), 231, 1), // hphystpool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentTo), 232, 1), // silentto REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentMode), 232, 1), // silentmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(minTempSilent), 233, 1), // mintempsilent REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentFrom), 233, 1), // silentfrom
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempParMode), 234, 1), // tempparmode REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentTo), 234, 1), // silentto
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeatMixValve), 235, 1), // auxheatmix REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(minTempSilent), 235, 1), // mintempsilent
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempDiffHeat), 236, 1), // tempdiffheat REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempParMode), 236, 1), // tempparmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempDiffCool), 237, 1), // tempdiffcool REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeatMixValve), 237, 1), // auxheatmix
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(vp_cooling), 238, 1), // vpcooling REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempDiffHeat), 238, 1), // tempdiffheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatCable), 239, 1), // heatcable REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempDiffCool), 239, 1), // tempdiffcool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(VC0valve), 240, 1), // vc0valve REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(vp_cooling), 240, 1), // vpcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(primePump), 241, 1), // primepump REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatCable), 241, 1), // heatcable
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(primePumpMod), 242, 1), // primepumpmod REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(VC0valve), 242, 1), // vc0valve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hp3wayValve), 243, 1), // hp3way REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(primePump), 243, 1), // primepump
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep1), 244, 1), // elheatstep1 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(primePumpMod), 244, 1), // primepumpmod
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep2), 245, 1), // elheatstep2 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hp3wayValve), 245, 1), // hp3way
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep3), 246, 1), // elheatstep3 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep1), 246, 1), // elheatstep1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpEA0), 247, 1), // hpea0 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep2), 247, 1), // elheatstep2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPumpMode), 248, 1), // hppumpmode REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep3), 248, 1), // elheatstep3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpFan), 249, 1), // fan REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpEA0), 249, 1), // hpea0
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(fanSpd), 250, 1), // fanspd REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPumpMode), 250, 1), // hppumpmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpShutdown), 251, 1), // shutdown REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpFan), 251, 1), // fan
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCurrPower), 252, 1), // hpcurrpower REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(fanSpd), 252, 1), // fanspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPowerLimit), 253, 1), // hppowerlimit REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpShutdown), 253, 1), // shutdown
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(exhaustTemp), 254, 1), // exhausttemp REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCurrPower), 254, 1), // hpcurrpower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnGas), 255, 1), // burngas REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPowerLimit), 255, 1), // hppowerlimit
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnGas2), 256, 1), // burngas2 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(exhaustTemp), 256, 1), // exhausttemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(flameCurr), 257, 1), // flamecurr REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnGas), 257, 1), // burngas
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(fanWork), 258, 1), // fanwork REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnGas2), 258, 1), // burngas2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(ignWork), 259, 1), // ignwork REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(flameCurr), 259, 1), // flamecurr
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(oilPreHeat), 260, 1), // oilpreheat REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(fanWork), 260, 1), // fanwork
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMinPower), 261, 1), // burnminpower REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(ignWork), 261, 1), // ignwork
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMaxPower), 262, 1), // burnmaxpower REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(oilPreHeat), 262, 1), // oilpreheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMinPeriod), 263, 1), // burnminperiod REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMinPower), 263, 1), // burnminpower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(absBurnPow), 264, 1), // absburnpow REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMaxPower), 264, 1), // burnmaxpower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatblock), 265, 1), // heatblock REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMinPeriod), 265, 1), // burnminperiod
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boilHystOn), 266, 1), // boilhyston REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(absBurnPow), 266, 1), // absburnpow
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boilHystOff), 267, 1), // boilhystoff REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatblock), 267, 1), // heatblock
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boil2HystOn), 268, 1), // boil2hyston REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boilHystOn), 268, 1), // boilhyston
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boil2HystOff), 269, 1), // boil2hystoff REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boilHystOff), 269, 1), // boilhystoff
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveOn), 270, 1), // curveon REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boil2HystOn), 270, 1), // boil2hyston
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveBase), 271, 1), // curvebase REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boil2HystOff), 271, 1), // boil2hystoff
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveEnd), 272, 1), // curveend REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveOn), 272, 1), // curveon
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(summertemp), 273, 1), // summertemp REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveBase), 273, 1), // curvebase
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nofrostmode), 274, 1), // nofrostmode REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveEnd), 274, 1), // curveend
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nofrosttemp), 275, 1), // nofrosttemp REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(summertemp), 275, 1), // summertemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(gasMeterHeat), 276, 2), // gasmeterheat REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nofrostmode), 276, 1), // nofrostmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgHeat2), 278, 2), // nrgheat2 REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nofrosttemp), 277, 1), // nofrosttemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nomPower), 280, 1), // nompower REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(gasMeterHeat), 278, 2), // gasmeterheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(netFlowTemp), 281, 1), // netflowtemp REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgHeat2), 280, 2), // nrgheat2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatValve), 282, 1), // heatvalve REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nomPower), 282, 1), // nompower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(keepWarmTemp), 283, 1), // keepwarmtemp REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(netFlowTemp), 283, 1), // netflowtemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(setReturnTemp), 284, 1), // setreturntemp REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatValve), 284, 1), // heatvalve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingOn), 285, 1), // heating REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(keepWarmTemp), 285, 1), // keepwarmtemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(setReturnTemp), 286, 1), // setreturntemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingOn), 287, 1), // heating
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(nrgWw), 0, 2), // nrg 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_(meterWw), 2, 2), // meter
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(upTimeCompWw), 4, 2), // uptimecomp REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(upTimeCompWw), 4, 2), // uptimecomp
@@ -524,30 +526,34 @@ const std::initializer_list<Modbus::EntityModbusInfo> Modbus::modbus_register_ma
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpActivity), 16, 1), // hpactivity REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpActivity), 16, 1), // hpactivity
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpPower), 17, 1), // hppower REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpPower), 17, 1), // hppower
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpCurrPower), 18, 1), // hpcurrpower REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpCurrPower), 18, 1), // hpcurrpower
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hybridStrategy), 19, 1), // hybridstrategy REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpPumpFlow), 19, 1), // hppumpflow
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(lowNoiseMode), 20, 1), // lownoisemode REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpCompSpdER1), 20, 1), // hpcompspder1
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(lowNoiseStart), 21, 1), // lownoisestart REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hpSpeedSetpoint), 21, 1), // hpSpeedSetpoint
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(lowNoiseStop), 22, 1), // lownoisestop REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(smartGridMode), 22, 1), // smartgridmode
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(energyPriceGas), 23, 1), // energypricegas REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(hybridStrategy), 23, 1), // hybridstrategy
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(energyPriceEl), 24, 1), // energypriceel REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(lowNoiseMode), 24, 1), // lownoisemode
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(energyPricePV), 25, 1), // energyfeedpv REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(lowNoiseStart), 25, 1), // lownoisestart
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(switchOverTemp), 26, 1), // switchovertemp REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(lowNoiseStop), 26, 1), // lownoisestop
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(airPurgeMode), 27, 1), // airpurgemode REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(energyPriceGas), 27, 1), // energypricegas
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(heatPumpOutput), 28, 1), // heatpumpoutput REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(energyPriceEl), 28, 1), // energypriceel
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(coolingCircuit), 29, 1), // coolingcircuit REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(energyPricePV), 29, 1), // energyfeedpv
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(compStartMod), 30, 1), // compstartmod REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(switchOverTemp), 30, 1), // switchovertemp
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(heatDrainPan), 31, 1), // heatdrainpan REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(airPurgeMode), 31, 1), // airpurgemode
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(heatCable), 32, 1), // heatcable REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(heatPumpOutput), 32, 1), // heatpumpoutput
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(nrgTotal), 33, 2), // nrgtotal REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(coolingCircuit), 33, 1), // coolingcircuit
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(nrgHeat), 35, 2), // nrgheat REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(compStartMod), 34, 1), // compstartmod
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(meterTotal), 37, 2), // metertotal REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(heatDrainPan), 35, 1), // heatdrainpan
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(meterComp), 39, 2), // metercomp REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(heatCable), 36, 1), // heatcable
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(meterEHeat), 41, 2), // metereheat REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(nrgTotal), 37, 2), // nrgtotal
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(meterHeat), 43, 2), // meterheat REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(nrgHeat), 39, 2), // nrgheat
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(heatingStarts), 45, 2), // heatingstarts REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(meterTotal), 41, 2), // metertotal
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(fuelHeat), 47, 2), // fuelheat REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(meterComp), 43, 2), // metercomp
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(elHeat), 49, 2), // elheat REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(meterEHeat), 45, 2), // metereheat
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(elGenHeat), 51, 2), // elgenheat REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(meterHeat), 47, 2), // meterheat
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(heatingStarts), 49, 2), // heatingstarts
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(fuelHeat), 51, 2), // fuelheat
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(elHeat), 53, 2), // elheat
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DEVICE_DATA, FL_(elGenHeat), 55, 2), // elgenheat
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DHW, FL_(hybridDHW), 0, 1), // hybriddhw REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DHW, FL_(hybridDHW), 0, 1), // hybriddhw
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DHW, FL_(nrgWw), 1, 2), // nrg REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DHW, FL_(nrgWw), 1, 2), // nrg
REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DHW, FL_(meterWw), 3, 2), // meter REGISTER_MAPPING(dt::HEATPUMP, TAG_TYPE_DHW, FL_(meterWw), 3, 2), // meter
+2 -2
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -643,7 +643,7 @@ bool Mqtt::queue_message(const uint8_t operation, const std::string & topic, con
// check free mem // check free mem
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
// if (ESP.getFreeHeap() < 60 * 1024 || ESP.getMaxAllocHeap() < 40 * 1024) { // if (ESP.getFreeHeap() < 60 * 1024 || ESP.getMaxAllocHeap() < 40 * 1024) {
if (heap_caps_get_free_size(MALLOC_CAP_8BIT) < 60 * 1024) { // checks free Heap+PSRAM if (heap_caps_get_free_size(MALLOC_CAP_8BIT) < MQTT_MIN_FREE_HEAP) { // checks free Heap+PSRAM
if (operation == Operation::PUBLISH) { if (operation == Operation::PUBLISH) {
mqtt_message_id_++; mqtt_message_id_++;
mqtt_publish_fails_++; mqtt_publish_fails_++;
+2 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -64,6 +64,7 @@ class Mqtt {
static constexpr uint8_t MQTT_TOPIC_MAX_SIZE = 128; // fixed, not a user setting anymore static constexpr uint8_t MQTT_TOPIC_MAX_SIZE = 128; // fixed, not a user setting anymore
static constexpr uint16_t MQTT_QUEUE_MAX_SIZE = 300; static constexpr uint16_t MQTT_QUEUE_MAX_SIZE = 300;
static constexpr uint32_t MQTT_DISCONNECT_TIMEOUT = 1000; // max ms to flush a graceful disconnect on non-PSRAM boards static constexpr uint32_t MQTT_DISCONNECT_TIMEOUT = 1000; // max ms to flush a graceful disconnect on non-PSRAM boards
static constexpr uint32_t MQTT_MIN_FREE_HEAP = 60 * 1024; // don't queue any MQTT message below this much free heap+PSRAM (in bytes) - 60 KB
static void on_connect(); static void on_connect();
static void on_disconnect(espMqttClientTypes::DisconnectReason reason); static void on_disconnect(espMqttClientTypes::DisconnectReason reason);
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+46 -48
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -33,6 +33,7 @@
#include "firmwareVersion.h" #include "firmwareVersion.h"
#include "shuntingYard.h" // for compute() used by the message and sendmail commands #include "shuntingYard.h" // for compute() used by the message and sendmail commands
#include "httpClient.h" // for the shared TLS client settings
#if defined(EMSESP_TEST) #if defined(EMSESP_TEST)
#include "../test/test.h" #include "../test/test.h"
@@ -218,7 +219,7 @@ bool System::command_sendmail(const char * value, const int8_t) {
ESP_SSLClient * ssl_client = nullptr; ESP_SSLClient * ssl_client = nullptr;
SMTPClient * smtp = nullptr; SMTPClient * smtp = nullptr;
basic_client->setTimeout(5000); basic_client->setTimeout(SMTP_TIMEOUT_MS);
const bool implicit_ssl = (security == EMAIL_SECURITY::SSL); const bool implicit_ssl = (security == EMAIL_SECURITY::SSL);
const bool start_tls = (security == EMAIL_SECURITY::STARTTLS); const bool start_tls = (security == EMAIL_SECURITY::STARTTLS);
@@ -229,8 +230,8 @@ bool System::command_sendmail(const char * value, const int8_t) {
} else { } else {
ssl_client = new ESP_SSLClient; ssl_client = new ESP_SSLClient;
ssl_client->setInsecure(); ssl_client->setInsecure();
ssl_client->setBufferSizes(16384, 1024); ssl_client->setBufferSizes(HttpClient::TLS_RX_BUFFER_SIZE, HttpClient::TLS_TX_BUFFER_SIZE);
ssl_client->setTimeout(5); ssl_client->setTimeout(HttpClient::TLS_READ_TIMEOUT_S);
// enableSSL is baked in at setClient() — true only for implicit SSL (port 465) // enableSSL is baked in at setClient() — true only for implicit SSL (port 465)
ssl_client->setClient(basic_client, implicit_ssl); ssl_client->setClient(basic_client, implicit_ssl);
if (start_tls) { if (start_tls) {
@@ -655,7 +656,7 @@ void System::system_restart(const char * partitionname) {
Mqtt::disconnect(); // gracefully disconnect MQTT (flushes the DISCONNECT before reboot, needed for QOS1) Mqtt::disconnect(); // gracefully disconnect MQTT (flushes the DISCONNECT before reboot, needed for QOS1)
EMSuart::stop(); // stop UART so there is no interference EMSuart::stop(); // stop UART so there is no interference
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
delay(1000); // wait 1 second delay(500); // wait 1/2 second
ESP.restart(); // ka-boom! - this is the only place where the ESP32 restart is called ESP.restart(); // ka-boom! - this is the only place where the ESP32 restart is called
#endif #endif
} }
@@ -1361,8 +1362,9 @@ void System::show_system(uuid::console::Shell & shell) {
// see if there is a restore of an older settings file that needs to be applied // see if there is a restore of an older settings file that needs to be applied
// note there can be only one file at a time // note there can be only one file at a time
// called at boot before any services load their settings, returns true if system settings files were restored
bool System::check_restore() { bool System::check_restore() {
bool reboot_required = false; // true if we need to reboot bool settings_restored = false; // true if system settings files were restored
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
File new_file = LittleFS.open(TEMP_FILENAME_PATH); File new_file = LittleFS.open(TEMP_FILENAME_PATH);
@@ -1377,7 +1379,7 @@ bool System::check_restore() {
// system backup, which is a consolidated json object with all the settings files // system backup, which is a consolidated json object with all the settings files
if (settings_type == "systembackup") { if (settings_type == "systembackup") {
reboot_required = true; settings_restored = true;
JsonArray sections = input["systembackup"].as<JsonArray>(); JsonArray sections = input["systembackup"].as<JsonArray>();
for (JsonObject section : sections) { for (JsonObject section : sections) {
std::string section_type = section["type"]; std::string section_type = section["type"];
@@ -1506,14 +1508,14 @@ bool System::check_restore() {
} }
} }
// It's a single settings file. Parse each section separately. If it's system related it will require a reboot // It's a single settings file. Parse each section separately
else if (settings_type == "settings") { else if (settings_type == "settings") {
reboot_required = saveSettings(NETWORK_SETTINGS_FILE, input); settings_restored = saveSettings(NETWORK_SETTINGS_FILE, input);
reboot_required |= saveSettings(AP_SETTINGS_FILE, input); settings_restored |= saveSettings(AP_SETTINGS_FILE, input);
reboot_required |= saveSettings(MQTT_SETTINGS_FILE, input); settings_restored |= saveSettings(MQTT_SETTINGS_FILE, input);
reboot_required |= saveSettings(NTP_SETTINGS_FILE, input); settings_restored |= saveSettings(NTP_SETTINGS_FILE, input);
reboot_required |= saveSettings(SECURITY_SETTINGS_FILE, input); settings_restored |= saveSettings(SECURITY_SETTINGS_FILE, input);
reboot_required |= saveSettings(EMSESP_SETTINGS_FILE, input); settings_restored |= saveSettings(EMSESP_SETTINGS_FILE, input);
} else if (settings_type == "customizations") { } else if (settings_type == "customizations") {
saveSettings(EMSESP_CUSTOMIZATION_FILE, input); saveSettings(EMSESP_CUSTOMIZATION_FILE, input);
} else if (settings_type == "schedule") { } else if (settings_type == "schedule") {
@@ -1525,7 +1527,7 @@ bool System::check_restore() {
new_file.close(); new_file.close();
if (LittleFS.rename(TEMP_FILENAME_PATH, EMSESP_CUSTOMSUPPORT_FILE)) { if (LittleFS.rename(TEMP_FILENAME_PATH, EMSESP_CUSTOMSUPPORT_FILE)) {
LOG_INFO("Custom support file stored"); LOG_INFO("Custom support file stored");
return false; // no need to reboot return false;
} else { } else {
LOG_ERROR("Failed to save custom support file"); LOG_ERROR("Failed to save custom support file");
} }
@@ -1542,7 +1544,7 @@ bool System::check_restore() {
} }
#endif #endif
return reboot_required; return settings_restored;
} }
// handle upgrades from previous versions // handle upgrades from previous versions
@@ -2923,11 +2925,13 @@ bool System::load_board_profile(std::vector<int8_t> & data, const std::string &
// https://github.com/emsesp/EMS-ESP32/issues/3063 // https://github.com/emsesp/EMS-ESP32/issues/3063
// /api//system/led command that takes an argument in the form [color]:[pattern] // /api//system/led command that takes an argument in the form [color]:[pattern]
// color is red, green, blue, yellow, white // color is red, green, blue, yellow, white
// color is optional
// pattern is // pattern is
// blink1 for 1 time // blink1 for 1 time
// blink2 for 2 times // blink2 for 2 times
// blink3 for 3 times // blink3 for 3 times
// rgb for RGB // rgb for RGB
// cpc for CPC
// For example: /api/system/led?data=red:blink1 // For example: /api/system/led?data=red:blink1
// For older non-RGB models, the colour would default to just being on. // For older non-RGB models, the colour would default to just being on.
bool System::command_led(const char * value, const int8_t) { bool System::command_led(const char * value, const int8_t) {
@@ -2936,16 +2940,19 @@ bool System::command_led(const char * value, const int8_t) {
} }
std::string arg = value; std::string arg = value;
if (arg.find(':') == std::string::npos) { std::string color;
LOG_ERROR("LED command must be in the form [color]:[pattern]"); std::string pattern;
return false; // not in the form [color]:[pattern] auto sep = arg.find(':');
if (sep == std::string::npos) {
pattern = arg; // no color given, only a pattern
} else {
color = arg.substr(0, sep);
pattern = arg.substr(sep + 1);
} }
std::string color = arg.substr(0, arg.find(':'));
std::string pattern = arg.substr(arg.find(':') + 1);
// set and validate the color and pattern // set and validate the color and pattern
if (!EMSESP::led_.set_custom_led_routine(color, pattern)) { if (!EMSESP::led_.set_custom_led_routine(color, pattern)) {
LOG_ERROR("Invalid color or pattern."); LOG_ERROR("Invalid color or pattern");
return false; return false;
} }
@@ -3093,8 +3100,7 @@ void System::ntp_connected(bool b) {
// get NTP status // get NTP status
bool System::ntp_connected() { bool System::ntp_connected() {
// timeout 2 hours, ntp sync is normally every hour. if ((uuid::get_uptime_sec() - ntp_last_check_ > NTP_TIMEOUT_SEC) && ntp_connected_) {
if ((uuid::get_uptime_sec() - ntp_last_check_ > 7201) && ntp_connected_) {
ntp_connected(false); ntp_connected(false);
} }
@@ -3124,8 +3130,8 @@ String System::getBBQKeesGatewayDetails([[maybe_unused]] uint8_t detail) {
} }
const char * mfg[] = {"unknown", "BBQKees Electronics", "", "", "", "", "", ""}; const char * mfg[] = {"unknown", "BBQKees Electronics", "", "", "", "", "", ""};
const char * model[] = {"unknown", "S3", "E32V2", "E32V2.2", "S32", "E32", "", "", ""}; const char * model[] = {"unknown", "S3", "E32V2", "E32V2.2", "S32", "E32", "", ""};
const char * board[] = {"CUSTOM", "S32S3", "E32V2", "E32V2_2", "S32", "E32", "", "", ""}; const char * board[] = {"CUSTOM", "S32S3", "E32V2", "E32V2_2", "S32", "E32", "", ""};
switch (detail) { switch (detail) {
case FUSE_VALUE::MFG: case FUSE_VALUE::MFG:
@@ -3200,19 +3206,13 @@ bool System::uploadFirmwareURL(const char * url) {
if (is_https) { if (is_https) {
ssl_client.setInsecure(); // no CA validation, matches the rest of the project ssl_client.setInsecure(); // no CA validation, matches the rest of the project
// BearSSL needs a receive buffer large enough to hold one full TLS record. // a small (e.g. 1 KB) RX buffer makes the body unreadable: the headers still fit one small
// GitHub's release-assets CDN sends standard up-to-16 KB records and does NOT // record, hence Content-Length looks fine, but the first body record cannot be decoded
// negotiate max_fragment_length, so a small (e.g. 1 KB) RX buffer makes the ssl_client.setBufferSizes(HttpClient::TLS_RX_BUFFER_SIZE, HttpClient::TLS_TX_BUFFER_SIZE);
// body unreadable (headers still fit one small record, hence Content-Length ssl_client.setSessionTimeout(HttpClient::TLS_SESSION_TIMEOUT_S);
// looks fine, but the first body record cannot be decoded). 16384 + overhead
// is the safe value the library itself uses by default; we go a bit smaller
// to be friendlier to 4 MB / no-PSRAM boards while still big enough for any
// record the CDN actually sends in practice.
ssl_client.setBufferSizes(16384, 1024);
ssl_client.setSessionTimeout(120);
} }
basic_client.setTimeout(15000); // socket-level read timeout basic_client.setTimeout(FIRMWARE_UPLOAD_READ_TIMEOUT_S * 1000); // socket-level read timeout, in ms
ssl_client.setTimeout(15); // Stream::readBytes timeout used by Update ssl_client.setTimeout(FIRMWARE_UPLOAD_READ_TIMEOUT_S); // Stream::readBytes timeout used by Update
ssl_client.setClient(&basic_client, is_https); // enableSSL = false for plain HTTP ssl_client.setClient(&basic_client, is_https); // enableSSL = false for plain HTTP
const uint16_t port = is_https ? 443 : 80; const uint16_t port = is_https ? 443 : 80;
@@ -3248,9 +3248,9 @@ bool System::uploadFirmwareURL(const char * url) {
ssl_client.println("Connection: close"); ssl_client.println("Connection: close");
ssl_client.print("\r\n"); ssl_client.print("\r\n");
// wait for the first byte (up to 8s, matching the previous HTTP timeout) // wait for the first byte (matching the previous HTTP timeout)
uint32_t ms = millis(); uint32_t ms = millis();
while (ssl_client.connected() && !ssl_client.available() && millis() - ms < 8000) { while (ssl_client.connected() && !ssl_client.available() && millis() - ms < FIRMWARE_UPLOAD_RESPONSE_TIMEOUT) {
delay(1); delay(1);
} }
@@ -3326,7 +3326,7 @@ bool System::uploadFirmwareURL(const char * url) {
// wait for the first byte of the body so the read loop sees real data // wait for the first byte of the body so the read loop sees real data
// (headers and body may arrive in separate TLS records) // (headers and body may arrive in separate TLS records)
uint32_t body_wait = millis(); uint32_t body_wait = millis();
while (ssl_client.connected() && !ssl_client.available() && millis() - body_wait < 8000) { while (ssl_client.connected() && !ssl_client.available() && millis() - body_wait < FIRMWARE_UPLOAD_RESPONSE_TIMEOUT) {
delay(1); delay(1);
} }
if (!ssl_client.available()) { if (!ssl_client.available()) {
@@ -3341,7 +3341,7 @@ bool System::uploadFirmwareURL(const char * url) {
} }
// check we have a valid size // check we have a valid size
if (firmware_size < 1677721) { // 1.6MB or greater is required if (firmware_size < (int)MIN_FIRMWARE_SIZE) {
LOG_ERROR("Firmware upload failed - invalid size"); LOG_ERROR("Firmware upload failed - invalid size");
return false; // error return false; // error
} }
@@ -3360,9 +3360,7 @@ bool System::uploadFirmwareURL(const char * url) {
EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_UPLOADING); EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_UPLOADING);
// explicit chunked read loop instead of Update.writeStream(): // explicit chunked read loop instead of Update.writeStream():
constexpr size_t CHUNK_SIZE = 1024; uint8_t buf[FIRMWARE_UPLOAD_CHUNK_SIZE];
constexpr uint32_t READ_TIMEOUT_MS = 30000; // overall stall timeout per chunk
uint8_t buf[CHUNK_SIZE];
size_t total_read = 0; size_t total_read = 0;
bool magic_ok = false; bool magic_ok = false;
int last_pct = -1; int last_pct = -1;
@@ -3386,7 +3384,7 @@ bool System::uploadFirmwareURL(const char * url) {
if (!ssl_client.connected()) { if (!ssl_client.connected()) {
break; break;
} }
if (millis() - wait_start > READ_TIMEOUT_MS) { if (millis() - wait_start > FIRMWARE_UPLOAD_STALL_TIMEOUT) {
break; break;
} }
// also bail out promptly if a cancel arrives mid-stall // also bail out promptly if a cancel arrives mid-stall
@@ -3407,8 +3405,8 @@ bool System::uploadFirmwareURL(const char * url) {
} }
size_t want = (size_t)firmware_size - total_read; size_t want = (size_t)firmware_size - total_read;
if (want > CHUNK_SIZE) { if (want > FIRMWARE_UPLOAD_CHUNK_SIZE) {
want = CHUNK_SIZE; want = FIRMWARE_UPLOAD_CHUNK_SIZE;
} }
size_t n = stream->readBytes(buf, want); size_t n = stream->readBytes(buf, want);
+16 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -370,6 +370,9 @@ class System {
static constexpr uint8_t HEALTHCHECK_NO_NETWORK = (1 << 1); // 2 static constexpr uint8_t HEALTHCHECK_NO_NETWORK = (1 << 1); // 2
static constexpr uint8_t HEALTHCHECK_RESET = (1 << 7); // 128 static constexpr uint8_t HEALTHCHECK_RESET = (1 << 7); // 128
// smallest .bin accepted as a firmware image, for both URL and web uploads - 1.6 MB
static constexpr size_t MIN_FIRMWARE_SIZE = 1677721;
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
@@ -402,6 +405,18 @@ class System {
static constexpr uint32_t SYSTEM_CHECK_FREQUENCY = 5000; // do a system check every 5 seconds static constexpr uint32_t SYSTEM_CHECK_FREQUENCY = 5000; // do a system check every 5 seconds
#endif #endif
// NTP syncs about every hour, so allow one missed sync before treating it as lost (in seconds) - 2 hours
static constexpr uint32_t NTP_TIMEOUT_SEC = 7201;
// email
static constexpr uint32_t SMTP_TIMEOUT_MS = 5000; // socket read timeout (in ms) - 5 seconds
// firmware upload from URL
static constexpr uint32_t FIRMWARE_UPLOAD_RESPONSE_TIMEOUT = 8000; // max wait for the first byte of the response headers/body (in ms) - 8 seconds
static constexpr uint32_t FIRMWARE_UPLOAD_READ_TIMEOUT_S = 15; // socket and Stream::readBytes timeout used by Update (in seconds)
static constexpr uint32_t FIRMWARE_UPLOAD_STALL_TIMEOUT = 30000; // abort if no data arrives for a chunk (in ms) - 30 seconds
static constexpr size_t FIRMWARE_UPLOAD_CHUNK_SIZE = 1024; // read buffer, on the stack
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
static uuid::syslog::SyslogService syslog_; static uuid::syslog::SyslogService syslog_;
#endif #endif
+2 -2
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -286,7 +286,7 @@ void TxService::send_poll() const {
uint8_t TxService::get_send_id() { uint8_t TxService::get_send_id() {
static uint32_t count = 0; static uint32_t count = 0;
if (!tx_telegrams_.empty() && tx_telegrams_.front().telegram_->src != ems_bus_id()) { if (!tx_telegrams_.empty() && tx_telegrams_.front().telegram_->src != ems_bus_id()) {
if (++count > 500) { // after 500 polls (~3-10 sec) there will be no master poll for this id if (++count > MAX_POLLS_WITHOUT_MASTER) {
tx_telegrams_.pop_front(); tx_telegrams_.pop_front();
count = 0; count = 0;
return tx_telegrams_.empty() ? ems_bus_id() : tx_telegrams_.front().telegram_->src; return tx_telegrams_.empty() ? ems_bus_id() : tx_telegrams_.front().telegram_->src;
+4 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -440,6 +440,9 @@ class TxService : public EMSbus {
static constexpr uint8_t MAXIMUM_TX_RETRIES = 3; static constexpr uint8_t MAXIMUM_TX_RETRIES = 3;
static constexpr uint32_t POST_SEND_DELAY = 2000; static constexpr uint32_t POST_SEND_DELAY = 2000;
// drop a queued Tx telegram sent from another id if the master hasn't polled that id after this many polls (~3-10 seconds)
static constexpr uint32_t MAX_POLLS_WITHOUT_MASTER = 500;
private: private:
std::deque<QueuedTxTelegram, AllocatorPSRAM<QueuedTxTelegram>> tx_telegrams_; // the Tx queue std::deque<QueuedTxTelegram, AllocatorPSRAM<QueuedTxTelegram>> tx_telegrams_; // the Tx queue
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+18 -2
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -632,7 +632,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
// register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpHeatingOn_, DeviceValueType::BOOL, FL_(hpHeatingOn), DeviceValueUOM::NONE); // register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpHeatingOn_, DeviceValueType::BOOL, FL_(hpHeatingOn), DeviceValueUOM::NONE);
// register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCoolingOn_, DeviceValueType::BOOL, FL_(hpCoolingOn), DeviceValueUOM::NONE); // register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCoolingOn_, DeviceValueType::BOOL, FL_(hpCoolingOn), DeviceValueUOM::NONE);
// register_device_value(DeviceValueTAG::TAG_DHW1, &hpWwOn_, DeviceValueType::BOOL, FL_(hpWwOn), DeviceValueUOM::NONE); // register_device_value(DeviceValueTAG::TAG_DHW1, &hpWwOn_, DeviceValueType::BOOL, FL_(hpWwOn), DeviceValueUOM::NONE);
// register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPoolOn_, DeviceValueType::BOOL, FL_(hpPoolOn), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPoolOn_, DeviceValueType::BOOL, FL_(hpPoolOn), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpBrinePumpSpd_, DeviceValueType::UINT8, FL_(hpBrinePumpSpd), DeviceValueUOM::PERCENT); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpBrinePumpSpd_, DeviceValueType::UINT8, FL_(hpBrinePumpSpd), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpSwitchValve_, DeviceValueType::BOOL, FL_(hpSwitchValve), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpSwitchValve_, DeviceValueType::BOOL, FL_(hpSwitchValve), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCompSpd_, DeviceValueType::UINT8, FL_(hpCompSpd), DeviceValueUOM::PERCENT); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCompSpd_, DeviceValueType::UINT8, FL_(hpCompSpd), DeviceValueUOM::PERCENT);
@@ -666,6 +666,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPh1_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpPh1), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPh1_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpPh1), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTa4_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTa4), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTa4_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTa4), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTw1_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTw1), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTw1_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTw1), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolOn_, DeviceValueType::BOOL, FL_(poolOn), DeviceValueUOM::NONE, MAKE_CF_CB(set_pool_on));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&poolSetTemp_, &poolSetTemp_,
DeviceValueType::UINT8, DeviceValueType::UINT8,
@@ -1815,7 +1816,9 @@ void Boiler::process_HpTemperatures(const std::shared_ptr<const Telegram> & tele
// Heatpump pool unit - type 0x48A // Heatpump pool unit - type 0x48A
// 08 00 FF 00 03 8A 01 4C 01 0C 00 00 0A 00 1E 00 00 01 00 04 4A 00 // 08 00 FF 00 03 8A 01 4C 01 0C 00 00 0A 00 1E 00 00 01 00 04 4A 00
// RC300 switches the pool: 10 08 FF 00 03 8A 01 (on) / 00 (off)
void Boiler::process_HpPool(const std::shared_ptr<const Telegram> & telegram) { void Boiler::process_HpPool(const std::shared_ptr<const Telegram> & telegram) {
has_update(telegram, poolOn_, 0);
has_update(telegram, poolSetTemp_, 1); has_update(telegram, poolSetTemp_, 1);
} }
@@ -2164,8 +2167,11 @@ void Boiler::process_HpSilentMode(const std::shared_ptr<const Telegram> & telegr
} }
// Boiler(0x08) -B-> All(0x00), ?(0x0488), data: 8E 00 00 00 00 00 01 03 // Boiler(0x08) -B-> All(0x00), ?(0x0488), data: 8E 00 00 00 00 00 01 03
// byte 0 bit 6 is set while the heatpump is actually heating the pool
// (switches together with 0x5C4 and MP100 0x5BA offset 2)
void Boiler::process_HpValve(const std::shared_ptr<const Telegram> & telegram) { void Boiler::process_HpValve(const std::shared_ptr<const Telegram> & telegram) {
// has_bitupdate(telegram, auxHeaterStatus_, 0, 2); // has_bitupdate(telegram, auxHeaterStatus_, 0, 2);
has_bitupdate(telegram, hpPoolOn_, 0, 6);
has_update(telegram, auxHeatMixValve_, 7); has_update(telegram, auxHeatMixValve_, 7);
has_update(telegram, pc1Rate_, 13); // percent has_update(telegram, pc1Rate_, 13); // percent
} }
@@ -3161,6 +3167,16 @@ bool Boiler::set_pool_temp(const char * value, const int8_t id) {
return true; return true;
} }
// Switch the pool on/off 0x48A, same as RC300
bool Boiler::set_pool_on(const char * value, const int8_t id) {
bool v;
if (!Helpers::value2bool(value, v)) {
return false;
}
write_command(0x48A, 0, v ? 0x01 : 0x00, 0x48A);
return true;
}
bool Boiler::set_emergency_temp(const char * value, const int8_t id) { bool Boiler::set_emergency_temp(const char * value, const int8_t id) {
int v; int v;
if (!Helpers::value2temperature(value, v)) { if (!Helpers::value2temperature(value, v)) {
+4 -2
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -213,7 +213,7 @@ class Boiler : public EMSdevice {
// uint8_t hpHeatingOn_; // uint8_t hpHeatingOn_;
// uint8_t hpCoolingOn_; // uint8_t hpCoolingOn_;
// uint8_t hpWwOn_; // uint8_t hpWwOn_;
// uint8_t hpPoolOn_; uint8_t hpPoolOn_;
int16_t hpTc0_; int16_t hpTc0_;
int16_t hpTc1_; int16_t hpTc1_;
int16_t hpTc3_; int16_t hpTc3_;
@@ -253,6 +253,7 @@ class Boiler : public EMSdevice {
uint8_t hpTargetSpd_; uint8_t hpTargetSpd_;
// Pool unit // Pool unit
uint8_t poolOn_;
int8_t poolSetTemp_; int8_t poolSetTemp_;
// Inputs // Inputs
@@ -465,6 +466,7 @@ class Boiler : public EMSdevice {
bool set_ww_hyst_on(const char * value, const int8_t id); bool set_ww_hyst_on(const char * value, const int8_t id);
bool set_ww_hyst_off(const char * value, const int8_t id); bool set_ww_hyst_off(const char * value, const int8_t id);
bool set_pool_temp(const char * value, const int8_t id); bool set_pool_temp(const char * value, const int8_t id);
bool set_pool_on(const char * value, const int8_t id);
bool set_emergency_temp(const char * value, const int8_t id); bool set_emergency_temp(const char * value, const int8_t id);
bool set_emergency_ops(const char * value, const int8_t id); bool set_emergency_ops(const char * value, const int8_t id);
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+57 -24
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -16,6 +16,30 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/*
* Broadcast (0x099A), data: 05 00 00 00 00 00 00 37 00 00 1D 00 00 52 00 00 13 01 00 01 7C
* Broadcast (0x099B), data: 80 00 80 00 01 3C 01 38 80 00 80 00 80 00 01 37 00 00 00 00 64
* Broadcast (0x099C), data: 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 76 00 00
data: 00 2B 00 03 04 13 00 00 00 00 00 02 02 02 (offset 24)
* Broadcast (0x099D), data: 02 02 00 00 02 00 01 38 00 00 63 03 E8 00 00 00 00
* Broadcast (0x099E), data: 03
* Broadcast (0x099F), data 05 4E 20 00 00 00 00 02 00 01 34 00 00 3F 00 00 5C 00 01 DD 00 01 37 00
data 00 3F 00 00 5D 00 00 57 00 02 23 00 01 3D 02 80 00 5A 01 86 01 68 00 00 C0 (offset 24)
data 00 00 00 00 (offset 49)
* Broadcast (0x09A0), data: 02 23 01 3E 01 39 00 5D 01 DE 01 38 00 40 00 5E 00 58 00 3F 01 34 00 02
* Broadcast (0x09A2), data: 00 00 00 00
* Broadcast (0x09A3), data: 01 01 01 00 0A 01 0A 00 00 00 00 00 00 01 01 00 00 (offset 2)
* Broadcast (0x09A4), data: 00 35 00 00 01 42 00 00 00 00 30 01 00 00 00 00 00 00 00 00 00 00 00 00 00
data: 02 (offset 25)
* Broadcast (0x09A5), data: 00 00 00 00 00 00 00 00 0A 01 00 01 03 03 00 5A 00 00 00 00 00 00 00 00 14
data: 00 00 00 (offset 25)
* Broadcast (0x09A6), data: 05 01 00 01 F4 1F 01 1F 01 01 03 00 3F 00 00 00 19 64 00 3C 00 01 01 19
data: 02 EC 01 19 00 (offset 24)
* Broadcast (0x09A8), data: 01 18 01 00 01 17 00 06 00 00 86 06 00 2E 07 D0 00 00 00 45 00 04
*/
#include "heatpump.h" #include "heatpump.h"
namespace emsesp { namespace emsesp {
@@ -26,8 +50,7 @@ Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, c
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// telegram handlers // telegram handlers
// register_telegram_type(0x042B, "HP1", false, MAKE_PF_CB(process_HPMonitor1)); // register_telegram_type(0x042B, "HP1", false, MAKE_PF_CB(process_HPMonitor1));
register_telegram_type(0x047B, "HP2", false, MAKE_PF_CB(process_HPMonitor2)); register_telegram_type(0x47B, "HP2", false, MAKE_PF_CB(process_HPMonitor2));
register_telegram_type(0x998, "HPSettings", true, MAKE_PF_CB(process_HPSettings), 20); register_telegram_type(0x998, "HPSettings", true, MAKE_PF_CB(process_HPSettings), 20);
register_telegram_type(0x999, "HPFunctionTest", true, MAKE_PF_CB(process_HPFunctionTest), 11); register_telegram_type(0x999, "HPFunctionTest", true, MAKE_PF_CB(process_HPFunctionTest), 11);
register_telegram_type(0x9A0, "HPTemperature", false, MAKE_PF_CB(process_HPTemperature)); register_telegram_type(0x9A0, "HPTemperature", false, MAKE_PF_CB(process_HPTemperature));
@@ -39,6 +62,9 @@ Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, c
register_telegram_type(0x12E, "HPEnergy1", false, MAKE_PF_CB(process_HpEnergy1)); register_telegram_type(0x12E, "HPEnergy1", false, MAKE_PF_CB(process_HpEnergy1));
register_telegram_type(0x13B, "HPEnergy2", false, MAKE_PF_CB(process_HpEnergy2)); register_telegram_type(0x13B, "HPEnergy2", false, MAKE_PF_CB(process_HpEnergy2));
register_telegram_type(0x4AA, "HPPower", false, MAKE_PF_CB(process_HpPower)); register_telegram_type(0x4AA, "HPPower", false, MAKE_PF_CB(process_HpPower));
register_telegram_type(0x9A8, "HPVolume", false, MAKE_PF_CB(process_HPVolume));
register_telegram_type(0x99D, "HPComp2", false, MAKE_PF_CB(process_HPComp2));
register_telegram_type(0x4AA, "HPPower", false, MAKE_PF_CB(process_HpPower));
// device values // device values
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &airHumidity_, DeviceValueType::UINT8, FL_(airHumidity), DeviceValueUOM::PERCENT); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &airHumidity_, DeviceValueType::UINT8, FL_(airHumidity), DeviceValueUOM::PERCENT);
@@ -74,6 +100,17 @@ Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, c
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPower_, DeviceValueType::UINT16, FL_(hpPower), DeviceValueUOM::W); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPower_, DeviceValueType::UINT16, FL_(hpPower), DeviceValueUOM::W);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCurrPower_, DeviceValueType::UINT16, FL_(hpCurrPower), DeviceValueUOM::W); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCurrPower_, DeviceValueType::UINT16, FL_(hpCurrPower), DeviceValueUOM::W);
// https://github.com/emsesp/EMS-ESP32/issues/3196
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&hpPumpFlow_,
DeviceValueType::UINT16,
DeviceValueNumOp::DV_NUMOP_MUL10,
FL_(hpPumpFlow),
DeviceValueUOM::LH);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCompSpdER1_, DeviceValueType::UINT8, FL_(hpCompSpdER1), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpSpeedSetpoint_, DeviceValueType::UINT8, FL_(hpSpeedSetpoint), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &smartGridMode_, DeviceValueType::UINT8, FL_(smartGridMode), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&controlStrategy_, &controlStrategy_,
DeviceValueType::ENUM, DeviceValueType::ENUM,
@@ -230,6 +267,7 @@ void Heatpump::process_HPTemperature(const std::shared_ptr<const Telegram> & tel
has_update(telegram, hpTa4_, 16); // drain pan temp. has_update(telegram, hpTa4_, 16); // drain pan temp.
has_update(telegram, hpJr0_, 18); // low pressure sensor has_update(telegram, hpJr0_, 18); // low pressure sensor
has_update(telegram, hpJr1_, 20); // high pressure sensor has_update(telegram, hpJr1_, 20); // high pressure sensor
has_update(telegram, hpCompSpdER1_, 22); // compressor speed ER1
} }
// 0x099B // 0x099B
@@ -298,6 +336,7 @@ void Heatpump::process_HpStarts(const std::shared_ptr<const Telegram> & telegram
has_update(telegram, hpActivity_, 2); // https://github.com/emsesp/EMS-ESP32/issues/2883 has_update(telegram, hpActivity_, 2); // https://github.com/emsesp/EMS-ESP32/issues/2883
has_update(telegram, heatStartsHp_, 11, 3); has_update(telegram, heatStartsHp_, 11, 3);
has_update(telegram, wwStartsHp_, 14, 3); has_update(telegram, wwStartsHp_, 14, 3);
has_update(telegram, smartGridMode_, 17); // smart grid mode
} }
// 0x0112E energy consumption // 0x0112E energy consumption
@@ -320,28 +359,22 @@ void Heatpump::process_HpPower(const std::shared_ptr<const Telegram> & telegram)
has_update(telegram, hpCurrPower_, 0); has_update(telegram, hpCurrPower_, 0);
} }
/* // https://github.com/emsesp/EMS-ESP32/issues/3196
* Broadcast (0x099A), data: 05 00 00 00 00 00 00 37 00 00 1D 00 00 52 00 00 13 01 00 01 7C // 0x09A8 HPVolume
* Broadcast (0x099B), data: 80 00 80 00 01 3C 01 38 80 00 80 00 80 00 01 37 00 00 00 00 64 // Broadcast (0x09A8), data: 01 18 01 00 01 17 00 06 00 00 86 06 00 2E 07 D0 00 00 00 45 00 04
* Broadcast (0x099C), data: 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 76 00 00 void Heatpump::process_HPVolume(const std::shared_ptr<const Telegram> & telegram) {
data: 00 2B 00 03 04 13 00 00 00 00 00 02 02 02 (offset 24) has_update(telegram, hpPumpFlow_, 12);
* Broadcast (0x099D), data: 02 02 00 00 02 00 01 38 00 00 63 03 E8 00 00 00 00 }
* Broadcast (0x099E), data: 03
* Broadcast (0x099F), data 05 4E 20 00 00 00 00 02 00 01 34 00 00 3F 00 00 5C 00 01 DD 00 01 37 00
data 00 3F 00 00 5D 00 00 57 00 02 23 00 01 3D 02 80 00 5A 01 86 01 68 00 00 C0 (offset 24)
data 00 00 00 00 (offset 49)
* Broadcast (0x09A0), data: 02 23 01 3E 01 39 00 5D 01 DE 01 38 00 40 00 5E 00 58 00 3F 01 34 00 02
* Broadcast (0x09A2), data: 00 00 00 00
* Broadcast (0x09A3), data: 01 01 01 00 0A 01 0A 00 00 00 00 00 00 01 01 00 00 (offset 2)
* Broadcast (0x09A4), data: 00 35 00 00 01 42 00 00 00 00 30 01 00 00 00 00 00 00 00 00 00 00 00 00 00
data: 02 (offset 25)
* Broadcast (0x09A5), data: 00 00 00 00 00 00 00 00 0A 01 00 01 03 03 00 5A 00 00 00 00 00 00 00 00 14
data: 00 00 00 (offset 25)
* Broadcast (0x09A6), data: 05 01 00 01 F4 1F 01 1F 01 01 03 00 3F 00 00 00 19 64 00 3C 00 01 01 19
data: 02 EC 01 19 00 (offset 24)
* Broadcast (0x09A8), data: 01 18 01 00 01 17 00 06 00 00 86 06 00 2E 07 D0 00 00 00 45 00 04
*/ // 0x099D HPComp2
// Broadcast (0x099D), data: 02 02 00 00 02 00 01 38 00 00 63 03 E8 00 00 00 00
void Heatpump::process_HPComp2(const std::shared_ptr<const Telegram> & telegram) {
has_update(telegram, hpSpeedSetpoint_, 8);
}
//
// Setters
//
bool Heatpump::set_controlStrategy(const char * value, const int8_t id) { bool Heatpump::set_controlStrategy(const char * value, const int8_t id) {
uint8_t v; uint8_t v;
+7 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -44,12 +44,16 @@ class Heatpump : public EMSdevice {
uint8_t heatingPumpMod_; uint8_t heatingPumpMod_;
uint8_t hpCompSpd_; uint8_t hpCompSpd_;
uint8_t hpActivity_; uint8_t hpActivity_;
uint8_t hpCompSpdER1_; // TODO: could be same as hpCompSpd_ ?
uint16_t hpPower_; uint16_t hpPower_;
uint16_t hpCurrPower_; uint16_t hpCurrPower_;
uint16_t hpPumpFlow_;
uint8_t hpSpeedSetpoint_;
// Function test // Function test
uint8_t airPurgeMode_; uint8_t airPurgeMode_;
uint8_t smartGridMode_;
uint8_t heatPumpOutput_; uint8_t heatPumpOutput_;
uint8_t coolingCircuit_; uint8_t coolingCircuit_;
uint8_t compStartMod_; uint8_t compStartMod_;
@@ -102,6 +106,8 @@ class Heatpump : public EMSdevice {
void process_HpEnergy1(const std::shared_ptr<const Telegram> & telegram); void process_HpEnergy1(const std::shared_ptr<const Telegram> & telegram);
void process_HpEnergy2(const std::shared_ptr<const Telegram> & telegram); void process_HpEnergy2(const std::shared_ptr<const Telegram> & telegram);
void process_HpPower(const std::shared_ptr<const Telegram> & telegram); void process_HpPower(const std::shared_ptr<const Telegram> & telegram);
void process_HPVolume(const std::shared_ptr<const Telegram> & telegram);
void process_HPComp2(const std::shared_ptr<const Telegram> & telegram);
bool set_controlStrategy(const char * value, const int8_t id); bool set_controlStrategy(const char * value, const int8_t id);
bool set_lowNoiseMode(const char * value, const int8_t id); bool set_lowNoiseMode(const char * value, const int8_t id);
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+17 -1
View File
@@ -28,6 +28,7 @@ Pool::Pool(uint8_t device_type, uint8_t device_id, uint8_t product_id, const cha
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// Pool module // Pool module
register_telegram_type(0x5BA, "HpPoolStatus", true, MAKE_PF_CB(process_HpPoolStatus), 4); register_telegram_type(0x5BA, "HpPoolStatus", true, MAKE_PF_CB(process_HpPoolStatus), 4);
register_telegram_type(0x5C4, "HpPoolShunt", false, MAKE_PF_CB(process_HpPoolShunt));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&poolTemp_, &poolTemp_,
DeviceValueType::INT16, DeviceValueType::INT16,
@@ -36,15 +37,30 @@ Pool::Pool(uint8_t device_type, uint8_t device_id, uint8_t product_id, const cha
DeviceValueUOM::DEGREES); DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShuntStatus_, DeviceValueType::ENUM, FL_(enum_shunt), FL_(poolShuntStatus), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShuntStatus_, DeviceValueType::ENUM, FL_(enum_shunt), FL_(poolShuntStatus), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShunt_, DeviceValueType::UINT8, FL_(poolShunt), DeviceValueUOM::PERCENT); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShunt_, DeviceValueType::UINT8, FL_(poolShunt), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShuntSet_, DeviceValueType::UINT8, FL_(poolShuntSet), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolRequest_, DeviceValueType::BOOL, FL_(poolRequest), DeviceValueUOM::NONE);
} }
// Mixer MP100 for pools - 0x5BA // Mixer MP100 for pools - 0x5BA
// MP100(0x11) -> Boiler(0x08): 11 08 FF 00 04 BA 01 45 02 00 02
// offset 4: MP100 input contacts, pool requests heat (0 = active, 2 = inactive), only in the telegram to the boiler,
// the answer to a read request is one byte shorter
void Pool::process_HpPoolStatus(const std::shared_ptr<const Telegram> & telegram) { void Pool::process_HpPoolStatus(const std::shared_ptr<const Telegram> & telegram) {
uint8_t request = EMS_VALUE_UINT8_NOTSET;
if (telegram->read_value(request, 4)) {
has_update(poolRequest_, request == 0 ? EMS_VALUE_BOOL_ON : EMS_VALUE_BOOL_OFF);
}
has_update(telegram, poolTemp_, 0); has_update(telegram, poolTemp_, 0);
has_update(telegram, poolShunt_, 3); // 0-100% how much is the shunt open? has_update(telegram, poolShunt_, 3); // 0-100%, 0% = pool / 100% = heat
telegram->read_value(poolShuntStatus__, 2); telegram->read_value(poolShuntStatus__, 2);
uint8_t pss = poolShunt_ == 100 ? 3 : (poolShunt_ == 0 ? 4 : poolShuntStatus__); uint8_t pss = poolShunt_ == 100 ? 3 : (poolShunt_ == 0 ? 4 : poolShuntStatus__);
has_update(poolShuntStatus_, pss); has_update(poolShuntStatus_, pss);
} }
// Boiler(0x08) -> MP100(0x11), 0x5C4: 08 11 FF 00 04 C4 64
// shunt setpoint from the heatpump, 0% = pool / 100% = heat, poolshunt follows within ~2 min
void Pool::process_HpPoolShunt(const std::shared_ptr<const Telegram> & telegram) {
has_update(telegram, poolShuntSet_, 0);
}
} // namespace emsesp } // namespace emsesp
+3
View File
@@ -31,12 +31,15 @@ class Pool : public EMSdevice {
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void process_HpPoolStatus(const std::shared_ptr<const Telegram> & telegram); void process_HpPoolStatus(const std::shared_ptr<const Telegram> & telegram);
void process_HpPoolShunt(const std::shared_ptr<const Telegram> & telegram);
private: private:
// MP100 pool // MP100 pool
int16_t poolTemp_; int16_t poolTemp_;
uint8_t poolShuntStatus_; uint8_t poolShuntStatus_;
uint8_t poolShunt_; uint8_t poolShunt_;
uint8_t poolShuntSet_;
uint8_t poolRequest_;
uint8_t poolShuntStatus__ = EMS_VALUE_UINT8_NOTSET; // temp value uint8_t poolShuntStatus__ = EMS_VALUE_UINT8_NOTSET; // temp value
}; };
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* EMS-ESP - https://github.com/emsesp/EMS-ESP * EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org * Copyright 2020-2026 emsesp.org
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

Some files were not shown because too many files have changed in this diff Show More