Merge pull request #2884 from proddy/dev

some small fixes and changes
This commit is contained in:
Proddy
2026-01-06 22:19:40 +01:00
committed by GitHub
43 changed files with 797 additions and 448 deletions

View File

@@ -26,8 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- FW200 display options [#2610](https://github.com/emsesp/EMS-ESP32/discussions/2610) - FW200 display options [#2610](https://github.com/emsesp/EMS-ESP32/discussions/2610)
- CR11 mode settings OFF/MANUAL depends on selTemp [#2437](https://github.com/emsesp/EMS-ESP32/issues/2437) - CR11 mode settings OFF/MANUAL depends on selTemp [#2437](https://github.com/emsesp/EMS-ESP32/issues/2437)
- implemented eFuse settings for BBQKees boards to store model type and ESP chipset - implemented eFuse settings for BBQKees boards to store model type and ESP chipset
- Analogsensors for pulse output [#2624](https://github.com/emsesp/EMS-ESP32/discussions/2624) - analogsensors for pulse output [#2624](https://github.com/emsesp/EMS-ESP32/discussions/2624)
- Analogsensors frequency input [#2631](https://github.com/emsesp/EMS-ESP32/discussions/2631) - analogsensors frequency input [#2631](https://github.com/emsesp/EMS-ESP32/discussions/2631)
- SRC plus thermostats [#2636](https://github.com/emsesp/EMS-ESP32/issues/2636) - SRC plus thermostats [#2636](https://github.com/emsesp/EMS-ESP32/issues/2636)
- Greenstar 2000 [#2645](https://github.com/emsesp/EMS-ESP32/issues/2645) - Greenstar 2000 [#2645](https://github.com/emsesp/EMS-ESP32/issues/2645)
- RC3xx `dhw modetype` [#2659](https://github.com/emsesp/EMS-ESP32/discussions/2659) - RC3xx `dhw modetype` [#2659](https://github.com/emsesp/EMS-ESP32/discussions/2659)

View File

@@ -6,12 +6,19 @@ For more details go to [emsesp.org](https://emsesp.org/).
## Added ## Added
- update time safed in nvs - update time saved in nvs
## Fixed ## Fixed
- selflowtemp [#2876](https://github.com/emsesp/EMS-ESP32/issues/2876) - fix EMS bus disconnected errors on some systems [#2881](https://github.com/emsesp/EMS-ESP32/issues/2881)
- selflowtemp fix [#2876](https://github.com/emsesp/EMS-ESP32/issues/2876)
- updated valid GPIOs for ESP32S2, ESP32S3 and ESP32 that caused custom systems to block gpios [#2887](https://github.com/emsesp/EMS-ESP32/issues/2887)
- Junkers wwcharge offset [#2860](https://github.com/emsesp/EMS-ESP32/issues/2860)
- fixed minflowtemp [#2890](https://github.com/emsesp/EMS-ESP32/issues/2890)
- don't add HA uom/classes for bool values [#2885](https://github.com/emsesp/EMS-ESP32/issues/2885)
- fixed missing progress bar on web firmware uploads
## Changed ## Changed
- snapshot gpios in temporarly ram - snapshot gpios stored in temporary ram
- GPIOs stored along with the name and reported in log if conflicting

View File

@@ -67,7 +67,7 @@ DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSO
DEFINES += -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_DEBUG -DEMC_RX_BUFFER_SIZE=1500 DEFINES += -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_DEBUG -DEMC_RX_BUFFER_SIZE=1500
DEFINES += $(ARGS) DEFINES += $(ARGS)
DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.8.0-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32S3\" DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32S3\"
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# Sources & Files # Sources & Files

View File

@@ -37,8 +37,8 @@
"flash_size": "4MB", "flash_size": "4MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
"maximum_size": 4194304, "maximum_size": 4194304,
"use_1200bps_touch": true, "use_1200bps_touch": false,
"wait_for_upload_port": true, "wait_for_upload_port": false,
"require_upload_port": true, "require_upload_port": true,
"speed": 921600 "speed": 921600
}, },

View File

@@ -35,6 +35,7 @@
"managed_components/**", "managed_components/**",
"pnpm-*.yaml", "pnpm-*.yaml",
"vite.config.ts", "vite.config.ts",
"lib/esp32-psram/**" "lib/esp32-psram/**",
"test/test_api/test_api.h"
] ]
} }

View File

@@ -37,7 +37,7 @@
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"magic-string": "^0.30.21", "magic-string": "^0.30.21",
"mime-types": "^3.0.2", "mime-types": "^3.0.2",
"preact": "^10.28.1", "preact": "^10.28.2",
"react": "^19.2.3", "react": "^19.2.3",
"react-dom": "^19.2.3", "react-dom": "^19.2.3",
"react-icons": "^5.5.0", "react-icons": "^5.5.0",
@@ -51,18 +51,18 @@
"@eslint/js": "^9.39.2", "@eslint/js": "^9.39.2",
"@preact/compat": "^18.3.1", "@preact/compat": "^18.3.1",
"@preact/preset-vite": "^2.10.2", "@preact/preset-vite": "^2.10.2",
"@trivago/prettier-plugin-sort-imports": "^6.0.0", "@trivago/prettier-plugin-sort-imports": "^6.0.1",
"@types/node": "^25.0.3", "@types/node": "^25.0.3",
"@types/react": "^19.2.7", "@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"axe-core": "^4.11.0", "axe-core": "^4.11.1",
"concurrently": "^9.2.1", "concurrently": "^9.2.1",
"eslint": "^9.39.2", "eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8", "eslint-config-prettier": "^10.1.8",
"prettier": "^3.7.4", "prettier": "^3.7.4",
"rollup-plugin-visualizer": "^6.0.5", "rollup-plugin-visualizer": "^6.0.5",
"terser": "^5.44.1", "terser": "^5.44.1",
"typescript-eslint": "^8.51.0", "typescript-eslint": "^8.52.0",
"vite": "^7.3.0", "vite": "^7.3.0",
"vite-plugin-imagemin": "^0.6.1", "vite-plugin-imagemin": "^0.6.1",
"vite-tsconfig-paths": "^6.0.3" "vite-tsconfig-paths": "^6.0.3"

409
interface/pnpm-lock.yaml generated
View File

@@ -25,7 +25,7 @@ importers:
version: 7.3.6(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.3))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.3))(@types/react@19.2.7)(react@19.2.3))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) version: 7.3.6(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.3))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.3))(@types/react@19.2.7)(react@19.2.3))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@preact/compat': '@preact/compat':
specifier: ^18.3.1 specifier: ^18.3.1
version: 18.3.1(preact@10.28.1) version: 18.3.1(preact@10.28.2)
'@table-library/react-table-library': '@table-library/react-table-library':
specifier: 4.1.15 specifier: 4.1.15
version: 4.1.15(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) version: 4.1.15(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -51,8 +51,8 @@ importers:
specifier: ^3.0.2 specifier: ^3.0.2
version: 3.0.2 version: 3.0.2
preact: preact:
specifier: ^10.28.1 specifier: ^10.28.2
version: 10.28.1 version: 10.28.2
react: react:
specifier: ^19.2.3 specifier: ^19.2.3
version: 19.2.3 version: 19.2.3
@@ -83,10 +83,10 @@ importers:
version: 9.39.2 version: 9.39.2
'@preact/preset-vite': '@preact/preset-vite':
specifier: ^2.10.2 specifier: ^2.10.2
version: 2.10.2(@babel/core@7.28.5)(preact@10.28.1)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)) version: 2.10.2(@babel/core@7.28.5)(preact@10.28.2)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1))
'@trivago/prettier-plugin-sort-imports': '@trivago/prettier-plugin-sort-imports':
specifier: ^6.0.0 specifier: ^6.0.1
version: 6.0.0(prettier@3.7.4) version: 6.0.1(prettier@3.7.4)
'@types/node': '@types/node':
specifier: ^25.0.3 specifier: ^25.0.3
version: 25.0.3 version: 25.0.3
@@ -97,8 +97,8 @@ importers:
specifier: ^19.2.3 specifier: ^19.2.3
version: 19.2.3(@types/react@19.2.7) version: 19.2.3(@types/react@19.2.7)
axe-core: axe-core:
specifier: ^4.11.0 specifier: ^4.11.1
version: 4.11.0 version: 4.11.1
concurrently: concurrently:
specifier: ^9.2.1 specifier: ^9.2.1
version: 9.2.1 version: 9.2.1
@@ -113,13 +113,13 @@ importers:
version: 3.7.4 version: 3.7.4
rollup-plugin-visualizer: rollup-plugin-visualizer:
specifier: ^6.0.5 specifier: ^6.0.5
version: 6.0.5(rollup@4.54.0) version: 6.0.5(rollup@4.55.1)
terser: terser:
specifier: ^5.44.1 specifier: ^5.44.1
version: 5.44.1 version: 5.44.1
typescript-eslint: typescript-eslint:
specifier: ^8.51.0 specifier: ^8.52.0
version: 8.51.0(eslint@9.39.2)(typescript@5.9.3) version: 8.52.0(eslint@9.39.2)(typescript@5.9.3)
vite: vite:
specifier: ^7.3.0 specifier: ^7.3.0
version: 7.3.0(@types/node@25.0.3)(terser@5.44.1) version: 7.3.0(@types/node@25.0.3)(terser@5.44.1)
@@ -679,113 +679,128 @@ packages:
resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
engines: {node: '>= 8.0.0'} engines: {node: '>= 8.0.0'}
'@rollup/rollup-android-arm-eabi@4.54.0': '@rollup/rollup-android-arm-eabi@4.55.1':
resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==} resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==}
cpu: [arm] cpu: [arm]
os: [android] os: [android]
'@rollup/rollup-android-arm64@4.54.0': '@rollup/rollup-android-arm64@4.55.1':
resolution: {integrity: sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==} resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==}
cpu: [arm64] cpu: [arm64]
os: [android] os: [android]
'@rollup/rollup-darwin-arm64@4.54.0': '@rollup/rollup-darwin-arm64@4.55.1':
resolution: {integrity: sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==} resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@rollup/rollup-darwin-x64@4.54.0': '@rollup/rollup-darwin-x64@4.55.1':
resolution: {integrity: sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==} resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@rollup/rollup-freebsd-arm64@4.54.0': '@rollup/rollup-freebsd-arm64@4.55.1':
resolution: {integrity: sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==} resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==}
cpu: [arm64] cpu: [arm64]
os: [freebsd] os: [freebsd]
'@rollup/rollup-freebsd-x64@4.54.0': '@rollup/rollup-freebsd-x64@4.55.1':
resolution: {integrity: sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==} resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==}
cpu: [x64] cpu: [x64]
os: [freebsd] os: [freebsd]
'@rollup/rollup-linux-arm-gnueabihf@4.54.0': '@rollup/rollup-linux-arm-gnueabihf@4.55.1':
resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==} resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@rollup/rollup-linux-arm-musleabihf@4.54.0': '@rollup/rollup-linux-arm-musleabihf@4.55.1':
resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==} resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@rollup/rollup-linux-arm64-gnu@4.54.0': '@rollup/rollup-linux-arm64-gnu@4.55.1':
resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==} resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@rollup/rollup-linux-arm64-musl@4.54.0': '@rollup/rollup-linux-arm64-musl@4.55.1':
resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==} resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@rollup/rollup-linux-loong64-gnu@4.54.0': '@rollup/rollup-linux-loong64-gnu@4.55.1':
resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==} resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==}
cpu: [loong64] cpu: [loong64]
os: [linux] os: [linux]
'@rollup/rollup-linux-ppc64-gnu@4.54.0': '@rollup/rollup-linux-loong64-musl@4.55.1':
resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==} resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==}
cpu: [loong64]
os: [linux]
'@rollup/rollup-linux-ppc64-gnu@4.55.1':
resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
'@rollup/rollup-linux-riscv64-gnu@4.54.0': '@rollup/rollup-linux-ppc64-musl@4.55.1':
resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==} resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==}
cpu: [ppc64]
os: [linux]
'@rollup/rollup-linux-riscv64-gnu@4.55.1':
resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
'@rollup/rollup-linux-riscv64-musl@4.54.0': '@rollup/rollup-linux-riscv64-musl@4.55.1':
resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==} resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
'@rollup/rollup-linux-s390x-gnu@4.54.0': '@rollup/rollup-linux-s390x-gnu@4.55.1':
resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==} resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
'@rollup/rollup-linux-x64-gnu@4.54.0': '@rollup/rollup-linux-x64-gnu@4.55.1':
resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==} resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@rollup/rollup-linux-x64-musl@4.54.0': '@rollup/rollup-linux-x64-musl@4.55.1':
resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==} resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@rollup/rollup-openharmony-arm64@4.54.0': '@rollup/rollup-openbsd-x64@4.55.1':
resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==} resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==}
cpu: [x64]
os: [openbsd]
'@rollup/rollup-openharmony-arm64@4.55.1':
resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==}
cpu: [arm64] cpu: [arm64]
os: [openharmony] os: [openharmony]
'@rollup/rollup-win32-arm64-msvc@4.54.0': '@rollup/rollup-win32-arm64-msvc@4.55.1':
resolution: {integrity: sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==} resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@rollup/rollup-win32-ia32-msvc@4.54.0': '@rollup/rollup-win32-ia32-msvc@4.55.1':
resolution: {integrity: sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==} resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==}
cpu: [ia32] cpu: [ia32]
os: [win32] os: [win32]
'@rollup/rollup-win32-x64-gnu@4.54.0': '@rollup/rollup-win32-x64-gnu@4.55.1':
resolution: {integrity: sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==} resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@rollup/rollup-win32-x64-msvc@4.54.0': '@rollup/rollup-win32-x64-msvc@4.55.1':
resolution: {integrity: sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==} resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
@@ -800,8 +815,8 @@ packages:
react: '>=16.8.0' react: '>=16.8.0'
react-dom: '>=16.8.0' react-dom: '>=16.8.0'
'@trivago/prettier-plugin-sort-imports@6.0.0': '@trivago/prettier-plugin-sort-imports@6.0.1':
resolution: {integrity: sha512-Xarx55ow0R8oC7ViL5fPmDsg1EBa1dVhyZFVbFXNtPPJyW2w9bJADIla8YFSaNG9N06XfcklA9O9vmw4noNxkQ==} resolution: {integrity: sha512-6B13DCWDfAfh4AEJ43gRgeCSAQmlKG5LHqHzHc0lbUwgBy0rX7o41US+46Fd4XiXBx+JDGEz3NBadCbUls0dUQ==}
engines: {node: '>= 20'} engines: {node: '>= 20'}
peerDependencies: peerDependencies:
'@vue/compiler-sfc': 3.x '@vue/compiler-sfc': 3.x
@@ -888,63 +903,63 @@ packages:
'@types/svgo@2.6.4': '@types/svgo@2.6.4':
resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==} resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==}
'@typescript-eslint/eslint-plugin@8.51.0': '@typescript-eslint/eslint-plugin@8.52.0':
resolution: {integrity: sha512-XtssGWJvypyM2ytBnSnKtHYOGT+4ZwTnBVl36TA4nRO2f4PRNGz5/1OszHzcZCvcBMh+qb7I06uoCmLTRdR9og==} resolution: {integrity: sha512-okqtOgqu2qmZJ5iN4TWlgfF171dZmx2FzdOv2K/ixL2LZWDStL8+JgQerI2sa8eAEfoydG9+0V96m7V+P8yE1Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
'@typescript-eslint/parser': ^8.51.0 '@typescript-eslint/parser': ^8.52.0
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0' typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/parser@8.51.0': '@typescript-eslint/parser@8.52.0':
resolution: {integrity: sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A==} resolution: {integrity: sha512-iIACsx8pxRnguSYhHiMn2PvhvfpopO9FXHyn1mG5txZIsAaB6F0KwbFnUQN3KCiG3Jcuad/Cao2FAs1Wp7vAyg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0' typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/project-service@8.51.0': '@typescript-eslint/project-service@8.52.0':
resolution: {integrity: sha512-Luv/GafO07Z7HpiI7qeEW5NW8HUtZI/fo/kE0YbtQEFpJRUuR0ajcWfCE5bnMvL7QQFrmT/odMe8QZww8X2nfQ==} resolution: {integrity: sha512-xD0MfdSdEmeFa3OmVqonHi+Cciab96ls1UhIF/qX/O/gPu5KXD0bY9lu33jj04fjzrXHcuvjBcBC+D3SNSadaw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
typescript: '>=4.8.4 <6.0.0' typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/scope-manager@8.51.0': '@typescript-eslint/scope-manager@8.52.0':
resolution: {integrity: sha512-JhhJDVwsSx4hiOEQPeajGhCWgBMBwVkxC/Pet53EpBVs7zHHtayKefw1jtPaNRXpI9RA2uocdmpdfE7T+NrizA==} resolution: {integrity: sha512-ixxqmmCcc1Nf8S0mS0TkJ/3LKcC8mruYJPOU6Ia2F/zUUR4pApW7LzrpU3JmtePbRUTes9bEqRc1Gg4iyRnDzA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/tsconfig-utils@8.51.0': '@typescript-eslint/tsconfig-utils@8.52.0':
resolution: {integrity: sha512-Qi5bSy/vuHeWyir2C8u/uqGMIlIDu8fuiYWv48ZGlZ/k+PRPHtaAu7erpc7p5bzw2WNNSniuxoMSO4Ar6V9OXw==} resolution: {integrity: sha512-jl+8fzr/SdzdxWJznq5nvoI7qn2tNYV/ZBAEcaFMVXf+K6jmXvAFrgo/+5rxgnL152f//pDEAYAhhBAZGrVfwg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
typescript: '>=4.8.4 <6.0.0' typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/type-utils@8.51.0': '@typescript-eslint/type-utils@8.52.0':
resolution: {integrity: sha512-0XVtYzxnobc9K0VU7wRWg1yiUrw4oQzexCG2V2IDxxCxhqBMSMbjB+6o91A+Uc0GWtgjCa3Y8bi7hwI0Tu4n5Q==} resolution: {integrity: sha512-JD3wKBRWglYRQkAtsyGz1AewDu3mTc7NtRjR/ceTyGoPqmdS5oCdx/oZMWD5Zuqmo6/MpsYs0wp6axNt88/2EQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0' typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/types@8.51.0': '@typescript-eslint/types@8.52.0':
resolution: {integrity: sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag==} resolution: {integrity: sha512-LWQV1V4q9V4cT4H5JCIx3481iIFxH1UkVk+ZkGGAV1ZGcjGI9IoFOfg3O6ywz8QqCDEp7Inlg6kovMofsNRaGg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.51.0': '@typescript-eslint/typescript-estree@8.52.0':
resolution: {integrity: sha512-1qNjGqFRmlq0VW5iVlcyHBbCjPB7y6SxpBkrbhNWMy/65ZoncXCEPJxkRZL8McrseNH6lFhaxCIaX+vBuFnRng==} resolution: {integrity: sha512-XP3LClsCc0FsTK5/frGjolyADTh3QmsLp6nKd476xNI9CsSsLnmn4f0jrzNoAulmxlmNIpeXuHYeEQv61Q6qeQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
typescript: '>=4.8.4 <6.0.0' typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/utils@8.51.0': '@typescript-eslint/utils@8.52.0':
resolution: {integrity: sha512-11rZYxSe0zabiKaCP2QAwRf/dnmgFgvTmeDTtZvUvXG3UuAdg/GU02NExmmIXzz3vLGgMdtrIosI84jITQOxUA==} resolution: {integrity: sha512-wYndVMWkweqHpEpwPhwqE2lnD2DxC6WVLupU/DOt/0/v+/+iQbbzO3jOHjmBMnhu0DgLULvOaU4h4pwHYi2oRQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0' typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/visitor-keys@8.51.0': '@typescript-eslint/visitor-keys@8.52.0':
resolution: {integrity: sha512-mM/JRQOzhVN1ykejrvwnBRV3+7yTKK8tVANVN3o1O0t0v7o+jqdVu9crPy5Y9dov15TJk/FTIgoUGHrTOVL3Zg==} resolution: {integrity: sha512-ink3/Zofus34nmBsPjow63FP5M7IGff0RKAgqR6+CFpdk22M7aLwC9gOcLGYqr7MczLPzZVERW9hRog3O4n1sQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
acorn-jsx@5.3.2: acorn-jsx@5.3.2:
@@ -1008,8 +1023,8 @@ packages:
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
axe-core@4.11.0: axe-core@4.11.1:
resolution: {integrity: sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==} resolution: {integrity: sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==}
engines: {node: '>=4'} engines: {node: '>=4'}
babel-plugin-macros@3.1.0: babel-plugin-macros@3.1.0:
@@ -2460,8 +2475,8 @@ packages:
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
preact@10.28.1: preact@10.28.2:
resolution: {integrity: sha512-u1/ixq/lVQI0CakKNvLDEcW5zfCjUQfZdK9qqWuIJtsezuyG6pk9TWj75GMuI/EzRSZB/VAE43sNWWZfiy8psw==} resolution: {integrity: sha512-lbteaWGzGHdlIuiJ0l2Jq454m6kcpI1zNje6d8MlGAFlYvP2GO4ibnat7P74Esfz4sPTdM6UxtTwh/d3pwM9JA==}
prelude-ls@1.2.1: prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
@@ -2625,8 +2640,8 @@ packages:
rollup: rollup:
optional: true optional: true
rollup@4.54.0: rollup@4.55.1:
resolution: {integrity: sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==} resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'} engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true hasBin: true
@@ -2884,8 +2899,8 @@ packages:
resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==} resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
ts-api-utils@2.3.0: ts-api-utils@2.4.0:
resolution: {integrity: sha512-6eg3Y9SF7SsAvGzRHQvvc1skDAhwI4YQ32ui1scxD1Ccr0G5qIIbUBT3pFTKX8kmWIQClHobtUdNuaBgwdfdWg==} resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==}
engines: {node: '>=18.12'} engines: {node: '>=18.12'}
peerDependencies: peerDependencies:
typescript: '>=4.8.4' typescript: '>=4.8.4'
@@ -2924,8 +2939,8 @@ packages:
peerDependencies: peerDependencies:
typescript: '>=3.5.1' typescript: '>=3.5.1'
typescript-eslint@8.51.0: typescript-eslint@8.52.0:
resolution: {integrity: sha512-jh8ZuM5oEh2PSdyQG9YAEM1TCGuWenLSuSUhf/irbVUNW9O5FhbFVONviN2TgMTBnUmyHv7E56rYnfLZK6TkiA==} resolution: {integrity: sha512-atlQQJ2YkO4pfTVQmQ+wvYQwexPDOIgo+RaVcD7gHgzy/IQA+XTyuxNM9M9TVXvttkF7koBHmcwisKdOAf2EcA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
@@ -3591,16 +3606,16 @@ snapshots:
'@popperjs/core@2.11.8': {} '@popperjs/core@2.11.8': {}
'@preact/compat@18.3.1(preact@10.28.1)': '@preact/compat@18.3.1(preact@10.28.2)':
dependencies: dependencies:
preact: 10.28.1 preact: 10.28.2
'@preact/preset-vite@2.10.2(@babel/core@7.28.5)(preact@10.28.1)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1))': '@preact/preset-vite@2.10.2(@babel/core@7.28.5)(preact@10.28.2)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1))':
dependencies: dependencies:
'@babel/core': 7.28.5 '@babel/core': 7.28.5
'@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.5) '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.5)
'@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.5) '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.5)
'@prefresh/vite': 2.4.11(preact@10.28.1)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)) '@prefresh/vite': 2.4.11(preact@10.28.2)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1))
'@rollup/pluginutils': 4.2.1 '@rollup/pluginutils': 4.2.1
babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.28.5) babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.28.5)
debug: 4.4.3 debug: 4.4.3
@@ -3613,20 +3628,20 @@ snapshots:
'@prefresh/babel-plugin@0.5.2': {} '@prefresh/babel-plugin@0.5.2': {}
'@prefresh/core@1.5.9(preact@10.28.1)': '@prefresh/core@1.5.9(preact@10.28.2)':
dependencies: dependencies:
preact: 10.28.1 preact: 10.28.2
'@prefresh/utils@1.2.1': {} '@prefresh/utils@1.2.1': {}
'@prefresh/vite@2.4.11(preact@10.28.1)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1))': '@prefresh/vite@2.4.11(preact@10.28.2)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1))':
dependencies: dependencies:
'@babel/core': 7.28.5 '@babel/core': 7.28.5
'@prefresh/babel-plugin': 0.5.2 '@prefresh/babel-plugin': 0.5.2
'@prefresh/core': 1.5.9(preact@10.28.1) '@prefresh/core': 1.5.9(preact@10.28.2)
'@prefresh/utils': 1.2.1 '@prefresh/utils': 1.2.1
'@rollup/pluginutils': 4.2.1 '@rollup/pluginutils': 4.2.1
preact: 10.28.1 preact: 10.28.2
vite: 7.3.0(@types/node@25.0.3)(terser@5.44.1) vite: 7.3.0(@types/node@25.0.3)(terser@5.44.1)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -3636,70 +3651,79 @@ snapshots:
estree-walker: 2.0.2 estree-walker: 2.0.2
picomatch: 2.3.1 picomatch: 2.3.1
'@rollup/rollup-android-arm-eabi@4.54.0': '@rollup/rollup-android-arm-eabi@4.55.1':
optional: true optional: true
'@rollup/rollup-android-arm64@4.54.0': '@rollup/rollup-android-arm64@4.55.1':
optional: true optional: true
'@rollup/rollup-darwin-arm64@4.54.0': '@rollup/rollup-darwin-arm64@4.55.1':
optional: true optional: true
'@rollup/rollup-darwin-x64@4.54.0': '@rollup/rollup-darwin-x64@4.55.1':
optional: true optional: true
'@rollup/rollup-freebsd-arm64@4.54.0': '@rollup/rollup-freebsd-arm64@4.55.1':
optional: true optional: true
'@rollup/rollup-freebsd-x64@4.54.0': '@rollup/rollup-freebsd-x64@4.55.1':
optional: true optional: true
'@rollup/rollup-linux-arm-gnueabihf@4.54.0': '@rollup/rollup-linux-arm-gnueabihf@4.55.1':
optional: true optional: true
'@rollup/rollup-linux-arm-musleabihf@4.54.0': '@rollup/rollup-linux-arm-musleabihf@4.55.1':
optional: true optional: true
'@rollup/rollup-linux-arm64-gnu@4.54.0': '@rollup/rollup-linux-arm64-gnu@4.55.1':
optional: true optional: true
'@rollup/rollup-linux-arm64-musl@4.54.0': '@rollup/rollup-linux-arm64-musl@4.55.1':
optional: true optional: true
'@rollup/rollup-linux-loong64-gnu@4.54.0': '@rollup/rollup-linux-loong64-gnu@4.55.1':
optional: true optional: true
'@rollup/rollup-linux-ppc64-gnu@4.54.0': '@rollup/rollup-linux-loong64-musl@4.55.1':
optional: true optional: true
'@rollup/rollup-linux-riscv64-gnu@4.54.0': '@rollup/rollup-linux-ppc64-gnu@4.55.1':
optional: true optional: true
'@rollup/rollup-linux-riscv64-musl@4.54.0': '@rollup/rollup-linux-ppc64-musl@4.55.1':
optional: true optional: true
'@rollup/rollup-linux-s390x-gnu@4.54.0': '@rollup/rollup-linux-riscv64-gnu@4.55.1':
optional: true optional: true
'@rollup/rollup-linux-x64-gnu@4.54.0': '@rollup/rollup-linux-riscv64-musl@4.55.1':
optional: true optional: true
'@rollup/rollup-linux-x64-musl@4.54.0': '@rollup/rollup-linux-s390x-gnu@4.55.1':
optional: true optional: true
'@rollup/rollup-openharmony-arm64@4.54.0': '@rollup/rollup-linux-x64-gnu@4.55.1':
optional: true optional: true
'@rollup/rollup-win32-arm64-msvc@4.54.0': '@rollup/rollup-linux-x64-musl@4.55.1':
optional: true optional: true
'@rollup/rollup-win32-ia32-msvc@4.54.0': '@rollup/rollup-openbsd-x64@4.55.1':
optional: true optional: true
'@rollup/rollup-win32-x64-gnu@4.54.0': '@rollup/rollup-openharmony-arm64@4.55.1':
optional: true optional: true
'@rollup/rollup-win32-x64-msvc@4.54.0': '@rollup/rollup-win32-arm64-msvc@4.55.1':
optional: true
'@rollup/rollup-win32-ia32-msvc@4.55.1':
optional: true
'@rollup/rollup-win32-x64-gnu@4.55.1':
optional: true
'@rollup/rollup-win32-x64-msvc@4.55.1':
optional: true optional: true
'@sindresorhus/is@0.7.0': {} '@sindresorhus/is@0.7.0': {}
@@ -3713,7 +3737,7 @@ snapshots:
react-virtualized-auto-sizer: 1.0.26(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react-virtualized-auto-sizer: 1.0.26(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
react-window: 1.8.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react-window: 1.8.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@trivago/prettier-plugin-sort-imports@6.0.0(prettier@3.7.4)': '@trivago/prettier-plugin-sort-imports@6.0.1(prettier@3.7.4)':
dependencies: dependencies:
'@babel/generator': 7.28.5 '@babel/generator': 7.28.5
'@babel/parser': 7.28.5 '@babel/parser': 7.28.5
@@ -3803,95 +3827,95 @@ snapshots:
dependencies: dependencies:
'@types/node': 25.0.3 '@types/node': 25.0.3
'@typescript-eslint/eslint-plugin@8.51.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3)': '@typescript-eslint/eslint-plugin@8.52.0(@typescript-eslint/parser@8.52.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3)':
dependencies: dependencies:
'@eslint-community/regexpp': 4.12.2 '@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.51.0(eslint@9.39.2)(typescript@5.9.3) '@typescript-eslint/parser': 8.52.0(eslint@9.39.2)(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.51.0 '@typescript-eslint/scope-manager': 8.52.0
'@typescript-eslint/type-utils': 8.51.0(eslint@9.39.2)(typescript@5.9.3) '@typescript-eslint/type-utils': 8.52.0(eslint@9.39.2)(typescript@5.9.3)
'@typescript-eslint/utils': 8.51.0(eslint@9.39.2)(typescript@5.9.3) '@typescript-eslint/utils': 8.52.0(eslint@9.39.2)(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.51.0 '@typescript-eslint/visitor-keys': 8.52.0
eslint: 9.39.2 eslint: 9.39.2
ignore: 7.0.5 ignore: 7.0.5
natural-compare: 1.4.0 natural-compare: 1.4.0
ts-api-utils: 2.3.0(typescript@5.9.3) ts-api-utils: 2.4.0(typescript@5.9.3)
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/parser@8.51.0(eslint@9.39.2)(typescript@5.9.3)': '@typescript-eslint/parser@8.52.0(eslint@9.39.2)(typescript@5.9.3)':
dependencies: dependencies:
'@typescript-eslint/scope-manager': 8.51.0 '@typescript-eslint/scope-manager': 8.52.0
'@typescript-eslint/types': 8.51.0 '@typescript-eslint/types': 8.52.0
'@typescript-eslint/typescript-estree': 8.51.0(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.51.0 '@typescript-eslint/visitor-keys': 8.52.0
debug: 4.4.3 debug: 4.4.3
eslint: 9.39.2 eslint: 9.39.2
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/project-service@8.51.0(typescript@5.9.3)': '@typescript-eslint/project-service@8.52.0(typescript@5.9.3)':
dependencies: dependencies:
'@typescript-eslint/tsconfig-utils': 8.51.0(typescript@5.9.3) '@typescript-eslint/tsconfig-utils': 8.52.0(typescript@5.9.3)
'@typescript-eslint/types': 8.51.0 '@typescript-eslint/types': 8.52.0
debug: 4.4.3 debug: 4.4.3
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/scope-manager@8.51.0': '@typescript-eslint/scope-manager@8.52.0':
dependencies: dependencies:
'@typescript-eslint/types': 8.51.0 '@typescript-eslint/types': 8.52.0
'@typescript-eslint/visitor-keys': 8.51.0 '@typescript-eslint/visitor-keys': 8.52.0
'@typescript-eslint/tsconfig-utils@8.51.0(typescript@5.9.3)': '@typescript-eslint/tsconfig-utils@8.52.0(typescript@5.9.3)':
dependencies: dependencies:
typescript: 5.9.3 typescript: 5.9.3
'@typescript-eslint/type-utils@8.51.0(eslint@9.39.2)(typescript@5.9.3)': '@typescript-eslint/type-utils@8.52.0(eslint@9.39.2)(typescript@5.9.3)':
dependencies: dependencies:
'@typescript-eslint/types': 8.51.0 '@typescript-eslint/types': 8.52.0
'@typescript-eslint/typescript-estree': 8.51.0(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.51.0(eslint@9.39.2)(typescript@5.9.3) '@typescript-eslint/utils': 8.52.0(eslint@9.39.2)(typescript@5.9.3)
debug: 4.4.3 debug: 4.4.3
eslint: 9.39.2 eslint: 9.39.2
ts-api-utils: 2.3.0(typescript@5.9.3) ts-api-utils: 2.4.0(typescript@5.9.3)
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/types@8.51.0': {} '@typescript-eslint/types@8.52.0': {}
'@typescript-eslint/typescript-estree@8.51.0(typescript@5.9.3)': '@typescript-eslint/typescript-estree@8.52.0(typescript@5.9.3)':
dependencies: dependencies:
'@typescript-eslint/project-service': 8.51.0(typescript@5.9.3) '@typescript-eslint/project-service': 8.52.0(typescript@5.9.3)
'@typescript-eslint/tsconfig-utils': 8.51.0(typescript@5.9.3) '@typescript-eslint/tsconfig-utils': 8.52.0(typescript@5.9.3)
'@typescript-eslint/types': 8.51.0 '@typescript-eslint/types': 8.52.0
'@typescript-eslint/visitor-keys': 8.51.0 '@typescript-eslint/visitor-keys': 8.52.0
debug: 4.4.3 debug: 4.4.3
minimatch: 9.0.5 minimatch: 9.0.5
semver: 7.7.3 semver: 7.7.3
tinyglobby: 0.2.15 tinyglobby: 0.2.15
ts-api-utils: 2.3.0(typescript@5.9.3) ts-api-utils: 2.4.0(typescript@5.9.3)
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/utils@8.51.0(eslint@9.39.2)(typescript@5.9.3)': '@typescript-eslint/utils@8.52.0(eslint@9.39.2)(typescript@5.9.3)':
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2) '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2)
'@typescript-eslint/scope-manager': 8.51.0 '@typescript-eslint/scope-manager': 8.52.0
'@typescript-eslint/types': 8.51.0 '@typescript-eslint/types': 8.52.0
'@typescript-eslint/typescript-estree': 8.51.0(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3)
eslint: 9.39.2 eslint: 9.39.2
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/visitor-keys@8.51.0': '@typescript-eslint/visitor-keys@8.52.0':
dependencies: dependencies:
'@typescript-eslint/types': 8.51.0 '@typescript-eslint/types': 8.52.0
eslint-visitor-keys: 4.2.1 eslint-visitor-keys: 4.2.1
acorn-jsx@5.3.2(acorn@8.15.0): acorn-jsx@5.3.2(acorn@8.15.0):
@@ -3942,7 +3966,7 @@ snapshots:
dependencies: dependencies:
possible-typed-array-names: 1.1.0 possible-typed-array-names: 1.1.0
axe-core@4.11.0: {} axe-core@4.11.1: {}
babel-plugin-macros@3.1.0: babel-plugin-macros@3.1.0:
dependencies: dependencies:
@@ -5473,7 +5497,7 @@ snapshots:
picocolors: 1.1.1 picocolors: 1.1.1
source-map-js: 1.2.1 source-map-js: 1.2.1
preact@10.28.1: {} preact@10.28.2: {}
prelude-ls@1.2.1: {} prelude-ls@1.2.1: {}
@@ -5614,41 +5638,44 @@ snapshots:
dependencies: dependencies:
glob: 7.2.3 glob: 7.2.3
rollup-plugin-visualizer@6.0.5(rollup@4.54.0): rollup-plugin-visualizer@6.0.5(rollup@4.55.1):
dependencies: dependencies:
open: 8.4.2 open: 8.4.2
picomatch: 4.0.3 picomatch: 4.0.3
source-map: 0.7.6 source-map: 0.7.6
yargs: 17.7.2 yargs: 17.7.2
optionalDependencies: optionalDependencies:
rollup: 4.54.0 rollup: 4.55.1
rollup@4.54.0: rollup@4.55.1:
dependencies: dependencies:
'@types/estree': 1.0.8 '@types/estree': 1.0.8
optionalDependencies: optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.54.0 '@rollup/rollup-android-arm-eabi': 4.55.1
'@rollup/rollup-android-arm64': 4.54.0 '@rollup/rollup-android-arm64': 4.55.1
'@rollup/rollup-darwin-arm64': 4.54.0 '@rollup/rollup-darwin-arm64': 4.55.1
'@rollup/rollup-darwin-x64': 4.54.0 '@rollup/rollup-darwin-x64': 4.55.1
'@rollup/rollup-freebsd-arm64': 4.54.0 '@rollup/rollup-freebsd-arm64': 4.55.1
'@rollup/rollup-freebsd-x64': 4.54.0 '@rollup/rollup-freebsd-x64': 4.55.1
'@rollup/rollup-linux-arm-gnueabihf': 4.54.0 '@rollup/rollup-linux-arm-gnueabihf': 4.55.1
'@rollup/rollup-linux-arm-musleabihf': 4.54.0 '@rollup/rollup-linux-arm-musleabihf': 4.55.1
'@rollup/rollup-linux-arm64-gnu': 4.54.0 '@rollup/rollup-linux-arm64-gnu': 4.55.1
'@rollup/rollup-linux-arm64-musl': 4.54.0 '@rollup/rollup-linux-arm64-musl': 4.55.1
'@rollup/rollup-linux-loong64-gnu': 4.54.0 '@rollup/rollup-linux-loong64-gnu': 4.55.1
'@rollup/rollup-linux-ppc64-gnu': 4.54.0 '@rollup/rollup-linux-loong64-musl': 4.55.1
'@rollup/rollup-linux-riscv64-gnu': 4.54.0 '@rollup/rollup-linux-ppc64-gnu': 4.55.1
'@rollup/rollup-linux-riscv64-musl': 4.54.0 '@rollup/rollup-linux-ppc64-musl': 4.55.1
'@rollup/rollup-linux-s390x-gnu': 4.54.0 '@rollup/rollup-linux-riscv64-gnu': 4.55.1
'@rollup/rollup-linux-x64-gnu': 4.54.0 '@rollup/rollup-linux-riscv64-musl': 4.55.1
'@rollup/rollup-linux-x64-musl': 4.54.0 '@rollup/rollup-linux-s390x-gnu': 4.55.1
'@rollup/rollup-openharmony-arm64': 4.54.0 '@rollup/rollup-linux-x64-gnu': 4.55.1
'@rollup/rollup-win32-arm64-msvc': 4.54.0 '@rollup/rollup-linux-x64-musl': 4.55.1
'@rollup/rollup-win32-ia32-msvc': 4.54.0 '@rollup/rollup-openbsd-x64': 4.55.1
'@rollup/rollup-win32-x64-gnu': 4.54.0 '@rollup/rollup-openharmony-arm64': 4.55.1
'@rollup/rollup-win32-x64-msvc': 4.54.0 '@rollup/rollup-win32-arm64-msvc': 4.55.1
'@rollup/rollup-win32-ia32-msvc': 4.55.1
'@rollup/rollup-win32-x64-gnu': 4.55.1
'@rollup/rollup-win32-x64-msvc': 4.55.1
fsevents: 2.3.3 fsevents: 2.3.3
run-parallel@1.2.0: run-parallel@1.2.0:
@@ -5882,7 +5909,7 @@ snapshots:
dependencies: dependencies:
escape-string-regexp: 1.0.5 escape-string-regexp: 1.0.5
ts-api-utils@2.3.0(typescript@5.9.3): ts-api-utils@2.4.0(typescript@5.9.3):
dependencies: dependencies:
typescript: 5.9.3 typescript: 5.9.3
@@ -5912,12 +5939,12 @@ snapshots:
dependencies: dependencies:
typescript: 5.9.3 typescript: 5.9.3
typescript-eslint@8.51.0(eslint@9.39.2)(typescript@5.9.3): typescript-eslint@8.52.0(eslint@9.39.2)(typescript@5.9.3):
dependencies: dependencies:
'@typescript-eslint/eslint-plugin': 8.51.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3) '@typescript-eslint/eslint-plugin': 8.52.0(@typescript-eslint/parser@8.52.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3)
'@typescript-eslint/parser': 8.51.0(eslint@9.39.2)(typescript@5.9.3) '@typescript-eslint/parser': 8.52.0(eslint@9.39.2)(typescript@5.9.3)
'@typescript-eslint/typescript-estree': 8.51.0(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.51.0(eslint@9.39.2)(typescript@5.9.3) '@typescript-eslint/utils': 8.52.0(eslint@9.39.2)(typescript@5.9.3)
eslint: 9.39.2 eslint: 9.39.2
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
@@ -6019,7 +6046,7 @@ snapshots:
fdir: 6.5.0(picomatch@4.0.3) fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3 picomatch: 4.0.3
postcss: 8.5.6 postcss: 8.5.6
rollup: 4.54.0 rollup: 4.55.1
tinyglobby: 0.2.15 tinyglobby: 0.2.15
optionalDependencies: optionalDependencies:
'@types/node': 25.0.3 '@types/node': 25.0.3

View File

@@ -788,10 +788,12 @@ const Customizations = () => {
</> </>
); );
return ( return restarting ? (
<SystemMonitor />
) : (
<SectionContent> <SectionContent>
{blocker ? <BlockNavigation blocker={blocker} /> : null} {blocker ? <BlockNavigation blocker={blocker} /> : null}
{restarting ? <SystemMonitor /> : renderContent()} {renderContent()}
{selectedDeviceEntity && ( {selectedDeviceEntity && (
<SettingsCustomizationsDialog <SettingsCustomizationsDialog
open={dialogOpen} open={dialogOpen}

View File

@@ -896,10 +896,12 @@ const ApplicationSettings = () => {
); );
}; };
return ( return restarting ? (
<SystemMonitor />
) : (
<SectionContent> <SectionContent>
{blocker ? <BlockNavigation blocker={blocker} /> : null} {blocker ? <BlockNavigation blocker={blocker} /> : null}
{restarting ? <SystemMonitor /> : content()} {content()}
</SectionContent> </SectionContent>
); );
}; };

View File

@@ -182,7 +182,7 @@ const Settings = () => {
restarting restarting
]); ]);
return <SectionContent>{restarting ? <SystemMonitor /> : content}</SectionContent>; return restarting ? <SystemMonitor /> : <SectionContent>{content}</SectionContent>;
}; };
export default Settings; export default Settings;

View File

@@ -397,10 +397,12 @@ const NetworkSettings = () => {
); );
}; };
return ( return restarting ? (
<SystemMonitor />
) : (
<SectionContent> <SectionContent>
{blocker ? <BlockNavigation blocker={blocker} /> : null} {blocker ? <BlockNavigation blocker={blocker} /> : null}
{restarting ? <SystemMonitor /> : content()} {content()}
</SectionContent> </SectionContent>
); );
}; };

View File

@@ -443,7 +443,7 @@ const SystemStatus = () => {
renderRestartDialog renderRestartDialog
]); ]);
return <SectionContent>{restarting ? <SystemMonitor /> : content}</SectionContent>; return restarting ? <SystemMonitor /> : <SectionContent>{content}</SectionContent>;
}; };
export default SystemStatus; export default SystemStatus;

View File

@@ -103,8 +103,8 @@ const SystemMonitor = () => {
height: '100vh', height: '100vh',
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center'
backdropFilter: 'blur(8px)' // backdropFilter: 'blur(8px)'
}} }}
> >
<Box <Box

View File

@@ -868,7 +868,7 @@ const Version = () => {
installPartitionFirmware installPartitionFirmware
]); ]);
return <SectionContent>{restarting ? <SystemMonitor /> : content}</SectionContent>; return restarting ? <SystemMonitor /> : <SectionContent>{content}</SectionContent>;
}; };
export default memo(Version); export default memo(Version);

View File

@@ -39,9 +39,8 @@ const LayoutMenuItemComponent = ({
left: 0, left: 0,
top: 0, top: 0,
bottom: 0, bottom: 0,
width: selected ? '4px' : '0px', width: selected ? '3px' : '0px',
backgroundColor: '#90caf9', backgroundColor: '#90caf9',
borderRadius: '0 2px 2px 0',
transition: 'width 0.05s cubic-bezier(0.55, 0.085, 0.68, 0.53)' transition: 'width 0.05s cubic-bezier(0.55, 0.085, 0.68, 0.53)'
} }
}), }),

View File

@@ -136,9 +136,16 @@ const createManualChunks = (detailed = false) => {
return 'vendor'; return 'vendor';
} }
if (detailed) { if (detailed) {
if (id.includes('components/')) return 'components'; // Group circularly dependent modules together to avoid circular chunk warnings
if (id.includes('app/')) return 'app'; // components, app, and utils are tightly coupled, so combine them
if (id.includes('utils/')) return 'utils'; if (
id.includes('components/') ||
id.includes('app/') ||
id.includes('utils/')
) {
return 'app';
}
// Keep api separate as it's typically more independent
if (id.includes('api/')) return 'api'; if (id.includes('api/')) return 'api';
} }
return undefined; return undefined;

View File

@@ -52,7 +52,7 @@ ModbusClientTCPasync::~ModbusClientTCPasync() {
} }
} }
// force close client // force close client
MTA_client.close(true); MTA_client.close();
} }
// optionally manually connect to modbus server. Otherwise connection will be made upon first request // optionally manually connect to modbus server. Otherwise connection will be made upon first request
@@ -79,7 +79,7 @@ void ModbusClientTCPasync::connect(IPAddress host, uint16_t port) {
// manually disconnect from modbus server. Connection will also auto close after idle time // manually disconnect from modbus server. Connection will also auto close after idle time
void ModbusClientTCPasync::disconnect(bool force) { void ModbusClientTCPasync::disconnect(bool force) {
LOG_D("disconnecting\n"); LOG_D("disconnecting\n");
MTA_client.close(force); MTA_client.close();
} }
// Set timeout value // Set timeout value

View File

@@ -253,7 +253,7 @@ void ModbusServerTCPasync::onClientConnect(AsyncClient* client) {
LOG_D("nr clients: %u\n", clients.size()); LOG_D("nr clients: %u\n", clients.size());
} else { } else {
LOG_D("max number of clients reached, closing new\n"); LOG_D("max number of clients reached, closing new\n");
client->close(true); client->close();
delete client; delete client;
} }
} }

View File

@@ -42,7 +42,7 @@ int ClientAsync::read(uint8_t* buf, size_t size) {
} }
void ClientAsync::stop() { void ClientAsync::stop() {
client.close(false); client.close();
} }
bool ClientAsync::connected() { bool ClientAsync::connected() {

View File

@@ -76,6 +76,10 @@ 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 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); 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) {
return 0;
}
#define PROGMEM #define PROGMEM
#define PGM_P const char * #define PGM_P const char *

View File

@@ -10,7 +10,7 @@
}, },
"dependencies": { "dependencies": {
"@msgpack/msgpack": "^3.1.3", "@msgpack/msgpack": "^3.1.3",
"@trivago/prettier-plugin-sort-imports": "^6.0.0", "@trivago/prettier-plugin-sort-imports": "^6.0.1",
"formidable": "^3.5.4", "formidable": "^3.5.4",
"itty-router": "^5.0.22", "itty-router": "^5.0.22",
"prettier": "^3.7.4" "prettier": "^3.7.4"

View File

@@ -12,8 +12,8 @@ importers:
specifier: ^3.1.3 specifier: ^3.1.3
version: 3.1.3 version: 3.1.3
'@trivago/prettier-plugin-sort-imports': '@trivago/prettier-plugin-sort-imports':
specifier: ^6.0.0 specifier: ^6.0.1
version: 6.0.0(prettier@3.7.4) version: 6.0.1(prettier@3.7.4)
formidable: formidable:
specifier: ^3.5.4 specifier: ^3.5.4
version: 3.5.4 version: 3.5.4
@@ -87,8 +87,8 @@ packages:
'@paralleldrive/cuid2@2.3.1': '@paralleldrive/cuid2@2.3.1':
resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==}
'@trivago/prettier-plugin-sort-imports@6.0.0': '@trivago/prettier-plugin-sort-imports@6.0.1':
resolution: {integrity: sha512-Xarx55ow0R8oC7ViL5fPmDsg1EBa1dVhyZFVbFXNtPPJyW2w9bJADIla8YFSaNG9N06XfcklA9O9vmw4noNxkQ==} resolution: {integrity: sha512-6B13DCWDfAfh4AEJ43gRgeCSAQmlKG5LHqHzHc0lbUwgBy0rX7o41US+46Fd4XiXBx+JDGEz3NBadCbUls0dUQ==}
engines: {node: '>= 20'} engines: {node: '>= 20'}
peerDependencies: peerDependencies:
'@vue/compiler-sfc': 3.x '@vue/compiler-sfc': 3.x
@@ -246,7 +246,7 @@ snapshots:
dependencies: dependencies:
'@noble/hashes': 1.8.0 '@noble/hashes': 1.8.0
'@trivago/prettier-plugin-sort-imports@6.0.0(prettier@3.7.4)': '@trivago/prettier-plugin-sort-imports@6.0.1(prettier@3.7.4)':
dependencies: dependencies:
'@babel/generator': 7.28.5 '@babel/generator': 7.28.5
'@babel/parser': 7.28.5 '@babel/parser': 7.28.5

View File

@@ -106,7 +106,7 @@ board_build.filesystem = littlefs
lib_deps = lib_deps =
bblanchon/ArduinoJson @ 7.4.2 bblanchon/ArduinoJson @ 7.4.2
ESP32Async/AsyncTCP @ 3.4.10 ESP32Async/AsyncTCP @ 3.4.10
ESP32Async/ESPAsyncWebServer @ 3.9.3 ESP32Async/ESPAsyncWebServer @ 3.9.4
https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8 https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
@@ -228,7 +228,7 @@ build_src_flags =
-DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_STANDALONE -DEMSESP_TEST
-DEMSESP_UNITY -DEMSESP_UNITY
-DARDUINOJSON_ENABLE_ARDUINO_STRING=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING=1
-DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.8.0-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\" -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
-std=gnu++17 -Og -ggdb -std=gnu++17 -Og -ggdb
-Wall -Wextra -Wall -Wextra
-Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces -Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces
@@ -284,7 +284,7 @@ build_flags =
[env:standalone] [env:standalone]
extends = env:native extends = env:native
build_flags = build_flags =
-DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.8.0-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\" -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
; Modbus ; Modbus
; Creates the file modbus_entity_parameters.hpp ; Creates the file modbus_entity_parameters.hpp

View File

@@ -58,12 +58,12 @@ enum APNetworkStatus { ACTIVE = 0, INACTIVE, LINGERING };
class APSettings { class APSettings {
public: public:
uint8_t provisionMode; // 0 = on, 2 = off uint8_t provisionMode = FACTORY_AP_PROVISION_MODE; // 0 = on, 2 = off
String ssid; String ssid = FACTORY_AP_SSID;
String password; String password = FACTORY_AP_PASSWORD;
uint8_t channel; uint8_t channel = FACTORY_AP_CHANNEL;
bool ssidHidden; bool ssidHidden = FACTORY_AP_SSID_HIDDEN;
uint8_t maxClients; uint8_t maxClients = FACTORY_AP_MAX_CLIENTS;
IPAddress localIP; IPAddress localIP;
IPAddress gatewayIP; IPAddress gatewayIP;

View File

@@ -70,6 +70,10 @@ class FSPersistence {
// failed to open file, return false // failed to open file, return false
if (!settingsFile || !jsonObject.size()) { if (!settingsFile || !jsonObject.size()) {
#if defined(EMSESP_DEBUG)
Serial.printf("Failed to write file %s", _filePath);
Serial.println();
#endif
return false; return false;
} }

View File

@@ -8,6 +8,7 @@
#include <espMqttClient.h> #include <espMqttClient.h>
#include <uuid/common.h> #include <uuid/common.h>
#include <default_settings.h>
#define MQTT_RECONNECTION_DELAY 2000 // 2 seconds #define MQTT_RECONNECTION_DELAY 2000 // 2 seconds
@@ -65,37 +66,37 @@
class MqttSettings { class MqttSettings {
public: public:
bool enabled; bool enabled = FACTORY_MQTT_ENABLED;
String host; String host = FACTORY_MQTT_HOST;
uint16_t port; uint16_t port = FACTORY_MQTT_PORT;
String rootCA; String rootCA = "";
bool enableTLS; bool enableTLS = false;
String username; String username = FACTORY_MQTT_USERNAME;
String password; String password = FACTORY_MQTT_PASSWORD;
String clientId; String clientId;
uint16_t keepAlive; uint16_t keepAlive = FACTORY_MQTT_KEEP_ALIVE;
bool cleanSession; bool cleanSession = FACTORY_MQTT_CLEAN_SESSION;
// EMS-ESP specific // EMS-ESP specific
String base; String base = FACTORY_MQTT_BASE;
uint16_t publish_time_boiler; uint16_t publish_time_boiler = EMSESP_DEFAULT_PUBLISH_TIME;
uint16_t publish_time_thermostat; uint16_t publish_time_thermostat = EMSESP_DEFAULT_PUBLISH_TIME;
uint16_t publish_time_solar; uint16_t publish_time_solar = EMSESP_DEFAULT_PUBLISH_TIME;
uint16_t publish_time_mixer; uint16_t publish_time_mixer = EMSESP_DEFAULT_PUBLISH_TIME;
uint16_t publish_time_water; uint16_t publish_time_water = EMSESP_DEFAULT_PUBLISH_TIME;
uint16_t publish_time_other; uint16_t publish_time_other = EMSESP_DEFAULT_PUBLISH_TIME_OTHER;
uint16_t publish_time_sensor; uint16_t publish_time_sensor = EMSESP_DEFAULT_PUBLISH_TIME;
uint16_t publish_time_heartbeat; uint16_t publish_time_heartbeat = EMSESP_DEFAULT_PUBLISH_HEARTBEAT;
uint8_t mqtt_qos; uint8_t mqtt_qos = EMSESP_DEFAULT_MQTT_QOS;
bool mqtt_retain; bool mqtt_retain = EMSESP_DEFAULT_MQTT_RETAIN;
bool ha_enabled; bool ha_enabled = EMSESP_DEFAULT_HA_ENABLED;
uint8_t nested_format; uint8_t nested_format = EMSESP_DEFAULT_NESTED_FORMAT;
String discovery_prefix; String discovery_prefix = EMSESP_DEFAULT_DISCOVERY_PREFIX;
uint8_t discovery_type; uint8_t discovery_type = EMSESP_DEFAULT_DISCOVERY_TYPE;
bool publish_single; bool publish_single = EMSESP_DEFAULT_PUBLISH_SINGLE;
bool publish_single2cmd; bool publish_single2cmd = EMSESP_DEFAULT_PUBLISH_SINGLE2CMD;
bool send_response; bool send_response = EMSESP_DEFAULT_SEND_RESPONSE;
uint8_t entity_format; uint8_t entity_format = EMSESP_DEFAULT_ENTITY_FORMAT;
static void read(MqttSettings & settings, JsonObject root); static void read(MqttSettings & settings, JsonObject root);
static StateUpdateResult update(JsonObject root, MqttSettings & settings); static StateUpdateResult update(JsonObject root, MqttSettings & settings);

View File

@@ -30,10 +30,10 @@
class NTPSettings { class NTPSettings {
public: public:
bool enabled; bool enabled = FACTORY_NTP_ENABLED;
String tzLabel; String tzLabel = FACTORY_NTP_TIME_ZONE_LABEL;
String tzFormat; String tzFormat = FACTORY_NTP_TIME_ZONE_FORMAT;
String server; String server = FACTORY_NTP_SERVER;
static void read(NTPSettings & settings, JsonObject root); static void read(NTPSettings & settings, JsonObject root);
static StateUpdateResult update(JsonObject root, NTPSettings & settings); static StateUpdateResult update(JsonObject root, NTPSettings & settings);

View File

@@ -64,17 +64,17 @@
class NetworkSettings { class NetworkSettings {
public: public:
// core wifi configuration // core wifi configuration
String ssid; String ssid = FACTORY_WIFI_SSID;
String bssid; String bssid = "";
String password; String password = FACTORY_WIFI_PASSWORD;
String hostname; String hostname = FACTORY_WIFI_HOSTNAME;
bool staticIPConfig; bool staticIPConfig = false;
bool bandwidth20; bool bandwidth20 = false;
uint8_t tx_power; uint8_t tx_power = 0;
bool nosleep; bool nosleep = true;
bool enableMDNS; bool enableMDNS = true;
bool enableCORS; bool enableCORS = false;
String CORSOrigin; String CORSOrigin = "*";
// optional configuration for static IP address // optional configuration for static IP address
IPAddress localIP; IPAddress localIP;

View File

@@ -9,7 +9,6 @@
#include <list> #include <list>
#define ACCESS_TOKEN_PARAMATER "access_token" #define ACCESS_TOKEN_PARAMATER "access_token"
#define AUTHORIZATION_HEADER "Authorization" #define AUTHORIZATION_HEADER "Authorization"
#define AUTHORIZATION_HEADER_PREFIX "Bearer " #define AUTHORIZATION_HEADER_PREFIX "Bearer "
#define AUTHORIZATION_HEADER_PREFIX_LEN 7 #define AUTHORIZATION_HEADER_PREFIX_LEN 7

View File

@@ -172,7 +172,7 @@ void UploadFileService::handleError(AsyncWebServerRequest * request, int code) {
// check for invalid extension and immediately kill the connection, which will throw an error // check for invalid extension and immediately kill the connection, which will throw an error
// that is caught by the web code. Unfortunately the http error code is not sent to the client on fast network connections // that is caught by the web code. Unfortunately the http error code is not sent to the client on fast network connections
if (code == 406) { if (code == 406) {
request->client()->close(true); request->client()->close();
_is_firmware = false; _is_firmware = false;
Update.abort(); Update.abort();
} }

View File

@@ -576,7 +576,7 @@ bool AnalogSensor::update(uint8_t gpio, const char * org_name, double offset, do
newSensor.is_system = is_system; newSensor.is_system = is_system;
settings.analogCustomizations.push_back(newSensor); settings.analogCustomizations.push_back(newSensor);
// check the gpio again and add to used list // check the gpio again and add to used list
if (EMSESP::system_.add_gpio(gpio, "Analog Sensor")) { if (EMSESP::system_.add_gpio(gpio, name)) {
LOG_DEBUG("Adding customization for analog sensor GPIO %02d", gpio); LOG_DEBUG("Adding customization for analog sensor GPIO %02d", gpio);
return StateUpdateResult::CHANGED; // persist the change return StateUpdateResult::CHANGED; // persist the change
} else { } else {

View File

@@ -25,10 +25,6 @@
#define EMSESP_DEFAULT_LOCALE EMSESP_LOCALE_EN // English #define EMSESP_DEFAULT_LOCALE EMSESP_LOCALE_EN // English
#endif #endif
#ifndef EMSESP_DEFAULT_VERSION
#define EMSESP_DEFAULT_VERSION ""
#endif
#ifndef EMSESP_DEFAULT_TX_MODE #ifndef EMSESP_DEFAULT_TX_MODE
#define EMSESP_DEFAULT_TX_MODE 1 // EMS1.0 #define EMSESP_DEFAULT_TX_MODE 1 // EMS1.0
#endif #endif

View File

@@ -20,6 +20,7 @@
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
#include "esp_ota_ops.h" #include "esp_ota_ops.h"
#include "rom/rtc.h"
#endif #endif
static_assert(uuid::thread_safe, "uuid-common must be thread-safe"); static_assert(uuid::thread_safe, "uuid-common must be thread-safe");
@@ -1721,15 +1722,31 @@ void EMSESP::start() {
LOG_INFO("EMS-ESP version %s", EMSESP_APP_VERSION); LOG_INFO("EMS-ESP version %s", EMSESP_APP_VERSION);
#endif #endif
// check if the firmware is fresh LOG_DEBUG("System is running in Debug mode");
// check if the firmware is fresh, i.e. a new install or a new version has been uploaded
// this is set in UploadFileService::uploadComplete() // this is set in UploadFileService::uploadComplete()
// and reset in System::set_partition_install_date() // and reset in System::set_partition_install_date()
if (!EMSESP::nvs_.getBool(EMSESP_NVS_BOOT_NEW_FIRMWARE)) { if (EMSESP::nvs_.getBool(EMSESP_NVS_BOOT_NEW_FIRMWARE)) {
LOG_DEBUG("Firmware is fresh"); LOG_DEBUG("Firmware is a new install");
} else {
// check if the firmware has been uploaded via Serial/USB
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
if (rtc_get_reset_reason(0) == 11) { // ESP_RST_USB (Reset by USB peripheral, on CPU 0 only
#else
if ((rtc_get_reset_reason(0) == 14 || rtc_get_reset_reason(1) == 14)) { // APP CPU reset by PRO CPU, can be either CPUs
#endif
LOG_DEBUG("Firmware is a new install, uploaded via Serial/USB");
EMSESP::nvs_.putBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, true); // set flag so it's picked up later to set the install date
}
} }
LOG_DEBUG("System is running in Debug mode"); // S2 are C3 are both single core
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
LOG_INFO("Last system reset reason Core0: %s", system_.reset_reason(0).c_str());
#else
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
// see if we're restoring a settings file // see if we're restoring a settings file
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
@@ -1837,7 +1854,7 @@ void EMSESP::loop() {
if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_INVALID_GPIO) { if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_INVALID_GPIO) {
static bool only_once = false; static bool only_once = false;
if (!only_once) { if (!only_once) {
LOG_ERROR("Invalid GPIOs used. Please check your settings and log"); LOG_ERROR("Invalid GPIOs used. Please check your settings and the system log");
only_once = true; only_once = true;
} }
} }

View File

@@ -106,7 +106,7 @@ bool System::led_flash_timer_ = false;
// GPIOs // GPIOs
std::vector<uint8_t, AllocatorPSRAM<uint8_t>> System::valid_system_gpios_; std::vector<uint8_t, AllocatorPSRAM<uint8_t>> System::valid_system_gpios_;
std::vector<uint8_t, AllocatorPSRAM<uint8_t>> System::used_gpios_; std::vector<System::GpioUsage, AllocatorPSRAM<System::GpioUsage>> System::used_gpios_;
// find the index of the language // find the index of the language
// 0 = EN, 1 = DE, etc... // 0 = EN, 1 = DE, etc...
@@ -316,11 +316,9 @@ void System::get_partition_info() {
auto current_partition = (const char *)esp_ota_get_running_partition()->label; auto current_partition = (const char *)esp_ota_get_running_partition()->label;
// update the current version and partition name in NVS if not already set (saves on flash wearing) // update the current version and partition name in NVS if not already set
if (EMSESP::nvs_.getString(current_partition) != EMSESP_APP_VERSION || emsesp::EMSESP::nvs_.getBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, false)) { if (EMSESP::nvs_.getString(current_partition) != EMSESP_APP_VERSION || emsesp::EMSESP::nvs_.getBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, true)) {
if (EMSESP::nvs_.getBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, false)) {
EMSESP::nvs_.putBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, false); EMSESP::nvs_.putBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, false);
}
EMSESP::nvs_.putString(current_partition, EMSESP_APP_VERSION); EMSESP::nvs_.putString(current_partition, EMSESP_APP_VERSION);
char c[20]; char c[20];
snprintf(c, sizeof(c), "d_%s", current_partition); snprintf(c, sizeof(c), "d_%s", current_partition);
@@ -1216,16 +1214,16 @@ void System::show_system(uuid::console::Shell & shell) {
// GPIOs // GPIOs
shell.println(" GPIOs:"); shell.println(" GPIOs:");
shell.printf(" in use:"); shell.printf(" in use:");
for (const auto & gpio : used_gpios_) { for (const auto & usage : used_gpios_) {
shell.printf(" %d", gpio); shell.printf(" %d(%s)", usage.pin, usage.source.c_str());
} }
shell.printfln(" (total %d)", used_gpios_.size()); shell.printfln(" [total %d]", used_gpios_.size());
auto available = available_gpios(); auto available = available_gpios();
shell.printf(" available:"); shell.printf(" available:");
for (const auto & gpio : available) { for (const auto & gpio : available) {
shell.printf(" %d", gpio); shell.printf(" %d", gpio);
} }
shell.printfln(" (total %d)", available.size()); shell.printfln(" [total %d]", available.size());
// List all partitions and their version info // List all partitions and their version info
shell.println(" Partitions:"); shell.println(" Partitions:");
for (const auto & partition : partition_info_) { for (const auto & partition : partition_info_) {
@@ -1410,7 +1408,7 @@ bool System::check_upgrade() {
// see if we're missing a version, will be < 3.5.0b13 from Dec 23 2022 // see if we're missing a version, will be < 3.5.0b13 from Dec 23 2022
missing_version = (settingsVersion.empty() || (settingsVersion.length() < 5)); missing_version = (settingsVersion.empty() || (settingsVersion.length() < 5));
if (missing_version) { if (missing_version) {
LOG_WARNING("No version information found"); LOG_WARNING("No version information found. Assuming version 3.5.0");
settingsVersion = "3.5.0"; // this was the last stable version without version info settingsVersion = "3.5.0"; // this was the last stable version without version info
} }
@@ -1422,7 +1420,7 @@ bool System::check_upgrade() {
bool save_version = true; bool save_version = true;
bool reboot_required = false; bool reboot_required = false;
LOG_DEBUG("Checking for version upgrades (settings file is v%d.%d.%d%s)", LOG_DEBUG("Checking for version upgrades from v%d.%d.%d%s",
settings_version.major(), settings_version.major(),
settings_version.minor(), settings_version.minor(),
settings_version.patch(), settings_version.patch(),
@@ -1432,7 +1430,7 @@ bool System::check_upgrade() {
if (this_version > settings_version) { if (this_version > settings_version) {
// we need to do an upgrade // we need to do an upgrade
if (missing_version) { if (missing_version) {
LOG_NOTICE("Upgrading to version %d.%d.%d%s", this_version.major(), this_version.minor(), this_version.patch(), this_version_type); LOG_NOTICE("Upgrading to version %d.%d.%d%s", this_version.major(), this_version.minor(), this_version.patch(), this_version_type.c_str());
} else { } else {
LOG_NOTICE("Upgrading from version %d.%d.%d%s to %d.%d.%d%s", LOG_NOTICE("Upgrading from version %d.%d.%d%s to %d.%d.%d%s",
settings_version.major(), settings_version.major(),
@@ -1499,7 +1497,15 @@ bool System::check_upgrade() {
}); });
} else if (this_version < settings_version) { } else if (this_version < settings_version) {
// downgrading // downgrading
LOG_NOTICE("Downgrading to version %d.%d.%d%s", this_version.major(), this_version.minor(), this_version.patch(), this_version_type.c_str()); LOG_NOTICE("Downgrading from version %d.%d.%d%s to version %d.%d.%d%s",
settings_version.major(),
settings_version.minor(),
settings_version.patch(),
settings_version_type.c_str(),
this_version.major(),
this_version.minor(),
this_version.patch(),
this_version_type.c_str());
} else { } else {
save_version = false; // same version, do nothing save_version = false; // same version, do nothing
} }
@@ -2033,6 +2039,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
#endif #endif
node["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3); node["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3);
node["uptimeSec"] = uuid::get_uptime_sec(); node["uptimeSec"] = uuid::get_uptime_sec();
node["resetReason"] = EMSESP::system_.reset_reason(0) + " / " + EMSESP::system_.reset_reason(1);
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
node["platform"] = EMSESP_PLATFORM; node["platform"] = EMSESP_PLATFORM;
node["cpuType"] = ESP.getChipModel(); node["cpuType"] = ESP.getChipModel();
@@ -2045,9 +2052,6 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
node["freeApp"] = EMSESP::system_.appFree(); // kilobytes node["freeApp"] = EMSESP::system_.appFree(); // kilobytes
node["partition"] = (const char *)esp_ota_get_running_partition()->label; // active partition node["partition"] = (const char *)esp_ota_get_running_partition()->label; // active partition
node["flash_chip_size"] = ESP.getFlashChipSize() / 1024; // kilobytes node["flash_chip_size"] = ESP.getFlashChipSize() / 1024; // kilobytes
#endif
node["resetReason"] = EMSESP::system_.reset_reason(0) + " / " + EMSESP::system_.reset_reason(1);
#ifndef EMSESP_STANDALONE
node["psram"] = (EMSESP::system_.PSram() > 0); // make boolean node["psram"] = (EMSESP::system_.PSram() > 0); // make boolean
if (EMSESP::system_.PSram()) { if (EMSESP::system_.PSram()) {
node["psramSize"] = EMSESP::system_.PSram(); node["psramSize"] = EMSESP::system_.PSram();
@@ -2057,9 +2061,27 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 #if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
node["temperature"] = EMSESP::system_.temperature(); node["temperature"] = EMSESP::system_.temperature();
#endif #endif
node["txpause"] = EMSbus::tx_mode() == EMS_TXMODE_OFF;
#endif #endif
node["txpause"] = EMSbus::tx_mode() == EMS_TXMODE_OFF;
// GPIO information
std::string gpios_in_use_str;
for (const auto & usage : EMSESP::system_.used_gpios_) {
if (!gpios_in_use_str.empty()) {
gpios_in_use_str += ", ";
}
gpios_in_use_str += Helpers::itoa(usage.pin);
}
node["gpios_in_use"] = gpios_in_use_str;
std::string gpios_available_str;
for (const auto & gpio : EMSESP::system_.available_gpios()) {
if (!gpios_available_str.empty()) {
gpios_available_str += ", ";
}
gpios_available_str += Helpers::itoa(gpio);
}
node["gpios_available"] = gpios_available_str;
// Network Status // Network Status
node = output["network"].to<JsonObject>(); node = output["network"].to<JsonObject>();
@@ -2448,15 +2470,15 @@ bool System::command_txpause(const char * value, const int8_t id) {
// format command - factory reset, removing all config files // format command - factory reset, removing all config files
bool System::command_format(const char * value, const int8_t id) { bool System::command_format(const char * value, const int8_t id) {
#if !defined(EMSESP_STANDALONE) && !defined(EMSESP_DEBUG) #if !defined(EMSESP_STANDALONE) && !defined(EMSESP_TEST)
// don't really format the filesystem in debug or standalone mode // don't really format the filesystem in test or standalone mode
if (LittleFS.format()) { if (LittleFS.format()) {
LOG_INFO("Filesystem formatted successfully. All config files removed."); LOG_INFO("Filesystem formatted successfully. All config files removed.");
} else { } else {
LOG_ERROR("Format failed"); LOG_ERROR("Format failed");
} }
#else #else
LOG_INFO("Format command not available in standalone or debug mode"); LOG_ERROR("Format command not available in standalone or test mode");
#endif #endif
// restart will be handled by the main loop // restart will be handled by the main loop
@@ -2553,21 +2575,6 @@ bool System::ntp_connected() {
// see if its a BBQKees Gateway by checking the nvs values // see if its a BBQKees Gateway by checking the nvs values
String System::getBBQKeesGatewayDetails(uint8_t detail) { String System::getBBQKeesGatewayDetails(uint8_t detail) {
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
/*
if (!EMSESP::nvs_.isKey("mfg")) {
return "";
}
// mfg can be either "BBQKees" or "BBQKees Electronics"
auto mfg = EMSESP::nvs_.getString("mfg");
if (mfg) {
if (!mfg.startsWith("BBQKees")) {
return "";
}
}
return "BBQKees Gateway Model " + EMSESP::nvs_.getString("model") + " v" + EMSESP::nvs_.getString("hwrevision") + "/" + EMSESP::nvs_.getString("batch");
*/
union { union {
struct { struct {
uint32_t no : 4; uint32_t no : 4;
@@ -2580,14 +2587,17 @@ String System::getBBQKeesGatewayDetails(uint8_t detail) {
}; };
uint32_t reg; uint32_t reg;
} gw; } gw;
for (uint8_t reg = 0; reg < 8; reg++) { for (uint8_t reg = 0; reg < 8; reg++) {
gw.reg = esp_efuse_read_reg(EFUSE_BLK3, reg); gw.reg = esp_efuse_read_reg(EFUSE_BLK3, reg);
if (reg == 7 || esp_efuse_read_reg(EFUSE_BLK3, reg + 1) == 0) if (reg == 7 || esp_efuse_read_reg(EFUSE_BLK3, reg + 1) == 0)
break; break;
} }
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:
return gw.mfg < 2 ? String(mfg[gw.mfg]) : "unknown"; return gw.mfg < 2 ? String(mfg[gw.mfg]) : "unknown";
@@ -2605,9 +2615,11 @@ String System::getBBQKeesGatewayDetails(uint8_t detail) {
default: default:
break; break;
} }
if (!gw.reg || gw.mfg > 1 || gw.model > 5) { if (!gw.reg || gw.mfg > 1 || gw.model > 5) {
return ""; return "";
} }
return String(mfg[gw.mfg]) + " " + String(model[gw.model]) + " rev." + String(gw.rev_major) + "." + String(gw.rev_minor) + "/" + String(2000 + gw.year) return String(mfg[gw.mfg]) + " " + String(model[gw.model]) + " rev." + String(gw.rev_major) + "." + String(gw.rev_minor) + "/" + String(2000 + gw.year)
+ (gw.month < 10 ? "0" : "") + String(gw.month) + String(gw.no); + (gw.month < 10 ? "0" : "") + String(gw.month) + String(gw.no);
#else #else
@@ -2684,6 +2696,9 @@ bool System::uploadFirmwareURL(const char * url) {
// we're about to start the upload, set the status so the Web System Monitor spots it // we're about to start the upload, set the status so the Web System Monitor spots it
EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_UPLOADING); EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_UPLOADING);
// set a callback so we can monitor progress in the WebUI
Update.onProgress([](size_t progress, size_t total) { EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_UPLOADING + (progress * 100 / total)); });
// get tcp stream and send it to Updater // get tcp stream and send it to Updater
WiFiClient * stream = http.getStreamPtr(); WiFiClient * stream = http.getStreamPtr();
if (Update.writeStream(*stream) != firmware_size) { if (Update.writeStream(*stream) != firmware_size) {
@@ -2772,19 +2787,27 @@ bool System::command_read(const char * value, const int8_t id) {
} }
// set the system status code - SYSTEM_STATUS in system.h // set the system status code - SYSTEM_STATUS in system.h
// this is also used in the SystemMonitor.tsx WebUI to show the progress of the firmware upload, start at 100
void System::systemStatus(uint8_t status_code) { void System::systemStatus(uint8_t status_code) {
if (systemStatus_ != status_code) { if (systemStatus_ != status_code) {
systemStatus_ = status_code; systemStatus_ = status_code;
#ifdef EMSESP_DEBUG
if (status_code < SYSTEM_STATUS::SYSTEM_STATUS_UPLOADING) {
LOG_DEBUG("Setting System status code %d", status_code); LOG_DEBUG("Setting System status code %d", status_code);
} }
#endif
}
} }
uint8_t System::systemStatus() { uint8_t System::systemStatus() {
return systemStatus_; return systemStatus_;
} }
// takes a string range like "6-11, 1, 23, 24-48" which has optional ranges and single values and converts to a vector of ints // takes two arguments:
std::vector<uint8_t, AllocatorPSRAM<uint8_t>> System::string_range_to_vector(const std::string & range) { // the first is the full range of pins to consider
// the second is a string range of GPIOs to exclude, like "6-11, 1, 23, 24-48"
// returns a vector array of GPIOs that are valid for use
std::vector<uint8_t, AllocatorPSRAM<uint8_t>> System::string_range_to_vector(const std::string & range, const std::string & exclude) {
std::vector<uint8_t, AllocatorPSRAM<uint8_t>> gpios; std::vector<uint8_t, AllocatorPSRAM<uint8_t>> gpios;
std::string::size_type pos = 0; std::string::size_type pos = 0;
std::string::size_type prev = 0; std::string::size_type prev = 0;
@@ -2816,41 +2839,122 @@ std::vector<uint8_t, AllocatorPSRAM<uint8_t>> System::string_range_to_vector(con
// handle the last part // handle the last part
process_part(range.substr(prev)); process_part(range.substr(prev));
// if exclude list is provided, parse it and remove excluded GPIOs
if (!exclude.empty()) {
std::vector<uint8_t, AllocatorPSRAM<uint8_t>> exclude_gpios;
pos = 0;
prev = 0;
auto process_exclude = [&exclude_gpios](std::string part) {
// trim whitespace
part.erase(0, part.find_first_not_of(" \t"));
part.erase(part.find_last_not_of(" \t") + 1);
// check if it's a range (contains '-')
std::string::size_type dash_pos = part.find('-');
if (dash_pos != std::string::npos) {
// it's a range like "6-11"
int start = std::stoi(part.substr(0, dash_pos));
int end = std::stoi(part.substr(dash_pos + 1));
for (int i = start; i <= end; i++) {
exclude_gpios.push_back(static_cast<uint8_t>(i));
}
} else {
exclude_gpios.push_back(static_cast<uint8_t>(std::stoi(part)));
}
};
while ((pos = exclude.find(',', prev)) != std::string::npos) {
process_exclude(exclude.substr(prev, pos - prev));
prev = pos + 1;
}
// handle the last part
process_exclude(exclude.substr(prev));
// remove excluded GPIOs from the main list
gpios.erase(std::remove_if(gpios.begin(),
gpios.end(),
[&exclude_gpios](uint8_t gpio) { return std::find(exclude_gpios.begin(), exclude_gpios.end(), gpio) != exclude_gpios.end(); }),
gpios.end());
}
return gpios; return gpios;
} }
// initialize a list of valid GPIOs based on the ESP32 board // initialize a list of valid GPIOs based on the ESP32 board
// note: we always allow 0, which is used to indicate Dallas or LED is disabled // string_to_vector() take two strings, the first is the range of GPIOs to use, the second is a list of GPIOs to exclude
// notes:
// we always allow 0 (which is usually a strapping pin), because it's used to indicate whether EMS-ESP Dallas or the LED is disabled
// we allow UART0, 1 and 2 as they are configurable
// strapping pins are disabled as they can affect boot behaviour
// we accept GPIOs that are fixed on BBQKees boards
//
void System::set_valid_system_gpios() { void System::set_valid_system_gpios() {
valid_system_gpios_.clear(); // reset system list valid_system_gpios_.clear(); // reset system list
used_gpios_.clear(); // reset used list used_gpios_.clear(); // reset used list
// get free gpios based on board/platform type // get free gpios based on board/platform type
#if CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32C3
// https://www.wemos.cc/en/latest/c3/c3_mini.html // https://docs.espressif.com/projects/esp-idf/en/stable/esp32c3/api-reference/peripherals/gpio.html
valid_system_gpios_ = string_range_to_vector("0-10"); // UART0=20,21 // excluded:
// GPIO2, GPIO8 - GPIO9 = strapping pins
// GPIO12 - GPIO17 = used for SPI flash and PSRAM
// GPIO18 - GPIO19 = USB-JTAG
//
// notes on what is allowed:
// GPIO10 = button on BOARD_C3_MINI_V1
valid_system_gpios_ = string_range_to_vector("0-21", "2, 8-9, 12-17, 18-19");
#elif CONFIG_IDF_TARGET_ESP32S2 #elif CONFIG_IDF_TARGET_ESP32S2
// 43 and 44 are UART0 pins // https://docs.espressif.com/projects/esp-idf/en/stable/esp32s2/api-reference/peripherals/gpio.html
// 38 and 39 are strapping pins, input only // excluded:
valid_system_gpios_ = string_range_to_vector("0-14, 19, 20, 21, 33-37, 45, 46"); // GPIO26 - GPIO32 = SPI flash and PSRAM
// GPIO45 - GPIO46 = strapping pins
// GPIO39 - GPIO42 = USB-JTAG
// GPIO22 - GPIO25 = don't exist
//
// notes on what is allowed:
valid_system_gpios_ = string_range_to_vector("0-46", "26-32, 45-46, 39-42, 22-25");
#elif CONFIG_IDF_TARGET_ESP32S3 #elif CONFIG_IDF_TARGET_ESP32S3
// 43 and 44 are UART0 pins // https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/peripherals/gpio.html
// 33-37 for Octal SPI (SPIIO4 through SPIIO7 and SPIDQS) // excluded:
// 38 and 39 are input only // GPIO3, GPIO45 - GPIO46 = strapping pins
// 45 and 36 are strapping pins, input only // GPIO26 - GPIO32 = SPI flash and PSRAM and not recommended
// 47 and 48 are valid on a Wemos S3 (https://github.com/emsesp/EMS-ESP32/issues/2874) // GPIO33 - GPIO37 = Octal flash/PSRAM
valid_system_gpios_ = string_range_to_vector("0-14, 17, 18, 21, 33-39, 45-48"); // GPIO19 - GPIO20 = USB-JTAG
// GPIO22 - GPIO25 = don't exist
//
// notes on what is allowed:
// GPIO11 - GPIO19 = ADC analog input only pins
// GPIO47 - GPIO48 = valid on a Wemos S3
// GPIO8 = used by Liligo S3 board profile for Rx
valid_system_gpios_ = string_range_to_vector("0-48", "3, 45-46, 26-32, 33-37, 19-20, 22-25");
#elif CONFIG_IDF_TARGET_ESP32 #elif CONFIG_IDF_TARGET_ESP32
// 1 and 3 are UART0 pins, but used for some eth-boards (BBQKees-E32, OlimexPOE) // https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/gpio.html
// 32-39 is ADC1, input only // excluded:
// GPIO6 - GPIO11, GPIO16 - GPIO17 = used for SPI flash and PSRAM
// GPIO12 - GPIO15 = USB-JTAG (but we allow GPIO14 for BBQKees) and GPIO12 & GPIO13 also reserved for BBQKees E32V2.2
// GPIO20, GPIO24, GPIO28 - GPIO31 = don't exist
//
// notes on what is allowed:
// GPIO34, GPIO35, GPIO37 = input only
// GPIO2, GPIO4, GPIO5, GPIO14 = used on BBQKees boards for either LED, Dallas or Rx
// GPIO23 and GPIO18 are used by Ethernet
// GPIO25 - GPIO37 = ADC2
// GPIO32 - GPIO39 = ADC1
// GPIO36 = used on BBQKees boards for supply_voltage (E32V2.2) (note may conflict with WiFI on other boards)
// GPIO39 = used on BBQKees boards for core_voltage (E32V2.2) (note may conflict with WiFI on other boards)
if (ESP.getPsramSize() > 0) { if (ESP.getPsramSize() > 0) {
// if psram is enabled remove pins 16 and 17 from the list // remove SPI0/1 PSRAM pins GPIO16 (CS) and GPIO17 (CLK) from the list
valid_system_gpios_ = string_range_to_vector("0-5, 12-15, 18-19, 23, 25-27, 32-39"); valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 12, 13, 15, 16, 17, 20, 24, 28-31");
} else { } else {
valid_system_gpios_ = string_range_to_vector("0-5, 12-19, 23, 25-27, 32-39"); valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 12, 13, 15, 20, 24, 28-31");
} }
#elif defined(EMSESP_STANDALONE) #elif defined(EMSESP_STANDALONE)
valid_system_gpios_ = string_range_to_vector("0-5, 12-19, 23, 25-27, 32-39"); valid_system_gpios_ = string_range_to_vector("0-39");
#endif #endif
} }
@@ -2860,8 +2964,9 @@ bool System::add_gpio(uint8_t pin, const char * source_name) {
// check if this is a valid user GPIO // check if this is a valid user GPIO
if (std::find(valid_system_gpios_.begin(), valid_system_gpios_.end(), pin) != valid_system_gpios_.end()) { if (std::find(valid_system_gpios_.begin(), valid_system_gpios_.end(), pin) != valid_system_gpios_.end()) {
// It's valid now check if it's already in the used list // It's valid now check if it's already in the used list
if (std::find(used_gpios_.begin(), used_gpios_.end(), pin) != used_gpios_.end()) { auto it = std::find_if(used_gpios_.begin(), used_gpios_.end(), [pin](const GpioUsage & usage) { return usage.pin == pin; });
LOG_WARNING("GPIO %d for %s is already in use", pin, source_name); if (it != used_gpios_.end()) {
LOG_WARNING("GPIO %d for %s is already in use by %s", pin, source_name, it->source.c_str());
return false; // Pin is already used return false; // Pin is already used
} }
} else { } else {
@@ -2874,24 +2979,24 @@ bool System::add_gpio(uint8_t pin, const char * source_name) {
remove_gpio(pin); remove_gpio(pin);
LOG_DEBUG("Adding GPIO %d for %s to used gpio list", pin, source_name); LOG_DEBUG("Adding GPIO %d for %s to used gpio list", pin, source_name);
used_gpios_.push_back(pin); // add to used list used_gpios_.push_back({pin, source_name}); // add to used list
return true; return true;
} }
// remove a gpio from both valid and used lists // remove a gpio from both valid and used lists
void System::remove_gpio(uint8_t pin, bool also_system) { void System::remove_gpio(uint8_t pin, bool also_system) {
auto it = std::find(used_gpios_.begin(), used_gpios_.end(), pin); auto it = std::find_if(used_gpios_.begin(), used_gpios_.end(), [pin](const GpioUsage & usage) { return usage.pin == pin; });
if (it != used_gpios_.end()) { if (it != used_gpios_.end()) {
LOG_DEBUG("GPIO %d removed from used gpio list", pin); LOG_DEBUG("GPIO %d removed from used gpio list", pin);
used_gpios_.erase(it); used_gpios_.erase(it);
} }
if (also_system) { if (also_system) {
it = std::find(valid_system_gpios_.begin(), valid_system_gpios_.end(), pin); auto it_sys = std::find(valid_system_gpios_.begin(), valid_system_gpios_.end(), pin);
if (it != valid_system_gpios_.end()) { if (it_sys != valid_system_gpios_.end()) {
LOG_DEBUG("GPIO %d removed from valid gpio list", pin); LOG_DEBUG("GPIO %d removed from valid gpio list", pin);
valid_system_gpios_.erase(it); valid_system_gpios_.erase(it_sys);
} }
} }
} }
@@ -2900,7 +3005,7 @@ void System::remove_gpio(uint8_t pin, bool also_system) {
std::vector<uint8_t> System::available_gpios() { std::vector<uint8_t> System::available_gpios() {
std::vector<uint8_t> gpios; std::vector<uint8_t> gpios;
for (const auto & gpio : valid_system_gpios_) { for (const auto & gpio : valid_system_gpios_) {
if (std::find(used_gpios_.begin(), used_gpios_.end(), gpio) == used_gpios_.end()) { if (std::find_if(used_gpios_.begin(), used_gpios_.end(), [gpio](const GpioUsage & usage) { return usage.pin == gpio; }) == used_gpios_.end()) {
gpios.push_back(gpio); // didn't find it in used_gpios_, so it's available gpios.push_back(gpio); // didn't find it in used_gpios_, so it's available
} }
} }
@@ -2909,8 +3014,8 @@ std::vector<uint8_t> System::available_gpios() {
// make a snapshot of the current GPIOs // make a snapshot of the current GPIOs
void System::make_snapshot_gpios(std::vector<int8_t> & u_gpios, std::vector<int8_t> & s_gpios) { void System::make_snapshot_gpios(std::vector<int8_t> & u_gpios, std::vector<int8_t> & s_gpios) {
for (const auto & gpio : used_gpios_) { for (const auto & usage : used_gpios_) {
u_gpios.push_back(gpio); u_gpios.push_back(usage.pin);
} }
for (const auto & gpio : valid_system_gpios_) { for (const auto & gpio : valid_system_gpios_) {
s_gpios.push_back(gpio); s_gpios.push_back(gpio);
@@ -2921,7 +3026,7 @@ void System::make_snapshot_gpios(std::vector<int8_t> & u_gpios, std::vector<int8
void System::restore_snapshot_gpios(std::vector<int8_t> & u_gpios, std::vector<int8_t> & s_gpios) { void System::restore_snapshot_gpios(std::vector<int8_t> & u_gpios, std::vector<int8_t> & s_gpios) {
used_gpios_.clear(); used_gpios_.clear();
for (const auto & gpio : u_gpios) { for (const auto & gpio : u_gpios) {
used_gpios_.push_back(gpio); used_gpios_.push_back({static_cast<uint8_t>(gpio), "restored"});
} }
valid_system_gpios_.clear(); valid_system_gpios_.clear();

View File

@@ -159,7 +159,6 @@ class System {
static void extractSettings(const char * filename, const char * section, JsonObject output); static void extractSettings(const char * filename, const char * section, JsonObject output);
static bool saveSettings(const char * filename, const char * section, JsonObject input); static bool saveSettings(const char * filename, const char * section, JsonObject input);
// GPIOs
static bool add_gpio(uint8_t pin, const char * source_name); static bool add_gpio(uint8_t pin, const char * source_name);
static std::vector<uint8_t> available_gpios(); static std::vector<uint8_t> available_gpios();
static bool load_board_profile(std::vector<int8_t> & data, const std::string & board_profile); static bool load_board_profile(std::vector<int8_t> & data, const std::string & board_profile);
@@ -434,11 +433,15 @@ class System {
void led_monitor(); void led_monitor();
void system_check(); void system_check();
static std::vector<uint8_t, AllocatorPSRAM<uint8_t>> string_range_to_vector(const std::string & range); static std::vector<uint8_t, AllocatorPSRAM<uint8_t>> string_range_to_vector(const std::string & range, const std::string & exclude = "");
// GPIOs // GPIOs
struct GpioUsage {
uint8_t pin;
std::string source;
};
static std::vector<uint8_t, AllocatorPSRAM<uint8_t>> valid_system_gpios_; // list of valid GPIOs for the ESP32 board that can be used static std::vector<uint8_t, AllocatorPSRAM<uint8_t>> valid_system_gpios_; // list of valid GPIOs for the ESP32 board that can be used
static std::vector<uint8_t, AllocatorPSRAM<uint8_t>> used_gpios_; // list of GPIOs used by the application static std::vector<GpioUsage, AllocatorPSRAM<GpioUsage>> used_gpios_; // list of GPIOs used by the application
int8_t wifi_quality(int8_t dBm); int8_t wifi_quality(int8_t dBm);

View File

@@ -221,14 +221,14 @@ void RxService::add(uint8_t * data, uint8_t length) {
LOG_TRACE("Rx: %s", Helpers::data_to_hex(data, length).c_str()); LOG_TRACE("Rx: %s", Helpers::data_to_hex(data, length).c_str());
} }
LOG_DEBUG("New Rx telegram, message length %d", message_length); // if we don't have a type_id exit
// do not exit on empty message, it is checked later for toggle fetch
// if we don't have a type_id exit,
// do not exit on empty message, it is checked for toggle fetch
if (type_id == 0) { if (type_id == 0) {
return; return;
} }
LOG_DEBUG("New Rx telegram, message length %d", message_length);
// create the telegram // create the telegram
auto telegram = std::make_shared<Telegram>(operation, src, dest, type_id, offset, message_data, message_length); auto telegram = std::make_shared<Telegram>(operation, src, dest, type_id, offset, message_data, message_length);

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.8.1-dev.3" #define EMSESP_APP_VERSION "3.8.1-dev.4"

View File

@@ -120,10 +120,11 @@ StateUpdateResult WebCustomization::update(JsonObject root, WebCustomization & c
for (const JsonObject analogJson : analogJsons) { for (const JsonObject analogJson : analogJsons) {
// create each of the sensor, overwriting any previous settings // create each of the sensor, overwriting any previous settings
// if the gpio is invalid skip the sensor // if the gpio is invalid skip the sensor
if (!EMSESP::system_.add_gpio(analogJson["gpio"].as<uint8_t>(), "Analog Sensor")) { auto analog_sensor_name = analogJson["name"].as<const char *>();
if (!EMSESP::system_.add_gpio(analogJson["gpio"].as<uint8_t>(), analog_sensor_name)) {
EMSESP::logger().warning("Analog sensor: Invalid GPIO %d for %s. Skipping.", EMSESP::logger().warning("Analog sensor: Invalid GPIO %d for %s. Skipping.",
analogJson["gpio"].as<uint8_t>(), analogJson["gpio"].as<uint8_t>(),
analogJson["name"].as<const char *>()); analog_sensor_name);
continue; continue;
} }
auto analog = AnalogCustomization(); auto analog = AnalogCustomization();

View File

@@ -97,7 +97,7 @@ void WebLogService::show(Shell & shell) {
} }
shell.println(); shell.println();
shell.printfln("Recent Log (level %s, max %d messages):", uuid::log::format_level_uppercase(level_), maximum_log_messages_); shell.printfln("Recent Log:");
shell.println(); shell.println();
for (const auto & message : log_messages_) { for (const auto & message : log_messages_) {

View File

@@ -96,9 +96,7 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
std::vector<int8_t> system_gpios; std::vector<int8_t> system_gpios;
EMSESP::system_.make_snapshot_gpios(used_gpios, system_gpios); EMSESP::system_.make_snapshot_gpios(used_gpios, system_gpios);
reset_flags(); settings.version = root["version"] | EMSESP_APP_VERSION; // save the version, we use it later in System::check_upgrade()
settings.version = root["version"] | EMSESP_DEFAULT_VERSION; // save the version, we use it later in System::check_upgrade()
settings.board_profile = root["board_profile"] | EMSESP_DEFAULT_BOARD_PROFILE; settings.board_profile = root["board_profile"] | EMSESP_DEFAULT_BOARD_PROFILE;
// get current values that are related to the board profile // get current values that are related to the board profile
@@ -113,10 +111,13 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
settings.eth_clock_mode = root["eth_clock_mode"]; settings.eth_clock_mode = root["eth_clock_mode"];
settings.led_type = root["led_type"]; // 1 = RGB-LED settings.led_type = root["led_type"]; // 1 = RGB-LED
reset_flags();
// see if the user has changed the board profile // see if the user has changed the board profile
// this will set: led_gpio, dallas_gpio, rx_gpio, tx_gpio, pbutton_gpio, phy_type, eth_power, eth_phy_addr, eth_clock_mode, led_type // this will set: led_gpio, dallas_gpio, rx_gpio, tx_gpio, pbutton_gpio, phy_type, eth_power, eth_phy_addr, eth_clock_mode, led_type
// this will always run when EMS-ESP starts since original_settings{} is empty // this will always run when EMS-ESP starts since original_settings{} is empty
if (original_settings.board_profile != settings.board_profile) { if (original_settings.board_profile != settings.board_profile || original_settings.board_profile == "default"
|| original_settings.board_profile.length() == 0) {
set_board_profile(settings); set_board_profile(settings);
add_flags(ChangeFlags::RESTART); add_flags(ChangeFlags::RESTART);
} }
@@ -306,10 +307,10 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
// save the settings if changed from the webUI // save the settings if changed from the webUI
// if we encountered an invalid GPIO, rollback changes and don't save settings, and report the error to WebUI // if we encountered an invalid GPIO, rollback changes and don't save settings, and report the error to WebUI
// without a restart
if (!have_valid_gpios) { if (!have_valid_gpios) {
// replace settings with original settings // replace settings with original settings
settings = original_settings; // the original settings are still valid settings = original_settings;
// restore the GPIOs from the snapshot
EMSESP::system_.restore_snapshot_gpios(used_gpios, system_gpios); EMSESP::system_.restore_snapshot_gpios(used_gpios, system_gpios);
// report the error to WebUI // report the error to WebUI
@@ -320,7 +321,8 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
// save the setting internally, for reference later // save the setting internally, for reference later
EMSESP::system_.store_settings(settings); EMSESP::system_.store_settings(settings);
if (has_flags(WebSettings::ChangeFlags::RESTART)) { // and finally always write to the settings file
if (has_flags(ChangeFlags::RESTART)) {
return StateUpdateResult::CHANGED_RESTART; return StateUpdateResult::CHANGED_RESTART;
} }

View File

@@ -30,7 +30,7 @@ namespace emsesp {
class WebSettings { class WebSettings {
public: public:
String version; String version = EMSESP_APP_VERSION;
String locale; String locale;
uint8_t tx_mode; uint8_t tx_mode;
uint8_t ems_bus_id; uint8_t ems_bus_id;

View File

@@ -203,17 +203,40 @@ void capture(const char * url = nullptr) {
} }
if (url) { if (url) {
// call API, find and replace all double quotes with escaped quotes // call API, store the response in a string
std::string escaped_response = call_url(url); std::string response = call_url(url);
size_t pos = 0; // escape all special characters for C++ string literal
while ((pos = escaped_response.find("\"", pos)) != std::string::npos) { std::string escaped_response;
escaped_response.replace(pos, 1, "\\\""); escaped_response.reserve(response.length() * 2); // pre-allocate for efficiency
pos += 2;
for (char c : response) {
switch (c) {
case '\n':
escaped_response += "\\n";
break;
case '\r':
escaped_response += "\\r";
break;
case '\t':
escaped_response += "\\t";
break;
case '\\':
escaped_response += "\\\\";
break;
case '\"':
escaped_response += "\\\"";
break;
default:
escaped_response += c;
break;
}
} }
Serial.printf("void test_%d() {\n", count++); Serial.printf("void test_%d() {\n", count++);
Serial.printf(" auto expected_response = \"%s\";\n", escaped_response.c_str()); Serial.print(" auto expected_response = \"");
Serial.print(escaped_response.c_str());
Serial.println("\";");
Serial.printf(" TEST_ASSERT_EQUAL_STRING(expected_response, call_url(\"%s\"));\n", url); Serial.printf(" TEST_ASSERT_EQUAL_STRING(expected_response, call_url(\"%s\"));\n", url);
Serial.println("}"); Serial.println("}");
Serial.println(); Serial.println();

View File

@@ -67,103 +67,159 @@ void test_4() {
} }
void test_5() { void test_5() {
auto expected_response =
"[{\"api_data\":\"# HELP emsesp_heatingoff force heating off, boolean, readable, writeable, visible\\n# TYPE emsesp_heatingoff "
"gauge\\nemsesp_heatingoff 0\\n# HELP emsesp_heatingactive is my heating on?, boolean, readable, visible\\n# TYPE emsesp_heatingactive "
"gauge\\nemsesp_heatingactive 0\\n# HELP emsesp_tapwateractive tapwater active, boolean, readable, visible\\n# TYPE emsesp_tapwateractive "
"gauge\\nemsesp_tapwateractive 1\\n# HELP emsesp_selflowtemp selected flow temperature, °C, readable, writeable, visible\\n# TYPE emsesp_selflowtemp "
"gauge\\nemsesp_selflowtemp 0\\n# HELP emsesp_curflowtemp current flow temperature, °C, readable, visible\\n# TYPE emsesp_curflowtemp "
"gauge\\nemsesp_curflowtemp 60.20\\n# HELP emsesp_rettemp return temperature, °C, readable, visible\\n# TYPE emsesp_rettemp gauge\\nemsesp_rettemp "
"48.10\\n# HELP emsesp_syspress system pressure, bar, readable, visible\\n# TYPE emsesp_syspress gauge\\nemsesp_syspress 1.40\\n# HELP emsesp_burngas "
"gas, boolean, readable, visible\\n# TYPE emsesp_burngas gauge\\nemsesp_burngas 1\\n# HELP emsesp_burngas2 gas stage 2, boolean, readable, visible\\n# "
"TYPE emsesp_burngas2 gauge\\nemsesp_burngas2 0\\n# HELP emsesp_flamecurr flame current, µA, readable, visible\\n# TYPE emsesp_flamecurr "
"gauge\\nemsesp_flamecurr 37.40\\n# HELP emsesp_fanwork fan, boolean, readable, visible\\n# TYPE emsesp_fanwork gauge\\nemsesp_fanwork 1\\n# HELP "
"emsesp_ignwork ignition, boolean, readable, visible\\n# TYPE emsesp_ignwork gauge\\nemsesp_ignwork 0\\n# HELP emsesp_oilpreheat oil preheating, "
"boolean, readable, visible\\n# TYPE emsesp_oilpreheat gauge\\nemsesp_oilpreheat 0\\n# HELP emsesp_heatingpump heating pump, boolean, readable, "
"visible\\n# TYPE emsesp_heatingpump gauge\\nemsesp_heatingpump 1\\n# HELP emsesp_selburnpow burner selected max power, %, readable, writeable, "
"visible\\n# TYPE emsesp_selburnpow gauge\\nemsesp_selburnpow 115\\n# HELP emsesp_curburnpow burner current power, %, readable, visible\\n# TYPE "
"emsesp_curburnpow gauge\\nemsesp_curburnpow 61\\n# HELP emsesp_ubauptime total UBA operating time, minutes, readable, visible\\n# TYPE "
"emsesp_ubauptime gauge\\nemsesp_ubauptime 3940268\\n# HELP emsesp_servicecodenumber service code number, readable, visible\\n# TYPE "
"emsesp_servicecodenumber gauge\\nemsesp_servicecodenumber 201\\n# HELP emsesp_seltemp selected temperature, °C, readable, writeable, visible\\n# TYPE "
"emsesp_seltemp gauge\\nemsesp_seltemp{circuit=\\\"dhw\\\"} 52\\n# HELP emsesp_comfort comfort, enum, (0: hot; 1: eco; 2: intelligent), readable, "
"writeable, visible\\n# TYPE emsesp_comfort gauge\\nemsesp_comfort{circuit=\\\"dhw\\\"} 0\\n# HELP emsesp_flowtempoffset flow temperature offset, °C, "
"readable, writeable, visible\\n# TYPE emsesp_flowtempoffset gauge\\nemsesp_flowtempoffset{circuit=\\\"dhw\\\"} 40\\n# HELP emsesp_chargeoptimization "
"charge optimization, boolean, readable, writeable, visible\\n# TYPE emsesp_chargeoptimization gauge\\nemsesp_chargeoptimization{circuit=\\\"dhw\\\"} "
"0\\n# HELP emsesp_circpump circulation pump available, boolean, readable, writeable, visible\\n# TYPE emsesp_circpump "
"gauge\\nemsesp_circpump{circuit=\\\"dhw\\\"} 0\\n# HELP emsesp_chargetype charging type, enum, (0: chargepump; 1: 3-way valve), readable, visible\\n# "
"TYPE emsesp_chargetype gauge\\nemsesp_chargetype{circuit=\\\"dhw\\\"} 1\\n# HELP emsesp_hyston hysteresis on temperature, °C, readable, writeable, "
"visible\\n# TYPE emsesp_hyston gauge\\nemsesp_hyston{circuit=\\\"dhw\\\"} -5\\n# HELP emsesp_disinfectiontemp disinfection temperature, °C, readable, "
"writeable, visible\\n# TYPE emsesp_disinfectiontemp gauge\\nemsesp_disinfectiontemp{circuit=\\\"dhw\\\"} 70\\n# HELP emsesp_circmode circulation pump "
"mode, enum, (0: off; 1: 1x3min; 2: 2x3min; 3: 3x3min; 4: 4x3min; 5: 5x3min; 6: 6x3min; 7: continuous), readable, writeable, visible\\n# TYPE "
"emsesp_circmode gauge\\nemsesp_circmode{circuit=\\\"dhw\\\"} 0\\n# HELP emsesp_circ circulation active, boolean, readable, writeable, visible\\n# "
"TYPE emsesp_circ gauge\\nemsesp_circ{circuit=\\\"dhw\\\"} 0\\n# HELP emsesp_storagetemp1 storage intern temperature, °C, readable, visible\\n# TYPE "
"emsesp_storagetemp1 gauge\\nemsesp_storagetemp1{circuit=\\\"dhw\\\"} 53.80\\n# HELP emsesp_activated activated, boolean, readable, writeable, "
"visible\\n# TYPE emsesp_activated gauge\\nemsesp_activated{circuit=\\\"dhw\\\"} 1\\n# HELP emsesp_3wayvalve 3-way valve active, boolean, readable, "
"visible\\n# TYPE emsesp_3wayvalve gauge\\nemsesp_3wayvalve{circuit=\\\"dhw\\\"} 1\\n# HELP emsesp_chargepump charge pump, boolean, readable, "
"visible\\n# TYPE emsesp_chargepump gauge\\nemsesp_chargepump{circuit=\\\"dhw\\\"} 0\\n# HELP emsesp_nompower nominal Power, kW, readable, writeable, "
"visible\\n# TYPE emsesp_nompower gauge\\nemsesp_nompower 0\\n# HELP emsesp_nrgtotal total energy, kWh, readable, visible\\n# TYPE emsesp_nrgtotal "
"gauge\\nemsesp_nrgtotal 0\\n# HELP emsesp_nrgheat energy heating, kWh, readable, writeable, visible\\n# TYPE emsesp_nrgheat gauge\\nemsesp_nrgheat "
"0\\n# HELP emsesp_nrg energy, kWh, readable, writeable, visible\\n# TYPE emsesp_nrg gauge\\nemsesp_nrg{circuit=\\\"dhw\\\"} 0\\n\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/metrics"));
}
void test_6() {
auto expected_response = "[{\"name\":\"comfort\",\"fullname\":\"dhw " auto expected_response = "[{\"name\":\"comfort\",\"fullname\":\"dhw "
"comfort\",\"circuit\":\"dhw\",\"index\":0,\"enum\":[\"hot\",\"eco\",\"intelligent\"],\"value\":\"hot\",\"type\":\"enum\"," "comfort\",\"circuit\":\"dhw\",\"index\":0,\"enum\":[\"hot\",\"eco\",\"intelligent\"],\"value\":\"hot\",\"type\":\"enum\","
"\"readable\":true,\"writeable\":true,\"visible\":true}]"; "\"readable\":true,\"writeable\":true,\"visible\":true}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/comfort")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/comfort"));
} }
void test_6() { void test_7() {
auto expected_response = "[{\"api_data\":\"hot\"}]"; auto expected_response = "[{\"api_data\":\"hot\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/comfort/value")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/comfort/value"));
} }
void test_7() { void test_8() {
auto expected_response = "[{\"api_data\":\"dhw comfort\"}]"; auto expected_response = "[{\"api_data\":\"dhw comfort\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/comfort/fullname")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/comfort/fullname"));
} }
void test_8() { void test_9() {
auto expected_response = "[{\"name\":\"outdoortemp\",\"fullname\":\"outside " auto expected_response = "[{\"name\":\"outdoortemp\",\"fullname\":\"outside "
"temperature\",\"circuit\":\"\",\"type\":\"number\",\"uom\":\"°C\",\"state_class\":\"measurement\",\"device_class\":" "temperature\",\"circuit\":\"\",\"type\":\"number\",\"uom\":\"°C\",\"state_class\":\"measurement\",\"device_class\":"
"\"temperature\",\"readable\":true,\"writeable\":false,\"visible\":true}]"; "\"temperature\",\"readable\":true,\"writeable\":false,\"visible\":true}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/outdoortemp")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/outdoortemp"));
} }
void test_9() { void test_10() {
auto expected_response = "[{\"name\":\"chargetype\",\"fullname\":\"dhw charging type\",\"circuit\":\"dhw\",\"index\":1,\"enum\":[\"chargepump\",\"3-way " auto expected_response = "[{\"name\":\"chargetype\",\"fullname\":\"dhw charging type\",\"circuit\":\"dhw\",\"index\":1,\"enum\":[\"chargepump\",\"3-way "
"valve\"],\"value\":\"3-way valve\",\"type\":\"enum\",\"readable\":true,\"writeable\":false,\"visible\":true}]"; "valve\"],\"value\":\"3-way valve\",\"type\":\"enum\",\"readable\":true,\"writeable\":false,\"visible\":true}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/dhw/chargetype")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/dhw/chargetype"));
} }
void test_10() { void test_11() {
auto expected_response = "[{\"api_data\":\"false\"}]"; auto expected_response = "[{\"api_data\":\"false\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/dhw.chargetype/writeable")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/dhw.chargetype/writeable"));
} }
void test_11() { void test_12() {
auto expected_response = "[{\"api_data\":\"37.4\"}]"; auto expected_response = "[{\"api_data\":\"37.4\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/flamecurr/value")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/flamecurr/value"));
} }
void test_12() { void test_13() {
auto expected_response = "[{\"hc1\":{\"seltemp\":20.5,\"currtemp\":22.8,\"haclimate\":\"roomTemp\",\"modetype\":\"heat\",\"remotetemp\":null},\"hc2\":{" auto expected_response = "[{\"hc1\":{\"seltemp\":20.5,\"currtemp\":22.8,\"haclimate\":\"roomTemp\",\"modetype\":\"heat\",\"remotetemp\":null},\"hc2\":{"
"\"seltemp\":20.6,\"currtemp\":22.9,\"haclimate\":\"roomTemp\",\"modetype\":\"eco\",\"remotetemp\":null},\"hc3\":{\"seltemp\":20." "\"seltemp\":20.6,\"currtemp\":22.9,\"haclimate\":\"roomTemp\",\"modetype\":\"eco\",\"remotetemp\":null},\"hc3\":{\"seltemp\":20."
"7,\"currtemp\":23.0,\"haclimate\":\"roomTemp\",\"modetype\":\"nofrost\",\"remotetemp\":null},\"dhw\":{}}]"; "7,\"currtemp\":23.0,\"haclimate\":\"roomTemp\",\"modetype\":\"nofrost\",\"remotetemp\":null},\"dhw\":{}}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat"));
} }
void test_13() { void test_14() {
auto expected_response = "[{\"seltemp\":20.5,\"currtemp\":22.8,\"haclimate\":\"roomTemp\",\"modetype\":\"heat\",\"remotetemp\":null}]"; auto expected_response = "[{\"seltemp\":20.5,\"currtemp\":22.8,\"haclimate\":\"roomTemp\",\"modetype\":\"heat\",\"remotetemp\":null}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat/hc1/values")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat/hc1/values"));
} }
void test_14() { void test_15() {
auto expected_response =
"[{\"api_data\":\"# HELP emsesp_seltemp selected room temperature, °C, readable, writeable, visible\\n# TYPE emsesp_seltemp "
"gauge\\nemsesp_seltemp{circuit=\\\"hc1\\\"} 20.50\\n# HELP emsesp_currtemp current room temperature, °C, readable, visible\\n# TYPE emsesp_currtemp "
"gauge\\nemsesp_currtemp{circuit=\\\"hc1\\\"} 22.80\\n# HELP emsesp_haclimate mqtt discovery current room temperature, enum, (0: selTemp; 1: "
"roomTemp), readable, visible\\n# TYPE emsesp_haclimate gauge\\nemsesp_haclimate{circuit=\\\"hc1\\\"} 1\\n# HELP emsesp_modetype mode type, enum, (0: "
"nofrost; 1: eco; 2: heat), readable, visible\\n# TYPE emsesp_modetype gauge\\nemsesp_modetype{circuit=\\\"hc1\\\"} "
"2\\nemsesp_seltemp{circuit=\\\"hc2\\\"} 20.60\\nemsesp_currtemp{circuit=\\\"hc2\\\"} 22.90\\nemsesp_haclimate{circuit=\\\"hc2\\\"} "
"1\\nemsesp_modetype{circuit=\\\"hc2\\\"} 1\\nemsesp_seltemp{circuit=\\\"hc3\\\"} 20.70\\nemsesp_currtemp{circuit=\\\"hc3\\\"} "
"23\\nemsesp_haclimate{circuit=\\\"hc3\\\"} 1\\nemsesp_modetype{circuit=\\\"hc3\\\"} 0\\n\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat/metrics"));
}
void test_16() {
auto expected_response = "[{\"name\":\"seltemp\",\"fullname\":\"hc1 selected room " auto expected_response = "[{\"name\":\"seltemp\",\"fullname\":\"hc1 selected room "
"temperature\",\"circuit\":\"hc1\",\"value\":20.5,\"type\":\"number\",\"min\":0,\"max\":30,\"uom\":\"°C\",\"state_class\":" "temperature\",\"circuit\":\"hc1\",\"value\":20.5,\"type\":\"number\",\"min\":0,\"max\":30,\"uom\":\"°C\",\"state_class\":"
"\"measurement\",\"device_class\":\"temperature\",\"readable\":true,\"writeable\":true,\"visible\":true}]"; "\"measurement\",\"device_class\":\"temperature\",\"readable\":true,\"writeable\":true,\"visible\":true}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat/hc1/seltemp")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat/hc1/seltemp"));
} }
void test_15() { void test_17() {
auto expected_response = "[{\"name\":\"seltemp\",\"fullname\":\"hc2 selected room " auto expected_response = "[{\"name\":\"seltemp\",\"fullname\":\"hc2 selected room "
"temperature\",\"circuit\":\"hc2\",\"value\":20.6,\"type\":\"number\",\"min\":0,\"max\":30,\"uom\":\"°C\",\"state_class\":" "temperature\",\"circuit\":\"hc2\",\"value\":20.6,\"type\":\"number\",\"min\":0,\"max\":30,\"uom\":\"°C\",\"state_class\":"
"\"measurement\",\"device_class\":\"temperature\",\"readable\":true,\"writeable\":true,\"visible\":true}]"; "\"measurement\",\"device_class\":\"temperature\",\"readable\":true,\"writeable\":true,\"visible\":true}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat/hc2/seltemp")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat/hc2/seltemp"));
} }
void test_16() { void test_18() {
auto expected_response = "[{\"test_custom\":0.00,\"test_read_only\":70.00,\"test_ram\":\"14\",\"test_seltemp\":\"14\"}]"; auto expected_response = "[{\"test_custom\":0.00,\"test_read_only\":70.00,\"test_ram\":\"14\",\"test_seltemp\":\"14\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom"));
} }
void test_17() { void test_19() {
auto expected_response = "[{\"test_custom\":0.00,\"test_read_only\":70.00,\"test_ram\":\"14\",\"test_seltemp\":\"14\"}]"; auto expected_response = "[{\"test_custom\":0.00,\"test_read_only\":70.00,\"test_ram\":\"14\",\"test_seltemp\":\"14\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/info")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/info"));
} }
void test_18() { void test_20() {
auto expected_response = "[{\"name\":\"test_seltemp\",\"fullname\":\"test_seltemp\",\"storage\":\"ram\",\"type\":\"number\",\"readable\":true," auto expected_response = "[{\"name\":\"test_seltemp\",\"fullname\":\"test_seltemp\",\"storage\":\"ram\",\"type\":\"number\",\"readable\":true,"
"\"writeable\":true,\"visible\":true,\"ent_cat\":\"diagnostic\",\"value\":\"14\"}]"; "\"writeable\":true,\"visible\":true,\"ent_cat\":\"diagnostic\",\"value\":\"14\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/test_seltemp")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/test_seltemp"));
} }
void test_19() { void test_21() {
auto expected_response = "[{\"api_data\":\"14\"}]"; auto expected_response = "[{\"api_data\":\"14\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/test_seltemp/value")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/test_seltemp/value"));
} }
void test_20() { void test_22() {
auto expected_response = "[{\"name\":\"test_custom\",\"fullname\":\"test_custom\",\"storage\":\"ems\",\"type\":\"number\",\"readable\":true,\"writeable\":" auto expected_response = "[{\"name\":\"test_custom\",\"fullname\":\"test_custom\",\"storage\":\"ems\",\"type\":\"number\",\"readable\":true,\"writeable\":"
"true,\"visible\":true,\"device_id\":\"0x08\",\"type_id\":\"0x18\",\"offset\":0,\"factor\":1,\"ent_cat\":\"diagnostic\",\"uom\":" "true,\"visible\":true,\"device_id\":\"0x08\",\"type_id\":\"0x18\",\"offset\":0,\"factor\":1,\"ent_cat\":\"diagnostic\",\"uom\":"
"\"°C\",\"state_class\":\"measurement\",\"device_class\":\"temperature\",\"value\":0.00}]"; "\"°C\",\"state_class\":\"measurement\",\"device_class\":\"temperature\",\"value\":0.00}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/test_custom")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/test_custom"));
} }
void test_21() { void test_23() {
auto expected_response = auto expected_response =
"[{\"system\":{\"version\":\"dev\",\"uptime\":\"000+00:00:00.000\",\"uptimeSec\":0,\"resetReason\":\"Unknown / " "[{\"system\":{\"version\":\"dev\",\"uptime\":\"000+00:00:00.000\",\"uptimeSec\":0,\"resetReason\":\"Unknown / "
"Unknown\"},\"network\":{\"network\":\"WiFi\",\"hostname\":\"ems-esp\",\"RSSI\":-23,\"TxPowerSetting\":0,\"staticIP\":false,\"lowBandwidth\":false," "Unknown\",\"txpause\":false,\"gpios_in_use\":\"23, 5, 2, 18, 0\",\"gpios_available\":\"1, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, "
"21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, "
"39\"},\"network\":{\"network\":\"WiFi\",\"hostname\":\"ems-esp\",\"RSSI\":-23,\"TxPowerSetting\":0,\"staticIP\":false,\"lowBandwidth\":false,"
"\"disableSleep\":true,\"enableMDNS\":true,\"enableCORS\":false},\"ntp\":{\"NTPstatus\":\"disconnected\",\"enabled\":true,\"server\":\"pool.ntp.org\"," "\"disableSleep\":true,\"enableMDNS\":true,\"enableCORS\":false},\"ntp\":{\"NTPstatus\":\"disconnected\",\"enabled\":true,\"server\":\"pool.ntp.org\","
"\"tzLabel\":\"Europe/" "\"tzLabel\":\"Europe/"
"London\",\"NTPStatus\":\"disconnected\"},\"ap\":{\"provisionMode\":\"always\",\"ssid\":\"ems-esp\"},\"mqtt\":{\"MQTTStatus\":\"disconnected\"," "London\",\"NTPStatus\":\"disconnected\"},\"ap\":{\"provisionMode\":\"always\",\"ssid\":\"ems-esp\"},\"mqtt\":{\"MQTTStatus\":\"disconnected\","
@@ -175,7 +231,7 @@ void test_21() {
"\"temperatureSensorFails\":0,\"analogSensors\":5,\"analogSensorReads\":0,\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{" "\"temperatureSensorFails\":0,\"analogSensors\":5,\"analogSensorReads\":0,\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{"
"\"busStatus\":\"connected\",\"busProtocol\":\"Buderus\",\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0," "\"busStatus\":\"connected\",\"busProtocol\":\"Buderus\",\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0,"
"\"busReadsFailed\":0,\"busWritesFailed\":0,\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":" "\"busReadsFailed\":0,\"busWritesFailed\":0,\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":"
"\"en\",\"txMode\":8,\"emsBusID\":11,\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false," "\"en\",\"txMode\":1,\"emsBusID\":11,\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false,"
"\"readonlyMode\":false,\"fahrenheit\":false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true," "\"readonlyMode\":false,\"fahrenheit\":false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true,"
"\"telnetEnabled\":true,\"maxWebLogBuffer\":25,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":" "\"telnetEnabled\":true,\"maxWebLogBuffer\":25,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":"
"\"boiler\",\"name\":\"My Custom " "\"boiler\",\"name\":\"My Custom "
@@ -189,10 +245,12 @@ void test_21() {
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system"));
} }
void test_22() { void test_24() {
auto expected_response = auto expected_response =
"[{\"system\":{\"version\":\"dev\",\"uptime\":\"000+00:00:00.000\",\"uptimeSec\":0,\"resetReason\":\"Unknown / " "[{\"system\":{\"version\":\"dev\",\"uptime\":\"000+00:00:00.000\",\"uptimeSec\":0,\"resetReason\":\"Unknown / "
"Unknown\"},\"network\":{\"network\":\"WiFi\",\"hostname\":\"ems-esp\",\"RSSI\":-23,\"TxPowerSetting\":0,\"staticIP\":false,\"lowBandwidth\":false," "Unknown\",\"txpause\":false,\"gpios_in_use\":\"23, 5, 2, 18, 0\",\"gpios_available\":\"1, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, "
"21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, "
"39\"},\"network\":{\"network\":\"WiFi\",\"hostname\":\"ems-esp\",\"RSSI\":-23,\"TxPowerSetting\":0,\"staticIP\":false,\"lowBandwidth\":false,"
"\"disableSleep\":true,\"enableMDNS\":true,\"enableCORS\":false},\"ntp\":{\"NTPstatus\":\"disconnected\",\"enabled\":true,\"server\":\"pool.ntp.org\"," "\"disableSleep\":true,\"enableMDNS\":true,\"enableCORS\":false},\"ntp\":{\"NTPstatus\":\"disconnected\",\"enabled\":true,\"server\":\"pool.ntp.org\","
"\"tzLabel\":\"Europe/" "\"tzLabel\":\"Europe/"
"London\",\"NTPStatus\":\"disconnected\"},\"ap\":{\"provisionMode\":\"always\",\"ssid\":\"ems-esp\"},\"mqtt\":{\"MQTTStatus\":\"disconnected\"," "London\",\"NTPStatus\":\"disconnected\"},\"ap\":{\"provisionMode\":\"always\",\"ssid\":\"ems-esp\"},\"mqtt\":{\"MQTTStatus\":\"disconnected\","
@@ -204,7 +262,7 @@ void test_22() {
"\"temperatureSensorFails\":0,\"analogSensors\":5,\"analogSensorReads\":0,\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{" "\"temperatureSensorFails\":0,\"analogSensors\":5,\"analogSensorReads\":0,\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{"
"\"busStatus\":\"connected\",\"busProtocol\":\"Buderus\",\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0," "\"busStatus\":\"connected\",\"busProtocol\":\"Buderus\",\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0,"
"\"busReadsFailed\":0,\"busWritesFailed\":0,\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":" "\"busReadsFailed\":0,\"busWritesFailed\":0,\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":"
"\"en\",\"txMode\":8,\"emsBusID\":11,\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false," "\"en\",\"txMode\":1,\"emsBusID\":11,\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false,"
"\"readonlyMode\":false,\"fahrenheit\":false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true," "\"readonlyMode\":false,\"fahrenheit\":false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true,"
"\"telnetEnabled\":true,\"maxWebLogBuffer\":25,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":" "\"telnetEnabled\":true,\"maxWebLogBuffer\":25,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":"
"\"boiler\",\"name\":\"My Custom " "\"boiler\",\"name\":\"My Custom "
@@ -218,169 +276,255 @@ void test_22() {
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/info")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/info"));
} }
void test_23() { void test_25() {
auto expected_response =
"[{\"api_data\":\"# HELP emsesp_system_uptimesec uptimeSec\\n# TYPE emsesp_system_uptimesec gauge\\nemsesp_system_uptimesec 0\\n# HELP "
"emsesp_system_txpause txpause\\n# TYPE emsesp_system_txpause gauge\\nemsesp_system_txpause 0\\n# HELP emsesp_system_info info\\n# TYPE "
"emsesp_system_info gauge\\nemsesp_system_info{version=\\\"dev\\\", resetreason=\\\"Unknown / Unknown\\\", gpios_in_use=\\\"23, 5, 2, 18, 0\\\", "
"gpios_available=\\\"1, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, "
"39\\\"} 1\\n# HELP emsesp_network_rssi RSSI\\n# TYPE emsesp_network_rssi gauge\\nemsesp_network_rssi -23\\n# HELP emsesp_network_txpowersetting "
"TxPowerSetting\\n# TYPE emsesp_network_txpowersetting gauge\\nemsesp_network_txpowersetting 0\\n# HELP emsesp_network_staticip staticIP\\n# TYPE "
"emsesp_network_staticip gauge\\nemsesp_network_staticip 0\\n# HELP emsesp_network_lowbandwidth lowBandwidth\\n# TYPE emsesp_network_lowbandwidth "
"gauge\\nemsesp_network_lowbandwidth 0\\n# HELP emsesp_network_disablesleep disableSleep\\n# TYPE emsesp_network_disablesleep "
"gauge\\nemsesp_network_disablesleep 1\\n# HELP emsesp_network_enablemdns enableMDNS\\n# TYPE emsesp_network_enablemdns "
"gauge\\nemsesp_network_enablemdns 1\\n# HELP emsesp_network_enablecors enableCORS\\n# TYPE emsesp_network_enablecors "
"gauge\\nemsesp_network_enablecors 0\\n# HELP emsesp_network_info info\\n# TYPE emsesp_network_info gauge\\nemsesp_network_info{network=\\\"WiFi\\\", "
"hostname=\\\"ems-esp\\\"} 1\\n# HELP emsesp_ntp_enabled enabled\\n# TYPE emsesp_ntp_enabled gauge\\nemsesp_ntp_enabled 1\\n# HELP emsesp_ntp_info "
"info\\n# TYPE emsesp_ntp_info gauge\\nemsesp_ntp_info{ntpstatus=\\\"disconnected\\\", server=\\\"pool.ntp.org\\\", tzlabel=\\\"Europe/London\\\"} "
"1\\n# HELP emsesp_ap_info info\\n# TYPE emsesp_ap_info gauge\\nemsesp_ap_info{provisionmode=\\\"always\\\", ssid=\\\"ems-esp\\\"} 1\\n# HELP "
"emsesp_mqtt_mqttpublishes MQTTPublishes\\n# TYPE emsesp_mqtt_mqttpublishes gauge\\nemsesp_mqtt_mqttpublishes 0\\n# HELP emsesp_mqtt_mqttqueued "
"MQTTQueued\\n# TYPE emsesp_mqtt_mqttqueued gauge\\nemsesp_mqtt_mqttqueued 0\\n# HELP emsesp_mqtt_mqttpublishfails MQTTPublishFails\\n# TYPE "
"emsesp_mqtt_mqttpublishfails gauge\\nemsesp_mqtt_mqttpublishfails 0\\n# HELP emsesp_mqtt_mqttreconnects MQTTReconnects\\n# TYPE "
"emsesp_mqtt_mqttreconnects gauge\\nemsesp_mqtt_mqttreconnects 0\\n# HELP emsesp_mqtt_enabled enabled\\n# TYPE emsesp_mqtt_enabled "
"gauge\\nemsesp_mqtt_enabled 1\\n# HELP emsesp_mqtt_keepalive keepAlive\\n# TYPE emsesp_mqtt_keepalive gauge\\nemsesp_mqtt_keepalive 60\\n# HELP "
"emsesp_mqtt_cleansession cleanSession\\n# TYPE emsesp_mqtt_cleansession gauge\\nemsesp_mqtt_cleansession 0\\n# HELP emsesp_mqtt_entityformat "
"entityFormat\\n# TYPE emsesp_mqtt_entityformat gauge\\nemsesp_mqtt_entityformat 1\\n# HELP emsesp_mqtt_discoverytype discoveryType\\n# TYPE "
"emsesp_mqtt_discoverytype gauge\\nemsesp_mqtt_discoverytype 0\\n# HELP emsesp_mqtt_nestedformat nestedFormat\\n# TYPE emsesp_mqtt_nestedformat "
"gauge\\nemsesp_mqtt_nestedformat 1\\n# HELP emsesp_mqtt_haenabled haEnabled\\n# TYPE emsesp_mqtt_haenabled gauge\\nemsesp_mqtt_haenabled 1\\n# HELP "
"emsesp_mqtt_mqttqos mqttQos\\n# TYPE emsesp_mqtt_mqttqos gauge\\nemsesp_mqtt_mqttqos 0\\n# HELP emsesp_mqtt_mqttretain mqttRetain\\n# TYPE "
"emsesp_mqtt_mqttretain gauge\\nemsesp_mqtt_mqttretain 0\\n# HELP emsesp_mqtt_publishtimeheartbeat publishTimeHeartbeat\\n# TYPE "
"emsesp_mqtt_publishtimeheartbeat gauge\\nemsesp_mqtt_publishtimeheartbeat 60\\n# HELP emsesp_mqtt_publishtimeboiler publishTimeBoiler\\n# TYPE "
"emsesp_mqtt_publishtimeboiler gauge\\nemsesp_mqtt_publishtimeboiler 10\\n# HELP emsesp_mqtt_publishtimethermostat publishTimeThermostat\\n# TYPE "
"emsesp_mqtt_publishtimethermostat gauge\\nemsesp_mqtt_publishtimethermostat 10\\n# HELP emsesp_mqtt_publishtimesolar publishTimeSolar\\n# TYPE "
"emsesp_mqtt_publishtimesolar gauge\\nemsesp_mqtt_publishtimesolar 10\\n# HELP emsesp_mqtt_publishtimemixer publishTimeMixer\\n# TYPE "
"emsesp_mqtt_publishtimemixer gauge\\nemsesp_mqtt_publishtimemixer 10\\n# HELP emsesp_mqtt_publishtimewater publishTimeWater\\n# TYPE "
"emsesp_mqtt_publishtimewater gauge\\nemsesp_mqtt_publishtimewater 0\\n# HELP emsesp_mqtt_publishtimeother publishTimeOther\\n# TYPE "
"emsesp_mqtt_publishtimeother gauge\\nemsesp_mqtt_publishtimeother 10\\n# HELP emsesp_mqtt_publishtimesensor publishTimeSensor\\n# TYPE "
"emsesp_mqtt_publishtimesensor gauge\\nemsesp_mqtt_publishtimesensor 10\\n# HELP emsesp_mqtt_publishsingle publishSingle\\n# TYPE "
"emsesp_mqtt_publishsingle gauge\\nemsesp_mqtt_publishsingle 0\\n# HELP emsesp_mqtt_publish2command publish2command\\n# TYPE "
"emsesp_mqtt_publish2command gauge\\nemsesp_mqtt_publish2command 0\\n# HELP emsesp_mqtt_sendresponse sendResponse\\n# TYPE emsesp_mqtt_sendresponse "
"gauge\\nemsesp_mqtt_sendresponse 0\\n# HELP emsesp_mqtt_info info\\n# TYPE emsesp_mqtt_info gauge\\nemsesp_mqtt_info{mqttstatus=\\\"disconnected\\\", "
"clientid=\\\"ems-esp\\\", base=\\\"ems-esp\\\", discoveryprefix=\\\"homeassistant\\\"} 1\\n# HELP emsesp_syslog_enabled enabled\\n# TYPE "
"emsesp_syslog_enabled gauge\\nemsesp_syslog_enabled 0\\n# HELP emsesp_sensor_temperaturesensors temperatureSensors\\n# TYPE "
"emsesp_sensor_temperaturesensors gauge\\nemsesp_sensor_temperaturesensors 3\\n# HELP emsesp_sensor_temperaturesensorreads temperatureSensorReads\\n# "
"TYPE emsesp_sensor_temperaturesensorreads gauge\\nemsesp_sensor_temperaturesensorreads 0\\n# HELP emsesp_sensor_temperaturesensorfails "
"temperatureSensorFails\\n# TYPE emsesp_sensor_temperaturesensorfails gauge\\nemsesp_sensor_temperaturesensorfails 0\\n# HELP "
"emsesp_sensor_analogsensors analogSensors\\n# TYPE emsesp_sensor_analogsensors gauge\\nemsesp_sensor_analogsensors 5\\n# HELP "
"emsesp_sensor_analogsensorreads analogSensorReads\\n# TYPE emsesp_sensor_analogsensorreads gauge\\nemsesp_sensor_analogsensorreads 0\\n# HELP "
"emsesp_sensor_analogsensorfails analogSensorFails\\n# TYPE emsesp_sensor_analogsensorfails gauge\\nemsesp_sensor_analogsensorfails 0\\n# HELP "
"emsesp_api_apicalls APICalls\\n# TYPE emsesp_api_apicalls gauge\\nemsesp_api_apicalls 0\\n# HELP emsesp_api_apifails APIFails\\n# TYPE "
"emsesp_api_apifails gauge\\nemsesp_api_apifails 0\\n# HELP emsesp_bus_bustelegramsreceived busTelegramsReceived\\n# TYPE "
"emsesp_bus_bustelegramsreceived gauge\\nemsesp_bus_bustelegramsreceived 8\\n# HELP emsesp_bus_busreads busReads\\n# TYPE emsesp_bus_busreads "
"gauge\\nemsesp_bus_busreads 0\\n# HELP emsesp_bus_buswrites busWrites\\n# TYPE emsesp_bus_buswrites gauge\\nemsesp_bus_buswrites 0\\n# HELP "
"emsesp_bus_busincompletetelegrams busIncompleteTelegrams\\n# TYPE emsesp_bus_busincompletetelegrams gauge\\nemsesp_bus_busincompletetelegrams 0\\n# "
"HELP emsesp_bus_busreadsfailed busReadsFailed\\n# TYPE emsesp_bus_busreadsfailed gauge\\nemsesp_bus_busreadsfailed 0\\n# HELP "
"emsesp_bus_buswritesfailed busWritesFailed\\n# TYPE emsesp_bus_buswritesfailed gauge\\nemsesp_bus_buswritesfailed 0\\n# HELP "
"emsesp_bus_busrxlinequality busRxLineQuality\\n# TYPE emsesp_bus_busrxlinequality gauge\\nemsesp_bus_busrxlinequality 100\\n# HELP "
"emsesp_bus_bustxlinequality busTxLineQuality\\n# TYPE emsesp_bus_bustxlinequality gauge\\nemsesp_bus_bustxlinequality 100\\n# HELP emsesp_bus_info "
"info\\n# TYPE emsesp_bus_info gauge\\nemsesp_bus_info{busstatus=\\\"connected\\\", busprotocol=\\\"Buderus\\\"} 1\\n# HELP emsesp_settings_txmode "
"txMode\\n# TYPE emsesp_settings_txmode gauge\\nemsesp_settings_txmode 1\\n# HELP emsesp_settings_emsbusid emsBusID\\n# TYPE emsesp_settings_emsbusid "
"gauge\\nemsesp_settings_emsbusid 11\\n# HELP emsesp_settings_showertimer showerTimer\\n# TYPE emsesp_settings_showertimer "
"gauge\\nemsesp_settings_showertimer 0\\n# HELP emsesp_settings_showerminduration showerMinDuration\\n# TYPE emsesp_settings_showerminduration "
"gauge\\nemsesp_settings_showerminduration 180\\n# HELP emsesp_settings_showeralert showerAlert\\n# TYPE emsesp_settings_showeralert "
"gauge\\nemsesp_settings_showeralert 0\\n# HELP emsesp_settings_hideled hideLed\\n# TYPE emsesp_settings_hideled gauge\\nemsesp_settings_hideled 0\\n# "
"HELP emsesp_settings_notokenapi noTokenApi\\n# TYPE emsesp_settings_notokenapi gauge\\nemsesp_settings_notokenapi 0\\n# HELP "
"emsesp_settings_readonlymode readonlyMode\\n# TYPE emsesp_settings_readonlymode gauge\\nemsesp_settings_readonlymode 0\\n# HELP "
"emsesp_settings_fahrenheit fahrenheit\\n# TYPE emsesp_settings_fahrenheit gauge\\nemsesp_settings_fahrenheit 0\\n# HELP "
"emsesp_settings_dallasparasite dallasParasite\\n# TYPE emsesp_settings_dallasparasite gauge\\nemsesp_settings_dallasparasite 0\\n# HELP "
"emsesp_settings_boolformat boolFormat\\n# TYPE emsesp_settings_boolformat gauge\\nemsesp_settings_boolformat 1\\n# HELP emsesp_settings_booldashboard "
"boolDashboard\\n# TYPE emsesp_settings_booldashboard gauge\\nemsesp_settings_booldashboard 1\\n# HELP emsesp_settings_enumformat enumFormat\\n# TYPE "
"emsesp_settings_enumformat gauge\\nemsesp_settings_enumformat 1\\n# HELP emsesp_settings_analogenabled analogEnabled\\n# TYPE "
"emsesp_settings_analogenabled gauge\\nemsesp_settings_analogenabled 1\\n# HELP emsesp_settings_telnetenabled telnetEnabled\\n# TYPE "
"emsesp_settings_telnetenabled gauge\\nemsesp_settings_telnetenabled 1\\n# HELP emsesp_settings_maxweblogbuffer maxWebLogBuffer\\n# TYPE "
"emsesp_settings_maxweblogbuffer gauge\\nemsesp_settings_maxweblogbuffer 25\\n# HELP emsesp_settings_modbusenabled modbusEnabled\\n# TYPE "
"emsesp_settings_modbusenabled gauge\\nemsesp_settings_modbusenabled 0\\n# HELP emsesp_settings_forceheatingoff forceHeatingOff\\n# TYPE "
"emsesp_settings_forceheatingoff gauge\\nemsesp_settings_forceheatingoff 0\\n# HELP emsesp_settings_developermode developerMode\\n# TYPE "
"emsesp_settings_developermode gauge\\nemsesp_settings_developermode 0\\n# HELP emsesp_settings_info info\\n# TYPE emsesp_settings_info "
"gauge\\nemsesp_settings_info{boardprofile=\\\"S32\\\", locale=\\\"en\\\"} 1\\n# HELP emsesp_device_productid productID\\n# TYPE "
"emsesp_device_productid gauge\\nemsesp_device_productid{type=\\\"boiler\\\", name=\\\"My Custom Boiler\\\", deviceid=\\\"0x08\\\", "
"version=\\\"01.00\\\"} 123\\n# HELP emsesp_device_entities entities\\n# TYPE emsesp_device_entities "
"gauge\\nemsesp_device_entities{type=\\\"boiler\\\", name=\\\"My Custom Boiler\\\", deviceid=\\\"0x08\\\", version=\\\"01.00\\\"} "
"39\\nemsesp_device_productid{type=\\\"thermostat\\\", name=\\\"FW120\\\", deviceid=\\\"0x10\\\", version=\\\"01.00\\\"} "
"192\\nemsesp_device_entities{type=\\\"thermostat\\\", name=\\\"FW120\\\", deviceid=\\\"0x10\\\", version=\\\"01.00\\\"} "
"15\\nemsesp_device_entities{type=\\\"temperaturesensor\\\", name=\\\"temperaturesensor\\\"} 3\\nemsesp_device_entities{type=\\\"analogsensor\\\", "
"name=\\\"analogsensor\\\"} 5\\nemsesp_device_entities{type=\\\"scheduler\\\", name=\\\"scheduler\\\"} 2\\nemsesp_device_entities{type=\\\"custom\\\", "
"name=\\\"custom\\\"} 4\\n\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/metrics"));
}
void test_26() {
auto expected_response = auto expected_response =
"[{\"name\":\"locale\",\"circuit\":\"settings\",\"readable\":true,\"writeable\":false,\"visible\":true,\"value\":\"en\",\"type\":\"string\"}]"; "[{\"name\":\"locale\",\"circuit\":\"settings\",\"readable\":true,\"writeable\":false,\"visible\":true,\"value\":\"en\",\"type\":\"string\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/settings/locale")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/settings/locale"));
} }
void test_24() { void test_27() {
auto expected_response = "[{}]"; auto expected_response = "[{}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/fetch")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/fetch"));
} }
void test_25() { void test_28() {
auto expected_response = "[{\"network\":\"WiFi\",\"hostname\":\"ems-esp\",\"RSSI\":\"-23\",\"TxPowerSetting\":\"0\",\"staticIP\":\"false\"," auto expected_response = "[{\"network\":\"WiFi\",\"hostname\":\"ems-esp\",\"RSSI\":\"-23\",\"TxPowerSetting\":\"0\",\"staticIP\":\"false\","
"\"lowBandwidth\":\"false\",\"disableSleep\":\"true\",\"enableMDNS\":\"true\",\"enableCORS\":\"false\"}]"; "\"lowBandwidth\":\"false\",\"disableSleep\":\"true\",\"enableMDNS\":\"true\",\"enableCORS\":\"false\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/network/values")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/network/values"));
} }
void test_26() { void test_29() {
auto expected_response = "[{\"test_scheduler\":\"on\"}]"; auto expected_response = "[{\"test_scheduler\":\"on\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler"));
} }
void test_27() { void test_30() {
auto expected_response = "[{\"test_scheduler\":\"on\"}]"; auto expected_response = "[{\"test_scheduler\":\"on\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/info")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/info"));
} }
void test_28() { void test_31() {
auto expected_response = "[{\"name\":\"test_scheduler\",\"fullname\":\"test_scheduler\",\"type\":\"boolean\",\"value\":\"on\",\"time\":\"12:00\"," auto expected_response = "[{\"name\":\"test_scheduler\",\"fullname\":\"test_scheduler\",\"type\":\"boolean\",\"value\":\"on\",\"time\":\"12:00\","
"\"command\":\"system/fetch\",\"cmd_data\":\"10\",\"readable\":true,\"writeable\":true,\"visible\":true}]"; "\"command\":\"system/fetch\",\"cmd_data\":\"10\",\"readable\":true,\"writeable\":true,\"visible\":true}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/test_scheduler")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/test_scheduler"));
} }
void test_29() { void test_32() {
auto expected_response = "[{\"test_tempsensor1\":12.3,\"test_tempsensor2\":45.6,\"gateway_temperature\":28.1}]"; auto expected_response = "[{\"test_tempsensor1\":12.3,\"test_tempsensor2\":45.6,\"gateway_temperature\":28.1}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor"));
} }
void test_30() { void test_33() {
auto expected_response = "[{\"test_tempsensor1\":12.3,\"test_tempsensor2\":45.6,\"gateway_temperature\":28.1}]"; auto expected_response = "[{\"test_tempsensor1\":12.3,\"test_tempsensor2\":45.6,\"gateway_temperature\":28.1}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/info")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/info"));
} }
void test_31() { void test_34() {
auto expected_response = "[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"fullname\":\"test_tempsensor2\",\"value\":45.6,\"type\":" auto expected_response = "[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"fullname\":\"test_tempsensor2\",\"value\":45.6,\"type\":"
"\"number\",\"uom\":\"°C\",\"readable\":true,\"writeable\":false,\"visible\":true,\"is_system\":false}]"; "\"number\",\"uom\":\"°C\",\"readable\":true,\"writeable\":false,\"visible\":true,\"is_system\":false}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_tempsensor2")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_tempsensor2"));
} }
void test_32() { void test_35() {
auto expected_response = "[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"fullname\":\"test_tempsensor2\",\"value\":45.6,\"type\":" auto expected_response = "[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"fullname\":\"test_tempsensor2\",\"value\":45.6,\"type\":"
"\"number\",\"uom\":\"°C\",\"readable\":true,\"writeable\":false,\"visible\":true,\"is_system\":false}]"; "\"number\",\"uom\":\"°C\",\"readable\":true,\"writeable\":false,\"visible\":true,\"is_system\":false}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/0B_0C0D_0E0F_1011")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/0B_0C0D_0E0F_1011"));
} }
void test_33() { void test_36() {
auto expected_response = "[{\"api_data\":\"45.6\"}]"; auto expected_response = "[{\"api_data\":\"45.6\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_tempsensor2/value")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_tempsensor2/value"));
} }
void test_34() { void test_37() {
auto expected_response = "[{\"test_analogsensor1\":0,\"test_analogsensor2\":1,\"test_analogsensor3\":0,\"test_analogsensor4\":0,\"test_analogsensor5\":0}]"; auto expected_response = "[{\"test_analogsensor1\":0,\"test_analogsensor2\":1,\"test_analogsensor3\":0,\"test_analogsensor4\":0,\"test_analogsensor5\":0}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor"));
} }
void test_35() { void test_38() {
auto expected_response = "[{\"test_analogsensor1\":0,\"test_analogsensor2\":1,\"test_analogsensor3\":0,\"test_analogsensor4\":0,\"test_analogsensor5\":0}]"; auto expected_response = "[{\"test_analogsensor1\":0,\"test_analogsensor2\":1,\"test_analogsensor3\":0,\"test_analogsensor4\":0,\"test_analogsensor5\":0}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/info")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/info"));
} }
void test_36() { void test_39() {
auto expected_response = auto expected_response =
"[{\"name\":\"test_analogsensor1\",\"fullname\":\"test_analogsensor1\",\"gpio\":36,\"type\":\"number\",\"analog\":\"adc\",\"value\":0,\"readable\":" "[{\"name\":\"test_analogsensor1\",\"fullname\":\"test_analogsensor1\",\"gpio\":36,\"type\":\"number\",\"analog\":\"adc\",\"value\":0,\"readable\":"
"true,\"writeable\":false,\"visible\":true,\"is_system\":false,\"offset\":0,\"factor\":0.2,\"uom\":\"mV\"}]"; "true,\"writeable\":false,\"visible\":true,\"is_system\":false,\"offset\":0,\"factor\":0.2,\"uom\":\"mV\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analogsensor1")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analogsensor1"));
} }
void test_37() { void test_40() {
auto expected_response = "[{\"api_data\":\"0\"}]"; auto expected_response = "[{\"api_data\":\"0\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analogsensor1/offset")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analogsensor1/offset"));
} }
void test_38() { void test_41() {
auto expected_response = "[{\"message\":\"unknown device boiler2\"}]"; auto expected_response = "[{\"message\":\"unknown device boiler2\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler2")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler2"));
} }
void test_39() { void test_42() {
auto expected_response = "[{}]"; auto expected_response = "[{}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/bad/value")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/bad/value"));
} }
void test_40() { void test_43() {
auto expected_response = "[{\"message\":\"no attribute 'valu' in comfort\"}]"; auto expected_response = "[{\"message\":\"no attribute 'valu' in comfort\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/comfort/valu")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/comfort/valu"));
} }
void test_41() { void test_44() {
auto expected_response = "[{\"message\":\"no 'settings' in system\"}]"; auto expected_response = "[{\"message\":\"no 'settings' in system\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/settings/locale2")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/settings/locale2"));
} }
void test_42() { void test_45() {
auto expected_response = "[{\"message\":\"no 'settings2' in system\"}]"; auto expected_response = "[{\"message\":\"no 'settings2' in system\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/settings2")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/settings2"));
} }
void test_43() { void test_46() {
auto expected_response = "[{\"message\":\"no 'settings2' in system\"}]"; auto expected_response = "[{\"message\":\"no 'settings2' in system\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/settings2/locale2")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/settings2/locale2"));
} }
void test_44() { void test_47() {
auto expected_response = "[{\"message\":\"no 'test_scheduler2' in scheduler\"}]"; auto expected_response = "[{\"message\":\"no 'test_scheduler2' in scheduler\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/test_scheduler2")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/test_scheduler2"));
} }
void test_45() { void test_48() {
auto expected_response = "[{\"message\":\"no attribute 'val' in test_scheduler\"}]"; auto expected_response = "[{\"message\":\"no attribute 'val' in test_scheduler\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/test_scheduler/val")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/test_scheduler/val"));
} }
void test_46() { void test_49() {
auto expected_response = "[{\"message\":\"no 'test_scheduler2' in scheduler\"}]"; auto expected_response = "[{\"message\":\"no 'test_scheduler2' in scheduler\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/test_scheduler2/val2")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/test_scheduler2/val2"));
} }
void test_47() { void test_50() {
auto expected_response = "[{\"message\":\"no 'test_seltemp2' in custom\"}]"; auto expected_response = "[{\"message\":\"no 'test_seltemp2' in custom\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/test_seltemp2")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/test_seltemp2"));
} }
void test_48() { void test_51() {
auto expected_response = "[{\"message\":\"Command test_seltemp failed (Error)\"}]"; auto expected_response = "[{\"message\":\"Command test_seltemp failed (Error)\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/test_seltemp/val")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/test_seltemp/val"));
} }
void test_49() { void test_52() {
auto expected_response = "[{\"message\":\"no 'test_sensor20' in temperaturesensor\"}]"; auto expected_response = "[{\"message\":\"no 'test_sensor20' in temperaturesensor\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_sensor20")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_sensor20"));
} }
void test_50() { void test_53() {
auto expected_response = "[{\"message\":\"no '0b_0c0d_0e0f_xxxx' in temperaturesensor\"}]"; auto expected_response = "[{\"message\":\"no '0b_0c0d_0e0f_xxxx' in temperaturesensor\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/0B_0C0D_0E0F_XXXX")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/0B_0C0D_0E0F_XXXX"));
} }
void test_51() { void test_54() {
auto expected_response = "[{\"message\":\"no attribute 'bad' in test_tempsensor2\"}]"; auto expected_response = "[{\"message\":\"no attribute 'bad' in test_tempsensor2\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_tempsensor2/bad")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_tempsensor2/bad"));
} }
void test_52() { void test_55() {
auto expected_response = "[{\"message\":\"no attribute 'bad' in test_analogsensor1\"}]"; auto expected_response = "[{\"message\":\"no attribute 'bad' in test_analogsensor1\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analogsensor1/bad")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analogsensor1/bad"));
} }
void test_53() { void test_56() {
auto expected_response = "[{\"message\":\"no 'test_analog10' in analogsensor\"}]"; auto expected_response = "[{\"message\":\"no 'test_analog10' in analogsensor\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analog10")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analog10"));
} }
void test_54() { void test_57() {
auto expected_response = "[{\"message\":\"no 'test_analog10' in analogsensor\"}]"; auto expected_response = "[{\"message\":\"no 'test_analog10' in analogsensor\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analog10/bad2")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analog10/bad2"));
} }
@@ -440,6 +584,9 @@ void run_tests() {
RUN_TEST(test_52); RUN_TEST(test_52);
RUN_TEST(test_53); RUN_TEST(test_53);
RUN_TEST(test_54); RUN_TEST(test_54);
RUN_TEST(test_55);
RUN_TEST(test_56);
RUN_TEST(test_57);
} }
// ---------- END - CUT HERE ---------- // ---------- END - CUT HERE ----------