mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-06-13 19:36:26 +03:00
Feature: Make RGB LED (preset colors) accessible via API/etc #3039
Fixes #3063
This commit is contained in:
@@ -18,6 +18,7 @@ For more details go to [emsesp.org](https://emsesp.org/).
|
|||||||
- updated version check [#3047](https://github.com/emsesp/EMS-ESP32/issues/3047)
|
- updated version check [#3047](https://github.com/emsesp/EMS-ESP32/issues/3047)
|
||||||
- auto-logic to set ht3/ems+ tx-mode
|
- auto-logic to set ht3/ems+ tx-mode
|
||||||
- polarity for digital_in sensors [#3070](https://github.com/emsesp/EMS-ESP32/discussions/3070)
|
- polarity for digital_in sensors [#3070](https://github.com/emsesp/EMS-ESP32/discussions/3070)
|
||||||
|
- user-requested LED blink [#3063](https://github.com/emsesp/EMS-ESP32/issues/3063)
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
"react": "^19.2.6",
|
"react": "^19.2.6",
|
||||||
"react-dom": "^19.2.6",
|
"react-dom": "^19.2.6",
|
||||||
"react-icons": "^5.6.0",
|
"react-icons": "^5.6.0",
|
||||||
"react-router": "^7.15.0",
|
"react-router": "^7.15.1",
|
||||||
"react-toastify": "^11.1.0",
|
"react-toastify": "^11.1.0",
|
||||||
"typesafe-i18n": "^5.27.1",
|
"typesafe-i18n": "^5.27.1",
|
||||||
"typescript": "^6.0.3"
|
"typescript": "^6.0.3"
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"@preact/preset-vite": "^2.10.5",
|
"@preact/preset-vite": "^2.10.5",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
||||||
"@types/node": "^25.7.0",
|
"@types/node": "^25.8.0",
|
||||||
"@types/react": "^19.2.14",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"concurrently": "^9.2.1",
|
"concurrently": "^9.2.1",
|
||||||
|
|||||||
76
interface/pnpm-lock.yaml
generated
76
interface/pnpm-lock.yaml
generated
@@ -54,8 +54,8 @@ importers:
|
|||||||
specifier: ^5.6.0
|
specifier: ^5.6.0
|
||||||
version: 5.6.0(react@19.2.6)
|
version: 5.6.0(react@19.2.6)
|
||||||
react-router:
|
react-router:
|
||||||
specifier: ^7.15.0
|
specifier: ^7.15.1
|
||||||
version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
version: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||||
react-toastify:
|
react-toastify:
|
||||||
specifier: ^11.1.0
|
specifier: ^11.1.0
|
||||||
version: 11.1.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
version: 11.1.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||||
@@ -71,13 +71,13 @@ importers:
|
|||||||
version: 10.0.1(eslint@10.3.0)
|
version: 10.0.1(eslint@10.3.0)
|
||||||
'@preact/preset-vite':
|
'@preact/preset-vite':
|
||||||
specifier: ^2.10.5
|
specifier: ^2.10.5
|
||||||
version: 2.10.5(@babel/core@7.29.0)(preact@10.29.1)(rollup@4.59.0)(vite@8.0.13(@types/node@25.7.0)(terser@5.47.1))
|
version: 2.10.5(@babel/core@7.29.0)(preact@10.29.1)(rollup@4.59.0)(vite@8.0.13(@types/node@25.8.0)(terser@5.47.1))
|
||||||
'@trivago/prettier-plugin-sort-imports':
|
'@trivago/prettier-plugin-sort-imports':
|
||||||
specifier: ^6.0.2
|
specifier: ^6.0.2
|
||||||
version: 6.0.2(prettier@3.8.3)
|
version: 6.0.2(prettier@3.8.3)
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^25.7.0
|
specifier: ^25.8.0
|
||||||
version: 25.7.0
|
version: 25.8.0
|
||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: ^19.2.14
|
specifier: ^19.2.14
|
||||||
version: 19.2.14
|
version: 19.2.14
|
||||||
@@ -107,10 +107,10 @@ importers:
|
|||||||
version: 8.59.3(eslint@10.3.0)(typescript@6.0.3)
|
version: 8.59.3(eslint@10.3.0)(typescript@6.0.3)
|
||||||
vite:
|
vite:
|
||||||
specifier: ^8.0.13
|
specifier: ^8.0.13
|
||||||
version: 8.0.13(@types/node@25.7.0)(terser@5.47.1)
|
version: 8.0.13(@types/node@25.8.0)(terser@5.47.1)
|
||||||
vite-plugin-imagemin:
|
vite-plugin-imagemin:
|
||||||
specifier: ^0.6.1
|
specifier: ^0.6.1
|
||||||
version: 0.6.1(vite@8.0.13(@types/node@25.7.0)(terser@5.47.1))
|
version: 0.6.1(vite@8.0.13(@types/node@25.8.0)(terser@5.47.1))
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -829,8 +829,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==}
|
resolution: {integrity: sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==}
|
||||||
deprecated: This is a stub types definition. minimatch provides its own type definitions, so you do not need this installed.
|
deprecated: This is a stub types definition. minimatch provides its own type definitions, so you do not need this installed.
|
||||||
|
|
||||||
'@types/node@25.7.0':
|
'@types/node@25.8.0':
|
||||||
resolution: {integrity: sha512-z+pdZyxE+RTQE9AcboAZCb4otwcrvgHD+GlBpPgn0emDVt0ohrTMhAwlr2Wd9nZ+nihhYFxO2pThz3C5qSu2Eg==}
|
resolution: {integrity: sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==}
|
||||||
|
|
||||||
'@types/parse-json@4.0.2':
|
'@types/parse-json@4.0.2':
|
||||||
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
|
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
|
||||||
@@ -1330,8 +1330,8 @@ packages:
|
|||||||
duplexer3@0.1.5:
|
duplexer3@0.1.5:
|
||||||
resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==}
|
resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==}
|
||||||
|
|
||||||
electron-to-chromium@1.5.355:
|
electron-to-chromium@1.5.356:
|
||||||
resolution: {integrity: sha512-LUPZhKzZPYSPme1jEYohpkA+ybYCJztr1quAdBd7E7h3+VOBVcKkwwtBJu41nrjawrRzfb8mtMfzWozoaK0ZIQ==}
|
resolution: {integrity: sha512-9NgFd7m5t5MCJ5rUSjJITUXAH9mEGlrlofnMf4YEr+pz6JlP7cWmTAH+JFmbPnaSW8koVTkuW7pacORWAnA5Yw==}
|
||||||
|
|
||||||
emoji-regex@10.6.0:
|
emoji-regex@10.6.0:
|
||||||
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
|
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
|
||||||
@@ -2589,8 +2589,8 @@ packages:
|
|||||||
react-is@19.2.6:
|
react-is@19.2.6:
|
||||||
resolution: {integrity: sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==}
|
resolution: {integrity: sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==}
|
||||||
|
|
||||||
react-router@7.15.0:
|
react-router@7.15.1:
|
||||||
resolution: {integrity: sha512-HW9vYwuM8f4yx66Izy8xfrzCM+SBJluoZcCbww9A1TySax11S5Vgw6fi3ZjMONw9J4gQwngL7PzkyIpJJpJ7RQ==}
|
resolution: {integrity: sha512-R8rl9HhgikFYoPJymnUtPXWbnDb3oget6lQnfIoupbt61aT9aOhRkDsY2XRhZRyX1Z/8a5sL74fXmFNm3NRK5A==}
|
||||||
engines: {node: '>=20.0.0'}
|
engines: {node: '>=20.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: '>=18'
|
react: '>=18'
|
||||||
@@ -3010,8 +3010,8 @@ packages:
|
|||||||
unbzip2-stream@1.4.3:
|
unbzip2-stream@1.4.3:
|
||||||
resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==}
|
resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==}
|
||||||
|
|
||||||
undici-types@7.21.0:
|
undici-types@7.24.6:
|
||||||
resolution: {integrity: sha512-w9IMgQrz4O0YN1LtB7K5P63vhlIOvC7opSmouCJ+ZywlPAlO9gIkJ+otk6LvGpAs2wg4econaCz3TvQ9xPoyuQ==}
|
resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==}
|
||||||
|
|
||||||
universalify@2.0.1:
|
universalify@2.0.1:
|
||||||
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
|
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
|
||||||
@@ -3604,19 +3604,19 @@ snapshots:
|
|||||||
|
|
||||||
'@popperjs/core@2.11.8': {}
|
'@popperjs/core@2.11.8': {}
|
||||||
|
|
||||||
'@preact/preset-vite@2.10.5(@babel/core@7.29.0)(preact@10.29.1)(rollup@4.59.0)(vite@8.0.13(@types/node@25.7.0)(terser@5.47.1))':
|
'@preact/preset-vite@2.10.5(@babel/core@7.29.0)(preact@10.29.1)(rollup@4.59.0)(vite@8.0.13(@types/node@25.8.0)(terser@5.47.1))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.29.0
|
'@babel/core': 7.29.0
|
||||||
'@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0)
|
'@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0)
|
||||||
'@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.29.0)
|
'@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.29.0)
|
||||||
'@prefresh/vite': 2.4.12(preact@10.29.1)(vite@8.0.13(@types/node@25.7.0)(terser@5.47.1))
|
'@prefresh/vite': 2.4.12(preact@10.29.1)(vite@8.0.13(@types/node@25.8.0)(terser@5.47.1))
|
||||||
'@rollup/pluginutils': 5.3.0(rollup@4.59.0)
|
'@rollup/pluginutils': 5.3.0(rollup@4.59.0)
|
||||||
babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.29.0)
|
babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.29.0)
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
magic-string: 0.30.21
|
magic-string: 0.30.21
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
vite: 8.0.13(@types/node@25.7.0)(terser@5.47.1)
|
vite: 8.0.13(@types/node@25.8.0)(terser@5.47.1)
|
||||||
vite-prerender-plugin: 0.5.13(vite@8.0.13(@types/node@25.7.0)(terser@5.47.1))
|
vite-prerender-plugin: 0.5.13(vite@8.0.13(@types/node@25.8.0)(terser@5.47.1))
|
||||||
zimmerframe: 1.1.4
|
zimmerframe: 1.1.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- preact
|
- preact
|
||||||
@@ -3631,7 +3631,7 @@ snapshots:
|
|||||||
|
|
||||||
'@prefresh/utils@1.2.1': {}
|
'@prefresh/utils@1.2.1': {}
|
||||||
|
|
||||||
'@prefresh/vite@2.4.12(preact@10.29.1)(vite@8.0.13(@types/node@25.7.0)(terser@5.47.1))':
|
'@prefresh/vite@2.4.12(preact@10.29.1)(vite@8.0.13(@types/node@25.8.0)(terser@5.47.1))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.29.0
|
'@babel/core': 7.29.0
|
||||||
'@prefresh/babel-plugin': 0.5.3
|
'@prefresh/babel-plugin': 0.5.3
|
||||||
@@ -3639,7 +3639,7 @@ snapshots:
|
|||||||
'@prefresh/utils': 1.2.1
|
'@prefresh/utils': 1.2.1
|
||||||
'@rollup/pluginutils': 4.2.1
|
'@rollup/pluginutils': 4.2.1
|
||||||
preact: 10.29.1
|
preact: 10.29.1
|
||||||
vite: 8.0.13(@types/node@25.7.0)(terser@5.47.1)
|
vite: 8.0.13(@types/node@25.8.0)(terser@5.47.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -3822,7 +3822,7 @@ snapshots:
|
|||||||
'@types/glob@7.2.0':
|
'@types/glob@7.2.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/minimatch': 6.0.0
|
'@types/minimatch': 6.0.0
|
||||||
'@types/node': 25.7.0
|
'@types/node': 25.8.0
|
||||||
|
|
||||||
'@types/imagemin-gifsicle@7.0.4':
|
'@types/imagemin-gifsicle@7.0.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3851,21 +3851,21 @@ snapshots:
|
|||||||
|
|
||||||
'@types/imagemin@7.0.1':
|
'@types/imagemin@7.0.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 25.7.0
|
'@types/node': 25.8.0
|
||||||
|
|
||||||
'@types/json-schema@7.0.15': {}
|
'@types/json-schema@7.0.15': {}
|
||||||
|
|
||||||
'@types/keyv@3.1.4':
|
'@types/keyv@3.1.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 25.7.0
|
'@types/node': 25.8.0
|
||||||
|
|
||||||
'@types/minimatch@6.0.0':
|
'@types/minimatch@6.0.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
minimatch: 10.2.5
|
minimatch: 10.2.5
|
||||||
|
|
||||||
'@types/node@25.7.0':
|
'@types/node@25.8.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.21.0
|
undici-types: 7.24.6
|
||||||
|
|
||||||
'@types/parse-json@4.0.2': {}
|
'@types/parse-json@4.0.2': {}
|
||||||
|
|
||||||
@@ -3885,11 +3885,11 @@ snapshots:
|
|||||||
|
|
||||||
'@types/responselike@1.0.3':
|
'@types/responselike@1.0.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 25.7.0
|
'@types/node': 25.8.0
|
||||||
|
|
||||||
'@types/svgo@2.6.4':
|
'@types/svgo@2.6.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 25.7.0
|
'@types/node': 25.8.0
|
||||||
|
|
||||||
'@typescript-eslint/eslint-plugin@8.59.3(@typescript-eslint/parser@8.59.3(eslint@10.3.0)(typescript@6.0.3))(eslint@10.3.0)(typescript@6.0.3)':
|
'@typescript-eslint/eslint-plugin@8.59.3(@typescript-eslint/parser@8.59.3(eslint@10.3.0)(typescript@6.0.3))(eslint@10.3.0)(typescript@6.0.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -4109,7 +4109,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
baseline-browser-mapping: 2.10.29
|
baseline-browser-mapping: 2.10.29
|
||||||
caniuse-lite: 1.0.30001792
|
caniuse-lite: 1.0.30001792
|
||||||
electron-to-chromium: 1.5.355
|
electron-to-chromium: 1.5.356
|
||||||
node-releases: 2.0.44
|
node-releases: 2.0.44
|
||||||
update-browserslist-db: 1.2.3(browserslist@4.28.2)
|
update-browserslist-db: 1.2.3(browserslist@4.28.2)
|
||||||
|
|
||||||
@@ -4468,7 +4468,7 @@ snapshots:
|
|||||||
|
|
||||||
duplexer3@0.1.5: {}
|
duplexer3@0.1.5: {}
|
||||||
|
|
||||||
electron-to-chromium@1.5.355: {}
|
electron-to-chromium@1.5.356: {}
|
||||||
|
|
||||||
emoji-regex@10.6.0: {}
|
emoji-regex@10.6.0: {}
|
||||||
|
|
||||||
@@ -5648,7 +5648,7 @@ snapshots:
|
|||||||
|
|
||||||
react-is@19.2.6: {}
|
react-is@19.2.6: {}
|
||||||
|
|
||||||
react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6):
|
react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
cookie: 1.1.1
|
cookie: 1.1.1
|
||||||
react: 19.2.6
|
react: 19.2.6
|
||||||
@@ -6088,7 +6088,7 @@ snapshots:
|
|||||||
buffer: 5.7.1
|
buffer: 5.7.1
|
||||||
through: 2.3.8
|
through: 2.3.8
|
||||||
|
|
||||||
undici-types@7.21.0: {}
|
undici-types@7.24.6: {}
|
||||||
|
|
||||||
universalify@2.0.1: {}
|
universalify@2.0.1: {}
|
||||||
|
|
||||||
@@ -6121,7 +6121,7 @@ snapshots:
|
|||||||
spdx-correct: 3.2.0
|
spdx-correct: 3.2.0
|
||||||
spdx-expression-parse: 3.0.1
|
spdx-expression-parse: 3.0.1
|
||||||
|
|
||||||
vite-plugin-imagemin@0.6.1(vite@8.0.13(@types/node@25.7.0)(terser@5.47.1)):
|
vite-plugin-imagemin@0.6.1(vite@8.0.13(@types/node@25.8.0)(terser@5.47.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/imagemin': 7.0.1
|
'@types/imagemin': 7.0.1
|
||||||
'@types/imagemin-gifsicle': 7.0.4
|
'@types/imagemin-gifsicle': 7.0.4
|
||||||
@@ -6146,11 +6146,11 @@ snapshots:
|
|||||||
imagemin-webp: 6.1.0
|
imagemin-webp: 6.1.0
|
||||||
jpegtran-bin: 6.0.1
|
jpegtran-bin: 6.0.1
|
||||||
pathe: 0.2.0
|
pathe: 0.2.0
|
||||||
vite: 8.0.13(@types/node@25.7.0)(terser@5.47.1)
|
vite: 8.0.13(@types/node@25.8.0)(terser@5.47.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
vite-prerender-plugin@0.5.13(vite@8.0.13(@types/node@25.7.0)(terser@5.47.1)):
|
vite-prerender-plugin@0.5.13(vite@8.0.13(@types/node@25.8.0)(terser@5.47.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
kolorist: 1.8.0
|
kolorist: 1.8.0
|
||||||
magic-string: 0.30.21
|
magic-string: 0.30.21
|
||||||
@@ -6158,9 +6158,9 @@ snapshots:
|
|||||||
simple-code-frame: 1.3.0
|
simple-code-frame: 1.3.0
|
||||||
source-map: 0.7.6
|
source-map: 0.7.6
|
||||||
stack-trace: 1.0.0
|
stack-trace: 1.0.0
|
||||||
vite: 8.0.13(@types/node@25.7.0)(terser@5.47.1)
|
vite: 8.0.13(@types/node@25.8.0)(terser@5.47.1)
|
||||||
|
|
||||||
vite@8.0.13(@types/node@25.7.0)(terser@5.47.1):
|
vite@8.0.13(@types/node@25.8.0)(terser@5.47.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
lightningcss: 1.32.0
|
lightningcss: 1.32.0
|
||||||
picomatch: 4.0.4
|
picomatch: 4.0.4
|
||||||
@@ -6168,7 +6168,7 @@ snapshots:
|
|||||||
rolldown: 1.0.1
|
rolldown: 1.0.1
|
||||||
tinyglobby: 0.2.16
|
tinyglobby: 0.2.16
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/node': 25.7.0
|
'@types/node': 25.8.0
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
terser: 5.47.1
|
terser: 5.47.1
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ Network EMSESP::network_; // network services
|
|||||||
TemperatureSensor EMSESP::temperaturesensor_; // Temperature sensors
|
TemperatureSensor EMSESP::temperaturesensor_; // Temperature sensors
|
||||||
AnalogSensor EMSESP::analogsensor_; // Analog sensors
|
AnalogSensor EMSESP::analogsensor_; // Analog sensors
|
||||||
Shower EMSESP::shower_; // Shower logic
|
Shower EMSESP::shower_; // Shower logic
|
||||||
|
LED EMSESP::led_; // LED handler
|
||||||
Preferences EMSESP::nvs_; // NV Storage
|
Preferences EMSESP::nvs_; // NV Storage
|
||||||
|
|
||||||
// for a specific EMS device go and request data values
|
// for a specific EMS device go and request data values
|
||||||
@@ -1532,7 +1533,7 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
|
|||||||
Roomctrl::check(data[1], data, length);
|
Roomctrl::check(data[1], data, length);
|
||||||
#ifdef EMSESP_UART_DEBUG
|
#ifdef EMSESP_UART_DEBUG
|
||||||
// get_uptime is only updated once per loop, does not give the right time
|
// get_uptime is only updated once per loop, does not give the right time
|
||||||
LOG_TRACE("[UART_DEBUG] Echo after %d ms: %s", ::millis() - rx_time_, Helpers::data_to_hex(data, length).c_str());
|
LOG_TRACE("[UART_DEBUG] Echo after %d ms: %s", uuid::get_uptime_ms() - rx_time_, Helpers::data_to_hex(data, length).c_str());
|
||||||
#endif
|
#endif
|
||||||
// add to RxQueue for log/watch
|
// add to RxQueue for log/watch
|
||||||
rxservice_.add(data, length);
|
rxservice_.add(data, length);
|
||||||
@@ -1616,11 +1617,11 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
|
|||||||
#ifdef EMSESP_UART_DEBUG
|
#ifdef EMSESP_UART_DEBUG
|
||||||
char s[4];
|
char s[4];
|
||||||
if (first_value & 0x80) {
|
if (first_value & 0x80) {
|
||||||
LOG_TRACE("[UART_DEBUG] next Poll %s after %d ms", Helpers::hextoa(s, first_value), ::millis() - rx_time_);
|
LOG_TRACE("[UART_DEBUG] next Poll %s after %d ms", Helpers::hextoa(s, first_value), uuid::get_uptime_ms() - rx_time_);
|
||||||
// time measurement starts here, use millis because get_uptime is only updated once per loop
|
// time measurement starts here, use millis because get_uptime is only updated once per loop
|
||||||
rx_time_ = ::millis();
|
rx_time_ = uuid::get_uptime_ms();
|
||||||
} else {
|
} else {
|
||||||
LOG_TRACE("[UART_DEBUG] Poll ack %s after %d ms", Helpers::hextoa(s, first_value), ::millis() - rx_time_);
|
LOG_TRACE("[UART_DEBUG] Poll ack %s after %d ms", Helpers::hextoa(s, first_value), uuid::get_uptime_ms() - rx_time_);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// check for poll to us, if so send top message from Tx queue immediately and quit
|
// check for poll to us, if so send top message from Tx queue immediately and quit
|
||||||
@@ -1634,7 +1635,7 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
#ifdef EMSESP_UART_DEBUG
|
#ifdef EMSESP_UART_DEBUG
|
||||||
LOG_TRACE("[UART_DEBUG] Reply after %d ms: %s", ::millis() - rx_time_, Helpers::data_to_hex(data, length).c_str());
|
LOG_TRACE("[UART_DEBUG] Reply after %d ms: %s", uuid::get_uptime_ms() - rx_time_, Helpers::data_to_hex(data, length).c_str());
|
||||||
#endif
|
#endif
|
||||||
Roomctrl::check(data[1], data, length); // check if there is a message for the roomcontroller
|
Roomctrl::check(data[1], data, length); // check if there is a message for the roomcontroller
|
||||||
|
|
||||||
@@ -1711,10 +1712,10 @@ void EMSESP::start() {
|
|||||||
bool factory_settings = false;
|
bool factory_settings = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(EMSESP_DEBUG)
|
// #if defined(EMSESP_DEBUG)
|
||||||
// LOG_DEBUG("Listing root directory before:");
|
// LOG_DEBUG("Listing root directory before:");
|
||||||
// system_.listDir("/", 3); // show the contents of the root directory
|
// system_.listDir("/", 3); // show the contents of the root directory
|
||||||
#endif
|
// #endif
|
||||||
|
|
||||||
// start NVS storage
|
// start NVS storage
|
||||||
if (!nvs_.begin("ems-esp", false, "nvs1")) { // try bigger nvs partition on 16M flash first
|
if (!nvs_.begin("ems-esp", false, "nvs1")) { // try bigger nvs partition on 16M flash first
|
||||||
@@ -1730,10 +1731,10 @@ void EMSESP::start() {
|
|||||||
// loads core system services settings (mqtt, ap, ntp etc)
|
// loads core system services settings (mqtt, ap, ntp etc)
|
||||||
esp32React.begin();
|
esp32React.begin();
|
||||||
|
|
||||||
#if defined(EMSESP_DEBUG)
|
// #if defined(EMSESP_DEBUG)
|
||||||
// LOG_DEBUG("Listing root directory after:");
|
// LOG_DEBUG("Listing root directory after:");
|
||||||
// system_.listDir("/", 3); // show the contents of the root directory
|
// system_.listDir("/", 3); // show the contents of the root directory
|
||||||
#endif
|
// #endif
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
if (factory_settings) {
|
if (factory_settings) {
|
||||||
@@ -1866,7 +1867,7 @@ void EMSESP::loop() {
|
|||||||
|
|
||||||
// handles LED and checks system health, and syslog service
|
// handles LED and checks system health, and syslog service
|
||||||
if (system_.loop()) {
|
if (system_.loop()) {
|
||||||
return; // LED flashing is active, skip the rest of the loop
|
return; // LED flashing is active meaning its about to reboot, skip the rest of the loop
|
||||||
}
|
}
|
||||||
|
|
||||||
esp32React.loop(); // core services: Network, AP, MQTT and NTP
|
esp32React.loop(); // core services: Network, AP, MQTT and NTP
|
||||||
|
|||||||
@@ -233,6 +233,7 @@ class EMSESP {
|
|||||||
static TemperatureSensor temperaturesensor_;
|
static TemperatureSensor temperaturesensor_;
|
||||||
static AnalogSensor analogsensor_;
|
static AnalogSensor analogsensor_;
|
||||||
static Shower shower_;
|
static Shower shower_;
|
||||||
|
static LED led_;
|
||||||
static RxService rxservice_;
|
static RxService rxservice_;
|
||||||
static TxService txservice_;
|
static TxService txservice_;
|
||||||
static Preferences nvs_;
|
static Preferences nvs_;
|
||||||
|
|||||||
287
src/core/led.cpp
Normal file
287
src/core/led.cpp
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
/*
|
||||||
|
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||||
|
* Copyright 2020-2025 emsesp.org
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "led.h"
|
||||||
|
#include "emsesp.h"
|
||||||
|
|
||||||
|
namespace emsesp {
|
||||||
|
|
||||||
|
uuid::log::Logger LED::logger_{F_(led), uuid::log::Facility::KERN};
|
||||||
|
|
||||||
|
// initialise the LED, fetching the settings from the WebSettingsService
|
||||||
|
// set the LED to on or off when in normal operating mode
|
||||||
|
void LED::init() {
|
||||||
|
// copy the application settings
|
||||||
|
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
||||||
|
led_gpio_ = settings.led_gpio;
|
||||||
|
led_type_ = settings.led_type;
|
||||||
|
hide_led_ = settings.hide_led;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!led_gpio_) { // 0 means disabled
|
||||||
|
LOG_INFO("LED disabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for safety
|
||||||
|
if (!led_type_) {
|
||||||
|
pinMode(led_gpio_, OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_led(false); // start with LED off
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle LED routine
|
||||||
|
// called from the System::loop()
|
||||||
|
// returns true if the LED flash is active, i.e its a lock down state
|
||||||
|
bool LED::loop(uint8_t healthcheck, bool button_busy) {
|
||||||
|
if (!led_gpio_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if LED flashing is active it means its about to perform a factory reset, so don't do anything else and keep it flashing
|
||||||
|
if (led_fast_flash_timer_) {
|
||||||
|
led_fast_flash();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// show the LED status based on the healthcheck and button busy status
|
||||||
|
monitor(healthcheck, button_busy);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn the LED off (false) or to it's default state (true)
|
||||||
|
void LED::reset_led(bool default_state) {
|
||||||
|
if (!led_gpio_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (default_state) {
|
||||||
|
// set the LED to it's default state (for RGB its green)
|
||||||
|
set_led(hide_led_ ? Color::OFF : Color::GREEN); // Green
|
||||||
|
} else {
|
||||||
|
// force it off
|
||||||
|
set_led(Color::OFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LED flash every few ms and then perform a factory reset
|
||||||
|
void LED::led_fast_flash() {
|
||||||
|
uint32_t current_time = uuid::get_uptime();
|
||||||
|
|
||||||
|
if (current_time - last_toggle_time_ >= LED_FLASH_INTERVAL_MS) {
|
||||||
|
led_flash_state_ = !led_flash_state_;
|
||||||
|
last_toggle_time_ = current_time;
|
||||||
|
set_led(led_flash_state_ ? Color::YELLOW : Color::OFF); // Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
// after duration, turn off the LED
|
||||||
|
if (current_time - led_flash_start_time_ >= led_flash_duration_) {
|
||||||
|
reset_led(false);
|
||||||
|
led_fast_flash_timer_ = false;
|
||||||
|
#ifndef EMSESP_DEBUG
|
||||||
|
System::command_format(nullptr, 0); // Execute format operation, unless in debug mode
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set LED on/off or RGB color
|
||||||
|
// ignores whether the LED is hidden or not (hide_led_ is set)
|
||||||
|
void LED::set_led(Color color) {
|
||||||
|
uint8_t red = 0;
|
||||||
|
uint8_t green = 0;
|
||||||
|
uint8_t blue = 0;
|
||||||
|
if (color == Color::RED) {
|
||||||
|
red = RGB_LED_BRIGHTNESS;
|
||||||
|
green = 0;
|
||||||
|
blue = 0;
|
||||||
|
} else if (color == Color::GREEN) {
|
||||||
|
red = 0;
|
||||||
|
green = RGB_LED_BRIGHTNESS;
|
||||||
|
blue = 0;
|
||||||
|
} else if (color == Color::BLUE) {
|
||||||
|
red = 0;
|
||||||
|
green = 0;
|
||||||
|
blue = RGB_LED_BRIGHTNESS;
|
||||||
|
} else if (color == Color::YELLOW) {
|
||||||
|
red = RGB_LED_BRIGHTNESS;
|
||||||
|
green = RGB_LED_BRIGHTNESS;
|
||||||
|
blue = 0;
|
||||||
|
} else if (color == Color::OFF) { // off
|
||||||
|
red = 0;
|
||||||
|
green = 0;
|
||||||
|
blue = 0;
|
||||||
|
} else if (color == Color::ON) { // white
|
||||||
|
red = RGB_LED_BRIGHTNESS;
|
||||||
|
green = RGB_LED_BRIGHTNESS;
|
||||||
|
blue = RGB_LED_BRIGHTNESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (led_type_) {
|
||||||
|
rgbLedWrite(led_gpio_, red, green, blue);
|
||||||
|
} else {
|
||||||
|
digitalWrite(led_gpio_, (red == 0 && green == 0 && blue == 0) || color == Color::OFF ? !LED_ON : LED_ON);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set LED custom routine
|
||||||
|
// color is red, green, blue, yellow, white
|
||||||
|
// pattern is blink1, blink2, blink3, rgb
|
||||||
|
// For example: /api/system/led?data=red:blink1
|
||||||
|
// For older non-RGB models, the colour would default to just being on.
|
||||||
|
void LED::set_led_routine(std::string color, std::string pattern) {
|
||||||
|
Color color_type = Color::OFF;
|
||||||
|
if (color == "red") {
|
||||||
|
color_type = Color::RED;
|
||||||
|
} else if (color == "green") {
|
||||||
|
color_type = Color::GREEN;
|
||||||
|
} else if (color == "blue") {
|
||||||
|
color_type = Color::BLUE;
|
||||||
|
} else if (color == "yellow") {
|
||||||
|
color_type = Color::YELLOW;
|
||||||
|
} else if (color == "white") {
|
||||||
|
color_type = Color::ON;
|
||||||
|
} else {
|
||||||
|
color_type = Color::OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
color_steps_[0] = Color::OFF;
|
||||||
|
color_steps_[1] = Color::OFF;
|
||||||
|
color_steps_[2] = Color::OFF;
|
||||||
|
|
||||||
|
if (pattern == "blink1") {
|
||||||
|
color_steps_[0] = color_type;
|
||||||
|
} else if (pattern == "blink2") {
|
||||||
|
color_steps_[0] = color_type;
|
||||||
|
color_steps_[1] = color_type;
|
||||||
|
} else if (pattern == "blink3") {
|
||||||
|
color_steps_[0] = color_type;
|
||||||
|
color_steps_[1] = color_type;
|
||||||
|
color_steps_[2] = color_type;
|
||||||
|
} else if (pattern == "rgb") {
|
||||||
|
color_steps_[0] = Color::RED;
|
||||||
|
color_steps_[1] = Color::GREEN;
|
||||||
|
color_steps_[2] = Color::BLUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// uses LED to show system health and user-requested LED blinks
|
||||||
|
// it works in a batch of 3 configured flashes, then a long pause
|
||||||
|
// the timing is different for user-requested LED blink and for system healthcheck
|
||||||
|
void LED::monitor(uint8_t healthcheck, bool button_busy) {
|
||||||
|
// see if we're doing as user-requested LED blink
|
||||||
|
bool is_user_led_blink = false;
|
||||||
|
if (color_steps_[0] != Color::OFF || color_steps_[1] != Color::OFF || color_steps_[2] != Color::OFF) {
|
||||||
|
is_user_led_blink = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if button is pressed, show LED (yellow on RGB LED, on/off on standard LED) and exit
|
||||||
|
if (last_button_busy_ != button_busy) {
|
||||||
|
last_button_busy_ = button_busy;
|
||||||
|
set_led(button_busy ? Color::OFF : Color::YELLOW); // Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
// we only need to run the LED monitor if there are errors, or if a button has been pressed or a user-requested LED blink is active
|
||||||
|
if ((!healthcheck || button_busy) && !is_user_led_blink) {
|
||||||
|
return; // nothing to show
|
||||||
|
}
|
||||||
|
|
||||||
|
// first long pause before we start flashing
|
||||||
|
auto current_time = uuid::get_uptime();
|
||||||
|
if (led_long_timer_
|
||||||
|
&& (uint32_t)(current_time - led_long_timer_) >= (is_user_led_blink ? HEALTHCHECK_LED_LONG_FAST_DURATION : HEALTHCHECK_LED_LONG_DURATION)) {
|
||||||
|
led_short_timer_ = current_time; // start the short timer
|
||||||
|
led_long_timer_ = 0; // stop long timer
|
||||||
|
led_flash_step_ = 1; // enable the short flash timer
|
||||||
|
}
|
||||||
|
|
||||||
|
// the flash timer which starts after the long pause
|
||||||
|
if (led_flash_step_
|
||||||
|
&& (uint32_t)(current_time - led_short_timer_) >= (is_user_led_blink ? HEALTHCHECK_LED_FLASH_FAST_DURATION : HEALTHCHECK_LED_FLASH_DURATION)) {
|
||||||
|
led_long_timer_ = 0; // stop the long timer
|
||||||
|
led_short_timer_ = current_time;
|
||||||
|
|
||||||
|
if (++led_flash_step_ == 8) {
|
||||||
|
// finished first iteration, reset the whole sequence
|
||||||
|
led_long_timer_ = uuid::get_uptime();
|
||||||
|
led_flash_step_ = 0;
|
||||||
|
reset_led(true); // LED back to what is was before
|
||||||
|
} else if (led_flash_step_ % 2) {
|
||||||
|
// handle the three step events (on odd numbers 3,5,7 etc). see if we need to set a LED color
|
||||||
|
|
||||||
|
// For the system healthcheck:
|
||||||
|
// 1 flash (blue) is the EMS bus is not connected
|
||||||
|
// 2 flashes (red, red) if the network (wifi or ethernet) is not connected
|
||||||
|
// 3 flashes (red, red, blue) is both the bus and the network are not connected
|
||||||
|
bool no_network = (healthcheck & System::HEALTHCHECK_NO_NETWORK) == System::HEALTHCHECK_NO_NETWORK;
|
||||||
|
bool no_bus = (healthcheck & System::HEALTHCHECK_NO_BUS) == System::HEALTHCHECK_NO_BUS;
|
||||||
|
|
||||||
|
switch (led_flash_step_) {
|
||||||
|
case 3: // first flash
|
||||||
|
if (is_user_led_blink) {
|
||||||
|
set_led(color_steps_[0]);
|
||||||
|
color_steps_[0] = Color::OFF; // reset
|
||||||
|
} else {
|
||||||
|
if (no_network) {
|
||||||
|
set_led(Color::RED); // red, no network
|
||||||
|
} else if (no_bus) {
|
||||||
|
set_led(Color::BLUE); // blue, no bus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 5: // second flash
|
||||||
|
if (is_user_led_blink) {
|
||||||
|
set_led(color_steps_[1]);
|
||||||
|
color_steps_[1] = Color::OFF; // reset
|
||||||
|
} else if (no_network) {
|
||||||
|
set_led(Color::RED); // red, no network
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 7: // third flash
|
||||||
|
if (is_user_led_blink) {
|
||||||
|
set_led(color_steps_[2]);
|
||||||
|
color_steps_[2] = Color::OFF; // reset
|
||||||
|
} else if (no_network && no_bus) {
|
||||||
|
set_led(Color::BLUE); // blue, no network and no bus
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// turn off LED after the LED flash, or on even number count
|
||||||
|
set_led(Color::OFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the LED flash timer - duration in seconds
|
||||||
|
void LED::start_led_fast_flash(uint8_t duration) {
|
||||||
|
// Don't start if already running
|
||||||
|
if (led_fast_flash_timer_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset counter and state
|
||||||
|
led_flash_start_time_ = uuid::get_uptime(); // current time
|
||||||
|
led_flash_duration_ = (uint32_t)duration * 1000; // duration in milliseconds
|
||||||
|
led_fast_flash_timer_ = true; // it's active
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace emsesp
|
||||||
81
src/core/led.h
Normal file
81
src/core/led.h
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||||
|
* Copyright 2020-2025 emsesp.org
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EMSESP_LED_H_
|
||||||
|
#define EMSESP_LED_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <uuid/log.h>
|
||||||
|
|
||||||
|
#include "emsesp_common.h"
|
||||||
|
|
||||||
|
namespace emsesp {
|
||||||
|
|
||||||
|
class LED {
|
||||||
|
public:
|
||||||
|
enum Color { RED = 0, GREEN = 1, BLUE = 2, YELLOW = 3, OFF = 4, ON = 5 };
|
||||||
|
|
||||||
|
void init();
|
||||||
|
bool loop(uint8_t healthcheck, bool button_busy);
|
||||||
|
|
||||||
|
void reset_led(bool default_state = true); // turn the LED to default state or use false for off
|
||||||
|
void start_led_fast_flash(uint8_t duration); // duration in seconds
|
||||||
|
|
||||||
|
void set_led(Color color);
|
||||||
|
void set_led_routine(std::string color, std::string pattern);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static uuid::log::Logger logger_;
|
||||||
|
|
||||||
|
void monitor(uint8_t led_routine, bool button_busy);
|
||||||
|
void led_fast_flash();
|
||||||
|
|
||||||
|
static constexpr uint32_t HEALTHCHECK_LED_LONG_DURATION = 1000; // 1 second between flash sequences
|
||||||
|
static constexpr uint32_t HEALTHCHECK_LED_LONG_FAST_DURATION = 500; // 1/2 second between flash sequences
|
||||||
|
static constexpr uint32_t HEALTHCHECK_LED_FLASH_DURATION = 150; // 150ms
|
||||||
|
static constexpr uint32_t HEALTHCHECK_LED_FLASH_FAST_DURATION = 150;
|
||||||
|
static constexpr uint32_t LED_FLASH_INTERVAL_MS = 100; // LED toggle period during factory-reset flash
|
||||||
|
static constexpr uint8_t RGB_LED_BRIGHTNESS = 20; // 255 is max brightness
|
||||||
|
static constexpr uint8_t LED_ON = HIGH; // LED on
|
||||||
|
|
||||||
|
// local copies of the application settings
|
||||||
|
uint8_t led_gpio_ = 0;
|
||||||
|
uint8_t led_type_ = 0;
|
||||||
|
bool hide_led_ = false;
|
||||||
|
|
||||||
|
bool led_fast_flash_timer_ = false;
|
||||||
|
uint32_t led_flash_start_time_ = 0;
|
||||||
|
uint32_t led_flash_duration_ = 0;
|
||||||
|
|
||||||
|
// led_flash() state
|
||||||
|
bool led_flash_state_ = false;
|
||||||
|
uint32_t last_toggle_time_ = 0;
|
||||||
|
|
||||||
|
// monitor() state
|
||||||
|
bool last_button_busy_ = false;
|
||||||
|
uint32_t led_long_timer_ = 1; // 1 will kick it off immediately
|
||||||
|
uint32_t led_short_timer_ = 0;
|
||||||
|
uint8_t led_flash_step_ = 0; // 0 means we're not in the short flash timer
|
||||||
|
|
||||||
|
// set_led_routine() state
|
||||||
|
Color color_steps_[3] = {Color::OFF, Color::OFF, Color::OFF};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace emsesp
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -43,6 +43,7 @@ MAKE_WORD(fetch)
|
|||||||
MAKE_WORD(restart)
|
MAKE_WORD(restart)
|
||||||
MAKE_WORD(format)
|
MAKE_WORD(format)
|
||||||
MAKE_WORD(txpause)
|
MAKE_WORD(txpause)
|
||||||
|
MAKE_WORD(led)
|
||||||
MAKE_WORD(raw)
|
MAKE_WORD(raw)
|
||||||
MAKE_WORD(watch)
|
MAKE_WORD(watch)
|
||||||
MAKE_WORD(syslog)
|
MAKE_WORD(syslog)
|
||||||
@@ -171,7 +172,6 @@ MAKE_WORD_CUSTOM(password_prompt, "Password: ")
|
|||||||
MAKE_WORD_CUSTOM(unset, "<unset>")
|
MAKE_WORD_CUSTOM(unset, "<unset>")
|
||||||
MAKE_WORD_CUSTOM(enable_mandatory, "<enable | disable>")
|
MAKE_WORD_CUSTOM(enable_mandatory, "<enable | disable>")
|
||||||
MAKE_WORD_CUSTOM(service_mandatory, "<ap | mqtt | ntp>")
|
MAKE_WORD_CUSTOM(service_mandatory, "<ap | mqtt | ntp>")
|
||||||
MAKE_WORD_CUSTOM(txpause_cmd, "enable/disable TX")
|
|
||||||
|
|
||||||
// more common names that don't need translations
|
// more common names that don't need translations
|
||||||
MAKE_NOTRANSLATION(1x3min, "1x3min")
|
MAKE_NOTRANSLATION(1x3min, "1x3min")
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ MAKE_WORD_TRANSLATION(system_cmd, "system setting", "System Einstellung", "syste
|
|||||||
MAKE_WORD_TRANSLATION(showertimer_cmd, "enable shower timer", "aktiviere Duschzeitmessung", "activeer douche timer", "aktivera duschtimer", "aktywuj czasomierz prysznica", "aktiver dusjtimer", "activer minuteur de douche", "duş zamanlayıcısını etkinleştir", "abilita timer doccia", "povoliť časovač sprchovania", "povolit časovač sprchy")
|
MAKE_WORD_TRANSLATION(showertimer_cmd, "enable shower timer", "aktiviere Duschzeitmessung", "activeer douche timer", "aktivera duschtimer", "aktywuj czasomierz prysznica", "aktiver dusjtimer", "activer minuteur de douche", "duş zamanlayıcısını etkinleştir", "abilita timer doccia", "povoliť časovač sprchovania", "povolit časovač sprchy")
|
||||||
MAKE_WORD_TRANSLATION(showeralert_cmd, "enable shower alert", "aktiviere Duschzeitwarnung", "activeer douche alarm", "aktivera duschvarning", "aktywuj alarm prysznica", "aktiver dusjvarsel", "activer alerte de douche", "duş uyarısını etkinleştir", "abilita allarme doccia", "povoliť upozornenie na sprchu", "povolit alarm sprchy")
|
MAKE_WORD_TRANSLATION(showeralert_cmd, "enable shower alert", "aktiviere Duschzeitwarnung", "activeer douche alarm", "aktivera duschvarning", "aktywuj alarm prysznica", "aktiver dusjvarsel", "activer alerte de douche", "duş uyarısını etkinleştir", "abilita allarme doccia", "povoliť upozornenie na sprchu", "povolit alarm sprchy")
|
||||||
MAKE_WORD_TRANSLATION(txpause_cmd, "pause EMS Tx", "EMS Tx pausieren", "pauzeer EMS Tx", "pausa EMS Tx", "wstrzymaj EMS Tx", "pause EMS Tx", "pause EMS Tx", "EMS Tx'i duraklat", "pausa EMS Tx", "pozastaviť EMS Tx", "pauzovat EMS Tx")
|
MAKE_WORD_TRANSLATION(txpause_cmd, "pause EMS Tx", "EMS Tx pausieren", "pauzeer EMS Tx", "pausa EMS Tx", "wstrzymaj EMS Tx", "pause EMS Tx", "pause EMS Tx", "EMS Tx'i duraklat", "pausa EMS Tx", "pozastaviť EMS Tx", "pauzovat EMS Tx")
|
||||||
|
MAKE_WORD_TRANSLATION(led_cmd, "flash the LED", "LED blinken", "LED knipperen", "LED blinka", "LED błyska", "LED blink", "LED clignote", "LED yanıp söner", "LED lampeggia", "LED bliká", "LED bliká")
|
||||||
|
|
||||||
// tags
|
// tags
|
||||||
MAKE_WORD_TRANSLATION(tag_hc1, "hc1", "HK1", "hc1", "VK1", "OG1", "hc1", "hc1", "ID1", "hc1", "hc1", "hc1")
|
MAKE_WORD_TRANSLATION(tag_hc1, "hc1", "HK1", "hc1", "VK1", "OG1", "hc1", "hc1", "ID1", "hc1", "hc1", "hc1")
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ NetPhase Network::initialPhase() const {
|
|||||||
void Network::loop() {
|
void Network::loop() {
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
// if we already have a Wifi or Ethernet connection then re-check every NETWORK_RECONNECTION_DELAY_LONG, otherwise NETWORK_RECONNECTION_DELAY_SHORT
|
// if we already have a Wifi or Ethernet connection then re-check every NETWORK_RECONNECTION_DELAY_LONG, otherwise NETWORK_RECONNECTION_DELAY_SHORT
|
||||||
const unsigned long currentMillis = millis();
|
const unsigned long currentMillis = uuid::get_uptime_ms();
|
||||||
const uint32_t reconnectDelay =
|
const uint32_t reconnectDelay =
|
||||||
(network_iface_ == NetIface::WIFI || network_iface_ == NetIface::ETHERNET) ? NETWORK_RECONNECTION_DELAY_LONG : NETWORK_RECONNECTION_DELAY_SHORT;
|
(network_iface_ == NetIface::WIFI || network_iface_ == NetIface::ETHERNET) ? NETWORK_RECONNECTION_DELAY_LONG : NETWORK_RECONNECTION_DELAY_SHORT;
|
||||||
if (!lastConnectionAttempt_ || static_cast<uint32_t>(currentMillis - lastConnectionAttempt_) >= reconnectDelay) {
|
if (!lastConnectionAttempt_ || static_cast<uint32_t>(currentMillis - lastConnectionAttempt_) >= reconnectDelay) {
|
||||||
|
|||||||
@@ -88,13 +88,6 @@ bool System::test_set_all_active_ = false;
|
|||||||
uint32_t System::max_alloc_mem_;
|
uint32_t System::max_alloc_mem_;
|
||||||
uint32_t System::heap_mem_;
|
uint32_t System::heap_mem_;
|
||||||
|
|
||||||
// LED flash timer
|
|
||||||
uint8_t System::led_flash_gpio_ = 0;
|
|
||||||
uint8_t System::led_flash_type_ = 0;
|
|
||||||
uint32_t System::led_flash_start_time_ = 0;
|
|
||||||
uint32_t System::led_flash_duration_ = 0;
|
|
||||||
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<System::GpioUsage, AllocatorPSRAM<System::GpioUsage>> System::used_gpios_;
|
std::vector<System::GpioUsage, AllocatorPSRAM<System::GpioUsage>> System::used_gpios_;
|
||||||
@@ -733,14 +726,12 @@ void System::start() {
|
|||||||
hostname(networkSettings.hostname.c_str()); // sets the hostname
|
hostname(networkSettings.hostname.c_str()); // sets the hostname
|
||||||
});
|
});
|
||||||
|
|
||||||
commands_init(); // console & api commands
|
commands_init(); // console & api commands
|
||||||
led_init(); // init LED
|
EMSESP::led_.init(); // init LED
|
||||||
button_init(); // button
|
button_init(); // button
|
||||||
|
uart_init(); // start UART
|
||||||
last_system_check_ = 0; // force the LED to go from fast flash to pulse
|
syslog_init(); // start syslog
|
||||||
uart_init(); // start UART
|
modbus_init(); // start modbus
|
||||||
syslog_init(); // start syslog
|
|
||||||
modbus_init(); // start modbus
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// button single click
|
// button single click
|
||||||
@@ -757,7 +748,7 @@ void System::button_OnClick(PButton & b) {
|
|||||||
// reconnect to AP by removing the SSID from the network settings
|
// reconnect to AP by removing the SSID from the network settings
|
||||||
// note: in v3.9 this is normal behaviour to fallback to AP if the Wifi or Ethernet connection fails
|
// note: in v3.9 this is normal behaviour to fallback to AP if the Wifi or Ethernet connection fails
|
||||||
void System::button_OnDblClick(PButton & b) {
|
void System::button_OnDblClick(PButton & b) {
|
||||||
LOG_NOTICE("Button pressed - double click - wifi reconnect to AP");
|
LOG_NOTICE("Button pressed - double click - reset network");
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
// set AP mode to always so will join AP if wifi ssid fails to connect
|
// set AP mode to always so will join AP if wifi ssid fails to connect
|
||||||
EMSESP::esp32React.getAPSettingsService()->update([&](APSettings & apSettings) {
|
EMSESP::esp32React.getAPSettingsService()->update([&](APSettings & apSettings) {
|
||||||
@@ -773,55 +764,6 @@ void System::button_OnDblClick(PButton & b) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// LED flash every 100ms
|
|
||||||
void System::led_flash() {
|
|
||||||
static bool led_flash_state_ = false;
|
|
||||||
static uint32_t last_toggle_time_ = 0;
|
|
||||||
uint32_t current_time = uuid::get_uptime();
|
|
||||||
|
|
||||||
if (current_time - last_toggle_time_ >= 100) { // every 100ms
|
|
||||||
led_flash_state_ = !led_flash_state_;
|
|
||||||
last_toggle_time_ = current_time;
|
|
||||||
|
|
||||||
if (led_flash_type_) {
|
|
||||||
uint8_t intensity = led_flash_state_ ? RGB_LED_BRIGHTNESS : 0;
|
|
||||||
EMSESP_RGB_WRITE(led_flash_gpio_, intensity, intensity, 0); // RGB LED - Yellow
|
|
||||||
} else {
|
|
||||||
digitalWrite(led_flash_gpio_, led_flash_state_ ? LED_ON : !LED_ON); // Standard LED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// after duration, turn off the LED
|
|
||||||
if (current_time - led_flash_start_time_ >= led_flash_duration_) {
|
|
||||||
if (led_flash_type_) {
|
|
||||||
EMSESP_RGB_WRITE(led_flash_gpio_, 0, 0, 0);
|
|
||||||
} else {
|
|
||||||
digitalWrite(led_flash_gpio_, !LED_ON);
|
|
||||||
}
|
|
||||||
led_flash_timer_ = false;
|
|
||||||
command_format(nullptr, 0); // Execute format operation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the LED flash timer - duration in seconds
|
|
||||||
void System::start_led_flash(uint8_t duration) {
|
|
||||||
// Don't start if already running
|
|
||||||
if (led_flash_timer_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get LED settings
|
|
||||||
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
|
||||||
led_flash_type_ = settings.led_type;
|
|
||||||
led_flash_gpio_ = settings.led_gpio;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Reset counter and state
|
|
||||||
led_flash_start_time_ = uuid::get_uptime(); // current time
|
|
||||||
led_flash_duration_ = duration * 1000; // duration in milliseconds
|
|
||||||
led_flash_timer_ = true; // it's active
|
|
||||||
}
|
|
||||||
|
|
||||||
// button long press
|
// button long press
|
||||||
void System::button_OnLongPress(PButton & b) {
|
void System::button_OnLongPress(PButton & b) {
|
||||||
LOG_NOTICE("Button pressed - long press - restart EMS-ESP");
|
LOG_NOTICE("Button pressed - long press - restart EMS-ESP");
|
||||||
@@ -831,7 +773,7 @@ void System::button_OnLongPress(PButton & b) {
|
|||||||
// button indefinite press
|
// button indefinite press
|
||||||
void System::button_OnVLongPress(PButton & b) {
|
void System::button_OnVLongPress(PButton & b) {
|
||||||
LOG_NOTICE("Button pressed - very long press - perform factory reset");
|
LOG_NOTICE("Button pressed - very long press - perform factory reset");
|
||||||
start_led_flash(5); // Start LED flash timer for 5 seconds
|
EMSESP::led_.start_led_fast_flash(5); // Start LED flash timer for 5 seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
// push button
|
// push button
|
||||||
@@ -850,21 +792,7 @@ void System::button_init() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the LED to on or off when in normal operating mode
|
// init UART
|
||||||
void System::led_init() {
|
|
||||||
if (!led_gpio_) { // 0 means disabled
|
|
||||||
LOG_INFO("LED disabled");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (led_type_) {
|
|
||||||
EMSESP_RGB_WRITE(led_gpio_, 0, 0, 0);
|
|
||||||
} else {
|
|
||||||
pinMode(led_gpio_, OUTPUT);
|
|
||||||
digitalWrite(led_gpio_, !LED_ON); // start with LED off
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void System::uart_init() {
|
void System::uart_init() {
|
||||||
EMSuart::stop();
|
EMSuart::stop();
|
||||||
EMSuart::start(tx_mode_, rx_gpio_, tx_gpio_); // start UART, GPIOs have already been checked
|
EMSuart::start(tx_mode_, rx_gpio_, tx_gpio_); // start UART, GPIOs have already been checked
|
||||||
@@ -879,18 +807,16 @@ bool System::loop() {
|
|||||||
system_restart();
|
system_restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if LED flashing is active, run the LED flash
|
myPButton_.check(); // check button press
|
||||||
if (led_flash_timer_) {
|
system_check(); // System health check
|
||||||
led_flash();
|
|
||||||
return true; // is active
|
// handle the LED
|
||||||
|
if (EMSESP::led_.loop(healthcheck_, myPButton_.button_busy())) {
|
||||||
|
return true; // restart is pending, skip the rest of the loop
|
||||||
}
|
}
|
||||||
|
|
||||||
led_monitor(); // check status and report back using the LED
|
|
||||||
myPButton_.check(); // check button press
|
|
||||||
system_check(); // check system health
|
|
||||||
|
|
||||||
// syslog
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
|
// syslog service
|
||||||
if (syslog_enabled_) {
|
if (syslog_enabled_) {
|
||||||
syslog_.loop();
|
syslog_.loop();
|
||||||
}
|
}
|
||||||
@@ -898,7 +824,7 @@ bool System::loop() {
|
|||||||
|
|
||||||
send_info_mqtt();
|
send_info_mqtt();
|
||||||
|
|
||||||
return false; // LED flashing is not active
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send MQTT info topic appended with the version information as JSON, as a retained flag
|
// send MQTT info topic appended with the version information as JSON, as a retained flag
|
||||||
@@ -1065,22 +991,9 @@ void System::system_check() {
|
|||||||
static uint8_t last_healthcheck_ = 0;
|
static uint8_t last_healthcheck_ = 0;
|
||||||
if (healthcheck_ != last_healthcheck_) {
|
if (healthcheck_ != last_healthcheck_) {
|
||||||
last_healthcheck_ = healthcheck_;
|
last_healthcheck_ = healthcheck_;
|
||||||
|
|
||||||
EMSESP::system_.send_heartbeat(); // send MQTT heartbeat immediately when connected
|
EMSESP::system_.send_heartbeat(); // send MQTT heartbeat immediately when connected
|
||||||
|
|
||||||
// see if we're better now
|
|
||||||
if (healthcheck_ == 0) {
|
if (healthcheck_ == 0) {
|
||||||
// everything is healthy, show LED permanently on or off depending on setting
|
EMSESP::led_.reset_led(true); // LED back to what is was before
|
||||||
// Green on RGB LED, on/off on standard LED
|
|
||||||
if (led_gpio_) {
|
|
||||||
led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 0, hide_led_ ? 0 : RGB_LED_BRIGHTNESS, 0)
|
|
||||||
: digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON); // Green
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// turn off LED so we're ready for the warning flashes
|
|
||||||
if (led_gpio_) {
|
|
||||||
led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1096,6 +1009,7 @@ void System::commands_init() {
|
|||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, FL_(restart_cmd), CommandFlag::ADMIN_ONLY);
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, FL_(restart_cmd), CommandFlag::ADMIN_ONLY);
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(format), System::command_format, FL_(format_cmd), CommandFlag::ADMIN_ONLY);
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(format), System::command_format, FL_(format_cmd), CommandFlag::ADMIN_ONLY);
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(txpause), System::command_txpause, FL_(txpause_cmd), CommandFlag::ADMIN_ONLY);
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(txpause), System::command_txpause, FL_(txpause_cmd), CommandFlag::ADMIN_ONLY);
|
||||||
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(led), System::command_led, FL_(led_cmd), CommandFlag::ADMIN_ONLY);
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(watch), System::command_watch, FL_(watch_cmd));
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(watch), System::command_watch, FL_(watch_cmd));
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(message), System::command_message, FL_(message_cmd));
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(message), System::command_message, FL_(message_cmd));
|
||||||
#if defined(EMSESP_TEST)
|
#if defined(EMSESP_TEST)
|
||||||
@@ -1109,98 +1023,6 @@ void System::commands_init() {
|
|||||||
Mqtt::subscribe(EMSdevice::DeviceType::SYSTEM, "system/#", nullptr); // use empty function callback
|
Mqtt::subscribe(EMSdevice::DeviceType::SYSTEM, "system/#", nullptr); // use empty function callback
|
||||||
}
|
}
|
||||||
|
|
||||||
// uses LED to show system health
|
|
||||||
void System::led_monitor() {
|
|
||||||
// if button is pressed, show LED (yellow on RGB LED, on/off on standard LED)
|
|
||||||
static bool button_busy_ = false;
|
|
||||||
if (button_busy_ != myPButton_.button_busy()) {
|
|
||||||
button_busy_ = myPButton_.button_busy();
|
|
||||||
if (led_type_) {
|
|
||||||
EMSESP_RGB_WRITE(led_gpio_, button_busy_ ? RGB_LED_BRIGHTNESS : 0, button_busy_ ? RGB_LED_BRIGHTNESS : 0, 0); // Yellow
|
|
||||||
} else {
|
|
||||||
digitalWrite(led_gpio_, button_busy_ ? LED_ON : !LED_ON);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we only need to run the LED healthcheck if there are errors
|
|
||||||
// skip if we're in the led_flash_timer or if a button has been pressed
|
|
||||||
if (!healthcheck_ || !led_gpio_ || button_busy_ || led_flash_timer_) {
|
|
||||||
return; // all good
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t led_long_timer_ = 1; // 1 will kick it off immediately
|
|
||||||
static uint32_t led_short_timer_ = 0;
|
|
||||||
static uint8_t led_flash_step_ = 0; // 0 means we're not in the short flash timer
|
|
||||||
|
|
||||||
auto current_time = uuid::get_uptime();
|
|
||||||
|
|
||||||
// first long pause before we start flashing
|
|
||||||
if (led_long_timer_ && (uint32_t)(current_time - led_long_timer_) >= HEALTHCHECK_LED_LONG_DUARATION) {
|
|
||||||
led_short_timer_ = current_time; // start the short timer
|
|
||||||
led_long_timer_ = 0; // stop long timer
|
|
||||||
led_flash_step_ = 1; // enable the short flash timer
|
|
||||||
}
|
|
||||||
|
|
||||||
// the flash timer which starts after the long pause
|
|
||||||
if (led_flash_step_ && (uint32_t)(current_time - led_short_timer_) >= HEALTHCHECK_LED_FLASH_DUARATION) {
|
|
||||||
led_long_timer_ = 0; // stop the long timer
|
|
||||||
led_short_timer_ = current_time;
|
|
||||||
static bool led_on_ = false;
|
|
||||||
|
|
||||||
if (++led_flash_step_ == 8) {
|
|
||||||
// reset the whole sequence
|
|
||||||
led_long_timer_ = uuid::get_uptime();
|
|
||||||
led_flash_step_ = 0;
|
|
||||||
led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); // LED off
|
|
||||||
} else if (led_flash_step_ % 2) {
|
|
||||||
// handle the step events (on odd numbers 3,5,7,etc). see if we need to turn on a LED
|
|
||||||
// 1 flash (blue) is the EMS bus is not connected
|
|
||||||
// 2 flashes (red, red) if the network (wifi or ethernet) is not connected
|
|
||||||
// 3 flashes (red, red, blue) is both the bus and the network are not connected
|
|
||||||
bool no_network = (healthcheck_ & HEALTHCHECK_NO_NETWORK) == HEALTHCHECK_NO_NETWORK;
|
|
||||||
bool no_bus = (healthcheck_ & HEALTHCHECK_NO_BUS) == HEALTHCHECK_NO_BUS;
|
|
||||||
|
|
||||||
if (led_type_) {
|
|
||||||
if (led_flash_step_ == 3) {
|
|
||||||
if (no_network) {
|
|
||||||
EMSESP_RGB_WRITE(led_gpio_, RGB_LED_BRIGHTNESS, 0, 0); // red
|
|
||||||
} else if (no_bus) {
|
|
||||||
EMSESP_RGB_WRITE(led_gpio_, 0, 0, RGB_LED_BRIGHTNESS); // blue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (led_flash_step_ == 5 && no_network) {
|
|
||||||
EMSESP_RGB_WRITE(led_gpio_, RGB_LED_BRIGHTNESS, 0, 0); // red
|
|
||||||
}
|
|
||||||
if ((led_flash_step_ == 7) && no_network && no_bus) {
|
|
||||||
EMSESP_RGB_WRITE(led_gpio_, 0, 0, RGB_LED_BRIGHTNESS); // blue
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((led_flash_step_ == 3) && (no_network || no_bus)) {
|
|
||||||
led_on_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((led_flash_step_ == 5) && no_network) {
|
|
||||||
led_on_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((led_flash_step_ == 7) && no_network && no_bus) {
|
|
||||||
led_on_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (led_on_) {
|
|
||||||
digitalWrite(led_gpio_, LED_ON); // LED on
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// turn the led off after the flash, on even number count
|
|
||||||
if (led_on_) {
|
|
||||||
led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON);
|
|
||||||
led_on_ = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the quality (Received Signal Strength Indicator) of the WiFi network as a %
|
// Return the quality (Received Signal Strength Indicator) of the WiFi network as a %
|
||||||
// High quality: 90% ~= -55dBm
|
// High quality: 90% ~= -55dBm
|
||||||
// Medium quality: 50% ~= -75dBm
|
// Medium quality: 50% ~= -75dBm
|
||||||
@@ -2667,11 +2489,11 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
|
|||||||
node["ethPhyAddr"] = settings.eth_phy_addr;
|
node["ethPhyAddr"] = settings.eth_phy_addr;
|
||||||
node["ethClockMmode"] = settings.eth_clock_mode;
|
node["ethClockMmode"] = settings.eth_clock_mode;
|
||||||
}
|
}
|
||||||
node["rxGPIO"] = EMSESP::system_.rx_gpio_;
|
node["rxGPIO"] = settings.rx_gpio;
|
||||||
node["txGPIO"] = EMSESP::system_.tx_gpio_;
|
node["txGPIO"] = settings.tx_gpio;
|
||||||
node["dallasGPIO"] = EMSESP::system_.dallas_gpio_;
|
node["dallasGPIO"] = settings.dallas_gpio;
|
||||||
node["pbuttonGPIO"] = EMSESP::system_.pbutton_gpio_;
|
node["pbuttonGPIO"] = settings.pbutton_gpio;
|
||||||
node["ledGPIO"] = EMSESP::system_.led_gpio_;
|
node["ledGPIO"] = settings.led_gpio;
|
||||||
node["ledType"] = settings.led_type;
|
node["ledType"] = settings.led_type;
|
||||||
}
|
}
|
||||||
node["hideLed"] = settings.hide_led;
|
node["hideLed"] = settings.hide_led;
|
||||||
@@ -2846,6 +2668,43 @@ bool System::load_board_profile(std::vector<int8_t> & data, const std::string &
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// led command
|
||||||
|
// https://github.com/emsesp/EMS-ESP32/issues/3063
|
||||||
|
// /api//system/led command that takes an argument in the form [color]:[pattern]
|
||||||
|
// color is red, green, blue, yellow, white
|
||||||
|
// pattern is
|
||||||
|
// blink1 for 1 time
|
||||||
|
// blink2 for 2 times
|
||||||
|
// blink3 for 3 times
|
||||||
|
// rgb for RGB
|
||||||
|
// For example: /api/system/led?data=red:blink1
|
||||||
|
// For older non-RGB models, the colour would default to just being on.
|
||||||
|
bool System::command_led(const char * value, const int8_t id) {
|
||||||
|
if (!value) {
|
||||||
|
return false; // no argument
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string arg = value;
|
||||||
|
if (arg.find(':') == std::string::npos) {
|
||||||
|
LOG_ERROR("LED command must be in the form [color]:[pattern]");
|
||||||
|
return false; // not in the form [color]:[pattern]
|
||||||
|
}
|
||||||
|
std::string color = arg.substr(0, arg.find(':'));
|
||||||
|
std::string pattern = arg.substr(arg.find(':') + 1);
|
||||||
|
|
||||||
|
// the color must be red, green, blue, yellow, white
|
||||||
|
// the style must be blink1, blink2, blink3
|
||||||
|
if ((color != "red" && color != "green" && color != "blue" && color != "yellow" && color != "white")
|
||||||
|
|| (pattern != "blink1" && pattern != "blink2" && pattern != "blink3" && pattern != "rgb")) {
|
||||||
|
LOG_ERROR("Invalid format. Must be [red|green|blue|yellow|white]:[blink1|blink2|blink3|rgb]");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSESP::led_.set_led_routine(color, pattern);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// txpause command - temporarily pause the TX, by setting Txmode to 0 (disabled)
|
// txpause command - temporarily pause the TX, by setting Txmode to 0 (disabled)
|
||||||
bool System::command_txpause(const char * value, const int8_t id) {
|
bool System::command_txpause(const char * value, const int8_t id) {
|
||||||
bool arg;
|
bool arg;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "mqtt.h"
|
#include "mqtt.h"
|
||||||
#include "telegram.h"
|
#include "telegram.h"
|
||||||
|
#include "led.h"
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
#include <esp_wifi.h>
|
#include <esp_wifi.h>
|
||||||
@@ -37,8 +38,6 @@
|
|||||||
#include <uuid/log.h>
|
#include <uuid/log.h>
|
||||||
#include <PButton.h>
|
#include <PButton.h>
|
||||||
|
|
||||||
#define EMSESP_RGB_WRITE rgbLedWrite
|
|
||||||
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
// there is no official API available on the original ESP32
|
// there is no official API available on the original ESP32
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -54,8 +53,6 @@ using uuid::console::Shell;
|
|||||||
|
|
||||||
#define EMSESP_CUSTOMSUPPORT_FILE "/config/customSupport.json"
|
#define EMSESP_CUSTOMSUPPORT_FILE "/config/customSupport.json"
|
||||||
|
|
||||||
#define RGB_LED_BRIGHTNESS 20 // 255 is max brightness
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
enum PHY_type : uint8_t { PHY_TYPE_NONE = 0, PHY_TYPE_LAN8720, PHY_TYPE_TLK110, PHY_TYPE_RTL8201 };
|
enum PHY_type : uint8_t { PHY_TYPE_NONE = 0, PHY_TYPE_LAN8720, PHY_TYPE_TLK110, PHY_TYPE_RTL8201 };
|
||||||
@@ -98,6 +95,7 @@ class System {
|
|||||||
static bool command_service(const char * cmd, const char * value);
|
static bool command_service(const char * cmd, const char * value);
|
||||||
static bool command_sendmail(const char * value, const int8_t id);
|
static bool command_sendmail(const char * value, const int8_t id);
|
||||||
static bool command_txpause(const char * value, const int8_t id);
|
static bool command_txpause(const char * value, const int8_t id);
|
||||||
|
static bool command_led(const char * value, const int8_t id);
|
||||||
|
|
||||||
static bool get_value_info(JsonObject root, const char * cmd);
|
static bool get_value_info(JsonObject root, const char * cmd);
|
||||||
static void get_value_json(JsonObject output, const std::string & circuit, const std::string & name, JsonVariant val);
|
static void get_value_json(JsonObject output, const std::string & circuit, const std::string & name, JsonVariant val);
|
||||||
@@ -144,7 +142,6 @@ class System {
|
|||||||
|
|
||||||
static bool uploadFirmwareURL(const char * url = nullptr);
|
static bool uploadFirmwareURL(const char * url = nullptr);
|
||||||
|
|
||||||
void led_init();
|
|
||||||
void button_init();
|
void button_init();
|
||||||
void commands_init();
|
void commands_init();
|
||||||
void uart_init();
|
void uart_init();
|
||||||
@@ -354,6 +351,10 @@ class System {
|
|||||||
|
|
||||||
static bool set_partition(const char * partitionname);
|
static bool set_partition(const char * partitionname);
|
||||||
|
|
||||||
|
// healthcheck flags - shared with LED for status visualization
|
||||||
|
static constexpr uint8_t HEALTHCHECK_NO_BUS = (1 << 0); // 1
|
||||||
|
static constexpr uint8_t HEALTHCHECK_NO_NETWORK = (1 << 1); // 2
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static uuid::log::Logger logger_;
|
static uuid::log::Logger logger_;
|
||||||
|
|
||||||
@@ -374,15 +375,6 @@ class System {
|
|||||||
static constexpr uint32_t BUTTON_Debounce = 40; // Debounce period to prevent flickering when pressing or releasing the button (in ms)
|
static constexpr uint32_t BUTTON_Debounce = 40; // Debounce period to prevent flickering when pressing or releasing the button (in ms)
|
||||||
static constexpr uint32_t BUTTON_DblClickDelay = 250; // Max period between clicks for a double click event (in ms)
|
static constexpr uint32_t BUTTON_DblClickDelay = 250; // Max period between clicks for a double click event (in ms)
|
||||||
|
|
||||||
// LED flash timer
|
|
||||||
static bool led_flash_timer_;
|
|
||||||
static uint8_t led_flash_gpio_;
|
|
||||||
static uint8_t led_flash_type_;
|
|
||||||
static uint32_t led_flash_start_time_;
|
|
||||||
static uint32_t led_flash_duration_;
|
|
||||||
static void start_led_flash(uint8_t duration);
|
|
||||||
static void led_flash();
|
|
||||||
|
|
||||||
// button press delays
|
// button press delays
|
||||||
static constexpr uint32_t BUTTON_LongPressDelay = 3000; // Hold period for a long press event (in ms) - ~3 seconds
|
static constexpr uint32_t BUTTON_LongPressDelay = 3000; // Hold period for a long press event (in ms) - ~3 seconds
|
||||||
static constexpr uint32_t BUTTON_VLongPressDelay = 9500; // Hold period for a very long press event (in ms) - !10 seconds
|
static constexpr uint32_t BUTTON_VLongPressDelay = 9500; // Hold period for a very long press event (in ms) - !10 seconds
|
||||||
@@ -393,17 +385,11 @@ class System {
|
|||||||
#else
|
#else
|
||||||
static constexpr uint32_t SYSTEM_CHECK_FREQUENCY = 5000; // do a system check every 5 seconds
|
static constexpr uint32_t SYSTEM_CHECK_FREQUENCY = 5000; // do a system check every 5 seconds
|
||||||
#endif
|
#endif
|
||||||
static constexpr uint32_t HEALTHCHECK_LED_LONG_DUARATION = 1500; // 1.5 seconds
|
|
||||||
static constexpr uint32_t HEALTHCHECK_LED_FLASH_DUARATION = 150; // 150ms
|
|
||||||
static constexpr uint8_t HEALTHCHECK_NO_BUS = (1 << 0); // 1
|
|
||||||
static constexpr uint8_t HEALTHCHECK_NO_NETWORK = (1 << 1); // 2
|
|
||||||
static constexpr uint8_t LED_ON = HIGH; // LED on
|
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
static uuid::syslog::SyslogService syslog_;
|
static uuid::syslog::SyslogService syslog_;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
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, const std::string & exclude = "");
|
static std::vector<uint8_t, AllocatorPSRAM<uint8_t>> string_range_to_vector(const std::string & range, const std::string & exclude = "");
|
||||||
|
|||||||
@@ -450,7 +450,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
|||||||
// THESE ONLY WORK WITH AN ESP32, not in standalone/native mode
|
// THESE ONLY WORK WITH AN ESP32, not in standalone/native mode
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
if (command == "ls") {
|
if (command == "ls") {
|
||||||
listDir(LittleFS, "/", 3);
|
EMSESP::system_.listDir("/", 3);
|
||||||
ok = true;
|
ok = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1091,6 +1091,22 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
|||||||
shell.invoke_command("call boiler circpump/value");
|
shell.invoke_command("call boiler circpump/value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (command == "led") {
|
||||||
|
shell.printfln("Testing LED...");
|
||||||
|
|
||||||
|
JsonDocument doc;
|
||||||
|
AsyncWebServerRequest request;
|
||||||
|
|
||||||
|
request.method(HTTP_POST);
|
||||||
|
char data1[] = "{\"data\":\"red:blink1\"}";
|
||||||
|
deserializeJson(doc, data1);
|
||||||
|
JsonVariant json = doc.as<JsonVariant>();
|
||||||
|
request.url("/api/system/led");
|
||||||
|
EMSESP::webAPIService.webAPIService(&request, json);
|
||||||
|
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (command == "shuntingyard") {
|
if (command == "shuntingyard") {
|
||||||
shell.printfln("Testing shunting yard...");
|
shell.printfln("Testing shunting yard...");
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ namespace emsesp {
|
|||||||
// #define EMSESP_DEBUG_DEFAULT "hpmode"
|
// #define EMSESP_DEBUG_DEFAULT "hpmode"
|
||||||
// #define EMSESP_DEBUG_DEFAULT "shuntingyard"
|
// #define EMSESP_DEBUG_DEFAULT "shuntingyard"
|
||||||
// #define EMSESP_DEBUG_DEFAULT "src"
|
// #define EMSESP_DEBUG_DEFAULT "src"
|
||||||
|
#define EMSESP_DEBUG_DEFAULT "led"
|
||||||
|
|
||||||
#ifndef EMSESP_DEBUG_DEFAULT
|
#ifndef EMSESP_DEBUG_DEFAULT
|
||||||
#define EMSESP_DEBUG_DEFAULT "general"
|
#define EMSESP_DEBUG_DEFAULT "general"
|
||||||
|
|||||||
@@ -387,7 +387,7 @@ void WebSettingsService::onUpdate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (WebSettings::has_flags(WebSettings::ChangeFlags::LED)) {
|
if (WebSettings::has_flags(WebSettings::ChangeFlags::LED)) {
|
||||||
EMSESP::system_.led_init();
|
EMSESP::led_.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WebSettings::has_flags(WebSettings::ChangeFlags::MQTT)) {
|
if (WebSettings::has_flags(WebSettings::ChangeFlags::MQTT)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user