Merge remote-tracking branch 'origin/flash_optimization' into dev #646

This commit is contained in:
Proddy
2022-10-08 10:02:48 +02:00
104 changed files with 3083 additions and 3662 deletions

View File

@@ -4,14 +4,15 @@
## Added ## Added
- Translations in Web UI and all device entity names (DE, NL, SE, PL, NO, ...). [#22](https://github.com/emsesp/EMS-ESP32/issues/22) - Translations in Web UI and all device entity names (DE, NL, SE, PL, NO, ...) [#22](https://github.com/emsesp/EMS-ESP32/issues/22)
- Add support for Lolin C3 mini [#620](https://github.com/emsesp/EMS-ESP32/pull/620) - Add support for Lolin C3 mini [#620](https://github.com/emsesp/EMS-ESP32/pull/620)
- Add support for ESP32-S2 [#667](https://github.com/emsesp/EMS-ESP32/pull/667)
- Add devices: Greenstar 30Ri boiler, Junkers FW500 thermostat, Buderus BC30 controller - Add devices: Greenstar 30Ri boiler, Junkers FW500 thermostat, Buderus BC30 controller
- Add program memory info - Add program memory info
- Add mqtt queue and connection infos - Add mqtt queue and connection infos
- Add min/max setting to customizations - Add min/max setting to customizations
- Adapt min/max if ems-value is not in this range - Adapt min/max if ems-value is not in this range
- Add heatpump settings for inputs and limits - Add heat pump settings for inputs and limits
## Fixed ## Fixed
@@ -22,8 +23,8 @@
- Discovery in HomeAssistant don't work with custom base topic. [#596](https://github.com/emsesp/EMS-ESP32/issues/596) Base topic containing `/` are changed to `_` - Discovery in HomeAssistant don't work with custom base topic. [#596](https://github.com/emsesp/EMS-ESP32/issues/596) Base topic containing `/` are changed to `_`
- RF room temperature sensor are shown as thermostat - RF room temperature sensor are shown as thermostat
- render mqtt float json values with trailing zero - render mqtt float json values with trailing zero
- removed flash strings
## **BREAKING CHANGES:** ## **BREAKING CHANGES:**
- When upgrading from 3.4.x you may need to erase the flash on the ESP32 before uploading the firmware. Make sure you make a backup of the settings and customizations via the WebUI (System->Upload/Download) - When upgrading from 3.4.x you may need to erase the flash on the ESP32 before uploading the firmware. Make sure you make a backup of the settings and customizations via the WebUI (System->Upload/Download)

View File

@@ -1,5 +1,5 @@
{ {
"adapter": "react", "adapter": "react",
"baseLocale": "en", "baseLocale": "en",
"$schema": "https://unpkg.com/typesafe-i18n@5.13.0/schema/typesafe-i18n.json" "$schema": "https://unpkg.com/typesafe-i18n@5.14.0/schema/typesafe-i18n.json"
} }

View File

@@ -12,15 +12,15 @@
"@emotion/styled": "^11.10.4", "@emotion/styled": "^11.10.4",
"@msgpack/msgpack": "^2.8.0", "@msgpack/msgpack": "^2.8.0",
"@mui/icons-material": "^5.10.6", "@mui/icons-material": "^5.10.6",
"@mui/material": "^5.10.7", "@mui/material": "^5.10.8",
"@table-library/react-table-library": "4.0.18", "@table-library/react-table-library": "4.0.23",
"@types/lodash": "^4.14.185", "@types/lodash": "^4.14.186",
"@types/node": "^18.7.23", "@types/node": "^18.8.3",
"@types/react": "^18.0.21", "@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6", "@types/react-dom": "^18.0.6",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
"async-validator": "^4.2.5", "async-validator": "^4.2.5",
"axios": "^0.27.2", "axios": "^1.1.2",
"http-proxy-middleware": "^2.0.6", "http-proxy-middleware": "^2.0.6",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
@@ -31,10 +31,10 @@
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-dropzone": "^14.2.2", "react-dropzone": "^14.2.2",
"react-icons": "^4.4.0", "react-icons": "^4.4.0",
"react-router-dom": "^6.4.1", "react-router-dom": "^6.4.2",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"sockette": "^2.0.6", "sockette": "^2.0.6",
"typesafe-i18n": "^5.13.1", "typesafe-i18n": "^5.14.0",
"typescript": "^4.8.4" "typescript": "^4.8.4"
}, },
"devDependencies": { "devDependencies": {
@@ -2316,9 +2316,9 @@
} }
}, },
"node_modules/@humanwhocodes/config-array": { "node_modules/@humanwhocodes/config-array": {
"version": "0.10.5", "version": "0.10.7",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.5.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz",
"integrity": "sha512-XVVDtp+dVvRxMoxSiSfasYaG02VEe1qH5cKgMQJWhol6HwzbcqoCMJi8dAGoYAO57jhUyhI6cWuRiTcRaDaYug==", "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==",
"dependencies": { "dependencies": {
"@humanwhocodes/object-schema": "^1.2.1", "@humanwhocodes/object-schema": "^1.2.1",
"debug": "^4.1.1", "debug": "^4.1.1",
@@ -3103,9 +3103,9 @@
} }
}, },
"node_modules/@mui/base": { "node_modules/@mui/base": {
"version": "5.0.0-alpha.99", "version": "5.0.0-alpha.100",
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.99.tgz", "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.100.tgz",
"integrity": "sha512-D04H6O1c0Jv561yI0SVbpa8MpqpW3G43CwJxV2o6ALfI0DMJ45w07dGafmDchb6aCWTRTdggd3rjgmuzyNwPiQ==", "integrity": "sha512-bSoJEKCENtmJrJDECHUe9PiqztIUACuSskyqw9ypqE7Dz3WxL3e8puFsWBkUsz+WOCjXh4B4Xljn88Ucxxv5HA==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.19.0", "@babel/runtime": "^7.19.0",
"@emotion/is-prop-valid": "^1.2.0", "@emotion/is-prop-valid": "^1.2.0",
@@ -3135,9 +3135,9 @@
} }
}, },
"node_modules/@mui/core-downloads-tracker": { "node_modules/@mui/core-downloads-tracker": {
"version": "5.10.7", "version": "5.10.8",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.7.tgz", "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.8.tgz",
"integrity": "sha512-3N0UYVy3MbrHzM3j6f7fIUCZ+bQ1/sSZq143tLxwSssW3Z4AqE83brpr5flEY1Lx+Aowv/cPyQMmZxzRlFCGqw==", "integrity": "sha512-V5D7OInO4P9PdT/JACg7fwjbOORm3GklaMVgdGomjyxiyetgRND5CC9r35e1LK/DqHdoyDuhbFzdfrqWtpmEIw==",
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/mui" "url": "https://opencollective.com/mui"
@@ -3169,14 +3169,14 @@
} }
}, },
"node_modules/@mui/material": { "node_modules/@mui/material": {
"version": "5.10.7", "version": "5.10.8",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.10.7.tgz", "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.10.8.tgz",
"integrity": "sha512-o1jcQGii+q7ORrXhBiMmGzFDaboc1qTgOOC3zDW+NR9ryVzWzL7qEeqoORbgDB5zk9OBsXCjB91fUH/ls5xMwg==", "integrity": "sha512-sF/Ka0IJjGXV52zoT4xAWEqXVRjNYbIjATo9L4Q5oQC5iJpGrKJFY16uNtWWB0+vp/nayAuPGZHrxtV+t3ecdQ==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.19.0", "@babel/runtime": "^7.19.0",
"@mui/base": "5.0.0-alpha.99", "@mui/base": "5.0.0-alpha.100",
"@mui/core-downloads-tracker": "^5.10.7", "@mui/core-downloads-tracker": "^5.10.8",
"@mui/system": "^5.10.7", "@mui/system": "^5.10.8",
"@mui/types": "^7.2.0", "@mui/types": "^7.2.0",
"@mui/utils": "^5.10.6", "@mui/utils": "^5.10.6",
"@types/react-transition-group": "^4.4.5", "@types/react-transition-group": "^4.4.5",
@@ -3239,9 +3239,9 @@
} }
}, },
"node_modules/@mui/styled-engine": { "node_modules/@mui/styled-engine": {
"version": "5.10.7", "version": "5.10.8",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.10.7.tgz", "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.10.8.tgz",
"integrity": "sha512-CCrtW+vvCKEm6pOE/QcutQ+ORC/iE6D1ghscN4l7LE2JXPvTXO/z0yu8Wxug1JEDlWm4r1Qa0PzJe1P9bjKzNA==", "integrity": "sha512-w+y8WI18EJV6zM/q41ug19cE70JTeO6sWFsQ7tgePQFpy6ToCVPh0YLrtqxUZXSoMStW5FMw0t9fHTFAqPbngw==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.19.0", "@babel/runtime": "^7.19.0",
"@emotion/cache": "^11.10.3", "@emotion/cache": "^11.10.3",
@@ -3270,13 +3270,13 @@
} }
}, },
"node_modules/@mui/system": { "node_modules/@mui/system": {
"version": "5.10.7", "version": "5.10.8",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.10.7.tgz", "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.10.8.tgz",
"integrity": "sha512-kwyhjjKGsgtBRFl6vSqidDZcNKU5S1juTgm4Xi2fyWxaEbIQb9Sh9y0iVP2bNCJzgDr0alLaENOZOEaDWHISAQ==", "integrity": "sha512-hRQ354zcrYP/KHqK8FheICSvE9raQaUgQaV+A3oD4JETaFUCVI9Ytt+RcQYgTqx02xlCXIjl8LK1rPjTneySqw==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.19.0", "@babel/runtime": "^7.19.0",
"@mui/private-theming": "^5.10.6", "@mui/private-theming": "^5.10.6",
"@mui/styled-engine": "^5.10.7", "@mui/styled-engine": "^5.10.8",
"@mui/types": "^7.2.0", "@mui/types": "^7.2.0",
"@mui/utils": "^5.10.6", "@mui/utils": "^5.10.6",
"clsx": "^1.2.1", "clsx": "^1.2.1",
@@ -3470,9 +3470,9 @@
} }
}, },
"node_modules/@remix-run/router": { "node_modules/@remix-run/router": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.1.tgz", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.2.tgz",
"integrity": "sha512-eBV5rvW4dRFOU1eajN7FmYxjAIVz/mRHgUE9En9mBn6m3mulK3WTR5C3iQhL9MZ14rWAq+xOlEaCkDiW0/heOg==", "integrity": "sha512-GRSOFhJzjGN+d4sKHTMSvNeUPoZiDHWmRnXfzaxrqe7dE/Nzlc8BiMSJdLDESZlndM7jIUrZ/F4yWqVYlI0rwQ==",
"engines": { "engines": {
"node": ">=14" "node": ">=14"
} }
@@ -3557,9 +3557,9 @@
"integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==" "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg=="
}, },
"node_modules/@sinclair/typebox": { "node_modules/@sinclair/typebox": {
"version": "0.24.43", "version": "0.24.44",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.43.tgz", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.44.tgz",
"integrity": "sha512-1orQTvtazZmsPeBroJjysvsOQCYV2yjWlebkSY38pl5vr2tdLjEJ+LoxITlGNZaH2RE19WlAwQMkH/7C14wLfw==" "integrity": "sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg=="
}, },
"node_modules/@sinonjs/commons": { "node_modules/@sinonjs/commons": {
"version": "1.8.3", "version": "1.8.3",
@@ -3796,9 +3796,9 @@
} }
}, },
"node_modules/@table-library/react-table-library": { "node_modules/@table-library/react-table-library": {
"version": "4.0.18", "version": "4.0.23",
"resolved": "https://registry.npmjs.org/@table-library/react-table-library/-/react-table-library-4.0.18.tgz", "resolved": "https://registry.npmjs.org/@table-library/react-table-library/-/react-table-library-4.0.23.tgz",
"integrity": "sha512-3GX5712YuWPFeUilr8UG22SCNR9BylD5Y4xPF+pHhb1QM7WXw6SLgpeGq6UDTQGOtmKtKtwKGWXdkmvVDg8pkA==", "integrity": "sha512-o2L/fqhwQNxsNbbm3LIiyZzEwaTslhG1tY9ArkYdS0xJyRhJxcOLfbJ3+dcnOOn+aIJpmPmQH+gr7RYJC0P8uw==",
"dependencies": { "dependencies": {
"clsx": "1.1.1", "clsx": "1.1.1",
"react-virtualized-auto-sizer": "1.0.6", "react-virtualized-auto-sizer": "1.0.6",
@@ -4019,9 +4019,9 @@
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
}, },
"node_modules/@types/lodash": { "node_modules/@types/lodash": {
"version": "4.14.185", "version": "4.14.186",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.185.tgz", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.186.tgz",
"integrity": "sha512-evMDG1bC4rgQg4ku9tKpuMh5iBNEwNa3tf9zRHdP1qlv+1WUg44xat4IxCE14gIpZRGUUWAx2VhItCZc25NfMA==" "integrity": "sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw=="
}, },
"node_modules/@types/mime": { "node_modules/@types/mime": {
"version": "3.0.1", "version": "3.0.1",
@@ -4029,9 +4029,9 @@
"integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA=="
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "18.7.23", "version": "18.8.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz",
"integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==" "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w=="
}, },
"node_modules/@types/parse-json": { "node_modules/@types/parse-json": {
"version": "4.0.0", "version": "4.0.0",
@@ -5008,12 +5008,13 @@
} }
}, },
"node_modules/axios": { "node_modules/axios": {
"version": "0.27.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.2.tgz",
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", "integrity": "sha512-bznQyETwElsXl2RK7HLLwb5GPpOLlycxHCtrpDR/4RqqBzjARaOTo3jz4IgtntWUYee7Ne4S8UHd92VCuzPaWA==",
"dependencies": { "dependencies": {
"follow-redirects": "^1.14.9", "follow-redirects": "^1.15.0",
"form-data": "^4.0.0" "form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
} }
}, },
"node_modules/axobject-query": { "node_modules/axobject-query": {
@@ -5561,9 +5562,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001412", "version": "1.0.30001414",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001412.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001414.tgz",
"integrity": "sha512-+TeEIee1gS5bYOiuf+PS/kp2mrXic37Hl66VY6EAfxasIk5fELTktK2oOezYed12H8w7jt3s512PpulQidPjwA==", "integrity": "sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@@ -6755,9 +6756,9 @@
} }
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.4.266", "version": "1.4.270",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.266.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.270.tgz",
"integrity": "sha512-saJTYECxUSv7eSpnXw0XIEvUkP9x4s/x2mm3TVX7k4rIFS6f5TjBih1B5h437WzIhHQjid+d8ouQzPQskMervQ==" "integrity": "sha512-KNhIzgLiJmDDC444dj9vEOpZEgsV96ult9Iff98Vanumn+ShJHd5se8aX6KeVxdc0YQeqdrezBZv89rleDbvSg=="
}, },
"node_modules/emittery": { "node_modules/emittery": {
"version": "0.8.1", "version": "0.8.1",
@@ -11430,9 +11431,9 @@
} }
}, },
"node_modules/js-sdsl": { "node_modules/js-sdsl": {
"version": "4.1.4", "version": "4.1.5",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz",
"integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==" "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q=="
}, },
"node_modules/js-tokens": { "node_modules/js-tokens": {
"version": "4.0.0", "version": "4.0.0",
@@ -12853,9 +12854,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.16", "version": "8.4.17",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz",
"integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", "integrity": "sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@@ -14147,6 +14148,11 @@
"node": ">= 0.10" "node": ">= 0.10"
} }
}, },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/psl": { "node_modules/psl": {
"version": "1.9.0", "version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
@@ -14545,11 +14551,11 @@
} }
}, },
"node_modules/react-router": { "node_modules/react-router": {
"version": "6.4.1", "version": "6.4.2",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.1.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.2.tgz",
"integrity": "sha512-OJASKp5AykDWFewgWUim1vlLr7yfD4vO/h+bSgcP/ix8Md+LMHuAjovA74MQfsfhQJGGN1nHRhwS5qQQbbBt3A==", "integrity": "sha512-Rb0BAX9KHhVzT1OKhMvCDMw776aTYM0DtkxqUBP8dNBom3mPXlfNs76JNGK8wKJ1IZEY1+WGj+cvZxHVk/GiKw==",
"dependencies": { "dependencies": {
"@remix-run/router": "1.0.1" "@remix-run/router": "1.0.2"
}, },
"engines": { "engines": {
"node": ">=14" "node": ">=14"
@@ -14559,12 +14565,12 @@
} }
}, },
"node_modules/react-router-dom": { "node_modules/react-router-dom": {
"version": "6.4.1", "version": "6.4.2",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.1.tgz", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.2.tgz",
"integrity": "sha512-MY7NJCrGNVJtGp8ODMOBHu20UaIkmwD2V3YsAOUQoCXFk7Ppdwf55RdcGyrSj+ycSL9Uiwrb3gTLYSnzcRoXww==", "integrity": "sha512-yM1kjoTkpfjgczPrcyWrp+OuQMyB1WleICiiGfstnQYo/S8hPEEnVjr/RdmlH6yKK4Tnj1UGXFSa7uwAtmDoLQ==",
"dependencies": { "dependencies": {
"@remix-run/router": "1.0.1", "@remix-run/router": "1.0.2",
"react-router": "6.4.1" "react-router": "6.4.2"
}, },
"engines": { "engines": {
"node": ">=14" "node": ">=14"
@@ -16420,9 +16426,9 @@
} }
}, },
"node_modules/typesafe-i18n": { "node_modules/typesafe-i18n": {
"version": "5.13.1", "version": "5.14.0",
"resolved": "https://registry.npmjs.org/typesafe-i18n/-/typesafe-i18n-5.13.1.tgz", "resolved": "https://registry.npmjs.org/typesafe-i18n/-/typesafe-i18n-5.14.0.tgz",
"integrity": "sha512-9Cgikxcj+2LAWQGZ8pOQAf14P+aOOcOel/G1kSAXAObA4Htj8R+qgCx9DqUnxjRfugWzM/19ZqGss7dl8Dw7Gg==", "integrity": "sha512-ZNHysUvZZhmUuMjBvDGtUI8vT3g//4ay5fFOk2sJCsjx4ztippW1Hrhrq59nJ9mV/Q0u4OX80Gyorq8L3rwNLw==",
"bin": { "bin": {
"typesafe-i18n": "cli/typesafe-i18n.mjs" "typesafe-i18n": "cli/typesafe-i18n.mjs"
}, },
@@ -19062,9 +19068,9 @@
} }
}, },
"@humanwhocodes/config-array": { "@humanwhocodes/config-array": {
"version": "0.10.5", "version": "0.10.7",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.5.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz",
"integrity": "sha512-XVVDtp+dVvRxMoxSiSfasYaG02VEe1qH5cKgMQJWhol6HwzbcqoCMJi8dAGoYAO57jhUyhI6cWuRiTcRaDaYug==", "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==",
"requires": { "requires": {
"@humanwhocodes/object-schema": "^1.2.1", "@humanwhocodes/object-schema": "^1.2.1",
"debug": "^4.1.1", "debug": "^4.1.1",
@@ -19643,9 +19649,9 @@
"integrity": "sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==" "integrity": "sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ=="
}, },
"@mui/base": { "@mui/base": {
"version": "5.0.0-alpha.99", "version": "5.0.0-alpha.100",
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.99.tgz", "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.100.tgz",
"integrity": "sha512-D04H6O1c0Jv561yI0SVbpa8MpqpW3G43CwJxV2o6ALfI0DMJ45w07dGafmDchb6aCWTRTdggd3rjgmuzyNwPiQ==", "integrity": "sha512-bSoJEKCENtmJrJDECHUe9PiqztIUACuSskyqw9ypqE7Dz3WxL3e8puFsWBkUsz+WOCjXh4B4Xljn88Ucxxv5HA==",
"requires": { "requires": {
"@babel/runtime": "^7.19.0", "@babel/runtime": "^7.19.0",
"@emotion/is-prop-valid": "^1.2.0", "@emotion/is-prop-valid": "^1.2.0",
@@ -19658,9 +19664,9 @@
} }
}, },
"@mui/core-downloads-tracker": { "@mui/core-downloads-tracker": {
"version": "5.10.7", "version": "5.10.8",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.7.tgz", "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.8.tgz",
"integrity": "sha512-3N0UYVy3MbrHzM3j6f7fIUCZ+bQ1/sSZq143tLxwSssW3Z4AqE83brpr5flEY1Lx+Aowv/cPyQMmZxzRlFCGqw==" "integrity": "sha512-V5D7OInO4P9PdT/JACg7fwjbOORm3GklaMVgdGomjyxiyetgRND5CC9r35e1LK/DqHdoyDuhbFzdfrqWtpmEIw=="
}, },
"@mui/icons-material": { "@mui/icons-material": {
"version": "5.10.6", "version": "5.10.6",
@@ -19671,14 +19677,14 @@
} }
}, },
"@mui/material": { "@mui/material": {
"version": "5.10.7", "version": "5.10.8",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.10.7.tgz", "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.10.8.tgz",
"integrity": "sha512-o1jcQGii+q7ORrXhBiMmGzFDaboc1qTgOOC3zDW+NR9ryVzWzL7qEeqoORbgDB5zk9OBsXCjB91fUH/ls5xMwg==", "integrity": "sha512-sF/Ka0IJjGXV52zoT4xAWEqXVRjNYbIjATo9L4Q5oQC5iJpGrKJFY16uNtWWB0+vp/nayAuPGZHrxtV+t3ecdQ==",
"requires": { "requires": {
"@babel/runtime": "^7.19.0", "@babel/runtime": "^7.19.0",
"@mui/base": "5.0.0-alpha.99", "@mui/base": "5.0.0-alpha.100",
"@mui/core-downloads-tracker": "^5.10.7", "@mui/core-downloads-tracker": "^5.10.8",
"@mui/system": "^5.10.7", "@mui/system": "^5.10.8",
"@mui/types": "^7.2.0", "@mui/types": "^7.2.0",
"@mui/utils": "^5.10.6", "@mui/utils": "^5.10.6",
"@types/react-transition-group": "^4.4.5", "@types/react-transition-group": "^4.4.5",
@@ -19700,9 +19706,9 @@
} }
}, },
"@mui/styled-engine": { "@mui/styled-engine": {
"version": "5.10.7", "version": "5.10.8",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.10.7.tgz", "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.10.8.tgz",
"integrity": "sha512-CCrtW+vvCKEm6pOE/QcutQ+ORC/iE6D1ghscN4l7LE2JXPvTXO/z0yu8Wxug1JEDlWm4r1Qa0PzJe1P9bjKzNA==", "integrity": "sha512-w+y8WI18EJV6zM/q41ug19cE70JTeO6sWFsQ7tgePQFpy6ToCVPh0YLrtqxUZXSoMStW5FMw0t9fHTFAqPbngw==",
"requires": { "requires": {
"@babel/runtime": "^7.19.0", "@babel/runtime": "^7.19.0",
"@emotion/cache": "^11.10.3", "@emotion/cache": "^11.10.3",
@@ -19711,13 +19717,13 @@
} }
}, },
"@mui/system": { "@mui/system": {
"version": "5.10.7", "version": "5.10.8",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.10.7.tgz", "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.10.8.tgz",
"integrity": "sha512-kwyhjjKGsgtBRFl6vSqidDZcNKU5S1juTgm4Xi2fyWxaEbIQb9Sh9y0iVP2bNCJzgDr0alLaENOZOEaDWHISAQ==", "integrity": "sha512-hRQ354zcrYP/KHqK8FheICSvE9raQaUgQaV+A3oD4JETaFUCVI9Ytt+RcQYgTqx02xlCXIjl8LK1rPjTneySqw==",
"requires": { "requires": {
"@babel/runtime": "^7.19.0", "@babel/runtime": "^7.19.0",
"@mui/private-theming": "^5.10.6", "@mui/private-theming": "^5.10.6",
"@mui/styled-engine": "^5.10.7", "@mui/styled-engine": "^5.10.8",
"@mui/types": "^7.2.0", "@mui/types": "^7.2.0",
"@mui/utils": "^5.10.6", "@mui/utils": "^5.10.6",
"clsx": "^1.2.1", "clsx": "^1.2.1",
@@ -19819,9 +19825,9 @@
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==" "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
}, },
"@remix-run/router": { "@remix-run/router": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.1.tgz", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.2.tgz",
"integrity": "sha512-eBV5rvW4dRFOU1eajN7FmYxjAIVz/mRHgUE9En9mBn6m3mulK3WTR5C3iQhL9MZ14rWAq+xOlEaCkDiW0/heOg==" "integrity": "sha512-GRSOFhJzjGN+d4sKHTMSvNeUPoZiDHWmRnXfzaxrqe7dE/Nzlc8BiMSJdLDESZlndM7jIUrZ/F4yWqVYlI0rwQ=="
}, },
"@rollup/plugin-babel": { "@rollup/plugin-babel": {
"version": "5.3.1", "version": "5.3.1",
@@ -19877,9 +19883,9 @@
"integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==" "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg=="
}, },
"@sinclair/typebox": { "@sinclair/typebox": {
"version": "0.24.43", "version": "0.24.44",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.43.tgz", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.44.tgz",
"integrity": "sha512-1orQTvtazZmsPeBroJjysvsOQCYV2yjWlebkSY38pl5vr2tdLjEJ+LoxITlGNZaH2RE19WlAwQMkH/7C14wLfw==" "integrity": "sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg=="
}, },
"@sinonjs/commons": { "@sinonjs/commons": {
"version": "1.8.3", "version": "1.8.3",
@@ -20018,9 +20024,9 @@
} }
}, },
"@table-library/react-table-library": { "@table-library/react-table-library": {
"version": "4.0.18", "version": "4.0.23",
"resolved": "https://registry.npmjs.org/@table-library/react-table-library/-/react-table-library-4.0.18.tgz", "resolved": "https://registry.npmjs.org/@table-library/react-table-library/-/react-table-library-4.0.23.tgz",
"integrity": "sha512-3GX5712YuWPFeUilr8UG22SCNR9BylD5Y4xPF+pHhb1QM7WXw6SLgpeGq6UDTQGOtmKtKtwKGWXdkmvVDg8pkA==", "integrity": "sha512-o2L/fqhwQNxsNbbm3LIiyZzEwaTslhG1tY9ArkYdS0xJyRhJxcOLfbJ3+dcnOOn+aIJpmPmQH+gr7RYJC0P8uw==",
"requires": { "requires": {
"clsx": "1.1.1", "clsx": "1.1.1",
"react-virtualized-auto-sizer": "1.0.6", "react-virtualized-auto-sizer": "1.0.6",
@@ -20223,9 +20229,9 @@
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
}, },
"@types/lodash": { "@types/lodash": {
"version": "4.14.185", "version": "4.14.186",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.185.tgz", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.186.tgz",
"integrity": "sha512-evMDG1bC4rgQg4ku9tKpuMh5iBNEwNa3tf9zRHdP1qlv+1WUg44xat4IxCE14gIpZRGUUWAx2VhItCZc25NfMA==" "integrity": "sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw=="
}, },
"@types/mime": { "@types/mime": {
"version": "3.0.1", "version": "3.0.1",
@@ -20233,9 +20239,9 @@
"integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA=="
}, },
"@types/node": { "@types/node": {
"version": "18.7.23", "version": "18.8.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz",
"integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==" "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w=="
}, },
"@types/parse-json": { "@types/parse-json": {
"version": "4.0.0", "version": "4.0.0",
@@ -20973,12 +20979,13 @@
"integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==" "integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w=="
}, },
"axios": { "axios": {
"version": "0.27.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.2.tgz",
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", "integrity": "sha512-bznQyETwElsXl2RK7HLLwb5GPpOLlycxHCtrpDR/4RqqBzjARaOTo3jz4IgtntWUYee7Ne4S8UHd92VCuzPaWA==",
"requires": { "requires": {
"follow-redirects": "^1.14.9", "follow-redirects": "^1.15.0",
"form-data": "^4.0.0" "form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
} }
}, },
"axobject-query": { "axobject-query": {
@@ -21399,9 +21406,9 @@
} }
}, },
"caniuse-lite": { "caniuse-lite": {
"version": "1.0.30001412", "version": "1.0.30001414",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001412.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001414.tgz",
"integrity": "sha512-+TeEIee1gS5bYOiuf+PS/kp2mrXic37Hl66VY6EAfxasIk5fELTktK2oOezYed12H8w7jt3s512PpulQidPjwA==" "integrity": "sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg=="
}, },
"case-sensitive-paths-webpack-plugin": { "case-sensitive-paths-webpack-plugin": {
"version": "2.4.0", "version": "2.4.0",
@@ -22255,9 +22262,9 @@
} }
}, },
"electron-to-chromium": { "electron-to-chromium": {
"version": "1.4.266", "version": "1.4.270",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.266.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.270.tgz",
"integrity": "sha512-saJTYECxUSv7eSpnXw0XIEvUkP9x4s/x2mm3TVX7k4rIFS6f5TjBih1B5h437WzIhHQjid+d8ouQzPQskMervQ==" "integrity": "sha512-KNhIzgLiJmDDC444dj9vEOpZEgsV96ult9Iff98Vanumn+ShJHd5se8aX6KeVxdc0YQeqdrezBZv89rleDbvSg=="
}, },
"emittery": { "emittery": {
"version": "0.8.1", "version": "0.8.1",
@@ -25614,9 +25621,9 @@
} }
}, },
"js-sdsl": { "js-sdsl": {
"version": "4.1.4", "version": "4.1.5",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz",
"integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==" "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q=="
}, },
"js-tokens": { "js-tokens": {
"version": "4.0.0", "version": "4.0.0",
@@ -26649,9 +26656,9 @@
} }
}, },
"postcss": { "postcss": {
"version": "8.4.16", "version": "8.4.17",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz",
"integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", "integrity": "sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==",
"requires": { "requires": {
"nanoid": "^3.3.4", "nanoid": "^3.3.4",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
@@ -27407,6 +27414,11 @@
} }
} }
}, },
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"psl": { "psl": {
"version": "1.9.0", "version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
@@ -27692,20 +27704,20 @@
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==" "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
}, },
"react-router": { "react-router": {
"version": "6.4.1", "version": "6.4.2",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.1.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.2.tgz",
"integrity": "sha512-OJASKp5AykDWFewgWUim1vlLr7yfD4vO/h+bSgcP/ix8Md+LMHuAjovA74MQfsfhQJGGN1nHRhwS5qQQbbBt3A==", "integrity": "sha512-Rb0BAX9KHhVzT1OKhMvCDMw776aTYM0DtkxqUBP8dNBom3mPXlfNs76JNGK8wKJ1IZEY1+WGj+cvZxHVk/GiKw==",
"requires": { "requires": {
"@remix-run/router": "1.0.1" "@remix-run/router": "1.0.2"
} }
}, },
"react-router-dom": { "react-router-dom": {
"version": "6.4.1", "version": "6.4.2",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.1.tgz", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.2.tgz",
"integrity": "sha512-MY7NJCrGNVJtGp8ODMOBHu20UaIkmwD2V3YsAOUQoCXFk7Ppdwf55RdcGyrSj+ycSL9Uiwrb3gTLYSnzcRoXww==", "integrity": "sha512-yM1kjoTkpfjgczPrcyWrp+OuQMyB1WleICiiGfstnQYo/S8hPEEnVjr/RdmlH6yKK4Tnj1UGXFSa7uwAtmDoLQ==",
"requires": { "requires": {
"@remix-run/router": "1.0.1", "@remix-run/router": "1.0.2",
"react-router": "6.4.1" "react-router": "6.4.2"
} }
}, },
"react-scripts": { "react-scripts": {
@@ -29096,9 +29108,9 @@
} }
}, },
"typesafe-i18n": { "typesafe-i18n": {
"version": "5.13.1", "version": "5.14.0",
"resolved": "https://registry.npmjs.org/typesafe-i18n/-/typesafe-i18n-5.13.1.tgz", "resolved": "https://registry.npmjs.org/typesafe-i18n/-/typesafe-i18n-5.14.0.tgz",
"integrity": "sha512-9Cgikxcj+2LAWQGZ8pOQAf14P+aOOcOel/G1kSAXAObA4Htj8R+qgCx9DqUnxjRfugWzM/19ZqGss7dl8Dw7Gg==", "integrity": "sha512-ZNHysUvZZhmUuMjBvDGtUI8vT3g//4ay5fFOk2sJCsjx4ztippW1Hrhrq59nJ9mV/Q0u4OX80Gyorq8L3rwNLw==",
"requires": {} "requires": {}
}, },
"typescript": { "typescript": {

View File

@@ -8,15 +8,15 @@
"@emotion/styled": "^11.10.4", "@emotion/styled": "^11.10.4",
"@msgpack/msgpack": "^2.8.0", "@msgpack/msgpack": "^2.8.0",
"@mui/icons-material": "^5.10.6", "@mui/icons-material": "^5.10.6",
"@mui/material": "^5.10.7", "@mui/material": "^5.10.8",
"@table-library/react-table-library": "4.0.18", "@table-library/react-table-library": "4.0.23",
"@types/lodash": "^4.14.185", "@types/lodash": "^4.14.186",
"@types/node": "^18.7.23", "@types/node": "^18.8.3",
"@types/react": "^18.0.21", "@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6", "@types/react-dom": "^18.0.6",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
"async-validator": "^4.2.5", "async-validator": "^4.2.5",
"axios": "^0.27.2", "axios": "^1.1.2",
"http-proxy-middleware": "^2.0.6", "http-proxy-middleware": "^2.0.6",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
@@ -27,10 +27,10 @@
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-dropzone": "^14.2.2", "react-dropzone": "^14.2.2",
"react-icons": "^4.4.0", "react-icons": "^4.4.0",
"react-router-dom": "^6.4.1", "react-router-dom": "^6.4.2",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"sockette": "^2.0.6", "sockette": "^2.0.6",
"typesafe-i18n": "^5.13.1", "typesafe-i18n": "^5.14.0",
"typescript": "^4.8.4" "typescript": "^4.8.4"
}, },
"scripts": { "scripts": {

View File

@@ -9,8 +9,6 @@ import * as AuthenticationApi from './api/authentication';
import { PROJECT_NAME } from './api/env'; import { PROJECT_NAME } from './api/env';
import { AuthenticationContext } from './contexts/authentication'; import { AuthenticationContext } from './contexts/authentication';
import { AxiosError } from 'axios';
import { extractErrorMessage, onEnterCallback, updateValue } from './utils'; import { extractErrorMessage, onEnterCallback, updateValue } from './utils';
import { SignInRequest } from './types'; import { SignInRequest } from './types';
import { ValidatedTextField } from './components'; import { ValidatedTextField } from './components';
@@ -58,8 +56,8 @@ const SignIn: FC = () => {
try { try {
const { data: loginResponse } = await AuthenticationApi.signIn(signInRequest); const { data: loginResponse } = await AuthenticationApi.signIn(signInRequest);
authenticationContext.signIn(loginResponse.access_token); authenticationContext.signIn(loginResponse.access_token);
} catch (error: unknown) { } catch (error) {
if (error instanceof AxiosError) { if (error.response) {
if (error.response?.status === 401) { if (error.response?.status === 401) {
enqueueSnackbar(LL.INVALID_LOGIN(), { variant: 'warning' }); enqueueSnackbar(LL.INVALID_LOGIN(), { variant: 'warning' });
} }
@@ -131,7 +129,12 @@ const SignIn: FC = () => {
<PLflag style={{ width: 24 }} /> <PLflag style={{ width: 24 }} />
&nbsp;PL &nbsp;PL
</Button> </Button>
<Button disabled size="small" variant={locale === 'no' ? 'contained' : 'outlined'} onClick={() => selectLocale('no')}> <Button
disabled
size="small"
variant={locale === 'no' ? 'contained' : 'outlined'}
onClick={() => selectLocale('no')}
>
<NOflag style={{ width: 24 }} /> <NOflag style={{ width: 24 }} />
&nbsp;NO &nbsp;NO
</Button> </Button>

View File

@@ -1,4 +1,4 @@
import axios, { AxiosPromise, CancelToken } from 'axios'; import axios, { AxiosPromise, CancelToken, AxiosProgressEvent } from 'axios';
import { decode } from '@msgpack/msgpack'; import { decode } from '@msgpack/msgpack';
@@ -89,7 +89,7 @@ function calculateEventSourceRoot(endpointPath: string) {
export interface FileUploadConfig { export interface FileUploadConfig {
cancelToken?: CancelToken; cancelToken?: CancelToken;
onUploadProgress?: (progressEvent: ProgressEvent) => void; onUploadProgress?: (progressEvent: AxiosProgressEvent) => void;
} }
export const startUploadFile = (url: string, file: File, config?: FileUploadConfig): AxiosPromise<void> => { export const startUploadFile = (url: string, file: File, config?: FileUploadConfig): AxiosPromise<void> => {

View File

@@ -1,6 +1,8 @@
import { FC, Fragment } from 'react'; import { FC, Fragment } from 'react';
import { useDropzone, DropzoneState } from 'react-dropzone'; import { useDropzone, DropzoneState } from 'react-dropzone';
import { AxiosProgressEvent } from 'axios';
import { Box, Button, LinearProgress, Theme, Typography, useTheme } from '@mui/material'; import { Box, Button, LinearProgress, Theme, Typography, useTheme } from '@mui/material';
import CloudUploadIcon from '@mui/icons-material/CloudUpload'; import CloudUploadIcon from '@mui/icons-material/CloudUpload';
@@ -8,8 +10,6 @@ import CancelIcon from '@mui/icons-material/Cancel';
import { useI18nContext } from '../../i18n/i18n-react'; import { useI18nContext } from '../../i18n/i18n-react';
const progressPercentage = (progress: ProgressEvent) => Math.round((progress.loaded * 100) / progress.total);
const getBorderColor = (theme: Theme, props: DropzoneState) => { const getBorderColor = (theme: Theme, props: DropzoneState) => {
if (props.isDragAccept) { if (props.isDragAccept) {
return theme.palette.success.main; return theme.palette.success.main;
@@ -27,7 +27,7 @@ export interface SingleUploadProps {
onDrop: (acceptedFiles: File[]) => void; onDrop: (acceptedFiles: File[]) => void;
onCancel: () => void; onCancel: () => void;
uploading: boolean; uploading: boolean;
progress?: ProgressEvent; progress?: AxiosProgressEvent;
} }
const SingleUpload: FC<SingleUploadProps> = ({ onDrop, onCancel, uploading, progress }) => { const SingleUpload: FC<SingleUploadProps> = ({ onDrop, onCancel, uploading, progress }) => {
@@ -47,8 +47,8 @@ const SingleUpload: FC<SingleUploadProps> = ({ onDrop, onCancel, uploading, prog
const progressText = () => { const progressText = () => {
if (uploading) { if (uploading) {
if (progress?.lengthComputable) { if (progress?.total) {
return LL.UPLOADING() + `: ${progressPercentage(progress)}%`; return LL.UPLOADING() + ': ' + Math.round((progress.loaded * 100) / progress.total) + '%';
} }
return LL.UPLOADING() + `\u2026`; return LL.UPLOADING() + `\u2026`;
} }
@@ -80,8 +80,8 @@ const SingleUpload: FC<SingleUploadProps> = ({ onDrop, onCancel, uploading, prog
<Fragment> <Fragment>
<Box width="100%" p={2}> <Box width="100%" p={2}>
<LinearProgress <LinearProgress
variant={!progress || progress.lengthComputable ? 'determinate' : 'indeterminate'} variant={!progress || progress.total ? 'determinate' : 'indeterminate'}
value={!progress ? 0 : progress.lengthComputable ? progressPercentage(progress) : 0} value={!progress ? 0 : progress.total ? Math.round((progress.loaded * 100) / progress.total) : 0}
/> />
</Box> </Box>
<Button startIcon={<CancelIcon />} variant="outlined" color="secondary" onClick={onCancel}> <Button startIcon={<CancelIcon />} variant="outlined" color="secondary" onClick={onCancel}>

View File

@@ -1,5 +1,5 @@
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import axios, { AxiosPromise, CancelTokenSource } from 'axios'; import axios, { AxiosPromise, CancelTokenSource, AxiosProgressEvent } from 'axios';
import { useSnackbar } from 'notistack'; import { useSnackbar } from 'notistack';
import { extractErrorMessage } from '../../utils'; import { extractErrorMessage } from '../../utils';
@@ -16,7 +16,7 @@ const useFileUpload = ({ upload }: MediaUploadOptions) => {
const { enqueueSnackbar } = useSnackbar(); const { enqueueSnackbar } = useSnackbar();
const [uploading, setUploading] = useState<boolean>(false); const [uploading, setUploading] = useState<boolean>(false);
const [uploadProgress, setUploadProgress] = useState<ProgressEvent>(); const [uploadProgress, setUploadProgress] = useState<AxiosProgressEvent>();
const [uploadCancelToken, setUploadCancelToken] = useState<CancelTokenSource>(); const [uploadCancelToken, setUploadCancelToken] = useState<CancelTokenSource>();
const resetUploadingStates = () => { const resetUploadingStates = () => {
@@ -47,7 +47,7 @@ const useFileUpload = ({ upload }: MediaUploadOptions) => {
}); });
resetUploadingStates(); resetUploadingStates();
enqueueSnackbar(LL.UPLOAD() + ' ' + LL.SUCCESSFUL(), { variant: 'success' }); enqueueSnackbar(LL.UPLOAD() + ' ' + LL.SUCCESSFUL(), { variant: 'success' });
} catch (error: unknown) { } catch (error) {
if (axios.isCancel(error)) { if (axios.isCancel(error)) {
enqueueSnackbar(LL.UPLOAD() + ' ' + LL.ABORTED(), { variant: 'warning' }); enqueueSnackbar(LL.UPLOAD() + ' ' + LL.ABORTED(), { variant: 'warning' });
} else { } else {

View File

@@ -28,7 +28,7 @@ const Authentication: FC<RequiredChildrenProps> = ({ children }) => {
const decodedMe = AuthenticationApi.decodeMeJWT(accessToken); const decodedMe = AuthenticationApi.decodeMeJWT(accessToken);
setMe(decodedMe); setMe(decodedMe);
enqueueSnackbar(LL.LOGGED_IN({ name: decodedMe.username }), { variant: 'success' }); enqueueSnackbar(LL.LOGGED_IN({ name: decodedMe.username }), { variant: 'success' });
} catch (error: unknown) { } catch (error) {
setMe(undefined); setMe(undefined);
throw new Error('Failed to parse JWT'); throw new Error('Failed to parse JWT');
} }
@@ -54,7 +54,7 @@ const Authentication: FC<RequiredChildrenProps> = ({ children }) => {
await AuthenticationApi.verifyAuthorization(); await AuthenticationApi.verifyAuthorization();
setMe(AuthenticationApi.decodeMeJWT(accessToken)); setMe(AuthenticationApi.decodeMeJWT(accessToken));
setInitialized(true); setInitialized(true);
} catch (error: unknown) { } catch (error) {
setMe(undefined); setMe(undefined);
setInitialized(true); setInitialized(true);
} }

View File

@@ -16,7 +16,7 @@ const FeaturesLoader: FC<RequiredChildrenProps> = (props) => {
try { try {
const response = await FeaturesApi.readFeatures(); const response = await FeaturesApi.readFeatures();
setFeatures(response.data); setFeatures(response.data);
} catch (error: unknown) { } catch (error) {
setErrorMessage(extractErrorMessage(error, 'Failed to fetch application details.')); setErrorMessage(extractErrorMessage(error, 'Failed to fetch application details.'));
} }
}, []); }, []);

View File

@@ -50,9 +50,9 @@ const MqttStatusForm: FC = () => {
return LL.NOT_ENABLED(); return LL.NOT_ENABLED();
} }
if (connected) { if (connected) {
return (LL.CONNECTED() + (connect_count > 1 ? ' (' + connect_count + ')' : '')); return LL.CONNECTED() + (connect_count > 1 ? ' (' + connect_count + ')' : '');
} }
return (LL.DISCONNECTED() + (connect_count > 1 ? ' (' + connect_count + ')' : '')); return LL.DISCONNECTED() + (connect_count > 1 ? ' (' + connect_count + ')' : '');
}; };
const disconnectReason = ({ disconnect_reason }: MqttStatus) => { const disconnectReason = ({ disconnect_reason }: MqttStatus) => {

View File

@@ -1,8 +1,6 @@
import { useEffect, FC, useState, useCallback, useRef } from 'react'; import { useEffect, FC, useState, useCallback, useRef } from 'react';
import { useSnackbar } from 'notistack'; import { useSnackbar } from 'notistack';
import { AxiosError } from 'axios';
import { Button } from '@mui/material'; import { Button } from '@mui/material';
import PermScanWifiIcon from '@mui/icons-material/PermScanWifi'; import PermScanWifiIcon from '@mui/icons-material/PermScanWifi';
@@ -57,8 +55,8 @@ const WiFiNetworkScanner: FC = () => {
newNetworkList.networks.sort(compareNetworks); newNetworkList.networks.sort(compareNetworks);
setNetworkList(newNetworkList); setNetworkList(newNetworkList);
} }
} catch (error: unknown) { } catch (error) {
if (error instanceof AxiosError) { if (error.response) {
finishedWithError(LL.PROBLEM_LOADING() + ' ' + error.response?.data.message); finishedWithError(LL.PROBLEM_LOADING() + ' ' + error.response?.data.message);
} else { } else {
finishedWithError(LL.PROBLEM_LOADING()); finishedWithError(LL.PROBLEM_LOADING());
@@ -73,8 +71,8 @@ const WiFiNetworkScanner: FC = () => {
try { try {
await NetworkApi.scanNetworks(); await NetworkApi.scanNetworks();
setTimeout(pollNetworkList, POLLING_FREQUENCY); setTimeout(pollNetworkList, POLLING_FREQUENCY);
} catch (error: unknown) { } catch (error) {
if (error instanceof AxiosError) { if (error.response) {
finishedWithError(LL.PROBLEM_LOADING() + ' ' + error.response?.data.message); finishedWithError(LL.PROBLEM_LOADING() + ' ' + error.response?.data.message);
} else { } else {
finishedWithError(LL.PROBLEM_LOADING()); finishedWithError(LL.PROBLEM_LOADING());

View File

@@ -91,7 +91,7 @@ const NTPStatusForm: FC = () => {
enqueueSnackbar(LL.TIME_SET(), { variant: 'success' }); enqueueSnackbar(LL.TIME_SET(), { variant: 'success' });
setSettingTime(false); setSettingTime(false);
loadData(); loadData();
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' });
} finally { } finally {
setProcessing(false); setProcessing(false);

View File

@@ -37,7 +37,7 @@ const GenerateToken: FC<GenerateTokenProps> = ({ username, onClose }) => {
const getToken = useCallback(async () => { const getToken = useCallback(async () => {
try { try {
setToken((await SecurityApi.generateToken(username)).data); setToken((await SecurityApi.generateToken(username)).data);
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' });
} }
}, [username, enqueueSnackbar, LL]); }, [username, enqueueSnackbar, LL]);

View File

@@ -50,7 +50,7 @@ const GeneralFileUpload: FC<UploadFileProps> = ({ uploadGeneralFile }) => {
} else { } else {
saveFile(response.data, 'settings'); saveFile(response.data, 'settings');
} }
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' });
} }
}; };
@@ -63,7 +63,7 @@ const GeneralFileUpload: FC<UploadFileProps> = ({ uploadGeneralFile }) => {
} else { } else {
saveFile(response.data, 'customizations'); saveFile(response.data, 'customizations');
} }
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' });
} }
}; };

View File

@@ -21,7 +21,7 @@ const RestartMonitor: FC = () => {
try { try {
await SystemApi.readSystemStatus(POLL_TIMEOUT); await SystemApi.readSystemStatus(POLL_TIMEOUT);
document.location.href = '/fileUpdated'; document.location.href = '/fileUpdated';
} catch (error: unknown) { } catch (error) {
if (new Date().getTime() < timeoutAt.current) { if (new Date().getTime() < timeoutAt.current) {
setTimeoutId(setTimeout(poll.current, POLL_INTERVAL)); setTimeoutId(setTimeout(poll.current, POLL_INTERVAL));
} else { } else {

View File

@@ -111,7 +111,7 @@ const SystemLog: FC = () => {
if (response.status !== 200) { if (response.status !== 200) {
enqueueSnackbar(LL.PROBLEM_UPDATING(), { variant: 'error' }); enqueueSnackbar(LL.PROBLEM_UPDATING(), { variant: 'error' });
} }
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' });
} }
} }
@@ -163,7 +163,7 @@ const SystemLog: FC = () => {
const fetchLog = useCallback(async () => { const fetchLog = useCallback(async () => {
try { try {
setLogEntries((await SystemApi.readLogEntries()).data); setLogEntries((await SystemApi.readLogEntries()).data);
} catch (error: unknown) { } catch (error) {
setErrorMessage(extractErrorMessage(error, LL.PROBLEM_LOADING())); setErrorMessage(extractErrorMessage(error, LL.PROBLEM_LOADING()));
} }
}, [LL]); }, [LL]);

View File

@@ -86,7 +86,7 @@ const SystemStatusForm: FC = () => {
try { try {
await SystemApi.restart(); await SystemApi.restart();
enqueueSnackbar(LL.APPLICATION_RESTARTING(), { variant: 'info' }); enqueueSnackbar(LL.APPLICATION_RESTARTING(), { variant: 'info' });
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' });
} finally { } finally {
setConfirmRestart(false); setConfirmRestart(false);
@@ -180,7 +180,7 @@ const SystemStatusForm: FC = () => {
try { try {
await SystemApi.factoryReset(); await SystemApi.factoryReset();
enqueueSnackbar(LL.SYSTEM_FACTORY_TEXT(), { variant: 'info' }); enqueueSnackbar(LL.SYSTEM_FACTORY_TEXT(), { variant: 'info' });
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' });
} finally { } finally {
setConfirmFactoryReset(false); setConfirmFactoryReset(false);

File diff suppressed because it is too large Load Diff

View File

@@ -98,8 +98,7 @@ const pl: BaseTranslation = {
APPLICATION_SETTINGS: 'Ustawienia aplikacji', APPLICATION_SETTINGS: 'Ustawienia aplikacji',
CUSTOMIZATION: 'Personalizacja', CUSTOMIZATION: 'Personalizacja',
APPLICATION_RESTARTING: 'Trwa ponowne uruchamianie', APPLICATION_RESTARTING: 'Trwa ponowne uruchamianie',
BOARD_PROFILE_TEXT: BOARD_PROFILE_TEXT: 'Wybierz z listy wstępną konfigurację płytki interfejsu lub stwórz własną konfigurację',
'Wybierz z listy wstępną konfigurację płytki interfejsu lub stwórz własną konfigurację',
BOARD_PROFILE: 'Profil płytki', BOARD_PROFILE: 'Profil płytki',
BUTTON: 'Przycisk', BUTTON: 'Przycisk',
TEMPERATURE: 'Temperatura', TEMPERATURE: 'Temperatura',
@@ -109,7 +108,7 @@ const pl: BaseTranslation = {
HIDE_LED: 'Wyłącz LED', HIDE_LED: 'Wyłącz LED',
ENABLE_TELNET: 'Aktywuj dostęp dla konsoli Telnet', ENABLE_TELNET: 'Aktywuj dostęp dla konsoli Telnet',
ENABLE_ANALOG: 'Aktywuj czujniki analogowe', ENABLE_ANALOG: 'Aktywuj czujniki analogowe',
CONVERT_FAHRENHEIT: "Konwertuj temperatury do skali Fahrenheita", CONVERT_FAHRENHEIT: 'Konwertuj temperatury do skali Fahrenheita',
BYPASS_TOKEN: 'Pomiń autoryzację tokenem w wywołaniach API', BYPASS_TOKEN: 'Pomiń autoryzację tokenem w wywołaniach API',
READONLY: 'Tryb pracy "tylko do odczytu" (blokuje wszystkie komendy zapisu na magistralę EMS)', READONLY: 'Tryb pracy "tylko do odczytu" (blokuje wszystkie komendy zapisu na magistralę EMS)',
UNDERCLOCK_CPU: 'Obniż taktowanie CPU', UNDERCLOCK_CPU: 'Obniż taktowanie CPU',

View File

@@ -364,7 +364,7 @@ const DashboardData: FC = () => {
const fetchCoreData = useCallback(async () => { const fetchCoreData = useCallback(async () => {
try { try {
setCoreData((await EMSESP.readCoreData()).data); setCoreData((await EMSESP.readCoreData()).data);
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' });
} }
}, [enqueueSnackbar, LL]); }, [enqueueSnackbar, LL]);
@@ -385,7 +385,7 @@ const DashboardData: FC = () => {
const unique_id = parseInt(id); const unique_id = parseInt(id);
try { try {
setDeviceData((await EMSESP.readDeviceData({ id: unique_id })).data); setDeviceData((await EMSESP.readDeviceData({ id: unique_id })).data);
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' });
} }
}; };
@@ -393,7 +393,7 @@ const DashboardData: FC = () => {
const fetchSensorData = async () => { const fetchSensorData = async () => {
try { try {
setSensorData((await EMSESP.readSensorData()).data); setSensorData((await EMSESP.readSensorData()).data);
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' });
} }
}; };
@@ -474,7 +474,7 @@ const DashboardData: FC = () => {
enqueueSnackbar(LL.WRITE_COMMAND({ cmd: 'send' }), { variant: 'success' }); enqueueSnackbar(LL.WRITE_COMMAND({ cmd: 'send' }), { variant: 'success' });
} }
setDeviceValue(undefined); setDeviceValue(undefined);
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' });
} finally { } finally {
refreshData(); refreshData();
@@ -508,7 +508,7 @@ const DashboardData: FC = () => {
<ValidatedTextField <ValidatedTextField
name="v" name="v"
label={deviceValue.id.slice(2)} label={deviceValue.id.slice(2)}
value={typeof deviceValue.v === 'number' ? (Math.round(deviceValue.v * 10) / 10) : deviceValue.v} value={typeof deviceValue.v === 'number' ? Math.round(deviceValue.v * 10) / 10 : deviceValue.v}
autoFocus autoFocus
multiline={deviceValue.u ? false : true} multiline={deviceValue.u ? false : true}
sx={{ width: '30ch' }} sx={{ width: '30ch' }}
@@ -566,7 +566,7 @@ const DashboardData: FC = () => {
enqueueSnackbar(LL.TEMP_SENSOR() + ' ' + LL.UPDATED(), { variant: 'success' }); enqueueSnackbar(LL.TEMP_SENSOR() + ' ' + LL.UPDATED(), { variant: 'success' });
} }
setSensor(undefined); setSensor(undefined);
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' });
} finally { } finally {
setSensor(undefined); setSensor(undefined);
@@ -992,7 +992,7 @@ const DashboardData: FC = () => {
} else { } else {
enqueueSnackbar(LL.ANALOG_SENSOR() + ' ' + LL.REMOVED(), { variant: 'success' }); enqueueSnackbar(LL.ANALOG_SENSOR() + ' ' + LL.REMOVED(), { variant: 'success' });
} }
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' });
} finally { } finally {
setAnalog(undefined); setAnalog(undefined);
@@ -1020,7 +1020,7 @@ const DashboardData: FC = () => {
} else { } else {
enqueueSnackbar(LL.ANALOG_SENSOR() + ' ' + LL.UPDATED(), { variant: 'success' }); enqueueSnackbar(LL.ANALOG_SENSOR() + ' ' + LL.UPDATED(), { variant: 'success' });
} }
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' });
} finally { } finally {
setAnalog(undefined); setAnalog(undefined);

View File

@@ -149,7 +149,7 @@ const DashboardStatus: FC = () => {
try { try {
await EMSESP.scanDevices(); await EMSESP.scanDevices();
enqueueSnackbar(LL.SCANNING() + '...', { variant: 'info' }); enqueueSnackbar(LL.SCANNING() + '...', { variant: 'info' });
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' });
} finally { } finally {
setConfirmScan(false); setConfirmScan(false);

View File

@@ -50,7 +50,7 @@ const HelpInformation: FC = () => {
} else { } else {
saveFile(response.data, endpoint); saveFile(response.data, endpoint);
} }
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' });
} }
}; };

View File

@@ -68,7 +68,7 @@ const SettingsApplication: FC = () => {
eth_clock_mode: response.data.eth_clock_mode eth_clock_mode: response.data.eth_clock_mode
}); });
} }
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' });
} finally { } finally {
setProcessingBoard(false); setProcessingBoard(false);
@@ -107,7 +107,7 @@ const SettingsApplication: FC = () => {
try { try {
await EMSESP.restart(); await EMSESP.restart();
enqueueSnackbar(LL.APPLICATION_RESTARTING(), { variant: 'info' }); enqueueSnackbar(LL.APPLICATION_RESTARTING(), { variant: 'info' });
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' });
} }
}; };

View File

@@ -131,7 +131,7 @@ const SettingsCustomization: FC = () => {
const fetchDevices = useCallback(async () => { const fetchDevices = useCallback(async () => {
try { try {
setDevices((await EMSESP.readDevices()).data); setDevices((await EMSESP.readDevices()).data);
} catch (error: unknown) { } catch (error) {
setErrorMessage(extractErrorMessage(error, LL.PROBLEM_LOADING())); setErrorMessage(extractErrorMessage(error, LL.PROBLEM_LOADING()));
} }
}, [LL]); }, [LL]);
@@ -144,7 +144,7 @@ const SettingsCustomization: FC = () => {
try { try {
const new_deviceEntities = (await EMSESP.readDeviceEntities({ id: unique_id })).data; const new_deviceEntities = (await EMSESP.readDeviceEntities({ id: unique_id })).data;
setInitialMask(new_deviceEntities); setInitialMask(new_deviceEntities);
} catch (error: unknown) { } catch (error) {
setErrorMessage(extractErrorMessage(error, LL.PROBLEM_LOADING())); setErrorMessage(extractErrorMessage(error, LL.PROBLEM_LOADING()));
} }
}; };
@@ -243,7 +243,7 @@ const SettingsCustomization: FC = () => {
try { try {
await EMSESP.resetCustomizations(); await EMSESP.resetCustomizations();
enqueueSnackbar(LL.CUSTOMIZATIONS_RESTART(), { variant: 'info' }); enqueueSnackbar(LL.CUSTOMIZATIONS_RESTART(), { variant: 'info' });
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' });
} finally { } finally {
setConfirmReset(false); setConfirmReset(false);
@@ -254,13 +254,15 @@ const SettingsCustomization: FC = () => {
if (devices && deviceEntities && selectedDevice !== -1) { if (devices && deviceEntities && selectedDevice !== -1) {
const masked_entities = deviceEntities const masked_entities = deviceEntities
.filter((de) => de.m !== de.o_m || de.cn !== de.o_cn || de.ma !== de.o_ma || de.mi !== de.o_mi) .filter((de) => de.m !== de.o_m || de.cn !== de.o_cn || de.ma !== de.o_ma || de.mi !== de.o_mi)
.map((new_de) => .map(
new_de.m.toString(16).padStart(2, '0') + (new_de) =>
new_de.id + new_de.m.toString(16).padStart(2, '0') +
((new_de.cn || new_de.mi || new_de.ma) ? '|' : '') + new_de.id +
(new_de.cn ? new_de.cn : '') + (new_de.cn || new_de.mi || new_de.ma ? '|' : '') +
(new_de.mi ? '>' + new_de.mi : '') + (new_de.cn ? new_de.cn : '') +
(new_de.ma ? '<' + new_de.ma : '')); (new_de.mi ? '>' + new_de.mi : '') +
(new_de.ma ? '<' + new_de.ma : '')
);
// check size in bytes to match buffer in CPP, which is 4096 // check size in bytes to match buffer in CPP, which is 4096
const bytes = new TextEncoder().encode(JSON.stringify(masked_entities)).length; const bytes = new TextEncoder().encode(JSON.stringify(masked_entities)).length;
@@ -279,7 +281,7 @@ const SettingsCustomization: FC = () => {
} else { } else {
enqueueSnackbar(LL.PROBLEM_UPDATING(), { variant: 'error' }); enqueueSnackbar(LL.PROBLEM_UPDATING(), { variant: 'error' });
} }
} catch (error: unknown) { } catch (error) {
enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' });
} }
setInitialMask(deviceEntities); setInitialMask(deviceEntities);

View File

@@ -1,7 +1,5 @@
import { AxiosError } from 'axios'; export const extractErrorMessage = (error: any, defaultMessage: string) => {
if (error.request) {
export const extractErrorMessage = (error: unknown, defaultMessage: string) => {
if (error instanceof AxiosError) {
return defaultMessage + ' (' + error.request.statusText + ')'; return defaultMessage + ' (' + error.request.statusText + ')';
} else if (error instanceof Error) { } else if (error instanceof Error) {
return defaultMessage + ' (' + error.message + ')'; return defaultMessage + ' (' + error.message + ')';

View File

@@ -26,7 +26,7 @@ export const useRest = <D>({ read, update }: RestRequestOptions<D>) => {
setErrorMessage(undefined); setErrorMessage(undefined);
try { try {
setData((await read()).data); setData((await read()).data);
} catch (error: unknown) { } catch (error) {
const message = extractErrorMessage(error, LL.PROBLEM_LOADING()); const message = extractErrorMessage(error, LL.PROBLEM_LOADING());
enqueueSnackbar(message, { variant: 'error' }); enqueueSnackbar(message, { variant: 'error' });
setErrorMessage(message); setErrorMessage(message);
@@ -49,7 +49,7 @@ export const useRest = <D>({ read, update }: RestRequestOptions<D>) => {
} else { } else {
enqueueSnackbar(LL.SETTINGS() + ' ' + LL.SAVED(), { variant: 'success' }); enqueueSnackbar(LL.SETTINGS() + ' ' + LL.SAVED(), { variant: 'success' });
} }
} catch (error: unknown) { } catch (error) {
const message = extractErrorMessage(error, LL.PROBLEM_UPDATING()); const message = extractErrorMessage(error, LL.PROBLEM_UPDATING());
enqueueSnackbar(message, { variant: 'error' }); enqueueSnackbar(message, { variant: 'error' });
setErrorMessage(message); setErrorMessage(message);

View File

@@ -14,6 +14,7 @@
"resolveJsonModule": true, "resolveJsonModule": true,
"isolatedModules": true, "isolatedModules": true,
"noEmit": true, "noEmit": true,
"useUnknownInCatchVariables": false,
"jsx": "react-jsx" "jsx": "react-jsx"
}, },
"include": ["src"] "include": ["src"]

View File

@@ -49,9 +49,9 @@ void APSettingsService::startAP() {
WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask); WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask);
esp_wifi_set_bandwidth((wifi_interface_t)ESP_IF_WIFI_AP, WIFI_BW_HT20); esp_wifi_set_bandwidth((wifi_interface_t)ESP_IF_WIFI_AP, WIFI_BW_HT20);
WiFi.softAP(_state.ssid.c_str(), _state.password.c_str(), _state.channel, _state.ssidHidden, _state.maxClients); WiFi.softAP(_state.ssid.c_str(), _state.password.c_str(), _state.channel, _state.ssidHidden, _state.maxClients);
#ifdef ARDUINO_LOLIN_C3_MINI #ifdef ARDUINO_LOLIN_C3_MINI
WiFi.setTxPower(WIFI_POWER_8_5dBm); //https://www.wemos.cc/en/latest/c3/c3_mini.html#about-wifi WiFi.setTxPower(WIFI_POWER_8_5dBm); //https://www.wemos.cc/en/latest/c3/c3_mini.html#about-wifi
#endif #endif
if (!_dnsServer) { if (!_dnsServer) {
IPAddress apIp = WiFi.softAPIP(); IPAddress apIp = WiFi.softAPIP();
emsesp::EMSESP::logger().info(F("Starting Access Point with captive portal on %s"), apIp.toString().c_str()); emsesp::EMSESP::logger().info(F("Starting Access Point with captive portal on %s"), apIp.toString().c_str());

View File

@@ -56,7 +56,7 @@ class NTPSettingsService : public StatefulService<NTPSettings> {
public: public:
NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager); NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
void begin(); void begin();
static void ntp_received(struct timeval * tv); static void ntp_received(struct timeval * tv);
private: private:
@@ -68,7 +68,6 @@ class NTPSettingsService : public StatefulService<NTPSettings> {
void WiFiEvent(WiFiEvent_t event); void WiFiEvent(WiFiEvent_t event);
void configureNTP(); void configureNTP();
void configureTime(AsyncWebServerRequest * request, JsonVariant & json); void configureTime(AsyncWebServerRequest * request, JsonVariant & json);
}; };
#endif #endif

View File

@@ -75,9 +75,9 @@ void NetworkSettingsService::manageSTA() {
}); });
WiFi.begin(_state.ssid.c_str(), _state.password.c_str()); // attempt to connect to the network WiFi.begin(_state.ssid.c_str(), _state.password.c_str()); // attempt to connect to the network
#ifdef ARDUINO_LOLIN_C3_MINI #ifdef ARDUINO_LOLIN_C3_MINI
WiFi.setTxPower(WIFI_POWER_8_5dBm); //https://www.wemos.cc/en/latest/c3/c3_mini.html#about-wifi WiFi.setTxPower(WIFI_POWER_8_5dBm); //https://www.wemos.cc/en/latest/c3/c3_mini.html#about-wifi
#endif #endif
} }
} }

View File

@@ -85,7 +85,8 @@ std::string printable_to_string(const Printable & printable);
* *
* @since 1.0.0 * @since 1.0.0
*/ */
using flash_string_vector = std::vector<const __FlashStringHelper *>;
using string_vector = std::vector<const char *>;
/** /**
* Loop function that must be called regularly to detect a 32-bit * Loop function that must be called regularly to detect a 32-bit

View File

@@ -42,30 +42,36 @@ namespace uuid {
namespace console { namespace console {
void Commands::add_command(const flash_string_vector & name, command_function function) { void Commands::add_command(const string_vector & name, command_function function) {
add_command(0, 0, name, flash_string_vector{}, function, nullptr); add_command(0, 0, name, string_vector{}, function, nullptr);
} }
void Commands::add_command(const flash_string_vector & name, const flash_string_vector & arguments, command_function function) { void Commands::add_command(const string_vector & name, const string_vector & arguments, command_function function) {
add_command(0, 0, name, arguments, function, nullptr); add_command(0, 0, name, arguments, function, nullptr);
} }
void Commands::add_command(const flash_string_vector & name, const flash_string_vector & arguments, command_function function, argument_completion_function arg_function) { void Commands::add_command(const string_vector & name, const string_vector & arguments, command_function function, argument_completion_function arg_function) {
add_command(0, 0, name, arguments, function, arg_function); add_command(0, 0, name, arguments, function, arg_function);
} }
void Commands::add_command(unsigned int context, unsigned int flags, const flash_string_vector & name, command_function function) { void Commands::add_command(unsigned int context, unsigned int flags, const string_vector & name, command_function function) {
add_command(context, flags, name, flash_string_vector{}, function, nullptr); add_command(context, flags, name, string_vector{}, function, nullptr);
} }
void Commands::add_command(unsigned int context, unsigned int flags, const flash_string_vector & name, const flash_string_vector & arguments, command_function function) { void Commands::add_command(unsigned int context, unsigned int flags, const string_vector & name, const string_vector & arguments, command_function function) {
add_command(context, flags, name, arguments, function, nullptr); add_command(context, flags, name, arguments, function, nullptr);
} }
void Commands::add_command(unsigned int context, unsigned int flags, const flash_string_vector & name, const flash_string_vector & arguments, command_function function, argument_completion_function arg_function) { void Commands::add_command(unsigned int context,
unsigned int flags,
const string_vector & name,
const string_vector & arguments,
command_function function,
argument_completion_function arg_function) {
commands_.emplace(std::piecewise_construct, std::forward_as_tuple(context), std::forward_as_tuple(flags, name, arguments, function, arg_function)); commands_.emplace(std::piecewise_construct, std::forward_as_tuple(context), std::forward_as_tuple(flags, name, arguments, function, arg_function));
} }
// added by proddy // added by proddy
// note we should really iterate and free up the lambda code and any flashstrings // note we should really iterate and free up the lambda code and any flashstrings
void Commands::remove_all_commands() { void Commands::remove_all_commands() {
@@ -139,7 +145,7 @@ bool Commands::find_longest_common_prefix(const std::multimap<size_t, const Comm
for (size_t length = 0; all_match && length < shortest_match; length++) { for (size_t length = 0; all_match && length < shortest_match; length++) {
for (auto command_it = std::next(commands.begin()); command_it != commands.end(); command_it++) { for (auto command_it = std::next(commands.begin()); command_it != commands.end(); command_it++) {
if (read_flash_string(*std::next(first.begin(), length)) != read_flash_string(*std::next(command_it->second->name_.begin(), length))) { if ((*std::next(first.begin(), length)) != (*std::next(command_it->second->name_.begin(), length))) {
all_match = false; all_match = false;
break; break;
} }
@@ -152,7 +158,7 @@ bool Commands::find_longest_common_prefix(const std::multimap<size_t, const Comm
auto name_it = first.begin(); auto name_it = first.begin();
for (size_t i = 0; i < component_prefix; i++) { for (size_t i = 0; i < component_prefix; i++) {
longest_name.push_back(std::move(read_flash_string(*name_it))); longest_name.push_back(std::move((*name_it)));
name_it++; name_it++;
} }
} }
@@ -167,7 +173,8 @@ bool Commands::find_longest_common_prefix(const std::multimap<size_t, const Comm
for (auto command_it = std::next(commands.begin()); command_it != commands.end(); command_it++) { for (auto command_it = std::next(commands.begin()); command_it != commands.end(); command_it++) {
// This relies on the null terminator character limiting the // This relies on the null terminator character limiting the
// length before it becomes longer than any of the strings // length before it becomes longer than any of the strings
if (pgm_read_byte(reinterpret_cast<PGM_P>(first) + length) != pgm_read_byte(reinterpret_cast<PGM_P>(*std::next(command_it->second->name_.begin(), component_prefix)) + length)) { if (pgm_read_byte(reinterpret_cast<PGM_P>(first) + length)
!= pgm_read_byte(reinterpret_cast<PGM_P>(*std::next(command_it->second->name_.begin(), component_prefix)) + length)) {
all_match = false; all_match = false;
break; break;
} }
@@ -179,7 +186,8 @@ bool Commands::find_longest_common_prefix(const std::multimap<size_t, const Comm
} }
if (chars_prefix > 0) { if (chars_prefix > 0) {
longest_name.push_back(std::move(read_flash_string(first).substr(0, chars_prefix))); // TODO fix, no more PGM
longest_name.push_back(std::string(first).substr(0, chars_prefix));
return false; return false;
} }
} }
@@ -243,7 +251,7 @@ Commands::Completion Commands::complete_command(Shell & shell, const CommandLine
} }
if (!temp_command_name.empty() && command_line.total_size() <= temp_command_name.size()) { if (!temp_command_name.empty() && command_line.total_size() <= temp_command_name.size()) {
temp_command = std::make_unique<Command>(0, flash_string_vector{}, flash_string_vector{}, nullptr, nullptr); temp_command = std::make_unique<Command>(0, string_vector{}, string_vector{}, nullptr, nullptr);
count = 1; count = 1;
match = commands.partial.end(); match = commands.partial.end();
result.replacement.trailing_space = whole_components; result.replacement.trailing_space = whole_components;
@@ -259,10 +267,11 @@ Commands::Completion Commands::complete_command(Shell & shell, const CommandLine
auto & matching_command = match->second; auto & matching_command = match->second;
for (auto & name : matching_command->name_) { for (auto & name : matching_command->name_) {
result.replacement->push_back(std::move(read_flash_string(name))); result.replacement->push_back(std::move((name)));
} }
if (command_line.total_size() > result.replacement->size() && command_line.total_size() <= matching_command->name_.size() + matching_command->maximum_arguments()) { if (command_line.total_size() > result.replacement->size()
&& command_line.total_size() <= matching_command->name_.size() + matching_command->maximum_arguments()) {
// Try to auto-complete arguments // Try to auto-complete arguments
std::vector<std::string> arguments{std::next(command_line->cbegin(), result.replacement->size()), command_line->cend()}; std::vector<std::string> arguments{std::next(command_line->cbegin(), result.replacement->size()), command_line->cend()};
@@ -332,7 +341,7 @@ Commands::Completion Commands::complete_command(Shell & shell, const CommandLine
remaining_help.escape_initial_parameters(); remaining_help.escape_initial_parameters();
for (auto it = std::next(matching_command->arguments_.cbegin(), current_args_count); it != matching_command->arguments_.cend(); it++) { for (auto it = std::next(matching_command->arguments_.cbegin(), current_args_count); it != matching_command->arguments_.cend(); it++) {
remaining_help->push_back(std::move(read_flash_string(*it))); remaining_help->push_back(std::move((*it)));
} }
} }
@@ -380,7 +389,7 @@ Commands::Completion Commands::complete_command(Shell & shell, const CommandLine
} }
for (; flash_name_it != command_it->second->name_.cend(); flash_name_it++) { for (; flash_name_it != command_it->second->name_.cend(); flash_name_it++) {
std::string name = read_flash_string(*flash_name_it); std::string name = (*flash_name_it);
// Skip parts of the command name that match the command line // Skip parts of the command name that match the command line
if (line_it != command_line->cend()) { if (line_it != command_line->cend()) {
@@ -403,7 +412,7 @@ Commands::Completion Commands::complete_command(Shell & shell, const CommandLine
continue; continue;
} }
help->push_back(std::move(read_flash_string(argument))); help->push_back(std::move((argument)));
} }
result.help.push_back(std::move(help)); result.help.push_back(std::move(help));
@@ -416,7 +425,7 @@ Commands::Completion Commands::complete_command(Shell & shell, const CommandLine
if (commands.exact.count(longest->first) == 1) { if (commands.exact.count(longest->first) == 1) {
for (auto & name : longest->second->name_) { for (auto & name : longest->second->name_) {
result.replacement->push_back(std::move(read_flash_string(name))); result.replacement->push_back(std::move((name))); // TODO remove all moves?
} }
// Add a space because there are sub-commands for a command that has matched exactly // Add a space because there are sub-commands for a command that has matched exactly
@@ -449,7 +458,7 @@ Commands::Match Commands::find_command(Shell & shell, const CommandLine & comman
auto line_it = command_line->cbegin(); auto line_it = command_line->cbegin();
for (; name_it != command.name_.cend() && line_it != command_line->cend(); name_it++, line_it++) { for (; name_it != command.name_.cend() && line_it != command_line->cend(); name_it++, line_it++) {
std::string name = read_flash_string(*name_it); std::string name = (*name_it);
size_t found = name.rfind(*line_it, 0); size_t found = name.rfind(*line_it, 0);
if (found == std::string::npos) { if (found == std::string::npos) {
@@ -499,12 +508,12 @@ void Commands::for_each_available_command(Shell & shell, apply_function f) const
name.reserve(command_it->second.name_.size()); name.reserve(command_it->second.name_.size());
for (auto flash_name : command_it->second.name_) { for (auto flash_name : command_it->second.name_) {
name.push_back(std::move(read_flash_string(flash_name))); name.push_back(std::move((flash_name)));
} }
arguments.reserve(command_it->second.arguments_.size()); arguments.reserve(command_it->second.arguments_.size());
for (auto flash_argument : command_it->second.arguments_) { for (auto flash_argument : command_it->second.arguments_) {
arguments.push_back(std::move(read_flash_string(flash_argument))); arguments.push_back(std::move((flash_argument)));
} }
f(name, arguments); f(name, arguments);
@@ -512,7 +521,11 @@ void Commands::for_each_available_command(Shell & shell, apply_function f) const
} }
} }
Commands::Command::Command(unsigned int flags, const flash_string_vector name, const flash_string_vector arguments, command_function function, argument_completion_function arg_function) Commands::Command::Command(unsigned int flags,
const string_vector name,
const string_vector arguments,
command_function function,
argument_completion_function arg_function)
: flags_(flags) : flags_(flags)
, name_(name) , name_(name)
, arguments_(arguments) , arguments_(arguments)
@@ -524,7 +537,7 @@ Commands::Command::~Command() {
} }
size_t Commands::Command::minimum_arguments() const { size_t Commands::Command::minimum_arguments() const {
return std::count_if(arguments_.cbegin(), arguments_.cend(), [](const __FlashStringHelper * argument) { return pgm_read_byte(argument) == '<'; }); return std::count_if(arguments_.cbegin(), arguments_.cend(), [](const char * argument) { return pgm_read_byte(argument) == '<'; });
} }
} // namespace console } // namespace console

View File

@@ -135,8 +135,8 @@ void Shell::loop_one() {
} }
} }
void Shell::set_command_str(const __FlashStringHelper * str) { void Shell::set_command_str(const char * str) {
line_buffer_ = read_flash_string(str); line_buffer_ = (str);
erase_current_line(); erase_current_line();
prompt_displayed_ = false; prompt_displayed_ = false;
display_prompt(); display_prompt();
@@ -262,30 +262,30 @@ void Shell::loop_normal() {
} else if (esc_ == 1) { // pos1 } else if (esc_ == 1) { // pos1
cursor_ = line_buffer_.length(); cursor_ = line_buffer_.length();
} else if (esc_ == 11) { // F1 } else if (esc_ == 11) { // F1
set_command_str(F("help")); set_command_str("help");
} else if (esc_ == 12) { // F2 } else if (esc_ == 12) { // F2
set_command_str(F("show")); set_command_str("show");
} else if (esc_ == 13) { // F3 } else if (esc_ == 13) { // F3
set_command_str(F("log notice")); set_command_str("log notice");
} else if (esc_ == 14) { // F4 } else if (esc_ == 14) { // F4
set_command_str(F("log info")); set_command_str("log info");
} else if (esc_ == 15) { // F5 } else if (esc_ == 15) { // F5
set_command_str(F("log debug")); set_command_str("log debug");
} else if (esc_ == 17) { // F6 } else if (esc_ == 17) { // F6
set_command_str(F("watch off")); set_command_str("watch off");
} else if (esc_ == 18) { // F7 } else if (esc_ == 18) { // F7
set_command_str(F("watch on")); set_command_str("watch on");
} else if (esc_ == 19) { // F8 } else if (esc_ == 19) { // F8
set_command_str(F("watch raw")); set_command_str("watch raw");
} else if (esc_ == 20) { // F9 } else if (esc_ == 20) { // F9
set_command_str(F("call system info")); set_command_str("call system info");
} else if (esc_ == 21) { // F10 } else if (esc_ == 21) { // F10
set_command_str(F("call system settings")); set_command_str("call system settings");
} else if (esc_ == 23) { // F11 } else if (esc_ == 23) { // F11
line_buffer_ = read_flash_string(F("call send \"0B \"")); line_buffer_ = ("call send \"0B \"");
cursor_ = 1; cursor_ = 1;
} else if (esc_ == 24) { // F12 } else if (esc_ == 24) { // F12
set_command_str(F("log debug; watch raw")); set_command_str("log debug; watch raw");
} }
esc_ = 0; esc_ = 0;
} else if (c >= '0' && (c <= '9')) { // numbers } else if (c >= '0' && (c <= '9')) { // numbers
@@ -320,7 +320,7 @@ void Shell::loop_normal() {
idle_time_ = uuid::get_uptime_ms(); idle_time_ = uuid::get_uptime_ms();
} }
Shell::PasswordData::PasswordData(const __FlashStringHelper * password_prompt, password_function && password_function) Shell::PasswordData::PasswordData(const char * password_prompt, password_function && password_function)
: password_prompt_(password_prompt) : password_prompt_(password_prompt)
, password_function_(std::move(password_function)) { , password_function_(std::move(password_function)) {
} }
@@ -452,7 +452,7 @@ void Shell::loop_blocking() {
} }
} }
void Shell::enter_password(const __FlashStringHelper * prompt, password_function function) { void Shell::enter_password(const char * prompt, password_function function) {
if (mode_ == Mode::NORMAL) { if (mode_ == Mode::NORMAL) {
mode_ = Mode::PASSWORD; mode_ = Mode::PASSWORD;
mode_data_ = std::make_unique<Shell::PasswordData>(prompt, std::move(function)); mode_data_ = std::make_unique<Shell::PasswordData>(prompt, std::move(function));

View File

@@ -30,8 +30,8 @@ namespace uuid {
namespace console { namespace console {
static const char __pstr__logger_name[] __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "shell"; static const char __pstr__logger_name[] = "shell";
const uuid::log::Logger Shell::logger_{reinterpret_cast<const __FlashStringHelper *>(__pstr__logger_name), uuid::log::Facility::LPR}; const uuid::log::Logger Shell::logger_{(__pstr__logger_name), uuid::log::Facility::LPR};
Shell::QueuedLogMessage::QueuedLogMessage(unsigned long id, std::shared_ptr<uuid::log::Message> && content) Shell::QueuedLogMessage::QueuedLogMessage(unsigned long id, std::shared_ptr<uuid::log::Message> && content)
: id_(id) : id_(id)

View File

@@ -335,7 +335,7 @@ class Shell : public std::enable_shared_from_this<Shell>, public uuid::log::Hand
* execution. * execution.
* @since 0.1.0 * @since 0.1.0
*/ */
void enter_password(const __FlashStringHelper * prompt, password_function function); void enter_password(const char * prompt, password_function function);
/** /**
* Stop executing anything on this shell for a period of time. * Stop executing anything on this shell for a period of time.
@@ -682,11 +682,11 @@ class Shell : public std::enable_shared_from_this<Shell>, public uuid::log::Hand
* execution. * execution.
* @since 0.1.0 * @since 0.1.0
*/ */
PasswordData(const __FlashStringHelper * password_prompt, password_function && password_function); PasswordData(const char * password_prompt, password_function && password_function);
~PasswordData() override = default; ~PasswordData() override = default;
const __FlashStringHelper * password_prompt_; /*!< Prompt requesting password input. @since 0.1.0 */ const char * password_prompt_; /*!< Prompt requesting password input. @since 0.1.0 */
password_function password_function_; /*!< Function to execute after password entry. @since 0.1.0 */ password_function password_function_; /*!< Function to execute after password entry. @since 0.1.0 */
}; };
/** /**
@@ -761,7 +761,7 @@ class Shell : public std::enable_shared_from_this<Shell>, public uuid::log::Hand
const std::shared_ptr<const uuid::log::Message> content_; /*!< Log message content. @since 0.1.0 */ const std::shared_ptr<const uuid::log::Message> content_; /*!< Log message content. @since 0.1.0 */
}; };
Shell(const Shell &) = delete; Shell(const Shell &) = delete;
Shell & operator=(const Shell &) = delete; Shell & operator=(const Shell &) = delete;
/** /**
@@ -893,7 +893,7 @@ class Shell : public std::enable_shared_from_this<Shell>, public uuid::log::Hand
* @since 0.1.0 * @since 0.1.0
*/ */
size_t vprintf(const __FlashStringHelper * format, va_list ap); size_t vprintf(const __FlashStringHelper * format, va_list ap);
void set_command_str(const __FlashStringHelper * str); void set_command_str(const char * str);
static const uuid::log::Logger logger_; /*!< uuid::log::Logger instance for shells. @since 0.1.0 */ static const uuid::log::Logger logger_; /*!< uuid::log::Logger instance for shells. @since 0.1.0 */
static std::set<std::shared_ptr<Shell>> shells_; /*!< Registered running shells to be executed. @since 0.1.0 */ static std::set<std::shared_ptr<Shell>> shells_; /*!< Registered running shells to be executed. @since 0.1.0 */
@@ -906,7 +906,7 @@ class Shell : public std::enable_shared_from_this<Shell>, public uuid::log::Hand
size_t maximum_log_messages_ = MAX_LOG_MESSAGES; /*!< Maximum command line length in bytes. @since 0.6.0 */ size_t maximum_log_messages_ = MAX_LOG_MESSAGES; /*!< Maximum command line length in bytes. @since 0.6.0 */
std::string line_buffer_; /*!< Command line buffer. Limited to maximum_command_line_length() bytes. @since 0.1.0 */ std::string line_buffer_; /*!< Command line buffer. Limited to maximum_command_line_length() bytes. @since 0.1.0 */
std::string line_old_[MAX_LINES]; /*!< old Command line buffer.*/ std::string line_old_[MAX_LINES]; /*!< old Command line buffer.*/
uint8_t line_no_ = 0; uint8_t line_no_ = 0;
size_t maximum_command_line_length_ = MAX_COMMAND_LINE_LENGTH; /*!< Maximum command line length in bytes. @since 0.6.0 */ size_t maximum_command_line_length_ = MAX_COMMAND_LINE_LENGTH; /*!< Maximum command line length in bytes. @since 0.6.0 */
unsigned char previous_ = 0; /*!< Previous character that was entered on the command line. Used to detect CRLF line endings. @since 0.1.0 */ unsigned char previous_ = 0; /*!< Previous character that was entered on the command line. Used to detect CRLF line endings. @since 0.1.0 */
uint8_t cursor_ = 0; /*!< cursor position from end of line */ uint8_t cursor_ = 0; /*!< cursor position from end of line */
@@ -955,9 +955,9 @@ class CommandLine {
~CommandLine() = default; ~CommandLine() = default;
#ifdef UNIT_TEST #ifdef UNIT_TEST
CommandLine(CommandLine &&) = default; CommandLine(CommandLine &&) = default;
CommandLine & operator=(CommandLine &&) = default; CommandLine & operator=(CommandLine &&) = default;
CommandLine(const CommandLine &) __attribute__((deprecated)) = default; CommandLine(const CommandLine &) __attribute__((deprecated)) = default;
CommandLine & operator=(const CommandLine &) __attribute__((deprecated)) = default; CommandLine & operator=(const CommandLine &) __attribute__((deprecated)) = default;
#endif #endif
@@ -1188,7 +1188,7 @@ class Commands {
* executed. * executed.
* @since 0.2.0 * @since 0.2.0
*/ */
void add_command(const flash_string_vector & name, command_function function); void add_command(const string_vector & name, command_function function);
/** /**
* Add a command with arguments to the list of commands in this * Add a command with arguments to the list of commands in this
* container. * container.
@@ -1205,7 +1205,7 @@ class Commands {
* executed. * executed.
* @since 0.2.0 * @since 0.2.0
*/ */
void add_command(const flash_string_vector & name, const flash_string_vector & arguments, command_function function); void add_command(const string_vector & name, const string_vector & arguments, command_function function);
/** /**
* Add a command with arguments and automatic argument completion * Add a command with arguments and automatic argument completion
* to the list of commands in this container. * to the list of commands in this container.
@@ -1224,7 +1224,7 @@ class Commands {
* completions for this command. * completions for this command.
* @since 0.2.0 * @since 0.2.0
*/ */
void add_command(const flash_string_vector & name, const flash_string_vector & arguments, command_function function, argument_completion_function arg_function); void add_command(const string_vector & name, const string_vector & arguments, command_function function, argument_completion_function arg_function);
/** /**
* Add a command with no arguments to the list of commands in this * Add a command with no arguments to the list of commands in this
* container. * container.
@@ -1239,7 +1239,7 @@ class Commands {
* executed. * executed.
* @since 0.1.0 * @since 0.1.0
*/ */
void add_command(unsigned int context, unsigned int flags, const flash_string_vector & name, command_function function); void add_command(unsigned int context, unsigned int flags, const string_vector & name, command_function function);
/** /**
* Add a command with arguments to the list of commands in this * Add a command with arguments to the list of commands in this
* container. * container.
@@ -1257,7 +1257,7 @@ class Commands {
* executed. * executed.
* @since 0.1.0 * @since 0.1.0
*/ */
void add_command(unsigned int context, unsigned int flags, const flash_string_vector & name, const flash_string_vector & arguments, command_function function); void add_command(unsigned int context, unsigned int flags, const string_vector & name, const string_vector & arguments, command_function function);
/** /**
* Add a command with arguments and automatic argument completion * Add a command with arguments and automatic argument completion
* to the list of commands in this container. * to the list of commands in this container.
@@ -1279,8 +1279,8 @@ class Commands {
*/ */
void add_command(unsigned int context, void add_command(unsigned int context,
unsigned int flags, unsigned int flags,
const flash_string_vector & name, const string_vector & name,
const flash_string_vector & arguments, const string_vector & arguments,
command_function function, command_function function,
argument_completion_function arg_function); argument_completion_function arg_function);
@@ -1344,11 +1344,7 @@ class Commands {
* completions for this command. * completions for this command.
* @since 0.1.0 * @since 0.1.0
*/ */
Command(unsigned int flags, Command(unsigned int flags, const string_vector name, const string_vector arguments, command_function function, argument_completion_function arg_function);
const flash_string_vector name,
const flash_string_vector arguments,
command_function function,
argument_completion_function arg_function);
~Command(); ~Command();
/** /**
@@ -1372,13 +1368,13 @@ class Commands {
} }
unsigned int flags_; /*!< Shell flags that must be set for this command to be available. @since 0.1.0 */ unsigned int flags_; /*!< Shell flags that must be set for this command to be available. @since 0.1.0 */
const flash_string_vector name_; /*!< Name of the command as a std::vector of flash strings. @since 0.1.0 */ const string_vector name_; /*!< Name of the command as a std::vector of flash strings. @since 0.1.0 */
const flash_string_vector arguments_; /*!< Help text for arguments that the command accepts as a std::vector of flash strings. @since 0.1.0 */ const string_vector arguments_; /*!< Help text for arguments that the command accepts as a std::vector of flash strings. @since 0.1.0 */
command_function function_; /*!< Function to be used when the command is executed. @since 0.1.0 */ command_function function_; /*!< Function to be used when the command is executed. @since 0.1.0 */
argument_completion_function arg_function_; /*!< Function to be used to perform argument completions for this command. @since 0.1.0 */ argument_completion_function arg_function_; /*!< Function to be used to perform argument completions for this command. @since 0.1.0 */
private: private:
Command(const Command &) = delete; Command(const Command &) = delete;
Command & operator=(const Command &) = delete; Command & operator=(const Command &) = delete;
}; };
@@ -1487,7 +1483,7 @@ class StreamConsole : virtual public Shell {
explicit StreamConsole(Stream & stream); explicit StreamConsole(Stream & stream);
private: private:
StreamConsole(const StreamConsole &) = delete; StreamConsole(const StreamConsole &) = delete;
StreamConsole & operator=(const StreamConsole &) = delete; StreamConsole & operator=(const StreamConsole &) = delete;
/** /**

View File

@@ -26,17 +26,17 @@ namespace uuid {
namespace log { namespace log {
static constexpr const char * pstr_level_lowercase_off __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "off"; static constexpr const char * pstr_level_lowercase_off = "off";
static constexpr const char * pstr_level_lowercase_emerg __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "emerg"; static constexpr const char * pstr_level_lowercase_emerg = "emerg";
static constexpr const char * pstr_level_lowercase_crit __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "crit"; static constexpr const char * pstr_level_lowercase_crit = "crit";
static constexpr const char * pstr_level_lowercase_alert __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "alert"; static constexpr const char * pstr_level_lowercase_alert = "alert";
static constexpr const char * pstr_level_lowercase_err __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "err"; static constexpr const char * pstr_level_lowercase_err = "err";
static constexpr const char * pstr_level_lowercase_warning __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "warning"; static constexpr const char * pstr_level_lowercase_warning = "warning";
static constexpr const char * pstr_level_lowercase_notice __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "notice"; static constexpr const char * pstr_level_lowercase_notice = "notice";
static constexpr const char * pstr_level_lowercase_info __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "info"; static constexpr const char * pstr_level_lowercase_info = "info";
static constexpr const char * pstr_level_lowercase_debug __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "debug"; static constexpr const char * pstr_level_lowercase_debug = "debug";
static constexpr const char * pstr_level_lowercase_trace __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "trace"; static constexpr const char * pstr_level_lowercase_trace = "trace";
static constexpr const char * pstr_level_lowercase_all __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "all"; static constexpr const char * pstr_level_lowercase_all = "all";
static const __FlashStringHelper * log_level_lowercase[(int)Level::ALL - (int)Level::OFF + 1] __attribute__((__aligned__(sizeof(uint32_t)))) static const __FlashStringHelper * log_level_lowercase[(int)Level::ALL - (int)Level::OFF + 1] __attribute__((__aligned__(sizeof(uint32_t))))
PROGMEM = {reinterpret_cast<const __FlashStringHelper *>(pstr_level_lowercase_off), PROGMEM = {reinterpret_cast<const __FlashStringHelper *>(pstr_level_lowercase_off),

View File

@@ -26,17 +26,17 @@ namespace uuid {
namespace log { namespace log {
static constexpr const char * pstr_level_uppercase_off __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "OFF"; static constexpr const char * pstr_level_uppercase_off = "OFF";
static constexpr const char * pstr_level_uppercase_emerg __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "EMERG"; static constexpr const char * pstr_level_uppercase_emerg = "EMERG";
static constexpr const char * pstr_level_uppercase_crit __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "CRIT"; static constexpr const char * pstr_level_uppercase_crit = "CRIT";
static constexpr const char * pstr_level_uppercase_alert __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "ALERT"; static constexpr const char * pstr_level_uppercase_alert = "ALERT";
static constexpr const char * pstr_level_uppercase_err __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "ERR"; static constexpr const char * pstr_level_uppercase_err = "ERR";
static constexpr const char * pstr_level_uppercase_warning __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "WARNING"; static constexpr const char * pstr_level_uppercase_warning = "WARNING";
static constexpr const char * pstr_level_uppercase_notice __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "NOTICE"; static constexpr const char * pstr_level_uppercase_notice = "NOTICE";
static constexpr const char * pstr_level_uppercase_info __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "INFO"; static constexpr const char * pstr_level_uppercase_info = "INFO";
static constexpr const char * pstr_level_uppercase_debug __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "DEBUG"; static constexpr const char * pstr_level_uppercase_debug = "DEBUG";
static constexpr const char * pstr_level_uppercase_trace __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "TRACE"; static constexpr const char * pstr_level_uppercase_trace = "TRACE";
static constexpr const char * pstr_level_uppercase_all __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "ALL"; static constexpr const char * pstr_level_uppercase_all = "ALL";
static const __FlashStringHelper * log_level_uppercase[(int)Level::ALL - (int)Level::OFF + 1] __attribute__((__aligned__(sizeof(uint32_t)))) static const __FlashStringHelper * log_level_uppercase[(int)Level::ALL - (int)Level::OFF + 1] __attribute__((__aligned__(sizeof(uint32_t))))
PROGMEM = {reinterpret_cast<const __FlashStringHelper *>(pstr_level_uppercase_off), PROGMEM = {reinterpret_cast<const __FlashStringHelper *>(pstr_level_uppercase_off),

View File

@@ -47,7 +47,7 @@ std::string format_timestamp_ms(uint64_t timestamp_ms, unsigned int days_width)
static std::vector<char> text(10 + 1 /* days */ + 2 + 1 /* hours */ + 2 + 1 /* minutes */ + 2 + 1 /* seconds */ + 3 /* milliseconds */ + 1); static std::vector<char> text(10 + 1 /* days */ + 2 + 1 /* hours */ + 2 + 1 /* minutes */ + 2 + 1 /* seconds */ + 3 /* milliseconds */ + 1);
snprintf_P(text.data(), text.size(), PSTR("%0*lu+%02u:%02u:%02u.%03u"), std::min(days_width, 10U), days, hours, minutes, seconds, milliseconds); snprintf(text.data(), text.size(), ("%0*lu+%02u:%02u:%02u.%03u"), std::min(days_width, 10U), days, hours, minutes, seconds, milliseconds);
return text.data(); return text.data();
} }

View File

@@ -36,7 +36,7 @@ namespace log {
std::map<Handler *, Level> Logger::handlers_; std::map<Handler *, Level> Logger::handlers_;
Level Logger::level_ = Level::OFF; Level Logger::level_ = Level::OFF;
Message::Message(uint64_t uptime_ms, Level level, Facility facility, const __FlashStringHelper * name, const std::string && text) Message::Message(uint64_t uptime_ms, Level level, Facility facility, const char * name, const std::string && text)
: uptime_ms(uptime_ms) : uptime_ms(uptime_ms)
, level(level) , level(level)
, facility(facility) , facility(facility)
@@ -44,7 +44,7 @@ Message::Message(uint64_t uptime_ms, Level level, Facility facility, const __Fla
, text(std::move(text)) { , text(std::move(text)) {
} }
Logger::Logger(const __FlashStringHelper * name, Facility facility) Logger::Logger(const char * name, Facility facility)
: name_(name) : name_(name)
, facility_(facility){ , facility_(facility){

View File

@@ -231,7 +231,7 @@ struct Message {
* @param[in] text Log message text. * @param[in] text Log message text.
* @since 1.0.0 * @since 1.0.0
*/ */
Message(uint64_t uptime_ms, Level level, Facility facility, const __FlashStringHelper * name, const std::string && text); Message(uint64_t uptime_ms, Level level, Facility facility, const char * name, const std::string && text);
~Message() = default; ~Message() = default;
/** /**
@@ -261,7 +261,7 @@ struct Message {
* *
* @since 1.0.0 * @since 1.0.0
*/ */
const __FlashStringHelper * name; const char * name;
/** /**
* Formatted log message text. * Formatted log message text.
@@ -331,7 +331,7 @@ class Logger {
* *
* @since 1.0.0 * @since 1.0.0
*/ */
Logger(const __FlashStringHelper * name, Facility facility = Facility::LOCAL0); Logger(const char * name, Facility facility = Facility::LOCAL0);
~Logger() = default; ~Logger() = default;
/** /**
@@ -626,8 +626,8 @@ class Logger {
static std::map<Handler *, Level> handlers_; /*!< Registered log handlers. @since 1.0.0 */ static std::map<Handler *, Level> handlers_; /*!< Registered log handlers. @since 1.0.0 */
static Level level_; /*!< Minimum global log level across all handlers. @since 1.0.0 */ static Level level_; /*!< Minimum global log level across all handlers. @since 1.0.0 */
const __FlashStringHelper * name_; /*!< Logger name (flash string). @since 1.0.0 */ const char * name_; /*!< Logger name (flash string). @since 1.0.0 */
const Facility facility_; /*!< Default logging facility for messages. @since 1.0.0 */ const Facility facility_; /*!< Default logging facility for messages. @since 1.0.0 */
}; };
} // namespace log } // namespace log

View File

@@ -82,13 +82,13 @@
#include <uuid/common.h> #include <uuid/common.h>
#include <uuid/log.h> #include <uuid/log.h>
static const char __pstr__logger_name[] __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "syslog"; static const char __pstr__logger_name[] = "syslog";
namespace uuid { namespace uuid {
namespace syslog { namespace syslog {
uuid::log::Logger SyslogService::logger_{FPSTR(__pstr__logger_name), uuid::log::Facility::SYSLOG}; uuid::log::Logger SyslogService::logger_{__pstr__logger_name, uuid::log::Facility::SYSLOG};
bool SyslogService::QueuedLogMessage::time_good_ = false; bool SyslogService::QueuedLogMessage::time_good_ = false;
SyslogService::~SyslogService() { SyslogService::~SyslogService() {
@@ -116,7 +116,7 @@ void SyslogService::remove_queued_messages(uuid::log::Level level) {
} }
} }
log_message_id_ -= offset; log_message_id_ -= offset;
log_message_fails_ += offset; log_message_fails_ += offset;
} }
@@ -269,8 +269,8 @@ void SyslogService::loop() {
operator<<(std::make_shared<uuid::log::Message>(uuid::get_uptime_ms(), operator<<(std::make_shared<uuid::log::Message>(uuid::get_uptime_ms(),
uuid::log::Level::INFO, uuid::log::Level::INFO,
uuid::log::Facility::SYSLOG, uuid::log::Facility::SYSLOG,
reinterpret_cast<const __FlashStringHelper *>(__pstr__logger_name), (__pstr__logger_name),
uuid::read_flash_string(F("-- MARK --")))); (F("-- MARK --"))));
} }
} }
} }
@@ -443,7 +443,8 @@ bool SyslogService::transmit(const QueuedLogMessage & message) {
udp_.print('-'); udp_.print('-');
} }
udp_.printf_P(PSTR(" %s %s - - - "), hostname_.c_str(), uuid::read_flash_string(message.content_->name).c_str()); // TODO should use flash?
udp_.printf_P(PSTR(" %s %s - - - "), hostname_.c_str(), (message.content_->name));
char id_c_str[15]; char id_c_str[15];
snprintf_P(id_c_str, sizeof(id_c_str), PSTR(" %lu: "), message.id_); snprintf_P(id_c_str, sizeof(id_c_str), PSTR(" %lu: "), message.id_);

View File

@@ -28,329 +28,322 @@ namespace uuid {
namespace telnet { namespace telnet {
TelnetStream::TelnetStream(WiFiClient &client) TelnetStream::TelnetStream(WiFiClient & client)
: client_(client) { : client_(client) {
output_buffer_.reserve(BUFFER_SIZE); output_buffer_.reserve(BUFFER_SIZE);
} }
void TelnetStream::start() { void TelnetStream::start() {
raw_write({ raw_write({IAC, WILL, OPT_ECHO, IAC, WILL, OPT_BINARY, IAC, WILL, OPT_SGA, IAC, DONT, OPT_ECHO, IAC, DO, OPT_BINARY, IAC, DO, OPT_SGA});
IAC, WILL, OPT_ECHO,
IAC, WILL, OPT_BINARY,
IAC, WILL, OPT_SGA,
IAC, DONT, OPT_ECHO,
IAC, DO, OPT_BINARY,
IAC, DO, OPT_SGA
});
} }
int TelnetStream::available() { int TelnetStream::available() {
if (peek() == -1) { if (peek() == -1) {
return 0; return 0;
} else { } else {
return 1; return 1;
} }
} }
int TelnetStream::read() { int TelnetStream::read() {
if (peek_ != -1) { if (peek_ != -1) {
int data = peek_; int data = peek_;
peek_ = -1; peek_ = -1;
return data; return data;
} }
buffer_flush(); buffer_flush();
restart: restart:
int data = raw_read(); int data = raw_read();
if (data == -1) { if (data == -1) {
return -1; return -1;
} }
unsigned char c = data; unsigned char c = data;
if (sub_negotiation_) { if (sub_negotiation_) {
if (previous_raw_in_ == IAC) { if (previous_raw_in_ == IAC) {
switch (c) { switch (c) {
case SE: case SE:
sub_negotiation_ = false; sub_negotiation_ = false;
previous_raw_in_ = 0; previous_raw_in_ = 0;
goto restart; goto restart;
case IAC: case IAC:
previous_raw_in_ = 0; previous_raw_in_ = 0;
goto restart; goto restart;
} }
} else { } else {
switch (c) { switch (c) {
case IAC: case IAC:
previous_raw_in_ = c; previous_raw_in_ = c;
goto restart; goto restart;
default: default:
previous_raw_in_ = 0; previous_raw_in_ = 0;
goto restart; goto restart;
} }
} }
} else { } else {
if (previous_raw_in_ == IAC) { if (previous_raw_in_ == IAC) {
switch (c) { switch (c) {
case IP: case IP:
// Interrupt (^C) // Interrupt (^C)
previous_raw_in_ = 0; previous_raw_in_ = 0;
c = '\x03'; c = '\x03';
break; break;
case EC: case EC:
// Backspace (^H) // Backspace (^H)
previous_raw_in_ = 0; previous_raw_in_ = 0;
c = '\x08'; c = '\x08';
break; break;
case EL: case EL:
// Delete line (^U) // Delete line (^U)
previous_raw_in_ = 0; previous_raw_in_ = 0;
c = '\x15'; c = '\x15';
break; break;
case IAC: case IAC:
previous_raw_in_ = 0; previous_raw_in_ = 0;
break; break;
case SB: case SB:
case WILL: case WILL:
case WONT: case WONT:
case DO: case DO:
case DONT: case DONT:
previous_raw_in_ = c; previous_raw_in_ = c;
goto restart; goto restart;
case SE: case SE:
case DM: case DM:
case BRK: case BRK:
case AO: case AO:
case AYT: case AYT:
case GA: case GA:
case NOP: case NOP:
default: default:
previous_raw_in_ = 0; previous_raw_in_ = 0;
goto restart; goto restart;
} }
} else if (previous_raw_in_ == SB) { } else if (previous_raw_in_ == SB) {
sub_negotiation_ = true; sub_negotiation_ = true;
previous_raw_in_ = 0; previous_raw_in_ = 0;
goto restart; goto restart;
} else if (previous_raw_in_ == WILL || previous_raw_in_ == WONT) { } else if (previous_raw_in_ == WILL || previous_raw_in_ == WONT) {
switch (c) { switch (c) {
case OPT_ECHO: case OPT_ECHO:
// Don't do these // Don't do these
raw_write({IAC, DONT, c}); raw_write({IAC, DONT, c});
break; break;
case OPT_BINARY: case OPT_BINARY:
case OPT_SGA: case OPT_SGA:
// Do these // Do these
raw_write({IAC, DO, c}); raw_write({IAC, DO, c});
break; break;
default: default:
// Don't do anything else // Don't do anything else
raw_write({IAC, DONT, c}); raw_write({IAC, DONT, c});
break; break;
} }
previous_raw_in_ = 0; previous_raw_in_ = 0;
goto restart; goto restart;
} else if (previous_raw_in_ == DO) { } else if (previous_raw_in_ == DO) {
switch (c) { switch (c) {
case OPT_ECHO: case OPT_ECHO:
case OPT_BINARY: case OPT_BINARY:
case OPT_SGA: case OPT_SGA:
// These are always enabled // These are always enabled
break; break;
default: default:
// Refuse to do anything else // Refuse to do anything else
raw_write({IAC, WONT, c}); raw_write({IAC, WONT, c});
break; break;
} }
previous_raw_in_ = 0; previous_raw_in_ = 0;
goto restart; goto restart;
} else if (previous_raw_in_ == DONT) { } else if (previous_raw_in_ == DONT) {
switch (c) { switch (c) {
case OPT_ECHO: case OPT_ECHO:
case OPT_BINARY: case OPT_BINARY:
case OPT_SGA: case OPT_SGA:
// Insist that we do these // Insist that we do these
raw_write({IAC, WILL, c}); raw_write({IAC, WILL, c});
break; break;
default: default:
// Everything else is always disabled // Everything else is always disabled
break; break;
} }
previous_raw_in_ = 0; previous_raw_in_ = 0;
goto restart; goto restart;
} else { } else {
switch (c) { switch (c) {
case IAC: case IAC:
previous_raw_in_ = c; previous_raw_in_ = c;
goto restart; goto restart;
default: default:
previous_raw_in_ = 0; previous_raw_in_ = 0;
break; break;
} }
} }
} }
if (previous_in_ == CR) { if (previous_in_ == CR) {
if (c == NUL) { if (c == NUL) {
previous_in_ = 0; previous_in_ = 0;
goto restart; goto restart;
} }
} }
previous_in_ = c; previous_in_ = c;
return c; return c;
} }
int TelnetStream::peek() { int TelnetStream::peek() {
buffer_flush(); buffer_flush();
// It's too complicated to implement this by calling peek() // It's too complicated to implement this by calling peek()
// on the original stream, especially if the original stream // on the original stream, especially if the original stream
// doesn't actually support peeking. // doesn't actually support peeking.
if (peek_ == -1) { if (peek_ == -1) {
peek_ = read(); peek_ = read();
} }
return peek_; return peek_;
} }
size_t TelnetStream::write(uint8_t data) { size_t TelnetStream::write(uint8_t data) {
if (previous_out_ == CR && data != LF) { if (previous_out_ == CR && data != LF) {
previous_out_ = data; previous_out_ = data;
if (raw_write({NUL, data}) != 2) { if (raw_write({NUL, data}) != 2) {
return 0; return 0;
} }
} else { } else {
previous_out_ = data; previous_out_ = data;
} }
if (data == IAC) { if (data == IAC) {
if (raw_write({IAC, IAC}) != 2) { if (raw_write({IAC, IAC}) != 2) {
return 0; return 0;
} }
} else { } else {
if (raw_write(data) != 1) { if (raw_write(data) != 1) {
return 0; return 0;
} }
} }
return 1; return 1;
} }
size_t TelnetStream::write(const uint8_t *buffer, size_t size) { size_t TelnetStream::write(const uint8_t * buffer, size_t size) {
std::vector<unsigned char> data; std::vector<unsigned char> data;
data.reserve(size); data.reserve(size);
while (size-- > 0) { while (size-- > 0) {
unsigned char c = *buffer++; unsigned char c = *buffer++;
if (previous_out_ == CR && c != LF) { if (previous_out_ == CR && c != LF) {
data.push_back((unsigned char)NUL); data.push_back((unsigned char)NUL);
} }
if (c == IAC) { if (c == IAC) {
data.push_back((unsigned char)IAC); data.push_back((unsigned char)IAC);
} }
previous_out_ = c; previous_out_ = c;
data.push_back(c); data.push_back(c);
} }
size_t len = raw_write(data); size_t len = raw_write(data);
if (len < size) { if (len < size) {
len = 0; len = 0;
} }
return len; return len;
} }
void TelnetStream::flush() { void TelnetStream::flush() {
// This is a pure virtual function in Arduino's Stream class, which // This is a pure virtual function in Arduino's Stream class, which
// makes no sense because that class is for input and this is an // makes no sense because that class is for input and this is an
// output function. Later versions move it to Print as an empty // output function. Later versions move it to Print as an empty
// virtual function so this is here for backward compatibility. // virtual function so this is here for backward compatibility.
} }
int TelnetStream::raw_available() { int TelnetStream::raw_available() {
return client_.available(); return client_.available();
} }
int TelnetStream::raw_read() { int TelnetStream::raw_read() {
return client_.read(); return client_.read();
} }
void TelnetStream::buffer_flush() { void TelnetStream::buffer_flush() {
if (!output_buffer_.empty()) { if (!output_buffer_.empty()) {
size_t len = client_.write(reinterpret_cast<const unsigned char*>(output_buffer_.data()), output_buffer_.size()); size_t len = client_.write(reinterpret_cast<const unsigned char *>(output_buffer_.data()), output_buffer_.size());
if (len != output_buffer_.size()) { if (len != output_buffer_.size()) {
client_.stop(); client_.stop();
} }
output_buffer_.clear(); output_buffer_.clear();
output_buffer_.shrink_to_fit(); output_buffer_.shrink_to_fit();
} }
} }
size_t TelnetStream::raw_write(unsigned char data) { size_t TelnetStream::raw_write(unsigned char data) {
output_buffer_.push_back(data); output_buffer_.push_back(data);
if (output_buffer_.size() >= BUFFER_SIZE) { if (output_buffer_.size() >= BUFFER_SIZE) {
buffer_flush(); buffer_flush();
} }
return 1; return 1;
} }
size_t TelnetStream::raw_write(const std::vector<unsigned char> &data) { size_t TelnetStream::raw_write(const std::vector<unsigned char> & data) {
return raw_write(reinterpret_cast<const unsigned char*>(data.data()), data.size()); return raw_write(reinterpret_cast<const unsigned char *>(data.data()), data.size());
} }
size_t TelnetStream::raw_write(const uint8_t *buffer, size_t size) { size_t TelnetStream::raw_write(const uint8_t * buffer, size_t size) {
size_t offset = 0; size_t offset = 0;
size_t remaining = size; size_t remaining = size;
if (!output_buffer_.empty()) { if (!output_buffer_.empty()) {
// Fill the rest of the buffer // Fill the rest of the buffer
size_t block = std::min(remaining, BUFFER_SIZE - output_buffer_.size()); size_t block = std::min(remaining, BUFFER_SIZE - output_buffer_.size());
output_buffer_.insert(output_buffer_.end(), buffer, buffer + block); output_buffer_.insert(output_buffer_.end(), buffer, buffer + block);
offset += block; offset += block;
remaining -= block; remaining -= block;
if (output_buffer_.size() >= BUFFER_SIZE) { if (output_buffer_.size() >= BUFFER_SIZE) {
buffer_flush(); buffer_flush();
} }
} }
if (remaining >= BUFFER_SIZE) { if (remaining >= BUFFER_SIZE) {
// Output directly if it won't fit in the buffer // Output directly if it won't fit in the buffer
size_t len = client_.write(buffer + offset, remaining); size_t len = client_.write(buffer + offset, remaining);
if (len != remaining) { if (len != remaining) {
client_.stop(); client_.stop();
return offset + len; return offset + len;
} }
} else if (remaining > 0) { } else if (remaining > 0) {
// Put the rest in the buffer // Put the rest in the buffer
output_buffer_.insert(output_buffer_.end(), buffer + offset, buffer + offset + remaining); output_buffer_.insert(output_buffer_.end(), buffer + offset, buffer + offset + remaining);
} }
return size; return size;
} }
} // namespace telnet } // namespace telnet

View File

@@ -54,22 +54,20 @@
#endif #endif
#endif #endif
static const char __pstr__logger_name[] __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "telnet";
namespace uuid { namespace uuid {
namespace telnet { namespace telnet {
uuid::log::Logger TelnetService::logger_{FPSTR(__pstr__logger_name), uuid::log::Facility::DAEMON}; uuid::log::Logger TelnetService::logger_{"telnet", uuid::log::Facility::DAEMON};
TelnetService::TelnetService(std::shared_ptr<uuid::console::Commands> commands, unsigned int context, unsigned int flags) TelnetService::TelnetService(std::shared_ptr<uuid::console::Commands> commands, unsigned int context, unsigned int flags)
: TelnetService(DEFAULT_PORT, commands, context, flags) { : TelnetService(DEFAULT_PORT, commands, context, flags) {
} }
TelnetService::TelnetService(uint16_t port, std::shared_ptr<uuid::console::Commands> commands, unsigned int context, unsigned int flags) TelnetService::TelnetService(uint16_t port, std::shared_ptr<uuid::console::Commands> commands, unsigned int context, unsigned int flags)
: TelnetService(port, [commands, context, flags](Stream & stream, const IPAddress & addr __attribute__((unused)), uint16_t port __attribute__((unused))) -> std::shared_ptr<uuid::console::Shell> { : TelnetService(port,
return std::make_shared<uuid::console::StreamConsole>(commands, stream, context, flags); [commands, context, flags](Stream & stream, const IPAddress & addr __attribute__((unused)), uint16_t port __attribute__((unused)))
}) { -> std::shared_ptr<uuid::console::Shell> { return std::make_shared<uuid::console::StreamConsole>(commands, stream, context, flags); }) {
} }
TelnetService::TelnetService(shell_factory_function shell_factory) TelnetService::TelnetService(shell_factory_function shell_factory)
@@ -145,7 +143,9 @@ void TelnetService::loop() {
if (client) { if (client) {
if (connections_.size() >= maximum_connections_) { if (connections_.size() >= maximum_connections_) {
#if UUID_TELNET_HAVE_WIFICLIENT_REMOTE #if UUID_TELNET_HAVE_WIFICLIENT_REMOTE
logger_.info(F("New connection from [%s]:%u rejected (connection limit reached)"), uuid::printable_to_string(client.remoteIP()).c_str(), client.remotePort()); logger_.info(F("New connection from [%s]:%u rejected (connection limit reached)"),
uuid::printable_to_string(client.remoteIP()).c_str(),
client.remotePort());
#else #else
logger_.info(F("New connection rejected (connection limit reached)")); logger_.info(F("New connection rejected (connection limit reached)"));
#endif #endif

View File

@@ -21,9 +21,9 @@
#include <Arduino.h> #include <Arduino.h>
#ifdef ARDUINO_ARCH_ESP8266 #ifdef ARDUINO_ARCH_ESP8266
# include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#else #else
# include <WiFi.h> #include <WiFi.h>
#endif #endif
#include <WiFiUdp.h> #include <WiFiUdp.h>
@@ -51,47 +51,47 @@ namespace telnet {
* *
* @since 0.1.0 * @since 0.1.0
*/ */
class TelnetStream: public ::Stream { class TelnetStream : public ::Stream {
public: public:
/** /**
* Create a new telnet stream wrapper. * Create a new telnet stream wrapper.
* *
* @param[in] client Client connection. * @param[in] client Client connection.
* @since 0.1.0 * @since 0.1.0
*/ */
explicit TelnetStream(WiFiClient &client); explicit TelnetStream(WiFiClient & client);
virtual ~TelnetStream() = default; virtual ~TelnetStream() = default;
/** /**
* Perform initial negotiation. * Perform initial negotiation.
* *
* @since 0.1.0 * @since 0.1.0
*/ */
void start(); void start();
/** /**
* Check for available input. * Check for available input.
* *
* @return The number of bytes available to read. * @return The number of bytes available to read.
* @since 0.1.0 * @since 0.1.0
*/ */
int available() override; int available() override;
/** /**
* Read one byte from the available input. * Read one byte from the available input.
* *
* @return An unsigned char if input is available, otherwise -1. * @return An unsigned char if input is available, otherwise -1.
* @since 0.1.0 * @since 0.1.0
*/ */
int read() override; int read() override;
/** /**
* Read one byte from the available input without advancing to the * Read one byte from the available input without advancing to the
* next one. * next one.
* *
* @return An unsigned char if input is available, otherwise -1. * @return An unsigned char if input is available, otherwise -1.
* @since 0.1.0 * @since 0.1.0
*/ */
int peek() override; int peek() override;
/** /**
* Write one byte to the output stream. * Write one byte to the output stream.
* *
* Disconnect the client if the socket buffer is full. * Disconnect the client if the socket buffer is full.
@@ -100,8 +100,8 @@ public:
* @return The number of bytes that were output. * @return The number of bytes that were output.
* @since 0.1.0 * @since 0.1.0
*/ */
size_t write(uint8_t data) override; size_t write(uint8_t data) override;
/** /**
* Write an array of bytes to the output stream. * Write an array of bytes to the output stream.
* *
* Disconnect the client if the socket buffer is full. * Disconnect the client if the socket buffer is full.
@@ -111,8 +111,8 @@ public:
* @return The number of bytes that were output. * @return The number of bytes that were output.
* @since 0.1.0 * @since 0.1.0
*/ */
size_t write(const uint8_t *buffer, size_t size) override; size_t write(const uint8_t * buffer, size_t size) override;
/** /**
* Does nothing. * Does nothing.
* *
* This is a pure virtual function in Arduino's Stream class, which * This is a pure virtual function in Arduino's Stream class, which
@@ -122,66 +122,69 @@ public:
* *
* @since 0.1.0 * @since 0.1.0
*/ */
void flush() override; void flush() override;
private: private:
static constexpr const unsigned char NUL = 0; /*!< No operation. @since 0.1.0 */ static constexpr const unsigned char NUL = 0; /*!< No operation. @since 0.1.0 */
static constexpr const unsigned char BEL = 7; /*!< Produces an audible or visible signal. @since 0.1.0 */ static constexpr const unsigned char BEL = 7; /*!< Produces an audible or visible signal. @since 0.1.0 */
static constexpr const unsigned char BS = 8; /*!< Moves the print head one character position towards the left margin. @since 0.1.0 */ static constexpr const unsigned char BS = 8; /*!< Moves the print head one character position towards the left margin. @since 0.1.0 */
static constexpr const unsigned char HT = 9; /*!< Moves the printer to the next horizontal tab stop. @since 0.1.0 */ static constexpr const unsigned char HT = 9; /*!< Moves the printer to the next horizontal tab stop. @since 0.1.0 */
static constexpr const unsigned char LF = 10; /*!< Line Feed. @since 0.1.0 */ static constexpr const unsigned char LF = 10; /*!< Line Feed. @since 0.1.0 */
static constexpr const unsigned char VT = 11; /*!< Moves the printer to the next vertical tab stop. @since 0.1.0 */ static constexpr const unsigned char VT = 11; /*!< Moves the printer to the next vertical tab stop. @since 0.1.0 */
static constexpr const unsigned char FF = 12; /*!< Moves the printer to the top of the next page, keeping the same horizontal position. @since 0.1.0 */ static constexpr const unsigned char FF = 12; /*!< Moves the printer to the top of the next page, keeping the same horizontal position. @since 0.1.0 */
static constexpr const unsigned char CR = 13; /*!< Carriage Return. @since 0.1.0 */ static constexpr const unsigned char CR = 13; /*!< Carriage Return. @since 0.1.0 */
static constexpr const unsigned char SE = 240; /*!< End of sub-negotiation parameters. @since 0.1.0 */ static constexpr const unsigned char SE = 240; /*!< End of sub-negotiation parameters. @since 0.1.0 */
static constexpr const unsigned char NOP = 241; /*!< No operation. @since 0.1.0 */ static constexpr const unsigned char NOP = 241; /*!< No operation. @since 0.1.0 */
static constexpr const unsigned char DM = 242; /*!< The data stream portion of a Synch. @since 0.1.0 */ static constexpr const unsigned char DM = 242; /*!< The data stream portion of a Synch. @since 0.1.0 */
static constexpr const unsigned char BRK = 243; /*!< NVT character BRK. @since 0.1.0 */ static constexpr const unsigned char BRK = 243; /*!< NVT character BRK. @since 0.1.0 */
static constexpr const unsigned char IP = 244; /*!< Interrupt Process function. @since 0.1.0 */ static constexpr const unsigned char IP = 244; /*!< Interrupt Process function. @since 0.1.0 */
static constexpr const unsigned char AO = 245; /*!< Abort Output function. @since 0.1.0 */ static constexpr const unsigned char AO = 245; /*!< Abort Output function. @since 0.1.0 */
static constexpr const unsigned char AYT = 246; /*!< Are You There function. @since 0.1.0 */ static constexpr const unsigned char AYT = 246; /*!< Are You There function. @since 0.1.0 */
static constexpr const unsigned char EC = 247; /*!< Erase Character function. @since 0.1.0 */ static constexpr const unsigned char EC = 247; /*!< Erase Character function. @since 0.1.0 */
static constexpr const unsigned char EL = 248; /*!< Erase Line function. @since 0.1.0 */ static constexpr const unsigned char EL = 248; /*!< Erase Line function. @since 0.1.0 */
static constexpr const unsigned char GA = 249; /*!< Go Ahead signal. @since 0.1.0 */ static constexpr const unsigned char GA = 249; /*!< Go Ahead signal. @since 0.1.0 */
static constexpr const unsigned char SB = 250; /*!< Sub-negotiation of the indicated option. @since 0.1.0 */ static constexpr const unsigned char SB = 250; /*!< Sub-negotiation of the indicated option. @since 0.1.0 */
static constexpr const unsigned char WILL = 251; /*!< Indicates the desire to begin performing, or confirmation that you are now performing, the indicated option. @since 0.1.0 */ static constexpr const unsigned char WILL =
static constexpr const unsigned char WONT = 252; /*!< Indicates the refusal to perform, or continue performing, the indicated option. @since 0.1.0 */ 251; /*!< Indicates the desire to begin performing, or confirmation that you are now performing, the indicated option. @since 0.1.0 */
static constexpr const unsigned char DO = 253; /*!< Indicates the request that the other party perform, or confirmation that you are expecting the other party to perform, the indicated option. @since 0.1.0 */ static constexpr const unsigned char WONT = 252; /*!< Indicates the refusal to perform, or continue performing, the indicated option. @since 0.1.0 */
static constexpr const unsigned char DONT = 254; /*!< Indicates the demand that the other party stop performing, or confirmation that you are no longer expecting the other party to perform, the indicated option. @since 0.1.0 */ static constexpr const unsigned char DO =
static constexpr const unsigned char IAC = 255; /*!< Interpret As Command escape character. @since 0.1.0 */ 253; /*!< Indicates the request that the other party perform, or confirmation that you are expecting the other party to perform, the indicated option. @since 0.1.0 */
static constexpr const unsigned char DONT =
254; /*!< Indicates the demand that the other party stop performing, or confirmation that you are no longer expecting the other party to perform, the indicated option. @since 0.1.0 */
static constexpr const unsigned char IAC = 255; /*!< Interpret As Command escape character. @since 0.1.0 */
static constexpr const unsigned char OPT_BINARY = 0; /*!< Binary (8-bit) transmission mode. (RFC 856). @since 0.1.0 */ static constexpr const unsigned char OPT_BINARY = 0; /*!< Binary (8-bit) transmission mode. (RFC 856). @since 0.1.0 */
static constexpr const unsigned char OPT_ECHO = 1; /*!< Remote Echo (RFC 857). @since 0.1.0 */ static constexpr const unsigned char OPT_ECHO = 1; /*!< Remote Echo (RFC 857). @since 0.1.0 */
static constexpr const unsigned char OPT_SGA = 3; /*!< Suppress Go Ahead (RFC 858). @since 0.1.0 */ static constexpr const unsigned char OPT_SGA = 3; /*!< Suppress Go Ahead (RFC 858). @since 0.1.0 */
static constexpr const size_t BUFFER_SIZE = 536; /*!< Output buffer size. @since 0.1.0 */ static constexpr const size_t BUFFER_SIZE = 536; /*!< Output buffer size. @since 0.1.0 */
TelnetStream(const TelnetStream&) = delete; TelnetStream(const TelnetStream &) = delete;
TelnetStream& operator=(const TelnetStream&) = delete; TelnetStream & operator=(const TelnetStream &) = delete;
/** /**
* Directly check for available input. * Directly check for available input.
* *
* @return The number of bytes available to read. * @return The number of bytes available to read.
* @since 0.1.0 * @since 0.1.0
*/ */
int raw_available(); int raw_available();
/** /**
* Read one byte directly from the available input. * Read one byte directly from the available input.
* *
* @return An unsigned char if input is available, otherwise -1. * @return An unsigned char if input is available, otherwise -1.
* @since 0.1.0 * @since 0.1.0
*/ */
int raw_read(); int raw_read();
/** /**
* Flush output stream buffer. * Flush output stream buffer.
* *
* Disconnect the client if the socket buffer is full. * Disconnect the client if the socket buffer is full.
* *
* @since 0.1.0 * @since 0.1.0
*/ */
void buffer_flush(); void buffer_flush();
/** /**
* Write one byte directly to the output stream. * Write one byte directly to the output stream.
* *
* Disconnect the client if the socket buffer is full. * Disconnect the client if the socket buffer is full.
@@ -190,8 +193,8 @@ private:
* @return The number of bytes that were output. * @return The number of bytes that were output.
* @since 0.1.0 * @since 0.1.0
*/ */
size_t raw_write(unsigned char data); size_t raw_write(unsigned char data);
/** /**
* Write a vector of bytes directly to the output stream. * Write a vector of bytes directly to the output stream.
* *
* Disconnect the client if the socket buffer is full. * Disconnect the client if the socket buffer is full.
@@ -200,8 +203,8 @@ private:
* @return The number of bytes that were output. * @return The number of bytes that were output.
* @since 0.1.0 * @since 0.1.0
*/ */
size_t raw_write(const std::vector<unsigned char> &data); size_t raw_write(const std::vector<unsigned char> & data);
/** /**
* Write an array of bytes directly to the output stream. * Write an array of bytes directly to the output stream.
* *
* Disconnect the client if the socket buffer is full. * Disconnect the client if the socket buffer is full.
@@ -211,15 +214,15 @@ private:
* @return The number of bytes that were output. * @return The number of bytes that were output.
* @since 0.1.0 * @since 0.1.0
*/ */
size_t raw_write(const uint8_t *buffer, size_t size); size_t raw_write(const uint8_t * buffer, size_t size);
WiFiClient &client_; /*!< Client connection. @since 0.1.0 */ WiFiClient & client_; /*!< Client connection. @since 0.1.0 */
unsigned char previous_raw_in_ = 0; /*!< Previous raw character that was received. Used to detect commands. @since 0.1.0 */ unsigned char previous_raw_in_ = 0; /*!< Previous raw character that was received. Used to detect commands. @since 0.1.0 */
bool sub_negotiation_ = false; /*!< Sub-negotiation mode. @since 0.1.0 */ bool sub_negotiation_ = false; /*!< Sub-negotiation mode. @since 0.1.0 */
unsigned char previous_in_ = 0; /*!< Previous character that was received. Used to detect CR NUL. @since 0.1.0 */ unsigned char previous_in_ = 0; /*!< Previous character that was received. Used to detect CR NUL. @since 0.1.0 */
unsigned char previous_out_ = 0; /*!< Previous character that was sent. Used to insert NUL after CR without LF. @since 0.1.0 */ unsigned char previous_out_ = 0; /*!< Previous character that was sent. Used to insert NUL after CR without LF. @since 0.1.0 */
int peek_ = -1; /*!< Previously read data cached by peek(). @since 0.1.0 */ int peek_ = -1; /*!< Previously read data cached by peek(). @since 0.1.0 */
std::vector<char> output_buffer_; /*!< Buffer data to be output until a read function is called. @since 0.1.0 */ std::vector<char> output_buffer_; /*!< Buffer data to be output until a read function is called. @since 0.1.0 */
}; };
/** /**
@@ -228,13 +231,13 @@ private:
* @since 0.1.0 * @since 0.1.0
*/ */
class TelnetService { class TelnetService {
public: public:
static constexpr size_t MAX_CONNECTIONS = 3; /*!< Maximum number of concurrent open connections. @since 0.1.0 */ static constexpr size_t MAX_CONNECTIONS = 3; /*!< Maximum number of concurrent open connections. @since 0.1.0 */
static constexpr uint16_t DEFAULT_PORT = 23; /*!< Default TCP port to listen on. @since 0.1.0 */ static constexpr uint16_t DEFAULT_PORT = 23; /*!< Default TCP port to listen on. @since 0.1.0 */
static constexpr unsigned long DEFAULT_IDLE_TIMEOUT = 600; /*!< Default initial idle timeout (in seconds). @since 0.1.0 */ static constexpr unsigned long DEFAULT_IDLE_TIMEOUT = 600; /*!< Default initial idle timeout (in seconds). @since 0.1.0 */
static constexpr unsigned long DEFAULT_WRITE_TIMEOUT = 0; /*!< Default write timeout (in milliseconds). @ since 0.1.0 */ static constexpr unsigned long DEFAULT_WRITE_TIMEOUT = 0; /*!< Default write timeout (in milliseconds). @ since 0.1.0 */
/** /**
* Function to handle the creation of a shell. * Function to handle the creation of a shell.
* *
* @param[in] stream Stream for the telnet connection. * @param[in] stream Stream for the telnet connection.
@@ -242,9 +245,9 @@ public:
* @param[in] port Remote port. * @param[in] port Remote port.
* @since 0.1.0 * @since 0.1.0
*/ */
using shell_factory_function = std::function<std::shared_ptr<uuid::console::Shell>(Stream &stream, const IPAddress &addr, uint16_t port)>; using shell_factory_function = std::function<std::shared_ptr<uuid::console::Shell>(Stream & stream, const IPAddress & addr, uint16_t port)>;
/** /**
* Create a new telnet service listening on the default port. * Create a new telnet service listening on the default port.
* *
* @param[in] commands Commands available for execution in shells. * @param[in] commands Commands available for execution in shells.
@@ -252,9 +255,9 @@ public:
* @param[in] flags Initial flags for shells. * @param[in] flags Initial flags for shells.
* @since 0.1.0 * @since 0.1.0
*/ */
TelnetService(std::shared_ptr<uuid::console::Commands> commands, unsigned int context = 0, unsigned int flags = 0); TelnetService(std::shared_ptr<uuid::console::Commands> commands, unsigned int context = 0, unsigned int flags = 0);
/** /**
* Create a new telnet service listening on a specific port. * Create a new telnet service listening on a specific port.
* *
* @param[in] port TCP listening port. * @param[in] port TCP listening port.
@@ -263,74 +266,74 @@ public:
* @param[in] flags Initial flags for shells. * @param[in] flags Initial flags for shells.
* @since 0.1.0 * @since 0.1.0
*/ */
TelnetService(uint16_t port, std::shared_ptr<uuid::console::Commands> commands, unsigned int context = 0, unsigned int flags = 0); TelnetService(uint16_t port, std::shared_ptr<uuid::console::Commands> commands, unsigned int context = 0, unsigned int flags = 0);
/** /**
* Create a new telnet service listening on the default port. * Create a new telnet service listening on the default port.
* *
* @param[in] shell_factory Function to create a shell for new connections. * @param[in] shell_factory Function to create a shell for new connections.
* @since 0.1.0 * @since 0.1.0
*/ */
explicit TelnetService(shell_factory_function shell_factory); explicit TelnetService(shell_factory_function shell_factory);
/** /**
* Create a new telnet service listening on a specific port. * Create a new telnet service listening on a specific port.
* *
* @param[in] port TCP listening port. * @param[in] port TCP listening port.
* @param[in] shell_factory Function to create a shell for new connections. * @param[in] shell_factory Function to create a shell for new connections.
* @since 0.1.0 * @since 0.1.0
*/ */
TelnetService(uint16_t port, shell_factory_function shell_factory); TelnetService(uint16_t port, shell_factory_function shell_factory);
~TelnetService() = default; ~TelnetService() = default;
/** /**
* Start listening for connections on the configured port. * Start listening for connections on the configured port.
* *
* @since 0.1.0 * @since 0.1.0
*/ */
void start(); void start();
/** /**
* Close all connections. * Close all connections.
* *
* The listening status is not affected. * The listening status is not affected.
* *
* @since 0.1.0 * @since 0.1.0
*/ */
void close_all(); void close_all();
/** /**
* Stop listening for connections. * Stop listening for connections.
* *
* Existing connections are not affected. * Existing connections are not affected.
* *
* @since 0.1.0 * @since 0.1.0
*/ */
void stop(); void stop();
/** /**
* Get the maximum number of concurrent open connections. * Get the maximum number of concurrent open connections.
* *
* @return The maximum number of concurrent open connections. * @return The maximum number of concurrent open connections.
* @since 0.1.0 * @since 0.1.0
*/ */
size_t maximum_connections() const; size_t maximum_connections() const;
/** /**
* Set the maximum number of concurrent open connections. * Set the maximum number of concurrent open connections.
* *
* Defaults to TelnetService::MAX_CONNECTIONS. * Defaults to TelnetService::MAX_CONNECTIONS.
* *
* @since 0.1.0 * @since 0.1.0
*/ */
void maximum_connections(size_t count); void maximum_connections(size_t count);
/** /**
* Get the initial idle timeout for new connections. * Get the initial idle timeout for new connections.
* *
* @return The initial idle timeout in seconds (or 0 for disabled). * @return The initial idle timeout in seconds (or 0 for disabled).
* @since 0.1.0 * @since 0.1.0
*/ */
unsigned long initial_idle_timeout() const; unsigned long initial_idle_timeout() const;
/** /**
* Set the initial idle timeout for new connections. * Set the initial idle timeout for new connections.
* *
* Defaults to TelnetService::DEFAULT_IDLE_TIMEOUT. * Defaults to TelnetService::DEFAULT_IDLE_TIMEOUT.
@@ -338,17 +341,17 @@ public:
* @param[in] timeout Idle timeout in seconds (or 0 to disable). * @param[in] timeout Idle timeout in seconds (or 0 to disable).
* @since 0.1.0 * @since 0.1.0
*/ */
void initial_idle_timeout(unsigned long timeout); void initial_idle_timeout(unsigned long timeout);
/** /**
* Get the default socket write timeout for new connections. * Get the default socket write timeout for new connections.
* *
* @return The default socket write timeout in seconds (or 0 for * @return The default socket write timeout in seconds (or 0 for
* platform default). * platform default).
* @since 0.1.0 * @since 0.1.0
*/ */
unsigned long default_write_timeout() const; unsigned long default_write_timeout() const;
/** /**
* Set the default socket write timeout for new connections. * Set the default socket write timeout for new connections.
* *
* Defaults to TelnetService::DEFAULT_WRITE_TIMEOUT (platform * Defaults to TelnetService::DEFAULT_WRITE_TIMEOUT (platform
@@ -358,26 +361,26 @@ public:
* platform default). * platform default).
* @since 0.1.0 * @since 0.1.0
*/ */
void default_write_timeout(unsigned long timeout); void default_write_timeout(unsigned long timeout);
/** /**
* Accept new connections. * Accept new connections.
* *
* @since 0.1.0 * @since 0.1.0
*/ */
void loop(); void loop();
private: private:
/** /**
* Telnet connection. * Telnet connection.
* *
* Holds the client and stream instance for the lifetime of the shell. * Holds the client and stream instance for the lifetime of the shell.
* *
* @since 0.1.0 * @since 0.1.0
*/ */
class Connection { class Connection {
public: public:
/** /**
* Create a telnet connection shell. * Create a telnet connection shell.
* *
* @param[in] shell_factory Function to create a shell for new connections. * @param[in] shell_factory Function to create a shell for new connections.
@@ -386,52 +389,52 @@ private:
* @param[in] write_timeout Idle timeout in milliseconds. * @param[in] write_timeout Idle timeout in milliseconds.
* @since 0.1.0 * @since 0.1.0
*/ */
Connection(shell_factory_function &shell_factory, WiFiClient &&client, unsigned long idle_timeout, unsigned long write_timeout); Connection(shell_factory_function & shell_factory, WiFiClient && client, unsigned long idle_timeout, unsigned long write_timeout);
~Connection() = default; ~Connection() = default;
/** /**
* Check if the shell is still active. * Check if the shell is still active.
* *
* @return Active status of the shell. * @return Active status of the shell.
* @since 0.1.0 * @since 0.1.0
*/ */
bool active(); bool active();
/** /**
* Stop the shell if the client is not connected. * Stop the shell if the client is not connected.
* *
* @return Active status of the shell. * @return Active status of the shell.
* @since 0.1.0 * @since 0.1.0
*/ */
bool loop(); bool loop();
/** /**
* Stop the shell. * Stop the shell.
* *
* @since 0.1.0 * @since 0.1.0
*/ */
void stop(); void stop();
private: private:
Connection(const Connection&) = delete; Connection(const Connection &) = delete;
Connection& operator=(const Connection&) = delete; Connection & operator=(const Connection &) = delete;
WiFiClient client_; /*!< Client connection. @since 0.1.0 */ WiFiClient client_; /*!< Client connection. @since 0.1.0 */
TelnetStream stream_; /*!< Telnet stream for the connection. @since 0.1.0 */ TelnetStream stream_; /*!< Telnet stream for the connection. @since 0.1.0 */
std::shared_ptr<uuid::console::Shell> shell_; /*!< Shell for connection. @since 0.1.0 */ std::shared_ptr<uuid::console::Shell> shell_; /*!< Shell for connection. @since 0.1.0 */
IPAddress addr_; /*!< Remote address of connection. @since 0.1.0 */ IPAddress addr_; /*!< Remote address of connection. @since 0.1.0 */
uint16_t port_; /*!< Remote port of connection. @since 0.1.0 */ uint16_t port_; /*!< Remote port of connection. @since 0.1.0 */
}; };
TelnetService(const TelnetService&) = delete; TelnetService(const TelnetService &) = delete;
TelnetService& operator=(const TelnetService&) = delete; TelnetService & operator=(const TelnetService &) = delete;
static uuid::log::Logger logger_; /*!< uuid::log::Logger instance for telnet services. @since 0.1.0 */ static uuid::log::Logger logger_; /*!< uuid::log::Logger instance for telnet services. @since 0.1.0 */
WiFiServer server_; /*!< TCP server. @since 0.1.0 */ WiFiServer server_; /*!< TCP server. @since 0.1.0 */
size_t maximum_connections_ = MAX_CONNECTIONS; /*!< Maximum number of concurrent open connections. @since 0.1.0 */ size_t maximum_connections_ = MAX_CONNECTIONS; /*!< Maximum number of concurrent open connections. @since 0.1.0 */
std::list<Connection> connections_; /*!< Open connections. @since 0.1.0 */ std::list<Connection> connections_; /*!< Open connections. @since 0.1.0 */
shell_factory_function shell_factory_; /*!< Function to create a shell. @since 0.1.0 */ shell_factory_function shell_factory_; /*!< Function to create a shell. @since 0.1.0 */
unsigned long initial_idle_timeout_ = DEFAULT_IDLE_TIMEOUT; /*!< Initial idle timeout (in seconds). @since 0.1.0 */ unsigned long initial_idle_timeout_ = DEFAULT_IDLE_TIMEOUT; /*!< Initial idle timeout (in seconds). @since 0.1.0 */
unsigned long write_timeout_ = DEFAULT_WRITE_TIMEOUT; /*!< Write timeout (in milliseconds). @since 0.1.0 */ unsigned long write_timeout_ = DEFAULT_WRITE_TIMEOUT; /*!< Write timeout (in milliseconds). @since 0.1.0 */
}; };
} // namespace telnet } // namespace telnet

View File

@@ -68,11 +68,10 @@ void ledcWrite(uint8_t chan, uint32_t duty);
#define PROGMEM #define PROGMEM
#define PGM_P const char * #define PGM_P const char *
#define PSTR(s) s
class __FlashStringHelper; class __FlashStringHelper;
#define FPSTR(string_literal) (reinterpret_cast<const __FlashStringHelper *>(string_literal)) #define FPSTR(string_literal) (reinterpret_cast<const __FlashStringHelper *>(string_literal))
#define F(string_literal) (FPSTR(PSTR(string_literal))) #define F(string_literal) (FPSTR((string_literal)))
int snprintf_P(char * str, size_t size, const char * format, ...); int snprintf_P(char * str, size_t size, const char * format, ...);
int vsnprintf_P(char * str, size_t size, const char * format, va_list ap); int vsnprintf_P(char * str, size_t size, const char * format, va_list ap);
@@ -97,7 +96,7 @@ class Print {
virtual size_t write(uint8_t c) = 0; virtual size_t write(uint8_t c) = 0;
virtual size_t write(const uint8_t * buffer, size_t size) = 0; virtual size_t write(const uint8_t * buffer, size_t size) = 0;
size_t print(char c) { size_t print(char c) {
return write((uint8_t)c); return write((uint8_t)c);
} }
size_t print(const char * data) { size_t print(const char * data) {
return write(reinterpret_cast<const uint8_t *>(data), strlen(data)); return write(reinterpret_cast<const uint8_t *>(data), strlen(data));

View File

@@ -26,12 +26,12 @@ struct AsyncMqttClientMessageProperties {
namespace AsyncMqttClientInternals { namespace AsyncMqttClientInternals {
typedef std::function<void(bool sessionPresent)> OnConnectUserCallback; typedef std::function<void(bool sessionPresent)> OnConnectUserCallback;
typedef std::function<void(AsyncMqttClientDisconnectReason reason)> OnDisconnectUserCallback; typedef std::function<void(AsyncMqttClientDisconnectReason reason)> OnDisconnectUserCallback;
typedef std::function<void(uint16_t packetId, uint8_t qos)> OnSubscribeUserCallback; typedef std::function<void(uint16_t packetId, uint8_t qos)> OnSubscribeUserCallback;
typedef std::function<void(uint16_t packetId)> OnUnsubscribeUserCallback; typedef std::function<void(uint16_t packetId)> OnUnsubscribeUserCallback;
typedef std::function<void(char * topic, char * payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total)> OnMessageUserCallback; typedef std::function<void(char * topic, char * payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total)> OnMessageUserCallback;
typedef std::function<void(uint16_t packetId)> OnPublishUserCallback; typedef std::function<void(uint16_t packetId)> OnPublishUserCallback;
}; // namespace AsyncMqttClientInternals }; // namespace AsyncMqttClientInternals
class AsyncMqttClient { class AsyncMqttClient {

View File

@@ -13,120 +13,111 @@
template <class T> template <class T>
class HttpGetEndpoint { class HttpGetEndpoint {
public: public:
HttpGetEndpoint(JsonStateReader<T> stateReader, HttpGetEndpoint(JsonStateReader<T> stateReader,
StatefulService<T>* statefulService, StatefulService<T> * statefulService,
AsyncWebServer* server, AsyncWebServer * server,
const String& servicePath, const String & servicePath,
SecurityManager* securityManager, SecurityManager * securityManager,
AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN, AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN,
size_t bufferSize = DEFAULT_BUFFER_SIZE) : size_t bufferSize = DEFAULT_BUFFER_SIZE)
_stateReader(stateReader), _statefulService(statefulService), _bufferSize(bufferSize) { : _stateReader(stateReader)
} , _statefulService(statefulService)
, _bufferSize(bufferSize) {
}
HttpGetEndpoint(JsonStateReader<T> stateReader, HttpGetEndpoint(JsonStateReader<T> stateReader,
StatefulService<T>* statefulService, StatefulService<T> * statefulService,
AsyncWebServer* server, AsyncWebServer * server,
const String& servicePath, const String & servicePath,
size_t bufferSize = DEFAULT_BUFFER_SIZE) : size_t bufferSize = DEFAULT_BUFFER_SIZE)
_stateReader(stateReader), _statefulService(statefulService), _bufferSize(bufferSize) { : _stateReader(stateReader)
} , _statefulService(statefulService)
, _bufferSize(bufferSize) {
}
protected: protected:
JsonStateReader<T> _stateReader; JsonStateReader<T> _stateReader;
StatefulService<T>* _statefulService; StatefulService<T> * _statefulService;
size_t _bufferSize; size_t _bufferSize;
void fetchSettings(AsyncWebServerRequest* request) { void fetchSettings(AsyncWebServerRequest * request) {
} }
}; };
template <class T> template <class T>
class HttpPostEndpoint { class HttpPostEndpoint {
public: public:
HttpPostEndpoint(JsonStateReader<T> stateReader, HttpPostEndpoint(JsonStateReader<T> stateReader,
JsonStateUpdater<T> stateUpdater, JsonStateUpdater<T> stateUpdater,
StatefulService<T>* statefulService, StatefulService<T> * statefulService,
AsyncWebServer* server, AsyncWebServer * server,
const String& servicePath, const String & servicePath,
SecurityManager* securityManager, SecurityManager * securityManager,
AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN, AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN,
size_t bufferSize = DEFAULT_BUFFER_SIZE) : size_t bufferSize = DEFAULT_BUFFER_SIZE)
_stateReader(stateReader), : _stateReader(stateReader)
_stateUpdater(stateUpdater), , _stateUpdater(stateUpdater)
_statefulService(statefulService), , _statefulService(statefulService)
_bufferSize(bufferSize) { , _bufferSize(bufferSize) {
}
HttpPostEndpoint(JsonStateReader<T> stateReader,
JsonStateUpdater<T> stateUpdater,
StatefulService<T>* statefulService,
AsyncWebServer* server,
const String& servicePath,
size_t bufferSize = DEFAULT_BUFFER_SIZE) :
_stateReader(stateReader),
_stateUpdater(stateUpdater),
_statefulService(statefulService),
_bufferSize(bufferSize) {
}
protected:
JsonStateReader<T> _stateReader;
JsonStateUpdater<T> _stateUpdater;
StatefulService<T>* _statefulService;
size_t _bufferSize;
void updateSettings(AsyncWebServerRequest* request, JsonVariant& json) {
if (!json.is<JsonObject>()) {
return;
} }
JsonObject jsonObject = json.as<JsonObject>();
StateUpdateResult outcome = _statefulService->updateWithoutPropagation(jsonObject, _stateUpdater); HttpPostEndpoint(JsonStateReader<T> stateReader,
if (outcome == StateUpdateResult::ERROR) { JsonStateUpdater<T> stateUpdater,
return; StatefulService<T> * statefulService,
AsyncWebServer * server,
const String & servicePath,
size_t bufferSize = DEFAULT_BUFFER_SIZE)
: _stateReader(stateReader)
, _stateUpdater(stateUpdater)
, _statefulService(statefulService)
, _bufferSize(bufferSize) {
} }
if (outcome == StateUpdateResult::CHANGED) {
protected:
JsonStateReader<T> _stateReader;
JsonStateUpdater<T> _stateUpdater;
StatefulService<T> * _statefulService;
size_t _bufferSize;
void updateSettings(AsyncWebServerRequest * request, JsonVariant & json) {
if (!json.is<JsonObject>()) {
return;
}
JsonObject jsonObject = json.as<JsonObject>();
StateUpdateResult outcome = _statefulService->updateWithoutPropagation(jsonObject, _stateUpdater);
if (outcome == StateUpdateResult::ERROR) {
return;
}
if (outcome == StateUpdateResult::CHANGED) {
}
} }
}
}; };
template <class T> template <class T>
class HttpEndpoint : public HttpGetEndpoint<T>, public HttpPostEndpoint<T> { class HttpEndpoint : public HttpGetEndpoint<T>, public HttpPostEndpoint<T> {
public: public:
HttpEndpoint(JsonStateReader<T> stateReader, HttpEndpoint(JsonStateReader<T> stateReader,
JsonStateUpdater<T> stateUpdater, JsonStateUpdater<T> stateUpdater,
StatefulService<T>* statefulService, StatefulService<T> * statefulService,
AsyncWebServer* server, AsyncWebServer * server,
const String& servicePath, const String & servicePath,
SecurityManager* securityManager, SecurityManager * securityManager,
AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN, AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN,
size_t bufferSize = DEFAULT_BUFFER_SIZE) : size_t bufferSize = DEFAULT_BUFFER_SIZE)
HttpGetEndpoint<T>(stateReader, : HttpGetEndpoint<T>(stateReader, statefulService, server, servicePath, securityManager, authenticationPredicate, bufferSize)
statefulService, , HttpPostEndpoint<T>(stateReader, stateUpdater, statefulService, server, servicePath, securityManager, authenticationPredicate, bufferSize) {
server, }
servicePath,
securityManager,
authenticationPredicate,
bufferSize),
HttpPostEndpoint<T>(stateReader,
stateUpdater,
statefulService,
server,
servicePath,
securityManager,
authenticationPredicate,
bufferSize) {
}
HttpEndpoint(JsonStateReader<T> stateReader, HttpEndpoint(JsonStateReader<T> stateReader,
JsonStateUpdater<T> stateUpdater, JsonStateUpdater<T> stateUpdater,
StatefulService<T>* statefulService, StatefulService<T> * statefulService,
AsyncWebServer* server, AsyncWebServer * server,
const String& servicePath, const String & servicePath,
size_t bufferSize = DEFAULT_BUFFER_SIZE) : size_t bufferSize = DEFAULT_BUFFER_SIZE)
HttpGetEndpoint<T>(stateReader, statefulService, server, servicePath, bufferSize), : HttpGetEndpoint<T>(stateReader, statefulService, server, servicePath, bufferSize)
HttpPostEndpoint<T>(stateReader, stateUpdater, statefulService, server, servicePath, bufferSize) { , HttpPostEndpoint<T>(stateReader, stateUpdater, statefulService, server, servicePath, bufferSize) {
} }
}; };
#endif #endif

View File

@@ -61,51 +61,51 @@ typedef enum {
} wifi_auth_mode_t; } wifi_auth_mode_t;
typedef struct { typedef struct {
uint32_t status; /**< status of scanning APs: 0 — success, 1 - failure */ uint32_t status; /**< status of scanning APs: 0 — success, 1 - failure */
uint8_t number; /**< number of scan results */ uint8_t number; /**< number of scan results */
uint8_t scan_id; /**< scan sequence number, used for block scan */ uint8_t scan_id; /**< scan sequence number, used for block scan */
} wifi_event_sta_scan_done_t; } wifi_event_sta_scan_done_t;
/** Argument structure for WIFI_EVENT_STA_CONNECTED event */ /** Argument structure for WIFI_EVENT_STA_CONNECTED event */
typedef struct { typedef struct {
uint8_t ssid[32]; /**< SSID of connected AP */ uint8_t ssid[32]; /**< SSID of connected AP */
uint8_t ssid_len; /**< SSID length of connected AP */ uint8_t ssid_len; /**< SSID length of connected AP */
uint8_t bssid[6]; /**< BSSID of connected AP*/ uint8_t bssid[6]; /**< BSSID of connected AP*/
uint8_t channel; /**< channel of connected AP*/ uint8_t channel; /**< channel of connected AP*/
wifi_auth_mode_t authmode;/**< authentication mode used by AP*/ wifi_auth_mode_t authmode; /**< authentication mode used by AP*/
} wifi_event_sta_connected_t; } wifi_event_sta_connected_t;
/** Argument structure for WIFI_EVENT_STA_DISCONNECTED event */ /** Argument structure for WIFI_EVENT_STA_DISCONNECTED event */
typedef struct { typedef struct {
uint8_t ssid[32]; /**< SSID of disconnected AP */ uint8_t ssid[32]; /**< SSID of disconnected AP */
uint8_t ssid_len; /**< SSID length of disconnected AP */ uint8_t ssid_len; /**< SSID length of disconnected AP */
uint8_t bssid[6]; /**< BSSID of disconnected AP */ uint8_t bssid[6]; /**< BSSID of disconnected AP */
uint8_t reason; /**< reason of disconnection */ uint8_t reason; /**< reason of disconnection */
} wifi_event_sta_disconnected_t; } wifi_event_sta_disconnected_t;
/** Argument structure for WIFI_EVENT_STA_AUTHMODE_CHANGE event */ /** Argument structure for WIFI_EVENT_STA_AUTHMODE_CHANGE event */
typedef struct { typedef struct {
wifi_auth_mode_t old_mode; /**< the old auth mode of AP */ wifi_auth_mode_t old_mode; /**< the old auth mode of AP */
wifi_auth_mode_t new_mode; /**< the new auth mode of AP */ wifi_auth_mode_t new_mode; /**< the new auth mode of AP */
} wifi_event_sta_authmode_change_t; } wifi_event_sta_authmode_change_t;
/** Argument structure for WIFI_EVENT_STA_WPS_ER_PIN event */ /** Argument structure for WIFI_EVENT_STA_WPS_ER_PIN event */
typedef struct { typedef struct {
uint8_t pin_code[8]; /**< PIN code of station in enrollee mode */ uint8_t pin_code[8]; /**< PIN code of station in enrollee mode */
} wifi_event_sta_wps_er_pin_t; } wifi_event_sta_wps_er_pin_t;
/** Argument structure for WIFI_EVENT_STA_WPS_ER_FAILED event */ /** Argument structure for WIFI_EVENT_STA_WPS_ER_FAILED event */
typedef enum { typedef enum {
WPS_FAIL_REASON_NORMAL = 0, /**< ESP32 WPS normal fail reason */ WPS_FAIL_REASON_NORMAL = 0, /**< ESP32 WPS normal fail reason */
WPS_FAIL_REASON_RECV_M2D, /**< ESP32 WPS receive M2D frame */ WPS_FAIL_REASON_RECV_M2D, /**< ESP32 WPS receive M2D frame */
WPS_FAIL_REASON_MAX WPS_FAIL_REASON_MAX
} wifi_event_sta_wps_fail_reason_t; } wifi_event_sta_wps_fail_reason_t;
typedef union { typedef union {
wifi_event_sta_scan_done_t wifi_scan_done; wifi_event_sta_scan_done_t wifi_scan_done;
wifi_event_sta_authmode_change_t wifi_sta_authmode_change; wifi_event_sta_authmode_change_t wifi_sta_authmode_change;
wifi_event_sta_connected_t wifi_sta_connected; wifi_event_sta_connected_t wifi_sta_connected;
wifi_event_sta_disconnected_t wifi_sta_disconnected; wifi_event_sta_disconnected_t wifi_sta_disconnected;
} arduino_event_info_t; } arduino_event_info_t;
typedef struct { typedef struct {

View File

@@ -4,139 +4,136 @@
#include "../../src/emsesp_stub.h" // proddy added #include "../../src/emsesp_stub.h" // proddy added
SecuritySettingsService::SecuritySettingsService(AsyncWebServer* server, FS* fs) : SecuritySettingsService::SecuritySettingsService(AsyncWebServer * server, FS * fs)
_httpEndpoint(SecuritySettings::read, SecuritySettings::update, this, server, SECURITY_SETTINGS_PATH, this), : _httpEndpoint(SecuritySettings::read, SecuritySettings::update, this, server, SECURITY_SETTINGS_PATH, this)
_fsPersistence(SecuritySettings::read, SecuritySettings::update, this, fs, SECURITY_SETTINGS_FILE), , _fsPersistence(SecuritySettings::read, SecuritySettings::update, this, fs, SECURITY_SETTINGS_FILE)
_jwtHandler(FACTORY_JWT_SECRET) { , _jwtHandler(FACTORY_JWT_SECRET) {
addUpdateHandler([&](const String& originId) { configureJWTHandler(); }, false); addUpdateHandler([&](const String & originId) { configureJWTHandler(); }, false);
} }
void SecuritySettingsService::begin() { void SecuritySettingsService::begin() {
_fsPersistence.readFromFS(); _fsPersistence.readFromFS();
configureJWTHandler(); configureJWTHandler();
} }
Authentication SecuritySettingsService::authenticateRequest(AsyncWebServerRequest* request) { Authentication SecuritySettingsService::authenticateRequest(AsyncWebServerRequest * request) {
AsyncWebHeader* authorizationHeader = request->getHeader(AUTHORIZATION_HEADER); AsyncWebHeader * authorizationHeader = request->getHeader(AUTHORIZATION_HEADER);
if (authorizationHeader) { if (authorizationHeader) {
String value = authorizationHeader->value(); String value = authorizationHeader->value();
if (value.startsWith(AUTHORIZATION_HEADER_PREFIX)) { if (value.startsWith(AUTHORIZATION_HEADER_PREFIX)) {
value = value.substring(AUTHORIZATION_HEADER_PREFIX_LEN); value = value.substring(AUTHORIZATION_HEADER_PREFIX_LEN);
return authenticateJWT(value); return authenticateJWT(value);
}
} else if (request->hasParam(ACCESS_TOKEN_PARAMATER)) {
AsyncWebParameter * tokenParamater = request->getParam(ACCESS_TOKEN_PARAMATER);
String value = tokenParamater->value();
return authenticateJWT(value);
} }
} else if (request->hasParam(ACCESS_TOKEN_PARAMATER)) { return Authentication();
AsyncWebParameter* tokenParamater = request->getParam(ACCESS_TOKEN_PARAMATER);
String value = tokenParamater->value();
return authenticateJWT(value);
}
return Authentication();
} }
void SecuritySettingsService::configureJWTHandler() { void SecuritySettingsService::configureJWTHandler() {
_jwtHandler.setSecret(_state.jwtSecret); _jwtHandler.setSecret(_state.jwtSecret);
} }
Authentication SecuritySettingsService::authenticateJWT(String& jwt) { Authentication SecuritySettingsService::authenticateJWT(String & jwt) {
DynamicJsonDocument payloadDocument(MAX_JWT_SIZE); DynamicJsonDocument payloadDocument(MAX_JWT_SIZE);
_jwtHandler.parseJWT(jwt, payloadDocument); _jwtHandler.parseJWT(jwt, payloadDocument);
if (payloadDocument.is<JsonObject>()) { if (payloadDocument.is<JsonObject>()) {
JsonObject parsedPayload = payloadDocument.as<JsonObject>(); JsonObject parsedPayload = payloadDocument.as<JsonObject>();
String username = parsedPayload["username"]; String username = parsedPayload["username"];
for (User _user : _state.users) {
if (_user.username == username && validatePayload(parsedPayload, &_user)) {
return Authentication(_user);
}
}
}
return Authentication();
}
Authentication SecuritySettingsService::authenticate(const String & username, const String & password) {
for (User _user : _state.users) { for (User _user : _state.users) {
if (_user.username == username && validatePayload(parsedPayload, &_user)) { if (_user.username == username && _user.password == password) {
return Authentication(_user); return Authentication(_user);
} }
} }
} return Authentication();
return Authentication();
} }
Authentication SecuritySettingsService::authenticate(const String& username, const String& password) { inline void populateJWTPayload(JsonObject & payload, User * user) {
for (User _user : _state.users) { payload["username"] = user->username;
if (_user.username == username && _user.password == password) { payload["admin"] = user->admin;
return Authentication(_user);
}
}
return Authentication();
} }
inline void populateJWTPayload(JsonObject& payload, User* user) { boolean SecuritySettingsService::validatePayload(JsonObject & parsedPayload, User * user) {
payload["username"] = user->username; DynamicJsonDocument jsonDocument(MAX_JWT_SIZE);
payload["admin"] = user->admin; JsonObject payload = jsonDocument.to<JsonObject>();
populateJWTPayload(payload, user);
return payload == parsedPayload;
} }
boolean SecuritySettingsService::validatePayload(JsonObject& parsedPayload, User* user) { String SecuritySettingsService::generateJWT(User * user) {
DynamicJsonDocument jsonDocument(MAX_JWT_SIZE); DynamicJsonDocument jsonDocument(MAX_JWT_SIZE);
JsonObject payload = jsonDocument.to<JsonObject>(); JsonObject payload = jsonDocument.to<JsonObject>();
populateJWTPayload(payload, user); populateJWTPayload(payload, user);
return payload == parsedPayload; return _jwtHandler.buildJWT(payload);
}
String SecuritySettingsService::generateJWT(User* user) {
DynamicJsonDocument jsonDocument(MAX_JWT_SIZE);
JsonObject payload = jsonDocument.to<JsonObject>();
populateJWTPayload(payload, user);
return _jwtHandler.buildJWT(payload);
} }
ArRequestFilterFunction SecuritySettingsService::filterRequest(AuthenticationPredicate predicate) { ArRequestFilterFunction SecuritySettingsService::filterRequest(AuthenticationPredicate predicate) {
return [this, predicate](AsyncWebServerRequest* request) { return [this, predicate](AsyncWebServerRequest * request) {
Authentication authentication = authenticateRequest(request); Authentication authentication = authenticateRequest(request);
return predicate(authentication); return predicate(authentication);
}; };
} }
ArRequestHandlerFunction SecuritySettingsService::wrapRequest(ArRequestHandlerFunction onRequest, ArRequestHandlerFunction SecuritySettingsService::wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate) {
AuthenticationPredicate predicate) { return [this, onRequest, predicate](AsyncWebServerRequest * request) {
return [this, onRequest, predicate](AsyncWebServerRequest* request) { Authentication authentication = authenticateRequest(request);
Authentication authentication = authenticateRequest(request); if (!predicate(authentication)) {
if (!predicate(authentication)) { request->send(401);
request->send(401); return;
return; }
} onRequest(request);
onRequest(request); };
};
} }
ArJsonRequestHandlerFunction SecuritySettingsService::wrapCallback(ArJsonRequestHandlerFunction onRequest, ArJsonRequestHandlerFunction SecuritySettingsService::wrapCallback(ArJsonRequestHandlerFunction onRequest, AuthenticationPredicate predicate) {
AuthenticationPredicate predicate) { return [this, onRequest, predicate](AsyncWebServerRequest * request, JsonVariant & json) {
return [this, onRequest, predicate](AsyncWebServerRequest* request, JsonVariant& json) { Authentication authentication = authenticateRequest(request);
Authentication authentication = authenticateRequest(request); if (!predicate(authentication)) {
if (!predicate(authentication)) { request->send(401);
request->send(401); return;
return; }
} onRequest(request, json);
onRequest(request, json); };
};
} }
#else #else
User ADMIN_USER = User(FACTORY_ADMIN_USERNAME, FACTORY_ADMIN_PASSWORD, true); User ADMIN_USER = User(FACTORY_ADMIN_USERNAME, FACTORY_ADMIN_PASSWORD, true);
SecuritySettingsService::SecuritySettingsService(AsyncWebServer* server, FS* fs) : SecurityManager() { SecuritySettingsService::SecuritySettingsService(AsyncWebServer * server, FS * fs)
: SecurityManager() {
} }
SecuritySettingsService::~SecuritySettingsService() { SecuritySettingsService::~SecuritySettingsService() {
} }
ArRequestFilterFunction SecuritySettingsService::filterRequest(AuthenticationPredicate predicate) { ArRequestFilterFunction SecuritySettingsService::filterRequest(AuthenticationPredicate predicate) {
return [this, predicate](AsyncWebServerRequest* request) { return true; }; return [this, predicate](AsyncWebServerRequest * request) { return true; };
} }
// Return the admin user on all request - disabling security features // Return the admin user on all request - disabling security features
Authentication SecuritySettingsService::authenticateRequest(AsyncWebServerRequest* request) { Authentication SecuritySettingsService::authenticateRequest(AsyncWebServerRequest * request) {
return Authentication(ADMIN_USER); return Authentication(ADMIN_USER);
} }
// Return the function unwrapped // Return the function unwrapped
ArRequestHandlerFunction SecuritySettingsService::wrapRequest(ArRequestHandlerFunction onRequest, ArRequestHandlerFunction SecuritySettingsService::wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate) {
AuthenticationPredicate predicate) { return onRequest;
return onRequest;
} }
ArJsonRequestHandlerFunction SecuritySettingsService::wrapCallback(ArJsonRequestHandlerFunction onRequest, ArJsonRequestHandlerFunction SecuritySettingsService::wrapCallback(ArJsonRequestHandlerFunction onRequest, AuthenticationPredicate predicate) {
AuthenticationPredicate predicate) { return onRequest;
return onRequest;
} }
#endif #endif

View File

@@ -16,10 +16,10 @@
#endif #endif
enum class StateUpdateResult { enum class StateUpdateResult {
CHANGED = 0, // The update changed the state and propagation should take place if required CHANGED = 0, // The update changed the state and propagation should take place if required
CHANGED_RESTART, // The update changed the state and the service should be restarted CHANGED_RESTART, // The update changed the state and the service should be restarted
UNCHANGED, // The state was unchanged, propagation should not take place UNCHANGED, // The state was unchanged, propagation should not take place
ERROR // There was a problem updating the state, propagation should not take place ERROR // There was a problem updating the state, propagation should not take place
}; };
template <typename T> template <typename T>

View File

@@ -240,6 +240,8 @@ const mqtt_status = {
client_id: 'ems-esp', client_id: 'ems-esp',
disconnect_reason: 0, disconnect_reason: 0,
mqtt_fails: 0, mqtt_fails: 0,
mqtt_queued: 1,
connect_count: 2,
} }
// SYSTEM // SYSTEM
@@ -592,20 +594,15 @@ const emsesp_deviceentities_1 = [
m: 0, m: 0,
w: false, w: false,
}, },
// { {
// v: 'test data', v: 18.2,
// n: 'test', n: 'hc1 selected room temperature',
// id: 'test', id: 'hc1/seltemp',
// m: 0, m: 0,
// w: false, mi: 5,
// }, ma: 52,
// { w: true,
// v: 18.2, },
// n: 'hc1 selected room temperature',
// id: 'hc1/seltemp',
// m: 0,
// w: true,
// },
{ {
v: 22.6, v: 22.6,
n: 'hc1 current room temperature', n: 'hc1 current room temperature',

View File

@@ -102,4 +102,4 @@ platform = espressif32
board_upload.flash_size = 4MB board_upload.flash_size = 4MB
board_build.partitions = esp32_partition_4M.csv board_build.partitions = esp32_partition_4M.csv
build_flags = ${common.build_flags} build_flags = ${common.build_flags}
build_unflags = ${common.unbuild_flags} build_unflags = ${common.unbuild_flags}

View File

@@ -20,28 +20,27 @@ def bin_copy(source, target, env):
app_version = bag.get('app_version') app_version = bag.get('app_version')
platform = "ESP32" platform = "ESP32"
chip_target = env.get('PIOENV').upper()
# this breaks the CI so removed
# flash_size = env["PIOENV"].split('_')[1] # flash_size = env["PIOENV"].split('_')[1]
# print(env.Dump()) # print(env.Dump())
# my_flags = env.ParseFlags(env['BUILD_FLAGS']) # my_flags = env.ParseFlags(env['BUILD_FLAGS'])
# defines = {k: v for (k, v) in my_flags.get("CPPDEFINES")} # defines = {k: v for (k, v) in my_flags.get("CPPDEFINES")}
# print(my_flags) # print(my_flags)
# print((my_flags.get("CPPDEFINES")) # print(my_flags.get("CPPDEFINES")
# alternatively take platform from the pio target # alternatively take platform from the pio target
# platform = str(target[0]).split(os.path.sep)[2] # platform = str(target[0]).split(os.path.sep)[2]
chip_target = env.get('PIOENV').upper() chip_target = env.get('PIOENV').upper()
print("app version: "+app_version) print("app version: " + app_version)
print("chip_target: "+chip_target) print("platform: " + platform)
print("platform: "+platform) print("chip_target: " + chip_target)
# print("flash size: "+flash_size)
# convert . to _ so Windows doesn't complain # convert . to _ so Windows doesn't complain
variant = "EMS-ESP-" + app_version.replace(".", "_") + "-" + chip_target variant = "EMS-ESP-" + chip_target + "-" + app_version.replace(".", "_")
# variant = "EMS-ESP-" + app_version.replace(".", "_") + "-" + platform + "_" + flash_size
# check if output directories exist and create if necessary # check if output directories exist and create if necessary
if not os.path.isdir(OUTPUT_DIR): if not os.path.isdir(OUTPUT_DIR):

View File

@@ -32,7 +32,7 @@ void AnalogSensor::start() {
analogSetAttenuation(ADC_2_5db); // for all channels 1.5V analogSetAttenuation(ADC_2_5db); // for all channels 1.5V
LOG_INFO(F("Starting Analog sensor service")); LOG_INFO("Starting Analog sensor service");
// Add API call for /info // Add API call for /info
Command::add( Command::add(
@@ -44,7 +44,7 @@ void AnalogSensor::start() {
EMSdevice::DeviceType::ANALOGSENSOR, EMSdevice::DeviceType::ANALOGSENSOR,
F_(setvalue), F_(setvalue),
[&](const char * value, const int8_t id) { return command_setvalue(value, id); }, [&](const char * value, const int8_t id) { return command_setvalue(value, id); },
F("set io value"), // TODO this needs translating ("set io value"), // TODO translate this
CommandFlag::ADMIN_ONLY); CommandFlag::ADMIN_ONLY);
Command::add( Command::add(
EMSdevice::DeviceType::ANALOGSENSOR, EMSdevice::DeviceType::ANALOGSENSOR,
@@ -123,12 +123,12 @@ void AnalogSensor::reload() {
for (auto & sensor : sensors_) { for (auto & sensor : sensors_) {
sensor.ha_registered = false; // force HA configs to be re-created sensor.ha_registered = false; // force HA configs to be re-created
if (sensor.type() == AnalogType::ADC) { if (sensor.type() == AnalogType::ADC) {
LOG_DEBUG(F("Adding analog ADC sensor on GPIO%d"), sensor.gpio()); LOG_DEBUG("Adding analog ADC sensor on GPIO%d", sensor.gpio());
// analogSetPinAttenuation does not work with analogReadMilliVolts // analogSetPinAttenuation does not work with analogReadMilliVolts
sensor.analog_ = 0; // initialize sensor.analog_ = 0; // initialize
sensor.last_reading_ = 0; sensor.last_reading_ = 0;
} else if (sensor.type() == AnalogType::COUNTER) { } else if (sensor.type() == AnalogType::COUNTER) {
LOG_DEBUG(F("Adding analog I/O Counter sensor on GPIO%d"), sensor.gpio()); LOG_DEBUG("Adding analog I/O Counter sensor on GPIO%d", sensor.gpio());
pinMode(sensor.gpio(), INPUT_PULLUP); pinMode(sensor.gpio(), INPUT_PULLUP);
#ifndef ARDUINO_LOLIN_C3_MINI #ifndef ARDUINO_LOLIN_C3_MINI
if (sensor.gpio() == 25 || sensor.gpio() == 26) { if (sensor.gpio() == 25 || sensor.gpio() == 26) {
@@ -139,7 +139,7 @@ void AnalogSensor::reload() {
sensor.poll_ = digitalRead(sensor.gpio()); sensor.poll_ = digitalRead(sensor.gpio());
publish_sensor(sensor); publish_sensor(sensor);
} else if (sensor.type() == AnalogType::TIMER || sensor.type() == AnalogType::RATE) { } else if (sensor.type() == AnalogType::TIMER || sensor.type() == AnalogType::RATE) {
LOG_DEBUG(F("Adding analog Timer/Rate sensor on GPIO%d"), sensor.gpio()); LOG_DEBUG("Adding analog Timer/Rate sensor on GPIO%d", sensor.gpio());
pinMode(sensor.gpio(), INPUT_PULLUP); pinMode(sensor.gpio(), INPUT_PULLUP);
sensor.polltime_ = uuid::get_uptime(); sensor.polltime_ = uuid::get_uptime();
sensor.last_polltime_ = uuid::get_uptime(); sensor.last_polltime_ = uuid::get_uptime();
@@ -148,7 +148,7 @@ void AnalogSensor::reload() {
sensor.set_value(0); sensor.set_value(0);
publish_sensor(sensor); publish_sensor(sensor);
} else if (sensor.type() == AnalogType::DIGITAL_IN) { } else if (sensor.type() == AnalogType::DIGITAL_IN) {
LOG_DEBUG(F("Adding analog Read sensor on GPIO%d"), sensor.gpio()); LOG_DEBUG("Adding analog Read sensor on GPIO%d", sensor.gpio());
pinMode(sensor.gpio(), INPUT_PULLUP); pinMode(sensor.gpio(), INPUT_PULLUP);
sensor.set_value(digitalRead(sensor.gpio())); // initial value sensor.set_value(digitalRead(sensor.gpio())); // initial value
sensor.set_uom(0); // no uom, just for safe measures sensor.set_uom(0); // no uom, just for safe measures
@@ -156,7 +156,7 @@ void AnalogSensor::reload() {
sensor.poll_ = digitalRead(sensor.gpio()); sensor.poll_ = digitalRead(sensor.gpio());
publish_sensor(sensor); publish_sensor(sensor);
} else if (sensor.type() == AnalogType::DIGITAL_OUT) { } else if (sensor.type() == AnalogType::DIGITAL_OUT) {
LOG_DEBUG(F("Adding analog Write sensor on GPIO%d"), sensor.gpio()); LOG_DEBUG("Adding analog Write sensor on GPIO%d", sensor.gpio());
pinMode(sensor.gpio(), OUTPUT); pinMode(sensor.gpio(), OUTPUT);
if (sensor.gpio() == 25 || sensor.gpio() == 26) { if (sensor.gpio() == 25 || sensor.gpio() == 26) {
if (sensor.offset() > 255) { if (sensor.offset() > 255) {
@@ -175,7 +175,7 @@ void AnalogSensor::reload() {
sensor.set_uom(0); // no uom, just for safe measures sensor.set_uom(0); // no uom, just for safe measures
publish_sensor(sensor); publish_sensor(sensor);
} else if (sensor.type() >= AnalogType::PWM_0) { } else if (sensor.type() >= AnalogType::PWM_0) {
LOG_DEBUG(F("Adding PWM output sensor on GPIO%d"), sensor.gpio()); LOG_DEBUG("Adding PWM output sensor on GPIO%d", sensor.gpio());
uint channel = sensor.type() - AnalogType::PWM_0; uint channel = sensor.type() - AnalogType::PWM_0;
ledcSetup(channel, sensor.factor(), 13); ledcSetup(channel, sensor.factor(), 13);
ledcAttachPin(sensor.gpio(), channel); ledcAttachPin(sensor.gpio(), channel);
@@ -277,7 +277,7 @@ bool AnalogSensor::update(uint8_t gpio, const std::string & name, float offset,
found_sensor = true; // found the record found_sensor = true; // found the record
// see if it's marked for deletion // see if it's marked for deletion
if (type == AnalogType::MARK_DELETED) { if (type == AnalogType::MARK_DELETED) {
LOG_DEBUG(F("Removing analog sensor GPIO %d"), gpio); LOG_DEBUG("Removing analog sensor GPIO %d", gpio);
settings.analogCustomizations.remove(AnalogCustomization); settings.analogCustomizations.remove(AnalogCustomization);
} else { } else {
// update existing record // update existing record
@@ -286,7 +286,7 @@ bool AnalogSensor::update(uint8_t gpio, const std::string & name, float offset,
AnalogCustomization.factor = factor; AnalogCustomization.factor = factor;
AnalogCustomization.uom = uom; AnalogCustomization.uom = uom;
AnalogCustomization.type = type; AnalogCustomization.type = type;
LOG_DEBUG(F("Customizing existing analog GPIO %d"), gpio); LOG_DEBUG("Customizing existing analog GPIO %d", gpio);
} }
return StateUpdateResult::CHANGED; // persist the change return StateUpdateResult::CHANGED; // persist the change
} }
@@ -312,7 +312,7 @@ bool AnalogSensor::update(uint8_t gpio, const std::string & name, float offset,
newSensor.uom = uom; newSensor.uom = uom;
newSensor.type = type; newSensor.type = type;
settings.analogCustomizations.push_back(newSensor); settings.analogCustomizations.push_back(newSensor);
LOG_DEBUG(F("Adding new customization for analog sensor GPIO %d"), gpio); LOG_DEBUG("Adding new customization for analog sensor GPIO %d", gpio);
return StateUpdateResult::CHANGED; // persist the change return StateUpdateResult::CHANGED; // persist the change
}, },
"local"); "local");
@@ -338,9 +338,9 @@ void AnalogSensor::publish_sensor(const Sensor & sensor) const {
if (Mqtt::publish_single()) { if (Mqtt::publish_single()) {
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
if (Mqtt::publish_single2cmd()) { if (Mqtt::publish_single2cmd()) {
snprintf(topic, sizeof(topic), "%s/%s", read_flash_string(F_(analogsensor)).c_str(), sensor.name().c_str()); snprintf(topic, sizeof(topic), "%s/%s", (F_(analogsensor)), sensor.name().c_str());
} else { } else {
snprintf(topic, sizeof(topic), "%s%s/%s", read_flash_string(F_(analogsensor)).c_str(), "_data", sensor.name().c_str()); snprintf(topic, sizeof(topic), "%s%s/%s", (F_(analogsensor)), "_data", sensor.name().c_str());
} }
char payload[10]; char payload[10];
Mqtt::publish(topic, Helpers::render_value(payload, sensor.value(), 2)); // always publish as floats Mqtt::publish(topic, Helpers::render_value(payload, sensor.value(), 2)); // always publish as floats
@@ -353,7 +353,7 @@ void AnalogSensor::remove_ha_topic(const uint8_t gpio) const {
return; return;
} }
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG
LOG_DEBUG(F("Removing HA config for analog sensor GPIO %d"), gpio); LOG_DEBUG("Removing HA config for analog sensor GPIO %d", gpio);
#endif #endif
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%d/config", Mqtt::basename().c_str(), gpio); snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%d/config", Mqtt::basename().c_str(), gpio);
@@ -403,7 +403,7 @@ void AnalogSensor::publish_values(const bool force) {
// create HA config // create HA config
if (Mqtt::ha_enabled() && (!sensor.ha_registered || force)) { if (Mqtt::ha_enabled() && (!sensor.ha_registered || force)) {
LOG_DEBUG(F("Recreating HA config for analog sensor GPIO %d"), sensor.gpio()); LOG_DEBUG("Recreating HA config for analog sensor GPIO %d", sensor.gpio());
StaticJsonDocument<EMSESP_JSON_SIZE_MEDIUM> config; StaticJsonDocument<EMSESP_JSON_SIZE_MEDIUM> config;
@@ -447,7 +447,7 @@ void AnalogSensor::publish_values(const bool force) {
} }
} }
Mqtt::publish(F("analogsensor_data"), doc.as<JsonObject>()); Mqtt::publish("analogsensor_data", doc.as<JsonObject>());
} }
// called from emsesp.cpp, similar to the emsdevice->get_value_info // called from emsesp.cpp, similar to the emsdevice->get_value_info

View File

@@ -82,7 +82,7 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
// validate the device, make sure it exists // validate the device, make sure it exists
uint8_t device_type = EMSdevice::device_name_2_device_type(device_s); uint8_t device_type = EMSdevice::device_name_2_device_type(device_s);
if (!device_has_commands(device_type)) { if (!device_has_commands(device_type)) {
LOG_DEBUG(F("Command failed: unknown device '%s'"), device_s); LOG_DEBUG("Command failed: unknown device '%s'", device_s);
return message(CommandRet::ERROR, "unknown device", output); return message(CommandRet::ERROR, "unknown device", output);
} }
@@ -170,15 +170,15 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
std::string Command::return_code_string(const uint8_t return_code) { std::string Command::return_code_string(const uint8_t return_code) {
switch (return_code) { switch (return_code) {
case CommandRet::ERROR: case CommandRet::ERROR:
return read_flash_string(F("Error")); return ("Error");
case CommandRet::OK: case CommandRet::OK:
return read_flash_string(F("OK")); return ("OK");
case CommandRet::NOT_FOUND: case CommandRet::NOT_FOUND:
return read_flash_string(F("Not Found")); return ("Not Found");
case CommandRet::NOT_ALLOWED: case CommandRet::NOT_ALLOWED:
return read_flash_string(F("Not Authorized")); return ("Not Authorized");
case CommandRet::FAIL: case CommandRet::FAIL:
return read_flash_string(F("Failed")); return ("Failed");
default: default:
break; break;
} }
@@ -248,7 +248,7 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
if ((device_type > EMSdevice::DeviceType::SYSTEM) && (!value || !strlen(value))) { if ((device_type > EMSdevice::DeviceType::SYSTEM) && (!value || !strlen(value))) {
if (!cf || !cf->cmdfunction_json_) { if (!cf || !cf->cmdfunction_json_) {
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
LOG_DEBUG(F("[DEBUG] Calling %s command '%s' to retrieve attributes"), dname.c_str(), cmd); LOG_DEBUG("[DEBUG] Calling %s command '%s' to retrieve attributes", dname.c_str(), cmd);
#endif #endif
return EMSESP::get_device_value_info(output, cmd, id, device_type) ? CommandRet::OK : CommandRet::ERROR; // entity = cmd return EMSESP::get_device_value_info(output, cmd, id, device_type) ? CommandRet::OK : CommandRet::ERROR; // entity = cmd
} }
@@ -264,15 +264,15 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
if ((value == nullptr) || (strlen(value) == 0)) { if ((value == nullptr) || (strlen(value) == 0)) {
if (EMSESP::system_.readonly_mode()) { if (EMSESP::system_.readonly_mode()) {
LOG_INFO(F("[readonly] Calling command '%s/%s' (%s)"), dname.c_str(), cmd, read_flash_string(cf->description_).c_str()); LOG_INFO(("[readonly] Calling command '%s/%s' (%s)"), dname.c_str(), cmd, cf->description_);
} else { } else {
LOG_DEBUG(F("Calling command '%s/%s' (%s)"), dname.c_str(), cmd, read_flash_string(cf->description_).c_str()); LOG_DEBUG(("Calling command '%s/%s' (%s)"), dname.c_str(), cmd, (cf->description_));
} }
} else { } else {
if (EMSESP::system_.readonly_mode()) { if (EMSESP::system_.readonly_mode()) {
LOG_INFO(F("[readonly] Calling command '%s/%s' (%s) with value %s"), dname.c_str(), cmd, read_flash_string(cf->description_).c_str(), value); LOG_INFO(("[readonly] Calling command '%s/%s' (%s) with value %s"), dname.c_str(), cmd, cf->description_, value);
} else { } else {
LOG_DEBUG(F("Calling command '%s/%s' (%s) with value %s"), dname.c_str(), cmd, read_flash_string(cf->description_).c_str(), value); LOG_DEBUG(("Calling command '%s/%s' (%s) with value %s"), dname.c_str(), cmd, (cf->description_), value);
} }
} }
@@ -294,14 +294,14 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
} }
// we didn't find the command and its not an endpoint, report error // we didn't find the command and its not an endpoint, report error
LOG_DEBUG(F("Command failed: invalid command '%s'"), cmd); LOG_DEBUG("Command failed: invalid command '%s'", cmd);
return message(CommandRet::NOT_FOUND, "invalid command", output); return message(CommandRet::NOT_FOUND, "invalid command", output);
} }
// add a command to the list, which does not return json // add a command to the list, which does not return json
void Command::add(const uint8_t device_type, const __FlashStringHelper * cmd, const cmd_function_p cb, const __FlashStringHelper * description, uint8_t flags) { void Command::add(const uint8_t device_type, const char * cmd, const cmd_function_p cb, const char * description, uint8_t flags) {
// if the command already exists for that device type don't add it // if the command already exists for that device type don't add it
if (find_command(device_type, read_flash_string(cmd).c_str()) != nullptr) { if (find_command(device_type, cmd) != nullptr) {
return; return;
} }
@@ -314,9 +314,9 @@ void Command::add(const uint8_t device_type, const __FlashStringHelper * cmd, co
} }
// add a command to the list, which does return a json object as output // add a command to the list, which does return a json object as output
void Command::add(const uint8_t device_type, const __FlashStringHelper * cmd, const cmd_json_function_p cb, const __FlashStringHelper * description, uint8_t flags) { void Command::add(const uint8_t device_type, const char * cmd, const cmd_json_function_p cb, const char * description, uint8_t flags) {
// if the command already exists for that device type don't add it // if the command already exists for that device type don't add it
if (find_command(device_type, read_flash_string(cmd).c_str()) != nullptr) { if (find_command(device_type, cmd) != nullptr) {
return; return;
} }
@@ -338,7 +338,7 @@ Command::CmdFunction * Command::find_command(const uint8_t device_type, const ch
} }
for (auto & cf : cmdfunctions_) { for (auto & cf : cmdfunctions_) {
if (!strcmp(lowerCmd, Helpers::toLower(read_flash_string(cf.cmd_)).c_str()) && (cf.device_type_ == device_type)) { if (!strcmp(lowerCmd, cf.cmd_) && (cf.device_type_ == device_type)) {
return &cf; return &cf;
} }
} }
@@ -357,14 +357,14 @@ bool Command::list(const uint8_t device_type, JsonObject & output) {
std::list<std::string> sorted_cmds; std::list<std::string> sorted_cmds;
for (const auto & cf : cmdfunctions_) { for (const auto & cf : cmdfunctions_) {
if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN)) { if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN)) {
sorted_cmds.push_back(read_flash_string(cf.cmd_)); sorted_cmds.push_back((cf.cmd_));
} }
} }
sorted_cmds.sort(); sorted_cmds.sort();
for (const auto & cl : sorted_cmds) { for (const auto & cl : sorted_cmds) {
for (const auto & cf : cmdfunctions_) { for (const auto & cf : cmdfunctions_) {
if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN) && cf.description_ && (cl == read_flash_string(cf.cmd_))) { if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN) && cf.description_ && (cl == std::string(cf.cmd_))) {
output[cl] = cf.description_; output[cl] = cf.description_;
} }
} }
@@ -376,7 +376,7 @@ bool Command::list(const uint8_t device_type, JsonObject & output) {
// output list of all commands to console for a specific DeviceType // output list of all commands to console for a specific DeviceType
void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbose) { void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbose) {
if (cmdfunctions_.empty()) { if (cmdfunctions_.empty()) {
shell.println(F("No commands available")); shell.println("No commands available");
return; return;
} }
@@ -384,7 +384,7 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo
std::list<std::string> sorted_cmds; std::list<std::string> sorted_cmds;
for (const auto & cf : cmdfunctions_) { for (const auto & cf : cmdfunctions_) {
if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN)) { if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN)) {
sorted_cmds.push_back(read_flash_string(cf.cmd_)); sorted_cmds.push_back((cf.cmd_));
} }
} }
sorted_cmds.sort(); sorted_cmds.sort();
@@ -404,7 +404,7 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo
for (const auto & cl : sorted_cmds) { for (const auto & cl : sorted_cmds) {
// find and print the description // find and print the description
for (const auto & cf : cmdfunctions_) { for (const auto & cf : cmdfunctions_) {
if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN) && cf.description_ && (cl == read_flash_string(cf.cmd_))) { if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN) && cf.description_ && (cl == std::string(cf.cmd_))) {
uint8_t i = cl.length(); uint8_t i = cl.length();
shell.print(" "); shell.print(" ");
if (cf.has_flags(MQTT_SUB_FLAG_HC)) { if (cf.has_flags(MQTT_SUB_FLAG_HC)) {
@@ -424,7 +424,7 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo
shell.print(EMSdevice::tag_to_string(DeviceValueTAG::TAG_DEVICE_DATA_WW)); shell.print(EMSdevice::tag_to_string(DeviceValueTAG::TAG_DEVICE_DATA_WW));
shell.print(' '); shell.print(' ');
} }
shell.print(read_flash_string(cf.description_).c_str()); shell.print((cf.description_));
if (!cf.has_flags(CommandFlag::ADMIN_ONLY)) { if (!cf.has_flags(CommandFlag::ADMIN_ONLY)) {
shell.print(' '); shell.print(' ');
shell.print(COLOR_BRIGHT_RED); shell.print(COLOR_BRIGHT_RED);
@@ -497,7 +497,7 @@ void Command::show_devices(uuid::console::Shell & shell) {
// output list of all commands to console // output list of all commands to console
// calls show with verbose mode set // calls show with verbose mode set
void Command::show_all(uuid::console::Shell & shell) { void Command::show_all(uuid::console::Shell & shell) {
shell.println(F("Available commands (*=do not need authorization): ")); shell.println(("Available commands (*=do not need authorization): "));
// show system first // show system first
shell.print(COLOR_BOLD_ON); shell.print(COLOR_BOLD_ON);

View File

@@ -54,19 +54,19 @@ using cmd_json_function_p = std::function<bool(const char * data, const int8_t i
class Command { class Command {
public: public:
struct CmdFunction { struct CmdFunction {
uint8_t device_type_; // DeviceType:: uint8_t device_type_; // DeviceType::
uint8_t flags_; // mqtt flags for command subscriptions uint8_t flags_; // mqtt flags for command subscriptions
const __FlashStringHelper * cmd_; const char * cmd_;
const cmd_function_p cmdfunction_; const cmd_function_p cmdfunction_;
const cmd_json_function_p cmdfunction_json_; const cmd_json_function_p cmdfunction_json_;
const __FlashStringHelper * description_; const char * description_;
CmdFunction(const uint8_t device_type, CmdFunction(const uint8_t device_type,
const uint8_t flags, const uint8_t flags,
const __FlashStringHelper * cmd, const char * cmd,
const cmd_function_p cmdfunction, const cmd_function_p cmdfunction,
const cmd_json_function_p cmdfunction_json, const cmd_json_function_p cmdfunction_json,
const __FlashStringHelper * description) const char * description)
: device_type_(device_type) : device_type_(device_type)
, flags_(flags) , flags_(flags)
, cmd_(cmd) , cmd_(cmd)
@@ -99,18 +99,12 @@ class Command {
static uint8_t call(const uint8_t device_type, const char * cmd, const char * value); static uint8_t call(const uint8_t device_type, const char * cmd, const char * value);
// with normal call back function taking a value and id // with normal call back function taking a value and id
static void add(const uint8_t device_type, static void
const __FlashStringHelper * cmd, add(const uint8_t device_type, const char * cmd, const cmd_function_p cb, const char * description, uint8_t flags = CommandFlag::MQTT_SUB_FLAG_DEFAULT);
const cmd_function_p cb,
const __FlashStringHelper * description,
uint8_t flags = CommandFlag::MQTT_SUB_FLAG_DEFAULT);
// callback function taking value, id and a json object for its output // callback function taking value, id and a json object for its output
static void add(const uint8_t device_type, static void
const __FlashStringHelper * cmd, add(const uint8_t device_type, const char * cmd, const cmd_json_function_p cb, const char * description, uint8_t flags = CommandFlag::MQTT_SUB_FLAG_DEFAULT);
const cmd_json_function_p cb,
const __FlashStringHelper * description,
uint8_t flags = CommandFlag::MQTT_SUB_FLAG_DEFAULT);
static void show_all(uuid::console::Shell & shell); static void show_all(uuid::console::Shell & shell);
static Command::CmdFunction * find_command(const uint8_t device_type, const char * cmd); static Command::CmdFunction * find_command(const uint8_t device_type, const char * cmd);

View File

@@ -31,29 +31,23 @@ using uuid::log::Level;
#define LOG_ERROR(...) logger_.err(__VA_ARGS__) #define LOG_ERROR(...) logger_.err(__VA_ARGS__)
// flash strings // flash strings
using uuid::flash_string_vector; using uuid::string_vector;
using uuid::read_flash_string; using string_vector = std::vector<const char *>;
#ifdef FPSTR #ifdef FPSTR
#undef FPSTR #undef FPSTR
#endif #endif
#define FJSON(x) x
// #define FJSON(x) F(x)
// clang-format off // clang-format off
#define MAKE_STR(string_name, string_literal) static constexpr const char * __str__##string_name = string_literal; #define FPSTR(pstr_pointer) pstr_pointer
#define MAKE_PSTR(string_name, string_literal) static const char __pstr__##string_name[] = string_literal;
#define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
#define F_(string_name) FPSTR(__pstr__##string_name)
#define MAKE_PSTR(string_name, string_literal) static const char __pstr__##string_name[] __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = string_literal;
#define MAKE_PSTR_WORD(string_name) MAKE_PSTR(string_name, #string_name) #define MAKE_PSTR_WORD(string_name) MAKE_PSTR(string_name, #string_name)
#define F_(string_name) (__pstr__##string_name)
#define FL_(list_name) (__pstr__L_##list_name) #define FL_(list_name) (__pstr__L_##list_name)
#define MAKE_PSTR_LIST(list_name, ...) static const __FlashStringHelper * const __pstr__L_##list_name[] PROGMEM = {__VA_ARGS__, nullptr}; #define MAKE_PSTR_LIST(list_name, ...) static const char * const __pstr__L_##list_name[] = {__VA_ARGS__, nullptr};
#define MAKE_PSTR_ENUM(enum_name, ...) static const __FlashStringHelper * const * __pstr__L_##enum_name[] PROGMEM = {__VA_ARGS__, nullptr}; #define MAKE_PSTR_ENUM(enum_name, ...) static const char * const * __pstr__L_##enum_name[] = {__VA_ARGS__, nullptr};
// clang-format on // clang-format on

View File

@@ -45,26 +45,26 @@ EMSESPShell::EMSESPShell()
} }
void EMSESPShell::started() { void EMSESPShell::started() {
logger().log(LogLevel::DEBUG, LogFacility::CONSOLE, F("User session opened on console %s"), console_name().c_str()); logger().log(LogLevel::DEBUG, LogFacility::CONSOLE, ("User session opened on console %s"), console_name().c_str());
} }
void EMSESPShell::stopped() { void EMSESPShell::stopped() {
if (has_flags(CommandFlags::ADMIN)) { if (has_flags(CommandFlags::ADMIN)) {
logger().log(LogLevel::DEBUG, LogFacility::AUTH, F("su session closed on console %s"), console_name().c_str()); logger().log(LogLevel::DEBUG, LogFacility::AUTH, ("su session closed on console %s"), console_name().c_str());
} }
logger().log(LogLevel::DEBUG, LogFacility::CONSOLE, F("User session closed on console %s"), console_name().c_str()); logger().log(LogLevel::DEBUG, LogFacility::CONSOLE, ("User session closed on console %s"), console_name().c_str());
} }
// show welcome banner // show welcome banner
// this is one of the first functions called when the shell is started // this is one of the first functions called when the shell is started
void EMSESPShell::display_banner() { void EMSESPShell::display_banner() {
println(); println();
printfln(F("┌──────────────────────────────────────┐")); printfln("┌──────────────────────────────────────┐");
printfln(F("│ %sEMS-ESP version %-10s%s │"), COLOR_BOLD_ON, EMSESP_APP_VERSION, COLOR_BOLD_OFF); printfln("│ %sEMS-ESP version %-10s%s │", COLOR_BOLD_ON, EMSESP_APP_VERSION, COLOR_BOLD_OFF);
printfln(F("│ %s%shttps://github.com/emsesp/EMS-ESP32%s │"), COLOR_BRIGHT_GREEN, COLOR_UNDERLINE, COLOR_RESET); printfln("│ %s%shttps://github.com/emsesp/EMS-ESP32%s │", COLOR_BRIGHT_GREEN, COLOR_UNDERLINE, COLOR_RESET);
printfln(F("│ │")); printfln("│ │");
printfln(F("│ type %shelp%s to show available commands │"), COLOR_UNDERLINE, COLOR_RESET); printfln("│ type %shelp%s to show available commands │", COLOR_UNDERLINE, COLOR_RESET);
printfln(F("└──────────────────────────────────────┘")); printfln("└──────────────────────────────────────┘");
println(); println();
// set console name // set console name
@@ -100,9 +100,9 @@ void EMSESPShell::add_console_commands() {
commands->add_command(ShellContext::MAIN, commands->add_command(ShellContext::MAIN,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(show)}, string_vector{F_(show)},
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
shell.printfln(F("%s%sEMS-ESP version %s%s"), COLOR_BRIGHT_GREEN, COLOR_BOLD_ON, EMSESP_APP_VERSION, COLOR_RESET); shell.printfln("%s%sEMS-ESP version %s%s", COLOR_BRIGHT_GREEN, COLOR_BOLD_ON, EMSESP_APP_VERSION, COLOR_RESET);
shell.println(); shell.println();
EMSESP::show_device_values(shell); EMSESP::show_device_values(shell);
EMSESP::show_sensor_values(shell); EMSESP::show_sensor_values(shell);
@@ -110,36 +110,36 @@ void EMSESPShell::add_console_commands() {
commands->add_command(ShellContext::MAIN, commands->add_command(ShellContext::MAIN,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(show), F_(devices)}, string_vector{F_(show), F_(devices)},
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { EMSESP::show_devices(shell); }); [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { EMSESP::show_devices(shell); });
commands->add_command(ShellContext::MAIN, commands->add_command(ShellContext::MAIN,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(show), F_(ems)}, string_vector{F_(show), F_(ems)},
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { EMSESP::show_ems(shell); }); [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { EMSESP::show_ems(shell); });
commands->add_command(ShellContext::MAIN, commands->add_command(ShellContext::MAIN,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(show), F_(values)}, string_vector{F_(show), F_(values)},
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { EMSESP::show_device_values(shell); }); [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { EMSESP::show_device_values(shell); });
commands->add_command(ShellContext::MAIN, commands->add_command(ShellContext::MAIN,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(show), F_(mqtt)}, string_vector{F_(show), F_(mqtt)},
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { Mqtt::show_mqtt(shell); }); [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { Mqtt::show_mqtt(shell); });
commands->add_command(ShellContext::MAIN, commands->add_command(ShellContext::MAIN,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(show), F_(commands)}, string_vector{F_(show), F_(commands)},
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { Command::show_all(shell); }); [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { Command::show_all(shell); });
commands->add_command( commands->add_command(
ShellContext::MAIN, ShellContext::MAIN,
CommandFlags::ADMIN, CommandFlags::ADMIN,
flash_string_vector{F_(set), F_(bus_id)}, string_vector{F_(set), F_(bus_id)},
flash_string_vector{F_(deviceid_mandatory)}, string_vector{F_(deviceid_mandatory)},
[](Shell & shell, const std::vector<std::string> & arguments) { [](Shell & shell, const std::vector<std::string> & arguments) {
uint8_t device_id = Helpers::hextoint(arguments.front().c_str()); uint8_t device_id = Helpers::hextoint(arguments.front().c_str());
if ((device_id == 0x0B) || (device_id == 0x0D) || (device_id == 0x0A) || (device_id == 0x0F) || (device_id == 0x12)) { if ((device_id == 0x0B) || (device_id == 0x0D) || (device_id == 0x0A) || (device_id == 0x0F) || (device_id == 0x12)) {
@@ -151,24 +151,24 @@ void EMSESPShell::add_console_commands() {
}, },
"local"); "local");
} else { } else {
shell.println(F("Must be 0B, 0D, 0A, 0F or 12")); shell.println("Must be 0B, 0D, 0A, 0F or 12");
} }
}, },
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> { [](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> {
return std::vector<std::string>{ return std::vector<std::string>{
read_flash_string(F("0B")), ("0B"),
read_flash_string(F("0D")), ("0D"),
read_flash_string(F("0A")), ("0A"),
read_flash_string(F("0F")), ("0F"),
read_flash_string(F("12")), ("12"),
}; };
}); });
commands->add_command(ShellContext::MAIN, commands->add_command(ShellContext::MAIN,
CommandFlags::ADMIN, CommandFlags::ADMIN,
flash_string_vector{F_(set), F_(tx_mode)}, string_vector{F_(set), F_(tx_mode)},
flash_string_vector{F_(n_mandatory)}, string_vector{F_(n_mandatory)},
[](Shell & shell, const std::vector<std::string> & arguments) { [](Shell & shell, const std::vector<std::string> & arguments) {
uint8_t tx_mode = std::strtol(arguments[0].c_str(), nullptr, 10); uint8_t tx_mode = std::strtol(arguments[0].c_str(), nullptr, 10);
// save the tx_mode // save the tx_mode
@@ -183,13 +183,13 @@ void EMSESPShell::add_console_commands() {
commands->add_command(ShellContext::MAIN, commands->add_command(ShellContext::MAIN,
CommandFlags::ADMIN, CommandFlags::ADMIN,
flash_string_vector{F_(scan), F_(devices)}, string_vector{F_(scan), F_(devices)},
flash_string_vector{F_(deep_optional)}, string_vector{F_(deep_optional)},
[](Shell & shell, const std::vector<std::string> & arguments) { [](Shell & shell, const std::vector<std::string> & arguments) {
if (arguments.size() == 0) { if (arguments.size() == 0) {
EMSESP::scan_devices(); EMSESP::scan_devices();
} else { } else {
shell.printfln(F("Performing a deep scan...")); shell.printfln("Performing a deep scan...");
EMSESP::clear_all_devices(); EMSESP::clear_all_devices();
std::vector<uint8_t> Device_Ids; std::vector<uint8_t> Device_Ids;
@@ -222,10 +222,10 @@ void EMSESPShell::add_console_commands() {
commands->add_command(ShellContext::MAIN, commands->add_command(ShellContext::MAIN,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(set)}, string_vector{F_(set)},
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
EMSESP::webSettingsService.read([&](WebSettings & settings) { EMSESP::webSettingsService.read([&](WebSettings & settings) {
shell.printfln(F("Language: %s"), settings.locale.c_str()); shell.printfln("Language: %s", settings.locale.c_str());
shell.printfln(F_(tx_mode_fmt), settings.tx_mode); shell.printfln(F_(tx_mode_fmt), settings.tx_mode);
shell.printfln(F_(bus_id_fmt), settings.ems_bus_id); shell.printfln(F_(bus_id_fmt), settings.ems_bus_id);
shell.printfln(F_(board_profile_fmt), settings.board_profile.c_str()); shell.printfln(F_(board_profile_fmt), settings.board_profile.c_str());
@@ -234,13 +234,13 @@ void EMSESPShell::add_console_commands() {
commands->add_command(ShellContext::MAIN, commands->add_command(ShellContext::MAIN,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(read)}, string_vector{F_(read)},
flash_string_vector{F_(deviceid_mandatory), F_(typeid_mandatory), F_(offset_optional), F_(length_optional)}, string_vector{F_(deviceid_mandatory), F_(typeid_mandatory), F_(offset_optional), F_(length_optional)},
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) { [=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
uint8_t device_id = Helpers::hextoint(arguments.front().c_str()); uint8_t device_id = Helpers::hextoint(arguments.front().c_str());
if (!EMSESP::valid_device(device_id)) { if (!EMSESP::valid_device(device_id)) {
shell.printfln(F("Invalid deviceID")); shell.printfln("Invalid deviceID");
return; return;
} }
@@ -261,31 +261,31 @@ void EMSESPShell::add_console_commands() {
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
commands->add_command(ShellContext::MAIN, commands->add_command(ShellContext::MAIN,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(set), F_(timeout)}, string_vector{F_(set), F_(timeout)},
flash_string_vector{F_(n_mandatory)}, string_vector{F_(n_mandatory)},
[](Shell & shell, const std::vector<std::string> & arguments) { [](Shell & shell, const std::vector<std::string> & arguments) {
uint16_t value = Helpers::atoint(arguments.front().c_str()); uint16_t value = Helpers::atoint(arguments.front().c_str());
telnet_.initial_idle_timeout(value * 60); telnet_.initial_idle_timeout(value * 60);
shell.printfln(F("Telnet timeout set to %d minutes"), value); shell.printfln("Telnet timeout set to %d minutes", value);
}); });
#endif #endif
commands->add_command(ShellContext::MAIN, commands->add_command(ShellContext::MAIN,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(watch)}, string_vector{F_(watch)},
flash_string_vector{F_(watch_format_optional), F_(watchid_optional)}, string_vector{F_(watch_format_optional), F_(watchid_optional)},
[](Shell & shell, const std::vector<std::string> & arguments) { [](Shell & shell, const std::vector<std::string> & arguments) {
uint16_t watch_id = WATCH_ID_NONE; uint16_t watch_id = WATCH_ID_NONE;
if (!arguments.empty()) { if (!arguments.empty()) {
// get raw/pretty // get raw/pretty
if (arguments[0] == read_flash_string(F_(raw))) { if (arguments[0] == (F_(raw))) {
EMSESP::watch(EMSESP::WATCH_RAW); // raw EMSESP::watch(EMSESP::WATCH_RAW); // raw
} else if (arguments[0] == Helpers::translated_word(FL_(on), true) || arguments[0] == read_flash_string(FL_(on)[0])) { } else if (arguments[0] == Helpers::translated_word(FL_(on), true) || arguments[0] == (FL_(on)[0])) {
EMSESP::watch(EMSESP::WATCH_ON); // on EMSESP::watch(EMSESP::WATCH_ON); // on
} else if (arguments[0] == Helpers::translated_word(FL_(off), true) || arguments[0] == read_flash_string(FL_(off)[0])) { } else if (arguments[0] == Helpers::translated_word(FL_(off), true) || arguments[0] == (FL_(off)[0])) {
EMSESP::watch(EMSESP::WATCH_OFF); // off EMSESP::watch(EMSESP::WATCH_OFF); // off
} else if (arguments[0] == Helpers::translated_word(FL_(unknown), true) || arguments[0] == read_flash_string(FL_(unknown)[0])) { } else if (arguments[0] == Helpers::translated_word(FL_(unknown), true) || arguments[0] == (FL_(unknown)[0])) {
EMSESP::watch(EMSESP::WATCH_UNKNOWN); // unknown EMSESP::watch(EMSESP::WATCH_UNKNOWN); // unknown
watch_id = WATCH_ID_NONE; watch_id = WATCH_ID_NONE;
} else { } else {
@@ -305,43 +305,43 @@ void EMSESPShell::add_console_commands() {
EMSESP::watch_id(watch_id); EMSESP::watch_id(watch_id);
} else { } else {
shell.printfln(F("Invalid: use watch raw|on|off|unknown|id [id]")); shell.printfln("Invalid: use watch raw|on|off|unknown|id [id]");
return; return;
} }
uint8_t watch = EMSESP::watch(); uint8_t watch = EMSESP::watch();
if (watch == EMSESP::WATCH_OFF) { if (watch == EMSESP::WATCH_OFF) {
shell.printfln(F("Watching telegrams is off")); shell.printfln("Watching telegrams is off");
return; return;
} }
// if logging is off, the watch won't show anything, show force it back to NOTICE // if logging is off, the watch won't show anything, show force it back to NOTICE
if (shell.log_level() < Level::NOTICE) { if (shell.log_level() < Level::NOTICE) {
shell.log_level(Level::NOTICE); shell.log_level(Level::NOTICE);
shell.printfln(F("Setting log level to Notice")); shell.printfln("Setting log level to Notice");
} }
if (watch == EMSESP::WATCH_ON) { if (watch == EMSESP::WATCH_ON) {
shell.printfln(F("Watching incoming telegrams, displayed in decoded format")); shell.printfln("Watching incoming telegrams, displayed in decoded format");
} else if (watch == EMSESP::WATCH_RAW) { } else if (watch == EMSESP::WATCH_RAW) {
shell.printfln(F("Watching incoming telegrams, displayed as raw bytes")); // WATCH_RAW shell.printfln("Watching incoming telegrams, displayed as raw bytes"); // WATCH_RAW
} else { } else {
shell.printfln(F("Watching unknown telegrams")); // WATCH_UNKNOWN shell.printfln("Watching unknown telegrams"); // WATCH_UNKNOWN
} }
watch_id = EMSESP::watch_id(); watch_id = EMSESP::watch_id();
if (watch_id > 0x80) { if (watch_id > 0x80) {
shell.printfln(F("Filtering only telegrams that match a telegram type of 0x%02X"), watch_id); shell.printfln("Filtering only telegrams that match a telegram type of 0x%02X", watch_id);
} else if (watch_id != WATCH_ID_NONE) { } else if (watch_id != WATCH_ID_NONE) {
shell.printfln(F("Filtering only telegrams that match a deviceID or telegram type of 0x%02X"), watch_id); shell.printfln("Filtering only telegrams that match a deviceID or telegram type of 0x%02X", watch_id);
} }
}); });
commands->add_command( commands->add_command(
ShellContext::MAIN, ShellContext::MAIN,
CommandFlags::ADMIN, CommandFlags::ADMIN,
flash_string_vector{F_(call)}, string_vector{F_(call)},
flash_string_vector{F_(device_type_optional), F_(cmd_optional), F_(data_optional), F_(id_optional)}, string_vector{F_(device_type_optional), F_(cmd_optional), F_(data_optional), F_(id_optional)},
[&](Shell & shell, const std::vector<std::string> & arguments) { [&](Shell & shell, const std::vector<std::string> & arguments) {
if (arguments.empty()) { if (arguments.empty()) {
Command::show_all(shell); // list options Command::show_all(shell); // list options
@@ -351,7 +351,7 @@ void EMSESPShell::add_console_commands() {
// validate the device_type // validate the device_type
uint8_t device_type = EMSdevice::device_name_2_device_type(arguments[0].c_str()); uint8_t device_type = EMSdevice::device_name_2_device_type(arguments[0].c_str());
if (!Command::device_has_commands(device_type)) { if (!Command::device_has_commands(device_type)) {
shell.print(F("Invalid device. Available devices are: ")); shell.print("Invalid device. Available devices are: ");
Command::show_devices(shell); Command::show_devices(shell);
return; return;
} }
@@ -359,7 +359,7 @@ void EMSESPShell::add_console_commands() {
// validate that a command is present // validate that a command is present
if (arguments.size() < 2) { if (arguments.size() < 2) {
shell.print(F("Missing command. Available commands are: ")); shell.print("Missing command. Available commands are: ");
Command::show(shell, device_type, false); // non-verbose mode Command::show(shell, device_type, false); // non-verbose mode
return; return;
} }
@@ -399,11 +399,11 @@ void EMSESPShell::add_console_commands() {
} }
if (return_code == CommandRet::NOT_FOUND) { if (return_code == CommandRet::NOT_FOUND) {
shell.println(F("Unknown command")); shell.println("Unknown command");
shell.print(F("Available commands are: ")); shell.print("Available commands are: ");
Command::show(shell, device_type, false); // non-verbose mode Command::show(shell, device_type, false); // non-verbose mode
} else if (return_code != CommandRet::OK) { } else if (return_code != CommandRet::OK) {
shell.printfln(F("Bad syntax (error code %d)"), return_code); shell.printfln(("Bad syntax (error code %d)"), return_code);
} }
}, },
[&](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) -> std::vector<std::string> { [&](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) -> std::vector<std::string> {
@@ -424,7 +424,7 @@ void EMSESPShell::add_console_commands() {
if (Command::device_has_commands(device_type)) { if (Command::device_has_commands(device_type)) {
for (const auto & cf : Command::commands()) { for (const auto & cf : Command::commands()) {
if (cf.device_type_ == device_type) { if (cf.device_type_ == device_type) {
command_list.emplace_back(read_flash_string(cf.cmd_)); command_list.emplace_back((cf.cmd_));
} }
} }
return command_list; return command_list;
@@ -448,8 +448,8 @@ void Console::load_standard_commands(unsigned int context) {
// create commands test and t // create commands test and t
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F("test")}, string_vector{("test")},
flash_string_vector{F_(name_optional), F_(data_optional)}, string_vector{F_(name_optional), F_(data_optional)},
[](Shell & shell, const std::vector<std::string> & arguments) { [](Shell & shell, const std::vector<std::string> & arguments) {
if (arguments.empty()) { if (arguments.empty()) {
Test::run_test(shell, "default"); Test::run_test(shell, "default");
@@ -460,7 +460,7 @@ void Console::load_standard_commands(unsigned int context) {
} }
}); });
EMSESPShell::commands->add_command(context, CommandFlags::USER, flash_string_vector{F("t")}, [](Shell & shell, const std::vector<std::string> & arguments) { EMSESPShell::commands->add_command(context, CommandFlags::USER, string_vector{("t")}, [](Shell & shell, const std::vector<std::string> & arguments) {
Test::run_test(shell, "default"); Test::run_test(shell, "default");
}); });
#endif #endif
@@ -468,8 +468,8 @@ void Console::load_standard_commands(unsigned int context) {
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(debug)}, string_vector{F_(debug)},
flash_string_vector{F_(name_optional)}, string_vector{F_(name_optional)},
[](Shell & shell, const std::vector<std::string> & arguments) { [](Shell & shell, const std::vector<std::string> & arguments) {
if (arguments.empty()) { if (arguments.empty()) {
Test::debug(shell, "default"); Test::debug(shell, "default");
@@ -482,8 +482,8 @@ void Console::load_standard_commands(unsigned int context) {
EMSESPShell::commands->add_command( EMSESPShell::commands->add_command(
context, context,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(log)}, string_vector{F_(log)},
flash_string_vector{F_(log_level_optional)}, string_vector{F_(log_level_optional)},
[](Shell & shell, const std::vector<std::string> & arguments) { [](Shell & shell, const std::vector<std::string> & arguments) {
if (!arguments.empty()) { if (!arguments.empty()) {
uuid::log::Level level; uuid::log::Level level;
@@ -494,7 +494,7 @@ void Console::load_standard_commands(unsigned int context) {
return; return;
} }
} else { } else {
shell.print(F("levels: ")); shell.print("levels: ");
std::vector<std::string> v = uuid::log::levels_lowercase(); std::vector<std::string> v = uuid::log::levels_lowercase();
size_t i = v.size(); size_t i = v.size();
while (i--) { while (i--) {
@@ -511,22 +511,22 @@ void Console::load_standard_commands(unsigned int context) {
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(help)}, string_vector{F_(help)},
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
shell.print_all_available_commands(); shell.print_all_available_commands();
}); });
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(exit)}, string_vector{F_(exit)},
[=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { shell.stop(); }); [=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { shell.stop(); });
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(su)}, string_vector{F_(su)},
[=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { [=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
auto become_admin = [](Shell & shell) { auto become_admin = [](Shell & shell) {
shell.logger().log(LogLevel::NOTICE, LogFacility::AUTH, F("su session opened on console")); shell.logger().log(LogLevel::NOTICE, LogFacility::AUTH, ("su session opened on console"));
shell.add_flags(CommandFlags::ADMIN); shell.add_flags(CommandFlags::ADMIN);
}; };
@@ -542,8 +542,8 @@ void Console::load_standard_commands(unsigned int context) {
become_admin(shell); become_admin(shell);
} else { } else {
shell.delay_until(now + INVALID_PASSWORD_DELAY_MS, [](Shell & shell) { shell.delay_until(now + INVALID_PASSWORD_DELAY_MS, [](Shell & shell) {
shell.logger().log(LogLevel::NOTICE, LogFacility::AUTH, F("Invalid su password on console")); shell.logger().log(LogLevel::NOTICE, LogFacility::AUTH, ("Invalid su password on console"));
shell.println(F("su: incorrect password")); shell.println("su: incorrect password");
}); });
} }
}); });
@@ -557,21 +557,21 @@ void Console::load_standard_commands(unsigned int context) {
void Console::load_system_commands(unsigned int context) { void Console::load_system_commands(unsigned int context) {
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,
CommandFlags::ADMIN, CommandFlags::ADMIN,
flash_string_vector{F_(restart)}, string_vector{F_(restart)},
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) { [](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) {
EMSESP::system_.system_restart(); EMSESP::system_.system_restart();
}); });
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,
CommandFlags::ADMIN, CommandFlags::ADMIN,
flash_string_vector{F_(wifi), F_(reconnect)}, string_vector{F_(wifi), F_(reconnect)},
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) { [](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) {
EMSESP::system_.wifi_reconnect(); EMSESP::system_.wifi_reconnect();
}); });
EMSESPShell::commands->add_command(ShellContext::MAIN, EMSESPShell::commands->add_command(ShellContext::MAIN,
CommandFlags::ADMIN, CommandFlags::ADMIN,
flash_string_vector{F_(format)}, string_vector{F_(format)},
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
shell.enter_password(F_(password_prompt), [=](Shell & shell, bool completed, const std::string & password) { shell.enter_password(F_(password_prompt), [=](Shell & shell, bool completed, const std::string & password) {
if (completed) { if (completed) {
@@ -579,7 +579,7 @@ void Console::load_system_commands(unsigned int context) {
if (securitySettings.jwtSecret.equals(password.c_str())) { if (securitySettings.jwtSecret.equals(password.c_str())) {
EMSESP::system_.format(shell); EMSESP::system_.format(shell);
} else { } else {
shell.println(F("incorrect password")); shell.println("incorrect password");
} }
}); });
} }
@@ -588,7 +588,7 @@ void Console::load_system_commands(unsigned int context) {
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,
CommandFlags::ADMIN, CommandFlags::ADMIN,
flash_string_vector{F_(passwd)}, string_vector{F_(passwd)},
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
shell.enter_password(F_(new_password_prompt1), [](Shell & shell, bool completed, const std::string & password1) { shell.enter_password(F_(new_password_prompt1), [](Shell & shell, bool completed, const std::string & password1) {
if (completed) { if (completed) {
@@ -602,9 +602,9 @@ void Console::load_system_commands(unsigned int context) {
return StateUpdateResult::CHANGED; return StateUpdateResult::CHANGED;
}, },
"local"); "local");
shell.println(F("su password updated")); shell.println("su password updated");
} else { } else {
shell.println(F("Passwords do not match")); shell.println("Passwords do not match");
} }
} }
}); });
@@ -614,7 +614,7 @@ void Console::load_system_commands(unsigned int context) {
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(show), F_(system)}, string_vector{F_(show), F_(system)},
[=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { [=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
EMSESP::system_.show_system(shell); EMSESP::system_.show_system(shell);
shell.println(); shell.println();
@@ -622,8 +622,8 @@ void Console::load_system_commands(unsigned int context) {
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,
CommandFlags::ADMIN, CommandFlags::ADMIN,
flash_string_vector{F_(set), F_(hostname)}, string_vector{F_(set), F_(hostname)},
flash_string_vector{F_(name_mandatory)}, string_vector{F_(name_mandatory)},
[](Shell & shell, const std::vector<std::string> & arguments) { [](Shell & shell, const std::vector<std::string> & arguments) {
shell.println("The network connection will be reset..."); shell.println("The network connection will be reset...");
Shell::loop_all(); Shell::loop_all();
@@ -638,8 +638,8 @@ void Console::load_system_commands(unsigned int context) {
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,
CommandFlags::ADMIN, CommandFlags::ADMIN,
flash_string_vector{F_(set), F_(wifi), F_(ssid)}, string_vector{F_(set), F_(wifi), F_(ssid)},
flash_string_vector{F_(name_mandatory)}, string_vector{F_(name_mandatory)},
[](Shell & shell, const std::vector<std::string> & arguments) { [](Shell & shell, const std::vector<std::string> & arguments) {
EMSESP::esp8266React.getNetworkSettingsService()->updateWithoutPropagation([&](NetworkSettings & networkSettings) { EMSESP::esp8266React.getNetworkSettingsService()->updateWithoutPropagation([&](NetworkSettings & networkSettings) {
networkSettings.ssid = arguments.front().c_str(); networkSettings.ssid = arguments.front().c_str();
@@ -651,8 +651,8 @@ void Console::load_system_commands(unsigned int context) {
// added by mvdp // added by mvdp
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,
CommandFlags::ADMIN, CommandFlags::ADMIN,
flash_string_vector{F("mqtt"), F("subscribe")}, string_vector{("mqtt"), ("subscribe")},
flash_string_vector{F("<topic>")}, string_vector{("<topic>")},
[](Shell & shell, const std::vector<std::string> & arguments) { [](Shell & shell, const std::vector<std::string> & arguments) {
Mqtt::subscribe(arguments.front()); Mqtt::subscribe(arguments.front());
shell.println("subscribing"); shell.println("subscribing");
@@ -660,7 +660,7 @@ void Console::load_system_commands(unsigned int context) {
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,
CommandFlags::ADMIN, CommandFlags::ADMIN,
flash_string_vector{F_(set), F_(wifi), F_(password)}, string_vector{F_(set), F_(wifi), F_(password)},
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
shell.enter_password(F_(new_password_prompt1), [](Shell & shell, bool completed, const std::string & password1) { shell.enter_password(F_(new_password_prompt1), [](Shell & shell, bool completed, const std::string & password1) {
if (completed) { if (completed) {
@@ -675,7 +675,7 @@ void Console::load_system_commands(unsigned int context) {
}); });
shell.println("Use `wifi reconnect` to save and apply the new settings"); shell.println("Use `wifi reconnect` to save and apply the new settings");
} else { } else {
shell.println(F("Passwords do not match")); shell.println("Passwords do not match");
} }
} }
}); });
@@ -685,13 +685,13 @@ void Console::load_system_commands(unsigned int context) {
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,
CommandFlags::ADMIN, CommandFlags::ADMIN,
flash_string_vector{F_(set), F_(board_profile)}, string_vector{F_(set), F_(board_profile)},
flash_string_vector{F_(name_mandatory)}, string_vector{F_(name_mandatory)},
[](Shell & shell, const std::vector<std::string> & arguments) { [](Shell & shell, const std::vector<std::string> & arguments) {
std::vector<int8_t> data; // led, dallas, rx, tx, button, phy_type, eth_power, eth_phy_addr, eth_clock_mode std::vector<int8_t> data; // led, dallas, rx, tx, button, phy_type, eth_power, eth_phy_addr, eth_clock_mode
std::string board_profile = Helpers::toUpper(arguments.front()); std::string board_profile = Helpers::toUpper(arguments.front());
if (!EMSESP::system_.load_board_profile(data, board_profile)) { if (!EMSESP::system_.load_board_profile(data, board_profile)) {
shell.println(F("Invalid board profile (S32, E32, MH-ET, NODEMCU, OLIMEX, OLIMEXPOE, C3MINI, CUSTOM)")); shell.println(("Invalid board profile (S32, E32, MH-ET, NODEMCU, OLIMEX, OLIMEXPOE, C3MINI, CUSTOM)"));
return; return;
} }
EMSESP::webSettingsService.update( EMSESP::webSettingsService.update(
@@ -714,7 +714,7 @@ void Console::load_system_commands(unsigned int context) {
}); });
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,
CommandFlags::ADMIN, CommandFlags::ADMIN,
flash_string_vector{F_(show), F_(users)}, string_vector{F_(show), F_(users)},
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
EMSESP::system_.show_users(shell); EMSESP::system_.show_users(shell);
}); });
@@ -730,14 +730,14 @@ std::string EMSESPShell::prompt_suffix() {
} }
void EMSESPShell::end_of_transmission() { void EMSESPShell::end_of_transmission() {
invoke_command(read_flash_string(F_(exit))); invoke_command((F_(exit)));
} }
EMSESPStreamConsole::EMSESPStreamConsole(Stream & stream, bool local) EMSESPStreamConsole::EMSESPStreamConsole(Stream & stream, bool local)
: uuid::console::Shell(commands, ShellContext::MAIN, local ? (CommandFlags::USER | CommandFlags::LOCAL) : CommandFlags::USER) : uuid::console::Shell(commands, ShellContext::MAIN, local ? (CommandFlags::USER | CommandFlags::LOCAL) : CommandFlags::USER)
, uuid::console::StreamConsole(stream) , uuid::console::StreamConsole(stream)
, EMSESPShell() , EMSESPShell()
, name_(read_flash_string(F("Serial"))) , name_("Serial")
, pty_(SIZE_MAX) , pty_(SIZE_MAX)
, addr_() , addr_()
, port_(0) { , port_(0) {
@@ -763,14 +763,14 @@ EMSESPStreamConsole::EMSESPStreamConsole(Stream & stream, const IPAddress & addr
snprintf(text.data(), text.size(), "pty%u", (uint16_t)pty_); snprintf(text.data(), text.size(), "pty%u", (uint16_t)pty_);
name_ = text.data(); name_ = text.data();
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
logger().info(F("Allocated console %s for connection from [%s]:%u"), name_.c_str(), uuid::printable_to_string(addr_).c_str(), port_); logger().info("Allocated console %s for connection from [%s]:%u", name_.c_str(), uuid::printable_to_string(addr_).c_str(), port_);
#endif #endif
} }
EMSESPStreamConsole::~EMSESPStreamConsole() { EMSESPStreamConsole::~EMSESPStreamConsole() {
if (pty_ != SIZE_MAX) { if (pty_ != SIZE_MAX) {
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
logger().info(F("Shutdown console %s for connection from [%s]:%u"), name_.c_str(), uuid::printable_to_string(addr_).c_str(), port_); logger().info("Shutdown console %s for connection from [%s]:%u", name_.c_str(), uuid::printable_to_string(addr_).c_str(), port_);
#endif #endif
ptys_[pty_] = false; ptys_[pty_] = false;
ptys_.shrink_to_fit(); ptys_.shrink_to_fit();

View File

@@ -42,7 +42,7 @@ void DallasSensor::start() {
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
bus_.begin(dallas_gpio_); bus_.begin(dallas_gpio_);
LOG_INFO(F("Starting Dallas sensor service")); LOG_INFO("Starting Dallas sensor service");
#endif #endif
// Add API calls // Add API calls
@@ -84,7 +84,7 @@ void DallasSensor::loop() {
if (state_ == State::IDLE) { if (state_ == State::IDLE) {
if (time_now - last_activity_ >= READ_INTERVAL_MS) { if (time_now - last_activity_ >= READ_INTERVAL_MS) {
#ifdef EMSESP_DEBUG_SENSOR #ifdef EMSESP_DEBUG_SENSOR
LOG_DEBUG(F("[DEBUG] Read sensor temperature")); LOG_DEBUG("[DEBUG] Read sensor temperature");
#endif #endif
if (bus_.reset() || parasite_) { if (bus_.reset() || parasite_) {
YIELD; YIELD;
@@ -99,7 +99,7 @@ void DallasSensor::loop() {
if (++scanretry_ > SCAN_MAX) { // every 30 sec if (++scanretry_ > SCAN_MAX) { // every 30 sec
scanretry_ = 0; scanretry_ = 0;
#ifdef EMSESP_DEBUG_SENSOR #ifdef EMSESP_DEBUG_SENSOR
LOG_ERROR(F("Bus reset failed")); LOG_ERROR("Bus reset failed");
#endif #endif
for (auto & sensor : sensors_) { for (auto & sensor : sensors_) {
sensor.temperature_c = EMS_VALUE_SHORT_NOTSET; sensor.temperature_c = EMS_VALUE_SHORT_NOTSET;
@@ -112,13 +112,13 @@ void DallasSensor::loop() {
} else if (state_ == State::READING) { } else if (state_ == State::READING) {
if (temperature_convert_complete() && (time_now - last_activity_ > CONVERSION_MS)) { if (temperature_convert_complete() && (time_now - last_activity_ > CONVERSION_MS)) {
#ifdef EMSESP_DEBUG_SENSOR #ifdef EMSESP_DEBUG_SENSOR
LOG_DEBUG(F("Scanning for sensors")); LOG_DEBUG("Scanning for sensors");
#endif #endif
bus_.reset_search(); bus_.reset_search();
state_ = State::SCANNING; state_ = State::SCANNING;
} else if (time_now - last_activity_ > READ_TIMEOUT_MS) { } else if (time_now - last_activity_ > READ_TIMEOUT_MS) {
#ifdef EMSESP_DEBUG_SENSOR #ifdef EMSESP_DEBUG_SENSOR
LOG_WARNING(F("Dallas sensor read timeout")); LOG_WARNING("Dallas sensor read timeout");
#endif #endif
state_ = State::IDLE; state_ = State::IDLE;
sensorfails_++; sensorfails_++;
@@ -126,7 +126,7 @@ void DallasSensor::loop() {
} else if (state_ == State::SCANNING) { } else if (state_ == State::SCANNING) {
if (time_now - last_activity_ > SCAN_TIMEOUT_MS) { if (time_now - last_activity_ > SCAN_TIMEOUT_MS) {
#ifdef EMSESP_DEBUG_SENSOR #ifdef EMSESP_DEBUG_SENSOR
LOG_ERROR(F("Dallas sensor scan timeout")); LOG_ERROR("Dallas sensor scan timeout");
#endif #endif
state_ = State::IDLE; state_ = State::IDLE;
sensorfails_++; sensorfails_++;
@@ -181,12 +181,12 @@ void DallasSensor::loop() {
default: default:
sensorfails_++; sensorfails_++;
LOG_ERROR(F("Unknown dallas sensor %s"), Sensor(addr).id().c_str()); LOG_ERROR("Unknown dallas sensor %s", Sensor(addr).id().c_str());
break; break;
} }
} else { } else {
sensorfails_++; sensorfails_++;
LOG_ERROR(F("Invalid dallas sensor %s"), Sensor(addr).id().c_str()); LOG_ERROR("Invalid dallas sensor %s", Sensor(addr).id().c_str());
} }
} else { } else {
if (!parasite_) { if (!parasite_) {
@@ -204,7 +204,7 @@ void DallasSensor::loop() {
scancnt_ = 0; scancnt_ = 0;
} else if (scancnt_ == SCAN_START + 1) { // startup } else if (scancnt_ == SCAN_START + 1) { // startup
firstscan_ = sensors_.size(); firstscan_ = sensors_.size();
// LOG_DEBUG(F("Adding %d dallas sensor(s) from first scan"), firstscan_); // LOG_DEBUG(("Adding %d dallas sensor(s) from first scan"), firstscan_);
} else if ((scancnt_ <= 0) && (firstscan_ != sensors_.size())) { // check 2 times for no change of sensor # } else if ((scancnt_ <= 0) && (firstscan_ != sensors_.size())) { // check 2 times for no change of sensor #
scancnt_ = SCAN_START; scancnt_ = SCAN_START;
sensors_.clear(); // restart scaning and clear to get correct numbering sensors_.clear(); // restart scaning and clear to get correct numbering
@@ -230,7 +230,7 @@ bool DallasSensor::temperature_convert_complete() {
int16_t DallasSensor::get_temperature_c(const uint8_t addr[]) { int16_t DallasSensor::get_temperature_c(const uint8_t addr[]) {
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
if (!bus_.reset()) { if (!bus_.reset()) {
LOG_ERROR(F("Bus reset failed before reading scratchpad from %s"), Sensor(addr).id().c_str()); LOG_ERROR("Bus reset failed before reading scratchpad from %s", Sensor(addr).id().c_str());
return EMS_VALUE_SHORT_NOTSET; return EMS_VALUE_SHORT_NOTSET;
} }
YIELD; YIELD;
@@ -242,13 +242,13 @@ int16_t DallasSensor::get_temperature_c(const uint8_t addr[]) {
YIELD; YIELD;
if (!bus_.reset()) { if (!bus_.reset()) {
LOG_ERROR(F("Bus reset failed after reading scratchpad from %s"), Sensor(addr).id().c_str()); LOG_ERROR("Bus reset failed after reading scratchpad from %s", Sensor(addr).id().c_str());
return EMS_VALUE_SHORT_NOTSET; return EMS_VALUE_SHORT_NOTSET;
} }
YIELD; YIELD;
if (bus_.crc8(scratchpad, SCRATCHPAD_LEN - 1) != scratchpad[SCRATCHPAD_LEN - 1]) { if (bus_.crc8(scratchpad, SCRATCHPAD_LEN - 1) != scratchpad[SCRATCHPAD_LEN - 1]) {
LOG_WARNING(F("Invalid scratchpad CRC: %02X%02X%02X%02X%02X%02X%02X%02X%02X from sensor %s"), LOG_WARNING("Invalid scratchpad CRC: %02X%02X%02X%02X%02X%02X%02X%02X%02X from sensor %s",
scratchpad[0], scratchpad[0],
scratchpad[1], scratchpad[1],
scratchpad[2], scratchpad[2],
@@ -315,7 +315,7 @@ bool DallasSensor::update(const std::string & id, const std::string & name, int1
SensorCustomization.name = name; SensorCustomization.name = name;
SensorCustomization.offset = offset; SensorCustomization.offset = offset;
found = true; found = true;
LOG_DEBUG(F("Customizing existing sensor ID %s"), id.c_str()); LOG_DEBUG("Customizing existing sensor ID %s", id.c_str());
break; break;
} }
} }
@@ -325,7 +325,7 @@ bool DallasSensor::update(const std::string & id, const std::string & name, int1
newSensor.name = name; newSensor.name = name;
newSensor.offset = offset; newSensor.offset = offset;
settings.sensorCustomizations.push_back(newSensor); settings.sensorCustomizations.push_back(newSensor);
LOG_DEBUG(F("Adding new customization for sensor ID %s"), id.c_str()); LOG_DEBUG("Adding new customization for sensor ID %s", id.c_str());
} }
sensor.ha_registered = false; // it's changed so we may need to recreate the HA config sensor.ha_registered = false; // it's changed so we may need to recreate the HA config
return StateUpdateResult::CHANGED; return StateUpdateResult::CHANGED;
@@ -397,11 +397,13 @@ bool DallasSensor::get_value_info(JsonObject & output, const char * cmd, const i
if (Helpers::hasValue(sensor.temperature_c)) { if (Helpers::hasValue(sensor.temperature_c)) {
output["value"] = serialized(Helpers::render_value(val, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0)); output["value"] = serialized(Helpers::render_value(val, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0));
} }
output["type"] = F_(number); output["type"] = F_(number);
output["min"] = serialized(Helpers::render_value(val, -55, 0, EMSESP::system_.fahrenheit() ? 2 : 0)); output["min"] = serialized(Helpers::render_value(val, -55, 0, EMSESP::system_.fahrenheit() ? 2 : 0));
output["max"] = serialized(Helpers::render_value(val, 125, 0, EMSESP::system_.fahrenheit() ? 2 : 0)); output["max"] = serialized(Helpers::render_value(val, 125, 0, EMSESP::system_.fahrenheit() ? 2 : 0));
output["uom"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES); output["uom"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES);
output["writeable"] = false; output["writeable"] = false;
// if we're filtering on an attribute, go find it // if we're filtering on an attribute, go find it
if (attribute_s) { if (attribute_s) {
if (output.containsKey(attribute_s)) { if (output.containsKey(attribute_s)) {
@@ -428,9 +430,9 @@ void DallasSensor::publish_sensor(const Sensor & sensor) {
if (Mqtt::publish_single()) { if (Mqtt::publish_single()) {
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
if (Mqtt::publish_single2cmd()) { if (Mqtt::publish_single2cmd()) {
snprintf(topic, sizeof(topic), "%s/%s", read_flash_string(F_(dallassensor)).c_str(), sensor.name().c_str()); snprintf(topic, sizeof(topic), "%s/%s", (F_(dallassensor)), sensor.name().c_str());
} else { } else {
snprintf(topic, sizeof(topic), "%s%s/%s", read_flash_string(F_(dallassensor)).c_str(), "_data", sensor.name().c_str()); snprintf(topic, sizeof(topic), "%s%s/%s", (F_(dallassensor)), "_data", sensor.name().c_str());
} }
char payload[10]; char payload[10];
Mqtt::publish(topic, Helpers::render_value(payload, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0)); Mqtt::publish(topic, Helpers::render_value(payload, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0));
@@ -443,7 +445,7 @@ void DallasSensor::remove_ha_topic(const std::string & id) {
return; return;
} }
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG
LOG_DEBUG(F("Removing HA config for temperature sensor ID %s"), id.c_str()); LOG_DEBUG("Removing HA config for temperature sensor ID %s", id.c_str());
#endif #endif
// use '_' as HA doesn't like '-' in the topic name // use '_' as HA doesn't like '-' in the topic name
std::string sensorid = id; std::string sensorid = id;
@@ -486,10 +488,10 @@ void DallasSensor::publish_values(const bool force) {
// to e.g. homeassistant/sensor/ems-esp/dallassensor_28-233D-9497-0C03/config // to e.g. homeassistant/sensor/ems-esp/dallassensor_28-233D-9497-0C03/config
if (Mqtt::ha_enabled()) { if (Mqtt::ha_enabled()) {
if (!sensor.ha_registered || force) { if (!sensor.ha_registered || force) {
LOG_DEBUG(F("Recreating HA config for sensor ID %s"), sensor.id().c_str()); LOG_DEBUG("Recreating HA config for sensor ID %s", sensor.id().c_str());
StaticJsonDocument<EMSESP_JSON_SIZE_MEDIUM> config; StaticJsonDocument<EMSESP_JSON_SIZE_MEDIUM> config;
config["dev_cla"] = FJSON("temperature"); config["dev_cla"] = "temperature";
char stat_t[50]; char stat_t[50];
snprintf(stat_t, sizeof(stat_t), "%s/dallassensor_data", Mqtt::base().c_str()); snprintf(stat_t, sizeof(stat_t), "%s/dallassensor_data", Mqtt::base().c_str());
@@ -533,7 +535,7 @@ void DallasSensor::publish_values(const bool force) {
} }
} }
Mqtt::publish(F("dallassensor_data"), doc.as<JsonObject>()); Mqtt::publish("dallassensor_data", doc.as<JsonObject>());
} }
@@ -577,7 +579,7 @@ bool DallasSensor::Sensor::apply_customization() {
if (!sensors.empty()) { if (!sensors.empty()) {
for (const auto & sensor : sensors) { for (const auto & sensor : sensors) {
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
LOG_DEBUG(F("Loading customization for dallas sensor %s"), sensor.id.c_str()); LOG_DEBUG("Loading customization for dallas sensor %s", sensor.id.c_str());
#endif #endif
if (id_ == sensor.id) { if (id_ == sensor.id) {
set_name(sensor.name); set_name(sensor.name);

View File

@@ -24,142 +24,142 @@
*/ */
// Boilers - 0x08 // Boilers - 0x08
{ 64, DeviceType::BOILER, F("BK13/BK15/Smartline/GB1x2"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, { 64, DeviceType::BOILER, "BK13/BK15/Smartline/GB1x2", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 72, DeviceType::BOILER, F("GB125/MC10"), DeviceFlags::EMS_DEVICE_FLAG_EMS}, { 72, DeviceType::BOILER, "GB125/MC10", DeviceFlags::EMS_DEVICE_FLAG_EMS},
{ 81, DeviceType::BOILER, F("Cascade CM10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, { 81, DeviceType::BOILER, "Cascade CM10", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 84, DeviceType::BOILER, F("Logamax Plus GB022"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, { 84, DeviceType::BOILER, "Logamax Plus GB022", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 95, DeviceType::BOILER, F("Condens 2500/Logamax/Logomatic/Cerapur Top/Greenstar/Generic HT3"), DeviceFlags::EMS_DEVICE_FLAG_HT3}, { 95, DeviceType::BOILER, "Condens 2500/Logamax/Logomatic/Cerapur Top/Greenstar/Generic HT3", DeviceFlags::EMS_DEVICE_FLAG_HT3},
{115, DeviceType::BOILER, F("Topline/GB162"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {115, DeviceType::BOILER, "Topline/GB162", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{122, DeviceType::BOILER, F("Proline"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {122, DeviceType::BOILER, "Proline", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{123, DeviceType::BOILER, F("GBx72/Trendline/Cerapur/Greenstar Si/27i"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {123, DeviceType::BOILER, "GBx72/Trendline/Cerapur/Greenstar Si/27i", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{131, DeviceType::BOILER, F("GB212"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {131, DeviceType::BOILER, "GB212", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{132, DeviceType::BOILER, F("GC7000F"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {132, DeviceType::BOILER, "GC7000F", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{133, DeviceType::BOILER, F("Logano GB125/KB195i/Logamatic MC110"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {133, DeviceType::BOILER, "Logano GB125/KB195i/Logamatic MC110", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{154, DeviceType::BOILER, F("Greenstar 30Ri Compact"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {154, DeviceType::BOILER, "Greenstar 30Ri Compact", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{167, DeviceType::BOILER, F("Cerapur Aero"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {167, DeviceType::BOILER, "Cerapur Aero", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{168, DeviceType::BOILER, F("Hybrid Heatpump"), DeviceFlags::EMS_DEVICE_FLAG_HYBRID}, {168, DeviceType::BOILER, "Hybrid Heatpump", DeviceFlags::EMS_DEVICE_FLAG_HYBRID},
{170, DeviceType::BOILER, F("Logano GB212"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {170, DeviceType::BOILER, "Logano GB212", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{172, DeviceType::BOILER, F("Enviline/Compress 6000AW/Hybrid 7000iAW/SupraEco/Geo 5xx"), DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP}, {172, DeviceType::BOILER, "Enviline/Compress 6000AW/Hybrid 7000iAW/SupraEco/Geo 5xx", DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP},
{173, DeviceType::BOILER, F("Geo 5xx"), DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP}, {173, DeviceType::BOILER, "Geo 5xx", DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP},
{195, DeviceType::BOILER, F("Condens 5000i/Greenstar 8000"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {195, DeviceType::BOILER, "Condens 5000i/Greenstar 8000", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{203, DeviceType::BOILER, F("Logamax U122/Cerapur"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {203, DeviceType::BOILER, "Logamax U122/Cerapur", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{206, DeviceType::BOILER, F("Ecomline Excellent"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {206, DeviceType::BOILER, "Ecomline Excellent", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{208, DeviceType::BOILER, F("Logamax Plus/GB192/Condens GC9000"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {208, DeviceType::BOILER, "Logamax Plus/GB192/Condens GC9000", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{210, DeviceType::BOILER, F("Cascade MC400"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {210, DeviceType::BOILER, "Cascade MC400", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{211, DeviceType::BOILER, F("EasyControl Adapter"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {211, DeviceType::BOILER, "EasyControl Adapter", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{228, DeviceType::BOILER, F("Alternative Heatsource"), DeviceFlags::EMS_DEVICE_FLAG_AM200}, {228, DeviceType::BOILER, "Alternative Heatsource", DeviceFlags::EMS_DEVICE_FLAG_AM200},
{234, DeviceType::BOILER, F("Logamax Plus GB122/Condense 2300"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {234, DeviceType::BOILER, "Logamax Plus GB122/Condense 2300", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Controllers - 0x09 / 0x10 / 0x50 // Controllers - 0x09 / 0x10 / 0x50
{ 68, DeviceType::CONTROLLER, F("BC10/RFM20"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 { 68, DeviceType::CONTROLLER, "BC10/RFM20", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{ 81, DeviceType::CONTROLLER, F("CM10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, { 81, DeviceType::CONTROLLER, "CM10", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 84, DeviceType::CONTROLLER, F("GB022"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, { 84, DeviceType::CONTROLLER, "GB022", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 89, DeviceType::CONTROLLER, F("BC10 GB142"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 { 89, DeviceType::CONTROLLER, "BC10 GB142", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{ 95, DeviceType::CONTROLLER, F("HT3"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 { 95, DeviceType::CONTROLLER, "HT3", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{114, DeviceType::CONTROLLER, F("BC10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {114, DeviceType::CONTROLLER, "BC10", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{125, DeviceType::CONTROLLER, F("BC25"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {125, DeviceType::CONTROLLER, "BC25", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{152, DeviceType::CONTROLLER, F("Controller"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {152, DeviceType::CONTROLLER, "Controller", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{168, DeviceType::CONTROLLER, F("Hybrid Heatpump"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {168, DeviceType::CONTROLLER, "Hybrid Heatpump", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{169, DeviceType::CONTROLLER, F("BC40"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {169, DeviceType::CONTROLLER, "BC40", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{190, DeviceType::CONTROLLER, F("BC10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {190, DeviceType::CONTROLLER, "BC10", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{194, DeviceType::CONTROLLER, F("BC10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {194, DeviceType::CONTROLLER, "BC10", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{206, DeviceType::CONTROLLER, F("Ecomline"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {206, DeviceType::CONTROLLER, "Ecomline", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{207, DeviceType::CONTROLLER, F("Sense II/CS200"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x10 {207, DeviceType::CONTROLLER, "Sense II/CS200", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x10
{209, DeviceType::CONTROLLER, F("ErP"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {209, DeviceType::CONTROLLER, "ErP", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{218, DeviceType::CONTROLLER, F("M200/RFM200"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x50 {218, DeviceType::CONTROLLER, "M200/RFM200", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x50
{220, DeviceType::CONTROLLER, F("BC30"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x16 {220, DeviceType::CONTROLLER, "BC30", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x16
{224, DeviceType::CONTROLLER, F("9000i"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {224, DeviceType::CONTROLLER, "9000i", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{229, DeviceType::CONTROLLER, F("8700i"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {229, DeviceType::CONTROLLER, "8700i", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{230, DeviceType::CONTROLLER, F("BC Base"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {230, DeviceType::CONTROLLER, "BC Base", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{240, DeviceType::CONTROLLER, F("Rego 3000"), DeviceFlags::EMS_DEVICE_FLAG_IVT}, // 0x09 {240, DeviceType::CONTROLLER, "Rego 3000", DeviceFlags::EMS_DEVICE_FLAG_IVT}, // 0x09
{241, DeviceType::CONTROLLER, F("Condens 5000i"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {241, DeviceType::CONTROLLER, "Condens 5000i", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
// Thermostat - not currently supporting write operations, like the Easy/100 types - 0x18 // Thermostat - not currently supporting write operations, like the Easy/100 types - 0x18
{202, DeviceType::THERMOSTAT, F("Logamatic TC100/Moduline Easy"), DeviceFlags::EMS_DEVICE_FLAG_EASY | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write {202, DeviceType::THERMOSTAT, "Logamatic TC100/Moduline Easy", DeviceFlags::EMS_DEVICE_FLAG_EASY | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write
{203, DeviceType::THERMOSTAT, F("EasyControl CT200"), DeviceFlags::EMS_DEVICE_FLAG_EASY | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write {203, DeviceType::THERMOSTAT, "EasyControl CT200", DeviceFlags::EMS_DEVICE_FLAG_EASY | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write
// Thermostat - Buderus/Nefit/Bosch specific - 0x17 / 0x10 / 0x18 / 0x19-0x1B for hc2-4 / 0x38 // Thermostat - Buderus/Nefit/Bosch specific - 0x17 / 0x10 / 0x18 / 0x19-0x1B for hc2-4 / 0x38
{ 65, DeviceType::THERMOSTAT, F("RC10"), DeviceFlags::EMS_DEVICE_FLAG_RC20_N},// 0x17 { 65, DeviceType::THERMOSTAT, "RC10", DeviceFlags::EMS_DEVICE_FLAG_RC20_N},// 0x17
{ 67, DeviceType::THERMOSTAT, F("RC30"), DeviceFlags::EMS_DEVICE_FLAG_RC30_N},// 0x10 - based on RC35 { 67, DeviceType::THERMOSTAT, "RC30", DeviceFlags::EMS_DEVICE_FLAG_RC30_N},// 0x10 - based on RC35
{ 77, DeviceType::THERMOSTAT, F("RC20/Moduline 300"), DeviceFlags::EMS_DEVICE_FLAG_RC20},// 0x17 { 77, DeviceType::THERMOSTAT, "RC20/Moduline 300", DeviceFlags::EMS_DEVICE_FLAG_RC20},// 0x17
{ 78, DeviceType::THERMOSTAT, F("Moduline 400"), DeviceFlags::EMS_DEVICE_FLAG_RC30}, // 0x10 { 78, DeviceType::THERMOSTAT, "Moduline 400", DeviceFlags::EMS_DEVICE_FLAG_RC30}, // 0x10
{ 79, DeviceType::THERMOSTAT, F("RC10/Moduline 100"), DeviceFlags::EMS_DEVICE_FLAG_RC10},// 0x17 { 79, DeviceType::THERMOSTAT, "RC10/Moduline 100", DeviceFlags::EMS_DEVICE_FLAG_RC10},// 0x17
{ 80, DeviceType::THERMOSTAT, F("Moduline 200"), DeviceFlags::EMS_DEVICE_FLAG_RC10}, // 0x17 { 80, DeviceType::THERMOSTAT, "Moduline 200", DeviceFlags::EMS_DEVICE_FLAG_RC10}, // 0x17
{ 86, DeviceType::THERMOSTAT, F("RC35"), DeviceFlags::EMS_DEVICE_FLAG_RC35}, // 0x10 { 86, DeviceType::THERMOSTAT, "RC35", DeviceFlags::EMS_DEVICE_FLAG_RC35}, // 0x10
{ 90, DeviceType::THERMOSTAT, F("RC10/Moduline 100"), DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17 { 90, DeviceType::THERMOSTAT, "RC10/Moduline 100", DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17
{ 93, DeviceType::THERMOSTAT, F("RC20RF"), DeviceFlags::EMS_DEVICE_FLAG_RC20}, // 0x19 { 93, DeviceType::THERMOSTAT, "RC20RF", DeviceFlags::EMS_DEVICE_FLAG_RC20}, // 0x19
{ 94, DeviceType::THERMOSTAT, F("RFM20 Remote"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x18 { 94, DeviceType::THERMOSTAT, "RFM20 Remote", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x18
{151, DeviceType::THERMOSTAT, F("RC25"), DeviceFlags::EMS_DEVICE_FLAG_RC25}, // 0x17 {151, DeviceType::THERMOSTAT, "RC25", DeviceFlags::EMS_DEVICE_FLAG_RC25}, // 0x17
{157, DeviceType::THERMOSTAT, F("RC200/CW100"), DeviceFlags::EMS_DEVICE_FLAG_RC100}, // 0x18 {157, DeviceType::THERMOSTAT, "RC200/CW100", DeviceFlags::EMS_DEVICE_FLAG_RC100}, // 0x18
{158, DeviceType::THERMOSTAT, F("RC300/RC310/Moduline 3000/1010H/CW400/Sense II"), DeviceFlags::EMS_DEVICE_FLAG_RC300}, // 0x10 {158, DeviceType::THERMOSTAT, "RC300/RC310/Moduline 3000/1010H/CW400/Sense II", DeviceFlags::EMS_DEVICE_FLAG_RC300}, // 0x10
{165, DeviceType::THERMOSTAT, F("RC100/Moduline 1000/1010"), DeviceFlags::EMS_DEVICE_FLAG_RC100}, // 0x18, 0x38 {165, DeviceType::THERMOSTAT, "RC100/Moduline 1000/1010", DeviceFlags::EMS_DEVICE_FLAG_RC100}, // 0x18, 0x38
{172, DeviceType::THERMOSTAT, F("Rego 2000/3000"), DeviceFlags::EMS_DEVICE_FLAG_RC300}, // 0x10 {172, DeviceType::THERMOSTAT, "Rego 2000/3000", DeviceFlags::EMS_DEVICE_FLAG_RC300}, // 0x10
{216, DeviceType::THERMOSTAT, F("CRF200S"), DeviceFlags::EMS_DEVICE_FLAG_CRF | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18 {216, DeviceType::THERMOSTAT, "CRF200S", DeviceFlags::EMS_DEVICE_FLAG_CRF | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18
{246, DeviceType::THERMOSTAT, F("Comfort+2RF"), DeviceFlags::EMS_DEVICE_FLAG_CRF | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18 {246, DeviceType::THERMOSTAT, "Comfort+2RF", DeviceFlags::EMS_DEVICE_FLAG_CRF | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18
// Thermostat - Sieger - 0x10 / 0x17 // Thermostat - Sieger - 0x10 / 0x17
{ 66, DeviceType::THERMOSTAT, F("ES72/RC20"), DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17 or remote { 66, DeviceType::THERMOSTAT, "ES72/RC20", DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17 or remote
{ 76, DeviceType::THERMOSTAT, F("ES73"), DeviceFlags::EMS_DEVICE_FLAG_RC30_N}, // 0x10 { 76, DeviceType::THERMOSTAT, "ES73", DeviceFlags::EMS_DEVICE_FLAG_RC30_N}, // 0x10
{113, DeviceType::THERMOSTAT, F("ES72/RC20"), DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17 {113, DeviceType::THERMOSTAT, "ES72/RC20", DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17
// Thermostat - Junkers - 0x10 // Thermostat - Junkers - 0x10
{105, DeviceType::THERMOSTAT, F("FW100"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS}, {105, DeviceType::THERMOSTAT, "FW100", DeviceFlags::EMS_DEVICE_FLAG_JUNKERS},
{106, DeviceType::THERMOSTAT, F("FW200"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS}, {106, DeviceType::THERMOSTAT, "FW200", DeviceFlags::EMS_DEVICE_FLAG_JUNKERS},
{107, DeviceType::THERMOSTAT, F("FR100"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS | DeviceFlags::EMS_DEVICE_FLAG_JUNKERS_OLD}, // older model {107, DeviceType::THERMOSTAT, "FR100", DeviceFlags::EMS_DEVICE_FLAG_JUNKERS | DeviceFlags::EMS_DEVICE_FLAG_JUNKERS_OLD}, // older model
{108, DeviceType::THERMOSTAT, F("FR110"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS | DeviceFlags::EMS_DEVICE_FLAG_JUNKERS_OLD}, // older model {108, DeviceType::THERMOSTAT, "FR110", DeviceFlags::EMS_DEVICE_FLAG_JUNKERS | DeviceFlags::EMS_DEVICE_FLAG_JUNKERS_OLD}, // older model
{109, DeviceType::THERMOSTAT, F("FB10"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS}, {109, DeviceType::THERMOSTAT, "FB10", DeviceFlags::EMS_DEVICE_FLAG_JUNKERS},
{110, DeviceType::THERMOSTAT, F("FB100"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS}, {110, DeviceType::THERMOSTAT, "FB100", DeviceFlags::EMS_DEVICE_FLAG_JUNKERS},
{111, DeviceType::THERMOSTAT, F("FR10"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS | DeviceFlags::EMS_DEVICE_FLAG_JUNKERS_OLD}, // older model {111, DeviceType::THERMOSTAT, "FR10", DeviceFlags::EMS_DEVICE_FLAG_JUNKERS | DeviceFlags::EMS_DEVICE_FLAG_JUNKERS_OLD}, // older model
{116, DeviceType::THERMOSTAT, F("FW500"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS}, {116, DeviceType::THERMOSTAT, "FW500", DeviceFlags::EMS_DEVICE_FLAG_JUNKERS},
{147, DeviceType::THERMOSTAT, F("FR50"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS | DeviceFlags::EMS_DEVICE_FLAG_JUNKERS_OLD}, {147, DeviceType::THERMOSTAT, "FR50", DeviceFlags::EMS_DEVICE_FLAG_JUNKERS | DeviceFlags::EMS_DEVICE_FLAG_JUNKERS_OLD},
{191, DeviceType::THERMOSTAT, F("FR120"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS | DeviceFlags::EMS_DEVICE_FLAG_JUNKERS_OLD}, // older model {191, DeviceType::THERMOSTAT, "FR120", DeviceFlags::EMS_DEVICE_FLAG_JUNKERS | DeviceFlags::EMS_DEVICE_FLAG_JUNKERS_OLD}, // older model
{192, DeviceType::THERMOSTAT, F("FW120"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS}, {192, DeviceType::THERMOSTAT, "FW120", DeviceFlags::EMS_DEVICE_FLAG_JUNKERS},
// Thermostat remote - 0x38 // Thermostat remote - 0x38
{200, DeviceType::THERMOSTAT, F("RC100H"), DeviceFlags::EMS_DEVICE_FLAG_RC100H}, {200, DeviceType::THERMOSTAT, "RC100H", DeviceFlags::EMS_DEVICE_FLAG_RC100H},
// Solar Modules - 0x30 (for solar), 0x2A, 0x41 (for ww) // Solar Modules - 0x30 (for solar), 0x2A, 0x41 (for ww)
{ 73, DeviceType::SOLAR, F("SM10"), DeviceFlags::EMS_DEVICE_FLAG_SM10}, { 73, DeviceType::SOLAR, "SM10", DeviceFlags::EMS_DEVICE_FLAG_SM10},
{101, DeviceType::SOLAR, F("ISM1"), DeviceFlags::EMS_DEVICE_FLAG_ISM}, {101, DeviceType::SOLAR, "ISM1", DeviceFlags::EMS_DEVICE_FLAG_ISM},
{103, DeviceType::SOLAR, F("ISM2"), DeviceFlags::EMS_DEVICE_FLAG_ISM}, {103, DeviceType::SOLAR, "ISM2", DeviceFlags::EMS_DEVICE_FLAG_ISM},
{162, DeviceType::SOLAR, F("SM50"), DeviceFlags::EMS_DEVICE_FLAG_SM100}, {162, DeviceType::SOLAR, "SM50", DeviceFlags::EMS_DEVICE_FLAG_SM100},
{163, DeviceType::SOLAR, F("SM100/MS100"), DeviceFlags::EMS_DEVICE_FLAG_SM100}, {163, DeviceType::SOLAR, "SM100/MS100", DeviceFlags::EMS_DEVICE_FLAG_SM100},
{164, DeviceType::SOLAR, F("SM200/MS200"), DeviceFlags::EMS_DEVICE_FLAG_SM100}, {164, DeviceType::SOLAR, "SM200/MS200", DeviceFlags::EMS_DEVICE_FLAG_SM100},
// Mixer Modules - 0x20-0x27 for HC, 0x28-0x29 for WWC and 0x11 for the MP100 // Mixer Modules - 0x20-0x27 for HC, 0x28-0x29 for WWC and 0x11 for the MP100
{ 69, DeviceType::MIXER, F("MM10"), DeviceFlags::EMS_DEVICE_FLAG_MM10}, { 69, DeviceType::MIXER, "MM10", DeviceFlags::EMS_DEVICE_FLAG_MM10},
{100, DeviceType::MIXER, F("IPM"), DeviceFlags::EMS_DEVICE_FLAG_IPM}, {100, DeviceType::MIXER, "IPM", DeviceFlags::EMS_DEVICE_FLAG_IPM},
{102, DeviceType::MIXER, F("IPM"), DeviceFlags::EMS_DEVICE_FLAG_IPM}, {102, DeviceType::MIXER, "IPM", DeviceFlags::EMS_DEVICE_FLAG_IPM},
{159, DeviceType::MIXER, F("MM50"), DeviceFlags::EMS_DEVICE_FLAG_MMPLUS}, {159, DeviceType::MIXER, "MM50", DeviceFlags::EMS_DEVICE_FLAG_MMPLUS},
{160, DeviceType::MIXER, F("MM100"), DeviceFlags::EMS_DEVICE_FLAG_MMPLUS}, {160, DeviceType::MIXER, "MM100", DeviceFlags::EMS_DEVICE_FLAG_MMPLUS},
{161, DeviceType::MIXER, F("MM200"), DeviceFlags::EMS_DEVICE_FLAG_MMPLUS}, {161, DeviceType::MIXER, "MM200", DeviceFlags::EMS_DEVICE_FLAG_MMPLUS},
{204, DeviceType::MIXER, F("MP100"), DeviceFlags::EMS_DEVICE_FLAG_MP}, // pool {204, DeviceType::MIXER, "MP100", DeviceFlags::EMS_DEVICE_FLAG_MP}, // pool
// Heat Pumps - 0x38? // Heat Pumps - 0x38?
{252, DeviceType::HEATPUMP, F("HP Module"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {252, DeviceType::HEATPUMP, "HP Module", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Heat Pumps - 0x53 // Heat Pumps - 0x53
{248, DeviceType::HEATPUMP, F("Hybrid Manager HM200"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {248, DeviceType::HEATPUMP, "Hybrid Manager HM200", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Connect devices - 0x02 // Connect devices - 0x02
{171, DeviceType::CONNECT, F("OpenTherm Converter"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {171, DeviceType::CONNECT, "OpenTherm Converter", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{205, DeviceType::CONNECT, F("Moduline Easy Connect"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {205, DeviceType::CONNECT, "Moduline Easy Connect", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{206, DeviceType::CONNECT, F("Easy Connect"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {206, DeviceType::CONNECT, "Easy Connect", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Wireless sensor base - 0x50 // Wireless sensor base - 0x50
{236, DeviceType::CONNECT, F("Wireless sensor base"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {236, DeviceType::CONNECT, "Wireless sensor base", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{238, DeviceType::CONNECT, F("Wireless sensor base"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {238, DeviceType::CONNECT, "Wireless sensor base", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Switches - 0x11 // Switches - 0x11
{ 71, DeviceType::SWITCH, F("WM10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, { 71, DeviceType::SWITCH, "WM10", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// EM10 error contact and analog flowtemp control- 0x12 // EM10 error contact and analog flowtemp control- 0x12
{ 74, DeviceType::GATEWAY, F("Error Module EM10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, { 74, DeviceType::GATEWAY, "Error Module EM10", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Gateways - 0x48 // Gateways - 0x48
{189, DeviceType::GATEWAY, F("KM200/MB LAN 2"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, {189, DeviceType::GATEWAY, "KM200/MB LAN 2", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Generic - 0x40 or other with no product-id and no version // Generic - 0x40 or other with no product-id and no version
{0, DeviceType::GENERIC, F("unknown"), DeviceFlags::EMS_DEVICE_FLAG_NONE} {0, DeviceType::GENERIC, "unknown", DeviceFlags::EMS_DEVICE_FLAG_NONE}
// clang-format on // clang-format on

View File

@@ -24,16 +24,16 @@ REGISTER_FACTORY(Boiler, EMSdevice::DeviceType::BOILER)
uuid::log::Logger Boiler::logger_{F_(boiler), uuid::log::Facility::CONSOLE}; uuid::log::Logger Boiler::logger_{F_(boiler), uuid::log::Facility::CONSOLE};
Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand) Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// alternative heatsource special messages // alternative heatsource special messages
if (device_id == EMSdevice::EMS_DEVICE_ID_AM200) { if (device_id == EMSdevice::EMS_DEVICE_ID_AM200) {
register_telegram_type(0x54D, F("AmTemperatures"), false, MAKE_PF_CB(process_amTempMessage)); register_telegram_type(0x54D, "AmTemperatures", false, MAKE_PF_CB(process_amTempMessage));
register_telegram_type(0x54E, F("AmStatus"), false, MAKE_PF_CB(process_amStatusMessage)); register_telegram_type(0x54E, "AmStatus", false, MAKE_PF_CB(process_amStatusMessage));
register_telegram_type(0x54F, F("AmCommand"), false, MAKE_PF_CB(process_amCommandMessage)); // not broadcasted, but actually not used register_telegram_type(0x54F, "AmCommand", false, MAKE_PF_CB(process_amCommandMessage)); // not broadcasted, but actually not used
register_telegram_type(0x550, F("AmExtra"), false, MAKE_PF_CB(process_amExtraMessage)); register_telegram_type(0x550, "AmExtra", false, MAKE_PF_CB(process_amExtraMessage));
register_telegram_type(0x54C, F("AmSettings"), true, MAKE_PF_CB(process_amSettingMessage)); // not broadcasted register_telegram_type(0x54C, "AmSettings", true, MAKE_PF_CB(process_amSettingMessage)); // not broadcasted
register_device_value(DeviceValueTAG::TAG_AHS, register_device_value(DeviceValueTAG::TAG_AHS,
&curFlowTemp_, &curFlowTemp_,
@@ -113,12 +113,12 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
if (device_id >= EMSdevice::EMS_DEVICE_ID_BOILER_1) { if (device_id >= EMSdevice::EMS_DEVICE_ID_BOILER_1) {
uint8_t hs = device_id - EMSdevice::EMS_DEVICE_ID_BOILER_1; // heating source id, count from 0 uint8_t hs = device_id - EMSdevice::EMS_DEVICE_ID_BOILER_1; // heating source id, count from 0
// Runtime of each heatingsource in 0x06DC, ff // Runtime of each heatingsource in 0x06DC, ff
register_telegram_type(0x6DC + hs, F("CascadeMessage"), false, MAKE_PF_CB(process_CascadeMessage)); register_telegram_type(0x6DC + hs, "CascadeMessage", false, MAKE_PF_CB(process_CascadeMessage));
register_device_value(DeviceValueTAG::TAG_HS1 + hs, &burnWorkMin_, DeviceValueType::TIME, FL_(burnWorkMin), DeviceValueUOM::MINUTES); register_device_value(DeviceValueTAG::TAG_HS1 + hs, &burnWorkMin_, DeviceValueType::TIME, FL_(burnWorkMin), DeviceValueUOM::MINUTES);
// selBurnpower in D2 and E4 // selBurnpower in D2 and E4
// register_telegram_type(0xD2, F("CascadePowerMessage"), false, MAKE_PF_CB(process_CascadePowerMessage)); // register_telegram_type(0xD2, "CascadePowerMessage", false, MAKE_PF_CB(process_CascadePowerMessage));
// individual Flowtemps and powervalues for each heatingsource in E4 // individual Flowtemps and powervalues for each heatingsource in E4
register_telegram_type(0xE4, F("UBAMonitorFastPlus"), false, MAKE_PF_CB(process_UBAMonitorFastPlus)); register_telegram_type(0xE4, "UBAMonitorFastPlus", false, MAKE_PF_CB(process_UBAMonitorFastPlus));
register_device_value(DeviceValueTAG::TAG_HS1 + hs, &selFlowTemp_, DeviceValueType::UINT, FL_(selFlowTemp), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_HS1 + hs, &selFlowTemp_, DeviceValueType::UINT, FL_(selFlowTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_HS1 + hs, &selBurnPow_, DeviceValueType::UINT, FL_(selBurnPow), DeviceValueUOM::PERCENT); register_device_value(DeviceValueTAG::TAG_HS1 + hs, &selBurnPow_, DeviceValueType::UINT, FL_(selBurnPow), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_HS1 + hs, register_device_value(DeviceValueTAG::TAG_HS1 + hs,
@@ -136,51 +136,51 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
// the telegram handlers... // the telegram handlers...
// common for all boilers // common for all boilers
register_telegram_type(0xBF, F("ErrorMessage"), false, MAKE_PF_CB(process_ErrorMessage)); register_telegram_type(0xBF, "ErrorMessage", false, MAKE_PF_CB(process_ErrorMessage));
register_telegram_type(0x10, F("UBAErrorMessage1"), false, MAKE_PF_CB(process_UBAErrorMessage)); register_telegram_type(0x10, "UBAErrorMessage1", false, MAKE_PF_CB(process_UBAErrorMessage));
register_telegram_type(0x11, F("UBAErrorMessage2"), false, MAKE_PF_CB(process_UBAErrorMessage)); register_telegram_type(0x11, "UBAErrorMessage2", false, MAKE_PF_CB(process_UBAErrorMessage));
register_telegram_type(0xC2, F("UBAErrorMessage3"), false, MAKE_PF_CB(process_UBAErrorMessage2)); register_telegram_type(0xC2, "UBAErrorMessage3", false, MAKE_PF_CB(process_UBAErrorMessage2));
register_telegram_type(0x14, F("UBATotalUptime"), true, MAKE_PF_CB(process_UBATotalUptime)); register_telegram_type(0x14, "UBATotalUptime", true, MAKE_PF_CB(process_UBATotalUptime));
register_telegram_type(0x15, F("UBAMaintenanceData"), false, MAKE_PF_CB(process_UBAMaintenanceData)); register_telegram_type(0x15, "UBAMaintenanceData", false, MAKE_PF_CB(process_UBAMaintenanceData));
register_telegram_type(0x1C, F("UBAMaintenanceStatus"), false, MAKE_PF_CB(process_UBAMaintenanceStatus)); register_telegram_type(0x1C, "UBAMaintenanceStatus", false, MAKE_PF_CB(process_UBAMaintenanceStatus));
// EMS1.0 and maybe EMS+? // EMS1.0 and maybe EMS+?
register_telegram_type(0x18, F("UBAMonitorFast"), false, MAKE_PF_CB(process_UBAMonitorFast)); register_telegram_type(0x18, "UBAMonitorFast", false, MAKE_PF_CB(process_UBAMonitorFast));
register_telegram_type(0x19, F("UBAMonitorSlow"), false, MAKE_PF_CB(process_UBAMonitorSlow)); register_telegram_type(0x19, "UBAMonitorSlow", false, MAKE_PF_CB(process_UBAMonitorSlow));
register_telegram_type(0x1A, F("UBASetPoints"), false, MAKE_PF_CB(process_UBASetPoints)); register_telegram_type(0x1A, "UBASetPoints", false, MAKE_PF_CB(process_UBASetPoints));
register_telegram_type(0x35, F("UBAFlags"), false, MAKE_PF_CB(process_UBAFlags)); register_telegram_type(0x35, "UBAFlags", false, MAKE_PF_CB(process_UBAFlags));
// only EMS 1.0 // only EMS 1.0
register_telegram_type(0x16, F("UBAParameters"), true, MAKE_PF_CB(process_UBAParameters)); register_telegram_type(0x16, "UBAParameters", true, MAKE_PF_CB(process_UBAParameters));
register_telegram_type(0x33, F("UBAParameterWW"), true, MAKE_PF_CB(process_UBAParameterWW)); register_telegram_type(0x33, "UBAParameterWW", true, MAKE_PF_CB(process_UBAParameterWW));
register_telegram_type(0x34, F("UBAMonitorWW"), false, MAKE_PF_CB(process_UBAMonitorWW)); register_telegram_type(0x34, "UBAMonitorWW", false, MAKE_PF_CB(process_UBAMonitorWW));
// not ems1.0, but HT3 // not ems1.0, but HT3
if (model() != EMSdevice::EMS_DEVICE_FLAG_EMS) { if (model() != EMSdevice::EMS_DEVICE_FLAG_EMS) {
register_telegram_type(0x26, F("UBASettingsWW"), true, MAKE_PF_CB(process_UBASettingsWW)); register_telegram_type(0x26, "UBASettingsWW", true, MAKE_PF_CB(process_UBASettingsWW));
register_telegram_type(0x2A, F("MC110Status"), false, MAKE_PF_CB(process_MC110Status)); register_telegram_type(0x2A, "MC110Status", false, MAKE_PF_CB(process_MC110Status));
} }
// only EMS+ // only EMS+
if (model() != EMSdevice::EMS_DEVICE_FLAG_EMS && model() != EMSdevice::EMS_DEVICE_FLAG_HT3 && model() != EMSdevice::EMS_DEVICE_FLAG_HYBRID) { if (model() != EMSdevice::EMS_DEVICE_FLAG_EMS && model() != EMSdevice::EMS_DEVICE_FLAG_HT3 && model() != EMSdevice::EMS_DEVICE_FLAG_HYBRID) {
register_telegram_type(0xD1, F("UBAOutdoorTemp"), false, MAKE_PF_CB(process_UBAOutdoorTemp)); register_telegram_type(0xD1, "UBAOutdoorTemp", false, MAKE_PF_CB(process_UBAOutdoorTemp));
register_telegram_type(0xE3, F("UBAMonitorSlowPlus2"), false, MAKE_PF_CB(process_UBAMonitorSlowPlus2)); register_telegram_type(0xE3, "UBAMonitorSlowPlus2", false, MAKE_PF_CB(process_UBAMonitorSlowPlus2));
register_telegram_type(0xE4, F("UBAMonitorFastPlus"), false, MAKE_PF_CB(process_UBAMonitorFastPlus)); register_telegram_type(0xE4, "UBAMonitorFastPlus", false, MAKE_PF_CB(process_UBAMonitorFastPlus));
register_telegram_type(0xE5, F("UBAMonitorSlowPlus"), false, MAKE_PF_CB(process_UBAMonitorSlowPlus)); register_telegram_type(0xE5, "UBAMonitorSlowPlus", false, MAKE_PF_CB(process_UBAMonitorSlowPlus));
register_telegram_type(0xE6, F("UBAParametersPlus"), true, MAKE_PF_CB(process_UBAParametersPlus)); register_telegram_type(0xE6, "UBAParametersPlus", true, MAKE_PF_CB(process_UBAParametersPlus));
register_telegram_type(0xE9, F("UBAMonitorWWPlus"), false, MAKE_PF_CB(process_UBAMonitorWWPlus)); register_telegram_type(0xE9, "UBAMonitorWWPlus", false, MAKE_PF_CB(process_UBAMonitorWWPlus));
register_telegram_type(0xEA, F("UBAParameterWWPlus"), true, MAKE_PF_CB(process_UBAParameterWWPlus)); register_telegram_type(0xEA, "UBAParameterWWPlus", true, MAKE_PF_CB(process_UBAParameterWWPlus));
} }
if (model() == EMSdevice::EMS_DEVICE_FLAG_HEATPUMP) { if (model() == EMSdevice::EMS_DEVICE_FLAG_HEATPUMP) {
register_telegram_type(0x494, F("UBAEnergySupplied"), false, MAKE_PF_CB(process_UBAEnergySupplied)); register_telegram_type(0x494, "UBAEnergySupplied", false, MAKE_PF_CB(process_UBAEnergySupplied));
register_telegram_type(0x495, F("UBAInformation"), false, MAKE_PF_CB(process_UBAInformation)); register_telegram_type(0x495, "UBAInformation", false, MAKE_PF_CB(process_UBAInformation));
register_telegram_type(0x48D, F("HpPower"), true, MAKE_PF_CB(process_HpPower)); register_telegram_type(0x48D, "HpPower", true, MAKE_PF_CB(process_HpPower));
register_telegram_type(0x48F, F("HpOutdoor"), false, MAKE_PF_CB(process_HpOutdoor)); register_telegram_type(0x48F, "HpOutdoor", false, MAKE_PF_CB(process_HpOutdoor));
register_telegram_type(0x48A, F("HpPool"), true, MAKE_PF_CB(process_HpPool)); register_telegram_type(0x48A, "HpPool", true, MAKE_PF_CB(process_HpPool));
register_telegram_type(0x4A2, F("HpInput"), false, MAKE_PF_CB(process_HpInput)); register_telegram_type(0x4A2, "HpInput", false, MAKE_PF_CB(process_HpInput));
register_telegram_type(0x486, F("HpInConfig"), false, MAKE_PF_CB(process_HpInConfig)); register_telegram_type(0x486, "HpInConfig", false, MAKE_PF_CB(process_HpInConfig));
register_telegram_type(0x492, F("HpHeaterConfig"), false, MAKE_PF_CB(process_HpHeaterConfig)); register_telegram_type(0x492, "HpHeaterConfig", false, MAKE_PF_CB(process_HpHeaterConfig));
} }
/* /*
@@ -189,7 +189,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
* enable settings here if no thermostat is used in system * enable settings here if no thermostat is used in system
* *
if (model() == EMSdevice::EMS_DEVICE_FLAG_HYBRID) { if (model() == EMSdevice::EMS_DEVICE_FLAG_HYBRID) {
register_telegram_type(0xBB, F("HybridHp"), true, MAKE_PF_CB(process_HybridHp)); register_telegram_type(0xBB, "HybridHp", true, MAKE_PF_CB(process_HybridHp));
} }
*/ */
@@ -2178,11 +2178,11 @@ bool Boiler::set_ww_circulation_mode(const char * value, const int8_t id) {
} }
if (v < 7) { if (v < 7) {
// LOG_INFO(F("Setting dhw circulation mode %dx3min"), v); // LOG_INFO("Setting dhw circulation mode %dx3min", v);
} else if (v == 7) { } else if (v == 7) {
// LOG_INFO(F("Setting dhw circulation mode continuous")); // LOG_INFO("Setting dhw circulation mode continuous");
} else { } else {
// LOG_WARNING(F("Set dhw circulation mode: Invalid value")); // LOG_WARNING("Set dhw circulation mode: Invalid value");
return false; return false;
} }
@@ -2206,12 +2206,12 @@ bool Boiler::set_reset(const char * value, const int8_t id) {
} }
if (num == 1) { if (num == 1) {
// LOG_INFO(F("Reset boiler maintenance message")); // LOG_INFO("Reset boiler maintenance message");
write_command(0x05, 0x08, 0xFF, 0x1C); write_command(0x05, 0x08, 0xFF, 0x1C);
has_update(&reset_); has_update(&reset_);
return true; return true;
} else if (num == 2) { } else if (num == 2) {
// LOG_INFO(F("Reset boiler error message")); // LOG_INFO("Reset boiler error message");
write_command(0x05, 0x00, 0x5A); // error reset write_command(0x05, 0x00, 0x5A); // error reset
has_update(&reset_); has_update(&reset_);
return true; return true;
@@ -2228,7 +2228,7 @@ bool Boiler::set_maintenance(const char * value, const int8_t id) {
std::string s; std::string s;
if (Helpers::value2string(value, s)) { if (Helpers::value2string(value, s)) {
if (s == Helpers::translated_word(FL_(reset))) { if (s == Helpers::translated_word(FL_(reset))) {
// LOG_INFO(F("Reset boiler maintenance message")); // LOG_INFO("Reset boiler maintenance message");
write_command(0x05, 0x08, 0xFF, 0x1C); write_command(0x05, 0x08, 0xFF, 0x1C);
return true; return true;
} }
@@ -2239,11 +2239,11 @@ bool Boiler::set_maintenance(const char * value, const int8_t id) {
uint8_t month = (value[3] - '0') * 10 + (value[4] - '0'); uint8_t month = (value[3] - '0') * 10 + (value[4] - '0');
uint8_t year = (uint8_t)(Helpers::atoint(&value[6]) - 2000); uint8_t year = (uint8_t)(Helpers::atoint(&value[6]) - 2000);
if (day > 0 && day < 32 && month > 0 && month < 13) { if (day > 0 && day < 32 && month > 0 && month < 13) {
LOG_INFO(F("Setting maintenance date to %02d.%02d.%04d"), day, month, year + 2000); LOG_INFO("Setting maintenance date to %02d.%02d.%04d", day, month, year + 2000);
uint8_t data[5] = {2, (uint8_t)(maintenanceTime_ / 100), day, month, year}; uint8_t data[5] = {2, (uint8_t)(maintenanceTime_ / 100), day, month, year};
write_command(0x15, 0, data, 5, 0x15); write_command(0x15, 0, data, 5, 0x15);
} else { } else {
LOG_WARNING(F("Setting maintenance: wrong format %d.%d.%d"), day, month, year + 2000); LOG_WARNING("Setting maintenance: wrong format %d.%d.%d", day, month, year + 2000);
return false; return false;
} }
return true; return true;
@@ -2252,7 +2252,7 @@ bool Boiler::set_maintenance(const char * value, const int8_t id) {
int hrs; int hrs;
if (Helpers::value2number(value, hrs)) { if (Helpers::value2number(value, hrs)) {
if (hrs > 99 && hrs < 25600) { if (hrs > 99 && hrs < 25600) {
LOG_INFO(F("Setting maintenance time %d hours"), hrs); LOG_INFO("Setting maintenance time %d hours", hrs);
uint8_t data[2] = {1, (uint8_t)(hrs / 100)}; uint8_t data[2] = {1, (uint8_t)(hrs / 100)};
write_command(0x15, 0, data, 2, 0x15); write_command(0x15, 0, data, 2, 0x15);
return true; return true;
@@ -2261,12 +2261,12 @@ bool Boiler::set_maintenance(const char * value, const int8_t id) {
uint8_t num; uint8_t num;
if (Helpers::value2enum(value, num, FL_(enum_off_time_date_manual))) { if (Helpers::value2enum(value, num, FL_(enum_off_time_date_manual))) {
LOG_INFO(F("Setting maintenance type to %s"), value); LOG_INFO("Setting maintenance type to %s", value);
write_command(0x15, 0, num, 0x15); write_command(0x15, 0, num, 0x15);
return true; return true;
} }
LOG_WARNING(F("Setting maintenance: wrong format")); LOG_WARNING("Setting maintenance: wrong format");
return false; return false;
} }
//maintenance //maintenance
@@ -2274,13 +2274,13 @@ bool Boiler::set_maintenancetime(const char * value, const int8_t id) {
int hrs; int hrs;
if (Helpers::value2number(value, hrs)) { if (Helpers::value2number(value, hrs)) {
if (hrs > 99 && hrs < 25600) { if (hrs > 99 && hrs < 25600) {
LOG_INFO(F("Setting maintenance time %d hours"), hrs); LOG_INFO("Setting maintenance time %d hours", hrs);
uint8_t data[2] = {1, (uint8_t)(hrs / 100)}; uint8_t data[2] = {1, (uint8_t)(hrs / 100)};
write_command(0x15, 0, data, 2, 0x15); write_command(0x15, 0, data, 2, 0x15);
return true; return true;
} }
} }
LOG_WARNING(F("Setting maintenance: wrong format")); LOG_WARNING("Setting maintenance: wrong format");
return false; return false;
} }
@@ -2291,17 +2291,17 @@ bool Boiler::set_maintenancedate(const char * value, const int8_t id) {
uint8_t month = (value[3] - '0') * 10 + (value[4] - '0'); uint8_t month = (value[3] - '0') * 10 + (value[4] - '0');
uint8_t year = (uint8_t)(Helpers::atoint(&value[6]) - 2000); uint8_t year = (uint8_t)(Helpers::atoint(&value[6]) - 2000);
if (day > 0 && day < 32 && month > 0 && month < 13) { if (day > 0 && day < 32 && month > 0 && month < 13) {
LOG_INFO(F("Setting maintenance date to %02d.%02d.%04d"), day, month, year + 2000); LOG_INFO("Setting maintenance date to %02d.%02d.%04d", day, month, year + 2000);
uint8_t data[5] = {2, (uint8_t)(maintenanceTime_ / 100), day, month, year}; uint8_t data[5] = {2, (uint8_t)(maintenanceTime_ / 100), day, month, year};
write_command(0x15, 0, data, 5, 0x15); write_command(0x15, 0, data, 5, 0x15);
} else { } else {
LOG_WARNING(F("Setting maintenance: wrong format %d.%d.%d"), day, month, year + 2000); LOG_WARNING("Setting maintenance: wrong format %d.%d.%d", day, month, year + 2000);
return false; return false;
} }
return true; return true;
} }
LOG_WARNING(F("Setting maintenance: wrong format")); LOG_WARNING("Setting maintenance: wrong format");
return false; return false;
} }
@@ -2312,7 +2312,7 @@ bool Boiler::set_pool_temp(const char * value, const int8_t id) {
return false; return false;
} }
uint8_t v2 = ((v * 2) + 0.5); uint8_t v2 = ((v * 2) + 0.5);
// LOG_INFO(F("Setting pool temperature to %d.%d C"), v2 >> 1, (v2 & 0x01) * 5); // LOG_INFO("Setting pool temperature to %d.%d C", v2 >> 1, (v2 & 0x01) * 5);
write_command(0x48A, 1, v2, 0x48A); write_command(0x48A, 1, v2, 0x48A);
return true; return true;

View File

@@ -25,7 +25,7 @@ namespace emsesp {
class Boiler : public EMSdevice { class Boiler : public EMSdevice {
public: public:
Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand); Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand);
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;

View File

@@ -22,7 +22,7 @@ namespace emsesp {
REGISTER_FACTORY(Connect, EMSdevice::DeviceType::CONNECT); REGISTER_FACTORY(Connect, EMSdevice::DeviceType::CONNECT);
Connect::Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand) Connect::Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
} }

View File

@@ -25,7 +25,7 @@ namespace emsesp {
class Connect : public EMSdevice { class Connect : public EMSdevice {
public: public:
Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand); Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand);
}; };
} // namespace emsesp } // namespace emsesp

View File

@@ -22,11 +22,11 @@ namespace emsesp {
REGISTER_FACTORY(Controller, EMSdevice::DeviceType::CONTROLLER); REGISTER_FACTORY(Controller, EMSdevice::DeviceType::CONTROLLER);
Controller::Controller(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand) Controller::Controller(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// IVT broadcasts Thermostat time from controller (0x09) if display is off. // IVT broadcasts Thermostat time from controller (0x09) if display is off.
if ((flags & 0x0F) == EMS_DEVICE_FLAG_IVT) { if ((flags & 0x0F) == EMS_DEVICE_FLAG_IVT) {
register_telegram_type(0x06, F("RCTime"), false, MAKE_PF_CB(process_dateTime)); register_telegram_type(0x06, "RCTime", false, MAKE_PF_CB(process_dateTime));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, FL_(dateTime), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, FL_(dateTime), DeviceValueUOM::NONE);
} }
} }

View File

@@ -25,7 +25,7 @@ namespace emsesp {
class Controller : public EMSdevice { class Controller : public EMSdevice {
public: public:
Controller(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand); Controller(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand);
void process_dateTime(std::shared_ptr<const Telegram> telegram); void process_dateTime(std::shared_ptr<const Telegram> telegram);

View File

@@ -22,7 +22,7 @@ namespace emsesp {
REGISTER_FACTORY(Gateway, EMSdevice::DeviceType::GATEWAY); REGISTER_FACTORY(Gateway, EMSdevice::DeviceType::GATEWAY);
Gateway::Gateway(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand) Gateway::Gateway(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
} }

View File

@@ -25,7 +25,7 @@ namespace emsesp {
class Gateway : public EMSdevice { class Gateway : public EMSdevice {
public: public:
Gateway(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand); Gateway(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand);
}; };
} // namespace emsesp } // namespace emsesp

View File

@@ -24,7 +24,7 @@ REGISTER_FACTORY(Generic, EMSdevice::DeviceType::GENERIC);
uuid::log::Logger Generic::logger_{F_(generic), uuid::log::Facility::CONSOLE}; uuid::log::Logger Generic::logger_{F_(generic), uuid::log::Facility::CONSOLE};
Generic::Generic(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand) Generic::Generic(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
} }

View File

@@ -25,7 +25,7 @@ namespace emsesp {
class Generic : public EMSdevice { class Generic : public EMSdevice {
public: public:
Generic(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand); Generic(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand);
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;

View File

@@ -22,11 +22,11 @@ namespace emsesp {
REGISTER_FACTORY(Heatpump, EMSdevice::DeviceType::HEATPUMP); REGISTER_FACTORY(Heatpump, EMSdevice::DeviceType::HEATPUMP);
Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand) Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// telegram handlers // telegram handlers
register_telegram_type(0x042B, F("HP1"), false, MAKE_PF_CB(process_HPMonitor1)); register_telegram_type(0x042B, "HP1", false, MAKE_PF_CB(process_HPMonitor1));
register_telegram_type(0x047B, F("HP2"), false, MAKE_PF_CB(process_HPMonitor2)); register_telegram_type(0x047B, "HP2", false, MAKE_PF_CB(process_HPMonitor2));
// device values // device values
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &airHumidity_, DeviceValueType::UINT, FL_(airHumidity), DeviceValueUOM::PERCENT); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &airHumidity_, DeviceValueType::UINT, FL_(airHumidity), DeviceValueUOM::PERCENT);

View File

@@ -25,7 +25,7 @@ namespace emsesp {
class Heatpump : public EMSdevice { class Heatpump : public EMSdevice {
public: public:
Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand); Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand);
private: private:
uint8_t airHumidity_; uint8_t airHumidity_;

View File

@@ -24,11 +24,11 @@ REGISTER_FACTORY(Mixer, EMSdevice::DeviceType::MIXER);
uuid::log::Logger Mixer::logger_{F_(mixer), uuid::log::Facility::CONSOLE}; uuid::log::Logger Mixer::logger_{F_(mixer), uuid::log::Facility::CONSOLE};
Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand) Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// Pool module // Pool module
if (flags == EMSdevice::EMS_DEVICE_FLAG_MP) { if (flags == EMSdevice::EMS_DEVICE_FLAG_MP) {
register_telegram_type(0x5BA, F("HpPoolStatus"), true, MAKE_PF_CB(process_HpPoolStatus)); register_telegram_type(0x5BA, "HpPoolStatus", true, MAKE_PF_CB(process_HpPoolStatus));
type_ = Type::MP; type_ = Type::MP;
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&poolTemp_, &poolTemp_,
@@ -43,8 +43,8 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
// EMS+ // EMS+
if (flags == EMSdevice::EMS_DEVICE_FLAG_MMPLUS) { if (flags == EMSdevice::EMS_DEVICE_FLAG_MMPLUS) {
if (device_id >= 0x20 && device_id <= 0x27) { if (device_id >= 0x20 && device_id <= 0x27) {
register_telegram_type(device_id - 0x20 + 0x02D7, F("MMPLUSStatusMessage_HC"), false, MAKE_PF_CB(process_MMPLUSStatusMessage_HC)); register_telegram_type(device_id - 0x20 + 0x02D7, "MMPLUSStatusMessage_HC", false, MAKE_PF_CB(process_MMPLUSStatusMessage_HC));
// register_telegram_type(device_id - 0x20 + 0x02E1, F("MMPLUSStetMessage_HC"), true, MAKE_PF_CB(process_MMPLUSSetMessage_HC)); // register_telegram_type(device_id - 0x20 + 0x02E1, "MMPLUSStetMessage_HC", true, MAKE_PF_CB(process_MMPLUSSetMessage_HC));
type_ = Type::HC; type_ = Type::HC;
hc_ = device_id - 0x20 + 1; hc_ = device_id - 0x20 + 1;
uint8_t tag = DeviceValueTAG::TAG_HC1 + hc_ - 1; uint8_t tag = DeviceValueTAG::TAG_HC1 + hc_ - 1;
@@ -53,9 +53,9 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
register_device_value(tag, &flowSetTemp_, DeviceValueType::UINT, FL_(flowSetTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_flowSetTemp)); register_device_value(tag, &flowSetTemp_, DeviceValueType::UINT, FL_(flowSetTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_flowSetTemp));
register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, FL_(pumpStatus), DeviceValueUOM::NONE, MAKE_CF_CB(set_pump)); register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, FL_(pumpStatus), DeviceValueUOM::NONE, MAKE_CF_CB(set_pump));
} else if (device_id >= 0x28 && device_id <= 0x29) { } else if (device_id >= 0x28 && device_id <= 0x29) {
register_telegram_type(device_id - 0x28 + 0x0331, F("MMPLUSStatusMessage_WWC"), false, MAKE_PF_CB(process_MMPLUSStatusMessage_WWC)); register_telegram_type(device_id - 0x28 + 0x0331, "MMPLUSStatusMessage_WWC", false, MAKE_PF_CB(process_MMPLUSStatusMessage_WWC));
register_telegram_type(device_id - 0x28 + 0x0313, F("MMPLUSConfigMessage_WWC"), true, MAKE_PF_CB(process_MMPLUSConfigMessage_WWC)); register_telegram_type(device_id - 0x28 + 0x0313, "MMPLUSConfigMessage_WWC", true, MAKE_PF_CB(process_MMPLUSConfigMessage_WWC));
// register_telegram_type(device_id - 0x28 + 0x033B, F("MMPLUSSetMessage_WWC"), true, MAKE_PF_CB(process_MMPLUSSetMessage_WWC)); // register_telegram_type(device_id - 0x28 + 0x033B, "MMPLUSSetMessage_WWC", true, MAKE_PF_CB(process_MMPLUSSetMessage_WWC));
type_ = Type::WWC; type_ = Type::WWC;
hc_ = device_id - 0x28 + 1; hc_ = device_id - 0x28 + 1;
uint8_t tag = DeviceValueTAG::TAG_WWC1 + hc_ - 1; uint8_t tag = DeviceValueTAG::TAG_WWC1 + hc_ - 1;
@@ -85,9 +85,9 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
// EMS 1.0 // EMS 1.0
if (flags == EMSdevice::EMS_DEVICE_FLAG_MM10) { if (flags == EMSdevice::EMS_DEVICE_FLAG_MM10) {
register_telegram_type(0x00AA, F("MMConfigMessage"), true, MAKE_PF_CB(process_MMConfigMessage)); register_telegram_type(0x00AA, "MMConfigMessage", true, MAKE_PF_CB(process_MMConfigMessage));
register_telegram_type(0x00AB, F("MMStatusMessage"), false, MAKE_PF_CB(process_MMStatusMessage)); register_telegram_type(0x00AB, "MMStatusMessage", false, MAKE_PF_CB(process_MMStatusMessage));
register_telegram_type(0x00AC, F("MMSetMessage"), false, MAKE_PF_CB(process_MMSetMessage)); register_telegram_type(0x00AC, "MMSetMessage", false, MAKE_PF_CB(process_MMSetMessage));
type_ = Type::HC; type_ = Type::HC;
hc_ = device_id - 0x20 + 1; hc_ = device_id - 0x20 + 1;
uint8_t tag = DeviceValueTAG::TAG_HC1 + hc_ - 1; uint8_t tag = DeviceValueTAG::TAG_HC1 + hc_ - 1;
@@ -110,10 +110,10 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
// HT3 // HT3
if (flags == EMSdevice::EMS_DEVICE_FLAG_IPM) { if (flags == EMSdevice::EMS_DEVICE_FLAG_IPM) {
if (device_id >= 0x40) { // special DHW pos 10 if (device_id >= 0x40) { // special DHW pos 10
register_telegram_type(0x34, F("UBAMonitorWW"), false, MAKE_PF_CB(process_IPMMonitorWW)); register_telegram_type(0x34, "UBAMonitorWW", false, MAKE_PF_CB(process_IPMMonitorWW));
register_telegram_type(0x1E, F("HydrTemp"), false, MAKE_PF_CB(process_IPMHydrTemp)); register_telegram_type(0x1E, "HydrTemp", false, MAKE_PF_CB(process_IPMHydrTemp));
register_telegram_type(0x33, F("UBAParameterWW"), true, MAKE_PF_CB(process_IPMParameterWW)); register_telegram_type(0x33, "UBAParameterWW", true, MAKE_PF_CB(process_IPMParameterWW));
// register_telegram_type(0x10D, F("wwNTCStatus"), false, MAKE_PF_CB(process_wwNTCStatus)); // register_telegram_type(0x10D, "wwNTCStatus", false, MAKE_PF_CB(process_wwNTCStatus));
type_ = Type::WWC; type_ = Type::WWC;
hc_ = device_id - 0x40 + 1; hc_ = device_id - 0x40 + 1;
uint8_t tag = DeviceValueTAG::TAG_WWC9 + hc_ - 1; uint8_t tag = DeviceValueTAG::TAG_WWC9 + hc_ - 1;
@@ -139,9 +139,9 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
MAKE_CF_CB(set_wwCircPump)); MAKE_CF_CB(set_wwCircPump));
register_device_value(tag, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode), FL_(wwCircMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwCircMode)); register_device_value(tag, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode), FL_(wwCircMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwCircMode));
} else { } else {
register_telegram_type(0x010C, F("IPMStatusMessage"), false, MAKE_PF_CB(process_IPMStatusMessage)); register_telegram_type(0x010C, "IPMStatusMessage", false, MAKE_PF_CB(process_IPMStatusMessage));
register_telegram_type(0x011E, F("IPMTempMessage"), false, MAKE_PF_CB(process_IPMTempMessage)); register_telegram_type(0x011E, "IPMTempMessage", false, MAKE_PF_CB(process_IPMTempMessage));
// register_telegram_type(0x0123, F("IPMSetMessage"), false, MAKE_PF_CB(process_IPMSetMessage)); // register_telegram_type(0x0123, "IPMSetMessage", false, MAKE_PF_CB(process_IPMSetMessage));
type_ = Type::HC; type_ = Type::HC;
hc_ = device_id - 0x20 + 1; hc_ = device_id - 0x20 + 1;
uint8_t tag = DeviceValueTAG::TAG_HC1 + hc_ - 1; uint8_t tag = DeviceValueTAG::TAG_HC1 + hc_ - 1;

View File

@@ -25,7 +25,7 @@ namespace emsesp {
class Mixer : public EMSdevice { class Mixer : public EMSdevice {
public: public:
Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand); Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand);
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;

View File

@@ -24,48 +24,48 @@ REGISTER_FACTORY(Solar, EMSdevice::DeviceType::SOLAR);
uuid::log::Logger Solar::logger_{F_(solar), uuid::log::Facility::CONSOLE}; uuid::log::Logger Solar::logger_{F_(solar), uuid::log::Facility::CONSOLE};
Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand) Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// telegram handlers // telegram handlers
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM10) { if (flags == EMSdevice::EMS_DEVICE_FLAG_SM10) {
register_telegram_type(0x97, F("SM10Monitor"), false, MAKE_PF_CB(process_SM10Monitor)); register_telegram_type(0x97, "SM10Monitor", false, MAKE_PF_CB(process_SM10Monitor));
register_telegram_type(0x96, F("SM10Config"), true, MAKE_PF_CB(process_SM10Config)); register_telegram_type(0x96, "SM10Config", true, MAKE_PF_CB(process_SM10Config));
EMSESP::send_read_request(0x97, device_id); EMSESP::send_read_request(0x97, device_id);
} }
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) { if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) {
if (device_id == 0x2A) { // SM100 DHW if (device_id == 0x2A) { // SM100 DHW
register_telegram_type(0x07D6, F("SM100wwTemperature"), false, MAKE_PF_CB(process_SM100wwTemperature)); register_telegram_type(0x07D6, "SM100wwTemperature", false, MAKE_PF_CB(process_SM100wwTemperature));
register_telegram_type(0x07AA, F("SM100wwStatus"), false, MAKE_PF_CB(process_SM100wwStatus)); register_telegram_type(0x07AA, "SM100wwStatus", false, MAKE_PF_CB(process_SM100wwStatus));
register_telegram_type(0x07AB, F("SM100wwCommand"), false, MAKE_PF_CB(process_SM100wwCommand)); register_telegram_type(0x07AB, "SM100wwCommand", false, MAKE_PF_CB(process_SM100wwCommand));
register_telegram_type(0x07A5, F("SM100wwCirc"), true, MAKE_PF_CB(process_SM100wwCirc)); register_telegram_type(0x07A5, "SM100wwCirc", true, MAKE_PF_CB(process_SM100wwCirc));
register_telegram_type(0x07A6, F("SM100wwParam"), true, MAKE_PF_CB(process_SM100wwParam)); register_telegram_type(0x07A6, "SM100wwParam", true, MAKE_PF_CB(process_SM100wwParam));
register_telegram_type(0x07AE, F("SM100wwKeepWarm"), true, MAKE_PF_CB(process_SM100wwKeepWarm)); register_telegram_type(0x07AE, "SM100wwKeepWarm", true, MAKE_PF_CB(process_SM100wwKeepWarm));
register_telegram_type(0x07E0, F("SM100wwStatus2"), true, MAKE_PF_CB(process_SM100wwStatus2)); register_telegram_type(0x07E0, "SM100wwStatus2", true, MAKE_PF_CB(process_SM100wwStatus2));
} else { } else {
// F9 is not a telegram type, it's a flag for configure // F9 is not a telegram type, it's a flag for configure
// register_telegram_type(0xF9, F("ParamCfg"), false, MAKE_PF_CB(process_SM100ParamCfg)); // register_telegram_type(0xF9, "ParamCfg", false, MAKE_PF_CB(process_SM100ParamCfg));
register_telegram_type(0x0358, F("SM100SystemConfig"), true, MAKE_PF_CB(process_SM100SystemConfig)); register_telegram_type(0x0358, "SM100SystemConfig", true, MAKE_PF_CB(process_SM100SystemConfig));
register_telegram_type(0x035A, F("SM100CircuitConfig"), true, MAKE_PF_CB(process_SM100CircuitConfig)); register_telegram_type(0x035A, "SM100CircuitConfig", true, MAKE_PF_CB(process_SM100CircuitConfig));
register_telegram_type(0x035D, F("SM100Circuit2Config"), true, MAKE_PF_CB(process_SM100Circuit2Config)); register_telegram_type(0x035D, "SM100Circuit2Config", true, MAKE_PF_CB(process_SM100Circuit2Config));
register_telegram_type(0x0362, F("SM100Monitor"), false, MAKE_PF_CB(process_SM100Monitor)); register_telegram_type(0x0362, "SM100Monitor", false, MAKE_PF_CB(process_SM100Monitor));
register_telegram_type(0x0363, F("SM100Monitor2"), false, MAKE_PF_CB(process_SM100Monitor2)); register_telegram_type(0x0363, "SM100Monitor2", false, MAKE_PF_CB(process_SM100Monitor2));
register_telegram_type(0x0366, F("SM100Config"), false, MAKE_PF_CB(process_SM100Config)); register_telegram_type(0x0366, "SM100Config", false, MAKE_PF_CB(process_SM100Config));
register_telegram_type(0x0364, F("SM100Status"), false, MAKE_PF_CB(process_SM100Status)); register_telegram_type(0x0364, "SM100Status", false, MAKE_PF_CB(process_SM100Status));
register_telegram_type(0x036A, F("SM100Status2"), false, MAKE_PF_CB(process_SM100Status2)); register_telegram_type(0x036A, "SM100Status2", false, MAKE_PF_CB(process_SM100Status2));
register_telegram_type(0x0380, F("SM100CollectorConfig"), true, MAKE_PF_CB(process_SM100CollectorConfig)); register_telegram_type(0x0380, "SM100CollectorConfig", true, MAKE_PF_CB(process_SM100CollectorConfig));
register_telegram_type(0x038E, F("SM100Energy"), true, MAKE_PF_CB(process_SM100Energy)); register_telegram_type(0x038E, "SM100Energy", true, MAKE_PF_CB(process_SM100Energy));
register_telegram_type(0x0391, F("SM100Time"), true, MAKE_PF_CB(process_SM100Time)); register_telegram_type(0x0391, "SM100Time", true, MAKE_PF_CB(process_SM100Time));
register_telegram_type(0x035F, F("SM100Config1"), true, MAKE_PF_CB(process_SM100Config1)); register_telegram_type(0x035F, "SM100Config1", true, MAKE_PF_CB(process_SM100Config1));
register_telegram_type(0x035C, F("SM100HeatAssist"), true, MAKE_PF_CB(process_SM100HeatAssist)); register_telegram_type(0x035C, "SM100HeatAssist", true, MAKE_PF_CB(process_SM100HeatAssist));
register_telegram_type(0x0361, F("SM100Differential"), true, MAKE_PF_CB(process_SM100Differential)); register_telegram_type(0x0361, "SM100Differential", true, MAKE_PF_CB(process_SM100Differential));
} }
} }
if (flags == EMSdevice::EMS_DEVICE_FLAG_ISM) { if (flags == EMSdevice::EMS_DEVICE_FLAG_ISM) {
register_telegram_type(0x0103, F("ISM1StatusMessage"), true, MAKE_PF_CB(process_ISM1StatusMessage)); register_telegram_type(0x0103, "ISM1StatusMessage", true, MAKE_PF_CB(process_ISM1StatusMessage));
register_telegram_type(0x0101, F("ISM1Set"), true, MAKE_PF_CB(process_ISM1Set)); register_telegram_type(0x0101, "ISM1Set", true, MAKE_PF_CB(process_ISM1Set));
register_telegram_type(0x0104, F("ISM2StatusMessage"), false, MAKE_PF_CB(process_ISM2StatusMessage)); register_telegram_type(0x0104, "ISM2StatusMessage", false, MAKE_PF_CB(process_ISM2StatusMessage));
} }
// device values... // device values...
@@ -664,7 +664,7 @@ void Solar::process_SM100ParamCfg(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(max, 13); telegram->read_value(max, 13);
telegram->read_value(cur, 17); telegram->read_value(cur, 17);
// LOG_DEBUG(F("SM100ParamCfg param=0x%04X, offset=%d, min=%d, default=%d, max=%d, current=%d"), t_id, of, min, def, max, cur)); // LOG_DEBUG("SM100ParamCfg param=0x%04X, offset=%d, min=%d, default=%d, max=%d, current=%d", t_id, of, min, def, max, cur));
} }
/* /*

View File

@@ -25,7 +25,7 @@ namespace emsesp {
class Solar : public EMSdevice { class Solar : public EMSdevice {
public: public:
Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand); Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand);
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;

View File

@@ -22,12 +22,12 @@ namespace emsesp {
REGISTER_FACTORY(Switch, EMSdevice::DeviceType::SWITCH); REGISTER_FACTORY(Switch, EMSdevice::DeviceType::SWITCH);
Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand) Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// WM10 module, device_id 0x11 // WM10 module, device_id 0x11
register_telegram_type(0x9C, F("WM10MonitorMessage"), false, MAKE_PF_CB(process_WM10MonitorMessage)); register_telegram_type(0x9C, "WM10MonitorMessage", false, MAKE_PF_CB(process_WM10MonitorMessage));
register_telegram_type(0x9D, F("WM10SetMessage"), false, MAKE_PF_CB(process_WM10SetMessage)); register_telegram_type(0x9D, "WM10SetMessage", false, MAKE_PF_CB(process_WM10SetMessage));
register_telegram_type(0x1E, F("WM10TempMessage"), false, MAKE_PF_CB(process_WM10TempMessage)); register_telegram_type(0x1E, "WM10TempMessage", false, MAKE_PF_CB(process_WM10TempMessage));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &activated_, DeviceValueType::BOOL, FL_(activated), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &activated_, DeviceValueType::BOOL, FL_(activated), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,

View File

@@ -25,7 +25,7 @@ namespace emsesp {
class Switch : public EMSdevice { class Switch : public EMSdevice {
public: public:
Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand); Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand);
private: private:
void process_WM10SetMessage(std::shared_ptr<const Telegram> telegram); void process_WM10SetMessage(std::shared_ptr<const Telegram> telegram);

View File

@@ -24,37 +24,37 @@ REGISTER_FACTORY(Thermostat, EMSdevice::DeviceType::THERMOSTAT);
uuid::log::Logger Thermostat::logger_{F_(thermostat), uuid::log::Facility::CONSOLE}; uuid::log::Logger Thermostat::logger_{F_(thermostat), uuid::log::Facility::CONSOLE};
Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand) Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
uint8_t model = this->model(); uint8_t model = this->model();
// RF remote sensor seen at 0x40, maybe this is also for different hc with id 0x40 - 0x47? emsesp.cpp maps only 0x40 // RF remote sensor seen at 0x40, maybe this is also for different hc with id 0x40 - 0x47? emsesp.cpp maps only 0x40
if (device_id >= 0x40 && device_id <= 0x47) { if (device_id >= 0x40 && device_id <= 0x47) {
register_telegram_type(0x0435, F("RFTemp"), false, MAKE_PF_CB(process_RemoteTemp)); register_telegram_type(0x0435, "RFTemp", false, MAKE_PF_CB(process_RemoteTemp));
return; return;
} }
// remote thermostats with humidity: RC100H remote // remote thermostats with humidity: RC100H remote
if (device_id >= 0x38 && device_id <= 0x3F) { if (device_id >= 0x38 && device_id <= 0x3F) {
register_telegram_type(0x042B, F("RemoteTemp"), false, MAKE_PF_CB(process_RemoteTemp)); register_telegram_type(0x042B, "RemoteTemp", false, MAKE_PF_CB(process_RemoteTemp));
register_telegram_type(0x047B, F("RemoteHumidity"), false, MAKE_PF_CB(process_RemoteHumidity)); register_telegram_type(0x047B, "RemoteHumidity", false, MAKE_PF_CB(process_RemoteHumidity));
register_telegram_type(0x0273, F("RemoteCorrection"), true, MAKE_PF_CB(process_RemoteCorrection)); register_telegram_type(0x0273, "RemoteCorrection", true, MAKE_PF_CB(process_RemoteCorrection));
register_device_values(); // register device values for common values (not heating circuit) register_device_values(); // register device values for common values (not heating circuit)
return; // no values to add return; // no values to add
} }
// common telegram handlers // common telegram handlers
register_telegram_type(EMS_TYPE_RCOutdoorTemp, F("RCOutdoorTemp"), false, MAKE_PF_CB(process_RCOutdoorTemp)); register_telegram_type(EMS_TYPE_RCOutdoorTemp, "RCOutdoorTemp", false, MAKE_PF_CB(process_RCOutdoorTemp));
register_telegram_type(EMS_TYPE_RCTime, F("RCTime"), false, MAKE_PF_CB(process_RCTime)); register_telegram_type(EMS_TYPE_RCTime, "RCTime", false, MAKE_PF_CB(process_RCTime));
register_telegram_type(0xA2, F("RCError"), false, MAKE_PF_CB(process_RCError)); register_telegram_type(0xA2, "RCError", false, MAKE_PF_CB(process_RCError));
register_telegram_type(0x12, F("RCErrorMessage"), false, MAKE_PF_CB(process_RCErrorMessage)); register_telegram_type(0x12, "RCErrorMessage", false, MAKE_PF_CB(process_RCErrorMessage));
register_telegram_type(0x13, F("RCErrorMessage2"), false, MAKE_PF_CB(process_RCErrorMessage)); register_telegram_type(0x13, "RCErrorMessage2", false, MAKE_PF_CB(process_RCErrorMessage));
// RC10 // RC10
if (model == EMSdevice::EMS_DEVICE_FLAG_RC10) { if (model == EMSdevice::EMS_DEVICE_FLAG_RC10) {
monitor_typeids = {0xB1}; monitor_typeids = {0xB1};
set_typeids = {0xB0}; set_typeids = {0xB0};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC10Monitor"), false, MAKE_PF_CB(process_RC10Monitor)); register_telegram_type(monitor_typeids[i], "RC10Monitor", false, MAKE_PF_CB(process_RC10Monitor));
register_telegram_type(set_typeids[i], F("RC10Set"), false, MAKE_PF_CB(process_RC10Set)); register_telegram_type(set_typeids[i], "RC10Set", false, MAKE_PF_CB(process_RC10Set));
} }
// RC35 // RC35
@@ -64,15 +64,15 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
timer_typeids = {0x3F, 0x49, 0x53, 0x5D}; timer_typeids = {0x3F, 0x49, 0x53, 0x5D};
timer2_typeids = {0x42, 0x4C, 0x56, 0x60}; timer2_typeids = {0x42, 0x4C, 0x56, 0x60};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC35Monitor"), false, MAKE_PF_CB(process_RC35Monitor)); register_telegram_type(monitor_typeids[i], "RC35Monitor", false, MAKE_PF_CB(process_RC35Monitor));
register_telegram_type(set_typeids[i], F("RC35Set"), false, MAKE_PF_CB(process_RC35Set)); register_telegram_type(set_typeids[i], "RC35Set", false, MAKE_PF_CB(process_RC35Set));
register_telegram_type(timer_typeids[i], F("RC35Timer"), false, MAKE_PF_CB(process_RC35Timer)); register_telegram_type(timer_typeids[i], "RC35Timer", false, MAKE_PF_CB(process_RC35Timer));
register_telegram_type(timer2_typeids[i], F("RC35Timer2"), false, MAKE_PF_CB(process_RC35Timer)); register_telegram_type(timer2_typeids[i], "RC35Timer2", false, MAKE_PF_CB(process_RC35Timer));
} }
register_telegram_type(EMS_TYPE_IBASettings, F("IBASettings"), true, MAKE_PF_CB(process_IBASettings)); register_telegram_type(EMS_TYPE_IBASettings, "IBASettings", true, MAKE_PF_CB(process_IBASettings));
register_telegram_type(EMS_TYPE_wwSettings, F("WWSettings"), true, MAKE_PF_CB(process_RC35wwSettings)); register_telegram_type(EMS_TYPE_wwSettings, "WWSettings", true, MAKE_PF_CB(process_RC35wwSettings));
register_telegram_type(0x38, F("WWTimer"), true, MAKE_PF_CB(process_RC35wwTimer)); register_telegram_type(0x38, "WWTimer", true, MAKE_PF_CB(process_RC35wwTimer));
register_telegram_type(0x39, F("WWCircTimer"), true, MAKE_PF_CB(process_RC35wwTimer)); register_telegram_type(0x39, "WWCircTimer", true, MAKE_PF_CB(process_RC35wwTimer));
// RC20 // RC20
} else if (model == EMSdevice::EMS_DEVICE_FLAG_RC20) { } else if (model == EMSdevice::EMS_DEVICE_FLAG_RC20) {
@@ -81,22 +81,22 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
curve_typeids = {0x90}; curve_typeids = {0x90};
timer_typeids = {0x8F}; timer_typeids = {0x8F};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, MAKE_PF_CB(process_RC20Monitor)); register_telegram_type(monitor_typeids[i], "RC20Monitor", false, MAKE_PF_CB(process_RC20Monitor));
register_telegram_type(set_typeids[i], F("RC20Set"), false, MAKE_PF_CB(process_RC20Set)); register_telegram_type(set_typeids[i], "RC20Set", false, MAKE_PF_CB(process_RC20Set));
register_telegram_type(curve_typeids[i], F("RC20Temp"), false, MAKE_PF_CB(process_RC20Temp)); register_telegram_type(curve_typeids[i], "RC20Temp", false, MAKE_PF_CB(process_RC20Temp));
register_telegram_type(timer_typeids[i], F("RC20Timer"), false, MAKE_PF_CB(process_RC20Timer)); register_telegram_type(timer_typeids[i], "RC20Timer", false, MAKE_PF_CB(process_RC20Timer));
} }
// remote thermostat uses only 0xAF // remote thermostat uses only 0xAF
register_telegram_type(0xAF, F("RC20Remote"), false, MAKE_PF_CB(process_RC20Remote)); register_telegram_type(0xAF, "RC20Remote", false, MAKE_PF_CB(process_RC20Remote));
// RC20 newer // RC20 newer
} else if ((model == EMSdevice::EMS_DEVICE_FLAG_RC20_N) || (model == EMSdevice::EMS_DEVICE_FLAG_RC25)) { } else if ((model == EMSdevice::EMS_DEVICE_FLAG_RC20_N) || (model == EMSdevice::EMS_DEVICE_FLAG_RC25)) {
monitor_typeids = {0xAE}; monitor_typeids = {0xAE};
set_typeids = {0xAD}; set_typeids = {0xAD};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, MAKE_PF_CB(process_RC20Monitor_2)); register_telegram_type(monitor_typeids[i], "RC20Monitor", false, MAKE_PF_CB(process_RC20Monitor_2));
register_telegram_type(set_typeids[i], F("RC20Set"), false, MAKE_PF_CB(process_RC20Set_2)); register_telegram_type(set_typeids[i], "RC20Set", false, MAKE_PF_CB(process_RC20Set_2));
} }
register_telegram_type(0xAF, F("RC20Remote"), false, MAKE_PF_CB(process_RC20Remote)); register_telegram_type(0xAF, "RC20Remote", false, MAKE_PF_CB(process_RC20Remote));
// RC30 // RC30
} else if (model == EMSdevice::EMS_DEVICE_FLAG_RC30) { } else if (model == EMSdevice::EMS_DEVICE_FLAG_RC30) {
monitor_typeids = {0x41}; monitor_typeids = {0x41};
@@ -104,27 +104,27 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
curve_typeids = {0x40}; curve_typeids = {0x40};
timer_typeids = {0x3F}; timer_typeids = {0x3F};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC30Monitor"), false, MAKE_PF_CB(process_RC30Monitor)); register_telegram_type(monitor_typeids[i], "RC30Monitor", false, MAKE_PF_CB(process_RC30Monitor));
register_telegram_type(set_typeids[i], F("RC30Set"), false, MAKE_PF_CB(process_RC30Set)); register_telegram_type(set_typeids[i], "RC30Set", false, MAKE_PF_CB(process_RC30Set));
register_telegram_type(curve_typeids[i], F("RC30Temp"), false, MAKE_PF_CB(process_RC30Temp)); register_telegram_type(curve_typeids[i], "RC30Temp", false, MAKE_PF_CB(process_RC30Temp));
register_telegram_type(timer_typeids[i], F("RC30Timer"), false, MAKE_PF_CB(process_RC35Timer)); register_telegram_type(timer_typeids[i], "RC30Timer", false, MAKE_PF_CB(process_RC35Timer));
} }
register_telegram_type(EMS_TYPE_RC30wwSettings, F("RC30WWSettings"), true, MAKE_PF_CB(process_RC30wwSettings)); register_telegram_type(EMS_TYPE_RC30wwSettings, "RC30WWSettings", true, MAKE_PF_CB(process_RC30wwSettings));
register_telegram_type(0x38, F("WWTimer"), true, MAKE_PF_CB(process_RC35wwTimer)); register_telegram_type(0x38, "WWTimer", true, MAKE_PF_CB(process_RC35wwTimer));
register_telegram_type(0x39, F("WWCircTimer"), true, MAKE_PF_CB(process_RC35wwTimer)); register_telegram_type(0x39, "WWCircTimer", true, MAKE_PF_CB(process_RC35wwTimer));
// EASY // EASY
} else if (model == EMSdevice::EMS_DEVICE_FLAG_EASY) { } else if (model == EMSdevice::EMS_DEVICE_FLAG_EASY) {
monitor_typeids = {0x0A}; monitor_typeids = {0x0A};
set_typeids = {}; set_typeids = {};
register_telegram_type(monitor_typeids[0], F("EasyMonitor"), true, MAKE_PF_CB(process_EasyMonitor)); register_telegram_type(monitor_typeids[0], "EasyMonitor", true, MAKE_PF_CB(process_EasyMonitor));
// CRF // CRF
} else if (model == EMSdevice::EMS_DEVICE_FLAG_CRF) { } else if (model == EMSdevice::EMS_DEVICE_FLAG_CRF) {
monitor_typeids = {0x02A5, 0x02A6, 0x02A7, 0x02A8}; monitor_typeids = {0x02A5, 0x02A6, 0x02A7, 0x02A8};
set_typeids = {}; set_typeids = {};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("CRFMonitor"), false, MAKE_PF_CB(process_CRFMonitor)); register_telegram_type(monitor_typeids[i], "CRFMonitor", false, MAKE_PF_CB(process_CRFMonitor));
} }
// RC300/RC100 // RC300/RC100
@@ -136,46 +136,46 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
curve_typeids = {0x029B, 0x029C, 0x029D, 0x029E, 0x029F, 0x02A0, 0x02A1, 0x02A2}; curve_typeids = {0x029B, 0x029C, 0x029D, 0x029E, 0x029F, 0x02A0, 0x02A1, 0x02A2};
summer2_typeids = {0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0476, 0x0477, 0x0478}; summer2_typeids = {0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0476, 0x0477, 0x0478};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC300Monitor"), false, MAKE_PF_CB(process_RC300Monitor)); register_telegram_type(monitor_typeids[i], "RC300Monitor", false, MAKE_PF_CB(process_RC300Monitor));
register_telegram_type(set_typeids[i], F("RC300Set"), false, MAKE_PF_CB(process_RC300Set)); register_telegram_type(set_typeids[i], "RC300Set", false, MAKE_PF_CB(process_RC300Set));
register_telegram_type(summer_typeids[i], F("RC300Summer"), false, MAKE_PF_CB(process_RC300Summer)); register_telegram_type(summer_typeids[i], "RC300Summer", false, MAKE_PF_CB(process_RC300Summer));
register_telegram_type(curve_typeids[i], F("RC300Curves"), false, MAKE_PF_CB(process_RC300Curve)); register_telegram_type(curve_typeids[i], "RC300Curves", false, MAKE_PF_CB(process_RC300Curve));
register_telegram_type(summer2_typeids[i], F("RC300Summer2"), false, MAKE_PF_CB(process_RC300Summer2)); register_telegram_type(summer2_typeids[i], "RC300Summer2", false, MAKE_PF_CB(process_RC300Summer2));
} }
for (uint8_t i = 0; i < set2_typeids.size(); i++) { for (uint8_t i = 0; i < set2_typeids.size(); i++) {
register_telegram_type(set2_typeids[i], F("RC300Set2"), false, MAKE_PF_CB(process_RC300Set2)); register_telegram_type(set2_typeids[i], "RC300Set2", false, MAKE_PF_CB(process_RC300Set2));
} }
register_telegram_type(0x2F5, F("RC300WWmode"), true, MAKE_PF_CB(process_RC300WWmode)); register_telegram_type(0x2F5, "RC300WWmode", true, MAKE_PF_CB(process_RC300WWmode));
register_telegram_type(0x31B, F("RC300WWtemp"), true, MAKE_PF_CB(process_RC300WWtemp)); register_telegram_type(0x31B, "RC300WWtemp", true, MAKE_PF_CB(process_RC300WWtemp));
register_telegram_type(0x31D, F("RC300WWmode2"), false, MAKE_PF_CB(process_RC300WWmode2)); register_telegram_type(0x31D, "RC300WWmode2", false, MAKE_PF_CB(process_RC300WWmode2));
register_telegram_type(0x31E, F("RC300WWmode2"), false, MAKE_PF_CB(process_RC300WWmode2)); register_telegram_type(0x31E, "RC300WWmode2", false, MAKE_PF_CB(process_RC300WWmode2));
register_telegram_type(0x23A, F("RC300OutdoorTemp"), true, MAKE_PF_CB(process_RC300OutdoorTemp)); register_telegram_type(0x23A, "RC300OutdoorTemp", true, MAKE_PF_CB(process_RC300OutdoorTemp));
register_telegram_type(0x267, F("RC300Floordry"), false, MAKE_PF_CB(process_RC300Floordry)); register_telegram_type(0x267, "RC300Floordry", false, MAKE_PF_CB(process_RC300Floordry));
register_telegram_type(0x240, F("RC300Settings"), true, MAKE_PF_CB(process_RC300Settings)); register_telegram_type(0x240, "RC300Settings", true, MAKE_PF_CB(process_RC300Settings));
// JUNKERS/HT3 // JUNKERS/HT3
} else if (model == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) { } else if (model == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) {
monitor_typeids = {0x016F, 0x0170, 0x0171, 0x0172}; monitor_typeids = {0x016F, 0x0170, 0x0171, 0x0172};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("JunkersMonitor"), false, MAKE_PF_CB(process_JunkersMonitor)); register_telegram_type(monitor_typeids[i], "JunkersMonitor", false, MAKE_PF_CB(process_JunkersMonitor));
} }
if (has_flags(EMS_DEVICE_FLAG_JUNKERS_OLD)) { if (has_flags(EMS_DEVICE_FLAG_JUNKERS_OLD)) {
// FR120, FR100 // FR120, FR100
set_typeids = {0x0179, 0x017A, 0x017B, 0x017C}; set_typeids = {0x0179, 0x017A, 0x017B, 0x017C};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(set_typeids[i], F("JunkersSet"), false, MAKE_PF_CB(process_JunkersSet2)); register_telegram_type(set_typeids[i], "JunkersSet", false, MAKE_PF_CB(process_JunkersSet2));
} }
} else { } else {
set_typeids = {0x0165, 0x0166, 0x0167, 0x0168}; set_typeids = {0x0165, 0x0166, 0x0167, 0x0168};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(set_typeids[i], F("JunkersSet"), false, MAKE_PF_CB(process_JunkersSet)); register_telegram_type(set_typeids[i], "JunkersSet", false, MAKE_PF_CB(process_JunkersSet));
} }
} }
register_telegram_type(0xBB, F("HybridSettings"), true, MAKE_PF_CB(process_JunkersHybridSettings)); register_telegram_type(0xBB, "HybridSettings", true, MAKE_PF_CB(process_JunkersHybridSettings));
register_telegram_type(0x23, F("JunkersSetMixer"), true, MAKE_PF_CB(process_JunkersSetMixer)); register_telegram_type(0x23, "JunkersSetMixer", true, MAKE_PF_CB(process_JunkersSetMixer));
register_telegram_type(0x123, F("JunkersRemote"), false, MAKE_PF_CB(process_JunkersRemoteMonitor)); register_telegram_type(0x123, "JunkersRemote", false, MAKE_PF_CB(process_JunkersRemoteMonitor));
register_telegram_type(0x1D3, F("JunkersDhw"), true, MAKE_PF_CB(process_JunkersWW)); register_telegram_type(0x1D3, "JunkersDhw", true, MAKE_PF_CB(process_JunkersWW));
} }
// register device values for common values (not heating circuit) // register device values for common values (not heating circuit)
@@ -593,7 +593,7 @@ void Thermostat::process_RC20Timer(std::shared_ptr<const Telegram> telegram) {
uint8_t time = telegram->message_data[1]; uint8_t time = telegram->message_data[1];
// we use EN settings for the day abbreviation // we use EN settings for the day abbreviation
std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day][0]); std::string sday = (FL_(enum_dayOfWeek)[day][0]);
// std::string sday = Helpers::translated_word(FL_(enum_dayOfWeek)[day]); // std::string sday = Helpers::translated_word(FL_(enum_dayOfWeek)[day]);
if (day == 7) { if (day == 7) {
@@ -680,6 +680,12 @@ void Thermostat::process_JunkersSet(std::shared_ptr<const Telegram> telegram) {
return; return;
} }
has_update(telegram, hc->daytemp, 17); // is * 2
has_update(telegram, hc->nighttemp, 16); // is * 2
has_update(telegram, hc->nofrosttemp, 15); // is * 2
has_update(telegram, hc->control, 1); // remote: 0-off, 1-FB10, 2-FB100
has_enumupdate(telegram, hc->program, 13, 1); // 1-6: 1 = A, 2 = B,...
has_enumupdate(telegram, hc->mode, 14, 1); // 0 = nofrost, 1 = eco, 2 = heat, 3 = auto
has_update(telegram, hc->daytemp, 17); // is * 2 has_update(telegram, hc->daytemp, 17); // is * 2
has_update(telegram, hc->nighttemp, 16); // is * 2 has_update(telegram, hc->nighttemp, 16); // is * 2
has_update(telegram, hc->nofrosttemp, 15); // is * 2 has_update(telegram, hc->nofrosttemp, 15); // is * 2
@@ -795,7 +801,7 @@ void Thermostat::process_RC35wwTimer(std::shared_ptr<const Telegram> telegram) {
char data[sizeof(wwSwitchTime_)]; char data[sizeof(wwSwitchTime_)];
// we use EN settings for the day abbreviation // we use EN settings for the day abbreviation
std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day][0]); std::string sday = (FL_(enum_dayOfWeek)[day][0]);
// std::string sday = Helpers::translated_word(FL_(enum_dayOfWeek)[day]); // std::string sday = Helpers::translated_word(FL_(enum_dayOfWeek)[day]);
if (day == 7) { if (day == 7) {
snprintf(data, sizeof(data), "%02d not_set", no); snprintf(data, sizeof(data), "%02d not_set", no);
@@ -1274,7 +1280,7 @@ void Thermostat::process_RC35Timer(std::shared_ptr<const Telegram> telegram) {
uint8_t time = telegram->message_data[1]; uint8_t time = telegram->message_data[1];
// we use EN settings for the day abbreviation // we use EN settings for the day abbreviation
std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day][0]); std::string sday = (FL_(enum_dayOfWeek)[day][0]);
// std::string sday = Helpers::translated_word(FL_(enum_dayOfWeek)[day]); // std::string sday = Helpers::translated_word(FL_(enum_dayOfWeek)[day]);
if (day == 7) { if (day == 7) {
snprintf(data, sizeof(data), "%02d not_set", no); snprintf(data, sizeof(data), "%02d not_set", no);
@@ -1372,7 +1378,7 @@ void Thermostat::process_RCTime(std::shared_ptr<const Telegram> telegram) {
double difference = difftime(now, ttime); double difference = difftime(now, ttime);
if (difference > 15 || difference < -15) { if (difference > 15 || difference < -15) {
set_datetime("ntp", -1); // set from NTP set_datetime("ntp", -1); // set from NTP
LOG_INFO(F("thermostat time correction from ntp")); LOG_INFO("thermostat time correction from ntp");
} }
} }
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
@@ -1383,7 +1389,7 @@ void Thermostat::process_RCTime(std::shared_ptr<const Telegram> telegram) {
} }
struct timeval newnow = {.tv_sec = ttime}; struct timeval newnow = {.tv_sec = ttime};
settimeofday(&newnow, nullptr); settimeofday(&newnow, nullptr);
LOG_INFO(F("ems-esp time set from thermostat")); LOG_INFO("ems-esp time set from thermostat");
} }
#endif #endif
} }
@@ -1551,7 +1557,7 @@ bool Thermostat::set_calinttemp(const char * value, const int8_t id) {
} }
auto t = (int8_t)(ct * 10); auto t = (int8_t)(ct * 10);
LOG_DEBUG(F("Calibrating internal temperature to %d.%d C"), t / 10, t < 0 ? -t % 10 : t % 10); LOG_DEBUG("Calibrating internal temperature to %d.%d C", t / 10, t < 0 ? -t % 10 : t % 10);
if (model() == EMS_DEVICE_FLAG_RC10) { if (model() == EMS_DEVICE_FLAG_RC10) {
write_command(0xB0, 0, t, 0xB0); write_command(0xB0, 0, t, 0xB0);
@@ -2155,7 +2161,7 @@ bool Thermostat::set_datetime(const char * value, const int8_t id) {
return false; return false;
} }
if (!EMSESP::system_.ntp_connected()) { if (!EMSESP::system_.ntp_connected()) {
LOG_WARNING(F("Set date: no valid NTP data, setting from ESP Clock")); LOG_WARNING("Set date: no valid NTP data, setting from ESP Clock");
} }
data[0] = tm_->tm_year - 100; // Bosch counts from 2000 data[0] = tm_->tm_year - 100; // Bosch counts from 2000
@@ -2183,15 +2189,15 @@ bool Thermostat::set_datetime(const char * value, const int8_t id) {
data[7] = 0; data[7] = 0;
} }
} else { } else {
LOG_WARNING(F("Set date: invalid data, wrong length")); LOG_WARNING("Set date: invalid data, wrong length");
return false; return false;
} }
if (data[1] == 0 || data[1] > 12 || data[2] > 23 || data[3] == 0 || data[3] > 31 || data[4] > 59 || data[5] > 59 || data[6] > 6 || data[7] > 3) { if (data[1] == 0 || data[1] > 12 || data[2] > 23 || data[3] == 0 || data[3] > 31 || data[4] > 59 || data[5] > 59 || data[6] > 6 || data[7] > 3) {
LOG_WARNING(F("Invalid date/time: %02d.%02d.2%03d-%02d:%02d:%02d-%d-%d"), data[3], data[1], data[0], data[2], data[4], data[5], data[6], data[7]); LOG_WARNING("Invalid date/time: %02d.%02d.2%03d-%02d:%02d:%02d-%d-%d", data[3], data[1], data[0], data[2], data[4], data[5], data[6], data[7]);
return false; return false;
} }
// LOG_INFO(F("Setting date and time: %02d.%02d.2%03d-%02d:%02d:%02d-%d-%d"), data[3], data[1], data[0], data[2], data[4], data[5], data[6], data[7]); // LOG_INFO("Setting date and time: %02d.%02d.2%03d-%02d:%02d:%02d-%d-%d", data[3], data[1], data[0], data[2], data[4], data[5], data[6], data[7]);
write_command(EMS_TYPE_time, 0, data, 8, EMS_TYPE_time); write_command(EMS_TYPE_time, 0, data, 8, EMS_TYPE_time);
return true; return true;
@@ -2664,7 +2670,7 @@ bool Thermostat::set_switchtime(const char * value, const uint16_t type_id, char
day = 7; day = 7;
on = 7; on = 7;
time = 0x90; time = 0x90;
// LOG_INFO(F("switchtime %02d cleared"), no); // LOG_INFO("switchtime %02d cleared", no);
} }
} else { } else {
if (strlen(value) > 1) { if (strlen(value) > 1) {
@@ -2681,7 +2687,7 @@ bool Thermostat::set_switchtime(const char * value, const uint16_t type_id, char
if (strlen(value) > 4) { if (strlen(value) > 4) {
for (uint8_t i = 0; i < 7; i++) { for (uint8_t i = 0; i < 7; i++) {
// we use EN settings for the day abbreviation // we use EN settings for the day abbreviation
if (!strncmp(&value[3], read_flash_string(FL_(enum_dayOfWeek)[i][0]).c_str(), 2)) { if (!strncmp(&value[3], (FL_(enum_dayOfWeek)[i][0]), 2)) {
day = i; day = i;
} }
@@ -2705,7 +2711,7 @@ bool Thermostat::set_switchtime(const char * value, const uint16_t type_id, char
day = 7; day = 7;
on = 7; on = 7;
time = 0x90; time = 0x90;
// LOG_INFO(F("switchtime %02d cleared"), no); // LOG_INFO("switchtime %02d cleared", no);
} }
} }
uint8_t data[2] = {0xE7, 0x90}; // unset switchtime uint8_t data[2] = {0xE7, 0x90}; // unset switchtime
@@ -2721,20 +2727,20 @@ bool Thermostat::set_switchtime(const char * value, const uint16_t type_id, char
max_on = 1; max_on = 1;
} }
if (no > 41 || time > 0x90 || ((on < min_on || on > max_on) && on != 7)) { if (no > 41 || time > 0x90 || ((on < min_on || on > max_on) && on != 7)) {
// LOG_WARNING(F("Setting switchtime: Invalid data: %s"), value); // LOG_WARNING("Setting switchtime: Invalid data: %s", value);
// LOG_WARNING(F("Setting switchtime: Invalid data: %02d.%1d.0x%02X.%1d"), no, day, time, on); // LOG_WARNING("Setting switchtime: Invalid data: %02d.%1d.0x%02X.%1d", no, day, time, on);
return false; return false;
} }
if (data[0] != 0xE7) { if (data[0] != 0xE7) {
// we use EN settings for the day abbreviation // we use EN settings for the day abbreviation
std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day][0]); std::string sday = (FL_(enum_dayOfWeek)[day][0]);
// std::string sday = Helpers::translated_word(FL_(enum_dayOfWeek)[day]); // std::string sday = Helpers::translated_word(FL_(enum_dayOfWeek)[day]);
if (model() == EMS_DEVICE_FLAG_RC35 || model() == EMS_DEVICE_FLAG_RC30_N) { if (model() == EMS_DEVICE_FLAG_RC35 || model() == EMS_DEVICE_FLAG_RC30_N) {
snprintf(out, len, "%02d %s %02d:%02d %s", no, sday.c_str(), time / 6, 10 * (time % 6), on ? "on" : "off"); snprintf(out, len, "%02d %s %02d:%02d %s", no, sday.c_str(), time / 6, 10 * (time % 6), on ? "on" : "off");
} else if ((model() == EMS_DEVICE_FLAG_RC20) || (model() == EMS_DEVICE_FLAG_RC30)) { } else if ((model() == EMS_DEVICE_FLAG_RC20) || (model() == EMS_DEVICE_FLAG_RC30)) {
snprintf(out, len, "%02d %s %02d:%02d T%d", no, sday.c_str(), time / 6, 10 * (time % 6), on); snprintf(out, len, "%02d %s %02d:%02d T%d", no, sday.c_str(), time / 6, 10 * (time % 6), on);
} else { } else {
std::string son = read_flash_string(FL_(enum_switchmode)[on][0]); std::string son = (FL_(enum_switchmode)[on][0]);
// std::string son = Helpers::translated_word(FL_(enum_switchmode)[on]); // std::string son = Helpers::translated_word(FL_(enum_switchmode)[on]);
snprintf(out, len, "%02d %s %02d:%02d %s", no, sday.c_str(), time / 6, 10 * (time % 6), son.c_str()); snprintf(out, len, "%02d %s %02d:%02d %s", no, sday.c_str(), time / 6, 10 * (time % 6), son.c_str());
} }

View File

@@ -25,7 +25,7 @@ namespace emsesp {
class Thermostat : public EMSdevice { class Thermostat : public EMSdevice {
public: public:
Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand); Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand);
class HeatingCircuit { class HeatingCircuit {
public: public:
HeatingCircuit(const uint8_t hc_num, const uint8_t model) HeatingCircuit(const uint8_t hc_num, const uint8_t model)

View File

@@ -44,39 +44,39 @@ bool EMSdevice::has_entities() const {
} }
std::string EMSdevice::tag_to_string(uint8_t tag) { std::string EMSdevice::tag_to_string(uint8_t tag) {
return read_flash_string(DeviceValue::DeviceValueTAG_s[tag]); return (DeviceValue::DeviceValueTAG_s[tag]);
} }
std::string EMSdevice::tag_to_mqtt(uint8_t tag) { std::string EMSdevice::tag_to_mqtt(uint8_t tag) {
return read_flash_string(DeviceValue::DeviceValueTAG_mqtt[tag]); return (DeviceValue::DeviceValueTAG_mqtt[tag]);
} }
// convert UOM to a string - these don't need translating // convert UOM to a string - these don't need translating
std::string EMSdevice::uom_to_string(uint8_t uom) { std::string EMSdevice::uom_to_string(uint8_t uom) {
if (EMSESP::system_.fahrenheit() && (uom == DeviceValueUOM::DEGREES || uom == DeviceValueUOM::DEGREES_R)) { if (EMSESP::system_.fahrenheit() && (uom == DeviceValueUOM::DEGREES || uom == DeviceValueUOM::DEGREES_R)) {
return read_flash_string(DeviceValue::DeviceValueUOM_s[DeviceValueUOM::FAHRENHEIT]); return (DeviceValue::DeviceValueUOM_s[DeviceValueUOM::FAHRENHEIT]);
} }
return read_flash_string(DeviceValue::DeviceValueUOM_s[uom]); return (DeviceValue::DeviceValueUOM_s[uom]);
} }
std::string EMSdevice::brand_to_string() const { std::string EMSdevice::brand_to_string() const {
switch (brand_) { switch (brand_) {
case EMSdevice::Brand::BOSCH: case EMSdevice::Brand::BOSCH:
return read_flash_string(F("Bosch")); return ("Bosch");
case EMSdevice::Brand::JUNKERS: case EMSdevice::Brand::JUNKERS:
return read_flash_string(F("Junkers")); return ("Junkers");
case EMSdevice::Brand::BUDERUS: case EMSdevice::Brand::BUDERUS:
return read_flash_string(F("Buderus")); return ("Buderus");
case EMSdevice::Brand::NEFIT: case EMSdevice::Brand::NEFIT:
return read_flash_string(F("Nefit")); return ("Nefit");
case EMSdevice::Brand::SIEGER: case EMSdevice::Brand::SIEGER:
return read_flash_string(F("Sieger")); return ("Sieger");
case EMSdevice::Brand::WORCESTER: case EMSdevice::Brand::WORCESTER:
return read_flash_string(F("Worcester")); return ("Worcester");
case EMSdevice::Brand::IVT: case EMSdevice::Brand::IVT:
return read_flash_string(F("IVT")); return ("IVT");
default: default:
return read_flash_string(F("")); return ("");
} }
} }
@@ -84,29 +84,29 @@ std::string EMSdevice::brand_to_string() const {
std::string EMSdevice::device_type_2_device_name(const uint8_t device_type) { std::string EMSdevice::device_type_2_device_name(const uint8_t device_type) {
switch (device_type) { switch (device_type) {
case DeviceType::SYSTEM: case DeviceType::SYSTEM:
return read_flash_string(F_(system)); return (F_(system));
case DeviceType::BOILER: case DeviceType::BOILER:
return read_flash_string(F_(boiler)); return (F_(boiler));
case DeviceType::THERMOSTAT: case DeviceType::THERMOSTAT:
return read_flash_string(F_(thermostat)); return (F_(thermostat));
case DeviceType::HEATPUMP: case DeviceType::HEATPUMP:
return read_flash_string(F_(heatpump)); return (F_(heatpump));
case DeviceType::SOLAR: case DeviceType::SOLAR:
return read_flash_string(F_(solar)); return (F_(solar));
case DeviceType::CONNECT: case DeviceType::CONNECT:
return read_flash_string(F_(connect)); return (F_(connect));
case DeviceType::MIXER: case DeviceType::MIXER:
return read_flash_string(F_(mixer)); return (F_(mixer));
case DeviceType::DALLASSENSOR: case DeviceType::DALLASSENSOR:
return read_flash_string(F_(dallassensor)); return (F_(dallassensor));
case DeviceType::ANALOGSENSOR: case DeviceType::ANALOGSENSOR:
return read_flash_string(F_(analogsensor)); return (F_(analogsensor));
case DeviceType::CONTROLLER: case DeviceType::CONTROLLER:
return read_flash_string(F_(controller)); return (F_(controller));
case DeviceType::SWITCH: case DeviceType::SWITCH:
return read_flash_string(F_(switch)); return (F_(switch));
case DeviceType::GATEWAY: case DeviceType::GATEWAY:
return read_flash_string(F_(gateway)); return (F_(gateway));
default: default:
return Helpers::translated_word(FL_(unknown)); return Helpers::translated_word(FL_(unknown));
} }
@@ -193,11 +193,11 @@ uint8_t EMSdevice::decode_brand(uint8_t value) {
std::string EMSdevice::to_string() const { std::string EMSdevice::to_string() const {
// for devices that haven't been lookup yet, don't show all details // for devices that haven't been lookup yet, don't show all details
if (product_id_ == 0) { if (product_id_ == 0) {
return name_ + " (DeviceID:" + Helpers::hextoa(device_id_) + ")"; return std::string(name_) + " (DeviceID:" + Helpers::hextoa(device_id_) + ")";
} }
if (brand_ == Brand::NO_BRAND) { if (brand_ == Brand::NO_BRAND) {
return name_ + " (DeviceID:" + Helpers::hextoa(device_id_) + ", ProductID:" + Helpers::itoa(product_id_) + ", Version:" + version_ + ")"; return std::string(name_) + " (DeviceID:" + Helpers::hextoa(device_id_) + ", ProductID:" + Helpers::itoa(product_id_) + ", Version:" + version_ + ")";
} }
return brand_to_string() + " " + name_ + " (DeviceID:" + Helpers::hextoa(device_id_) + ", ProductID:" + Helpers::itoa(product_id_) + ", Version:" + version_ return brand_to_string() + " " + name_ + " (DeviceID:" + Helpers::hextoa(device_id_) + ", ProductID:" + Helpers::itoa(product_id_) + ", Version:" + version_
@@ -215,7 +215,7 @@ std::string EMSdevice::to_string_short() const {
// for each telegram that has the fetch value set (true) do a read request // for each telegram that has the fetch value set (true) do a read request
void EMSdevice::fetch_values() { void EMSdevice::fetch_values() {
EMSESP::logger().debug(F("Fetching values for deviceID 0x%02X"), device_id()); EMSESP::logger().debug("Fetching values for deviceID 0x%02X", device_id());
for (const auto & tf : telegram_functions_) { for (const auto & tf : telegram_functions_) {
if (tf.fetch_) { if (tf.fetch_) {
@@ -226,7 +226,7 @@ void EMSdevice::fetch_values() {
// toggle on/off automatic fetch for a telegramID // toggle on/off automatic fetch for a telegramID
void EMSdevice::toggle_fetch(uint16_t telegram_id, bool toggle) { void EMSdevice::toggle_fetch(uint16_t telegram_id, bool toggle) {
EMSESP::logger().debug(F("Toggling fetch for deviceID 0x%02X, telegramID 0x%02X to %d"), device_id(), telegram_id, toggle); EMSESP::logger().debug("Toggling fetch for deviceID 0x%02X, telegramID 0x%02X to %d", device_id(), telegram_id, toggle);
for (auto & tf : telegram_functions_) { for (auto & tf : telegram_functions_) {
if (tf.telegram_type_id_ == telegram_id) { if (tf.telegram_type_id_ == telegram_id) {
@@ -264,9 +264,9 @@ void EMSdevice::list_device_entries(JsonObject & output) const {
// if we have a tag prefix it // if we have a tag prefix it
char key[50]; char key[50];
if (!EMSdevice::tag_to_mqtt(dv.tag).empty()) { if (!EMSdevice::tag_to_mqtt(dv.tag).empty()) {
snprintf(key, sizeof(key), "%s.%s", EMSdevice::tag_to_mqtt(dv.tag).c_str(), read_flash_string(dv.short_name).c_str()); snprintf(key, sizeof(key), "%s.%s", EMSdevice::tag_to_mqtt(dv.tag).c_str(), (dv.short_name));
} else { } else {
snprintf(key, sizeof(key), "%s", read_flash_string(dv.short_name).c_str()); snprintf(key, sizeof(key), "%s", (dv.short_name));
} }
JsonArray details = output.createNestedArray(key); JsonArray details = output.createNestedArray(key);
@@ -289,7 +289,7 @@ void EMSdevice::show_telegram_handlers(uuid::console::Shell & shell) const {
} }
/* /*
// colored list of type-ids // colored list of type-ids
shell.printf(F(" This %s will listen to telegram type IDs: "), device_type_name().c_str()); shell.printf(" This %s will listen to telegram type IDs: ", device_type_name().c_str());
for (const auto & tf : telegram_functions_) { for (const auto & tf : telegram_functions_) {
if (tf.received_ && !tf.fetch_) { if (tf.received_ && !tf.fetch_) {
shell.printf(COLOR_BRIGHT_GREEN); shell.printf(COLOR_BRIGHT_GREEN);
@@ -298,34 +298,34 @@ void EMSdevice::show_telegram_handlers(uuid::console::Shell & shell) const {
} else { } else {
shell.printf(COLOR_BRIGHT_RED); shell.printf(COLOR_BRIGHT_RED);
} }
shell.printf(F("0x%02X "), tf.telegram_type_id_); shell.printf("0x%02X ", tf.telegram_type_id_);
} }
shell.printf(COLOR_RESET); shell.printf(COLOR_RESET);
*/ */
shell.printf(F(" Received telegram type IDs: ")); shell.printf(" Received telegram type IDs: ");
for (const auto & tf : telegram_functions_) { for (const auto & tf : telegram_functions_) {
if (tf.received_ && !tf.fetch_) { if (tf.received_ && !tf.fetch_) {
shell.printf(F("0x%02X "), tf.telegram_type_id_); shell.printf("0x%02X ", tf.telegram_type_id_);
} }
} }
shell.println(); shell.println();
shell.printf(F(" Fetched telegram type IDs: ")); shell.printf(" Fetched telegram type IDs: ");
for (const auto & tf : telegram_functions_) { for (const auto & tf : telegram_functions_) {
if (tf.fetch_) { if (tf.fetch_) {
shell.printf(F("0x%02X "), tf.telegram_type_id_); shell.printf("0x%02X ", tf.telegram_type_id_);
} }
} }
shell.println(); shell.println();
shell.printf(F(" Pending telegram type IDs: ")); shell.printf(" Pending telegram type IDs: ");
for (const auto & tf : telegram_functions_) { for (const auto & tf : telegram_functions_) {
if (!tf.received_ && !tf.fetch_) { if (!tf.received_ && !tf.fetch_) {
shell.printf(F("0x%02X "), tf.telegram_type_id_); shell.printf("0x%02X ", tf.telegram_type_id_);
} }
} }
shell.println(); shell.println();
shell.printf(F(" Ignored telegram type IDs: ")); shell.printf(" Ignored telegram type IDs: ");
for (auto handlers : handlers_ignored_) { for (auto handlers : handlers_ignored_) {
shell.printf(F("0x%02X "), handlers); shell.printf("0x%02X ", handlers);
} }
shell.println(); shell.println();
} }
@@ -379,7 +379,7 @@ void EMSdevice::show_mqtt_handlers(uuid::console::Shell & shell) const {
} }
// register a callback function for a specific telegram type // register a callback function for a specific telegram type
void EMSdevice::register_telegram_type(const uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, const process_function_p f) { void EMSdevice::register_telegram_type(const uint16_t telegram_type_id, const char * telegram_type_name, bool fetch, const process_function_p f) {
telegram_functions_.emplace_back(telegram_type_id, telegram_type_name, fetch, false, f); telegram_functions_.emplace_back(telegram_type_id, telegram_type_name, fetch, false, f);
} }
@@ -390,28 +390,34 @@ void EMSdevice::register_telegram_type(const uint16_t telegram_type_id, const __
// type: one of DeviceValueType // type: one of DeviceValueType
// options: options for enum, which are translated as a list of lists // options: options for enum, which are translated as a list of lists
// options_single: list of names // options_single: list of names
// numeric_operatpr: to divide or multiply, see DeviceValueNumOps:: // numeric_operator: to divide or multiply, see DeviceValueNumOps::
// short_name: used in Mqtt as keys // short_name: used in MQTT as keys
// fullname: used in Web and Console unless empty (nullptr) - can be translated // fullname: used in Web and Console unless empty (nullptr) - can be translated
// uom: unit of measure from DeviceValueUOM // uom: unit of measure from DeviceValueUOM
// has_cmd: true if this is an associated command // has_cmd: true if this is an associated command
// min: min allowed value // min: min allowed value
// max: max allowed value // max: max allowed value
void EMSdevice::add_device_value(uint8_t tag, void EMSdevice::add_device_value(uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
const __FlashStringHelper * const ** options, const char * const ** options,
const __FlashStringHelper * const * options_single, const char * const * options_single,
int8_t numeric_operator, int8_t numeric_operator,
const __FlashStringHelper * const * name, const char * const * name,
uint8_t uom, uint8_t uom,
const cmd_function_p f, const cmd_function_p f,
int16_t min, int16_t min,
uint16_t max) { uint16_t max) {
bool has_cmd = (f != nullptr); bool has_cmd = (f != nullptr);
auto short_name = name[0]; auto short_name = name[0];
const class __FlashStringHelper * const * fullname = &name[1]; // translations start at index 1
const char * const * fullname;
if (Helpers::count_items(name) == 1) {
fullname = nullptr; // no translations available, use empty to prevent crash
} else {
fullname = &name[1]; // translations start at index 1
}
// initialize the device value depending on it's type // initialize the device value depending on it's type
if (type == DeviceValueType::STRING) { if (type == DeviceValueType::STRING) {
@@ -440,7 +446,7 @@ void EMSdevice::add_device_value(uint8_t tag,
EMSESP::webCustomizationService.read([&](WebCustomization & settings) { EMSESP::webCustomizationService.read([&](WebCustomization & settings) {
for (EntityCustomization entityCustomization : settings.entityCustomizations) { for (EntityCustomization entityCustomization : settings.entityCustomizations) {
if ((entityCustomization.product_id == product_id()) && (entityCustomization.device_id == device_id())) { if ((entityCustomization.product_id == product_id()) && (entityCustomization.device_id == device_id())) {
std::string entity = tag < DeviceValueTAG::TAG_HC1 ? read_flash_string(short_name) : tag_to_string(tag) + "/" + read_flash_string(short_name); std::string entity = tag < DeviceValueTAG::TAG_HC1 ? (short_name) : tag_to_string(tag) + "/" + (short_name);
for (std::string entity_id : entityCustomization.entity_ids) { for (std::string entity_id : entityCustomization.entity_ids) {
// if there is an appended custom name, strip it to get the true entity name // if there is an appended custom name, strip it to get the true entity name
// and extract the new custom name // and extract the new custom name
@@ -472,7 +478,6 @@ void EMSdevice::add_device_value(uint8_t tag,
// add the device entity // add the device entity
devicevalues_.emplace_back( devicevalues_.emplace_back(
device_type_, tag, value_p, type, options, options_single, numeric_operator, short_name, fullname, custom_fullname, uom, has_cmd, min, max, state); device_type_, tag, value_p, type, options, options_single, numeric_operator, short_name, fullname, custom_fullname, uom, has_cmd, min, max, state);
devicevalues_.back().set_custom_minmax();
// add a new command if it has a function attached // add a new command if it has a function attached
if (!has_cmd) { if (!has_cmd) {
@@ -491,107 +496,102 @@ void EMSdevice::add_device_value(uint8_t tag,
// add the command to our library // add the command to our library
// cmd is the short_name and the description is the fullname (not the custom fullname) // cmd is the short_name and the description is the fullname (not the custom fullname)
Command::add(device_type_, short_name, f, Helpers::translated_fword(fullname), flags); Command::add(device_type_, short_name, f, Helpers::translated_word(fullname).c_str(), flags);
} }
// single list of options // single list of options
void EMSdevice::register_device_value(uint8_t tag, void EMSdevice::register_device_value(uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
const __FlashStringHelper * const * options_single, const char * const * options_single,
const __FlashStringHelper * const * name, const char * const * name,
uint8_t uom, uint8_t uom,
const cmd_function_p f) { const cmd_function_p f) {
// create a multi-list from the options // create a multi-list from the options
add_device_value(tag, value_p, type, nullptr, options_single, 0, name, uom, f, 0, 0); add_device_value(tag, value_p, type, nullptr, options_single, 0, name, uom, f, 0, 0);
}; };
// single list of options, with no translations, with min and max // single list of options, with no translations, with min and max
void EMSdevice::register_device_value(uint8_t tag, void EMSdevice::register_device_value(uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
const __FlashStringHelper * const * options_single, const char * const * options_single,
const __FlashStringHelper * const * name, const char * const * name,
uint8_t uom, uint8_t uom,
const cmd_function_p f, const cmd_function_p f,
int16_t min, int16_t min,
uint16_t max) { uint16_t max) {
// create a multi-list from the options // create a multi-list from the options
add_device_value(tag, value_p, type, nullptr, options_single, 0, name, uom, f, min, max); add_device_value(tag, value_p, type, nullptr, options_single, 0, name, uom, f, min, max);
}; };
void EMSdevice::register_device_value(uint8_t tag, void EMSdevice::register_device_value(uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
int8_t numeric_operator, int8_t numeric_operator,
const __FlashStringHelper * const * name, const char * const * name,
uint8_t uom, uint8_t uom,
const cmd_function_p f) { const cmd_function_p f) {
add_device_value(tag, value_p, type, nullptr, nullptr, numeric_operator, name, uom, f, 0, 0); add_device_value(tag, value_p, type, nullptr, nullptr, numeric_operator, name, uom, f, 0, 0);
} }
void EMSdevice::register_device_value(uint8_t tag, void EMSdevice::register_device_value(uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
int8_t numeric_operator, int8_t numeric_operator,
const __FlashStringHelper * const * name, const char * const * name,
uint8_t uom, uint8_t uom,
const cmd_function_p f, const cmd_function_p f,
int16_t min, int16_t min,
uint16_t max) { uint16_t max) {
add_device_value(tag, value_p, type, nullptr, nullptr, numeric_operator, name, uom, f, min, max); add_device_value(tag, value_p, type, nullptr, nullptr, numeric_operator, name, uom, f, min, max);
} }
// no options, no function // no options, no function
void EMSdevice::register_device_value(uint8_t tag, void * value_p, uint8_t type, const __FlashStringHelper * const * name, uint8_t uom, const cmd_function_p f) { void EMSdevice::register_device_value(uint8_t tag, void * value_p, uint8_t type, const char * const * name, uint8_t uom, const cmd_function_p f) {
add_device_value(tag, value_p, type, nullptr, nullptr, 0, name, uom, f, 0, 0); add_device_value(tag, value_p, type, nullptr, nullptr, 0, name, uom, f, 0, 0);
}; };
// no options, with min/max // no options, with min/max
void EMSdevice::register_device_value(uint8_t tag, void EMSdevice::register_device_value(uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
const __FlashStringHelper * const * name, const char * const * name,
uint8_t uom, uint8_t uom,
const cmd_function_p f, const cmd_function_p f,
int16_t min, int16_t min,
uint16_t max) { uint16_t max) {
add_device_value(tag, value_p, type, nullptr, nullptr, 0, name, uom, f, min, max); add_device_value(tag, value_p, type, nullptr, nullptr, 0, name, uom, f, min, max);
}; };
// function with min and max values // function with min and max values
// adds a new command to the command list // adds a new command to the command list
// in this function we separate out the short and long names and take any translations // in this function we separate out the short and long names and take any translations
void EMSdevice::register_device_value(uint8_t tag, void EMSdevice::register_device_value(uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
const __FlashStringHelper * const ** options, const char * const ** options,
const __FlashStringHelper * const * name, const char * const * name,
uint8_t uom, uint8_t uom,
const cmd_function_p f, const cmd_function_p f,
int16_t min, int16_t min,
uint16_t max) { uint16_t max) {
add_device_value(tag, value_p, type, options, nullptr, 0, name, uom, f, min, max); add_device_value(tag, value_p, type, options, nullptr, 0, name, uom, f, min, max);
} }
// function with no min and max values (set to 0) // function with no min and max values (set to 0)
void EMSdevice::register_device_value(uint8_t tag, void EMSdevice::register_device_value(uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
const __FlashStringHelper * const ** options, const char * const ** options,
const __FlashStringHelper * const * name, const char * const * name,
uint8_t uom, uint8_t uom,
const cmd_function_p f) { const cmd_function_p f) {
add_device_value(tag, value_p, type, options, nullptr, 0, name, uom, f, 0, 0); add_device_value(tag, value_p, type, options, nullptr, 0, name, uom, f, 0, 0);
} }
// no associated command function, or min/max values // no associated command function, or min/max values
void EMSdevice::register_device_value(uint8_t tag, void EMSdevice::register_device_value(uint8_t tag, void * value_p, uint8_t type, const char * const ** options, const char * const * name, uint8_t uom) {
void * value_p,
uint8_t type,
const __FlashStringHelper * const ** options,
const __FlashStringHelper * const * name,
uint8_t uom) {
add_device_value(tag, value_p, type, options, nullptr, 0, name, uom, nullptr, 0, 0); add_device_value(tag, value_p, type, options, nullptr, 0, name, uom, nullptr, 0, 0);
} }
@@ -610,7 +610,7 @@ bool EMSdevice::is_readonly(const std::string & cmd, const int8_t id) const {
uint8_t tag = id > 0 ? DeviceValueTAG::TAG_HC1 + id - 1 : DeviceValueTAG::TAG_NONE; uint8_t tag = id > 0 ? DeviceValueTAG::TAG_HC1 + id - 1 : DeviceValueTAG::TAG_NONE;
for (const auto & dv : devicevalues_) { for (const auto & dv : devicevalues_) {
// check command name and tag, id -1 is default hc and only checks name // check command name and tag, id -1 is default hc and only checks name
if (dv.has_cmd && read_flash_string(dv.short_name) == cmd && (dv.tag < DeviceValueTAG::TAG_HC1 || dv.tag == tag || id == -1)) { if (dv.has_cmd && std::string(dv.short_name) == cmd && (dv.tag < DeviceValueTAG::TAG_HC1 || dv.tag == tag || id == -1)) {
return dv.has_state(DeviceValueState::DV_READONLY); return dv.has_state(DeviceValueState::DV_READONLY);
} }
} }
@@ -638,24 +638,14 @@ void EMSdevice::publish_value(void * value_p) const {
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
if (Mqtt::publish_single2cmd()) { if (Mqtt::publish_single2cmd()) {
if (dv.tag >= DeviceValueTAG::TAG_HC1) { if (dv.tag >= DeviceValueTAG::TAG_HC1) {
snprintf(topic, snprintf(topic, sizeof(topic), "%s/%s/%s", device_type_2_device_name(device_type_).c_str(), tag_to_mqtt(dv.tag).c_str(), (dv.short_name));
sizeof(topic),
"%s/%s/%s",
device_type_2_device_name(device_type_).c_str(),
tag_to_mqtt(dv.tag).c_str(),
read_flash_string(dv.short_name).c_str());
} else { } else {
snprintf(topic, sizeof(topic), "%s/%s", device_type_2_device_name(device_type_).c_str(), read_flash_string(dv.short_name).c_str()); snprintf(topic, sizeof(topic), "%s/%s", device_type_2_device_name(device_type_).c_str(), (dv.short_name));
} }
} else if (Mqtt::is_nested() && dv.tag >= DeviceValueTAG::TAG_HC1) { } else if (Mqtt::is_nested() && dv.tag >= DeviceValueTAG::TAG_HC1) {
snprintf(topic, snprintf(topic, sizeof(topic), "%s/%s/%s", Mqtt::tag_to_topic(device_type_, dv.tag).c_str(), tag_to_mqtt(dv.tag).c_str(), (dv.short_name));
sizeof(topic),
"%s/%s/%s",
Mqtt::tag_to_topic(device_type_, dv.tag).c_str(),
tag_to_mqtt(dv.tag).c_str(),
read_flash_string(dv.short_name).c_str());
} else { } else {
snprintf(topic, sizeof(topic), "%s/%s", Mqtt::tag_to_topic(device_type_, dv.tag).c_str(), read_flash_string(dv.short_name).c_str()); snprintf(topic, sizeof(topic), "%s/%s", Mqtt::tag_to_topic(device_type_, dv.tag).c_str(), (dv.short_name));
} }
int8_t num_op = dv.numeric_operator; int8_t num_op = dv.numeric_operator;
@@ -717,7 +707,6 @@ void EMSdevice::publish_value(void * value_p) const {
// looks up the UOM for a given key from the device value table // looks up the UOM for a given key from the device value table
// key is the fullname // key is the fullname
// TODO really should be using the shortname as the identifier
std::string EMSdevice::get_value_uom(const char * key) const { std::string EMSdevice::get_value_uom(const char * key) const {
// the key may have a TAG string prefixed at the beginning. If so, remove it // the key may have a TAG string prefixed at the beginning. If so, remove it
char new_key[80]; char new_key[80];
@@ -725,11 +714,12 @@ std::string EMSdevice::get_value_uom(const char * key) const {
char * key_p = new_key; char * key_p = new_key;
for (uint8_t i = 0; i < DeviceValue::tag_count; i++) { for (uint8_t i = 0; i < DeviceValue::tag_count; i++) {
auto tag = read_flash_string(DeviceValue::DeviceValueTAG_s[i]); auto tag = (DeviceValue::DeviceValueTAG_s[i]);
if (!tag.empty()) { if (tag) {
std::string key2 = key; // copy char to a std::string std::string key2 = key; // copy string to a std::string so we can use the find function
if ((key2.find(tag) != std::string::npos) && (key[tag.length()] == ' ')) { uint8_t length = strlen(tag);
key_p += tag.length() + 1; // remove the tag if ((key2.find(tag) != std::string::npos) && (key[length] == ' ')) {
key_p += length + 1; // remove the tag
break; break;
} }
} }
@@ -824,7 +814,7 @@ void EMSdevice::generate_values_web(JsonObject & output) {
if (dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY)) { if (dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY)) {
// add the name of the Command function // add the name of the Command function
if (dv.tag >= DeviceValueTAG::TAG_HC1) { if (dv.tag >= DeviceValueTAG::TAG_HC1) {
obj["c"] = tag_to_mqtt(dv.tag) + "/" + read_flash_string(dv.short_name); obj["c"] = tag_to_mqtt(dv.tag) + "/" + (dv.short_name);
} else { } else {
obj["c"] = dv.short_name; obj["c"] = dv.short_name;
} }
@@ -912,7 +902,6 @@ void EMSdevice::generate_values_web_customization(JsonArray & output) {
} else if (dv.type == DeviceValueType::ULONG) { } else if (dv.type == DeviceValueType::ULONG) {
obj["v"] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), dv.numeric_operator); obj["v"] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), dv.numeric_operator);
} else if (dv.type == DeviceValueType::TIME) { } else if (dv.type == DeviceValueType::TIME) {
// sometimes we need to divide by 60
obj["v"] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), dv.numeric_operator); obj["v"] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), dv.numeric_operator);
} }
} }
@@ -920,9 +909,9 @@ void EMSdevice::generate_values_web_customization(JsonArray & output) {
// id holds the shortname and must always have a value for the WebUI table to work // id holds the shortname and must always have a value for the WebUI table to work
if (dv.tag >= DeviceValueTAG::TAG_HC1) { if (dv.tag >= DeviceValueTAG::TAG_HC1) {
obj["id"] = tag_to_string(dv.tag) + "/" + read_flash_string(dv.short_name); obj["id"] = tag_to_string(dv.tag) + "/" + (dv.short_name);
} else { } else {
obj["id"] = read_flash_string(dv.short_name); obj["id"] = (dv.short_name);
} }
// n is the fullname, and can be optional // n is the fullname, and can be optional
@@ -945,8 +934,12 @@ void EMSdevice::generate_values_web_customization(JsonArray & output) {
obj["cn"] = custom_fullname; obj["cn"] = custom_fullname;
} }
} else { } else {
// it's a command obj["n"] = "!" + fullname; // prefix commands with a !
obj["n"] = "!" + fullname; // prefix ! to fullname for commands }
// add the custom name, is optional
if (!dv.custom_fullname.empty()) {
obj["cn"] = dv.custom_fullname;
} }
obj["m"] = dv.state >> 4; // send back the mask state. We're only interested in the high nibble obj["m"] = dv.state >> 4; // send back the mask state. We're only interested in the high nibble
@@ -984,8 +977,7 @@ void EMSdevice::set_climate_minmax(uint8_t tag, int16_t min, uint16_t max) {
// returns true if the entity has a mask set (not 0 the default) // returns true if the entity has a mask set (not 0 the default)
void EMSdevice::setCustomEntity(const std::string & entity_id) { void EMSdevice::setCustomEntity(const std::string & entity_id) {
for (auto & dv : devicevalues_) { for (auto & dv : devicevalues_) {
std::string entity_name = std::string entity_name = dv.tag < DeviceValueTAG::TAG_HC1 ? (dv.short_name) : tag_to_string(dv.tag) + "/" + (dv.short_name);
dv.tag < DeviceValueTAG::TAG_HC1 ? read_flash_string(dv.short_name) : tag_to_string(dv.tag) + "/" + read_flash_string(dv.short_name);
// extra shortname // extra shortname
std::string shortname; std::string shortname;
@@ -1021,10 +1013,14 @@ void EMSdevice::setCustomEntity(const std::string & entity_id) {
auto min = dv.min; auto min = dv.min;
auto max = dv.max; auto max = dv.max;
// set the min / max
dv.set_custom_minmax(); dv.set_custom_minmax();
if (Mqtt::ha_enabled() && dv.short_name == FL_(seltemp)[0] && (min != dv.min || max != dv.max)) { if (Mqtt::ha_enabled() && dv.short_name == FL_(seltemp)[0] && (min != dv.min || max != dv.max)) {
set_climate_minmax(dv.tag, dv.min, dv.max); set_climate_minmax(dv.tag, dv.min, dv.max);
} }
return; return;
} }
} }
@@ -1033,9 +1029,8 @@ void EMSdevice::setCustomEntity(const std::string & entity_id) {
// populate a string vector with entities that have masks set or have a custom name // populate a string vector with entities that have masks set or have a custom name
void EMSdevice::getCustomEntities(std::vector<std::string> & entity_ids) { void EMSdevice::getCustomEntities(std::vector<std::string> & entity_ids) {
for (const auto & dv : devicevalues_) { for (const auto & dv : devicevalues_) {
std::string entity_name = std::string entity_name = dv.tag < DeviceValueTAG::TAG_HC1 ? (dv.short_name) : tag_to_string(dv.tag) + "/" + (dv.short_name);
dv.tag < DeviceValueTAG::TAG_HC1 ? read_flash_string(dv.short_name) : tag_to_string(dv.tag) + "/" + read_flash_string(dv.short_name); uint8_t mask = dv.state >> 4;
uint8_t mask = dv.state >> 4;
if (mask || !dv.custom_fullname.empty()) { if (mask || !dv.custom_fullname.empty()) {
if (dv.custom_fullname.empty()) { if (dv.custom_fullname.empty()) {
@@ -1073,7 +1068,7 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
// search device value with this tag // search device value with this tag
for (auto & dv : devicevalues_) { for (auto & dv : devicevalues_) {
if (strcmp(command_s, Helpers::toLower(read_flash_string(dv.short_name)).c_str()) == 0 && (tag <= 0 || tag == dv.tag)) { if (!strcmp(command_s, dv.short_name) && (tag <= 0 || tag == dv.tag)) {
uint8_t fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; uint8_t fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0;
const char * type = "type"; const char * type = "type";
@@ -1159,7 +1154,7 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
json[value] = Helpers::render_boolean(s, value_b); json[value] = Helpers::render_boolean(s, value_b);
} }
} }
json[type] = F("boolean"); json[type] = ("boolean");
break; break;
case DeviceValueType::TIME: case DeviceValueType::TIME:
@@ -1173,7 +1168,7 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
if (Helpers::hasValue((char *)(dv.value_p))) { if (Helpers::hasValue((char *)(dv.value_p))) {
json[value] = (char *)(dv.value_p); json[value] = (char *)(dv.value_p);
} }
json[type] = F("string"); json[type] = ("string");
break; break;
case DeviceValueType::CMD: case DeviceValueType::CMD:
@@ -1218,7 +1213,7 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
// if we're filtering on an attribute, go find it // if we're filtering on an attribute, go find it
if (attribute_s) { if (attribute_s) {
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
EMSESP::logger().debug(F("[DEBUG] Attribute '%s'"), attribute_s); EMSESP::logger().debug("[DEBUG] Attribute '%s'", attribute_s);
#endif #endif
if (json.containsKey(attribute_s)) { if (json.containsKey(attribute_s)) {
JsonVariant data = json[attribute_s]; JsonVariant data = json[attribute_s];
@@ -1293,7 +1288,7 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c
strlcpy(name, fullname.c_str(), sizeof(name)); // use full name strlcpy(name, fullname.c_str(), sizeof(name)); // use full name
} }
} else { } else {
strlcpy(name, read_flash_string(dv.short_name).c_str(), sizeof(name)); // use short name strlcpy(name, (dv.short_name), sizeof(name)); // use short name
// if we have a tag, and its different to the last one create a nested object. only for hc, wwc and hs // if we have a tag, and its different to the last one create a nested object. only for hc, wwc and hs
if (dv.tag != old_tag) { if (dv.tag != old_tag) {
@@ -1360,8 +1355,7 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c
} else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { } else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) {
uint32_t time_value = *(uint32_t *)(dv.value_p); uint32_t time_value = *(uint32_t *)(dv.value_p);
if (dv.numeric_operator == DeviceValueNumOp::DV_NUMOP_DIV60) { if (dv.numeric_operator == DeviceValueNumOp::DV_NUMOP_DIV60) {
// sometimes we need to divide by 60 time_value /= 60; // sometimes we need to divide by 60
time_value /= 60;
} }
if (output_target == OUTPUT_TARGET::API_VERBOSE || output_target == OUTPUT_TARGET::CONSOLE) { if (output_target == OUTPUT_TARGET::API_VERBOSE || output_target == OUTPUT_TARGET::CONSOLE) {
char time_s[60]; char time_s[60];
@@ -1480,14 +1474,14 @@ bool EMSdevice::has_telegram_id(uint16_t id) const {
std::string EMSdevice::telegram_type_name(std::shared_ptr<const Telegram> telegram) const { std::string EMSdevice::telegram_type_name(std::shared_ptr<const Telegram> telegram) const {
// see if it's one of the common ones, like Version // see if it's one of the common ones, like Version
if (telegram->type_id == EMS_TYPE_VERSION) { if (telegram->type_id == EMS_TYPE_VERSION) {
return read_flash_string(F("Version")); return ("Version");
} else if (telegram->type_id == EMS_TYPE_UBADevices) { } else if (telegram->type_id == EMS_TYPE_UBADevices) {
return read_flash_string(F("UBADevices")); return ("UBADevices");
} }
for (const auto & tf : telegram_functions_) { for (const auto & tf : telegram_functions_) {
if ((tf.telegram_type_id_ == telegram->type_id) && (telegram->type_id != 0xFF)) { if ((tf.telegram_type_id_ == telegram->type_id) && (telegram->type_id != 0xFF)) {
return read_flash_string(tf.telegram_type_name_); return (tf.telegram_type_name_);
} }
} }
@@ -1502,7 +1496,7 @@ bool EMSdevice::handle_telegram(std::shared_ptr<const Telegram> telegram) {
// if the data block is empty and we have not received data before, assume that this telegram // if the data block is empty and we have not received data before, assume that this telegram
// is not recognized by the bus master. So remove it from the automatic fetch list // is not recognized by the bus master. So remove it from the automatic fetch list
if (telegram->message_length == 0 && telegram->offset == 0 && !tf.received_) { if (telegram->message_length == 0 && telegram->offset == 0 && !tf.received_) {
EMSESP::logger().debug(F("This telegram (%s) is not recognized by the EMS bus"), read_flash_string(tf.telegram_type_name_).c_str()); EMSESP::logger().debug(("This telegram (%s) is not recognized by the EMS bus"), (tf.telegram_type_name_));
tf.fetch_ = false; tf.fetch_ = false;
return false; return false;
} }

View File

@@ -34,7 +34,7 @@ class EMSdevice {
static constexpr uint8_t EMS_DEVICES_MAX_TELEGRAMS = 20; static constexpr uint8_t EMS_DEVICES_MAX_TELEGRAMS = 20;
// device_type defines which derived class to use, e.g. BOILER, THERMOSTAT etc.. // device_type defines which derived class to use, e.g. BOILER, THERMOSTAT etc..
EMSdevice(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand) EMSdevice(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
: device_type_(device_type) : device_type_(device_type)
, device_id_(device_id) , device_id_(device_id)
, product_id_(product_id) , product_id_(product_id)
@@ -104,11 +104,11 @@ class EMSdevice {
return brand_; return brand_;
} }
inline void name(const std::string & name) { inline void name(const char * name) {
name_ = name; name_ = name;
} }
inline std::string name() const { inline const char * name() const {
return name_; return name_;
} }
@@ -193,7 +193,7 @@ class EMSdevice {
using process_function_p = std::function<void(std::shared_ptr<const Telegram>)>; using process_function_p = std::function<void(std::shared_ptr<const Telegram>)>;
void register_telegram_type(const uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, const process_function_p cb); void register_telegram_type(const uint16_t telegram_type_id, const char * telegram_type_name, bool fetch, const process_function_p cb);
bool handle_telegram(std::shared_ptr<const Telegram> telegram); bool handle_telegram(std::shared_ptr<const Telegram> telegram);
std::string get_value_uom(const char * key) const; std::string get_value_uom(const char * key) const;
@@ -205,93 +205,77 @@ class EMSdevice {
void generate_values_web(JsonObject & output); void generate_values_web(JsonObject & output);
void generate_values_web_customization(JsonArray & output); void generate_values_web_customization(JsonArray & output);
void add_device_value(uint8_t tag, void add_device_value(uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
const __FlashStringHelper * const ** options, const char * const ** options,
const __FlashStringHelper * const * options_single, const char * const * options_single,
int8_t numeric_operator, int8_t numeric_operator,
const __FlashStringHelper * const * name, const char * const * name,
uint8_t uom, uint8_t uom,
const cmd_function_p f, const cmd_function_p f,
int16_t min, int16_t min,
uint16_t max); uint16_t max);
void register_device_value(uint8_t tag, void register_device_value(uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
const __FlashStringHelper * const ** options, const char * const ** options,
const __FlashStringHelper * const * name, const char * const * name,
uint8_t uom, uint8_t uom,
const cmd_function_p f, const cmd_function_p f,
int16_t min, int16_t min,
uint16_t max); uint16_t max);
void register_device_value(uint8_t tag, void
void * value_p, register_device_value(uint8_t tag, void * value_p, uint8_t type, const char * const ** options, const char * const * name, uint8_t uom, const cmd_function_p f);
uint8_t type,
const __FlashStringHelper * const ** options,
const __FlashStringHelper * const * name,
uint8_t uom,
const cmd_function_p f);
void register_device_value(uint8_t tag, void register_device_value(uint8_t tag, void * value_p, uint8_t type, const char * const ** options, const char * const * name, uint8_t uom);
void * value_p,
uint8_t type,
const __FlashStringHelper * const ** options,
const __FlashStringHelper * const * name,
uint8_t uom);
void register_device_value(uint8_t tag, void register_device_value(uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
int8_t numeric_operator, int8_t numeric_operator,
const __FlashStringHelper * const * name, const char * const * name,
uint8_t uom, uint8_t uom,
const cmd_function_p f = nullptr); const cmd_function_p f = nullptr);
void register_device_value(uint8_t tag, void register_device_value(uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
int8_t numeric_operator, int8_t numeric_operator,
const __FlashStringHelper * const * name, const char * const * name,
uint8_t uom, uint8_t uom,
const cmd_function_p f, const cmd_function_p f,
int16_t min, int16_t min,
uint16_t max); uint16_t max);
// single list of options // single list of options
void register_device_value(uint8_t tag, void register_device_value(uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
const __FlashStringHelper * const * options_single, const char * const * options_single,
const __FlashStringHelper * const * name, const char * const * name,
uint8_t uom, uint8_t uom,
const cmd_function_p f = nullptr); const cmd_function_p f = nullptr);
// single list of options, with no translations, with min and max // single list of options, with no translations, with min and max
void register_device_value(uint8_t tag, void register_device_value(uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
const __FlashStringHelper * const * options_single, const char * const * options_single,
const __FlashStringHelper * const * name, const char * const * name,
uint8_t uom, uint8_t uom,
const cmd_function_p f, const cmd_function_p f,
int16_t min, int16_t min,
uint16_t max); uint16_t max);
// no options, optional function f // no options, optional function f
void register_device_value(uint8_t tag, void * value_p, uint8_t type, const __FlashStringHelper * const * name, uint8_t uom, const cmd_function_p f = nullptr); void register_device_value(uint8_t tag, void * value_p, uint8_t type, const char * const * name, uint8_t uom, const cmd_function_p f = nullptr);
// no options, with min/max // no options, with min/max
void register_device_value(uint8_t tag, void
void * value_p, register_device_value(uint8_t tag, void * value_p, uint8_t type, const char * const * name, uint8_t uom, const cmd_function_p f, int16_t min, uint16_t max);
uint8_t type,
const __FlashStringHelper * const * name,
uint8_t uom,
const cmd_function_p f,
int16_t min,
uint16_t max);
void write_command(const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const uint16_t validate_typeid) const; void write_command(const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const uint16_t validate_typeid) const;
void write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid) const; void write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid) const;
@@ -425,27 +409,27 @@ class EMSdevice {
bool has_entities() const; bool has_entities() const;
private: private:
uint8_t unique_id_; uint8_t unique_id_;
uint8_t device_type_ = DeviceType::SYSTEM; uint8_t device_type_ = DeviceType::SYSTEM;
uint8_t device_id_ = 0; uint8_t device_id_ = 0;
uint8_t product_id_ = 0; uint8_t product_id_ = 0;
char version_[6]; char version_[6];
std::string name_; // the long name for the EMS model const char * name_; // the long name for the EMS model
uint8_t flags_ = 0; uint8_t flags_ = 0;
uint8_t brand_ = Brand::NO_BRAND; uint8_t brand_ = Brand::NO_BRAND;
bool ha_config_done_ = false; bool ha_config_done_ = false;
bool has_update_ = false; bool has_update_ = false;
bool ha_config_firstrun_ = true; // this means a first setup of HA is needed after a restart bool ha_config_firstrun_ = true; // this means a first setup of HA is needed after a restart
struct TelegramFunction { struct TelegramFunction {
uint16_t telegram_type_id_; // it's type_id uint16_t telegram_type_id_; // it's type_id
const __FlashStringHelper * telegram_type_name_; // e.g. RC20Message const char * telegram_type_name_; // e.g. RC20Message
bool fetch_; // if this type_id be queried automatically bool fetch_; // if this type_id be queried automatically
bool received_; bool received_;
process_function_p process_function_; process_function_p process_function_;
TelegramFunction(uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, bool received, const process_function_p process_function) TelegramFunction(uint16_t telegram_type_id, const char * telegram_type_name, bool fetch, bool received, const process_function_p process_function)
: telegram_type_id_(telegram_type_id) : telegram_type_id_(telegram_type_id)
, telegram_type_name_(telegram_type_name) , telegram_type_name_(telegram_type_name)
, fetch_(fetch) , fetch_(fetch)

View File

@@ -23,21 +23,21 @@
namespace emsesp { namespace emsesp {
// constructor // constructor
DeviceValue::DeviceValue(uint8_t device_type, DeviceValue::DeviceValue(uint8_t device_type,
uint8_t tag, uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
const __FlashStringHelper * const ** options, const char * const ** options,
const __FlashStringHelper * const * options_single, const char * const * options_single,
int8_t numeric_operator, int8_t numeric_operator,
const __FlashStringHelper * const short_name, const char * const short_name,
const __FlashStringHelper * const * fullname, const char * const * fullname,
std::string & custom_fullname, std::string & custom_fullname,
uint8_t uom, uint8_t uom,
bool has_cmd, bool has_cmd,
int16_t min, int16_t min,
uint16_t max, uint16_t max,
uint8_t state) uint8_t state)
: device_type(device_type) : device_type(device_type)
, tag(tag) , tag(tag)
, value_p(value_p) , value_p(value_p)
@@ -60,10 +60,14 @@ DeviceValue::DeviceValue(uint8_t device_type,
options_size = Helpers::count_items(options); options_size = Helpers::count_items(options);
} }
// set the min/max
set_custom_minmax();
#ifdef EMSESP_STANDALONE #ifdef EMSESP_STANDALONE
// only added for debugging // only added for debugging
Serial.print("registering entity: "); Serial.print(COLOR_BRIGHT_RED_BACKGROUND);
Serial.print(read_flash_string(short_name).c_str()); Serial.print(" registering entity: ");
Serial.print((short_name));
Serial.print("/"); Serial.print("/");
if (!custom_fullname.empty()) { if (!custom_fullname.empty()) {
Serial.print(COLOR_BRIGHT_CYAN); Serial.print(COLOR_BRIGHT_CYAN);
@@ -83,23 +87,23 @@ DeviceValue::DeviceValue(uint8_t device_type,
Serial.print(" option"); Serial.print(" option");
Serial.print(i + 1); Serial.print(i + 1);
Serial.print(":"); Serial.print(":");
auto str = Helpers::translated_fword(options[i]); auto str = Helpers::translated_word(options[i]);
Serial.print(read_flash_string(str).c_str()); Serial.print((str.c_str()));
i++; i++;
} }
} else if (options_single != nullptr) { } else if (options_single != nullptr) {
Serial.print("option1:!"); Serial.print("option1:!");
Serial.print(read_flash_string(options_single[0]).c_str()); Serial.print((options_single[0]));
Serial.print("!"); Serial.print("!");
} }
Serial.println(""); Serial.println(COLOR_RESET);
#endif #endif
} }
// mapping of UOM, to match order in DeviceValueUOM enum emsdevice.h // mapping of UOM, to match order in DeviceValueUOM enum emsdevice.h
// also maps to DeviceValueUOM in interface/src/project/types.ts for the Web UI // also maps to DeviceValueUOM in interface/src/project/types.ts for the Web UI
// must be an int of 4 bytes, 32bit aligned // must be an int of 4 bytes, 32bit aligned
const __FlashStringHelper * DeviceValue::DeviceValueUOM_s[] __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = { const char * DeviceValue::DeviceValueUOM_s[] = {
F_(uom_blank), F_(uom_blank),
F_(uom_degrees), F_(uom_degrees),
@@ -125,7 +129,7 @@ const __FlashStringHelper * DeviceValue::DeviceValueUOM_s[] __attribute__((__ali
// mapping of TAGs, to match order in DeviceValueTAG enum in emsdevice.h // mapping of TAGs, to match order in DeviceValueTAG enum in emsdevice.h
// must be an int of 4 bytes, 32bit aligned // must be an int of 4 bytes, 32bit aligned
const __FlashStringHelper * const DeviceValue::DeviceValueTAG_s[] PROGMEM = { const char * const DeviceValue::DeviceValueTAG_s[] = {
F_(tag_none), // "" F_(tag_none), // ""
F_(tag_heartbeat), // "" F_(tag_heartbeat), // ""
@@ -171,7 +175,7 @@ const __FlashStringHelper * const DeviceValue::DeviceValueTAG_s[] PROGMEM = {
}; };
// MQTT topics derived from tags // MQTT topics derived from tags
const __FlashStringHelper * const DeviceValue::DeviceValueTAG_mqtt[] PROGMEM = { const char * const DeviceValue::DeviceValueTAG_mqtt[] = {
F_(tag_none), // "" F_(tag_none), // ""
F_(heartbeat), // "heartbeat" F_(heartbeat), // "heartbeat"
@@ -217,7 +221,7 @@ const __FlashStringHelper * const DeviceValue::DeviceValueTAG_mqtt[] PROGMEM = {
}; };
// count #tags once at compile time // count #tags once at compile time
size_t DeviceValue::tag_count = sizeof(DeviceValue::DeviceValueTAG_s) / sizeof(__FlashStringHelper *); size_t DeviceValue::tag_count = sizeof(DeviceValue::DeviceValueTAG_s) / sizeof(char *);
// checks whether the device value has an actual value // checks whether the device value has an actual value
// returns true if its valid // returns true if its valid

View File

@@ -25,7 +25,6 @@
#include "helpers.h" // for conversions #include "helpers.h" // for conversions
#include "default_settings.h" // for enum types #include "default_settings.h" // for enum types
#include <uuid/common.h> // for read_flash_string
namespace emsesp { namespace emsesp {
@@ -143,38 +142,38 @@ class DeviceValue {
DV_NUMOP_MUL15 = -15 DV_NUMOP_MUL15 = -15
}; };
uint8_t device_type; // EMSdevice::DeviceType uint8_t device_type; // EMSdevice::DeviceType
uint8_t tag; // DeviceValueTAG::* uint8_t tag; // DeviceValueTAG::*
void * value_p; // pointer to variable of any type void * value_p; // pointer to variable of any type
uint8_t type; // DeviceValueType::* uint8_t type; // DeviceValueType::*
const __FlashStringHelper * const ** options; // options as a flash char array const char * const ** options; // options as a flash char array
const __FlashStringHelper * const * options_single; // options are not translated const char * const * options_single; // options are not translated
int8_t numeric_operator; int8_t numeric_operator;
uint8_t options_size; // number of options in the char array, calculated uint8_t options_size; // number of options in the char array, calculated
const __FlashStringHelper * const short_name; // used in MQTT and API const char * const short_name; // used in MQTT and API
const __FlashStringHelper * const * fullname; // used in Web and Console, is translated const char * const * fullname; // used in Web and Console, is translated
std::string custom_fullname; // optional, from customization std::string custom_fullname; // optional, from customization
uint8_t uom; // DeviceValueUOM::* uint8_t uom; // DeviceValueUOM::*
bool has_cmd; // true if there is a Console/MQTT command which matches the short_name bool has_cmd; // true if there is a Console/MQTT command which matches the short_name
int16_t min; // min range int16_t min; // min range
uint16_t max; // max range uint16_t max; // max range
uint8_t state; // DeviceValueState::* uint8_t state; // DeviceValueState::*
DeviceValue(uint8_t device_type, DeviceValue(uint8_t device_type,
uint8_t tag, uint8_t tag,
void * value_p, void * value_p,
uint8_t type, uint8_t type,
const __FlashStringHelper * const ** options, const char * const ** options,
const __FlashStringHelper * const * options_single, const char * const * options_single,
int8_t numeric_operator, int8_t numeric_operator,
const __FlashStringHelper * const short_name, const char * const short_name,
const __FlashStringHelper * const * fullname, const char * const * fullname,
std::string & custom_fullname, std::string & custom_fullname,
uint8_t uom, uint8_t uom,
bool has_cmd, bool has_cmd,
int16_t min, int16_t min,
uint16_t max, uint16_t max,
uint8_t state); uint8_t state);
bool hasValue() const; bool hasValue() const;
bool get_min_max(int16_t & dv_set_min, uint16_t & dv_set_max); bool get_min_max(int16_t & dv_set_min, uint16_t & dv_set_max);
@@ -199,10 +198,10 @@ class DeviceValue {
return state; return state;
} }
static const __FlashStringHelper * DeviceValueUOM_s[]; static const char * DeviceValueUOM_s[];
static const __FlashStringHelper * const DeviceValueTAG_s[]; static const char * const DeviceValueTAG_s[];
static const __FlashStringHelper * const DeviceValueTAG_mqtt[]; static const char * const DeviceValueTAG_mqtt[];
static size_t tag_count; // # tags static size_t tag_count; // # tags
}; };
}; // namespace emsesp }; // namespace emsesp

View File

@@ -190,7 +190,7 @@ void EMSESP::uart_init() {
if (System::is_valid_gpio(rx_gpio) && System::is_valid_gpio(tx_gpio)) { if (System::is_valid_gpio(rx_gpio) && System::is_valid_gpio(tx_gpio)) {
EMSuart::start(tx_mode, rx_gpio, tx_gpio); // start UART EMSuart::start(tx_mode, rx_gpio, tx_gpio); // start UART
} else { } else {
LOG_WARNING(F("Invalid UART Rx/Tx GPIOs. Check config.")); LOG_WARNING("Invalid UART Rx/Tx GPIOs. Check config.");
} }
txservice_.start(); // sends out request to EMS bus for all devices txservice_.start(); // sends out request to EMS bus for all devices
@@ -234,42 +234,42 @@ void EMSESP::show_ems(uuid::console::Shell & shell) {
// EMS bus information // EMS bus information
switch (bus_status()) { switch (bus_status()) {
case BUS_STATUS_OFFLINE: case BUS_STATUS_OFFLINE:
shell.printfln(F("EMS Bus is disconnected.")); shell.printfln("EMS Bus is disconnected.");
break; break;
case BUS_STATUS_TX_ERRORS: case BUS_STATUS_TX_ERRORS:
shell.printfln(F("EMS Bus is connected, but Tx is not stable.")); shell.printfln("EMS Bus is connected, but Tx is not stable.");
break; break;
default: default:
shell.printfln(F("EMS Bus is connected.")); shell.printfln("EMS Bus is connected.");
break; break;
} }
shell.println(); shell.println();
if (bus_status() != BUS_STATUS_OFFLINE) { if (bus_status() != BUS_STATUS_OFFLINE) {
shell.printfln(F("EMS Bus info:")); shell.printfln("EMS Bus info:");
EMSESP::webSettingsService.read([&](WebSettings & settings) { shell.printfln(F(" Tx mode: %d"), settings.tx_mode); }); EMSESP::webSettingsService.read([&](WebSettings & settings) { shell.printfln(" Tx mode: %d", settings.tx_mode); });
shell.printfln(F(" Bus protocol: %s"), EMSbus::is_ht3() ? F("HT3") : F("Buderus")); shell.printfln(" Bus protocol: %s", EMSbus::is_ht3() ? ("HT3") : ("Buderus"));
shell.printfln(F(" #recognized EMS devices: %d"), EMSESP::emsdevices.size()); shell.printfln(" #recognized EMS devices: %d", EMSESP::emsdevices.size());
shell.printfln(F(" #telegrams received: %d"), rxservice_.telegram_count()); shell.printfln(" #telegrams received: %d", rxservice_.telegram_count());
shell.printfln(F(" #read requests sent: %d"), txservice_.telegram_read_count()); shell.printfln(" #read requests sent: %d", txservice_.telegram_read_count());
shell.printfln(F(" #write requests sent: %d"), txservice_.telegram_write_count()); shell.printfln(" #write requests sent: %d", txservice_.telegram_write_count());
shell.printfln(F(" #incomplete telegrams: %d"), rxservice_.telegram_error_count()); shell.printfln(" #incomplete telegrams: %d", rxservice_.telegram_error_count());
shell.printfln(F(" #read fails (after %d retries): %d"), TxService::MAXIMUM_TX_RETRIES, txservice_.telegram_read_fail_count()); shell.printfln((" #read fails (after %d retries): %d"), TxService::MAXIMUM_TX_RETRIES, txservice_.telegram_read_fail_count());
shell.printfln(F(" #write fails (after %d retries): %d"), TxService::MAXIMUM_TX_RETRIES, txservice_.telegram_write_fail_count()); shell.printfln((" #write fails (after %d retries): %d"), TxService::MAXIMUM_TX_RETRIES, txservice_.telegram_write_fail_count());
shell.printfln(F(" Rx line quality: %d%%"), rxservice_.quality()); shell.printfln(" Rx line quality: %d%%", rxservice_.quality());
shell.printfln(F(" Tx line quality: %d%%"), (txservice_.read_quality() + txservice_.read_quality()) / 2); shell.printfln(" Tx line quality: %d%%", (txservice_.read_quality() + txservice_.read_quality()) / 2);
shell.println(); shell.println();
} }
// Rx queue // Rx queue
auto rx_telegrams = rxservice_.queue(); auto rx_telegrams = rxservice_.queue();
if (rx_telegrams.empty()) { if (rx_telegrams.empty()) {
shell.printfln(F("Rx Queue is empty")); shell.printfln("Rx Queue is empty");
} else { } else {
shell.printfln(F("Rx Queue (%ld telegram%s):"), rx_telegrams.size(), rx_telegrams.size() == 1 ? "" : "s"); shell.printfln(("Rx Queue (%ld telegram%s):"), rx_telegrams.size(), rx_telegrams.size() == 1 ? "" : "s");
for (const auto & it : rx_telegrams) { for (const auto & it : rx_telegrams) {
shell.printfln(F(" [%02d] %s"), it.id_, pretty_telegram(it.telegram_).c_str()); shell.printfln(" [%02d] %s", it.id_, pretty_telegram(it.telegram_).c_str());
} }
} }
@@ -278,20 +278,20 @@ void EMSESP::show_ems(uuid::console::Shell & shell) {
// Tx queue // Tx queue
auto tx_telegrams = txservice_.queue(); auto tx_telegrams = txservice_.queue();
if (tx_telegrams.empty()) { if (tx_telegrams.empty()) {
shell.printfln(F("Tx Queue is empty")); shell.printfln("Tx Queue is empty");
} else { } else {
shell.printfln(F("Tx Queue (%ld telegram%s):"), tx_telegrams.size(), tx_telegrams.size() == 1 ? "" : "s"); shell.printfln(("Tx Queue (%ld telegram%s):"), tx_telegrams.size(), tx_telegrams.size() == 1 ? "" : "s");
std::string op; std::string op;
for (const auto & it : tx_telegrams) { for (const auto & it : tx_telegrams) {
if ((it.telegram_->operation) == Telegram::Operation::TX_RAW) { if ((it.telegram_->operation) == Telegram::Operation::TX_RAW) {
op = read_flash_string(F("RAW ")); op = "RAW ";
} else if ((it.telegram_->operation) == Telegram::Operation::TX_READ) { } else if ((it.telegram_->operation) == Telegram::Operation::TX_READ) {
op = read_flash_string(F("READ ")); op = "READ ";
} else if ((it.telegram_->operation) == Telegram::Operation::TX_WRITE) { } else if ((it.telegram_->operation) == Telegram::Operation::TX_WRITE) {
op = read_flash_string(F("WRITE")); op = "WRITE";
} }
shell.printfln(F(" [%02d%c] %s %s"), it.id_, ((it.retry_) ? '*' : ' '), op.c_str(), pretty_telegram(it.telegram_).c_str()); shell.printfln(" [%02d%c] %s %s", it.id_, ((it.retry_) ? '*' : ' '), op.c_str(), pretty_telegram(it.telegram_).c_str());
} }
} }
@@ -301,7 +301,7 @@ void EMSESP::show_ems(uuid::console::Shell & shell) {
// show EMS device values to the shell console // show EMS device values to the shell console
void EMSESP::show_device_values(uuid::console::Shell & shell) { void EMSESP::show_device_values(uuid::console::Shell & shell) {
if (emsdevices.empty()) { if (emsdevices.empty()) {
shell.printfln(F("No EMS devices detected.")); shell.printfln("No EMS devices detected.");
shell.println(); shell.println();
return; return;
} }
@@ -311,7 +311,7 @@ void EMSESP::show_device_values(uuid::console::Shell & shell) {
for (const auto & emsdevice : emsdevices) { for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_class.first)) { if (emsdevice && (emsdevice->device_type() == device_class.first)) {
// print header // print header
shell.printfln(F("%s: %s (%d)"), emsdevice->device_type_name().c_str(), emsdevice->to_string().c_str(), emsdevice->count_entities()); shell.printfln(("%s: %s (%d)"), emsdevice->device_type_name().c_str(), emsdevice->to_string().c_str(), emsdevice->count_entities());
DynamicJsonDocument doc(EMSESP_JSON_SIZE_XXLARGE_DYN); // use max size DynamicJsonDocument doc(EMSESP_JSON_SIZE_XXLARGE_DYN); // use max size
JsonObject json = doc.to<JsonObject>(); JsonObject json = doc.to<JsonObject>();
@@ -359,14 +359,14 @@ void EMSESP::show_device_values(uuid::console::Shell & shell) {
// show Dallas temperature sensors and Analog sensors // show Dallas temperature sensors and Analog sensors
void EMSESP::show_sensor_values(uuid::console::Shell & shell) { void EMSESP::show_sensor_values(uuid::console::Shell & shell) {
if (dallassensor_.have_sensors()) { if (dallassensor_.have_sensors()) {
shell.printfln(F("Temperature sensors:")); shell.printfln("Temperature sensors:");
char s[10]; char s[10];
char s2[10]; char s2[10];
uint8_t fahrenheit = EMSESP::system_.fahrenheit() ? 2 : 0; uint8_t fahrenheit = EMSESP::system_.fahrenheit() ? 2 : 0;
for (const auto & sensor : dallassensor_.sensors()) { for (const auto & sensor : dallassensor_.sensors()) {
if (Helpers::hasValue(sensor.temperature_c)) { if (Helpers::hasValue(sensor.temperature_c)) {
shell.printfln(F(" %s: %s%s °%c%s (offset %s, ID: %s)"), shell.printfln((" %s: %s%s °%c%s (offset %s, ID: %s)"),
sensor.name().c_str(), sensor.name().c_str(),
COLOR_BRIGHT_GREEN, COLOR_BRIGHT_GREEN,
Helpers::render_value(s, sensor.temperature_c, 10, fahrenheit), Helpers::render_value(s, sensor.temperature_c, 10, fahrenheit),
@@ -375,10 +375,7 @@ void EMSESP::show_sensor_values(uuid::console::Shell & shell) {
Helpers::render_value(s2, sensor.offset(), 10, fahrenheit), Helpers::render_value(s2, sensor.offset(), 10, fahrenheit),
sensor.id().c_str()); sensor.id().c_str());
} else { } else {
shell.printfln(F(" %s (offset %s, ID: %s)"), shell.printfln((" %s (offset %s, ID: %s)"), sensor.name().c_str(), Helpers::render_value(s, sensor.offset(), 10, fahrenheit), sensor.id().c_str());
sensor.name().c_str(),
Helpers::render_value(s, sensor.offset(), 10, fahrenheit),
sensor.id().c_str());
} }
} }
shell.println(); shell.println();
@@ -387,11 +384,11 @@ void EMSESP::show_sensor_values(uuid::console::Shell & shell) {
if (analogsensor_.have_sensors()) { if (analogsensor_.have_sensors()) {
char s[10]; char s[10];
char s2[10]; char s2[10];
shell.printfln(F("Analog sensors:")); shell.printfln("Analog sensors:");
for (const auto & sensor : analogsensor_.sensors()) { for (const auto & sensor : analogsensor_.sensors()) {
switch (sensor.type()) { switch (sensor.type()) {
case AnalogSensor::AnalogType::ADC: case AnalogSensor::AnalogType::ADC:
shell.printfln(F(" %s: %s%s %s%s (Type: ADC, Factor: %s, Offset: %d)"), shell.printfln((" %s: %s%s %s%s (Type: ADC, Factor: %s, Offset: %d)"),
sensor.name().c_str(), sensor.name().c_str(),
COLOR_BRIGHT_GREEN, COLOR_BRIGHT_GREEN,
Helpers::render_value(s, sensor.value(), 2), Helpers::render_value(s, sensor.value(), 2),
@@ -403,7 +400,7 @@ void EMSESP::show_sensor_values(uuid::console::Shell & shell) {
default: default:
// case AnalogSensor::AnalogType::DIGITAL_IN: // case AnalogSensor::AnalogType::DIGITAL_IN:
// case AnalogSensor::AnalogType::COUNTER: // case AnalogSensor::AnalogType::COUNTER:
shell.printfln(F(" %s: %s%d%s (Type: %s)"), shell.printfln((" %s: %s%d%s (Type: %s)"),
sensor.name().c_str(), sensor.name().c_str(),
COLOR_BRIGHT_GREEN, COLOR_BRIGHT_GREEN,
(uint16_t)sensor.value(), // as int (uint16_t)sensor.value(), // as int
@@ -540,7 +537,7 @@ void EMSESP::publish_device_values(uint8_t device_type) {
} }
if (need_publish) { if (need_publish) {
if (doc.overflowed()) { if (doc.overflowed()) {
LOG_WARNING(F("MQTT buffer overflow, please use individual topics")); LOG_WARNING("MQTT buffer overflow, please use individual topics");
} }
Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_NONE), json); Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_NONE), json);
} }
@@ -625,9 +622,9 @@ bool EMSESP::get_device_value_info(JsonObject & root, const char * cmd, const in
// search for recognized device_ids : Me, All, otherwise print hex value // search for recognized device_ids : Me, All, otherwise print hex value
std::string EMSESP::device_tostring(const uint8_t device_id) { std::string EMSESP::device_tostring(const uint8_t device_id) {
if ((device_id & 0x7F) == rxservice_.ems_bus_id()) { if ((device_id & 0x7F) == rxservice_.ems_bus_id()) {
return read_flash_string(F("Me")); return "Me";
} else if (device_id == 0x00) { } else if (device_id == 0x00) {
return read_flash_string(F("All")); return "All";
} else { } else {
char buffer[5]; char buffer[5];
return Helpers::hextoa(buffer, device_id); return Helpers::hextoa(buffer, device_id);
@@ -672,14 +669,14 @@ std::string EMSESP::pretty_telegram(std::shared_ptr<const Telegram> telegram) {
// check for global/common types like Version & UBADevices // check for global/common types like Version & UBADevices
if (telegram->type_id == EMSdevice::EMS_TYPE_VERSION) { if (telegram->type_id == EMSdevice::EMS_TYPE_VERSION) {
type_name = read_flash_string(F("Version")); type_name = "Version";
} else if (telegram->type_id == EMSdevice::EMS_TYPE_UBADevices) { } else if (telegram->type_id == EMSdevice::EMS_TYPE_UBADevices) {
type_name = read_flash_string(F("UBADevices")); type_name = "UBADevices";
} }
// if we don't know the type show // if we don't know the type show
if (type_name.empty()) { if (type_name.empty()) {
type_name = read_flash_string(F("?")); type_name = "?";
} }
std::string str; std::string str;
@@ -728,7 +725,7 @@ void EMSESP::process_UBADevices(std::shared_ptr<const Telegram> telegram) {
// if we haven't already detected this device, request it's version details, unless its us (EMS-ESP) // if we haven't already detected this device, request it's version details, unless its us (EMS-ESP)
// when the version info is received, it will automagically add the device // when the version info is received, it will automagically add the device
if ((device_id != EMSbus::ems_bus_id()) && !(EMSESP::device_exists(device_id))) { if ((device_id != EMSbus::ems_bus_id()) && !(EMSESP::device_exists(device_id))) {
LOG_DEBUG(F("New EMS device detected with ID 0x%02X. Requesting version information."), device_id); LOG_DEBUG("New EMS device detected with ID 0x%02X. Requesting version information.", device_id);
send_read_request(EMSdevice::EMS_TYPE_VERSION, device_id); send_read_request(EMSdevice::EMS_TYPE_VERSION, device_id);
} }
} }
@@ -788,7 +785,7 @@ void EMSESP::process_version(std::shared_ptr<const Telegram> telegram) {
bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) { bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) {
// if watching or reading... // if watching or reading...
if ((telegram->type_id == read_id_) && (telegram->dest == txservice_.ems_bus_id())) { if ((telegram->type_id == read_id_) && (telegram->dest == txservice_.ems_bus_id())) {
LOG_INFO(F("%s"), pretty_telegram(telegram).c_str()); LOG_INFO("%s", pretty_telegram(telegram).c_str());
if (Mqtt::send_response()) { if (Mqtt::send_response()) {
publish_response(telegram); publish_response(telegram);
} }
@@ -800,18 +797,18 @@ bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) {
} else if (watch() == WATCH_ON) { } else if (watch() == WATCH_ON) {
if ((watch_id_ == WATCH_ID_NONE) || (telegram->type_id == watch_id_) if ((watch_id_ == WATCH_ID_NONE) || (telegram->type_id == watch_id_)
|| ((watch_id_ < 0x80) && ((telegram->src == watch_id_) || (telegram->dest == watch_id_)))) { || ((watch_id_ < 0x80) && ((telegram->src == watch_id_) || (telegram->dest == watch_id_)))) {
LOG_NOTICE(F("%s"), pretty_telegram(telegram).c_str()); LOG_NOTICE("%s", pretty_telegram(telegram).c_str());
} else if (!trace_raw_) { } else if (!trace_raw_) {
LOG_TRACE(F("%s"), pretty_telegram(telegram).c_str()); LOG_TRACE("%s", pretty_telegram(telegram).c_str());
} }
} else if (!trace_raw_) { } else if (!trace_raw_) {
LOG_TRACE(F("%s"), pretty_telegram(telegram).c_str()); LOG_TRACE("%s", pretty_telegram(telegram).c_str());
} }
// only process broadcast telegrams or ones sent to us on request // only process broadcast telegrams or ones sent to us on request
// if ((telegram->dest != 0x00) && (telegram->dest != rxservice_.ems_bus_id())) { // if ((telegram->dest != 0x00) && (telegram->dest != rxservice_.ems_bus_id())) {
if (telegram->operation == Telegram::Operation::RX_READ) { if (telegram->operation == Telegram::Operation::RX_READ) {
// LOG_DEBUG(F("read telegram received, not processing")); // LOG_DEBUG("read telegram received, not processing");
return false; return false;
} }
@@ -861,9 +858,9 @@ bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) {
} }
if (!found) { if (!found) {
LOG_DEBUG(F("No telegram type handler found for ID 0x%02X (src 0x%02X)"), telegram->type_id, telegram->src); LOG_DEBUG(("No telegram type handler found for ID 0x%02X (src 0x%02X)"), telegram->type_id, telegram->src);
if (watch() == WATCH_UNKNOWN) { if (watch() == WATCH_UNKNOWN) {
LOG_NOTICE(F("%s"), pretty_telegram(telegram).c_str()); LOG_NOTICE("%s", pretty_telegram(telegram).c_str());
} }
if (!wait_km_ && !knowndevice && (telegram->src != EMSbus::ems_bus_id()) && (telegram->message_length > 0)) { if (!wait_km_ && !knowndevice && (telegram->src != EMSbus::ems_bus_id()) && (telegram->message_length > 0)) {
send_read_request(EMSdevice::EMS_TYPE_VERSION, telegram->src); send_read_request(EMSdevice::EMS_TYPE_VERSION, telegram->src);
@@ -887,12 +884,12 @@ bool EMSESP::device_exists(const uint8_t device_id) {
// for each associated EMS device go and get its system information // for each associated EMS device go and get its system information
void EMSESP::show_devices(uuid::console::Shell & shell) { void EMSESP::show_devices(uuid::console::Shell & shell) {
if (emsdevices.empty()) { if (emsdevices.empty()) {
shell.printfln(F("No EMS devices detected. Try using 'scan devices' from the ems menu.")); shell.printfln("No EMS devices detected. Try using 'scan devices' from the ems menu.");
shell.println(); shell.println();
return; return;
} }
shell.printfln(F("These EMS devices are currently active:")); shell.printfln("These EMS devices are currently active:");
shell.println(); shell.println();
// count the number of thermostats // count the number of thermostats
@@ -908,7 +905,7 @@ void EMSESP::show_devices(uuid::console::Shell & shell) {
for (const auto & device_class : EMSFactory::device_handlers()) { for (const auto & device_class : EMSFactory::device_handlers()) {
for (const auto & emsdevice : emsdevices) { for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_class.first)) { if (emsdevice && (emsdevice->device_type() == device_class.first)) {
shell.printf(F("%s: %s"), emsdevice->device_type_name().c_str(), emsdevice->to_string().c_str()); shell.printf("%s: %s", emsdevice->device_type_name().c_str(), emsdevice->to_string().c_str());
shell.println(); shell.println();
emsdevice->show_telegram_handlers(shell); emsdevice->show_telegram_handlers(shell);
@@ -935,7 +932,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
if (product_id == 0) { // update only with valid product_id if (product_id == 0) { // update only with valid product_id
return true; return true;
} }
LOG_DEBUG(F("Updating details for already active deviceID 0x%02X"), device_id); LOG_DEBUG("Updating details for already active deviceID 0x%02X", device_id);
emsdevice->product_id(product_id); emsdevice->product_id(product_id);
emsdevice->version(version); emsdevice->version(version);
// only set brand if it doesn't already exist // only set brand if it doesn't already exist
@@ -945,7 +942,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
// find the name and flags in our database // find the name and flags in our database
for (const auto & device : device_library_) { for (const auto & device : device_library_) {
if (device.product_id == product_id && device.device_type == emsdevice->device_type()) { if (device.product_id == product_id && device.device_type == emsdevice->device_type()) {
emsdevice->name(std::move(read_flash_string(device.name))); emsdevice->name(device.name);
emsdevice->add_flags(device.flags); emsdevice->add_flags(device.flags);
} }
} }
@@ -976,14 +973,13 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
// if we don't recognize the productID report it and add as a generic device // if we don't recognize the productID report it and add as a generic device
if (device_p == nullptr) { if (device_p == nullptr) {
LOG_NOTICE(F("Unrecognized EMS device (deviceID 0x%02X, productID %d). Please report on GitHub."), device_id, product_id); LOG_NOTICE(("Unrecognized EMS device (deviceID 0x%02X, productID %d). Please report on GitHub."), device_id, product_id);
std::string name("unknown");
emsdevices.push_back( emsdevices.push_back(
EMSFactory::add(DeviceType::GENERIC, device_id, product_id, version, name, DeviceFlags::EMS_DEVICE_FLAG_NONE, EMSdevice::Brand::NO_BRAND)); EMSFactory::add(DeviceType::GENERIC, device_id, product_id, version, "unknown", DeviceFlags::EMS_DEVICE_FLAG_NONE, EMSdevice::Brand::NO_BRAND));
return false; // not found return false; // not found
} }
auto name = read_flash_string(device_p->name); auto name = device_p->name;
auto device_type = device_p->device_type; auto device_type = device_p->device_type;
auto flags = device_p->flags; auto flags = device_p->flags;
@@ -1022,14 +1018,14 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
name = "generic boiler"; name = "generic boiler";
device_type = DeviceType::BOILER; device_type = DeviceType::BOILER;
flags = DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP; flags = DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP;
LOG_WARNING(F("Unknown EMS boiler. Using generic profile. Please report on GitHub.")); LOG_WARNING("Unknown EMS boiler. Using generic profile. Please report on GitHub.");
} else { } else {
LOG_WARNING(F("Unrecognized EMS device (device ID 0x%02X, no product ID). Please report on GitHub."), device_id); LOG_WARNING(("Unrecognized EMS device (device ID 0x%02X, no product ID). Please report on GitHub."), device_id);
return false; return false;
} }
} }
LOG_DEBUG(F("Adding new device %s (deviceID 0x%02X, productID %d, version %s)"), name.c_str(), device_id, product_id, version); LOG_DEBUG(("Adding new device %s (deviceID 0x%02X, productID %d, version %s)"), name, device_id, product_id, version);
emsdevices.push_back(EMSFactory::add(device_type, device_id, product_id, version, name, flags, brand)); emsdevices.push_back(EMSFactory::add(device_type, device_id, product_id, version, name, flags, brand));
// assign a unique ID. Note that this is not actual unique after a restart as it's dependent on the order that devices are found // assign a unique ID. Note that this is not actual unique after a restart as it's dependent on the order that devices are found
@@ -1043,7 +1039,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
fetch_device_values(device_id); // go and fetch its data fetch_device_values(device_id); // go and fetch its data
// Print to LOG showing we've added a new device // Print to LOG showing we've added a new device
LOG_INFO(F("Recognized new %s with deviceID 0x%02X"), EMSdevice::device_type_2_device_name(device_type).c_str(), device_id); LOG_INFO("Recognized new %s with deviceID 0x%02X", EMSdevice::device_type_2_device_name(device_type).c_str(), device_id);
// add command commands for all devices, except for connect, controller and gateway // add command commands for all devices, except for connect, controller and gateway
if ((device_type == DeviceType::CONNECT) || (device_type == DeviceType::CONTROLLER) || (device_type == DeviceType::GATEWAY)) { if ((device_type == DeviceType::CONNECT) || (device_type == DeviceType::CONTROLLER) || (device_type == DeviceType::GATEWAY)) {
@@ -1059,7 +1055,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
F_(info_cmd)); F_(info_cmd));
Command::add( Command::add(
device_type, device_type,
F("values"), ("values"),
[device_type](const char * value, const int8_t id, JsonObject & output) { [device_type](const char * value, const int8_t id, JsonObject & output) {
return command_info(device_type, output, id, EMSdevice::OUTPUT_TARGET::API_SHORTNAMES); // HIDDEN command showing short names, used in e.g. /api/boiler return command_info(device_type, output, id, EMSdevice::OUTPUT_TARGET::API_SHORTNAMES); // HIDDEN command showing short names, used in e.g. /api/boiler
}, },
@@ -1178,7 +1174,7 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data); Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data);
#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(F("[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", ::millis() - 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);
@@ -1194,14 +1190,14 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
// if we're waiting on a Write operation, we want a single byte 1 or 4 // if we're waiting on a Write operation, we want a single byte 1 or 4
if ((tx_state == Telegram::Operation::TX_WRITE) && (length == 1)) { if ((tx_state == Telegram::Operation::TX_WRITE) && (length == 1)) {
if (first_value == TxService::TX_WRITE_SUCCESS) { if (first_value == TxService::TX_WRITE_SUCCESS) {
LOG_DEBUG(F("Last Tx write successful")); LOG_DEBUG("Last Tx write successful");
txservice_.increment_telegram_write_count(); // last tx/write was confirmed ok txservice_.increment_telegram_write_count(); // last tx/write was confirmed ok
txservice_.send_poll(); // close the bus txservice_.send_poll(); // close the bus
publish_id_ = txservice_.post_send_query(); // follow up with any post-read if set publish_id_ = txservice_.post_send_query(); // follow up with any post-read if set
txservice_.reset_retry_count(); txservice_.reset_retry_count();
tx_successful = true; tx_successful = true;
} else if (first_value == TxService::TX_WRITE_FAIL) { } else if (first_value == TxService::TX_WRITE_FAIL) {
LOG_ERROR(F("Last Tx write rejected by host")); LOG_ERROR("Last Tx write rejected by host");
txservice_.send_poll(); // close the bus txservice_.send_poll(); // close the bus
txservice_.reset_retry_count(); txservice_.reset_retry_count();
} }
@@ -1210,7 +1206,7 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
uint8_t src = data[0]; uint8_t src = data[0];
uint8_t dest = data[1]; uint8_t dest = data[1];
if (txservice_.is_last_tx(src, dest)) { if (txservice_.is_last_tx(src, dest)) {
LOG_DEBUG(F("Last Tx read successful")); LOG_DEBUG("Last Tx read successful");
txservice_.increment_telegram_read_count(); txservice_.increment_telegram_read_count();
txservice_.send_poll(); // close the bus txservice_.send_poll(); // close the bus
txservice_.reset_retry_count(); txservice_.reset_retry_count();
@@ -1252,11 +1248,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(F("[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), ::millis() - 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_ = ::millis();
} else { } else {
LOG_TRACE(F("[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), ::millis() - 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
@@ -1268,7 +1264,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(F("[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", ::millis() - rx_time_, Helpers::data_to_hex(data, length).c_str());
#endif #endif
Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data); // check if there is a message for the roomcontroller Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data); // check if there is a message for the roomcontroller
@@ -1293,14 +1289,14 @@ void EMSESP::start() {
webLogService.begin(); // start web log service. now we can start capturing logs to the web log webLogService.begin(); // start web log service. now we can start capturing logs to the web log
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG
LOG_NOTICE(F("System is running in Debug mode")); LOG_NOTICE("System is running in Debug mode");
#endif #endif
LOG_INFO(F("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());
// do any system upgrades // do any system upgrades
if (system_.check_upgrade()) { if (system_.check_upgrade()) {
LOG_INFO(F("System needs a restart to apply new settings. Please wait.")); LOG_INFO("System needs a restart to apply new settings. Please wait.");
system_.system_restart(); system_.system_restart();
}; };
@@ -1316,7 +1312,7 @@ void EMSESP::start() {
// start all the EMS-ESP services // start all the EMS-ESP services
mqtt_.start(); // mqtt init mqtt_.start(); // mqtt init
system_.start(); // starts commands, led, adc, button, network, syslog & uart system_.start(); // starts commands, led, adc, button, network, syslog & uart
LOG_INFO(F("Starting EMS-ESP version %s (hostname: %s)"), EMSESP_APP_VERSION, system_.hostname().c_str()); // welcome message LOG_INFO(("Starting EMS-ESP version %s (hostname: %s)"), EMSESP_APP_VERSION, system_.hostname().c_str()); // welcome message
shower_.start(); // initialize shower timer and shower alert shower_.start(); // initialize shower timer and shower alert
dallassensor_.start(); // Dallas external sensors dallassensor_.start(); // Dallas external sensors
@@ -1327,7 +1323,7 @@ void EMSESP::start() {
device_library_ = { device_library_ = {
#include "device_library.h" #include "device_library.h"
}; };
LOG_INFO(F("Loaded EMS device library (%d records)"), device_library_.size()); LOG_INFO(("Loaded EMS device library (%d records)"), device_library_.size());
#if defined(EMSESP_STANDALONE) #if defined(EMSESP_STANDALONE)
Mqtt::on_connect(); // simulate an MQTT connection Mqtt::on_connect(); // simulate an MQTT connection
@@ -1344,6 +1340,7 @@ void EMSESP::scheduled_fetch_values() {
last_fetch_ = uuid::get_uptime(); last_fetch_ = uuid::get_uptime();
no = 1; no = 1;
} }
if (txservice_.tx_queue_empty()) { if (txservice_.tx_queue_empty()) {
uint8_t i = 0; uint8_t i = 0;
for (const auto & emsdevice : emsdevices) { for (const auto & emsdevice : emsdevices) {

View File

@@ -251,10 +251,10 @@ class EMSESP {
static constexpr uint8_t EMS_WAIT_KM_TIMEOUT = 60; // wait one minute static constexpr uint8_t EMS_WAIT_KM_TIMEOUT = 60; // wait one minute
struct Device_record { struct Device_record {
uint8_t product_id; uint8_t product_id;
EMSdevice::DeviceType device_type; EMSdevice::DeviceType device_type;
const __FlashStringHelper * name; const char * name;
uint8_t flags; uint8_t flags;
}; };
static std::vector<Device_record> device_library_; static std::vector<Device_record> device_library_;

View File

@@ -55,12 +55,12 @@ class EMSFactory {
} }
// Construct derived class returning an unique ptr // Construct derived class returning an unique ptr
static auto add(const uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, std::string & name, uint8_t flags, uint8_t brand) static auto add(const uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
-> std::unique_ptr<EMSdevice> { -> std::unique_ptr<EMSdevice> {
return std::unique_ptr<EMSdevice>(EMSFactory::makeRaw(device_type, device_id, product_id, version, name, flags, brand)); return std::unique_ptr<EMSdevice>(EMSFactory::makeRaw(device_type, device_id, product_id, version, name, flags, brand));
} }
virtual auto construct(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, std::string & name, uint8_t flags, uint8_t brand) const virtual auto construct(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand) const
-> EMSdevice * = 0; -> EMSdevice * = 0;
private: private:
@@ -72,7 +72,7 @@ class EMSFactory {
// Construct derived class returning a raw pointer // Construct derived class returning a raw pointer
// find which EMS device it is and use that class // find which EMS device it is and use that class
static auto makeRaw(const uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, std::string & name, uint8_t flags, uint8_t brand) static auto makeRaw(const uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
-> EMSdevice * { -> EMSdevice * {
auto it = EMSFactory::getRegister().find(device_type); auto it = EMSFactory::getRegister().find(device_type);
if (it != EMSFactory::getRegister().end()) { if (it != EMSFactory::getRegister().end()) {
@@ -90,7 +90,7 @@ class ConcreteEMSFactory : EMSFactory {
EMSFactory::registerFactory(device_type, this); EMSFactory::registerFactory(device_type, this);
} }
auto construct(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, std::string & name, uint8_t flags, uint8_t brand) const auto construct(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand) const
-> EMSdevice * { -> EMSdevice * {
return new DerivedClass(device_type, device_id, product_id, version, name, flags, brand); return new DerivedClass(device_type, device_id, product_id, version, name, flags, brand);
} }

View File

@@ -608,7 +608,7 @@ bool Helpers::value2bool(const char * value, bool & value_b) {
// checks to see if a string is member of a vector and return the index, also allow true/false for on/off // checks to see if a string is member of a vector and return the index, also allow true/false for on/off
// this for a list of lists, when using translated strings // this for a list of lists, when using translated strings
bool Helpers::value2enum(const char * value, uint8_t & value_ui, const __FlashStringHelper * const ** strs) { bool Helpers::value2enum(const char * value, uint8_t & value_ui, const char * const ** strs) {
if ((value == nullptr) || (strlen(value) == 0)) { if ((value == nullptr) || (strlen(value) == 0)) {
return false; return false;
} }
@@ -616,7 +616,7 @@ bool Helpers::value2enum(const char * value, uint8_t & value_ui, const __FlashSt
for (value_ui = 0; strs[value_ui]; value_ui++) { for (value_ui = 0; strs[value_ui]; value_ui++) {
std::string str1 = toLower(Helpers::translated_word(strs[value_ui])); std::string str1 = toLower(Helpers::translated_word(strs[value_ui]));
std::string str2 = toLower(read_flash_string(strs[value_ui][0])); // also check for default language std::string str2 = toLower((strs[value_ui][0])); // also check for default language
if ((str1 != "") if ((str1 != "")
&& ((str2 == "off" && str == "false") || (str2 == "on" && str == "true") || (str == str1) || (str == str2) && ((str2 == "off" && str == "false") || (str2 == "on" && str == "true") || (str == str1) || (str == str2)
|| (value[0] == ('0' + value_ui) && value[1] == '\0'))) { || (value[0] == ('0' + value_ui) && value[1] == '\0'))) {
@@ -628,14 +628,14 @@ bool Helpers::value2enum(const char * value, uint8_t & value_ui, const __FlashSt
} }
// checks to see if a string is member of a vector and return the index, also allow true/false for on/off // checks to see if a string is member of a vector and return the index, also allow true/false for on/off
bool Helpers::value2enum(const char * value, uint8_t & value_ui, const __FlashStringHelper * const * strs) { bool Helpers::value2enum(const char * value, uint8_t & value_ui, const char * const * strs) {
if ((value == nullptr) || (strlen(value) == 0)) { if ((value == nullptr) || (strlen(value) == 0)) {
return false; return false;
} }
std::string str = toLower(value); std::string str = toLower(value);
for (value_ui = 0; strs[value_ui]; value_ui++) { for (value_ui = 0; strs[value_ui]; value_ui++) {
std::string enum_str = toLower(read_flash_string(strs[value_ui])); std::string enum_str = toLower((strs[value_ui]));
if ((enum_str != "") if ((enum_str != "")
&& ((enum_str == "off" && (str == Helpers::translated_word(FL_(off)) || str == "false")) && ((enum_str == "off" && (str == Helpers::translated_word(FL_(off)) || str == "false"))
@@ -655,6 +655,10 @@ std::string Helpers::toLower(std::string const & s) {
return lc; return lc;
} }
std::string Helpers::toLower(const char * s) {
return toLower(std::string(s));
}
std::string Helpers::toUpper(std::string const & s) { std::string Helpers::toUpper(std::string const & s) {
std::string lc = s; std::string lc = s;
std::transform(lc.begin(), lc.end(), lc.begin(), [](unsigned char c) { return std::toupper(c); }); std::transform(lc.begin(), lc.end(), lc.begin(), [](unsigned char c) { return std::toupper(c); });
@@ -676,7 +680,7 @@ void Helpers::replace_char(char * str, char find, char replace) {
// count number of items in a list // count number of items in a list
// the end of a list has a nullptr // the end of a list has a nullptr
uint8_t Helpers::count_items(const __FlashStringHelper * const * list) { uint8_t Helpers::count_items(const char * const * list) {
uint8_t list_size = 0; uint8_t list_size = 0;
if (list != nullptr) { if (list != nullptr) {
while (list[list_size]) { while (list[list_size]) {
@@ -688,7 +692,7 @@ uint8_t Helpers::count_items(const __FlashStringHelper * const * list) {
// count number of items in a list of lists // count number of items in a list of lists
// the end of a list has a nullptr // the end of a list has a nullptr
uint8_t Helpers::count_items(const __FlashStringHelper * const ** list) { uint8_t Helpers::count_items(const char * const ** list) {
uint8_t list_size = 0; uint8_t list_size = 0;
if (list != nullptr) { if (list != nullptr) {
while (list[list_size]) { while (list[list_size]) {
@@ -699,29 +703,20 @@ uint8_t Helpers::count_items(const __FlashStringHelper * const ** list) {
} }
// return translated string as a std::string, optionally converting to lowercase (for console commands) // return translated string as a std::string, optionally converting to lowercase (for console commands)
// takes a FL(...) std::string Helpers::translated_word(const char * const * strings, bool to_lower) {
std::string Helpers::translated_word(const __FlashStringHelper * const * strings, bool to_lower) {
uint8_t language_index = EMSESP::system_.language_index(); uint8_t language_index = EMSESP::system_.language_index();
uint8_t index = 0; uint8_t index = 0;
// see how many translations we have for this entity. if there is no translation for this, revert to EN // check for empty
if (Helpers::count_items(strings) >= language_index + 1 && !read_flash_string(strings[language_index]).empty()) { if (!strings) {
index = language_index; return ""; // it's a nullptr with no translations, return empty to prevent unwanted crash
} }
return to_lower ? toLower(read_flash_string(strings[index])) : read_flash_string(strings[index]);
}
// return translated string
// takes a F(...)
const __FlashStringHelper * Helpers::translated_fword(const __FlashStringHelper * const * strings) {
uint8_t language_index = EMSESP::system_.language_index();
uint8_t index = 0;
// see how many translations we have for this entity. if there is no translation for this, revert to EN // see how many translations we have for this entity. if there is no translation for this, revert to EN
if (Helpers::count_items(strings) >= language_index + 1 && !read_flash_string(strings[language_index]).empty()) { if (Helpers::count_items(strings) >= language_index + 1 && strlen(strings[language_index])) {
index = language_index; index = language_index;
} }
return strings[index]; return to_lower ? toLower((strings[index])) : (strings[index]);
} }
} // namespace emsesp } // namespace emsesp

View File

@@ -54,7 +54,9 @@ class Helpers {
static std::string toLower(std::string const & s); static std::string toLower(std::string const & s);
static std::string toUpper(std::string const & s); static std::string toUpper(std::string const & s);
static void replace_char(char * str, char find, char replace); static std::string toLower(const char * s);
static void replace_char(char * str, char find, char replace);
static bool hasValue(const uint8_t & value, const uint8_t isBool = 0); static bool hasValue(const uint8_t & value, const uint8_t isBool = 0);
static bool hasValue(const int8_t & value); static bool hasValue(const int8_t & value);
@@ -67,16 +69,15 @@ class Helpers {
static bool value2float(const char * value, float & value_f); static bool value2float(const char * value, float & value_f);
static bool value2bool(const char * value, bool & value_b); static bool value2bool(const char * value, bool & value_b);
static bool value2string(const char * value, std::string & value_s); static bool value2string(const char * value, std::string & value_s);
static bool value2enum(const char * value, uint8_t & value_ui, const __FlashStringHelper * const ** strs); static bool value2enum(const char * value, uint8_t & value_ui, const char * const ** strs);
static bool value2enum(const char * value, uint8_t & value_ui, const __FlashStringHelper * const * strs); static bool value2enum(const char * value, uint8_t & value_ui, const char * const * strs);
static bool value2temperature(const char * value, float & value_f, bool relative = false); static bool value2temperature(const char * value, float & value_f, bool relative = false);
static bool value2temperature(const char * value, int & value_i, const bool relative = false, const int min = -2147483648, const int max = 2147483647); static bool value2temperature(const char * value, int & value_i, const bool relative = false, const int min = -2147483648, const int max = 2147483647);
static uint8_t count_items(const __FlashStringHelper * const ** list); static uint8_t count_items(const char * const ** list);
static uint8_t count_items(const __FlashStringHelper * const * list); static uint8_t count_items(const char * const * list);
static std::string translated_word(const __FlashStringHelper * const * strings, bool to_lower = false); static std::string translated_word(const char * const * strings, bool to_lower = false);
static const __FlashStringHelper * translated_fword(const __FlashStringHelper * const * strings);
#ifdef EMSESP_STANDALONE #ifdef EMSESP_STANDALONE
static char * ultostr(char * ptr, uint32_t value, const uint8_t base); static char * ultostr(char * ptr, uint32_t value, const uint8_t base);

View File

@@ -20,6 +20,8 @@
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-variable"
// clang-format off
/* /*
* THIS FILE CONTAINS STANDARD STRING LITERALS THAT DON'T NEED LANGUAGE TRANSLATIONS * THIS FILE CONTAINS STANDARD STRING LITERALS THAT DON'T NEED LANGUAGE TRANSLATIONS
*/ */
@@ -144,55 +146,55 @@ MAKE_PSTR(password_prompt, "Password: ")
MAKE_PSTR(unset, "<unset>") MAKE_PSTR(unset, "<unset>")
// more common names that don't need translations // more common names that don't need translations
MAKE_PSTR_LIST(1x3min, F("1x3min")) MAKE_PSTR_LIST(1x3min, "1x3min")
MAKE_PSTR_LIST(2x3min, F("2x3min")) MAKE_PSTR_LIST(2x3min, "2x3min")
MAKE_PSTR_LIST(3x3min, F("3x3min")) MAKE_PSTR_LIST(3x3min, "3x3min")
MAKE_PSTR_LIST(4x3min, F("4x3min")) MAKE_PSTR_LIST(4x3min, "4x3min")
MAKE_PSTR_LIST(5x3min, F("5x3min")) MAKE_PSTR_LIST(5x3min, "5x3min")
MAKE_PSTR_LIST(6x3min, F("6x3min")) MAKE_PSTR_LIST(6x3min, "6x3min")
MAKE_PSTR_LIST(auto, F("auto")) MAKE_PSTR_LIST(auto, "auto")
MAKE_PSTR_LIST(na, F("n/a")) MAKE_PSTR_LIST(na, "n/a")
MAKE_PSTR_LIST(rc3x, F("rc3x")) MAKE_PSTR_LIST(rc3x, "rc3x")
MAKE_PSTR_LIST(rc20, F("rc20")) MAKE_PSTR_LIST(rc20, "rc20")
MAKE_PSTR_LIST(fb10, F("fb10")) MAKE_PSTR_LIST(fb10, "fb10")
MAKE_PSTR_LIST(fb100, F("fb100")) MAKE_PSTR_LIST(fb100, "fb100")
MAKE_PSTR_LIST(dash, F("-")) MAKE_PSTR_LIST(dash, "-")
MAKE_PSTR_LIST(error, F("error")) MAKE_PSTR_LIST(error, "error")
MAKE_PSTR_LIST(BLANK, F("")) MAKE_PSTR_LIST(BLANK, "")
MAKE_PSTR_LIST(pwm, F("pwm")) MAKE_PSTR_LIST(pwm, "pwm")
MAKE_PSTR_LIST(pwm_invers, F("pwm inverse")) MAKE_PSTR_LIST(pwm_invers, "pwm inverse")
MAKE_PSTR_LIST(mpc, F("mpc")) MAKE_PSTR_LIST(mpc, "mpc")
MAKE_PSTR_LIST(tempauto, F("temp auto")) MAKE_PSTR_LIST(tempauto, "temp auto")
MAKE_PSTR_LIST(bypass, F("bypass")) MAKE_PSTR_LIST(bypass, "bypass")
MAKE_PSTR_LIST(mixer, F("mixer")) MAKE_PSTR_LIST(mixer, "mixer")
MAKE_PSTR_LIST(monovalent, F("monovalent")) MAKE_PSTR_LIST(monovalent, "monovalent")
MAKE_PSTR_LIST(bivalent, F("bivalent")) MAKE_PSTR_LIST(bivalent, "bivalent")
MAKE_PSTR_LIST(n_o, F("n_o")) MAKE_PSTR_LIST(n_o, "n_o")
MAKE_PSTR_LIST(n_c, F("n_c")) MAKE_PSTR_LIST(n_c, "n_c")
MAKE_PSTR_LIST(prog1, F("prog 1")) MAKE_PSTR_LIST(prog1, "prog 1")
MAKE_PSTR_LIST(prog2, F("prog 2")) MAKE_PSTR_LIST(prog2, "prog 2")
MAKE_PSTR_LIST(proga, F("prog a")) MAKE_PSTR_LIST(proga, "prog a")
MAKE_PSTR_LIST(progb, F("prog b")) MAKE_PSTR_LIST(progb, "prog b")
MAKE_PSTR_LIST(progc, F("prog c")) MAKE_PSTR_LIST(progc, "prog c")
MAKE_PSTR_LIST(progd, F("prog d")) MAKE_PSTR_LIST(progd, "prog d")
MAKE_PSTR_LIST(proge, F("prog e")) MAKE_PSTR_LIST(proge, "prog e")
MAKE_PSTR_LIST(progf, F("prog f")) MAKE_PSTR_LIST(progf, "prog f")
MAKE_PSTR_LIST(rc35, F("RC35")) MAKE_PSTR_LIST(rc35, "RC35")
MAKE_PSTR_LIST(0kW, F("0 kW")) MAKE_PSTR_LIST(0kW, "0 kW")
MAKE_PSTR_LIST(2kW, F("2 kW")) MAKE_PSTR_LIST(2kW, "2 kW")
MAKE_PSTR_LIST(3kW, F("3 kW")) MAKE_PSTR_LIST(3kW, "3 kW")
MAKE_PSTR_LIST(4kW, F("4 kW")) MAKE_PSTR_LIST(4kW, "4 kW")
MAKE_PSTR_LIST(6kW, F("6 kW")) MAKE_PSTR_LIST(6kW, "6 kW")
MAKE_PSTR_LIST(9kW, F("9 kW")) MAKE_PSTR_LIST(9kW, "9 kW")
// templates - this are not translated and will be saved under optons_single // templates - this are not translated and will be saved under options_single
MAKE_PSTR_LIST(tpl_datetime, F("Format: < NTP | dd.mm.yyyy-hh:mm:ss-day(0-6)-dst(0/1) >")) MAKE_PSTR_LIST(tpl_datetime, "Format: < NTP | dd.mm.yyyy-hh:mm:ss-day(0-6)-dst(0/1) >")
MAKE_PSTR_LIST(tpl_switchtime, F("Format: <nn> [ not_set | day hh:mm on|off ]")) MAKE_PSTR_LIST(tpl_switchtime, "Format: <nn> [ not_set | day hh:mm on|off ]")
MAKE_PSTR_LIST(tpl_switchtime1, F("Format: <nn> [ not_set | day hh:mm Tn ]")) MAKE_PSTR_LIST(tpl_switchtime1, "Format: <nn> [ not_set | day hh:mm Tn ]")
MAKE_PSTR_LIST(tpl_holidays, F("Format: < dd.mm.yyyy-dd.mm.yyyy >")) MAKE_PSTR_LIST(tpl_holidays, "Format: < dd.mm.yyyy-dd.mm.yyyy >")
MAKE_PSTR_LIST(tpl_date, F("Format: < dd.mm.yyyy >")) MAKE_PSTR_LIST(tpl_date, "Format: < dd.mm.yyyy >")
MAKE_PSTR_LIST(tpl_input, F("Format: <inv>[<evu1><evu2><evu3><comp><aux><cool><heat><dhw><pv>]")) MAKE_PSTR_LIST(tpl_input, "Format: <inv>[<evu1><evu2><evu3><comp><aux><cool><heat><dhw><pv>]")
MAKE_PSTR_LIST(tpl_input4, F("Format: <inv>[<comp><aux><cool><heat><dhw><pv>]")) MAKE_PSTR_LIST(tpl_input4, "Format: <inv>[<comp><aux><cool><heat><dhw><pv>]")
// Unit Of Measurement mapping - maps to DeviceValueUOM_s in emsdevice.cpp // Unit Of Measurement mapping - maps to DeviceValueUOM_s in emsdevice.cpp
// These don't need translating, it will mess up HA and the API // These don't need translating, it will mess up HA and the API
@@ -273,16 +275,17 @@ MAKE_PSTR(response, "response")
MAKE_PSTR(tag_boiler_data_ww_mqtt, "ww") MAKE_PSTR(tag_boiler_data_ww_mqtt, "ww")
MAKE_PSTR(tag_device_data_ww_mqtt, "") MAKE_PSTR(tag_device_data_ww_mqtt, "")
MAKE_PSTR_LIST(climate, F("HA climate config creation"), F("")) // empty fullname // Home Assistant - this is special and has no translations
MAKE_PSTR_LIST(climate, "HA climate config creation")
// syslog // syslog
MAKE_PSTR_LIST(list_syslog_level, F("off"), F("emerg"), F("alert"), F("crit"), F("error"), F("warn"), F("notice"), F("info"), F("debug"), F("trace"), F("all")) MAKE_PSTR_LIST(list_syslog_level, "off", "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug", "trace", "all")
// sensors // sensors
MAKE_PSTR_LIST(list_sensortype, F("none"), F("digital in"), F("counter"), F("adc"), F("timer"), F("rate"), F("digital out"), F("pwm 0"), F("pwm 1"), F("pwm 2")) MAKE_PSTR_LIST(list_sensortype, "none", "digital in", "counter", "adc", "timer", "rate", "digital out", "pwm 0", "pwm 1", "pwm 2")
// watch // watch
MAKE_PSTR_LIST(list_watch, F("off"), F("on"), F("raw"), F("unknown")) MAKE_PSTR_LIST(list_watch, "off", "on", "raw", "unknown")
/* /*
* The rest below are Enums and generated from translations lists * The rest below are Enums and generated from translations lists
@@ -302,16 +305,7 @@ MAKE_PSTR_ENUM(enum_reset, FL_(dash), FL_(maintenance), FL_(error))
MAKE_PSTR_ENUM(enum_maxHeat, FL_(0kW), FL_(2kW), FL_(3kW), FL_(4kW), FL_(6kW), FL_(9kW)) MAKE_PSTR_ENUM(enum_maxHeat, FL_(0kW), FL_(2kW), FL_(3kW), FL_(4kW), FL_(6kW), FL_(9kW))
// thermostat lists // thermostat lists
MAKE_PSTR_ENUM(enum_ibaMainDisplay, MAKE_PSTR_ENUM(enum_ibaMainDisplay, FL_(internal_temperature), FL_(internal_setpoint), FL_(external_temperature), FL_(burner_temperature), FL_(ww_temperature), FL_(functioning_mode), FL_(time), FL_(date), FL_(smoke_temperature))
FL_(internal_temperature),
FL_(internal_setpoint),
FL_(external_temperature),
FL_(burner_temperature),
FL_(ww_temperature),
FL_(functioning_mode),
FL_(time),
FL_(date),
FL_(smoke_temperature))
MAKE_PSTR_ENUM(enum_ibaLanguage, FL_(german), FL_(dutch), FL_(french), FL_(italian)) MAKE_PSTR_ENUM(enum_ibaLanguage, FL_(german), FL_(dutch), FL_(french), FL_(italian))
MAKE_PSTR_ENUM(enum_ibaLanguage_RC30, FL_(german), FL_(dutch)) MAKE_PSTR_ENUM(enum_ibaLanguage_RC30, FL_(german), FL_(dutch))
MAKE_PSTR_ENUM(enum_floordrystatus, FL_(off), FL_(start), FL_(heat), FL_(hold), FL_(cool), FL_(end)) MAKE_PSTR_ENUM(enum_floordrystatus, FL_(off), FL_(start), FL_(heat), FL_(hold), FL_(cool), FL_(end))
@@ -379,3 +373,5 @@ MAKE_PSTR_ENUM(enum_bufConfig, FL_(monovalent), FL_(bivalent))
MAKE_PSTR_ENUM(enum_blockTerm, FL_(n_o), FL_(n_c)) MAKE_PSTR_ENUM(enum_blockTerm, FL_(n_o), FL_(n_c))
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
// clang-format on

File diff suppressed because it is too large Load Diff

View File

@@ -186,26 +186,26 @@ void Mqtt::loop() {
// print MQTT log and other stuff to console // print MQTT log and other stuff to console
void Mqtt::show_mqtt(uuid::console::Shell & shell) { void Mqtt::show_mqtt(uuid::console::Shell & shell) {
shell.printfln(F("MQTT is %s"), connected() ? read_flash_string(F_(connected)).c_str() : read_flash_string(F_(disconnected)).c_str()); shell.printfln("MQTT is %s", connected() ? F_(connected) : F_(disconnected));
shell.printfln(F("MQTT publish errors: %lu"), mqtt_publish_fails_); shell.printfln("MQTT publish errors: %lu", mqtt_publish_fails_);
shell.println(); shell.println();
// show subscriptions // show subscriptions
shell.printfln(F("MQTT topic subscriptions:")); shell.printfln("MQTT topic subscriptions:");
for (const auto & mqtt_subfunction : mqtt_subfunctions_) { for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
shell.printfln(F(" %s/%s"), mqtt_base_.c_str(), mqtt_subfunction.topic_.c_str()); shell.printfln(" %s/%s", mqtt_base_.c_str(), mqtt_subfunction.topic_.c_str());
} }
shell.println(); shell.println();
// show queues // show queues
if (mqtt_messages_.empty()) { if (mqtt_messages_.empty()) {
shell.printfln(F("MQTT queue is empty")); shell.printfln("MQTT queue is empty");
shell.println(); shell.println();
return; return;
} }
shell.printfln(F("MQTT queue (%d/%d messages):"), mqtt_messages_.size(), MAX_MQTT_MESSAGES); shell.printfln(("MQTT queue (%d/%d messages):"), mqtt_messages_.size(), MAX_MQTT_MESSAGES);
for (const auto & message : mqtt_messages_) { for (const auto & message : mqtt_messages_) {
auto content = message.content_; auto content = message.content_;
@@ -222,12 +222,12 @@ void Mqtt::show_mqtt(uuid::console::Shell & shell) {
// Publish messages // Publish messages
if (message.retry_count_ == 0) { if (message.retry_count_ == 0) {
if (message.packet_id_ == 0) { if (message.packet_id_ == 0) {
shell.printfln(F(" [%02d] (Pub) topic=%s payload=%s"), message.id_, topic, content->payload.c_str()); shell.printfln((" [%02d] (Pub) topic=%s payload=%s"), message.id_, topic, content->payload.c_str());
} else { } else {
shell.printfln(F(" [%02d] (Pub) topic=%s payload=%s (pid %d)"), message.id_, topic, content->payload.c_str(), message.packet_id_); shell.printfln((" [%02d] (Pub) topic=%s payload=%s (pid %d)"), message.id_, topic, content->payload.c_str(), message.packet_id_);
} }
} else { } else {
shell.printfln(F(" [%02d] (Pub) topic=%s payload=%s (pid %d, retry #%d)"), shell.printfln((" [%02d] (Pub) topic=%s payload=%s (pid %d, retry #%d)"),
message.id_, message.id_,
topic, topic,
content->payload.c_str(), content->payload.c_str(),
@@ -236,7 +236,7 @@ void Mqtt::show_mqtt(uuid::console::Shell & shell) {
} }
} else { } else {
// Subscribe messages // Subscribe messages
shell.printfln(F(" [%02d] (Sub) topic=%s"), message.id_, topic); shell.printfln((" [%02d] (Sub) topic=%s"), message.id_, topic);
} }
} }
shell.println(); shell.println();
@@ -264,16 +264,16 @@ void Mqtt::on_message(const char * topic, const char * payload, size_t len) cons
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
if (len) { if (len) {
LOG_DEBUG(F("Received topic `%s` => payload `%s` (length %d)"), topic, message, len); LOG_DEBUG(("Received topic `%s` => payload `%s` (length %d)"), topic, message, len);
} else { } else {
LOG_DEBUG(F("Received topic `%s`"), topic); LOG_DEBUG("Received topic `%s`", topic);
} }
#endif #endif
// remove HA topics if we don't use discovery // remove HA topics if we don't use discovery
if (strncmp(topic, discovery_prefix().c_str(), discovery_prefix().size()) == 0) { if (strncmp(topic, discovery_prefix().c_str(), discovery_prefix().size()) == 0) {
if (!ha_enabled_ && len) { // don't ping pong the empty message if (!ha_enabled_ && len) { // don't ping pong the empty message
queue_publish_message(topic, "", true); queue_publish_message(topic, "", true);
LOG_DEBUG(F("Remove topic %s"), topic); LOG_DEBUG("Remove topic %s", topic);
} }
return; return;
} }
@@ -285,7 +285,7 @@ void Mqtt::on_message(const char * topic, const char * payload, size_t len) cons
snprintf(full_topic, sizeof(full_topic), "%s/%s", mqtt_base_.c_str(), mf.topic_.c_str()); snprintf(full_topic, sizeof(full_topic), "%s/%s", mqtt_base_.c_str(), mf.topic_.c_str());
if ((!strcmp(topic, full_topic)) && (mf.mqtt_subfunction_)) { if ((!strcmp(topic, full_topic)) && (mf.mqtt_subfunction_)) {
if (!(mf.mqtt_subfunction_)(message)) { if (!(mf.mqtt_subfunction_)(message)) {
LOG_ERROR(F("error: invalid payload %s for this topic %s"), message, topic); LOG_ERROR("error: invalid payload %s for this topic %s", message, topic);
if (send_response_) { if (send_response_) {
Mqtt::publish(F_(response), "error: invalid data"); Mqtt::publish(F_(response), "error: invalid data");
} }
@@ -341,10 +341,10 @@ void Mqtt::show_topic_handlers(uuid::console::Shell & shell, const uint8_t devic
return; return;
} }
// shell.print(F(" Subscribed MQTT topics: ")); // shell.print(" Subscribed MQTT topics: ");
// for (const auto & mqtt_subfunction : mqtt_subfunctions_) { // for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
// if (mqtt_subfunction.device_type_ == device_type) { // if (mqtt_subfunction.device_type_ == device_type) {
// shell.printf(F("%s "), mqtt_subfunction.topic_.c_str()); // shell.printf("%s ", mqtt_subfunction.topic_.c_str());
// } // }
// } // }
shell.println(); shell.println();
@@ -358,7 +358,7 @@ void Mqtt::on_publish(uint16_t packetId) const {
// find the MQTT message in the queue and remove it // find the MQTT message in the queue and remove it
if (mqtt_messages_.empty()) { if (mqtt_messages_.empty()) {
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
LOG_DEBUG(F("[DEBUG] No message stored for ACK pid %d"), packetId); LOG_DEBUG("[DEBUG] No message stored for ACK pid %d", packetId);
#endif #endif
return; return;
} }
@@ -368,18 +368,18 @@ void Mqtt::on_publish(uint16_t packetId) const {
// if the last published failed, don't bother checking it. wait for the next retry // if the last published failed, don't bother checking it. wait for the next retry
if (mqtt_message.packet_id_ == 0) { if (mqtt_message.packet_id_ == 0) {
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
LOG_DEBUG(F("[DEBUG] ACK for failed message pid 0")); LOG_DEBUG("[DEBUG] ACK for failed message pid 0");
#endif #endif
return; return;
} }
if (mqtt_message.packet_id_ != packetId) { if (mqtt_message.packet_id_ != packetId) {
LOG_ERROR(F("Mismatch, expecting PID %d, got %d"), mqtt_message.packet_id_, packetId); LOG_ERROR("Mismatch, expecting PID %d, got %d", mqtt_message.packet_id_, packetId);
mqtt_publish_fails_++; // increment error count mqtt_publish_fails_++; // increment error count
} }
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
LOG_DEBUG(F("[DEBUG] ACK pid %d"), packetId); LOG_DEBUG("[DEBUG] ACK pid %d", packetId);
#endif #endif
mqtt_messages_.pop_front(); // always remove from queue, regardless if there was a successful ACK mqtt_messages_.pop_front(); // always remove from queue, regardless if there was a successful ACK
@@ -450,17 +450,17 @@ void Mqtt::start() {
} }
connecting_ = false; connecting_ = false;
if (reason == AsyncMqttClientDisconnectReason::TCP_DISCONNECTED) { if (reason == AsyncMqttClientDisconnectReason::TCP_DISCONNECTED) {
LOG_WARNING(F("MQTT disconnected: TCP")); LOG_WARNING("MQTT disconnected: TCP");
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED) { } else if (reason == AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED) {
LOG_WARNING(F("MQTT disconnected: Identifier Rejected")); LOG_WARNING("MQTT disconnected: Identifier Rejected");
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_SERVER_UNAVAILABLE) { } else if (reason == AsyncMqttClientDisconnectReason::MQTT_SERVER_UNAVAILABLE) {
LOG_WARNING(F("MQTT disconnected: Server unavailable")); LOG_WARNING("MQTT disconnected: Server unavailable");
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_MALFORMED_CREDENTIALS) { } else if (reason == AsyncMqttClientDisconnectReason::MQTT_MALFORMED_CREDENTIALS) {
LOG_WARNING(F("MQTT disconnected: Malformed credentials")); LOG_WARNING("MQTT disconnected: Malformed credentials");
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_NOT_AUTHORIZED) { } else if (reason == AsyncMqttClientDisconnectReason::MQTT_NOT_AUTHORIZED) {
LOG_WARNING(F("MQTT disconnected: Not authorized")); LOG_WARNING("MQTT disconnected: Not authorized");
} else { } else {
LOG_WARNING(F("MQTT disconnected: code %d"), reason); LOG_WARNING("MQTT disconnected: code %d", reason);
} }
}); });
@@ -535,7 +535,7 @@ void Mqtt::on_connect() {
return; return;
} }
LOG_INFO(F("MQTT connected")); LOG_INFO("MQTT connected");
connecting_ = true; connecting_ = true;
connectcount_++; connectcount_++;
@@ -546,15 +546,15 @@ void Mqtt::on_connect() {
StaticJsonDocument<EMSESP_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_JSON_SIZE_MEDIUM> doc;
// first time to connect // first time to connect
if (connectcount_ == 1) { if (connectcount_ == 1) {
doc["event"] = FJSON("start"); doc["event"] = "start";
} else { } else {
doc["event"] = FJSON("reconnect"); doc["event"] = "reconnect";
} }
doc["version"] = EMSESP_APP_VERSION; doc["version"] = EMSESP_APP_VERSION;
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
if (WiFi.status() == WL_CONNECTED) { if (WiFi.status() == WL_CONNECTED) {
doc["connection"] = F("WiFi"); doc["connection"] = ("WiFi");
doc["hostname"] = WiFi.getHostname(); doc["hostname"] = WiFi.getHostname();
doc["SSID"] = WiFi.SSID(); doc["SSID"] = WiFi.SSID();
doc["BSSID"] = WiFi.BSSIDstr(); doc["BSSID"] = WiFi.BSSIDstr();
@@ -567,7 +567,7 @@ void Mqtt::on_connect() {
doc["IPv6 address"] = uuid::printable_to_string(WiFi.localIPv6()); doc["IPv6 address"] = uuid::printable_to_string(WiFi.localIPv6());
} }
} else if (EMSESP::system_.ethernet_connected()) { } else if (EMSESP::system_.ethernet_connected()) {
doc["connection"] = F("Ethernet"); doc["connection"] = ("Ethernet");
doc["hostname"] = ETH.getHostname(); doc["hostname"] = ETH.getHostname();
doc["MAC"] = ETH.macAddress(); doc["MAC"] = ETH.macAddress();
doc["IPv4 address"] = uuid::printable_to_string(ETH.localIP()) + "/" + uuid::printable_to_string(ETH.subnetMask()); doc["IPv4 address"] = uuid::printable_to_string(ETH.localIP()) + "/" + uuid::printable_to_string(ETH.subnetMask());
@@ -600,7 +600,7 @@ void Mqtt::on_connect() {
// re-subscribe to all custom registered MQTT topics // re-subscribe to all custom registered MQTT topics
resubscribe(); resubscribe();
publish_retain(F("status"), "online", true); // say we're alive to the Last Will topic, with retain on publish_retain("status", "online", true); // say we're alive to the Last Will topic, with retain on
mqtt_publish_fails_ = 0; // reset fail count to 0 mqtt_publish_fails_ = 0; // reset fail count to 0
@@ -609,7 +609,7 @@ void Mqtt::on_connect() {
LOG_INFO("Queue size: %d", mqtt_messages_.size()); LOG_INFO("Queue size: %d", mqtt_messages_.size());
for (const auto & message : mqtt_messages_) { for (const auto & message : mqtt_messages_) {
auto content = message.content_; auto content = message.content_;
LOG_INFO(F(" [%02d] (%d) topic=%s payload=%s"), message.id_, content->operation, content->topic.c_str(), content->payload.c_str()); LOG_INFO((" [%02d] (%d) topic=%s payload=%s"), message.id_, content->operation, content->topic.c_str(), content->payload.c_str());
} }
*/ */
} }
@@ -620,21 +620,21 @@ void Mqtt::on_connect() {
void Mqtt::ha_status() { void Mqtt::ha_status() {
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc; StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
doc["uniq_id"] = FJSON("ems-esp-system"); doc["uniq_id"] = "ems-esp-system";
doc["~"] = mqtt_base_; // default ems-esp doc["~"] = mqtt_base_; // default ems-esp
// doc["avty_t"] = FJSON("~/status"); // commented out, as it causes errors in HA sometimes // doc["avty_t"] = "~/status"; // commented out, as it causes errors in HA sometimes
// doc["json_attr_t"] = FJSON("~/heartbeat"); // store also as HA attributes // doc["json_attr_t"] = "~/heartbeat"; // store also as HA attributes
doc["stat_t"] = FJSON("~/heartbeat"); doc["stat_t"] = "~/heartbeat";
doc["object_id"] = FJSON("ems_esp_status"); doc["object_id"] = "ems_esp_status";
doc["name"] = FJSON("EMS-ESP status"); doc["name"] = "EMS-ESP status";
doc["ic"] = F_(icondevice); doc["ic"] = F_(icondevice);
doc["val_tpl"] = FJSON("{{value_json['bus_status']}}"); doc["val_tpl"] = "{{value_json['bus_status']}}";
JsonObject dev = doc.createNestedObject("dev"); JsonObject dev = doc.createNestedObject("dev");
dev["name"] = F_(EMSESP); // "EMS-ESP" dev["name"] = "EMS-ESP";
dev["sw"] = "v" + std::string(EMSESP_APP_VERSION); dev["sw"] = "v" + std::string(EMSESP_APP_VERSION);
dev["mf"] = FJSON("proddy"); dev["mf"] = "proddy";
dev["mdl"] = F_(EMSESP); // "EMS-ESP" dev["mdl"] = "EMS-ESP";
JsonArray ids = dev.createNestedArray("ids"); JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp"); ids.add("ems-esp");
@@ -644,19 +644,20 @@ void Mqtt::ha_status() {
// create the sensors - must match the MQTT payload keys // create the sensors - must match the MQTT payload keys
if (!EMSESP::system_.ethernet_connected()) { if (!EMSESP::system_.ethernet_connected()) {
publish_system_ha_sensor_config(DeviceValueType::INT, F("WiFi RSSI"), F("rssi"), DeviceValueUOM::DBM); publish_system_ha_sensor_config(DeviceValueType::INT, ("WiFi RSSI"), ("rssi"), DeviceValueUOM::DBM);
publish_system_ha_sensor_config(DeviceValueType::INT, F("WiFi strength"), F("wifistrength"), DeviceValueUOM::PERCENT); publish_system_ha_sensor_config(DeviceValueType::INT, ("WiFi strength"), ("wifistrength"), DeviceValueUOM::PERCENT);
} }
publish_system_ha_sensor_config(DeviceValueType::INT, F("Uptime"), F("uptime"), DeviceValueUOM::NONE);
publish_system_ha_sensor_config(DeviceValueType::INT, F("Uptime (sec)"), F("uptime_sec"), DeviceValueUOM::SECONDS); publish_system_ha_sensor_config(DeviceValueType::INT, ("Uptime"), ("uptime"), DeviceValueUOM::NONE);
publish_system_ha_sensor_config(DeviceValueType::BOOL, F("NTP status"), F("ntp_status"), DeviceValueUOM::NONE); publish_system_ha_sensor_config(DeviceValueType::INT, ("Uptime (sec)"), ("uptime_sec"), DeviceValueUOM::SECONDS);
publish_system_ha_sensor_config(DeviceValueType::INT, F("Free memory"), F("freemem"), DeviceValueUOM::KB); publish_system_ha_sensor_config(DeviceValueType::BOOL, ("NTP status"), ("ntp_status"), DeviceValueUOM::NONE);
publish_system_ha_sensor_config(DeviceValueType::INT, F("MQTT fails"), F("mqttfails"), DeviceValueUOM::NONE); publish_system_ha_sensor_config(DeviceValueType::INT, ("Free memory"), ("freemem"), DeviceValueUOM::KB);
publish_system_ha_sensor_config(DeviceValueType::INT, F("Rx received"), F("rxreceived"), DeviceValueUOM::NONE); publish_system_ha_sensor_config(DeviceValueType::INT, ("MQTT fails"), ("mqttfails"), DeviceValueUOM::NONE);
publish_system_ha_sensor_config(DeviceValueType::INT, F("Rx fails"), F("rxfails"), DeviceValueUOM::NONE); publish_system_ha_sensor_config(DeviceValueType::INT, ("Rx received"), ("rxreceived"), DeviceValueUOM::NONE);
publish_system_ha_sensor_config(DeviceValueType::INT, F("Tx reads"), F("txreads"), DeviceValueUOM::NONE); publish_system_ha_sensor_config(DeviceValueType::INT, ("Rx fails"), ("rxfails"), DeviceValueUOM::NONE);
publish_system_ha_sensor_config(DeviceValueType::INT, F("Tx writes"), F("txwrites"), DeviceValueUOM::NONE); publish_system_ha_sensor_config(DeviceValueType::INT, ("Tx reads"), ("txreads"), DeviceValueUOM::NONE);
publish_system_ha_sensor_config(DeviceValueType::INT, F("Tx fails"), F("txfails"), DeviceValueUOM::NONE); publish_system_ha_sensor_config(DeviceValueType::INT, ("Tx writes"), ("txwrites"), DeviceValueUOM::NONE);
publish_system_ha_sensor_config(DeviceValueType::INT, ("Tx fails"), ("txfails"), DeviceValueUOM::NONE);
} }
// add sub or pub task to the queue. // add sub or pub task to the queue.
@@ -686,7 +687,7 @@ std::shared_ptr<const MqttMessage> Mqtt::queue_message(const uint8_t operation,
// if the queue is full, make room but removing the last one // if the queue is full, make room but removing the last one
if (mqtt_messages_.size() >= MAX_MQTT_MESSAGES) { if (mqtt_messages_.size() >= MAX_MQTT_MESSAGES) {
mqtt_messages_.pop_front(); mqtt_messages_.pop_front();
LOG_WARNING(F("Queue overflow, removing one message")); LOG_WARNING("Queue overflow, removing one message");
mqtt_publish_fails_++; mqtt_publish_fails_++;
} }
mqtt_messages_.emplace_back(mqtt_message_id_++, std::move(message)); mqtt_messages_.emplace_back(mqtt_message_id_++, std::move(message));
@@ -718,17 +719,17 @@ void Mqtt::publish(const std::string & topic, const std::string & payload) {
} }
// MQTT Publish, using a user's retain flag - except for char * strings // MQTT Publish, using a user's retain flag - except for char * strings
void Mqtt::publish(const __FlashStringHelper * topic, const char * payload) { void Mqtt::publish(const char * topic, const char * payload) {
queue_publish_message(read_flash_string(topic), payload, mqtt_retain_); queue_publish_message((topic), payload, mqtt_retain_);
} }
// MQTT Publish, using a specific retain flag, topic is a flash string // MQTT Publish, using a specific retain flag, topic is a flash string
void Mqtt::publish(const __FlashStringHelper * topic, const std::string & payload) { void Mqtt::publish(const char * topic, const std::string & payload) {
queue_publish_message(read_flash_string(topic), payload, mqtt_retain_); queue_publish_message((topic), payload, mqtt_retain_);
} }
void Mqtt::publish(const __FlashStringHelper * topic, const JsonObject & payload) { void Mqtt::publish(const char * topic, const JsonObject & payload) {
publish(read_flash_string(topic), payload); publish_retain(topic, payload, mqtt_retain_);
} }
// publish json doc, only if its not empty // publish json doc, only if its not empty
@@ -737,12 +738,16 @@ void Mqtt::publish(const std::string & topic, const JsonObject & payload) {
} }
// MQTT Publish, using a specific retain flag, topic is a flash string, forcing retain flag // MQTT Publish, using a specific retain flag, topic is a flash string, forcing retain flag
void Mqtt::publish_retain(const __FlashStringHelper * topic, const std::string & payload, bool retain) { void Mqtt::publish_retain(const char * topic, const std::string & payload, bool retain) {
queue_publish_message(read_flash_string(topic), payload, retain); queue_publish_message((topic), payload, retain);
} }
// publish json doc, only if its not empty, using the retain flag // publish json doc, only if its not empty, using the retain flag
void Mqtt::publish_retain(const std::string & topic, const JsonObject & payload, bool retain) { void Mqtt::publish_retain(const std::string & topic, const JsonObject & payload, bool retain) {
publish_retain(topic.c_str(), payload, retain);
}
void Mqtt::publish_retain(const char * topic, const JsonObject & payload, bool retain) {
if (enabled() && payload.size()) { if (enabled() && payload.size()) {
std::string payload_text; std::string payload_text;
serializeJson(payload, payload_text); // convert json to string serializeJson(payload, payload_text); // convert json to string
@@ -750,30 +755,22 @@ void Mqtt::publish_retain(const std::string & topic, const JsonObject & payload,
} }
} }
void Mqtt::publish_retain(const __FlashStringHelper * topic, const JsonObject & payload, bool retain) {
publish_retain(read_flash_string(topic), payload, retain);
}
void Mqtt::publish_ha(const __FlashStringHelper * topic, const JsonObject & payload) {
publish_ha(read_flash_string(topic), payload);
}
// publish empty payload to remove the topic // publish empty payload to remove the topic
void Mqtt::publish_ha(const std::string & topic) { void Mqtt::publish_ha(const char * topic) {
if (!enabled()) { if (!enabled()) {
return; return;
} }
std::string fulltopic = Mqtt::discovery_prefix() + topic; std::string fulltopic = Mqtt::discovery_prefix() + topic;
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
LOG_DEBUG(F("[DEBUG] Publishing empty HA topic=%s"), fulltopic.c_str()); LOG_DEBUG("[DEBUG] Publishing empty HA topic=%s", fulltopic.c_str());
#endif #endif
queue_publish_message(fulltopic, "", true); // publish with retain to remove from broker queue_publish_message(fulltopic, "", true); // publish with retain to remove from broker
} }
// publish a Home Assistant config topic and payload, with retain flag off. // publish a Home Assistant config topic and payload, with retain flag off.
void Mqtt::publish_ha(const std::string & topic, const JsonObject & payload) { void Mqtt::publish_ha(const char * topic, const JsonObject & payload) {
if (!enabled()) { if (!enabled()) {
return; return;
} }
@@ -784,9 +781,9 @@ void Mqtt::publish_ha(const std::string & topic, const JsonObject & payload) {
std::string fulltopic = Mqtt::discovery_prefix() + topic; std::string fulltopic = Mqtt::discovery_prefix() + topic;
#if defined(EMSESP_STANDALONE) #if defined(EMSESP_STANDALONE)
LOG_DEBUG(F("Publishing HA topic=%s, payload=%s"), fulltopic.c_str(), payload_text.c_str()); LOG_DEBUG("Publishing HA topic=%s, payload=%s", fulltopic.c_str(), payload_text.c_str());
#elif defined(EMSESP_DEBUG) #elif defined(EMSESP_DEBUG)
LOG_DEBUG(F("[debug] Publishing HA topic=%s, payload=%s"), fulltopic.c_str(), payload_text.c_str()); LOG_DEBUG("[debug] Publishing HA topic=%s, payload=%s", fulltopic.c_str(), payload_text.c_str());
#endif #endif
// queue messages if the MQTT connection is not yet established. to ensure we don't miss messages // queue messages if the MQTT connection is not yet established. to ensure we don't miss messages
@@ -815,7 +812,7 @@ void Mqtt::process_queue() {
// it will have a real packet ID // it will have a real packet ID
if (mqtt_message.packet_id_ > 0) { if (mqtt_message.packet_id_ > 0) {
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
LOG_DEBUG(F("[DEBUG] Waiting for QOS-ACK")); LOG_DEBUG("[DEBUG] Waiting for QOS-ACK");
#endif #endif
// if we don't get the ack within 10 minutes, republish with new packet_id // if we don't get the ack within 10 minutes, republish with new packet_id
if (uuid::get_uptime_sec() - last_publish_queue_ < 600) { if (uuid::get_uptime_sec() - last_publish_queue_ < 600) {
@@ -826,13 +823,13 @@ void Mqtt::process_queue() {
// if we're subscribing... // if we're subscribing...
if (message->operation == Operation::SUBSCRIBE) { if (message->operation == Operation::SUBSCRIBE) {
LOG_DEBUG(F("Subscribing to topic '%s'"), topic); LOG_DEBUG("Subscribing to topic '%s'", topic);
uint16_t packet_id = mqttClient_->subscribe(topic, mqtt_qos_); uint16_t packet_id = mqttClient_->subscribe(topic, mqtt_qos_);
if (!packet_id) { if (!packet_id) {
if (++mqtt_messages_.front().retry_count_ < MQTT_PUBLISH_MAX_RETRY) { if (++mqtt_messages_.front().retry_count_ < MQTT_PUBLISH_MAX_RETRY) {
return; return;
} }
LOG_ERROR(F("Error subscribing to topic '%s'"), topic); LOG_ERROR("Error subscribing to topic '%s'", topic);
mqtt_publish_fails_++; // increment failure counter mqtt_publish_fails_++; // increment failure counter
} }
@@ -843,13 +840,13 @@ void Mqtt::process_queue() {
// if we're unsubscribing... // if we're unsubscribing...
if (message->operation == Operation::UNSUBSCRIBE) { if (message->operation == Operation::UNSUBSCRIBE) {
LOG_DEBUG(F("Subscribing to topic '%s'"), topic); LOG_DEBUG("Subscribing to topic '%s'", topic);
uint16_t packet_id = mqttClient_->unsubscribe(topic); uint16_t packet_id = mqttClient_->unsubscribe(topic);
if (!packet_id) { if (!packet_id) {
if (++mqtt_messages_.front().retry_count_ < MQTT_PUBLISH_MAX_RETRY) { if (++mqtt_messages_.front().retry_count_ < MQTT_PUBLISH_MAX_RETRY) {
return; return;
} }
LOG_ERROR(F("Error unsubscribing to topic '%s'"), topic); LOG_ERROR("Error unsubscribing to topic '%s'", topic);
mqtt_publish_fails_++; // increment failure counter mqtt_publish_fails_++; // increment failure counter
} }
@@ -860,7 +857,7 @@ void Mqtt::process_queue() {
// else try and publish it // else try and publish it
uint16_t packet_id = mqttClient_->publish(topic, mqtt_qos_, message->retain, message->payload.c_str(), message->payload.size(), false, mqtt_message.id_); uint16_t packet_id = mqttClient_->publish(topic, mqtt_qos_, message->retain, message->payload.c_str(), message->payload.size(), false, mqtt_message.id_);
LOG_DEBUG(F("Publishing topic %s (#%02d, retain=%d, retry=%d, size=%d, pid=%d)"), LOG_DEBUG(("Publishing topic %s (#%02d, retain=%d, retry=%d, size=%d, pid=%d)"),
topic, topic,
mqtt_message.id_, mqtt_message.id_,
message->retain, message->retain,
@@ -871,14 +868,14 @@ void Mqtt::process_queue() {
if (packet_id == 0) { if (packet_id == 0) {
// it failed. if we retried n times, give up. remove from queue // it failed. if we retried n times, give up. remove from queue
if (mqtt_message.retry_count_ == (MQTT_PUBLISH_MAX_RETRY - 1)) { if (mqtt_message.retry_count_ == (MQTT_PUBLISH_MAX_RETRY - 1)) {
LOG_ERROR(F("Failed to publish to %s after %d attempts"), topic, mqtt_message.retry_count_ + 1); LOG_ERROR("Failed to publish to %s after %d attempts", topic, mqtt_message.retry_count_ + 1);
mqtt_publish_fails_++; // increment failure counter mqtt_publish_fails_++; // increment failure counter
mqtt_messages_.pop_front(); // delete mqtt_messages_.pop_front(); // delete
return; return;
} else { } else {
// update the record // update the record
mqtt_messages_.front().retry_count_++; mqtt_messages_.front().retry_count_++;
LOG_DEBUG(F("Failed to publish to %s. Trying again, #%d"), topic, mqtt_message.retry_count_ + 1); LOG_DEBUG("Failed to publish to %s. Trying again, #%d", topic, mqtt_message.retry_count_ + 1);
return; // leave on queue for next time so it gets republished return; // leave on queue for next time so it gets republished
} }
} }
@@ -888,7 +885,7 @@ void Mqtt::process_queue() {
if (mqtt_qos_ != 0) { if (mqtt_qos_ != 0) {
mqtt_messages_.front().packet_id_ = packet_id; mqtt_messages_.front().packet_id_ = packet_id;
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
LOG_DEBUG(F("[DEBUG] Setting packetID for ACK to %d"), packet_id); LOG_DEBUG("[DEBUG] Setting packetID for ACK to %d", packet_id);
#endif #endif
return; return;
} }
@@ -927,8 +924,8 @@ void Mqtt::publish_ha_sensor_config(DeviceValue & dv, const std::string & model,
publish_ha_sensor_config(dv.type, publish_ha_sensor_config(dv.type,
dv.tag, dv.tag,
dv.get_fullname(), dv.get_fullname().c_str(),
dv.fullname[0], (dv.fullname ? dv.fullname[0] : nullptr), // EN name
dv.device_type, dv.device_type,
dv.short_name, dv.short_name,
dv.uom, dv.uom,
@@ -942,37 +939,35 @@ void Mqtt::publish_ha_sensor_config(DeviceValue & dv, const std::string & model,
} }
// publish HA sensor for System using the heartbeat tag // publish HA sensor for System using the heartbeat tag
void Mqtt::publish_system_ha_sensor_config(uint8_t type, const __FlashStringHelper * name, const __FlashStringHelper * entity, const uint8_t uom) { void Mqtt::publish_system_ha_sensor_config(uint8_t type, const char * name, const char * entity, const uint8_t uom) {
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc; StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
JsonObject dev_json = doc.createNestedObject("dev"); JsonObject dev_json = doc.createNestedObject("dev");
JsonArray ids = dev_json.createNestedArray("ids"); JsonArray ids = dev_json.createNestedArray("ids");
ids.add("ems-esp"); ids.add("ems-esp");
auto fullname = read_flash_string(name); publish_ha_sensor_config(type, DeviceValueTAG::TAG_HEARTBEAT, name, name, EMSdevice::DeviceType::SYSTEM, entity, uom, false, false, nullptr, 0, 0, 0, dev_json);
publish_ha_sensor_config(type, DeviceValueTAG::TAG_HEARTBEAT, fullname, name, EMSdevice::DeviceType::SYSTEM, entity, uom, false, false, nullptr, 0, 0, 0, dev_json);
} }
// MQTT discovery configs // MQTT discovery configs
// entity must match the key/value pair in the *_data topic // entity must match the key/value pair in the *_data topic
// note: some extra string copying done here, it looks messy but does help with heap fragmentation issues // note: some extra string copying done here, it looks messy but does help with heap fragmentation issues
void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdevice::DeviceValueType void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdevice::DeviceValueType
uint8_t tag, // EMSdevice::DeviceValueTAG uint8_t tag, // EMSdevice::DeviceValueTAG
const std::string & fullname, // fullname, already translated const char * const fullname, // fullname, already translated
const __FlashStringHelper * const en_name, const char * const en_name,
const uint8_t device_type, // EMSdevice::DeviceType const uint8_t device_type, // EMSdevice::DeviceType
const __FlashStringHelper * const entity, // same as shortname const char * const entity, // same as shortname
const uint8_t uom, // EMSdevice::DeviceValueUOM (0=NONE) const uint8_t uom, // EMSdevice::DeviceValueUOM (0=NONE)
const bool remove, // true if we want to remove this topic const bool remove, // true if we want to remove this topic
const bool has_cmd, const bool has_cmd,
const __FlashStringHelper * const ** options, const char * const ** options,
uint8_t options_size, uint8_t options_size,
const int16_t dv_set_min, const int16_t dv_set_min,
const int16_t dv_set_max, const int16_t dv_set_max,
const JsonObject & dev_json) { const JsonObject & dev_json) {
// ignore if name (fullname) is empty // ignore if name (fullname) is empty
if (fullname.empty() || en_name == nullptr) { if (fullname == nullptr || en_name == nullptr) {
return; return;
} }
@@ -983,9 +978,9 @@ void Mqtt::publish_ha_sensor_config(uint8_t type,
// create entity by add the hc/wwc tag if present, separating with a . // create entity by add the hc/wwc tag if present, separating with a .
char new_entity[50]; char new_entity[50];
if (tag >= DeviceValueTAG::TAG_HC1) { if (tag >= DeviceValueTAG::TAG_HC1) {
snprintf(new_entity, sizeof(new_entity), "%s.%s", EMSdevice::tag_to_string(tag).c_str(), read_flash_string(entity).c_str()); snprintf(new_entity, sizeof(new_entity), "%s.%s", EMSdevice::tag_to_string(tag).c_str(), (entity));
} else { } else {
snprintf(new_entity, sizeof(new_entity), "%s", read_flash_string(entity).c_str()); snprintf(new_entity, sizeof(new_entity), "%s", (entity));
} }
// build unique identifier which will be used in the topic, replacing all . with _ as not to break HA // build unique identifier which will be used in the topic, replacing all . with _ as not to break HA
@@ -1037,7 +1032,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type,
// if we're asking to remove this topic, send an empty payload and exit // if we're asking to remove this topic, send an empty payload and exit
// https://github.com/emsesp/EMS-ESP32/issues/196 // https://github.com/emsesp/EMS-ESP32/issues/196
if (remove) { if (remove) {
LOG_DEBUG(F("Removing HA config for %s"), uniq); LOG_DEBUG("Removing HA config for %s", uniq);
publish_ha(topic); publish_ha(topic);
return; return;
} }
@@ -1107,7 +1102,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type,
// friendly name = <tag> <name> // friendly name = <tag> <name>
char ha_name[70]; char ha_name[70];
char * F_name = strdup(fullname.c_str()); char * F_name = strdup(fullname);
F_name[0] = toupper(F_name[0]); // capitalize first letter F_name[0] = toupper(F_name[0]); // capitalize first letter
if (have_tag) { if (have_tag) {
snprintf(ha_name, sizeof(ha_name), "%s %s", EMSdevice::tag_to_string(tag).c_str(), F_name); snprintf(ha_name, sizeof(ha_name), "%s %s", EMSdevice::tag_to_string(tag).c_str(), F_name);
@@ -1120,14 +1115,12 @@ void Mqtt::publish_ha_sensor_config(uint8_t type,
// entity id is generated from the name, see https://www.home-assistant.io/docs/mqtt/discovery/#use-object_id-to-influence-the-entity-id // entity id is generated from the name, see https://www.home-assistant.io/docs/mqtt/discovery/#use-object_id-to-influence-the-entity-id
// so we override it to make it unique using entity_id // so we override it to make it unique using entity_id
// See https://github.com/emsesp/EMS-ESP32/issues/596 // See https://github.com/emsesp/EMS-ESP32/issues/596
// keep it compatible to v3.4, use english fullname, no prefix (basename prefix commmented out) // keep it compatible to v3.4, use english fullname, no prefix (basename prefix commented out)
char object_id[130]; char object_id[130];
if (have_tag) { if (have_tag) {
// snprintf(object_id, sizeof(object_id), "%s_%s_%s_%s", mqtt_basename_, device_name, EMSdevice::tag_to_string(tag).c_str(), read_flash_string(en_name).c_str()); snprintf(object_id, sizeof(object_id), "%s_%s_%s", device_name, EMSdevice::tag_to_string(tag).c_str(), en_name);
snprintf(object_id, sizeof(object_id), "%s_%s_%s", device_name, EMSdevice::tag_to_string(tag).c_str(), read_flash_string(en_name).c_str());
} else { } else {
// snprintf(object_id, sizeof(object_id), "%s_%s_%s", mqtt_basename_, device_name, read_flash_string(en_name).c_str()); snprintf(object_id, sizeof(object_id), "%s_%s", device_name, en_name);
snprintf(object_id, sizeof(object_id), "%s_%s", device_name, read_flash_string(en_name).c_str());
} }
doc["object_id"] = object_id; doc["object_id"] = object_id;
@@ -1137,7 +1130,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type,
if (is_nested()) { if (is_nested()) {
snprintf(val_tpl, sizeof(val_tpl), "{{value_json.%s}}", new_entity); snprintf(val_tpl, sizeof(val_tpl), "{{value_json.%s}}", new_entity);
} else { } else {
snprintf(val_tpl, sizeof(val_tpl), "{{value_json.%s}}", read_flash_string(entity).c_str()); snprintf(val_tpl, sizeof(val_tpl), "{{value_json.%s}}", entity);
} }
doc["val_tpl"] = val_tpl; doc["val_tpl"] = val_tpl;
@@ -1147,9 +1140,9 @@ void Mqtt::publish_ha_sensor_config(uint8_t type,
// and has no unit of measure or icon // and has no unit of measure or icon
if (type == DeviceValueType::BOOL) { if (type == DeviceValueType::BOOL) {
char result[10]; char result[10];
doc[F("payload_on")] = Helpers::render_boolean(result, true); doc[("payload_on")] = Helpers::render_boolean(result, true);
doc[F("payload_off")] = Helpers::render_boolean(result, false); doc[("payload_off")] = Helpers::render_boolean(result, false);
doc[sc_ha] = F_(measurement); doc[sc_ha] = F_(measurement);
} else { } else {
// always set the uom // always set the uom
if (uom != DeviceValueUOM::NONE) { if (uom != DeviceValueUOM::NONE) {
@@ -1169,11 +1162,11 @@ void Mqtt::publish_ha_sensor_config(uint8_t type,
case DeviceValueUOM::DEGREES: case DeviceValueUOM::DEGREES:
case DeviceValueUOM::DEGREES_R: case DeviceValueUOM::DEGREES_R:
doc[sc_ha] = F_(measurement); doc[sc_ha] = F_(measurement);
doc[dc_ha] = F("temperature"); // no icon needed doc[dc_ha] = "temperature"; // no icon needed
break; break;
case DeviceValueUOM::PERCENT: case DeviceValueUOM::PERCENT:
doc[sc_ha] = F_(measurement); doc[sc_ha] = F_(measurement);
doc[dc_ha] = F("power_factor"); // no icon needed doc[dc_ha] = "power_factor"; // no icon needed
break; break;
case DeviceValueUOM::SECONDS: case DeviceValueUOM::SECONDS:
case DeviceValueUOM::MINUTES: case DeviceValueUOM::MINUTES:
@@ -1198,11 +1191,11 @@ void Mqtt::publish_ha_sensor_config(uint8_t type,
} else { } else {
doc[sc_ha] = F_(measurement); doc[sc_ha] = F_(measurement);
} }
doc[dc_ha] = F("energy"); // no icon needed doc[dc_ha] = "energy"; // no icon needed
break; break;
case DeviceValueUOM::KWH: case DeviceValueUOM::KWH:
doc[sc_ha] = F_(total_increasing); doc[sc_ha] = F_(total_increasing);
doc[dc_ha] = F("energy"); // no icon needed doc[dc_ha] = "energy"; // no icon needed
break; break;
case DeviceValueUOM::UA: case DeviceValueUOM::UA:
doc[ic_ha] = F_(iconua); doc[ic_ha] = F_(iconua);
@@ -1210,16 +1203,16 @@ void Mqtt::publish_ha_sensor_config(uint8_t type,
break; break;
case DeviceValueUOM::BAR: case DeviceValueUOM::BAR:
doc[sc_ha] = F_(measurement); doc[sc_ha] = F_(measurement);
doc[dc_ha] = F("pressure"); doc[dc_ha] = "pressure";
break; break;
case DeviceValueUOM::W: case DeviceValueUOM::W:
case DeviceValueUOM::KW: case DeviceValueUOM::KW:
doc[sc_ha] = F_(measurement); doc[sc_ha] = F_(measurement);
doc[dc_ha] = F("power"); doc[dc_ha] = "power";
break; break;
case DeviceValueUOM::DBM: case DeviceValueUOM::DBM:
doc[sc_ha] = F_(measurement); doc[sc_ha] = F_(measurement);
doc[dc_ha] = F("signal_strength"); doc[dc_ha] = "signal_strength";
break; break;
case DeviceValueUOM::NONE: case DeviceValueUOM::NONE:
// for device entities which have numerical values, with no UOM // for device entities which have numerical values, with no UOM

View File

@@ -79,35 +79,34 @@ class Mqtt {
static void resubscribe(); static void resubscribe();
static void publish(const std::string & topic, const std::string & payload); static void publish(const std::string & topic, const std::string & payload);
static void publish(const __FlashStringHelper * topic, const char * payload); static void publish(const char * topic, const char * payload);
static void publish(const std::string & topic, const JsonObject & payload); static void publish(const std::string & topic, const JsonObject & payload);
static void publish(const __FlashStringHelper * topic, const JsonObject & payload); static void publish(const char * topic, const JsonObject & payload);
static void publish(const __FlashStringHelper * topic, const std::string & payload); static void publish(const char * topic, const std::string & payload);
static void publish_retain(const std::string & topic, const JsonObject & payload, bool retain); static void publish_retain(const std::string & topic, const JsonObject & payload, bool retain);
static void publish_retain(const __FlashStringHelper * topic, const std::string & payload, bool retain); static void publish_retain(const char * topic, const std::string & payload, bool retain);
static void publish_retain(const __FlashStringHelper * topic, const JsonObject & payload, bool retain); static void publish_retain(const char * topic, const JsonObject & payload, bool retain);
static void publish_ha(const std::string & topic, const JsonObject & payload); static void publish_ha(const char * topic, const JsonObject & payload);
static void publish_ha(const __FlashStringHelper * topic, const JsonObject & payload); static void publish_ha(const char * topic);
static void publish_ha(const std::string & topic);
static void static void
publish_ha_sensor_config(DeviceValue & dv, const std::string & model, const std::string & brand, const bool remove, const bool create_device_config = false); publish_ha_sensor_config(DeviceValue & dv, const std::string & model, const std::string & brand, const bool remove, const bool create_device_config = false);
static void publish_ha_sensor_config(uint8_t type, static void publish_ha_sensor_config(uint8_t type,
uint8_t tag, uint8_t tag,
const std::string & fullname, const char * const fullname,
const __FlashStringHelper * const en_name, const char * const en_name,
const uint8_t device_type, const uint8_t device_type,
const __FlashStringHelper * const entity, const char * const entity,
const uint8_t uom, const uint8_t uom,
const bool remove, const bool remove,
const bool has_cmd, const bool has_cmd,
const __FlashStringHelper * const ** options, const char * const ** options,
uint8_t options_size, uint8_t options_size,
const int16_t dv_set_min, const int16_t dv_set_min,
const int16_t dv_set_max, const int16_t dv_set_max,
const JsonObject & dev_json); const JsonObject & dev_json);
static void publish_system_ha_sensor_config(uint8_t type, const __FlashStringHelper * name, const __FlashStringHelper * entity, const uint8_t uom); static void publish_system_ha_sensor_config(uint8_t type, const char * name, const char * entity, const uint8_t uom);
static void publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp, const bool remove = false, const int16_t min = 5, const uint16_t max = 30); static void publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp, const bool remove = false, const int16_t min = 5, const uint16_t max = 30);
static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type); static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type);

View File

@@ -57,7 +57,7 @@ void Shower::loop() {
// first check to see if hot water has been on long enough to be recognized as a Shower/Bath // first check to see if hot water has been on long enough to be recognized as a Shower/Bath
if (!shower_state_ && (time_now - timer_start_) > SHOWER_MIN_DURATION) { if (!shower_state_ && (time_now - timer_start_) > SHOWER_MIN_DURATION) {
set_shower_state(true); set_shower_state(true);
LOG_DEBUG(F("[Shower] hot water still running, starting shower timer")); LOG_DEBUG("[Shower] hot water still running, starting shower timer");
} }
// check if the shower has been on too long // check if the shower has been on too long
else if ((time_now - timer_start_) > shower_alert_trigger_) { else if ((time_now - timer_start_) > shower_alert_trigger_) {
@@ -82,8 +82,8 @@ void Shower::loop() {
char s[50]; char s[50];
snprintf(s, 50, "%d minutes and %d seconds", (uint8_t)(duration_ / 60000), (uint8_t)((duration_ / 1000) % 60)); snprintf(s, 50, "%d minutes and %d seconds", (uint8_t)(duration_ / 60000), (uint8_t)((duration_ / 1000) % 60));
doc["duration"] = s; doc["duration"] = s;
Mqtt::publish(F("shower_data"), doc.as<JsonObject>()); Mqtt::publish("shower_data", doc.as<JsonObject>());
LOG_DEBUG(F("[Shower] finished with duration %d"), duration_); LOG_DEBUG("[Shower] finished with duration %d", duration_);
} }
} }
@@ -109,7 +109,7 @@ void Shower::loop() {
// turn back on the hot water for the shower // turn back on the hot water for the shower
void Shower::shower_alert_stop() { void Shower::shower_alert_stop() {
if (doing_cold_shot_) { if (doing_cold_shot_) {
LOG_DEBUG(F("Shower Alert stopped")); LOG_DEBUG("Shower Alert stopped");
(void)Command::call(EMSdevice::DeviceType::BOILER, "wwtapactivated", "true"); (void)Command::call(EMSdevice::DeviceType::BOILER, "wwtapactivated", "true");
doing_cold_shot_ = false; doing_cold_shot_ = false;
} }
@@ -117,7 +117,7 @@ void Shower::shower_alert_stop() {
// turn off hot water to send a shot of cold // turn off hot water to send a shot of cold
void Shower::shower_alert_start() { void Shower::shower_alert_start() {
if (shower_alert_) { if (shower_alert_) {
LOG_DEBUG(F("Shower Alert started")); LOG_DEBUG("Shower Alert started");
(void)Command::call(EMSdevice::DeviceType::BOILER, "wwtapactivated", "false"); (void)Command::call(EMSdevice::DeviceType::BOILER, "wwtapactivated", "false");
doing_cold_shot_ = true; doing_cold_shot_ = true;
alert_timer_start_ = uuid::get_uptime(); // timer starts now alert_timer_start_ = uuid::get_uptime(); // timer starts now
@@ -144,22 +144,22 @@ void Shower::set_shower_state(bool state, bool force) {
// always publish as a string // always publish as a string
char s[7]; char s[7];
Mqtt::publish(F("shower_active"), Helpers::render_boolean(s, shower_state_)); // https://github.com/emsesp/EMS-ESP/issues/369 Mqtt::publish("shower_active", Helpers::render_boolean(s, shower_state_)); // https://github.com/emsesp/EMS-ESP/issues/369
// send out HA MQTT Discovery config topic // send out HA MQTT Discovery config topic
if ((Mqtt::ha_enabled()) && (!ha_configdone_ || force)) { if ((Mqtt::ha_enabled()) && (!ha_configdone_ || force)) {
ha_configdone_ = true; ha_configdone_ = true;
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc; StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
doc["name"] = FJSON("Shower Active"); doc["name"] = "Shower Active";
doc["uniq_id"] = FJSON("shower_active"); doc["uniq_id"] = "shower_active";
doc["~"] = Mqtt::base(); doc["~"] = Mqtt::base();
doc["stat_t"] = FJSON("~/shower_active"); doc["stat_t"] = "~/shower_active";
// always render boolean as strings for HA // always render boolean as strings for HA
char result[10]; char result[10];
doc[F("payload_on")] = Helpers::render_boolean(result, true); doc[("payload_on")] = Helpers::render_boolean(result, true);
doc[F("payload_off")] = Helpers::render_boolean(result, false); doc[("payload_off")] = Helpers::render_boolean(result, false);
JsonObject dev = doc.createNestedObject("dev"); JsonObject dev = doc.createNestedObject("dev");
JsonArray ids = dev.createNestedArray("ids"); JsonArray ids = dev.createNestedArray("ids");

View File

@@ -77,19 +77,19 @@ bool System::command_fetch(const char * value, const int8_t id) {
std::string value_s; std::string value_s;
if (Helpers::value2string(value, value_s)) { if (Helpers::value2string(value, value_s)) {
if (value_s == "all") { if (value_s == "all") {
LOG_INFO(F("Requesting data from EMS devices")); LOG_INFO("Requesting data from EMS devices");
EMSESP::fetch_device_values(); EMSESP::fetch_device_values();
return true; return true;
} else if (value_s == read_flash_string(F_(boiler))) { } else if (value_s == (F_(boiler))) {
EMSESP::fetch_device_values_type(EMSdevice::DeviceType::BOILER); EMSESP::fetch_device_values_type(EMSdevice::DeviceType::BOILER);
return true; return true;
} else if (value_s == read_flash_string(F_(thermostat))) { } else if (value_s == (F_(thermostat))) {
EMSESP::fetch_device_values_type(EMSdevice::DeviceType::THERMOSTAT); EMSESP::fetch_device_values_type(EMSdevice::DeviceType::THERMOSTAT);
return true; return true;
} else if (value_s == read_flash_string(F_(solar))) { } else if (value_s == (F_(solar))) {
EMSESP::fetch_device_values_type(EMSdevice::DeviceType::SOLAR); EMSESP::fetch_device_values_type(EMSdevice::DeviceType::SOLAR);
return true; return true;
} else if (value_s == read_flash_string(F_(mixer))) { } else if (value_s == (F_(mixer))) {
EMSESP::fetch_device_values_type(EMSdevice::DeviceType::MIXER); EMSESP::fetch_device_values_type(EMSdevice::DeviceType::MIXER);
return true; return true;
} }
@@ -105,31 +105,31 @@ bool System::command_publish(const char * value, const int8_t id) {
if (Helpers::value2string(value, value_s)) { if (Helpers::value2string(value, value_s)) {
if (value_s == "ha") { if (value_s == "ha") {
EMSESP::publish_all(true); // includes HA EMSESP::publish_all(true); // includes HA
LOG_INFO(F("Publishing all data to MQTT, including HA configs")); LOG_INFO("Publishing all data to MQTT, including HA configs");
return true; return true;
} else if (value_s == read_flash_string(F_(boiler))) { } else if (value_s == (F_(boiler))) {
EMSESP::publish_device_values(EMSdevice::DeviceType::BOILER); EMSESP::publish_device_values(EMSdevice::DeviceType::BOILER);
return true; return true;
} else if (value_s == read_flash_string(F_(thermostat))) { } else if (value_s == (F_(thermostat))) {
EMSESP::publish_device_values(EMSdevice::DeviceType::THERMOSTAT); EMSESP::publish_device_values(EMSdevice::DeviceType::THERMOSTAT);
return true; return true;
} else if (value_s == read_flash_string(F_(solar))) { } else if (value_s == (F_(solar))) {
EMSESP::publish_device_values(EMSdevice::DeviceType::SOLAR); EMSESP::publish_device_values(EMSdevice::DeviceType::SOLAR);
return true; return true;
} else if (value_s == read_flash_string(F_(mixer))) { } else if (value_s == (F_(mixer))) {
EMSESP::publish_device_values(EMSdevice::DeviceType::MIXER); EMSESP::publish_device_values(EMSdevice::DeviceType::MIXER);
return true; return true;
} else if (value_s == "other") { } else if (value_s == "other") {
EMSESP::publish_other_values(); // switch and heat pump EMSESP::publish_other_values(); // switch and heat pump
return true; return true;
} else if ((value_s == read_flash_string(F_(dallassensor))) || (value_s == read_flash_string(F_(analogsensor)))) { } else if ((value_s == (F_(dallassensor))) || (value_s == (F_(analogsensor)))) {
EMSESP::publish_sensor_values(true); EMSESP::publish_sensor_values(true);
return true; return true;
} }
} }
EMSESP::publish_all(); EMSESP::publish_all();
LOG_INFO(F("Publishing all data to MQTT")); LOG_INFO("Publishing all data to MQTT");
return true; return true;
} }
@@ -166,11 +166,9 @@ bool System::command_watch(const char * value, const int8_t id) {
} }
if (Mqtt::publish_single() && w != EMSESP::watch()) { if (Mqtt::publish_single() && w != EMSESP::watch()) {
if (Mqtt::publish_single2cmd()) { if (Mqtt::publish_single2cmd()) {
Mqtt::publish(F("system/watch"), Mqtt::publish("system/watch", EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(w) : (FL_(list_watch)[w]));
EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(w) : read_flash_string(FL_(list_watch)[w]).c_str());
} else { } else {
Mqtt::publish(F("system_data/watch"), Mqtt::publish("system_data/watch", EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(w) : (FL_(list_watch)[w]));
EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(w) : read_flash_string(FL_(list_watch)[w]).c_str());
} }
} }
EMSESP::watch(w); EMSESP::watch(w);
@@ -178,9 +176,9 @@ bool System::command_watch(const char * value, const int8_t id) {
} else if (i) { } else if (i) {
if (Mqtt::publish_single() && i != EMSESP::watch_id()) { if (Mqtt::publish_single() && i != EMSESP::watch_id()) {
if (Mqtt::publish_single2cmd()) { if (Mqtt::publish_single2cmd()) {
Mqtt::publish(F("system/watch"), Helpers::hextoa(i)); Mqtt::publish("system/watch", Helpers::hextoa(i));
} else { } else {
Mqtt::publish(F("system_data/watch"), Helpers::hextoa(i)); Mqtt::publish("system_data/watch", Helpers::hextoa(i));
} }
} }
EMSESP::watch_id(i); EMSESP::watch_id(i);
@@ -194,7 +192,7 @@ bool System::command_watch(const char * value, const int8_t id) {
// restart EMS-ESP // restart EMS-ESP
void System::system_restart() { void System::system_restart() {
LOG_INFO(F("Restarting EMS-ESP...")); LOG_INFO("Restarting EMS-ESP...");
Shell::loop_all(); Shell::loop_all();
delay(1000); // wait a second delay(1000); // wait a second
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
@@ -204,7 +202,7 @@ void System::system_restart() {
// saves all settings // saves all settings
void System::wifi_reconnect() { void System::wifi_reconnect() {
LOG_INFO(F("WiFi reconnecting...")); LOG_INFO("WiFi reconnecting...");
Shell::loop_all(); Shell::loop_all();
EMSESP::console_.loop(); EMSESP::console_.loop();
delay(1000); // wait a second delay(1000); // wait a second
@@ -214,7 +212,7 @@ void System::wifi_reconnect() {
// format the FS. Wipes everything. // format the FS. Wipes everything.
void System::format(uuid::console::Shell & shell) { void System::format(uuid::console::Shell & shell) {
auto msg = F("Formatting file system. This will reset all settings to their defaults"); auto msg = ("Formatting file system. This will reset all settings to their defaults");
shell.logger().warning(msg); shell.logger().warning(msg);
shell.flush(); shell.flush();
@@ -243,7 +241,7 @@ void System::syslog_init() {
// start & configure syslog // start & configure syslog
if (!was_enabled) { if (!was_enabled) {
syslog_.start(); syslog_.start();
EMSESP::logger().info(F("Starting Syslog")); EMSESP::logger().info("Starting Syslog");
} }
syslog_.log_level((uuid::log::Level)syslog_level_); syslog_.log_level((uuid::log::Level)syslog_level_);
syslog_.mark_interval(syslog_mark_interval_); syslog_.mark_interval(syslog_mark_interval_);
@@ -252,12 +250,12 @@ void System::syslog_init() {
// register the command // register the command
// TODO translate this // TODO translate this
Command::add(EMSdevice::DeviceType::SYSTEM, F_(syslog), System::command_syslog_level, F("change the syslog level"), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(syslog), System::command_syslog_level, ("change the syslog level"), CommandFlag::ADMIN_ONLY);
} else if (was_enabled) { } else if (was_enabled) {
// in case service is still running, this flushes the queue // in case service is still running, this flushes the queue
// https://github.com/emsesp/EMS-ESP/issues/496 // https://github.com/emsesp/EMS-ESP/issues/496
EMSESP::logger().info(F("Stopping Syslog")); EMSESP::logger().info("Stopping Syslog");
syslog_.log_level((uuid::log::Level)-1); syslog_.log_level((uuid::log::Level)-1);
syslog_.mark_interval(0); syslog_.mark_interval(0);
syslog_.destination(""); syslog_.destination("");
@@ -265,23 +263,21 @@ void System::syslog_init() {
if (Mqtt::publish_single()) { if (Mqtt::publish_single()) {
if (Mqtt::publish_single2cmd()) { if (Mqtt::publish_single2cmd()) {
Mqtt::publish(F("system/syslog"), syslog_enabled_ ? read_flash_string(FL_(list_syslog_level)[syslog_level_ + 1]).c_str() : "off"); Mqtt::publish("system/syslog", syslog_enabled_ ? (FL_(list_syslog_level)[syslog_level_ + 1]) : "off");
if (EMSESP::watch_id() == 0 || EMSESP::watch() == 0) { if (EMSESP::watch_id() == 0 || EMSESP::watch() == 0) {
Mqtt::publish(F("system/watch"), Mqtt::publish("system/watch",
EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(EMSESP::watch()) EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(EMSESP::watch()) : (FL_(list_watch)[EMSESP::watch()]));
: read_flash_string(FL_(list_watch)[EMSESP::watch()]).c_str());
} else { } else {
Mqtt::publish(F("system/watch"), Helpers::hextoa(EMSESP::watch_id())); Mqtt::publish("system/watch", Helpers::hextoa(EMSESP::watch_id()));
} }
} else { } else {
Mqtt::publish(F("system_data/syslog"), syslog_enabled_ ? read_flash_string(FL_(list_syslog_level)[syslog_level_ + 1]).c_str() : "off"); Mqtt::publish("system_data/syslog", syslog_enabled_ ? (FL_(list_syslog_level)[syslog_level_ + 1]) : "off");
if (EMSESP::watch_id() == 0 || EMSESP::watch() == 0) { if (EMSESP::watch_id() == 0 || EMSESP::watch() == 0) {
Mqtt::publish(F("system_data/watch"), Mqtt::publish("system_data/watch",
EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(EMSESP::watch()) EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(EMSESP::watch()) : (FL_(list_watch)[EMSESP::watch()]));
: read_flash_string(FL_(list_watch)[EMSESP::watch()]).c_str());
} else { } else {
Mqtt::publish(F("system_data/watch"), Helpers::hextoa(EMSESP::watch_id())); Mqtt::publish("system_data/watch", Helpers::hextoa(EMSESP::watch_id()));
} }
} }
} }
@@ -348,7 +344,7 @@ void System::wifi_tweak() {
WiFi.setSleep(false); // turn off sleep - WIFI_PS_NONE WiFi.setSleep(false); // turn off sleep - WIFI_PS_NONE
bool s2 = WiFi.getSleep(); bool s2 = WiFi.getSleep();
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
LOG_DEBUG(F("[DEBUG] Adjusting WiFi - Tx power %d->%d, Sleep %d->%d"), p1, p2, s1, s2); LOG_DEBUG("[DEBUG] Adjusting WiFi - Tx power %d->%d, Sleep %d->%d", p1, p2, s1, s2);
#endif #endif
#endif #endif
} }
@@ -403,7 +399,7 @@ void System::start() {
// button single click // button single click
void System::button_OnClick(PButton & b) { void System::button_OnClick(PButton & b) {
LOG_DEBUG(F("Button pressed - single click")); LOG_DEBUG("Button pressed - single click");
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
@@ -414,20 +410,20 @@ void System::button_OnClick(PButton & b) {
// button double click // button double click
void System::button_OnDblClick(PButton & b) { void System::button_OnDblClick(PButton & b) {
LOG_DEBUG(F("Button pressed - double click - reconnect")); LOG_DEBUG("Button pressed - double click - reconnect");
EMSESP::system_.wifi_reconnect(); EMSESP::system_.wifi_reconnect();
} }
// button long press // button long press
void System::button_OnLongPress(PButton & b) { void System::button_OnLongPress(PButton & b) {
LOG_DEBUG(F("Button pressed - long press")); LOG_DEBUG("Button pressed - long press");
} }
// button indefinite press // button indefinite press
void System::button_OnVLongPress(PButton & b) { void System::button_OnVLongPress(PButton & b) {
LOG_DEBUG(F("Button pressed - very long press")); LOG_DEBUG("Button pressed - very long press");
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
LOG_WARNING(F("Performing factory reset...")); LOG_WARNING("Performing factory reset...");
EMSESP::console_.loop(); EMSESP::console_.loop();
EMSESP::esp8266React.factoryReset(); EMSESP::esp8266React.factoryReset();
#endif #endif
@@ -441,12 +437,12 @@ void System::button_init(bool refresh) {
if (is_valid_gpio(pbutton_gpio_)) { if (is_valid_gpio(pbutton_gpio_)) {
if (!myPButton_.init(pbutton_gpio_, HIGH)) { if (!myPButton_.init(pbutton_gpio_, HIGH)) {
LOG_DEBUG(F("Multi-functional button not detected")); LOG_DEBUG("Multi-functional button not detected");
} else { } else {
LOG_DEBUG(F("Multi-functional button enabled")); LOG_DEBUG("Multi-functional button enabled");
} }
} else { } else {
LOG_WARNING(F("Invalid button GPIO. Check config.")); LOG_WARNING("Invalid button GPIO. Check config.");
} }
myPButton_.onClick(BUTTON_Debounce, button_OnClick); myPButton_.onClick(BUTTON_Debounce, button_OnClick);
@@ -528,11 +524,11 @@ void System::loop() {
bool System::heartbeat_json(JsonObject & output) { bool System::heartbeat_json(JsonObject & output) {
uint8_t bus_status = EMSESP::bus_status(); uint8_t bus_status = EMSESP::bus_status();
if (bus_status == EMSESP::BUS_STATUS_TX_ERRORS) { if (bus_status == EMSESP::BUS_STATUS_TX_ERRORS) {
output["bus_status"] = FJSON("txerror"); output["bus_status"] = "txerror";
} else if (bus_status == EMSESP::BUS_STATUS_CONNECTED) { } else if (bus_status == EMSESP::BUS_STATUS_CONNECTED) {
output["bus_status"] = FJSON("connected"); output["bus_status"] = "connected";
} else { } else {
output["bus_status"] = FJSON("disconnected"); output["bus_status"] = "disconnected";
} }
output["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3); output["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3);
@@ -668,25 +664,25 @@ void System::system_check() {
// commands - takes static function pointers // commands - takes static function pointers
void System::commands_init() { void System::commands_init() {
// TODO these should be translated too // TODO translate this
Command::add(EMSdevice::DeviceType::SYSTEM, F_(send), System::command_send, F("send a telegram"), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(send), System::command_send, ("send a telegram"), CommandFlag::ADMIN_ONLY);
Command::add(EMSdevice::DeviceType::SYSTEM, F_(fetch), System::command_fetch, F("refresh all EMS values"), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(fetch), System::command_fetch, ("refresh all EMS values"), CommandFlag::ADMIN_ONLY);
Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, F("restart EMS-ESP"), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, ("restart EMS-ESP"), CommandFlag::ADMIN_ONLY);
Command::add(EMSdevice::DeviceType::SYSTEM, F_(watch), System::command_watch, F("watch incoming telegrams")); Command::add(EMSdevice::DeviceType::SYSTEM, F_(watch), System::command_watch, ("watch incoming telegrams"));
// register syslog command in syslog init // register syslog command in syslog init
// Command::add(EMSdevice::DeviceType::SYSTEM, F_(syslog), System::command_syslog_level, F("set syslog level"), CommandFlag::ADMIN_ONLY); // Command::add(EMSdevice::DeviceType::SYSTEM, F_(syslog), System::command_syslog_level, ("set syslog level"), CommandFlag::ADMIN_ONLY);
if (Mqtt::enabled()) { if (Mqtt::enabled()) {
Command::add(EMSdevice::DeviceType::SYSTEM, F_(publish), System::command_publish, F("force a MQTT publish")); Command::add(EMSdevice::DeviceType::SYSTEM, F_(publish), System::command_publish, ("force a MQTT publish"));
} }
// these commands will return data in JSON format // these commands will return data in JSON format
Command::add(EMSdevice::DeviceType::SYSTEM, F_(info), System::command_info, F("show system status")); Command::add(EMSdevice::DeviceType::SYSTEM, F_(info), System::command_info, ("show system status"));
Command::add(EMSdevice::DeviceType::SYSTEM, F_(commands), System::command_commands, F("fetch system commands")); Command::add(EMSdevice::DeviceType::SYSTEM, F_(commands), System::command_commands, ("fetch system commands"));
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
Command::add(EMSdevice::DeviceType::SYSTEM, F("test"), System::command_test, F("run a specific test")); Command::add(EMSdevice::DeviceType::SYSTEM, ("test"), System::command_test, ("run a specific test"));
#endif #endif
// MQTT subscribe "ems-esp/system/#" // MQTT subscribe "ems-esp/system/#"
@@ -776,12 +772,12 @@ int8_t System::wifi_quality(int8_t dBm) {
// print users to console // print users to console
void System::show_users(uuid::console::Shell & shell) { void System::show_users(uuid::console::Shell & shell) {
shell.printfln(F("Users:")); shell.printfln("Users:");
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
EMSESP::esp8266React.getSecuritySettingsService()->read([&](SecuritySettings & securitySettings) { EMSESP::esp8266React.getSecuritySettingsService()->read([&](SecuritySettings & securitySettings) {
for (const User & user : securitySettings.users) { for (const User & user : securitySettings.users) {
shell.printfln(F(" username: %s, password: %s, is_admin: %s"), user.username.c_str(), user.password.c_str(), user.admin ? F("yes") : F("no")); shell.printfln(" username: %s, password: %s, is_admin: %s", user.username.c_str(), user.password.c_str(), user.admin ? ("yes") : ("no"));
} }
}); });
#endif #endif
@@ -791,94 +787,94 @@ void System::show_users(uuid::console::Shell & shell) {
void System::show_system(uuid::console::Shell & shell) { void System::show_system(uuid::console::Shell & shell) {
shell.println("System:"); shell.println("System:");
shell.printfln(F(" Board profile: %s"), board_profile().c_str()); shell.printfln(" Board profile: %s", board_profile().c_str());
shell.printfln(F(" Uptime: %s"), uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3).c_str()); shell.printfln(" Uptime: %s", uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3).c_str());
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
shell.printfln(F(" SDK version: %s"), ESP.getSdkVersion()); shell.printfln(" SDK version: %s", ESP.getSdkVersion());
shell.printfln(F(" CPU frequency: %lu MHz"), ESP.getCpuFreqMHz()); shell.printfln(" CPU frequency: %lu MHz", ESP.getCpuFreqMHz());
shell.printfln(F(" Free heap: %lu KB"), (uint32_t)ESP.getFreeHeap() / 1024); shell.printfln(" Free heap: %lu KB", (uint32_t)ESP.getFreeHeap() / 1024);
shell.printfln(F(" App used/free: %lu KB / %lu KB"), appUsed(), appFree()); shell.printfln(" App used/free: %lu KB / %lu KB", appUsed(), appFree());
uint32_t FSused = LittleFS.usedBytes() / 1024; uint32_t FSused = LittleFS.usedBytes() / 1024;
shell.printfln(F(" FS used/free: %lu KB / %lu KB"), FSused, FStotal() - FSused); shell.printfln(" FS used/free: %lu KB / %lu KB", FSused, FStotal() - FSused);
shell.println(); shell.println();
shell.println("Network:"); shell.println("Network:");
switch (WiFi.status()) { switch (WiFi.status()) {
case WL_IDLE_STATUS: case WL_IDLE_STATUS:
shell.printfln(F(" Network: Idle")); shell.printfln(" Network: Idle");
break; break;
case WL_NO_SSID_AVAIL: case WL_NO_SSID_AVAIL:
shell.printfln(F(" Network: Network not found")); shell.printfln(" Network: Network not found");
break; break;
case WL_SCAN_COMPLETED: case WL_SCAN_COMPLETED:
shell.printfln(F(" Network: Network scan complete")); shell.printfln(" Network: Network scan complete");
break; break;
case WL_CONNECTED: case WL_CONNECTED:
shell.printfln(F(" Network: connected")); shell.printfln(" Network: connected");
shell.printfln(F(" SSID: %s"), WiFi.SSID().c_str()); shell.printfln(" SSID: %s", WiFi.SSID().c_str());
shell.printfln(F(" BSSID: %s"), WiFi.BSSIDstr().c_str()); shell.printfln(" BSSID: %s", WiFi.BSSIDstr().c_str());
shell.printfln(F(" RSSI: %d dBm (%d %%)"), WiFi.RSSI(), wifi_quality(WiFi.RSSI())); shell.printfln((" RSSI: %d dBm (%d %%)"), WiFi.RSSI(), wifi_quality(WiFi.RSSI()));
shell.printfln(F(" MAC address: %s"), WiFi.macAddress().c_str()); shell.printfln(" MAC address: %s", WiFi.macAddress().c_str());
shell.printfln(F(" Hostname: %s"), WiFi.getHostname()); shell.printfln(" Hostname: %s", WiFi.getHostname());
shell.printfln(F(" IPv4 address: %s/%s"), uuid::printable_to_string(WiFi.localIP()).c_str(), uuid::printable_to_string(WiFi.subnetMask()).c_str()); shell.printfln(" IPv4 address: %s/%s", uuid::printable_to_string(WiFi.localIP()).c_str(), uuid::printable_to_string(WiFi.subnetMask()).c_str());
shell.printfln(F(" IPv4 gateway: %s"), uuid::printable_to_string(WiFi.gatewayIP()).c_str()); shell.printfln(" IPv4 gateway: %s", uuid::printable_to_string(WiFi.gatewayIP()).c_str());
shell.printfln(F(" IPv4 nameserver: %s"), uuid::printable_to_string(WiFi.dnsIP()).c_str()); shell.printfln(" IPv4 nameserver: %s", uuid::printable_to_string(WiFi.dnsIP()).c_str());
if (WiFi.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000") { if (WiFi.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000") {
shell.printfln(F(" IPv6 address: %s"), uuid::printable_to_string(WiFi.localIPv6()).c_str()); shell.printfln(" IPv6 address: %s", uuid::printable_to_string(WiFi.localIPv6()).c_str());
} }
break; break;
case WL_CONNECT_FAILED: case WL_CONNECT_FAILED:
shell.printfln(F(" WiFi Network: Connection failed")); shell.printfln(" WiFi Network: Connection failed");
break; break;
case WL_CONNECTION_LOST: case WL_CONNECTION_LOST:
shell.printfln(F(" WiFi Network: Connection lost")); shell.printfln(" WiFi Network: Connection lost");
break; break;
case WL_DISCONNECTED: case WL_DISCONNECTED:
shell.printfln(F(" WiFi Network: Disconnected")); shell.printfln(" WiFi Network: Disconnected");
break; break;
case WL_NO_SHIELD: case WL_NO_SHIELD:
default: default:
shell.printfln(F(" WiFi Network: Unknown")); shell.printfln(" WiFi Network: Unknown");
break; break;
} }
// show Ethernet if connected // show Ethernet if connected
if (ethernet_connected_) { if (ethernet_connected_) {
shell.println(); shell.println();
shell.printfln(F(" Ethernet Network: connected")); shell.printfln(" Ethernet Network: connected");
shell.printfln(F(" MAC address: %s"), ETH.macAddress().c_str()); shell.printfln(" MAC address: %s", ETH.macAddress().c_str());
shell.printfln(F(" Hostname: %s"), ETH.getHostname()); shell.printfln(" Hostname: %s", ETH.getHostname());
shell.printfln(F(" IPv4 address: %s/%s"), uuid::printable_to_string(ETH.localIP()).c_str(), uuid::printable_to_string(ETH.subnetMask()).c_str()); shell.printfln(" IPv4 address: %s/%s", uuid::printable_to_string(ETH.localIP()).c_str(), uuid::printable_to_string(ETH.subnetMask()).c_str());
shell.printfln(F(" IPv4 gateway: %s"), uuid::printable_to_string(ETH.gatewayIP()).c_str()); shell.printfln(" IPv4 gateway: %s", uuid::printable_to_string(ETH.gatewayIP()).c_str());
shell.printfln(F(" IPv4 nameserver: %s"), uuid::printable_to_string(ETH.dnsIP()).c_str()); shell.printfln(" IPv4 nameserver: %s", uuid::printable_to_string(ETH.dnsIP()).c_str());
if (ETH.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000") { if (ETH.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000") {
shell.printfln(F(" IPv6 address: %s"), uuid::printable_to_string(ETH.localIPv6()).c_str()); shell.printfln(" IPv6 address: %s", uuid::printable_to_string(ETH.localIPv6()).c_str());
} }
} }
shell.println(); shell.println();
shell.println("Syslog:"); shell.println("Syslog:");
if (!syslog_enabled_) { if (!syslog_enabled_) {
shell.printfln(F(" Syslog: disabled")); shell.printfln(" Syslog: disabled");
} else { } else {
shell.printfln(F(" Syslog: %s"), syslog_.started() ? "started" : "stopped"); shell.printfln(" Syslog: %s", syslog_.started() ? "started" : "stopped");
shell.print(F(" ")); shell.print(" ");
shell.printfln(F_(host_fmt), !syslog_host_.isEmpty() ? syslog_host_.c_str() : read_flash_string(F_(unset)).c_str()); shell.printfln(F_(host_fmt), !syslog_host_.isEmpty() ? syslog_host_.c_str() : (F_(unset)));
shell.printfln(F(" IP: %s"), uuid::printable_to_string(syslog_.ip()).c_str()); shell.printfln(" IP: %s", uuid::printable_to_string(syslog_.ip()).c_str());
shell.print(F(" ")); shell.print(" ");
shell.printfln(F_(port_fmt), syslog_port_); shell.printfln(F_(port_fmt), syslog_port_);
shell.print(F(" ")); shell.print(" ");
shell.printfln(F_(log_level_fmt), uuid::log::format_level_lowercase(static_cast<uuid::log::Level>(syslog_level_))); shell.printfln(F_(log_level_fmt), uuid::log::format_level_lowercase(static_cast<uuid::log::Level>(syslog_level_)));
shell.print(F(" ")); shell.print(" ");
shell.printfln(F_(mark_interval_fmt), syslog_mark_interval_); shell.printfln(F_(mark_interval_fmt), syslog_mark_interval_);
shell.printfln(F(" Queued: %d"), syslog_.queued()); shell.printfln(" Queued: %d", syslog_.queued());
} }
#endif #endif
@@ -912,10 +908,10 @@ bool System::check_upgrade() {
// it's a customization file, just replace it and there's no need to reboot // it's a customization file, just replace it and there's no need to reboot
saveSettings(EMSESP_CUSTOMIZATION_FILE, "Customizations", input); saveSettings(EMSESP_CUSTOMIZATION_FILE, "Customizations", input);
} else { } else {
LOG_ERROR(F("Unrecognized file uploaded")); LOG_ERROR("Unrecognized file uploaded");
} }
} else { } else {
LOG_ERROR(F("Unrecognized file uploaded, not json")); LOG_ERROR("Unrecognized file uploaded, not json");
} }
// close (just in case) and remove the temp file // close (just in case) and remove the temp file
@@ -958,7 +954,7 @@ bool System::saveSettings(const char * filename, const char * section, JsonObjec
if (section_json) { if (section_json) {
File section_file = LittleFS.open(filename, "w"); File section_file = LittleFS.open(filename, "w");
if (section_file) { if (section_file) {
LOG_INFO(F("Applying new %s settings"), section); LOG_INFO("Applying new %s settings", section);
serializeJson(section_json, section_file); serializeJson(section_json, section_file);
section_file.close(); section_file.close();
return true; // reboot required return true; // reboot required
@@ -988,7 +984,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & outp
// Network Status // Network Status
node = output.createNestedObject("Network Status"); node = output.createNestedObject("Network Status");
if (WiFi.status() == WL_CONNECTED) { if (WiFi.status() == WL_CONNECTED) {
node["connection"] = F("WiFi"); node["connection"] = ("WiFi");
node["hostname"] = WiFi.getHostname(); node["hostname"] = WiFi.getHostname();
// node["SSID"] = WiFi.SSID(); // node["SSID"] = WiFi.SSID();
// node["BSSID"] = WiFi.BSSIDstr(); // node["BSSID"] = WiFi.BSSIDstr();
@@ -1001,7 +997,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & outp
node["IPv6 address"] = uuid::printable_to_string(WiFi.localIPv6()); node["IPv6 address"] = uuid::printable_to_string(WiFi.localIPv6());
} }
} else if (EMSESP::system_.ethernet_connected()) { } else if (EMSESP::system_.ethernet_connected()) {
node["connection"] = F("Ethernet"); node["connection"] = ("Ethernet");
node["hostname"] = ETH.getHostname(); node["hostname"] = ETH.getHostname();
node["MAC"] = ETH.macAddress(); node["MAC"] = ETH.macAddress();
node["IPv4 address"] = uuid::printable_to_string(ETH.localIP()) + "/" + uuid::printable_to_string(ETH.subnetMask()); node["IPv4 address"] = uuid::printable_to_string(ETH.localIP()) + "/" + uuid::printable_to_string(ETH.subnetMask());
@@ -1115,20 +1111,20 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & outp
node = output.createNestedObject("Bus Status"); node = output.createNestedObject("Bus Status");
switch (EMSESP::bus_status()) { switch (EMSESP::bus_status()) {
case EMSESP::BUS_STATUS_OFFLINE: case EMSESP::BUS_STATUS_OFFLINE:
node["bus status"] = (F("disconnected")); node["bus status"] = ("disconnected");
break; break;
case EMSESP::BUS_STATUS_TX_ERRORS: case EMSESP::BUS_STATUS_TX_ERRORS:
node["bus status"] = (F("connected, tx issues - try a different Tx Mode")); node["bus status"] = ("connected, tx issues - try a different Tx Mode");
break; break;
case EMSESP::BUS_STATUS_CONNECTED: case EMSESP::BUS_STATUS_CONNECTED:
node["bus status"] = (F("connected")); node["bus status"] = ("connected");
break; break;
default: default:
node["bus status"] = (F("unknown")); node["bus status"] = ("unknown");
break; break;
} }
if (EMSESP::bus_status() != EMSESP::BUS_STATUS_OFFLINE) { if (EMSESP::bus_status() != EMSESP::BUS_STATUS_OFFLINE) {
node["bus protocol"] = EMSbus::is_ht3() ? F("HT3") : F("Buderus"); node["bus protocol"] = EMSbus::is_ht3() ? ("HT3") : ("Buderus");
node["bus telegrams received (rx)"] = EMSESP::rxservice_.telegram_count(); node["bus telegrams received (rx)"] = EMSESP::rxservice_.telegram_count();
node["bus reads (tx)"] = EMSESP::txservice_.telegram_read_count(); node["bus reads (tx)"] = EMSESP::txservice_.telegram_read_count();
node["bus writes (tx)"] = EMSESP::txservice_.telegram_write_count(); node["bus writes (tx)"] = EMSESP::txservice_.telegram_write_count();
@@ -1174,9 +1170,8 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & outp
for (const auto & device_class : EMSFactory::device_handlers()) { for (const auto & device_class : EMSFactory::device_handlers()) {
for (const auto & emsdevice : EMSESP::emsdevices) { for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_class.first)) { if (emsdevice && (emsdevice->device_type() == device_class.first)) {
JsonObject obj = devices.createNestedObject(); JsonObject obj = devices.createNestedObject();
obj["type"] = emsdevice->device_type_name(); obj["type"] = emsdevice->device_type_name();
// obj["name"] = emsdevice->to_string();
obj["name"] = emsdevice->name(); obj["name"] = emsdevice->name();
obj["device id"] = Helpers::hextoa(emsdevice->device_id()); obj["device id"] = Helpers::hextoa(emsdevice->device_id());
obj["product id"] = emsdevice->product_id(); obj["product id"] = emsdevice->product_id();
@@ -1321,7 +1316,7 @@ std::string System::reset_reason(uint8_t cpu) const {
// set NTP status // set NTP status
void System::ntp_connected(bool b) { void System::ntp_connected(bool b) {
if (b != ntp_connected_) { if (b != ntp_connected_) {
LOG_INFO(b ? F("NTP connected") : F("NTP disconnected")); LOG_INFO(b ? ("NTP connected") : ("NTP disconnected"));
} }
ntp_connected_ = b; ntp_connected_ = b;
ntp_last_check_ = b ? uuid::get_uptime_sec() : 0; ntp_last_check_ = b ? uuid::get_uptime_sec() : 0;

View File

@@ -120,7 +120,7 @@ std::string Telegram::to_string() const {
// returns telegram's message body only, in hex // returns telegram's message body only, in hex
std::string Telegram::to_string_message() const { std::string Telegram::to_string_message() const {
if (this->message_length == 0) { if (this->message_length == 0) {
return read_flash_string(F("<empty>")); return ("<empty>");
} }
return Helpers::data_to_hex(this->message_data, this->message_length); return Helpers::data_to_hex(this->message_data, this->message_length);
@@ -150,9 +150,9 @@ void RxService::add(uint8_t * data, uint8_t length) {
if (data[length - 1] != crc) { if (data[length - 1] != crc) {
if ((data[0] & 0x7F) != ems_bus_id()) { // do not count echos as errors if ((data[0] & 0x7F) != ems_bus_id()) { // do not count echos as errors
telegram_error_count_++; telegram_error_count_++;
LOG_WARNING(F("Incomplete Rx: %s"), Helpers::data_to_hex(data, length - 1).c_str()); // exclude CRC LOG_WARNING("Incomplete Rx: %s", Helpers::data_to_hex(data, length - 1).c_str()); // exclude CRC
} else { } else {
LOG_TRACE(F("Incomplete Rx: %s"), Helpers::data_to_hex(data, length - 1).c_str()); // exclude CRC LOG_TRACE("Incomplete Rx: %s", Helpers::data_to_hex(data, length - 1).c_str()); // exclude CRC
} }
return; return;
} }
@@ -203,16 +203,16 @@ void RxService::add(uint8_t * data, uint8_t length) {
uint16_t trace_watch_id = EMSESP::watch_id(); uint16_t trace_watch_id = EMSESP::watch_id();
if ((trace_watch_id == WATCH_ID_NONE) || (type_id == trace_watch_id) if ((trace_watch_id == WATCH_ID_NONE) || (type_id == trace_watch_id)
|| ((trace_watch_id < 0x80) && ((src == trace_watch_id) || (dest == trace_watch_id)))) { || ((trace_watch_id < 0x80) && ((src == trace_watch_id) || (dest == trace_watch_id)))) {
LOG_NOTICE(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str()); LOG_NOTICE("Rx: %s", Helpers::data_to_hex(data, length).c_str());
} else if (EMSESP::trace_raw()) { } else if (EMSESP::trace_raw()) {
LOG_TRACE(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str()); LOG_TRACE("Rx: %s", Helpers::data_to_hex(data, length).c_str());
} }
} else if (EMSESP::trace_raw()) { } else if (EMSESP::trace_raw()) {
LOG_TRACE(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str()); LOG_TRACE("Rx: %s", Helpers::data_to_hex(data, length).c_str());
} }
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG
LOG_DEBUG(F("[DEBUG] New Rx telegram, message length %d"), message_length); LOG_DEBUG("[DEBUG] New Rx telegram, message length %d", message_length);
#endif #endif
// if we don't have a type_id exit, // if we don't have a type_id exit,
@@ -262,7 +262,7 @@ void TxService::start() {
// sends a 1 byte poll which is our own deviceID // sends a 1 byte poll which is our own deviceID
void TxService::send_poll() const { void TxService::send_poll() const {
//LOG_DEBUG(F("Ack %02X"),ems_bus_id() ^ ems_mask()); //LOG_DEBUG("Ack %02X",ems_bus_id() ^ ems_mask());
if (tx_mode()) { if (tx_mode()) {
EMSuart::send_poll(ems_bus_id() ^ ems_mask()); EMSuart::send_poll(ems_bus_id() ^ ems_mask());
} }
@@ -363,13 +363,13 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) {
// if we're in simulation mode, don't send anything, just quit // if we're in simulation mode, don't send anything, just quit
if (EMSESP::system_.readonly_mode() && (telegram->operation == Telegram::Operation::TX_WRITE)) { if (EMSESP::system_.readonly_mode() && (telegram->operation == Telegram::Operation::TX_WRITE)) {
LOG_INFO(F("[readonly] Sending write Tx telegram: %s"), Helpers::data_to_hex(telegram_raw, length - 1).c_str()); LOG_INFO("[readonly] Sending write Tx telegram: %s", Helpers::data_to_hex(telegram_raw, length - 1).c_str());
tx_state(Telegram::Operation::NONE); tx_state(Telegram::Operation::NONE);
return; return;
} }
LOG_DEBUG(F("Sending %s Tx [#%d], telegram: %s"), LOG_DEBUG("Sending %s Tx [#%d], telegram: %s",
(telegram->operation == Telegram::Operation::TX_WRITE) ? F("write") : F("read"), (telegram->operation == Telegram::Operation::TX_WRITE) ? ("write") : ("read"),
tx_telegram.id_, tx_telegram.id_,
Helpers::data_to_hex(telegram_raw, length - 1).c_str()); // exclude the last CRC byte Helpers::data_to_hex(telegram_raw, length - 1).c_str()); // exclude the last CRC byte
@@ -381,7 +381,7 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) {
uint16_t status = EMSuart::transmit(telegram_raw, length); uint16_t status = EMSuart::transmit(telegram_raw, length);
if (status == EMS_TX_STATUS_ERR) { if (status == EMS_TX_STATUS_ERR) {
LOG_ERROR(F("Failed to transmit Tx via UART.")); LOG_ERROR("Failed to transmit Tx via UART.");
if (telegram->operation == Telegram::Operation::TX_READ) { if (telegram->operation == Telegram::Operation::TX_READ) {
increment_telegram_read_fail_count(); // another Tx fail increment_telegram_read_fail_count(); // another Tx fail
} else { } else {
@@ -412,7 +412,7 @@ void TxService::send_telegram(const uint8_t * data, const uint8_t length) {
uint16_t status = EMSuart::transmit(telegram_raw, length); uint16_t status = EMSuart::transmit(telegram_raw, length);
if (status == EMS_TX_STATUS_ERR) { if (status == EMS_TX_STATUS_ERR) {
LOG_ERROR(F("Failed to transmit Tx via UART.")); LOG_ERROR("Failed to transmit Tx via UART.");
increment_telegram_fail_count(); // another Tx fail increment_telegram_fail_count(); // another Tx fail
} }
} }
@@ -429,10 +429,10 @@ void TxService::add(const uint8_t operation,
auto telegram = std::make_shared<Telegram>(operation, ems_bus_id(), dest, type_id, offset, message_data, message_length); auto telegram = std::make_shared<Telegram>(operation, ems_bus_id(), dest, type_id, offset, message_data, message_length);
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG
LOG_DEBUG(F("[DEBUG] New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length); LOG_DEBUG("[DEBUG] New Tx [#%d] telegram, length %d", tx_telegram_id_, message_length);
#endif #endif
// if the queue is full, make room but removing the last one // if the queue is full, make room by removing the last one
if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) { if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) {
if (tx_telegrams_.front().telegram_->operation == Telegram::Operation::TX_WRITE) { if (tx_telegrams_.front().telegram_->operation == Telegram::Operation::TX_WRITE) {
telegram_write_fail_count_++; telegram_write_fail_count_++;
@@ -493,7 +493,7 @@ void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t lengt
// if we don't have a type_id or empty data block, exit // if we don't have a type_id or empty data block, exit
if ((type_id == 0) || (message_length == 0)) { if ((type_id == 0) || (message_length == 0)) {
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG
LOG_DEBUG(F("[DEBUG] Tx telegram type %d failed, length %d"), type_id, message_length); LOG_DEBUG("[DEBUG] Tx telegram type %d failed, length %d", type_id, message_length);
#endif #endif
return; return;
} }
@@ -510,7 +510,7 @@ void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t lengt
auto telegram = std::make_shared<Telegram>(operation, src, dest, type_id, offset, message_data, message_length); // operation is TX_WRITE or TX_READ auto telegram = std::make_shared<Telegram>(operation, src, dest, type_id, offset, message_data, message_length); // operation is TX_WRITE or TX_READ
// if the queue is full, make room but removing the last one // if the queue is full, make room by removing the last one
if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) { if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) {
if (tx_telegrams_.front().telegram_->operation == Telegram::Operation::TX_WRITE) { if (tx_telegrams_.front().telegram_->operation == Telegram::Operation::TX_WRITE) {
telegram_write_fail_count_++; telegram_write_fail_count_++;
@@ -521,7 +521,7 @@ void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t lengt
} }
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG
LOG_DEBUG(F("[DEBUG] New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length); LOG_DEBUG("[DEBUG] New Tx [#%d] telegram, length %d", tx_telegram_id_, message_length);
#endif #endif
if (front) { if (front) {
@@ -538,7 +538,7 @@ void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t lengt
// send a Tx telegram to request data from an EMS device // send a Tx telegram to request data from an EMS device
void TxService::read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset, const uint8_t length) { void TxService::read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset, const uint8_t length) {
LOG_DEBUG(F("Tx read request to device 0x%02X for type ID 0x%02X"), dest, type_id); LOG_DEBUG("Tx read request to device 0x%02X for type ID 0x%02X", dest, type_id);
uint8_t message_data = (type_id > 0xFF) ? (EMS_MAX_TELEGRAM_MESSAGE_LENGTH - 2) : EMS_MAX_TELEGRAM_MESSAGE_LENGTH; uint8_t message_data = (type_id > 0xFF) ? (EMS_MAX_TELEGRAM_MESSAGE_LENGTH - 2) : EMS_MAX_TELEGRAM_MESSAGE_LENGTH;
// if length set, publish result and set telegram to front // if length set, publish result and set telegram to front
@@ -603,7 +603,7 @@ void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const ui
EMSESP::wait_validate(0); // do not wait for validation EMSESP::wait_validate(0); // do not wait for validation
if (operation == Telegram::Operation::TX_READ) { if (operation == Telegram::Operation::TX_READ) {
if (telegram_last_->offset > 0) { // ignore errors for higher offsets if (telegram_last_->offset > 0) { // ignore errors for higher offsets
LOG_DEBUG(F("Last Tx Read operation failed after %d retries. Ignoring request: %s"), MAXIMUM_TX_RETRIES, telegram_last_->to_string().c_str()); LOG_DEBUG("Last Tx Read operation failed after %d retries. Ignoring request: %s", MAXIMUM_TX_RETRIES, telegram_last_->to_string().c_str());
return; return;
} }
increment_telegram_read_fail_count(); // another Tx fail increment_telegram_read_fail_count(); // another Tx fail
@@ -611,8 +611,8 @@ void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const ui
increment_telegram_write_fail_count(); // another Tx fail increment_telegram_write_fail_count(); // another Tx fail
} }
LOG_ERROR(F("Last Tx %s operation failed after %d retries. Ignoring request: %s"), LOG_ERROR("Last Tx %s operation failed after %d retries. Ignoring request: %s",
(operation == Telegram::Operation::TX_WRITE) ? F("Write") : F("Read"), (operation == Telegram::Operation::TX_WRITE) ? ("Write") : ("Read"),
MAXIMUM_TX_RETRIES, MAXIMUM_TX_RETRIES,
telegram_last_->to_string().c_str()); telegram_last_->to_string().c_str());
@@ -623,8 +623,8 @@ void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const ui
} }
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG
LOG_DEBUG(F("[DEBUG] Last Tx %s operation failed. Retry #%d. sent message: %s, received: %s"), LOG_DEBUG("[DEBUG] Last Tx %s operation failed. Retry #%d. sent message: %s, received: %s",
(operation == Telegram::Operation::TX_WRITE) ? F("Write") : F("Read"), (operation == Telegram::Operation::TX_WRITE) ? ("Write") : ("Read"),
retry_count_, retry_count_,
telegram_last_->to_string().c_str(), telegram_last_->to_string().c_str(),
Helpers::data_to_hex(data, length - 1).c_str()); Helpers::data_to_hex(data, length - 1).c_str());
@@ -675,7 +675,7 @@ uint16_t TxService::post_send_query() {
(this->telegram_last_->type_id > 0xFF) ? (EMS_MAX_TELEGRAM_MESSAGE_LENGTH - 2) : EMS_MAX_TELEGRAM_MESSAGE_LENGTH; // request all data, 32 bytes (this->telegram_last_->type_id > 0xFF) ? (EMS_MAX_TELEGRAM_MESSAGE_LENGTH - 2) : EMS_MAX_TELEGRAM_MESSAGE_LENGTH; // request all data, 32 bytes
this->add(Telegram::Operation::TX_READ, dest, post_typeid, offset, &message_data, 1, 0, true); // add to top/front of queue this->add(Telegram::Operation::TX_READ, dest, post_typeid, offset, &message_data, 1, 0, true); // add to top/front of queue
// read_request(telegram_last_post_send_query_, dest, 0); // no offset // read_request(telegram_last_post_send_query_, dest, 0); // no offset
LOG_DEBUG(F("Sending post validate read, type ID 0x%02X to dest 0x%02X"), post_typeid, dest); LOG_DEBUG("Sending post validate read, type ID 0x%02X to dest 0x%02X", post_typeid, dest);
set_post_send_query(0); // reset set_post_send_query(0); // reset
// delay the request if we have a different type_id for post_send_query // delay the request if we have a different type_id for post_send_query
delayed_send_ = (this->telegram_last_->type_id == post_typeid) ? 0 : (uuid::get_uptime() + POST_SEND_DELAY); delayed_send_ = (this->telegram_last_->type_id == post_typeid) ? 0 : (uuid::get_uptime() + POST_SEND_DELAY);

View File

@@ -30,7 +30,7 @@ bool Test::run_test(const char * command, int8_t id) {
} }
if (strcmp(command, "general") == 0) { if (strcmp(command, "general") == 0) {
EMSESP::logger().info(F("Testing general. Adding a Boiler and Thermostat")); EMSESP::logger().info("Testing general. Adding a Boiler and Thermostat");
add_device(0x08, 123); // Nefit Trendline add_device(0x08, 123); // Nefit Trendline
add_device(0x18, 157); // Bosch CR100 add_device(0x18, 157); // Bosch CR100
@@ -54,7 +54,7 @@ bool Test::run_test(const char * command, int8_t id) {
} }
if (strcmp(command, "2thermostats") == 0) { if (strcmp(command, "2thermostats") == 0) {
EMSESP::logger().info(F("Testing with multiple thermostats...")); EMSESP::logger().info("Testing with multiple thermostats...");
add_device(0x08, 123); // GB072 add_device(0x08, 123); // GB072
add_device(0x10, 158); // RC310 add_device(0x10, 158); // RC310
@@ -86,7 +86,7 @@ bool Test::run_test(const char * command, int8_t id) {
} }
if (strcmp(command, "310") == 0) { if (strcmp(command, "310") == 0) {
EMSESP::logger().info(F("Adding a GB072/RC310 combo...")); EMSESP::logger().info("Adding a GB072/RC310 combo...");
add_device(0x08, 123); // GB072 add_device(0x08, 123); // GB072
add_device(0x10, 158); // RC310 add_device(0x10, 158); // RC310
@@ -113,7 +113,7 @@ bool Test::run_test(const char * command, int8_t id) {
} }
if (strcmp(command, "gateway") == 0) { if (strcmp(command, "gateway") == 0) {
EMSESP::logger().info(F("Adding a Gateway...")); EMSESP::logger().info("Adding a Gateway...");
// add 0x48 KM200, via a version command // add 0x48 KM200, via a version command
rx_telegram({0x48, 0x0B, 0x02, 0x00, 0xBD, 0x04, 0x06, 00, 00, 00, 00, 00, 00, 00}); rx_telegram({0x48, 0x0B, 0x02, 0x00, 0xBD, 0x04, 0x06, 00, 00, 00, 00, 00, 00, 00});
@@ -133,7 +133,7 @@ bool Test::run_test(const char * command, int8_t id) {
} }
if (strcmp(command, "mixer") == 0) { if (strcmp(command, "mixer") == 0) {
EMSESP::logger().info(F("Adding a mixer...")); EMSESP::logger().info("Adding a mixer...");
// add controller // add controller
add_device(0x09, 114); add_device(0x09, 114);
@@ -155,7 +155,7 @@ bool Test::run_test(const char * command, int8_t id) {
} }
if (strcmp(command, "boiler") == 0) { if (strcmp(command, "boiler") == 0) {
EMSESP::logger().info(F("Adding boiler...")); EMSESP::logger().info("Adding boiler...");
add_device(0x08, 123); // Nefit Trendline add_device(0x08, 123); // Nefit Trendline
// UBAuptime // UBAuptime
@@ -172,7 +172,7 @@ bool Test::run_test(const char * command, int8_t id) {
} }
if (strcmp(command, "thermostat") == 0) { if (strcmp(command, "thermostat") == 0) {
EMSESP::logger().info(F("Adding thermostat...")); EMSESP::logger().info("Adding thermostat...");
add_device(0x10, 192); // FW120 add_device(0x10, 192); // FW120
@@ -185,7 +185,7 @@ bool Test::run_test(const char * command, int8_t id) {
} }
if (strcmp(command, "solar") == 0) { if (strcmp(command, "solar") == 0) {
EMSESP::logger().info(F("Adding solar...")); EMSESP::logger().info("Adding solar...");
add_device(0x30, 163); // SM100 add_device(0x30, 163); // SM100
@@ -204,7 +204,7 @@ bool Test::run_test(const char * command, int8_t id) {
} }
if (strcmp(command, "heatpump") == 0) { if (strcmp(command, "heatpump") == 0) {
EMSESP::logger().info(F("Adding heatpump...")); EMSESP::logger().info("Adding heatpump...");
add_device(0x38, 200); // Enviline module add_device(0x38, 200); // Enviline module
add_device(0x10, 192); // FW120 thermostat add_device(0x10, 192); // FW120 thermostat
@@ -238,7 +238,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "general") { if (command == "general") {
shell.printfln(F("Testing adding a general boiler & thermostat...")); shell.printfln("Testing adding a general boiler & thermostat...");
run_test("general"); run_test("general");
shell.invoke_command("show devices"); shell.invoke_command("show devices");
shell.invoke_command("show"); shell.invoke_command("show");
@@ -247,7 +247,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "render") { if (command == "render") {
shell.printfln(F("Testing render...")); shell.printfln("Testing render...");
// check read_value to make sure it handles all the data type correctly // check read_value to make sure it handles all the data type correctly
uint8_t message_data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // message_length is 9 uint8_t message_data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // message_length is 9
@@ -315,7 +315,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "devices") { if (command == "devices") {
shell.printfln(F("Testing devices...")); shell.printfln("Testing devices...");
// A fake response - UBADevices(0x07) // A fake response - UBADevices(0x07)
rx_telegram({0x08, 0x00, 0x07, 0x00, 0x0B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); rx_telegram({0x08, 0x00, 0x07, 0x00, 0x0B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
@@ -323,7 +323,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// check for boiler and controller on same product_id // check for boiler and controller on same product_id
if (command == "double") { if (command == "double") {
shell.printfln(F("Testing double...")); shell.printfln("Testing double...");
add_device(0x08, 206); // Nefit Excellent HR30 add_device(0x08, 206); // Nefit Excellent HR30
add_device(0x09, 206); // Nefit Excellent HR30 Controller add_device(0x09, 206); // Nefit Excellent HR30 Controller
@@ -333,7 +333,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "620") { if (command == "620") {
EMSESP::logger().info(F("Testing 620...")); EMSESP::logger().info("Testing 620...");
// Version Controller // Version Controller
uart_telegram({0x09, 0x0B, 0x02, 0x00, 0x5F, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); uart_telegram({0x09, 0x0B, 0x02, 0x00, 0x5F, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
@@ -344,7 +344,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// unknown device // unknown device
if (command == "unknown") { if (command == "unknown") {
shell.printfln(F("Testing unknown...")); shell.printfln("Testing unknown...");
// add boiler // add boiler
add_device(0x08, 84); add_device(0x08, 84);
@@ -361,19 +361,19 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "unknown2") { if (command == "unknown2") {
shell.printfln(F("Testing unknown2...")); shell.printfln("Testing unknown2...");
// simulate getting version information back from an unknown device // simulate getting version information back from an unknown device
rx_telegram({0x09, 0x0B, 0x02, 0x00, 0x5A, 0x01, 0x02}); // productID is 90 which doesn't exist rx_telegram({0x09, 0x0B, 0x02, 0x00, 0x5A, 0x01, 0x02}); // productID is 90 which doesn't exist
} }
if (command == "gateway") { if (command == "gateway") {
shell.printfln(F("Testing Gateway...")); shell.printfln("Testing Gateway...");
run_test("gateway"); run_test("gateway");
} }
if (command == "310") { if (command == "310") {
shell.printfln(F("Testing RC310...")); shell.printfln("Testing RC310...");
run_test("310"); run_test("310");
shell.invoke_command("show devices"); shell.invoke_command("show devices");
shell.invoke_command("show"); shell.invoke_command("show");
@@ -382,14 +382,14 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "2thermostats") { if (command == "2thermostats") {
shell.printfln(F("Testing multiple thermostats...")); shell.printfln("Testing multiple thermostats...");
run_test("2thermostats"); run_test("2thermostats");
shell.invoke_command("show"); shell.invoke_command("show");
shell.invoke_command("show devices"); shell.invoke_command("show devices");
} }
if (command == "web") { if (command == "web") {
shell.printfln(F("Testing Web...")); shell.printfln("Testing Web...");
Mqtt::enabled(false); // turn off mqtt Mqtt::enabled(false); // turn off mqtt
Mqtt::ha_enabled(false); // turn off ha Mqtt::ha_enabled(false); // turn off ha
@@ -438,7 +438,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "board_profile") { if (command == "board_profile") {
shell.printfln(F("Testing board profile...")); shell.printfln("Testing board profile...");
shell.invoke_command("system"); shell.invoke_command("system");
shell.invoke_command("set board_profile wemos"); shell.invoke_command("set board_profile wemos");
@@ -447,7 +447,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "boiler") { if (command == "boiler") {
shell.printfln(F("Testing boiler...")); shell.printfln("Testing boiler...");
// Mqtt::ha_enabled(false); // Mqtt::ha_enabled(false);
Mqtt::ha_enabled(true); Mqtt::ha_enabled(true);
Mqtt::nested_format(1); Mqtt::nested_format(1);
@@ -475,7 +475,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "shower_alert") { if (command == "shower_alert") {
shell.printfln(F("Testing Shower Alert...")); shell.printfln("Testing Shower Alert...");
run_test("boiler"); run_test("boiler");
@@ -484,7 +484,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "fr120") { if (command == "fr120") {
shell.printfln(F("Testing adding a thermostat FR120...")); shell.printfln("Testing adding a thermostat FR120...");
add_device(0x10, 191); // FR120 thermostat add_device(0x10, 191); // FR120 thermostat
@@ -496,7 +496,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "ha") { if (command == "ha") {
shell.printfln(F("Testing HA mqtt discovery")); shell.printfln("Testing HA mqtt discovery");
Mqtt::ha_enabled(true); Mqtt::ha_enabled(true);
// Mqtt::ha_enabled(false); // Mqtt::ha_enabled(false);
@@ -518,7 +518,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "lastcode") { if (command == "lastcode") {
shell.printfln(F("Testing lastcode")); shell.printfln("Testing lastcode");
Mqtt::ha_enabled(false); Mqtt::ha_enabled(false);
Mqtt::nested_format(1); Mqtt::nested_format(1);
@@ -536,7 +536,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "dv") { if (command == "dv") {
shell.printfln(F("Testing device value rendering")); shell.printfln("Testing device value rendering");
Mqtt::ha_enabled(true); Mqtt::ha_enabled(true);
Mqtt::nested_format(1); Mqtt::nested_format(1);
@@ -550,12 +550,12 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "dallas") { if (command == "dallas") {
shell.printfln(F("Testing adding Dallas sensor")); shell.printfln("Testing adding Dallas sensor");
emsesp::EMSESP::dallassensor_.test(); emsesp::EMSESP::dallassensor_.test();
} }
if (command == "dallas_full") { if (command == "dallas_full") {
shell.printfln(F("Testing adding and changing Dallas sensor")); shell.printfln("Testing adding and changing Dallas sensor");
Mqtt::ha_enabled(true); Mqtt::ha_enabled(true);
Mqtt::nested_format(1); Mqtt::nested_format(1);
// Mqtt::nested_format(0); // Mqtt::nested_format(0);
@@ -571,7 +571,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "analog") { if (command == "analog") {
shell.printfln(F("Testing adding Analog sensor")); shell.printfln("Testing adding Analog sensor");
Mqtt::ha_enabled(true); Mqtt::ha_enabled(true);
// Mqtt::ha_enabled(false); // Mqtt::ha_enabled(false);
Mqtt::nested_format(1); Mqtt::nested_format(1);
@@ -597,12 +597,42 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// n=1 = EMSESP::system_.HEALTHCHECK_NO_BUS // n=1 = EMSESP::system_.HEALTHCHECK_NO_BUS
// n=2 = EMSESP::system_.HEALTHCHECK_NO_NETWORK // n=2 = EMSESP::system_.HEALTHCHECK_NO_NETWORK
shell.printfln(F("Testing healthcheck with %d"), n); shell.printfln("Testing healthcheck with %d", n);
EMSESP::system_.healthcheck(n); EMSESP::system_.healthcheck(n);
} }
if (command == "custom") {
shell.printfln(F("Testing custom entities"));
Mqtt::ha_enabled(true);
Mqtt::send_response(false);
run_test("thermostat");
// shell.invoke_command("call thermostat seltemp");
// shell.invoke_command("call system publish");
// toggle mode
for (const auto & emsdevice : EMSESP::emsdevices) {
Serial.print("Custom: ");
Serial.print(emsdevice->device_type_name().c_str());
Serial.print(" uniqueid=");
Serial.println(emsdevice->unique_id());
if (emsdevice->unique_id() == 1) { // thermostat
std::string a = "00hc1/seltemp|new name>5<52";
emsdevice->setCustomEntity(a);
break;
}
}
shell.invoke_command("call thermostat seltemp");
shell.invoke_command("call system publish");
}
if (command == "masked") { if (command == "masked") {
shell.printfln(F("Testing masked entities")); shell.printfln("Testing masked entities");
Mqtt::ha_enabled(true); Mqtt::ha_enabled(true);
Mqtt::send_response(false); Mqtt::send_response(false);
@@ -626,7 +656,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "dv2") { if (command == "dv2") {
shell.printfln(F("Testing device value lost")); shell.printfln("Testing device value lost");
Mqtt::ha_enabled(true); Mqtt::ha_enabled(true);
Mqtt::send_response(false); Mqtt::send_response(false);
@@ -647,7 +677,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
if (command == "api_values") { if (command == "api_values") {
#if defined(EMSESP_STANDALONE) #if defined(EMSESP_STANDALONE)
shell.printfln(F("Testing API getting values")); shell.printfln("Testing API getting values");
Mqtt::ha_enabled(false); Mqtt::ha_enabled(false);
Mqtt::nested_format(1); Mqtt::nested_format(1);
Mqtt::send_response(false); Mqtt::send_response(false);
@@ -680,7 +710,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "mqtt_post") { if (command == "mqtt_post") {
shell.printfln(F("Testing MQTT incoming changes")); shell.printfln("Testing MQTT incoming changes");
Mqtt::ha_enabled(false); Mqtt::ha_enabled(false);
Mqtt::nested_format(1); Mqtt::nested_format(1);
Mqtt::send_response(false); Mqtt::send_response(false);
@@ -696,7 +726,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
#if defined(EMSESP_STANDALONE) #if defined(EMSESP_STANDALONE)
// https://github.com/emsesp/EMS-ESP32/issues/541 // https://github.com/emsesp/EMS-ESP32/issues/541
if (command == "api_wwmode") { if (command == "api_wwmode") {
shell.printfln(F("Testing API wwmode")); shell.printfln("Testing API wwmode");
Mqtt::ha_enabled(false); Mqtt::ha_enabled(false);
Mqtt::nested_format(1); Mqtt::nested_format(1);
run_test("310"); run_test("310");
@@ -715,7 +745,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
#endif #endif
if (command == "api") { if (command == "api") {
shell.printfln(F("Testing API with MQTT and REST, standalone")); shell.printfln("Testing API with MQTT and REST, standalone");
Mqtt::ha_enabled(true); Mqtt::ha_enabled(true);
// Mqtt::ha_enabled(false); // Mqtt::ha_enabled(false);
@@ -990,7 +1020,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "mqtt_nested") { if (command == "mqtt_nested") {
shell.printfln(F("Testing nested MQTT")); shell.printfln("Testing nested MQTT");
Mqtt::ha_enabled(false); // turn off HA Discovery to stop the chatter Mqtt::ha_enabled(false); // turn off HA Discovery to stop the chatter
run_test("boiler"); run_test("boiler");
@@ -1010,7 +1040,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "thermostat") { if (command == "thermostat") {
shell.printfln(F("Testing adding a thermostat FW120...")); shell.printfln("Testing adding a thermostat FW120...");
run_test("thermostat"); run_test("thermostat");
shell.invoke_command("show"); shell.invoke_command("show");
@@ -1026,7 +1056,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "tc100") { if (command == "tc100") {
shell.printfln(F("Testing adding a TC100 thermostat to the EMS bus...")); shell.printfln("Testing adding a TC100 thermostat to the EMS bus...");
// add a thermostat // add a thermostat
add_device(0x18, 202); // Bosch TC100 - https://github.com/emsesp/EMS-ESP/issues/474 add_device(0x18, 202); // Bosch TC100 - https://github.com/emsesp/EMS-ESP/issues/474
@@ -1037,7 +1067,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "solar") { if (command == "solar") {
shell.printfln(F("Testing Solar")); shell.printfln("Testing Solar");
run_test("solar"); run_test("solar");
uart_telegram("30 00 FF 0A 02 6A 04"); // SM100 pump on (1)sh uart_telegram("30 00 FF 0A 02 6A 04"); // SM100 pump on (1)sh
@@ -1050,14 +1080,14 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "heatpump") { if (command == "heatpump") {
shell.printfln(F("Testing Heat Pump")); shell.printfln("Testing Heat Pump");
run_test("heatpump"); run_test("heatpump");
shell.invoke_command("call"); shell.invoke_command("call");
shell.invoke_command("call heatpump info"); shell.invoke_command("call heatpump info");
} }
if (command == "solar200") { if (command == "solar200") {
shell.printfln(F("Testing Solar SM200")); shell.printfln("Testing Solar SM200");
add_device(0x30, 164); // SM200 add_device(0x30, 164); // SM200
@@ -1082,7 +1112,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "km") { if (command == "km") {
shell.printfln(F("Testing KM200 Gateway")); shell.printfln("Testing KM200 Gateway");
add_device(0x10, 158); // RC300 add_device(0x10, 158); // RC300
add_device(0x48, 189); // KM200 add_device(0x48, 189); // KM200
@@ -1140,7 +1170,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "cr100") { if (command == "cr100") {
shell.printfln(F("Testing CR100")); shell.printfln("Testing CR100");
add_device(0x18, 157); // Bosch CR100 - https://github.com/emsesp/EMS-ESP/issues/355 add_device(0x18, 157); // Bosch CR100 - https://github.com/emsesp/EMS-ESP/issues/355
@@ -1165,14 +1195,14 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "rx2") { if (command == "rx2") {
shell.printfln(F("Testing Rx2...")); shell.printfln("Testing Rx2...");
for (uint8_t i = 0; i < 30; i++) { for (uint8_t i = 0; i < 30; i++) {
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00}); uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
} }
} }
if (command == "rx") { if (command == "rx") {
shell.printfln(F("Testing Rx...")); shell.printfln("Testing Rx...");
// fake telegrams. length includes CRC // fake telegrams. length includes CRC
// Boiler -> Me, UBAMonitorFast(0x18), telegram: 08 00 18 00 00 02 5A 73 3D 0A 10 65 40 02 1A 80 00 01 E1 01 76 0E 3D 48 00 C9 44 02 00 (#data=25) // Boiler -> Me, UBAMonitorFast(0x18), telegram: 08 00 18 00 00 02 5A 73 3D 0A 10 65 40 02 1A 80 00 01 E1 01 76 0E 3D 48 00 C9 44 02 00 (#data=25)
@@ -1229,7 +1259,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "tx") { if (command == "tx") {
shell.printfln(F("Testing Tx...")); shell.printfln("Testing Tx...");
// TX queue example - Me -> Thermostat, (0x91), telegram: 0B 17 91 05 44 45 46 47 (#data=4) // TX queue example - Me -> Thermostat, (0x91), telegram: 0B 17 91 05 44 45 46 47 (#data=4)
uint8_t t11[] = {0x44, 0x45, 0x46, 0x47}; uint8_t t11[] = {0x44, 0x45, 0x46, 0x47};
@@ -1266,7 +1296,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "poll") { if (command == "poll") {
shell.printfln(F("Testing Poll...")); shell.printfln("Testing Poll...");
// simulate sending a read request // simulate sending a read request
// uint8_t t16[] = {0x44, 0x45, 0x46, 0x47}; // Me -> Thermostat, (0x91), telegram: 0B 17 91 05 44 45 46 47 (#data=4) // uint8_t t16[] = {0x44, 0x45, 0x46, 0x47}; // Me -> Thermostat, (0x91), telegram: 0B 17 91 05 44 45 46 47 (#data=4)
@@ -1291,7 +1321,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "cmd") { if (command == "cmd") {
shell.printfln(F("Testing Commands...")); shell.printfln("Testing Commands...");
// add a thermostat with 3 HCs // add a thermostat with 3 HCs
add_device(0x10, 192); // FW120 add_device(0x10, 192); // FW120
@@ -1318,13 +1348,13 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "pin") { if (command == "pin") {
shell.printfln(F("Testing pin...")); shell.printfln("Testing pin...");
shell.invoke_command("call system pin"); shell.invoke_command("call system pin");
shell.invoke_command("call system pin 1 true"); shell.invoke_command("call system pin 1 true");
} }
if (command == "mqtt2") { if (command == "mqtt2") {
shell.printfln(F("Testing MQTT large payloads...")); shell.printfln("Testing MQTT large payloads...");
DynamicJsonDocument doc(EMSESP_JSON_SIZE_XXLARGE_DYN); DynamicJsonDocument doc(EMSESP_JSON_SIZE_XXLARGE_DYN);
@@ -1339,15 +1369,15 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
doc.shrinkToFit(); doc.shrinkToFit();
JsonObject jo = doc.as<JsonObject>(); JsonObject jo = doc.as<JsonObject>();
shell.printfln(F("Size of JSON payload = %d"), jo.memoryUsage()); shell.printfln("Size of JSON payload = %d", jo.memoryUsage());
shell.printfln(F("Length of JSON payload = %d"), measureJson(jo)); shell.printfln("Length of JSON payload = %d", measureJson(jo));
Mqtt::publish("test", jo); Mqtt::publish("test", jo);
Mqtt::show_mqtt(shell); // show queue Mqtt::show_mqtt(shell); // show queue
} }
if (command == "mqtt") { if (command == "mqtt") {
shell.printfln(F("Testing MQTT...")); shell.printfln("Testing MQTT...");
Mqtt::ha_enabled(false); Mqtt::ha_enabled(false);
Mqtt::enabled(true); Mqtt::enabled(true);
@@ -1422,7 +1452,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "poll2") { if (command == "poll2") {
shell.printfln(F("Testing Tx Sending last message on queue...")); shell.printfln("Testing Tx Sending last message on queue...");
EMSESP::show_ems(shell); EMSESP::show_ems(shell);
@@ -1433,7 +1463,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "rx2") { if (command == "rx2") {
shell.printfln(F("Testing rx2...")); shell.printfln("Testing rx2...");
uart_telegram({0x1B, 0x5B, 0xFD, 0x2D, 0x9E, 0x3A, 0xB6, 0xE5, 0x02, 0x20, 0x33, 0x30, 0x32, 0x3A, 0x20, 0x5B, uart_telegram({0x1B, 0x5B, 0xFD, 0x2D, 0x9E, 0x3A, 0xB6, 0xE5, 0x02, 0x20, 0x33, 0x30, 0x32, 0x3A, 0x20, 0x5B,
0x73, 0xFF, 0xFF, 0xCB, 0xDF, 0xB7, 0xA7, 0xB5, 0x67, 0x77, 0x77, 0xE4, 0xFF, 0xFD, 0x77, 0xFF}); 0x73, 0xFF, 0xFF, 0xCB, 0xDF, 0xB7, 0xA7, 0xB5, 0x67, 0x77, 0x77, 0xE4, 0xFF, 0xFD, 0x77, 0xFF});
@@ -1441,14 +1471,14 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// https://github.com/emsesp/EMS-ESP/issues/380#issuecomment-633663007 // https://github.com/emsesp/EMS-ESP/issues/380#issuecomment-633663007
if (command == "rx3") { if (command == "rx3") {
shell.printfln(F("Testing rx3...")); shell.printfln("Testing rx3...");
uart_telegram({0x21, 0x0B, 0xFF, 0x00}); uart_telegram({0x21, 0x0B, 0xFF, 0x00});
} }
// testing the UART tx command, without a queue // testing the UART tx command, without a queue
if (command == "tx2") { if (command == "tx2") {
shell.printfln(F("Testing tx2...")); shell.printfln("Testing tx2...");
uint8_t t[] = {0x0B, 0x88, 0x18, 0x00, 0x20, 0xD4}; // including CRC uint8_t t[] = {0x0B, 0x88, 0x18, 0x00, 0x20, 0xD4}; // including CRC
EMSuart::transmit(t, sizeof(t)); EMSuart::transmit(t, sizeof(t));
@@ -1456,14 +1486,14 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// send read request with offset // send read request with offset
if (command == "offset") { if (command == "offset") {
shell.printfln(F("Testing offset...")); shell.printfln("Testing offset...");
// send_read_request(0x18, 0x08); // send_read_request(0x18, 0x08);
EMSESP::txservice_.read_request(0x18, 0x08, 27); // no offset EMSESP::txservice_.read_request(0x18, 0x08, 27); // no offset
} }
if (command == "mixer") { if (command == "mixer") {
shell.printfln(F("Testing Mixer...")); shell.printfln("Testing Mixer...");
run_test("mixer"); run_test("mixer");
@@ -1477,13 +1507,13 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "crash") { if (command == "crash") {
shell.printfln(F("Forcing a crash...")); shell.printfln("Forcing a crash...");
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdiv-by-zero" #pragma GCC diagnostic ignored "-Wdiv-by-zero"
#pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-variable"
uint8_t a = 2 / 0; uint8_t a = 2 / 0;
shell.printfln(F("Testing %s"), a); shell.printfln("Testing %s", a);
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
} }

View File

@@ -31,8 +31,8 @@ namespace emsesp {
// #define EMSESP_DEBUG_DEFAULT "mixer" // #define EMSESP_DEBUG_DEFAULT "mixer"
// #define EMSESP_DEBUG_DEFAULT "web" // #define EMSESP_DEBUG_DEFAULT "web"
// #define EMSESP_DEBUG_DEFAULT "mqtt" // #define EMSESP_DEBUG_DEFAULT "mqtt"
// #define EMSESP_DEBUG_DEFAULT "general" #define EMSESP_DEBUG_DEFAULT "general"
#define EMSESP_DEBUG_DEFAULT "boiler" // #define EMSESP_DEBUG_DEFAULT "boiler"
// #define EMSESP_DEBUG_DEFAULT "mqtt2" // #define EMSESP_DEBUG_DEFAULT "mqtt2"
// #define EMSESP_DEBUG_DEFAULT "mqtt_nested" // #define EMSESP_DEBUG_DEFAULT "mqtt_nested"
// #define EMSESP_DEBUG_DEFAULT "ha" // #define EMSESP_DEBUG_DEFAULT "ha"
@@ -51,6 +51,7 @@ namespace emsesp {
// #define EMSESP_DEBUG_DEFAULT "api_values" // #define EMSESP_DEBUG_DEFAULT "api_values"
// #define EMSESP_DEBUG_DEFAULT "mqtt_post" // #define EMSESP_DEBUG_DEFAULT "mqtt_post"
// #define EMSESP_DEBUG_DEFAULT "api_wwmode" // #define EMSESP_DEBUG_DEFAULT "api_wwmode"
// #define EMSESP_DEBUG_DEFAULT "custom"
class Test { class Test {
public: public:

View File

@@ -27,7 +27,7 @@
#define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus extra for BRK #define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus extra for BRK
#if (defined(ARDUINO_LOLIN_C3_MINI)) || (defined(ARDUINO_LOLIN_S2_MINI)) #if (defined(ARDUINO_LOLIN_C3_MINI)) || (defined(ARDUINO_LOLIN_S2_MINI))
#define EMSUART_NUM UART_NUM_1 // on C3 mini we're using UART1 #define EMSUART_NUM UART_NUM_1 // on C3 and S2 we're using UART1
#else #else
#define EMSUART_NUM UART_NUM_2 // on the ESP32 we're using UART2 #define EMSUART_NUM UART_NUM_2 // on the ESP32 we're using UART2
#endif #endif

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