diff --git a/.github/workflows/pre_release.yml b/.github/workflows/pre_release.yml index 852e95909..11a8a07df 100644 --- a/.github/workflows/pre_release.yml +++ b/.github/workflows/pre_release.yml @@ -31,7 +31,7 @@ jobs: python -m pip install --upgrade pip pip install -U platformio platformio upgrade - platformio update + pio pkg update - name: Build WebUI run: | diff --git a/.github/workflows/tagged_release.yml b/.github/workflows/tagged_release.yml index f9169eac9..bdb623b8a 100644 --- a/.github/workflows/tagged_release.yml +++ b/.github/workflows/tagged_release.yml @@ -24,7 +24,7 @@ jobs: python -m pip install --upgrade pip pip install -U platformio platformio upgrade - platformio update + pio pkg update - name: Build WebUI run: | diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 0a7f332e7..731ba3454 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -1,5 +1,21 @@ # Changelog +# [3.5.0] + +## Added + +- Translations in Web UI and all device entity names to German. [#22](https://github.com/emsesp/EMS-ESP32/issues/22) + +## Fixed + +## Changed + +- Discovery in HomeAssistant don't work with custom base topic. [#596](https://github.com/emsesp/EMS-ESP32/issues/596) + +## **BREAKING CHANGES:** + +- MQTT Discovery (Home Assistant) entity names are now prefixed with the hostname, e.g. `select.thermostat_hc1_mode` becomes `select.emsesp_thermostat_hc1_mode`. You will need to recreate any custom dashboards. + # [3.4.2] ## Added diff --git a/esp32_partition_16M.csv b/esp32_partition_16M.csv new file mode 100644 index 000000000..014e72909 --- /dev/null +++ b/esp32_partition_16M.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, , 0x2000, +app0, app, ota_0, , 0x7F0000, +app1, app, ota_1, , 0x7F0000, +spiffs, data, spiffs, , 64K, \ No newline at end of file diff --git a/esp32_partition_4M.csv b/esp32_partition_4M.csv new file mode 100644 index 000000000..aa1a70df5 --- /dev/null +++ b/esp32_partition_4M.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, , 0x2000, +app0, app, ota_0, , 0x1F0000, +app1, app, ota_1, , 0x1F0000, +spiffs, data, spiffs, , 64K, \ No newline at end of file diff --git a/esp32_partition_app1984k_spiffs64k.csv b/esp32_partition_app1984k_spiffs64k.csv deleted file mode 100644 index 7eaebdbc1..000000000 --- a/esp32_partition_app1984k_spiffs64k.csv +++ /dev/null @@ -1,6 +0,0 @@ -# Name, Type, SubType, Offset, Size, Flags -nvs, data, nvs, 0x9000, 0x5000, -otadata, data, ota, 0xE000, 0x2000, -app0, app, ota_0, 0x10000, 0x1F0000, -app1, app, ota_1, 0x200000, 0x1F0000, -spiffs, data, spiffs, 0x3F0000, 0x10000, diff --git a/interface/.typesafe-i18n.json b/interface/.typesafe-i18n.json new file mode 100644 index 000000000..cfee40f06 --- /dev/null +++ b/interface/.typesafe-i18n.json @@ -0,0 +1,5 @@ +{ + "adapter": "react", + "baseLocale": "en", + "$schema": "https://unpkg.com/typesafe-i18n@5.13.0/schema/typesafe-i18n.json" +} \ No newline at end of file diff --git a/interface/package-lock.json b/interface/package-lock.json index fc559a3d1..0615193f8 100644 --- a/interface/package-lock.json +++ b/interface/package-lock.json @@ -1,12 +1,12 @@ { "name": "EMS-ESP", - "version": "3.4.0", + "version": "3.5.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "EMS-ESP", - "version": "3.4.0", + "version": "3.5.0", "dependencies": { "@emotion/react": "^11.10.4", "@emotion/styled": "^11.10.4", @@ -34,6 +34,7 @@ "react-router-dom": "^6.4.0", "react-scripts": "5.0.1", "sockette": "^2.0.6", + "typesafe-i18n": "^5.13.0", "typescript": "^4.8.3" }, "devDependencies": { @@ -65,27 +66,27 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.0.tgz", - "integrity": "sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.1.tgz", + "integrity": "sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz", - "integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.1.tgz", + "integrity": "sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==", "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.0", + "@babel/helper-compilation-targets": "^7.19.1", "@babel/helper-module-transforms": "^7.19.0", "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.0", + "@babel/parser": "^7.19.1", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", + "@babel/traverse": "^7.19.1", "@babel/types": "^7.19.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", @@ -102,11 +103,11 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.18.9.tgz", - "integrity": "sha512-KzSGpMBggz4fKbRbWLNyPVTuQr6cmCcBhOyXTw/fieOVaw5oYAwcAj4a7UKcDYCPxQq+CG1NCDZH9e2JTXquiQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", + "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", "dependencies": { - "eslint-scope": "^5.1.1", + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", "semver": "^6.3.0" }, @@ -118,18 +119,6 @@ "eslint": "^7.5.0 || ^8.0.0" } }, - "node_modules/@babel/eslint-parser/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", @@ -138,14 +127,6 @@ "node": ">=10" } }, - "node_modules/@babel/eslint-parser/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, "node_modules/@babel/generator": { "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", @@ -196,13 +177,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz", - "integrity": "sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz", + "integrity": "sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==", "dependencies": { - "@babel/compat-data": "^7.19.0", + "@babel/compat-data": "^7.19.1", "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", + "browserslist": "^4.21.3", "semver": "^6.3.0" }, "engines": { @@ -248,9 +229,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.2.tgz", - "integrity": "sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", "dependencies": { "@babel/helper-compilation-targets": "^7.17.7", "@babel/helper-plugin-utils": "^7.16.7", @@ -382,15 +363,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.9.tgz", - "integrity": "sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-member-expression-to-functions": "^7.18.9", "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9" + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -438,9 +419,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "engines": { "node": ">=6.9.0" } @@ -494,9 +475,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.0.tgz", - "integrity": "sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.1.tgz", + "integrity": "sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==", "bin": { "parser": "bin/babel-parser.js" }, @@ -535,9 +516,9 @@ } }, "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.0.tgz", - "integrity": "sha512-nhEByMUTx3uZueJ/QkJuSlCfN4FGg+xy+vRsfGQGzSauq5ks2Deid2+05Q3KhfaUjvec1IGhw/Zm3cFm8JigTQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz", + "integrity": "sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==", "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-plugin-utils": "^7.19.0", @@ -583,13 +564,13 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.19.0.tgz", - "integrity": "sha512-Bo5nOSjiJccjv00+BrDkmfeBLBi2B0qe8ygj24KdL8VdwtZz+710NCwehF+x/Ng+0mkHx5za2eAofmvVFLF4Fg==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.19.1.tgz", + "integrity": "sha512-LfIKNBBY7Q1OX5C4xAgRQffOg2OnhAo9fnbcOHgOC9Yytm2Sw+4XqHufRYU86tHomzepxtvuVaNO+3EVKR4ivw==", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.19.0", "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-replace-supers": "^7.19.1", "@babel/helper-split-export-declaration": "^7.18.6", "@babel/plugin-syntax-decorators": "^7.19.0" }, @@ -1333,9 +1314,9 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.0.tgz", - "integrity": "sha512-HDSuqOQzkU//kfGdiHBt71/hkDTApw4U/cMVgKgX7PqfB3LOaK+2GtCEsBu1dL9CkswDm0Gwehht1dCr421ULQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.19.0", "@babel/helper-plugin-utils": "^7.19.0" @@ -1509,15 +1490,15 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.10.tgz", - "integrity": "sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.1.tgz", + "integrity": "sha512-2nJjTUFIzBMP/f/miLxEK9vxwW/KUXsdvN4sR//TmuDhe6yU2h57WmIOE12Gng3MDP/xpjUV/ToZRdcf8Yj4fA==", "dependencies": { "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.9", - "babel-plugin-polyfill-corejs2": "^0.3.2", - "babel-plugin-polyfill-corejs3": "^0.5.3", - "babel-plugin-polyfill-regenerator": "^0.4.0", + "@babel/helper-plugin-utils": "^7.19.0", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", "semver": "^6.3.0" }, "engines": { @@ -1599,9 +1580,9 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.19.0.tgz", - "integrity": "sha512-DOOIywxPpkQHXijXv+s9MDAyZcLp12oYRl3CMWZ6u7TjSoCBq/KqHR/nNFR3+i2xqheZxoF0H2XyL7B6xeSRuA==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.19.1.tgz", + "integrity": "sha512-+ILcOU+6mWLlvCwnL920m2Ow3wWx3Wo8n2t5aROQmV55GZt+hOiLvBaa3DNzRjSEHa1aauRs4/YLmkCfFkhhRQ==", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.19.0", "@babel/helper-plugin-utils": "^7.19.0", @@ -1644,17 +1625,17 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.0.tgz", - "integrity": "sha512-1YUju1TAFuzjIQqNM9WsF4U6VbD/8t3wEAlw3LFYuuEr+ywqLRcSXxFKz4DCEj+sN94l/XTDiUXYRrsvMpz9WQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.1.tgz", + "integrity": "sha512-c8B2c6D16Lp+Nt6HcD+nHl0VbPKVnNPTpszahuxJJnurfMtKeZ80A+qUv48Y7wqvS+dTFuLuaM9oYxyNHbCLWA==", "dependencies": { - "@babel/compat-data": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.0", + "@babel/compat-data": "^7.19.1", + "@babel/helper-compilation-targets": "^7.19.1", "@babel/helper-plugin-utils": "^7.19.0", "@babel/helper-validator-option": "^7.18.6", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-async-generator-functions": "^7.19.0", + "@babel/plugin-proposal-async-generator-functions": "^7.19.1", "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-proposal-class-static-block": "^7.18.6", "@babel/plugin-proposal-dynamic-import": "^7.18.6", @@ -1702,7 +1683,7 @@ "@babel/plugin-transform-modules-commonjs": "^7.18.6", "@babel/plugin-transform-modules-systemjs": "^7.19.0", "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", "@babel/plugin-transform-new-target": "^7.18.6", "@babel/plugin-transform-object-super": "^7.18.6", "@babel/plugin-transform-parameters": "^7.18.8", @@ -1718,10 +1699,10 @@ "@babel/plugin-transform-unicode-regex": "^7.18.6", "@babel/preset-modules": "^0.1.5", "@babel/types": "^7.19.0", - "babel-plugin-polyfill-corejs2": "^0.3.2", - "babel-plugin-polyfill-corejs3": "^0.5.3", - "babel-plugin-polyfill-regenerator": "^0.4.0", - "core-js-compat": "^3.22.1", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", "semver": "^6.3.0" }, "engines": { @@ -1793,11 +1774,11 @@ } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.0.tgz", - "integrity": "sha512-JyXXoCu1N8GLuKc2ii8y5RGma5FMpFeO2nAQIe0Yzrbq+rQnN+sFj47auLblR5ka6aHNGPDgv8G/iI2Grb0ldQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz", + "integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==", "dependencies": { - "core-js-pure": "^3.20.2", + "core-js-pure": "^3.25.1", "regenerator-runtime": "^0.13.4" }, "engines": { @@ -1818,9 +1799,9 @@ } }, "node_modules/@babel/traverse": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.0.tgz", - "integrity": "sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.1.tgz", + "integrity": "sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==", "dependencies": { "@babel/code-frame": "^7.18.6", "@babel/generator": "^7.19.0", @@ -1828,7 +1809,7 @@ "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.0", + "@babel/parser": "^7.19.1", "@babel/types": "^7.19.0", "debug": "^4.1.0", "globals": "^11.1.0" @@ -1861,9 +1842,9 @@ "integrity": "sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg==" }, "node_modules/@csstools/postcss-cascade-layers": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.0.6.tgz", - "integrity": "sha512-ei4Vh4AJwTCXTNj7uzwduoZDO7nLPksQ0TI7OzUlyFq4P4Uhu6hU7R4AlLimDP/s6D3PQdHmRL4f7UOy370UHA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", "dependencies": { "@csstools/selector-specificity": "^2.0.2", "postcss-selector-parser": "^6.0.10" @@ -2272,9 +2253,9 @@ "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" }, "node_modules/@eslint/eslintrc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.1.tgz", - "integrity": "sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", + "integrity": "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -3362,6 +3343,34 @@ "react": "^17.0.0 || ^18.0.0" } }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3543,14 +3552,14 @@ "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" }, "node_modules/@rushstack/eslint-patch": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.4.tgz", - "integrity": "sha512-LwzQKA4vzIct1zNZzBmRKI9QuNpLgTQMEjsQLf3BXuGYb3QPTP4Yjf6mkdX+X1mYttZ808QpOwAzZjv28kq7DA==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", + "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==" }, "node_modules/@sinclair/typebox": { - "version": "0.24.39", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.39.tgz", - "integrity": "sha512-GqtkxoAjhTzoMwFg/JYRl+1+miOoyvp6mkLpbMSd2fIQak2KvY00ndlXxxkDBpuCPYkorZeEZf0LEQn9V9NRVQ==" + "version": "0.24.42", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.42.tgz", + "integrity": "sha512-d+2AtrHGyWek2u2ITF0lHRIv6Tt7X0dEHW+0rP+5aDCEjC3fiN2RBjrLD0yU0at52BcZbRGxLbAtXiR0hFCjYw==" }, "node_modules/@sinonjs/commons": { "version": "1.8.3", @@ -3932,9 +3941,9 @@ "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==" }, "node_modules/@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", + "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.18", @@ -3943,9 +3952,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.30", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz", - "integrity": "sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ==", + "version": "4.17.31", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", + "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -4081,9 +4090,9 @@ } }, "node_modules/@types/react-router": { - "version": "5.1.18", - "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.18.tgz", - "integrity": "sha512-YYknwy0D0iOwKQgz9v8nOzt2J6l4gouBmDnWqUUznltOTaon+r8US8ky8HvN0tXvc38U9m6z/t2RsVsnd1zM0g==", + "version": "5.1.19", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.19.tgz", + "integrity": "sha512-Fv/5kb2STAEMT3wHzdKQK2z8xKq38EDIGVrutYLmQVVLe+4orDFquU52hQrULnEHinMKv9FSA6lf9+uNT1ITtA==", "dependencies": { "@types/history": "^4.7.11", "@types/react": "*" @@ -4182,13 +4191,13 @@ "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.36.2.tgz", - "integrity": "sha512-OwwR8LRwSnI98tdc2z7mJYgY60gf7I9ZfGjN5EjCwwns9bdTuQfAXcsjSB2wSQ/TVNYSGKf4kzVXbNGaZvwiXw==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.37.0.tgz", + "integrity": "sha512-Fde6W0IafXktz1UlnhGkrrmnnGpAo1kyX7dnyHHVrmwJOn72Oqm3eYtddrpOwwel2W8PAK9F3pIL5S+lfoM0og==", "dependencies": { - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/type-utils": "5.36.2", - "@typescript-eslint/utils": "5.36.2", + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/type-utils": "5.37.0", + "@typescript-eslint/utils": "5.37.0", "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", @@ -4228,11 +4237,11 @@ } }, "node_modules/@typescript-eslint/experimental-utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.36.2.tgz", - "integrity": "sha512-JtRmWb31KQoxGV6CHz8cI+9ki6cC7ciZepXYpCLxsdAtQlBrRBxh5Qpe/ZHyJFOT9j7gyXE+W0shWzRLPfuAFQ==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.37.0.tgz", + "integrity": "sha512-mmzzOOK2YpwSgzhXpeSAtAlxBZVLGuq8OdvrfzibR4jfTTrTd3AjCy17M2dUKVFNsrNfLM0nWsxMsJz0kiYHqw==", "dependencies": { - "@typescript-eslint/utils": "5.36.2" + "@typescript-eslint/utils": "5.37.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -4246,13 +4255,13 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.36.2.tgz", - "integrity": "sha512-qS/Kb0yzy8sR0idFspI9Z6+t7mqk/oRjnAYfewG+VN73opAUvmYL3oPIMmgOX6CnQS6gmVIXGshlb5RY/R22pA==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.37.0.tgz", + "integrity": "sha512-01VzI/ipYKuaG5PkE5+qyJ6m02fVALmMPY3Qq5BHflDx3y4VobbLdHQkSMg9VPRS4KdNt4oYTMaomFoHonBGAw==", "dependencies": { - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/typescript-estree": "5.36.2", + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/typescript-estree": "5.37.0", "debug": "^4.3.4" }, "engines": { @@ -4272,12 +4281,12 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.36.2.tgz", - "integrity": "sha512-cNNP51L8SkIFSfce8B1NSUBTJTu2Ts4nWeWbFrdaqjmn9yKrAaJUBHkyTZc0cL06OFHpb+JZq5AUHROS398Orw==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.37.0.tgz", + "integrity": "sha512-F67MqrmSXGd/eZnujjtkPgBQzgespu/iCZ+54Ok9X5tALb9L2v3G+QBSoWkXG0p3lcTJsL+iXz5eLUEdSiJU9Q==", "dependencies": { - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/visitor-keys": "5.36.2" + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/visitor-keys": "5.37.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -4288,12 +4297,12 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.36.2.tgz", - "integrity": "sha512-rPQtS5rfijUWLouhy6UmyNquKDPhQjKsaKH0WnY6hl/07lasj8gPaH2UD8xWkePn6SC+jW2i9c2DZVDnL+Dokw==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.37.0.tgz", + "integrity": "sha512-BSx/O0Z0SXOF5tY0bNTBcDEKz2Ec20GVYvq/H/XNKiUorUFilH7NPbFUuiiyzWaSdN3PA8JV0OvYx0gH/5aFAQ==", "dependencies": { - "@typescript-eslint/typescript-estree": "5.36.2", - "@typescript-eslint/utils": "5.36.2", + "@typescript-eslint/typescript-estree": "5.37.0", + "@typescript-eslint/utils": "5.37.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -4314,9 +4323,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.36.2.tgz", - "integrity": "sha512-9OJSvvwuF1L5eS2EQgFUbECb99F0mwq501w0H0EkYULkhFa19Qq7WFbycdw1PexAc929asupbZcgjVIe6OK/XQ==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.37.0.tgz", + "integrity": "sha512-3frIJiTa5+tCb2iqR/bf7XwU20lnU05r/sgPJnRpwvfZaqCJBrl8Q/mw9vr3NrNdB/XtVyMA0eppRMMBqdJ1bA==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -4326,12 +4335,12 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.36.2.tgz", - "integrity": "sha512-8fyH+RfbKc0mTspfuEjlfqA4YywcwQK2Amcf6TDOwaRLg7Vwdu4bZzyvBZp4bjt1RRjQ5MDnOZahxMrt2l5v9w==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.37.0.tgz", + "integrity": "sha512-JkFoFIt/cx59iqEDSgIGnQpCTRv96MQnXCYvJi7QhBC24uyuzbD8wVbajMB1b9x4I0octYFJ3OwjAwNqk1AjDA==", "dependencies": { - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/visitor-keys": "5.36.2", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/visitor-keys": "5.37.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4366,14 +4375,14 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.36.2.tgz", - "integrity": "sha512-uNcopWonEITX96v9pefk9DC1bWMdkweeSsewJ6GeC7L6j2t0SJywisgkr9wUTtXk90fi2Eljj90HSHm3OGdGRg==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.37.0.tgz", + "integrity": "sha512-jUEJoQrWbZhmikbcWSMDuUSxEE7ID2W/QCV/uz10WtQqfOuKZUqFGjqLJ+qhDd17rjgp+QJPqTdPIBWwoob2NQ==", "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/typescript-estree": "5.36.2", + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/typescript-estree": "5.37.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, @@ -4409,11 +4418,11 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.36.2.tgz", - "integrity": "sha512-BtRvSR6dEdrNt7Net2/XDjbYKU5Ml6GqJgVfXT0CxTCJlnIqK7rAGreuWKMT2t8cFUT2Msv5oxw0GMRD7T5J7A==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.37.0.tgz", + "integrity": "sha512-Hp7rT4cENBPIzMwrlehLW/28EVCOcE9U1Z1BQTc8EA8v5qpr7GRGuG+U58V5tTY48zvUOA3KHvw3rA8tY9fbdA==", "dependencies": { - "@typescript-eslint/types": "5.36.2", + "@typescript-eslint/types": "5.37.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -4665,9 +4674,9 @@ } }, "node_modules/address": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/address/-/address-1.2.0.tgz", - "integrity": "sha512-tNEZYz5G/zYunxFm7sfhAxkXEuLj3K6BKwv6ZURlsF6yiUQ65z0Q2wZW9L5cPUl9ocofGvXOdFYbFHp0+6MOig==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.1.tgz", + "integrity": "sha512-B+6bi5D34+fDYENiH5qOlA0cV2rAGKuWZ9LeyUUehbXy8e0VS9e498yO0Jeeh+iM+6KbfudHTFjXw2MmJD4QRA==", "engines": { "node": ">= 10.0.0" } @@ -4960,9 +4969,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.8", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.8.tgz", - "integrity": "sha512-75Jr6Q/XpTqEf6D2ltS5uMewJIx5irCU1oBYJrWjFenq/m12WRRrz6g15L1EIoYvPLXTbEry7rDOwrcYNj77xw==", + "version": "10.4.11", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.11.tgz", + "integrity": "sha512-5lHp6DgRodxlBLSkzHOTcufWFflH1ewfy2hvFQyjrblBFlP/0Yh4O/Wrg4ow8WRlN3AAUFFLAQwX8hTptzqVHg==", "funding": [ { "type": "opencollective", @@ -4975,7 +4984,7 @@ ], "dependencies": { "browserslist": "^4.21.3", - "caniuse-lite": "^1.0.30001373", + "caniuse-lite": "^1.0.30001399", "fraction.js": "^4.2.0", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", @@ -5193,12 +5202,12 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.2.tgz", - "integrity": "sha512-LPnodUl3lS0/4wN3Rb+m+UK8s7lj2jcLRrjho4gLw+OJs+I4bvGXshINesY5xx/apM+biTnQ9reDI8yj+0M5+Q==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", "dependencies": { "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.2", + "@babel/helper-define-polyfill-provider": "^0.3.3", "semver": "^6.1.1" }, "peerDependencies": { @@ -5206,23 +5215,23 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", - "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.2", - "core-js-compat": "^3.21.0" + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.0.tgz", - "integrity": "sha512-RW1cnryiADFeHmfLS+WW/G431p1PsW5qdRdz0SDRi7TKcUgc7Oh/uXkT7MZ/+tGsT1BkczEAmD5XjUyJ5SWDTw==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.2" + "@babel/helper-define-polyfill-provider": "^0.3.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -5435,9 +5444,9 @@ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" }, "node_modules/browserslist": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", - "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", "funding": [ { "type": "opencollective", @@ -5449,10 +5458,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001370", - "electron-to-chromium": "^1.4.202", + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.5" + "update-browserslist-db": "^1.0.9" }, "bin": { "browserslist": "cli.js" @@ -5553,9 +5562,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001393", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001393.tgz", - "integrity": "sha512-N/od11RX+Gsk+1qY/jbPa0R6zJupEa0lxeBG598EbrtblxVCTJsQwbRBm6+V+rxpc5lHKdsXb9RY83cZIPLseA==", + "version": "1.0.30001402", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001402.tgz", + "integrity": "sha512-Mx4MlhXO5NwuvXGgVb+hg65HZ+bhUYsz8QtDGDo2QmaJS2GBX47Xfi2koL86lc8K+l+htXeTEB/Aeqvezoo6Ew==", "funding": [ { "type": "opencollective", @@ -5644,9 +5653,9 @@ } }, "node_modules/ci-info": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", - "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==" + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.4.0.tgz", + "integrity": "sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==" }, "node_modules/cjs-module-lexer": { "version": "1.2.2", @@ -6374,9 +6383,9 @@ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" }, "node_modules/csstype": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", - "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -6413,9 +6422,9 @@ } }, "node_modules/decimal.js": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.0.tgz", - "integrity": "sha512-Nv6ENEzyPQ6AItkGwLE2PGKinZZ9g59vSh2BeH6NqPu0OTKZ5ruJsVqh/orbAnqXc9pBbgXAIrc2EyaCj8NpGg==" + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.1.tgz", + "integrity": "sha512-F29o+vci4DodHYT9UrR5IEbfBw9pE5eSapIJdTqXK5+6hq+t8VRxwQyKlW2i+KDKFkkJQRvFyI/QXD83h8LyQw==" }, "node_modules/dedent": { "version": "0.7.0", @@ -6747,9 +6756,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.246", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.246.tgz", - "integrity": "sha512-/wFCHUE+Hocqr/LlVGsuKLIw4P2lBWwFIDcNMDpJGzyIysQV4aycpoOitAs32FT94EHKnNqDR/CVZJFbXEufJA==" + "version": "1.4.254", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.254.tgz", + "integrity": "sha512-Sh/7YsHqQYkA6ZHuHMy24e6TE4eX6KZVsZb9E/DvU1nQRIrH4BflO/4k+83tfdYvDl+MObvlqHPRICzEdC9c6Q==" }, "node_modules/emittery": { "version": "0.8.1", @@ -6991,11 +7000,11 @@ } }, "node_modules/eslint": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.0.tgz", - "integrity": "sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==", + "version": "8.23.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.1.tgz", + "integrity": "sha512-w7C1IXCc6fNqjpuYd0yPlcTKKmHlHHktRkzmBPZ+7cvNBQuiNjx0xaMTjAJGCafJhQkrFJooREv0CtrVzmHwqg==", "dependencies": { - "@eslint/eslintrc": "^1.3.1", + "@eslint/eslintrc": "^1.3.2", "@humanwhocodes/config-array": "^0.10.4", "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", "@humanwhocodes/module-importer": "^1.0.1", @@ -7014,7 +7023,6 @@ "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", "globals": "^13.15.0", "globby": "^11.1.0", @@ -7023,6 +7031,7 @@ "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -7295,9 +7304,9 @@ } }, "node_modules/eslint-plugin-testing-library": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.6.3.tgz", - "integrity": "sha512-//fhmCzopr8UDv5X2M3XMGxQ0j6KjKYZ+6PGqdV0woLiXTSTOAzuNsiTELGv883iCeUrYrnHhtObPXyiTMytVQ==", + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.6.4.tgz", + "integrity": "sha512-0oW3tC5NNT2WexmJ3848a/utawOymw4ibl3/NkwywndVAz2hT9+ab70imA7ccg3RaScQgMvJT60OL00hpmJvrg==", "dependencies": { "@typescript-eslint/utils": "^5.13.0" }, @@ -8127,9 +8136,9 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" }, "node_modules/follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", "funding": [ { "type": "individual", @@ -8444,9 +8453,9 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -9106,9 +9115,9 @@ } }, "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.6.tgz", + "integrity": "sha512-krO72EO2NptOGAX2KYyqbP9vYMlNAXdB53rq6f8LXY6RY7JdSR/3BD6wLUlPHSAesmY9vstNrjvqGaCiRK/91Q==", "engines": { "node": ">= 0.4" }, @@ -11425,6 +11434,11 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/js-sdsl": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", + "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -13027,9 +13041,9 @@ } }, "node_modules/postcss-custom-properties": { - "version": "12.1.8", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.8.tgz", - "integrity": "sha512-8rbj8kVu00RQh2fQF81oBqtduiANu4MIxhyf0HbbStgPtnFlWn0yiaYTpLHrPnJbffVY1s9apWsIoVZcc68FxA==", + "version": "12.1.9", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.9.tgz", + "integrity": "sha512-/E7PRvK8DAVljBbeWrcEQJPG72jaImxF3vvCNFwv9cC8CzigVoNIpeyfnJzphnN3Fd8/auBf5wvkw6W9MfmTyg==", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -13041,7 +13055,7 @@ "url": "https://opencollective.com/csstools" }, "peerDependencies": { - "postcss": "^8.4" + "postcss": "^8.2" } }, "node_modules/postcss-custom-selectors": { @@ -13546,9 +13560,9 @@ } }, "node_modules/postcss-nesting": { - "version": "10.1.10", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.1.10.tgz", - "integrity": "sha512-lqd7LXCq0gWc0wKXtoKDru5wEUNjm3OryLVNRZ8OnW8km6fSNUuFrjEhU3nklxXE2jvd4qrox566acgh+xQt8w==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", "dependencies": { "@csstools/selector-specificity": "^2.0.0", "postcss-selector-parser": "^6.0.10" @@ -13784,11 +13798,11 @@ } }, "node_modules/postcss-preset-env": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.1.tgz", - "integrity": "sha512-8884CHxQaoN1i4iEK+JvzOe8emODb5R4p/0dw4yEdo7QM4RdUk2sBx0fnzFyJt8BLfZSCGeVkKZ4HC564waBpQ==", + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.2.tgz", + "integrity": "sha512-rSMUEaOCnovKnwc5LvBDHUDzpGP+nrUeWZGWt9M72fBvckCi45JmnJigUr4QG4zZeOHmOCNCZnd2LKDvP++ZuQ==", "dependencies": { - "@csstools/postcss-cascade-layers": "^1.0.6", + "@csstools/postcss-cascade-layers": "^1.1.0", "@csstools/postcss-color-function": "^1.1.1", "@csstools/postcss-font-format-keywords": "^1.0.1", "@csstools/postcss-hwb-function": "^1.0.2", @@ -13802,7 +13816,7 @@ "@csstools/postcss-text-decoration-shorthand": "^1.0.0", "@csstools/postcss-trigonometric-functions": "^1.0.2", "@csstools/postcss-unset-value": "^1.0.2", - "autoprefixer": "^10.4.8", + "autoprefixer": "^10.4.11", "browserslist": "^4.21.3", "css-blank-pseudo": "^3.0.3", "css-has-pseudo": "^3.0.4", @@ -13814,7 +13828,7 @@ "postcss-color-hex-alpha": "^8.0.4", "postcss-color-rebeccapurple": "^7.1.1", "postcss-custom-media": "^8.0.2", - "postcss-custom-properties": "^12.1.8", + "postcss-custom-properties": "^12.1.9", "postcss-custom-selectors": "^6.0.3", "postcss-dir-pseudo-class": "^6.0.5", "postcss-double-position-gradients": "^3.1.2", @@ -13828,7 +13842,7 @@ "postcss-lab-function": "^4.2.1", "postcss-logical": "^5.0.4", "postcss-media-minmax": "^5.0.0", - "postcss-nesting": "^10.1.10", + "postcss-nesting": "^10.2.0", "postcss-opacity-percentage": "^1.1.2", "postcss-overflow-shorthand": "^3.0.4", "postcss-page-break": "^3.0.4", @@ -14775,9 +14789,9 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "node_modules/regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", "dependencies": { "regenerate": "^1.4.2" }, @@ -14831,14 +14845,14 @@ } }, "node_modules/regexpu-core": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.1.0.tgz", - "integrity": "sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", + "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", "dependencies": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.0.0" }, @@ -14847,14 +14861,14 @@ } }, "node_modules/regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==" }, "node_modules/regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "dependencies": { "jsesc": "~0.5.0" }, @@ -16396,6 +16410,21 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typesafe-i18n": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/typesafe-i18n/-/typesafe-i18n-5.13.0.tgz", + "integrity": "sha512-Q72l+LqB37kNT2R39mkTwQy1tuQ7URAahD1QXbR84itO864xvVgdoS8xaRAatp0y2/oU7f+2EzpAK3YGp0g+eA==", + "bin": { + "typesafe-i18n": "cli/typesafe-i18n.mjs" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ivanhofer" + }, + "peerDependencies": { + "typescript": ">=3.5.1" + } + }, "node_modules/typescript": { "version": "4.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", @@ -16457,9 +16486,9 @@ } }, "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "engines": { "node": ">=4" } @@ -16506,9 +16535,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.7.tgz", - "integrity": "sha512-iN/XYesmZ2RmmWAiI4Z5rq0YqSiv0brj9Ce9CfhNE4xIW2h+MFxcgkxIzZ+ShkFPUkjU3gQ+3oypadD3RAMtrg==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", + "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", "funding": [ { "type": "opencollective", @@ -17557,24 +17586,24 @@ } }, "@babel/compat-data": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.0.tgz", - "integrity": "sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==" + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.1.tgz", + "integrity": "sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==" }, "@babel/core": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz", - "integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.1.tgz", + "integrity": "sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==", "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.0", + "@babel/helper-compilation-targets": "^7.19.1", "@babel/helper-module-transforms": "^7.19.0", "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.0", + "@babel/parser": "^7.19.1", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", + "@babel/traverse": "^7.19.1", "@babel/types": "^7.19.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", @@ -17584,33 +17613,19 @@ } }, "@babel/eslint-parser": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.18.9.tgz", - "integrity": "sha512-KzSGpMBggz4fKbRbWLNyPVTuQr6cmCcBhOyXTw/fieOVaw5oYAwcAj4a7UKcDYCPxQq+CG1NCDZH9e2JTXquiQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", + "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", "requires": { - "eslint-scope": "^5.1.1", + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", "semver": "^6.3.0" }, "dependencies": { - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, "eslint-visitor-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" } } }, @@ -17654,13 +17669,13 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz", - "integrity": "sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz", + "integrity": "sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==", "requires": { - "@babel/compat-data": "^7.19.0", + "@babel/compat-data": "^7.19.1", "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", + "browserslist": "^4.21.3", "semver": "^6.3.0" } }, @@ -17688,9 +17703,9 @@ } }, "@babel/helper-define-polyfill-provider": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.2.tgz", - "integrity": "sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", "requires": { "@babel/helper-compilation-targets": "^7.17.7", "@babel/helper-plugin-utils": "^7.16.7", @@ -17786,15 +17801,15 @@ } }, "@babel/helper-replace-supers": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.9.tgz", - "integrity": "sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", "requires": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-member-expression-to-functions": "^7.18.9", "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9" + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" } }, "@babel/helper-simple-access": { @@ -17827,9 +17842,9 @@ "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==" }, "@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" }, "@babel/helper-validator-option": { "version": "7.18.6", @@ -17868,9 +17883,9 @@ } }, "@babel/parser": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.0.tgz", - "integrity": "sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==" + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.1.tgz", + "integrity": "sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.18.6", @@ -17891,9 +17906,9 @@ } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.0.tgz", - "integrity": "sha512-nhEByMUTx3uZueJ/QkJuSlCfN4FGg+xy+vRsfGQGzSauq5ks2Deid2+05Q3KhfaUjvec1IGhw/Zm3cFm8JigTQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz", + "integrity": "sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==", "requires": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-plugin-utils": "^7.19.0", @@ -17921,13 +17936,13 @@ } }, "@babel/plugin-proposal-decorators": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.19.0.tgz", - "integrity": "sha512-Bo5nOSjiJccjv00+BrDkmfeBLBi2B0qe8ygj24KdL8VdwtZz+710NCwehF+x/Ng+0mkHx5za2eAofmvVFLF4Fg==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.19.1.tgz", + "integrity": "sha512-LfIKNBBY7Q1OX5C4xAgRQffOg2OnhAo9fnbcOHgOC9Yytm2Sw+4XqHufRYU86tHomzepxtvuVaNO+3EVKR4ivw==", "requires": { "@babel/helper-create-class-features-plugin": "^7.19.0", "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-replace-supers": "^7.19.1", "@babel/helper-split-export-declaration": "^7.18.6", "@babel/plugin-syntax-decorators": "^7.19.0" } @@ -18392,9 +18407,9 @@ } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.0.tgz", - "integrity": "sha512-HDSuqOQzkU//kfGdiHBt71/hkDTApw4U/cMVgKgX7PqfB3LOaK+2GtCEsBu1dL9CkswDm0Gwehht1dCr421ULQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", "requires": { "@babel/helper-create-regexp-features-plugin": "^7.19.0", "@babel/helper-plugin-utils": "^7.19.0" @@ -18496,15 +18511,15 @@ } }, "@babel/plugin-transform-runtime": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.10.tgz", - "integrity": "sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.1.tgz", + "integrity": "sha512-2nJjTUFIzBMP/f/miLxEK9vxwW/KUXsdvN4sR//TmuDhe6yU2h57WmIOE12Gng3MDP/xpjUV/ToZRdcf8Yj4fA==", "requires": { "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.9", - "babel-plugin-polyfill-corejs2": "^0.3.2", - "babel-plugin-polyfill-corejs3": "^0.5.3", - "babel-plugin-polyfill-regenerator": "^0.4.0", + "@babel/helper-plugin-utils": "^7.19.0", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", "semver": "^6.3.0" } }, @@ -18550,9 +18565,9 @@ } }, "@babel/plugin-transform-typescript": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.19.0.tgz", - "integrity": "sha512-DOOIywxPpkQHXijXv+s9MDAyZcLp12oYRl3CMWZ6u7TjSoCBq/KqHR/nNFR3+i2xqheZxoF0H2XyL7B6xeSRuA==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.19.1.tgz", + "integrity": "sha512-+ILcOU+6mWLlvCwnL920m2Ow3wWx3Wo8n2t5aROQmV55GZt+hOiLvBaa3DNzRjSEHa1aauRs4/YLmkCfFkhhRQ==", "requires": { "@babel/helper-create-class-features-plugin": "^7.19.0", "@babel/helper-plugin-utils": "^7.19.0", @@ -18577,17 +18592,17 @@ } }, "@babel/preset-env": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.0.tgz", - "integrity": "sha512-1YUju1TAFuzjIQqNM9WsF4U6VbD/8t3wEAlw3LFYuuEr+ywqLRcSXxFKz4DCEj+sN94l/XTDiUXYRrsvMpz9WQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.1.tgz", + "integrity": "sha512-c8B2c6D16Lp+Nt6HcD+nHl0VbPKVnNPTpszahuxJJnurfMtKeZ80A+qUv48Y7wqvS+dTFuLuaM9oYxyNHbCLWA==", "requires": { - "@babel/compat-data": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.0", + "@babel/compat-data": "^7.19.1", + "@babel/helper-compilation-targets": "^7.19.1", "@babel/helper-plugin-utils": "^7.19.0", "@babel/helper-validator-option": "^7.18.6", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-async-generator-functions": "^7.19.0", + "@babel/plugin-proposal-async-generator-functions": "^7.19.1", "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-proposal-class-static-block": "^7.18.6", "@babel/plugin-proposal-dynamic-import": "^7.18.6", @@ -18635,7 +18650,7 @@ "@babel/plugin-transform-modules-commonjs": "^7.18.6", "@babel/plugin-transform-modules-systemjs": "^7.19.0", "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", "@babel/plugin-transform-new-target": "^7.18.6", "@babel/plugin-transform-object-super": "^7.18.6", "@babel/plugin-transform-parameters": "^7.18.8", @@ -18651,10 +18666,10 @@ "@babel/plugin-transform-unicode-regex": "^7.18.6", "@babel/preset-modules": "^0.1.5", "@babel/types": "^7.19.0", - "babel-plugin-polyfill-corejs2": "^0.3.2", - "babel-plugin-polyfill-corejs3": "^0.5.3", - "babel-plugin-polyfill-regenerator": "^0.4.0", - "core-js-compat": "^3.22.1", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", "semver": "^6.3.0" } }, @@ -18702,11 +18717,11 @@ } }, "@babel/runtime-corejs3": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.0.tgz", - "integrity": "sha512-JyXXoCu1N8GLuKc2ii8y5RGma5FMpFeO2nAQIe0Yzrbq+rQnN+sFj47auLblR5ka6aHNGPDgv8G/iI2Grb0ldQ==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz", + "integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==", "requires": { - "core-js-pure": "^3.20.2", + "core-js-pure": "^3.25.1", "regenerator-runtime": "^0.13.4" } }, @@ -18721,9 +18736,9 @@ } }, "@babel/traverse": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.0.tgz", - "integrity": "sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.1.tgz", + "integrity": "sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==", "requires": { "@babel/code-frame": "^7.18.6", "@babel/generator": "^7.19.0", @@ -18731,7 +18746,7 @@ "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.0", + "@babel/parser": "^7.19.1", "@babel/types": "^7.19.0", "debug": "^4.1.0", "globals": "^11.1.0" @@ -18758,9 +18773,9 @@ "integrity": "sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg==" }, "@csstools/postcss-cascade-layers": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.0.6.tgz", - "integrity": "sha512-ei4Vh4AJwTCXTNj7uzwduoZDO7nLPksQ0TI7OzUlyFq4P4Uhu6hU7R4AlLimDP/s6D3PQdHmRL4f7UOy370UHA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", "requires": { "@csstools/selector-specificity": "^2.0.2", "postcss-selector-parser": "^6.0.10" @@ -18994,9 +19009,9 @@ "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" }, "@eslint/eslintrc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.1.tgz", - "integrity": "sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", + "integrity": "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==", "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -19719,6 +19734,30 @@ "react-is": "^18.2.0" } }, + "@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "requires": { + "eslint-scope": "5.1.1" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + } + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -19824,14 +19863,14 @@ } }, "@rushstack/eslint-patch": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.4.tgz", - "integrity": "sha512-LwzQKA4vzIct1zNZzBmRKI9QuNpLgTQMEjsQLf3BXuGYb3QPTP4Yjf6mkdX+X1mYttZ808QpOwAzZjv28kq7DA==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", + "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==" }, "@sinclair/typebox": { - "version": "0.24.39", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.39.tgz", - "integrity": "sha512-GqtkxoAjhTzoMwFg/JYRl+1+miOoyvp6mkLpbMSd2fIQak2KvY00ndlXxxkDBpuCPYkorZeEZf0LEQn9V9NRVQ==" + "version": "0.24.42", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.42.tgz", + "integrity": "sha512-d+2AtrHGyWek2u2ITF0lHRIv6Tt7X0dEHW+0rP+5aDCEjC3fiN2RBjrLD0yU0at52BcZbRGxLbAtXiR0hFCjYw==" }, "@sinonjs/commons": { "version": "1.8.3", @@ -20097,9 +20136,9 @@ "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==" }, "@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", + "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", "requires": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.18", @@ -20108,9 +20147,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.30", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz", - "integrity": "sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ==", + "version": "4.17.31", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", + "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", "requires": { "@types/node": "*", "@types/qs": "*", @@ -20246,9 +20285,9 @@ } }, "@types/react-router": { - "version": "5.1.18", - "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.18.tgz", - "integrity": "sha512-YYknwy0D0iOwKQgz9v8nOzt2J6l4gouBmDnWqUUznltOTaon+r8US8ky8HvN0tXvc38U9m6z/t2RsVsnd1zM0g==", + "version": "5.1.19", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.19.tgz", + "integrity": "sha512-Fv/5kb2STAEMT3wHzdKQK2z8xKq38EDIGVrutYLmQVVLe+4orDFquU52hQrULnEHinMKv9FSA6lf9+uNT1ITtA==", "requires": { "@types/history": "^4.7.11", "@types/react": "*" @@ -20347,13 +20386,13 @@ "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" }, "@typescript-eslint/eslint-plugin": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.36.2.tgz", - "integrity": "sha512-OwwR8LRwSnI98tdc2z7mJYgY60gf7I9ZfGjN5EjCwwns9bdTuQfAXcsjSB2wSQ/TVNYSGKf4kzVXbNGaZvwiXw==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.37.0.tgz", + "integrity": "sha512-Fde6W0IafXktz1UlnhGkrrmnnGpAo1kyX7dnyHHVrmwJOn72Oqm3eYtddrpOwwel2W8PAK9F3pIL5S+lfoM0og==", "requires": { - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/type-utils": "5.36.2", - "@typescript-eslint/utils": "5.36.2", + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/type-utils": "5.37.0", + "@typescript-eslint/utils": "5.37.0", "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", @@ -20373,56 +20412,56 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.36.2.tgz", - "integrity": "sha512-JtRmWb31KQoxGV6CHz8cI+9ki6cC7ciZepXYpCLxsdAtQlBrRBxh5Qpe/ZHyJFOT9j7gyXE+W0shWzRLPfuAFQ==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.37.0.tgz", + "integrity": "sha512-mmzzOOK2YpwSgzhXpeSAtAlxBZVLGuq8OdvrfzibR4jfTTrTd3AjCy17M2dUKVFNsrNfLM0nWsxMsJz0kiYHqw==", "requires": { - "@typescript-eslint/utils": "5.36.2" + "@typescript-eslint/utils": "5.37.0" } }, "@typescript-eslint/parser": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.36.2.tgz", - "integrity": "sha512-qS/Kb0yzy8sR0idFspI9Z6+t7mqk/oRjnAYfewG+VN73opAUvmYL3oPIMmgOX6CnQS6gmVIXGshlb5RY/R22pA==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.37.0.tgz", + "integrity": "sha512-01VzI/ipYKuaG5PkE5+qyJ6m02fVALmMPY3Qq5BHflDx3y4VobbLdHQkSMg9VPRS4KdNt4oYTMaomFoHonBGAw==", "requires": { - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/typescript-estree": "5.36.2", + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/typescript-estree": "5.37.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.36.2.tgz", - "integrity": "sha512-cNNP51L8SkIFSfce8B1NSUBTJTu2Ts4nWeWbFrdaqjmn9yKrAaJUBHkyTZc0cL06OFHpb+JZq5AUHROS398Orw==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.37.0.tgz", + "integrity": "sha512-F67MqrmSXGd/eZnujjtkPgBQzgespu/iCZ+54Ok9X5tALb9L2v3G+QBSoWkXG0p3lcTJsL+iXz5eLUEdSiJU9Q==", "requires": { - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/visitor-keys": "5.36.2" + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/visitor-keys": "5.37.0" } }, "@typescript-eslint/type-utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.36.2.tgz", - "integrity": "sha512-rPQtS5rfijUWLouhy6UmyNquKDPhQjKsaKH0WnY6hl/07lasj8gPaH2UD8xWkePn6SC+jW2i9c2DZVDnL+Dokw==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.37.0.tgz", + "integrity": "sha512-BSx/O0Z0SXOF5tY0bNTBcDEKz2Ec20GVYvq/H/XNKiUorUFilH7NPbFUuiiyzWaSdN3PA8JV0OvYx0gH/5aFAQ==", "requires": { - "@typescript-eslint/typescript-estree": "5.36.2", - "@typescript-eslint/utils": "5.36.2", + "@typescript-eslint/typescript-estree": "5.37.0", + "@typescript-eslint/utils": "5.37.0", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.36.2.tgz", - "integrity": "sha512-9OJSvvwuF1L5eS2EQgFUbECb99F0mwq501w0H0EkYULkhFa19Qq7WFbycdw1PexAc929asupbZcgjVIe6OK/XQ==" + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.37.0.tgz", + "integrity": "sha512-3frIJiTa5+tCb2iqR/bf7XwU20lnU05r/sgPJnRpwvfZaqCJBrl8Q/mw9vr3NrNdB/XtVyMA0eppRMMBqdJ1bA==" }, "@typescript-eslint/typescript-estree": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.36.2.tgz", - "integrity": "sha512-8fyH+RfbKc0mTspfuEjlfqA4YywcwQK2Amcf6TDOwaRLg7Vwdu4bZzyvBZp4bjt1RRjQ5MDnOZahxMrt2l5v9w==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.37.0.tgz", + "integrity": "sha512-JkFoFIt/cx59iqEDSgIGnQpCTRv96MQnXCYvJi7QhBC24uyuzbD8wVbajMB1b9x4I0octYFJ3OwjAwNqk1AjDA==", "requires": { - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/visitor-keys": "5.36.2", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/visitor-keys": "5.37.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -20441,14 +20480,14 @@ } }, "@typescript-eslint/utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.36.2.tgz", - "integrity": "sha512-uNcopWonEITX96v9pefk9DC1bWMdkweeSsewJ6GeC7L6j2t0SJywisgkr9wUTtXk90fi2Eljj90HSHm3OGdGRg==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.37.0.tgz", + "integrity": "sha512-jUEJoQrWbZhmikbcWSMDuUSxEE7ID2W/QCV/uz10WtQqfOuKZUqFGjqLJ+qhDd17rjgp+QJPqTdPIBWwoob2NQ==", "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/typescript-estree": "5.36.2", + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/typescript-estree": "5.37.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, @@ -20470,11 +20509,11 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.36.2.tgz", - "integrity": "sha512-BtRvSR6dEdrNt7Net2/XDjbYKU5Ml6GqJgVfXT0CxTCJlnIqK7rAGreuWKMT2t8cFUT2Msv5oxw0GMRD7T5J7A==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.37.0.tgz", + "integrity": "sha512-Hp7rT4cENBPIzMwrlehLW/28EVCOcE9U1Z1BQTc8EA8v5qpr7GRGuG+U58V5tTY48zvUOA3KHvw3rA8tY9fbdA==", "requires": { - "@typescript-eslint/types": "5.36.2", + "@typescript-eslint/types": "5.37.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -20695,9 +20734,9 @@ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" }, "address": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/address/-/address-1.2.0.tgz", - "integrity": "sha512-tNEZYz5G/zYunxFm7sfhAxkXEuLj3K6BKwv6ZURlsF6yiUQ65z0Q2wZW9L5cPUl9ocofGvXOdFYbFHp0+6MOig==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.1.tgz", + "integrity": "sha512-B+6bi5D34+fDYENiH5qOlA0cV2rAGKuWZ9LeyUUehbXy8e0VS9e498yO0Jeeh+iM+6KbfudHTFjXw2MmJD4QRA==" }, "adjust-sourcemap-loader": { "version": "4.0.0", @@ -20908,12 +20947,12 @@ "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==" }, "autoprefixer": { - "version": "10.4.8", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.8.tgz", - "integrity": "sha512-75Jr6Q/XpTqEf6D2ltS5uMewJIx5irCU1oBYJrWjFenq/m12WRRrz6g15L1EIoYvPLXTbEry7rDOwrcYNj77xw==", + "version": "10.4.11", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.11.tgz", + "integrity": "sha512-5lHp6DgRodxlBLSkzHOTcufWFflH1ewfy2hvFQyjrblBFlP/0Yh4O/Wrg4ow8WRlN3AAUFFLAQwX8hTptzqVHg==", "requires": { "browserslist": "^4.21.3", - "caniuse-lite": "^1.0.30001373", + "caniuse-lite": "^1.0.30001399", "fraction.js": "^4.2.0", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", @@ -21070,30 +21109,30 @@ "requires": {} }, "babel-plugin-polyfill-corejs2": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.2.tgz", - "integrity": "sha512-LPnodUl3lS0/4wN3Rb+m+UK8s7lj2jcLRrjho4gLw+OJs+I4bvGXshINesY5xx/apM+biTnQ9reDI8yj+0M5+Q==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", "requires": { "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.2", + "@babel/helper-define-polyfill-provider": "^0.3.3", "semver": "^6.1.1" } }, "babel-plugin-polyfill-corejs3": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", - "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.2", - "core-js-compat": "^3.21.0" + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.0.tgz", - "integrity": "sha512-RW1cnryiADFeHmfLS+WW/G431p1PsW5qdRdz0SDRi7TKcUgc7Oh/uXkT7MZ/+tGsT1BkczEAmD5XjUyJ5SWDTw==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.2" + "@babel/helper-define-polyfill-provider": "^0.3.3" } }, "babel-plugin-transform-react-remove-prop-types": { @@ -21274,14 +21313,14 @@ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" }, "browserslist": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", - "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", "requires": { - "caniuse-lite": "^1.0.30001370", - "electron-to-chromium": "^1.4.202", + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.5" + "update-browserslist-db": "^1.0.9" } }, "bser": { @@ -21352,9 +21391,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001393", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001393.tgz", - "integrity": "sha512-N/od11RX+Gsk+1qY/jbPa0R6zJupEa0lxeBG598EbrtblxVCTJsQwbRBm6+V+rxpc5lHKdsXb9RY83cZIPLseA==" + "version": "1.0.30001402", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001402.tgz", + "integrity": "sha512-Mx4MlhXO5NwuvXGgVb+hg65HZ+bhUYsz8QtDGDo2QmaJS2GBX47Xfi2koL86lc8K+l+htXeTEB/Aeqvezoo6Ew==" }, "case-sensitive-paths-webpack-plugin": { "version": "2.4.0", @@ -21409,9 +21448,9 @@ "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" }, "ci-info": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", - "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==" + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.4.0.tgz", + "integrity": "sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==" }, "cjs-module-lexer": { "version": "1.2.2", @@ -21928,9 +21967,9 @@ } }, "csstype": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", - "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, "damerau-levenshtein": { "version": "1.0.8", @@ -21956,9 +21995,9 @@ } }, "decimal.js": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.0.tgz", - "integrity": "sha512-Nv6ENEzyPQ6AItkGwLE2PGKinZZ9g59vSh2BeH6NqPu0OTKZ5ruJsVqh/orbAnqXc9pBbgXAIrc2EyaCj8NpGg==" + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.1.tgz", + "integrity": "sha512-F29o+vci4DodHYT9UrR5IEbfBw9pE5eSapIJdTqXK5+6hq+t8VRxwQyKlW2i+KDKFkkJQRvFyI/QXD83h8LyQw==" }, "dedent": { "version": "0.7.0", @@ -22208,9 +22247,9 @@ } }, "electron-to-chromium": { - "version": "1.4.246", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.246.tgz", - "integrity": "sha512-/wFCHUE+Hocqr/LlVGsuKLIw4P2lBWwFIDcNMDpJGzyIysQV4aycpoOitAs32FT94EHKnNqDR/CVZJFbXEufJA==" + "version": "1.4.254", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.254.tgz", + "integrity": "sha512-Sh/7YsHqQYkA6ZHuHMy24e6TE4eX6KZVsZb9E/DvU1nQRIrH4BflO/4k+83tfdYvDl+MObvlqHPRICzEdC9c6Q==" }, "emittery": { "version": "0.8.1", @@ -22391,11 +22430,11 @@ } }, "eslint": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.0.tgz", - "integrity": "sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==", + "version": "8.23.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.1.tgz", + "integrity": "sha512-w7C1IXCc6fNqjpuYd0yPlcTKKmHlHHktRkzmBPZ+7cvNBQuiNjx0xaMTjAJGCafJhQkrFJooREv0CtrVzmHwqg==", "requires": { - "@eslint/eslintrc": "^1.3.1", + "@eslint/eslintrc": "^1.3.2", "@humanwhocodes/config-array": "^0.10.4", "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", "@humanwhocodes/module-importer": "^1.0.1", @@ -22414,7 +22453,6 @@ "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", "globals": "^13.15.0", "globby": "^11.1.0", @@ -22423,6 +22461,7 @@ "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -22737,9 +22776,9 @@ "requires": {} }, "eslint-plugin-testing-library": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.6.3.tgz", - "integrity": "sha512-//fhmCzopr8UDv5X2M3XMGxQ0j6KjKYZ+6PGqdV0woLiXTSTOAzuNsiTELGv883iCeUrYrnHhtObPXyiTMytVQ==", + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.6.4.tgz", + "integrity": "sha512-0oW3tC5NNT2WexmJ3848a/utawOymw4ibl3/NkwywndVAz2hT9+ab70imA7ccg3RaScQgMvJT60OL00hpmJvrg==", "requires": { "@typescript-eslint/utils": "^5.13.0" } @@ -23222,9 +23261,9 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" }, "follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" }, "fork-ts-checker-webpack-plugin": { "version": "6.5.2", @@ -23425,9 +23464,9 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -23907,9 +23946,9 @@ } }, "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.6.tgz", + "integrity": "sha512-krO72EO2NptOGAX2KYyqbP9vYMlNAXdB53rq6f8LXY6RY7JdSR/3BD6wLUlPHSAesmY9vstNrjvqGaCiRK/91Q==" }, "is-core-module": { "version": "2.10.0", @@ -25570,6 +25609,11 @@ } } }, + "js-sdsl": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", + "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -26694,9 +26738,9 @@ } }, "postcss-custom-properties": { - "version": "12.1.8", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.8.tgz", - "integrity": "sha512-8rbj8kVu00RQh2fQF81oBqtduiANu4MIxhyf0HbbStgPtnFlWn0yiaYTpLHrPnJbffVY1s9apWsIoVZcc68FxA==", + "version": "12.1.9", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.9.tgz", + "integrity": "sha512-/E7PRvK8DAVljBbeWrcEQJPG72jaImxF3vvCNFwv9cC8CzigVoNIpeyfnJzphnN3Fd8/auBf5wvkw6W9MfmTyg==", "requires": { "postcss-value-parser": "^4.2.0" } @@ -26971,9 +27015,9 @@ } }, "postcss-nesting": { - "version": "10.1.10", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.1.10.tgz", - "integrity": "sha512-lqd7LXCq0gWc0wKXtoKDru5wEUNjm3OryLVNRZ8OnW8km6fSNUuFrjEhU3nklxXE2jvd4qrox566acgh+xQt8w==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", "requires": { "@csstools/selector-specificity": "^2.0.0", "postcss-selector-parser": "^6.0.10" @@ -27098,11 +27142,11 @@ } }, "postcss-preset-env": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.1.tgz", - "integrity": "sha512-8884CHxQaoN1i4iEK+JvzOe8emODb5R4p/0dw4yEdo7QM4RdUk2sBx0fnzFyJt8BLfZSCGeVkKZ4HC564waBpQ==", + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.2.tgz", + "integrity": "sha512-rSMUEaOCnovKnwc5LvBDHUDzpGP+nrUeWZGWt9M72fBvckCi45JmnJigUr4QG4zZeOHmOCNCZnd2LKDvP++ZuQ==", "requires": { - "@csstools/postcss-cascade-layers": "^1.0.6", + "@csstools/postcss-cascade-layers": "^1.1.0", "@csstools/postcss-color-function": "^1.1.1", "@csstools/postcss-font-format-keywords": "^1.0.1", "@csstools/postcss-hwb-function": "^1.0.2", @@ -27116,7 +27160,7 @@ "@csstools/postcss-text-decoration-shorthand": "^1.0.0", "@csstools/postcss-trigonometric-functions": "^1.0.2", "@csstools/postcss-unset-value": "^1.0.2", - "autoprefixer": "^10.4.8", + "autoprefixer": "^10.4.11", "browserslist": "^4.21.3", "css-blank-pseudo": "^3.0.3", "css-has-pseudo": "^3.0.4", @@ -27128,7 +27172,7 @@ "postcss-color-hex-alpha": "^8.0.4", "postcss-color-rebeccapurple": "^7.1.1", "postcss-custom-media": "^8.0.2", - "postcss-custom-properties": "^12.1.8", + "postcss-custom-properties": "^12.1.9", "postcss-custom-selectors": "^6.0.3", "postcss-dir-pseudo-class": "^6.0.5", "postcss-double-position-gradients": "^3.1.2", @@ -27142,7 +27186,7 @@ "postcss-lab-function": "^4.2.1", "postcss-logical": "^5.0.4", "postcss-media-minmax": "^5.0.0", - "postcss-nesting": "^10.1.10", + "postcss-nesting": "^10.2.0", "postcss-opacity-percentage": "^1.1.2", "postcss-overflow-shorthand": "^3.0.4", "postcss-page-break": "^3.0.4", @@ -27823,9 +27867,9 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", "requires": { "regenerate": "^1.4.2" } @@ -27864,27 +27908,27 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" }, "regexpu-core": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.1.0.tgz", - "integrity": "sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", + "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", "requires": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.0.0" } }, "regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==" }, "regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "requires": { "jsesc": "~0.5.0" }, @@ -29036,6 +29080,12 @@ "is-typedarray": "^1.0.0" } }, + "typesafe-i18n": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/typesafe-i18n/-/typesafe-i18n-5.13.0.tgz", + "integrity": "sha512-Q72l+LqB37kNT2R39mkTwQy1tuQ7URAahD1QXbR84itO864xvVgdoS8xaRAatp0y2/oU7f+2EzpAK3YGp0g+eA==", + "requires": {} + }, "typescript": { "version": "4.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", @@ -29078,9 +29128,9 @@ "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==" }, "unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" }, "unique-string": { "version": "2.0.0", @@ -29111,9 +29161,9 @@ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" }, "update-browserslist-db": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.7.tgz", - "integrity": "sha512-iN/XYesmZ2RmmWAiI4Z5rq0YqSiv0brj9Ce9CfhNE4xIW2h+MFxcgkxIzZ+ShkFPUkjU3gQ+3oypadD3RAMtrg==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", + "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" diff --git a/interface/package.json b/interface/package.json index 59bd06c4d..b09abe77a 100644 --- a/interface/package.json +++ b/interface/package.json @@ -1,6 +1,6 @@ { "name": "EMS-ESP", - "version": "3.4.0", + "version": "3.5.0", "private": true, "proxy": "http://localhost:3080", "dependencies": { @@ -30,6 +30,7 @@ "react-router-dom": "^6.4.0", "react-scripts": "5.0.1", "sockette": "^2.0.6", + "typesafe-i18n": "^5.13.0", "typescript": "^4.8.3" }, "scripts": { @@ -41,8 +42,9 @@ "build-hosted": "env-cmd -f .env.hosted npm run build", "build-localhost": "PUBLIC_URL=/ react-app-rewired build", "mock-api": "nodemon --watch ../mock-api ../mock-api/server.js", - "standalone": "npm-run-all -p start mock-api", - "lint": "eslint . --ext .ts,.tsx" + "standalone": "npm-run-all -p start typesafe-i18n mock-api", + "lint": "eslint . --ext .ts,.tsx", + "typesafe-i18n": "typesafe-i18n" }, "eslintConfig": { "extends": [ @@ -78,7 +80,7 @@ "max-len": [ 1, { - "code": 200 + "code": 220 } ], "arrow-parens": 1 diff --git a/interface/src/App.tsx b/interface/src/App.tsx index 6427f07f9..d18e86252 100644 --- a/interface/src/App.tsx +++ b/interface/src/App.tsx @@ -1,4 +1,4 @@ -import { FC, createRef, createContext, useContext, RefObject } from 'react'; +import { FC, createRef, createContext, useContext, useEffect, useState, RefObject } from 'react'; import { SnackbarProvider } from 'notistack'; import { IconButton } from '@mui/material'; @@ -9,6 +9,13 @@ import { FeaturesLoader } from './contexts/features'; import CustomTheme from './CustomTheme'; import AppRouting from './AppRouting'; +import { localStorageDetector } from 'typesafe-i18n/detectors'; +import TypesafeI18n from './i18n/i18n-react'; +import { detectLocale } from './i18n/i18n-util'; +import { loadLocaleAsync } from './i18n/i18n-util.async'; + +const detectedLocale = detectLocale(localStorageDetector); + const App: FC = () => { const notistackRef: RefObject = createRef(); @@ -20,24 +27,34 @@ const App: FC = () => { const colorMode = useContext(ColorModeContext); + const [wasLoaded, setWasLoaded] = useState(false); + + useEffect(() => { + loadLocaleAsync(detectedLocale).then(() => setWasLoaded(true)); + }, []); + + if (!wasLoaded) return null; + return ( - - ( - - - - )} - > - - - - - + + + ( + + + + )} + > + + + + + + ); }; diff --git a/interface/src/AppRouting.tsx b/interface/src/AppRouting.tsx index 4861c715d..eac179b57 100644 --- a/interface/src/AppRouting.tsx +++ b/interface/src/AppRouting.tsx @@ -2,6 +2,8 @@ import { FC, useContext, useEffect } from 'react'; import { Navigate, Routes, Route, useLocation } from 'react-router-dom'; import { useSnackbar, VariantType } from 'notistack'; +import { useI18nContext } from './i18n/i18n-react'; + import { Authentication, AuthenticationContext } from './contexts/authentication'; import { FeaturesContext } from './contexts/features'; import { RequireAuthenticated, RequireUnauthenticated } from './components'; @@ -41,13 +43,14 @@ export const RemoveTrailingSlashes = () => { const AppRouting: FC = () => { const { features } = useContext(FeaturesContext); + const { LL } = useI18nContext(); return ( - } /> - } /> + } /> + } /> {features.security && ( { const authenticationContext = useContext(AuthenticationContext); const { enqueueSnackbar } = useSnackbar(); @@ -31,6 +40,9 @@ const SignIn: FC = () => { const validateAndSignIn = async () => { setProcessing(true); + SIGN_IN_REQUEST_VALIDATOR.messages({ + required: '%s ' + LL.IS_REQUIRED() + }); try { await validate(SIGN_IN_REQUEST_VALIDATOR, signInRequest); signIn(); @@ -47,10 +59,10 @@ const SignIn: FC = () => { } catch (error: unknown) { if (error instanceof AxiosError) { if (error.response?.status === 401) { - enqueueSnackbar('Invalid login details', { variant: 'warning' }); + enqueueSnackbar(LL.INVALID_LOGIN(), { variant: 'warning' }); } } else { - enqueueSnackbar(extractErrorMessage(error, 'Unexpected error, please try again'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.ERROR()), { variant: 'error' }); } setProcessing(false); } @@ -58,6 +70,14 @@ const SignIn: FC = () => { const submitOnEnter = onEnterCallback(signIn); + const { LL, setLocale, locale } = useContext(I18nContext); + + const selectLocale = async (loc: Locales) => { + localStorage.setItem('lang', loc); + await loadLocaleAsync(loc); + setLocale(loc); + }; + return ( { })} > {PROJECT_NAME} + + + + + + + { disabled={processing} type="password" name="password" - label="Password" + label={LL.PASSWORD()} value={signInRequest.password} onChange={updateLoginRequestValue} onKeyDown={submitOnEnter} @@ -107,7 +153,7 @@ const SignIn: FC = () => { /> - Sign In + {LL.SIGN_IN()} diff --git a/interface/src/components/layout/LayoutAuthMenu.tsx b/interface/src/components/layout/LayoutAuthMenu.tsx index 26c1d3fc4..1422233da 100644 --- a/interface/src/components/layout/LayoutAuthMenu.tsx +++ b/interface/src/components/layout/LayoutAuthMenu.tsx @@ -1,12 +1,35 @@ -import { FC, useState, useContext } from 'react'; +import { FC, useState, useContext, ChangeEventHandler } from 'react'; -import { Box, Button, Divider, IconButton, Popover, Typography, Avatar, styled, TypographyProps } from '@mui/material'; +import { + Box, + Button, + Divider, + IconButton, + Popover, + Typography, + Avatar, + styled, + TypographyProps, + MenuItem, + TextField +} from '@mui/material'; import PersonIcon from '@mui/icons-material/Person'; import AccountCircleIcon from '@mui/icons-material/AccountCircle'; import { AuthenticatedContext } from '../../contexts/authentication'; +import { I18nContext } from '../../i18n/i18n-react'; +import type { Locales } from '../../i18n/i18n-types'; +import { loadLocaleAsync } from '../../i18n/i18n-util.async'; + +import { ReactComponent as NLflag } from '../../i18n/NL.svg'; +import { ReactComponent as DEflag } from '../../i18n/DE.svg'; +import { ReactComponent as GBflag } from '../../i18n/GB.svg'; +import { ReactComponent as SEflag } from '../../i18n/SE.svg'; +import { ReactComponent as PLflag } from '../../i18n/PL.svg'; +import { ReactComponent as NOflag } from '../../i18n/NO.svg'; + const ItemTypography = styled(Typography)({ maxWidth: '250px', whiteSpace: 'nowrap', @@ -23,6 +46,15 @@ const LayoutAuthMenu: FC = () => { setAnchorEl(event.currentTarget); }; + const { locale, LL, setLocale } = useContext(I18nContext); + + const onLocaleSelected: ChangeEventHandler = async ({ target }) => { + const loc = target.value as Locales; + localStorage.setItem('lang', loc); + await loadLocaleAsync(loc); + setLocale(loc); + }; + const handleClose = () => { setAnchorEl(null); }; @@ -32,7 +64,48 @@ const LayoutAuthMenu: FC = () => { return ( <> - + + + +  EN + + + +  DE + + + +  NL + + + +  SE + + + +  PL + + + +  NO + + + + { {me.username} - {me.admin ? 'Admin User' : 'Guest User'} + + {me.admin ? LL.ADMIN() + ' ' + LL.USER() : LL.GUEST() + ' ' + LL.USER()} + diff --git a/interface/src/components/layout/LayoutMenu.tsx b/interface/src/components/layout/LayoutMenu.tsx index f3e1bfb6d..cff62bbf6 100644 --- a/interface/src/components/layout/LayoutMenu.tsx +++ b/interface/src/components/layout/LayoutMenu.tsx @@ -15,9 +15,12 @@ import ProjectMenu from '../../project/ProjectMenu'; import LayoutMenuItem from './LayoutMenuItem'; import { AuthenticatedContext } from '../../contexts/authentication'; +import { useI18nContext } from '../../i18n/i18n-react'; + const LayoutMenu: FC = () => { const { features } = useContext(FeaturesContext); const authenticatedContext = useContext(AuthenticatedContext); + const { LL } = useI18nContext(); return ( <> @@ -28,12 +31,17 @@ const LayoutMenu: FC = () => { )} - - - {features.ntp && } + + + {features.ntp && } {features.mqtt && } - - + + ); diff --git a/interface/src/components/loading/FormLoader.tsx b/interface/src/components/loading/FormLoader.tsx index 8b1baab7b..390b309b6 100644 --- a/interface/src/components/loading/FormLoader.tsx +++ b/interface/src/components/loading/FormLoader.tsx @@ -5,6 +5,8 @@ import RefreshIcon from '@mui/icons-material/Refresh'; import { MessageBox } from '..'; +import { useI18nContext } from '../../i18n/i18n-react'; + interface FormLoaderProps { message?: string; errorMessage?: string; @@ -12,12 +14,14 @@ interface FormLoaderProps { } const FormLoader: FC = ({ errorMessage, onRetry, message = 'Loading…' }) => { + const { LL } = useI18nContext(); + if (errorMessage) { return ( {onRetry && ( )} diff --git a/interface/src/components/loading/LoadingSpinner.tsx b/interface/src/components/loading/LoadingSpinner.tsx index eaeccf0ad..5baf6ecf8 100644 --- a/interface/src/components/loading/LoadingSpinner.tsx +++ b/interface/src/components/loading/LoadingSpinner.tsx @@ -2,23 +2,29 @@ import { FC } from 'react'; import { CircularProgress, Box, Typography, Theme } from '@mui/material'; +import { useI18nContext } from '../../i18n/i18n-react'; + interface LoadingSpinnerProps { height?: number | string; } -const LoadingSpinner: FC = ({ height = '100%' }) => ( - - ({ - margin: theme.spacing(4), - color: theme.palette.text.secondary - })} - size={100} - /> - - Loading… - - -); +const LoadingSpinner: FC = ({ height = '100%' }) => { + const { LL } = useI18nContext(); + + return ( + + ({ + margin: theme.spacing(4), + color: theme.palette.text.secondary + })} + size={100} + /> + + {LL.LOADING()}… + + + ); +}; export default LoadingSpinner; diff --git a/interface/src/components/upload/SingleUpload.tsx b/interface/src/components/upload/SingleUpload.tsx index acdc15071..574f4dae0 100644 --- a/interface/src/components/upload/SingleUpload.tsx +++ b/interface/src/components/upload/SingleUpload.tsx @@ -6,6 +6,8 @@ import { Box, Button, LinearProgress, Theme, Typography, useTheme } from '@mui/m import CloudUploadIcon from '@mui/icons-material/CloudUpload'; import CancelIcon from '@mui/icons-material/Cancel'; +import { useI18nContext } from '../../i18n/i18n-react'; + const progressPercentage = (progress: ProgressEvent) => Math.round((progress.loaded * 100) / progress.total); const getBorderColor = (theme: Theme, props: DropzoneState) => { @@ -41,14 +43,16 @@ const SingleUpload: FC = ({ onDrop, onCancel, uploading, prog const { getRootProps, getInputProps } = dropzoneState; const theme = useTheme(); + const { LL } = useI18nContext(); + const progressText = () => { if (uploading) { if (progress?.lengthComputable) { - return `Uploading: ${progressPercentage(progress)}%`; + return LL.UPLOADING() + `: ${progressPercentage(progress)}%`; } - return 'Uploading\u2026'; + return LL.UPLOADING() + `\u2026`; } - return 'Drop file or click here'; + return LL.UPLOAD_DROP_TEXT(); }; return ( @@ -81,7 +85,7 @@ const SingleUpload: FC = ({ onDrop, onCancel, uploading, prog /> )} diff --git a/interface/src/components/upload/useFileUpload.ts b/interface/src/components/upload/useFileUpload.ts index 0cc12b1aa..aaa588ac3 100644 --- a/interface/src/components/upload/useFileUpload.ts +++ b/interface/src/components/upload/useFileUpload.ts @@ -5,11 +5,15 @@ import { useSnackbar } from 'notistack'; import { extractErrorMessage } from '../../utils'; import { FileUploadConfig } from '../../api/endpoints'; +import { useI18nContext } from '../../i18n/i18n-react'; + interface MediaUploadOptions { upload: (file: File, config?: FileUploadConfig) => AxiosPromise; } const useFileUpload = ({ upload }: MediaUploadOptions) => { + const { LL } = useI18nContext(); + const { enqueueSnackbar } = useSnackbar(); const [uploading, setUploading] = useState(false); const [uploadProgress, setUploadProgress] = useState(); @@ -42,13 +46,13 @@ const useFileUpload = ({ upload }: MediaUploadOptions) => { cancelToken: cancelToken.token }); resetUploadingStates(); - enqueueSnackbar('File uploaded', { variant: 'success' }); + enqueueSnackbar(LL.UPLOAD() + ' ' + LL.SUCCESSFUL(), { variant: 'success' }); } catch (error: unknown) { if (axios.isCancel(error)) { - enqueueSnackbar('Upload aborted', { variant: 'warning' }); + enqueueSnackbar(LL.UPLOAD() + ' ' + LL.ABORTED(), { variant: 'warning' }); } else { resetUploadingStates(); - enqueueSnackbar(extractErrorMessage(error, 'Upload failed'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.UPLOAD() + ' ' + LL.FAILED()), { variant: 'error' }); } } }; diff --git a/interface/src/contexts/authentication/Authentication.tsx b/interface/src/contexts/authentication/Authentication.tsx index a1310e894..7bb3c87cf 100644 --- a/interface/src/contexts/authentication/Authentication.tsx +++ b/interface/src/contexts/authentication/Authentication.tsx @@ -2,6 +2,8 @@ import { FC, useCallback, useContext, useEffect, useState } from 'react'; import { useSnackbar } from 'notistack'; import { useNavigate } from 'react-router-dom'; +import { useI18nContext } from '../../i18n/i18n-react'; + import * as AuthenticationApi from '../../api/authentication'; import { ACCESS_TOKEN } from '../../api/endpoints'; import { RequiredChildrenProps } from '../../utils'; @@ -12,6 +14,8 @@ import { AuthenticationContext } from './context'; const Authentication: FC = ({ children }) => { const { features } = useContext(FeaturesContext); + const { LL } = useI18nContext(); + const navigate = useNavigate(); const { enqueueSnackbar } = useSnackbar(); @@ -23,7 +27,7 @@ const Authentication: FC = ({ children }) => { AuthenticationApi.getStorage().setItem(ACCESS_TOKEN, accessToken); const decodedMe = AuthenticationApi.decodeMeJWT(accessToken); setMe(decodedMe); - enqueueSnackbar(`Logged in as ${decodedMe.username}`, { variant: 'success' }); + enqueueSnackbar(LL.LOGGED_IN({ name: decodedMe.username }), { variant: 'success' }); } catch (error: unknown) { setMe(undefined); throw new Error('Failed to parse JWT'); diff --git a/interface/src/framework/ap/APSettingsForm.tsx b/interface/src/framework/ap/APSettingsForm.tsx index 8080f4f0f..8b3419760 100644 --- a/interface/src/framework/ap/APSettingsForm.tsx +++ b/interface/src/framework/ap/APSettingsForm.tsx @@ -19,6 +19,8 @@ import { APProvisionMode, APSettings } from '../../types'; import { numberValue, updateValue, useRest } from '../../utils'; import * as APApi from '../../api/ap'; +import { useI18nContext } from '../../i18n/i18n-react'; + export const isAPEnabled = ({ provision_mode }: APSettings) => { return provision_mode === APProvisionMode.AP_MODE_ALWAYS || provision_mode === APProvisionMode.AP_MODE_DISCONNECTED; }; @@ -29,6 +31,8 @@ const APSettingsForm: FC = () => { update: APApi.updateAPSettings }); + const { LL } = useI18nContext(); + const [fieldErrors, setFieldErrors] = useState(); const updateFormValue = updateValue(setData); @@ -53,7 +57,7 @@ const APSettingsForm: FC = () => { { onChange={updateFormValue} margin="normal" > - Always - When WiFi Disconnected - Never + {LL.AP_PROVIDE_TEXT_1()} + {LL.AP_PROVIDE_TEXT_2()} + {LL.AP_PROVIDE_TEXT_3()} {isAPEnabled(data) && ( <> { { { } - label="Hide SSID" + label={LL.AP_HIDE_SSID()} /> { type="submit" onClick={validateAndSubmit} > - Save + {LL.SAVE()} @@ -176,7 +180,7 @@ const APSettingsForm: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/framework/ap/APStatusForm.tsx b/interface/src/framework/ap/APStatusForm.tsx index e0a99e3b2..e4589c836 100644 --- a/interface/src/framework/ap/APStatusForm.tsx +++ b/interface/src/framework/ap/APStatusForm.tsx @@ -11,6 +11,8 @@ import { APNetworkStatus, APStatus } from '../../types'; import { ButtonRow, FormLoader, SectionContent } from '../../components'; import { useRest } from '../../utils'; +import { useI18nContext } from '../../i18n/i18n-react'; + export const apStatusHighlight = ({ status }: APStatus, theme: Theme) => { switch (status) { case APNetworkStatus.ACTIVE: @@ -24,24 +26,26 @@ export const apStatusHighlight = ({ status }: APStatus, theme: Theme) => { } }; -export const apStatus = ({ status }: APStatus) => { - switch (status) { - case APNetworkStatus.ACTIVE: - return 'Active'; - case APNetworkStatus.INACTIVE: - return 'Inactive'; - case APNetworkStatus.LINGERING: - return 'Lingering until idle'; - default: - return 'Unknown'; - } -}; - const APStatusForm: FC = () => { const { loadData, data, errorMessage } = useRest({ read: APApi.readAPStatus }); + const { LL } = useI18nContext(); + const theme = useTheme(); + const apStatus = ({ status }: APStatus) => { + switch (status) { + case APNetworkStatus.ACTIVE: + return LL.ACTIVE(); + case APNetworkStatus.INACTIVE: + return LL.INACTIVE(); + case APNetworkStatus.LINGERING: + return 'Lingering until idle'; + default: + return LL.UNKNOWN(); + } + }; + const content = () => { if (!data) { return ; @@ -56,7 +60,7 @@ const APStatusForm: FC = () => { - + @@ -87,7 +91,7 @@ const APStatusForm: FC = () => { @@ -95,7 +99,7 @@ const APStatusForm: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/framework/ap/AccessPoint.tsx b/interface/src/framework/ap/AccessPoint.tsx index 742db7b24..d90b645cc 100644 --- a/interface/src/framework/ap/AccessPoint.tsx +++ b/interface/src/framework/ap/AccessPoint.tsx @@ -8,8 +8,12 @@ import APStatusForm from './APStatusForm'; import APSettingsForm from './APSettingsForm'; import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from '../../components'; +import { useI18nContext } from '../../i18n/i18n-react'; + const AccessPoint: FC = () => { - useLayoutTitle('Access Point'); + const { LL } = useI18nContext(); + + useLayoutTitle(LL.ACCESS_POINT()); const authenticatedContext = useContext(AuthenticatedContext); @@ -18,8 +22,12 @@ const AccessPoint: FC = () => { return ( <> - - + + } /> diff --git a/interface/src/framework/mqtt/Mqtt.tsx b/interface/src/framework/mqtt/Mqtt.tsx index d44edb781..53ed3b44b 100644 --- a/interface/src/framework/mqtt/Mqtt.tsx +++ b/interface/src/framework/mqtt/Mqtt.tsx @@ -9,7 +9,11 @@ import { AuthenticatedContext } from '../../contexts/authentication'; import MqttStatusForm from './MqttStatusForm'; import MqttSettingsForm from './MqttSettingsForm'; +import { useI18nContext } from '../../i18n/i18n-react'; + const Mqtt: FC = () => { + const { LL } = useI18nContext(); + useLayoutTitle('MQTT'); const authenticatedContext = useContext(AuthenticatedContext); @@ -18,8 +22,8 @@ const Mqtt: FC = () => { return ( <> - - + + } /> diff --git a/interface/src/framework/mqtt/MqttSettingsForm.tsx b/interface/src/framework/mqtt/MqttSettingsForm.tsx index fe4f59fd8..1eecf0b55 100644 --- a/interface/src/framework/mqtt/MqttSettingsForm.tsx +++ b/interface/src/framework/mqtt/MqttSettingsForm.tsx @@ -1,7 +1,7 @@ import { FC, useState } from 'react'; import { ValidateFieldsError } from 'async-validator'; -import { Button, Checkbox, MenuItem, Grid, Typography } from '@mui/material'; +import { Button, Checkbox, MenuItem, Grid, Typography, InputAdornment } from '@mui/material'; import SaveIcon from '@mui/icons-material/Save'; import { MQTT_SETTINGS_VALIDATOR, validate } from '../../validators'; @@ -17,12 +17,16 @@ import { MqttSettings } from '../../types'; import { numberValue, updateValue, useRest } from '../../utils'; import * as MqttApi from '../../api/mqtt'; +import { useI18nContext } from '../../i18n/i18n-react'; + const MqttSettingsForm: FC = () => { const { loadData, saving, data, setData, saveData, errorMessage } = useRest({ read: MqttApi.readMqttSettings, update: MqttApi.updateMqttSettings }); + const { LL } = useI18nContext(); + const [fieldErrors, setFieldErrors] = useState(); const updateFormValue = updateValue(setData); @@ -46,7 +50,7 @@ const MqttSettingsForm: FC = () => { <> } - label="Enable MQTT" + label={LL.ENABLE_MQTT()} /> @@ -91,7 +95,7 @@ const MqttSettingsForm: FC = () => { { { { {LL.SECONDS()} + }} fullWidth variant="outlined" value={numberValue(data.keep_alive)} @@ -149,7 +156,7 @@ const MqttSettingsForm: FC = () => { margin="normal" select > - 0 (default) + 0 1 2 @@ -157,18 +164,18 @@ const MqttSettingsForm: FC = () => { } - label="Set Clean Session" + label={LL.MQTT_CLEAN_SESSION()} /> } - label="Always use Retain Flag" + label={LL.MQTT_RETAIN_FLAG()} /> - Formatting + {LL.FORMATTING()} { margin="normal" select > - Nested in a single topic - As individual topics + {LL.MQTT_NEST_1()} + {LL.MQTT_NEST_2()} } - label="Publish command output to a 'response' topic" + label={LL.MQTT_RESPONSE()} /> {!data.ha_enabled && ( } - label="Publish single value topics on change" + label={LL.MQTT_PUBLISH_TEXT_1()} /> {data.publish_single && ( @@ -197,7 +204,7 @@ const MqttSettingsForm: FC = () => { control={ } - label="Publish to command topics (ioBroker)" + label={LL.MQTT_PUBLISH_TEXT_2()} /> )} @@ -208,14 +215,14 @@ const MqttSettingsForm: FC = () => { } - label="Enable MQTT Discovery (Home Assistant, Domoticz)" + label={LL.MQTT_PUBLISH_TEXT_3()} /> {data.ha_enabled && ( { )} - Publish Intervals (in seconds, 0=automatic) + {LL.MQTT_PUBLISH_INTERVALS()} (0=auto) {LL.SECONDS()} + }} fullWidth variant="outlined" value={numberValue(data.publish_time_boiler)} @@ -247,7 +257,10 @@ const MqttSettingsForm: FC = () => { {LL.SECONDS()} + }} fullWidth variant="outlined" value={numberValue(data.publish_time_thermostat)} @@ -260,7 +273,10 @@ const MqttSettingsForm: FC = () => { {LL.SECONDS()} + }} fullWidth variant="outlined" value={numberValue(data.publish_time_solar)} @@ -273,7 +289,10 @@ const MqttSettingsForm: FC = () => { {LL.SECONDS()} + }} fullWidth variant="outlined" value={numberValue(data.publish_time_mixer)} @@ -286,7 +305,10 @@ const MqttSettingsForm: FC = () => { {LL.SECONDS()} + }} fullWidth variant="outlined" value={numberValue(data.publish_time_sensor)} @@ -299,7 +321,10 @@ const MqttSettingsForm: FC = () => { {LL.SECONDS()} + }} + label={LL.DEFAULT()} fullWidth variant="outlined" value={numberValue(data.publish_time_other)} @@ -318,7 +343,7 @@ const MqttSettingsForm: FC = () => { type="submit" onClick={validateAndSubmit} > - Save + {LL.SAVE()} @@ -326,7 +351,7 @@ const MqttSettingsForm: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/framework/mqtt/MqttStatusForm.tsx b/interface/src/framework/mqtt/MqttStatusForm.tsx index b39fff4c7..a889ec0fa 100644 --- a/interface/src/framework/mqtt/MqttStatusForm.tsx +++ b/interface/src/framework/mqtt/MqttStatusForm.tsx @@ -11,6 +11,8 @@ import { MqttStatus, MqttDisconnectReason } from '../../types'; import * as MqttApi from '../../api/mqtt'; import { useRest } from '../../utils'; +import { useI18nContext } from '../../i18n/i18n-react'; + export const mqttStatusHighlight = ({ enabled, connected }: MqttStatus, theme: Theme) => { if (!enabled) { return theme.palette.info.main; @@ -29,44 +31,46 @@ export const mqttPublishHighlight = ({ mqtt_fails }: MqttStatus, theme: Theme) = return theme.palette.error.main; }; -export const mqttStatus = ({ enabled, connected }: MqttStatus) => { - if (!enabled) { - return 'Not enabled'; - } - if (connected) { - return 'Connected'; - } - return 'Disconnected'; -}; - -export const disconnectReason = ({ disconnect_reason }: MqttStatus) => { - switch (disconnect_reason) { - case MqttDisconnectReason.TCP_DISCONNECTED: - return 'TCP disconnected'; - case MqttDisconnectReason.MQTT_UNACCEPTABLE_PROTOCOL_VERSION: - return 'Unacceptable protocol version'; - case MqttDisconnectReason.MQTT_IDENTIFIER_REJECTED: - return 'Client ID rejected'; - case MqttDisconnectReason.MQTT_SERVER_UNAVAILABLE: - return 'Server unavailable'; - case MqttDisconnectReason.MQTT_MALFORMED_CREDENTIALS: - return 'Malformed credentials'; - case MqttDisconnectReason.MQTT_NOT_AUTHORIZED: - return 'Not authorized'; - case MqttDisconnectReason.ESP8266_NOT_ENOUGH_SPACE: - return 'Device out of memory'; - case MqttDisconnectReason.TLS_BAD_FINGERPRINT: - return 'Server fingerprint invalid'; - default: - return 'Unknown'; - } -}; - const MqttStatusForm: FC = () => { const { loadData, data, errorMessage } = useRest({ read: MqttApi.readMqttStatus }); + const { LL } = useI18nContext(); + const theme = useTheme(); + const mqttStatus = ({ enabled, connected }: MqttStatus) => { + if (!enabled) { + return LL.NOT_ENABLED(); + } + if (connected) { + return LL.CONNECTED(); + } + return LL.DISCONNECTED(); + }; + + const disconnectReason = ({ disconnect_reason }: MqttStatus) => { + switch (disconnect_reason) { + case MqttDisconnectReason.TCP_DISCONNECTED: + return 'TCP disconnected'; + case MqttDisconnectReason.MQTT_UNACCEPTABLE_PROTOCOL_VERSION: + return 'Unacceptable protocol version'; + case MqttDisconnectReason.MQTT_IDENTIFIER_REJECTED: + return 'Client ID rejected'; + case MqttDisconnectReason.MQTT_SERVER_UNAVAILABLE: + return 'Server unavailable'; + case MqttDisconnectReason.MQTT_MALFORMED_CREDENTIALS: + return 'Malformed credentials'; + case MqttDisconnectReason.MQTT_NOT_AUTHORIZED: + return 'Not authorized'; + case MqttDisconnectReason.ESP8266_NOT_ENOUGH_SPACE: + return 'Device out of memory'; + case MqttDisconnectReason.TLS_BAD_FINGERPRINT: + return 'Server fingerprint invalid'; + default: + return 'Unknown'; + } + }; + const content = () => { if (!data) { return ; @@ -89,7 +93,7 @@ const MqttStatusForm: FC = () => { - + ); @@ -102,7 +106,7 @@ const MqttStatusForm: FC = () => { - + @@ -118,14 +122,14 @@ const MqttStatusForm: FC = () => { - + {data.enabled && renderConnectionStatus()} @@ -133,7 +137,7 @@ const MqttStatusForm: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/framework/network/NetworkConnection.tsx b/interface/src/framework/network/NetworkConnection.tsx index 27bf6d8cb..90ecda203 100644 --- a/interface/src/framework/network/NetworkConnection.tsx +++ b/interface/src/framework/network/NetworkConnection.tsx @@ -11,12 +11,16 @@ import NetworkStatusForm from './NetworkStatusForm'; import WiFiNetworkScanner from './WiFiNetworkScanner'; import NetworkSettingsForm from './NetworkSettingsForm'; +import { useI18nContext } from '../../i18n/i18n-react'; + const NetworkConnection: FC = () => { - useLayoutTitle('Network Connection'); + const { LL } = useI18nContext(); + useLayoutTitle(LL.NETWORK()); + + const { routerTab } = useRouterTab(); const authenticatedContext = useContext(AuthenticatedContext); const navigate = useNavigate(); - const { routerTab } = useRouterTab(); const [selectedNetwork, setSelectedNetwork] = useState(); @@ -41,9 +45,9 @@ const NetworkConnection: FC = () => { }} > - - - + + + } /> diff --git a/interface/src/framework/network/NetworkSettingsForm.tsx b/interface/src/framework/network/NetworkSettingsForm.tsx index c1221713d..2fb1e4294 100644 --- a/interface/src/framework/network/NetworkSettingsForm.tsx +++ b/interface/src/framework/network/NetworkSettingsForm.tsx @@ -10,7 +10,8 @@ import { ListItemAvatar, ListItemSecondaryAction, ListItemText, - Typography + Typography, + InputAdornment } from '@mui/material'; import LockOpenIcon from '@mui/icons-material/LockOpen'; @@ -36,7 +37,11 @@ import { ValidateFieldsError } from 'async-validator'; import { validate } from '../../validators'; import { createNetworkSettingsValidator } from '../../validators/network'; +import { useI18nContext } from '../../i18n/i18n-react'; + const WiFiSettingsForm: FC = () => { + const { LL } = useI18nContext(); + const { selectedNetwork, deselectNetwork } = useContext(WiFiConnectionContext); const [initialized, setInitialized] = useState(false); @@ -111,7 +116,7 @@ const WiFiSettingsForm: FC = () => { { { dBm + }} fullWidth variant="outlined" value={numberValue(data.tx_power)} @@ -146,21 +154,21 @@ const WiFiSettingsForm: FC = () => { } - label="Disable WiFi Sleep Mode" + label={LL.NETWORK_DISABLE_SLEEP()} /> } - label="Use Lower WiFi Bandwidth" + label={LL.NETWORK_LOW_BAND()} /> } - label="Enable mDNS Service" + label={LL.NETWORK_USE_DNS()} /> - General + {LL.GENERAL_OPTIONS()} { } - label="Enable IPv6 support" + label={LL.NETWORK_ENABLE_IPV6()} /> } - label="Use Fixed IP address" + label={LL.NETWORK_FIXED_IP()} /> {data.static_ip_config && ( <> @@ -246,7 +254,7 @@ const WiFiSettingsForm: FC = () => { type="submit" onClick={validateAndSubmit} > - Save + {LL.SAVE()} @@ -254,7 +262,7 @@ const WiFiSettingsForm: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/framework/network/NetworkStatusForm.tsx b/interface/src/framework/network/NetworkStatusForm.tsx index 986b60d14..eb99aa45b 100644 --- a/interface/src/framework/network/NetworkStatusForm.tsx +++ b/interface/src/framework/network/NetworkStatusForm.tsx @@ -14,6 +14,8 @@ import { NetworkConnectionStatus, NetworkStatus } from '../../types'; import * as NetworkApi from '../../api/network'; import { useRest } from '../../utils'; +import { useI18nContext } from '../../i18n/i18n-react'; + const isConnected = ({ status }: NetworkStatus) => status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED || status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED; @@ -35,29 +37,6 @@ const networkStatusHighlight = ({ status }: NetworkStatus, theme: Theme) => { } }; -const networkStatus = ({ status }: NetworkStatus) => { - switch (status) { - case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD: - return 'Inactive'; - case NetworkConnectionStatus.WIFI_STATUS_IDLE: - return 'Idle'; - case NetworkConnectionStatus.WIFI_STATUS_NO_SSID_AVAIL: - return 'No SSID Available'; - case NetworkConnectionStatus.WIFI_STATUS_CONNECTED: - return 'Connected (WiFi)'; - case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED: - return 'Connected (Ethernet)'; - case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED: - return 'Connection Failed'; - case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST: - return 'Connection Lost'; - case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED: - return 'Disconnected'; - default: - return 'Unknown'; - } -}; - export const isWiFi = ({ status }: NetworkStatus) => status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED; export const isEthernet = ({ status }: NetworkStatus) => status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED; @@ -81,8 +60,33 @@ const IPs = (status: NetworkStatus) => { const NetworkStatusForm: FC = () => { const { loadData, data, errorMessage } = useRest({ read: NetworkApi.readNetworkStatus }); + const { LL } = useI18nContext(); + const theme = useTheme(); + const networkStatus = ({ status }: NetworkStatus) => { + switch (status) { + case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD: + return LL.INACTIVE(); + case NetworkConnectionStatus.WIFI_STATUS_IDLE: + return LL.IDLE(); + case NetworkConnectionStatus.WIFI_STATUS_NO_SSID_AVAIL: + return 'No SSID Available'; + case NetworkConnectionStatus.WIFI_STATUS_CONNECTED: + return LL.CONNECTED() + ' (WiFi)'; + case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED: + return LL.CONNECTED() + ' (Ethernet)'; + case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED: + return LL.CONNECTED() + ' ' + LL.FAILED(); + case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST: + return LL.CONNECTED() + ' ' + LL.LOST(); + case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED: + return LL.DISCONNECTED(); + default: + return LL.UNKNOWN(); + } + }; + const content = () => { if (!data) { return ; @@ -162,7 +166,7 @@ const NetworkStatusForm: FC = () => { @@ -170,7 +174,7 @@ const NetworkStatusForm: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/framework/network/WiFiNetworkScanner.tsx b/interface/src/framework/network/WiFiNetworkScanner.tsx index 169bc6951..328888a94 100644 --- a/interface/src/framework/network/WiFiNetworkScanner.tsx +++ b/interface/src/framework/network/WiFiNetworkScanner.tsx @@ -12,6 +12,8 @@ import { ButtonRow, FormLoader, SectionContent } from '../../components'; import WiFiNetworkSelector from './WiFiNetworkSelector'; +import { useI18nContext } from '../../i18n/i18n-react'; + const NUM_POLLS = 10; const POLLING_FREQUENCY = 500; @@ -22,6 +24,8 @@ const compareNetworks = (network1: WiFiNetwork, network2: WiFiNetwork) => { }; const WiFiNetworkScanner: FC = () => { + const { LL } = useI18nContext(); + const { enqueueSnackbar } = useSnackbar(); const pollCount = useRef(0); @@ -46,7 +50,7 @@ const WiFiNetworkScanner: FC = () => { pollCount.current = completedPollCount; setTimeout(pollNetworkList, POLLING_FREQUENCY); } else { - finishedWithError('Device did not return network list in timely manner'); + finishedWithError(LL.PROBLEM_LOADING()); } } else { const newNetworkList = response.data; @@ -55,12 +59,12 @@ const WiFiNetworkScanner: FC = () => { } } catch (error: unknown) { if (error instanceof AxiosError) { - finishedWithError('Problem listing WiFi networks ' + error.response?.data.message); + finishedWithError(LL.PROBLEM_LOADING() + ' ' + error.response?.data.message); } else { - finishedWithError('Problem listing WiFi networks'); + finishedWithError(LL.PROBLEM_LOADING()); } } - }, [finishedWithError]); + }, [finishedWithError, LL]); const startNetworkScan = useCallback(async () => { pollCount.current = 0; @@ -71,12 +75,12 @@ const WiFiNetworkScanner: FC = () => { setTimeout(pollNetworkList, POLLING_FREQUENCY); } catch (error: unknown) { if (error instanceof AxiosError) { - finishedWithError('Problem scanning for WiFi networks ' + error.response?.data.message); + finishedWithError(LL.PROBLEM_LOADING() + ' ' + error.response?.data.message); } else { - finishedWithError('Problem scanning for WiFi networks'); + finishedWithError(LL.PROBLEM_LOADING()); } } - }, [finishedWithError, pollNetworkList]); + }, [finishedWithError, pollNetworkList, LL]); useEffect(() => { startNetworkScan(); @@ -84,13 +88,13 @@ const WiFiNetworkScanner: FC = () => { const renderNetworkScanner = () => { if (!networkList) { - return ; + return ; } return ; }; return ( - + {renderNetworkScanner()} diff --git a/interface/src/framework/network/WiFiNetworkSelector.tsx b/interface/src/framework/network/WiFiNetworkSelector.tsx index 960289ef6..b86f00efe 100644 --- a/interface/src/framework/network/WiFiNetworkSelector.tsx +++ b/interface/src/framework/network/WiFiNetworkSelector.tsx @@ -12,6 +12,8 @@ import { WiFiEncryptionType, WiFiNetwork, WiFiNetworkList } from '../../types'; import { WiFiConnectionContext } from './WiFiConnectionContext'; +import { useI18nContext } from '../../i18n/i18n-react'; + interface WiFiNetworkSelectorProps { networkList: WiFiNetworkList; } @@ -39,6 +41,8 @@ export const networkSecurityMode = ({ encryption_type }: WiFiNetwork) => { }; const WiFiNetworkSelector: FC = ({ networkList }) => { + const { LL } = useI18nContext(); + const wifiConnectionContext = useContext(WiFiConnectionContext); const renderNetwork = (network: WiFiNetwork) => { @@ -61,7 +65,7 @@ const WiFiNetworkSelector: FC = ({ networkList }) => { }; if (networkList.networks.length === 0) { - return ; + return ; } return {networkList.networks.map(renderNetwork)}; diff --git a/interface/src/framework/ntp/NTPSettingsForm.tsx b/interface/src/framework/ntp/NTPSettingsForm.tsx index 557239625..f538b87d9 100644 --- a/interface/src/framework/ntp/NTPSettingsForm.tsx +++ b/interface/src/framework/ntp/NTPSettingsForm.tsx @@ -12,12 +12,16 @@ import * as NTPApi from '../../api/ntp'; import { selectedTimeZone, timeZoneSelectItems, TIME_ZONES } from './TZ'; import { NTP_SETTINGS_VALIDATOR } from '../../validators/ntp'; +import { useI18nContext } from '../../i18n/i18n-react'; + const NTPSettingsForm: FC = () => { const { loadData, saving, data, setData, saveData, errorMessage } = useRest({ read: NTPApi.readNTPSettings, update: NTPApi.updateNTPSettings }); + const { LL } = useI18nContext(); + const updateFormValue = updateValue(setData); const [fieldErrors, setFieldErrors] = useState(); @@ -49,7 +53,7 @@ const NTPSettingsForm: FC = () => { <> } - label="Enable NTP" + label={LL.ENABLE_NTP()} /> { { margin="normal" select > - Time zone... + {LL.TIME_ZONE()}... {timeZoneSelectItems()} @@ -84,7 +88,7 @@ const NTPSettingsForm: FC = () => { type="submit" onClick={validateAndSubmit} > - Save + {LL.SAVE()} @@ -92,7 +96,7 @@ const NTPSettingsForm: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/framework/ntp/NTPStatusForm.tsx b/interface/src/framework/ntp/NTPStatusForm.tsx index 51182af5f..79934c92b 100644 --- a/interface/src/framework/ntp/NTPStatusForm.tsx +++ b/interface/src/framework/ntp/NTPStatusForm.tsx @@ -16,7 +16,8 @@ import { ListItemText, TextField, Theme, - useTheme + useTheme, + Typography } from '@mui/material'; import RefreshIcon from '@mui/icons-material/Refresh'; import AccessTimeIcon from '@mui/icons-material/AccessTime'; @@ -31,6 +32,8 @@ import { ButtonRow, FormLoader, SectionContent } from '../../components'; import { extractErrorMessage, formatDateTime, formatLocalDateTime, useRest } from '../../utils'; import { AuthenticatedContext } from '../../contexts/authentication'; +import { useI18nContext } from '../../i18n/i18n-react'; + export const isNtpActive = ({ status }: NTPStatus) => status === NTPSyncStatus.NTP_ACTIVE; export const isNtpEnabled = ({ status }: NTPStatus) => status !== NTPSyncStatus.NTP_DISABLED; @@ -47,19 +50,6 @@ export const ntpStatusHighlight = ({ status }: NTPStatus, theme: Theme) => { } }; -export const ntpStatus = ({ status }: NTPStatus) => { - switch (status) { - case NTPSyncStatus.NTP_DISABLED: - return 'Disabled'; - case NTPSyncStatus.NTP_INACTIVE: - return 'Inactive'; - case NTPSyncStatus.NTP_ACTIVE: - return 'Active'; - default: - return 'Unknown'; - } -}; - const NTPStatusForm: FC = () => { const { loadData, data, errorMessage } = useRest({ read: NTPApi.readNTPStatus }); const [localTime, setLocalTime] = useState(''); @@ -68,6 +58,8 @@ const NTPStatusForm: FC = () => { const { enqueueSnackbar } = useSnackbar(); const { me } = useContext(AuthenticatedContext); + const { LL } = useI18nContext(); + const updateLocalTime = (event: React.ChangeEvent) => setLocalTime(event.target.value); const openSetTime = () => { @@ -77,59 +69,71 @@ const NTPStatusForm: FC = () => { const theme = useTheme(); + const ntpStatus = ({ status }: NTPStatus) => { + switch (status) { + case NTPSyncStatus.NTP_DISABLED: + return LL.DISABLED(); + case NTPSyncStatus.NTP_INACTIVE: + return LL.INACTIVE(); + case NTPSyncStatus.NTP_ACTIVE: + return LL.ACTIVE(); + default: + return LL.UNKNOWN(); + } + }; + const configureTime = async () => { setProcessing(true); try { await NTPApi.updateTime({ local_time: formatLocalDateTime(new Date(localTime)) }); - enqueueSnackbar('Time set', { variant: 'success' }); + enqueueSnackbar(LL.TIME_SET(), { variant: 'success' }); setSettingTime(false); loadData(); } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem updating time'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); } finally { setProcessing(false); } }; - const renderSetTimeDialog = () => { - return ( - setSettingTime(false)}> - Set Time - - Enter local date and time below to set the device's time. - - - - - - - - ); - }; + const renderSetTimeDialog = () => ( + setSettingTime(false)}> + {LL.SET_TIME()} + + + {LL.SET_TIME_TEXT()} + + + + + + + + + ); const content = () => { if (!data) { @@ -145,7 +149,7 @@ const NTPStatusForm: FC = () => { - + {isNtpEnabled(data) && ( @@ -167,7 +171,7 @@ const NTPStatusForm: FC = () => { - + @@ -176,7 +180,7 @@ const NTPStatusForm: FC = () => { - + @@ -184,7 +188,7 @@ const NTPStatusForm: FC = () => { @@ -192,7 +196,7 @@ const NTPStatusForm: FC = () => { @@ -204,7 +208,7 @@ const NTPStatusForm: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/framework/ntp/NetworkTime.tsx b/interface/src/framework/ntp/NetworkTime.tsx index 309edff75..7e34e46c2 100644 --- a/interface/src/framework/ntp/NetworkTime.tsx +++ b/interface/src/framework/ntp/NetworkTime.tsx @@ -9,8 +9,11 @@ import { AuthenticatedContext } from '../../contexts/authentication'; import NTPStatusForm from './NTPStatusForm'; import NTPSettingsForm from './NTPSettingsForm'; +import { useI18nContext } from '../../i18n/i18n-react'; + const NetworkTime: FC = () => { - useLayoutTitle('Network Time'); + const { LL } = useI18nContext(); + useLayoutTitle("NTP"); const authenticatedContext = useContext(AuthenticatedContext); const { routerTab } = useRouterTab(); @@ -18,8 +21,8 @@ const NetworkTime: FC = () => { return ( <> - - + + } /> diff --git a/interface/src/framework/security/GenerateToken.tsx b/interface/src/framework/security/GenerateToken.tsx index 75296c946..6b28a0d72 100644 --- a/interface/src/framework/security/GenerateToken.tsx +++ b/interface/src/framework/security/GenerateToken.tsx @@ -19,6 +19,8 @@ import { MessageBox } from '../../components'; import * as SecurityApi from '../../api/security'; import { Token } from '../../types'; +import { useI18nContext } from '../../i18n/i18n-react'; + interface GenerateTokenProps { username?: string; onClose: () => void; @@ -28,15 +30,17 @@ const GenerateToken: FC = ({ username, onClose }) => { const [token, setToken] = useState(); const open = !!username; + const { LL } = useI18nContext(); + const { enqueueSnackbar } = useSnackbar(); const getToken = useCallback(async () => { try { setToken((await SecurityApi.generateToken(username)).data); } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem generating token'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); } - }, [username, enqueueSnackbar]); + }, [username, enqueueSnackbar, LL]); useEffect(() => { if (open) { @@ -46,16 +50,11 @@ const GenerateToken: FC = ({ username, onClose }) => { return ( - Access Token for {username} + {LL.ACCESS_TOKEN_FOR() + ' ' + username} {token ? ( <> - + @@ -63,13 +62,13 @@ const GenerateToken: FC = ({ username, onClose }) => { ) : ( - Generating token… + {LL.GENERATING_TOKEN()}… )} diff --git a/interface/src/framework/security/ManageUsersForm.tsx b/interface/src/framework/security/ManageUsersForm.tsx index c7b9324b8..827a5f5d8 100644 --- a/interface/src/framework/security/ManageUsersForm.tsx +++ b/interface/src/framework/security/ManageUsersForm.tsx @@ -20,6 +20,8 @@ import { createUserValidator } from '../../validators'; import { useRest } from '../../utils'; import { AuthenticatedContext } from '../../contexts/authentication'; +import { useI18nContext } from '../../i18n/i18n-react'; + import GenerateToken from './GenerateToken'; import UserForm from './UserForm'; @@ -34,9 +36,11 @@ const ManageUsersForm: FC = () => { const [generatingToken, setGeneratingToken] = useState(); const authenticatedContext = useContext(AuthenticatedContext); + const { LL } = useI18nContext(); + const table_theme = useTheme({ Table: ` - --data-table-library_grid-template-columns: repeat(1, minmax(0, 1fr)) 90px 120px; + --data-table-library_grid-template-columns: repeat(1, minmax(0, 1fr)) 120px 120px; `, BaseRow: ` font-size: 14px; @@ -136,8 +140,8 @@ const ManageUsersForm: FC = () => { <>
- USERNAME - IS ADMIN + {LL.USERNAME()} + {LL.IS_ADMIN()}
@@ -169,9 +173,7 @@ const ManageUsersForm: FC = () => { )} - {noAdminConfigured() && ( - - )} + {noAdminConfigured() && } @@ -183,14 +185,14 @@ const ManageUsersForm: FC = () => { type="submit" onClick={onSubmit} > - Save + {LL.SAVE()} @@ -210,7 +212,7 @@ const ManageUsersForm: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/framework/security/Security.tsx b/interface/src/framework/security/Security.tsx index f4f892407..3c5ca85ee 100644 --- a/interface/src/framework/security/Security.tsx +++ b/interface/src/framework/security/Security.tsx @@ -8,16 +8,19 @@ import { RouterTabs, useRouterTab, useLayoutTitle } from '../../components'; import SecuritySettingsForm from './SecuritySettingsForm'; import ManageUsersForm from './ManageUsersForm'; +import { useI18nContext } from '../../i18n/i18n-react'; + const Security: FC = () => { - useLayoutTitle('Security'); + const { LL } = useI18nContext(); + useLayoutTitle(LL.SECURITY()); const { routerTab } = useRouterTab(); return ( <> - - + + } /> diff --git a/interface/src/framework/security/SecuritySettingsForm.tsx b/interface/src/framework/security/SecuritySettingsForm.tsx index 0a300a3a2..1d2c65baa 100644 --- a/interface/src/framework/security/SecuritySettingsForm.tsx +++ b/interface/src/framework/security/SecuritySettingsForm.tsx @@ -11,7 +11,11 @@ import { SECURITY_SETTINGS_VALIDATOR, validate } from '../../validators'; import { updateValue, useRest } from '../../utils'; import { AuthenticatedContext } from '../../contexts/authentication'; +import { useI18nContext } from '../../i18n/i18n-react'; + const SecuritySettingsForm: FC = () => { + const { LL } = useI18nContext(); + const [fieldErrors, setFieldErrors] = useState(); const { loadData, saving, data, setData, saveData, errorMessage } = useRest({ read: SecurityApi.readSecuritySettings, @@ -42,7 +46,7 @@ const SecuritySettingsForm: FC = () => { { /> @@ -63,7 +67,7 @@ const SecuritySettingsForm: FC = () => { type="submit" onClick={validateAndSubmit} > - Save + {LL.SAVE()} @@ -71,7 +75,7 @@ const SecuritySettingsForm: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/framework/security/UserForm.tsx b/interface/src/framework/security/UserForm.tsx index 4a82f08a9..7a8f0d105 100644 --- a/interface/src/framework/security/UserForm.tsx +++ b/interface/src/framework/security/UserForm.tsx @@ -11,6 +11,8 @@ import { User } from '../../types'; import { updateValue } from '../../utils'; import { validate } from '../../validators'; +import { useI18nContext } from '../../i18n/i18n-react'; + interface UserFormProps { creating: boolean; validator: Schema; @@ -23,6 +25,8 @@ interface UserFormProps { } const UserForm: FC = ({ creating, validator, user, setUser, onDoneEditing, onCancelEditing }) => { + const { LL } = useI18nContext(); + const updateFormValue = updateValue(setUser); const [fieldErrors, setFieldErrors] = useState(); const open = !!user; @@ -49,12 +53,14 @@ const UserForm: FC = ({ creating, validator, user, setUser, onDon {user && ( <> - {creating ? 'Add' : 'Modify'} User + + {creating ? LL.ADD() : LL.MODIFY()} {LL.USER()} + = ({ creating, validator, user, setUser, onDon = ({ creating, validator, user, setUser, onDon /> } - label="is Admin?" + label={LL.IS_ADMIN()} /> diff --git a/interface/src/framework/system/GeneralFileUpload.tsx b/interface/src/framework/system/GeneralFileUpload.tsx index d634a7f11..d301e517f 100644 --- a/interface/src/framework/system/GeneralFileUpload.tsx +++ b/interface/src/framework/system/GeneralFileUpload.tsx @@ -14,6 +14,8 @@ import { extractErrorMessage } from '../../utils'; import * as EMSESP from '../../project/api'; +import { useI18nContext } from '../../i18n/i18n-react'; + interface UploadFileProps { uploadGeneralFile: (file: File, config?: FileUploadConfig) => AxiosPromise; } @@ -23,6 +25,8 @@ const GeneralFileUpload: FC = ({ uploadGeneralFile }) => { const { enqueueSnackbar } = useSnackbar(); + const { LL } = useI18nContext(); + const saveFile = (json: any, endpoint: string) => { const a = document.createElement('a'); const filename = 'emsesp_' + endpoint + '.json'; @@ -35,19 +39,19 @@ const GeneralFileUpload: FC = ({ uploadGeneralFile }) => { document.body.appendChild(a); a.click(); document.body.removeChild(a); - enqueueSnackbar('File downloaded', { variant: 'info' }); + enqueueSnackbar(LL.DOWNLOAD_SUCCESSFUL(), { variant: 'info' }); }; const downloadSettings = async () => { try { const response = await EMSESP.getSettings(); if (response.status !== 200) { - enqueueSnackbar('Unable to get settings', { variant: 'error' }); + enqueueSnackbar(LL.PROBLEM_LOADING(), { variant: 'error' }); } else { saveFile(response.data, 'settings'); } } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem with downloading'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' }); } }; @@ -55,47 +59,45 @@ const GeneralFileUpload: FC = ({ uploadGeneralFile }) => { try { const response = await EMSESP.getCustomizations(); if (response.status !== 200) { - enqueueSnackbar('Unable to get customizations', { variant: 'error' }); + enqueueSnackbar(LL.PROBLEM_LOADING(), { variant: 'error' }); } else { saveFile(response.data, 'customizations'); } } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem with downloading'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' }); } }; return ( <> - - Upload - {!uploading && ( - - - Upload a new firmware (.bin) file, settings or customizations (.json) file below. + <> + + {LL.UPLOAD()} - + + {LL.UPLOAD_TEXT()} + + )} - - Download - {!uploading && ( <> + + {LL.DOWNLOAD()} + - Download the application settings. Be careful when sharing your settings as this file contains passwords - and other sensitive system information. + {LL.DOWNLOAD_SETTINGS_TEXT()} - - Download the entity customizations. + {LL.DOWNLOAD_CUSTOMIZATION_TEXT()}{' '} )} diff --git a/interface/src/framework/system/OTASettingsForm.tsx b/interface/src/framework/system/OTASettingsForm.tsx index cec00f8d2..a35ecc741 100644 --- a/interface/src/framework/system/OTASettingsForm.tsx +++ b/interface/src/framework/system/OTASettingsForm.tsx @@ -12,6 +12,7 @@ import { ValidatedPasswordField, ValidatedTextField } from '../../components'; + import { OTASettings } from '../../types'; import { numberValue, updateValue, useRest } from '../../utils'; @@ -19,12 +20,16 @@ import { ValidateFieldsError } from 'async-validator'; import { validate } from '../../validators'; import { OTA_SETTINGS_VALIDATOR } from '../../validators/system'; +import { useI18nContext } from '../../i18n/i18n-react'; + const OTASettingsForm: FC = () => { const { loadData, saving, data, setData, saveData, errorMessage } = useRest({ read: SystemApi.readOTASettings, update: SystemApi.updateOTASettings }); + const { LL } = useI18nContext(); + const updateFormValue = updateValue(setData); const [fieldErrors, setFieldErrors] = useState(); @@ -48,7 +53,7 @@ const OTASettingsForm: FC = () => { <> } - label="Enable OTA Updates" + label={LL.ENABLE_OTA()} /> { { type="submit" onClick={validateAndSubmit} > - Save + {LL.SAVE()} @@ -88,7 +93,7 @@ const OTASettingsForm: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/framework/system/RestartMonitor.tsx b/interface/src/framework/system/RestartMonitor.tsx index 3e832f302..c8eb8cb42 100644 --- a/interface/src/framework/system/RestartMonitor.tsx +++ b/interface/src/framework/system/RestartMonitor.tsx @@ -4,6 +4,8 @@ import { FC, useRef, useState } from 'react'; import * as SystemApi from '../../api/system'; import { FormLoader } from '../../components'; +import { useI18nContext } from '../../i18n/i18n-react'; + const RESTART_TIMEOUT = 2 * 60 * 1000; const POLL_TIMEOUT = 2000; const POLL_INTERVAL = 5000; @@ -12,6 +14,8 @@ const RestartMonitor: FC = () => { const [failed, setFailed] = useState(false); const [timeoutId, setTimeoutId] = useState(); + const { LL } = useI18nContext(); + const timeoutAt = useRef(new Date().getTime() + RESTART_TIMEOUT); const poll = useRef(async () => { try { @@ -32,12 +36,7 @@ const RestartMonitor: FC = () => { useEffect(() => () => timeoutId && clearTimeout(timeoutId), [timeoutId]); - return ( - - ); + return ; }; export default RestartMonitor; diff --git a/interface/src/framework/system/System.tsx b/interface/src/framework/system/System.tsx index e8e38e391..3d77ebd06 100644 --- a/interface/src/framework/system/System.tsx +++ b/interface/src/framework/system/System.tsx @@ -12,8 +12,13 @@ import OTASettingsForm from './OTASettingsForm'; import SystemLog from './SystemLog'; +import { useI18nContext } from '../../i18n/i18n-react'; + const System: FC = () => { - useLayoutTitle('System'); + + const { LL } = useI18nContext(); + + useLayoutTitle(LL.SYSTEM()); const { me } = useContext(AuthenticatedContext); const { features } = useContext(FeaturesContext); @@ -22,11 +27,11 @@ const System: FC = () => { return ( <> - - + + - {features.ota && } - {features.upload_firmware && } + {features.ota && } + {features.upload_firmware && } } /> diff --git a/interface/src/framework/system/SystemLog.tsx b/interface/src/framework/system/SystemLog.tsx index 9d5413aa6..dff0c3f1d 100644 --- a/interface/src/framework/system/SystemLog.tsx +++ b/interface/src/framework/system/SystemLog.tsx @@ -15,6 +15,9 @@ import DownloadIcon from '@mui/icons-material/GetApp'; import { useSnackbar } from 'notistack'; import { EVENT_SOURCE_ROOT } from '../../api/endpoints'; + +import { useI18nContext } from '../../i18n/i18n-react'; + export const LOG_EVENTSOURCE_URL = EVENT_SOURCE_ROOT + 'log'; const useWindowSize = () => { @@ -63,6 +66,8 @@ const levelLabel = (level: LogLevel) => { const SystemLog: FC = () => { useWindowSize(); + const { LL } = useI18nContext(); + const { loadData, data, setData } = useRest({ read: SystemApi.readLogSettings }); @@ -104,10 +109,10 @@ const SystemLog: FC = () => { compact: data.compact }); if (response.status !== 200) { - enqueueSnackbar('Problem applying log settings', { variant: 'error' }); + enqueueSnackbar(LL.PROBLEM_UPDATING(), { variant: 'error' }); } } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem applying log settings'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); } } }; @@ -159,9 +164,9 @@ const SystemLog: FC = () => { try { setLogEntries((await SystemApi.readLogEntries()).data); } catch (error: unknown) { - setErrorMessage(extractErrorMessage(error, 'Failed to fetch log')); + setErrorMessage(extractErrorMessage(error, LL.PROBLEM_LOADING())); } - }, []); + }, [LL]); useEffect(() => { fetchLog(); @@ -214,7 +219,7 @@ const SystemLog: FC = () => { - Buffer size + {LL.BUFFER_SIZE()} { } - label="Compact" + label={LL.COMPACT()} /> @@ -273,7 +278,7 @@ const SystemLog: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/framework/system/SystemStatusForm.tsx b/interface/src/framework/system/SystemStatusForm.tsx index 52c1a3a4b..29f9e0893 100644 --- a/interface/src/framework/system/SystemStatusForm.tsx +++ b/interface/src/framework/system/SystemStatusForm.tsx @@ -39,6 +39,8 @@ import { AuthenticatedContext } from '../../contexts/authentication'; import axios from 'axios'; +import { useI18nContext } from '../../i18n/i18n-react'; + export const VERSIONCHECK_ENDPOINT = 'https://api.github.com/repos/emsesp/EMS-ESP32/releases/latest'; export const VERSIONCHECK_DEV_ENDPOINT = 'https://api.github.com/repos/emsesp/EMS-ESP32/releases/tags/latest'; export const uploadURL = window.location.origin + '/system/upload'; @@ -48,6 +50,8 @@ function formatNumber(num: number) { } const SystemStatusForm: FC = () => { + const { LL } = useI18nContext(); + const { loadData, data, errorMessage } = useRest({ read: SystemApi.readSystemStatus }); const { me } = useContext(AuthenticatedContext); @@ -80,9 +84,9 @@ const SystemStatusForm: FC = () => { setProcessing(true); try { await SystemApi.restart(); - enqueueSnackbar('EMS-ESP is restarting...', { variant: 'info' }); + enqueueSnackbar(LL.APPLICATION_RESTARTING(), { variant: 'info' }); } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem restarting device'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' }); } finally { setConfirmRestart(false); setProcessing(false); @@ -92,7 +96,7 @@ const SystemStatusForm: FC = () => { const renderRestartDialog = () => ( setConfirmRestart(false)}> Restart - Are you sure you want to restart EMS-ESP? + {LL.RESTART_TEXT()} @@ -119,16 +123,12 @@ const SystemStatusForm: FC = () => { const renderVersionDialog = () => { return ( setShowingVersion(false)}> - Version Check + {LL.VERSION_CHECK()} - + {latestVersion && ( - The latest official version is {latestVersion.version} ( + {LL.THE_LATEST()} official version is {latestVersion.version} ( {'release notes'} @@ -142,7 +142,7 @@ const SystemStatusForm: FC = () => { {latestDevVersion && ( - The latest development version is {latestDevVersion.version} + {LL.THE_LATEST()} development version is {latestDevVersion.version}  ( {'release notes'} @@ -157,17 +157,17 @@ const SystemStatusForm: FC = () => { - Use  + {LL.USE()}  {'UPLOAD'} -  to apply the new firmware +  {LL.SYSTEM_APPLY_FIRMWARE()} @@ -178,9 +178,9 @@ const SystemStatusForm: FC = () => { setProcessing(true); try { await SystemApi.factoryReset(); - enqueueSnackbar('Device has been factory reset and will now restart', { variant: 'info' }); + enqueueSnackbar(LL.SYSTEM_FACTORY_TEXT(), { variant: 'info' }); } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem factory resetting the device'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); } finally { setConfirmFactoryReset(false); setProcessing(false); @@ -189,8 +189,8 @@ const SystemStatusForm: FC = () => { const renderFactoryResetDialog = () => ( setConfirmFactoryReset(false)}> - Factory Reset - Are you sure you want to reset the device to its factory defaults? + {LL.FACTORY_RESET()} + {LL.SYSTEM_FACTORY_TEXT_DIALOG()} @@ -231,7 +231,7 @@ const SystemStatusForm: FC = () => { {latestVersion && ( )} @@ -242,7 +242,7 @@ const SystemStatusForm: FC = () => { - + @@ -251,7 +251,7 @@ const SystemStatusForm: FC = () => { - + @@ -260,7 +260,7 @@ const SystemStatusForm: FC = () => { - + @@ -270,7 +270,7 @@ const SystemStatusForm: FC = () => { { @@ -304,7 +304,7 @@ const SystemStatusForm: FC = () => { { { @@ -348,7 +348,7 @@ const SystemStatusForm: FC = () => { color="primary" onClick={() => setConfirmRestart(true)} > - Restart + {LL.RESTART()} @@ -370,7 +370,7 @@ const SystemStatusForm: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/framework/system/UploadFileForm.tsx b/interface/src/framework/system/UploadFileForm.tsx index 67db93083..5a5948217 100644 --- a/interface/src/framework/system/UploadFileForm.tsx +++ b/interface/src/framework/system/UploadFileForm.tsx @@ -7,9 +7,13 @@ import { FileUploadConfig } from '../../api/endpoints'; import GeneralFileUpload from './GeneralFileUpload'; import RestartMonitor from './RestartMonitor'; +import { useI18nContext } from '../../i18n/i18n-react'; + const UploadFileForm: FC = () => { const [restarting, setRestarting] = useState(); + const { LL } = useI18nContext(); + const uploadFile = useRef(async (file: File, config?: FileUploadConfig) => { const response = await SystemApi.uploadFile(file, config); setRestarting(true); @@ -17,7 +21,7 @@ const UploadFileForm: FC = () => { }); return ( - + {restarting ? : } ); diff --git a/interface/src/i18n/DE.svg b/interface/src/i18n/DE.svg new file mode 100644 index 000000000..df0775b2f --- /dev/null +++ b/interface/src/i18n/DE.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/interface/src/i18n/GB.svg b/interface/src/i18n/GB.svg new file mode 100644 index 000000000..4ada58ad3 --- /dev/null +++ b/interface/src/i18n/GB.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/interface/src/i18n/NL.svg b/interface/src/i18n/NL.svg new file mode 100644 index 000000000..016746af6 --- /dev/null +++ b/interface/src/i18n/NL.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/interface/src/i18n/NO.svg b/interface/src/i18n/NO.svg new file mode 100644 index 000000000..28a0c5df3 --- /dev/null +++ b/interface/src/i18n/NO.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/interface/src/i18n/PL.svg b/interface/src/i18n/PL.svg new file mode 100644 index 000000000..82b564b8c --- /dev/null +++ b/interface/src/i18n/PL.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/interface/src/i18n/SE.svg b/interface/src/i18n/SE.svg new file mode 100644 index 000000000..7ec1787a5 --- /dev/null +++ b/interface/src/i18n/SE.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts new file mode 100644 index 000000000..bf4a8f805 --- /dev/null +++ b/interface/src/i18n/de/index.ts @@ -0,0 +1,265 @@ +import type { Translation } from '../i18n-types'; + +const de: Translation = { + LANGUAGE: 'Sprache', + RETRY: 'Neuer Versuch', + LOADING: 'Laden', + IS_REQUIRED: 'ist erforderlich', + SIGN_IN: 'Einloggen', + SIGN_OUT: 'Ausloggen', + USERNAME: 'Nutzername', + PASSWORD: 'Passwort', + DASHBOARD: 'Kontrollzentrum', + SETTINGS: 'Einstellungen', + SAVED: 'gespeichert', + HELP: 'Hilfe', + LOGGED_IN: 'Eingeloggt als {name}', + PLEASE_SIGNIN: 'Bitte einloggen, um fortzufahren', + UPLOAD_SUCCESSFUL: 'Hochladen erfolgreich', + DOWNLOAD_SUCCESSFUL: 'Herunterladen erfolgreich', + INVALID_LOGIN: 'Ungültige Login Daten', + NETWORK: 'Netzwerk', + SECURITY: 'Sicherheit', + ONOFF_CAP: 'AN/AUS', + ONOFF: 'an/aus', + TYPE: 'Typ', + DESCRIPTION: 'Bezeichnung', + ENTITIES: 'Entitäten', + REFRESH: 'Aktualisieren', + EXPORT: 'Exportieren', + DEVICE_DETAILS: 'Geräte Details', + BRAND: 'Marke', + ENTITY_NAME: 'Entitätsname', + VALUE: 'Wert', + SHOW_FAV: 'nur Favoriten anzeigen', + DEVICE_SENSOR_DATA: 'Geräte- und Sensordaten', + DEVICES_SENSORS: 'Geräte & Sensoren', + ATTACHED_SENSORS: 'Angeschlossene EMS-ESP Sensoren', + RUN_COMMAND: 'Befehl ausführen', + CHANGE_VALUE: 'Wert ändern', + CANCEL: 'Abbrechen', + RESET: 'Zurücksetzen', + SEND: 'Senden', + SAVE: 'Speichern', + REMOVE: 'Entfernen', + PROBLEM_UPDATING: 'Problem beim Aktualisieren', + PROBLEM_LOADING: 'Problem beim Laden', + ACCESS_DENIED: 'Zugriff abgelehnt', + ANALOG_SENSOR: 'Analogsensor', + ANALOG_SENSORS: 'Analogsensoren', + UPDATED: 'Aktualisiert', + UPDATE: 'Aktualisieren', + REMOVED: 'Entfernt', + DELETION: 'Löschung', + OFFSET: 'Addition', + FACTOR: 'Faktor', + FREQ: 'Frequenz', + STARTVALUE: 'Startwert', + WARN_GPIO: 'Warnung: Vorsicht bei der korrekten Wahl des GPIO!', + EDIT: 'Editiere', + TEMP_SENSOR: 'Temperatursensor', + TEMP_SENSORS: 'Temperatursensoren', + WRITE_COMMAND: 'Befehl schreiben {cmd}', + EMS_BUS_WARNING: + 'EMS-Bus getrennt. Wenn diese Warnung nach einigen Sekunden immer noch besteht, überprüfen Sie bitte die Einstellungen und das Board-Profil', + EMS_BUS_SCANNING: 'Suche nach EMS Geräten...', + CONNECTED: 'Verbunden', + TX_ISSUES: 'Tx-Probleme - versuchen Sie einen anderen Tx-Modus', + DISCONNECTED: 'Getrennt', + EMS_SCAN: 'Möchten Sie wirklich eine vollständige Gerätesuche des EMS-Busses starten?', + EMS_BUS_STATUS: 'EMS-Busstatus', + ACTIVE_DEVICES: 'Aktive Geräte und Sensoren', + DEVICE: 'Gerät', + SUCCESS: 'ERFOLG', + FAIL: 'FEHLER', + QUALITY: 'QUALITÄT', + SCAN_DEVICES: 'Nach neuen Geräten suchen', + EMS_BUS_STATUS_TITLE: 'EMS-Bus- und Aktivitätsstatus', + SCAN: 'Suche', + STATUS_NAMES: [ + 'EMS-Telegramme empfangen (Rx)', + 'EMS-Telegramme gelesen (Tx)', + 'EMS-Telegramme geschrieben (Tx)', + 'Temperatursensoren gelesen', + 'Analogsensoren gelesen', + 'MQTT-Nachrichten gesendet', + 'API-Aufrufe', + 'Syslog-Mitteilungen' + ], + NUM_DEVICES: '{num} Gerät{{e}}', + NUM_TEMP_SENSORS: '{num} Temperatursensor{{en}}', + NUM_ANALOG_SENSORS: '{num} Analogsensor{{en}}', + NUM_DAYS: '{num} Tag{{e}}', + NUM_SECONDS: '{num} Sekunde{{n}}', + NUM_HOURS: '{num} Stunde{{n}}', + NUM_MINUTES: '{num} Minute{{n}}', + APPLICATION_SETTINGS: 'Anwendungseinstellungen', + CUSTOMIZATION: 'Anpassungen', + APPLICATION_RESTARTING: 'EMS-ESP startet neu', + BOARD_PROFILE_TEXT: + 'Wählen Sie ein vorkonfiguriertes Platinenprofil aus der Liste unten aus oder wählen Sie "Custom", um Ihre eigenen Hardwareeinstellungen zu konfigurieren', + BOARD_PROFILE: 'Platinenprofil', + BUTTON: 'Taste', + TEMPERATURE: 'Temperatur', + DISABLED: 'deaktiviert', + GENERAL_OPTIONS: 'Allgemeine Optionen', + LANGUAGE_ENTITIES: 'Sprache (für Geräteentitäten)', + HIDE_LED: 'LED ausblenden', + ENABLE_TELNET: 'Aktiviere Telnet Konsole', + ENABLE_ANALOG: 'Aktiviere Analogsensorsen', + CONVERT_FAHRENHEIT: 'Konvertiere Temperaturwerte in Fahrenheit', + BYPASS_TOKEN: 'Zugriffstoken-Autorisierung bei API-Aufrufen umgehen', + READONLY: 'Nur-Lese-Modus aktivieren (blockiert alle ausgehenden EMS Tx Write-Befehle)', + UNDERCLOCK_CPU: 'CPU-Geschwindigkeit untertakten', + ENABLE_SHOWER_TIMER: 'Duschtimer aktivieren', + ENABLE_SHOWER_ALERT: 'Duschalarm aktivieren', + TRIGGER_TIME: 'Auslösezeit', + COLD_SHOT_DURATION: 'Kaltschussdauer', + FORMATTING_OPTIONS: 'Formatierungsoptionen', + BOOLEAN_FORMAT_DASHBOARD: 'Boolsches Format für Web', + BOOLEAN_FORMAT_API: 'Boolesches Format API/MQTT', + ENUM_FORMAT: 'Enum Format API/MQTT', + INDEX: 'Index', + ENABLE_PARASITE: 'Parasitäre Stomversorgung', + LOGGING: 'Protokollierung', + LOG_HEX: 'EMS-Telegramme hexadezimal protokollieren', + ENABLE_SYSLOG: 'Syslog aktivieren', + MARK_INTERVAL: 'Intervallmarke', + SECONDS: 'Sekunden', + MINUTES: 'Minuten', + HOURS: 'Stunden', + RESTART: 'Neu starten', + RESTART_TEXT: 'EMS-ESP muss neu gestartet werden, um geänderte Systemeinstellungen zu übernehmen', + COMMAND: 'Befehl', + CUSTOMIZATIONS_RESTART: 'Alle Anpassungen wurden entfernt. Neustart...', + CUSTOMIZATIONS_FULL: 'Ausgewählte Entitäten haben das Limit überschritten. Bitte stapelweise speichern', + CUSTOMIZATIONS_SAVED: 'Anpassungen gespeichert', + CUSTOMIZATIONS_HELP_1: 'Wählen Sie ein Gerät aus und passen Sie die Entitäten mithilfe der Optionen an', + CUSTOMIZATIONS_HELP_2: 'als Favorit markieren', + CUSTOMIZATIONS_HELP_3: 'Schreibaktion deaktivieren', + CUSTOMIZATIONS_HELP_4: 'von MQTT und API ausschließen', + CUSTOMIZATIONS_HELP_5: 'Aus dem Kontrollzentrum ausblenden', + SELECT_DEVICE: 'Wählen Sie ein Gerät aus', + SET_ALL: 'setzen Sie alle', + OPTIONS: 'Optionen', + NAME: 'Name', + CUSTOMIZATIONS_RESET: + 'Möchten Sie wirklich alle Anpassungen entfernen, einschließlich der benutzerdefinierten Einstellungen der Temperatur- und Analogsensoren?', + DEVICE_ENTITIES: 'Geräteentitäten', + USER_CUSTOMIZATION: 'Benutzeranpassung', + SUPPORT_INFORMATION: 'Unterstützende Informationen', + CLICK_HERE: 'Hier klicken', + HELP_INFORMATION_1: 'EMS-ESP Konfigurationsanweisungen und mehr finden Sie im Online-Wiki', + HELP_INFORMATION_2: 'Für einen Live-Community-Chat besuchen Sie unseren Discord-Server', + HELP_INFORMATION_3: 'Um neue Funktionen anzufragen oder Fehler zu melden, eröffnen Sie ein Issue auf Github', + HELP_INFORMATION_4: 'Bitte laden Sie die System-Details und hängen Sie sie an das Support-Issue an. ', + HELP_INFORMATION_5: + 'EMS-ESP ist ein freies Open-Source Projekt. Bitte unterstützen Sie die zukünftige Entwicklung mit einem "Star" auf Github!', + SUPPORT_INFO: 'Support Info', + UPLOAD: 'Hochladen', + DOWNLOAD: 'Herunterladen', + ABORTED: 'abgebrochen', + FAILED: 'gescheitert', + SUCCESSFUL: 'erfolgreich', + SYSTEM: 'System', + LOG: 'Log', + STATUS: 'Status', + UPLOAD_DOWNLOAD: 'Hoch-/Herunterladen', + SYSTEM_VERSION_RUNNING: 'Sie verwenden die Version', + SYSTEM_APPLY_FIRMWARE: 'um die neue Firmware anzuwenden', + CLOSE: 'Schließen', + USE: 'Verwenden', + FACTORY_RESET: 'Werkseinstellung', + SYSTEM_FACTORY_TEXT: 'EMS-ESP wurde auf Werkseinstellung gesetzt und startet als Zugangspunkt neu', + SYSTEM_FACTORY_TEXT_DIALOG: 'Sind Sie sicher alle Einstellungen auf Werkseinstellung zu setzen?', + VERSION_CHECK: 'Versionsprüfung', + THE_LATEST: 'Die neueste', + PLATFORM: 'Platform (Platform / SDK)', + UPTIME: 'System Betriebszeit', + CPU_FREQ: 'CPU Frequenz', + HEAP: 'RAM Speicher (Frei / Max Belegt)', + PSRAM: 'PSRAM (Größe / Frei)', + FLASH: 'Flash Speicher (Größe / Geschwindigkeit)', + FILESYSTEM: 'Dateisystem (Genutzt / Gesamt)', + BUFFER_SIZE: 'Puffergröße', + COMPACT: 'Kompakte Darstellung', + ENABLE_OTA: 'OTA Updates verwenden', + DOWNLOAD_CUSTOMIZATION_TEXT: 'Herunterladen der individuellen Entitätsanpassungen', + DOWNLOAD_SETTINGS_TEXT: + 'Herunterladen der Anwendungseinstellungen. Vorsicht beim Teilen der Einstellungen, da sie Passwörter und andere sensitive Einstellungen enthalten', + UPLOAD_TEXT: 'Hochladen von neuer Firmware (.bin), Geräte- oder Entitätseinstellungen (.json)', + UPLOADING: 'Hochladen', + UPLOAD_DROP_TEXT: 'Klicken Sie hier, oder ziehen eine Datei hierher', + ERROR: 'Unerwarteter Fehler, bitter versuchen Sie es erneut', + TIME_SET: 'Zeit gesetzt', + MANAGE_USERS: 'Nutzerverwaltung', + IS_ADMIN: 'ist Admin', + USER_WARNING: 'Sie müssen mindestens einen Admin-Nutzer konfigurieren', + ADD: 'Hinzufügen', + ACCESS_TOKEN_FOR: 'Zugangs-Token für', + ACCESS_TOKEN_TEXT: + 'Dieses Token ist für REST API Aufrufe bestimmt, die eine Authentifizierung benötigen. Es kann entweder als Bearer Token im `Authorization-Header` oder in der Access_Token URL verwendet werden.', + GENERATING_TOKEN: 'Erzeuge Token', + USER: 'Nutzer', + MODIFY: 'Ändern', + SU_TEXT: + 'Das su (super user) Passwort wird zum Signieren der Authentifikations-Tokens verwendet und ermöglicht Admin-Berechtigung in der Konsole.', + NOT_ENABLED: 'Nicht aktiviert', + ERRORS: 'Fehler', + DISCONNECT_REASON: 'Grund der Verbindungsunterbrechung', + ENABLE_MQTT: 'MQTT aktivieren', + OPTIONAL: 'Optional', + FORMATTING: 'Formattierung', + FORMAT: 'Format', + MQTT_NEST_1: 'Als Nester in in einem Gesamttopic', + MQTT_NEST_2: 'Als einzelne Topics', + MQTT_RESPONSE: 'Veröffentliche die Kommandoantwort als `response` Topic', + MQTT_PUBLISH_TEXT_1: 'Veröffentliche einzelne Werte bei Veränderung als eigene Topics', + MQTT_PUBLISH_TEXT_2: 'Veröffentliche als Kommando-Topic (ioBroker)', + MQTT_PUBLISH_TEXT_3: 'Aktiviere `MQTT Discovery` (Home Assistant, Domoticz)', + MQTT_PUBLISH_TEXT_4: 'Prefix für die `Discovery`-Topics', + MQTT_PUBLISH_INTERVALS: 'Veröffentlichungs-Intervalle', + MQTT_INT_BOILER: 'Boiler und Wärmepumpen', + MQTT_INT_THERMOSTATS: 'Thermostate', + MQTT_INT_SOLAR: 'Solarmodule', + MQTT_INT_MIXER: 'Mischermodule', + DEFAULT: 'Standard', + MQTT_CLEAN_SESSION: 'Setze `Clean Session`', + MQTT_RETAIN_FLAG: 'Setze `Retain flag` immer', + INACTIVE: 'Inaktiv', + ACTIVE: 'Aktiv', + UNKNOWN: 'Unbekannt', + SET_TIME: 'Zeiteinstellung', + SET_TIME_TEXT: 'Geben Sie das lokale Datum und die Zeit ein', + LOCAL_TIME: 'Lokalzeit', + UTC_TIME: 'UTC Zeit', + ENABLE_NTP: 'Aktiviere NTP', + TIME_ZONE: 'Zeitzone', + ACCESS_POINT: 'Zugangspunkt', + AP_PROVIDE: 'Aktiviere Zugangspunkt', + AP_PROVIDE_TEXT_1: 'Immer', + AP_PROVIDE_TEXT_2: 'Wenn WiFi nicht verbunden', + AP_PROVIDE_TEXT_3: 'Niemals', + AP_PREFERRED_CHANNEL: 'Bevorzugter Kanal', + AP_HIDE_SSID: 'Verstecke SSID', + NETWORK_SCAN: 'Suche nach WiFi Netzwerken', + IDLE: 'Leerlauf', + LOST: 'Verloren', + SCANNING: 'Suche', + SCAN_AGAIN: 'Erneute Suche', + NETWORK_SCANNER: 'Netzwerk Suche', + NETWORK_NO_WIFI: 'Keine WiFi Netzwerke gefunden', + NETWORK_BLANK_SSID: 'Freilassen um WiFi zu deaktivieren', + POWER: 'Leistung', + NETWORK_DISABLE_SLEEP: 'Deaktiviere WiFi Schlafmodus', + NETWORK_LOW_BAND: 'Verwende niedrige WiFi Bandbreite', + NETWORK_USE_DNS: 'Aktiviere mDNS Service', + NETWORK_ENABLE_IPV6: 'Aktiviere IPv6 Unterstützung', + NETWORK_FIXED_IP: 'Feste IP Addresse', + ADMIN: 'Administrator', + GUEST: 'Gast', + NEW: 'Neuer', + RENAME: 'Ändere' +}; + +export default de; diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts new file mode 100644 index 000000000..c70c47e0e --- /dev/null +++ b/interface/src/i18n/en/index.ts @@ -0,0 +1,265 @@ +import type { BaseTranslation } from '../i18n-types'; + +const en: BaseTranslation = { + LANGUAGE: 'Language', + RETRY: 'Retry', + LOADING: 'Loading', + IS_REQUIRED: 'is required', + SIGN_IN: 'Sign In', + SIGN_OUT: 'Sign Out', + USERNAME: 'Username', + PASSWORD: 'Password', + DASHBOARD: 'Dashboard', + SETTINGS: 'Settings', + SAVED: 'saved', + HELP: 'Help', + LOGGED_IN: 'Logged in as {name}', + PLEASE_SIGNIN: 'Please sign in to continue', + UPLOAD_SUCCESSFUL: 'Upload successful', + DOWNLOAD_SUCCESSFUL: 'Download successful', + INVALID_LOGIN: 'Invalid login details', + NETWORK: 'Network', + SECURITY: 'Security', + ONOFF_CAP: 'ON/OFF', + ONOFF: 'on/off', + TYPE: 'Type', + DESCRIPTION: 'Description', + ENTITIES: 'Entities', + REFRESH: 'Refresh', + EXPORT: 'Export', + DEVICE_DETAILS: 'Device Details', + BRAND: 'Brand', + ENTITY_NAME: 'Entity Name', + VALUE: 'Value', + SHOW_FAV: 'only show favorites', + DEVICE_SENSOR_DATA: 'Device and Sensor Data', + DEVICES_SENSORS: 'Devices & Sensors', + ATTACHED_SENSORS: 'Attached EMS-ESP Sensors', + RUN_COMMAND: 'Call Command', + CHANGE_VALUE: 'Change Value', + CANCEL: 'Cancel', + RESET: 'Reset', + SEND: 'Send', + SAVE: 'Save', + REMOVE: 'Remove', + PROBLEM_UPDATING: 'Problem updating', + PROBLEM_LOADING: 'Problem loading', + ACCESS_DENIED: 'Access Denied', + ANALOG_SENSOR: 'Analog Sensor', + ANALOG_SENSORS: 'Analog Sensors', + UPDATED: 'Updated', + UPDATE: 'Update', + REMOVED: 'Removed', + DELETION: 'Deletion', + OFFSET: 'Offset', + FACTOR: 'Factor', + FREQ: 'Frequency', + STARTVALUE: 'Start value', + WARN_GPIO: 'Warning: be careful when assigning a GPIO!', + EDIT: 'Edit', + TEMP_SENSOR: 'Temperature Sensor', + TEMP_SENSORS: 'Temperature Sensors', + WRITE_COMMAND: 'Write command {cmd}', + EMS_BUS_WARNING: + 'EMS bus disconnected. If this warning still persists after a few seconds please check settings and board profile', + EMS_BUS_SCANNING: 'Scanning for EMS devices...', + CONNECTED: 'Connected', + TX_ISSUES: 'Tx issues - try a different Tx Mode', + DISCONNECTED: 'Disconnected', + EMS_SCAN: 'Are you sure you want to initiate a full device scan of the EMS bus?', + EMS_BUS_STATUS: 'EMS Bus Status', + ACTIVE_DEVICES: 'Active Devices & Sensors', + DEVICE: 'Device', + SUCCESS: 'SUCCESS', + FAIL: 'FAIL', + QUALITY: 'QUALITY', + SCAN_DEVICES: 'Scan for new devices', + EMS_BUS_STATUS_TITLE: 'EMS Bus & Activity Status', + SCAN: 'Scan', + STATUS_NAMES: [ + 'EMS Telegrams Received (Rx)', + 'EMS Reads (Tx)', + 'EMS Writes (Tx)', + 'Temperature Sensor Reads', + 'Analog Sensor Reads', + 'MQTT Publishes', + 'API Calls', + 'Syslog Messages' + ], + NUM_DEVICES: '{num} Device{{s}}', + NUM_TEMP_SENSORS: '{num} Temperature Sensor{{s}}', + NUM_ANALOG_SENSORS: '{num} Analog Sensor{{s}}', + NUM_DAYS: '{num} Day{{s}}', + NUM_SECONDS: '{num} Second{{s}}', + NUM_HOURS: '{num} Hour{{s}}', + NUM_MINUTES: '{num} Minute{{s}}', + APPLICATION_SETTINGS: 'Application Settings', + CUSTOMIZATION: 'Customization', + APPLICATION_RESTARTING: 'EMS-ESP is restarting', + BOARD_PROFILE_TEXT: + 'Select a pre-configured interface board profile from the list below or choose Custom to configure your own hardware settings', + BOARD_PROFILE: 'Board Profile', + BUTTON: 'Button', + TEMPERATURE: 'Temperature', + DISABLED: 'disabled', + GENERAL_OPTIONS: 'General Options', + LANGUAGE_ENTITIES: 'Language (for device entities)', + HIDE_LED: 'Hide LED', + ENABLE_TELNET: 'Enable Telnet Console', + ENABLE_ANALOG: 'Enable Analog Sensors', + CONVERT_FAHRENHEIT: 'Convert temperature values to Fahrenheit', + BYPASS_TOKEN: 'Bypass Access Token authorization on API calls', + READONLY: 'Enable read-only mode (blocks all outgoing EMS Tx Write commands)', + UNDERCLOCK_CPU: 'Underclock CPU speed', + ENABLE_SHOWER_TIMER: 'Enable Shower Timer', + ENABLE_SHOWER_ALERT: 'Enable Shower Alert', + TRIGGER_TIME: 'Trigger Time', + COLD_SHOT_DURATION: 'Cold Shot Duration', + FORMATTING_OPTIONS: 'Formatting Options', + BOOLEAN_FORMAT_DASHBOARD: 'Boolean Format Dashboard', + BOOLEAN_FORMAT_API: 'Boolean Format API/MQTT', + ENUM_FORMAT: 'Enum Format API/MQTT', + INDEX: 'Index', + ENABLE_PARASITE: 'Enable parasite power', + LOGGING: 'Logging', + LOG_HEX: 'Log EMS telegrams in hexadecimal', + ENABLE_SYSLOG: 'Enable Syslog', + MARK_INTERVAL: 'Mark Interval', + SECONDS: 'seconds', + MINUTES: 'minutes', + RESTART: 'Restart', + HOURS: 'hours', + RESTART_TEXT: 'EMS-ESP needs to be restarted to apply changed system settings', + COMMAND: 'Command', + CUSTOMIZATIONS_RESTART: 'All customizations have been removed. Restarting...', + CUSTOMIZATIONS_FULL: 'Selected entities exceeded limit. Please save in batches', + CUSTOMIZATIONS_SAVED: 'Customizations saved', + CUSTOMIZATIONS_HELP_1: 'Select a device and customize the entities options or click to rename', + CUSTOMIZATIONS_HELP_2: 'mark as favorite', + CUSTOMIZATIONS_HELP_3: 'disable write action', + CUSTOMIZATIONS_HELP_4: 'exclude from MQTT and API', + CUSTOMIZATIONS_HELP_5: 'hide from Dashboard', + SELECT_DEVICE: 'Select a device', + SET_ALL: 'set all', + OPTIONS: 'Options', + NAME: 'Name', + CUSTOMIZATIONS_RESET: + 'Are you sure you want remove all customizations including the custom settings of the Temperature and Analog sensors?', + DEVICE_ENTITIES: 'Device Entities', + USER_CUSTOMIZATION: 'User Customization', + SUPPORT_INFORMATION: 'Support Information', + CLICK_HERE: 'Click Here', + HELP_INFORMATION_1: 'Visit the online wiki to get instructions on how to configure EMS-ESP', + HELP_INFORMATION_2: 'For live community chat join our Discord server', + HELP_INFORMATION_3: 'To request a feature or report a bug', + HELP_INFORMATION_4: 'remember to download and attach your system information for a faster response when reporting an issue', + HELP_INFORMATION_5: + "EMS-ESP is a free and open-source project. Please support its future development by giving it a star on Github!", + SUPPORT_INFO: 'Support Info', + UPLOAD: 'Upload', + DOWNLOAD: 'Download', + ABORTED: 'aborted', + FAILED: 'failed', + SUCCESSFUL: 'successful', + SYSTEM: 'System', + LOG: 'Log', + STATUS: 'Status', + UPLOAD_DOWNLOAD: 'Upload/Download', + SYSTEM_VERSION_RUNNING: 'You are currently running version', + SYSTEM_APPLY_FIRMWARE: 'to apply the new firmware', + CLOSE: 'Close', + USE: 'Use', + FACTORY_RESET: 'Factory Reset', + SYSTEM_FACTORY_TEXT: 'Device has been factory reset and will now restart', + SYSTEM_FACTORY_TEXT_DIALOG: 'Are you sure you want to reset the device to its factory defaults?', + VERSION_CHECK: 'Version Check', + THE_LATEST: 'The latest', + PLATFORM: 'Device (Platform / SDK)', + UPTIME: 'System Uptime', + CPU_FREQ: 'CPU Frequency', + HEAP: 'Heap (Free / Max Alloc)', + PSRAM: 'PSRAM (Size / Free)', + FLASH: 'Flash Chip (Size / Speed)', + FILESYSTEM: 'File System (Used / Total)', + BUFFER_SIZE: 'Buffer Size', + COMPACT: 'Compact', + ENABLE_OTA: 'Enable OTA Updates', + DOWNLOAD_CUSTOMIZATION_TEXT: 'Download the entity customizations', + DOWNLOAD_SETTINGS_TEXT: + 'Download the application settings. Be careful when sharing your settings as this file contains passwords and other sensitive system information', + UPLOAD_TEXT: 'Upload a new firmware (.bin) file, settings or customizations (.json) file below', + UPLOADING: 'Uploading', + UPLOAD_DROP_TEXT: 'Drop file or click here', + ERROR: 'Unexpected Error, please try again', + TIME_SET: 'Time set', + MANAGE_USERS: 'Manage Users', + IS_ADMIN: 'is Admin', + USER_WARNING: 'You must have at least one admin user configured', + ADD: 'Add', + ACCESS_TOKEN_FOR: 'Access Token for', + ACCESS_TOKEN_TEXT: + 'The token below is used with REST API calls that require authorization. It can be passed either as a Bearer token in the Authorization header or in the access_token URL query parameter.', + GENERATING_TOKEN: 'Generating token', + USER: 'User', + MODIFY: 'Modify', + SU_TEXT: + 'The su (super user) password is used to sign authentication tokens and also enable admin privileges within the Console.', + NOT_ENABLED: 'Not enabled', + ERRORS: 'Errors', + DISCONNECT_REASON: 'Disconnect Reason', + ENABLE_MQTT: 'Enable MQTT', + OPTIONAL: 'Optional', + FORMATTING: 'Formatting', + FORMAT: 'Format', + MQTT_NEST_1: 'Nested in a single topic', + MQTT_NEST_2: 'As individual topics', + MQTT_RESPONSE: 'Publish command output to a `response` topic', + MQTT_PUBLISH_TEXT_1: 'Publish single value topics on change', + MQTT_PUBLISH_TEXT_2: 'Publish to command topics (ioBroker)', + MQTT_PUBLISH_TEXT_3: 'Enable MQTT Discovery (Home Assistant, Domoticz)', + MQTT_PUBLISH_TEXT_4: 'Prefix for the Discovery topics', + MQTT_PUBLISH_INTERVALS: 'Publish Intervals', + MQTT_INT_BOILER: 'Boilers and Heat Pumps', + MQTT_INT_THERMOSTATS: 'Thermostats', + MQTT_INT_SOLAR: 'Solar Modules', + MQTT_INT_MIXER: 'Mixer Modules', + DEFAULT: 'Default', + MQTT_CLEAN_SESSION: 'Set Clean Session', + MQTT_RETAIN_FLAG: 'Always set Retain flag', + INACTIVE: 'Inactive', + ACTIVE: 'Active', + UNKNOWN: 'Unknown', + SET_TIME: 'Set Time', + SET_TIME_TEXT: 'Enter local date and time below to set the time', + LOCAL_TIME: 'Local Time', + UTC_TIME: 'UTC Time', + ENABLE_NTP: 'Enable NTP', + TIME_ZONE: 'Time Zone', + ACCESS_POINT: 'Access Point', + AP_PROVIDE: 'Enable Access Point', + AP_PROVIDE_TEXT_1: 'always', + AP_PROVIDE_TEXT_2: 'when WiFi is disconnected', + AP_PROVIDE_TEXT_3: 'never', + AP_PREFERRED_CHANNEL: 'Preferred Channel', + AP_HIDE_SSID: 'Hide SSID', + NETWORK_SCAN: 'Scan WiFi Networks', + IDLE: 'Idle', + LOST: 'Lost', + SCANNING: 'Scanning', + SCAN_AGAIN: 'Scan again', + NETWORK_SCANNER: 'Network Scanner', + NETWORK_NO_WIFI: 'No WiFi networks found', + NETWORK_BLANK_SSID: 'leave blank to disable WiFi', + POWER: 'Power', + NETWORK_DISABLE_SLEEP: 'Disable WiFi Sleep Mode', + NETWORK_LOW_BAND: 'Use Lower WiFi Bandwidth', + NETWORK_USE_DNS: 'Enable mDNS Service', + NETWORK_ENABLE_IPV6: 'Enable IPv6 support', + NETWORK_FIXED_IP: 'Use Fixed IP address', + ADMIN: 'Admin', + GUEST: 'Guest', + NEW: 'New', + RENAME: 'Rename' +}; + +export default en; diff --git a/interface/src/i18n/formatters.ts b/interface/src/i18n/formatters.ts new file mode 100644 index 000000000..96561fed0 --- /dev/null +++ b/interface/src/i18n/formatters.ts @@ -0,0 +1,11 @@ +import type { FormattersInitializer } from 'typesafe-i18n'; +import type { Locales, Formatters } from './i18n-types'; +import { date } from 'typesafe-i18n/formatters'; + +export const initFormatters: FormattersInitializer = (locale: Locales) => { + const formatters: Formatters = { + weekday: date(locale, { weekday: 'long' }) + }; + + return formatters; +}; diff --git a/interface/src/i18n/i18n-react.tsx b/interface/src/i18n/i18n-react.tsx new file mode 100644 index 000000000..f113051fa --- /dev/null +++ b/interface/src/i18n/i18n-react.tsx @@ -0,0 +1,16 @@ +// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. +/* eslint-disable */ + +import { useContext } from 'react' +import { initI18nReact } from 'typesafe-i18n/react' +import type { I18nContextType } from 'typesafe-i18n/react' +import type { Formatters, Locales, TranslationFunctions, Translations } from './i18n-types' +import { loadedFormatters, loadedLocales } from './i18n-util' + +const { component: TypesafeI18n, context: I18nContext } = initI18nReact(loadedLocales, loadedFormatters) + +const useI18nContext = (): I18nContextType => useContext(I18nContext) + +export { I18nContext, useI18nContext } + +export default TypesafeI18n diff --git a/interface/src/i18n/i18n-types.ts b/interface/src/i18n/i18n-types.ts new file mode 100644 index 000000000..8cc257dfb --- /dev/null +++ b/interface/src/i18n/i18n-types.ts @@ -0,0 +1,2039 @@ +// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. +/* eslint-disable */ +import type { BaseTranslation as BaseTranslationType, LocalizedString, RequiredParams } from 'typesafe-i18n' + +export type BaseTranslation = BaseTranslationType +export type BaseLocale = 'en' + +export type Locales = + | 'de' + | 'en' + | 'nl' + | 'no' + | 'pl' + | 'se' + +export type Translation = RootTranslation + +export type Translations = RootTranslation + +type RootTranslation = { + /** + * Language + */ + LANGUAGE: string + /** + * Retry + */ + RETRY: string + /** + * Loading + */ + LOADING: string + /** + * is required + */ + IS_REQUIRED: string + /** + * Sign In + */ + SIGN_IN: string + /** + * Sign Out + */ + SIGN_OUT: string + /** + * Username + */ + USERNAME: string + /** + * Password + */ + PASSWORD: string + /** + * Dashboard + */ + DASHBOARD: string + /** + * Settings + */ + SETTINGS: string + /** + * saved + */ + SAVED: string + /** + * Help + */ + HELP: string + /** + * Logged in as {name} + * @param {unknown} name + */ + LOGGED_IN: RequiredParams<'name'> + /** + * Please sign in to continue + */ + PLEASE_SIGNIN: string + /** + * Upload successful + */ + UPLOAD_SUCCESSFUL: string + /** + * Download successful + */ + DOWNLOAD_SUCCESSFUL: string + /** + * Invalid login details + */ + INVALID_LOGIN: string + /** + * Network + */ + NETWORK: string + /** + * Security + */ + SECURITY: string + /** + * ON/OFF + */ + ONOFF_CAP: string + /** + * on/off + */ + ONOFF: string + /** + * Type + */ + TYPE: string + /** + * Description + */ + DESCRIPTION: string + /** + * Entities + */ + ENTITIES: string + /** + * Refresh + */ + REFRESH: string + /** + * Export + */ + EXPORT: string + /** + * Device Details + */ + DEVICE_DETAILS: string + /** + * Brand + */ + BRAND: string + /** + * Entity Name + */ + ENTITY_NAME: string + /** + * Value + */ + VALUE: string + /** + * only show favorites + */ + SHOW_FAV: string + /** + * Device and Sensor Data + */ + DEVICE_SENSOR_DATA: string + /** + * Devices & Sensors + */ + DEVICES_SENSORS: string + /** + * Attached EMS-ESP Sensors + */ + ATTACHED_SENSORS: string + /** + * Call Command + */ + RUN_COMMAND: string + /** + * Change Value + */ + CHANGE_VALUE: string + /** + * Cancel + */ + CANCEL: string + /** + * Reset + */ + RESET: string + /** + * Send + */ + SEND: string + /** + * Save + */ + SAVE: string + /** + * Remove + */ + REMOVE: string + /** + * Problem updating + */ + PROBLEM_UPDATING: string + /** + * Problem loading + */ + PROBLEM_LOADING: string + /** + * Access Denied + */ + ACCESS_DENIED: string + /** + * Analog Sensor + */ + ANALOG_SENSOR: string + /** + * Analog Sensors + */ + ANALOG_SENSORS: string + /** + * Updated + */ + UPDATED: string + /** + * Update + */ + UPDATE: string + /** + * Removed + */ + REMOVED: string + /** + * Deletion + */ + DELETION: string + /** + * Offset + */ + OFFSET: string + /** + * Factor + */ + FACTOR: string + /** + * Frequency + */ + FREQ: string + /** + * Start value + */ + STARTVALUE: string + /** + * Warning: be careful when assigning a GPIO! + */ + WARN_GPIO: string + /** + * Edit + */ + EDIT: string + /** + * Temperature Sensor + */ + TEMP_SENSOR: string + /** + * Temperature Sensors + */ + TEMP_SENSORS: string + /** + * Write command {cmd} + * @param {unknown} cmd + */ + WRITE_COMMAND: RequiredParams<'cmd'> + /** + * EMS bus disconnected. If this warning still persists after a few seconds please check settings and board profile + */ + EMS_BUS_WARNING: string + /** + * Scanning for EMS devices... + */ + EMS_BUS_SCANNING: string + /** + * Connected + */ + CONNECTED: string + /** + * Tx issues - try a different Tx Mode + */ + TX_ISSUES: string + /** + * Disconnected + */ + DISCONNECTED: string + /** + * Are you sure you want to initiate a full device scan of the EMS bus? + */ + EMS_SCAN: string + /** + * EMS Bus Status + */ + EMS_BUS_STATUS: string + /** + * Active Devices & Sensors + */ + ACTIVE_DEVICES: string + /** + * Device + */ + DEVICE: string + /** + * SUCCESS + */ + SUCCESS: string + /** + * FAIL + */ + FAIL: string + /** + * QUALITY + */ + QUALITY: string + /** + * Scan for new devices + */ + SCAN_DEVICES: string + /** + * EMS Bus & Activity Status + */ + EMS_BUS_STATUS_TITLE: string + /** + * Scan + */ + SCAN: string + STATUS_NAMES: { + /** + * EMS Telegrams Received (Rx) + */ + '0': string + /** + * EMS Reads (Tx) + */ + '1': string + /** + * EMS Writes (Tx) + */ + '2': string + /** + * Temperature Sensor Reads + */ + '3': string + /** + * Analog Sensor Reads + */ + '4': string + /** + * MQTT Publishes + */ + '5': string + /** + * API Calls + */ + '6': string + /** + * Syslog Messages + */ + '7': string + } + /** + * {num} Device{{s}} + * @param {string | number | boolean} num + */ + NUM_DEVICES: RequiredParams<'num'> + /** + * {num} Temperature Sensor{{s}} + * @param {string | number | boolean} num + */ + NUM_TEMP_SENSORS: RequiredParams<'num'> + /** + * {num} Analog Sensor{{s}} + * @param {string | number | boolean} num + */ + NUM_ANALOG_SENSORS: RequiredParams<'num'> + /** + * {num} Day{{s}} + * @param {string | number | boolean} num + */ + NUM_DAYS: RequiredParams<'num'> + /** + * {num} Second{{s}} + * @param {string | number | boolean} num + */ + NUM_SECONDS: RequiredParams<'num'> + /** + * {num} Hour{{s}} + * @param {string | number | boolean} num + */ + NUM_HOURS: RequiredParams<'num'> + /** + * {num} Minute{{s}} + * @param {string | number | boolean} num + */ + NUM_MINUTES: RequiredParams<'num'> + /** + * Application Settings + */ + APPLICATION_SETTINGS: string + /** + * Customization + */ + CUSTOMIZATION: string + /** + * EMS-ESP is restarting + */ + APPLICATION_RESTARTING: string + /** + * Select a pre-configured interface board profile from the list below or choose Custom to configure your own hardware settings + */ + BOARD_PROFILE_TEXT: string + /** + * Board Profile + */ + BOARD_PROFILE: string + /** + * Button + */ + BUTTON: string + /** + * Temperature + */ + TEMPERATURE: string + /** + * disabled + */ + DISABLED: string + /** + * General Options + */ + GENERAL_OPTIONS: string + /** + * Language (for device entities) + */ + LANGUAGE_ENTITIES: string + /** + * Hide LED + */ + HIDE_LED: string + /** + * Enable Telnet Console + */ + ENABLE_TELNET: string + /** + * Enable Analog Sensors + */ + ENABLE_ANALOG: string + /** + * Convert temperature values to Fahrenheit + */ + CONVERT_FAHRENHEIT: string + /** + * Bypass Access Token authorization on API calls + */ + BYPASS_TOKEN: string + /** + * Enable read-only mode (blocks all outgoing EMS Tx Write commands) + */ + READONLY: string + /** + * Underclock CPU speed + */ + UNDERCLOCK_CPU: string + /** + * Enable Shower Timer + */ + ENABLE_SHOWER_TIMER: string + /** + * Enable Shower Alert + */ + ENABLE_SHOWER_ALERT: string + /** + * Trigger Time + */ + TRIGGER_TIME: string + /** + * Cold Shot Duration + */ + COLD_SHOT_DURATION: string + /** + * Formatting Options + */ + FORMATTING_OPTIONS: string + /** + * Boolean Format Dashboard + */ + BOOLEAN_FORMAT_DASHBOARD: string + /** + * Boolean Format API/MQTT + */ + BOOLEAN_FORMAT_API: string + /** + * Enum Format API/MQTT + */ + ENUM_FORMAT: string + /** + * Index + */ + INDEX: string + /** + * Enable parasite power + */ + ENABLE_PARASITE: string + /** + * Logging + */ + LOGGING: string + /** + * Log EMS telegrams in hexadecimal + */ + LOG_HEX: string + /** + * Enable Syslog + */ + ENABLE_SYSLOG: string + /** + * Mark Interval + */ + MARK_INTERVAL: string + /** + * seconds + */ + SECONDS: string + /** + * minutes + */ + MINUTES: string + /** + * Restart + */ + RESTART: string + /** + * hours + */ + HOURS: string + /** + * EMS-ESP needs to be restarted to apply changed system settings + */ + RESTART_TEXT: string + /** + * Command + */ + COMMAND: string + /** + * All customizations have been removed. Restarting... + */ + CUSTOMIZATIONS_RESTART: string + /** + * Selected entities exceeded limit. Please save in batches + */ + CUSTOMIZATIONS_FULL: string + /** + * Customizations saved + */ + CUSTOMIZATIONS_SAVED: string + /** + * Select a device and customize the entities options or click to rename + */ + CUSTOMIZATIONS_HELP_1: string + /** + * mark as favorite + */ + CUSTOMIZATIONS_HELP_2: string + /** + * disable write action + */ + CUSTOMIZATIONS_HELP_3: string + /** + * exclude from MQTT and API + */ + CUSTOMIZATIONS_HELP_4: string + /** + * hide from Dashboard + */ + CUSTOMIZATIONS_HELP_5: string + /** + * Select a device + */ + SELECT_DEVICE: string + /** + * set all + */ + SET_ALL: string + /** + * Options + */ + OPTIONS: string + /** + * Name + */ + NAME: string + /** + * Are you sure you want remove all customizations including the custom settings of the Temperature and Analog sensors? + */ + CUSTOMIZATIONS_RESET: string + /** + * Device Entities + */ + DEVICE_ENTITIES: string + /** + * User Customization + */ + USER_CUSTOMIZATION: string + /** + * Support Information + */ + SUPPORT_INFORMATION: string + /** + * Click Here + */ + CLICK_HERE: string + /** + * Visit the online wiki to get instructions on how to configure EMS-ESP + */ + HELP_INFORMATION_1: string + /** + * For live community chat join our Discord server + */ + HELP_INFORMATION_2: string + /** + * To request a feature or report a bug + */ + HELP_INFORMATION_3: string + /** + * remember to download and attach your system information for a faster response when reporting an issue + */ + HELP_INFORMATION_4: string + /** + * EMS-ESP is a free and open-source project. Please support its future development by giving it a star on Github! + */ + HELP_INFORMATION_5: string + /** + * Support Info + */ + SUPPORT_INFO: string + /** + * Upload + */ + UPLOAD: string + /** + * Download + */ + DOWNLOAD: string + /** + * aborted + */ + ABORTED: string + /** + * failed + */ + FAILED: string + /** + * successful + */ + SUCCESSFUL: string + /** + * System + */ + SYSTEM: string + /** + * Log + */ + LOG: string + /** + * Status + */ + STATUS: string + /** + * Upload/Download + */ + UPLOAD_DOWNLOAD: string + /** + * You are currently running version + */ + SYSTEM_VERSION_RUNNING: string + /** + * to apply the new firmware + */ + SYSTEM_APPLY_FIRMWARE: string + /** + * Close + */ + CLOSE: string + /** + * Use + */ + USE: string + /** + * Factory Reset + */ + FACTORY_RESET: string + /** + * Device has been factory reset and will now restart + */ + SYSTEM_FACTORY_TEXT: string + /** + * Are you sure you want to reset the device to its factory defaults? + */ + SYSTEM_FACTORY_TEXT_DIALOG: string + /** + * Version Check + */ + VERSION_CHECK: string + /** + * The latest + */ + THE_LATEST: string + /** + * Device (Platform / SDK) + */ + PLATFORM: string + /** + * System Uptime + */ + UPTIME: string + /** + * CPU Frequency + */ + CPU_FREQ: string + /** + * Heap (Free / Max Alloc) + */ + HEAP: string + /** + * PSRAM (Size / Free) + */ + PSRAM: string + /** + * Flash Chip (Size / Speed) + */ + FLASH: string + /** + * File System (Used / Total) + */ + FILESYSTEM: string + /** + * Buffer Size + */ + BUFFER_SIZE: string + /** + * Compact + */ + COMPACT: string + /** + * Enable OTA Updates + */ + ENABLE_OTA: string + /** + * Download the entity customizations + */ + DOWNLOAD_CUSTOMIZATION_TEXT: string + /** + * Download the application settings. Be careful when sharing your settings as this file contains passwords and other sensitive system information + */ + DOWNLOAD_SETTINGS_TEXT: string + /** + * Upload a new firmware (.bin) file, settings or customizations (.json) file below + */ + UPLOAD_TEXT: string + /** + * Uploading + */ + UPLOADING: string + /** + * Drop file or click here + */ + UPLOAD_DROP_TEXT: string + /** + * Unexpected Error, please try again + */ + ERROR: string + /** + * Time set + */ + TIME_SET: string + /** + * Manage Users + */ + MANAGE_USERS: string + /** + * is Admin + */ + IS_ADMIN: string + /** + * You must have at least one admin user configured + */ + USER_WARNING: string + /** + * Add + */ + ADD: string + /** + * Access Token for + */ + ACCESS_TOKEN_FOR: string + /** + * The token below is used with REST API calls that require authorization. It can be passed either as a Bearer token in the Authorization header or in the access_token URL query parameter. + */ + ACCESS_TOKEN_TEXT: string + /** + * Generating token + */ + GENERATING_TOKEN: string + /** + * User + */ + USER: string + /** + * Modify + */ + MODIFY: string + /** + * The su (super user) password is used to sign authentication tokens and also enable admin privileges within the Console. + */ + SU_TEXT: string + /** + * Not enabled + */ + NOT_ENABLED: string + /** + * Errors + */ + ERRORS: string + /** + * Disconnect Reason + */ + DISCONNECT_REASON: string + /** + * Enable MQTT + */ + ENABLE_MQTT: string + /** + * Optional + */ + OPTIONAL: string + /** + * Formatting + */ + FORMATTING: string + /** + * Format + */ + FORMAT: string + /** + * Nested in a single topic + */ + MQTT_NEST_1: string + /** + * As individual topics + */ + MQTT_NEST_2: string + /** + * Publish command output to a `response` topic + */ + MQTT_RESPONSE: string + /** + * Publish single value topics on change + */ + MQTT_PUBLISH_TEXT_1: string + /** + * Publish to command topics (ioBroker) + */ + MQTT_PUBLISH_TEXT_2: string + /** + * Enable MQTT Discovery (Home Assistant, Domoticz) + */ + MQTT_PUBLISH_TEXT_3: string + /** + * Prefix for the Discovery topics + */ + MQTT_PUBLISH_TEXT_4: string + /** + * Publish Intervals + */ + MQTT_PUBLISH_INTERVALS: string + /** + * Boilers and Heat Pumps + */ + MQTT_INT_BOILER: string + /** + * Thermostats + */ + MQTT_INT_THERMOSTATS: string + /** + * Solar Modules + */ + MQTT_INT_SOLAR: string + /** + * Mixer Modules + */ + MQTT_INT_MIXER: string + /** + * Default + */ + DEFAULT: string + /** + * Set Clean Session + */ + MQTT_CLEAN_SESSION: string + /** + * Always set Retain flag + */ + MQTT_RETAIN_FLAG: string + /** + * Inactive + */ + INACTIVE: string + /** + * Active + */ + ACTIVE: string + /** + * Unknown + */ + UNKNOWN: string + /** + * Set Time + */ + SET_TIME: string + /** + * Enter local date and time below to set the time + */ + SET_TIME_TEXT: string + /** + * Local Time + */ + LOCAL_TIME: string + /** + * UTC Time + */ + UTC_TIME: string + /** + * Enable NTP + */ + ENABLE_NTP: string + /** + * Time Zone + */ + TIME_ZONE: string + /** + * Access Point + */ + ACCESS_POINT: string + /** + * Enable Access Point + */ + AP_PROVIDE: string + /** + * always + */ + AP_PROVIDE_TEXT_1: string + /** + * when WiFi is disconnected + */ + AP_PROVIDE_TEXT_2: string + /** + * never + */ + AP_PROVIDE_TEXT_3: string + /** + * Preferred Channel + */ + AP_PREFERRED_CHANNEL: string + /** + * Hide SSID + */ + AP_HIDE_SSID: string + /** + * Scan WiFi Networks + */ + NETWORK_SCAN: string + /** + * Idle + */ + IDLE: string + /** + * Lost + */ + LOST: string + /** + * Scanning + */ + SCANNING: string + /** + * Scan again + */ + SCAN_AGAIN: string + /** + * Network Scanner + */ + NETWORK_SCANNER: string + /** + * No WiFi networks found + */ + NETWORK_NO_WIFI: string + /** + * leave blank to disable WiFi + */ + NETWORK_BLANK_SSID: string + /** + * Power + */ + POWER: string + /** + * Disable WiFi Sleep Mode + */ + NETWORK_DISABLE_SLEEP: string + /** + * Use Lower WiFi Bandwidth + */ + NETWORK_LOW_BAND: string + /** + * Enable mDNS Service + */ + NETWORK_USE_DNS: string + /** + * Enable IPv6 support + */ + NETWORK_ENABLE_IPV6: string + /** + * Use Fixed IP address + */ + NETWORK_FIXED_IP: string + /** + * Admin + */ + ADMIN: string + /** + * Guest + */ + GUEST: string + /** + * New + */ + NEW: string + /** + * Rename + */ + RENAME: string +} + +export type TranslationFunctions = { + /** + * Language + */ + LANGUAGE: () => LocalizedString + /** + * Retry + */ + RETRY: () => LocalizedString + /** + * Loading + */ + LOADING: () => LocalizedString + /** + * is required + */ + IS_REQUIRED: () => LocalizedString + /** + * Sign In + */ + SIGN_IN: () => LocalizedString + /** + * Sign Out + */ + SIGN_OUT: () => LocalizedString + /** + * Username + */ + USERNAME: () => LocalizedString + /** + * Password + */ + PASSWORD: () => LocalizedString + /** + * Dashboard + */ + DASHBOARD: () => LocalizedString + /** + * Settings + */ + SETTINGS: () => LocalizedString + /** + * saved + */ + SAVED: () => LocalizedString + /** + * Help + */ + HELP: () => LocalizedString + /** + * Logged in as {name} + */ + LOGGED_IN: (arg: { name: unknown }) => LocalizedString + /** + * Please sign in to continue + */ + PLEASE_SIGNIN: () => LocalizedString + /** + * Upload successful + */ + UPLOAD_SUCCESSFUL: () => LocalizedString + /** + * Download successful + */ + DOWNLOAD_SUCCESSFUL: () => LocalizedString + /** + * Invalid login details + */ + INVALID_LOGIN: () => LocalizedString + /** + * Network + */ + NETWORK: () => LocalizedString + /** + * Security + */ + SECURITY: () => LocalizedString + /** + * ON/OFF + */ + ONOFF_CAP: () => LocalizedString + /** + * on/off + */ + ONOFF: () => LocalizedString + /** + * Type + */ + TYPE: () => LocalizedString + /** + * Description + */ + DESCRIPTION: () => LocalizedString + /** + * Entities + */ + ENTITIES: () => LocalizedString + /** + * Refresh + */ + REFRESH: () => LocalizedString + /** + * Export + */ + EXPORT: () => LocalizedString + /** + * Device Details + */ + DEVICE_DETAILS: () => LocalizedString + /** + * Brand + */ + BRAND: () => LocalizedString + /** + * Entity Name + */ + ENTITY_NAME: () => LocalizedString + /** + * Value + */ + VALUE: () => LocalizedString + /** + * only show favorites + */ + SHOW_FAV: () => LocalizedString + /** + * Device and Sensor Data + */ + DEVICE_SENSOR_DATA: () => LocalizedString + /** + * Devices & Sensors + */ + DEVICES_SENSORS: () => LocalizedString + /** + * Attached EMS-ESP Sensors + */ + ATTACHED_SENSORS: () => LocalizedString + /** + * Call Command + */ + RUN_COMMAND: () => LocalizedString + /** + * Change Value + */ + CHANGE_VALUE: () => LocalizedString + /** + * Cancel + */ + CANCEL: () => LocalizedString + /** + * Reset + */ + RESET: () => LocalizedString + /** + * Send + */ + SEND: () => LocalizedString + /** + * Save + */ + SAVE: () => LocalizedString + /** + * Remove + */ + REMOVE: () => LocalizedString + /** + * Problem updating + */ + PROBLEM_UPDATING: () => LocalizedString + /** + * Problem loading + */ + PROBLEM_LOADING: () => LocalizedString + /** + * Access Denied + */ + ACCESS_DENIED: () => LocalizedString + /** + * Analog Sensor + */ + ANALOG_SENSOR: () => LocalizedString + /** + * Analog Sensors + */ + ANALOG_SENSORS: () => LocalizedString + /** + * Updated + */ + UPDATED: () => LocalizedString + /** + * Update + */ + UPDATE: () => LocalizedString + /** + * Removed + */ + REMOVED: () => LocalizedString + /** + * Deletion + */ + DELETION: () => LocalizedString + /** + * Offset + */ + OFFSET: () => LocalizedString + /** + * Factor + */ + FACTOR: () => LocalizedString + /** + * Frequency + */ + FREQ: () => LocalizedString + /** + * Start value + */ + STARTVALUE: () => LocalizedString + /** + * Warning: be careful when assigning a GPIO! + */ + WARN_GPIO: () => LocalizedString + /** + * Edit + */ + EDIT: () => LocalizedString + /** + * Temperature Sensor + */ + TEMP_SENSOR: () => LocalizedString + /** + * Temperature Sensors + */ + TEMP_SENSORS: () => LocalizedString + /** + * Write command {cmd} + */ + WRITE_COMMAND: (arg: { cmd: unknown }) => LocalizedString + /** + * EMS bus disconnected. If this warning still persists after a few seconds please check settings and board profile + */ + EMS_BUS_WARNING: () => LocalizedString + /** + * Scanning for EMS devices... + */ + EMS_BUS_SCANNING: () => LocalizedString + /** + * Connected + */ + CONNECTED: () => LocalizedString + /** + * Tx issues - try a different Tx Mode + */ + TX_ISSUES: () => LocalizedString + /** + * Disconnected + */ + DISCONNECTED: () => LocalizedString + /** + * Are you sure you want to initiate a full device scan of the EMS bus? + */ + EMS_SCAN: () => LocalizedString + /** + * EMS Bus Status + */ + EMS_BUS_STATUS: () => LocalizedString + /** + * Active Devices & Sensors + */ + ACTIVE_DEVICES: () => LocalizedString + /** + * Device + */ + DEVICE: () => LocalizedString + /** + * SUCCESS + */ + SUCCESS: () => LocalizedString + /** + * FAIL + */ + FAIL: () => LocalizedString + /** + * QUALITY + */ + QUALITY: () => LocalizedString + /** + * Scan for new devices + */ + SCAN_DEVICES: () => LocalizedString + /** + * EMS Bus & Activity Status + */ + EMS_BUS_STATUS_TITLE: () => LocalizedString + /** + * Scan + */ + SCAN: () => LocalizedString + STATUS_NAMES: { + /** + * EMS Telegrams Received (Rx) + */ + '0': () => LocalizedString + /** + * EMS Reads (Tx) + */ + '1': () => LocalizedString + /** + * EMS Writes (Tx) + */ + '2': () => LocalizedString + /** + * Temperature Sensor Reads + */ + '3': () => LocalizedString + /** + * Analog Sensor Reads + */ + '4': () => LocalizedString + /** + * MQTT Publishes + */ + '5': () => LocalizedString + /** + * API Calls + */ + '6': () => LocalizedString + /** + * Syslog Messages + */ + '7': () => LocalizedString + } + /** + * {num} Device{{s}} + */ + NUM_DEVICES: (arg: { num: string | number | boolean }) => LocalizedString + /** + * {num} Temperature Sensor{{s}} + */ + NUM_TEMP_SENSORS: (arg: { num: string | number | boolean }) => LocalizedString + /** + * {num} Analog Sensor{{s}} + */ + NUM_ANALOG_SENSORS: (arg: { num: string | number | boolean }) => LocalizedString + /** + * {num} Day{{s}} + */ + NUM_DAYS: (arg: { num: string | number | boolean }) => LocalizedString + /** + * {num} Second{{s}} + */ + NUM_SECONDS: (arg: { num: string | number | boolean }) => LocalizedString + /** + * {num} Hour{{s}} + */ + NUM_HOURS: (arg: { num: string | number | boolean }) => LocalizedString + /** + * {num} Minute{{s}} + */ + NUM_MINUTES: (arg: { num: string | number | boolean }) => LocalizedString + /** + * Application Settings + */ + APPLICATION_SETTINGS: () => LocalizedString + /** + * Customization + */ + CUSTOMIZATION: () => LocalizedString + /** + * EMS-ESP is restarting + */ + APPLICATION_RESTARTING: () => LocalizedString + /** + * Select a pre-configured interface board profile from the list below or choose Custom to configure your own hardware settings + */ + BOARD_PROFILE_TEXT: () => LocalizedString + /** + * Board Profile + */ + BOARD_PROFILE: () => LocalizedString + /** + * Button + */ + BUTTON: () => LocalizedString + /** + * Temperature + */ + TEMPERATURE: () => LocalizedString + /** + * disabled + */ + DISABLED: () => LocalizedString + /** + * General Options + */ + GENERAL_OPTIONS: () => LocalizedString + /** + * Language (for device entities) + */ + LANGUAGE_ENTITIES: () => LocalizedString + /** + * Hide LED + */ + HIDE_LED: () => LocalizedString + /** + * Enable Telnet Console + */ + ENABLE_TELNET: () => LocalizedString + /** + * Enable Analog Sensors + */ + ENABLE_ANALOG: () => LocalizedString + /** + * Convert temperature values to Fahrenheit + */ + CONVERT_FAHRENHEIT: () => LocalizedString + /** + * Bypass Access Token authorization on API calls + */ + BYPASS_TOKEN: () => LocalizedString + /** + * Enable read-only mode (blocks all outgoing EMS Tx Write commands) + */ + READONLY: () => LocalizedString + /** + * Underclock CPU speed + */ + UNDERCLOCK_CPU: () => LocalizedString + /** + * Enable Shower Timer + */ + ENABLE_SHOWER_TIMER: () => LocalizedString + /** + * Enable Shower Alert + */ + ENABLE_SHOWER_ALERT: () => LocalizedString + /** + * Trigger Time + */ + TRIGGER_TIME: () => LocalizedString + /** + * Cold Shot Duration + */ + COLD_SHOT_DURATION: () => LocalizedString + /** + * Formatting Options + */ + FORMATTING_OPTIONS: () => LocalizedString + /** + * Boolean Format Dashboard + */ + BOOLEAN_FORMAT_DASHBOARD: () => LocalizedString + /** + * Boolean Format API/MQTT + */ + BOOLEAN_FORMAT_API: () => LocalizedString + /** + * Enum Format API/MQTT + */ + ENUM_FORMAT: () => LocalizedString + /** + * Index + */ + INDEX: () => LocalizedString + /** + * Enable parasite power + */ + ENABLE_PARASITE: () => LocalizedString + /** + * Logging + */ + LOGGING: () => LocalizedString + /** + * Log EMS telegrams in hexadecimal + */ + LOG_HEX: () => LocalizedString + /** + * Enable Syslog + */ + ENABLE_SYSLOG: () => LocalizedString + /** + * Mark Interval + */ + MARK_INTERVAL: () => LocalizedString + /** + * seconds + */ + SECONDS: () => LocalizedString + /** + * minutes + */ + MINUTES: () => LocalizedString + /** + * Restart + */ + RESTART: () => LocalizedString + /** + * hours + */ + HOURS: () => LocalizedString + /** + * EMS-ESP needs to be restarted to apply changed system settings + */ + RESTART_TEXT: () => LocalizedString + /** + * Command + */ + COMMAND: () => LocalizedString + /** + * All customizations have been removed. Restarting... + */ + CUSTOMIZATIONS_RESTART: () => LocalizedString + /** + * Selected entities exceeded limit. Please save in batches + */ + CUSTOMIZATIONS_FULL: () => LocalizedString + /** + * Customizations saved + */ + CUSTOMIZATIONS_SAVED: () => LocalizedString + /** + * Select a device and customize the entities options or click to rename + */ + CUSTOMIZATIONS_HELP_1: () => LocalizedString + /** + * mark as favorite + */ + CUSTOMIZATIONS_HELP_2: () => LocalizedString + /** + * disable write action + */ + CUSTOMIZATIONS_HELP_3: () => LocalizedString + /** + * exclude from MQTT and API + */ + CUSTOMIZATIONS_HELP_4: () => LocalizedString + /** + * hide from Dashboard + */ + CUSTOMIZATIONS_HELP_5: () => LocalizedString + /** + * Select a device + */ + SELECT_DEVICE: () => LocalizedString + /** + * set all + */ + SET_ALL: () => LocalizedString + /** + * Options + */ + OPTIONS: () => LocalizedString + /** + * Name + */ + NAME: () => LocalizedString + /** + * Are you sure you want remove all customizations including the custom settings of the Temperature and Analog sensors? + */ + CUSTOMIZATIONS_RESET: () => LocalizedString + /** + * Device Entities + */ + DEVICE_ENTITIES: () => LocalizedString + /** + * User Customization + */ + USER_CUSTOMIZATION: () => LocalizedString + /** + * Support Information + */ + SUPPORT_INFORMATION: () => LocalizedString + /** + * Click Here + */ + CLICK_HERE: () => LocalizedString + /** + * Visit the online wiki to get instructions on how to configure EMS-ESP + */ + HELP_INFORMATION_1: () => LocalizedString + /** + * For live community chat join our Discord server + */ + HELP_INFORMATION_2: () => LocalizedString + /** + * To request a feature or report a bug + */ + HELP_INFORMATION_3: () => LocalizedString + /** + * remember to download and attach your system information for a faster response when reporting an issue + */ + HELP_INFORMATION_4: () => LocalizedString + /** + * EMS-ESP is a free and open-source project. Please support its future development by giving it a star on Github! + */ + HELP_INFORMATION_5: () => LocalizedString + /** + * Support Info + */ + SUPPORT_INFO: () => LocalizedString + /** + * Upload + */ + UPLOAD: () => LocalizedString + /** + * Download + */ + DOWNLOAD: () => LocalizedString + /** + * aborted + */ + ABORTED: () => LocalizedString + /** + * failed + */ + FAILED: () => LocalizedString + /** + * successful + */ + SUCCESSFUL: () => LocalizedString + /** + * System + */ + SYSTEM: () => LocalizedString + /** + * Log + */ + LOG: () => LocalizedString + /** + * Status + */ + STATUS: () => LocalizedString + /** + * Upload/Download + */ + UPLOAD_DOWNLOAD: () => LocalizedString + /** + * You are currently running version + */ + SYSTEM_VERSION_RUNNING: () => LocalizedString + /** + * to apply the new firmware + */ + SYSTEM_APPLY_FIRMWARE: () => LocalizedString + /** + * Close + */ + CLOSE: () => LocalizedString + /** + * Use + */ + USE: () => LocalizedString + /** + * Factory Reset + */ + FACTORY_RESET: () => LocalizedString + /** + * Device has been factory reset and will now restart + */ + SYSTEM_FACTORY_TEXT: () => LocalizedString + /** + * Are you sure you want to reset the device to its factory defaults? + */ + SYSTEM_FACTORY_TEXT_DIALOG: () => LocalizedString + /** + * Version Check + */ + VERSION_CHECK: () => LocalizedString + /** + * The latest + */ + THE_LATEST: () => LocalizedString + /** + * Device (Platform / SDK) + */ + PLATFORM: () => LocalizedString + /** + * System Uptime + */ + UPTIME: () => LocalizedString + /** + * CPU Frequency + */ + CPU_FREQ: () => LocalizedString + /** + * Heap (Free / Max Alloc) + */ + HEAP: () => LocalizedString + /** + * PSRAM (Size / Free) + */ + PSRAM: () => LocalizedString + /** + * Flash Chip (Size / Speed) + */ + FLASH: () => LocalizedString + /** + * File System (Used / Total) + */ + FILESYSTEM: () => LocalizedString + /** + * Buffer Size + */ + BUFFER_SIZE: () => LocalizedString + /** + * Compact + */ + COMPACT: () => LocalizedString + /** + * Enable OTA Updates + */ + ENABLE_OTA: () => LocalizedString + /** + * Download the entity customizations + */ + DOWNLOAD_CUSTOMIZATION_TEXT: () => LocalizedString + /** + * Download the application settings. Be careful when sharing your settings as this file contains passwords and other sensitive system information + */ + DOWNLOAD_SETTINGS_TEXT: () => LocalizedString + /** + * Upload a new firmware (.bin) file, settings or customizations (.json) file below + */ + UPLOAD_TEXT: () => LocalizedString + /** + * Uploading + */ + UPLOADING: () => LocalizedString + /** + * Drop file or click here + */ + UPLOAD_DROP_TEXT: () => LocalizedString + /** + * Unexpected Error, please try again + */ + ERROR: () => LocalizedString + /** + * Time set + */ + TIME_SET: () => LocalizedString + /** + * Manage Users + */ + MANAGE_USERS: () => LocalizedString + /** + * is Admin + */ + IS_ADMIN: () => LocalizedString + /** + * You must have at least one admin user configured + */ + USER_WARNING: () => LocalizedString + /** + * Add + */ + ADD: () => LocalizedString + /** + * Access Token for + */ + ACCESS_TOKEN_FOR: () => LocalizedString + /** + * The token below is used with REST API calls that require authorization. It can be passed either as a Bearer token in the Authorization header or in the access_token URL query parameter. + */ + ACCESS_TOKEN_TEXT: () => LocalizedString + /** + * Generating token + */ + GENERATING_TOKEN: () => LocalizedString + /** + * User + */ + USER: () => LocalizedString + /** + * Modify + */ + MODIFY: () => LocalizedString + /** + * The su (super user) password is used to sign authentication tokens and also enable admin privileges within the Console. + */ + SU_TEXT: () => LocalizedString + /** + * Not enabled + */ + NOT_ENABLED: () => LocalizedString + /** + * Errors + */ + ERRORS: () => LocalizedString + /** + * Disconnect Reason + */ + DISCONNECT_REASON: () => LocalizedString + /** + * Enable MQTT + */ + ENABLE_MQTT: () => LocalizedString + /** + * Optional + */ + OPTIONAL: () => LocalizedString + /** + * Formatting + */ + FORMATTING: () => LocalizedString + /** + * Format + */ + FORMAT: () => LocalizedString + /** + * Nested in a single topic + */ + MQTT_NEST_1: () => LocalizedString + /** + * As individual topics + */ + MQTT_NEST_2: () => LocalizedString + /** + * Publish command output to a `response` topic + */ + MQTT_RESPONSE: () => LocalizedString + /** + * Publish single value topics on change + */ + MQTT_PUBLISH_TEXT_1: () => LocalizedString + /** + * Publish to command topics (ioBroker) + */ + MQTT_PUBLISH_TEXT_2: () => LocalizedString + /** + * Enable MQTT Discovery (Home Assistant, Domoticz) + */ + MQTT_PUBLISH_TEXT_3: () => LocalizedString + /** + * Prefix for the Discovery topics + */ + MQTT_PUBLISH_TEXT_4: () => LocalizedString + /** + * Publish Intervals + */ + MQTT_PUBLISH_INTERVALS: () => LocalizedString + /** + * Boilers and Heat Pumps + */ + MQTT_INT_BOILER: () => LocalizedString + /** + * Thermostats + */ + MQTT_INT_THERMOSTATS: () => LocalizedString + /** + * Solar Modules + */ + MQTT_INT_SOLAR: () => LocalizedString + /** + * Mixer Modules + */ + MQTT_INT_MIXER: () => LocalizedString + /** + * Default + */ + DEFAULT: () => LocalizedString + /** + * Set Clean Session + */ + MQTT_CLEAN_SESSION: () => LocalizedString + /** + * Always set Retain flag + */ + MQTT_RETAIN_FLAG: () => LocalizedString + /** + * Inactive + */ + INACTIVE: () => LocalizedString + /** + * Active + */ + ACTIVE: () => LocalizedString + /** + * Unknown + */ + UNKNOWN: () => LocalizedString + /** + * Set Time + */ + SET_TIME: () => LocalizedString + /** + * Enter local date and time below to set the time + */ + SET_TIME_TEXT: () => LocalizedString + /** + * Local Time + */ + LOCAL_TIME: () => LocalizedString + /** + * UTC Time + */ + UTC_TIME: () => LocalizedString + /** + * Enable NTP + */ + ENABLE_NTP: () => LocalizedString + /** + * Time Zone + */ + TIME_ZONE: () => LocalizedString + /** + * Access Point + */ + ACCESS_POINT: () => LocalizedString + /** + * Enable Access Point + */ + AP_PROVIDE: () => LocalizedString + /** + * always + */ + AP_PROVIDE_TEXT_1: () => LocalizedString + /** + * when WiFi is disconnected + */ + AP_PROVIDE_TEXT_2: () => LocalizedString + /** + * never + */ + AP_PROVIDE_TEXT_3: () => LocalizedString + /** + * Preferred Channel + */ + AP_PREFERRED_CHANNEL: () => LocalizedString + /** + * Hide SSID + */ + AP_HIDE_SSID: () => LocalizedString + /** + * Scan WiFi Networks + */ + NETWORK_SCAN: () => LocalizedString + /** + * Idle + */ + IDLE: () => LocalizedString + /** + * Lost + */ + LOST: () => LocalizedString + /** + * Scanning + */ + SCANNING: () => LocalizedString + /** + * Scan again + */ + SCAN_AGAIN: () => LocalizedString + /** + * Network Scanner + */ + NETWORK_SCANNER: () => LocalizedString + /** + * No WiFi networks found + */ + NETWORK_NO_WIFI: () => LocalizedString + /** + * leave blank to disable WiFi + */ + NETWORK_BLANK_SSID: () => LocalizedString + /** + * Power + */ + POWER: () => LocalizedString + /** + * Disable WiFi Sleep Mode + */ + NETWORK_DISABLE_SLEEP: () => LocalizedString + /** + * Use Lower WiFi Bandwidth + */ + NETWORK_LOW_BAND: () => LocalizedString + /** + * Enable mDNS Service + */ + NETWORK_USE_DNS: () => LocalizedString + /** + * Enable IPv6 support + */ + NETWORK_ENABLE_IPV6: () => LocalizedString + /** + * Use Fixed IP address + */ + NETWORK_FIXED_IP: () => LocalizedString + /** + * Admin + */ + ADMIN: () => LocalizedString + /** + * Guest + */ + GUEST: () => LocalizedString + /** + * New + */ + NEW: () => LocalizedString + /** + * Rename + */ + RENAME: () => LocalizedString +} + +export type Formatters = {} diff --git a/interface/src/i18n/i18n-util.async.ts b/interface/src/i18n/i18n-util.async.ts new file mode 100644 index 000000000..fb35c3bd3 --- /dev/null +++ b/interface/src/i18n/i18n-util.async.ts @@ -0,0 +1,31 @@ +// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. +/* eslint-disable */ + +import { initFormatters } from './formatters' +import type { Locales, Translations } from './i18n-types' +import { loadedFormatters, loadedLocales, locales } from './i18n-util' + +const localeTranslationLoaders = { + de: () => import('./de'), + en: () => import('./en'), + nl: () => import('./nl'), + no: () => import('./no'), + pl: () => import('./pl'), + se: () => import('./se'), +} + +const updateDictionary = (locale: Locales, dictionary: Partial) => + loadedLocales[locale] = { ...loadedLocales[locale], ...dictionary } + +export const importLocaleAsync = async (locale: Locales) => + (await localeTranslationLoaders[locale]()).default as unknown as Translations + +export const loadLocaleAsync = async (locale: Locales): Promise => { + updateDictionary(locale, await importLocaleAsync(locale)) + loadFormatters(locale) +} + +export const loadAllLocalesAsync = (): Promise => Promise.all(locales.map(loadLocaleAsync)) + +export const loadFormatters = (locale: Locales): void => + void (loadedFormatters[locale] = initFormatters(locale)) diff --git a/interface/src/i18n/i18n-util.sync.ts b/interface/src/i18n/i18n-util.sync.ts new file mode 100644 index 000000000..aa81b950b --- /dev/null +++ b/interface/src/i18n/i18n-util.sync.ts @@ -0,0 +1,34 @@ +// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. +/* eslint-disable */ + +import { initFormatters } from './formatters' +import type { Locales, Translations } from './i18n-types' +import { loadedFormatters, loadedLocales, locales } from './i18n-util' + +import de from './de' +import en from './en' +import nl from './nl' +import no from './no' +import pl from './pl' +import se from './se' + +const localeTranslations = { + de, + en, + nl, + no, + pl, + se, +} + +export const loadLocale = (locale: Locales): void => { + if (loadedLocales[locale]) return + + loadedLocales[locale] = localeTranslations[locale] as unknown as Translations + loadFormatters(locale) +} + +export const loadAllLocales = (): void => locales.forEach(loadLocale) + +export const loadFormatters = (locale: Locales): void => + void (loadedFormatters[locale] = initFormatters(locale)) diff --git a/interface/src/i18n/i18n-util.ts b/interface/src/i18n/i18n-util.ts new file mode 100644 index 000000000..63da3e066 --- /dev/null +++ b/interface/src/i18n/i18n-util.ts @@ -0,0 +1,37 @@ +// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. +/* eslint-disable */ + +import { i18n as initI18n, i18nObject as initI18nObject, i18nString as initI18nString } from 'typesafe-i18n' +import type { LocaleDetector } from 'typesafe-i18n/detectors' +import { detectLocale as detectLocaleFn } from 'typesafe-i18n/detectors' +import type { Formatters, Locales, Translations, TranslationFunctions } from './i18n-types' + +export const baseLocale: Locales = 'en' + +export const locales: Locales[] = [ + 'de', + 'en', + 'nl', + 'no', + 'pl', + 'se' +] + +export const isLocale = (locale: string) => locales.includes(locale as Locales) + +export const loadedLocales = {} as Record + +export const loadedFormatters = {} as Record + +export const i18nString = (locale: Locales) => initI18nString(locale, loadedFormatters[locale]) + +export const i18nObject = (locale: Locales) => + initI18nObject( + locale, + loadedLocales[locale], + loadedFormatters[locale] + ) + +export const i18n = () => initI18n(loadedLocales, loadedFormatters) + +export const detectLocale = (...detectors: LocaleDetector[]) => detectLocaleFn(baseLocale, locales, ...detectors) diff --git a/interface/src/i18n/nl/index.ts b/interface/src/i18n/nl/index.ts new file mode 100644 index 000000000..d545c42eb --- /dev/null +++ b/interface/src/i18n/nl/index.ts @@ -0,0 +1,265 @@ +import type { BaseTranslation } from '../i18n-types'; + +const nl: BaseTranslation = { + LANGUAGE: 'Taal', + RETRY: 'Opnieuw proberen', + LOADING: 'Laden', + IS_REQUIRED: 'is verplicht', + SIGN_IN: 'Inloggen', + SIGN_OUT: 'Uitloggen', + USERNAME: 'Gebruikersnaam', + PASSWORD: 'Wachtwoord', + DASHBOARD: 'Dashboard', + SETTINGS: 'Instellingen', + SAVED: 'opgeslagen', + HELP: 'Help', + LOGGED_IN: 'Ingelogd als {name}', + PLEASE_SIGNIN: 'Log in om verder te gaan', + UPLOAD_SUCCESSFUL: 'Upload successvol', + DOWNLOAD_SUCCESSFUL: 'Download successvol', + INVALID_LOGIN: 'Logingegevens fout', + NETWORK: 'Netwerk', + SECURITY: 'Beveiliging', + ONOFF_CAP: 'AAN/UIT', + ONOFF: 'aan/uit', + TYPE: 'Type', + DESCRIPTION: 'Beschrijving', + ENTITIES: 'Entiteiten', + REFRESH: 'Ververs', + EXPORT: 'Export', + BRAND: 'Merk', + ENTITY_NAME: 'Entiteit', + VALUE: 'Waarde', + SHOW_FAV: 'alleen favorieten weergeven', + DEVICE_SENSOR_DATA: 'Apparaat en Sensor data', + DEVICES_SENSORS: 'Apparaten & Sensoren', + ATTACHED_SENSORS: 'Aangesloten EMS-ESP sensoren', + RUN_COMMAND: 'Call commando', + CHANGE_VALUE: 'Wijzig waarde', + CANCEL: 'Annuleren', + RESET: 'Reset', + SEND: 'Verzenden', + SAVE: 'Opslaan', + REMOVE: 'Verwijderen', + PROBLEM_UPDATING: 'Probleem met updaten', + PROBLEM_LOADING: 'Probleem met laden', + ACCESS_DENIED: 'Toegang geweigerd', + ANALOG_SENSOR: 'Analoge sensor', + ANALOG_SENSORS: 'Analoge Sensoren', + UPDATED: 'Bijgewerkt', + UPDATE: 'Bijwerken', + REMOVED: 'Verwijderd', + DELETION: 'Verwijder', + OFFSET: 'Offset', + FACTOR: 'Factor', + FREQ: 'Frequentie', + STARTVALUE: 'Startwaarde', + WARN_GPIO: 'Waarschuwing: let op met het koppelen van de juiste GPIO pin!', + EDIT: 'Wijzigen', + TEMP_SENSOR: 'Temperatuur sensor', + TEMP_SENSORS: 'Temperatuur Sensoren', + WRITE_COMMAND: 'Schrijf commando {cmd}', + EMS_BUS_WARNING: + 'EMS bus niet gevonden. Als deze waarschuwing blijft staan na een paar seconden dan loop de instellingen na en in het bijzonder het apparaat type profiel na.', + EMS_BUS_SCANNING: 'Scannen naar EMS apparaten...', + CONNECTED: 'Verbonden', + TX_ISSUES: 'Tx bus probleem. Probeer een andere Tx verzendmodus', + DISCONNECTED: 'Niet verbonden', + EMS_SCAN: 'Weet je zeker dat je een volledige EMS bus scan uit wilt voeren?', + EMS_BUS_STATUS: 'EMS busstatus', + ACTIVE_DEVICES: 'Actieve Apparaten & Sensoren', + DEVICE: 'Apparaat', + SUCCESS: 'SUCCESS', + FAIL: 'MISLUKT', + QUALITY: 'QUALITEIT', + SCAN_DEVICES: 'Scannen naar nieuwe apparaten', + EMS_BUS_STATUS_TITLE: 'EMS Bus & Activiteitenstatus', + SCAN: 'Scan', + STATUS_NAMES: [ + 'EMS Telegrammen ontvangen (Rx)', + 'EMS Leesopdrachten (Tx)', + 'EMS Schrijfopdrachten (Tx)', + 'Temperatuursensoren uitgelezen', + 'Analoge sensoren uitgelezen', + 'MQTT publicaties', + 'API calls', + 'Syslog berichten' + ], + NUM_DEVICES: '{num} Apparaat{{en}}', + NUM_TEMP_SENSORS: '{num} Temperatuursensor{{en}}', + NUM_ANALOG_SENSORS: '{num} Analoge sensor{{en}}', + NUM_DAYS: '{num} Dag{{en}}', + NUM_SECONDS: '{num} Second{{en}}', + NUM_HOURS: '{num} Uur{{en}}', + NUM_MINUTES: '{num} Minuut{{en}}', + APPLICATION_SETTINGS: 'Applicatieinstellingen', + CUSTOMIZATION: 'Custom aanpassingen', + APPLICATION_RESTARTING: 'EMS-ESP herstarten', + BOARD_PROFILE_TEXT: + 'Selecteer een vooraf ingesteld apparaat profiel uit de lijst of kies Eigen om zelf uw hardware te configureren', + BOARD_PROFILE: 'Apparaatprofiel', + BUTTON: 'Toets', + TEMPERATURE: 'Temperatuur', + DISABLED: 'Uitgeschakeld', + GENERAL_OPTIONS: 'Algemene Opties', + LANGUAGE_ENTITIES: 'Taal (voor apparaat entiteiten)', + HIDE_LED: 'Verberg LED', + ENABLE_TELNET: 'Activeer Telnet console', + ENABLE_ANALOG: 'Activeer analoge sensoren', + CONVERT_FAHRENHEIT: 'Converteer temperatuurwaarden naar Fahrenheit', + BYPASS_TOKEN: 'Bypass Access Token authorization on API calls', + READONLY: 'Activeer read-only modus (blokkeert alle outgaande EMS Tx schrijf commandos)', + UNDERCLOCK_CPU: 'Underclock CPU snelheid', + ENABLE_SHOWER_TIMER: 'Activeer Douche Timer (tijdmeting)', + ENABLE_SHOWER_ALERT: 'Activeer Douchemelding', + TRIGGER_TIME: 'Trigger tijd', + COLD_SHOT_DURATION: 'Tijd Shot koud water', + FORMATTING_OPTIONS: 'Formatteringsopties', + BOOLEAN_FORMAT_DASHBOARD: 'Boolean formaat dashboard', + BOOLEAN_FORMAT_API: 'Boolean formaat API/MQTT', + ENUM_FORMAT: 'Enum formaat API/MQTT', + INDEX: 'Index', + ENABLE_PARASITE: 'Activeer Dallas parasitaire modus', + LOGGING: 'Logging', + LOG_HEX: 'Log EMS telegrammen in hexadecimaal', + ENABLE_SYSLOG: 'Activeer Syslog', + MARK_INTERVAL: 'Markeringsinterval', + SECONDS: 'seconden', + MINUTES: 'minuten', + RESTART: 'Herstarten', + HOURS: 'uren', + RESTART_TEXT: 'EMS-ESP dient opnieuw gestart te worden om de wijzingen toe te passen', + COMMAND: 'Commando', + CUSTOMIZATIONS_RESTART: 'Alle custom profielen worden verwijderd. Herstarten...', + CUSTOMIZATIONS_FULL: 'Te veel entiteiten geselecteerd. Sla op in delen aub', + CUSTOMIZATIONS_SAVED: 'Custom aanpassingen opgeslagen', + CUSTOMIZATIONS_HELP_1: 'Selecteer een apparaat en pas de entiteiten aan door middel van de opties', + CUSTOMIZATIONS_HELP_2: 'Markeer as favoriet', + CUSTOMIZATIONS_HELP_3: 'Zet schrijfacties uit', + CUSTOMIZATIONS_HELP_4: 'Uitsluiten van MQTT en API', + CUSTOMIZATIONS_HELP_5: 'verberg van het Dashboard', + SELECT_DEVICE: 'Selecteer een apparaat', + SET_ALL: 'Alles aanzetten', + OPTIONS: 'Opties', + NAME: 'Naam', + CUSTOMIZATIONS_RESET: + 'Weet je zeker dat je alle custom aanpassingen wilt verwijderen inclusief de custom instellingen voor analoge temperatuursensoren?', + DEVICE_ENTITIES: 'Apparaat Entiteiten', + USER_CUSTOMIZATION: 'Custom Instellingen', + SUPPORT_INFORMATION: 'Support Informatie', + CLICK_HERE: 'Klik Hier', + HELP_INFORMATION_1: 'Visit the online wiki to get instructions on how to configure EMS-ESP', + HELP_INFORMATION_2: 'For live community chat join our Discord server', + HELP_INFORMATION_3: 'To request a feature or report a bug', + HELP_INFORMATION_4: + 'remember to download and attach your system information for a faster response when reporting an issue', + HELP_INFORMATION_5: + "EMS-ESP is a free and open-source project. Please support its future development by giving it a star on Github!", + SUPPORT_INFO: 'Support Info', + UPLOAD: 'Upload', + DOWNLOAD: 'Download', + ABORTED: 'afgebroken', + FAILED: 'mislukt', + SUCCESSFUL: 'successvol', + SYSTEM: 'Systeem', + LOG: 'Log', + STATUS: 'Status', + UPLOAD_DOWNLOAD: 'Upload/Download', + SYSTEM_VERSION_RUNNING: 'op dit moment draai je versie', + SYSTEM_APPLY_FIRMWARE: 'om de nieuwe firmware te activeren', + CLOSE: 'Sluiten', + USE: 'Gebruik', + FACTORY_RESET: 'Fabrieksinstellingen', + SYSTEM_FACTORY_TEXT: 'Gateway is gereset en start nu weer op met fabrieksinstellingen', + SYSTEM_FACTORY_TEXT_DIALOG: 'Weet je zeker dat je een reset naar fabrieksinstellingen uit wilt voeren?', + VERSION_CHECK: 'Versie Check', + THE_LATEST: 'De laatste', + PLATFORM: 'Apparaat (Platform / SDK)', + UPTIME: 'Systeem Uptime', + CPU_FREQ: 'CPU Frequency', + HEAP: 'Heap (Free / Max Alloc)', + PSRAM: 'PSRAM (Size / Free)', + FLASH: 'Flash Chip (Size / Speed)', + FILESYSTEM: 'File System (Used / Total)', + BUFFER_SIZE: 'Buffer Size', + COMPACT: 'Compact', + ENABLE_OTA: 'Acitveer OTA Updates', + DOWNLOAD_CUSTOMIZATION_TEXT: 'Download alle custom instellingen', + DOWNLOAD_SETTINGS_TEXT: + 'Download de applicatie settings. Wees voorzichting met het delen van dit bestand want het bevat o.a. de wachtwoorden in plain text', + UPLOAD_TEXT: 'Upload een nieuwe firmware (.bin) file, instellingen of custom instellingen (.json) bestand hieronder', + UPLOADING: 'Uploading', + UPLOAD_DROP_TEXT: 'Sleep bestand hierheen of klik hier', + ERROR: 'Onverwachte fout, probeer opnieuw', + TIME_SET: 'Tijd ingesteld', + MANAGE_USERS: 'Beheer Gebruikers', + IS_ADMIN: 'is Admin', + USER_WARNING: 'U dient tenminste 1 admin gebruiker te configureren', + ADD: 'Toevoegen', + ACCESS_TOKEN_FOR: 'Access Token voor', + ACCESS_TOKEN_TEXT: + 'Het token hieronder wordt gebruikt voor de REST API calls die authorisatie nodig hebben. Het kan zowel als Bearer token in de Authorization header of in acccess_token URL query parameter gebruikt worden', + GENERATING_TOKEN: 'Token aan het genereren', + USER: 'Gebruiker', + MODIFY: 'Aanpassen', + SU_TEXT: + 'Het su (super user) wachtwoord wordt gebruikt om authorisatie tokens te signeren en ook om admin privileges te activeren in de console.', + NOT_ENABLED: 'Niet geactiveerd', + ERRORS: 'Foutmeldingen', + DISCONNECT_REASON: 'Verbinding verbroken vanwege', + ENABLE_MQTT: 'Activeer MQTT', + OPTIONAL: 'Optioneel', + FORMATTING: 'Formatteren', + FORMAT: 'Formattering', + MQTT_NEST_1: 'Genest in 1 topic', + MQTT_NEST_2: 'Als individuele topics', + MQTT_RESPONSE: 'Publiceer commando output naar een `response` topic', + MQTT_PUBLISH_TEXT_1: 'Publiceer enkele waarde topics on change', + MQTT_PUBLISH_TEXT_2: 'Publiceer naar commando topics (ioBroker)', + MQTT_PUBLISH_TEXT_3: 'Activeer MQTT Discovery (Home Assistant, Domoticz)', + MQTT_PUBLISH_TEXT_4: 'Prefix voor de Discovery topics', + MQTT_PUBLISH_INTERVALS: 'Publicatie intervallen', + MQTT_INT_BOILER: 'CV ketels en warmtepompen', + MQTT_INT_THERMOSTATS: 'Thermostaten', + MQTT_INT_SOLAR: 'Solar Modules', + MQTT_INT_MIXER: 'Mixer Modules', + DEFAULT: 'Default', + MQTT_CLEAN_SESSION: 'Set Clean Session', + MQTT_RETAIN_FLAG: 'Always set Retain flag', + INACTIVE: 'Inactief', + ACTIVE: 'Actief', + UNKNOWN: 'Onbekend', + SET_TIME: 'Tijd instellen', + SET_TIME_TEXT: 'Geef de locale datum en tijd in', + LOCAL_TIME: 'Locale Tijd', + UTC_TIME: 'UTC Tijd', + ENABLE_NTP: 'Activeer NTP', + TIME_ZONE: 'Tijdzone', + ACCESS_POINT: 'Access Point', + AP_PROVIDE: 'Activeer Access Point', + AP_PROVIDE_TEXT_1: 'altijd', + AP_PROVIDE_TEXT_2: 'als WiFi niet is verbonden', + AP_PROVIDE_TEXT_3: 'nooit', + AP_PREFERRED_CHANNEL: 'Voorkeurskanaal', + AP_HIDE_SSID: 'SSID verbergen', + NETWORK_SCAN: 'Scan WiFi Networken', + IDLE: 'Idle', + LOST: 'Verloren', + SCANNING: 'Scannen', + SCAN_AGAIN: 'Opnieuw scannen', + NETWORK_SCANNER: 'Netwerk Scanner', + NETWORK_NO_WIFI: 'Geen WiFi networken gevonden', + NETWORK_BLANK_SSID: 'laat leeg om WiFi uit te schakelen', + POWER: 'Vermogen', + NETWORK_DISABLE_SLEEP: 'WiFi Sleep Mode uitzetten', + NETWORK_LOW_BAND: 'Lagere WiFi bandbreedte gebruiken', + NETWORK_USE_DNS: 'Activeer mDNS Service', + NETWORK_ENABLE_IPV6: 'Activeer IPv6 support', + NETWORK_FIXED_IP: 'Gebruik vast IP addres', + ADMIN: 'Admin', + GUEST: 'Gast', + NEW: 'Nieuwe', + RENAME: 'Hernoem' +}; + +export default nl; diff --git a/interface/src/i18n/no/index.ts b/interface/src/i18n/no/index.ts new file mode 100644 index 000000000..c70c47e0e --- /dev/null +++ b/interface/src/i18n/no/index.ts @@ -0,0 +1,265 @@ +import type { BaseTranslation } from '../i18n-types'; + +const en: BaseTranslation = { + LANGUAGE: 'Language', + RETRY: 'Retry', + LOADING: 'Loading', + IS_REQUIRED: 'is required', + SIGN_IN: 'Sign In', + SIGN_OUT: 'Sign Out', + USERNAME: 'Username', + PASSWORD: 'Password', + DASHBOARD: 'Dashboard', + SETTINGS: 'Settings', + SAVED: 'saved', + HELP: 'Help', + LOGGED_IN: 'Logged in as {name}', + PLEASE_SIGNIN: 'Please sign in to continue', + UPLOAD_SUCCESSFUL: 'Upload successful', + DOWNLOAD_SUCCESSFUL: 'Download successful', + INVALID_LOGIN: 'Invalid login details', + NETWORK: 'Network', + SECURITY: 'Security', + ONOFF_CAP: 'ON/OFF', + ONOFF: 'on/off', + TYPE: 'Type', + DESCRIPTION: 'Description', + ENTITIES: 'Entities', + REFRESH: 'Refresh', + EXPORT: 'Export', + DEVICE_DETAILS: 'Device Details', + BRAND: 'Brand', + ENTITY_NAME: 'Entity Name', + VALUE: 'Value', + SHOW_FAV: 'only show favorites', + DEVICE_SENSOR_DATA: 'Device and Sensor Data', + DEVICES_SENSORS: 'Devices & Sensors', + ATTACHED_SENSORS: 'Attached EMS-ESP Sensors', + RUN_COMMAND: 'Call Command', + CHANGE_VALUE: 'Change Value', + CANCEL: 'Cancel', + RESET: 'Reset', + SEND: 'Send', + SAVE: 'Save', + REMOVE: 'Remove', + PROBLEM_UPDATING: 'Problem updating', + PROBLEM_LOADING: 'Problem loading', + ACCESS_DENIED: 'Access Denied', + ANALOG_SENSOR: 'Analog Sensor', + ANALOG_SENSORS: 'Analog Sensors', + UPDATED: 'Updated', + UPDATE: 'Update', + REMOVED: 'Removed', + DELETION: 'Deletion', + OFFSET: 'Offset', + FACTOR: 'Factor', + FREQ: 'Frequency', + STARTVALUE: 'Start value', + WARN_GPIO: 'Warning: be careful when assigning a GPIO!', + EDIT: 'Edit', + TEMP_SENSOR: 'Temperature Sensor', + TEMP_SENSORS: 'Temperature Sensors', + WRITE_COMMAND: 'Write command {cmd}', + EMS_BUS_WARNING: + 'EMS bus disconnected. If this warning still persists after a few seconds please check settings and board profile', + EMS_BUS_SCANNING: 'Scanning for EMS devices...', + CONNECTED: 'Connected', + TX_ISSUES: 'Tx issues - try a different Tx Mode', + DISCONNECTED: 'Disconnected', + EMS_SCAN: 'Are you sure you want to initiate a full device scan of the EMS bus?', + EMS_BUS_STATUS: 'EMS Bus Status', + ACTIVE_DEVICES: 'Active Devices & Sensors', + DEVICE: 'Device', + SUCCESS: 'SUCCESS', + FAIL: 'FAIL', + QUALITY: 'QUALITY', + SCAN_DEVICES: 'Scan for new devices', + EMS_BUS_STATUS_TITLE: 'EMS Bus & Activity Status', + SCAN: 'Scan', + STATUS_NAMES: [ + 'EMS Telegrams Received (Rx)', + 'EMS Reads (Tx)', + 'EMS Writes (Tx)', + 'Temperature Sensor Reads', + 'Analog Sensor Reads', + 'MQTT Publishes', + 'API Calls', + 'Syslog Messages' + ], + NUM_DEVICES: '{num} Device{{s}}', + NUM_TEMP_SENSORS: '{num} Temperature Sensor{{s}}', + NUM_ANALOG_SENSORS: '{num} Analog Sensor{{s}}', + NUM_DAYS: '{num} Day{{s}}', + NUM_SECONDS: '{num} Second{{s}}', + NUM_HOURS: '{num} Hour{{s}}', + NUM_MINUTES: '{num} Minute{{s}}', + APPLICATION_SETTINGS: 'Application Settings', + CUSTOMIZATION: 'Customization', + APPLICATION_RESTARTING: 'EMS-ESP is restarting', + BOARD_PROFILE_TEXT: + 'Select a pre-configured interface board profile from the list below or choose Custom to configure your own hardware settings', + BOARD_PROFILE: 'Board Profile', + BUTTON: 'Button', + TEMPERATURE: 'Temperature', + DISABLED: 'disabled', + GENERAL_OPTIONS: 'General Options', + LANGUAGE_ENTITIES: 'Language (for device entities)', + HIDE_LED: 'Hide LED', + ENABLE_TELNET: 'Enable Telnet Console', + ENABLE_ANALOG: 'Enable Analog Sensors', + CONVERT_FAHRENHEIT: 'Convert temperature values to Fahrenheit', + BYPASS_TOKEN: 'Bypass Access Token authorization on API calls', + READONLY: 'Enable read-only mode (blocks all outgoing EMS Tx Write commands)', + UNDERCLOCK_CPU: 'Underclock CPU speed', + ENABLE_SHOWER_TIMER: 'Enable Shower Timer', + ENABLE_SHOWER_ALERT: 'Enable Shower Alert', + TRIGGER_TIME: 'Trigger Time', + COLD_SHOT_DURATION: 'Cold Shot Duration', + FORMATTING_OPTIONS: 'Formatting Options', + BOOLEAN_FORMAT_DASHBOARD: 'Boolean Format Dashboard', + BOOLEAN_FORMAT_API: 'Boolean Format API/MQTT', + ENUM_FORMAT: 'Enum Format API/MQTT', + INDEX: 'Index', + ENABLE_PARASITE: 'Enable parasite power', + LOGGING: 'Logging', + LOG_HEX: 'Log EMS telegrams in hexadecimal', + ENABLE_SYSLOG: 'Enable Syslog', + MARK_INTERVAL: 'Mark Interval', + SECONDS: 'seconds', + MINUTES: 'minutes', + RESTART: 'Restart', + HOURS: 'hours', + RESTART_TEXT: 'EMS-ESP needs to be restarted to apply changed system settings', + COMMAND: 'Command', + CUSTOMIZATIONS_RESTART: 'All customizations have been removed. Restarting...', + CUSTOMIZATIONS_FULL: 'Selected entities exceeded limit. Please save in batches', + CUSTOMIZATIONS_SAVED: 'Customizations saved', + CUSTOMIZATIONS_HELP_1: 'Select a device and customize the entities options or click to rename', + CUSTOMIZATIONS_HELP_2: 'mark as favorite', + CUSTOMIZATIONS_HELP_3: 'disable write action', + CUSTOMIZATIONS_HELP_4: 'exclude from MQTT and API', + CUSTOMIZATIONS_HELP_5: 'hide from Dashboard', + SELECT_DEVICE: 'Select a device', + SET_ALL: 'set all', + OPTIONS: 'Options', + NAME: 'Name', + CUSTOMIZATIONS_RESET: + 'Are you sure you want remove all customizations including the custom settings of the Temperature and Analog sensors?', + DEVICE_ENTITIES: 'Device Entities', + USER_CUSTOMIZATION: 'User Customization', + SUPPORT_INFORMATION: 'Support Information', + CLICK_HERE: 'Click Here', + HELP_INFORMATION_1: 'Visit the online wiki to get instructions on how to configure EMS-ESP', + HELP_INFORMATION_2: 'For live community chat join our Discord server', + HELP_INFORMATION_3: 'To request a feature or report a bug', + HELP_INFORMATION_4: 'remember to download and attach your system information for a faster response when reporting an issue', + HELP_INFORMATION_5: + "EMS-ESP is a free and open-source project. Please support its future development by giving it a star on Github!", + SUPPORT_INFO: 'Support Info', + UPLOAD: 'Upload', + DOWNLOAD: 'Download', + ABORTED: 'aborted', + FAILED: 'failed', + SUCCESSFUL: 'successful', + SYSTEM: 'System', + LOG: 'Log', + STATUS: 'Status', + UPLOAD_DOWNLOAD: 'Upload/Download', + SYSTEM_VERSION_RUNNING: 'You are currently running version', + SYSTEM_APPLY_FIRMWARE: 'to apply the new firmware', + CLOSE: 'Close', + USE: 'Use', + FACTORY_RESET: 'Factory Reset', + SYSTEM_FACTORY_TEXT: 'Device has been factory reset and will now restart', + SYSTEM_FACTORY_TEXT_DIALOG: 'Are you sure you want to reset the device to its factory defaults?', + VERSION_CHECK: 'Version Check', + THE_LATEST: 'The latest', + PLATFORM: 'Device (Platform / SDK)', + UPTIME: 'System Uptime', + CPU_FREQ: 'CPU Frequency', + HEAP: 'Heap (Free / Max Alloc)', + PSRAM: 'PSRAM (Size / Free)', + FLASH: 'Flash Chip (Size / Speed)', + FILESYSTEM: 'File System (Used / Total)', + BUFFER_SIZE: 'Buffer Size', + COMPACT: 'Compact', + ENABLE_OTA: 'Enable OTA Updates', + DOWNLOAD_CUSTOMIZATION_TEXT: 'Download the entity customizations', + DOWNLOAD_SETTINGS_TEXT: + 'Download the application settings. Be careful when sharing your settings as this file contains passwords and other sensitive system information', + UPLOAD_TEXT: 'Upload a new firmware (.bin) file, settings or customizations (.json) file below', + UPLOADING: 'Uploading', + UPLOAD_DROP_TEXT: 'Drop file or click here', + ERROR: 'Unexpected Error, please try again', + TIME_SET: 'Time set', + MANAGE_USERS: 'Manage Users', + IS_ADMIN: 'is Admin', + USER_WARNING: 'You must have at least one admin user configured', + ADD: 'Add', + ACCESS_TOKEN_FOR: 'Access Token for', + ACCESS_TOKEN_TEXT: + 'The token below is used with REST API calls that require authorization. It can be passed either as a Bearer token in the Authorization header or in the access_token URL query parameter.', + GENERATING_TOKEN: 'Generating token', + USER: 'User', + MODIFY: 'Modify', + SU_TEXT: + 'The su (super user) password is used to sign authentication tokens and also enable admin privileges within the Console.', + NOT_ENABLED: 'Not enabled', + ERRORS: 'Errors', + DISCONNECT_REASON: 'Disconnect Reason', + ENABLE_MQTT: 'Enable MQTT', + OPTIONAL: 'Optional', + FORMATTING: 'Formatting', + FORMAT: 'Format', + MQTT_NEST_1: 'Nested in a single topic', + MQTT_NEST_2: 'As individual topics', + MQTT_RESPONSE: 'Publish command output to a `response` topic', + MQTT_PUBLISH_TEXT_1: 'Publish single value topics on change', + MQTT_PUBLISH_TEXT_2: 'Publish to command topics (ioBroker)', + MQTT_PUBLISH_TEXT_3: 'Enable MQTT Discovery (Home Assistant, Domoticz)', + MQTT_PUBLISH_TEXT_4: 'Prefix for the Discovery topics', + MQTT_PUBLISH_INTERVALS: 'Publish Intervals', + MQTT_INT_BOILER: 'Boilers and Heat Pumps', + MQTT_INT_THERMOSTATS: 'Thermostats', + MQTT_INT_SOLAR: 'Solar Modules', + MQTT_INT_MIXER: 'Mixer Modules', + DEFAULT: 'Default', + MQTT_CLEAN_SESSION: 'Set Clean Session', + MQTT_RETAIN_FLAG: 'Always set Retain flag', + INACTIVE: 'Inactive', + ACTIVE: 'Active', + UNKNOWN: 'Unknown', + SET_TIME: 'Set Time', + SET_TIME_TEXT: 'Enter local date and time below to set the time', + LOCAL_TIME: 'Local Time', + UTC_TIME: 'UTC Time', + ENABLE_NTP: 'Enable NTP', + TIME_ZONE: 'Time Zone', + ACCESS_POINT: 'Access Point', + AP_PROVIDE: 'Enable Access Point', + AP_PROVIDE_TEXT_1: 'always', + AP_PROVIDE_TEXT_2: 'when WiFi is disconnected', + AP_PROVIDE_TEXT_3: 'never', + AP_PREFERRED_CHANNEL: 'Preferred Channel', + AP_HIDE_SSID: 'Hide SSID', + NETWORK_SCAN: 'Scan WiFi Networks', + IDLE: 'Idle', + LOST: 'Lost', + SCANNING: 'Scanning', + SCAN_AGAIN: 'Scan again', + NETWORK_SCANNER: 'Network Scanner', + NETWORK_NO_WIFI: 'No WiFi networks found', + NETWORK_BLANK_SSID: 'leave blank to disable WiFi', + POWER: 'Power', + NETWORK_DISABLE_SLEEP: 'Disable WiFi Sleep Mode', + NETWORK_LOW_BAND: 'Use Lower WiFi Bandwidth', + NETWORK_USE_DNS: 'Enable mDNS Service', + NETWORK_ENABLE_IPV6: 'Enable IPv6 support', + NETWORK_FIXED_IP: 'Use Fixed IP address', + ADMIN: 'Admin', + GUEST: 'Guest', + NEW: 'New', + RENAME: 'Rename' +}; + +export default en; diff --git a/interface/src/i18n/pl/index.ts b/interface/src/i18n/pl/index.ts new file mode 100644 index 000000000..c70c47e0e --- /dev/null +++ b/interface/src/i18n/pl/index.ts @@ -0,0 +1,265 @@ +import type { BaseTranslation } from '../i18n-types'; + +const en: BaseTranslation = { + LANGUAGE: 'Language', + RETRY: 'Retry', + LOADING: 'Loading', + IS_REQUIRED: 'is required', + SIGN_IN: 'Sign In', + SIGN_OUT: 'Sign Out', + USERNAME: 'Username', + PASSWORD: 'Password', + DASHBOARD: 'Dashboard', + SETTINGS: 'Settings', + SAVED: 'saved', + HELP: 'Help', + LOGGED_IN: 'Logged in as {name}', + PLEASE_SIGNIN: 'Please sign in to continue', + UPLOAD_SUCCESSFUL: 'Upload successful', + DOWNLOAD_SUCCESSFUL: 'Download successful', + INVALID_LOGIN: 'Invalid login details', + NETWORK: 'Network', + SECURITY: 'Security', + ONOFF_CAP: 'ON/OFF', + ONOFF: 'on/off', + TYPE: 'Type', + DESCRIPTION: 'Description', + ENTITIES: 'Entities', + REFRESH: 'Refresh', + EXPORT: 'Export', + DEVICE_DETAILS: 'Device Details', + BRAND: 'Brand', + ENTITY_NAME: 'Entity Name', + VALUE: 'Value', + SHOW_FAV: 'only show favorites', + DEVICE_SENSOR_DATA: 'Device and Sensor Data', + DEVICES_SENSORS: 'Devices & Sensors', + ATTACHED_SENSORS: 'Attached EMS-ESP Sensors', + RUN_COMMAND: 'Call Command', + CHANGE_VALUE: 'Change Value', + CANCEL: 'Cancel', + RESET: 'Reset', + SEND: 'Send', + SAVE: 'Save', + REMOVE: 'Remove', + PROBLEM_UPDATING: 'Problem updating', + PROBLEM_LOADING: 'Problem loading', + ACCESS_DENIED: 'Access Denied', + ANALOG_SENSOR: 'Analog Sensor', + ANALOG_SENSORS: 'Analog Sensors', + UPDATED: 'Updated', + UPDATE: 'Update', + REMOVED: 'Removed', + DELETION: 'Deletion', + OFFSET: 'Offset', + FACTOR: 'Factor', + FREQ: 'Frequency', + STARTVALUE: 'Start value', + WARN_GPIO: 'Warning: be careful when assigning a GPIO!', + EDIT: 'Edit', + TEMP_SENSOR: 'Temperature Sensor', + TEMP_SENSORS: 'Temperature Sensors', + WRITE_COMMAND: 'Write command {cmd}', + EMS_BUS_WARNING: + 'EMS bus disconnected. If this warning still persists after a few seconds please check settings and board profile', + EMS_BUS_SCANNING: 'Scanning for EMS devices...', + CONNECTED: 'Connected', + TX_ISSUES: 'Tx issues - try a different Tx Mode', + DISCONNECTED: 'Disconnected', + EMS_SCAN: 'Are you sure you want to initiate a full device scan of the EMS bus?', + EMS_BUS_STATUS: 'EMS Bus Status', + ACTIVE_DEVICES: 'Active Devices & Sensors', + DEVICE: 'Device', + SUCCESS: 'SUCCESS', + FAIL: 'FAIL', + QUALITY: 'QUALITY', + SCAN_DEVICES: 'Scan for new devices', + EMS_BUS_STATUS_TITLE: 'EMS Bus & Activity Status', + SCAN: 'Scan', + STATUS_NAMES: [ + 'EMS Telegrams Received (Rx)', + 'EMS Reads (Tx)', + 'EMS Writes (Tx)', + 'Temperature Sensor Reads', + 'Analog Sensor Reads', + 'MQTT Publishes', + 'API Calls', + 'Syslog Messages' + ], + NUM_DEVICES: '{num} Device{{s}}', + NUM_TEMP_SENSORS: '{num} Temperature Sensor{{s}}', + NUM_ANALOG_SENSORS: '{num} Analog Sensor{{s}}', + NUM_DAYS: '{num} Day{{s}}', + NUM_SECONDS: '{num} Second{{s}}', + NUM_HOURS: '{num} Hour{{s}}', + NUM_MINUTES: '{num} Minute{{s}}', + APPLICATION_SETTINGS: 'Application Settings', + CUSTOMIZATION: 'Customization', + APPLICATION_RESTARTING: 'EMS-ESP is restarting', + BOARD_PROFILE_TEXT: + 'Select a pre-configured interface board profile from the list below or choose Custom to configure your own hardware settings', + BOARD_PROFILE: 'Board Profile', + BUTTON: 'Button', + TEMPERATURE: 'Temperature', + DISABLED: 'disabled', + GENERAL_OPTIONS: 'General Options', + LANGUAGE_ENTITIES: 'Language (for device entities)', + HIDE_LED: 'Hide LED', + ENABLE_TELNET: 'Enable Telnet Console', + ENABLE_ANALOG: 'Enable Analog Sensors', + CONVERT_FAHRENHEIT: 'Convert temperature values to Fahrenheit', + BYPASS_TOKEN: 'Bypass Access Token authorization on API calls', + READONLY: 'Enable read-only mode (blocks all outgoing EMS Tx Write commands)', + UNDERCLOCK_CPU: 'Underclock CPU speed', + ENABLE_SHOWER_TIMER: 'Enable Shower Timer', + ENABLE_SHOWER_ALERT: 'Enable Shower Alert', + TRIGGER_TIME: 'Trigger Time', + COLD_SHOT_DURATION: 'Cold Shot Duration', + FORMATTING_OPTIONS: 'Formatting Options', + BOOLEAN_FORMAT_DASHBOARD: 'Boolean Format Dashboard', + BOOLEAN_FORMAT_API: 'Boolean Format API/MQTT', + ENUM_FORMAT: 'Enum Format API/MQTT', + INDEX: 'Index', + ENABLE_PARASITE: 'Enable parasite power', + LOGGING: 'Logging', + LOG_HEX: 'Log EMS telegrams in hexadecimal', + ENABLE_SYSLOG: 'Enable Syslog', + MARK_INTERVAL: 'Mark Interval', + SECONDS: 'seconds', + MINUTES: 'minutes', + RESTART: 'Restart', + HOURS: 'hours', + RESTART_TEXT: 'EMS-ESP needs to be restarted to apply changed system settings', + COMMAND: 'Command', + CUSTOMIZATIONS_RESTART: 'All customizations have been removed. Restarting...', + CUSTOMIZATIONS_FULL: 'Selected entities exceeded limit. Please save in batches', + CUSTOMIZATIONS_SAVED: 'Customizations saved', + CUSTOMIZATIONS_HELP_1: 'Select a device and customize the entities options or click to rename', + CUSTOMIZATIONS_HELP_2: 'mark as favorite', + CUSTOMIZATIONS_HELP_3: 'disable write action', + CUSTOMIZATIONS_HELP_4: 'exclude from MQTT and API', + CUSTOMIZATIONS_HELP_5: 'hide from Dashboard', + SELECT_DEVICE: 'Select a device', + SET_ALL: 'set all', + OPTIONS: 'Options', + NAME: 'Name', + CUSTOMIZATIONS_RESET: + 'Are you sure you want remove all customizations including the custom settings of the Temperature and Analog sensors?', + DEVICE_ENTITIES: 'Device Entities', + USER_CUSTOMIZATION: 'User Customization', + SUPPORT_INFORMATION: 'Support Information', + CLICK_HERE: 'Click Here', + HELP_INFORMATION_1: 'Visit the online wiki to get instructions on how to configure EMS-ESP', + HELP_INFORMATION_2: 'For live community chat join our Discord server', + HELP_INFORMATION_3: 'To request a feature or report a bug', + HELP_INFORMATION_4: 'remember to download and attach your system information for a faster response when reporting an issue', + HELP_INFORMATION_5: + "EMS-ESP is a free and open-source project. Please support its future development by giving it a star on Github!", + SUPPORT_INFO: 'Support Info', + UPLOAD: 'Upload', + DOWNLOAD: 'Download', + ABORTED: 'aborted', + FAILED: 'failed', + SUCCESSFUL: 'successful', + SYSTEM: 'System', + LOG: 'Log', + STATUS: 'Status', + UPLOAD_DOWNLOAD: 'Upload/Download', + SYSTEM_VERSION_RUNNING: 'You are currently running version', + SYSTEM_APPLY_FIRMWARE: 'to apply the new firmware', + CLOSE: 'Close', + USE: 'Use', + FACTORY_RESET: 'Factory Reset', + SYSTEM_FACTORY_TEXT: 'Device has been factory reset and will now restart', + SYSTEM_FACTORY_TEXT_DIALOG: 'Are you sure you want to reset the device to its factory defaults?', + VERSION_CHECK: 'Version Check', + THE_LATEST: 'The latest', + PLATFORM: 'Device (Platform / SDK)', + UPTIME: 'System Uptime', + CPU_FREQ: 'CPU Frequency', + HEAP: 'Heap (Free / Max Alloc)', + PSRAM: 'PSRAM (Size / Free)', + FLASH: 'Flash Chip (Size / Speed)', + FILESYSTEM: 'File System (Used / Total)', + BUFFER_SIZE: 'Buffer Size', + COMPACT: 'Compact', + ENABLE_OTA: 'Enable OTA Updates', + DOWNLOAD_CUSTOMIZATION_TEXT: 'Download the entity customizations', + DOWNLOAD_SETTINGS_TEXT: + 'Download the application settings. Be careful when sharing your settings as this file contains passwords and other sensitive system information', + UPLOAD_TEXT: 'Upload a new firmware (.bin) file, settings or customizations (.json) file below', + UPLOADING: 'Uploading', + UPLOAD_DROP_TEXT: 'Drop file or click here', + ERROR: 'Unexpected Error, please try again', + TIME_SET: 'Time set', + MANAGE_USERS: 'Manage Users', + IS_ADMIN: 'is Admin', + USER_WARNING: 'You must have at least one admin user configured', + ADD: 'Add', + ACCESS_TOKEN_FOR: 'Access Token for', + ACCESS_TOKEN_TEXT: + 'The token below is used with REST API calls that require authorization. It can be passed either as a Bearer token in the Authorization header or in the access_token URL query parameter.', + GENERATING_TOKEN: 'Generating token', + USER: 'User', + MODIFY: 'Modify', + SU_TEXT: + 'The su (super user) password is used to sign authentication tokens and also enable admin privileges within the Console.', + NOT_ENABLED: 'Not enabled', + ERRORS: 'Errors', + DISCONNECT_REASON: 'Disconnect Reason', + ENABLE_MQTT: 'Enable MQTT', + OPTIONAL: 'Optional', + FORMATTING: 'Formatting', + FORMAT: 'Format', + MQTT_NEST_1: 'Nested in a single topic', + MQTT_NEST_2: 'As individual topics', + MQTT_RESPONSE: 'Publish command output to a `response` topic', + MQTT_PUBLISH_TEXT_1: 'Publish single value topics on change', + MQTT_PUBLISH_TEXT_2: 'Publish to command topics (ioBroker)', + MQTT_PUBLISH_TEXT_3: 'Enable MQTT Discovery (Home Assistant, Domoticz)', + MQTT_PUBLISH_TEXT_4: 'Prefix for the Discovery topics', + MQTT_PUBLISH_INTERVALS: 'Publish Intervals', + MQTT_INT_BOILER: 'Boilers and Heat Pumps', + MQTT_INT_THERMOSTATS: 'Thermostats', + MQTT_INT_SOLAR: 'Solar Modules', + MQTT_INT_MIXER: 'Mixer Modules', + DEFAULT: 'Default', + MQTT_CLEAN_SESSION: 'Set Clean Session', + MQTT_RETAIN_FLAG: 'Always set Retain flag', + INACTIVE: 'Inactive', + ACTIVE: 'Active', + UNKNOWN: 'Unknown', + SET_TIME: 'Set Time', + SET_TIME_TEXT: 'Enter local date and time below to set the time', + LOCAL_TIME: 'Local Time', + UTC_TIME: 'UTC Time', + ENABLE_NTP: 'Enable NTP', + TIME_ZONE: 'Time Zone', + ACCESS_POINT: 'Access Point', + AP_PROVIDE: 'Enable Access Point', + AP_PROVIDE_TEXT_1: 'always', + AP_PROVIDE_TEXT_2: 'when WiFi is disconnected', + AP_PROVIDE_TEXT_3: 'never', + AP_PREFERRED_CHANNEL: 'Preferred Channel', + AP_HIDE_SSID: 'Hide SSID', + NETWORK_SCAN: 'Scan WiFi Networks', + IDLE: 'Idle', + LOST: 'Lost', + SCANNING: 'Scanning', + SCAN_AGAIN: 'Scan again', + NETWORK_SCANNER: 'Network Scanner', + NETWORK_NO_WIFI: 'No WiFi networks found', + NETWORK_BLANK_SSID: 'leave blank to disable WiFi', + POWER: 'Power', + NETWORK_DISABLE_SLEEP: 'Disable WiFi Sleep Mode', + NETWORK_LOW_BAND: 'Use Lower WiFi Bandwidth', + NETWORK_USE_DNS: 'Enable mDNS Service', + NETWORK_ENABLE_IPV6: 'Enable IPv6 support', + NETWORK_FIXED_IP: 'Use Fixed IP address', + ADMIN: 'Admin', + GUEST: 'Guest', + NEW: 'New', + RENAME: 'Rename' +}; + +export default en; diff --git a/interface/src/i18n/se/index.ts b/interface/src/i18n/se/index.ts new file mode 100644 index 000000000..28efa285a --- /dev/null +++ b/interface/src/i18n/se/index.ts @@ -0,0 +1,266 @@ +import type { BaseTranslation } from '../i18n-types'; + +const se: BaseTranslation = { + LANGUAGE: 'Språk', + RETRY: 'Försök igen', + LOADING: 'Laddar', + IS_REQUIRED: 'Krävs', + SIGN_IN: 'Logga In', + SIGN_OUT: 'Logga Ut', + USERNAME: 'Användarnamn', + PASSWORD: 'Lösenord', + DASHBOARD: 'Kontrollpanel', + SETTINGS: 'Inställningar', + SAVED: 'Sparat', + HELP: 'Hjälp', + LOGGED_IN: 'Inloggad som {name}', + PLEASE_SIGNIN: 'Vänligen logga in för att fortsätta', + UPLOAD_SUCCESSFUL: 'Uppladdning lyckades', + DOWNLOAD_SUCCESSFUL: 'Nedladdning lyckades', + INVALID_LOGIN: 'Ogiltig login', + NETWORK: 'Nätverk', + SECURITY: 'Säkerhet', + ONOFF_CAP: 'PÅ/AV', + ONOFF: 'på/av', + TYPE: 'Typ', + DESCRIPTION: 'Beskrivning', + ENTITIES: 'Entiteter', + REFRESH: 'Uppdatera', + EXPORT: 'Export', + DEVICE_DETAILS: 'Enhetsdetaljer', + BRAND: 'Fabrikat', + ENTITY_NAME: 'Entitetsnamn', + VALUE: 'Värde', + SHOW_FAV: 'Visa enbart favoriter', + DEVICE_SENSOR_DATA: 'Enhets och Sensor-data', + DEVICES_SENSORS: 'Enheter & Sensorer', + ATTACHED_SENSORS: 'Anslutna EMS-ESP Sensorer', + RUN_COMMAND: 'Kör Kommando', + CHANGE_VALUE: 'Ändra Värde', + CANCEL: 'Avbryt', + RESET: 'Nollsäll', + SEND: 'Skicka', + SAVE: 'Spara', + REMOVE: 'Ta bort', + PROBLEM_UPDATING: 'Problem vid uppdatering', + PROBLEM_LOADING: 'Problem vid hämtning', + ACCESS_DENIED: 'Åtkomst Nekad', + ANALOG_SENSOR: 'Analog Sensor', + ANALOG_SENSORS: 'Analoga Sensorer', + UPDATED: 'Uppdaterad', + UPDATE: 'Uppdatera', + REMOVED: 'Raderad', + DELETION: 'Radering', + OFFSET: 'Kompensering', + FACTOR: 'Faktor', + FREQ: 'Frekvens', + STARTVALUE: 'Startvärde', + WARN_GPIO: 'Varning: Var försiktig vid aktivering av GPIO!', + EDIT: 'Ändra', + TEMP_SENSOR: 'Temperatursensor', + TEMP_SENSORS: 'Temperatursensorer', + WRITE_COMMAND: 'Skrivkommando {cmd}', + EMS_BUS_WARNING: + 'EMS-buss nedkopplad. Om denna varning kvarstår efter några sekunder, kontrollera inställningar och enhets-profil.', + EMS_BUS_SCANNING: 'Söker efter EMS-enheter...', + CONNECTED: 'Ansluten', + TX_ISSUES: 'Sändfel - Prova ett annat TX-läge', + DISCONNECTED: 'Nedkopplad', + EMS_SCAN: 'Är du säker att du vill initiera en full genomsökning av EMS-bussen?', + EMS_BUS_STATUS: 'EMS-Bus Status', + ACTIVE_DEVICES: 'Aktiva Enheter & Sensorer', + DEVICE: 'Enhet', + SUCCESS: 'Lyckades', + FAIL: 'Misslyckades', + QUALITY: 'Kvalitet', + SCAN_DEVICES: 'Sök efter nya enheter', + EMS_BUS_STATUS_TITLE: 'EMS-buss & aktivitetsstatus', + SCAN: 'Sök', + STATUS_NAMES: [ + 'EMS-telegram Mottagna (Rx)', + 'EMS-läsningar (Tx)', + 'EMS-skrivningar (Tx)', + 'Temperatursensor-läsningar', + 'Analog Sensor-läsningar', + 'MQTT-publiceringar', + 'API-anrop', + 'Syslog-meddelanden' + ], + NUM_DEVICES: '{num} Enhet{{er}}', + NUM_TEMP_SENSORS: '{num} Temperatur-sensor{{er}}', + NUM_ANALOG_SENSORS: '{num} Analoga Sensor{{er}}', + NUM_DAYS: '{num} Dag{{ar}}', + NUM_SECONDS: '{num} Sekund{{er}}', + NUM_HOURS: '{num} Timmar', + NUM_MINUTES: '{num} Minut{{er}}', + APPLICATION_SETTINGS: 'Inställningar', + CUSTOMIZATION: 'Anpassa', + APPLICATION_RESTARTING: 'EMS-ESP startar om', + BOARD_PROFILE_TEXT: + 'Välj en förkonfigurerad hårdvaruprofil från listan nedan eller välj Anpassad för att konfigurera dina egna hårdvaruinställningar', + BOARD_PROFILE: 'Hårdvaruprofil', + BUTTON: 'Knapp', + TEMPERATURE: 'Temperatur', + DISABLED: 'inaktiverad', + GENERAL_OPTIONS: 'Allmänna Inställningar', + LANGUAGE_ENTITIES: 'Språk (för entiteter)', + HIDE_LED: 'Inaktivera LED', + ENABLE_TELNET: 'Aktivera Telnet', + ENABLE_ANALOG: 'Aktivera Analoga Sensorer', + CONVERT_FAHRENHEIT: 'Konvertera temperatur till Fahrenheit', + BYPASS_TOKEN: 'Inaktivera Token-autensiering för API-anrop', + READONLY: 'Aktivera read-only (blockerar alla utgående skrivkommandon mot EMS-bussen)', + UNDERCLOCK_CPU: 'Nedklocka Processorhastighet', + ENABLE_SHOWER_TIMER: 'Aktivera Dusch-timer', + ENABLE_SHOWER_ALERT: 'Aktivera Dusch-warning', + TRIGGER_TIME: 'Aktiveringstid', + COLD_SHOT_DURATION: 'Längd på kalldusch', + FORMATTING_OPTIONS: 'Formatteringsalternativ', + BOOLEAN_FORMAT_DASHBOARD: 'Bool-format Kontrollpanel', + BOOLEAN_FORMAT_API: 'Bool-format API/MQTT', + ENUM_FORMAT: 'Enum-format API/MQTT', + INDEX: 'Index', + ENABLE_PARASITE: 'Aktivera parasitström', + LOGGING: 'Loggning', + LOG_HEX: 'Logga EMS-telegram i hexadecimal', + ENABLE_SYSLOG: 'Aktivera Syslog', + MARK_INTERVAL: 'Markerings-interval', + SECONDS: 'sekunder', + MINUTES: 'minuter', + RESTART: 'Starta om', + HOURS: 'timmar', + RESTART_TEXT: 'EMS-ESP kräver en omstart för att applicera förändrade systeminställningar', + COMMAND: 'Kommando', + CUSTOMIZATIONS_RESTART: 'Alla anpassningr har raderats. Startar om...', + CUSTOMIZATIONS_FULL: 'Antal valda enheter för högt. Vänligen spara i mindre antal åt gången.', + CUSTOMIZATIONS_SAVED: 'Anpassningar sparade', + CUSTOMIZATIONS_HELP_1: 'Välj en enhet och anpassa underenheter med hjälp av alternativen', + CUSTOMIZATIONS_HELP_2: 'markera som favorit', + CUSTOMIZATIONS_HELP_3: 'inaktivera skrivningar', + CUSTOMIZATIONS_HELP_4: 'exkludera från MQTT & API', + CUSTOMIZATIONS_HELP_5: 'göm från Kontrollpanel', + SELECT_DEVICE: 'Välj en enhet', + SET_ALL: 'ställ in alla', + OPTIONS: 'Alternativ', + NAME: 'Namn', + CUSTOMIZATIONS_RESET: + 'Är du säker på att du vill ta bort alla anpassningar inklusive inställningar för Temperatur och Analoga sensorer?', + DEVICE_ENTITIES: 'Enhets-entiteter', + USER_CUSTOMIZATION: 'Användaranpassningar', + SUPPORT_INFORMATION: 'Supportinformation', + CLICK_HERE: 'Klicka Här', + HELP_INFORMATION_1: 'Besök Wikin för instruktioner för hur du kan konfigurera EMS-ESP', + HELP_INFORMATION_2: 'För community-support besök vår Discord-server', + HELP_INFORMATION_3: 'Önska en ny funktion eller rapportera en bugg', + HELP_INFORMATION_4: + 'Bifoga din systeminformation för snabbare hantering när du rapporterar ett problem', + HELP_INFORMATION_5: + 'EMS-ESP är gratis och är öppen källkod. Bidra till utveklingen genom att ge oss en stjärna på GitHub!', + SUPPORT_INFO: 'Supportinfo', + UPLOAD: 'Uppladdning', + DOWNLOAD: 'Nedladdning', + ABORTED: 'Avbruten', + FAILED: 'Misslyckades', + SUCCESSFUL: 'Lyckades', + SYSTEM: 'System', + LOG: 'Logg', + STATUS: 'Status', + UPLOAD_DOWNLOAD: 'Upp/Nedladdning', + SYSTEM_VERSION_RUNNING: 'Du använder version', + SYSTEM_APPLY_FIRMWARE: 'för att aktivera ny firmware', + CLOSE: 'Stäng', + USE: 'Använd', + FACTORY_RESET: 'Fabriksåterställning', + SYSTEM_FACTORY_TEXT: 'Enheten har blivit fabriksåterställd och startar nu om', + SYSTEM_FACTORY_TEXT_DIALOG: 'Är du säker att du vill fabriksåterställa enheten?', + VERSION_CHECK: 'Versionskontroll', + THE_LATEST: 'Den senaste', + PLATFORM: 'Enhet (Plattform / SDK)', + UPTIME: 'Systemets Uptid', + CPU_FREQ: 'CPU-frekvens', + HEAP: 'Heap (Ledigt / Max allokerat)', + PSRAM: 'PSRAM (Storlek / Ledigt)', + FLASH: 'Flash Chip (Storlek / Hastighet)', + FILESYSTEM: 'Filsystem (Använt / Totalt)', + BUFFER_SIZE: 'Bufferstorlek', + COMPACT: 'Komprimera', + ENABLE_OTA: 'Aktivera OTA-uppdateringar', + DOWNLOAD_CUSTOMIZATION_TEXT: 'Ladda ner entitetsanpassningar', + DOWNLOAD_SETTINGS_TEXT: + 'Ladda ner applikationsinställningar. Var försiktig om du delar dina iställlningar då de innehåller lösenord och annan känslig systeminformation', + UPLOAD_TEXT: 'Ladda upp ett nytt firmware (.bin), inställningar eller anpassningar (.json) nedan', + UPLOADING: 'Laddar upp', + UPLOAD_DROP_TEXT: 'Släpp fil eller klicka här', + ERROR: 'Okänt Fel, var god försök igen', + TIME_SET: 'Ställ in tid', + MANAGE_USERS: 'Användarhantering', + IS_ADMIN: 'Admin', + USER_WARNING: 'Du måste ha minst en admin konfigurerad', + ADD: 'Lägg till', + ACCESS_TOKEN_FOR: 'Access Token för', + ACCESS_TOKEN_TEXT: + 'Nedan Token används med REST API-anrop som kräver auktorisering. Den kan skickas med antingen som en Bearer token i Authorization-headern eller i access_token URL query-parametern.', + GENERATING_TOKEN: 'Genererar token', + USER: 'Användare', + MODIFY: 'Ändra', + SU_TEXT: + 'SU-användarens (super user) lösenord används för att signera autensierings-tokens samt för att aktivera administratörsprivilegier i Console-läge', + NOT_ENABLED: 'Ej aktiv', + ERRORS: 'fel', + DISCONNECT_REASON: 'Anledning till nedkoppling', + ENABLE_MQTT: 'Aktivera MQTT', + OPTIONAL: 'Valfritt', + FORMATTING: 'Formatering', + FORMAT: 'Format', + MQTT_NEST_1: 'Nestlad i en topic.', + MQTT_NEST_2: 'Som individuella topics', + MQTT_RESPONSE: 'Publish-kommando som ett `response` topic', + MQTT_PUBLISH_TEXT_1: 'Publicera single value topics vid värdeförändring', + MQTT_PUBLISH_TEXT_2: 'Publicera till kommando-topics (ioBroker)', + MQTT_PUBLISH_TEXT_3: 'Aktivera MQTT Discovery (Home Assistant, Domoticz)', + MQTT_PUBLISH_TEXT_4: 'Prefix för Discovery topics', + MQTT_PUBLISH_INTERVALS: 'Publiceringsintervall', + MQTT_INT_BOILER: 'Värmepump/panna', + MQTT_INT_THERMOSTATS: 'Termostater', + MQTT_INT_SOLAR: 'Solpaneler', + MQTT_INT_MIXER: 'Blandarventiler', + DEFAULT: 'Standard', + MQTT_CLEAN_SESSION: 'Sätt "Clean Session"-flaggan', + MQTT_RETAIN_FLAG: 'Sätt "Always Retain"-flaggan', + INACTIVE: 'Inaktiv', + ACTIVE: 'Aktiv', + UNKNOWN: 'Okänt', + SET_TIME: 'Ställ in klockan', + SET_TIME_TEXT: 'Ange lokal datum och tid nedan för att ställa in klockan', + LOCAL_TIME: 'Lokal Tid', + UTC_TIME: 'UTC-tid', + ENABLE_NTP: 'Aktivera NTP', + TIME_ZONE: 'Tidszon', + ACCESS_POINT: 'Accesspunkt', + AP_PROVIDE: 'Aktivera Accesspunkt', + AP_PROVIDE_TEXT_1: 'alltid', + AP_PROVIDE_TEXT_2: 'när WiFi är nedkopplat', + AP_PROVIDE_TEXT_3: 'aldrig', + AP_PREFERRED_CHANNEL: 'Föredragen kanal', + AP_HIDE_SSID: 'Göm SSID', + NETWORK_SCAN: 'Sök efter WiFi-nätverk', + IDLE: 'Vilande', + LOST: 'Förlorad', + SCANNING: 'Söker', + SCAN_AGAIN: 'Sök igen', + NETWORK_SCANNER: 'Nätverks-scanner', + NETWORK_NO_WIFI: 'Inga WiFi-nätverk hittades', + NETWORK_BLANK_SSID: 'lämna blankt för att inaktivera WiFi', + POWER: 'Effekt', + NETWORK_DISABLE_SLEEP: 'Inaktivera sömnläge', + NETWORK_LOW_BAND: 'Använd lägre bandbredd', + NETWORK_USE_DNS: 'Aktivera mDNS-tjänsten', + NETWORK_ENABLE_IPV6: 'Aktivera IPv6-support', + NETWORK_FIXED_IP: 'Använd statiskt IP', + ADMIN: 'Admin', + GUEST: 'Gäst', + NEW: 'Ny', + RENAME: 'Byt namn' +}; + +export default se; diff --git a/interface/src/project/Dashboard.tsx b/interface/src/project/Dashboard.tsx index 10e284208..64dee8e0a 100644 --- a/interface/src/project/Dashboard.tsx +++ b/interface/src/project/Dashboard.tsx @@ -5,17 +5,21 @@ import { Tab } from '@mui/material'; import { RouterTabs, useRouterTab, useLayoutTitle } from '../components'; +import { useI18nContext } from '../i18n/i18n-react'; + import DashboardStatus from './DashboardStatus'; import DashboardData from './DashboardData'; const Dashboard: FC = () => { - useLayoutTitle('Dashboard'); const { routerTab } = useRouterTab(); + const { LL } = useI18nContext(); + useLayoutTitle(LL.DASHBOARD()); + return ( <> - + diff --git a/interface/src/project/DashboardData.tsx b/interface/src/project/DashboardData.tsx index 319e7215e..c60c4eed9 100644 --- a/interface/src/project/DashboardData.tsx +++ b/interface/src/project/DashboardData.tsx @@ -49,8 +49,6 @@ import DeviceIcon from './DeviceIcon'; import { IconContext } from 'react-icons'; -import { formatDurationMin, pluralize } from '../utils'; - import { AuthenticatedContext } from '../contexts/authentication'; import { ButtonRow, ValidatedTextField, SectionContent, MessageBox } from '../components'; @@ -74,12 +72,24 @@ import { DeviceEntityMask } from './types'; +import { useI18nContext } from '../i18n/i18n-react'; + +import parseMilliseconds from 'parse-ms'; + const DashboardData: FC = () => { const { me } = useContext(AuthenticatedContext); + const { LL } = useI18nContext(); + const { enqueueSnackbar } = useSnackbar(); - const [coreData, setCoreData] = useState({ connected: true, devices: [], active_sensors: 0, analog_enabled: false }); + const [coreData, setCoreData] = useState({ + connected: true, + devices: [], + active_sensors: 0, + analog_enabled: false + }); + const [deviceData, setDeviceData] = useState({ label: '', data: [] }); const [sensorData, setSensorData] = useState({ sensors: [], analogs: [] }); const [deviceValue, setDeviceValue] = useState(); @@ -134,7 +144,7 @@ const DashboardData: FC = () => { common_theme, { Table: ` - --data-table-library_grid-template-columns: 40px 100px repeat(1, minmax(0, 1fr)) 80px 40px; + --data-table-library_grid-template-columns: 40px 100px repeat(1, minmax(0, 1fr)) 100px 40px; `, BaseRow: ` .td { @@ -319,10 +329,10 @@ const DashboardData: FC = () => { const handleDownloadCsv = () => { const columns = [ - { accessor: (dv: any) => dv.id.slice(2), name: 'Entity' }, + { accessor: (dv: any) => dv.id.slice(2), name: LL.ENTITY_NAME() }, { accessor: (dv: any) => (typeof dv.v === 'number' ? new Intl.NumberFormat().format(dv.v) : dv.v), - name: 'Value' + name: LL.VALUE() }, { accessor: (dv: any) => DeviceValueUOM_s[dv.u], name: 'UoM' } ]; @@ -355,9 +365,9 @@ const DashboardData: FC = () => { try { setCoreData((await EMSESP.readCoreData()).data); } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Failed to fetch core data'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' }); } - }, [enqueueSnackbar]); + }, [enqueueSnackbar, LL]); useEffect(() => { fetchCoreData(); @@ -376,7 +386,7 @@ const DashboardData: FC = () => { try { setDeviceData((await EMSESP.readDeviceData({ id: unique_id })).data); } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem fetching device data'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' }); } }; @@ -384,21 +394,38 @@ const DashboardData: FC = () => { try { setSensorData((await EMSESP.readSensorData()).data); } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem fetching sensor data'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' }); } }; const isCmdOnly = (dv: DeviceValue) => dv.v === '' && dv.c; + const formatDurationMin = (duration_min: number) => { + const { days, hours, minutes } = parseMilliseconds(duration_min * 60000); + let formatted = ''; + if (days) { + formatted += LL.NUM_DAYS({ num: days }) + ' '; + } + if (hours) { + formatted += LL.NUM_HOURS({ num: hours }) + ' '; + } + if (minutes) { + formatted += LL.NUM_MINUTES({ num: minutes }); + } + return formatted; + }; + function formatValue(value: any, uom: number) { if (value === undefined) { return ''; } switch (uom) { case DeviceValueUOM.HOURS: - return value ? formatDurationMin(value * 60) : '0 hours'; + return value ? formatDurationMin(value * 60) : LL.NUM_HOURS({ num: 0 }); case DeviceValueUOM.MINUTES: - return value ? formatDurationMin(value) : '0 minutes'; + return value ? formatDurationMin(value) : LL.NUM_MINUTES({ num: 0 }); + case DeviceValueUOM.SECONDS: + return LL.NUM_SECONDS({ num: value }); case DeviceValueUOM.NONE: if (typeof value === 'number') { return new Intl.NumberFormat().format(value); @@ -414,13 +441,24 @@ const DashboardData: FC = () => { ' ' + DeviceValueUOM_s[uom] ); - case DeviceValueUOM.SECONDS: - return pluralize(value, DeviceValueUOM_s[uom]); default: return new Intl.NumberFormat().format(value) + ' ' + DeviceValueUOM_s[uom]; } } + const setUom = (uom: number) => { + switch (uom) { + case DeviceValueUOM.HOURS: + return LL.HOURS(); + case DeviceValueUOM.MINUTES: + return LL.MINUTES(); + case DeviceValueUOM.SECONDS: + return LL.SECONDS(); + default: + return DeviceValueUOM_s[uom]; + } + }; + const sendDeviceValue = async () => { if (deviceValue) { try { @@ -429,15 +467,15 @@ const DashboardData: FC = () => { devicevalue: deviceValue }); if (response.status === 204) { - enqueueSnackbar('Write command failed', { variant: 'error' }); + enqueueSnackbar(LL.WRITE_COMMAND({ cmd: 'failed' }), { variant: 'error' }); } else if (response.status === 403) { - enqueueSnackbar('Write access denied', { variant: 'error' }); + enqueueSnackbar(LL.ACCESS_DENIED(), { variant: 'error' }); } else { - enqueueSnackbar('Write command sent', { variant: 'success' }); + enqueueSnackbar(LL.WRITE_COMMAND({ cmd: 'send' }), { variant: 'success' }); } setDeviceValue(undefined); } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem writing value'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); } finally { refreshData(); setDeviceValue(undefined); @@ -449,7 +487,7 @@ const DashboardData: FC = () => { if (deviceValue) { return ( setDeviceValue(undefined)}> - {isCmdOnly(deviceValue) ? 'Run Command' : 'Change Value'} + {isCmdOnly(deviceValue) ? LL.RUN_COMMAND() : LL.CHANGE_VALUE()} {deviceValue.l && ( { onChange={updateValue(setDeviceValue)} inputProps={deviceValue.u ? { min: deviceValue.m, max: deviceValue.x, step: deviceValue.s } : {}} InputProps={{ - startAdornment: {DeviceValueUOM_s[deviceValue.u]} + startAdornment: {setUom(deviceValue.u)} }} /> )} @@ -491,7 +529,7 @@ const DashboardData: FC = () => { onClick={() => setDeviceValue(undefined)} color="secondary" > - Cancel + {LL.CANCEL()} @@ -521,15 +559,15 @@ const DashboardData: FC = () => { offset: sensor.o }); if (response.status === 204) { - enqueueSnackbar('Sensor change failed', { variant: 'error' }); + enqueueSnackbar(LL.TEMP_SENSOR() + ' ' + LL.UPLOAD_TEXT() + ' ' + LL.FAILED(), { variant: 'error' }); } else if (response.status === 403) { - enqueueSnackbar('Access denied', { variant: 'error' }); + enqueueSnackbar(LL.ACCESS_DENIED(), { variant: 'error' }); } else { - enqueueSnackbar('Sensor updated', { variant: 'success' }); + enqueueSnackbar(LL.TEMP_SENSOR() + ' ' + LL.UPDATED(), { variant: 'success' }); } setSensor(undefined); } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem updating sensor'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); } finally { setSensor(undefined); fetchSensorData(); @@ -541,16 +579,18 @@ const DashboardData: FC = () => { if (sensor) { return ( setSensor(undefined)}> - Edit Temperature Sensor + + {LL.EDIT()} {LL.TEMP_SENSOR()} + - Sensor ID {sensor.id} + Sensor ID: {sensor.id} { { onClick={() => setSensor(undefined)} color="secondary" > - Cancel + {LL.CANCEL()} @@ -602,17 +642,17 @@ const DashboardData: FC = () => { if (coreData && coreData.devices.length > 0 && deviceDialog !== -1) { return ( setDeviceDialog(-1)}> - Device Details + {LL.DEVICE_DETAILS()} - + - + - + { @@ -640,17 +680,20 @@ const DashboardData: FC = () => { const renderCoreData = () => ( - {!coreData.connected && } - {coreData.connected && coreData.devices.length === 0 && } + {!coreData.connected && } + {coreData.connected && coreData.devices.length === 0 && ( + + )} + {(tableList: any) => ( <>
- TYPE - DESCRIPTION - ENTITIES + {LL.TYPE()} + {LL.DESCRIPTION()} + {LL.ENTITIES()}
@@ -676,7 +719,7 @@ const DashboardData: FC = () => { Sensors - Attached EMS-ESP Sensors + {LL.ATTACHED_SENSORS()} {coreData.active_sensors} addAnalogSensor()}> @@ -723,7 +766,7 @@ const DashboardData: FC = () => { control={ setOnlyFav(!onlyFav)} />} label={ - only show favorites  + {LL.SHOW_FAV()}  } @@ -749,7 +792,7 @@ const DashboardData: FC = () => { endIcon={getSortIcon(dv_sort.state, 'NAME')} onClick={() => dv_sort.fns.onToggleSort({ sortKey: 'NAME' })} > - ENTITY NAME + {LL.ENTITY_NAME()} @@ -759,7 +802,7 @@ const DashboardData: FC = () => { endIcon={getSortIcon(dv_sort.state, 'VALUE')} onClick={() => dv_sort.fns.onToggleSort({ sortKey: 'VALUE' })} > - VALUE + {LL.VALUE()} @@ -806,7 +849,7 @@ const DashboardData: FC = () => { const renderDallasData = () => ( <> - Temperature Sensors + {LL.TEMP_SENSORS()}
{ endIcon={getSortIcon(sensor_sort.state, 'NAME')} onClick={() => sensor_sort.fns.onToggleSort({ sortKey: 'NAME' })} > - NAME + {LL.ENTITY_NAME()} @@ -835,7 +878,7 @@ const DashboardData: FC = () => { endIcon={getSortIcon(sensor_sort.state, 'TEMPERATURE')} onClick={() => sensor_sort.fns.onToggleSort({ sortKey: 'TEMPERATURE' })} > - TEMPERATURE + {LL.VALUE()} @@ -865,7 +908,7 @@ const DashboardData: FC = () => { const renderAnalogData = () => ( <> - Analog Sensors + {LL.ANALOG_SENSORS()}
@@ -890,7 +933,7 @@ const DashboardData: FC = () => { endIcon={getSortIcon(analog_sort.state, 'NAME')} onClick={() => analog_sort.fns.onToggleSort({ sortKey: 'NAME' })} > - NAME + {LL.ENTITY_NAME()} @@ -900,10 +943,10 @@ const DashboardData: FC = () => { endIcon={getSortIcon(analog_sort.state, 'TYPE')} onClick={() => analog_sort.fns.onToggleSort({ sortKey: 'TYPE' })} > - TYPE + {LL.TYPE()} - VALUE + {LL.VALUE()} @@ -943,14 +986,14 @@ const DashboardData: FC = () => { }); if (response.status === 204) { - enqueueSnackbar('Analog deletion failed', { variant: 'error' }); + enqueueSnackbar(LL.ANALOG_SENSOR() + ' ' + LL.DELETION() + ' ' + LL.FAILED(), { variant: 'error' }); } else if (response.status === 403) { - enqueueSnackbar('Access denied', { variant: 'error' }); + enqueueSnackbar(LL.ACCESS_DENIED(), { variant: 'error' }); } else { - enqueueSnackbar('Analog sensor removed', { variant: 'success' }); + enqueueSnackbar(LL.ANALOG_SENSOR() + ' ' + LL.REMOVED(), { variant: 'success' }); } } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem updating analog sensor'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); } finally { setAnalog(undefined); fetchSensorData(); @@ -971,14 +1014,14 @@ const DashboardData: FC = () => { }); if (response.status === 204) { - enqueueSnackbar('Analog sensor update failed', { variant: 'error' }); + enqueueSnackbar(LL.ANALOG_SENSOR() + ' ' + LL.UPDATE() + ' ' + LL.FAILED(), { variant: 'error' }); } else if (response.status === 403) { - enqueueSnackbar('Access denied', { variant: 'error' }); + enqueueSnackbar(LL.ACCESS_DENIED(), { variant: 'error' }); } else { - enqueueSnackbar('Analog sensor updated', { variant: 'success' }); + enqueueSnackbar(LL.ANALOG_SENSOR() + ' ' + LL.UPDATED(), { variant: 'success' }); } } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem updating analog'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); } finally { setAnalog(undefined); fetchSensorData(); @@ -990,7 +1033,9 @@ const DashboardData: FC = () => { if (analog) { return ( setAnalog(undefined)}> - Edit Analog Sensor + + {LL.EDIT()} {LL.ANALOG_SENSOR()} + @@ -1007,7 +1052,7 @@ const DashboardData: FC = () => { { /> - + {AnalogTypeNames.map((val, i) => ( {val} @@ -1038,7 +1089,7 @@ const DashboardData: FC = () => { { { { { { { { )} - Warning: be careful when assigning a GPIO! + {LL.WARN_GPIO()} @@ -1180,7 +1231,7 @@ const DashboardData: FC = () => { }; return ( - + {renderCoreData()} {renderDeviceData()} {renderDeviceDialog()} @@ -1191,11 +1242,11 @@ const DashboardData: FC = () => { {renderAnalogDialog()} {device_select.state.id && device_select.state.id !== 'sensor' && ( )} diff --git a/interface/src/project/DashboardStatus.tsx b/interface/src/project/DashboardStatus.tsx index 28783c42d..f72049c48 100644 --- a/interface/src/project/DashboardStatus.tsx +++ b/interface/src/project/DashboardStatus.tsx @@ -32,10 +32,14 @@ import { ButtonRow, FormLoader, SectionContent } from '../components'; import { Status, busConnectionStatus, Stat } from './types'; -import { formatDurationSec, pluralize, extractErrorMessage, useRest } from '../utils'; +import { extractErrorMessage, useRest } from '../utils'; import * as EMSESP from './api'; +import type { Translation } from '../i18n/i18n-types'; +import { useI18nContext } from '../i18n/i18n-react'; +import parseMilliseconds from 'parse-ms'; + export const isConnected = ({ status }: Status) => status !== busConnectionStatus.BUS_STATUS_OFFLINE; const busStatusHighlight = ({ status }: Status, theme: Theme) => { @@ -51,19 +55,6 @@ const busStatusHighlight = ({ status }: Status, theme: Theme) => { } }; -const busStatus = ({ status }: Status) => { - switch (status) { - case busConnectionStatus.BUS_STATUS_CONNECTED: - return 'Connected'; - case busConnectionStatus.BUS_STATUS_TX_ERRORS: - return 'Tx issues - try a different Tx Mode'; - case busConnectionStatus.BUS_STATUS_OFFLINE: - return 'Disconnected'; - default: - return 'Unknown'; - } -}; - const showQuality = (stat: Stat) => { if (stat.q === 0 || stat.s + stat.f === 0) { return; @@ -81,12 +72,32 @@ const showQuality = (stat: Stat) => { const DashboardStatus: FC = () => { const { loadData, data, errorMessage } = useRest({ read: EMSESP.readStatus }); + const { LL } = useI18nContext(); + const theme = useTheme(); const [confirmScan, setConfirmScan] = useState(false); const { enqueueSnackbar } = useSnackbar(); const { me } = useContext(AuthenticatedContext); + const showName = (id: any) => { + let name: keyof Translation['STATUS_NAMES'] = id; + return LL.STATUS_NAMES[name](); + }; + + const busStatus = ({ status }: Status) => { + switch (status) { + case busConnectionStatus.BUS_STATUS_CONNECTED: + return LL.CONNECTED(); + case busConnectionStatus.BUS_STATUS_TX_ERRORS: + return LL.TX_ISSUES(); + case busConnectionStatus.BUS_STATUS_OFFLINE: + return LL.DISCONNECTED(); + default: + return 'Unknown'; + } + }; + const stats_theme = tableTheme({ Table: ` --data-table-library_grid-template-columns: repeat(1, minmax(0, 1fr)) 90px 90px 80px; @@ -137,24 +148,40 @@ const DashboardStatus: FC = () => { const scan = async () => { try { await EMSESP.scanDevices(); - enqueueSnackbar('Scanning for devices...', { variant: 'info' }); + enqueueSnackbar(LL.SCANNING() + '...', { variant: 'info' }); } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem initiating scan'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); } finally { setConfirmScan(false); } }; + const formatDurationSec = (duration_sec: number) => { + const { days, hours, minutes, seconds } = parseMilliseconds(duration_sec * 1000); + let formatted = ' '; + if (days) { + formatted += LL.NUM_DAYS({ num: days }) + ' '; + } + if (hours) { + formatted += LL.NUM_HOURS({ num: hours }) + ' '; + } + if (minutes) { + formatted += LL.NUM_MINUTES({ num: minutes }) + ' '; + } + formatted += LL.NUM_SECONDS({ num: seconds }); + return formatted; + }; + const renderScanDialog = () => ( setConfirmScan(false)}> - EMS Device Scan - Are you sure you want to initiate a full device scan of the EMS bus? + {LL.SCAN_DEVICES()} + {LL.EMS_SCAN()} @@ -174,7 +201,7 @@ const DashboardStatus: FC = () => { - + @@ -183,13 +210,13 @@ const DashboardStatus: FC = () => { @@ -200,15 +227,15 @@ const DashboardStatus: FC = () => {
- SUCCESS - FAIL - QUALITY + {LL.SUCCESS()} + {LL.FAIL()} + {LL.QUALITY()}
{tableList.map((stat: Stat) => ( - {stat.id} + {showName(stat.id)} {Intl.NumberFormat().format(stat.s)} {Intl.NumberFormat().format(stat.f)} {showQuality(stat)} @@ -223,7 +250,7 @@ const DashboardStatus: FC = () => { @@ -235,7 +262,7 @@ const DashboardStatus: FC = () => { disabled={!me.admin} onClick={() => setConfirmScan(true)} > - Scan for new devices + {LL.SCAN_DEVICES()} @@ -245,7 +272,7 @@ const DashboardStatus: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/project/Help.tsx b/interface/src/project/Help.tsx index 924f936bd..1bb520668 100644 --- a/interface/src/project/Help.tsx +++ b/interface/src/project/Help.tsx @@ -5,16 +5,20 @@ import { Tab } from '@mui/material'; import { RouterTabs, useRouterTab, useLayoutTitle } from '../components'; +import { useI18nContext } from '../i18n/i18n-react'; + import HelpInformation from './HelpInformation'; const Help: FC = () => { - useLayoutTitle('Help'); + const { LL } = useI18nContext(); const { routerTab } = useRouterTab(); + useLayoutTitle(LL.HELP()); + return ( <> - + } /> diff --git a/interface/src/project/HelpInformation.tsx b/interface/src/project/HelpInformation.tsx index ae6de59de..e84a34a7f 100644 --- a/interface/src/project/HelpInformation.tsx +++ b/interface/src/project/HelpInformation.tsx @@ -11,12 +11,17 @@ import MenuBookIcon from '@mui/icons-material/MenuBookTwoTone'; import GitHubIcon from '@mui/icons-material/GitHub'; import StarIcon from '@mui/icons-material/Star'; import DownloadIcon from '@mui/icons-material/GetApp'; +import EastIcon from '@mui/icons-material/East'; import { extractErrorMessage } from '../utils'; +import { useI18nContext } from '../i18n/i18n-react'; + import * as EMSESP from './api'; const HelpInformation: FC = () => { + const { LL } = useI18nContext(); + const { enqueueSnackbar } = useSnackbar(); const saveFile = (json: any, endpoint: string) => { @@ -31,7 +36,7 @@ const HelpInformation: FC = () => { document.body.appendChild(a); a.click(); document.body.removeChild(a); - enqueueSnackbar('System information downloaded', { variant: 'info' }); + enqueueSnackbar(LL.DOWNLOAD_SUCCESSFUL(), { variant: 'info' }); }; const callAPI = async (endpoint: string) => { @@ -42,83 +47,85 @@ const HelpInformation: FC = () => { id: 0 }); if (response.status !== 200) { - enqueueSnackbar('API call failed', { variant: 'error' }); + enqueueSnackbar(LL.PROBLEM_LOADING(), { variant: 'error' }); } else { saveFile(response.data, endpoint); } } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem with downloading'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_LOADING()), { variant: 'error' }); } }; return ( - + - + - Visit the online  + {LL.HELP_INFORMATION_1()}  + +   - {'Wiki'} + {LL.CLICK_HERE()} -  to get instructions on how to  - - {'configure'} - -  EMS-ESP and access other information. - + - For live community chat join our  + {LL.HELP_INFORMATION_2()}  + +   - {'Discord'} + {LL.CLICK_HERE()} -  server. - + - - Submit a  + {LL.HELP_INFORMATION_3()}  + - support issue + {LL.CLICK_HERE()} -  for requesting a new feature or reporting a bug.
- Make sure you also  - -   and attach your system details for a faster response. +  )
- + - EMS-ESP will always be a free and open-source project -

Please consider supporting it with a  - on  - - {'GitHub'} - + {LL.HELP_INFORMATION_5()} +
+ + + {'Github'} + + + + + @proddy @MichaelDvP - @proddy @MichaelDvP
); diff --git a/interface/src/project/ProjectMenu.tsx b/interface/src/project/ProjectMenu.tsx index d03324eb1..fb5350e5e 100644 --- a/interface/src/project/ProjectMenu.tsx +++ b/interface/src/project/ProjectMenu.tsx @@ -6,6 +6,8 @@ import { AuthenticatedContext } from '../contexts/authentication'; import { PROJECT_PATH } from '../api/env'; +import { useI18nContext } from '../i18n/i18n-react'; + import TuneIcon from '@mui/icons-material/Tune'; import DashboardIcon from '@mui/icons-material/Dashboard'; import LayoutMenuItem from '../components/layout/LayoutMenuItem'; @@ -13,17 +15,18 @@ import InfoIcon from '@mui/icons-material/Info'; const ProjectMenu: FC = () => { const authenticatedContext = useContext(AuthenticatedContext); + const { LL } = useI18nContext(); return ( - + - + ); }; diff --git a/interface/src/project/Settings.tsx b/interface/src/project/Settings.tsx index 3ce59f639..51e8dadfe 100644 --- a/interface/src/project/Settings.tsx +++ b/interface/src/project/Settings.tsx @@ -5,18 +5,22 @@ import { Tab } from '@mui/material'; import { RouterTabs, useRouterTab, useLayoutTitle } from '../components'; +import { useI18nContext } from '../i18n/i18n-react'; + import SettingsApplication from './SettingsApplication'; import SettingsCustomization from './SettingsCustomization'; const Settings: FC = () => { - useLayoutTitle('Settings'); + const { LL } = useI18nContext(); const { routerTab } = useRouterTab(); + useLayoutTitle(LL.SETTINGS()); + return ( <> - - + + } /> diff --git a/interface/src/project/SettingsApplication.tsx b/interface/src/project/SettingsApplication.tsx index 945dfa137..c4df56b45 100644 --- a/interface/src/project/SettingsApplication.tsx +++ b/interface/src/project/SettingsApplication.tsx @@ -3,7 +3,7 @@ import { ValidateFieldsError } from 'async-validator'; import { useSnackbar } from 'notistack'; -import { Box, Button, Checkbox, MenuItem, Grid, Typography, Divider } from '@mui/material'; +import { Box, Button, Checkbox, MenuItem, Grid, Typography, Divider, InputAdornment } from '@mui/material'; import SaveIcon from '@mui/icons-material/Save'; import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew'; @@ -24,6 +24,8 @@ import { numberValue, extractErrorMessage, updateValue, useRest } from '../utils import * as EMSESP from './api'; import { Settings, BOARD_PROFILES } from './types'; +import { useI18nContext } from '../i18n/i18n-react'; + export function boardProfileSelectItems() { return Object.keys(BOARD_PROFILES).map((code) => ( @@ -38,6 +40,8 @@ const SettingsApplication: FC = () => { update: EMSESP.writeSettings }); + const { LL } = useI18nContext(); + const { enqueueSnackbar } = useSnackbar(); const updateFormValue = updateValue(setData); @@ -65,7 +69,7 @@ const SettingsApplication: FC = () => { }); } } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem fetching board profile'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); } finally { setProcessingBoard(false); } @@ -102,26 +106,23 @@ const SettingsApplication: FC = () => { validateAndSubmit(); try { await EMSESP.restart(); - enqueueSnackbar('EMS-ESP is restarting...', { variant: 'info' }); + enqueueSnackbar(LL.APPLICATION_RESTARTING(), { variant: 'info' }); } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem restarting device'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); } }; return ( <> - Interface Board Profile + Interface {LL.BOARD_PROFILE()} - - Select a pre-configured interface board profile from the list below or choose "Custom" to configure your own - hardware settings. - + {LL.BOARD_PROFILE_TEXT()} { { { { margin="normal" select > - No Ethernet Module + {LL.DISABLED()} LAN8720 TLK110 @@ -231,7 +232,7 @@ const SettingsApplication: FC = () => { { )} - EMS Bus Settings + EMS Bus {LL.SETTINGS()} @@ -319,63 +320,90 @@ const SettingsApplication: FC = () => { - General Options + {LL.GENERAL_OPTIONS()} + + + English (EN) + Deutsch (DE) + Nederlands (NL) + Svenska (SE) + Polski (PL) + Norsk (NO) + + {data.led_gpio !== 0 && ( } - label="Hide LED" + label={LL.HIDE_LED()} disabled={saving} /> )} } - label="Enable Telnet Console" + label={LL.ENABLE_TELNET()} disabled={saving} /> } - label="Enable Analog Sensors" + label={LL.ENABLE_ANALOG()} disabled={saving} /> } - label="Convert temperature values to Fahrenheit" + label={LL.CONVERT_FAHRENHEIT()} disabled={saving} /> } - label="Bypass Access Token authorization on API calls" + label={LL.BYPASS_TOKEN()} disabled={saving} /> } - label="Enable Read only mode (blocks all outgoing EMS Tx write commands)" + label={LL.READONLY()} disabled={saving} /> } - label="Underclock CPU speed" + label={LL.UNDERCLOCK_CPU()} disabled={saving} /> } - label="Enable Shower Timer" + label={LL.ENABLE_SHOWER_TIMER()} disabled={saving} /> } - label="Enable Shower Alert" + label={LL.ENABLE_SHOWER_ALERT()} disabled={!data.shower_timer} /> {data.shower_alert && ( <> - + {LL.MINUTES()} + }} variant="outlined" value={data.shower_alert_trigger} type="number" @@ -383,11 +411,14 @@ const SettingsApplication: FC = () => { disabled={!data.shower_timer} /> - + {LL.SECONDS()} + }} variant="outlined" value={data.shower_alert_coldshot} type="number" @@ -399,13 +430,13 @@ const SettingsApplication: FC = () => { )} - Formatting Options + {LL.FORMATTING_OPTIONS()} { margin="normal" select > - on/off - ON/OFF + {LL.ONOFF()} + {LL.ONOFF_CAP()} true/false 1/0 @@ -422,7 +453,7 @@ const SettingsApplication: FC = () => { { margin="normal" select > - "on"/"off" - "ON"/"OFF" + {LL.ONOFF()} + {LL.ONOFF_CAP()} "true"/"false" true/false "1"/"0" @@ -441,7 +472,7 @@ const SettingsApplication: FC = () => { { margin="normal" select > - Value - Index + {LL.VALUE()} + {LL.INDEX()} {data.dallas_gpio !== 0 && ( <> - Temperature Sensors + {LL.TEMP_SENSORS()} } - label="Enable parasite power" + label={LL.ENABLE_PARASITE()} disabled={saving} /> )} - Logging + {LL.LOGGING()} } - label="Log EMS telegrams in hexadecimal" + label={LL.LOG_HEX()} disabled={saving} /> { disabled={saving} /> } - label="Enable Syslog" + label={LL.ENABLE_SYSLOG()} /> {data.syslog_enabled && ( - + { disabled={saving} /> - + { disabled={saving} /> - + { ALL - + {LL.SECONDS()} + }} fullWidth variant="outlined" value={data.syslog_mark_interval} @@ -551,9 +585,9 @@ const SettingsApplication: FC = () => { )} {restartNeeded && ( - + )} @@ -567,7 +601,7 @@ const SettingsApplication: FC = () => { type="submit" onClick={validateAndSubmit} > - Save + {LL.SAVE()} )} @@ -576,7 +610,7 @@ const SettingsApplication: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/project/SettingsCustomization.tsx b/interface/src/project/SettingsCustomization.tsx index cdaeec26d..e83f58334 100644 --- a/interface/src/project/SettingsCustomization.tsx +++ b/interface/src/project/SettingsCustomization.tsx @@ -19,7 +19,6 @@ import { import { Table } from '@table-library/react-table-library/table'; import { useTheme } from '@table-library/react-table-library/theme'; -import { useSort, SortToggleType } from '@table-library/react-table-library/sort'; import { Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table'; import { useSnackbar } from 'notistack'; @@ -28,9 +27,6 @@ import SaveIcon from '@mui/icons-material/Save'; import CancelIcon from '@mui/icons-material/Cancel'; import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore'; -import KeyboardArrowUpOutlinedIcon from '@mui/icons-material/KeyboardArrowUpOutlined'; -import KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined'; -import UnfoldMoreOutlinedIcon from '@mui/icons-material/UnfoldMoreOutlined'; import SearchIcon from '@mui/icons-material/Search'; import FilterListIcon from '@mui/icons-material/FilterList'; @@ -40,16 +36,22 @@ import { ButtonRow, FormLoader, ValidatedTextField, SectionContent } from '../co import * as EMSESP from './api'; -import { extractErrorMessage } from '../utils'; +import { extractErrorMessage, updateValue } from '../utils'; import { DeviceShort, Devices, DeviceEntity, DeviceEntityMask } from './types'; +import { useI18nContext } from '../i18n/i18n-react'; + export const APIURL = window.location.origin + '/api/'; const SettingsCustomization: FC = () => { + const { LL } = useI18nContext(); + const { enqueueSnackbar } = useSnackbar(); - const [deviceEntities, setDeviceEntities] = useState([{ id: '', v: 0, n: '', m: 0, w: false }]); + const emptyDeviceEntity = { id: '', v: 0, n: '', cn: '', m: 0, w: false }; + + const [deviceEntities, setDeviceEntities] = useState([emptyDeviceEntity]); const [devices, setDevices] = useState(); const [errorMessage, setErrorMessage] = useState(); const [selectedDevice, setSelectedDevice] = useState(-1); @@ -57,6 +59,8 @@ const SettingsCustomization: FC = () => { const [selectedFilters, setSelectedFilters] = useState(0); const [search, setSearch] = useState(''); + const [deviceEntity, setDeviceEntity] = useState(); + // eslint-disable-next-line const [masks, setMasks] = useState(() => ['']); @@ -92,6 +96,7 @@ const SettingsCustomization: FC = () => { Row: ` background-color: #1e1e1e; position: relative; + cursor: pointer; .td { border-top: 1px solid #565656; @@ -104,6 +109,11 @@ const SettingsCustomization: FC = () => { font-weight: normal; } + &:hover .td { + border-top: 1px solid #177ac9; + border-bottom: 1px solid #177ac9; + } + &:nth-of-type(odd) .td { background-color: #303030; } @@ -118,50 +128,24 @@ const SettingsCustomization: FC = () => { ` }); - const getSortIcon = (state: any, sortKey: any) => { - if (state.sortKey === sortKey && state.reverse) { - return ; - } - if (state.sortKey === sortKey && !state.reverse) { - return ; - } - return ; - }; - - const entity_sort = useSort( - { nodes: deviceEntities }, - {}, - { - sortIcon: { - iconDefault: , - iconUp: , - iconDown: - }, - sortToggleType: SortToggleType.AlternateWithReset, - sortFns: { - NAME: (array) => array.sort((a, b) => a.id.localeCompare(b.id)) - } - } - ); - const fetchDevices = useCallback(async () => { try { setDevices((await EMSESP.readDevices()).data); } catch (error: unknown) { - setErrorMessage(extractErrorMessage(error, 'Failed to fetch device list')); + setErrorMessage(extractErrorMessage(error, LL.PROBLEM_LOADING())); } - }, []); + }, [LL]); const setInitialMask = (data: DeviceEntity[]) => { - setDeviceEntities(data.map((de) => ({ ...de, om: de.m }))); + setDeviceEntities(data.map((de) => ({ ...de, o_m: de.m, o_cn: de.cn }))); }; const fetchDeviceEntities = async (unique_id: number) => { try { - const data = (await EMSESP.readDeviceEntities({ id: unique_id })).data; - setInitialMask(data); + const new_deviceEntities = (await EMSESP.readDeviceEntities({ id: unique_id })).data; + setInitialMask(new_deviceEntities); } catch (error: unknown) { - setErrorMessage(extractErrorMessage(error, 'Problem fetching device entities')); + setErrorMessage(extractErrorMessage(error, LL.PROBLEM_LOADING())); } }; @@ -183,12 +167,16 @@ const SettingsCustomization: FC = () => { function formatName(de: DeviceEntity) { if (de.n === undefined || de.n === de.id) { return de.id; - } else if (de.n === '') { - return 'Command: ' + de.id; } + + if (de.n === '') { + return LL.COMMAND() + ': ' + de.id; + } + return ( <> - {de.n} ( + {de.cn !== undefined && de.cn !== '' ? de.cn : de.n} +  ( {de.id} @@ -250,9 +238,9 @@ const SettingsCustomization: FC = () => { const resetCustomization = async () => { try { await EMSESP.resetCustomizations(); - enqueueSnackbar('All customizations have been removed. Restarting...', { variant: 'info' }); + enqueueSnackbar(LL.CUSTOMIZATIONS_RESTART(), { variant: 'info' }); } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem resetting customizations'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); } finally { setConfirmReset(false); } @@ -261,26 +249,28 @@ const SettingsCustomization: FC = () => { const saveCustomization = async () => { if (devices && deviceEntities && selectedDevice !== -1) { const masked_entities = deviceEntities - .filter((de) => de.m !== de.om) - .map((new_de) => new_de.m.toString(16).padStart(2, '0') + new_de.id); + .filter((de) => de.m !== de.o_m || de.cn !== de.o_cn) + .map((new_de) => new_de.m.toString(16).padStart(2, '0') + new_de.id + (new_de.cn ? '|' + new_de.cn : '')); - if (masked_entities.length > 60) { - enqueueSnackbar('Selected entities exceeded limit of 60. Please Save in batches', { variant: 'warning' }); + // check size in bytes to match buffer in CPP, which is 4096 + const bytes = new TextEncoder().encode(JSON.stringify(masked_entities)).length; + if (bytes > 4000) { + enqueueSnackbar(LL.CUSTOMIZATIONS_FULL(), { variant: 'warning' }); return; } try { - const response = await EMSESP.writeMaskedEntities({ + const response = await EMSESP.writeCustomEntities({ id: devices?.devices[selectedDevice].i, entity_ids: masked_entities }); if (response.status === 200) { - enqueueSnackbar('Customization saved', { variant: 'success' }); + enqueueSnackbar(LL.CUSTOMIZATIONS_SAVED(), { variant: 'success' }); } else { - enqueueSnackbar('Customization save failed', { variant: 'error' }); + enqueueSnackbar(LL.PROBLEM_UPDATING(), { variant: 'error' }); } } catch (error: unknown) { - enqueueSnackbar(extractErrorMessage(error, 'Problem sending entity list'), { variant: 'error' }); + enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); } setInitialMask(deviceEntities); } @@ -294,21 +284,17 @@ const SettingsCustomization: FC = () => { return ( <> - Select a device and customize each of its entities using the options: + {LL.CUSTOMIZATIONS_HELP_1()} - - =mark as favorite   - - =disable write action   - - =exclude from MQTT and API   - - =hide from Dashboard + ={LL.CUSTOMIZATIONS_HELP_2()}   + ={LL.CUSTOMIZATIONS_HELP_3()}   + ={LL.CUSTOMIZATIONS_HELP_4()}   + ={LL.CUSTOMIZATIONS_HELP_5()} { select > - Select a device... + {LL.SELECT_DEVICE()}... {devices.devices.map((device: DeviceShort, index) => ( @@ -329,6 +315,29 @@ const SettingsCustomization: FC = () => { ); }; + const editEntity = (de: DeviceEntity) => { + if (de.cn === undefined) { + de.cn = ''; + } + setDeviceEntity(de); + }; + + const updateEntity = () => { + if (deviceEntity) { + setDeviceEntities((prevState) => { + const newState = prevState.map((obj) => { + if (obj.id === deviceEntity.id) { + return { ...obj, cn: deviceEntity.cn }; + } + return obj; + }); + return newState; + }); + } + + setDeviceEntity(undefined); + }; + const renderDeviceData = () => { if (devices?.devices.length === 0 || deviceEntities[0].id === '') { return; @@ -401,7 +410,7 @@ const SettingsCustomization: FC = () => { color="inherit" onClick={() => maskDisabled(false)} > - set all  + {LL.SET_ALL()}  @@ -416,35 +425,30 @@ const SettingsCustomization: FC = () => { color="inherit" onClick={() => maskDisabled(true)} > - set all  + {LL.SET_ALL()}  -
+
{(tableList: any) => ( <>
- OPTIONS + {LL.OPTIONS()} - - VALUE + {LL.VALUE()}
{tableList.map((de: DeviceEntity) => ( - + editEntity(de)}> { const renderResetDialog = () => ( setConfirmReset(false)}> - Reset - - Are you sure you want remove all customizations including the custom settings of the Temperature and Analog - sensors? - + {LL.RESET()} + {LL.CUSTOMIZATIONS_RESET()} @@ -529,15 +530,15 @@ const SettingsCustomization: FC = () => { return ( <> - Device Entities + {LL.DEVICE_ENTITIES()} {renderDeviceList()} - {renderDeviceData()} + {!deviceEntity && renderDeviceData()} @@ -548,7 +549,7 @@ const SettingsCustomization: FC = () => { color="error" onClick={() => setConfirmReset(true)} > - Reset + {LL.RESET()} @@ -557,8 +558,55 @@ const SettingsCustomization: FC = () => { ); }; + const renderEditEntity = () => { + if (deviceEntity) { + return ( + setDeviceEntity(undefined)}> + {LL.RENAME() + ' ' + LL.ENTITY_NAME()} + + + {deviceEntity.n} + + + + + + + + + + + + + ); + } + }; + return ( - + + {renderEditEntity()} {content()} ); diff --git a/interface/src/project/api.ts b/interface/src/project/api.ts index d6804cda4..266338214 100644 --- a/interface/src/project/api.ts +++ b/interface/src/project/api.ts @@ -12,7 +12,7 @@ import { DeviceData, DeviceEntity, UniqueID, - MaskedEntities, + CustomEntities, WriteValue, WriteSensor, WriteAnalog, @@ -63,8 +63,8 @@ export function readDeviceEntities(unique_id: UniqueID): AxiosPromise { - return AXIOS.post('/maskedEntities', maskedEntities); +export function writeCustomEntities(customEntities: CustomEntities): AxiosPromise { + return AXIOS.post('/customEntities', customEntities); } export function writeValue(writevalue: WriteValue): AxiosPromise { diff --git a/interface/src/project/types.ts b/interface/src/project/types.ts index d990e7381..7cac14bd7 100644 --- a/interface/src/project/types.ts +++ b/interface/src/project/types.ts @@ -1,4 +1,5 @@ export interface Settings { + locale: string; tx_mode: number; ems_bus_id: number; syslog_enabled: boolean; @@ -41,7 +42,7 @@ export enum busConnectionStatus { } export interface Stat { - id: string; // name + id: string; // id - needs to be a string s: number; // success f: number; // fail q: number; // quality @@ -136,12 +137,14 @@ export interface DeviceEntity { id: string; // shortname v?: any; // value, in any format, optional n?: string; // fullname, optional + cn?: string; // custom fullname, optional m: number; // mask - om?: number; // original mask before edits + o_m?: number; // original mask before edits + o_cn?: string; // original cn before edits w: boolean; // writeable } -export interface MaskedEntities { +export interface CustomEntities { id: number; entity_ids: string[]; } diff --git a/interface/src/utils/time.ts b/interface/src/utils/time.ts index 7a7986b52..f550e228f 100644 --- a/interface/src/utils/time.ts +++ b/interface/src/utils/time.ts @@ -1,5 +1,3 @@ -import parseMilliseconds from 'parse-ms'; - const LOCALE_FORMAT = new Intl.DateTimeFormat([...window.navigator.languages], { day: 'numeric', month: 'short', @@ -21,21 +19,6 @@ export const formatLocalDateTime = (date: Date) => { export const pluralize = (count: number, noun: string) => `${Intl.NumberFormat().format(count)} ${noun}${count !== 1 ? 's' : ''}`; -export const formatDurationMin = (duration_min: number) => { - const { days, hours, minutes } = parseMilliseconds(duration_min * 60000); - let formatted = ''; - if (days) { - formatted += pluralize(days, 'day') + ' '; - } - if (hours) { - formatted += pluralize(hours, 'hour') + ' '; - } - if (minutes) { - formatted += pluralize(minutes, 'minute') + ' '; - } - return formatted; -}; - export const formatDurationSec = (duration_sec: number) => { if (duration_sec === 0) { return ' '; diff --git a/interface/src/utils/useRest.ts b/interface/src/utils/useRest.ts index e889e4521..a615f215e 100644 --- a/interface/src/utils/useRest.ts +++ b/interface/src/utils/useRest.ts @@ -4,12 +4,16 @@ import { AxiosPromise } from 'axios'; import { extractErrorMessage } from '.'; +import { useI18nContext } from '../i18n/i18n-react'; + export interface RestRequestOptions { read: () => AxiosPromise; update?: (value: D) => AxiosPromise; } export const useRest = ({ read, update }: RestRequestOptions) => { + const { LL } = useI18nContext(); + const { enqueueSnackbar } = useSnackbar(); const [saving, setSaving] = useState(false); @@ -23,11 +27,11 @@ export const useRest = ({ read, update }: RestRequestOptions) => { try { setData((await read()).data); } catch (error: unknown) { - const message = extractErrorMessage(error, 'Problem loading data'); + const message = extractErrorMessage(error, LL.PROBLEM_LOADING()); enqueueSnackbar(message, { variant: 'error' }); setErrorMessage(message); } - }, [read, enqueueSnackbar]); + }, [read, enqueueSnackbar, LL]); const save = useCallback( async (toSave: D) => { @@ -43,17 +47,17 @@ export const useRest = ({ read, update }: RestRequestOptions) => { if (response.status === 202) { setRestartNeeded(true); } else { - enqueueSnackbar('Settings saved', { variant: 'success' }); + enqueueSnackbar(LL.SETTINGS() + ' ' + LL.SAVED(), { variant: 'success' }); } } catch (error: unknown) { - const message = extractErrorMessage(error, 'Problem saving data'); + const message = extractErrorMessage(error, LL.PROBLEM_UPDATING()); enqueueSnackbar(message, { variant: 'error' }); setErrorMessage(message); } finally { setSaving(false); } }, - [update, enqueueSnackbar] + [update, enqueueSnackbar, LL] ); const saveData = () => data && save(data); diff --git a/interface/src/validators/authentication.ts b/interface/src/validators/authentication.ts index ebf42fb68..96712b288 100644 --- a/interface/src/validators/authentication.ts +++ b/interface/src/validators/authentication.ts @@ -3,10 +3,8 @@ import Schema from 'async-validator'; export const SIGN_IN_REQUEST_VALIDATOR = new Schema({ username: { required: true, - message: 'Please provide a username' }, password: { required: true, - message: 'Please provide a password' } }); diff --git a/lib/ESPAsyncWebServer/AsyncWebSocket.cpp b/lib/ESPAsyncWebServer/AsyncWebSocket.cpp index 48baab476..b4425000b 100644 --- a/lib/ESPAsyncWebServer/AsyncWebSocket.cpp +++ b/lib/ESPAsyncWebServer/AsyncWebSocket.cpp @@ -704,8 +704,13 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen){ } else if(_pinfo.opcode == WS_PING){ _queueControl(new AsyncWebSocketControl(WS_PONG, data, datalen)); } else if(_pinfo.opcode == WS_PONG){ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-overflow" if(datalen != AWSC_PING_PAYLOAD_LEN || memcmp_P(data, AWSC_PING_PAYLOAD, AWSC_PING_PAYLOAD_LEN) != 0) _server->_handleEvent(this, WS_EVT_PONG, NULL, data, datalen); +#pragma GCC diagnostic pop + } else if(_pinfo.opcode < 8){//continuation or text/binary frame _server->_handleEvent(this, WS_EVT_DATA, (void *)&_pinfo, data, datalen); } diff --git a/lib/OneWire/OneWire.cpp b/lib/OneWire/OneWire.cpp index 38bf4ee2d..3ac6ddd81 100644 --- a/lib/OneWire/OneWire.cpp +++ b/lib/OneWire/OneWire.cpp @@ -143,6 +143,7 @@ sample code bearing this copyright. #include "OneWire.h" #include "util/OneWire_direct_gpio.h" +#pragma GCC diagnostic ignored "-Wunused-variable" void OneWire::begin(uint8_t pin) { @@ -154,7 +155,6 @@ void OneWire::begin(uint8_t pin) #endif } - // Perform the onewire reset function. We will wait up to 250uS for // the bus to come high, if it doesn't then it is broken or shorted // and we return a 0; @@ -578,3 +578,6 @@ uint16_t OneWire::crc16(const uint8_t* input, uint16_t len, uint16_t crc) #endif #endif + +#pragma GCC diagnostic pop + diff --git a/lib/framework/FSPersistence.h b/lib/framework/FSPersistence.h index 52c96d7ed..fb77e99ad 100644 --- a/lib/framework/FSPersistence.h +++ b/lib/framework/FSPersistence.h @@ -68,11 +68,28 @@ class FSPersistence { JsonObject jsonObject = jsonDocument.to(); _statefulService->read(jsonObject, _stateReader); + // make directories if required, for new IDF4.2 & LittleFS + String path(_filePath); + int index = 0; + while ((index = path.indexOf('/', index + 1)) != -1) { + String segment = path.substring(0, index); + if (!_fs->exists(segment)) { + _fs->mkdir(segment); + } + } + // serialize it to filesystem File settingsFile = _fs->open(_filePath, "w"); // failed to open file, return false if (!settingsFile) { +#if defined(EMSESP_DEBUG) +#if defined(EMSESP_USE_SERIAL) + Serial.println(); + Serial.printf("Cannot write to file system."); + Serial.println(); +#endif +#endif return false; } diff --git a/lib/framework/MqttSettingsService.cpp b/lib/framework/MqttSettingsService.cpp index 1762fb49d..67ac1e01a 100644 --- a/lib/framework/MqttSettingsService.cpp +++ b/lib/framework/MqttSettingsService.cpp @@ -104,7 +104,7 @@ void MqttSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { case ARDUINO_EVENT_ETH_GOT_IP6: case ARDUINO_EVENT_WIFI_STA_GOT_IP6: if (_state.enabled) { - // emsesp::EMSESP::logger().info(F("Network connection found, starting MQTT client")); + // emsesp::EMSESP::logger().info(F("IPv4 Network connection found, starting MQTT client")); onConfigUpdated(); } break; diff --git a/lib/framework/NTPSettingsService.cpp b/lib/framework/NTPSettingsService.cpp index 67fbf8df4..55ab6964c 100644 --- a/lib/framework/NTPSettingsService.cpp +++ b/lib/framework/NTPSettingsService.cpp @@ -50,6 +50,7 @@ void NTPSettingsService::configureNTP() { emsesp::EMSESP::system_.ntp_connected(false); if (connected_ && _state.enabled) { emsesp::EMSESP::logger().info(F("Starting NTP")); + sntp_set_sync_interval(3600000); // onehour sntp_set_time_sync_notification_cb(ntp_received); configTzTime(_state.tzFormat.c_str(), _state.server.c_str()); } else { diff --git a/lib/framework/SystemStatus.cpp b/lib/framework/SystemStatus.cpp index baf933050..c9f810382 100644 --- a/lib/framework/SystemStatus.cpp +++ b/lib/framework/SystemStatus.cpp @@ -24,7 +24,7 @@ void SystemStatus::systemStatus(AsyncWebServerRequest * request) { root["flash_chip_size"] = ESP.getFlashChipSize(); root["flash_chip_speed"] = ESP.getFlashChipSpeed(); - root["fs_total"] = LittleFS.totalBytes(); + root["fs_total"] = emsesp::EMSESP::system_.FStotal(); root["fs_used"] = LittleFS.usedBytes(); root["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3); diff --git a/lib_standalone/ESP8266React.h b/lib_standalone/ESP8266React.h index 1514fa1e3..4c17cc4aa 100644 --- a/lib_standalone/ESP8266React.h +++ b/lib_standalone/ESP8266React.h @@ -26,6 +26,7 @@ class DummySettings { public: + String locale = "en"; uint8_t tx_mode = 1; uint8_t ems_bus_id = 0x0B; bool syslog_enabled = false; diff --git a/lib_standalone/FSPersistence.h b/lib_standalone/FSPersistence.h index 10c4b7814..345e9b8ae 100644 --- a/lib_standalone/FSPersistence.h +++ b/lib_standalone/FSPersistence.h @@ -24,6 +24,8 @@ class FSPersistence { } void readFromFS() { + Serial.print("Fake reading file "); + Serial.println(_filePath); applyDefaults(); } diff --git a/mock-api/server.js b/mock-api/server.js index 1e6ebef3a..942b14b20 100644 --- a/mock-api/server.js +++ b/mock-api/server.js @@ -253,7 +253,7 @@ const UPLOAD_FILE_ENDPOINT = REST_ENDPOINT_ROOT + 'uploadFile' const SIGN_IN_ENDPOINT = REST_ENDPOINT_ROOT + 'signIn' const GENERATE_TOKEN_ENDPOINT = REST_ENDPOINT_ROOT + 'generateToken' const system_status = { - emsesp_version: '3.4demo', + emsesp_version: '3.5demo', esp_platform: 'ESP32', max_alloc_heap: 113792, psram_size: 0, @@ -302,11 +302,12 @@ const EMSESP_BOARDPROFILE_ENDPOINT = REST_ENDPOINT_ROOT + 'boardProfile' const EMSESP_WRITE_VALUE_ENDPOINT = REST_ENDPOINT_ROOT + 'writeValue' const EMSESP_WRITE_SENSOR_ENDPOINT = REST_ENDPOINT_ROOT + 'writeSensor' const EMSESP_WRITE_ANALOG_ENDPOINT = REST_ENDPOINT_ROOT + 'writeAnalog' -const EMSESP_MASKED_ENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'maskedEntities' +const EMSESP_CUSTOM_ENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'customEntities' const EMSESP_RESET_CUSTOMIZATIONS_ENDPOINT = REST_ENDPOINT_ROOT + 'resetCustomizations' settings = { - tx_mode: 1, + locale: 'en', + tx_mode: 4, ems_bus_id: 11, syslog_enabled: false, syslog_level: 3, @@ -344,29 +345,24 @@ const emsesp_devices = { devices: [ { i: 1, - d: 23, - p: 77, s: 'Thermostat (RC20/Moduline 300)', - t: 'thermostat1', + t: 'thermostat', }, { i: 2, - d: 8, - p: 123, s: 'Boiler (Nefit GBx72/Trendline/Cerapur/Greenstar Si/27i)', t: 'boiler', }, { i: 4, - d: 16, - p: 165, s: 'Thermostat (RC100/Moduline 1000/1010)', - t: 'thermostat2', + t: 'thermostat', }, ], } const emsesp_coredata = { + connected: true, // devices: [], devices: [ { @@ -429,13 +425,13 @@ const status = { num_sensors: 1, num_analogs: 1, stats: [ - { id: 'EMS Telegrams Received (Rx)', s: 56506, f: 11, q: 100 }, - { id: 'EMS Reads (Tx)', s: 9026, f: 0, q: 100 }, - { id: 'EMS Writes (Tx)', s: 33, f: 2, q: 95 }, - { id: 'Temperature Sensor Reads', s: 56506, f: 11, q: 100 }, - { id: 'Analog Sensor Reads', s: 0, f: 0, q: 100 }, - { id: 'MQTT Publishes', s: 12, f: 10, q: 20 }, - { id: 'API Calls', s: 0, f: 0, q: 0 }, + { id: '0', s: 56506, f: 11, q: 100 }, + { id: '1', s: 9026, f: 0, q: 100 }, + { id: '2', s: 33, f: 2, q: 95 }, + { id: '3', s: 56506, f: 11, q: 100 }, + { id: '4', s: 0, f: 0, q: 100 }, + { id: '5', s: 12, f: 10, q: 20 }, + { id: '6', s: 0, f: 0, q: 0 }, ], } @@ -446,7 +442,7 @@ const emsesp_devicedata_1 = { { v: '(0)', u: 0, - id: '00error code', + id: '08my custom error code', }, { v: '14:54:39 06/06/2021', @@ -584,8 +580,9 @@ const emsesp_deviceentities_1 = [ { v: '(0)', n: 'error code', + cn: 'my custom error code', id: 'errorcode', - m: 0, + m: 8, w: false, }, { @@ -602,19 +599,13 @@ const emsesp_deviceentities_1 = [ // m: 0, // w: false, // }, - { - v: 'roomTemp', - id: 'hc1/HA climate config creation', - m: 0, - w: false, - }, - { - v: 18.2, - n: 'hc1 selected room temperature', - id: 'hc1/seltemp', - m: 0, - w: true, - }, + // { + // v: 18.2, + // n: 'hc1 selected room temperature', + // id: 'hc1/seltemp', + // m: 0, + // w: true, + // }, { v: 22.6, n: 'hc1 current room temperature', @@ -852,6 +843,7 @@ rest_server.post(UPLOAD_FILE_ENDPOINT, (req, res) => { res.sendStatus(200) }) rest_server.post(SIGN_IN_ENDPOINT, (req, res) => { + console.log('Signed in as ' + req.body.username) res.json(signin) }) rest_server.get(GENERATE_TOKEN_ENDPOINT, (req, res) => { @@ -931,29 +923,64 @@ rest_server.post(EMSESP_DEVICEENTITIES_ENDPOINT, (req, res) => { }) function updateMask(entity, de, dd) { - const shortname = entity.slice(2) - const new_mask = parseInt(entity.slice(0, 2), 16) + const current_mask = parseInt(entity.slice(0, 2), 16) + const shortname_with_customname = entity.slice(2) + const shortname = shortname_with_customname.split('|')[0] + const new_custom_name = shortname_with_customname.split('|')[1] + + // find in de + de_objIndex = de.findIndex((obj) => obj.id === shortname) + if (de_objIndex !== -1) { + if (de[de_objIndex].cn) { + fullname = de[de_objIndex].cn + } else { + fullname = de[de_objIndex].n + } + + // find in dd, either looking for fullname or custom name + dd_objIndex = dd.data.findIndex((obj) => obj.id.slice(2) === fullname) + if (dd_objIndex !== -1) { + let changed = new Boolean(false) - objIndex = de.findIndex((obj) => obj.id == shortname) - if (objIndex !== -1) { - de[objIndex].m = new_mask - const fullname = de[objIndex].n - objIndex = dd.data.findIndex((obj) => obj.id.slice(2) == fullname) - if (objIndex !== -1) { // see if the mask has changed - const old_mask = parseInt(dd.data[objIndex].id.slice(0, 2), 16) - if (old_mask !== new_mask) { - const mask_hex = entity.slice(0, 2) - console.log('Updating ' + dd.data[objIndex].id + ' -> ' + mask_hex + fullname) - dd.data[objIndex].id = mask_hex + fullname + const old_mask = parseInt(dd.data[dd_objIndex].id.slice(0, 2), 16) + if (old_mask !== current_mask) { + changed = true + console.log('mask has changed to ' + current_mask.toString(16)) } + + // see if the custom name has changed + const old_custom_name = dd.data[dd_objIndex].cn + if (old_custom_name !== new_custom_name) { + changed = true + new_fullname = new_custom_name + console.log('name has changed to ' + new_custom_name) + } else { + new_fullname = fullname + } + + if (changed) { + console.log( + 'Updating ' + dd.data[dd_objIndex].id + ' -> ' + current_mask.toString(16).padStart(2, '0') + new_fullname, + ) + de[de_objIndex].m = current_mask + de[de_objIndex].cn = new_fullname + dd.data[dd_objIndex].id = current_mask.toString(16).padStart(2, '0') + new_fullname + } + + console.log('new dd:') + console.log(dd.data[dd_objIndex]) + console.log('new de:') + console.log(de[de_objIndex]) + } else { + console.log('error, dd not found') } } else { - console.log("can't locate record for name " + shortname) + console.log("can't locate record for shortname " + shortname) } } -rest_server.post(EMSESP_MASKED_ENTITIES_ENDPOINT, (req, res) => { +rest_server.post(EMSESP_CUSTOM_ENTITIES_ENDPOINT, (req, res) => { const id = req.body.id console.log('customization id = ' + id) console.log(req.body.entity_ids) @@ -1135,7 +1162,7 @@ rest_server.post(EMSESP_BOARDPROFILE_ENDPOINT, (req, res) => { // EMS-ESP API specific const emsesp_info = { System: { - version: '3.4.2', + version: '3.5.0', uptime: '001+06:40:34.018', 'uptime (seconds)': 110434, freemem: 131, diff --git a/pio_local.ini_example b/pio_local.ini_example index 9c2db40f8..6172ddb2c 100644 --- a/pio_local.ini_example +++ b/pio_local.ini_example @@ -8,16 +8,27 @@ ; my_build_flags = -DEMSESP_DEBUG -DEMSESP_USE_SERIAL ; my_build_flags = -DEMSESP_DEBUG -DCORE_DEBUG_LEVEL=5 ; 5=verbose, 4=debug, 3=info -[env:esp32] +[env:esp32_4M] ; if using OTA enter your details below -; upload_protocol = espota -; upload_flags = -; --port=8266 -; --auth=ems-esp-neo -; upload_port = ems-esp.local +; upload_protocol = espota +; upload_flags = +; --port=8266 +; --auth=ems-esp-neo +; upload_port = ems-esp.local +; for USB use +upload_port = /dev/ttyUSB* +; upload_port = COM3 extra_scripts = - pre:scripts/build_interface.py ; comment out if you don't want to re-build the WebUI each time + ; pre:scripts/build_interface.py ; comment out if you don't want to re-build the WebUI each time + scripts/rename_fw.py + +[env:esp32_16M] +upload_port = /dev/ttyUSB* +; upload_port = COM3 + +extra_scripts = + ; pre:scripts/build_interface.py ; comment out if you don't want to re-build the WebUI each time scripts/rename_fw.py ; pio run -e debug diff --git a/platformio.ini b/platformio.ini index 915333874..444bf4039 100644 --- a/platformio.ini +++ b/platformio.ini @@ -2,7 +2,8 @@ ; override any settings with your own local ones in pio_local.ini [platformio] -default_envs = esp32 +default_envs = esp32_4M +; default_envs = esp32_16M extra_configs = factory_settings.ini @@ -37,9 +38,11 @@ unbuild_flags = [env] framework = arduino monitor_speed = 115200 +monitor_raw = yes upload_speed = 921600 build_type = release lib_ldf_mode = chain+ +debug_build_flags = -Os # optimize for size check_tool = cppcheck, clangtidy check_severity = high, medium @@ -53,16 +56,28 @@ check_flags = extra_scripts = scripts/rename_fw.py board = esp32dev platform = espressif32 -board_build.partitions = esp32_partition_app1984k_spiffs64k.csv +board_build.partitions = esp32_partition_4M.csv build_flags = ${common.build_flags} build_unflags = ${common.unbuild_flags} -[env:esp32] +[env:esp32_4M] extra_scripts = pre:scripts/build_interface.py scripts/rename_fw.py board = esp32dev platform = espressif32 -board_build.partitions = esp32_partition_app1984k_spiffs64k.csv +board_upload.flash_size = 4MB +board_build.partitions = esp32_partition_4M.csv +build_flags = ${common.build_flags} +build_unflags = ${common.unbuild_flags} + +[env:esp32_16M] +extra_scripts = + pre:scripts/build_interface.py + scripts/rename_fw.py +board = esp32dev +platform = espressif32 +board_upload.flash_size = 16MB +board_build.partitions = esp32_partition_16M.csv build_flags = ${common.build_flags} build_unflags = ${common.unbuild_flags} diff --git a/scripts/rename_fw.py b/scripts/rename_fw.py index 2f8804a55..6c7612b5a 100644 --- a/scripts/rename_fw.py +++ b/scripts/rename_fw.py @@ -5,7 +5,6 @@ Import("env") OUTPUT_DIR = "build{}".format(os.path.sep) - def bin_copy(source, target, env): # get the build info @@ -21,20 +20,23 @@ def bin_copy(source, target, env): app_version = bag.get('app_version') platform = "ESP32" + flash_size = env["PIOENV"].split('_')[1] + # print(env.Dump()) # my_flags = env.ParseFlags(env['BUILD_FLAGS']) # defines = {k: v for (k, v) in my_flags.get("CPPDEFINES")} # print(my_flags) # print((my_flags.get("CPPDEFINES")) - # alternatively take platfrom from the pio target + # alternatively take platform from the pio target # platform = str(target[0]).split(os.path.sep)[2] print("app version: "+app_version) print("platform: "+platform) + print("flash size: "+flash_size) # convert . to _ so Windows doesn't complain - variant = "EMS-ESP-" + app_version.replace(".", "_") + "-" + platform + variant = "EMS-ESP-" + app_version.replace(".", "_") + "-" + platform + "_" + flash_size # check if output directories exist and create if necessary if not os.path.isdir(OUTPUT_DIR): @@ -52,10 +54,9 @@ def bin_copy(source, target, env): if os.path.isfile(f): os.remove(f) - print("renaming file to "+bin_file) + print("Renaming file to "+bin_file) # copy firmware.bin to firmware/.bin shutil.copy(str(target[0]), bin_file) - env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_copy]) diff --git a/scripts/run_sonar.sh b/scripts/run_sonar.sh old mode 100755 new mode 100644 diff --git a/sonar-project.properties b/sonar-project.properties index cd8e24393..98756864a 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,7 +1,7 @@ sonar.organization=emsesp sonar.projectKey=emsesp_EMS-ESP32 sonar.projectName=EMS-ESP32 -sonar.projectVersion=3.4 +sonar.projectVersion=3.5.0 sonar.sources=./src sonar.cfamily.build-wrapper-output=build_wrapper_output_directory sonar.sourceEncoding=UTF-8 diff --git a/src/analogsensor.cpp b/src/analogsensor.cpp index 0851a62e3..826f370f6 100644 --- a/src/analogsensor.cpp +++ b/src/analogsensor.cpp @@ -42,7 +42,7 @@ void AnalogSensor::start() { EMSdevice::DeviceType::ANALOGSENSOR, F_(setvalue), [&](const char * value, const int8_t id) { return command_setvalue(value, id); }, - F("set io value"), + F("set io value"), // TODO this needs translating CommandFlag::ADMIN_ONLY); Command::add( EMSdevice::DeviceType::ANALOGSENSOR, @@ -60,7 +60,10 @@ void AnalogSensor::reload() { #if defined(EMSESP_STANDALONE) analog_enabled_ = true; // for local offline testing #endif - + if (!analog_enabled_) { + sensors_.clear(); + return; + } // load the list of analog sensors from the customization service // and store them locally and then activate them EMSESP::webCustomizationService.read([&](WebCustomization & settings) { @@ -459,7 +462,7 @@ bool AnalogSensor::get_value_info(JsonObject & output, const char * cmd, const i output["gpio"] = sensor.gpio(); output["name"] = sensor.name(); output["type"] = F_(number); - output["analog"] = FL_(enum_sensortype)[sensor.type()]; + output["analog"] = FL_(list_sensortype)[sensor.type()]; output["uom"] = EMSdevice::uom_to_string(sensor.uom()); output["offset"] = sensor.offset(); output["factor"] = sensor.factor(); @@ -497,7 +500,7 @@ bool AnalogSensor::command_info(const char * value, const int8_t id, JsonObject JsonObject dataSensor = output.createNestedObject(sensor.name()); dataSensor["gpio"] = sensor.gpio(); dataSensor["type"] = F_(number); - dataSensor["analog"] = FL_(enum_sensortype)[sensor.type()]; + dataSensor["analog"] = FL_(list_sensortype)[sensor.type()]; if (sensor.type() == AnalogType::ADC) { dataSensor["uom"] = EMSdevice::uom_to_string(sensor.uom()); dataSensor["offset"] = sensor.offset(); diff --git a/src/command.cpp b/src/command.cpp index b4583c5cb..cae119bec 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -306,7 +306,7 @@ void Command::add(const uint8_t device_type, const __FlashStringHelper * cmd, co } // if the description is empty, it's hidden which means it will not show up in Web API or Console as an available command - if (description == nullptr) { + if (!description) { flags |= CommandFlag::HIDDEN; } @@ -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(' '); } - shell.print(read_flash_string(cf.description_)); + shell.print(read_flash_string(cf.description_).c_str()); if (!cf.has_flags(CommandFlag::ADMIN_ONLY)) { shell.print(' '); shell.print(COLOR_BRIGHT_RED); diff --git a/src/common.h b/src/common.h new file mode 100644 index 000000000..0e476c26e --- /dev/null +++ b/src/common.h @@ -0,0 +1,64 @@ +/* + * EMS-ESP - https://github.com/emsesp/EMS-ESP + * Copyright 2020 Paul Derbyshire + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef EMSESP_COMMON_H +#define EMSESP_COMMON_H + +// logging +#include + +using uuid::log::Level; +#define LOG_DEBUG(...) logger_.debug(__VA_ARGS__) +#define LOG_INFO(...) logger_.info(__VA_ARGS__) +#define LOG_TRACE(...) logger_.trace(__VA_ARGS__) +#define LOG_NOTICE(...) logger_.notice(__VA_ARGS__) +#define LOG_WARNING(...) logger_.warning(__VA_ARGS__) +#define LOG_ERROR(...) logger_.err(__VA_ARGS__) + +// flash strings +using uuid::flash_string_vector; +using uuid::read_flash_string; + +#ifdef FPSTR +#undef FPSTR +#endif + +#define FJSON(x) x +// #define FJSON(x) F(x) + +// clang-format off + +#define MAKE_STR(string_name, string_literal) static constexpr const char * __str__##string_name = string_literal; + +#define FPSTR(pstr_pointer) (reinterpret_cast(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 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_ENUM(enum_name, ...) static const __FlashStringHelper * const * __pstr__L_##enum_name[] PROGMEM = {__VA_ARGS__, nullptr}; + +// clang-format on + +// load translations +#include "locale_translations.h" +#include "locale_common.h" + +#endif diff --git a/src/console.cpp b/src/console.cpp index 3ebbc8ab0..80c06df14 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -225,6 +225,7 @@ void EMSESPShell::add_console_commands() { flash_string_vector{F_(set)}, [](Shell & shell, const std::vector & arguments __attribute__((unused))) { EMSESP::webSettingsService.read([&](WebSettings & settings) { + shell.printfln(F("Language: %s"), settings.locale.c_str()); shell.printfln(F_(tx_mode_fmt), settings.tx_mode); shell.printfln(F_(bus_id_fmt), settings.ems_bus_id); shell.printfln(F_(board_profile_fmt), settings.board_profile.c_str()); @@ -280,18 +281,19 @@ void EMSESPShell::add_console_commands() { // get raw/pretty if (arguments[0] == read_flash_string(F_(raw))) { EMSESP::watch(EMSESP::WATCH_RAW); // raw - } else if (arguments[0] == read_flash_string(F_(on))) { + } else if (arguments[0] == Helpers::translated_word(FL_(on), true) || arguments[0] == read_flash_string(FL_(on)[0])) { EMSESP::watch(EMSESP::WATCH_ON); // on - } else if (arguments[0] == read_flash_string(F_(off))) { + } else if (arguments[0] == Helpers::translated_word(FL_(off), true) || arguments[0] == read_flash_string(FL_(off)[0])) { EMSESP::watch(EMSESP::WATCH_OFF); // off - } else if (arguments[0] == read_flash_string(F_(unknown))) { + } else if (arguments[0] == Helpers::translated_word(FL_(unknown), true) || arguments[0] == read_flash_string(FL_(unknown)[0])) { EMSESP::watch(EMSESP::WATCH_UNKNOWN); // unknown watch_id = WATCH_ID_NONE; } else { watch_id = Helpers::hextoint(arguments[0].c_str()); - if (watch_id && ((EMSESP::watch() == EMSESP::WATCH_OFF) || (EMSESP::watch() == EMSESP::WATCH_UNKNOWN))) { + if (watch_id > 0 && ((EMSESP::watch() == EMSESP::WATCH_OFF) || (EMSESP::watch() == EMSESP::WATCH_UNKNOWN))) { EMSESP::watch(EMSESP::WATCH_ON); // on - } else if (!watch_id) { + } else if (watch_id == 0) { + EMSESP::watch(EMSESP::WATCH_OFF); // off return; } } @@ -302,6 +304,9 @@ void EMSESPShell::add_console_commands() { } EMSESP::watch_id(watch_id); + } else { + shell.printfln(F("Invalid: use watch raw|on|off|unknown|id [id]")); + return; } uint8_t watch = EMSESP::watch(); diff --git a/src/console.h b/src/console.h index 025255944..3f5d649be 100644 --- a/src/console.h +++ b/src/console.h @@ -26,36 +26,8 @@ #include "system.h" #include "mqtt.h" -using uuid::flash_string_vector; -using uuid::read_flash_string; using uuid::console::Commands; using uuid::console::Shell; -using uuid::log::Level; - -#define LOG_DEBUG(...) logger_.debug(__VA_ARGS__) -#define LOG_INFO(...) logger_.info(__VA_ARGS__) -#define LOG_TRACE(...) logger_.trace(__VA_ARGS__) -#define LOG_NOTICE(...) logger_.notice(__VA_ARGS__) -#define LOG_WARNING(...) logger_.warning(__VA_ARGS__) -#define LOG_ERROR(...) logger_.err(__VA_ARGS__) - -// clang-format off -// strings stored 32 bit aligned on ESP8266/ESP32 -#define MAKE_STR(string_name, string_literal) static constexpr const char * __str__##string_name = string_literal; -#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 F_(string_name) FPSTR(__pstr__##string_name) -#define FSTR_(string_name) __str__##string_name -#define MAKE_PSTR_LIST(list_name, ...) static const __FlashStringHelper * const __pstr__##list_name[] PROGMEM = {__VA_ARGS__, nullptr}; -#define FL_(list_name) (__pstr__##list_name) -// clang-format on - -// localizations -#include "locale_EN.h" - -#ifdef LOCAL -#undef LOCAL -#endif static constexpr uint32_t INVALID_PASSWORD_DELAY_MS = 2000; @@ -64,19 +36,14 @@ namespace emsesp { using LogLevel = ::uuid::log::Level; using LogFacility = ::uuid::log::Facility; -enum CommandFlags : uint8_t { - - USER = 0, - ADMIN = (1 << 0), - LOCAL = (1 << 1) - -}; +#ifdef LOCAL +#undef LOCAL +#endif +enum CommandFlags : uint8_t { USER = 0, ADMIN = (1 << 0), LOCAL = (1 << 1) }; enum ShellContext : uint8_t { - MAIN = 0, SYSTEM, - }; class EMSESPShell : virtual public uuid::console::Shell { diff --git a/src/dallassensor.cpp b/src/dallassensor.cpp index 6fb35951b..030ad5474 100644 --- a/src/dallassensor.cpp +++ b/src/dallassensor.cpp @@ -36,6 +36,7 @@ void DallasSensor::start() { reload(); if (!dallas_gpio_) { + sensors_.clear(); return; // disabled if dallas gpio is 0 } @@ -152,23 +153,23 @@ void DallasSensor::loop() { if (sensor.internal_id() == get_id(addr)) { t += sensor.offset(); if (t != sensor.temperature_c) { + sensor.temperature_c = t; publish_sensor(sensor); changed_ |= true; } - sensor.temperature_c = t; - sensor.read = true; - found = true; + sensor.read = true; + found = true; break; } } // add new sensor. this will create the id string, empty name and offset if (!found && (sensors_.size() < (MAX_SENSORS - 1))) { sensors_.emplace_back(addr); - sensors_.back().temperature_c = t + sensors_.back().offset(); - sensors_.back().read = true; - changed_ = true; + sensors_.back().read = true; + changed_ = true; // look in the customization service for an optional alias or offset for that particular sensor sensors_.back().apply_customization(); + sensors_.back().temperature_c = t + sensors_.back().offset(); publish_sensor(sensors_.back()); // call publish single // sort the sensors based on name // std::sort(sensors_.begin(), sensors_.end(), [](const Sensor & a, const Sensor & b) { return a.name() < b.name(); }); @@ -363,10 +364,10 @@ bool DallasSensor::command_info(const char * value, const int8_t id, JsonObject JsonObject dataSensor = output.createNestedObject(sensor.name()); dataSensor["id"] = sensor.id(); if (Helpers::hasValue(sensor.temperature_c)) { - dataSensor["temp"] = Helpers::round2((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); + dataSensor["temp"] = Helpers::transformNumFloat((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); } } else if (Helpers::hasValue(sensor.temperature_c)) { - output[sensor.name()] = Helpers::round2((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); + output[sensor.name()] = Helpers::transformNumFloat((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); } } @@ -392,11 +393,11 @@ bool DallasSensor::get_value_info(JsonObject & output, const char * cmd, const i output["id"] = sensor.id(); output["name"] = sensor.name(); if (Helpers::hasValue(sensor.temperature_c)) { - output["value"] = Helpers::round2((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); + output["value"] = Helpers::transformNumFloat((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); } output["type"] = F_(number); - output["min"] = Helpers::round2(-55, 0, EMSESP::system_.fahrenheit() ? 2 : 0); - output["max"] = Helpers::round2(125, 0, EMSESP::system_.fahrenheit() ? 2 : 0); + output["min"] = Helpers::transformNumFloat(-55, 0, EMSESP::system_.fahrenheit() ? 2 : 0); + output["max"] = Helpers::transformNumFloat(125, 0, EMSESP::system_.fahrenheit() ? 2 : 0); output["uom"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES); output["writeable"] = false; // if we're filtering on an attribute, go find it @@ -472,10 +473,10 @@ void DallasSensor::publish_values(const bool force) { JsonObject dataSensor = doc.createNestedObject(sensor.id()); dataSensor["name"] = sensor.name(); if (has_value) { - dataSensor["temp"] = Helpers::round2((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); + dataSensor["temp"] = Helpers::transformNumFloat((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); } } else if (has_value) { - doc[sensor.name()] = Helpers::round2((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); + doc[sensor.name()] = Helpers::transformNumFloat((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); } // create the HA MQTT config diff --git a/src/default_settings.h b/src/default_settings.h index 7ea40d574..70d373aaf 100644 --- a/src/default_settings.h +++ b/src/default_settings.h @@ -15,11 +15,20 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #ifndef EMSESP_DEFAULT_SETTINGS_H #define EMSESP_DEFAULT_SETTINGS_H // GENERAL SETTINGS +#ifndef EMSESP_STANDALONE +#define EMSESP_DEFAULT_LOCALE EMSESP_LOCALE_EN // English +#else +// this is for debugging different languages in standalone version +#define EMSESP_DEFAULT_LOCALE EMSESP_LOCALE_DE // German +// #define EMSESP_DEFAULT_LOCALE EMSESP_LOCALE_EN // English +#endif + #ifndef EMSESP_DEFAULT_TX_MODE #define EMSESP_DEFAULT_TX_MODE 1 // EMS1.0 #endif @@ -199,19 +208,19 @@ // matches Web UI settings enum { - BOOL_FORMAT_ONOFF_STR = 1, - BOOL_FORMAT_ONOFF_STR_CAP, - BOOL_FORMAT_TRUEFALSE_STR, - BOOL_FORMAT_TRUEFALSE, - BOOL_FORMAT_10_STR, - BOOL_FORMAT_10 + BOOL_FORMAT_ONOFF_STR = 1, // 1 + BOOL_FORMAT_ONOFF_STR_CAP, // 2 + BOOL_FORMAT_TRUEFALSE_STR, // 3 + BOOL_FORMAT_TRUEFALSE, // 4 + BOOL_FORMAT_10_STR, // 5 + BOOL_FORMAT_10 // 6 }; enum { - ENUM_FORMAT_VALUE = 1, - ENUM_FORMAT_INDEX // 2 + ENUM_FORMAT_VALUE = 1, // 1 + ENUM_FORMAT_INDEX // 2 }; diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index 9f9a55d66..54b87ed2e 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -27,6 +27,7 @@ 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) : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { // alternative heatsource special messages + if (device_id == EMSdevice::EMS_DEVICE_ID_AM200) { register_telegram_type(0x54D, F("AmTemperatures"), false, MAKE_PF_CB(process_amTempMessage)); register_telegram_type(0x54E, F("AmStatus"), false, MAKE_PF_CB(process_amStatusMessage)); @@ -34,25 +35,43 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_telegram_type(0x550, F("AmExtra"), false, MAKE_PF_CB(process_amExtraMessage)); register_telegram_type(0x54C, F("AmSettings"), true, MAKE_PF_CB(process_amSettingMessage)); // not broadcasted - register_device_value(DeviceValueTAG::TAG_AHS, &curFlowTemp_, DeviceValueType::SHORT, FL_(div10), FL_(sysFlowTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_AHS, &retTemp_, DeviceValueType::SHORT, FL_(div10), FL_(sysRetTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_AHS, &aFlowTemp_, DeviceValueType::SHORT, FL_(div10), FL_(aFlowTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_AHS, &aRetTemp_, DeviceValueType::SHORT, FL_(div10), FL_(aRetTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_AHS, &cylTopTemp_, DeviceValueType::SHORT, FL_(div10), FL_(aCylTopTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_AHS, &cylCenterTemp_, DeviceValueType::SHORT, FL_(div10), FL_(aCylCenterTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_AHS, &cylBottomTemp_, DeviceValueType::SHORT, FL_(div10), FL_(aCylBottomTemp), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_AHS, + &curFlowTemp_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(sysFlowTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_AHS, &retTemp_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(sysRetTemp), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_AHS, &aFlowTemp_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(aFlowTemp), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_AHS, &aRetTemp_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(aRetTemp), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_AHS, + &cylTopTemp_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(aCylTopTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_AHS, + &cylCenterTemp_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(aCylCenterTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_AHS, + &cylBottomTemp_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(aCylBottomTemp), + DeviceValueUOM::DEGREES); // register_device_value(DeviceValueTAG::TAG_AHS, &valveByPass_, DeviceValueType::BOOL, nullptr, FL_(valveByPass), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_AHS, &valveBuffer_, DeviceValueType::UINT, nullptr, FL_(valveBuffer), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_AHS, &valveReturn_, DeviceValueType::UINT, nullptr, FL_(valveReturn), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_AHS, &aPumpMod_, DeviceValueType::UINT, nullptr, FL_(aPumpMod), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_AHS, &valveBuffer_, DeviceValueType::UINT, FL_(valveBuffer), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_AHS, &valveReturn_, DeviceValueType::UINT, FL_(valveReturn), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_AHS, &aPumpMod_, DeviceValueType::UINT, FL_(aPumpMod), DeviceValueUOM::PERCENT); // register_device_value(DeviceValueTAG::TAG_AHS, &heatSource_, DeviceValueType::BOOL, nullptr, FL_(heatSource), DeviceValueUOM::NONE); // Settings: register_device_value( DeviceValueTAG::TAG_AHS, &vr2Config_, DeviceValueType::ENUM, FL_(enum_vr2Config), FL_(vr2Config), DeviceValueUOM::NONE, MAKE_CF_CB(set_vr2Config)); - register_device_value( - DeviceValueTAG::TAG_AHS, &ahsActivated_, DeviceValueType::BOOL, nullptr, FL_(ahsActivated), DeviceValueUOM::NONE, MAKE_CF_CB(set_ahsActivated)); - register_device_value( - DeviceValueTAG::TAG_AHS, &aPumpConfig_, DeviceValueType::BOOL, nullptr, FL_(aPumpConfig), DeviceValueUOM::NONE, MAKE_CF_CB(set_aPumpConfig)); + register_device_value(DeviceValueTAG::TAG_AHS, &ahsActivated_, DeviceValueType::BOOL, FL_(ahsActivated), DeviceValueUOM::NONE, MAKE_CF_CB(set_ahsActivated)); + register_device_value(DeviceValueTAG::TAG_AHS, &aPumpConfig_, DeviceValueType::BOOL, FL_(aPumpConfig), DeviceValueUOM::NONE, MAKE_CF_CB(set_aPumpConfig)); register_device_value(DeviceValueTAG::TAG_AHS, &aPumpSignal_, DeviceValueType::ENUM, @@ -60,35 +79,19 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const FL_(aPumpSignal), DeviceValueUOM::NONE, MAKE_CF_CB(set_aPumpSignal)); + register_device_value(DeviceValueTAG::TAG_AHS, &aPumpMin_, DeviceValueType::UINT, FL_(aPumpMin), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_aPumpMin), 12, 50); + register_device_value(DeviceValueTAG::TAG_AHS, &tempRise_, DeviceValueType::BOOL, FL_(tempRise), DeviceValueUOM::NONE, MAKE_CF_CB(set_tempRise)); register_device_value( - DeviceValueTAG::TAG_AHS, &aPumpMin_, DeviceValueType::UINT, nullptr, FL_(aPumpMin), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_aPumpMin), 12, 50); - register_device_value(DeviceValueTAG::TAG_AHS, &tempRise_, DeviceValueType::BOOL, nullptr, FL_(tempRise), DeviceValueUOM::NONE, MAKE_CF_CB(set_tempRise)); - register_device_value(DeviceValueTAG::TAG_AHS, - &setReturnTemp_, - DeviceValueType::UINT, - nullptr, - FL_(setReturnTemp), - DeviceValueUOM::DEGREES, - MAKE_CF_CB(set_setReturnTemp), - 40, - 75); + DeviceValueTAG::TAG_AHS, &setReturnTemp_, DeviceValueType::UINT, FL_(setReturnTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_setReturnTemp), 40, 75); register_device_value( - DeviceValueTAG::TAG_AHS, &mixRuntime_, DeviceValueType::USHORT, nullptr, FL_(mixRuntime), DeviceValueUOM::SECONDS, MAKE_CF_CB(set_mixRuntime), 0, 600); - register_device_value(DeviceValueTAG::TAG_AHS, - &setFlowTemp_, - DeviceValueType::UINT, - nullptr, - FL_(setFlowTemp), - DeviceValueUOM::DEGREES, - MAKE_CF_CB(set_setFlowTemp), - 40, - 75); + DeviceValueTAG::TAG_AHS, &mixRuntime_, DeviceValueType::USHORT, FL_(mixRuntime), DeviceValueUOM::SECONDS, MAKE_CF_CB(set_mixRuntime), 0, 600); + register_device_value( + DeviceValueTAG::TAG_AHS, &setFlowTemp_, DeviceValueType::UINT, FL_(setFlowTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_setFlowTemp), 40, 75); register_device_value( DeviceValueTAG::TAG_AHS, &bufBypass_, DeviceValueType::ENUM, FL_(enum_bufBypass), FL_(bufBypass), DeviceValueUOM::NONE, MAKE_CF_CB(set_bufBypass)); register_device_value(DeviceValueTAG::TAG_AHS, &bufMixRuntime_, DeviceValueType::USHORT, - nullptr, FL_(bufMixRuntime), DeviceValueUOM::SECONDS, MAKE_CF_CB(set_bufMixRuntime), @@ -100,33 +103,31 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const DeviceValueTAG::TAG_AHS, &blockMode_, DeviceValueType::ENUM, FL_(enum_blockMode), FL_(blockMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_blockMode)); register_device_value( DeviceValueTAG::TAG_AHS, &blockTerm_, DeviceValueType::ENUM, FL_(enum_blockTerm), FL_(blockTerm), DeviceValueUOM::NONE, MAKE_CF_CB(set_blockTerm)); + register_device_value(DeviceValueTAG::TAG_AHS, &blockHyst_, DeviceValueType::INT, FL_(blockHyst), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_blockHyst), 0, 50); register_device_value( - DeviceValueTAG::TAG_AHS, &blockHyst_, DeviceValueType::INT, nullptr, FL_(blockHyst), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_blockHyst), 0, 50); - register_device_value(DeviceValueTAG::TAG_AHS, - &releaseWait_, - DeviceValueType::UINT, - nullptr, - FL_(releaseWait), - DeviceValueUOM::MINUTES, - MAKE_CF_CB(set_releaseWait), - 0, - 240); + DeviceValueTAG::TAG_AHS, &releaseWait_, DeviceValueType::UINT, FL_(releaseWait), DeviceValueUOM::MINUTES, MAKE_CF_CB(set_releaseWait), 0, 240); return; } - // cascaded heatingsources, only some values per individual heatsource (hs) + + // cascaded heating sources, only some values per individual heatsource (hs) 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 // Runtime of each heatingsource in 0x06DC, ff register_telegram_type(0x6DC + hs, F("CascadeMessage"), false, MAKE_PF_CB(process_CascadeMessage)); - register_device_value(DeviceValueTAG::TAG_HS1 + hs, &burnWorkMin_, DeviceValueType::TIME, nullptr, FL_(burnWorkMin), DeviceValueUOM::MINUTES); + register_device_value(DeviceValueTAG::TAG_HS1 + hs, &burnWorkMin_, DeviceValueType::TIME, FL_(burnWorkMin), DeviceValueUOM::MINUTES); // selBurnpower in D2 and E4 // register_telegram_type(0xD2, F("CascadePowerMessage"), false, MAKE_PF_CB(process_CascadePowerMessage)); // individual Flowtemps and powervalues for each heatingsource in E4 register_telegram_type(0xE4, F("UBAMonitorFastPlus"), false, MAKE_PF_CB(process_UBAMonitorFastPlus)); - register_device_value(DeviceValueTAG::TAG_HS1 + hs, &selFlowTemp_, DeviceValueType::UINT, nullptr, FL_(selFlowTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_HS1 + hs, &selBurnPow_, DeviceValueType::UINT, nullptr, FL_(selBurnPow), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_HS1 + hs, &curFlowTemp_, DeviceValueType::USHORT, FL_(div10), FL_(curFlowTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_HS1 + hs, &curBurnPow_, DeviceValueType::UINT, nullptr, FL_(curBurnPow), DeviceValueUOM::PERCENT); + 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, + &curFlowTemp_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(curFlowTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_HS1 + hs, &curBurnPow_, DeviceValueType::UINT, FL_(curBurnPow), DeviceValueUOM::PERCENT); return; } @@ -142,15 +143,18 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_telegram_type(0x14, F("UBATotalUptime"), true, MAKE_PF_CB(process_UBATotalUptime)); register_telegram_type(0x15, F("UBAMaintenanceData"), false, MAKE_PF_CB(process_UBAMaintenanceData)); register_telegram_type(0x1C, F("UBAMaintenanceStatus"), false, MAKE_PF_CB(process_UBAMaintenanceStatus)); + // EMS1.0 and maybe EMS+? register_telegram_type(0x18, F("UBAMonitorFast"), false, MAKE_PF_CB(process_UBAMonitorFast)); register_telegram_type(0x19, F("UBAMonitorSlow"), false, MAKE_PF_CB(process_UBAMonitorSlow)); register_telegram_type(0x1A, F("UBASetPoints"), false, MAKE_PF_CB(process_UBASetPoints)); register_telegram_type(0x35, F("UBAFlags"), false, MAKE_PF_CB(process_UBAFlags)); + // only EMS 1.0 register_telegram_type(0x16, F("UBAParameters"), true, MAKE_PF_CB(process_UBAParameters)); register_telegram_type(0x33, F("UBAParameterWW"), true, MAKE_PF_CB(process_UBAParameterWW)); register_telegram_type(0x34, F("UBAMonitorWW"), false, MAKE_PF_CB(process_UBAMonitorWW)); + // not ems1.0, but HT3 if (model() != EMSdevice::EMS_DEVICE_FLAG_EMS) { register_telegram_type(0x26, F("UBASettingsWW"), true, MAKE_PF_CB(process_UBASettingsWW)); @@ -185,93 +189,100 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_telegram_type(0xBB, F("HybridHp"), true, MAKE_PF_CB(process_HybridHp)); } */ + // reset is a command uses a dummy variable which is always zero, shown as blank, but provides command enum options register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &reset_, DeviceValueType::CMD, FL_(enum_reset), FL_(reset), DeviceValueUOM::NONE, MAKE_CF_CB(set_reset)); has_update(reset_, 0); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingActive_, DeviceValueType::BOOL, nullptr, FL_(heatingActive), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &tapwaterActive_, DeviceValueType::BOOL, nullptr, FL_(tapwaterActive), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingActive_, DeviceValueType::BOOL, FL_(heatingActive), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &tapwaterActive_, DeviceValueType::BOOL, FL_(tapwaterActive), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &selFlowTemp_, DeviceValueType::UINT, FL_(selFlowTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_flow_temp)); register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &selFlowTemp_, DeviceValueType::UINT, nullptr, FL_(selFlowTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_flow_temp)); + DeviceValueTAG::TAG_DEVICE_DATA, &selBurnPow_, DeviceValueType::UINT, FL_(selBurnPow), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_burn_power), 0, 254); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingPumpMod_, DeviceValueType::UINT, FL_(heatingPumpMod), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingPump2Mod_, DeviceValueType::UINT, FL_(heatingPump2Mod), DeviceValueUOM::PERCENT); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, - &selBurnPow_, - DeviceValueType::UINT, - nullptr, - FL_(selBurnPow), - DeviceValueUOM::PERCENT, - MAKE_CF_CB(set_burn_power), - 0, - 254); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingPumpMod_, DeviceValueType::UINT, nullptr, FL_(heatingPumpMod), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingPump2Mod_, DeviceValueType::UINT, nullptr, FL_(heatingPump2Mod), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &outdoorTemp_, DeviceValueType::SHORT, FL_(div10), FL_(outdoorTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &curFlowTemp_, DeviceValueType::USHORT, FL_(div10), FL_(curFlowTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &retTemp_, DeviceValueType::USHORT, FL_(div10), FL_(retTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &switchTemp_, DeviceValueType::USHORT, FL_(div10), FL_(switchTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &sysPress_, DeviceValueType::UINT, FL_(div10), FL_(sysPress), DeviceValueUOM::BAR); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &boilTemp_, DeviceValueType::USHORT, FL_(div10), FL_(boilTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &exhaustTemp_, DeviceValueType::USHORT, FL_(div10), FL_(exhaustTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &burnGas_, DeviceValueType::BOOL, nullptr, FL_(burnGas), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &burnGas2_, DeviceValueType::BOOL, nullptr, FL_(burnGas2), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &flameCurr_, DeviceValueType::USHORT, FL_(div10), FL_(flameCurr), DeviceValueUOM::UA); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingPump_, DeviceValueType::BOOL, nullptr, FL_(heatingPump), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &fanWork_, DeviceValueType::BOOL, nullptr, FL_(fanWork), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ignWork_, DeviceValueType::BOOL, nullptr, FL_(ignWork), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &oilPreHeat_, DeviceValueType::BOOL, nullptr, FL_(oilPreHeat), DeviceValueUOM::NONE); + &outdoorTemp_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(outdoorTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &curFlowTemp_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(curFlowTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &retTemp_, DeviceValueType::USHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(retTemp), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &switchTemp_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(switchTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &sysPress_, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(sysPress), DeviceValueUOM::BAR); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &boilTemp_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(boilTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &exhaustTemp_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(exhaustTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &burnGas_, DeviceValueType::BOOL, FL_(burnGas), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &burnGas2_, DeviceValueType::BOOL, FL_(burnGas2), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &flameCurr_, DeviceValueType::USHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(flameCurr), DeviceValueUOM::UA); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingPump_, DeviceValueType::BOOL, FL_(heatingPump), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &fanWork_, DeviceValueType::BOOL, FL_(fanWork), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ignWork_, DeviceValueType::BOOL, FL_(ignWork), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &oilPreHeat_, DeviceValueType::BOOL, FL_(oilPreHeat), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingActivated_, DeviceValueType::BOOL, - nullptr, FL_(heatingActivated), DeviceValueUOM::NONE, MAKE_CF_CB(set_heating_activated)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingTemp_, DeviceValueType::UINT, - nullptr, FL_(heatingTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_heating_temp)); - register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &pumpModMax_, DeviceValueType::UINT, nullptr, FL_(pumpModMax), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_max_pump)); - register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &pumpModMin_, DeviceValueType::UINT, nullptr, FL_(pumpModMin), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_min_pump)); - register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &pumpDelay_, DeviceValueType::UINT, nullptr, FL_(pumpDelay), DeviceValueUOM::MINUTES, MAKE_CF_CB(set_pump_delay)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pumpModMax_, DeviceValueType::UINT, FL_(pumpModMax), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_max_pump)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pumpModMin_, DeviceValueType::UINT, FL_(pumpModMin), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_min_pump)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pumpDelay_, DeviceValueType::UINT, FL_(pumpDelay), DeviceValueUOM::MINUTES, MAKE_CF_CB(set_pump_delay)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &burnMinPeriod_, DeviceValueType::UINT, - nullptr, FL_(burnMinPeriod), DeviceValueUOM::MINUTES, MAKE_CF_CB(set_burn_period)); - register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &burnMinPower_, DeviceValueType::UINT, nullptr, FL_(burnMinPower), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_min_power)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, - &burnMaxPower_, + &burnMinPower_, DeviceValueType::UINT, - nullptr, - FL_(burnMaxPower), + FL_(burnMinPower), DeviceValueUOM::PERCENT, - MAKE_CF_CB(set_max_power), - 0, - 254); + MAKE_CF_CB(set_min_power)); register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &boilHystOn_, DeviceValueType::INT, nullptr, FL_(boilHystOn), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_hyst_on)); - register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &boilHystOff_, DeviceValueType::INT, nullptr, FL_(boilHystOff), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_hyst_off)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &setFlowTemp_, DeviceValueType::UINT, nullptr, FL_(setFlowTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &setBurnPow_, DeviceValueType::UINT, nullptr, FL_(setBurnPow), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &curBurnPow_, DeviceValueType::UINT, nullptr, FL_(curBurnPow), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &burnStarts_, DeviceValueType::ULONG, nullptr, FL_(burnStarts), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &burnWorkMin_, DeviceValueType::TIME, nullptr, FL_(burnWorkMin), DeviceValueUOM::MINUTES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &burn2WorkMin_, DeviceValueType::TIME, nullptr, FL_(burn2WorkMin), DeviceValueUOM::MINUTES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatWorkMin_, DeviceValueType::TIME, nullptr, FL_(heatWorkMin), DeviceValueUOM::MINUTES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &UBAuptime_, DeviceValueType::TIME, nullptr, FL_(UBAuptime), DeviceValueUOM::MINUTES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &lastCode_, DeviceValueType::STRING, nullptr, FL_(lastCode), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &serviceCode_, DeviceValueType::STRING, nullptr, FL_(serviceCode), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &serviceCodeNumber_, DeviceValueType::USHORT, nullptr, FL_(serviceCodeNumber), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &maintenanceMessage_, DeviceValueType::STRING, nullptr, FL_(maintenanceMessage), DeviceValueUOM::NONE); + DeviceValueTAG::TAG_DEVICE_DATA, &burnMaxPower_, DeviceValueType::UINT, FL_(burnMaxPower), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_max_power), 0, 254); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &boilHystOn_, DeviceValueType::INT, FL_(boilHystOn), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_hyst_on)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &boilHystOff_, DeviceValueType::INT, FL_(boilHystOff), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_hyst_off)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &setFlowTemp_, DeviceValueType::UINT, FL_(setFlowTemp), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &setBurnPow_, DeviceValueType::UINT, FL_(setBurnPow), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &curBurnPow_, DeviceValueType::UINT, FL_(curBurnPow), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &burnStarts_, DeviceValueType::ULONG, FL_(burnStarts), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &burnWorkMin_, DeviceValueType::TIME, FL_(burnWorkMin), DeviceValueUOM::MINUTES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &burn2WorkMin_, DeviceValueType::TIME, FL_(burn2WorkMin), DeviceValueUOM::MINUTES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatWorkMin_, DeviceValueType::TIME, FL_(heatWorkMin), DeviceValueUOM::MINUTES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &UBAuptime_, DeviceValueType::TIME, FL_(UBAuptime), DeviceValueUOM::MINUTES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &lastCode_, DeviceValueType::STRING, FL_(lastCode), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &serviceCode_, DeviceValueType::STRING, FL_(serviceCode), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &serviceCodeNumber_, DeviceValueType::USHORT, FL_(serviceCodeNumber), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &maintenanceMessage_, DeviceValueType::STRING, FL_(maintenanceMessage), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &maintenanceType_, DeviceValueType::ENUM, @@ -282,7 +293,6 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &maintenanceTime_, DeviceValueType::USHORT, - nullptr, FL_(maintenanceTime), DeviceValueUOM::HOURS, MAKE_CF_CB(set_maintenancetime)); @@ -296,14 +306,12 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &emergencyOps_, DeviceValueType::BOOL, - nullptr, FL_(emergencyOps), DeviceValueUOM::NONE, MAKE_CF_CB(set_emergency_ops)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &emergencyTemp_, DeviceValueType::UINT, - nullptr, FL_(emergencyTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_emergency_temp), @@ -336,7 +344,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyCostRatio_, DeviceValueType::UINT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(energyCostRatio), DeviceValueUOM::NONE, MAKE_CF_CB(set_energyCostRatio), @@ -345,7 +353,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &fossileFactor_, DeviceValueType::UINT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(fossileFactor), DeviceValueUOM::NONE, MAKE_CF_CB(set_fossileFactor), @@ -354,7 +362,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &electricFactor_, DeviceValueType::UINT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(electricFactor), DeviceValueUOM::NONE, MAKE_CF_CB(set_electricFactor), @@ -382,81 +390,110 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const */ // heatpump info if (model() == EMS_DEVICE_FLAG_HEATPUMP) { - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &upTimeControl_, DeviceValueType::TIME, FL_(div60), FL_(upTimeControl), DeviceValueUOM::MINUTES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &upTimeCompHeating_, DeviceValueType::TIME, FL_(div60), FL_(upTimeCompHeating), DeviceValueUOM::MINUTES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &upTimeCompCooling_, DeviceValueType::TIME, FL_(div60), FL_(upTimeCompCooling), DeviceValueUOM::MINUTES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &upTimeCompWw_, DeviceValueType::TIME, FL_(div60), FL_(upTimeCompWw), DeviceValueUOM::MINUTES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &upTimeCompPool_, DeviceValueType::TIME, FL_(div60), FL_(upTimeCompPool), DeviceValueUOM::MINUTES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &totalCompStarts_, DeviceValueType::ULONG, nullptr, FL_(totalCompStarts), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingStarts_, DeviceValueType::ULONG, nullptr, FL_(heatingStarts), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &coolingStarts_, DeviceValueType::ULONG, nullptr, FL_(coolingStarts), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwStarts2_, DeviceValueType::ULONG, nullptr, FL_(wwStarts2), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolStarts_, DeviceValueType::ULONG, nullptr, FL_(poolStarts), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgConsTotal_, DeviceValueType::ULONG, nullptr, FL_(nrgConsTotal), DeviceValueUOM::KWH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgConsCompTotal_, DeviceValueType::ULONG, nullptr, FL_(nrgConsCompTotal), DeviceValueUOM::KWH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgConsCompHeating_, DeviceValueType::ULONG, nullptr, FL_(nrgConsCompHeating), DeviceValueUOM::KWH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgConsCompWw_, DeviceValueType::ULONG, nullptr, FL_(nrgConsCompWw), DeviceValueUOM::KWH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgConsCompCooling_, DeviceValueType::ULONG, nullptr, FL_(nrgConsCompCooling), DeviceValueUOM::KWH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgConsCompPool_, DeviceValueType::ULONG, nullptr, FL_(nrgConsCompPool), DeviceValueUOM::KWH); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, - &auxElecHeatNrgConsTotal_, - DeviceValueType::ULONG, - nullptr, - FL_(auxElecHeatNrgConsTotal), - DeviceValueUOM::KWH); + &upTimeControl_, + DeviceValueType::TIME, + DeviceValueNumOp::DV_NUMOP_DIV60, + FL_(upTimeControl), + DeviceValueUOM::MINUTES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &upTimeCompHeating_, + DeviceValueType::TIME, + DeviceValueNumOp::DV_NUMOP_DIV60, + FL_(upTimeCompHeating), + DeviceValueUOM::MINUTES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &upTimeCompCooling_, + DeviceValueType::TIME, + DeviceValueNumOp::DV_NUMOP_DIV60, + FL_(upTimeCompCooling), + DeviceValueUOM::MINUTES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &upTimeCompWw_, + DeviceValueType::TIME, + DeviceValueNumOp::DV_NUMOP_DIV60, + FL_(upTimeCompWw), + DeviceValueUOM::MINUTES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &upTimeCompPool_, + DeviceValueType::TIME, + DeviceValueNumOp::DV_NUMOP_DIV60, + FL_(upTimeCompPool), + DeviceValueUOM::MINUTES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &totalCompStarts_, DeviceValueType::ULONG, FL_(totalCompStarts), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingStarts_, DeviceValueType::ULONG, FL_(heatingStarts), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &coolingStarts_, DeviceValueType::ULONG, FL_(coolingStarts), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwStarts2_, DeviceValueType::ULONG, FL_(wwStarts2), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolStarts_, DeviceValueType::ULONG, FL_(poolStarts), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgConsTotal_, DeviceValueType::ULONG, FL_(nrgConsTotal), DeviceValueUOM::KWH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgConsCompTotal_, DeviceValueType::ULONG, FL_(nrgConsCompTotal), DeviceValueUOM::KWH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgConsCompHeating_, DeviceValueType::ULONG, FL_(nrgConsCompHeating), DeviceValueUOM::KWH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgConsCompWw_, DeviceValueType::ULONG, FL_(nrgConsCompWw), DeviceValueUOM::KWH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgConsCompCooling_, DeviceValueType::ULONG, FL_(nrgConsCompCooling), DeviceValueUOM::KWH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgConsCompPool_, DeviceValueType::ULONG, FL_(nrgConsCompPool), DeviceValueUOM::KWH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &auxElecHeatNrgConsTotal_, DeviceValueType::ULONG, FL_(auxElecHeatNrgConsTotal), DeviceValueUOM::KWH); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &auxElecHeatNrgConsHeating_, DeviceValueType::ULONG, - nullptr, FL_(auxElecHeatNrgConsHeating), DeviceValueUOM::KWH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, - &auxElecHeatNrgConsWW_, - DeviceValueType::ULONG, - nullptr, - FL_(auxElecHeatNrgConsWW), - DeviceValueUOM::KWH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, - &auxElecHeatNrgConsPool_, - DeviceValueType::ULONG, - nullptr, - FL_(auxElecHeatNrgConsPool), - DeviceValueUOM::KWH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgSuppTotal_, DeviceValueType::ULONG, nullptr, FL_(nrgSuppTotal), DeviceValueUOM::KWH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgSuppHeating_, DeviceValueType::ULONG, nullptr, FL_(nrgSuppHeating), DeviceValueUOM::KWH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgSuppWw_, DeviceValueType::ULONG, nullptr, FL_(nrgSuppWw), DeviceValueUOM::KWH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgSuppCooling_, DeviceValueType::ULONG, nullptr, FL_(nrgSuppCooling), DeviceValueUOM::KWH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgSuppPool_, DeviceValueType::ULONG, nullptr, FL_(nrgSuppPool), DeviceValueUOM::KWH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPower_, DeviceValueType::UINT, FL_(div10), FL_(hpPower), DeviceValueUOM::KW); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCompOn_, DeviceValueType::BOOL, nullptr, FL_(hpCompOn), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &auxElecHeatNrgConsWW_, DeviceValueType::ULONG, FL_(auxElecHeatNrgConsWW), DeviceValueUOM::KWH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &auxElecHeatNrgConsPool_, DeviceValueType::ULONG, FL_(auxElecHeatNrgConsPool), DeviceValueUOM::KWH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgSuppTotal_, DeviceValueType::ULONG, FL_(nrgSuppTotal), DeviceValueUOM::KWH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgSuppHeating_, DeviceValueType::ULONG, FL_(nrgSuppHeating), DeviceValueUOM::KWH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgSuppWw_, DeviceValueType::ULONG, FL_(nrgSuppWw), DeviceValueUOM::KWH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgSuppCooling_, DeviceValueType::ULONG, FL_(nrgSuppCooling), DeviceValueUOM::KWH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgSuppPool_, DeviceValueType::ULONG, FL_(nrgSuppPool), DeviceValueUOM::KWH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPower_, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpPower), DeviceValueUOM::KW); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCompOn_, DeviceValueType::BOOL, FL_(hpCompOn), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpActivity_, DeviceValueType::ENUM, FL_(enum_hpactivity), FL_(hpActivity), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpHeatingOn_, DeviceValueType::BOOL, nullptr, FL_(hpHeatingOn), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCoolingOn_, DeviceValueType::BOOL, nullptr, FL_(hpCoolingOn), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpWwOn_, DeviceValueType::BOOL, nullptr, FL_(hpWwOn), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPoolOn_, DeviceValueType::BOOL, nullptr, FL_(hpPoolOn), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpBrinePumpSpd_, DeviceValueType::UINT, nullptr, FL_(hpBrinePumpSpd), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpSwitchValve_, DeviceValueType::BOOL, nullptr, FL_(hpSwitchValve), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCompSpd_, DeviceValueType::UINT, nullptr, FL_(hpCompSpd), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCircSpd_, DeviceValueType::UINT, nullptr, FL_(hpCircSpd), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpBrineIn_, DeviceValueType::SHORT, FL_(div10), FL_(hpBrineIn), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpBrineOut_, DeviceValueType::SHORT, FL_(div10), FL_(hpBrineOut), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpSuctionGas_, DeviceValueType::SHORT, FL_(div10), FL_(hpSuctionGas), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpHotGas_, DeviceValueType::SHORT, FL_(div10), FL_(hpHotGas), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTc0_, DeviceValueType::SHORT, FL_(div10), FL_(hpTc0), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTc1_, DeviceValueType::SHORT, FL_(div10), FL_(hpTc1), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTc3_, DeviceValueType::SHORT, FL_(div10), FL_(hpTc3), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTr3_, DeviceValueType::SHORT, FL_(div10), FL_(hpTr3), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTr4_, DeviceValueType::SHORT, FL_(div10), FL_(hpTr4), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTr5_, DeviceValueType::SHORT, FL_(div10), FL_(hpTr5), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTr6_, DeviceValueType::SHORT, FL_(div10), FL_(hpTr6), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTr7_, DeviceValueType::SHORT, FL_(div10), FL_(hpTr7), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTl2_, DeviceValueType::SHORT, FL_(div10), FL_(hpTl2), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPl1_, DeviceValueType::SHORT, FL_(div10), FL_(hpPl1), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPh1_, DeviceValueType::SHORT, FL_(div10), FL_(hpPh1), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpHeatingOn_, DeviceValueType::BOOL, FL_(hpHeatingOn), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCoolingOn_, DeviceValueType::BOOL, FL_(hpCoolingOn), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpWwOn_, DeviceValueType::BOOL, FL_(hpWwOn), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPoolOn_, DeviceValueType::BOOL, FL_(hpPoolOn), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpBrinePumpSpd_, DeviceValueType::UINT, FL_(hpBrinePumpSpd), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpSwitchValve_, DeviceValueType::BOOL, FL_(hpSwitchValve), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCompSpd_, DeviceValueType::UINT, FL_(hpCompSpd), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCircSpd_, DeviceValueType::UINT, FL_(hpCircSpd), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &hpBrineIn_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(hpBrineIn), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &hpBrineOut_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(hpBrineOut), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &hpSuctionGas_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(hpSuctionGas), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &hpHotGas_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(hpHotGas), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTc0_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTc0), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTc1_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTc1), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTc3_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTc3), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTr3_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTr3), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTr4_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTr4), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTr5_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTr5), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTr6_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTr6), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTr7_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTr7), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTl2_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTl2), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPl1_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpPl1), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPh1_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpPh1), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolSetTemp_, DeviceValueType::UINT, - FL_(div2), + DeviceValueNumOp::DV_NUMOP_DIV2, FL_(poolSetTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_pool_temp)); @@ -466,25 +503,21 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwTapActivated_, DeviceValueType::BOOL, - nullptr, FL_(wwtapactivated), DeviceValueUOM::NONE, MAKE_CF_CB(set_tapwarmwater_activated)); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwSetTemp_, DeviceValueType::UINT, nullptr, FL_(wwSetTemp), DeviceValueUOM::DEGREES); - register_device_value( - DeviceValueTAG::TAG_BOILER_DATA_WW, &wwSelTemp_, DeviceValueType::UINT, nullptr, FL_(wwSelTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_ww_temp)); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwSetTemp_, DeviceValueType::UINT, FL_(wwSetTemp), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwSelTemp_, DeviceValueType::UINT, FL_(wwSelTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_ww_temp)); register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwSelTempLow_, DeviceValueType::UINT, - nullptr, FL_(wwSelTempLow), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_ww_temp_low)); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwSelTempOff_, DeviceValueType::UINT, nullptr, FL_(wwSelTempOff), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwSelTempOff_, DeviceValueType::UINT, FL_(wwSelTempOff), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwSelTempSingle_, DeviceValueType::UINT, - nullptr, FL_(wwSelTempSingle), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_ww_temp_single)); @@ -506,7 +539,6 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwFlowTempOffset_, DeviceValueType::UINT, - nullptr, FL_(wwFlowTempOffset), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_ww_flowTempOffset), @@ -515,44 +547,30 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwChargeOptimization_, DeviceValueType::BOOL, - nullptr, FL_(wwChargeOptimization), DeviceValueUOM::NONE, MAKE_CF_CB(set_ww_chargeOptimization)); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, - &wwMaxPower_, - DeviceValueType::UINT, - nullptr, - FL_(wwMaxPower), - DeviceValueUOM::PERCENT, - MAKE_CF_CB(set_ww_maxpower), - 0, - 254); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, - &wwMaxTemp_, - DeviceValueType::UINT, - nullptr, - FL_(wwMaxTemp), - DeviceValueUOM::DEGREES, - MAKE_CF_CB(set_ww_maxtemp), - 0, - 70); + register_device_value( + DeviceValueTAG::TAG_BOILER_DATA_WW, &wwMaxPower_, DeviceValueType::UINT, FL_(wwMaxPower), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_ww_maxpower), 0, 254); + register_device_value( + DeviceValueTAG::TAG_BOILER_DATA_WW, &wwMaxTemp_, DeviceValueType::UINT, FL_(wwMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_ww_maxtemp), 0, 70); register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwCircPump_, DeviceValueType::BOOL, - nullptr, FL_(wwCircPump), DeviceValueUOM::NONE, MAKE_CF_CB(set_ww_circulation_pump)); register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwChargeType_, DeviceValueType::ENUM, FL_(enum_charge), FL_(wwChargeType), DeviceValueUOM::NONE); - register_device_value( - DeviceValueTAG::TAG_BOILER_DATA_WW, &wwHystOn_, DeviceValueType::INT, nullptr, FL_(wwHystOn), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_ww_hyst_on)); - register_device_value( - DeviceValueTAG::TAG_BOILER_DATA_WW, &wwHystOff_, DeviceValueType::INT, nullptr, FL_(wwHystOff), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_ww_hyst_off)); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwHystOn_, DeviceValueType::INT, FL_(wwHystOn), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_ww_hyst_on)); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, + &wwHystOff_, + DeviceValueType::INT, + FL_(wwHystOff), + DeviceValueUOM::DEGREES_R, + MAKE_CF_CB(set_ww_hyst_off)); register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwDisinfectionTemp_, DeviceValueType::UINT, - nullptr, FL_(wwDisinfectionTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_ww_disinfect_temp)); @@ -563,45 +581,76 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const FL_(wwCircMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_ww_circulation_mode)); - register_device_value( - DeviceValueTAG::TAG_BOILER_DATA_WW, &wwCirc_, DeviceValueType::BOOL, nullptr, FL_(wwCirc), DeviceValueUOM::NONE, MAKE_CF_CB(set_ww_circulation)); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwCurTemp_, DeviceValueType::USHORT, FL_(div10), FL_(wwCurTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwCurTemp2_, DeviceValueType::USHORT, FL_(div10), FL_(wwCurTemp2), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwCurFlow_, DeviceValueType::UINT, FL_(div10), FL_(wwCurFlow), DeviceValueUOM::LMIN); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwStorageTemp1_, DeviceValueType::USHORT, FL_(div10), FL_(wwStorageTemp1), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwStorageTemp2_, DeviceValueType::USHORT, FL_(div10), FL_(wwStorageTemp2), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwCirc_, DeviceValueType::BOOL, FL_(wwCirc), DeviceValueUOM::NONE, MAKE_CF_CB(set_ww_circulation)); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, + &wwCurTemp_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(wwCurTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, + &wwCurTemp2_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(wwCurTemp2), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, + &wwCurFlow_, + DeviceValueType::UINT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(wwCurFlow), + DeviceValueUOM::LMIN); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, + &wwStorageTemp1_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(wwStorageTemp1), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, + &wwStorageTemp2_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(wwStorageTemp2), + DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwActivated_, DeviceValueType::BOOL, - nullptr, FL_(wwActivated), DeviceValueUOM::NONE, MAKE_CF_CB(set_ww_activated)); - register_device_value( - DeviceValueTAG::TAG_BOILER_DATA_WW, &wwOneTime_, DeviceValueType::BOOL, nullptr, FL_(wwOneTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_ww_onetime)); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwOneTime_, DeviceValueType::BOOL, FL_(wwOneTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_ww_onetime)); register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwDisinfect_, DeviceValueType::BOOL, - nullptr, FL_(wwDisinfecting), DeviceValueUOM::NONE, MAKE_CF_CB(set_ww_disinfect)); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwCharging_, DeviceValueType::BOOL, nullptr, FL_(wwCharging), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwRecharging_, DeviceValueType::BOOL, nullptr, FL_(wwRecharging), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwTempOK_, DeviceValueType::BOOL, nullptr, FL_(wwTempOK), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwActive_, DeviceValueType::BOOL, nullptr, FL_(wwActive), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &ww3wayValve_, DeviceValueType::BOOL, nullptr, FL_(ww3wayValve), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwSetPumpPower_, DeviceValueType::UINT, nullptr, FL_(wwSetPumpPower), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwMixerTemp_, DeviceValueType::USHORT, FL_(div10), FL_(wwMixerTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwCylMiddleTemp_, DeviceValueType::USHORT, FL_(div10), FL_(wwCylMiddleTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwStarts_, DeviceValueType::ULONG, nullptr, FL_(wwStarts), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwWorkM_, DeviceValueType::TIME, nullptr, FL_(wwWorkM), DeviceValueUOM::MINUTES); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwCharging_, DeviceValueType::BOOL, FL_(wwCharging), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwRecharging_, DeviceValueType::BOOL, FL_(wwRecharging), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwTempOK_, DeviceValueType::BOOL, FL_(wwTempOK), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwActive_, DeviceValueType::BOOL, FL_(wwActive), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &ww3wayValve_, DeviceValueType::BOOL, FL_(ww3wayValve), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwSetPumpPower_, DeviceValueType::UINT, FL_(wwSetPumpPower), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, + &wwMixerTemp_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(wwMixerTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, + &wwCylMiddleTemp_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(wwCylMiddleTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwStarts_, DeviceValueType::ULONG, FL_(wwStarts), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wwWorkM_, DeviceValueType::TIME, FL_(wwWorkM), DeviceValueUOM::MINUTES); // fetch some initial data EMSESP::send_read_request(0x10, device_id); // read last errorcode on start (only published on errors) EMSESP::send_read_request(0x11, device_id); // read last errorcode on start (only published on errors) - EMSESP::send_read_request(0x15, device_id); // read maintenace data on start (only published on change) - EMSESP::send_read_request(0x1C, device_id); // read maintenace status on start (only published on change) + EMSESP::send_read_request(0x15, device_id); // read maintenance data on start (only published on change) + EMSESP::send_read_request(0x1C, device_id); // read maintenance status on start (only published on change) EMSESP::send_read_request(0xC2, device_id); // read last errorcode on start (only published on errors) } @@ -1286,9 +1335,6 @@ void Boiler::process_amCommandMessage(std::shared_ptr telegram) // pos 6: boiler blocking 0-off, 1-on } -// 0x0550 AM200 broadcasted message, all 27 bytes unkown -// Rx: 60 00 FF 00 04 50 00 FF 00 FF FF 00 0D 00 01 00 00 00 00 01 03 01 00 03 00 2D 19 C8 02 94 00 4A -// Rx: 60 00 FF 19 04 50 00 FF FF 39 void Boiler::process_amExtraMessage(std::shared_ptr telegram) { } @@ -1458,6 +1504,11 @@ bool Boiler::set_releaseWait(const char * value, const int8_t id) { return true; } + +// 0x0550 AM200 broadcasted message, all 27 bytes unkown +// Rx: 60 00 FF 00 04 50 00 FF 00 FF FF 00 0D 00 01 00 00 00 00 01 03 01 00 03 00 2D 19 C8 02 94 00 4A +// Rx: 60 00 FF 19 04 50 00 FF FF 39 + /* * Hybrid heatpump with telegram 0xBB is readable and writeable in boiler and thermostat * thermostat always overwrites settings in boiler @@ -2079,7 +2130,7 @@ bool Boiler::set_maintenance(const char * value, const int8_t id) { std::string s; if (Helpers::value2string(value, s)) { - if (s == Helpers::toLower(read_flash_string(F_(reset)))) { + if (s == Helpers::translated_word(FL_(reset))) { // LOG_INFO(F("Reset boiler maintenance message")); write_command(0x05, 0x08, 0xFF, 0x1C); return true; diff --git a/src/devices/boiler.h b/src/devices/boiler.h index ff5b1cfe5..78ea8c729 100644 --- a/src/devices/boiler.h +++ b/src/devices/boiler.h @@ -227,15 +227,11 @@ class Boiler : public EMSdevice { int8_t blockHyst_; // pos 14?: Hyst. for bolier block (K) uint8_t releaseWait_; // pos 15: Boiler release wait time (min) - - - /* - * Hybrid heatpump with telegram 0xBB is readable and writeable in boiler and thermostat - * thermostat always overwrites settings in boiler - * enable settings here if no thermostat is used in system - * -// HybridHP + // Hybrid heatpump with telegram 0xBB is readable and writeable in boiler and thermostat + // thermostat always overwrites settings in boiler + //enable settings here if no thermostat is used in system + // HybridHP uint8_t hybridStrategy_; // cost = 2, temperature = 3, mix = 4 int8_t switchOverTemp_; // degrees uint8_t energyCostRatio_; // is *10 @@ -243,7 +239,7 @@ class Boiler : public EMSdevice { uint8_t electricFactor_; // is * 10 uint8_t delayBoiler_; // minutes uint8_t tempDiffBoiler_; // relative temperature degrees - */ + */ void process_UBAParameterWW(std::shared_ptr telegram); void process_UBAMonitorFast(std::shared_ptr telegram); diff --git a/src/devices/controller.cpp b/src/devices/controller.cpp index 0922cf764..03e90a4a4 100644 --- a/src/devices/controller.cpp +++ b/src/devices/controller.cpp @@ -27,7 +27,7 @@ Controller::Controller(uint8_t device_type, uint8_t device_id, uint8_t product_i // IVT broadcasts Thermostat time from controller (0x09) if display is off. if ((flags & 0x0F) == EMS_DEVICE_FLAG_IVT) { register_telegram_type(0x06, F("RCTime"), false, MAKE_PF_CB(process_dateTime)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, FL_(dateTime), DeviceValueUOM::NONE); } } diff --git a/src/devices/generic.cpp b/src/devices/generic.cpp index c992195ac..81d17defb 100644 --- a/src/devices/generic.cpp +++ b/src/devices/generic.cpp @@ -29,7 +29,12 @@ Generic::Generic(uint8_t device_type, uint8_t device_id, uint8_t product_id, con // RF-Sensor 0x40 sending temperature in telegram 0x435, see https://github.com/emsesp/EMS-ESP32/issues/103 if (device_id == 0x40) { register_telegram_type(0x435, F("RFSensorMessage"), false, MAKE_PF_CB(process_RFSensorMessage)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &rfTemp_, DeviceValueType::SHORT, FL_(div10), FL_(RFTemp), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &rfTemp_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(RFTemp), + DeviceValueUOM::DEGREES); } } diff --git a/src/devices/heatpump.cpp b/src/devices/heatpump.cpp index 9ada1ce1b..cbb5d1ec2 100644 --- a/src/devices/heatpump.cpp +++ b/src/devices/heatpump.cpp @@ -29,8 +29,8 @@ Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, c register_telegram_type(0x047B, F("HP2"), false, MAKE_PF_CB(process_HPMonitor2)); // device values - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &airHumidity_, DeviceValueType::UINT, nullptr, FL_(airHumidity), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dewTemperature_, DeviceValueType::UINT, nullptr, FL_(dewTemperature), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &airHumidity_, DeviceValueType::UINT, FL_(airHumidity), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dewTemperature_, DeviceValueType::UINT, FL_(dewTemperature), DeviceValueUOM::DEGREES); } /* diff --git a/src/devices/mixer.cpp b/src/devices/mixer.cpp index b6954880b..cbde2d4bb 100644 --- a/src/devices/mixer.cpp +++ b/src/devices/mixer.cpp @@ -30,9 +30,14 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c if (flags == EMSdevice::EMS_DEVICE_FLAG_MP) { register_telegram_type(0x5BA, F("HpPoolStatus"), true, MAKE_PF_CB(process_HpPoolStatus)); type_ = Type::MP; - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolTemp_, DeviceValueType::SHORT, FL_(div10), FL_(poolTemp), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &poolTemp_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(poolTemp), + DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShuntStatus_, DeviceValueType::ENUM, FL_(enum_shunt), FL_(poolShuntStatus), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShunt_, DeviceValueType::UINT, nullptr, FL_(poolShunt), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShunt_, DeviceValueType::UINT, FL_(poolShunt), DeviceValueUOM::PERCENT); } // EMS+ @@ -43,10 +48,10 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c type_ = Type::HC; hc_ = device_id - 0x20 + 1; uint8_t tag = DeviceValueTAG::TAG_HC1 + hc_ - 1; - register_device_value(tag, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempHc), DeviceValueUOM::DEGREES); - register_device_value(tag, &status_, DeviceValueType::INT, nullptr, FL_(mixerStatus), DeviceValueUOM::PERCENT); - register_device_value(tag, &flowSetTemp_, DeviceValueType::UINT, nullptr, FL_(flowSetTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_flowSetTemp)); - register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, FL_(pumpStatus), DeviceValueUOM::NONE, MAKE_CF_CB(set_pump)); + register_device_value(tag, &flowTempHc_, DeviceValueType::USHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(flowTempHc), DeviceValueUOM::DEGREES); + register_device_value(tag, &status_, DeviceValueType::INT, FL_(mixerStatus), DeviceValueUOM::PERCENT); + 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)); } 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 + 0x0313, F("MMPLUSConfigMessage_WWC"), true, MAKE_PF_CB(process_MMPLUSConfigMessage_WWC)); @@ -54,25 +59,23 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c type_ = Type::WWC; hc_ = device_id - 0x28 + 1; uint8_t tag = DeviceValueTAG::TAG_WWC1 + hc_ - 1; - register_device_value(tag, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(wwTemp), DeviceValueUOM::DEGREES); - register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, FL_(wwPumpStatus), DeviceValueUOM::NONE); - register_device_value(tag, &status_, DeviceValueType::INT, nullptr, FL_(wwTempStatus), DeviceValueUOM::NONE); + register_device_value(tag, &flowTempHc_, DeviceValueType::USHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(wwTemp), DeviceValueUOM::DEGREES); + register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, FL_(wwPumpStatus), DeviceValueUOM::NONE); + register_device_value(tag, &status_, DeviceValueType::INT, FL_(wwTempStatus), DeviceValueUOM::NONE); - register_device_value(tag, &wwMaxTemp_, DeviceValueType::UINT, nullptr, FL_(wwMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwMaxTemp)); - register_device_value(tag, &wwDiffTemp_, DeviceValueType::INT, nullptr, FL_(wwDiffTemp), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwDiffTemp)); + register_device_value(tag, &wwMaxTemp_, DeviceValueType::UINT, FL_(wwMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwMaxTemp)); + register_device_value(tag, &wwDiffTemp_, DeviceValueType::INT, FL_(wwDiffTemp), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwDiffTemp)); register_device_value(tag, &wwDisinfectionTemp_, DeviceValueType::UINT, - nullptr, FL_(wwDisinfectionTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwDisinfectionTemp)); - register_device_value(tag, &wwReducedTemp_, DeviceValueType::UINT, nullptr, FL_(wwRedTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwReducedTemp)); - register_device_value(tag, &wwRequiredTemp_, DeviceValueType::UINT, nullptr, FL_(wwRequiredTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwRequiredTemp)); + register_device_value(tag, &wwReducedTemp_, DeviceValueType::UINT, FL_(wwRedTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwReducedTemp)); + register_device_value(tag, &wwRequiredTemp_, DeviceValueType::UINT, FL_(wwRequiredTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwRequiredTemp)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwCircPump_, DeviceValueType::BOOL, - nullptr, FL_(wwCircPump), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwCircPump)); @@ -88,13 +91,20 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c type_ = Type::HC; hc_ = device_id - 0x20 + 1; uint8_t tag = DeviceValueTAG::TAG_HC1 + hc_ - 1; - register_device_value(tag, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempHc), DeviceValueUOM::DEGREES); - register_device_value(tag, &status_, DeviceValueType::INT, nullptr, FL_(mixerStatus), DeviceValueUOM::PERCENT); - register_device_value(tag, &flowSetTemp_, DeviceValueType::UINT, nullptr, FL_(flowSetTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_flowSetTemp)); - register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, FL_(pumpStatus), DeviceValueUOM::NONE, MAKE_CF_CB(set_pump)); - register_device_value(tag, &activated_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::NONE, MAKE_CF_CB(set_activated)); - register_device_value( - tag, &setValveTime_, DeviceValueType::UINT, FL_(mul10), FL_(mixerSetTime), DeviceValueUOM::SECONDS, MAKE_CF_CB(set_setValveTime), 10, 120); + register_device_value(tag, &flowTempHc_, DeviceValueType::USHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(flowTempHc), DeviceValueUOM::DEGREES); + register_device_value(tag, &status_, DeviceValueType::INT, FL_(mixerStatus), DeviceValueUOM::PERCENT); + 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, &activated_, DeviceValueType::BOOL, FL_(activated), DeviceValueUOM::NONE, MAKE_CF_CB(set_activated)); + register_device_value(tag, + &setValveTime_, + DeviceValueType::UINT, + DeviceValueNumOp::DV_NUMOP_MUL10, + FL_(mixerSetTime), + DeviceValueUOM::SECONDS, + MAKE_CF_CB(set_setValveTime), + 10, + 120); } // HT3 @@ -107,26 +117,23 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c type_ = Type::WWC; hc_ = device_id - 0x40 + 1; uint8_t tag = DeviceValueTAG::TAG_WWC9 + hc_ - 1; - register_device_value(tag, &wwSelTemp_, DeviceValueType::UINT, nullptr, FL_(wwSelTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwSelTemp)); - register_device_value(tag, &wwCurTemp_1_, DeviceValueType::USHORT, FL_(div10), FL_(wwCurTemp), DeviceValueUOM::DEGREES); - register_device_value(tag, &wwCurTemp_2_, DeviceValueType::USHORT, FL_(div10), FL_(wwCurTemp2), DeviceValueUOM::DEGREES); - register_device_value(tag, &HydrTemp_, DeviceValueType::USHORT, FL_(div10), FL_(hydrTemp), DeviceValueUOM::DEGREES); - register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, FL_(pumpStatus), DeviceValueUOM::NONE); - register_device_value( - tag, &wwFlowTempOffset_, DeviceValueType::UINT, nullptr, FL_(wwFlowTempOffset), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwFlowTempOffset)); - register_device_value(tag, &wwHystOn_, DeviceValueType::INT, nullptr, FL_(wwHystOn), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwHystOn)); - register_device_value(tag, &wwHystOff_, DeviceValueType::INT, nullptr, FL_(wwHystOff), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwHystOff)); + register_device_value(tag, &wwSelTemp_, DeviceValueType::UINT, FL_(wwSelTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwSelTemp)); + register_device_value(tag, &wwCurTemp_1_, DeviceValueType::USHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(wwCurTemp), DeviceValueUOM::DEGREES); + register_device_value(tag, &wwCurTemp_2_, DeviceValueType::USHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(wwCurTemp2), DeviceValueUOM::DEGREES); + register_device_value(tag, &HydrTemp_, DeviceValueType::USHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hydrTemp), DeviceValueUOM::DEGREES); + register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, FL_(pumpStatus), DeviceValueUOM::NONE); + register_device_value(tag, &wwFlowTempOffset_, DeviceValueType::UINT, FL_(wwFlowTempOffset), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwFlowTempOffset)); + register_device_value(tag, &wwHystOn_, DeviceValueType::INT, FL_(wwHystOn), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwHystOn)); + register_device_value(tag, &wwHystOff_, DeviceValueType::INT, FL_(wwHystOff), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_wwHystOff)); register_device_value(tag, &wwDisinfectionTemp_, DeviceValueType::UINT, - nullptr, FL_(wwDisinfectionTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwDisinfectionTemp)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwCircPump_, DeviceValueType::BOOL, - nullptr, FL_(wwCircPump), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwCircPump)); @@ -138,11 +145,11 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c type_ = Type::HC; hc_ = device_id - 0x20 + 1; uint8_t tag = DeviceValueTAG::TAG_HC1 + hc_ - 1; - register_device_value(tag, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempHc), DeviceValueUOM::DEGREES); - register_device_value(tag, &status_, DeviceValueType::INT, nullptr, FL_(mixerStatus), DeviceValueUOM::PERCENT); - register_device_value(tag, &flowSetTemp_, DeviceValueType::UINT, nullptr, FL_(flowSetTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_flowSetTemp)); - register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, FL_(pumpStatus), DeviceValueUOM::NONE, MAKE_CF_CB(set_pump)); - register_device_value(tag, &flowTempVf_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempVf), DeviceValueUOM::DEGREES); + register_device_value(tag, &flowTempHc_, DeviceValueType::USHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(flowTempHc), DeviceValueUOM::DEGREES); + register_device_value(tag, &status_, DeviceValueType::INT, FL_(mixerStatus), DeviceValueUOM::PERCENT); + 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, &flowTempVf_, DeviceValueType::USHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(flowTempVf), DeviceValueUOM::DEGREES); } } } diff --git a/src/devices/solar.cpp b/src/devices/solar.cpp index 186b06f90..85b483eed 100644 --- a/src/devices/solar.cpp +++ b/src/devices/solar.cpp @@ -71,48 +71,68 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c // device values... // special case for a SM100 DHW device_id with 0x2A where it's not actual a solar module if (device_id == 0x2A) { - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwTemp_1_, DeviceValueType::USHORT, FL_(div10), FL_(wwTemp1), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwTemp_3_, DeviceValueType::USHORT, FL_(div10), FL_(wwTemp3), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwTemp_4_, DeviceValueType::USHORT, FL_(div10), FL_(wwTemp4), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwTemp_5_, DeviceValueType::USHORT, FL_(div10), FL_(wwTemp5), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwTemp_7_, DeviceValueType::USHORT, FL_(div10), FL_(wwTemp7), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwPump_, DeviceValueType::BOOL, nullptr, FL_(wwPump), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, + &wwTemp_1_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(wwTemp1), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, + &wwTemp_3_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(wwTemp3), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, + &wwTemp_4_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(wwTemp4), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, + &wwTemp_5_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(wwTemp5), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, + &wwTemp_7_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(wwTemp7), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwPump_, DeviceValueType::BOOL, FL_(wwPump), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwMaxTemp_, DeviceValueType::UINT, - nullptr, FL_(wwMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwMaxTemp)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwSelTemp_, DeviceValueType::UINT, - nullptr, FL_(wwSelTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwSelTemp)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwRedTemp_, DeviceValueType::UINT, - nullptr, FL_(wwRedTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwRedTemp)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwDailyTemp_, DeviceValueType::UINT, - nullptr, FL_(wwDailyTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwDailyTemp)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwDisinfectionTemp_, DeviceValueType::UINT, - nullptr, FL_(wwDisinfectionTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwDisinfectionTemp)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwCirc_, DeviceValueType::BOOL, nullptr, FL_(wwCirc), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwCirc)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwCirc_, DeviceValueType::BOOL, FL_(wwCirc), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwCirc)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwCircMode_, DeviceValueType::ENUM, @@ -123,181 +143,238 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwKeepWarm_, DeviceValueType::BOOL, - nullptr, FL_(wwKeepWarm), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwKeepWarm)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwStatus2_, DeviceValueType::ENUM, FL_(enum_wwStatus2), FL_(wwStatus2), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwPumpMod_, DeviceValueType::UINT, nullptr, FL_(wwPumpMod), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwFlow_, DeviceValueType::UINT, FL_(div10), FL_(wwFlow), DeviceValueUOM::LMIN); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwPumpMod_, DeviceValueType::UINT, FL_(wwPumpMod), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, + &wwFlow_, + DeviceValueType::UINT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(wwFlow), + DeviceValueUOM::LMIN); return; } // common solar values for all modules (except dhw) - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collectorTemp_, DeviceValueType::SHORT, FL_(div10), FL_(collectorTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylBottomTemp_, DeviceValueType::SHORT, FL_(div10), FL_(cylBottomTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPump_, DeviceValueType::BOOL, nullptr, FL_(solarPump), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pumpWorkTime_, DeviceValueType::TIME, nullptr, FL_(pumpWorkTime), DeviceValueUOM::MINUTES); - register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &cylMaxTemp_, DeviceValueType::UINT, nullptr, FL_(cylMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_cylMaxTemp)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylHeated_, DeviceValueType::BOOL, nullptr, FL_(cylHeated), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &collectorTemp_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(collectorTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &cylBottomTemp_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(cylBottomTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPump_, DeviceValueType::BOOL, FL_(solarPump), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pumpWorkTime_, DeviceValueType::TIME, FL_(pumpWorkTime), DeviceValueUOM::MINUTES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylMaxTemp_, DeviceValueType::UINT, FL_(cylMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_cylMaxTemp)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collectorShutdown_, DeviceValueType::BOOL, FL_(collectorShutdown), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylHeated_, DeviceValueType::BOOL, FL_(cylHeated), DeviceValueUOM::NONE); // values per device flag if (flags == EMSdevice::EMS_DEVICE_FLAG_SM10) { - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPumpMod_, DeviceValueType::UINT, nullptr, FL_(solarPumpMod), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPumpMod_, DeviceValueType::UINT, FL_(solarPumpMod), DeviceValueUOM::PERCENT); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPumpMinMod_, DeviceValueType::UINT, - nullptr, FL_(pumpMinMod), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_PumpMinMod)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPumpTurnonDiff_, DeviceValueType::UINT, - nullptr, FL_(solarPumpTurnonDiff), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_TurnonDiff)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPumpTurnoffDiff_, DeviceValueType::UINT, - nullptr, FL_(solarPumpTurnoffDiff), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_TurnoffDiff)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPower_, DeviceValueType::SHORT, nullptr, FL_(solarPower), DeviceValueUOM::W); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH); - register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &maxFlow_, DeviceValueType::UINT, FL_(div10), FL_(maxFlow), DeviceValueUOM::LMIN, MAKE_CF_CB(set_SM10MaxFlow)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPower_, DeviceValueType::SHORT, FL_(solarPower), DeviceValueUOM::W); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &energyLastHour_, + DeviceValueType::ULONG, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(energyLastHour), + DeviceValueUOM::WH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &maxFlow_, + DeviceValueType::UINT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(maxFlow), + DeviceValueUOM::LMIN, + MAKE_CF_CB(set_SM10MaxFlow)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwMinTemp_, DeviceValueType::UINT, - nullptr, FL_(wwMinTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwMinTemp)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarIsEnabled_, DeviceValueType::BOOL, - nullptr, FL_(solarIsEnabled), DeviceValueUOM::NONE, MAKE_CF_CB(set_solarEnabled)); - /* unknown values for testing and logging. Used by MichaelDvP + /* + // unknown values for testing and logging. Used by MichaelDvP register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &setting3_, DeviceValueType::UINT, nullptr, FL_(setting3), DeviceValueUOM::NONE, MAKE_CF_CB(set_CollectorMaxTemp)); + DeviceValueTAG::TAG_DEVICE_DATA, &setting3_, DeviceValueType::UINT, FL_(setting3), DeviceValueUOM::NONE, MAKE_CF_CB(set_CollectorMaxTemp)); register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &setting4_, DeviceValueType::UINT, nullptr, FL_(setting4), DeviceValueUOM::NONE, MAKE_CF_CB(set_CollectorMinTemp)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data11_, DeviceValueType::UINT, nullptr, FL_(data11), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data12_, DeviceValueType::UINT, nullptr, FL_(data12), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data1_, DeviceValueType::UINT, nullptr, FL_(data1), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data0_, DeviceValueType::UINT, nullptr, FL_(data0), DeviceValueUOM::NONE); + DeviceValueTAG::TAG_DEVICE_DATA, &setting4_, DeviceValueType::UINT, FL_(setting4), DeviceValueUOM::NONE, MAKE_CF_CB(set_CollectorMinTemp)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data11_, DeviceValueType::UINT, FL_(data11), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data12_, DeviceValueType::UINT, FL_(data12), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data1_, DeviceValueType::UINT, FL_(data1), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data0_, DeviceValueType::UINT, FL_(data0), DeviceValueUOM::NONE); */ } if (flags == EMSdevice::EMS_DEVICE_FLAG_ISM) { - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylMiddleTemp_, DeviceValueType::SHORT, FL_(div10), FL_(cylMiddleTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &retHeatAssist_, DeviceValueType::SHORT, FL_(div10), FL_(retHeatAssist), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1Valve_, DeviceValueType::BOOL, nullptr, FL_(m1Valve), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &cylMiddleTemp_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(cylMiddleTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &retHeatAssist_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(retHeatAssist), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1Valve_, DeviceValueType::BOOL, FL_(m1Valve), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &energyLastHour_, + DeviceValueType::ULONG, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(energyLastHour), + DeviceValueUOM::WH); } if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) { - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPumpMod_, DeviceValueType::UINT, nullptr, FL_(solarPumpMod), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPumpMod_, DeviceValueType::UINT, FL_(solarPumpMod), DeviceValueUOM::PERCENT); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPumpMinMod_, DeviceValueType::UINT, - FL_(mul5), + DeviceValueNumOp::DV_NUMOP_MUL5, FL_(pumpMinMod), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_PumpMinMod)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPumpTurnonDiff_, DeviceValueType::UINT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(solarPumpTurnonDiff), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_TurnonDiff)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPumpTurnoffDiff_, DeviceValueType::UINT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(solarPumpTurnoffDiff), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_TurnoffDiff)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collector2Temp_, DeviceValueType::SHORT, FL_(div10), FL_(collector2Temp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylMiddleTemp_, DeviceValueType::SHORT, FL_(div10), FL_(cylMiddleTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &retHeatAssist_, DeviceValueType::SHORT, FL_(div10), FL_(retHeatAssist), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1Valve_, DeviceValueType::BOOL, nullptr, FL_(m1Valve), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1Power_, DeviceValueType::UINT, nullptr, FL_(m1Power), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPump2_, DeviceValueType::BOOL, nullptr, FL_(solarPump2), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPump2Mod_, DeviceValueType::UINT, nullptr, FL_(solarPump2Mod), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylBottomTemp2_, DeviceValueType::SHORT, FL_(div10), FL_(cyl2BottomTemp), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &collector2Temp_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(collector2Temp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &cylMiddleTemp_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(cylMiddleTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &retHeatAssist_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(retHeatAssist), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1Valve_, DeviceValueType::BOOL, FL_(m1Valve), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1Power_, DeviceValueType::UINT, FL_(m1Power), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPump2_, DeviceValueType::BOOL, FL_(solarPump2), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPump2Mod_, DeviceValueType::UINT, FL_(solarPump2Mod), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &cylBottomTemp2_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(cyl2BottomTemp), + DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatExchangerTemp_, DeviceValueType::SHORT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(heatExchangerTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylPumpMod_, DeviceValueType::UINT, nullptr, FL_(cylPumpMod), DeviceValueUOM::PERCENT); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &valveStatus_, DeviceValueType::BOOL, nullptr, FL_(valveStatus), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylHeated_, DeviceValueType::BOOL, nullptr, FL_(cylHeated), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylPumpMod_, DeviceValueType::UINT, FL_(cylPumpMod), DeviceValueUOM::PERCENT); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &valveStatus_, DeviceValueType::BOOL, FL_(valveStatus), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylHeated_, DeviceValueType::BOOL, FL_(cylHeated), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collectorShutdown_, DeviceValueType::BOOL, FL_(collectorShutdown), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collectorMaxTemp_, DeviceValueType::UINT, - nullptr, FL_(collectorMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_CollectorMaxTemp)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collectorMinTemp_, DeviceValueType::UINT, - nullptr, FL_(collectorMinTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_CollectorMinTemp)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyToday_, DeviceValueType::ULONG, nullptr, FL_(energyToday), DeviceValueUOM::WH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyTotal_, DeviceValueType::ULONG, FL_(div10), FL_(energyTotal), DeviceValueUOM::KWH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pump2WorkTime_, DeviceValueType::TIME, nullptr, FL_(pump2WorkTime), DeviceValueUOM::MINUTES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1WorkTime_, DeviceValueType::TIME, nullptr, FL_(m1WorkTime), DeviceValueUOM::MINUTES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &energyLastHour_, + DeviceValueType::ULONG, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(energyLastHour), + DeviceValueUOM::WH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyToday_, DeviceValueType::ULONG, FL_(energyToday), DeviceValueUOM::WH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &energyTotal_, + DeviceValueType::ULONG, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(energyTotal), + DeviceValueUOM::KWH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pump2WorkTime_, DeviceValueType::TIME, FL_(pump2WorkTime), DeviceValueUOM::MINUTES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1WorkTime_, DeviceValueType::TIME, FL_(m1WorkTime), DeviceValueUOM::MINUTES); // register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cyl2MaxTemp_, DeviceValueType::UINT, nullptr, FL_(cyl2MaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_cyl2MaxTemp)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatTransferSystem_, DeviceValueType::BOOL, - nullptr, FL_(heatTransferSystem), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatTransferSystem)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &externalCyl_, DeviceValueType::BOOL, - nullptr, FL_(externalCyl), DeviceValueUOM::NONE, MAKE_CF_CB(set_externalCyl)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &thermalDisinfect_, DeviceValueType::BOOL, - nullptr, FL_(thermalDisinfect), DeviceValueUOM::NONE, MAKE_CF_CB(set_thermalDisinfect)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatMetering_, DeviceValueType::BOOL, - nullptr, FL_(heatMetering), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatMetering)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarIsEnabled_, DeviceValueType::BOOL, - nullptr, FL_(activated), DeviceValueUOM::NONE, MAKE_CF_CB(set_solarEnabled)); @@ -314,7 +391,6 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c DeviceValueTAG::TAG_DEVICE_DATA, &solarPumpKick_, DeviceValueType::BOOL, - nullptr, FL_(solarPumpKick), DeviceValueUOM::NONE, MAKE_CF_CB(set_solarPumpKick)); @@ -322,7 +398,6 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c DeviceValueTAG::TAG_DEVICE_DATA, &plainWaterMode_, DeviceValueType::BOOL, - nullptr, FL_(plainWaterMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_plainWaterMode)); @@ -330,7 +405,6 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c DeviceValueTAG::TAG_DEVICE_DATA, &doubleMatchFlow_, DeviceValueType::BOOL, - nullptr, FL_(doubleMatchFlow), DeviceValueUOM::NONE, MAKE_CF_CB(set_doubleMatchFlow)); @@ -338,21 +412,20 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPump2MinMod_, DeviceValueType::UINT, - nullptr, FL_(pump2MinMod), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_Pump2MinMod)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPump2TurnonDiff_, DeviceValueType::UINT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(solarPump2TurnonDiff), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_TurnonDiff2)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPump2TurnoffDiff_, DeviceValueType::UINT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(solarPump2TurnoffDiff), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_TurnoffDiff2)); @@ -360,7 +433,6 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c DeviceValueTAG::TAG_DEVICE_DATA, &solarPump2Kick_, DeviceValueType::BOOL, - nullptr, FL_(solarPump2Kick), DeviceValueUOM::NONE, MAKE_CF_CB(set_solarPump2Kick)); @@ -369,14 +441,13 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &climateZone_, DeviceValueType::UINT, - nullptr, FL_(climateZone), DeviceValueUOM::NONE, MAKE_CF_CB(set_climateZone)); // climate zone identifier register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collector1Area_, DeviceValueType::USHORT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(collector1Area), DeviceValueUOM::SQM, MAKE_CF_CB(set_collector1Area)); // Area of collector field 1 @@ -390,7 +461,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collector2Area_, DeviceValueType::USHORT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(collector2Area), DeviceValueUOM::SQM, MAKE_CF_CB(set_collector2Area)); // Area of collector field 2 @@ -408,11 +479,31 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c FL_(cylPriority), DeviceValueUOM::NONE, MAKE_CF_CB(set_cylPriority)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatCntFlowTemp_, DeviceValueType::USHORT, FL_(div10), FL_(heatCntFlowTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatCntRetTemp_, DeviceValueType::USHORT, FL_(div10), FL_(heatCntRetTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatCnt_, DeviceValueType::UINT, nullptr, FL_(heatCnt), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &swapFlowTemp_, DeviceValueType::USHORT, FL_(div10), FL_(swapFlowTemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &swapRetTemp_, DeviceValueType::USHORT, FL_(div10), FL_(swapRetTemp), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &heatCntFlowTemp_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(heatCntFlowTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &heatCntRetTemp_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(heatCntRetTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatCnt_, DeviceValueType::UINT, FL_(heatCnt), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &swapFlowTemp_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(swapFlowTemp), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &swapRetTemp_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(swapRetTemp), + DeviceValueUOM::DEGREES); } } diff --git a/src/devices/switch.cpp b/src/devices/switch.cpp index 29fc78490..12deddba7 100644 --- a/src/devices/switch.cpp +++ b/src/devices/switch.cpp @@ -29,9 +29,14 @@ Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const register_telegram_type(0x9D, F("WM10SetMessage"), false, MAKE_PF_CB(process_WM10SetMessage)); register_telegram_type(0x1E, F("WM10TempMessage"), false, MAKE_PF_CB(process_WM10TempMessage)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &activated_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempHc), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &status_, DeviceValueType::INT, nullptr, FL_(status), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &activated_, DeviceValueType::BOOL, FL_(activated), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &flowTempHc_, + DeviceValueType::USHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(flowTempHc), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &status_, DeviceValueType::INT, FL_(status), DeviceValueUOM::NONE); } // message 0x9D switch on/off diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 3e8806fae..352ad9cd8 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -36,11 +36,13 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i register_device_values(); // register device values for common values (not heating circuit) return; // no values to add } + // common telegram handlers register_telegram_type(EMS_TYPE_RCOutdoorTemp, F("RCOutdoorTemp"), false, MAKE_PF_CB(process_RCOutdoorTemp)); register_telegram_type(EMS_TYPE_RCTime, F("RCTime"), false, MAKE_PF_CB(process_RCTime)); register_telegram_type(0xA2, F("RCError"), false, MAKE_PF_CB(process_RCError)); register_telegram_type(0x12, F("RCErrorMessage"), false, MAKE_PF_CB(process_RCErrorMessage)); + register_telegram_type(0x13, F("RCErrorMessage2"), false, MAKE_PF_CB(process_RCErrorMessage)); // RC10 if (model == EMSdevice::EMS_DEVICE_FLAG_RC10) { monitor_typeids = {0xB1}; @@ -100,7 +102,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i register_telegram_type(monitor_typeids[i], F("RC30Monitor"), false, MAKE_PF_CB(process_RC30Monitor)); register_telegram_type(set_typeids[i], F("RC30Set"), false, MAKE_PF_CB(process_RC30Set)); register_telegram_type(curve_typeids[i], F("RC30Temp"), false, MAKE_PF_CB(process_RC30Temp)); - register_telegram_type(timer_typeids[i], F("RC30Timer"), false, MAKE_PF_CB(process_RC30Timer)); + register_telegram_type(timer_typeids[i], F("RC30Timer"), false, MAKE_PF_CB(process_RC35Timer)); } register_telegram_type(EMS_TYPE_RC30wwSettings, F("RC30WWSettings"), true, MAKE_PF_CB(process_RC30wwSettings)); register_telegram_type(0x38, F("WWTimer"), true, MAKE_PF_CB(process_RC35wwTimer)); @@ -347,6 +349,7 @@ std::shared_ptr Thermostat::heating_circuit(std::sha // set the flag saying we want its data during the next auto fetch // monitor is broadcasted, but not frequently in some thermostats (IVT, #356) + if (monitor_typeids.size()) { toggle_fetch(monitor_typeids[hc_num - 1], toggle_); } @@ -489,53 +492,6 @@ uint8_t Thermostat::HeatingCircuit::get_mode_type() const { return HeatingCircuit::Mode::DAY; } -// decodes the thermostat mode based on the thermostat type -// works with both modes and mode_types -std::string Thermostat::mode_tostring(uint8_t mode) { - switch (mode) { - case HeatingCircuit::Mode::OFF: - return read_flash_string(F_(off)); - case HeatingCircuit::Mode::MANUAL: - return read_flash_string(F_(manual)); - case HeatingCircuit::Mode::DAY: - return read_flash_string(F_(day)); - case HeatingCircuit::Mode::NIGHT: - return read_flash_string(F_(night)); - case HeatingCircuit::Mode::ECO: - return read_flash_string(F_(eco)); - case HeatingCircuit::Mode::COMFORT: - return read_flash_string(F_(comfort)); - case HeatingCircuit::Mode::HEAT: - return read_flash_string(F_(heat)); - case HeatingCircuit::Mode::HOLIDAY: - return read_flash_string(F_(holiday)); - case HeatingCircuit::Mode::NOFROST: - return read_flash_string(F_(nofrost)); - case HeatingCircuit::Mode::AUTO: - return read_flash_string(F_(auto)); - case HeatingCircuit::Mode::SUMMER: - return read_flash_string(F_(summer)); - case HeatingCircuit::Mode::OFFSET: - return read_flash_string(F_(offset)); - case HeatingCircuit::Mode::DESIGN: - return read_flash_string(F_(design)); - case HeatingCircuit::Mode::MINFLOW: - return read_flash_string(F_(minflow)); - case HeatingCircuit::Mode::MAXFLOW: - return read_flash_string(F_(maxflow)); - case HeatingCircuit::Mode::ROOMINFLUENCE: - return read_flash_string(F_(roominfluence[0])); - case HeatingCircuit::Mode::FLOWOFFSET: - return read_flash_string(F_(flowtempoffset[0])); - case HeatingCircuit::Mode::TEMPAUTO: - return read_flash_string(F_(tempauto)); - case HeatingCircuit::Mode::NOREDUCE: - return read_flash_string(F_(noreduce)); - default: - return read_flash_string(F_(unknown)); - } -} - // type 0xB1 - data from the RC10 thermostat (0x17) // Data: 04 23 00 BA 00 00 00 BA void Thermostat::process_RC10Monitor(std::shared_ptr telegram) { @@ -630,14 +586,16 @@ void Thermostat::process_RC20Timer(std::shared_ptr telegram) { uint8_t temp = telegram->message_data[0] & 7; uint8_t time = telegram->message_data[1]; - std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day]); + // we use EN settings for the day abbreviation + std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day][0]); + // std::string sday = Helpers::translated_word(FL_(enum_dayOfWeek)[day]); + if (day == 7) { snprintf(data, sizeof(data), "%02d not_set", no); } else { snprintf(data, sizeof(data), "%02d %s %02d:%02d T%d", no, sday.c_str(), time / 6, 10 * (time % 6), temp); } - strlcpy(hc->switchtime1, data, sizeof(hc->switchtime1)); - has_update(hc->switchtime1); // always publish + has_update(hc->switchtime1, data, sizeof(hc->switchtime1)); } } @@ -828,19 +786,27 @@ void Thermostat::process_RC35wwTimer(std::shared_ptr telegram) { uint8_t on = telegram->message_data[0] & 1; uint8_t time = telegram->message_data[1]; - std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day]); - char data[sizeof(wwSwitchTime_)]; + char data[sizeof(wwSwitchTime_)]; + // we use EN settings for the day abbreviation + std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day][0]); + // std::string sday = Helpers::translated_word(FL_(enum_dayOfWeek)[day]); if (day == 7) { snprintf(data, sizeof(data), "%02d not_set", no); } else { - snprintf(data, sizeof(data), "%02d %s %02d:%02d %s", no, sday.c_str(), time / 6, 10 * (time % 6), on ? "on" : "off"); + snprintf(data, + sizeof(data), + "%02d %s %02d:%02d %s", + no, + sday.c_str(), + time / 6, + 10 * (time % 6), + // on ? (Helpers::translated_word(FL_(on))).c_str() : (Helpers::translated_word(FL_(off))).c_str()); + on ? "on" : "off"); } if (telegram->type_id == 0x38) { - strlcpy(wwSwitchTime_, data, sizeof(wwSwitchTime_)); - has_update(wwSwitchTime_); + has_update(wwSwitchTime_, data, sizeof(wwSwitchTime_)); } else { - strlcpy(wwCircSwitchTime_, data, sizeof(wwCircSwitchTime_)); - has_update(wwCircSwitchTime_); + has_update(wwCircSwitchTime_, data, sizeof(wwCircSwitchTime_)); } if (is_fetch(telegram->type_id)) { toggle_fetch(telegram->type_id, false); // dont fetch again @@ -942,6 +908,7 @@ void Thermostat::process_CRFMonitor(std::shared_ptr telegram) { } // type 0x02A5 - data from the Nefit RC1010/3000 thermostat (0x18) and RC300/310s on 0x10 +// Rx: 10 0B FF 00 01 A5 80 00 01 30 23 00 30 28 01 E7 03 03 01 01 E7 02 33 00 00 11 01 03 FF FF 00 04 void Thermostat::process_RC300Monitor(std::shared_ptr telegram) { std::shared_ptr hc = heating_circuit(telegram); if (hc == nullptr) { @@ -977,6 +944,7 @@ void Thermostat::process_RC300Monitor(std::shared_ptr telegram) } // type 0x02B9 EMS+ for reading from RC300/RC310 thermostat +// Thermostat(0x10) -> Me(0x0B), RC300Set(0x2B9), data: FF 2E 2A 26 1E 02 4E FF FF 00 1C 01 E1 20 01 0F 05 00 00 02 1F void Thermostat::process_RC300Set(std::shared_ptr telegram) { std::shared_ptr hc = heating_circuit(telegram); if (hc == nullptr) { @@ -1202,64 +1170,6 @@ void Thermostat::process_RC30Temp(std::shared_ptr telegram) { has_update(telegram, hc->holidaytemp, 7); // is * 2 } -// type 0x3F (HC1) - timer setting for RC30 -void Thermostat::process_RC30Timer(std::shared_ptr telegram) { - std::shared_ptr hc = heating_circuit(telegram); - if (hc == nullptr) { - return; - } - - if ((telegram->message_length == 2 && telegram->offset < 83 && !(telegram->offset & 1)) - || (!telegram->offset && telegram->message_length > 1 && !strlen(hc->switchtime1))) { - char data[sizeof(hc->switchtime1)]; - uint8_t no = telegram->offset / 2; - uint8_t day = telegram->message_data[0] >> 5; - uint8_t temp = telegram->message_data[0] & 7; - uint8_t time = telegram->message_data[1]; - - std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day]); - if (day == 7) { - snprintf(data, sizeof(data), "%02d not_set", no); - } else { - snprintf(data, sizeof(data), "%02d %s %02d:%02d T%d", no, sday.c_str(), time / 6, 10 * (time % 6), temp); - } - strlcpy(hc->switchtime1, data, sizeof(hc->switchtime1)); - has_update(hc->switchtime1); // always publish - } - - has_update(telegram, hc->program, 84); // 0 .. 10, 0-userprogram 1, 10-userprogram 2 - has_update(telegram, hc->pause, 85); // time in hours - has_update(telegram, hc->party, 86); // time in hours - - if (telegram->message_length + telegram->offset >= 92 && telegram->offset <= 87) { - char data[sizeof(hc->vacation)]; - snprintf(data, - sizeof(data), - "%02d.%02d.%04d-%02d.%02d.%04d", - telegram->message_data[87 - telegram->offset], - telegram->message_data[88 - telegram->offset], - telegram->message_data[89 - telegram->offset] + 2000, - telegram->message_data[90 - telegram->offset], - telegram->message_data[91 - telegram->offset], - telegram->message_data[92 - telegram->offset] + 2000); - has_update(hc->vacation, data, sizeof(hc->vacation)); - } - - if (telegram->message_length + telegram->offset >= 98 && telegram->offset <= 93) { - char data[sizeof(hc->holiday)]; - snprintf(data, - sizeof(data), - "%02d.%02d.%04d-%02d.%02d.%04d", - telegram->message_data[93 - telegram->offset], - telegram->message_data[94 - telegram->offset], - telegram->message_data[95 - telegram->offset] + 2000, - telegram->message_data[96 - telegram->offset], - telegram->message_data[97 - telegram->offset], - telegram->message_data[98 - telegram->offset] + 2000); - has_update(hc->holiday, data, sizeof(hc->holiday)); - } -} - // type 0x3E (HC1), 0x48 (HC2), 0x52 (HC3), 0x5C (HC4) - data from the RC35 thermostat (0x10) - 16 bytes void Thermostat::process_RC35Monitor(std::shared_ptr telegram) { // exit if the 15th byte (second from last) is 0x00, which I think is calculated flow setpoint temperature @@ -1349,12 +1259,16 @@ void Thermostat::process_RC35Timer(std::shared_ptr telegram) { char data[sizeof(hc->switchtime1)]; uint8_t no = telegram->offset / 2; uint8_t day = telegram->message_data[0] >> 5; - uint8_t on = telegram->message_data[0] & 1; + uint8_t on = model() == EMS_DEVICE_FLAG_RC30 ? telegram->message_data[0] & 7 : telegram->message_data[0] & 1; uint8_t time = telegram->message_data[1]; - std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day]); + // we use EN settings for the day abbreviation + std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day][0]); + // std::string sday = Helpers::translated_word(FL_(enum_dayOfWeek)[day]); if (day == 7) { snprintf(data, sizeof(data), "%02d not_set", no); + } else if (model() == EMS_DEVICE_FLAG_RC30) { + snprintf(data, sizeof(data), "%02d %s %02d:%02d T%d", no, sday.c_str(), time / 6, 10 * (time % 6), on); } else { snprintf(data, sizeof(data), "%02d %s %02d:%02d %s", no, sday.c_str(), time / 6, 10 * (time % 6), on ? "on" : "off"); } @@ -1479,7 +1393,7 @@ void Thermostat::process_RCError(std::shared_ptr telegram) { has_update(errorCode_, code, sizeof(errorCode_)); } -// 0x12 error log +// 0x12 and 0x13 error log // RCErrorMessage(0x12), data: 32 32 03 30 95 0A 0A 15 18 00 01 19 32 32 03 30 95 0A 09 05 18 00 01 19 31 38 03 // RCErrorMessage(0x12), data: 39 95 08 09 0F 19 00 01 17 64 31 03 34 95 07 10 08 00 00 01 70 (offset 27) void Thermostat::process_RCErrorMessage(std::shared_ptr telegram) { @@ -1488,12 +1402,13 @@ void Thermostat::process_RCErrorMessage(std::shared_ptr telegram } // data: displaycode(2), errornumber(2), year, month, hour, day, minute, duration(2), src-addr - if (telegram->message_data[4] & 0x80) { // valid date - char code[sizeof(lastCode_)] = {0}; - uint16_t codeNo = EMS_VALUE_USHORT_NOTSET; - code[0] = telegram->message_data[0]; - code[1] = telegram->message_data[1]; - code[2] = 0; + if (telegram->message_data[4] & 0x80) { // valid date + static uint32_t lastCodeDate_ = 0; // last code date + char code[sizeof(lastCode_)] = {0}; + uint16_t codeNo = EMS_VALUE_USHORT_NOTSET; + code[0] = telegram->message_data[0]; + code[1] = telegram->message_data[1]; + code[2] = 0; telegram->read_value(codeNo, 2); uint16_t year = (telegram->message_data[4] & 0x7F) + 2000; uint8_t month = telegram->message_data[5]; @@ -1501,9 +1416,14 @@ void Thermostat::process_RCErrorMessage(std::shared_ptr telegram uint8_t hour = telegram->message_data[6]; uint8_t min = telegram->message_data[8]; uint16_t duration = EMS_VALUE_SHORT_NOTSET; + uint32_t date = (year - 2000) * 535680UL + month * 44640UL + day * 1440UL + hour * 60 + min; telegram->read_value(duration, 9); - snprintf(&code[2], sizeof(code) - 2, "(%d) %02d.%02d.%d %02d:%02d (%d min)", codeNo, day, month, year, hour, min, duration); - has_update(lastCode_, code, sizeof(lastCode_)); + // store only the newest code from telegrams 12 and 13 + if (date > lastCodeDate_) { + lastCodeDate_ = date; + snprintf(&code[2], sizeof(code) - 2, "(%d) %02d.%02d.%d %02d:%02d (%d min)", codeNo, day, month, year, hour, min, duration); + has_update(lastCode_, code, sizeof(lastCode_)); + } } } @@ -2264,27 +2184,27 @@ bool Thermostat::set_mode(const char * value, const int8_t id) { uint8_t num = value[0] - '0'; switch (model()) { case EMSdevice::EMS_DEVICE_FLAG_RC10: - mode = read_flash_string(FL_(enum_mode6)[num]); + mode = Helpers::translated_word(FL_(enum_mode6)[num], true); break; case EMSdevice::EMS_DEVICE_FLAG_RC20: case EMSdevice::EMS_DEVICE_FLAG_RC20_N: - mode = read_flash_string(FL_(enum_mode2)[num]); + mode = Helpers::translated_word(FL_(enum_mode2)[num], true); break; case EMSdevice::EMS_DEVICE_FLAG_RC25: case EMSdevice::EMS_DEVICE_FLAG_RC30: case EMSdevice::EMS_DEVICE_FLAG_RC35: case EMSdevice::EMS_DEVICE_FLAG_RC30_N: - mode = read_flash_string(FL_(enum_mode3)[num]); + mode = Helpers::translated_word(FL_(enum_mode3)[num], true); break; case EMSdevice::EMS_DEVICE_FLAG_RC300: case EMSdevice::EMS_DEVICE_FLAG_RC100: - mode = read_flash_string(FL_(enum_mode)[num]); + mode = Helpers::translated_word(FL_(enum_mode)[num], true); break; case EMSdevice::EMS_DEVICE_FLAG_JUNKERS: - mode = read_flash_string(FL_(enum_mode4)[num]); + mode = Helpers::translated_word(FL_(enum_mode4)[num], true); break; case EMSdevice::EMS_DEVICE_FLAG_CRF: - mode = read_flash_string(FL_(enum_mode5)[num]); + mode = Helpers::translated_word(FL_(enum_mode5)[num], true); break; default: return false; @@ -2294,34 +2214,35 @@ bool Thermostat::set_mode(const char * value, const int8_t id) { } uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id; - if (mode_tostring(HeatingCircuit::Mode::OFF) == mode) { + + if (Helpers::translated_word(FL_(off), true) == mode) { return set_mode_n(HeatingCircuit::Mode::OFF, hc_num); } - if (mode_tostring(HeatingCircuit::Mode::MANUAL) == mode) { + if (Helpers::translated_word(FL_(manual), true) == mode) { return set_mode_n(HeatingCircuit::Mode::MANUAL, hc_num); } - if (mode_tostring(HeatingCircuit::Mode::AUTO) == mode) { + if (Helpers::translated_word(FL_(auto), true) == mode) { return set_mode_n(HeatingCircuit::Mode::AUTO, hc_num); } - if (mode_tostring(HeatingCircuit::Mode::DAY) == mode) { + if (Helpers::translated_word(FL_(day), true) == mode) { return set_mode_n(HeatingCircuit::Mode::DAY, hc_num); } - if (mode_tostring(HeatingCircuit::Mode::NIGHT) == mode) { + if (Helpers::translated_word(FL_(night), true) == mode) { return set_mode_n(HeatingCircuit::Mode::NIGHT, hc_num); } - if (mode_tostring(HeatingCircuit::Mode::HEAT) == mode) { + if (Helpers::translated_word(FL_(heat), true) == mode) { return set_mode_n(HeatingCircuit::Mode::HEAT, hc_num); } - if (mode_tostring(HeatingCircuit::Mode::NOFROST) == mode) { + if (Helpers::translated_word(FL_(nofrost), true) == mode) { return set_mode_n(HeatingCircuit::Mode::NOFROST, hc_num); } - if (mode_tostring(HeatingCircuit::Mode::ECO) == mode) { + if (Helpers::translated_word(FL_(eco), true) == mode) { return set_mode_n(HeatingCircuit::Mode::ECO, hc_num); } - if (mode_tostring(HeatingCircuit::Mode::HOLIDAY) == mode) { + if (Helpers::translated_word(FL_(holiday), true) == mode) { return set_mode_n(HeatingCircuit::Mode::HOLIDAY, hc_num); } - if (mode_tostring(HeatingCircuit::Mode::COMFORT) == mode) { + if (Helpers::translated_word(FL_(comfort), true) == mode) { return set_mode_n(HeatingCircuit::Mode::COMFORT, hc_num); } @@ -2707,9 +2628,15 @@ bool Thermostat::set_switchtime(const char * value, const uint16_t type_id, char } if (strlen(value) > 4) { for (uint8_t i = 0; i < 7; i++) { - if (!strncmp(&value[3], read_flash_string(FL_(enum_dayOfWeek)[i]).c_str(), 2)) { + // we use EN settings for the day abbreviation + if (!strncmp(&value[3], read_flash_string(FL_(enum_dayOfWeek)[i][0]).c_str(), 2)) { day = i; } + + // auto translated_dow = Helpers::translated_word(FL_(enum_dayOfWeek)[i]); + // if (!strncmp(&value[3], translated_dow.c_str(), translated_dow.length())) { + // day = i; + // } } } if (strlen(value) > 10) { @@ -2747,13 +2674,16 @@ bool Thermostat::set_switchtime(const char * value, const uint16_t type_id, char return false; } if (data[0] != 0xE7) { - std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day]); + // we use EN settings for the day abbreviation + std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day][0]); + // s td::string sday = Helpers::translated_word(FL_(enum_dayOfWeek)[day]); 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"); } 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); } else { - std::string son = read_flash_string(FL_(enum_switchmode)[on]); + std::string son = read_flash_string(FL_(enum_switchmode)[on][0]); + // 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()); } } else { @@ -3378,17 +3308,22 @@ void Thermostat::register_device_values() { if (device_id() >= 0x38 && device_id() <= 0x3F) { // each device controls only one hc, so we tag the values uint8_t tag = DeviceValueTAG::TAG_HC1 + device_id() - 0x38; - register_device_value(tag, &tempsensor1_, DeviceValueType::SHORT, FL_(div10), FL_(remotetemp), DeviceValueUOM::DEGREES); - register_device_value(tag, &dewtemperature_, DeviceValueType::INT, nullptr, FL_(dewTemperature), DeviceValueUOM::DEGREES); - register_device_value(tag, &humidity_, DeviceValueType::INT, nullptr, FL_(airHumidity), DeviceValueUOM::PERCENT); - register_device_value( - tag, &ibaCalIntTemperature_, DeviceValueType::INT, FL_(div10), FL_(ibaCalIntTemperature), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_calinttemp)); + register_device_value(tag, &tempsensor1_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(remotetemp), DeviceValueUOM::DEGREES); + register_device_value(tag, &dewtemperature_, DeviceValueType::INT, FL_(dewTemperature), DeviceValueUOM::DEGREES); + register_device_value(tag, &humidity_, DeviceValueType::INT, FL_(airHumidity), DeviceValueUOM::PERCENT); + register_device_value(tag, + &ibaCalIntTemperature_, + DeviceValueType::INT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(ibaCalIntTemperature), + DeviceValueUOM::DEGREES_R, + MAKE_CF_CB(set_calinttemp)); return; } // Common for all thermostats - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &errorCode_, DeviceValueType::STRING, nullptr, FL_(errorCode), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &lastCode_, DeviceValueType::STRING, nullptr, FL_(lastCode), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &errorCode_, DeviceValueType::STRING, FL_(errorCode), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &lastCode_, DeviceValueType::STRING, FL_(lastCode), DeviceValueUOM::NONE); switch (this->model()) { case EMS_DEVICE_FLAG_RC100: @@ -3409,10 +3344,10 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dampedoutdoortemp2_, DeviceValueType::SHORT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(dampedoutdoortemp), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &floordrytemp_, DeviceValueType::UINT, nullptr, FL_(floordrytemp), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &floordrytemp_, DeviceValueType::UINT, FL_(floordrytemp), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaBuildingType_, DeviceValueType::ENUM, @@ -3423,20 +3358,16 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaMinExtTemperature_, DeviceValueType::INT, - nullptr, FL_(ibaMinExtTemperature), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minexttemp)); - register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &ibaDamping_, DeviceValueType::BOOL, nullptr, FL_(damping), DeviceValueUOM::NONE, MAKE_CF_CB(set_damping)); - register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwSetTemp_, DeviceValueType::UINT, nullptr, FL_(wwSetTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwtemp)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaDamping_, DeviceValueType::BOOL, FL_(damping), DeviceValueUOM::NONE, MAKE_CF_CB(set_damping)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwSetTemp_, DeviceValueType::UINT, FL_(wwSetTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwtemp)); register_device_value( DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode), FL_(wwMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwmode)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwSetTempLow_, DeviceValueType::UINT, - nullptr, FL_(wwSetTempLow), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwtemplow)); @@ -3450,18 +3381,16 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwChargeDuration_, DeviceValueType::UINT, - FL_(mul15), + DeviceValueNumOp::DV_NUMOP_MUL15, FL_(wwChargeDuration), DeviceValueUOM::MINUTES, MAKE_CF_CB(set_wwchargeduration)); - register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwCharge_, DeviceValueType::BOOL, nullptr, FL_(wwCharge), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwcharge)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwExtra1_, DeviceValueType::UINT, nullptr, FL_(wwExtra1), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwExtra2_, DeviceValueType::UINT, nullptr, FL_(wwExtra2), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwCharge_, DeviceValueType::BOOL, FL_(wwCharge), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwcharge)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwExtra1_, DeviceValueType::UINT, FL_(wwExtra1), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwExtra2_, DeviceValueType::UINT, FL_(wwExtra2), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwDisinfecting_, DeviceValueType::BOOL, - nullptr, FL_(wwDisinfecting), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwDisinfect)); @@ -3475,7 +3404,7 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwDisinfectHour_, DeviceValueType::UINT, - FL_(mul15), + DeviceValueNumOp::DV_NUMOP_MUL15, FL_(wwDisinfectTime), DeviceValueUOM::MINUTES, MAKE_CF_CB(set_wwDisinfectHour), @@ -3486,7 +3415,7 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaCalIntTemperature_, DeviceValueType::INT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(ibaCalIntTemperature), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_calinttemp)); @@ -3497,35 +3426,32 @@ void Thermostat::register_device_values() { FL_(heatingPID), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatingpid)); - register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &backlight_, DeviceValueType::BOOL, nullptr, FL_(backlight), DeviceValueUOM::NONE, MAKE_CF_CB(set_backlight)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &backlight_, DeviceValueType::BOOL, FL_(backlight), DeviceValueUOM::NONE, MAKE_CF_CB(set_backlight)); register_device_value( DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode3), FL_(wwMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwmode)); break; case EMS_DEVICE_FLAG_RC20_N: case EMS_DEVICE_FLAG_RC25: - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaMinExtTemperature_, DeviceValueType::INT, - nullptr, FL_(ibaMinExtTemperature), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minexttemp)); break; case EMS_DEVICE_FLAG_RC20: - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime break; case EMS_DEVICE_FLAG_RC30: - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaClockOffset_, DeviceValueType::INT, - nullptr, FL_(ibaClockOffset), DeviceValueUOM::SECONDS, MAKE_CF_CB(set_clockoffset)); // offset (in sec) to clock, 0xff=-1s, 0x02=2s - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &autodst_, DeviceValueType::BOOL, nullptr, FL_(autodst), DeviceValueUOM::NONE, MAKE_CF_CB(set_autodst)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &autodst_, DeviceValueType::BOOL, FL_(autodst), DeviceValueUOM::NONE, MAKE_CF_CB(set_autodst)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaLanguage_, DeviceValueType::ENUM, @@ -3539,26 +3465,11 @@ void Thermostat::register_device_values() { FL_(enum_ibaMainDisplay), FL_(ibaMainDisplay), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &backlight_, DeviceValueType::BOOL, FL_(backlight), DeviceValueUOM::NONE, MAKE_CF_CB(set_backlight)); register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &backlight_, DeviceValueType::BOOL, nullptr, FL_(backlight), DeviceValueUOM::NONE, MAKE_CF_CB(set_backlight)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, - &brightness_, - DeviceValueType::INT, - nullptr, - FL_(brightness), - DeviceValueUOM::NONE, - MAKE_CF_CB(set_brightness), - -15, - 15); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, - &mixingvalves_, - DeviceValueType::UINT, - nullptr, - FL_(mixingvalves), - DeviceValueUOM::NONE, - MAKE_CF_CB(set_mixingvalves), - 0, - 2); + DeviceValueTAG::TAG_DEVICE_DATA, &brightness_, DeviceValueType::INT, FL_(brightness), DeviceValueUOM::NONE, MAKE_CF_CB(set_brightness), -15, 15); + register_device_value( + DeviceValueTAG::TAG_DEVICE_DATA, &mixingvalves_, DeviceValueType::UINT, FL_(mixingvalves), DeviceValueUOM::NONE, MAKE_CF_CB(set_mixingvalves), 0, 2); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaBuildingType_, DeviceValueType::ENUM, @@ -3573,30 +3484,34 @@ void Thermostat::register_device_values() { FL_(heatingPID), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatingpid)); - register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &preheating_, DeviceValueType::BOOL, nullptr, FL_(preheating), DeviceValueUOM::NONE, MAKE_CF_CB(set_preheating)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &preheating_, DeviceValueType::BOOL, FL_(preheating), DeviceValueUOM::NONE, MAKE_CF_CB(set_preheating)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaCalIntTemperature_, DeviceValueType::INT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(ibaCalIntTemperature), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_calinttemp)); - register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &offtemp_, DeviceValueType::UINT, FL_(div2), FL_(offtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_offtemp), 5, 30); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &offtemp_, + DeviceValueType::UINT, + DeviceValueNumOp::DV_NUMOP_DIV2, + FL_(offtemp), + DeviceValueUOM::DEGREES, + MAKE_CF_CB(set_offtemp), + 5, + 30); register_device_value( DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode3), FL_(wwMode), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwmode)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwWhenModeOff_, DeviceValueType::BOOL, - nullptr, FL_(wwWhenModeOff), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwwhenmodeoff)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwDisinfecting_, DeviceValueType::BOOL, - nullptr, FL_(wwDisinfecting), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwDisinfect)); @@ -3610,7 +3525,6 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwDisinfectHour_, DeviceValueType::UINT, - nullptr, FL_(wwDisinfectHour), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwDisinfectHour), @@ -3632,7 +3546,7 @@ void Thermostat::register_device_values() { MAKE_CF_CB(set_wwVacation)); break; case EMS_DEVICE_FLAG_RC30_N: - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaMainDisplay_, DeviceValueType::ENUM, @@ -3643,24 +3557,22 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaClockOffset_, DeviceValueType::INT, - nullptr, FL_(ibaClockOffset), DeviceValueUOM::SECONDS); // offset (in sec) to clock, 0xff=-1s, 0x02=2s register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaCalIntTemperature_, DeviceValueType::INT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(ibaCalIntTemperature), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_calinttemp)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaMinExtTemperature_, DeviceValueType::INT, - nullptr, FL_(ibaMinExtTemperature), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minexttemp)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dampedoutdoortemp_, DeviceValueType::INT, nullptr, FL_(dampedoutdoortemp), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dampedoutdoortemp_, DeviceValueType::INT, FL_(dampedoutdoortemp), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaBuildingType_, DeviceValueType::ENUM, @@ -3694,7 +3606,6 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwDisinfecting_, DeviceValueType::BOOL, - nullptr, FL_(wwDisinfecting), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwDisinfect)); @@ -3708,7 +3619,6 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwDisinfectHour_, DeviceValueType::UINT, - nullptr, FL_(wwDisinfectHour), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwDisinfectHour), @@ -3717,14 +3627,12 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwMaxTemp_, DeviceValueType::UINT, - nullptr, FL_(wwMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwMaxTemp)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwOneTimeKey_, DeviceValueType::BOOL, - nullptr, FL_(wwOneTimeKey), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwOneTimeKey)); @@ -3768,7 +3676,7 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaCalIntTemperature_, DeviceValueType::INT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(ibaCalIntTemperature), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_calinttemp), @@ -3777,15 +3685,23 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaMinExtTemperature_, DeviceValueType::INT, - nullptr, FL_(ibaMinExtTemperature), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minexttemp)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &tempsensor1_, DeviceValueType::SHORT, FL_(div10), FL_(tempsensor1), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &tempsensor2_, DeviceValueType::SHORT, FL_(div10), FL_(tempsensor2), DeviceValueUOM::DEGREES); - register_device_value( - DeviceValueTAG::TAG_DEVICE_DATA, &ibaDamping_, DeviceValueType::BOOL, nullptr, FL_(damping), DeviceValueUOM::NONE, MAKE_CF_CB(set_damping)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dampedoutdoortemp_, DeviceValueType::INT, nullptr, FL_(dampedoutdoortemp), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &tempsensor1_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(tempsensor1), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &tempsensor2_, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(tempsensor2), + DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaDamping_, DeviceValueType::BOOL, FL_(damping), DeviceValueUOM::NONE, MAKE_CF_CB(set_damping)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dampedoutdoortemp_, DeviceValueType::INT, FL_(dampedoutdoortemp), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaBuildingType_, DeviceValueType::ENUM, @@ -3819,7 +3735,6 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwDisinfecting_, DeviceValueType::BOOL, - nullptr, FL_(wwDisinfecting), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwDisinfect)); @@ -3833,7 +3748,6 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwDisinfectHour_, DeviceValueType::UINT, - nullptr, FL_(wwDisinfectHour), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwDisinfectHour), @@ -3842,14 +3756,12 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwMaxTemp_, DeviceValueType::UINT, - nullptr, FL_(wwMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwMaxTemp)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwOneTimeKey_, DeviceValueType::BOOL, - nullptr, FL_(wwOneTimeKey), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwOneTimeKey)); @@ -3905,7 +3817,6 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &switchOverTemp_, DeviceValueType::INT, - nullptr, FL_(switchOverTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_switchOverTemp), @@ -3914,7 +3825,7 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyCostRatio_, DeviceValueType::UINT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(energyCostRatio), DeviceValueUOM::NONE, MAKE_CF_CB(set_energyCostRatio), @@ -3923,7 +3834,7 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &fossileFactor_, DeviceValueType::UINT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(fossileFactor), DeviceValueUOM::NONE, MAKE_CF_CB(set_fossileFactor), @@ -3932,7 +3843,7 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &electricFactor_, DeviceValueType::UINT, - FL_(div10), + DeviceValueNumOp::DV_NUMOP_DIV10, FL_(electricFactor), DeviceValueUOM::NONE, MAKE_CF_CB(set_electricFactor), @@ -3941,7 +3852,6 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &delayBoiler_, DeviceValueType::UINT, - nullptr, FL_(delayBoiler), DeviceValueUOM::MINUTES, MAKE_CF_CB(set_delayBoiler), @@ -3950,7 +3860,6 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &tempDiffBoiler_, DeviceValueType::UINT, - nullptr, FL_(tempDiffBoiler), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_tempDiffBoiler), @@ -3959,11 +3868,11 @@ void Thermostat::register_device_values() { break; case EMS_DEVICE_FLAG_EASY: // Easy TC100 have no date/time, see issue #100, not sure about CT200, so leave it. - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime break; case EMS_DEVICE_FLAG_CRF: default: - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime break; } } @@ -3976,18 +3885,18 @@ void Thermostat::register_device_values_hc(std::shared_ptrhc(); // different logic on how temperature values are stored, depending on model - const __FlashStringHelper * const * seltemp_divider; - const __FlashStringHelper * const * roomtemp_divider; + uint8_t seltemp_divider; + uint8_t roomtemp_divider; if (model == EMS_DEVICE_FLAG_EASY) { - seltemp_divider = FL_(div100); - roomtemp_divider = FL_(div100); + seltemp_divider = DeviceValueNumOp::DV_NUMOP_DIV100; + roomtemp_divider = DeviceValueNumOp::DV_NUMOP_DIV100; } else if (model == EMS_DEVICE_FLAG_JUNKERS) { - seltemp_divider = FL_(div10); - roomtemp_divider = FL_(div10); + seltemp_divider = DeviceValueNumOp::DV_NUMOP_DIV10; + roomtemp_divider = DeviceValueNumOp::DV_NUMOP_DIV10; } else { - seltemp_divider = FL_(div2); - roomtemp_divider = FL_(div10); + seltemp_divider = DeviceValueNumOp::DV_NUMOP_DIV2; + roomtemp_divider = DeviceValueNumOp::DV_NUMOP_DIV10; } if (has_flags(EMS_DEVICE_FLAG_NO_WRITE)) { register_device_value(tag, &hc->selTemp, DeviceValueType::SHORT, seltemp_divider, FL_(selRoomTemp), DeviceValueUOM::DEGREES); @@ -4000,31 +3909,41 @@ void Thermostat::register_device_values_hc(std::shared_ptrmode, DeviceValueType::ENUM, FL_(enum_mode6), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); - register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), FL_(daytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); - register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(nighttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); - register_device_value(tag, &hc->reducehours, DeviceValueType::UINT, nullptr, FL_(reducehours), DeviceValueUOM::HOURS, MAKE_CF_CB(set_reducehours)); - register_device_value(tag, &hc->reduceminutes, DeviceValueType::USHORT, nullptr, FL_(reduceminutes), DeviceValueUOM::MINUTES); + register_device_value( + tag, &hc->daytemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(daytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); + register_device_value( + tag, &hc->nighttemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(nighttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); + register_device_value(tag, &hc->reducehours, DeviceValueType::UINT, FL_(reducehours), DeviceValueUOM::HOURS, MAKE_CF_CB(set_reducehours)); + register_device_value(tag, &hc->reduceminutes, DeviceValueType::USHORT, FL_(reduceminutes), DeviceValueUOM::MINUTES); break; case EMS_DEVICE_FLAG_RC100: case EMS_DEVICE_FLAG_RC300: register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype), FL_(modetype), DeviceValueUOM::NONE); - register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(ecotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_ecotemp)); - register_device_value(tag, &hc->manualtemp, DeviceValueType::UINT, FL_(div2), FL_(manualtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_manualtemp)); - register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), FL_(comforttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_comforttemp)); - register_device_value(tag, &hc->summertemp, DeviceValueType::UINT, nullptr, FL_(summertemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_summertemp), 10, 30); - register_device_value(tag, &hc->designtemp, DeviceValueType::UINT, nullptr, FL_(designtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_designtemp)); - register_device_value(tag, &hc->offsettemp, DeviceValueType::INT, nullptr, FL_(offsettemp), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_offsettemp)); - register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, nullptr, FL_(minflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minflowtemp)); - register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, nullptr, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp)); - register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT, nullptr, FL_(roominfluence), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_roominfluence)); register_device_value( - tag, &hc->roominfl_factor, DeviceValueType::UINT, FL_(div10), FL_(roominfl_factor), DeviceValueUOM::NONE, MAKE_CF_CB(set_roominfl_factor)); - register_device_value(tag, &hc->curroominfl, DeviceValueType::SHORT, FL_(div10), FL_(curroominfl), DeviceValueUOM::DEGREES_R); + tag, &hc->nighttemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(ecotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_ecotemp)); + register_device_value( + tag, &hc->manualtemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(manualtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_manualtemp)); + register_device_value( + tag, &hc->daytemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(comforttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_comforttemp)); + register_device_value(tag, &hc->summertemp, DeviceValueType::UINT, FL_(summertemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_summertemp), 10, 30); + register_device_value(tag, &hc->designtemp, DeviceValueType::UINT, FL_(designtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_designtemp)); + register_device_value(tag, &hc->offsettemp, DeviceValueType::INT, FL_(offsettemp), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_offsettemp)); + register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, FL_(minflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minflowtemp)); + register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp)); + register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT, FL_(roominfluence), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_roominfluence)); + register_device_value(tag, + &hc->roominfl_factor, + DeviceValueType::UINT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(roominfl_factor), + DeviceValueUOM::NONE, + MAKE_CF_CB(set_roominfl_factor)); + register_device_value(tag, &hc->curroominfl, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(curroominfl), DeviceValueUOM::DEGREES_R); register_device_value( tag, &hc->nofrostmode, DeviceValueType::ENUM, FL_(enum_nofrostmode1), FL_(nofrostmode), DeviceValueUOM::NONE, MAKE_CF_CB(set_nofrostmode)); - register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT, nullptr, FL_(nofrosttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nofrosttemp)); - register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT, nullptr, FL_(targetflowtemp), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT, FL_(nofrosttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nofrosttemp)); + register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT, FL_(targetflowtemp), DeviceValueUOM::DEGREES); register_device_value( tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatingtype)); register_device_value( @@ -4041,65 +3960,99 @@ void Thermostat::register_device_values_hc(std::shared_ptrcontrolmode, DeviceValueType::ENUM, FL_(enum_controlmode1), FL_(controlmode), DeviceValueUOM::NONE, MAKE_CF_CB(set_controlmode)); register_device_value(tag, &hc->program, DeviceValueType::ENUM, FL_(enum_progMode), FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program)); - register_device_value( - tag, &hc->tempautotemp, DeviceValueType::INT, FL_(div2), FL_(tempautotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_tempautotemp), -1, 30); - register_device_value( - tag, &hc->remoteseltemp, DeviceValueType::INT, FL_(div2), FL_(remoteseltemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_remoteseltemp), -1, 30); - register_device_value(tag, &hc->fastHeatup, DeviceValueType::UINT, nullptr, FL_(fastheatup), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_fastheatup)); + register_device_value(tag, + &hc->tempautotemp, + DeviceValueType::INT, + DeviceValueNumOp::DV_NUMOP_DIV2, + FL_(tempautotemp), + DeviceValueUOM::DEGREES, + MAKE_CF_CB(set_tempautotemp), + -1, + 30); + register_device_value(tag, + &hc->remoteseltemp, + DeviceValueType::INT, + DeviceValueNumOp::DV_NUMOP_DIV2, + FL_(remoteseltemp), + DeviceValueUOM::DEGREES, + MAKE_CF_CB(set_remoteseltemp), + -1, + 30); + register_device_value(tag, &hc->fastHeatup, DeviceValueType::UINT, FL_(fastheatup), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_fastheatup)); register_device_value(tag, &hc->switchonoptimization, DeviceValueType::BOOL, - nullptr, FL_(switchonoptimization), DeviceValueUOM::NONE, MAKE_CF_CB(set_switchonoptimization)); register_device_value(tag, &hc->reducemode, DeviceValueType::ENUM, FL_(enum_reducemode1), FL_(reducemode), DeviceValueUOM::NONE, MAKE_CF_CB(set_reducemode)); - register_device_value(tag, &hc->noreducetemp, DeviceValueType::INT, nullptr, FL_(noreducetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_noreducetemp)); - register_device_value(tag, &hc->reducetemp, DeviceValueType::INT, nullptr, FL_(reducetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_reducetemp)); - register_device_value(tag, &hc->wwprio, DeviceValueType::BOOL, nullptr, FL_(wwprio), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwprio)); + register_device_value(tag, &hc->noreducetemp, DeviceValueType::INT, FL_(noreducetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_noreducetemp)); + register_device_value(tag, &hc->reducetemp, DeviceValueType::INT, FL_(reducetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_reducetemp)); + register_device_value(tag, &hc->wwprio, DeviceValueType::BOOL, FL_(wwprio), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwprio)); break; case EMS_DEVICE_FLAG_CRF: register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode5), FL_(mode), DeviceValueUOM::NONE); register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype5), FL_(modetype), DeviceValueUOM::NONE); - register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT, nullptr, FL_(targetflowtemp), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT, FL_(targetflowtemp), DeviceValueUOM::DEGREES); break; case EMS_DEVICE_FLAG_RC20: register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode2), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); - register_device_value(tag, &hc->manualtemp, DeviceValueType::UINT, FL_(div2), FL_(manualtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_manualtemp)); - register_device_value(tag, &hc->daylowtemp, DeviceValueType::UINT, FL_(div2), FL_(daylowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daylowtemp)); - register_device_value(tag, &hc->daymidtemp, DeviceValueType::UINT, FL_(div2), FL_(daymidtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daymidtemp)); - register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), FL_(dayhightemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); - register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(nighttemp2), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); + register_device_value( + tag, &hc->manualtemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(manualtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_manualtemp)); + register_device_value( + tag, &hc->daylowtemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(daylowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daylowtemp)); + register_device_value( + tag, &hc->daymidtemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(daymidtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daymidtemp)); + register_device_value( + tag, &hc->daytemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(dayhightemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); + register_device_value( + tag, &hc->nighttemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(nighttemp2), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); register_device_value( tag, &hc->switchtime1, DeviceValueType::STRING, FL_(tpl_switchtime1), FL_(switchtime), DeviceValueUOM::NONE, MAKE_CF_CB(set_switchtime1)); break; case EMS_DEVICE_FLAG_RC20_N: register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode2), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype3), FL_(modetype), DeviceValueUOM::NONE); - register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), FL_(daytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); - register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(nighttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); + register_device_value( + tag, &hc->daytemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(daytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); + register_device_value( + tag, &hc->nighttemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(nighttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); register_device_value(tag, &hc->program, DeviceValueType::ENUM, FL_(enum_progMode3), FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program)); - register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, nullptr, FL_(minflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minflowtemp)); - register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, nullptr, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp)); - register_device_value(tag, &hc->tempautotemp, DeviceValueType::UINT, FL_(div2), FL_(tempautotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_tempautotemp)); + register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, FL_(minflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minflowtemp)); + register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp)); + register_device_value(tag, + &hc->tempautotemp, + DeviceValueType::UINT, + DeviceValueNumOp::DV_NUMOP_DIV2, + FL_(tempautotemp), + DeviceValueUOM::DEGREES, + MAKE_CF_CB(set_tempautotemp)); register_device_value( tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatingtype)); - register_device_value(tag, &hc->summertemp, DeviceValueType::UINT, nullptr, FL_(summertemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_summertemp), 10, 30); + register_device_value(tag, &hc->summertemp, DeviceValueType::UINT, FL_(summertemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_summertemp), 10, 30); register_device_value(tag, &hc->summermode, DeviceValueType::ENUM, FL_(enum_summer), FL_(summermode), DeviceValueUOM::NONE); - register_device_value(tag, &hc->remotetemp, DeviceValueType::SHORT, FL_(div10), FL_(remotetemp), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->remotetemp, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(remotetemp), DeviceValueUOM::DEGREES); break; case EMS_DEVICE_FLAG_RC25: register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode3), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype3), FL_(modetype), DeviceValueUOM::NONE); - register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), FL_(daytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); - register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(nighttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); + register_device_value( + tag, &hc->daytemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(daytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); + register_device_value( + tag, &hc->nighttemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(nighttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); register_device_value(tag, &hc->program, DeviceValueType::ENUM, FL_(enum_progMode3), FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program)); - register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, nullptr, FL_(minflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minflowtemp)); - register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, nullptr, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp)); - register_device_value(tag, &hc->tempautotemp, DeviceValueType::UINT, FL_(div2), FL_(tempautotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_tempautotemp)); + register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, FL_(minflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minflowtemp)); + register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp)); + register_device_value(tag, + &hc->tempautotemp, + DeviceValueType::UINT, + DeviceValueNumOp::DV_NUMOP_DIV2, + FL_(tempautotemp), + DeviceValueUOM::DEGREES, + MAKE_CF_CB(set_tempautotemp)); register_device_value( tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatingtype)); - register_device_value(tag, &hc->summertemp, DeviceValueType::UINT, nullptr, FL_(summertemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_summertemp), 9, 25); + register_device_value(tag, &hc->summertemp, DeviceValueType::UINT, FL_(summertemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_summertemp), 9, 25); register_device_value(tag, &hc->summermode, DeviceValueType::ENUM, FL_(enum_summer), FL_(summermode), DeviceValueUOM::NONE); break; case EMS_DEVICE_FLAG_RC30: @@ -4107,41 +4060,64 @@ void Thermostat::register_device_values_hc(std::shared_ptrholiday, DeviceValueType::STRING, FL_(tpl_holidays), FL_(holidays), DeviceValueUOM::NONE, MAKE_CF_CB(set_holiday)); register_device_value(tag, &hc->vacation, DeviceValueType::STRING, FL_(tpl_holidays), FL_(vacations), DeviceValueUOM::NONE, MAKE_CF_CB(set_vacation)); register_device_value(tag, &hc->program, DeviceValueType::ENUM, FL_(enum_progMode2), FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program)); - register_device_value(tag, &hc->pause, DeviceValueType::UINT, nullptr, FL_(pause), DeviceValueUOM::HOURS, MAKE_CF_CB(set_pause)); - register_device_value(tag, &hc->party, DeviceValueType::UINT, nullptr, FL_(party), DeviceValueUOM::HOURS, MAKE_CF_CB(set_party)); + register_device_value(tag, &hc->pause, DeviceValueType::UINT, FL_(pause), DeviceValueUOM::HOURS, MAKE_CF_CB(set_pause)); + register_device_value(tag, &hc->party, DeviceValueType::UINT, FL_(party), DeviceValueUOM::HOURS, MAKE_CF_CB(set_party)); register_device_value( tag, &hc->switchtime1, DeviceValueType::STRING, FL_(tpl_switchtime1), FL_(switchtime1), DeviceValueUOM::NONE, MAKE_CF_CB(set_switchtime1)); register_device_value( tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatingtype)); register_device_value( tag, &hc->controlmode, DeviceValueType::ENUM, FL_(enum_controlmode2), FL_(controlmode), DeviceValueUOM::NONE, MAKE_CF_CB(set_controlmode)); - register_device_value(tag, &hc->holidaytemp, DeviceValueType::UINT, FL_(div2), FL_(holidaytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_holidaytemp)); - register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(nighttemp2), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); - register_device_value(tag, &hc->daylowtemp, DeviceValueType::UINT, FL_(div2), FL_(daylowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daylowtemp)); - register_device_value(tag, &hc->daymidtemp, DeviceValueType::UINT, FL_(div2), FL_(daymidtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daymidtemp)); - register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), FL_(dayhightemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); + register_device_value(tag, + &hc->holidaytemp, + DeviceValueType::UINT, + DeviceValueNumOp::DV_NUMOP_DIV2, + FL_(holidaytemp), + DeviceValueUOM::DEGREES, + MAKE_CF_CB(set_holidaytemp)); + register_device_value( + tag, &hc->nighttemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(nighttemp2), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); + register_device_value( + tag, &hc->daylowtemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(daylowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daylowtemp)); + register_device_value( + tag, &hc->daymidtemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(daymidtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daymidtemp)); + register_device_value( + tag, &hc->daytemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(dayhightemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); break; case EMS_DEVICE_FLAG_RC30_N: case EMS_DEVICE_FLAG_RC35: register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode3), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype3), FL_(modetype), DeviceValueUOM::NONE); - register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), FL_(daytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); - register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(nighttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); - register_device_value(tag, &hc->designtemp, DeviceValueType::UINT, nullptr, FL_(designtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_designtemp)); - register_device_value(tag, &hc->offsettemp, DeviceValueType::INT, FL_(div2), FL_(offsettemp), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_offsettemp)); - register_device_value(tag, &hc->holidaytemp, DeviceValueType::UINT, FL_(div2), FL_(holidaytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_holidaytemp)); - register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT, nullptr, FL_(targetflowtemp), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->summertemp, DeviceValueType::UINT, nullptr, FL_(summertemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_summertemp), 9, 25); + register_device_value( + tag, &hc->daytemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(daytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); + register_device_value( + tag, &hc->nighttemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(nighttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); + register_device_value(tag, &hc->designtemp, DeviceValueType::UINT, FL_(designtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_designtemp)); + register_device_value(tag, + &hc->offsettemp, + DeviceValueType::INT, + DeviceValueNumOp::DV_NUMOP_DIV2, + FL_(offsettemp), + DeviceValueUOM::DEGREES_R, + MAKE_CF_CB(set_offsettemp)); + register_device_value(tag, + &hc->holidaytemp, + DeviceValueType::UINT, + DeviceValueNumOp::DV_NUMOP_DIV2, + FL_(holidaytemp), + DeviceValueUOM::DEGREES, + MAKE_CF_CB(set_holidaytemp)); + register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT, FL_(targetflowtemp), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->summertemp, DeviceValueType::UINT, FL_(summertemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_summertemp), 9, 25); register_device_value(tag, &hc->summermode, DeviceValueType::ENUM, FL_(enum_summer), FL_(summermode), DeviceValueUOM::NONE); - register_device_value(tag, &hc->holidaymode, DeviceValueType::BOOL, nullptr, FL_(holidaymode), DeviceValueUOM::NONE); - register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT, nullptr, FL_(nofrosttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nofrosttemp)); + register_device_value(tag, &hc->holidaymode, DeviceValueType::BOOL, FL_(holidaymode), DeviceValueUOM::NONE); + register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT, FL_(nofrosttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nofrosttemp)); register_device_value( tag, &hc->nofrostmode, DeviceValueType::ENUM, FL_(enum_nofrostmode), FL_(nofrostmode), DeviceValueUOM::NONE, MAKE_CF_CB(set_nofrostmode)); - register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT, nullptr, FL_(roominfluence), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_roominfluence)); - register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, nullptr, FL_(minflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minflowtemp)); - register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, nullptr, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp)); - register_device_value( - tag, &hc->flowtempoffset, DeviceValueType::UINT, nullptr, FL_(flowtempoffset), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_flowtempoffset)); + register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT, FL_(roominfluence), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_roominfluence)); + register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, FL_(minflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minflowtemp)); + register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp)); + register_device_value(tag, &hc->flowtempoffset, DeviceValueType::UINT, FL_(flowtempoffset), DeviceValueUOM::DEGREES_R, MAKE_CF_CB(set_flowtempoffset)); register_device_value( tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatingtype)); register_device_value(tag, &hc->reducemode, DeviceValueType::ENUM, FL_(enum_reducemode), FL_(reducemode), DeviceValueUOM::NONE, MAKE_CF_CB(set_reducemode)); @@ -4151,16 +4127,28 @@ void Thermostat::register_device_values_hc(std::shared_ptrholiday, DeviceValueType::STRING, FL_(tpl_holidays), FL_(holidays), DeviceValueUOM::NONE, MAKE_CF_CB(set_holiday)); register_device_value(tag, &hc->vacation, DeviceValueType::STRING, FL_(tpl_holidays), FL_(vacations), DeviceValueUOM::NONE, MAKE_CF_CB(set_vacation)); register_device_value(tag, &hc->program, DeviceValueType::ENUM, FL_(enum_progMode2), FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program)); - register_device_value(tag, &hc->pause, DeviceValueType::UINT, nullptr, FL_(pause), DeviceValueUOM::HOURS, MAKE_CF_CB(set_pause)); - register_device_value(tag, &hc->party, DeviceValueType::UINT, nullptr, FL_(party), DeviceValueUOM::HOURS, MAKE_CF_CB(set_party)); - register_device_value(tag, &hc->tempautotemp, DeviceValueType::UINT, FL_(div2), FL_(tempautotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_tempautotemp)); - register_device_value(tag, &hc->noreducetemp, DeviceValueType::INT, nullptr, FL_(noreducetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_noreducetemp)); - register_device_value(tag, &hc->reducetemp, DeviceValueType::INT, nullptr, FL_(reducetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_reducetemp)); - register_device_value(tag, &hc->vacreducetemp, DeviceValueType::INT, nullptr, FL_(vacreducetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_vacreducetemp)); + register_device_value(tag, &hc->pause, DeviceValueType::UINT, FL_(pause), DeviceValueUOM::HOURS, MAKE_CF_CB(set_pause)); + register_device_value(tag, &hc->party, DeviceValueType::UINT, FL_(party), DeviceValueUOM::HOURS, MAKE_CF_CB(set_party)); + register_device_value(tag, + &hc->tempautotemp, + DeviceValueType::UINT, + DeviceValueNumOp::DV_NUMOP_DIV2, + FL_(tempautotemp), + DeviceValueUOM::DEGREES, + MAKE_CF_CB(set_tempautotemp)); + register_device_value(tag, &hc->noreducetemp, DeviceValueType::INT, FL_(noreducetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_noreducetemp)); + register_device_value(tag, &hc->reducetemp, DeviceValueType::INT, FL_(reducetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_reducetemp)); + register_device_value(tag, &hc->vacreducetemp, DeviceValueType::INT, FL_(vacreducetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_vacreducetemp)); register_device_value( tag, &hc->vacreducemode, DeviceValueType::ENUM, FL_(enum_reducemode), FL_(vacreducemode), DeviceValueUOM::NONE, MAKE_CF_CB(set_vacreducemode)); - register_device_value(tag, &hc->remotetemp, DeviceValueType::SHORT, FL_(div10), FL_(remotetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_remotetemp)); - register_device_value(tag, &hc->wwprio, DeviceValueType::BOOL, nullptr, FL_(wwprio), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwprio)); + register_device_value(tag, + &hc->remotetemp, + DeviceValueType::SHORT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(remotetemp), + DeviceValueUOM::DEGREES, + MAKE_CF_CB(set_remotetemp)); + register_device_value(tag, &hc->wwprio, DeviceValueType::BOOL, FL_(wwprio), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwprio)); register_device_value( tag, &hc->switchtime1, DeviceValueType::STRING, FL_(tpl_switchtime), FL_(switchtime1), DeviceValueUOM::NONE, MAKE_CF_CB(set_switchtime1)); register_device_value( @@ -4169,13 +4157,21 @@ void Thermostat::register_device_values_hc(std::shared_ptrmode, DeviceValueType::ENUM, FL_(enum_mode4), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype4), FL_(modetype), DeviceValueUOM::NONE); - register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), FL_(heattemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_heattemp)); - register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(ecotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_ecotemp)); - register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT, FL_(div2), FL_(nofrosttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nofrosttemp)); + register_device_value( + tag, &hc->daytemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(heattemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_heattemp)); + register_device_value( + tag, &hc->nighttemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(ecotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_ecotemp)); + register_device_value(tag, + &hc->nofrosttemp, + DeviceValueType::INT, + DeviceValueNumOp::DV_NUMOP_DIV2, + FL_(nofrosttemp), + DeviceValueUOM::DEGREES, + MAKE_CF_CB(set_nofrosttemp)); register_device_value(tag, &hc->control, DeviceValueType::ENUM, FL_(enum_j_control), FL_(control), DeviceValueUOM::NONE, MAKE_CF_CB(set_control)); register_device_value(tag, &hc->program, DeviceValueType::ENUM, FL_(enum_progMode4), FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program)); - register_device_value(tag, &hc->remotetemp, DeviceValueType::SHORT, FL_(div10), FL_(remotetemp), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT, nullptr, FL_(targetflowtemp), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->remotetemp, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(remotetemp), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT, FL_(targetflowtemp), DeviceValueUOM::DEGREES); break; default: break; diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index 61e28d3ec..7414b2f94 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -149,8 +149,6 @@ class Thermostat : public EMSdevice { uint8_t model_; // the model type }; - static std::string mode_tostring(uint8_t mode); - private: static uuid::log::Logger logger_; @@ -239,8 +237,6 @@ class Thermostat : public EMSdevice { std::vector> heating_circuits_; // each thermostat can have multiple heating circuits - uint8_t zero_value_ = 0; // for fixing current room temperature to 0 for HA - // Generic Types static constexpr uint16_t EMS_TYPE_RCTime = 0x06; // time static constexpr uint16_t EMS_TYPE_RCOutdoorTemp = 0xA3; // is an automatic thermostat broadcast, outdoor external temp @@ -353,7 +349,6 @@ class Thermostat : public EMSdevice { void process_RC30Set(std::shared_ptr telegram); void process_RC30Temp(std::shared_ptr telegram); void process_RC30wwSettings(std::shared_ptr telegram); - void process_RC30Timer(std::shared_ptr telegram); void process_RC20Monitor(std::shared_ptr telegram); void process_RC20Set(std::shared_ptr telegram); void process_RC20Temp(std::shared_ptr telegram); diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index c3ab9e431..dd3bf1654 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -51,6 +51,7 @@ std::string EMSdevice::tag_to_mqtt(uint8_t tag) { return read_flash_string(DeviceValue::DeviceValueTAG_mqtt[tag]); } +// convert UOM to a string - these don't need translating std::string EMSdevice::uom_to_string(uint8_t uom) { if (EMSESP::system_.fahrenheit() && (uom == DeviceValueUOM::DEGREES || uom == DeviceValueUOM::DEGREES_R)) { return read_flash_string(DeviceValue::DeviceValueUOM_s[DeviceValueUOM::FAHRENHEIT]); @@ -107,7 +108,7 @@ std::string EMSdevice::device_type_2_device_name(const uint8_t device_type) { case DeviceType::GATEWAY: return read_flash_string(F_(gateway)); default: - return read_flash_string(F_(unknown)); + return Helpers::translated_word(FL_(unknown)); } } @@ -258,7 +259,8 @@ bool EMSdevice::has_tag(const uint8_t tag) const { // called from the command 'entities' void EMSdevice::list_device_entries(JsonObject & output) const { for (const auto & dv : devicevalues_) { - if (!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && dv.type != DeviceValueType::CMD && dv.full_name) { + std::string fullname = dv.get_fullname(); + if (!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && dv.type != DeviceValueType::CMD && !fullname.empty()) { // if we have a tag prefix it char key[50]; if (!EMSdevice::tag_to_mqtt(dv.tag).empty()) { @@ -270,7 +272,7 @@ void EMSdevice::list_device_entries(JsonObject & output) const { JsonArray details = output.createNestedArray(key); // add the full name description - details.add(dv.full_name); + details.add(fullname); // add uom if (!uom_to_string(dv.uom).empty() && uom_to_string(dv.uom) != " ") { @@ -386,23 +388,31 @@ void EMSdevice::register_telegram_type(const uint16_t telegram_type_id, const __ // tag: to be used to group mqtt together, either as separate topics as a nested object // value_p: pointer to the value from the .h file // type: one of DeviceValueType -// options: options for enum or a divider for int (e.g. F("10")) +// options: options for enum, which are translated as a list of lists +// options_single: list of names +// numeric_operatpr: to divide or multiply, see DeviceValueNumOps:: // short_name: used in Mqtt as keys -// full_name: used in Web and Console unless empty (nullptr) +// fullname: used in Web and Console unless empty (nullptr) - can be translated // uom: unit of measure from DeviceValueUOM // has_cmd: true if this is an associated command // min: min allowed value // max: max allowed value -void EMSdevice::register_device_value(uint8_t tag, - void * value_p, - uint8_t type, - const __FlashStringHelper * const * options, - const __FlashStringHelper * short_name, - const __FlashStringHelper * full_name, - uint8_t uom, - bool has_cmd, - int16_t min, - uint16_t max) { +void EMSdevice::add_device_value(uint8_t tag, + void * value_p, + uint8_t type, + const __FlashStringHelper * const ** options, + const __FlashStringHelper * const * options_single, + int8_t numeric_operator, + const __FlashStringHelper * const * name, + uint8_t uom, + const cmd_function_p f, + int16_t min, + uint16_t max) { + bool has_cmd = (f != nullptr); + + auto short_name = name[0]; + const class __FlashStringHelper * const * fullname = &name[1]; // translations start at index 1 + // initialize the device value depending on it's type if (type == DeviceValueType::STRING) { *(char *)(value_p) = {'\0'}; // this is important for string functions like strlen() to work later @@ -420,27 +430,38 @@ void EMSdevice::register_device_value(uint8_t tag, *(uint8_t *)(value_p) = EMS_VALUE_UINT_NOTSET; // enums behave as uint8_t } - // count #options - uint8_t options_size = 0; - if (options != nullptr) { - uint8_t i = 0; - while (options[i++]) { - options_size++; - } - } - // determine state uint8_t state = DeviceValueState::DV_DEFAULT; + // custom fullname + std::string custom_fullname = std::string(""); + // scan through customizations to see if it's on the exclusion list by matching the productID and deviceID EMSESP::webCustomizationService.read([&](WebCustomization & settings) { for (EntityCustomization entityCustomization : settings.entityCustomizations) { 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); for (std::string entity_id : entityCustomization.entity_ids) { - if (entity_id.substr(2) == entity) { + // if there is an appended custom name, strip it to get the true entity name + // and extract the new custom name + std::string shortname; + auto custom_name_pos = entity_id.find('|'); + bool has_custom_name = (custom_name_pos != std::string::npos); + if (has_custom_name) { + shortname = entity_id.substr(2, custom_name_pos - 2); + } else { + shortname = entity_id.substr(2); + } + + // we found the device entity + if (shortname == entity) { + // get Mask uint8_t mask = Helpers::hextoint(entity_id.substr(0, 2).c_str()); state = mask << 4; // set state high bits to flag, turn off active and ha flags + // see if there is a custom name in the entity string + if (has_custom_name) { + custom_fullname = entity_id.substr(custom_name_pos + 1); + } break; } } @@ -448,28 +469,12 @@ void EMSdevice::register_device_value(uint8_t tag, } }); - // add the device - devicevalues_.emplace_back(device_type_, tag, value_p, type, options, options_size, short_name, full_name, uom, 0, has_cmd, min, max, state); -} - -// function with min and max values -// adds a new command to the command list -void EMSdevice::register_device_value(uint8_t tag, - void * value_p, - uint8_t type, - const __FlashStringHelper * const * options, - const __FlashStringHelper * const * name, - uint8_t uom, - const cmd_function_p f, - int16_t min, - uint16_t max) { - auto short_name = name[0]; - auto full_name = name[1]; - - register_device_value(tag, value_p, type, options, short_name, full_name, uom, (f != nullptr), min, max); + // add the device entity + 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); // add a new command if it has a function attached - if (f == nullptr) { + if (!has_cmd) { return; } @@ -484,29 +489,109 @@ void EMSdevice::register_device_value(uint8_t tag, } // add the command to our library - // cmd is the short_name and the description is the full_name - Command::add(device_type_, short_name, f, full_name, flags); + // 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); } -// function with no min and max values (set to 0) +// single list of options void EMSdevice::register_device_value(uint8_t tag, void * value_p, uint8_t type, - const __FlashStringHelper * const * options, + const __FlashStringHelper * const * options_single, const __FlashStringHelper * const * name, uint8_t uom, const cmd_function_p f) { - register_device_value(tag, value_p, type, options, name, uom, f, 0, 0); -} + // create a multi-list from the options + add_device_value(tag, value_p, type, nullptr, options_single, 0, name, uom, f, 0, 0); +}; -// no associated command function, or min/max values +// single list of options, with no translations, with min and max void EMSdevice::register_device_value(uint8_t tag, void * value_p, uint8_t type, - const __FlashStringHelper * const * options, + const __FlashStringHelper * const * options_single, const __FlashStringHelper * const * name, - uint8_t uom) { - register_device_value(tag, value_p, type, options, name, uom, nullptr, 0, 0); + uint8_t uom, + const cmd_function_p f, + int16_t min, + uint16_t max) { + // create a multi-list from the options + 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 * value_p, + uint8_t type, + int8_t numeric_operator, + const __FlashStringHelper * const * name, + uint8_t uom, + const cmd_function_p f) { + 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 * value_p, + uint8_t type, + int8_t numeric_operator, + const __FlashStringHelper * const * name, + uint8_t uom, + const cmd_function_p f, + int16_t min, + uint16_t max) { + add_device_value(tag, value_p, type, nullptr, nullptr, numeric_operator, name, uom, f, min, max); +} + +// 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) { + add_device_value(tag, value_p, type, nullptr, nullptr, 0, name, uom, f, 0, 0); +}; + +// no options, with min/max +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, + int16_t min, + uint16_t max) { + add_device_value(tag, value_p, type, nullptr, nullptr, 0, name, uom, f, min, max); +}; + +// function with min and max values +// adds a new command to the command list +// in this function we separate out the short and long names and take any translations +void EMSdevice::register_device_value(uint8_t tag, + void * value_p, + uint8_t type, + const __FlashStringHelper * const ** options, + const __FlashStringHelper * const * name, + uint8_t uom, + const cmd_function_p f, + int16_t min, + uint16_t 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) +void EMSdevice::register_device_value(uint8_t tag, + void * value_p, + uint8_t type, + const __FlashStringHelper * const ** options, + const __FlashStringHelper * const * name, + uint8_t uom, + const cmd_function_p f) { + add_device_value(tag, value_p, type, options, nullptr, 0, name, uom, f, 0, 0); +} + +// no associated command function, or min/max values +void EMSdevice::register_device_value(uint8_t tag, + 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); } // check if value is readable via mqtt/api @@ -572,7 +657,8 @@ void EMSdevice::publish_value(void * value_p) const { snprintf(topic, sizeof(topic), "%s/%s", Mqtt::tag_to_topic(device_type_, dv.tag).c_str(), read_flash_string(dv.short_name).c_str()); } - int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0; + int8_t num_op = dv.numeric_operator; + char payload[55] = {'\0'}; uint8_t fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; @@ -585,32 +671,32 @@ void EMSdevice::publish_value(void * value_p) const { if (EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX) { Helpers::render_value(payload, *(uint8_t *)(value_p), 0); } else { - strlcpy(payload, read_flash_string(dv.options[*(uint8_t *)(value_p)]).c_str(), sizeof(payload)); + auto enum_str = Helpers::translated_word(dv.options[*(uint8_t *)(value_p)]); + strlcpy(payload, enum_str.c_str(), sizeof(payload)); } } break; } case DeviceValueType::USHORT: - Helpers::render_value(payload, *(uint16_t *)(value_p), divider, fahrenheit); + Helpers::render_value(payload, *(uint16_t *)(value_p), num_op, fahrenheit); break; case DeviceValueType::UINT: - Helpers::render_value(payload, *(uint8_t *)(value_p), divider, fahrenheit); + Helpers::render_value(payload, *(uint8_t *)(value_p), num_op, fahrenheit); break; case DeviceValueType::SHORT: - Helpers::render_value(payload, *(int16_t *)(value_p), divider, fahrenheit); + Helpers::render_value(payload, *(int16_t *)(value_p), num_op, fahrenheit); break; case DeviceValueType::INT: - Helpers::render_value(payload, *(int8_t *)(value_p), divider, fahrenheit); + Helpers::render_value(payload, *(int8_t *)(value_p), num_op, fahrenheit); break; case DeviceValueType::ULONG: - Helpers::render_value(payload, *(uint32_t *)(value_p), divider, fahrenheit); + Helpers::render_value(payload, *(uint32_t *)(value_p), num_op, fahrenheit); break; - case DeviceValueType::BOOL: { + case DeviceValueType::BOOL: Helpers::render_boolean(payload, (bool)*(uint8_t *)(value_p)); break; - } case DeviceValueType::TIME: - Helpers::render_value(payload, *(uint32_t *)(value_p), divider); + Helpers::render_value(payload, *(uint32_t *)(value_p), num_op); break; case DeviceValueType::STRING: if (Helpers::hasValue((char *)(value_p))) { @@ -629,6 +715,8 @@ void EMSdevice::publish_value(void * value_p) const { } // looks up the UOM for a given key from the device value table +// key is the fullname +// TODO really should be using the shortname as the identifier 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 char new_key[80]; @@ -648,7 +736,8 @@ std::string EMSdevice::get_value_uom(const char * key) const { // look up key in our device value list for (const auto & dv : devicevalues_) { - if ((!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && dv.full_name) && (read_flash_string(dv.full_name) == key_p)) { + auto fullname = dv.get_fullname(); + if ((!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && !fullname.empty()) && (fullname == key_p)) { // ignore TIME since "minutes" is already added to the string value if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) { break; @@ -669,11 +758,13 @@ void EMSdevice::generate_values_web(JsonObject & output) { JsonArray data = output.createNestedArray("data"); for (auto & dv : devicevalues_) { + auto fullname = dv.get_fullname(); + // check conditions: - // 1. full_name cannot be empty + // 1. fullname cannot be empty // 2. it must have a valid value, if it is not a command like 'reset' // 3. show favorites first - if (!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && dv.full_name && (dv.hasValue() || (dv.type == DeviceValueType::CMD))) { + if (!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && !fullname.empty() && (dv.hasValue() || (dv.type == DeviceValueType::CMD))) { JsonObject obj = data.createNestedObject(); // create the object, we know there is a value uint8_t fahrenheit = 0; @@ -691,33 +782,28 @@ void EMSdevice::generate_values_web(JsonObject & output) { // handle ENUMs else if ((dv.type == DeviceValueType::ENUM) && (*(uint8_t *)(dv.value_p) < dv.options_size)) { - obj["v"] = dv.options[*(uint8_t *)(dv.value_p)]; + obj["v"] = Helpers::translated_word(dv.options[*(uint8_t *)(dv.value_p)]); } // handle numbers else { - // If a divider is specified, do the division to 2 decimals places and send back as double/float - // otherwise force as an integer whole - // the nested if's is necessary due to the way the ArduinoJson templates are pre-processed by the compiler - int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0; - fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; + // note, the nested if's is necessary due to the way the ArduinoJson templates are pre-processed by the compiler + fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; if ((dv.type == DeviceValueType::INT) && Helpers::hasValue(*(int8_t *)(dv.value_p))) { - obj["v"] = Helpers::round2(*(int8_t *)(dv.value_p), divider, fahrenheit); + obj["v"] = Helpers::transformNumFloat(*(int8_t *)(dv.value_p), dv.numeric_operator, fahrenheit); } else if ((dv.type == DeviceValueType::UINT) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) { - obj["v"] = Helpers::round2(*(uint8_t *)(dv.value_p), divider, fahrenheit); + obj["v"] = Helpers::transformNumFloat(*(uint8_t *)(dv.value_p), dv.numeric_operator, fahrenheit); } else if ((dv.type == DeviceValueType::SHORT) && Helpers::hasValue(*(int16_t *)(dv.value_p))) { - obj["v"] = Helpers::round2(*(int16_t *)(dv.value_p), divider, fahrenheit); + obj["v"] = Helpers::transformNumFloat(*(int16_t *)(dv.value_p), dv.numeric_operator, fahrenheit); } else if ((dv.type == DeviceValueType::USHORT) && Helpers::hasValue(*(uint16_t *)(dv.value_p))) { - obj["v"] = Helpers::round2(*(uint16_t *)(dv.value_p), divider, fahrenheit); + obj["v"] = Helpers::transformNumFloat(*(uint16_t *)(dv.value_p), dv.numeric_operator, fahrenheit); } else if ((dv.type == DeviceValueType::ULONG) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - obj["v"] = Helpers::round2(*(uint32_t *)(dv.value_p), divider, fahrenheit); + obj["v"] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), dv.numeric_operator, fahrenheit); } else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - uint32_t time_value = *(uint32_t *)(dv.value_p); - obj["v"] = (divider > 0) ? time_value / divider : time_value; // sometimes we need to divide by 60 + obj["v"] = dv.numeric_operator ? (*(uint32_t *)(dv.value_p) / dv.numeric_operator) : *(uint32_t *)(dv.value_p); } else { - // must have a value for sorting to work - obj["v"] = ""; + obj["v"] = ""; // must have a value for sorting to work } } @@ -728,9 +814,9 @@ void EMSdevice::generate_values_web(JsonObject & output) { // add name, prefixing the tag if it exists. This is the id used in the WebUI table and must be unique if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) { - obj["id"] = mask + read_flash_string(dv.full_name); + obj["id"] = mask + dv.get_fullname(); } else { - obj["id"] = mask + tag_to_string(dv.tag) + " " + read_flash_string(dv.full_name); + obj["id"] = mask + tag_to_string(dv.tag) + " " + dv.get_fullname(); } // add commands and options @@ -741,12 +827,14 @@ void EMSdevice::generate_values_web(JsonObject & output) { } else { obj["c"] = dv.short_name; } + // add the Command options if (dv.type == DeviceValueType::ENUM || (dv.type == DeviceValueType::CMD && dv.options_size > 1)) { JsonArray l = obj.createNestedArray("l"); for (uint8_t i = 0; i < dv.options_size; i++) { - if (!read_flash_string(dv.options[i]).empty()) { - l.add(read_flash_string(dv.options[i])); + auto enum_str = Helpers::translated_word(dv.options[i]); + if (!enum_str.empty()) { + l.add(enum_str); } } } else if (dv.type == DeviceValueType::BOOL) { @@ -758,18 +846,19 @@ void EMSdevice::generate_values_web(JsonObject & output) { // add command help template else if (dv.type == DeviceValueType::STRING || dv.type == DeviceValueType::CMD) { if (dv.options_size == 1) { - obj["h"] = dv.options[0]; + obj["h"] = dv.options_single[0]; // NOT translated } } - // add steps to numeric values with divider/multiplier + // handle INTs + // add steps to numeric values with numeric_operator else { - int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0; - char s[10]; - if (divider > 0) { - obj["s"] = Helpers::render_value(s, (float)1 / divider, 1); - } else if (divider < 0) { - obj["s"] = Helpers::render_value(s, (-1) * divider, 0); + char s[10]; + if (dv.numeric_operator > 0) { + obj["s"] = Helpers::render_value(s, (float)1 / dv.numeric_operator, 1); + } else if (dv.numeric_operator < 0) { + obj["s"] = Helpers::render_value(s, (-1) * dv.numeric_operator, 0); } + int16_t dv_set_min, dv_set_max; if (dv.get_min_max(dv_set_min, dv_set_max)) { obj["m"] = Helpers::render_value(s, dv_set_min, 0); @@ -804,39 +893,45 @@ void EMSdevice::generate_values_web_customization(JsonArray & output) { // handle ENUMs else if ((dv.type == DeviceValueType::ENUM) && (*(uint8_t *)(dv.value_p) < dv.options_size)) { - obj["v"] = dv.options[*(uint8_t *)(dv.value_p)]; + obj["v"] = Helpers::translated_word(dv.options[*(uint8_t *)(dv.value_p)]); } // handle Integers and Floats else { - // If a divider is specified, do the division to 2 decimals places and send back as double/float - // otherwise force as an integer whole - // the nested if's is necessary due to the way the ArduinoJson templates are pre-processed by the compiler - uint8_t divider = 0; - uint8_t factor = 1; - if (dv.options_size == 1) { - auto s_str = read_flash_string(dv.options[0]); // prevent object backing the pointer will be destroyed at the end of the full-expression - const char * s = s_str.c_str(); - if (s[0] == '*') { - factor = Helpers::atoint(&s[1]); - } else { - divider = Helpers::atoint(s); - } + int8_t num_op = dv.numeric_operator; + bool make_float; + if (num_op == 0) { + // no changes to number + make_float = false; + num_op = 1; // so it gets *1 + } else if (num_op < 0) { + // negative numbers, convert to a positive multiplier + make_float = false; + num_op *= -1; + } else { + // has a divider, make it a float + make_float = true; + } + + // always convert temperatures to floats with 1 decimal place + if ((dv.uom == DeviceValueUOM::DEGREES) || (dv.uom == DeviceValueUOM::DEGREES_R)) { + make_float = true; } if (dv.type == DeviceValueType::INT) { - obj["v"] = divider ? Helpers::round2(*(int8_t *)(dv.value_p), divider) : *(int8_t *)(dv.value_p) * factor; + obj["v"] = make_float ? Helpers::transformNumFloat(*(int8_t *)(dv.value_p), num_op) : *(int8_t *)(dv.value_p) * num_op; } else if (dv.type == DeviceValueType::UINT) { - obj["v"] = divider ? Helpers::round2(*(uint8_t *)(dv.value_p), divider) : *(uint8_t *)(dv.value_p) * factor; + obj["v"] = make_float ? Helpers::transformNumFloat(*(uint8_t *)(dv.value_p), num_op) : *(uint8_t *)(dv.value_p) * num_op; } else if (dv.type == DeviceValueType::SHORT) { - obj["v"] = divider ? Helpers::round2(*(int16_t *)(dv.value_p), divider) : *(int16_t *)(dv.value_p) * factor; + obj["v"] = make_float ? Helpers::transformNumFloat(*(int16_t *)(dv.value_p), num_op) : *(int16_t *)(dv.value_p) * num_op; } else if (dv.type == DeviceValueType::USHORT) { - obj["v"] = divider ? Helpers::round2(*(uint16_t *)(dv.value_p), divider) : *(uint16_t *)(dv.value_p) * factor; + obj["v"] = make_float ? Helpers::transformNumFloat(*(uint16_t *)(dv.value_p), num_op) : *(uint16_t *)(dv.value_p) * num_op; } else if (dv.type == DeviceValueType::ULONG) { - obj["v"] = divider ? Helpers::round2(*(uint32_t *)(dv.value_p), divider) : *(uint32_t *)(dv.value_p) * factor; + obj["v"] = make_float ? Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), num_op) : *(uint32_t *)(dv.value_p) * num_op; } else if (dv.type == DeviceValueType::TIME) { - uint32_t time_value = *(uint32_t *)(dv.value_p); - obj["v"] = (divider > 0) ? time_value / divider : time_value * factor; // sometimes we need to divide by 60 + // sometimes we need to divide by 60 + obj["v"] = (num_op == DeviceValueNumOp::DV_NUMOP_DIV60) ? (uint32_t)Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), num_op) + : *(uint32_t *)(dv.value_p); } } } @@ -850,13 +945,14 @@ void EMSdevice::generate_values_web_customization(JsonArray & output) { // n is the fullname, and can be optional // don't add the fullname if its a command + auto fullname = Helpers::translated_word(dv.fullname); if (dv.type != DeviceValueType::CMD) { - if (dv.full_name) { + if (!fullname.empty()) { if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) { - obj["n"] = dv.full_name; + obj["n"] = fullname; } else { char name[50]; - snprintf(name, sizeof(name), "%s %s", tag_to_string(dv.tag).c_str(), read_flash_string(dv.full_name).c_str()); + snprintf(name, sizeof(name), "%s %s", tag_to_string(dv.tag).c_str(), fullname.c_str()); obj["n"] = name; } } @@ -864,6 +960,11 @@ void EMSdevice::generate_values_web_customization(JsonArray & output) { obj["n"] = ""; } + // 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["w"] = dv.has_cmd; // if writable } @@ -871,34 +972,61 @@ void EMSdevice::generate_values_web_customization(JsonArray & output) { // set mask per device entity based on the id which is prefixed with the 2 char hex mask value // returns true if the entity has a mask set (not 0 the default) -void EMSdevice::mask_entity(const std::string & entity_id) { +void EMSdevice::setCustomEntity(const std::string & entity_id) { for (auto & dv : devicevalues_) { std::string entity_name = dv.tag < DeviceValueTAG::TAG_HC1 ? read_flash_string(dv.short_name) : tag_to_string(dv.tag) + "/" + read_flash_string(dv.short_name); - if (entity_name == entity_id.substr(2)) { - // this entity has a new mask set + + // extra shortname + std::string shortname; + auto custom_name_pos = entity_id.find('|'); + bool has_custom_name = (custom_name_pos != std::string::npos); + if (has_custom_name) { + shortname = entity_id.substr(2, custom_name_pos - 2); + } else { + shortname = entity_id.substr(2); + } + + if (entity_name == shortname) { + // check the masks uint8_t current_mask = dv.state >> 4; uint8_t new_mask = Helpers::hextoint(entity_id.substr(0, 2).c_str()); // first character contains mask flags + + // if it's a new mask, reconfigure HA if (Mqtt::ha_enabled() && ((current_mask ^ new_mask) & (DeviceValueState::DV_READONLY >> 4))) { // remove ha config on change of dv_readonly flag dv.remove_state(DeviceValueState::DV_HA_CONFIG_CREATED); Mqtt::publish_ha_sensor_config(dv, "", "", true); // delete topic (remove = true) } + + // always write the mask dv.state = ((dv.state & 0x0F) | (new_mask << 4)); // set state high bits to flag + + // set the custom name if it has one, or clear it + if (has_custom_name) { + dv.custom_fullname = entity_id.substr(custom_name_pos + 1); + } else { + dv.custom_fullname = ""; + } + return; } } } -// populate a string vector with entities that have masks set -void EMSdevice::getMaskedEntities(std::vector & entity_ids) { +// populate a string vector with entities that have masks set or have a custom name +void EMSdevice::getCustomEntities(std::vector & entity_ids) { for (const auto & dv : devicevalues_) { std::string entity_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; - if (mask) { - entity_ids.push_back(Helpers::hextoa(mask, false) + entity_name); + if (mask || !dv.custom_fullname.empty()) { + if (dv.custom_fullname.empty()) { + entity_ids.push_back(Helpers::hextoa(mask, false) + entity_name); + } else { + entity_ids.push_back(Helpers::hextoa(mask, false) + entity_name + "|" + dv.custom_fullname); + } } } } @@ -930,7 +1058,8 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8 // search device value with this tag for (auto & dv : devicevalues_) { if (strcmp(command_s, Helpers::toLower(read_flash_string(dv.short_name)).c_str()) == 0 && (tag <= 0 || tag == dv.tag)) { - int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0; + int8_t num_op = dv.numeric_operator; + uint8_t fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; const char * type = "type"; @@ -938,12 +1067,12 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8 json["name"] = dv.short_name; - if (dv.full_name != nullptr) { - const char * fullname = "fullname"; + auto fullname = dv.get_fullname(); + if (!fullname.empty()) { if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) { - json[fullname] = dv.full_name; + json["fullname"] = fullname; } else { - json[fullname] = tag_to_string(dv.tag) + " " + read_flash_string(dv.full_name); + json["fullname"] = tag_to_string(dv.tag) + " " + fullname; } } @@ -957,48 +1086,48 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8 if (EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX) { json[value] = (uint8_t)(*(uint8_t *)(dv.value_p)); } else { - json[value] = dv.options[*(uint8_t *)(dv.value_p)]; // text + json[value] = Helpers::translated_word(dv.options[*(uint8_t *)(dv.value_p)]); // text } } json[type] = F_(enum); JsonArray enum_ = json.createNestedArray(F_(enum)); for (uint8_t i = 0; i < dv.options_size; i++) { - enum_.add(dv.options[i]); + enum_.add(Helpers::translated_word(dv.options[i])); } break; } case DeviceValueType::USHORT: if (Helpers::hasValue(*(uint16_t *)(dv.value_p))) { - json[value] = Helpers::round2(*(uint16_t *)(dv.value_p), divider, fahrenheit); + json[value] = Helpers::transformNumFloat(*(uint16_t *)(dv.value_p), num_op, fahrenheit); } json[type] = F_(number); break; case DeviceValueType::UINT: if (Helpers::hasValue(*(uint8_t *)(dv.value_p))) { - json[value] = Helpers::round2(*(uint8_t *)(dv.value_p), divider, fahrenheit); + json[value] = Helpers::transformNumFloat(*(uint8_t *)(dv.value_p), num_op, fahrenheit); } json[type] = F_(number); break; case DeviceValueType::SHORT: if (Helpers::hasValue(*(int16_t *)(dv.value_p))) { - json[value] = Helpers::round2(*(int16_t *)(dv.value_p), divider, fahrenheit); + json[value] = Helpers::transformNumFloat(*(int16_t *)(dv.value_p), num_op, fahrenheit); } json[type] = F_(number); break; case DeviceValueType::INT: if (Helpers::hasValue(*(int8_t *)(dv.value_p))) { - json[value] = Helpers::round2(*(int8_t *)(dv.value_p), divider, fahrenheit); + json[value] = Helpers::transformNumFloat(*(int8_t *)(dv.value_p), num_op, fahrenheit); } json[type] = F_(number); break; case DeviceValueType::ULONG: if (Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - json[value] = Helpers::round2(*(uint32_t *)(dv.value_p), divider); + json[value] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), num_op); } json[type] = F_(number); break; @@ -1020,7 +1149,7 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8 case DeviceValueType::TIME: if (Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - json[value] = Helpers::round2(*(uint32_t *)(dv.value_p), divider); + json[value] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), num_op); } json[type] = F_(number); break; @@ -1037,13 +1166,13 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8 if (dv.options_size > 1) { JsonArray enum_ = json.createNestedArray(F_(enum)); for (uint8_t i = 0; i < dv.options_size; i++) { - enum_.add(dv.options[i]); + enum_.add(Helpers::translated_word(dv.options[i])); } } break; default: - json[type] = F_(unknown); + json[type] = Helpers::translated_word(FL_(unknown)); break; } @@ -1122,12 +1251,14 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c dv.remove_state(DeviceValueState::DV_ACTIVE); } + auto fullname = dv.get_fullname(); + // check conditions: // 1. it must have a valid value (state is active) // 2. it must have a visible flag // 3. it must match the given tag filter or have an empty tag // 4. it must not have the exclude flag set or outputs to console - if (dv.has_state(DeviceValueState::DV_ACTIVE) && dv.full_name && (tag_filter == DeviceValueTAG::TAG_NONE || tag_filter == dv.tag) + if (dv.has_state(DeviceValueState::DV_ACTIVE) && !fullname.empty() && (tag_filter == DeviceValueTAG::TAG_NONE || tag_filter == dv.tag) && (output_target == OUTPUT_TARGET::CONSOLE || !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE))) { has_values = true; // flagged if we actually have data @@ -1136,11 +1267,12 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c // create the name for the JSON key char name[80]; + if (output_target == OUTPUT_TARGET::API_VERBOSE || output_target == OUTPUT_TARGET::CONSOLE) { if (have_tag) { - snprintf(name, 80, "%s %s", tag_to_string(dv.tag).c_str(), read_flash_string(dv.full_name).c_str()); // prefix the tag + snprintf(name, 80, "%s %s", tag_to_string(dv.tag).c_str(), fullname.c_str()); // prefix the tag } else { - strlcpy(name, read_flash_string(dv.full_name).c_str(), sizeof(name)); // use full name + strlcpy(name, fullname.c_str(), sizeof(name)); // use full name } } else { strlcpy(name, read_flash_string(dv.short_name).c_str(), sizeof(name)); // use short name @@ -1161,15 +1293,15 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c if (Mqtt::ha_enabled() && (output_target == OUTPUT_TARGET::MQTT)) { char s[7]; json[name] = Helpers::render_boolean(s, value_b); // for HA always render as string - } else { - if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) { - json[name] = value_b; - } else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) { - json[name] = value_b ? 1 : 0; - } else { - char s[7]; - json[name] = Helpers::render_boolean(s, value_b); - } + } else if (output_target == OUTPUT_TARGET::CONSOLE) { + char s[7]; + json[name] = Helpers::render_boolean(s, value_b, true); // console use web settings + } else if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) { + json[name] = value_b; + } else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) { + json[name] = value_b ? 1 : 0; + char s[7]; + json[name] = Helpers::render_boolean(s, value_b); } } @@ -1180,86 +1312,91 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c // handle ENUMs else if ((dv.type == DeviceValueType::ENUM) && (*(uint8_t *)(dv.value_p) < dv.options_size)) { - // check for numeric enum-format - if (EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX) { + // check for numeric enum-format, console use text format + if (EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX && output_target != OUTPUT_TARGET::CONSOLE) { json[name] = (uint8_t)(*(uint8_t *)(dv.value_p)); } else { - json[name] = dv.options[*(uint8_t *)(dv.value_p)]; + json[name] = Helpers::translated_word(dv.options[*(uint8_t *)(dv.value_p)]); } } // handle Numbers - // If a divider is specified, do the division to 2 decimals places and send back as double/float - // otherwise force as a whole integer - // note: the strange nested if's is necessary due to the way the ArduinoJson templates are pre-processed by the compiler else { - // If a divider is specified, do the division to 2 decimals places and send back as double/float - // otherwise force as an integer whole - uint8_t divider = 0; - uint8_t factor = 1; - if (dv.options_size == 1) { - auto s_str = read_flash_string(dv.options[0]); // prevent object backing the pointer will be destroyed at the end of the full-expression - const char * s = s_str.c_str(); - if (s[0] == '*') { - factor = Helpers::atoint(&s[1]); - } else { - divider = Helpers::atoint(s); - } - } - - // fahrenheit, 0 is no converstion other 1 or 2. not sure why? + // fahrenheit, 0 is no conversion other 1 or 2. not sure why? uint8_t fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; + int8_t num_op = dv.numeric_operator; + bool make_float; + if (num_op == 0) { + // no changes to number + make_float = false; + num_op = 1; // so it gets *1 + } else if (num_op < 0) { + // negative numbers, convert to a positive multiplier + make_float = false; + num_op *= -1; + } else { + // has a divider, make it a float + make_float = true; + } + // always convert temperatures to floats with 1 decimal place - bool make_float = (divider || (dv.uom == DeviceValueUOM::DEGREES) || (dv.uom == DeviceValueUOM::DEGREES_R)); + if ((dv.uom == DeviceValueUOM::DEGREES) || (dv.uom == DeviceValueUOM::DEGREES_R)) { + make_float = true; + } if (dv.type == DeviceValueType::INT) { if (make_float) { - json[name] = Helpers::round2(*(int8_t *)(dv.value_p), divider, fahrenheit); + json[name] = Helpers::transformNumFloat(*(int8_t *)(dv.value_p), num_op, fahrenheit); } else { - json[name] = *(int8_t *)(dv.value_p) * factor; + json[name] = *(int8_t *)(dv.value_p) * num_op; } } else if (dv.type == DeviceValueType::UINT) { if (make_float) { - json[name] = Helpers::round2(*(uint8_t *)(dv.value_p), divider, fahrenheit); + json[name] = Helpers::transformNumFloat(*(uint8_t *)(dv.value_p), num_op, fahrenheit); } else { - json[name] = *(uint8_t *)(dv.value_p) * factor; + json[name] = *(uint8_t *)(dv.value_p) * num_op; } } else if (dv.type == DeviceValueType::SHORT) { if (make_float) { - json[name] = Helpers::round2(*(int16_t *)(dv.value_p), divider, fahrenheit); + json[name] = Helpers::transformNumFloat(*(int16_t *)(dv.value_p), num_op, fahrenheit); } else { - json[name] = *(int16_t *)(dv.value_p) * factor; + json[name] = *(int16_t *)(dv.value_p) * num_op; } } else if (dv.type == DeviceValueType::USHORT) { if (make_float) { - json[name] = Helpers::round2(*(uint16_t *)(dv.value_p), divider, fahrenheit); + json[name] = Helpers::transformNumFloat(*(uint16_t *)(dv.value_p), num_op, fahrenheit); } else { - json[name] = *(uint16_t *)(dv.value_p) * factor; + json[name] = *(uint16_t *)(dv.value_p) * num_op; } } else if (dv.type == DeviceValueType::ULONG) { if (make_float) { - json[name] = Helpers::round2(*(uint32_t *)(dv.value_p), divider, fahrenheit); + json[name] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), num_op, fahrenheit); } else { - json[name] = *(uint32_t *)(dv.value_p) * factor; + json[name] = *(uint32_t *)(dv.value_p) * num_op; } } else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - uint32_t time_value = *(uint32_t *)(dv.value_p); - time_value = Helpers::round2(time_value, divider); // sometimes we need to divide by 60 + uint32_t time_value; + if (num_op == DeviceValueNumOp::DV_NUMOP_DIV60) { + // sometimes we need to divide by 60 + time_value = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), num_op); + } else { + time_value = *(uint32_t *)(dv.value_p); + } if (output_target == OUTPUT_TARGET::API_VERBOSE || output_target == OUTPUT_TARGET::CONSOLE) { - char time_s[40]; + char time_s[60]; snprintf(time_s, sizeof(time_s), "%d %s %d %s %d %s", (time_value / 1440), - read_flash_string(F_(days)).c_str(), + Helpers::translated_word(FL_(days)).c_str(), ((time_value % 1440) / 60), - read_flash_string(F_(hours)).c_str(), + Helpers::translated_word(FL_(hours)).c_str(), (time_value % 60), - read_flash_string(F_(minutes)).c_str()); + Helpers::translated_word(FL_(minutes)).c_str()); json[name] = time_s; } else { json[name] = time_value; diff --git a/src/emsdevice.h b/src/emsdevice.h index dad865d1c..0ff13ba38 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -187,8 +187,8 @@ class EMSdevice { void list_device_entries(JsonObject & output) const; void add_handlers_ignored(const uint16_t handler); - void mask_entity(const std::string & entity_id); - void getMaskedEntities(std::vector & entity_ids); + void setCustomEntity(const std::string & entity_id); + void getCustomEntities(std::vector & entity_ids); using process_function_p = std::function)>; @@ -204,41 +204,93 @@ class EMSdevice { void generate_values_web(JsonObject & output); void generate_values_web_customization(JsonArray & output); - void register_device_value(uint8_t tag, - void * value_p, - uint8_t type, - const __FlashStringHelper * const * options, - const __FlashStringHelper * short_name, - const __FlashStringHelper * full_name, - uint8_t uom, - bool has_cmd, - int16_t min, - uint16_t max); + void add_device_value(uint8_t tag, + void * value_p, + uint8_t type, + const __FlashStringHelper * const ** options, + const __FlashStringHelper * const * options_single, + int8_t numeric_operator, + const __FlashStringHelper * const * name, + uint8_t uom, + const cmd_function_p f, + int16_t min, + uint16_t max); + + void register_device_value(uint8_t tag, + void * value_p, + uint8_t type, + const __FlashStringHelper * const ** options, + const __FlashStringHelper * const * name, + uint8_t uom, + const cmd_function_p f, + int16_t min, + uint16_t max); + + void register_device_value(uint8_t tag, + void * value_p, + 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 * value_p, + uint8_t type, + const __FlashStringHelper * const ** options, + const __FlashStringHelper * const * name, + uint8_t uom); void register_device_value(uint8_t tag, void * value_p, uint8_t type, - const __FlashStringHelper * const * options, + int8_t numeric_operator, + 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, + int8_t numeric_operator, const __FlashStringHelper * const * name, uint8_t uom, const cmd_function_p f, int16_t min, uint16_t max); + // single list of options void register_device_value(uint8_t tag, void * value_p, uint8_t type, - const __FlashStringHelper * const * options, + const __FlashStringHelper * const * options_single, const __FlashStringHelper * const * name, uint8_t uom, - const cmd_function_p f); + const cmd_function_p f = nullptr); + // single list of options, with no translations, with min and max void register_device_value(uint8_t tag, void * value_p, uint8_t type, - const __FlashStringHelper * const * options, + const __FlashStringHelper * const * options_single, const __FlashStringHelper * const * name, - uint8_t uom); + uint8_t uom, + const cmd_function_p f, + int16_t min, + uint16_t max); + + // 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); + + // no options, with min/max + 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, + 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, const uint8_t value, const uint16_t validate_typeid) const; @@ -306,10 +358,21 @@ class EMSdevice { }; // static device IDs - static constexpr uint8_t EMS_DEVICE_ID_BOILER = 0x08; // fixed device_id for Master Boiler/UBA - static constexpr uint8_t EMS_DEVICE_ID_BOILER_1 = 0x70; // fixed device_id for 1st. Cascade Boiler/UBA - static constexpr uint8_t EMS_DEVICE_ID_BOILER_F = 0x7F; // fixed device_id for last Cascade Boiler/UBA - static constexpr uint8_t EMS_DEVICE_ID_AM200 = 0x60; // fixed device_id for alternative Heating AM200 + static constexpr uint8_t EMS_DEVICE_ID_BOILER = 0x08; // fixed device_id for Master Boiler/UBA + static constexpr uint8_t EMS_DEVICE_ID_BOILER_1 = 0x70; // fixed device_id for 1st. Cascade Boiler/UBA + static constexpr uint8_t EMS_DEVICE_ID_BOILER_F = 0x7F; // fixed device_id for last Cascade Boiler/UBA + static constexpr uint8_t EMS_DEVICE_ID_AM200 = 0x60; // fixed device_id for alternative Heating AM200 + static constexpr uint8_t EMS_DEVICE_ID_RS232 = 0x04; + static constexpr uint8_t EMS_DEVICE_ID_TERMINAL = 0x0A; + static constexpr uint8_t EMS_DEVICE_ID_SERVICEKEY = 0x0B; + static constexpr uint8_t EMS_DEVICE_ID_CASCADE = 0x0C; + static constexpr uint8_t EMS_DEVICE_ID_EASYCOM = 0x0D; + static constexpr uint8_t EMS_DEVICE_ID_CONVERTER = 0x0E; + static constexpr uint8_t EMS_DEVICE_ID_CLOCK = 0x0F; + static constexpr uint8_t EMS_DEVICE_ID_SWITCH = 0x11; // Switch WM10 + static constexpr uint8_t EMS_DEVICE_ID_ERROR = 0x12; // Error module WM10 + static constexpr uint8_t EMS_DEVICE_ID_PUMP = 0x15; // pump module PM10 + static constexpr uint8_t EMS_DEVICE_ID_MODEM = 0x48; // generic type IDs static constexpr uint16_t EMS_TYPE_VERSION = 0x02; // type ID for Version information. Generic across all EMS devices. @@ -390,10 +453,13 @@ class EMSdevice { } }; +#ifdef EMSESP_STANDALONE + void debug_print_dv(const char * shortname); +#endif + std::vector telegram_functions_; // each EMS device has its own set of registered telegram types - // device values - std::vector devicevalues_; + std::vector devicevalues_; // all the device values std::vector handlers_ignored_; }; diff --git a/src/emsdevicevalue.cpp b/src/emsdevicevalue.cpp index 79d5d3cf0..649d4fff8 100644 --- a/src/emsdevicevalue.cpp +++ b/src/emsdevicevalue.cpp @@ -22,30 +22,104 @@ namespace emsesp { +// constructor +DeviceValue::DeviceValue(uint8_t device_type, + uint8_t tag, + void * value_p, + uint8_t type, + const __FlashStringHelper * const ** options, + const __FlashStringHelper * const * options_single, + int8_t numeric_operator, + const __FlashStringHelper * const short_name, + const __FlashStringHelper * const * fullname, + std::string & custom_fullname, + uint8_t uom, + bool has_cmd, + int16_t min, + uint16_t max, + uint8_t state) + : device_type(device_type) + , tag(tag) + , value_p(value_p) + , type(type) + , options(options) + , options_single(options_single) + , numeric_operator(numeric_operator) + , short_name(short_name) + , fullname(fullname) + , custom_fullname(custom_fullname) + , uom(uom) + , has_cmd(has_cmd) + , min(min) + , max(max) + , state(state) { + // calculate #options in options list + if (options_single) { + options_size = 1; + } else { + options_size = Helpers::count_items(options); + } + +#ifdef EMSESP_STANDALONE + // only added for debugging + Serial.print("registering entity: "); + Serial.print(read_flash_string(short_name).c_str()); + Serial.print("/"); + if (!custom_fullname.empty()) { + Serial.print(COLOR_BRIGHT_CYAN); + Serial.print(custom_fullname.c_str()); + Serial.print(COLOR_RESET); + } else { + Serial.print(Helpers::translated_word(fullname).c_str()); + } + Serial.print(" (#options="); + Serial.print(options_size); + Serial.print(",numop="); + Serial.print(numeric_operator); + Serial.print(") "); + if (options != nullptr) { + uint8_t i = 0; + while (i < options_size) { + Serial.print(" option"); + Serial.print(i + 1); + Serial.print(":"); + auto str = Helpers::translated_fword(options[i]); + Serial.print(read_flash_string(str).c_str()); + i++; + } + } else if (options_single != nullptr) { + Serial.print("option1:!"); + Serial.print(read_flash_string(options_single[0]).c_str()); + Serial.print("!"); + } + Serial.println(""); +#endif +} + // 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 // must be an int of 4 bytes, 32bit aligned const __FlashStringHelper * DeviceValue::DeviceValueUOM_s[] __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = { - F_(blank), - F_(degrees), - F_(degrees), - F_(percent), - F_(lmin), - F_(kwh), - F_(wh), - F_(hours), - F_(minutes), - F_(ua), - F_(bar), - F_(kw), - F_(w), - F_(kb), - F_(seconds), - F_(dbm), - F_(fahrenheit), - F_(mv), - F_(sqm) + F_(uom_blank), + F_(uom_degrees), + F_(uom_degrees), + F_(uom_percent), + F_(uom_lmin), + F_(uom_kwh), + F_(uom_wh), + F_(uom_hours), + F_(uom_minutes), + F_(uom_ua), + F_(uom_bar), + F_(uom_kw), + F_(uom_w), + F_(uom_kb), + F_(uom_seconds), + F_(uom_dbm), + F_(uom_fahrenheit), + F_(uom_mv), + F_(uom_sqm) }; @@ -196,10 +270,10 @@ bool DeviceValue::get_min_max(int16_t & dv_set_min, int16_t & dv_set_max) { uint8_t fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (uom == DeviceValueUOM::DEGREES) ? 2 : (uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; // if we have individual limits set already, just do the conversion - // limits are not scaled with divider and temperatures are °C + // limits are not scaled with num operator and temperatures are °C if (min != 0 || max != 0) { - dv_set_min = Helpers::round2(min, 0, fahrenheit); - dv_set_max = Helpers::round2(max, 0, fahrenheit); + dv_set_min = Helpers::transformNumFloat(min, 0, fahrenheit); + dv_set_max = Helpers::transformNumFloat(max, 0, fahrenheit); return true; } @@ -207,17 +281,15 @@ bool DeviceValue::get_min_max(int16_t & dv_set_min, int16_t & dv_set_max) { dv_set_min = 0; dv_set_max = 0; - int8_t divider = (options_size == 1) ? Helpers::atoint(uuid::read_flash_string(options[0]).c_str()) : 0; - if (type == DeviceValueType::USHORT) { - dv_set_min = Helpers::round2(0, divider, fahrenheit); - dv_set_max = Helpers::round2(EMS_VALUE_USHORT_NOTSET, divider, fahrenheit); + dv_set_min = Helpers::transformNumFloat(0, numeric_operator, fahrenheit); + dv_set_max = Helpers::transformNumFloat(EMS_VALUE_USHORT_NOTSET, numeric_operator, fahrenheit); return true; } if (type == DeviceValueType::SHORT) { - dv_set_min = Helpers::round2(-EMS_VALUE_SHORT_NOTSET, divider, fahrenheit); - dv_set_max = Helpers::round2(EMS_VALUE_SHORT_NOTSET, divider, fahrenheit); + dv_set_min = Helpers::transformNumFloat(-EMS_VALUE_SHORT_NOTSET, numeric_operator, fahrenheit); + dv_set_max = Helpers::transformNumFloat(EMS_VALUE_SHORT_NOTSET, numeric_operator, fahrenheit); return true; } @@ -225,7 +297,7 @@ bool DeviceValue::get_min_max(int16_t & dv_set_min, int16_t & dv_set_max) { if (uom == DeviceValueUOM::PERCENT) { dv_set_max = 100; } else { - dv_set_max = Helpers::round2(EMS_VALUE_UINT_NOTSET, divider, fahrenheit); + dv_set_max = Helpers::transformNumFloat(EMS_VALUE_UINT_NOTSET, numeric_operator, fahrenheit); } return true; } @@ -235,23 +307,32 @@ bool DeviceValue::get_min_max(int16_t & dv_set_min, int16_t & dv_set_max) { dv_set_min = -100; dv_set_max = 100; } else { - dv_set_min = Helpers::round2(-EMS_VALUE_INT_NOTSET, divider, fahrenheit); - dv_set_max = Helpers::round2(EMS_VALUE_INT_NOTSET, divider, fahrenheit); + dv_set_min = Helpers::transformNumFloat(-EMS_VALUE_INT_NOTSET, numeric_operator, fahrenheit); + dv_set_max = Helpers::transformNumFloat(EMS_VALUE_INT_NOTSET, numeric_operator, fahrenheit); } return true; } if (type == DeviceValueType::ULONG) { - dv_set_max = Helpers::round2(EMS_VALUE_ULONG_NOTSET, divider); + dv_set_max = Helpers::transformNumFloat(EMS_VALUE_ULONG_NOTSET, numeric_operator); return true; } if (type == DeviceValueType::TIME) { - dv_set_max = Helpers::round2(EMS_VALUE_ULONG_NOTSET, divider); + dv_set_max = Helpers::transformNumFloat(EMS_VALUE_ULONG_NOTSET, numeric_operator); return true; } return false; // nothing changed, not supported } +// returns the translated fullname or the custom fullname (if provided) +// always returns a std::string +std::string DeviceValue::get_fullname() const { + if (custom_fullname.empty()) { + return Helpers::translated_word(fullname); + } + return custom_fullname; +} + } // namespace emsesp diff --git a/src/emsdevicevalue.h b/src/emsdevicevalue.h index cff8519f6..6420692fa 100644 --- a/src/emsdevicevalue.h +++ b/src/emsdevicevalue.h @@ -130,55 +130,58 @@ class DeviceValue { DV_FAVORITE = (1 << 7) // 128 - sort to front }; - uint8_t device_type; // EMSdevice::DeviceType - uint8_t tag; // DeviceValueTAG::* - void * value_p; // pointer to variable of any type - uint8_t type; // DeviceValueType::* - const __FlashStringHelper * const * options; // options as a flash char array - uint8_t options_size; // number of options in the char array, calculated - const __FlashStringHelper * short_name; // used in MQTT - const __FlashStringHelper * full_name; // used in Web and Console - uint8_t uom; // DeviceValueUOM::* - uint8_t ha; // DevcieValueHA:: - bool has_cmd; // true if there is a Console/MQTT command which matches the short_name - int16_t min; // min range - uint16_t max; // max range - uint8_t state; // DeviceValueState::* + // numeric operators + // negative numbers used for multipliers + enum DeviceValueNumOp : int8_t { + DV_NUMOP_NONE = 0, // default + DV_NUMOP_DIV2 = 2, + DV_NUMOP_DIV10 = 10, + DV_NUMOP_DIV60 = 60, + DV_NUMOP_DIV100 = 100, + DV_NUMOP_MUL5 = -5, + DV_NUMOP_MUL10 = -10, + DV_NUMOP_MUL15 = -15 + }; - DeviceValue(uint8_t device_type, - uint8_t tag, - void * value_p, - uint8_t type, - const __FlashStringHelper * const * options, - uint8_t options_size, - const __FlashStringHelper * short_name, - const __FlashStringHelper * full_name, - uint8_t uom, - uint8_t ha, - bool has_cmd, - int16_t min, - uint16_t max, - uint8_t state) - : device_type(device_type) - , tag(tag) - , value_p(value_p) - , type(type) - , options(options) - , options_size(options_size) - , short_name(short_name) - , full_name(full_name) - , uom(uom) - , ha(ha) - , has_cmd(has_cmd) - , min(min) - , max(max) - , state(state) { - } + uint8_t device_type; // EMSdevice::DeviceType + uint8_t tag; // DeviceValueTAG::* + void * value_p; // pointer to variable of any type + uint8_t type; // DeviceValueType::* + const __FlashStringHelper * const ** options; // options as a flash char array + const __FlashStringHelper * const * options_single; // options are not translated + int8_t numeric_operator; + uint8_t options_size; // number of options in the char array, calculated + const __FlashStringHelper * const short_name; // used in MQTT and API + const __FlashStringHelper * const * fullname; // used in Web and Console, is translated + std::string custom_fullname; // optional, from customization + uint8_t uom; // DeviceValueUOM::* + bool has_cmd; // true if there is a Console/MQTT command which matches the short_name + int16_t min; // min range + uint16_t max; // max range + uint8_t state; // DeviceValueState::* + + DeviceValue(uint8_t device_type, + uint8_t tag, + void * value_p, + uint8_t type, + const __FlashStringHelper * const ** options, + const __FlashStringHelper * const * options_single, + int8_t numeric_operator, + const __FlashStringHelper * const short_name, + const __FlashStringHelper * const * fullname, + std::string & custom_fullname, + uint8_t uom, + bool has_cmd, + int16_t min, + uint16_t max, + uint8_t state); bool hasValue() const; bool get_min_max(int16_t & dv_set_min, int16_t & dv_set_max); - // state flags + std::string get_fullname() const; + + // dv state flags void add_state(uint8_t s) { state |= s; } diff --git a/src/emsesp.cpp b/src/emsesp.cpp index ca64b0e7e..42d405edc 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -299,7 +299,6 @@ void EMSESP::show_ems(uuid::console::Shell & shell) { } // show EMS device values to the shell console -// generate_values_json is called in verbose mode void EMSESP::show_device_values(uuid::console::Shell & shell) { if (emsdevices.empty()) { shell.printfln(F("No EMS devices detected.")); @@ -317,7 +316,7 @@ void EMSESP::show_device_values(uuid::console::Shell & shell) { DynamicJsonDocument doc(EMSESP_JSON_SIZE_XXLARGE_DYN); // use max size JsonObject json = doc.to(); - emsdevice->generate_values(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::CONSOLE); // verbose mode and nested + emsdevice->generate_values(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::CONSOLE); // print line uint8_t id = 0; @@ -334,7 +333,7 @@ void EMSESP::show_device_values(uuid::console::Shell & shell) { char s[10]; shell.print(Helpers::render_value(s, data.as(), 1)); } else if (data.is()) { - shell.print(data.as() ? F_(on) : F_(off)); + shell.print(data.as() ? Helpers::translated_word(FL_(on)) : Helpers::translated_word(FL_(off))); } // if there is a uom print it @@ -488,6 +487,8 @@ void EMSESP::reset_mqtt_ha() { for (const auto & emsdevice : emsdevices) { emsdevice->ha_config_clear(); } + + // force the re-creating of the dallas and analog sensor topics (for HA) dallassensor_.reload(); analogsensor_.reload(); } @@ -684,10 +685,13 @@ std::string EMSESP::pretty_telegram(std::shared_ptr telegram) { std::string str; str.reserve(200); if (telegram->operation == Telegram::Operation::RX_READ) { - str = src_name + "(" + Helpers::hextoa(src) + ") <- " + dest_name + "(" + Helpers::hextoa(dest) + "), " + type_name + "(" + str = src_name + "(" + Helpers::hextoa(src) + ") -R-> " + dest_name + "(" + Helpers::hextoa(dest) + "), " + type_name + "(" + Helpers::hextoa(telegram->type_id) + "), length: " + Helpers::hextoa(telegram->message_data[0]); + } else if (telegram->dest == 0) { + str = src_name + "(" + Helpers::hextoa(src) + ") -B-> " + dest_name + "(" + Helpers::hextoa(dest) + "), " + type_name + "(" + + Helpers::hextoa(telegram->type_id) + "), data: " + telegram->to_string_message(); } else { - str = src_name + "(" + Helpers::hextoa(src) + ") -> " + dest_name + "(" + Helpers::hextoa(dest) + "), " + type_name + "(" + str = src_name + "(" + Helpers::hextoa(src) + ") -W-> " + dest_name + "(" + Helpers::hextoa(dest) + "), " + type_name + "(" + Helpers::hextoa(telegram->type_id) + "), data: " + telegram->to_string_message(); } @@ -993,27 +997,27 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const name = "generic thermostat"; device_type = DeviceType::THERMOSTAT; flags = DeviceFlags::EMS_DEVICE_FLAG_RC10 | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE; - } else if (device_id == 0x04) { + } else if (device_id == EMSdevice::EMS_DEVICE_ID_RS232) { name = "RS232"; device_type = DeviceType::CONNECT; - } else if (device_id == 0x0A) { + } else if (device_id == EMSdevice::EMS_DEVICE_ID_TERMINAL) { name = "terminal"; device_type = DeviceType::CONNECT; - } else if (device_id == 0x0B) { + } else if (device_id == EMSdevice::EMS_DEVICE_ID_SERVICEKEY) { name = "service key"; device_type = DeviceType::CONNECT; - } else if (device_id == 0x0C) { + } else if (device_id == EMSdevice::EMS_DEVICE_ID_CASCADE) { name = "cascade"; device_type = DeviceType::CONNECT; - } else if (device_id == 0x0D) { + } else if (device_id == EMSdevice::EMS_DEVICE_ID_EASYCOM) { // see https://github.com/emsesp/EMS-ESP/issues/460#issuecomment-709553012 name = "modem"; device_type = DeviceType::CONNECT; - } else if (device_id == 0x0E) { + } else if (device_id == EMSdevice::EMS_DEVICE_ID_CONVERTER) { name = "converter"; // generic - } else if (device_id == 0x0F) { + } else if (device_id == EMSdevice::EMS_DEVICE_ID_CLOCK) { name = "clock"; // generic - } else if (device_id == 0x08) { + } else if (device_id == EMSdevice::EMS_DEVICE_ID_BOILER) { name = "generic boiler"; device_type = DeviceType::BOILER; flags = DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP; @@ -1212,7 +1216,7 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { tx_successful = true; // if telegram is longer read next part with offset +25 for ems+ or +27 for ems1.0 - if ((length == 32) && (txservice_.read_next_tx(data[3]) == read_id_)) { + if ((length >= 31) && (txservice_.read_next_tx(data[3], length) == read_id_)) { read_next_ = true; } } @@ -1271,11 +1275,6 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { } } -// sends raw data of bytes along the Tx line -void EMSESP::send_raw_telegram(const char * data) { - txservice_.send_raw(data); -} - // start all the core services // the services must be loaded in the correct order void EMSESP::start() { @@ -1291,11 +1290,16 @@ void EMSESP::start() { esp8266React.begin(); // loads core system services settings (network, mqtt, ap, ntp etc) webLogService.begin(); // start web log service. now we can start capturing logs to the web log + +#ifdef EMSESP_DEBUG + LOG_NOTICE(F("System is running in Debug mode")); +#endif + LOG_INFO(F("Last system reset reason Core0: %s, Core1: %s"), system_.reset_reason(0).c_str(), system_.reset_reason(1).c_str()); // do any system upgrades if (system_.check_upgrade()) { - LOG_INFO(F("System will be restarted to apply upgrade")); + LOG_INFO(F("System needs a restart to apply new settings. Please wait.")); system_.system_restart(); }; diff --git a/src/emsesp.h b/src/emsesp.h index 1098a10d0..4a31f7c5d 100644 --- a/src/emsesp.h +++ b/src/emsesp.h @@ -92,6 +92,8 @@ using DeviceValueUOM = emsesp::DeviceValue::DeviceValueUOM; using DeviceValueType = emsesp::DeviceValue::DeviceValueType; using DeviceValueState = emsesp::DeviceValue::DeviceValueState; using DeviceValueTAG = emsesp::DeviceValue::DeviceValueTAG; +using DeviceValueNumOp = emsesp::DeviceValue::DeviceValueNumOp; + class Shower; // forward declaration for compiler @@ -126,7 +128,6 @@ class EMSESP { static void send_write_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset, const uint8_t value); static void send_write_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid); - static void send_raw_telegram(const char * data); static bool device_exists(const uint8_t device_id); static bool cmd_is_readonly(const uint8_t device_type, const char * cmd, const int8_t id); diff --git a/src/helpers.cpp b/src/helpers.cpp index 5058d0938..0cd90635f 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -177,10 +177,11 @@ char * Helpers::smallitoa(char * result, const uint16_t value) { // for strings only char * Helpers::render_boolean(char * result, const bool value, const bool dashboard) { uint8_t bool_format_ = dashboard ? EMSESP::system_.bool_dashboard() : EMSESP::system_.bool_format(); + if (bool_format_ == BOOL_FORMAT_ONOFF_STR) { - strlcpy(result, value ? read_flash_string(F_(on)).c_str() : read_flash_string(F_(off)).c_str(), 5); + strlcpy(result, value ? translated_word(FL_(on)).c_str() : translated_word(FL_(off)).c_str(), 5); } else if (bool_format_ == BOOL_FORMAT_ONOFF_STR_CAP) { - strlcpy(result, value ? read_flash_string(F_(ON)).c_str() : read_flash_string(F_(OFF)).c_str(), 5); + strlcpy(result, value ? translated_word(FL_(ON)).c_str() : translated_word(FL_(OFF)).c_str(), 5); } else if ((bool_format_ == BOOL_FORMAT_10) || (bool_format_ == BOOL_FORMAT_10_STR)) { strlcpy(result, value ? "1" : "0", 2); } else { @@ -439,17 +440,41 @@ int Helpers::atoint(const char * value) { // The conversion to Fahrenheit is different for absolute temperatures and relative temperatures like hysteresis. // fahrenheit=0 - off, no conversion // fahrenheit=1 - relative, 1.8t -// fahrenheit=2 - absolute, 1.8t + 32(fahrenheit-1). -float Helpers::round2(float value, const int8_t divider, const uint8_t fahrenheit) { - float val = (value * 100 + 0.5); - if (divider > 0) { - val = ((value / divider) * 100 + 0.5); - } else if (divider < 0) { - val = value * -100 * divider; +// fahrenheit=2 - absolute, 1.8t + 32(fahrenheit-1) +float Helpers::transformNumFloat(float value, const int8_t numeric_operator, const uint8_t fahrenheit) { + float val; + + switch (numeric_operator) { + case DeviceValueNumOp::DV_NUMOP_DIV2: + val = ((value / 2) * 100 + 0.5); + break; + case DeviceValueNumOp::DV_NUMOP_DIV10: + val = ((value / 10) * 100 + 0.5); + break; + case DeviceValueNumOp::DV_NUMOP_DIV60: + val = ((value / 60) * 100 + 0.5); + break; + case DeviceValueNumOp::DV_NUMOP_DIV100: + val = ((value / 100) * 100 + 0.5); + break; + case DeviceValueNumOp::DV_NUMOP_MUL5: + val = value * -100 * 5; + break; + case DeviceValueNumOp::DV_NUMOP_MUL10: + val = value * -100 * 10; + break; + case DeviceValueNumOp::DV_NUMOP_MUL15: + val = value * -100 * 15; + break; + default: + val = (value * 100 + 0.5); // no ops + break; } + if (value < 0) { // negative rounding val = val - 1; } + if (fahrenheit) { val = val * 1.8 + 3200 * (fahrenheit - 1); } @@ -568,12 +593,12 @@ bool Helpers::value2bool(const char * value, bool & value_b) { std::string bool_str = toLower(value); // convert to lower case - if ((bool_str == read_flash_string(F_(on))) || (bool_str == "1") || (bool_str == "true")) { + if ((bool_str == Helpers::translated_word(FL_(on))) || (bool_str == "on") || (bool_str == "1") || (bool_str == "true")) { value_b = true; return true; // is a bool } - if ((bool_str == read_flash_string(F_(off))) || (bool_str == "0") || (bool_str == "false")) { + if ((bool_str == Helpers::translated_word(FL_(off))) || (bool_str == "off") || (bool_str == "0") || (bool_str == "false")) { value_b = false; return true; // is a bool } @@ -581,6 +606,27 @@ bool Helpers::value2bool(const char * value, bool & value_b) { return false; // not a bool } +// 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 +bool Helpers::value2enum(const char * value, uint8_t & value_ui, const __FlashStringHelper * const ** strs) { + if ((value == nullptr) || (strlen(value) == 0)) { + return false; + } + std::string str = toLower(value); + + for (value_ui = 0; strs[value_ui]; 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 + if ((str1 != "") + && ((str2 == "off" && str == "false") || (str2 == "on" && str == "true") || (str == str1) || (str == str2) + || (value[0] == ('0' + value_ui) && value[1] == '\0'))) { + return true; + } + } + + return false; +} + // 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) { if ((value == nullptr) || (strlen(value) == 0)) { @@ -589,13 +635,16 @@ bool Helpers::value2enum(const char * value, uint8_t & value_ui, const __FlashSt std::string str = toLower(value); for (value_ui = 0; strs[value_ui]; value_ui++) { - std::string str1 = toLower(read_flash_string(strs[value_ui])); - if ((str1 != "") - && ((str1 == read_flash_string(F_(off)) && str == "false") || (str1 == read_flash_string(F_(on)) && str == "true") || (str == str1) + std::string enum_str = toLower(read_flash_string(strs[value_ui])); + + if ((enum_str != "") + && ((enum_str == "off" && (str == Helpers::translated_word(FL_(off)) || str == "false")) + || (enum_str == "on" && (str == Helpers::translated_word(FL_(on)) || str == "true")) || (str == enum_str) || (value[0] == ('0' + value_ui) && value[1] == '\0'))) { return true; } } + return false; } @@ -617,7 +666,7 @@ void Helpers::replace_char(char * str, char find, char replace) { int i = 0; while (str[i] != '\0') { - /*Replace the matched character...*/ + // Replace the matched character... if (str[i] == find) str[i] = replace; @@ -625,4 +674,55 @@ void Helpers::replace_char(char * str, char find, char replace) { } } +// count number of items in a list +// the end of a list has a nullptr +uint8_t Helpers::count_items(const __FlashStringHelper * const * list) { + uint8_t list_size = 0; + if (list != nullptr) { + while (list[list_size]) { + list_size++; + } + } + return list_size; +} + +// count number of items in a list of lists +// the end of a list has a nullptr +uint8_t Helpers::count_items(const __FlashStringHelper * const ** list) { + uint8_t list_size = 0; + if (list != nullptr) { + while (list[list_size]) { + list_size++; + } + } + return list_size; +} + +// return translated string as a std::string, optionally converting to lowercase (for console commands) +// takes a FL(...) +std::string Helpers::translated_word(const __FlashStringHelper * const * strings, bool to_lower) { + 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 + if (Helpers::count_items(strings) >= language_index + 1) { + index = language_index; + } + + 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 + if (Helpers::count_items(strings) >= language_index + 1) { + index = language_index; + } + return strings[index]; +} + } // namespace emsesp diff --git a/src/helpers.h b/src/helpers.h index 29ef108b8..396baa960 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -21,13 +21,10 @@ #include "telegram.h" // for EMS_VALUE_* settings -#define FJSON(x) x -// #define FJSON(x) F(x) +#include "common.h" namespace emsesp { -using flash_string_vector = std::vector; - class Helpers { public: static char * render_value(char * result, const float value, const int8_t format); // format is the precision @@ -52,7 +49,9 @@ class Helpers { static int atoint(const char * value); static bool check_abs(const int32_t i); static uint32_t abs(const int32_t i); - static float round2(float value, const int8_t divider, const uint8_t fahrenheit = 0); + + static float transformNumFloat(float value, const int8_t numeric_operator, const uint8_t fahrenheit = 0); + static std::string toLower(std::string const & s); static std::string toUpper(std::string const & s); static void replace_char(char * str, char find, char replace); @@ -68,10 +67,17 @@ class Helpers { static bool value2float(const char * value, float & value_f); static bool value2bool(const char * value, bool & value_b); 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 __FlashStringHelper * const * strs); 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 uint8_t count_items(const __FlashStringHelper * const ** list); + static uint8_t count_items(const __FlashStringHelper * const * list); + + static std::string translated_word(const __FlashStringHelper * const * strings, bool to_lower = false); + static const __FlashStringHelper * translated_fword(const __FlashStringHelper * const * strings); + #ifdef EMSESP_STANDALONE static char * ultostr(char * ptr, uint32_t value, const uint8_t base); #endif diff --git a/src/locale_DE.h b/src/locale_DE.h deleted file mode 100644 index 103703568..000000000 --- a/src/locale_DE.h +++ /dev/null @@ -1,858 +0,0 @@ -/* - * EMS-ESP - https://github.com/emsesp/EMS-ESP - * Copyright 2020 Paul Derbyshire - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -// common words -MAKE_PSTR_WORD(debug) -MAKE_PSTR_WORD(exit) -MAKE_PSTR_WORD(help) -MAKE_PSTR_WORD(log) -MAKE_PSTR_WORD(logout) -MAKE_PSTR_WORD(enabled) -MAKE_PSTR_WORD(disabled) -MAKE_PSTR_WORD(set) -MAKE_PSTR_WORD(show) -MAKE_PSTR_WORD(on) -MAKE_PSTR_WORD(off) -MAKE_PSTR_WORD(ON) -MAKE_PSTR_WORD(OFF) -MAKE_PSTR_WORD(su) -MAKE_PSTR_WORD(name) -MAKE_PSTR_WORD(auto) -MAKE_PSTR_WORD(scan) -MAKE_PSTR_WORD(password) -MAKE_PSTR_WORD(read) -MAKE_PSTR_WORD(version) -MAKE_PSTR_WORD(values) -MAKE_PSTR_WORD(system) -MAKE_PSTR_WORD(fetch) -MAKE_PSTR_WORD(restart) -MAKE_PSTR_WORD(format) -MAKE_PSTR_WORD(raw) -MAKE_PSTR_WORD(watch) -MAKE_PSTR_WORD(syslog) -MAKE_PSTR_WORD(send) -MAKE_PSTR_WORD(telegram) -MAKE_PSTR_WORD(bus_id) -MAKE_PSTR_WORD(tx_mode) -MAKE_PSTR_WORD(ems) -MAKE_PSTR_WORD(devices) -MAKE_PSTR_WORD(shower) -MAKE_PSTR_WORD(mqtt) -MAKE_PSTR_WORD(emsesp) -MAKE_PSTR_WORD(connected) -MAKE_PSTR_WORD(disconnected) -MAKE_PSTR_WORD(passwd) -MAKE_PSTR_WORD(hostname) -MAKE_PSTR_WORD(wifi) -MAKE_PSTR_WORD(reconnect) -MAKE_PSTR_WORD(ssid) -MAKE_PSTR_WORD(heartbeat) -MAKE_PSTR_WORD(users) -MAKE_PSTR_WORD(publish) -MAKE_PSTR_WORD(timeout) -MAKE_PSTR_WORD(board_profile) -MAKE_PSTR_WORD(setvalue) - -// for commands -MAKE_PSTR_WORD(call) -MAKE_PSTR_WORD(cmd) -MAKE_PSTR_WORD(id) -MAKE_PSTR_WORD(hc) -MAKE_PSTR_WORD(wwc) -MAKE_PSTR_WORD(device) -MAKE_PSTR_WORD(data) -MAKE_PSTR_WORD(command) -MAKE_PSTR_WORD(commands) -MAKE_PSTR_WORD(info) -MAKE_PSTR_WORD(settings) -MAKE_PSTR_WORD(customizations) -MAKE_PSTR_WORD(value) -MAKE_PSTR_WORD(error) -MAKE_PSTR_WORD(entities) - -// devices -MAKE_PSTR_WORD(boiler) -MAKE_PSTR_WORD(thermostat) -MAKE_PSTR_WORD(switch) -MAKE_PSTR_WORD(solar) -MAKE_PSTR_WORD(mixer) -MAKE_PSTR_WORD(gateway) -MAKE_PSTR_WORD(controller) -MAKE_PSTR_WORD(connect) -MAKE_PSTR_WORD(heatpump) -MAKE_PSTR_WORD(generic) -MAKE_PSTR_WORD(analogsensor) -MAKE_PSTR_WORD(unknown) -MAKE_PSTR_WORD(dallassensor) - -// format strings -MAKE_PSTR(host_fmt, "Host: %s") -MAKE_PSTR(port_fmt, "Port: %d") -MAKE_PSTR(hostname_fmt, "Hostname: %s") -MAKE_PSTR(board_profile_fmt, "Board Profile: %s") -MAKE_PSTR(mark_interval_fmt, "Mark interval: %lus") -MAKE_PSTR(wifi_ssid_fmt, "WiFi SSID: %s") -MAKE_PSTR(wifi_password_fmt, "WiFi Password: %S") -MAKE_PSTR(tx_mode_fmt, "Tx mode: %d") -MAKE_PSTR(bus_id_fmt, "Bus ID: %02X") -MAKE_PSTR(log_level_fmt, "Log level: %s") - -MAKE_STR(productid_fmt, "%s EMS ProductID") - -MAKE_PSTR_LIST(enum_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(enum_watch, F_(off), F_(on), F_(raw), F_(unknown)) -MAKE_PSTR_LIST(enum_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")) - -// strings -MAKE_PSTR(EMSESP, "EMS-ESP") -MAKE_PSTR(cmd_optional, "[cmd]") -MAKE_PSTR(ha_optional, "[ha]") -MAKE_PSTR(deep_optional, "[deep]") -MAKE_PSTR(watchid_optional, "[ID]") -MAKE_PSTR(watch_format_optional, "[off | on | raw | unknown]") -MAKE_PSTR(invalid_watch, "Invalid watch type") -MAKE_PSTR(data_mandatory, "\"XX XX ...\"") -MAKE_PSTR(asterisks, "********") -MAKE_PSTR(n_mandatory, "") -MAKE_PSTR(sensorid_optional, "[sensor ID]") -MAKE_PSTR(id_optional, "[id|hc]") -MAKE_PSTR(data_optional, "[data]") -MAKE_PSTR(offset_optional, "[offset]") -MAKE_PSTR(length_optional, "[length]") -MAKE_PSTR(typeid_mandatory, "") -MAKE_PSTR(deviceid_mandatory, "") -MAKE_PSTR(device_type_optional, "[device]") -MAKE_PSTR(invalid_log_level, "Invalid log level") -MAKE_PSTR(log_level_optional, "[level]") -MAKE_PSTR(name_mandatory, "") -MAKE_PSTR(name_optional, "[name]") -MAKE_PSTR(new_password_prompt1, "Enter new password: ") -MAKE_PSTR(new_password_prompt2, "Retype new password: ") -MAKE_PSTR(password_prompt, "Password: ") -MAKE_PSTR(unset, "") - -// command descriptions -MAKE_PSTR(info_cmd, "lists all values") -MAKE_PSTR(commands_cmd, "lists all commands") -MAKE_PSTR(entities_cmd, "lists all entities") - -MAKE_PSTR_WORD(number) -MAKE_PSTR_WORD(enum) -MAKE_PSTR_WORD(text) - -MAKE_PSTR_WORD(2) -MAKE_PSTR_WORD(4) -MAKE_PSTR_WORD(10) -MAKE_PSTR_WORD(100) -MAKE_PSTR_WORD(60) - -MAKE_PSTR_LIST(div2, F_(2)) -MAKE_PSTR_LIST(div4, F_(4)) -MAKE_PSTR_LIST(div10, F_(10)) -MAKE_PSTR_LIST(div60, F_(60)) -MAKE_PSTR_LIST(div100, F_(100)) -MAKE_PSTR_LIST(mul5, F("-5")) -MAKE_PSTR_LIST(mul10, F("-10")) -MAKE_PSTR_LIST(mul15, F("-15")) - -// Unit Of Measurement mapping - maps to DeviceValueUOM_s in emsdevice.cpp -// uom - also used with HA see https://github.com/home-assistant/core/blob/d7ac4bd65379e11461c7ce0893d3533d8d8b8cbf/homeassistant/const.py#L384 -MAKE_PSTR(blank, " ") -MAKE_PSTR(percent, "%") -MAKE_PSTR(degrees, "°C") -MAKE_PSTR(kwh, "kWh") -MAKE_PSTR(wh, "Wh") -MAKE_PSTR(bar, "bar") -MAKE_PSTR(minutes, "Minuten") -MAKE_PSTR(hours, "Stunden") -MAKE_PSTR(days, "Tage") -MAKE_PSTR(ua, "uA") -MAKE_PSTR(lmin, "l/min") -MAKE_PSTR(kw, "kW") -MAKE_PSTR(w, "W") -MAKE_PSTR(kb, "KB") -MAKE_PSTR(seconds, "seconds") -MAKE_PSTR(dbm, "dBm") -MAKE_PSTR(fahrenheit, "°F") -MAKE_PSTR(mv, "mV") -MAKE_PSTR(sqm, "sqm") -MAKE_PSTR(m3, "m3") -MAKE_PSTR(l, "l") -// MAKE_PSTR(times, "mal") -// MAKE_PSTR(oclock, "Uhr") - -// TAG mapping - maps to DeviceValueTAG_s in emsdevice.cpp -// use empty string if want to suppress showing tags -// mqtt tags must not have spaces -MAKE_PSTR(tag_none, "") -MAKE_PSTR(tag_heartbeat, "") -MAKE_PSTR(tag_boiler_data_ww, "ww") -MAKE_PSTR(tag_device_data, "") -MAKE_PSTR(tag_device_data_ww, "ww") -MAKE_PSTR(tag_hc1, "hc1") -MAKE_PSTR(tag_hc2, "hc2") -MAKE_PSTR(tag_hc3, "hc3") -MAKE_PSTR(tag_hc4, "hc4") -MAKE_PSTR(tag_hc5, "hc5") -MAKE_PSTR(tag_hc6, "hc6") -MAKE_PSTR(tag_hc7, "hc7") -MAKE_PSTR(tag_hc8, "hc8") -MAKE_PSTR(tag_wwc1, "wwc1") -MAKE_PSTR(tag_wwc2, "wwc2") -MAKE_PSTR(tag_wwc3, "wwc3") -MAKE_PSTR(tag_wwc4, "wwc4") -MAKE_PSTR(tag_wwc5, "wwc5") -MAKE_PSTR(tag_wwc6, "wwc6") -MAKE_PSTR(tag_wwc7, "wwc7") -MAKE_PSTR(tag_wwc8, "wwc8") -MAKE_PSTR(tag_wwc9, "wwc9") -MAKE_PSTR(tag_wwc10, "wwc10") -MAKE_PSTR(tag_ahs, "ahs") -MAKE_PSTR(tag_hs1, "hs1") -MAKE_PSTR(tag_hs2, "hs2") -MAKE_PSTR(tag_hs3, "hs3") -MAKE_PSTR(tag_hs4, "hs4") -MAKE_PSTR(tag_hs5, "hs5") -MAKE_PSTR(tag_hs6, "hs6") -MAKE_PSTR(tag_hs7, "hs7") -MAKE_PSTR(tag_hs8, "hs8") -MAKE_PSTR(tag_hs9, "hs9") -MAKE_PSTR(tag_hs10, "hs10") -MAKE_PSTR(tag_hs11, "hs11") -MAKE_PSTR(tag_hs12, "hs12") -MAKE_PSTR(tag_hs13, "hs13") -MAKE_PSTR(tag_hs14, "hs14") -MAKE_PSTR(tag_hs15, "hs15") -MAKE_PSTR(tag_hs16, "hs16") - -// MQTT topic names -// MAKE_PSTR(tag_heartbeat_mqtt, "heartbeat") -// MAKE_PSTR(tag_boiler_data_mqtt, "") -MAKE_PSTR(tag_boiler_data_ww_mqtt, "ww") -MAKE_PSTR(tag_device_data_ww_mqtt, "") - -// boiler -MAKE_PSTR(time, "Zeit") -MAKE_PSTR(date, "Datum") -MAKE_PSTR_WORD(1x3min) -MAKE_PSTR_WORD(2x3min) -MAKE_PSTR_WORD(3x3min) -MAKE_PSTR_WORD(4x3min) -MAKE_PSTR_WORD(5x3min) -MAKE_PSTR_WORD(6x3min) -MAKE_PSTR_(continuos, "kontinuierlich") -MAKE_PSTR(3wayvalve, "3-Wege Ventil") -MAKE_PSTR(chargepump, "Ladepumpe") -MAKE_PSTR(hot, "Heiss") -MAKE_PSTR(high_comfort, "Heiss Komfort") -MAKE_PSTR(eco, "Eco") -MAKE_PSTR(intelligent, "Intelligent") -MAKE_PSTR_(flow, "Fluss") -MAKE_PSTR(manual, "Manuell") -MAKE_PSTR_(buffer, "Speicher") -MAKE_PSTR(bufferedflow, "Durchlaufspeicher") -MAKE_PSTR(layeredbuffer, "Schichtspeicher") -MAKE_PSTR(maintenance, "Wartung") -MAKE_PSTR(heating, "Heizen") -MAKE_PSTR(cooling, "K�hlen") - -// boiler lists -MAKE_PSTR_LIST(tpl_date, F("Format: < dd.mm.yyyy >")) // template for text input -MAKE_PSTR_LIST(enum_off_time_date_manual, F_(off), F_(time), F_(date), F_(manual)) -MAKE_PSTR_LIST(enum_freq, F_(off), F_(1x3min), F_(2x3min), F_(3x3min), F_(4x3min), F_(5x3min), F_(6x3min), F_(continuous)) -MAKE_PSTR_LIST(enum_charge, F_(chargepump), F_(3wayvalve)) -MAKE_PSTR_LIST(enum_comfort, F_(hot), F_(eco), F_(intelligent)) -MAKE_PSTR_LIST(enum_comfort1, F_(high_comfort), F_(eco)) -MAKE_PSTR_LIST(enum_flow, F_(off), F_(flow), F_(bufferedflow), F_(buffer), F_(layeredbuffer)) -MAKE_PSTR_LIST(enum_reset, F("-"), F_(maintenance), F_(error)) -// MAKE_PSTR_LIST(enum_bool, F_(off), F_(on)) - -// AM200 lists -MAKE_PSTR_LIST(enum_vr2Config, F_(off), F("bypass")); -MAKE_PSTR_LIST(enum_aPumpSignal, F_(off), F("pwm"), F("pwm_invers")); -MAKE_PSTR_LIST(enum_bufBypass, F("no"), F_(mixer), F("valve")); -MAKE_PSTR_LIST(enum_bufConfig, F("monovalent"), F("bivalent")); -MAKE_PSTR_LIST(enum_blockMode, F_(off), F_(auto), F("blocking")); -MAKE_PSTR_LIST(enum_blockTerm, F("n_o"), F("n_c")); - -//heatpump -MAKE_PSTR_LIST(enum_hpactivity, F("Kein"), F("Heizen"), F("Kühlen"), F("Warmwasser"), F("Pool")) - -// mixer -MAKE_PSTR_LIST(enum_shunt, F("gestoppt"), F("öffnen"), F("schließen"), F("Offen"), F("Geschlossen")) - -// thermostat -MAKE_PSTR(light, "Leicht") -MAKE_PSTR(medium, "Mittel") -MAKE_PSTR(heavy, "Schwer") -MAKE_PSTR(own_prog, "Eigenprog") -MAKE_PSTR(start, "Start") -MAKE_PSTR(heat, "Heizen") -MAKE_PSTR(hold, "Halten") -MAKE_PSTR(cool, "Kühl") -MAKE_PSTR(end, "Ende") -MAKE_PSTR(german, "Deutsch") -MAKE_PSTR(dutch, "Niederländisch") -MAKE_PSTR(french, "Französisch") -MAKE_PSTR(italian, "Italienisch") -MAKE_PSTR(high, "hoch") -MAKE_PSTR(low, "niedrig") -MAKE_PSTR(radiator, "Heizkörper") -MAKE_PSTR(convector, "Konvektor") -MAKE_PSTR(floor, "Fussboden") -MAKE_PSTR(summer, "Sommer") -MAKE_PSTR(winter, "Winter") -MAKE_PSTR(outdoor, "Aussentemperatur") -MAKE_PSTR_WORD(mpc) -MAKE_PSTR(room, "Raum") -MAKE_PSTR(room_outdoor, "Raum+Au�en") -MAKE_PSTR(power, "Leistung") -MAKE_PSTR(constant, "konstant") -MAKE_PSTR(simple, "einfach") -MAKE_PSTR(optimized, "optimiert") -MAKE_PSTR(nofrost, "Frostschutz") -MAKE_PSTR(comfort, "Komfort") -MAKE_PSTR(night, "Nacht") -MAKE_PSTR(day, "Tag") -MAKE_PSTR(holiday, "Urlaub") -MAKE_PSTR(reduce, "reduziert") -MAKE_PSTR(noreduce, "unreduziert") -MAKE_PSTR(offset, "Anhebung") -MAKE_PSTR(design, "Auslegung") -MAKE_PSTR_WORD(tempauto) -MAKE_PSTR(minflow, "minfluss") -MAKE_PSTR(maxflow, "maxfluss") -MAKE_PSTR_WORD(rc3x) -MAKE_PSTR_WORD(rc20) - -MAKE_PSTR(internal_temperature, "interne Temperatur") -MAKE_PSTR(internal_setpoint, "interner Sollwert") -MAKE_PSTR(external_temperature, "externe Temperatur") -MAKE_PSTR(burner_temperature, "Kesseltemperatur") -MAKE_PSTR(ww_temperature, "Wassertemperatur") -MAKE_PSTR(functioning_mode, "functioning mode") -MAKE_PSTR(smoke_temperature, "Abgastemperatur") - -// thermostat lists -MAKE_PSTR_LIST(tpl_datetime, F("Format: < NTP | dd.mm.yyyy-hh:mm:ss-dw-dst >")) -MAKE_PSTR_LIST(tpl_switchtime, F("Format: < nn.d.o.hh:mm >")) -MAKE_PSTR_LIST(tpl_switchtime1, F("Format: [ not_set | day hh:mm Tn ]")) -MAKE_PSTR_LIST(tpl_holidays, F("Format: < dd.mm.yyyy-dd.mm.yyyy >")) -MAKE_PSTR_LIST(enum_ibaMainDisplay, - F_(internal_temperature), - F_(internal_setpoint), - F_(external_temperature), - F_(burner_temperature), - F_(ww_temperature), - F_(functioning_mode), - F_(time), - F_(date), - F_(smoke_temperature)) -MAKE_PSTR_LIST(enum_ibaLanguage, F_(german), F_(dutch), F_(french), F_(italian)) -MAKE_PSTR_LIST(enum_ibaLanguage_RC30, F_(german), F_(dutch)) -MAKE_PSTR_LIST(enum_floordrystatus, F_(off), F_(start), F_(heat), F_(hold), F_(cool), F_(end)) -MAKE_PSTR_LIST(enum_ibaBuildingType, F_(light), F_(medium), F_(heavy)) // RC300 -MAKE_PSTR_LIST(enum_PID, F("fast"), F_(medium), F("slow")) -MAKE_PSTR_LIST(enum_wwMode, F_(off), F("normal"), F_(comfort), F_(auto), F_(own_prog), F_(eco)) -MAKE_PSTR_LIST(enum_wwCircMode, F_(off), F_(on), F_(auto), F_(own_prog)) -MAKE_PSTR_LIST(enum_wwMode2, F_(off), F_(on), F_(auto)) -MAKE_PSTR_LIST(enum_wwMode3, F_(on), F_(off), F_(auto)) -MAKE_PSTR_LIST(enum_heatingtype, F_(off), F_(radiator), F_(convector), F_(floor)) -MAKE_PSTR_LIST(enum_summermode, F_(summer), F_(auto), F_(winter)) -MAKE_PSTR_LIST(enum_hpoperatingmode, F_(off), F_(auto), F("heizen"), F("kühlen")) -MAKE_PSTR_LIST(enum_summer, F_(winter), F_(summer)) -MAKE_PSTR_LIST(enum_operatingstate, F_(heating), F_(off), F_(cooling)) - -MAKE_PSTR_LIST(enum_mode, F_(manual), F_(auto)) // RC100, RC300, RC310 -MAKE_PSTR_LIST(enum_mode2, F_(off), F_(manual), F_(auto)) // RC20 -MAKE_PSTR_LIST(enum_mode3, F_(night), F_(day), F_(auto)) // RC35, RC30, RC25 -MAKE_PSTR_LIST(enum_mode4, F_(nofrost), F_(eco), F_(heat), F_(auto)) // JUNKERS -MAKE_PSTR_LIST(enum_mode5, F_(auto), F_(off)) // CRF -MAKE_PSTR_LIST(enum_mode6, F_(nofrost), F_(night), F_(day)) // RC10 - -MAKE_PSTR_LIST(enum_modetype, F_(eco), F_(comfort)) -// MAKE_PSTR_LIST(enum_modetype2, F_(day)) -MAKE_PSTR_LIST(enum_modetype3, F_(night), F_(day)) -MAKE_PSTR_LIST(enum_modetype4, F_(nofrost), F_(eco), F_(heat)) -MAKE_PSTR_LIST(enum_modetype5, F_(off), F_(on)) - -MAKE_PSTR_LIST(enum_reducemode, F_(nofrost), F_(reduce), F_(room), F_(outdoor)) -MAKE_PSTR_LIST(enum_reducemode1, F_(outdoor), F_(room), F_(reduce)) // RC310 values: 1-3 -MAKE_PSTR_LIST(enum_nofrostmode, F_(off), F_(room), F_(outdoor)) -MAKE_PSTR_LIST(enum_nofrostmode1, F_(room), F_(outdoor), F_(room_outdoor)) - -MAKE_PSTR_LIST(enum_controlmode, F_(off), F_(optimized), F_(simple), F_(mpc), F_(room), F_(power), F_(constant)) -MAKE_PSTR_LIST(enum_controlmode1, F("weather-compensated"), F("outside-basepoint"), F("n/a"), F_(room)) // RC310 1-4 -MAKE_PSTR_LIST(enum_controlmode2, F_(outdoor), F_(room)) -// MAKE_PSTR_LIST(enum_controlmode3, F_(off), F_(room), F_(outdoor), F("room+outdoor")) -MAKE_PSTR_LIST(enum_control, F_(off), F_(rc20), F_(rc3x)) -MAKE_PSTR_LIST(enum_j_control, F_(off), F("fb10"), F("fb110")) - -MAKE_PSTR_LIST(enum_wwProgMode, F("std Prog"), F_(own_prog)) -MAKE_PSTR_LIST(enum_dayOfWeek, F("Mo"), F("Di"), F("Mi"), F("Do"), F("Fr"), F("Sa"), F("So"), F("Alle")) -MAKE_PSTR_LIST(enum_progMode, F("Prog_1"), F("Prog_2")) -MAKE_PSTR_LIST(enum_progMode2, - F("Eigen_1"), - F("Familie"), - F("Morgends"), - F("Abends"), - F("Vormittag"), - F("Nachmittag"), - F("Mittag"), - F("Singles"), - F("Senioren"), - F("Neu"), - F("Eigen_2")) -MAKE_PSTR_LIST(enum_progMode3, F("Familie"), F("Morgends"), F("Abends"), F("Vormittag"), F("Nachmittag"), F("Mittag"), F("Singles"), F("Senioren")) -MAKE_PSTR_LIST(enum_progMode4, F("prog_a"), F("prog_b"), F("prog_c"), F("prog_d"), F("prog_e"), F("prog_f")) - -MAKE_PSTR_LIST(enum_switchmode, F_(off), F_(eco), F_(comfort), F_(heat)) -MAKE_PSTR_LIST(enum_climate, F("Solltemperature"), F("Raumtemperatur")) - -// solar list -MAKE_PSTR_LIST(enum_solarmode, F_(constant), F("pwm"), F("analog")) -MAKE_PSTR_LIST(enum_collectortype, F("flach"), F("vakuum")) -MAKE_PSTR_LIST(enum_cylprio, F("Zyl_1"), F("Zyl_2")) - -// id used to store the device ID, goes into MQTT payload -MAKE_PSTR_LIST(ID, F_(id)) - -// Boiler -// extra commands -MAKE_PSTR_LIST(wwtapactivated, F("wwtapactivated"), F("Aktiviere Warmwasser im Wartungsmodus")) -MAKE_PSTR_LIST(reset, F("reset"), F("Reset")) - -// single mqtt topics -MAKE_PSTR_WORD(heating_active) -MAKE_PSTR_WORD(tapwater_active) -MAKE_PSTR_WORD(response) - -// mqtt, commands and text -MAKE_PSTR_LIST(heatingActive, F("heatingactive"), F("Heizung aktiv")) -MAKE_PSTR_LIST(tapwaterActive, F("tapwateractive"), F("Warmwasser aktiv")) -MAKE_PSTR_LIST(selFlowTemp, F("selflowtemp"), F("Sollwert Flusstemperatur")) -MAKE_PSTR_LIST(selBurnPow, F("selburnpow"), F("Sollwert Brennerleistung")) -MAKE_PSTR_LIST(heatingPumpMod, F("heatingpumpmod"), F("Heizungspumpe 1 Modulation")) -MAKE_PSTR_LIST(heatingPump2Mod, F("heatingpump2mod"), F("Heizungspumpe 2 Modulation")) -MAKE_PSTR_LIST(outdoorTemp, F("outdoortemp"), F("Aussentemperatur")) -MAKE_PSTR_LIST(curFlowTemp, F("curflowtemp"), F("aktuelle Flusstemperatur")) -MAKE_PSTR_LIST(retTemp, F("rettemp"), F("Rücklauftemperatur")) -MAKE_PSTR_LIST(switchTemp, F("switchtemp"), F("Mischer Schalttemperatur")) -MAKE_PSTR_LIST(sysPress, F("syspress"), F("Systemdruck")) -MAKE_PSTR_LIST(boilTemp, F("boiltemp"), F("Kesseltemperatur")) -MAKE_PSTR_LIST(exhaustTemp, F("exhausttemp"), F("Auslasstemperatur")) -MAKE_PSTR_LIST(burnGas, F("burngas"), F("Gas")) -MAKE_PSTR_LIST(burnGas2, F("burngas2"), F("Gas Stufe 2")) -MAKE_PSTR_LIST(flameCurr, F("flamecurr"), F("Flammstrom")) -MAKE_PSTR_LIST(heatingPump, F("heatingpump"), F("Heizungspumpe")) -MAKE_PSTR_LIST(fanWork, F("fanwork"), F("Gebläse")) -MAKE_PSTR_LIST(ignWork, F("ignwork"), F("Zündung")) -MAKE_PSTR_LIST(oilPreHeat, F("oilpreheat"), F("oil preheating")) -MAKE_PSTR_LIST(heatingActivated, F("heatingactivated"), F("Heizen aktiviert")) -MAKE_PSTR_LIST(heatingTemp, F("heatingtemp"), F("Kesseltemperatur")) -MAKE_PSTR_LIST(pumpModMax, F("pumpmodmax"), F("Kesselpumpen Maximalleistung")) -MAKE_PSTR_LIST(pumpModMin, F("pumpmodmin"), F("Kesselpumpen Minmalleistung")) -MAKE_PSTR_LIST(pumpDelay, F("pumpdelay"), F("Pumpennachlauf")) -MAKE_PSTR_LIST(burnMinPeriod, F("burnminperiod"), F("Antipendelzeit")) -MAKE_PSTR_LIST(burnMinPower, F("burnminpower"), F("minimale Brennerleistung")) -MAKE_PSTR_LIST(burnMaxPower, F("burnmaxpower"), F("maximale Brennerleistung")) -MAKE_PSTR_LIST(boilHystOn, F("boilhyston"), F("Hysterese ein temperatur")) -MAKE_PSTR_LIST(boilHystOff, F("boilhystoff"), F("Hysterese aus temperatur")) -MAKE_PSTR_LIST(setFlowTemp, F("setflowtemp"), F("Sollwert Flusstemperatur")) -MAKE_PSTR_LIST(setBurnPow, F("setburnpow"), F("Sollwert Brennerleistung")) -MAKE_PSTR_LIST(curBurnPow, F("curburnpow"), F("Brennerleistung")) -MAKE_PSTR_LIST(burnStarts, F("burnstarts"), F("Brenner # starts")) -MAKE_PSTR_LIST(burnWorkMin, F("burnworkmin"), F("Brenner Laufzeit")) -MAKE_PSTR_LIST(burn2WorkMin, F("burn2workmin"), F("Brenner Stufe 2 Laufzeit")) -MAKE_PSTR_LIST(heatWorkMin, F("heatworkmin"), F("Heizung Laufzeit")) -MAKE_PSTR_LIST(UBAuptime, F("ubauptime"), F("gesamte Laufzeit")) -MAKE_PSTR_LIST(lastCode, F("lastcode"), F("Fehlerspeicher")) -MAKE_PSTR_LIST(serviceCode, F("servicecode"), F("Statusmeldung")) -MAKE_PSTR_LIST(serviceCodeNumber, F("servicecodenumber"), F("Statusmeldungsnummer")) -MAKE_PSTR_LIST(maintenanceMessage, F("maintenancemessage"), F("Wartungsmeldung")) -MAKE_PSTR_LIST(maintenanceDate, F("maintenancedate"), F("Wartungsdatum")) -MAKE_PSTR_LIST(maintenanceType, F_(maintenance), F("Wartungsplan")) -MAKE_PSTR_LIST(maintenanceTime, F("maintenancetime"), F("Wartung in")) -MAKE_PSTR_LIST(emergencyOps, F("emergencyops"), F("emergency operation")) -MAKE_PSTR_LIST(emergencyTemp, F("emergencytemp"), F("emergency temperature")) - -// heatpump/compress specific -MAKE_PSTR_LIST(upTimeControl, F("uptimecontrol"), F("Betriebszeit total heizen")) -MAKE_PSTR_LIST(upTimeCompHeating, F("uptimecompheating"), F("Betriebszeit Kompressor heizen")) -MAKE_PSTR_LIST(upTimeCompCooling, F("uptimecompcooling"), F("Betriebszeit Kompressor kühlen")) -MAKE_PSTR_LIST(upTimeCompWw, F("uptimecompww"), F("Betriebszeit Kompressor")) -MAKE_PSTR_LIST(upTimeCompPool, F("uptimecomppool"), F("Betriebszeit Kompressor Pool")) -MAKE_PSTR_LIST(totalCompStarts, F("totalcompstarts"), F("gesamt Kompressor Starts")) -MAKE_PSTR_LIST(heatingStarts, F("heatingstarts"), F("Heizen Starts")) -MAKE_PSTR_LIST(coolingStarts, F("coolingstarts"), F("Kühlen Starts")) -MAKE_PSTR_LIST(poolStarts, F("poolstarts"), F("Pool Starts")) -MAKE_PSTR_LIST(nrgConsTotal, F("nrgconstotal"), F("totaler Energieverbrauch")) -MAKE_PSTR_LIST(nrgConsCompTotal, F("nrgconscomptotal"), F("Energieverbrauch Kompressor total")) -MAKE_PSTR_LIST(nrgConsCompHeating, F("nrgconscompheating"), F("Energieverbrauch Kompressor heizen")) -MAKE_PSTR_LIST(nrgConsCompWw, F("nrgconscompww"), F("Energieverbrauch Kompressor")) -MAKE_PSTR_LIST(nrgConsCompCooling, F("nrgconscompcooling"), F("Energieverbrauch Kompressor kühlen")) -MAKE_PSTR_LIST(nrgConsCompPool, F("nrgconscomppool"), F("Energieverbrauch Kompressor Pool")) -MAKE_PSTR_LIST(nrgSuppTotal, F("nrgsupptotal"), F("gesamte Energieabgabe")) -MAKE_PSTR_LIST(nrgSuppHeating, F("nrgsuppheating"), F("gesamte Energieabgabe heizen")) -MAKE_PSTR_LIST(nrgSuppWw, F("nrgsuppww"), F("gesamte Energieabgabe")) -MAKE_PSTR_LIST(nrgSuppCooling, F("nrgsuppcooling"), F("gesamte Energieabgabe kühlen")) -MAKE_PSTR_LIST(nrgSuppPool, F("nrgsupppool"), F("gesamte Energieabgabe Pool")) -MAKE_PSTR_LIST(auxElecHeatNrgConsTotal, F("auxelecheatnrgconstotal"), F("Energieverbrauch el. Zusatzheizung")) -MAKE_PSTR_LIST(auxElecHeatNrgConsHeating, F("auxelecheatnrgconsheating"), F("Energieverbrauch el. Zusatzheizung Heizen")) -MAKE_PSTR_LIST(auxElecHeatNrgConsWW, F("auxelecheatnrgconsww"), F("Energieverbrauch el. Zusatzheizung")) -MAKE_PSTR_LIST(auxElecHeatNrgConsPool, F("auxelecheatnrgconspool"), F("Energieverbrauch el. Zusatzheizung Pool")) - -MAKE_PSTR_LIST(hpPower, F("hppower"), F("Leistung Wärmepumpe")) -MAKE_PSTR_LIST(hpCompOn, F("hpcompon"), F("HP Compressor")) -MAKE_PSTR_LIST(hpHeatingOn, F("hpheatingon"), F("HP Heating")) -MAKE_PSTR_LIST(hpCoolingOn, F("hpcoolingon"), F("HP Cooling")) -MAKE_PSTR_LIST(hpWwOn, F("hpwwon"), F("HP dhw")) -MAKE_PSTR_LIST(hpPoolOn, F("hppoolon"), F("HP Pool")) -MAKE_PSTR_LIST(hpBrinePumpSpd, F("hpbrinepumpspd"), F("Brine Pump Speed")) -MAKE_PSTR_LIST(hpCompSpd, F("hpcompspd"), F("Compressor Speed")) -MAKE_PSTR_LIST(hpCircSpd, F("hpcircspd"), F("Circulation pump Speed")) -MAKE_PSTR_LIST(hpBrineIn, F("hpbrinein"), F("Brine in/Evaporator")) -MAKE_PSTR_LIST(hpBrineOut, F("hpbrineout"), F("Brine out/Condenser")) -MAKE_PSTR_LIST(hpSuctionGas, F("hpsuctiongas"), F("Suction gas")) -MAKE_PSTR_LIST(hpHotGas, F("hphotgas"), F("Hot gas/Compressed")) -MAKE_PSTR_LIST(hpSwitchValve, F("hpswitchvalve"), F("Switch Valve")) -MAKE_PSTR_LIST(hpActivity, F("hpactivity"), F("Compressor Activity")) -MAKE_PSTR_LIST(hpTc0, F("hptc0"), F("Wärmeträgerflüssigkeit Eingang (TC0)")) -MAKE_PSTR_LIST(hpTc1, F("hptc1"), F("Wärmeträgerflüssigkeit Ausgang (TC1)")) -MAKE_PSTR_LIST(hpTc3, F("hptc3"), F("Verflüssigertemperatur (TC3)")) -MAKE_PSTR_LIST(hpTr3, F("hptr3"), F(" Temperaturfühler Kältemittel (Flüssigkeit) (TR3)")) -MAKE_PSTR_LIST(hpTr4, F("hptr4"), F("Verdampfer Eintritt (TR4)")) -MAKE_PSTR_LIST(hpTr5, F("hptr5"), F("Temperaturfühler Kompessoransaugleitung (TR5)")) -MAKE_PSTR_LIST(hpTr6, F("hptr6"), F("Temperaturfühler Kompressorausgangsleitung (TR6)")) -MAKE_PSTR_LIST(hpTr7, F("hptr7"), F("Temperaturfühler Kältemittel (Gas) (TR7)")) -MAKE_PSTR_LIST(hpTl2, F("hptl2"), F("Außenlufttemperaturfühler (TL2)")) -MAKE_PSTR_LIST(hpPl1, F("hppl1"), F("Niedrigdruckfühler (PL1)")) -MAKE_PSTR_LIST(hpPh1, F("hpph1"), F("Hochdruckfühler (PH1)")) - -// hybrid heatpump -MAKE_PSTR_LIST(enum_hybridStrategy, F("co2-optimized"), F("cost-optimized"), F("outside-temp-switched"), F("co2-cost-mix")) -MAKE_PSTR_LIST(hybridStrategy, F("hybridstrategy"), F("hybrid control strategy")) -MAKE_PSTR_LIST(switchOverTemp, F("switchovertemp"), F("outside switchover temperature")) -MAKE_PSTR_LIST(energyCostRatio, F("energycostratio"), F("energy cost ratio")) -MAKE_PSTR_LIST(fossileFactor, F("fossilefactor"), F("fossile energy factor")) -MAKE_PSTR_LIST(electricFactor, F("electricfactor"), F("electric energy factor")) -MAKE_PSTR_LIST(delayBoiler, F("delayboiler"), F("delay boiler support")) -MAKE_PSTR_LIST(tempDiffBoiler, F("tempdiffboiler"), F("tempediff boiler support")) - -// alternative heatsource AM200 -MAKE_PSTR_LIST(aCylTopTemp, F("cyltoptemp"), F("Zylinder oben Temperatur")) -MAKE_PSTR_LIST(aCylCenterTemp, F("cylcentertemp"), F("Zylinder mitte Temperatur")) -MAKE_PSTR_LIST(aCylBottomTemp, F("cylbottomtemp"), F("Zylinder unten Temperatur")) -MAKE_PSTR_LIST(aFlowTemp, F("altflowtemp"), F("Alternativ hs Flusstemperatur")) -MAKE_PSTR_LIST(aRetTemp, F("altrettemp"), F("Alternativ hs Rücktemperatur")) -MAKE_PSTR_LIST(sysFlowTemp, F("sysflowtemp"), F("System Flusstemperature")) -MAKE_PSTR_LIST(sysRetTemp, F("sysrettemp"), F("System Rücktemperature")) -MAKE_PSTR_LIST(valveByPass, F("valvebypass"), F("bypass Ventil")) -MAKE_PSTR_LIST(valveBuffer, F("valvebuffer"), F("Puffer Ventil")) -MAKE_PSTR_LIST(valveReturn, F("valvereturn"), F("Rückfluss Ventil")) -MAKE_PSTR_LIST(aPumpMod, F("altpumpmod"), F("Alternativ hs Pumpenmodulation")) -MAKE_PSTR_LIST(heatSource, F("heatsource"), F("Alternativ Heizung")) - -MAKE_PSTR_LIST(vr2Config, F("vr2config"), F("vr2 configuration")) -MAKE_PSTR_LIST(ahsActivated, F("ahsactivated"), F("alternate heat source activation")) -MAKE_PSTR_LIST(aPumpConfig, F("apumpconfig"), F("primary pump config")) -MAKE_PSTR_LIST(aPumpSignal, F("apumpsignal"), F("output for pr1 pump")) -MAKE_PSTR_LIST(aPumpMin, F("apumpmin"), F("min output pump pr1")) -MAKE_PSTR_LIST(tempRise, F("temprise"), F("ahs return temp rise")) -MAKE_PSTR_LIST(setReturnTemp, F("setreturntemp"), F("set temp return")) -MAKE_PSTR_LIST(mixRuntime, F("mixruntime"), F("mixer run time")) -// MAKE_PSTR_LIST(setFlowTemp, F("setflowtemp"), F("set flow temp")) -MAKE_PSTR_LIST(bufBypass, F("bufbypass"), F("buffer bypass config")) -MAKE_PSTR_LIST(bufMixRuntime, F("bufmixruntime"), F("bypass mixer run time")) -MAKE_PSTR_LIST(bufConfig, F("bufconfig"), F("dhw buffer config")) -MAKE_PSTR_LIST(blockMode, F("blockmode"), F("config htg. blocking mode")) -MAKE_PSTR_LIST(blockTerm, F("blockterm"), F("config of block terminal")) -MAKE_PSTR_LIST(blockHyst, F("blockhyst"), F("hyst. for bolier block")) -MAKE_PSTR_LIST(releaseWait, F("releasewait"), F("boiler release wait time")) - -// the following are dhw for the boiler and automatically tagged with 'ww' -MAKE_PSTR_LIST(wWSelTemp, F("wwseltemp"), F("gewählte Temperatur")) -MAKE_PSTR_LIST(wwSelTempLow, F("wwseltemplow"), F("selected lower temperature")) -MAKE_PSTR_LIST(wwSelTempOff, F("wwseltempoff"), F("selected temperature for off")) -MAKE_PSTR_LIST(wwSelTempSingle, F("wwseltempsingle"), F("single charge temperature")) -MAKE_PSTR_LIST(wWSetTemp, F("wwsettemp"), F("Solltemperatur")) -MAKE_PSTR_LIST(wWType, F("wwtype"), F("Typ")) -MAKE_PSTR_LIST(wWComfort, F("wwcomfort"), F("Komfort")) -MAKE_PSTR_LIST(wWFlowTempOffset, F("wwflowtempoffset"), F("Flusstemperaturanhebung")) -MAKE_PSTR_LIST(wWMaxPower, F("wwmaxpower"), F("max Leistung")) -MAKE_PSTR_LIST(wWCircPump, F("wwcircpump"), F("Zirkulationspumpe vorhanden")) -MAKE_PSTR_LIST(wWChargeType, F("wwchargetype"), F("Ladungstyp")) -MAKE_PSTR_LIST(wWDisinfectionTemp, F("wwdisinfectiontemp"), F("Desinfectionstemperatur")) -MAKE_PSTR_LIST(wWCircMode, F("wwcircmode"), F("Zirkulationspumpenfrequenz")) -MAKE_PSTR_LIST(wWCirc, F("wwcirc"), F("Zirkulation aktiv")) -MAKE_PSTR_LIST(wWCurTemp, F("wwcurtemp"), F("aktuelle Warmwasser Temperatur intern")) -MAKE_PSTR_LIST(wWCurTemp2, F("wwcurtemp2"), F("aktuelle Warmwaser Temperatur extern")) -MAKE_PSTR_LIST(wWCurFlow, F("wwcurflow"), F("aktueller Durchfluss")) -MAKE_PSTR_LIST(wWStorageTemp1, F("wwstoragetemp1"), F("interne Speichertemperature")) -MAKE_PSTR_LIST(wWStorageTemp2, F("wwstoragetemp2"), F("externer Speichertemperatur")) -MAKE_PSTR_LIST(wWActivated, F("wwactivated"), F("aktiviert")) -MAKE_PSTR_LIST(wWOneTime, F("wwonetime"), F("Einmalladung")) -MAKE_PSTR_LIST(wWDisinfecting, F("wwdisinfect"), F("Desinfizieren")) -MAKE_PSTR_LIST(wWCharging, F("wwcharging"), F("Laden")) -MAKE_PSTR_LIST(wWRecharging, F("wwrecharging"), F("Nachladen")) -MAKE_PSTR_LIST(wWTempOK, F("wwtempok"), F("Temperatur ok")) -MAKE_PSTR_LIST(wWActive, F("wwactive"), F("aktiv")) -MAKE_PSTR_LIST(wwTempOK, F("wwtempok"), F("Temperatur ok")) -MAKE_PSTR_LIST(wwActive, F("wwactive"), F("aktiv")) -MAKE_PSTR_LIST(ww3wayValve, F("ww3wayvalve"), F("3-Wegeventil aktiv")) -MAKE_PSTR_LIST(wWSetPumpPower, F("wwsetpumppower"), F("Soll Pumpenleistung")) -MAKE_PSTR_LIST(mixerTemp, F("mixertemp"), F("Mischertemperatur")) -MAKE_PSTR_LIST(wwCylMiddleTemp, F("wwcylmiddletemp"), F("cylinder middle temperature (TS3)")) -MAKE_PSTR_LIST(wWStarts, F("wwstarts"), F("Anzahl starts")) -MAKE_PSTR_LIST(wWStarts2, F("wwstarts2"), F("Kreis 2 Anzahl Starts")) -MAKE_PSTR_LIST(wWWorkM, F("wwworkm"), F("aktive Zeit")) -MAKE_PSTR_LIST(wWHystOn, F("wwhyston"), F("Hysterese Einschalttemperatur")) -MAKE_PSTR_LIST(wWHystOff, F("wwhystoff"), F("Hysterese Ausschalttemperatur")) -MAKE_PSTR_LIST(wwProgMode, F("wwprogmode"), F("Programmmodus")) -MAKE_PSTR_LIST(wwCircProg, F("wwcircprog"), F("Zirkulationsprogramm")) -MAKE_PSTR_LIST(wwMaxTemp, F("wwmaxtemp"), F("Maximale Temperatur")) -MAKE_PSTR_LIST(wwOneTimeKey, F("wwonetimekey"), F("Einmalladungstaste")) - -// mqtt values / commands -MAKE_PSTR_LIST(switchtime, F("switchtime"), F("Program Schaltzeit")) -MAKE_PSTR_LIST(switchtime1, F("switchtime1"), F("Program 1 Schaltzeit")) -MAKE_PSTR_LIST(switchtime2, F("switchtime2"), F("Programm 2 Schaltzeit")) -MAKE_PSTR_LIST(wwswitchtime, F("wwswitchtime"), F("Programm Schaltzeit")) -MAKE_PSTR_LIST(wwcircswitchtime, F("wwcircswitchtime"), F("Zirculationsprogramm Schaltzeit")) -MAKE_PSTR_LIST(dateTime, F("datetime"), F("Datum/Zeit")) -MAKE_PSTR_LIST(errorCode, F("errorcode"), F("Fehlermeldung")) -MAKE_PSTR_LIST(ibaMainDisplay, F("display"), F("Anzeige")) -MAKE_PSTR_LIST(ibaLanguage, F("language"), F("Sprache")) -MAKE_PSTR_LIST(ibaClockOffset, F("clockoffset"), F("Uhrkorrektur")) -MAKE_PSTR_LIST(ibaBuildingType, F("building"), F("Gebäude")) -MAKE_PSTR_LIST(heatingPID, F("heatingpid"), F("heating PID")) -MAKE_PSTR_LIST(ibaCalIntTemperature, F("intoffset"), F("Korrektur interner Temperatur")) -MAKE_PSTR_LIST(ibaMinExtTemperature, F("minexttemp"), F("min Aussentemperatur")) -MAKE_PSTR_LIST(backlight, F("backlight"), F("key backlight")) -MAKE_PSTR_LIST(damping, F("damping"), F("Dämpfung der Außentemperatur")) -MAKE_PSTR_LIST(tempsensor1, F("inttemp1"), F("Temperatursensor 1")) -MAKE_PSTR_LIST(tempsensor2, F("inttemp2"), F("Temperatursensor 2")) -MAKE_PSTR_LIST(dampedoutdoortemp, F("dampedoutdoortemp"), F("gedämpfte Aussentemperatur")) -MAKE_PSTR_LIST(floordrystatus, F("floordry"), F("Estrichtrocknung")) -MAKE_PSTR_LIST(floordrytemp, F("floordrytemp"), F("Estrichtrocknungs Temperatur")) -MAKE_PSTR_LIST(brightness, F("brightness"), F("bildschirmhelligkeit")) -MAKE_PSTR_LIST(autodst, F("autodst"), F("automatische sommerzeit umstellung")) -MAKE_PSTR_LIST(preheating, F("preheating"), F("vorheizen im uhrenprogramm")) -MAKE_PSTR_LIST(offtemp, F("offtemp"), F("temperatur bei ausgeschaltetem modus")) -MAKE_PSTR_LIST(mixingvalves, F("mixingvalves"), F("mischventile")) -// thermostat ww -MAKE_PSTR_LIST(wwMode, F("wwmode"), F("modus")) -MAKE_PSTR_LIST(wwSetTempLow, F("wwsettemplow"), F("untere Solltemperatur")) -MAKE_PSTR_LIST(wwCharge, F("wwcharge"), F("charge")) -MAKE_PSTR_LIST(wwChargeDuration, F("wwchargeduration"), F("charge duration")) -MAKE_PSTR_LIST(wwDisinfect, F("wwdisinfect"), F("disinfection")) -MAKE_PSTR_LIST(wwDisinfectDay, F("wwdisinfectday"), F("disinfection day")) -MAKE_PSTR_LIST(wwDisinfectHour, F("wwdisinfecthour"), F("disinfection hour")) -MAKE_PSTR_LIST(wwDisinfectTime, F("wwdisinfecttime"), F("disinfection time")) -MAKE_PSTR_LIST(wwExtra1, F("wwextra1"), F("Kreis 1 Extra")) -MAKE_PSTR_LIST(wwExtra2, F("wwextra2"), F("Kreis 2 Extra")) -MAKE_PSTR_LIST(wwDailyHeating, F("wwdailyheating"), F("daily heating")) -MAKE_PSTR_LIST(wwDailyHeatTime, F("wwdailyheattime"), F("daily heating time")) -MAKE_PSTR_LIST(wwWhenModeOff, F("wwwhenmodeoff"), F("wenn Thermostatmodus ist aus")) -// thermostat hc -MAKE_PSTR_LIST(climate, F("climate")) -MAKE_PSTR_LIST(selRoomTemp, F("seltemp"), F("Sollwert Raumtemperatur")) -MAKE_PSTR_LIST(roomTemp, F("currtemp"), F("aktuelle Raumtemperatur")) -MAKE_PSTR_LIST(mode, F("mode"), F("modus")) -MAKE_PSTR_LIST(modetype, F("modetype"), F("modus Typ")) -MAKE_PSTR_LIST(fastheatup, F("fastheatup"), F("fast heatup")) -MAKE_PSTR_LIST(daytemp, F("daytemp"), F("Tagestemperatur")) -MAKE_PSTR_LIST(daylowtemp, F("daytemp2"), F("Tagestemperatur T2")) -MAKE_PSTR_LIST(daymidtemp, F("daytemp3"), F("Tagestemperatur T3")) -MAKE_PSTR_LIST(dayhightemp, F("daytemp4"), F("Tagestemperatur T4")) -MAKE_PSTR_LIST(heattemp, F("heattemp"), F("Heizen Temperatur")) -MAKE_PSTR_LIST(nighttemp, F("nighttemp"), F("Nachttemperatur")) -MAKE_PSTR_LIST(nighttemp2, F("nighttemp"), F("Nachttemperatur T1")) -MAKE_PSTR_LIST(ecotemp, F("ecotemp"), F("eco Temperatur")) -MAKE_PSTR_LIST(manualtemp, F("manualtemp"), F("manuelle Temperatur")) -MAKE_PSTR_LIST(tempautotemp, F("tempautotemp"), F("zwischenzeitliche Solltemperatur")) -MAKE_PSTR_LIST(comforttemp, F("comforttemp"), F("Komforttemperatur")) -MAKE_PSTR_LIST(summertemp, F("summertemp"), F("Sommertemperatur")) -MAKE_PSTR_LIST(designtemp, F("designtemp"), F("design-Temperatur")) -MAKE_PSTR_LIST(offsettemp, F("offsettemp"), F("Temperaturanhebung")) -MAKE_PSTR_LIST(minflowtemp, F("minflowtemp"), F("min Flusstemperatur")) -MAKE_PSTR_LIST(maxflowtemp, F("maxflowtemp"), F("max Flusstemperatur")) -MAKE_PSTR_LIST(roominfluence, F("roominfluence"), F("Raumeinfluss")) -MAKE_PSTR_LIST(roominfl_factor, F("roominflfactor"), F("Raumeinfluss Factor")) -MAKE_PSTR_LIST(curroominfl, F("curroominfl"), F("aktueller Raumeinfluss")) -MAKE_PSTR_LIST(nofrosttemp, F("nofrosttemp"), F("Frostschutztemperatur")) -MAKE_PSTR_LIST(targetflowtemp, F("targetflowtemp"), F("berechnete Flusstemperatur")) -MAKE_PSTR_LIST(heatingtype, F("heatingtype"), F("Heizungstyp")) -MAKE_PSTR_LIST(summersetmode, F("summersetmode"), F("Einstellung Sommerbetrieb")) -MAKE_PSTR_LIST(hpoperatingmode, F("hpoperatingmode"), F("Wärmepumpe Betriebsmodus")) -MAKE_PSTR_LIST(hpoperatingstate, F("hpoperatingstate"), F("heatpump operating state")) -MAKE_PSTR_LIST(controlmode, F("controlmode"), F("Kontrollmodus")) -MAKE_PSTR_LIST(control, F("control"), F("Fernsteuerung")) -MAKE_PSTR_LIST(wwHolidays, F("wwholidays"), F("holiday dates")) -MAKE_PSTR_LIST(wwVacations, F("wwvacations"), F("vacation dates")) -MAKE_PSTR_LIST(holidays, F("holidays"), F("holiday dates")) -MAKE_PSTR_LIST(vacations, F("vacations"), F("vacation dates")) -MAKE_PSTR_LIST(program, F("program"), F("Programm")) -MAKE_PSTR_LIST(pause, F("pause"), F("Pausenzeit")) -MAKE_PSTR_LIST(party, F("party"), F("Partyzeit")) -MAKE_PSTR_LIST(wwprio, F("wwprio"), F("dhw priority")) -MAKE_PSTR_LIST(holidaytemp, F("holidaytemp"), F("Urlaubstemperatur")) -MAKE_PSTR_LIST(summermode, F("summermode"), F("Sommerbetrieb")) -MAKE_PSTR_LIST(holidaymode, F("holidaymode"), F("Urlaubsbetrieb")) -MAKE_PSTR_LIST(flowtempoffset, F("flowtempoffset"), F("Flusstemperaturanhebung")) -MAKE_PSTR_LIST(reducemode, F("reducemode"), F("Absenkmodus")) -MAKE_PSTR_LIST(noreducetemp, F("noreducetemp"), F("Absenkung unterbrechen unter Temperatur")) -MAKE_PSTR_LIST(reducetemp, F("reducetemp"), F("Absenkmodus unter Temperatur")) -MAKE_PSTR_LIST(vacreducetemp, F("vacreducetemp"), F("Urlaub Absenkmodus unter Temperatur")) -MAKE_PSTR_LIST(vacreducemode, F("vacreducemode"), F("Urlaub Absenkmodus")) -MAKE_PSTR_LIST(nofrostmode, F("nofrostmode"), F("Frostschutz Modus")) -MAKE_PSTR_LIST(nofrostmode1, F("nofrostmode1"), F("nofrost mode")) // RC310 -MAKE_PSTR_LIST(remotetemp, F("remotetemp"), F("Raumtemperatur der Fernsteuerung")) -MAKE_PSTR_LIST(reducehours, F("reducehours"), F("duration for nighttemp")) -MAKE_PSTR_LIST(reduceminutes, F("reduceminutes"), F("remaining time for nightmode")) -MAKE_PSTR_LIST(switchonoptimization, F("switchonoptimization"), F("switch-on optimization")) - -// heatpump -MAKE_PSTR_LIST(airHumidity, F("airhumidity"), F("relative Luftfeuchte")) -MAKE_PSTR_LIST(dewTemperature, F("dewtemperature"), F("Taupunkttemperatur")) - -// mixer -MAKE_PSTR_LIST(flowSetTemp, F("flowsettemp"), F("Sollwert Flusstemperatur")) -MAKE_PSTR_LIST(flowTempHc, F("flowtemphc"), F("Flusstemperatur des hk (TC1)")) -MAKE_PSTR_LIST(pumpStatus, F("pumpstatus"), F("Pumpenstatus des hk (PC1)")) -MAKE_PSTR_LIST(mixerStatus, F("valvestatus"), F("Mischerventil Position (VC1)")) -MAKE_PSTR_LIST(flowTempVf, F("flowtempvf"), F("Flusstemperatur am Kessel (T0/Vf)")) -MAKE_PSTR_LIST(mixerSetTime, F("valvesettime"), F("time to set valve")) -// mixer prefixed with wwc -MAKE_PSTR_LIST(wwPumpStatus, F("pumpstatus"), F("Pumpenstatus des wwk (PC1)")) -MAKE_PSTR_LIST(wwTempStatus, F("tempstatus"), F("Temperaturschalter des wwk (MC1)")) -MAKE_PSTR_LIST(wwTemp, F("wwtemp"), F("aktuelle Temperatur")) -// mixer pool -MAKE_PSTR_LIST(poolSetTemp, F("poolsettemp"), F("pool set temperature")) -MAKE_PSTR_LIST(poolTemp, F("pooltemp"), F("pool temperature")) -MAKE_PSTR_LIST(poolShuntStatus, F("poolshuntstatus"), F("pool shunt status opening/closing")) -MAKE_PSTR_LIST(poolShunt, F("poolshunt"), F("pool shunt open/close (0% = pool / 100% = heat)")) -MAKE_PSTR_LIST(hydrTemp, F("hydrTemp"), F("hydraulic header temperature")) - -// solar -MAKE_PSTR_LIST(collectorTemp, F("collectortemp"), F("Kollektortemperatur (TS1)")) -MAKE_PSTR_LIST(collector2Temp, F("collector2temp"), F("collector 2 temperature (TS7)")) -MAKE_PSTR_LIST(cylBottomTemp, F("cylbottomtemp"), F("Speicher Bodentemperatur (TS2)")) -MAKE_PSTR_LIST(cyl2BottomTemp, F("cyl2bottomtemp"), F("2. Speicher Bodentemperatur (TS5)")) -MAKE_PSTR_LIST(heatExchangerTemp, F("heatexchangertemp"), F("wärmetauscher Temperatur (TS6)")) -MAKE_PSTR_LIST(cylMiddleTemp, F("cylmiddletemp"), F("cylinder middle temperature (TS3)")) -MAKE_PSTR_LIST(retHeatAssist, F("retheatassist"), F("return temperature heat assistance (TS4)")) -// correct name for M1? value not found, try this: -MAKE_PSTR_LIST(m1Valve, F("heatassistvalve"), F("heat assistance valve (M1)")) -MAKE_PSTR_LIST(m1Power, F("heatassistpower"), F("heat assistance valve power (M1)")) -MAKE_PSTR_LIST(collectorMaxTemp, F("collectormaxtemp"), F("maximale Kollektortemperatur")) -MAKE_PSTR_LIST(collectorMinTemp, F("collectormintemp"), F("minimale Kollektortemperatur")) -MAKE_PSTR_LIST(cylMaxTemp, F("cylmaxtemp"), F("maximale Speichertemperatur")) -// MAKE_PSTR_LIST(cyl2MaxTemp, F("cyl2maxtemp"), F("maximum cylinder 2 temperature")) -MAKE_PSTR_LIST(solarPumpMod, F("solarpumpmod"), F("Pumpenmodulation (PS1)")) -MAKE_PSTR_LIST(cylPumpMod, F("cylpumpmod"), F("Speicherpumpenmodulation (PS5)")) -MAKE_PSTR_LIST(solarPump, F("solarpump"), F("Pumpe (PS1)")) -MAKE_PSTR_LIST(solarPump2, F("solarpump2"), F("pump 2 (PS4)")) -MAKE_PSTR_LIST(solarPump2Mod, F("solarpump2mod"), F("pump 2 modulation (PS4)")) -MAKE_PSTR_LIST(valveStatus, F("valvestatus"), F("ventilstatus")) -MAKE_PSTR_LIST(cylHeated, F("cylheated"), F("Speichertemperatur erreicht")) -MAKE_PSTR_LIST(collectorShutdown, F("collectorshutdown"), F("Kollektorabschaltung")) -MAKE_PSTR_LIST(pumpWorkTime, F("pumpworktime"), F("Pumpenlaufzeit")) -MAKE_PSTR_LIST(pump2WorkTime, F("pump2worktime"), F("Pumpe 2 Laufzeit")) -MAKE_PSTR_LIST(m1WorkTime, F("m1worktime"), F("Differenzregelung Arbeitszeit")) -MAKE_PSTR_LIST(energyLastHour, F("energylasthour"), F("Energie letzte Std")) -MAKE_PSTR_LIST(energyTotal, F("energytotal"), F("Gesamtenergie")) -MAKE_PSTR_LIST(energyToday, F("energytoday"), F("Energie heute")) -MAKE_PSTR_LIST(pumpMinMod, F("pumpminmod"), F("minimum pump modulation")) -MAKE_PSTR_LIST(maxFlow, F("maxflow"), F("maximum solar flow")) -MAKE_PSTR_LIST(solarPower, F("solarpower"), F("actual solar power")) -MAKE_PSTR_LIST(solarPumpTurnonDiff, F("turnondiff"), F("pump turn on difference")) -MAKE_PSTR_LIST(solarPumpTurnoffDiff, F("turnoffdiff"), F("pump turn off difference")) -MAKE_PSTR_LIST(pump2MinMod, F("pump2minmod"), F("minimum pump 2 modulation")) -MAKE_PSTR_LIST(solarPump2TurnonDiff, F("turnondiff2"), F("pump 2 turn on difference")) -MAKE_PSTR_LIST(solarPump2TurnoffDiff, F("turnoffdiff2"), F("pump 2 turn off difference")) - -// solar ww -MAKE_PSTR_LIST(wwTemp1, F("wwtemp1"), F("Temperatur 1")) -MAKE_PSTR_LIST(wwTemp3, F("wwtemp3"), F("Temperatur 3")) -MAKE_PSTR_LIST(wwTemp4, F("wwtemp4"), F("Temperatur 4")) -MAKE_PSTR_LIST(wwTemp5, F("wwtemp5"), F("Temperatur 5")) -MAKE_PSTR_LIST(wwTemp7, F("wwtemp7"), F("Temperatur 7")) -MAKE_PSTR_LIST(wwPump, F("wwpump"), F("Pumpe")) -// solar ww and mixer wwc -MAKE_PSTR_LIST(wwMinTemp, F("wwmintemp"), F("minimale Temperatur")) -MAKE_PSTR_LIST(wwRedTemp, F("wwredtemp"), F("redizierte Temperatur")) -MAKE_PSTR_LIST(wwDailyTemp, F("wwdailytemp"), F("tägl. Temperatur")) -MAKE_PSTR_LIST(wwKeepWarm, F("wwkeepwarm"), F("Warmhalten")) -MAKE_PSTR_LIST(wwStatus2, F("wwstatus2"), F("Status 2")) -MAKE_PSTR_LIST(enum_wwStatus2, F(""), F(""), F(""), F("no_heat"), F(""), F(""), F("heatrequest"), F(""), F("disinfecting"), F("hold")) -MAKE_PSTR_LIST(wwPumpMod, F("wwpumpmod"), F("Pumpen Modulation")) -MAKE_PSTR_LIST(wwFlow, F("wwflow"), F("Flussrate")) -// extra mixer ww -MAKE_PSTR_LIST(wwRequiredTemp, F("wwrequiredtemp"), F("benötigte Temperatur")) -MAKE_PSTR_LIST(wwDiffTemp, F("wwdifftemp"), F("Start Differential Temperatur")) - -//SM100 -MAKE_PSTR_LIST(heatTransferSystem, F("heattransfersystem"), F("Wärmetransfer System")) -MAKE_PSTR_LIST(externalCyl, F("externalcyl"), F("Externer Speicher")) -MAKE_PSTR_LIST(thermalDisinfect, F("thermaldisinfect"), F("Thermische Desinfektion")) -MAKE_PSTR_LIST(heatMetering, F("heatmetering"), F("Wärmemessung")) -MAKE_PSTR_LIST(solarIsEnabled, F("solarenabled"), F("Solarmodul aktiviert")) - -// telegram 0x035A -MAKE_PSTR_LIST(solarPumpMode, F("solarpumpmode"), F("solar Pumpen Einst.")) -MAKE_PSTR_LIST(solarPumpKick, F("pumpkick"), F("pumpkick")) -MAKE_PSTR_LIST(plainWaterMode, F("plainwatermode"), F("plain water mode")) -MAKE_PSTR_LIST(doubleMatchFlow, F("doublematchflow"), F("doublematchflow")) -MAKE_PSTR_LIST(solarPump2Mode, F("pump2mode"), F("pump 2 mode")) -MAKE_PSTR_LIST(solarPump2Kick, F("pump2kick"), F("pumpkick 2")) - -// telegram 0x035F -MAKE_PSTR_LIST(cylPriority, F("cylpriority"), F("Speicher Priorität")) - -// telegram 0x380 -MAKE_PSTR_LIST(climateZone, F("climatezone"), F("climate zone")) -MAKE_PSTR_LIST(collector1Area, F("collector1area"), F("Kollektor 1 Fläche")) -MAKE_PSTR_LIST(collector1Type, F("collector1type"), F("Kollektor 1 Type")) -MAKE_PSTR_LIST(collector2Area, F("collector2area"), F("Kollektor 2 Fläche")) -MAKE_PSTR_LIST(collector2Type, F("collector2type"), F("Kollektor 2 Type")) - -// telegram 0x0363 heatCounter -MAKE_PSTR_LIST(heatCntFlowTemp, F("heatcntflowtemp"), F("Wärmezähler Fluss-Temperatur")) -MAKE_PSTR_LIST(heatCntRetTemp, F("heatcntrettemp"), F("Wärmezähler Rückfluss-Temperatur")) -MAKE_PSTR_LIST(heatCnt, F("heatcnt"), F("Wärmezäler Impulse")) -MAKE_PSTR_LIST(swapFlowTemp, F("swapflowtemp"), F("Austausch Fluss-Temperatur (TS14)")) -MAKE_PSTR_LIST(swapRetTemp, F("swaprettemp"), F("Austausch Rückfluss-Temperatur (TS15)")) - -// switch -MAKE_PSTR_LIST(activated, F("activated"), F("aktiviert")) -MAKE_PSTR_LIST(status, F("status"), F("Status")) - -// unknown fields to track (SM10) -MAKE_PSTR_LIST(data11, F("data11"), F("unknown datafield 11")) -MAKE_PSTR_LIST(data12, F("data12"), F("unknown datafield 12")) -MAKE_PSTR_LIST(data8, F("data8"), F("unknown datafield 8")) -MAKE_PSTR_LIST(data0, F("data0"), F("unknown datafield 0")) -MAKE_PSTR_LIST(data1, F("data1"), F("unknown datafield 1")) -MAKE_PSTR_LIST(setting3, F("setting3"), F("unknown setting 3")) -MAKE_PSTR_LIST(setting4, F("setting4"), F("unknown setting 4")) - -// RF sensor, id 0x40, telegram 0x435 -MAKE_PSTR_LIST(RFTemp, F("rftemp"), F("RF Raumtemperatur Sensor")); diff --git a/src/locale_EN.h b/src/locale_EN.h deleted file mode 100644 index 93b9b8248..000000000 --- a/src/locale_EN.h +++ /dev/null @@ -1,848 +0,0 @@ -/* - * EMS-ESP - https://github.com/emsesp/EMS-ESP - * Copyright 2020 Paul Derbyshire - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -// common words -MAKE_PSTR_WORD(debug) -MAKE_PSTR_WORD(exit) -MAKE_PSTR_WORD(help) -MAKE_PSTR_WORD(log) -MAKE_PSTR_WORD(logout) -MAKE_PSTR_WORD(enabled) -MAKE_PSTR_WORD(disabled) -MAKE_PSTR_WORD(set) -MAKE_PSTR_WORD(show) -MAKE_PSTR_WORD(on) -MAKE_PSTR_WORD(off) -MAKE_PSTR_WORD(ON) -MAKE_PSTR_WORD(OFF) -MAKE_PSTR_WORD(su) -MAKE_PSTR_WORD(name) -MAKE_PSTR_WORD(auto) -MAKE_PSTR_WORD(scan) -MAKE_PSTR_WORD(password) -MAKE_PSTR_WORD(read) -MAKE_PSTR_WORD(version) -MAKE_PSTR_WORD(values) -MAKE_PSTR_WORD(system) -MAKE_PSTR_WORD(fetch) -MAKE_PSTR_WORD(restart) -MAKE_PSTR_WORD(format) -MAKE_PSTR_WORD(raw) -MAKE_PSTR_WORD(watch) -MAKE_PSTR_WORD(syslog) -MAKE_PSTR_WORD(send) -MAKE_PSTR_WORD(telegram) -MAKE_PSTR_WORD(bus_id) -MAKE_PSTR_WORD(tx_mode) -MAKE_PSTR_WORD(ems) -MAKE_PSTR_WORD(devices) -MAKE_PSTR_WORD(shower) -MAKE_PSTR_WORD(mqtt) -MAKE_PSTR_WORD(emsesp) -MAKE_PSTR_WORD(connected) -MAKE_PSTR_WORD(disconnected) -MAKE_PSTR_WORD(passwd) -MAKE_PSTR_WORD(hostname) -MAKE_PSTR_WORD(wifi) -MAKE_PSTR_WORD(reconnect) -MAKE_PSTR_WORD(ssid) -MAKE_PSTR_WORD(heartbeat) -MAKE_PSTR_WORD(users) -MAKE_PSTR_WORD(publish) -MAKE_PSTR_WORD(timeout) -MAKE_PSTR_WORD(board_profile) -MAKE_PSTR_WORD(setvalue) - -// for commands -MAKE_PSTR_WORD(call) -MAKE_PSTR_WORD(cmd) -MAKE_PSTR_WORD(id) -MAKE_PSTR_WORD(hc) -MAKE_PSTR_WORD(wwc) -MAKE_PSTR_WORD(device) -MAKE_PSTR_WORD(data) -MAKE_PSTR_WORD(command) -MAKE_PSTR_WORD(commands) -MAKE_PSTR_WORD(info) -MAKE_PSTR_WORD(settings) -MAKE_PSTR_WORD(customizations) -MAKE_PSTR_WORD(value) -MAKE_PSTR_WORD(error) -MAKE_PSTR_WORD(entities) - -// devices -MAKE_PSTR_WORD(boiler) -MAKE_PSTR_WORD(thermostat) -MAKE_PSTR_WORD(switch) -MAKE_PSTR_WORD(solar) -MAKE_PSTR_WORD(mixer) -MAKE_PSTR_WORD(gateway) -MAKE_PSTR_WORD(controller) -MAKE_PSTR_WORD(connect) -MAKE_PSTR_WORD(heatpump) -MAKE_PSTR_WORD(generic) -MAKE_PSTR_WORD(analogsensor) -MAKE_PSTR_WORD(unknown) -MAKE_PSTR_WORD(dallassensor) - -// format strings -MAKE_PSTR(host_fmt, "Host: %s") -MAKE_PSTR(port_fmt, "Port: %d") -MAKE_PSTR(hostname_fmt, "Hostname: %s") -MAKE_PSTR(board_profile_fmt, "Board Profile: %s") -MAKE_PSTR(mark_interval_fmt, "Mark interval: %lus") -MAKE_PSTR(wifi_ssid_fmt, "WiFi SSID: %s") -MAKE_PSTR(wifi_password_fmt, "WiFi Password: %S") -MAKE_PSTR(tx_mode_fmt, "Tx mode: %d") -MAKE_PSTR(bus_id_fmt, "Bus ID: %02X") -MAKE_PSTR(log_level_fmt, "Log level: %s") - -MAKE_STR(productid_fmt, "%s EMS ProductID") - -MAKE_PSTR_LIST(enum_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(enum_watch, F_(off), F_(on), F_(raw), F_(unknown)) -MAKE_PSTR_LIST(enum_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")) - -// strings -MAKE_PSTR(EMSESP, "EMS-ESP") -MAKE_PSTR(cmd_optional, "[cmd]") -MAKE_PSTR(ha_optional, "[ha]") -MAKE_PSTR(deep_optional, "[deep]") -MAKE_PSTR(watchid_optional, "[ID]") -MAKE_PSTR(watch_format_optional, "[off | on | raw | unknown]") -MAKE_PSTR(invalid_watch, "Invalid watch type") -MAKE_PSTR(data_mandatory, "\"XX XX ...\"") -MAKE_PSTR(asterisks, "********") -MAKE_PSTR(n_mandatory, "") -MAKE_PSTR(sensorid_optional, "[sensor ID]") -MAKE_PSTR(id_optional, "[id|hc]") -MAKE_PSTR(data_optional, "[data]") -MAKE_PSTR(offset_optional, "[offset]") -MAKE_PSTR(length_optional, "[length]") -MAKE_PSTR(typeid_mandatory, "") -MAKE_PSTR(deviceid_mandatory, "") -MAKE_PSTR(device_type_optional, "[device]") -MAKE_PSTR(invalid_log_level, "Invalid log level") -MAKE_PSTR(log_level_optional, "[level]") -MAKE_PSTR(name_mandatory, "") -MAKE_PSTR(name_optional, "[name]") -MAKE_PSTR(new_password_prompt1, "Enter new password: ") -MAKE_PSTR(new_password_prompt2, "Retype new password: ") -MAKE_PSTR(password_prompt, "Password: ") -MAKE_PSTR(unset, "") - -// command descriptions -MAKE_PSTR(info_cmd, "lists all values") -MAKE_PSTR(commands_cmd, "lists all commands") -MAKE_PSTR(entities_cmd, "lists all entities") - -MAKE_PSTR_WORD(number) -MAKE_PSTR_WORD(enum) -MAKE_PSTR_WORD(text) - -MAKE_PSTR_WORD(2) -MAKE_PSTR_WORD(4) -MAKE_PSTR_WORD(10) -MAKE_PSTR_WORD(100) -MAKE_PSTR_WORD(60) - -MAKE_PSTR_LIST(div2, F_(2)) -MAKE_PSTR_LIST(div4, F_(4)) -MAKE_PSTR_LIST(div10, F_(10)) -MAKE_PSTR_LIST(div60, F_(60)) -MAKE_PSTR_LIST(div100, F_(100)) -MAKE_PSTR_LIST(mul5, F("-5")) -MAKE_PSTR_LIST(mul10, F("-10")) -MAKE_PSTR_LIST(mul15, F("-15")) - -// Unit Of Measurement mapping - maps to DeviceValueUOM_s in emsdevice.cpp -// uom - also used with HA see https://github.com/home-assistant/core/blob/d7ac4bd65379e11461c7ce0893d3533d8d8b8cbf/homeassistant/const.py#L384 -MAKE_PSTR(blank, " ") -MAKE_PSTR(percent, "%") -MAKE_PSTR(degrees, "°C") -MAKE_PSTR(kwh, "kWh") -MAKE_PSTR(wh, "Wh") -MAKE_PSTR(bar, "bar") -MAKE_PSTR(minutes, "minutes") -MAKE_PSTR(hours, "hours") -MAKE_PSTR(days, "days") -MAKE_PSTR(ua, "uA") -MAKE_PSTR(lmin, "l/min") -MAKE_PSTR(kw, "kW") -MAKE_PSTR(w, "W") -MAKE_PSTR(kb, "KB") -MAKE_PSTR(seconds, "seconds") -MAKE_PSTR(dbm, "dBm") -MAKE_PSTR(fahrenheit, "°F") -MAKE_PSTR(mv, "mV") -MAKE_PSTR(sqm, "sqm") -MAKE_PSTR(m3, "m3") -MAKE_PSTR(l, "l") -// MAKE_PSTR(times, "times") -// MAKE_PSTR(oclock, "o'clock") - -// TAG mapping - maps to DeviceValueTAG_s in emsdevice.cpp -// use empty string if want to suppress showing tags -// mqtt tags must not have spaces -MAKE_PSTR(tag_none, "") -MAKE_PSTR(tag_heartbeat, "") -MAKE_PSTR(tag_boiler_data_ww, "dhw") -MAKE_PSTR(tag_device_data, "") -MAKE_PSTR(tag_device_data_ww, "dhw") -MAKE_PSTR(tag_hc1, "hc1") -MAKE_PSTR(tag_hc2, "hc2") -MAKE_PSTR(tag_hc3, "hc3") -MAKE_PSTR(tag_hc4, "hc4") -MAKE_PSTR(tag_hc5, "hc5") -MAKE_PSTR(tag_hc6, "hc6") -MAKE_PSTR(tag_hc7, "hc7") -MAKE_PSTR(tag_hc8, "hc8") -MAKE_PSTR(tag_wwc1, "wwc1") -MAKE_PSTR(tag_wwc2, "wwc2") -MAKE_PSTR(tag_wwc3, "wwc3") -MAKE_PSTR(tag_wwc4, "wwc4") -MAKE_PSTR(tag_wwc5, "wwc5") -MAKE_PSTR(tag_wwc6, "wwc6") -MAKE_PSTR(tag_wwc7, "wwc7") -MAKE_PSTR(tag_wwc8, "wwc8") -MAKE_PSTR(tag_wwc9, "wwc9") -MAKE_PSTR(tag_wwc10, "wwc10") -MAKE_PSTR(tag_ahs, "ahs") -MAKE_PSTR(tag_hs1, "hs1") -MAKE_PSTR(tag_hs2, "hs2") -MAKE_PSTR(tag_hs3, "hs3") -MAKE_PSTR(tag_hs4, "hs4") -MAKE_PSTR(tag_hs5, "hs5") -MAKE_PSTR(tag_hs6, "hs6") -MAKE_PSTR(tag_hs7, "hs7") -MAKE_PSTR(tag_hs8, "hs8") -MAKE_PSTR(tag_hs9, "hs9") -MAKE_PSTR(tag_hs10, "hs10") -MAKE_PSTR(tag_hs11, "hs11") -MAKE_PSTR(tag_hs12, "hs12") -MAKE_PSTR(tag_hs13, "hs13") -MAKE_PSTR(tag_hs14, "hs14") -MAKE_PSTR(tag_hs15, "hs15") -MAKE_PSTR(tag_hs16, "hs16") - -// MQTT topic names -// MAKE_PSTR(tag_heartbeat_mqtt, "heartbeat") -// MAKE_PSTR(tag_boiler_data_mqtt, "") -MAKE_PSTR(tag_boiler_data_ww_mqtt, "ww") -MAKE_PSTR(tag_device_data_ww_mqtt, "") - -// boiler -MAKE_PSTR_WORD(time) -MAKE_PSTR_WORD(date) -MAKE_PSTR_WORD(1x3min) -MAKE_PSTR_WORD(2x3min) -MAKE_PSTR_WORD(3x3min) -MAKE_PSTR_WORD(4x3min) -MAKE_PSTR_WORD(5x3min) -MAKE_PSTR_WORD(6x3min) -MAKE_PSTR_WORD(continuous) -MAKE_PSTR(3wayvalve, "3-way valve") -MAKE_PSTR(chargepump, "charge pump") -MAKE_PSTR_WORD(hot) -MAKE_PSTR_WORD(high_comfort) -MAKE_PSTR_WORD(eco) -MAKE_PSTR_WORD(intelligent) -MAKE_PSTR_WORD(flow) -MAKE_PSTR_WORD(manual) -MAKE_PSTR_WORD(buffer) -MAKE_PSTR(bufferedflow, "buffered flow") -MAKE_PSTR(layeredbuffer, "layered buffer") -MAKE_PSTR_WORD(maintenance) -MAKE_PSTR_WORD(heating) -MAKE_PSTR_WORD(cooling) - -// boiler lists -MAKE_PSTR_LIST(tpl_date, F("Format: < dd.mm.yyyy >")) // template for text input -MAKE_PSTR_LIST(enum_off_time_date_manual, F_(off), F_(time), F_(date), F_(manual)) -MAKE_PSTR_LIST(enum_freq, F_(off), F_(1x3min), F_(2x3min), F_(3x3min), F_(4x3min), F_(5x3min), F_(6x3min), F_(continuous)) -MAKE_PSTR_LIST(enum_charge, F_(chargepump), F_(3wayvalve)) -MAKE_PSTR_LIST(enum_comfort, F_(hot), F_(eco), F_(intelligent)) -MAKE_PSTR_LIST(enum_comfort1, F_(high_comfort), F_(eco)) -MAKE_PSTR_LIST(enum_flow, F_(off), F_(flow), F_(bufferedflow), F_(buffer), F_(layeredbuffer)) -MAKE_PSTR_LIST(enum_reset, F("-"), F_(maintenance), F_(error)) -// MAKE_PSTR_LIST(enum_bool, F_(off), F_(on)) - -// AM200 lists -MAKE_PSTR_LIST(enum_vr2Config, F_(off), F("bypass")); -MAKE_PSTR_LIST(enum_aPumpSignal, F_(off), F("pwm"), F("pwm_invers")); -MAKE_PSTR_LIST(enum_bufBypass, F("no"), F_(mixer), F("valve")); -MAKE_PSTR_LIST(enum_bufConfig, F("monovalent"), F("bivalent")); -MAKE_PSTR_LIST(enum_blockMode, F_(off), F_(auto), F("blocking")); -MAKE_PSTR_LIST(enum_blockTerm, F("n_o"), F("n_c")); - -//heatpump -MAKE_PSTR_LIST(enum_hpactivity, F("none"), F_(heating), F_(cooling), F("hot_water"), F("pool")) - -// mixer -MAKE_PSTR_LIST(enum_shunt, F("stopped"), F("opening"), F("closing"), F("open"), F("close")) - -// thermostat -MAKE_PSTR_WORD(light) -MAKE_PSTR_WORD(medium) -MAKE_PSTR_WORD(heavy) -MAKE_PSTR_WORD(own_prog) -MAKE_PSTR_WORD(start) -MAKE_PSTR_WORD(heat) -MAKE_PSTR_WORD(hold) -MAKE_PSTR_WORD(cool) -MAKE_PSTR_WORD(end) -MAKE_PSTR_WORD(german) -MAKE_PSTR_WORD(dutch) -MAKE_PSTR_WORD(french) -MAKE_PSTR_WORD(italian) -MAKE_PSTR_WORD(high) -MAKE_PSTR_WORD(low) -MAKE_PSTR_WORD(radiator) -MAKE_PSTR_WORD(convector) -MAKE_PSTR_WORD(floor) -MAKE_PSTR_WORD(summer) -MAKE_PSTR_WORD(winter) -MAKE_PSTR_WORD(outdoor) -MAKE_PSTR_WORD(mpc) -MAKE_PSTR_WORD(room) -MAKE_PSTR_WORD(room_outdoor) -MAKE_PSTR_WORD(power) -MAKE_PSTR_WORD(constant) -MAKE_PSTR_WORD(simple) -MAKE_PSTR_WORD(optimized) -MAKE_PSTR_WORD(nofrost) -MAKE_PSTR_WORD(comfort) -MAKE_PSTR_WORD(night) -MAKE_PSTR_WORD(day) -MAKE_PSTR_WORD(holiday) -MAKE_PSTR_WORD(reduce) -MAKE_PSTR_WORD(noreduce) -MAKE_PSTR_WORD(offset) -MAKE_PSTR_WORD(design) -MAKE_PSTR_WORD(tempauto) -MAKE_PSTR_WORD(minflow) -MAKE_PSTR_WORD(maxflow) -MAKE_PSTR_WORD(rc3x) -MAKE_PSTR_WORD(rc20) - -MAKE_PSTR(internal_temperature, "internal temperature") -MAKE_PSTR(internal_setpoint, "internal setpoint") -MAKE_PSTR(external_temperature, "external temperature") -MAKE_PSTR(burner_temperature, "burner temperature") -MAKE_PSTR(ww_temperature, "ww temperature") -MAKE_PSTR(functioning_mode, "functioning mode") -MAKE_PSTR(smoke_temperature, "smoke temperature") - -// thermostat lists -MAKE_PSTR_LIST(tpl_datetime, F("Format: < NTP | dd.mm.yyyy-hh:mm:ss-day(0-6)-dst(0/1) >")) -MAKE_PSTR_LIST(tpl_switchtime, F("Format: [ not_set | day hh:mm on|off ]")) -MAKE_PSTR_LIST(tpl_switchtime1, F("Format: [ not_set | day hh:mm Tn ]")) -MAKE_PSTR_LIST(tpl_holidays, F("format: < dd.mm.yyyy-dd.mm.yyyy >")) -MAKE_PSTR_LIST(enum_ibaMainDisplay, - F_(internal_temperature), - F_(internal_setpoint), - F_(external_temperature), - F_(burner_temperature), - F_(ww_temperature), - F_(functioning_mode), - F_(time), - F_(date), - F_(smoke_temperature)) -MAKE_PSTR_LIST(enum_ibaLanguage, F_(german), F_(dutch), F_(french), F_(italian)) -MAKE_PSTR_LIST(enum_ibaLanguage_RC30, F_(german), F_(dutch)) -MAKE_PSTR_LIST(enum_floordrystatus, F_(off), F_(start), F_(heat), F_(hold), F_(cool), F_(end)) -MAKE_PSTR_LIST(enum_ibaBuildingType, F_(light), F_(medium), F_(heavy)) -MAKE_PSTR_LIST(enum_PID, F("fast"), F_(medium), F("slow")) -MAKE_PSTR_LIST(enum_wwMode, F_(off), F("normal"), F_(comfort), F_(auto), F_(own_prog), F_(eco)) -MAKE_PSTR_LIST(enum_wwCircMode, F_(off), F_(on), F_(auto), F_(own_prog)) -MAKE_PSTR_LIST(enum_wwMode2, F_(off), F_(on), F_(auto)) -MAKE_PSTR_LIST(enum_wwMode3, F_(on), F_(off), F_(auto)) -MAKE_PSTR_LIST(enum_heatingtype, F_(off), F_(radiator), F_(convector), F_(floor)) -MAKE_PSTR_LIST(enum_summermode, F_(summer), F_(auto), F_(winter)) -MAKE_PSTR_LIST(enum_hpoperatingmode, F_(off), F_(auto), F_(heating), F_(cooling)) -MAKE_PSTR_LIST(enum_summer, F_(winter), F_(summer)) -MAKE_PSTR_LIST(enum_operatingstate, F_(heating), F_(off), F_(cooling)) - -MAKE_PSTR_LIST(enum_mode, F_(manual), F_(auto)) // RC100, RC300, RC310 -MAKE_PSTR_LIST(enum_mode2, F_(off), F_(manual), F_(auto)) // RC20 -MAKE_PSTR_LIST(enum_mode3, F_(night), F_(day), F_(auto)) // RC35, RC30, RC25 -MAKE_PSTR_LIST(enum_mode4, F_(nofrost), F_(eco), F_(heat), F_(auto)) // JUNKERS -MAKE_PSTR_LIST(enum_mode5, F_(auto), F_(off)) // CRF -MAKE_PSTR_LIST(enum_mode6, F_(nofrost), F_(night), F_(day)) // RC10 - -MAKE_PSTR_LIST(enum_modetype, F_(eco), F_(comfort)) -// MAKE_PSTR_LIST(enum_modetype2, F_(day)) -MAKE_PSTR_LIST(enum_modetype3, F_(night), F_(day)) -MAKE_PSTR_LIST(enum_modetype4, F_(nofrost), F_(eco), F_(heat)) -MAKE_PSTR_LIST(enum_modetype5, F_(off), F_(on)) - -MAKE_PSTR_LIST(enum_reducemode, F_(nofrost), F_(reduce), F_(room), F_(outdoor)) -MAKE_PSTR_LIST(enum_reducemode1, F_(outdoor), F_(room), F_(reduce)) // RC310 values: 1-3 -MAKE_PSTR_LIST(enum_nofrostmode, F_(off), F_(room), F_(outdoor)) -MAKE_PSTR_LIST(enum_nofrostmode1, F_(room), F_(outdoor), F_(room_outdoor)) - -MAKE_PSTR_LIST(enum_controlmode, F_(off), F_(optimized), F_(simple), F_(mpc), F_(room), F_(power), F_(constant)) -MAKE_PSTR_LIST(enum_controlmode1, F("weather-compensated"), F("outside-basepoint"), F("n/a"), F_(room)) // RC310 1-4 -MAKE_PSTR_LIST(enum_controlmode2, F_(outdoor), F_(room)) -// MAKE_PSTR_LIST(enum_controlmode3, F_(off), F_(room), F_(outdoor), F("room+outdoor")) -MAKE_PSTR_LIST(enum_control, F_(off), F_(rc20), F_(rc3x)) -MAKE_PSTR_LIST(enum_j_control, F_(off), F("fb10"), F("fb100")) - -MAKE_PSTR_LIST(enum_wwProgMode, F("std_prog"), F_(own_prog)) -MAKE_PSTR_LIST(enum_dayOfWeek, F("mo"), F("tu"), F("we"), F("th"), F("fr"), F("sa"), F("su"), F("all")) -MAKE_PSTR_LIST(enum_progMode, F("prog_1"), F("prog_2")) -MAKE_PSTR_LIST(enum_progMode2, F("own_1"), F("family"), F("morning"), F("evening"), F("am"), F("pm"), F("midday"), F("singles"), F("seniors"), F("new"), F("own_2")) -MAKE_PSTR_LIST(enum_progMode3, F("family"), F("morning"), F("evening"), F("am"), F("pm"), F("midday"), F("singles"), F("seniors")) -MAKE_PSTR_LIST(enum_progMode4, F("prog_a"), F("prog_b"), F("prog_c"), F("prog_d"), F("prog_e"), F("prog_f")) - -MAKE_PSTR_LIST(enum_switchmode, F_(off), F_(eco), F_(comfort), F_(heat)) -MAKE_PSTR_LIST(enum_climate, F("selTemp"), F("roomTemp")) - -// solar list -MAKE_PSTR_LIST(enum_solarmode, F_(constant), F("pwm"), F("analog")) -MAKE_PSTR_LIST(enum_collectortype, F("flat"), F("vacuum")) -MAKE_PSTR_LIST(enum_cylprio, F("cyl_1"), F("cyl_2")) - -// id used to store the device ID. empty full name so only gets displayed in the MQTT payload -MAKE_PSTR_LIST(ID, F_(id)) - -// Boiler -// extra commands, with no json output -MAKE_PSTR_LIST(wwtapactivated, F("wwtapactivated"), F("turn on/off")) -MAKE_PSTR_LIST(reset, F("reset"), F("reset")) - -// single mqtt topics -MAKE_PSTR_WORD(heating_active) -MAKE_PSTR_WORD(tapwater_active) -MAKE_PSTR_WORD(response) - -// mqtt, commands and text -MAKE_PSTR_LIST(heatingActive, F("heatingactive"), F("heating active")) -MAKE_PSTR_LIST(tapwaterActive, F("tapwateractive"), F("tapwater active")) -MAKE_PSTR_LIST(selFlowTemp, F("selflowtemp"), F("selected flow temperature")) -MAKE_PSTR_LIST(selBurnPow, F("selburnpow"), F("burner selected max power")) -MAKE_PSTR_LIST(heatingPumpMod, F("heatingpumpmod"), F("heating pump modulation")) -MAKE_PSTR_LIST(heatingPump2Mod, F("heatingpump2mod"), F("heating pump 2 modulation")) -MAKE_PSTR_LIST(outdoorTemp, F("outdoortemp"), F("outside temperature")) -MAKE_PSTR_LIST(curFlowTemp, F("curflowtemp"), F("current flow temperature")) -MAKE_PSTR_LIST(retTemp, F("rettemp"), F("return temperature")) -MAKE_PSTR_LIST(switchTemp, F("switchtemp"), F("mixing switch temperature")) -MAKE_PSTR_LIST(sysPress, F("syspress"), F("system pressure")) -MAKE_PSTR_LIST(boilTemp, F("boiltemp"), F("actual boiler temperature")) -MAKE_PSTR_LIST(exhaustTemp, F("exhausttemp"), F("exhaust temperature")) -MAKE_PSTR_LIST(burnGas, F("burngas"), F("gas")) -MAKE_PSTR_LIST(burnGas2, F("burngas2"), F("gas stage 2")) -MAKE_PSTR_LIST(flameCurr, F("flamecurr"), F("flame current")) -MAKE_PSTR_LIST(heatingPump, F("heatingpump"), F("heating pump")) -MAKE_PSTR_LIST(fanWork, F("fanwork"), F("fan")) -MAKE_PSTR_LIST(ignWork, F("ignwork"), F("ignition")) -MAKE_PSTR_LIST(oilPreHeat, F("oilpreheat"), F("oil preheating")) -MAKE_PSTR_LIST(heatingActivated, F("heatingactivated"), F("heating activated")) -MAKE_PSTR_LIST(heatingTemp, F("heatingtemp"), F("heating temperature")) -MAKE_PSTR_LIST(pumpModMax, F("pumpmodmax"), F("burner pump max power")) -MAKE_PSTR_LIST(pumpModMin, F("pumpmodmin"), F("burner pump min power")) -MAKE_PSTR_LIST(pumpDelay, F("pumpdelay"), F("pump delay")) -MAKE_PSTR_LIST(burnMinPeriod, F("burnminperiod"), F("burner min period")) -MAKE_PSTR_LIST(burnMinPower, F("burnminpower"), F("burner min power")) -MAKE_PSTR_LIST(burnMaxPower, F("burnmaxpower"), F("burner max power")) -MAKE_PSTR_LIST(boilHystOn, F("boilhyston"), F("hysteresis on temperature")) -MAKE_PSTR_LIST(boilHystOff, F("boilhystoff"), F("hysteresis off temperature")) -MAKE_PSTR_LIST(setFlowTemp, F("setflowtemp"), F("set flow temperature")) -MAKE_PSTR_LIST(setBurnPow, F("setburnpow"), F("burner set power")) -MAKE_PSTR_LIST(curBurnPow, F("curburnpow"), F("burner current power")) -MAKE_PSTR_LIST(burnStarts, F("burnstarts"), F("burner starts")) -MAKE_PSTR_LIST(burnWorkMin, F("burnworkmin"), F("total burner operating time")) -MAKE_PSTR_LIST(burn2WorkMin, F("burn2workmin"), F("burner stage 2 operating time")) -MAKE_PSTR_LIST(heatWorkMin, F("heatworkmin"), F("total heat operating time")) -MAKE_PSTR_LIST(UBAuptime, F("ubauptime"), F("total UBA operating time")) -MAKE_PSTR_LIST(lastCode, F("lastcode"), F("last error code")) -MAKE_PSTR_LIST(serviceCode, F("servicecode"), F("service code")) -MAKE_PSTR_LIST(serviceCodeNumber, F("servicecodenumber"), F("service code number")) -MAKE_PSTR_LIST(maintenanceMessage, F("maintenancemessage"), F("maintenance message")) -MAKE_PSTR_LIST(maintenanceDate, F("maintenancedate"), F("next maintenance date")) -MAKE_PSTR_LIST(maintenanceType, F_(maintenance), F("maintenance scheduled")) -MAKE_PSTR_LIST(maintenanceTime, F("maintenancetime"), F("time to next maintenance")) -MAKE_PSTR_LIST(emergencyOps, F("emergencyops"), F("emergency operation")) -MAKE_PSTR_LIST(emergencyTemp, F("emergencytemp"), F("emergency temperature")) - -// heatpump/compress specific -MAKE_PSTR_LIST(upTimeControl, F("uptimecontrol"), F("total operating time heat")) -MAKE_PSTR_LIST(upTimeCompHeating, F("uptimecompheating"), F("operating time compressor heating")) -MAKE_PSTR_LIST(upTimeCompCooling, F("uptimecompcooling"), F("operating time compressor cooling")) -MAKE_PSTR_LIST(upTimeCompWw, F("uptimecompww"), F("operating time compressor dhw")) -MAKE_PSTR_LIST(upTimeCompPool, F("uptimecomppool"), F("operating time compressor pool")) -MAKE_PSTR_LIST(totalCompStarts, F("totalcompstarts"), F("total compressor control starts")) -MAKE_PSTR_LIST(heatingStarts, F("heatingstarts"), F("heating control starts")) -MAKE_PSTR_LIST(coolingStarts, F("coolingstarts"), F("cooling control starts")) -MAKE_PSTR_LIST(poolStarts, F("poolstarts"), F("pool control starts")) -MAKE_PSTR_LIST(nrgConsTotal, F("nrgconstotal"), F("total energy consumption")) -MAKE_PSTR_LIST(nrgConsCompTotal, F("nrgconscomptotal"), F("total energy consumption compressor")) -MAKE_PSTR_LIST(nrgConsCompHeating, F("nrgconscompheating"), F("energy consumption compressor heating")) -MAKE_PSTR_LIST(nrgConsCompWw, F("nrgconscompww"), F("energy consumption compressor dhw")) -MAKE_PSTR_LIST(nrgConsCompCooling, F("nrgconscompcooling"), F("energy consumption compressor cooling")) -MAKE_PSTR_LIST(nrgConsCompPool, F("nrgconscomppool"), F("energy consumption compressor pool")) -MAKE_PSTR_LIST(nrgSuppTotal, F("nrgsupptotal"), F("total energy supplied")) -MAKE_PSTR_LIST(nrgSuppHeating, F("nrgsuppheating"), F("total energy supplied heating")) -MAKE_PSTR_LIST(nrgSuppWw, F("nrgsuppww"), F("total energy warm supplied dhw")) -MAKE_PSTR_LIST(nrgSuppCooling, F("nrgsuppcooling"), F("total energy supplied cooling")) -MAKE_PSTR_LIST(nrgSuppPool, F("nrgsupppool"), F("total energy supplied pool")) -MAKE_PSTR_LIST(auxElecHeatNrgConsTotal, F("auxelecheatnrgconstotal"), F("total auxiliary electrical heater energy consumption")) -MAKE_PSTR_LIST(auxElecHeatNrgConsHeating, F("auxelecheatnrgconsheating"), F("auxiliary electrical heater energy consumption heating")) -MAKE_PSTR_LIST(auxElecHeatNrgConsWW, F("auxelecheatnrgconsww"), F("auxiliary electrical heater energy consumption dhw")) -MAKE_PSTR_LIST(auxElecHeatNrgConsPool, F("auxelecheatnrgconspool"), F("auxiliary electrical heater energy consumption pool")) - -MAKE_PSTR_LIST(hpPower, F("hppower"), F("compressor power output")) -MAKE_PSTR_LIST(hpCompOn, F("hpcompon"), F("hp compressor")) -MAKE_PSTR_LIST(hpHeatingOn, F("hpheatingon"), F("hp heating")) -MAKE_PSTR_LIST(hpCoolingOn, F("hpcoolingon"), F("hp cooling")) -MAKE_PSTR_LIST(hpWwOn, F("hpwwon"), F("hp dhw")) -MAKE_PSTR_LIST(hpPoolOn, F("hppoolon"), F("hp pool")) -MAKE_PSTR_LIST(hpBrinePumpSpd, F("hpbrinepumpspd"), F("brine pump speed")) -MAKE_PSTR_LIST(hpCompSpd, F("hpcompspd"), F("compressor speed")) -MAKE_PSTR_LIST(hpCircSpd, F("hpcircspd"), F("circulation pump speed")) -MAKE_PSTR_LIST(hpBrineIn, F("hpbrinein"), F("brine in/evaporator")) -MAKE_PSTR_LIST(hpBrineOut, F("hpbrineout"), F("brine out/condenser")) -MAKE_PSTR_LIST(hpSuctionGas, F("hpsuctiongas"), F("suction gas")) -MAKE_PSTR_LIST(hpHotGas, F("hphotgas"), F("hot gas/compressed")) -MAKE_PSTR_LIST(hpSwitchValve, F("hpswitchvalve"), F("switch valve")) -MAKE_PSTR_LIST(hpActivity, F("hpactivity"), F("compressor activity")) -MAKE_PSTR_LIST(hpTc0, F("hptc0"), F("heat carrier return (TC0)")) -MAKE_PSTR_LIST(hpTc1, F("hptc1"), F("heat carrier forward (TC1)")) -MAKE_PSTR_LIST(hpTc3, F("hptc3"), F("condenser temperature (TC3)")) -MAKE_PSTR_LIST(hpTr3, F("hptr3"), F("refrigerant temperature liquid side (condenser output) (TR3)")) -MAKE_PSTR_LIST(hpTr4, F("hptr4"), F("evaporator inlet temperature (TR4)")) -MAKE_PSTR_LIST(hpTr5, F("hptr5"), F("compressor Inlet temperature (TR5)")) -MAKE_PSTR_LIST(hpTr6, F("hptr6"), F("compressor outlet temperature (TR6)")) -MAKE_PSTR_LIST(hpTr7, F("hptr7"), F("refrigerant temperature gas side (condenser input) (TR7)")) -MAKE_PSTR_LIST(hpTl2, F("hptl2"), F("air inlet temperature (TL2)")) -MAKE_PSTR_LIST(hpPl1, F("hppl1"), F("low pressure side temperature (PL1)")) -MAKE_PSTR_LIST(hpPh1, F("hpph1"), F("high pressure side temperature (PH1)")) - -// hybrid heatpump -MAKE_PSTR_LIST(enum_hybridStrategy, F("co2-optimized"), F("cost-optimized"), F("outside-temp-switched"), F("co2-cost-mix")) -MAKE_PSTR_LIST(hybridStrategy, F("hybridstrategy"), F("hybrid control strategy")) -MAKE_PSTR_LIST(switchOverTemp, F("switchovertemp"), F("outside switchover temperature")) -MAKE_PSTR_LIST(energyCostRatio, F("energycostratio"), F("energy cost ratio")) -MAKE_PSTR_LIST(fossileFactor, F("fossilefactor"), F("fossile energy factor")) -MAKE_PSTR_LIST(electricFactor, F("electricfactor"), F("electric energy factor")) -MAKE_PSTR_LIST(delayBoiler, F("delayboiler"), F("delay boiler support")) -MAKE_PSTR_LIST(tempDiffBoiler, F("tempdiffboiler"), F("tempediff boiler support")) - -// alternative heatsource AM200 -MAKE_PSTR_LIST(aCylTopTemp, F("cyltoptemp"), F("cylinder top temperature")) -MAKE_PSTR_LIST(aCylCenterTemp, F("cylcentertemp"), F("cylinder center temperature")) -MAKE_PSTR_LIST(aCylBottomTemp, F("cylbottomtemp"), F("cylinder bottom temperature")) -MAKE_PSTR_LIST(aFlowTemp, F("altflowtemp"), F("alternative hs flow temperature")) -MAKE_PSTR_LIST(aRetTemp, F("altrettemp"), F("alternative hs return temperature")) -MAKE_PSTR_LIST(sysFlowTemp, F("sysflowtemp"), F("system flow temperature")) -MAKE_PSTR_LIST(sysRetTemp, F("sysrettemp"), F("system return temperature")) -MAKE_PSTR_LIST(valveByPass, F("valvebypass"), F("bypass valve")) -MAKE_PSTR_LIST(valveBuffer, F("valvebuffer"), F("buffer valve")) -MAKE_PSTR_LIST(valveReturn, F("valvereturn"), F("return valve")) -MAKE_PSTR_LIST(aPumpMod, F("altpumpmod"), F("alternative hs pump modulation")) -MAKE_PSTR_LIST(heatSource, F("heatsource"), F("alternative heating active")) - -MAKE_PSTR_LIST(vr2Config, F("vr2config"), F("vr2 configuration")) -MAKE_PSTR_LIST(ahsActivated, F("ahsactivated"), F("alternate heat source activation")) -MAKE_PSTR_LIST(aPumpConfig, F("apumpconfig"), F("primary pump config")) -MAKE_PSTR_LIST(aPumpSignal, F("apumpsignal"), F("output for pr1 pump")) -MAKE_PSTR_LIST(aPumpMin, F("apumpmin"), F("min output pump pr1")) -MAKE_PSTR_LIST(tempRise, F("temprise"), F("ahs return temp rise")) -MAKE_PSTR_LIST(setReturnTemp, F("setreturntemp"), F("set temp return")) -MAKE_PSTR_LIST(mixRuntime, F("mixruntime"), F("mixer run time")) -// MAKE_PSTR_LIST(setFlowTemp, F("setflowtemp"), F("set flow temp")) -MAKE_PSTR_LIST(bufBypass, F("bufbypass"), F("buffer bypass config")) -MAKE_PSTR_LIST(bufMixRuntime, F("bufmixruntime"), F("bypass mixer run time")) -MAKE_PSTR_LIST(bufConfig, F("bufconfig"), F("dhw buffer config")) -MAKE_PSTR_LIST(blockMode, F("blockmode"), F("config htg. blocking mode")) -MAKE_PSTR_LIST(blockTerm, F("blockterm"), F("config of block terminal")) -MAKE_PSTR_LIST(blockHyst, F("blockhyst"), F("hyst. for bolier block")) -MAKE_PSTR_LIST(releaseWait, F("releasewait"), F("boiler release wait time")) - -// the following are dhw for the boiler and automatically tagged with 'ww' -MAKE_PSTR_LIST(wwSelTemp, F("wwseltemp"), F("selected temperature")) -MAKE_PSTR_LIST(wwSelTempLow, F("wwseltemplow"), F("selected lower temperature")) -MAKE_PSTR_LIST(wwSelTempOff, F("wwseltempoff"), F("selected temperature for off")) -MAKE_PSTR_LIST(wwSelTempSingle, F("wwseltempsingle"), F("single charge temperature")) -MAKE_PSTR_LIST(wwSetTemp, F("wwsettemp"), F("set temperature")) -MAKE_PSTR_LIST(wwType, F("wwtype"), F("type")) -MAKE_PSTR_LIST(wwComfort, F("wwcomfort"), F("comfort")) -MAKE_PSTR_LIST(wwComfort1, F("wwcomfort1"), F("comfort mode")) -MAKE_PSTR_LIST(wwFlowTempOffset, F("wwflowtempoffset"), F("flow temperature offset")) -MAKE_PSTR_LIST(wwMaxPower, F("wwmaxpower"), F("max power")) -MAKE_PSTR_LIST(wwCircPump, F("wwcircpump"), F("circulation pump available")) -MAKE_PSTR_LIST(wwChargeType, F("wwchargetype"), F("charging type")) -MAKE_PSTR_LIST(wwDisinfectionTemp, F("wwdisinfectiontemp"), F("disinfection temperature")) -MAKE_PSTR_LIST(wwCircMode, F("wwcircmode"), F("circulation pump mode")) // also used in thermostat -MAKE_PSTR_LIST(wwCirc, F("wwcirc"), F("circulation active")) -MAKE_PSTR_LIST(wwCurTemp, F("wwcurtemp"), F("current intern temperature")) -MAKE_PSTR_LIST(wwCurTemp2, F("wwcurtemp2"), F("current extern temperature")) -MAKE_PSTR_LIST(wwCurFlow, F("wwcurflow"), F("current tap water flow")) -MAKE_PSTR_LIST(wwStorageTemp1, F("wwstoragetemp1"), F("storage intern temperature")) -MAKE_PSTR_LIST(wwStorageTemp2, F("wwstoragetemp2"), F("storage extern temperature")) -MAKE_PSTR_LIST(wwActivated, F("wwactivated"), F("activated")) -MAKE_PSTR_LIST(wwOneTime, F("wwonetime"), F("one time charging")) -MAKE_PSTR_LIST(wwDisinfecting, F("wwdisinfecting"), F("disinfecting")) -MAKE_PSTR_LIST(wwCharging, F("wwcharging"), F("charging")) -MAKE_PSTR_LIST(wwChargeOptimization, F("wwchargeoptimization"), F("charge optimization")) -MAKE_PSTR_LIST(wwRecharging, F("wwrecharging"), F("recharging")) -MAKE_PSTR_LIST(wwTempOK, F("wwtempok"), F("temperature ok")) -MAKE_PSTR_LIST(wwActive, F("wwactive"), F("active")) -MAKE_PSTR_LIST(ww3wayValve, F("ww3wayvalve"), F("3way valve active")) -MAKE_PSTR_LIST(wwSetPumpPower, F("wwsetpumppower"), F("set pump power")) -MAKE_PSTR_LIST(wwMixerTemp, F("wwmixertemp"), F("mixer temperature")) -MAKE_PSTR_LIST(wwCylMiddleTemp, F("wwcylmiddletemp"), F("cylinder middle temperature (TS3)")) -MAKE_PSTR_LIST(wwStarts, F("wwstarts"), F("starts")) -MAKE_PSTR_LIST(wwStarts2, F("wwstarts2"), F("control starts2")) -MAKE_PSTR_LIST(wwWorkM, F("wwworkm"), F("active time")) -MAKE_PSTR_LIST(wwHystOn, F("wwhyston"), F("hysteresis on temperature")) -MAKE_PSTR_LIST(wwHystOff, F("wwhystoff"), F("hysteresis off temperature")) -MAKE_PSTR_LIST(wwProgMode, F("wwprogmode"), F("program")) -MAKE_PSTR_LIST(wwCircProg, F("wwcircprog"), F("circulation program")) -MAKE_PSTR_LIST(wwMaxTemp, F("wwmaxtemp"), F("maximum temperature")) -MAKE_PSTR_LIST(wwOneTimeKey, F("wwonetimekey"), F("one time key function")) - -// mqtt values / commands -MAKE_PSTR_LIST(switchtime, F("switchtime"), F("program switchtime")) -MAKE_PSTR_LIST(switchtime1, F("switchtime1"), F("own1 program switchtime")) -MAKE_PSTR_LIST(switchtime2, F("switchtime2"), F("own2 program switchtime")) -MAKE_PSTR_LIST(wwswitchtime, F("wwswitchtime"), F("program switchtime")) -MAKE_PSTR_LIST(wwcircswitchtime, F("wwcircswitchtime"), F("circulation program switchtime")) -MAKE_PSTR_LIST(dateTime, F("datetime"), F("date/time")) -MAKE_PSTR_LIST(errorCode, F("errorcode"), F("error code")) -MAKE_PSTR_LIST(ibaMainDisplay, F("display"), F("display")) -MAKE_PSTR_LIST(ibaLanguage, F("language"), F("language")) -MAKE_PSTR_LIST(ibaClockOffset, F("clockoffset"), F("clock offset")) -MAKE_PSTR_LIST(ibaBuildingType, F("building"), F("building type")) -MAKE_PSTR_LIST(heatingPID, F("heatingpid"), F("heating PID")) -MAKE_PSTR_LIST(ibaCalIntTemperature, F("intoffset"), F("internal temperature offset")) -MAKE_PSTR_LIST(ibaMinExtTemperature, F("minexttemp"), F("minimal external temperature")) -MAKE_PSTR_LIST(backlight, F("backlight"), F("key backlight")) -MAKE_PSTR_LIST(damping, F("damping"), F("damping outdoor temperature")) -MAKE_PSTR_LIST(tempsensor1, F("inttemp1"), F("temperature sensor 1")) -MAKE_PSTR_LIST(tempsensor2, F("inttemp2"), F("temperature sensor 2")) -MAKE_PSTR_LIST(dampedoutdoortemp, F("dampedoutdoortemp"), F("damped outdoor temperature")) -MAKE_PSTR_LIST(floordrystatus, F("floordry"), F("floor drying")) -MAKE_PSTR_LIST(floordrytemp, F("floordrytemp"), F("floor drying temperature")) -MAKE_PSTR_LIST(brightness, F("brightness"), F("screen brightness")) -MAKE_PSTR_LIST(autodst, F("autodst"), F("automatic change daylight saving time")) -MAKE_PSTR_LIST(preheating, F("preheating"), F("preheating in the clock program")) -MAKE_PSTR_LIST(offtemp, F("offtemp"), F("temperature when mode is off")) -MAKE_PSTR_LIST(mixingvalves, F("mixingvalves"), F("mixing valves")) -// thermostat ww -MAKE_PSTR_LIST(wwMode, F("wwmode"), F("mode")) -MAKE_PSTR_LIST(wwSetTempLow, F("wwsettemplow"), F("set low temperature")) -MAKE_PSTR_LIST(wwCharge, F("wwcharge"), F("charge")) -MAKE_PSTR_LIST(wwChargeDuration, F("wwchargeduration"), F("charge duration")) -MAKE_PSTR_LIST(wwDisinfect, F("wwdisinfect"), F("disinfection")) -MAKE_PSTR_LIST(wwDisinfectDay, F("wwdisinfectday"), F("disinfection day")) -MAKE_PSTR_LIST(wwDisinfectHour, F("wwdisinfecthour"), F("disinfection hour")) -MAKE_PSTR_LIST(wwDisinfectTime, F("wwdisinfecttime"), F("disinfection time")) -MAKE_PSTR_LIST(wwExtra1, F("wwextra1"), F("circuit 1 extra")) -MAKE_PSTR_LIST(wwExtra2, F("wwextra2"), F("circuit 2 extra")) -MAKE_PSTR_LIST(wwDailyHeating, F("wwdailyheating"), F("daily heating")) -MAKE_PSTR_LIST(wwDailyHeatTime, F("wwdailyheattime"), F("daily heating time")) -MAKE_PSTR_LIST(wwWhenModeOff, F("wwwhenmodeoff"), F("when thermostat mode off")) -// thermostat hc -MAKE_PSTR_LIST(climate, F("HA climate config creation")) // no full-name, hidden, only for creation -MAKE_PSTR_LIST(selRoomTemp, F("seltemp"), F("selected room temperature")) -MAKE_PSTR_LIST(roomTemp, F("currtemp"), F("current room temperature")) -MAKE_PSTR_LIST(mode, F("mode"), F("mode")) -MAKE_PSTR_LIST(modetype, F("modetype"), F("mode type")) -MAKE_PSTR_LIST(fastheatup, F("fastheatup"), F("fast heatup")) -MAKE_PSTR_LIST(daytemp, F("daytemp"), F("day temperature")) -MAKE_PSTR_LIST(daylowtemp, F("daytemp2"), F("day temperature T2")) -MAKE_PSTR_LIST(daymidtemp, F("daytemp3"), F("day temperature T3")) -MAKE_PSTR_LIST(dayhightemp, F("daytemp4"), F("day temperature T4")) -MAKE_PSTR_LIST(heattemp, F("heattemp"), F("heat temperature")) -MAKE_PSTR_LIST(nighttemp, F("nighttemp"), F("night temperature")) -MAKE_PSTR_LIST(nighttemp2, F("nighttemp"), F("night temperature T1")) -MAKE_PSTR_LIST(ecotemp, F("ecotemp"), F("eco temperature")) -MAKE_PSTR_LIST(manualtemp, F("manualtemp"), F("manual temperature")) -MAKE_PSTR_LIST(tempautotemp, F("tempautotemp"), F("temporary set temperature automode")) -MAKE_PSTR_LIST(remoteseltemp, F("remoteseltemp"), F("temporary set temperature from remote")) -MAKE_PSTR_LIST(comforttemp, F("comforttemp"), F("comfort temperature")) -MAKE_PSTR_LIST(summertemp, F("summertemp"), F("summer temperature")) -MAKE_PSTR_LIST(designtemp, F("designtemp"), F("design temperature")) -MAKE_PSTR_LIST(offsettemp, F("offsettemp"), F("offset temperature")) -MAKE_PSTR_LIST(minflowtemp, F("minflowtemp"), F("min flow temperature")) -MAKE_PSTR_LIST(maxflowtemp, F("maxflowtemp"), F("max flow temperature")) -MAKE_PSTR_LIST(roominfluence, F("roominfluence"), F("room influence")) -MAKE_PSTR_LIST(roominfl_factor, F("roominflfactor"), F("room influence factor")) -MAKE_PSTR_LIST(curroominfl, F("curroominfl"), F("current room influence")) -MAKE_PSTR_LIST(nofrosttemp, F("nofrosttemp"), F("nofrost temperature")) -MAKE_PSTR_LIST(targetflowtemp, F("targetflowtemp"), F("target flow temperature")) -MAKE_PSTR_LIST(heatingtype, F("heatingtype"), F("heating type")) -MAKE_PSTR_LIST(summersetmode, F("summersetmode"), F("set summer mode")) -MAKE_PSTR_LIST(hpoperatingmode, F("hpoperatingmode"), F("heatpump operating mode")) -MAKE_PSTR_LIST(hpoperatingstate, F("hpoperatingstate"), F("heatpump operating state")) -MAKE_PSTR_LIST(controlmode, F("controlmode"), F("control mode")) -MAKE_PSTR_LIST(control, F("control"), F("control device")) -MAKE_PSTR_LIST(wwHolidays, F("wwholidays"), F("holiday dates")) -MAKE_PSTR_LIST(wwVacations, F("wwvacations"), F("vacation dates")) -MAKE_PSTR_LIST(holidays, F("holidays"), F("holiday dates")) -MAKE_PSTR_LIST(vacations, F("vacations"), F("vacation dates")) -MAKE_PSTR_LIST(program, F("program"), F("program")) -MAKE_PSTR_LIST(pause, F("pause"), F("pause time")) -MAKE_PSTR_LIST(party, F("party"), F("party time")) -MAKE_PSTR_LIST(wwprio, F("wwprio"), F("dhw priority")) -MAKE_PSTR_LIST(holidaytemp, F("holidaytemp"), F("holiday temperature")) -MAKE_PSTR_LIST(summermode, F("summermode"), F("summer mode")) -MAKE_PSTR_LIST(holidaymode, F("holidaymode"), F("holiday mode")) -MAKE_PSTR_LIST(flowtempoffset, F("flowtempoffset"), F("flow temperature offset for mixer")) -MAKE_PSTR_LIST(reducemode, F("reducemode"), F("reduce mode")) -MAKE_PSTR_LIST(noreducetemp, F("noreducetemp"), F("no reduce below temperature")) -MAKE_PSTR_LIST(reducetemp, F("reducetemp"), F("off/reduce switch temperature")) -MAKE_PSTR_LIST(vacreducetemp, F("vacreducetemp"), F("vacations off/reduce switch temperature")) -MAKE_PSTR_LIST(vacreducemode, F("vacreducemode"), F("vacations reduce mode")) -MAKE_PSTR_LIST(nofrostmode, F("nofrostmode"), F("nofrost mode")) -MAKE_PSTR_LIST(nofrostmode1, F("nofrostmode1"), F("nofrost mode")) // RC310 -MAKE_PSTR_LIST(remotetemp, F("remotetemp"), F("room temperature from remote")) -MAKE_PSTR_LIST(reducehours, F("reducehours"), F("duration for nighttemp")) -MAKE_PSTR_LIST(reduceminutes, F("reduceminutes"), F("remaining time for nightmode")) -MAKE_PSTR_LIST(switchonoptimization, F("switchonoptimization"), F("switch-on optimization")) - -// heatpump -MAKE_PSTR_LIST(airHumidity, F("airhumidity"), F("relative air humidity")) -MAKE_PSTR_LIST(dewTemperature, F("dewtemperature"), F("dew point temperature")) - -// mixer -MAKE_PSTR_LIST(flowSetTemp, F("flowsettemp"), F("setpoint flow temperature")) -MAKE_PSTR_LIST(flowTempHc, F("flowtemphc"), F("flow temperature (TC1)")) -MAKE_PSTR_LIST(pumpStatus, F("pumpstatus"), F("pump status (PC1)")) -MAKE_PSTR_LIST(mixerStatus, F("valvestatus"), F("mixing valve actuator (VC1)")) -MAKE_PSTR_LIST(flowTempVf, F("flowtempvf"), F("flow temperature in header (T0/Vf)")) -MAKE_PSTR_LIST(mixerSetTime, F("valvesettime"), F("time to set valve")) -// mixer prefixed with wwc -MAKE_PSTR_LIST(wwPumpStatus, F("pumpstatus"), F("pump status in assigned wwc (PC1)")) -MAKE_PSTR_LIST(wwTempStatus, F("wwtempstatus"), F("temperature switch in assigned wwc (MC1)")) -MAKE_PSTR_LIST(wwTemp, F("wwtemp"), F("current temperature")) -// mixer pool -MAKE_PSTR_LIST(poolSetTemp, F("poolsettemp"), F("pool set temperature")) -MAKE_PSTR_LIST(poolTemp, F("pooltemp"), F("pool temperature")) -MAKE_PSTR_LIST(poolShuntStatus, F("poolshuntstatus"), F("pool shunt status opening/closing")) -MAKE_PSTR_LIST(poolShunt, F("poolshunt"), F("pool shunt open/close (0% = pool / 100% = heat)")) -MAKE_PSTR_LIST(hydrTemp, F("hydrTemp"), F("hydraulic header temperature")) - -// solar -MAKE_PSTR_LIST(collectorTemp, F("collectortemp"), F("collector temperature (TS1)")) -MAKE_PSTR_LIST(collector2Temp, F("collector2temp"), F("collector 2 temperature (TS7)")) -MAKE_PSTR_LIST(cylBottomTemp, F("cylbottomtemp"), F("cylinder bottom temperature (TS2)")) -MAKE_PSTR_LIST(cyl2BottomTemp, F("cyl2bottomtemp"), F("second cylinder bottom temperature (TS5)")) -MAKE_PSTR_LIST(heatExchangerTemp, F("heatexchangertemp"), F("heat exchanger temperature (TS6)")) -MAKE_PSTR_LIST(cylMiddleTemp, F("cylmiddletemp"), F("cylinder middle temperature (TS3)")) -MAKE_PSTR_LIST(retHeatAssist, F("retheatassist"), F("return temperature heat assistance (TS4)")) -// correct name for M1? value not found, try this: -MAKE_PSTR_LIST(m1Valve, F("heatassistvalve"), F("heat assistance valve (M1)")) -MAKE_PSTR_LIST(m1Power, F("heatassistpower"), F("heat assistance valve power (M1)")) -MAKE_PSTR_LIST(collectorMaxTemp, F("collectormaxtemp"), F("maximum collector temperature")) -MAKE_PSTR_LIST(collectorMinTemp, F("collectormintemp"), F("minimum collector temperature")) -MAKE_PSTR_LIST(cylMaxTemp, F("cylmaxtemp"), F("maximum cylinder temperature")) -// MAKE_PSTR_LIST(cyl2MaxTemp, F("cyl2maxtemp"), F("maximum cylinder 2 temperature")) -MAKE_PSTR_LIST(solarPumpMod, F("solarpumpmod"), F("pump modulation (PS1)")) -MAKE_PSTR_LIST(cylPumpMod, F("cylpumpmod"), F("cylinder pump modulation (PS5)")) -MAKE_PSTR_LIST(solarPump, F("solarpump"), F("pump (PS1)")) -MAKE_PSTR_LIST(solarPump2, F("solarpump2"), F("pump 2 (PS4)")) -MAKE_PSTR_LIST(solarPump2Mod, F("solarpump2mod"), F("pump 2 modulation (PS4)")) -MAKE_PSTR_LIST(valveStatus, F("valvestatus"), F("valve status")) -MAKE_PSTR_LIST(cylHeated, F("cylheated"), F("cyl heated")) -MAKE_PSTR_LIST(collectorShutdown, F("collectorshutdown"), F("collector shutdown")) -MAKE_PSTR_LIST(pumpWorkTime, F("pumpworktime"), F("pump working time")) -MAKE_PSTR_LIST(pump2WorkTime, F("pump2worktime"), F("pump 2 working time")) -MAKE_PSTR_LIST(m1WorkTime, F("m1worktime"), F("differential control working time")) -MAKE_PSTR_LIST(energyLastHour, F("energylasthour"), F("energy last hour")) -MAKE_PSTR_LIST(energyTotal, F("energytotal"), F("total energy")) -MAKE_PSTR_LIST(energyToday, F("energytoday"), F("total energy today")) -MAKE_PSTR_LIST(pumpMinMod, F("pumpminmod"), F("minimum pump modulation")) -MAKE_PSTR_LIST(maxFlow, F("maxflow"), F("maximum solar flow")) -MAKE_PSTR_LIST(solarPower, F("solarpower"), F("actual solar power")) -MAKE_PSTR_LIST(solarPumpTurnonDiff, F("turnondiff"), F("pump turn on difference")) -MAKE_PSTR_LIST(solarPumpTurnoffDiff, F("turnoffdiff"), F("pump turn off difference")) -MAKE_PSTR_LIST(pump2MinMod, F("pump2minmod"), F("minimum pump 2 modulation")) -MAKE_PSTR_LIST(solarPump2TurnonDiff, F("turnondiff2"), F("pump 2 turn on difference")) -MAKE_PSTR_LIST(solarPump2TurnoffDiff, F("turnoffdiff2"), F("pump 2 turn off difference")) - -// solar ww -MAKE_PSTR_LIST(wwTemp1, F("wwtemp1"), F("temperature 1")) -MAKE_PSTR_LIST(wwTemp3, F("wwtemp3"), F("temperature 3")) -MAKE_PSTR_LIST(wwTemp4, F("wwtemp4"), F("temperature 4")) -MAKE_PSTR_LIST(wwTemp5, F("wwtemp5"), F("temperature 5")) -MAKE_PSTR_LIST(wwTemp7, F("wwtemp7"), F("temperature 7")) -MAKE_PSTR_LIST(wwPump, F("wwpump"), F("pump")) -// solar ww and mixer wwc -MAKE_PSTR_LIST(wwMinTemp, F("wwmintemp"), F("minimum temperature")) -MAKE_PSTR_LIST(wwRedTemp, F("wwredtemp"), F("reduced temperature")) -MAKE_PSTR_LIST(wwDailyTemp, F("wwdailytemp"), F("daily temperature")) -MAKE_PSTR_LIST(wwKeepWarm, F("wwkeepwarm"), F("keep warm")) -MAKE_PSTR_LIST(wwStatus2, F("wwstatus2"), F("status 2")) -MAKE_PSTR_LIST(enum_wwStatus2, F(""), F(""), F(""), F("no_heat"), F(""), F(""), F("heatrequest"), F(""), F("disinfecting"), F("hold")) -MAKE_PSTR_LIST(wwPumpMod, F("wwpumpmod"), F("pump modulation")) -MAKE_PSTR_LIST(wwFlow, F("wwflow"), F("flow rate")) -// extra mixer ww -MAKE_PSTR_LIST(wwRequiredTemp, F("wwrequiredtemp"), F("required temperature")) -MAKE_PSTR_LIST(wwDiffTemp, F("wwdifftemp"), F("start differential temperature")) - -//SM100 -MAKE_PSTR_LIST(heatTransferSystem, F("heattransfersystem"), F("heattransfer system")) -MAKE_PSTR_LIST(externalCyl, F("externalcyl"), F("external cylinder")) -MAKE_PSTR_LIST(thermalDisinfect, F("thermaldisinfect"), F("thermal disinfection")) -MAKE_PSTR_LIST(heatMetering, F("heatmetering"), F("heatmetering")) -MAKE_PSTR_LIST(solarIsEnabled, F("solarenabled"), F("solarmodule enabled")) - -// telegram 0x035A -MAKE_PSTR_LIST(solarPumpMode, F("solarpumpmode"), F("pump mode")) -MAKE_PSTR_LIST(solarPumpKick, F("pumpkick"), F("pumpkick")) -MAKE_PSTR_LIST(plainWaterMode, F("plainwatermode"), F("plain water mode")) -MAKE_PSTR_LIST(doubleMatchFlow, F("doublematchflow"), F("doublematchflow")) -MAKE_PSTR_LIST(solarPump2Mode, F("pump2mode"), F("pump 2 mode")) -MAKE_PSTR_LIST(solarPump2Kick, F("pump2kick"), F("pumpkick 2")) - -// telegram 0x035F -MAKE_PSTR_LIST(cylPriority, F("cylpriority"), F("cylinder priority")) - -// telegram 0x380 -MAKE_PSTR_LIST(climateZone, F("climatezone"), F("climate zone")) -MAKE_PSTR_LIST(collector1Area, F("collector1area"), F("collector 1 area")) -MAKE_PSTR_LIST(collector1Type, F("collector1type"), F("collector 1 type")) -MAKE_PSTR_LIST(collector2Area, F("collector2area"), F("collector 2 area")) -MAKE_PSTR_LIST(collector2Type, F("collector2type"), F("collector 2 type")) - -// telegram 0x0363 heatCounter -MAKE_PSTR_LIST(heatCntFlowTemp, F("heatcntflowtemp"), F("heat counter flow temperature")) -MAKE_PSTR_LIST(heatCntRetTemp, F("heatcntrettemp"), F("heat counter return temperature")) -MAKE_PSTR_LIST(heatCnt, F("heatcnt"), F("heat counter impulses")) -MAKE_PSTR_LIST(swapFlowTemp, F("swapflowtemp"), F("swap flow temperature (TS14)")) -MAKE_PSTR_LIST(swapRetTemp, F("swaprettemp"), F("swap return temperature (TS15)")) - -// switch -MAKE_PSTR_LIST(activated, F("activated"), F("activated")) -MAKE_PSTR_LIST(status, F("status"), F("status")) - -// unknown fields to track (SM10) -MAKE_PSTR_LIST(data11, F("data11"), F("unknown datafield 11")) -MAKE_PSTR_LIST(data12, F("data12"), F("unknown datafield 12")) -MAKE_PSTR_LIST(data8, F("data8"), F("unknown datafield 8")) -MAKE_PSTR_LIST(data0, F("data0"), F("unknown datafield 0")) -MAKE_PSTR_LIST(data1, F("data1"), F("unknown datafield 1")) -MAKE_PSTR_LIST(setting3, F("setting3"), F("unknown setting 3")) -MAKE_PSTR_LIST(setting4, F("setting4"), F("unknown setting 4")) - -// RF sensor, id 0x40, telegram 0x435 -MAKE_PSTR_LIST(RFTemp, F("rftemp"), F("RF room temperature sensor")); diff --git a/src/locale_common.h b/src/locale_common.h new file mode 100644 index 000000000..b0d32323a --- /dev/null +++ b/src/locale_common.h @@ -0,0 +1,370 @@ +/* + * EMS-ESP - https://github.com/emsesp/EMS-ESP + * Copyright 2020 Paul Derbyshire + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" + +/* + * THIS FILE CONTAINS STANDARD STRING LITERALS THAT DON'T NEED LANGUAGE TRANSLATIONS + */ + +// common words +MAKE_PSTR_WORD(debug) +MAKE_PSTR_WORD(exit) +MAKE_PSTR_WORD(help) +MAKE_PSTR_WORD(log) +MAKE_PSTR_WORD(logout) +MAKE_PSTR_WORD(enabled) +MAKE_PSTR_WORD(disabled) +MAKE_PSTR_WORD(set) +MAKE_PSTR_WORD(show) +MAKE_PSTR_WORD(su) +MAKE_PSTR_WORD(name) +MAKE_PSTR_WORD(scan) +MAKE_PSTR_WORD(password) +MAKE_PSTR_WORD(read) +MAKE_PSTR_WORD(version) +MAKE_PSTR_WORD(values) +MAKE_PSTR_WORD(system) +MAKE_PSTR_WORD(fetch) +MAKE_PSTR_WORD(restart) +MAKE_PSTR_WORD(format) +MAKE_PSTR_WORD(raw) +MAKE_PSTR_WORD(watch) +MAKE_PSTR_WORD(syslog) +MAKE_PSTR_WORD(send) +MAKE_PSTR_WORD(telegram) +MAKE_PSTR_WORD(bus_id) +MAKE_PSTR_WORD(tx_mode) +MAKE_PSTR_WORD(ems) +MAKE_PSTR_WORD(devices) +MAKE_PSTR_WORD(shower) +MAKE_PSTR_WORD(mqtt) +MAKE_PSTR_WORD(emsesp) +MAKE_PSTR_WORD(connected) +MAKE_PSTR_WORD(disconnected) +MAKE_PSTR_WORD(passwd) +MAKE_PSTR_WORD(hostname) +MAKE_PSTR_WORD(wifi) +MAKE_PSTR_WORD(reconnect) +MAKE_PSTR_WORD(ssid) +MAKE_PSTR_WORD(heartbeat) +MAKE_PSTR_WORD(users) +MAKE_PSTR_WORD(publish) +MAKE_PSTR_WORD(timeout) +MAKE_PSTR_WORD(board_profile) +MAKE_PSTR_WORD(setvalue) + +// for commands +MAKE_PSTR_WORD(call) +MAKE_PSTR_WORD(cmd) +MAKE_PSTR_WORD(id) +MAKE_PSTR_WORD(hc) +MAKE_PSTR_WORD(wwc) +MAKE_PSTR_WORD(device) +MAKE_PSTR_WORD(data) +MAKE_PSTR_WORD(command) +MAKE_PSTR_WORD(commands) +MAKE_PSTR_WORD(info) +MAKE_PSTR_WORD(settings) +MAKE_PSTR_WORD(customizations) +MAKE_PSTR_WORD(value) +MAKE_PSTR_WORD(entities) + +// devices +MAKE_PSTR_WORD(boiler) +MAKE_PSTR_WORD(thermostat) +MAKE_PSTR_WORD(switch) +MAKE_PSTR_WORD(solar) +MAKE_PSTR_WORD(mixer) +MAKE_PSTR_WORD(gateway) +MAKE_PSTR_WORD(controller) +MAKE_PSTR_WORD(connect) +MAKE_PSTR_WORD(heatpump) +MAKE_PSTR_WORD(generic) +MAKE_PSTR_WORD(analogsensor) +MAKE_PSTR_WORD(dallassensor) + +MAKE_PSTR(number, "number") +MAKE_PSTR(enum, "enum") +MAKE_PSTR(text, "text") + +// Console +MAKE_PSTR(EMSESP, "EMS-ESP") +MAKE_PSTR(host_fmt, "Host: %s") +MAKE_PSTR(port_fmt, "Port: %d") +MAKE_PSTR(hostname_fmt, "Hostname: %s") +MAKE_PSTR(board_profile_fmt, "Board Profile: %s") +MAKE_PSTR(mark_interval_fmt, "Mark interval: %lus") +MAKE_PSTR(wifi_ssid_fmt, "WiFi SSID: %s") +MAKE_PSTR(wifi_password_fmt, "WiFi Password: %S") +MAKE_PSTR(tx_mode_fmt, "Tx mode: %d") +MAKE_PSTR(bus_id_fmt, "Bus ID: %02X") +MAKE_PSTR(log_level_fmt, "Log level: %s") +MAKE_PSTR(cmd_optional, "[cmd]") +MAKE_PSTR(ha_optional, "[ha]") +MAKE_PSTR(deep_optional, "[deep]") +MAKE_PSTR(watchid_optional, "[ID]") +MAKE_PSTR(watch_format_optional, "[off | on | raw | unknown]") +MAKE_PSTR(invalid_watch, "Invalid watch type") +MAKE_PSTR(data_mandatory, "\"XX XX ...\"") +MAKE_PSTR(asterisks, "********") +MAKE_PSTR(n_mandatory, "") +MAKE_PSTR(sensorid_optional, "[sensor ID]") +MAKE_PSTR(id_optional, "[id|hc]") +MAKE_PSTR(data_optional, "[data]") +MAKE_PSTR(offset_optional, "[offset]") +MAKE_PSTR(length_optional, "[length]") +MAKE_PSTR(typeid_mandatory, "") +MAKE_PSTR(deviceid_mandatory, "") +MAKE_PSTR(device_type_optional, "[device]") +MAKE_PSTR(invalid_log_level, "Invalid log level") +MAKE_PSTR(log_level_optional, "[level]") +MAKE_PSTR(name_mandatory, "") +MAKE_PSTR(name_optional, "[name]") +MAKE_PSTR(new_password_prompt1, "Enter new password: ") +MAKE_PSTR(new_password_prompt2, "Retype new password: ") +MAKE_PSTR(password_prompt, "Password: ") +MAKE_PSTR(unset, "") + +// more common names that don't need translations +MAKE_PSTR_LIST(1x3min, F("1x3min")) +MAKE_PSTR_LIST(2x3min, F("2x3min")) +MAKE_PSTR_LIST(3x3min, F("3x3min")) +MAKE_PSTR_LIST(4x3min, F("4x3min")) +MAKE_PSTR_LIST(5x3min, F("5x3min")) +MAKE_PSTR_LIST(6x3min, F("6x3min")) +MAKE_PSTR_LIST(auto, F("auto")) +MAKE_PSTR_LIST(na, F("n/a")) +MAKE_PSTR_LIST(rc3x, F("rc3x")) +MAKE_PSTR_LIST(rc20, F("rc20")) +MAKE_PSTR_LIST(fb10, F("fb10")) +MAKE_PSTR_LIST(fb100, F("fb100")) +MAKE_PSTR_LIST(dash, F("-")) +MAKE_PSTR_LIST(error, F("error")) +MAKE_PSTR_LIST(BLANK, F("")) +MAKE_PSTR_LIST(pwm, F("pwm")) +MAKE_PSTR_LIST(pwm_invers, F("pwm inverse")) +MAKE_PSTR_LIST(mpc, F("mpc")) +MAKE_PSTR_LIST(tempauto, F("temp auto")) +MAKE_PSTR_LIST(bypass, F("bypass")) +MAKE_PSTR_LIST(mixer, F("mixer")) +MAKE_PSTR_LIST(monovalent, F("monovalent")) +MAKE_PSTR_LIST(bivalent, F("bivalent")) +MAKE_PSTR_LIST(n_o, F("n_o")) +MAKE_PSTR_LIST(n_c, F("n_c")) +MAKE_PSTR_LIST(prog1, F("prog 1")) +MAKE_PSTR_LIST(prog2, F("prog 2")) +MAKE_PSTR_LIST(proga, F("prog a")) +MAKE_PSTR_LIST(progb, F("prog b")) +MAKE_PSTR_LIST(progc, F("prog c")) +MAKE_PSTR_LIST(progd, F("prog d")) +MAKE_PSTR_LIST(proge, F("prog e")) +MAKE_PSTR_LIST(progf, F("prog f")) + +// templates - this are not translated and will be saved under optons_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_switchtime, F("Format: [ not_set | day hh:mm on|off ]")) +MAKE_PSTR_LIST(tpl_switchtime1, F("Format: [ not_set | day hh:mm Tn ]")) +MAKE_PSTR_LIST(tpl_holidays, F("Format: < dd.mm.yyyy-dd.mm.yyyy >")) +MAKE_PSTR_LIST(tpl_date, F("Format: < dd.mm.yyyy >")) + +// Unit Of Measurement mapping - maps to DeviceValueUOM_s in emsdevice.cpp +// These don't need translating, it will mess up HA and the API +MAKE_PSTR(uom_blank, " ") +MAKE_PSTR(uom_percent, "%") +MAKE_PSTR(uom_degrees, "°C") +MAKE_PSTR(uom_hours, "hours") +MAKE_PSTR(uom_minutes, "minutes") +MAKE_PSTR(uom_seconds, "seconds") +MAKE_PSTR(uom_kwh, "kWh") +MAKE_PSTR(uom_wh, "Wh") +MAKE_PSTR(uom_bar, "bar") +MAKE_PSTR(uom_ua, "uA") +MAKE_PSTR(uom_lmin, "l/min") +MAKE_PSTR(uom_kw, "kW") +MAKE_PSTR(uom_w, "W") +MAKE_PSTR(uom_kb, "KB") +MAKE_PSTR(uom_dbm, "dBm") +MAKE_PSTR(uom_fahrenheit, "°F") +MAKE_PSTR(uom_mv, "mV") +MAKE_PSTR(uom_sqm, "sqm") +MAKE_PSTR(uom_m3, "m3") +MAKE_PSTR(uom_l, "l") + +// commands +MAKE_PSTR(info_cmd, "lists all values") +MAKE_PSTR(commands_cmd, "lists all commands") +MAKE_PSTR(entities_cmd, "lists all entities") + +// TAG mapping - maps to DeviceValueTAG_s in emsdevice.cpp +// use empty string if want to suppress showing tags +// mqtt tags must not have spaces +MAKE_PSTR(tag_none, "") +MAKE_PSTR(tag_heartbeat, "") +MAKE_PSTR(tag_boiler_data_ww, "dhw") +MAKE_PSTR(tag_device_data, "") +MAKE_PSTR(tag_device_data_ww, "dhw") +MAKE_PSTR(tag_hc1, "hc1") +MAKE_PSTR(tag_hc2, "hc2") +MAKE_PSTR(tag_hc3, "hc3") +MAKE_PSTR(tag_hc4, "hc4") +MAKE_PSTR(tag_hc5, "hc5") +MAKE_PSTR(tag_hc6, "hc6") +MAKE_PSTR(tag_hc7, "hc7") +MAKE_PSTR(tag_hc8, "hc8") +MAKE_PSTR(tag_wwc1, "wwc1") +MAKE_PSTR(tag_wwc2, "wwc2") +MAKE_PSTR(tag_wwc3, "wwc3") +MAKE_PSTR(tag_wwc4, "wwc4") +MAKE_PSTR(tag_wwc5, "wwc5") +MAKE_PSTR(tag_wwc6, "wwc6") +MAKE_PSTR(tag_wwc7, "wwc7") +MAKE_PSTR(tag_wwc8, "wwc8") +MAKE_PSTR(tag_wwc9, "wwc9") +MAKE_PSTR(tag_wwc10, "wwc10") +MAKE_PSTR(tag_ahs, "ahs") +MAKE_PSTR(tag_hs1, "hs1") +MAKE_PSTR(tag_hs2, "hs2") +MAKE_PSTR(tag_hs3, "hs3") +MAKE_PSTR(tag_hs4, "hs4") +MAKE_PSTR(tag_hs5, "hs5") +MAKE_PSTR(tag_hs6, "hs6") +MAKE_PSTR(tag_hs7, "hs7") +MAKE_PSTR(tag_hs8, "hs8") +MAKE_PSTR(tag_hs9, "hs9") +MAKE_PSTR(tag_hs10, "hs10") +MAKE_PSTR(tag_hs11, "hs11") +MAKE_PSTR(tag_hs12, "hs12") +MAKE_PSTR(tag_hs13, "hs13") +MAKE_PSTR(tag_hs14, "hs14") +MAKE_PSTR(tag_hs15, "hs15") +MAKE_PSTR(tag_hs16, "hs16") + +// MQTT topics and prefixes +MAKE_PSTR(heating_active, "heating_active") +MAKE_PSTR(tapwater_active, "tapwater_active") +MAKE_PSTR(response, "response") +MAKE_PSTR(tag_boiler_data_ww_mqtt, "ww") +MAKE_PSTR(tag_device_data_ww_mqtt, "") + +MAKE_PSTR_LIST(climate, F("HA climate config creation")) + +// 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")) + +// 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")) + +// watch +MAKE_PSTR_LIST(list_watch, F("off"), F("on"), F("raw"), F("unknown")) + +/* + * The rest below are Enums and generated from translations lists + */ + +MAKE_PSTR_ENUM(enum_cylprio, FL_(cyl1), FL_(cyl2)) +MAKE_PSTR_ENUM(enum_progMode, FL_(prog1), FL_(prog2)) +MAKE_PSTR_ENUM(enum_progMode4, FL_(proga), FL_(progb), FL_(progc), FL_(progd), FL_(proge), FL_(progf)) +MAKE_PSTR_ENUM(enum_climate, FL_(seltemp), FL_(roomtemp)) +MAKE_PSTR_ENUM(enum_charge, FL_(chargepump), FL_(3wayvalve)) +MAKE_PSTR_ENUM(enum_freq, FL_(off), FL_(1x3min), FL_(2x3min), FL_(3x3min), FL_(4x3min), FL_(5x3min), FL_(6x3min), FL_(continuous)) +MAKE_PSTR_ENUM(enum_off_time_date_manual, FL_(off), FL_(time), FL_(date), FL_(manual)) +MAKE_PSTR_ENUM(enum_comfort, FL_(hot), FL_(eco), FL_(intelligent)) +MAKE_PSTR_ENUM(enum_comfort1, FL_(high_comfort), FL_(eco)) +MAKE_PSTR_ENUM(enum_flow, FL_(off), FL_(flow), FL_(bufferedflow), FL_(buffer), FL_(layeredbuffer)) +MAKE_PSTR_ENUM(enum_reset, FL_(dash), FL_(maintenance), FL_(error)) + +// thermostat lists +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)) +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_floordrystatus, FL_(off), FL_(start), FL_(heat), FL_(hold), FL_(cool), FL_(end)) +MAKE_PSTR_ENUM(enum_ibaBuildingType, FL_(light), FL_(medium), FL_(heavy)) +MAKE_PSTR_ENUM(enum_PID, FL_(fast), FL_(medium), FL_(slow)) +MAKE_PSTR_ENUM(enum_wwMode, FL_(off), FL_(normal), FL_(comfort), FL_(auto), FL_(own_prog), FL_(eco)) +MAKE_PSTR_ENUM(enum_wwCircMode, FL_(off), FL_(on), FL_(auto), FL_(own_prog)) +MAKE_PSTR_ENUM(enum_wwMode2, FL_(off), FL_(on), FL_(auto)) +MAKE_PSTR_ENUM(enum_wwMode3, FL_(on), FL_(off), FL_(auto)) +MAKE_PSTR_ENUM(enum_heatingtype, FL_(off), FL_(radiator), FL_(convector), FL_(floor)) +MAKE_PSTR_ENUM(enum_summermode, FL_(summer), FL_(auto), FL_(winter)) +MAKE_PSTR_ENUM(enum_hpoperatingmode, FL_(off), FL_(auto), FL_(heating), FL_(cooling)) +MAKE_PSTR_ENUM(enum_summer, FL_(winter), FL_(summer)) +MAKE_PSTR_ENUM(enum_operatingstate, FL_(heating), FL_(off), FL_(cooling)) + +MAKE_PSTR_ENUM(enum_mode, FL_(manual), FL_(auto)) // RC100, RC300, RC310 +MAKE_PSTR_ENUM(enum_mode2, FL_(off), FL_(manual), FL_(auto)) // RC20 +MAKE_PSTR_ENUM(enum_mode3, FL_(night), FL_(day), FL_(auto)) // RC35, RC30, RC25 +MAKE_PSTR_ENUM(enum_mode4, FL_(nofrost), FL_(eco), FL_(heat), FL_(auto)) // JUNKERS +MAKE_PSTR_ENUM(enum_mode5, FL_(auto), FL_(off)) // CRF +MAKE_PSTR_ENUM(enum_mode6, FL_(nofrost), FL_(night), FL_(day)) // RC10 + +MAKE_PSTR_ENUM(enum_modetype, FL_(eco), FL_(comfort)) +MAKE_PSTR_ENUM(enum_modetype3, FL_(night), FL_(day)) +MAKE_PSTR_ENUM(enum_modetype4, FL_(nofrost), FL_(eco), FL_(heat)) +MAKE_PSTR_ENUM(enum_modetype5, FL_(off), FL_(on)) + +MAKE_PSTR_ENUM(enum_reducemode, FL_(nofrost), FL_(reduce), FL_(room), FL_(outdoor)) +MAKE_PSTR_ENUM(enum_reducemode1, FL_(outdoor), FL_(room), FL_(reduce)) // RC310 values: 1-3 +MAKE_PSTR_ENUM(enum_nofrostmode, FL_(off), FL_(room), FL_(outdoor)) +MAKE_PSTR_ENUM(enum_nofrostmode1, FL_(room), FL_(outdoor), FL_(room_outdoor)) + +MAKE_PSTR_ENUM(enum_controlmode, FL_(off), FL_(optimized), FL_(simple), FL_(mpc), FL_(room), FL_(power), FL_(constant)) +MAKE_PSTR_ENUM(enum_controlmode1, FL_(weather_compensated), FL_(outside_basepoint), FL_(na), FL_(room)) // RC310 1-4 +MAKE_PSTR_ENUM(enum_controlmode2, FL_(outdoor), FL_(room)) +MAKE_PSTR_ENUM(enum_control, FL_(off), FL_(rc20), FL_(rc3x)) +MAKE_PSTR_ENUM(enum_j_control, FL_(off), FL_(fb10), FL_(fb100)) + +MAKE_PSTR_ENUM(enum_switchmode, FL_(off), FL_(eco), FL_(comfort), FL_(heat)) + +MAKE_PSTR_ENUM(enum_dayOfWeek, FL_(day_mo), FL_(day_tu), FL_(day_we), FL_(day_th), FL_(day_fr), FL_(day_sa), FL_(day_su), FL_(all)) +MAKE_PSTR_ENUM(enum_progMode2, FL_(own_1), FL_(family), FL_(morning), FL_(evening), FL_(am), FL_(pm), FL_(midday), FL_(singles), FL_(seniors), FL_(new), FL_(own_2)) +MAKE_PSTR_ENUM(enum_progMode3, FL_(family), FL_(morning), FL_(evening), FL_(am), FL_(pm), FL_(midday), FL_(singles), FL_(seniors)) +MAKE_PSTR_ENUM(enum_hybridStrategy, FL_(co2_optimized), FL_(cost_optimized), FL_(outside_temp_switched), FL_(co2_cost_mix)) + +// heat pump +MAKE_PSTR_ENUM(enum_hpactivity, FL_(none), FL_(heating), FL_(cooling), FL_(hot_water), FL_(pool)) + +// solar +MAKE_PSTR_ENUM(enum_solarmode, FL_(constant), FL_(pwm), FL_(analog)) +MAKE_PSTR_ENUM(enum_collectortype, FL_(flat), FL_(vacuum)) +MAKE_PSTR_ENUM(enum_wwStatus2, FL_(BLANK), FL_(BLANK), FL_(BLANK), FL_(no_heat), FL_(BLANK), FL_(BLANK), FL_(heatrequest), FL_(BLANK), FL_(disinfecting), FL_(hold)) + +// mixer +MAKE_PSTR_ENUM(enum_shunt, FL_(stopped), FL_(opening), FL_(closing), FL_(open), FL_(close)) +MAKE_PSTR_ENUM(enum_wwProgMode, FL_(std_prog), FL_(own_prog)) + +// AM200 lists +MAKE_PSTR_ENUM(enum_vr2Config, FL_(off), FL_(bypass)) +MAKE_PSTR_ENUM(enum_aPumpSignal, FL_(off), FL_(pwm), FL_(pwm_invers)) +MAKE_PSTR_ENUM(enum_bufBypass, FL_(no), FL_(mixer), FL_(valve)) +MAKE_PSTR_ENUM(enum_blockMode, FL_(off), FL_(auto), FL_(blocking)) +MAKE_PSTR_ENUM(enum_bufConfig, FL_(monovalent), FL_(bivalent)) +MAKE_PSTR_ENUM(enum_blockTerm, FL_(n_o), FL_(n_c)) + +#pragma GCC diagnostic pop diff --git a/src/locale_translations.h b/src/locale_translations.h new file mode 100644 index 000000000..91e2a48cc --- /dev/null +++ b/src/locale_translations.h @@ -0,0 +1,1171 @@ +/* + * EMS-ESP - https://github.com/emsesp/EMS-ESP + * Copyright 2020 Paul Derbyshire + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +// Define languages here +// Makes sure they are also added in same order to languages[] in system.cpp +#define EMSESP_LOCALE_EN "en" +#define EMSESP_LOCALE_DE "de" +#define EMSESP_LOCALE_NL "nl" +#define EMSESP_LOCALE_SE "se" +#define EMSESP_LOCALE_PL "pl" +#define EMSESP_LOCALE_NO "no" + +// translations are in order en, de,nl, se.... +// if there is no translation, it will default to en + +// General +MAKE_PSTR_LIST(on, F("on"), F("an"), F("naar"), F("på")) +MAKE_PSTR_LIST(off, F("off"), F("aus"), F("van"), F("av")) +MAKE_PSTR_LIST(ON, F("ON"), F("AN"), F("NAAR"), F("PÅ")) +MAKE_PSTR_LIST(OFF, F("OFF"), F("AUS"), F("VAN"), F("AV")) + +// Unit Of Measurement mapping - maps to DeviceValueUOM_s in emsdevice.cpp +// uom - also used with HA see https://github.com/home-assistant/core/blob/d7ac4bd65379e11461c7ce0893d3533d8d8b8cbf/homeassistant/const.py#L384 +MAKE_PSTR_LIST(minutes, F("minutes"), F("Minuten"), F("Minuten"), F("Minuter")) +MAKE_PSTR_LIST(hours, F("hours"), F("Stunden"), F("Uren"), F("Timmar")) +MAKE_PSTR_LIST(days, F("days"), F("Tage"), F("Dagen"), F("Dagar")) +MAKE_PSTR_LIST(seconds, F("seconds"), F("Sekunden"), F("Seconden"), F("Sekunder")) + +// general +MAKE_PSTR_LIST(day_mo, F("mo"), F("Mo"), F("Mo"), F("Må")) +MAKE_PSTR_LIST(day_tu, F("tu"), F("Di"), F("Di"), F("Ti")) +MAKE_PSTR_LIST(day_we, F("we"), F("Mi"), F("Wo"), F("On")) +MAKE_PSTR_LIST(day_th, F("th"), F("Do"), F("Do"), F("To")) +MAKE_PSTR_LIST(day_fr, F("fr"), F("Fr"), F("Vr"), F("Fr")) +MAKE_PSTR_LIST(day_sa, F("sa"), F("Sa"), F("Za"), F("Lö")) +MAKE_PSTR_LIST(day_su, F("su"), F("So"), F("Zo"), F("Sö")) +MAKE_PSTR_LIST(all, F("all"), F("Alle"), F("Alle"), F("Alla")) +MAKE_PSTR_LIST(own_1, F("own 1"), F("Eigen 1"), F("Eigen 1"), F("Egen 1")) +MAKE_PSTR_LIST(family, F("family"), F("Familie"), F("Familie"), F("Familj")) +MAKE_PSTR_LIST(morning, F("morning"), F("Morgends"), F("'s ochtends"), F("Morgon")) +MAKE_PSTR_LIST(evening, F("evening"), F("Abends"), F("'s avonds"), F("Kväll")) +MAKE_PSTR_LIST(seniors, F("seniors"), F("Senioren"), F("Senioren"), F("Seniorer")) +MAKE_PSTR_LIST(no, F("no"), F("nein"), F("nee"), F("nej")) +MAKE_PSTR_LIST(new, F("new"), F("Neu"), F("Nieuw"), F("Ny")) +MAKE_PSTR_LIST(own_2, F("own 2"), F("Eigen 2"), F("Eigen 2"), F("Egen 2")) +MAKE_PSTR_LIST(singles, F("singles"), F("Singles"), F("Singles"), F("Singlar")) +MAKE_PSTR_LIST(am, F("am"), F("Vormittag"), F("Ochtend"), F("Förmiddag")) +MAKE_PSTR_LIST(pm, F("pm"), F("Nachmittag"), F("Namiddag"), F("Eftermiddag")) +MAKE_PSTR_LIST(midday, F("midday"), F("Mittag"), F("Middag"), F("Middag")) +MAKE_PSTR_LIST(unknown, F("unknown"), F("Unbekannt"), F("Onbekend"), F("Okänt")) +MAKE_PSTR_LIST(flat, F("flat"), F("flach"), F("vlak"), F("Platt")) +MAKE_PSTR_LIST(vacuum, F("vacuum"), F("vakuum"), F("vacuum"), F("Vakuum")) +MAKE_PSTR_LIST(co2_optimized, F("co2 optimized"), F("CO2 optimiert"), F("CO2 geoptimaliseerd"), F("CO2-optimerad")) +MAKE_PSTR_LIST(cost_optimized, F("cost optimized"), F("kostenoptimiert"), F("kosten geoptimaliseerd"), F("kostnadsoptimerad")) +MAKE_PSTR_LIST(outside_temp_switched, F("outside temp switched"), F("Außentemp. gesteuert"), F("Buitentemp. gestuurd"), F("Utomhustemp korrigerad")) +MAKE_PSTR_LIST(co2_cost_mix, F("co2 cost mix"), F("Kostenmix"), F("Kostenmix"), F("Kostnadsmix")) +MAKE_PSTR_LIST(analog, F("analog"), F("analog"), F("analoog"), F("analog")) +MAKE_PSTR_LIST(normal, F("normal"), F("normal"), F("normaal"), F("normal")) +MAKE_PSTR_LIST(blocking, F("blocking"), F("Blockierung"), F("Blokkering"), F("Blockering")) + +// boiler +MAKE_PSTR_LIST(time, F("time"), F("Zeit"), F("Tijd"), F("Tid")) +MAKE_PSTR_LIST(date, F("date"), F("Datum"), F("Datum"), F("Datum")) +MAKE_PSTR_LIST(continuous, F("continuous"), F("kontinuierlich"), F("continue"), F("kontinuerlig")) +MAKE_PSTR_LIST(3wayvalve, F("3-way valve"), F("3-Wege Ventil"), F("3-weg klep"), F("trevägsventil")) +MAKE_PSTR_LIST(chargepump, F("chargepump"), F("Ladepumpe"), F("laadpomp"), F("laddpump")) +MAKE_PSTR_LIST(hot, F("hot"), F("Heiß"), F("Heet"), F("Het")) +MAKE_PSTR_LIST(high_comfort, F("high comfort"), F("gehobener Komfort"), F("Verhoogd comfort"), F("Förhöjd komfort")) +MAKE_PSTR_LIST(eco, F("eco"), F("Eco"), F("Eco"), F("Eko")) +MAKE_PSTR_LIST(intelligent, F("intelligent"), F("Intelligent"), F("Intelligent"), F("Intelligent")) +MAKE_PSTR_LIST(flow, F("flow"), F("Durchfluss"), F("Volumestroom"), F("Flöde")) +MAKE_PSTR_LIST(manual, F("manual"), F("Manuell"), F("Hamdmatig"), F("Manuell")) +MAKE_PSTR_LIST(buffer, F("buffer"), F("Speicher"), F("Buffer"), F("Buffert")) +MAKE_PSTR_LIST(bufferedflow, F("buffered flow"), F("Durchlaufspeicher"), F("Doorstroombuffer"), F("Buffertflöde")) +MAKE_PSTR_LIST(layeredbuffer, F("layered buffer"), F("Schichtspeicher"), F("Gelaagde buffer"), F("Lagrad buffert")) +MAKE_PSTR_LIST(maintenance, F("maintenance"), F("Wartung"), F("Onderhoud"), F("Underhåll")) +MAKE_PSTR_LIST(heating, F("heating"), F("Heizen"), F("Verwarmen"), F("Uppvärmning")) +MAKE_PSTR_LIST(cooling, F("cooling"), F("Kühlen"), F("Koelen"), F("Kyler")) +MAKE_PSTR_LIST(disinfecting, F("disinfecting"), F("desinfizieren"), F("Desinfecteren"), F("Desinficerar")) +MAKE_PSTR_LIST(no_heat, F("no heat"), F("keine Wärme"), F("Geen warmte"), F("Ingen värme")) +MAKE_PSTR_LIST(heatrequest, F("heat request"), F("Wärmeanforderung"), F("Verwarmignsverzoek"), F("Värmeförfrågan")) +MAKE_PSTR_LIST(valve, F("valve"), F("Ventil"), F("Klep"), F("Ventil")) + +// heatpump +MAKE_PSTR_LIST(none, F("none"), F("keiner"), F("geen"), F("ingen")) +MAKE_PSTR_LIST(hot_water, F("hot water"), F("heißes Wasser"), F("warm water"), F("varmvatten")) +MAKE_PSTR_LIST(pool, F("pool"), F("Pool"), F("zwembad"), F("pool")) + +// thermostat +MAKE_PSTR_LIST(seltemp, F("selTemp"), F("Solltemperatur"), F("Doeltemperatuur"), F("Börtemperatur")) +MAKE_PSTR_LIST(roomtemp, F("roomTemp"), F("Raumtemperatur"), F("Kamertemperatuur"), F("Rumstemperatur")) +MAKE_PSTR_LIST(own_prog, F("own prog"), F("Eigenprog."), F("Eigen prog."), F("Egen prog.")) +MAKE_PSTR_LIST(std_prog, F("std prog"), F("Standardprog."), F("Standaard prog."), F("Standardprog.")) +MAKE_PSTR_LIST(light, F("light"), F("Leicht"), F("Licht"), F("Lätt")) +MAKE_PSTR_LIST(medium, F("medium"), F("Mittel"), F("Middel"), F("Medel")) +MAKE_PSTR_LIST(heavy, F("heavy"), F("Schwer"), F("Zwaar"), F("Tung")) +MAKE_PSTR_LIST(start, F("start"), F("Start"), F("Start"), F("Start")) +MAKE_PSTR_LIST(heat, F("heat"), F("Heizen"), F("Verwarmen"), F("Värme")) +MAKE_PSTR_LIST(hold, F("hold"), F("Halten"), F("Pauzeren"), F("Paus")) +MAKE_PSTR_LIST(cool, F("cool"), F("Kühlen"), F("Koelen"), F("Kyla")) +MAKE_PSTR_LIST(end, F("end"), F("Ende"), F("Einde"), F("Slut")) +MAKE_PSTR_LIST(german, F("german"), F("Deutsch"), F("Duits"), F("Tyska")) +MAKE_PSTR_LIST(dutch, F("dutch"), F("Niederländisch"), F("Nederlands"), F("Nederländska")) +MAKE_PSTR_LIST(french, F("french"), F("Französisch"), F("Frans"), F("Franska")) +MAKE_PSTR_LIST(italian, F("italian"), F("Italienisch"), F("Italiaans"), F("Italienska")) +MAKE_PSTR_LIST(high, F("high"), F("hoch"), F("hoog"), F("Hög")) +MAKE_PSTR_LIST(low, F("low"), F("niedrig"), F("laag"), F("Låg")) +MAKE_PSTR_LIST(radiator, F("radiator"), F("Heizkörper"), F("Radiator"), F("Radiator")) +MAKE_PSTR_LIST(convector, F("convector"), F("Konvektor"), F("Convector"), F("Konvektor")) +MAKE_PSTR_LIST(floor, F("floor"), F("Fussboden"), F("Vloer"), F("Golv")) +MAKE_PSTR_LIST(summer, F("summer"), F("Sommer"), F("Zomer"), F("Sommar")) +MAKE_PSTR_LIST(winter, F("winter"), F("Winter"), F("Winter"), F("Vinter")) +MAKE_PSTR_LIST(outdoor, F("outdoor"), F("Außen"), F("Buiten"), F("Utomhus")) +MAKE_PSTR_LIST(room, F("room"), F("Raum"), F("Kamer"), F("Rum")) +MAKE_PSTR_LIST(room_outdoor, F("room outdoor"), F("Raum+Außen"), F("Kamer+Buiten"), F("Rum+Ute")) +MAKE_PSTR_LIST(power, F("power"), F("Leistung"), F("Vermogen"), F("Effekt")) +MAKE_PSTR_LIST(constant, F("constant"), F("konstant"), F("constant"), F("Konstant")) +MAKE_PSTR_LIST(simple, F("simple"), F("einfach"), F("simpel"), F("enkel")) +MAKE_PSTR_LIST(optimized, F("optimized"), F("optimiert"), F("geoptimaliseerd"), F("optimerad")) +MAKE_PSTR_LIST(nofrost, F("nofrost"), F("Frostschutz"), F("Vorstbescherming"), F("Frostskydd")) +MAKE_PSTR_LIST(comfort, F("comfort"), F("Komfort"), F("Comfort"), F("Komfort")) +MAKE_PSTR_LIST(night, F("night"), F("Nacht"), F("Nacht"), F("Natt")) +MAKE_PSTR_LIST(day, F("day"), F("Tag"), F("Dag"), F("Dag")) +MAKE_PSTR_LIST(holiday, F("holiday"), F("Urlaub"), F("Vakantie"), F("Helgdag")) +MAKE_PSTR_LIST(reduce, F("reduce"), F("reduziert"), F("gereduceerd"), F("Reducera")) +MAKE_PSTR_LIST(noreduce, F("no reduce"), F("unreduziert"), F("niet gerduceerd"), F("oreducerad")) +MAKE_PSTR_LIST(offset, F("offset"), F("Anhebung"), F("offset"), F("Förskutning")) +MAKE_PSTR_LIST(design, F("design"), F("Auslegung"), F("Ontwero"), F("Design")) +MAKE_PSTR_LIST(minflow, F("min flow"), F("min. Durchfluss"), F("Min. Doorstroom"), F("Min flöde")) +MAKE_PSTR_LIST(maxflow, F("max flow"), F("max. Durchfluss"), F("Max. Doorstroom"), F("Max flöde")) +MAKE_PSTR_LIST(fast, F("fast"), F("schnell"), F("snel"), F("snabb")) +MAKE_PSTR_LIST(slow, F("slow"), F("langsam"), F("langzaam"), F("långsam")) +MAKE_PSTR_LIST(internal_temperature, F("internal temperature"), F("Interne Temperatur"), F("Interne Temperatuur"), F("Interntemperatur")) +MAKE_PSTR_LIST(internal_setpoint, F("internal setpoint"), F("Interner Sollwert"), F("Interne Streeftemperatuur"), F("Internt börvärde")) +MAKE_PSTR_LIST(external_temperature, F("external temperature"), F("Externe Temperatur"), F("Externe Temperatuur"), F("Extern temperatur")) +MAKE_PSTR_LIST(burner_temperature, F("burner temperature"), F("Brennertemperatur"), F("Brander Temperuur"), F("Brännartemperatur")) +MAKE_PSTR_LIST(ww_temperature, F("ww temperature"), F("Wassertemperatur"), F("Watertemperatuur"), F("Vattentemperatur")) +MAKE_PSTR_LIST(smoke_temperature, F("smoke temperature"), F("Abgastemperatur"), F("Buitentemperatuur"), F("Rökgastemperatur")) +MAKE_PSTR_LIST(weather_compensated, F("weather compensated"), F("Wetter kompensiert"), F("Weer gecompenseerd"), F("Väderkompenserad")) +MAKE_PSTR_LIST(outside_basepoint, F("outside basepoint"), F("außerhalb des Basispunktes"), F("Buiten basispunt"), F("Utomhus baspunkt")) +MAKE_PSTR_LIST(functioning_mode, F("functioning mode"), F("Funktionsweise"), F("Functiemodus"), F("Driftläge")) + +// mixer +MAKE_PSTR_LIST(stopped, F("stopped"), F("gestoppt"), F("gestopt"), F("stoppad")) +MAKE_PSTR_LIST(opening, F("opening"), F("öffnen"), F("openen"), F("öppnar")) +MAKE_PSTR_LIST(closing, F("closing"), F("schließen"), F("sluiten"), F("stänger")) +MAKE_PSTR_LIST(open, F("open"), F("Offen"), F("Open"), F("Öppen")) +MAKE_PSTR_LIST(close, F("close"), F("Geschlossen"), F("Gesloten"), F("Stängd")) + +// Boiler +MAKE_PSTR_LIST(wwtapactivated, F("wwtapactivated"), F("turn on/off"), F("aktiviert im Wartungsmodus"), F("zet aan/uit"), F("sätt på/av")) +MAKE_PSTR_LIST(reset, F("reset"), F("Reset"), F("Reset"), F("Nollställ")) +MAKE_PSTR_LIST(oilPreHeat, F("oilpreheat"), F("oil preheating"), F("Ölvorwärmung"), F("Olie voorverwarming"), F("Förvärmning olja")) +MAKE_PSTR_LIST(heatingActive, F("heatingactive"), F("heating active"), F("Heizen aktiv"), F("Verwarming actief"), F("Uppvärmning aktiv")) +MAKE_PSTR_LIST(tapwaterActive, F("tapwateractive"), F("tapwater active"), F("Warmwasser aktiv"), F("Warm water actief"), F("Varmvatten aktiv")) +MAKE_PSTR_LIST(selFlowTemp, + F("selflowtemp"), + F("selected flow temperature"), + F("Sollwert Vorlauftemperatur"), + F("Ingestelde aanvoertemperatuur"), + F("Börvärde Flödestemperatur")) +MAKE_PSTR_LIST(selBurnPow, + F("selburnpow"), + F("burner selected max power"), + F("Sollwert Brennerleistung"), + F("Ingestelde maximale brandervermogen"), + F("Brännare vald maxeffekt")) +MAKE_PSTR_LIST(heatingPumpMod, + F("heatingpumpmod"), + F("heating pump modulation"), + F("Heizungspumpe 1 Modulation"), + F("Modulatie verwarmingspomp"), + F("Modulering Värmepump")) +MAKE_PSTR_LIST(heatingPump2Mod, + F("heatingpump2mod"), + F("heating pump 2 modulation"), + F("Heizungspumpe 2 Modulation"), + F("Modulatie verwarmingspomp 2"), + F("Modulering Värmepump 2")) +MAKE_PSTR_LIST(outdoorTemp, F("outdoortemp"), F("outside temperature"), F("Aussentemperatur"), F("Buitentemperatuur"), F("Utomhustemperatur")) +MAKE_PSTR_LIST(curFlowTemp, + F("curflowtemp"), + F("current flow temperature"), + F("aktuelle Vorlauftemperatur"), + F("Huidige aanvoertemperatuur"), + F("Aktuell flödestemperatur")) +MAKE_PSTR_LIST(retTemp, F("rettemp"), F("return temperature"), F("Rücklauftemperatur"), F("Retourtemperatuur"), F("Returtemperatur")) +MAKE_PSTR_LIST(switchTemp, F("switchtemp"), F("mixing switch temperature"), F("Mischer Schalttemperatur"), F("Mixer temperatuur"), F("Blandartemperatur")) +MAKE_PSTR_LIST(sysPress, F("syspress"), F("system pressure"), F("Systemdruck"), F("Systeemdruk"), F("systemtryck")) +MAKE_PSTR_LIST(boilTemp, F("boiltemp"), F("actual boiler temperature"), F("Kesseltemperatur"), F("Keteltemperatuur"), F("Temperatur Värmepanna")) +MAKE_PSTR_LIST(exhaustTemp, F("exhausttemp"), F("exhaust temperature"), F("Auslasstemperatur"), F("Uitlaattemperatuur"), F("Avgastemperatur")) +MAKE_PSTR_LIST(burnGas, F("burngas"), F("gas"), F("Gas"), F("Gas"), F("Gas")) +MAKE_PSTR_LIST(burnGas2, F("burngas2"), F("gas stage 2"), F("Gas Stufe 2"), F("gas fase 2"), F("Gas Fas 2")) +MAKE_PSTR_LIST(flameCurr, F("flamecurr"), F("flame current"), F("Flammstrom"), F("Vlammenstroom"), F("Lågström")) +MAKE_PSTR_LIST(heatingPump, F("heatingpump"), F("heating pump"), F("Heizungspumpe"), F("Verwarmingspomp"), F("Värmepump")) +MAKE_PSTR_LIST(fanWork, F("fanwork"), F("fan"), F("Gebläse"), F("Ventilator"), F("Fläkt")) +MAKE_PSTR_LIST(ignWork, F("ignwork"), F("ignition"), F("Zündung"), F("Ontsteking"), F("Tändning")) +MAKE_PSTR_LIST(heatingActivated, F("heatingactivated"), F("heating activated"), F("Heizen aktiviert"), F("Verwarmen geactiveerd"), F("Uppvärmning aktiv")) +MAKE_PSTR_LIST(heatingTemp, F("heatingtemp"), F("heating temperature"), F("Heizungstemperatur"), F("Verwarmingstemperatuur"), F("Uppvärmningstemperatur")) +MAKE_PSTR_LIST(pumpModMax, F("pumpmodmax"), F("boiler pump max power"), F("Kesselpumpen Maximalleistung"), F("Ketelpomp max vermogen"), F("Värmepannepump max effekt")) +MAKE_PSTR_LIST(pumpModMin, F("pumpmodmin"), F("boiler pump min power"), F("Kesselpumpen Minmalleistung"), F("Ketelpomp min vermogen"), F("Värmepannepump min effekt")) +MAKE_PSTR_LIST(pumpDelay, F("pumpdelay"), F("pump delay"), F("Pumpennachlauf"), F("Pomp nalooptijd"), F("Pumpfördröjning")) +MAKE_PSTR_LIST(burnMinPeriod, F("burnminperiod"), F("burner min period"), F("Antipendelzeit"), F("Antipendeltijd"), F("Värmepanna Min Period")) +MAKE_PSTR_LIST(burnMinPower, F("burnminpower"), F("burner min power"), F("minimale Brennerleistung"), F("Minimaal brandervermogen"), F("Värmepanna Min Effekt")) +MAKE_PSTR_LIST(burnMaxPower, F("burnmaxpower"), F("burner max power"), F("maximale Brennerleistung"), F("Maximaal brandervermogen"), F("Värmepanna Max Effekt")) +MAKE_PSTR_LIST(boilHystOn, + F("boilhyston"), + F("hysteresis on temperature"), + F("Einschaltdifferenz"), + F("ketel aan hysterese verschil"), + F("Hysteres aktiveringstemperatur")) +MAKE_PSTR_LIST(boilHystOff, + F("boilhystoff"), + F("hysteresis off temperature"), + F("Ausschaltdifferenz"), + F("ketel uit hysterese verschil"), + F("Hysteres inaktiveringstemperatur")) +MAKE_PSTR_LIST(setFlowTemp, + F("setflowtemp"), + F("set flow temperature"), + F("Sollwert Vorlauftemperatur"), + F("Ingestelde aanvoertemperatuur"), + F("Börvärde Flödestemperatur")) +MAKE_PSTR_LIST(setBurnPow, F("setburnpow"), F("burner set power"), F("Sollwert Brennerleistung"), F("Ingesteld brandervermogen"), F("Värmepanna vald Effekt")) +MAKE_PSTR_LIST(curBurnPow, F("curburnpow"), F("burner current power"), F("Brennerleistung"), F("Brandervermogen"), F("Värmepanna aktuell effekt")) +MAKE_PSTR_LIST(burnStarts, F("burnstarts"), F("burner starts"), F("Brenner # starts"), F("Aantal brander starts"), F("Värmepanna antal starter")) +MAKE_PSTR_LIST(burnWorkMin, F("burnworkmin"), F("total burner operating time"), F("Brenner Laufzeit"), F("Totale branderlooptijd"), F("Värmepanna aktiva timmar")) +MAKE_PSTR_LIST(burn2WorkMin, + F("burn2workmin"), + F("burner stage 2 operating time"), + F("Brenner Stufe 2 Laufzeit"), + F("Totale looptijd brander fase 2"), + F("Värmepanna steg 2 aktiva timmar")) +MAKE_PSTR_LIST(heatWorkMin, F("heatworkmin"), F("total heat operating time"), F("Heizung Laufzeit"), F("Totale looptijd verwarming"), F("Uppvärmning aktiva timmar")) +MAKE_PSTR_LIST(UBAuptime, F("ubauptime"), F("total UBA operating time"), F("gesamte Laufzeit"), F("totale looptijd branderautomaat (UBA)"), F("Total Tid")) +MAKE_PSTR_LIST(lastCode, F("lastcode"), F("last error code"), F("Fehlerspeicher"), F("Laatste foutcode"), F("Senaste Felkod")) +MAKE_PSTR_LIST(serviceCode, F("servicecode"), F("service code"), F("Statusmeldung"), F("Statuscode"), F("Servicekod")) +MAKE_PSTR_LIST(serviceCodeNumber, F("servicecodenumber"), F("service code number"), F("Statusmeldungsnummer"), F("Status codenummer"), F("Servicekodsnummer")) +MAKE_PSTR_LIST(maintenanceMessage, F("maintenancemessage"), F("maintenance message"), F("Wartungsmeldung"), F("Onderhoudsmelding"), F("Servicemeddelande")) +MAKE_PSTR_LIST(maintenanceDate, F("maintenancedate"), F("next maintenance date"), F("Wartungsdatum"), F("Onderhoudsdatum"), F("Datum nästa Service")) +MAKE_PSTR_LIST(maintenanceType, F("maintenance"), F("maintenance scheduled"), F("Wartungsplan"), F("Onderhoud gepland"), F("Underhåll schemlagt")) +MAKE_PSTR_LIST(maintenanceTime, F("maintenancetime"), F("time to next maintenance"), F("Wartung in"), F("Onderhoud in"), F("Tid till nästa underhåll")) +MAKE_PSTR_LIST(emergencyOps, F("emergencyops"), F("emergency operation"), F("Notoperation"), F("Noodoperatie"), F("Nöddrift")) +MAKE_PSTR_LIST(emergencyTemp, F("emergencytemp"), F("emergency temperature"), F("Nottemperatur"), F("Noodtemperatuur"), F("Nödtemperatur")) + +// heatpump/compress specific +MAKE_PSTR_LIST(upTimeControl, F("uptimecontrol"), F("total operating time heat"), F("Betriebszeit Heizen gesamt"), F("Totale bedrijfstijd"), F("Total tid uppvärmning")) +MAKE_PSTR_LIST(upTimeCompHeating, + F("uptimecompheating"), + F("operating time compressor heating"), + F("Betriebszeit Kompressor heizen"), + F("Bedrijfstijd compressor verwarmingsbedrijf"), + F("Total tid kompressor uppvärmning")) +MAKE_PSTR_LIST(upTimeCompCooling, + F("uptimecompcooling"), + F("operating time compressor cooling"), + F("Betriebszeit Kompressor kühlen"), + F("Bedrijfstijd compressor koelbedrijf"), + F("Total tid kompressor kyla")) +MAKE_PSTR_LIST(upTimeCompWw, + F("uptimecompww"), + F("operating time compressor dhw"), + F("Betriebszeit Kompressor"), + F("Bedrijfstijd compressor warmwaterbedrijf"), + F("Total tid kompressor varmvatten")) +MAKE_PSTR_LIST(upTimeCompPool, + F("uptimecomppool"), + F("operating time compressor pool"), + F("Betriebszeit Kompressor Pool"), + F("Bedrijfstijd compressor voor zwembadbedrijf"), + F("Total tid kompressor pool")) +MAKE_PSTR_LIST(totalCompStarts, + F("totalcompstarts"), + F("total compressor control starts"), + F("Kompressor Starts gesamt"), + F("Totaal compressorstarts"), + F("Kompressorstarter Totalt")) +MAKE_PSTR_LIST(heatingStarts, F("heatingstarts"), F("heating control starts"), F("Heizen Starts"), F("Starts verwarmingsbedrijf"), F("Kompressorstarter Uppvärmning")) +MAKE_PSTR_LIST(coolingStarts, F("coolingstarts"), F("cooling control starts"), F("Kühlen Starts"), F("Starts koelbedrijf"), F("Kompressorstarter Kyla")) +MAKE_PSTR_LIST(poolStarts, F("poolstarts"), F("pool control starts"), F("Pool Starts"), F("Starts zwembadbedrijf"), F("Kompressorstarter Pool")) +MAKE_PSTR_LIST(nrgConsTotal, + F("nrgconstotal"), + F("total energy consumption"), + F("totaler Energieverbrauch"), + F("Energieverbrauch gesamt"), + F("Energieverbruik totaal"), + F("Energiförbrukning")) +MAKE_PSTR_LIST(nrgConsCompTotal, + F("nrgconscomptotal"), + F("total energy consumption compressor"), + F("Energieverbrauch Kompressor gesamt"), + F("Energieverbruik compressor totaal"), + F("Energiförbrukning kompressor")) +MAKE_PSTR_LIST(nrgConsCompHeating, + F("nrgconscompheating"), + F("energy consumption compressor heating"), + F("Energieverbrauch Kompressor heizen"), + F("Energieverbruik compressor verwarmingsbedrijf"), + F("Energiförbrukning uppvärmning")) +MAKE_PSTR_LIST(nrgConsCompWw, + F("nrgconscompww"), + F("energy consumption compressor dhw"), + F("Energieverbrauch Kompressor"), + F("Energieverbruik compressor warmwaterbedrijf"), + F("Energiförbrukning varmvatten")) +MAKE_PSTR_LIST(nrgConsCompCooling, + F("nrgconscompcooling"), + F("energy consumption compressor cooling"), + F("Energieverbrauch Kompressor kühlen"), + F("Energieverbruik compressor koelbedrijf"), + F("Energiförbrukning kyla")) +MAKE_PSTR_LIST(nrgConsCompPool, + F("nrgconscomppool"), + F("energy consumption compressor pool"), + F("Energieverbrauch Kompressor Pool"), + F("Energiebedrijf compressor zwembadbedrijf"), + F("Energiförbrukning pool")) +MAKE_PSTR_LIST(nrgSuppTotal, F("nrgsupptotal"), F("total energy supplied"), F("gesamte Energieabgabe"), F("Totaal opgewekte energie"), F("Tillförd energi")) +MAKE_PSTR_LIST(nrgSuppHeating, + F("nrgsuppheating"), + F("total energy supplied heating"), + F("gesamte Energieabgabe heizen"), + F("Opgewekte energie verwarmingsbedrijf"), + F("Tillförd energi Uppvärmning")) +MAKE_PSTR_LIST(nrgSuppWw, + F("nrgsuppww"), + F("total energy warm supplied dhw"), + F("gesamte Energieabgabe"), + F("Opgewekte energie warmwaterbedrijf"), + F("Tillförd energi Varmvatten")) +MAKE_PSTR_LIST(nrgSuppCooling, + F("nrgsuppcooling"), + F("total energy supplied cooling"), + F("gesamte Energieabgabe kühlen"), + F("Opgewekte energie koelbedrijf"), + F("Tillförd energi Kyla")) +MAKE_PSTR_LIST(nrgSuppPool, + F("nrgsupppool"), + F("total energy supplied pool"), + F("gesamte Energieabgabe Pool"), + F("Opgewekte energie zwembadbedrijf"), + F("TIllförd energi Pool")) +MAKE_PSTR_LIST(auxElecHeatNrgConsTotal, + F("auxelecheatnrgconstotal"), + F("total auxiliary electrical heater energy consumption"), + F("Energieverbrauch el. Zusatzheizung"), + F("Totaal energieverbruik electrisch verwarmingselement"), + F("Energiförbrukning Elpatron")) +MAKE_PSTR_LIST(auxElecHeatNrgConsHeating, + F("auxelecheatnrgconsheating"), + F("auxiliary electrical heater energy consumption heating"), + F("Energieverbrauch el. Zusatzheizung Heizen"), + F("Energieverbruik electrisch verwarmingselement voor verwarmingsbedrijf"), + F("Energiförbrukning Elpatron Uppvärmning")) +MAKE_PSTR_LIST(auxElecHeatNrgConsWW, + F("auxelecheatnrgconsww"), + F("auxiliary electrical heater energy consumption dhw"), + F("Energieverbrauch el. Zusatzheizung"), + F("Energieverbruik electrisch verwarmingselement voor warmwaterbedrijf"), + F("Energiförbrukning Elpatron Varmvatten")) +MAKE_PSTR_LIST(auxElecHeatNrgConsPool, + F("auxelecheatnrgconspool"), + F("auxiliary electrical heater energy consumption pool"), + F("Energieverbrauch el. Zusatzheizung Pool"), + F("Energieverbruik electrisch verwarmingselement voor zwembadbedrijf"), + F("Energiförbrukning Elpatron Pool")) + +MAKE_PSTR_LIST(hpCompOn, F("hpcompon"), F("hp compressor"), F("WP Kompressor"), F("WP compressor"), F("VP Kompressor")) +MAKE_PSTR_LIST(hpHeatingOn, F("hpheatingon"), F("hp heating"), F("WP Heizen"), F("WP verwarmingsbedrijf"), F("VP Uppvärmning")) +MAKE_PSTR_LIST(hpCoolingOn, F("hpcoolingon"), F("hp cooling"), F("WP Kühlen"), F("WP koelbedrijf"), F("VP Kyla")) +MAKE_PSTR_LIST(hpWwOn, F("hpwwon"), F("hp dhw"), F("WP Warmwasser"), F("WP warmwaterbedrijf"), F("VP Varmvatten")) +MAKE_PSTR_LIST(hpPoolOn, F("hppoolon"), F("hp pool"), F("WP Pool"), F("WP zwembadbedrijf"), F("VP Pool")) +MAKE_PSTR_LIST(hpBrinePumpSpd, F("hpbrinepumpspd"), F("brine pump speed"), F("Solepumpen-Geschw."), F("Snelheid pekelpomp"), F("Hastighet Brine-pump")) +MAKE_PSTR_LIST(hpCompSpd, F("hpcompspd"), F("compressor speed"), F("Kompressor-Geschw."), F("Snelheid compressor"), F("Kompressorhastighet")) +MAKE_PSTR_LIST(hpCircSpd, F("hpcircspd"), F("circulation pump speed"), F("Zirkulationspumpen-Geschw."), F("Snelheid circulatiepomp"), F("Hastighet Cirkulationspump")) +MAKE_PSTR_LIST(hpBrineIn, F("hpbrinein"), F("brine in/evaporator"), F("Sole in/Verdampfer"), F("pekel in/verdamper"), F("Brine in/förångare")) +MAKE_PSTR_LIST(hpBrineOut, F("hpbrineout"), F("brine out/condenser"), F("Sole aus/Kondensator"), F("pekel uit/condensor"), F("Brine ut/kondensor")) +MAKE_PSTR_LIST(hpSuctionGas, F("hpsuctiongas"), F("suction gas"), F("Gasansaugung"), F("Gasaanzuiging"), F("Gasintag")) +MAKE_PSTR_LIST(hpHotGas, F("hphotgas"), F("hot gas/compressed"), F("Heißgas/verdichtet"), F("heet gas/samengeperst"), F("Hetgas/komprimerad")) +MAKE_PSTR_LIST(hpSwitchValve, F("hpswitchvalve"), F("switch valve"), F("Schaltventil"), F("schakelklep"), F("Växelventil")) +MAKE_PSTR_LIST(hpActivity, F("hpactivity"), F("compressor activity"), F("Kompressor aktiv"), F("Compressoractiviteit"), F("Kompressoraktivitet")) + +MAKE_PSTR_LIST(hpPower, F("hppower"), F("compressor power output"), F("Kopressorleistung"), F("Compressorvermogen"), F("Kompressoreffekt")) +MAKE_PSTR_LIST(hpTc0, F("hptc0"), F("heat carrier return (TC0)"), F("Kältemittel Rücklauf (TC0)"), F("Koudemiddel retour (TC0O"), F("Värmebärare Retur (TC0)")) +MAKE_PSTR_LIST(hpTc1, F("hptc1"), F("heat carrier forward (TC1)"), F("Kältemittel Vorlauf (TC1)"), F("Koudemiddel aanvoer (TC1)"), F("Värmebärare Framledning (TC1)")) +MAKE_PSTR_LIST(hpTc3, F("hptc3"), F("condenser temperature (TC3)"), F("Verflüssigertemperatur (TC3)"), F("Condensortemperatuur (TC3)"), F("Kondensortemperatur (TC3)")) +MAKE_PSTR_LIST(hpTr3, + F("hptr3"), + F("refrigerant temperature liquid side (condenser output) (TR3)"), + F("Kältemittel (flüssig) (TR3)"), + F("Temperatuur koudemiddel vloeibare zijde (TR3)"), + F("Köldmedium temperatur (kondensorutlopp) (TR3)")) +MAKE_PSTR_LIST(hpTr4, + F("hptr4"), + F("evaporator inlet temperature (TR4)"), + F("Verdampfer Eingang (TR4)"), + F("Verdamper ingangstemperatuur (TR4)"), + F("Förångare inloppstemp (TR4)")) +MAKE_PSTR_LIST(hpTr5, + F("hptr5"), + F("compressor inlet temperature (TR5)"), + F("Kompessoreingang (TR5)"), + F("Compressor ingangstemperatuur (TR5)"), + F("Kompressor inloppstemp (TR5)")) +MAKE_PSTR_LIST(hpTr6, + F("hptr6"), + F("compressor outlet temperature (TR6)"), + F("Kompressorausgang (TR6)"), + F("Compressor uitgangstemperatuur (TR6)"), + F("Kompressor utloppstemp (TR6)")) +MAKE_PSTR_LIST(hpTr7, + F("hptr7"), + F("refrigerant temperature gas side (condenser input) (TR7)"), + F("Kältemittel (gasförmig) (TR7)"), + F("Temperatuur koudemiddel gasvormig (TR7)"), + F("Köldmedium temperatur gassida (kondensorinlopp) (TR7)")) +MAKE_PSTR_LIST(hpTl2, + F("hptl2"), + F("air inlet temperature (TL2)"), + F("Außenluft-Einlasstemperatur (TL2)"), + F("Temperatuur luchtinlaat (TL2)"), + F("Luftintagstemperatur (TL2)")) +MAKE_PSTR_LIST(hpPl1, + F("hppl1"), + F("low pressure side temperature (PL1)"), + F("Niedrigdruckfühler (PL1)"), + F("Temperatuur lage drukzijde (PL1)"), + F("Temperatur Lågtryckssidan (PL1)")) +MAKE_PSTR_LIST(hpPh1, + F("hpph1"), + F("high pressure side temperature (PH1)"), + F("Hochdruckfühler (PH1)"), + F("Temperatuur hoge drukzijde (PH1)"), + F("Temperatur Högtryckssidan (PH1)")) + +MAKE_PSTR_LIST(hpInput1, F("hpin1"), F("input 1 state"), F("Eingang 1 Status"), F("Status input 1"), F("Status Ingång 1")) +MAKE_PSTR_LIST(hpInput2, F("hpin2"), F("input 2 state"), F("Eingang 2 Status"), F("Status input 2"), F("Status Ingång 2")) +MAKE_PSTR_LIST(hpInput3, F("hpin3"), F("input 3 state"), F("Eingang 3 Status"), F("Status input 3"), F("Status Ingång 3")) +MAKE_PSTR_LIST(hpInput4, F("hpin4"), F("input 4 state"), F("Eingang 4 Status"), F("Status input 4"), F("Status Ingång 4")) +MAKE_PSTR_LIST(hpIn1Opt, F("hpin1opt"), F("input 1 options"), F("Eingang 1 Einstellung"), F("Instelling input 1"), F("Inställningar Ingång 1")) +MAKE_PSTR_LIST(hpIn2Opt, F("hpin2opt"), F("input 2 options"), F("Eingang 2 Einstellung"), F("Instelling input 2"), F("Inställningar Ingång 2")) +MAKE_PSTR_LIST(hpIn3Opt, F("hpin3opt"), F("input 3 options"), F("Eingang 3 Einstellung"), F("Instelling input 3"), F("Inställningar Ingång 3")) +MAKE_PSTR_LIST(hpIn4Opt, F("hpin4opt"), F("input 4 options"), F("Eingang 4 Einstellung"), F("Instelling input 4"), F("Inställningar Ingång 4")) + +// hybrid heatpump +MAKE_PSTR_LIST(hybridStrategy, F("hybridstrategy"), F("hybrid control strategy"), F("Hybrid Strategie"), F("Hybride strategie"), F("Hybrid kontrollstrategi")) +MAKE_PSTR_LIST(switchOverTemp, + F("switchovertemp"), + F("outside switchover temperature"), + F("Außentemperatur für Umschaltung"), + F("Schakeltemperatuur buitentemperatuur"), + F("Utomhus Omställningstemperatur")) +MAKE_PSTR_LIST(energyCostRatio, F("energycostratio"), F("energy cost ratio"), F("Energie-Kosten-Verhältnis"), F("Energiekostenratio"), F("Energi/Kostnads-förhållande")) +MAKE_PSTR_LIST(fossileFactor, + F("fossilefactor"), + F("fossile energy factor"), + F("Energiefaktor Fossil"), + F("Energiefactor fossiele brandstof"), + F("Energifaktor fossilenergi")) +MAKE_PSTR_LIST(electricFactor, + F("electricfactor"), + F("electric energy factor"), + F("Energiefaktor elektrisch"), + F("Energiefactor electrisch"), + F("Elektrisk energifaktor")) +MAKE_PSTR_LIST(delayBoiler, F("delayboiler"), F("delay boiler support"), F("Verzögerungs-Option"), F("Vertragingsoptie"), F("Fördörjningsoption")) +MAKE_PSTR_LIST(tempDiffBoiler, + F("tempdiffboiler"), + F("temp diff boiler support"), + F("Temperaturdifferenz-Option"), + F("Verschiltemperatuuroptie"), + F("Temperaturskillnadsoption")) + +// alternative heatsource AM200 +MAKE_PSTR_LIST(aCylTopTemp, + F("cyltoptemp"), + F("cylinder top temperature"), + F("Speicher oben Temperatur"), + F("Buffer temperatuur boven"), + F("Cylindertemperatur Toppen")) +MAKE_PSTR_LIST(aCylCenterTemp, + F("cylcentertemp"), + F("cylinder center temperature"), + F("Speicher mitte Temperatur"), + F("Buffer temperatuur midden"), + F("Cylindertemperatur Mitten")) +MAKE_PSTR_LIST(aCylBottomTemp, + F("cylbottomtemp"), + F("cylinder bottom temperature"), + F("Speicher unten Temperatur"), + F("Buffer temperatuur onder"), + F("Cylindertemperatur Botten")) +MAKE_PSTR_LIST(aFlowTemp, + F("altflowtemp"), + F("alternative hs flow temperature"), + F("Alternativer WE Vorlauftemperatur"), + F("Alternatieve warmtebron aanvoertemperatuur"), + F("Alternativ flödestemp värmekälla")) +MAKE_PSTR_LIST(aRetTemp, + F("altrettemp"), + F("alternative hs return temperature"), + F("Alternativer WE Rücklauftemperatur"), + F("Alternatieve warmtebron retourtemperatuur"), + F("Alternativ returtemp värmekälla")) +MAKE_PSTR_LIST(sysFlowTemp, F("sysflowtemp"), F("system flow temperature"), F("System Vorlauftemperatur"), F("Systeem aanvoertemperatuur"), F("Systemflödestemperatur")) +MAKE_PSTR_LIST(sysRetTemp, F("sysrettemp"), F("system return temperature"), F("System Rücklauftemperatur"), F("Systeem retourtemperatuur"), F("Systemreturtemperatur")) +MAKE_PSTR_LIST(valveByPass, F("valvebypass"), F("bypass valve"), F("Bypass-Ventil"), F("Bypass klep"), F("Bypassventil")) +MAKE_PSTR_LIST(valveBuffer, F("valvebuffer"), F("buffer valve"), F("Puffer-Ventil"), F("Bufferklep"), F("Buffertventil")) +MAKE_PSTR_LIST(valveReturn, F("valvereturn"), F("return valve"), F("Rückfluss-Ventil"), F("Retourklep"), F("Returventil")) +MAKE_PSTR_LIST(aPumpMod, + F("altpumpmod"), + F("alternative hs pump modulation"), + F("Alternativer WE Pumpenmodulation"), + F("Alternatieve warmtebron pomp modulatie"), + F("Alternativ Pumpmodulering Värmekälla")) +MAKE_PSTR_LIST(heatSource, + F("heatsource"), + F("alternative heating active"), + F("Alternativer Wärmeerzeuger aktiv"), + F("Alternatieve warmtebron aktief"), + F("Alternativ Värmekälla aktiv")) + +MAKE_PSTR_LIST(vr2Config, F("vr2config"), F("vr2 configuration"), F("VR2 Konfiguration"), F("VR2 configuratie"), F("VR2 Konfiguration")) +MAKE_PSTR_LIST(ahsActivated, + F("ahsactivated"), + F("alternate heat source activation"), + F("Alt. Wärmeerzeuger aktiviert"), + F("Altenatieve warmtebron geactiveerd"), + F("Alternativ värmekälla aktivering")) +MAKE_PSTR_LIST(aPumpConfig, F("apumpconfig"), F("primary pump config"), F("Konfig. Hauptpumpe"), F("Primaire pomp configuratie"), F("Konfiguration Primärpump")) +MAKE_PSTR_LIST(aPumpSignal, F("apumpsignal"), F("output for pr1 pump"), F("Signal Hauptpumpe"), F("Output voor pomp PR1"), F("Utgång från pump PR1")) +MAKE_PSTR_LIST(aPumpMin, F("apumpmin"), F("min output pump pr1"), F("Minimale Pumpenansteuerung"), F("Minimale output pomp PR1"), F("Min Output Pump PR1")) +MAKE_PSTR_LIST(tempRise, F("temprise"), F("ahs return temp rise"), F("Rücklauf Temperaturerhöhung"), F("Verhoging retourtemperatuur"), F("Förhöjd returtemperatur")) +MAKE_PSTR_LIST(setReturnTemp, F("setreturntemp"), F("set temp return"), F("Soll-Rücklauftemperatur"), F("Streeftemperatuur retour"), F("Vald returtemperatur")) +MAKE_PSTR_LIST(mixRuntime, F("mixruntime"), F("mixer run time"), F("Mischer-Laufzeit"), F("Mixer looptijd"), F("Blandningsventil drifttid")) +MAKE_PSTR_LIST(bufBypass, F("bufbypass"), F("buffer bypass config"), F("Konfig. Bypass"), F("Buffer bypass configuratie"), F("Konfiguration Buffer bypass")) +MAKE_PSTR_LIST(bufMixRuntime, + F("bufmixruntime"), + F("bypass mixer run time"), + F("Speicher-Mischer-Laufzeit"), + F("Buffer mixer looptijd"), + F("Blandningsventil Bypass drifttid")) +MAKE_PSTR_LIST(bufConfig, + F("bufconfig"), + F("dhw buffer config"), + F("Konfig. Warmwasserspeicher"), + F("Warmwater boiler configuratie"), + F("Konfiguration Varmvattentank")) +MAKE_PSTR_LIST(blockMode, F("blockmode"), F("config htg. blocking mode"), F("Konfig. Sperr-Modus"), F("Configuratie blokeermodus"), F("Konfiguration Blockeringsläge")) +MAKE_PSTR_LIST(blockTerm, + F("blockterm"), + F("config of block terminal"), + F("Konfig. Sperrterminal"), + F("Configuratie blookerterminal"), + F("Konfiguration Blockeringsterminal")) +MAKE_PSTR_LIST(blockHyst, F("blockhyst"), F("hyst. for boiler block"), F("Hysterese Sperrmodus"), F("Hysterese blokeerterminal"), F("Hysteres Blockeringsmodul")) +MAKE_PSTR_LIST(releaseWait, F("releasewait"), F("boiler release wait time"), F("Wartezeit Freigabe"), F("Wachttijd ketel vrijgave"), F("Väntetid Frisläppning")) + +// the following are dhw for the boiler and automatically tagged with 'dhw' +MAKE_PSTR_LIST(wwSelTempLow, + F("wwseltemplow"), + F("selected lower temperature"), + F("untere Solltemperatur"), + F("Onderste streeftemperatuur"), + F("Vald lägstatemperatur")) +MAKE_PSTR_LIST(wwSelTempOff, + F("wwseltempoff"), + F("selected temperature for off"), + F("Solltemperatur bei AUS"), + F("Streeftemperatuur bij UIT"), + F("Vald tempereatur för AV")) +MAKE_PSTR_LIST(wwSelTempSingle, + F("wwseltempsingle"), + F("single charge temperature"), + F("Solltemperature Einmalladung"), + F("Streeftemperatuur enkele lading"), + F("Temperatur Engångsladdning")) +MAKE_PSTR_LIST(wwCylMiddleTemp, + F("wwcylmiddletemp"), + F("cylinder middle temperature (TS3)"), + F("Speichertemperature Mitte"), + F("Buffer temperatuur midden"), + F("Cylinder Temperatur Mitten (TS3)")) + +MAKE_PSTR_LIST(wwSelTemp, F("wwseltemp"), F("selected temperature"), F("gewählte Temperatur"), F("Geselecteerd temperatuur"), F("Vald Temperatur")) +MAKE_PSTR_LIST(wwSetTemp, F("wwsettemp"), F("set temperature"), F("Solltemperatur"), F("Streeftemperatuut"), F("Börtempertur")) +MAKE_PSTR_LIST(wwType, F("wwtype"), F("type"), F("Typ"), F("type"), F("Typ")) +MAKE_PSTR_LIST(wwComfort, F("wwcomfort"), F("comfort"), F("Komfort"), F("Comfort"), F("Komfort")) +MAKE_PSTR_LIST(wwComfort1, F("wwcomfort1"), F("comfort mode"), F("Komfort-Modus"), F("Comfort modus"), F("Komfortläge")) +MAKE_PSTR_LIST(wwFlowTempOffset, + F("wwflowtempoffset"), + F("flow temperature offset"), + F("Vorlauftemperaturanhebung"), + F("Aanvoertemperatuur offset"), + F("Flödestemperatur förskjutning")) +MAKE_PSTR_LIST(wwMaxPower, F("wwmaxpower"), F("max power"), F("max Leistung"), F("Maximaal vermogen"), F("Max Effekt")) +MAKE_PSTR_LIST(wwCircPump, + F("wwcircpump"), + F("circulation pump available"), + F("Zirkulationspumpe vorhanden"), + F("Circulatiepomp aanwezig"), + F("Cirkulationspump tillgänglig")) +MAKE_PSTR_LIST(wwChargeType, F("wwchargetype"), F("charging type"), F("Ladungstyp"), F("Buffer laadtype"), F("Laddningstyp")) +MAKE_PSTR_LIST(wwDisinfectionTemp, + F("wwdisinfectiontemp"), + F("disinfection temperature"), + F("Desinfectionstemperatur"), + F("Desinfectietemperatuur"), + F("Desinfektionstemperatur")) +MAKE_PSTR_LIST(wwCircMode, F("wwcircmode"), F("circulation pump mode"), F("Zirkulationspumpen-Modus"), F("Modus circulatiepomp"), F("Läge Cirkulationspump")) +MAKE_PSTR_LIST(wwCirc, F("wwcirc"), F("circulation active"), F("Zirkulation aktiv"), F("Circulatiepomp actief"), F("Cirkulation aktiv")) +MAKE_PSTR_LIST(wwCurTemp, + F("wwcurtemp"), + F("current intern temperature"), + F("aktuelle interne Temperatur"), + F("Huidige interne temperatuur"), + F("Aktuell Intern Temperatur")) +MAKE_PSTR_LIST(wwCurTemp2, + F("wwcurtemp2"), + F("current extern temperature"), + F("aktuelle externe Temperatur"), + F("Huidige externe temperatuur"), + F("Aktuell Extern Temperatur")) +MAKE_PSTR_LIST(wwCurFlow, F("wwcurflow"), F("current tap water flow"), F("aktueller Durchfluss"), F("Hudige warmwater doorstroming"), F("Aktuellt tappvattenflöde")) +MAKE_PSTR_LIST(wwStorageTemp1, + F("wwstoragetemp1"), + F("storage intern temperature"), + F("interne Speichertemperature"), + F("Interne buffertemperatuur"), + F("Beredare Intern Temperatur")) +MAKE_PSTR_LIST(wwStorageTemp2, + F("wwstoragetemp2"), + F("storage extern temperature"), + F("externer Speichertemperatur"), + F("Externe buffertemperatuur"), + F("Beredare Extern Tempereatur")) +MAKE_PSTR_LIST(wwActivated, F("wwactivated"), F("activated"), F("aktiviert"), F("geactiveerd"), F("Aktiverad")) +MAKE_PSTR_LIST(wwOneTime, F("wwonetime"), F("one time charging"), F("Einmalladung"), F("Buffer eenmalig laden"), F("Engångsladdning")) +MAKE_PSTR_LIST(wwDisinfecting, F("wwdisinfecting"), F("disinfecting"), F("Desinfizieren"), F("Desinfectie"), F("Desinficerar")) +MAKE_PSTR_LIST(wwCharging, F("wwcharging"), F("charging"), F("Laden"), F("Laden"), F("Laddar")) +MAKE_PSTR_LIST(wwChargeOptimization, F("wwchargeoptimization"), F("charge optimization"), F("Ladungsoptimierung"), F("laadoptimalisatie"), F("Laddningsoptimering")) +MAKE_PSTR_LIST(wwRecharging, F("wwrecharging"), F("recharging"), F("Nachladen"), F("herladen"), F("Omladdar")) +MAKE_PSTR_LIST(wwTempOK, F("wwtempok"), F("temperature ok"), F("Temperatur ok"), F("Temperatuur OK"), F("Temperatur OK")) +MAKE_PSTR_LIST(wwActive, F("wwactive"), F("active"), F("aktiv"), F("Actief"), F("Aktiv")) +MAKE_PSTR_LIST(ww3wayValve, F("ww3wayvalve"), F("3-way valve active"), F("3-Wegeventil aktiv"), F("3-wegklep actief"), F("Trevägsventil Aktiv")) +MAKE_PSTR_LIST(wwSetPumpPower, F("wwsetpumppower"), F("set pump power"), F("Soll Pumpenleistung"), F("Streefwaarde pompvermogen"), F("Vald pumpeffekt")) +MAKE_PSTR_LIST(wwMixerTemp, F("wwmixertemp"), F("mixer temperature"), F("Mischertemperatur"), F("Mixertemperatuur"), F("Blandningsventil-tempertur")) +MAKE_PSTR_LIST(wwStarts, F("wwstarts"), F("starts"), F("Anzahl Starts"), F("Aantal starts"), F("Antal Starter")) +MAKE_PSTR_LIST(wwStarts2, F("wwstarts2"), F("control starts2"), F("Kreis 2 Anzahl Starts"), F("Aantal starts circuit 2"), F("Antal Starter Krets 2")) +MAKE_PSTR_LIST(wwWorkM, F("wwworkm"), F("active time"), F("aktive Zeit"), F("Actieve tijd"), F("Aktiv Tid")) +MAKE_PSTR_LIST(wwHystOn, + F("wwhyston"), + F("hysteresis on temperature"), + F("Einschalttemperaturdifferenz"), + F("Inschakeltemperatuurverschil"), + F("Hysteres PÅ-temperatur")) +MAKE_PSTR_LIST(wwHystOff, + F("wwhystoff"), + F("hysteresis off temperature"), + F("Ausschalttemperaturdifferenz"), + F("Uitschakeltemperatuurverschil"), + F("Hysteres AV-temperatur")) +MAKE_PSTR_LIST(wwProgMode, F("wwprogmode"), F("program"), F("Programmmodus"), F("Programma"), F("Program")) +MAKE_PSTR_LIST(wwCircProg, F("wwcircprog"), F("circulation program"), F("Zirkulationsprogramm"), F("Circulatieprogramma"), F("Cirkulationsprogram")) +MAKE_PSTR_LIST(wwMaxTemp, F("wwmaxtemp"), F("maximum temperature"), F("Maximale Temperatur"), F("Maximale temperatuur"), F("Maximal Temperatur")) +MAKE_PSTR_LIST(wwOneTimeKey, F("wwonetimekey"), F("one time key function"), F("Einmalladungstaste"), F("Knop voor eenmalig laden buffer"), F("Engångsfunktion")) + +// mqtt values / commands +MAKE_PSTR_LIST(switchtime, F("switchtime"), F("program switchtime"), F("Programm Schaltzeit"), F("Programma schakeltijd"), F("Program Bytestid")) +MAKE_PSTR_LIST(switchtime1, F("switchtime1"), F("own1 program switchtime"), F("Programm 1 Schaltzeit"), F("Schakeltijd programma 1"), F("Program 1 Bytestid")) +MAKE_PSTR_LIST(switchtime2, F("switchtime2"), F("own2 program switchtime"), F("Programm 2 Schaltzeit"), F("Schakeltijd programma 2"), F("Program 2 Bytestid")) +MAKE_PSTR_LIST(wwswitchtime, + F("wwswitchtime"), + F("program switchtime"), + F("Programm Schaltzeit"), + F("Warm water programma schakeltijd"), + F("Varmvattenprogram Bytestid")) +MAKE_PSTR_LIST(wwcircswitchtime, + F("wwcircswitchtime"), + F("circulation program switchtime"), + F("Zirculationsprogramm Schaltzeit"), + F("Schakeltijd circulatieprogramma"), + F("Cirkulationsprogram Bytestid")) +MAKE_PSTR_LIST(dateTime, F("datetime"), F("date/time"), F("Datum/Zeit"), F("Datum/Tijd"), F("Datum/Tid")) +MAKE_PSTR_LIST(errorCode, F("errorcode"), F("error code"), F("Fehlermeldung"), F("Foutmeldingscode"), F("Felkod")) +MAKE_PSTR_LIST(ibaMainDisplay, F("display"), F("display"), F("Anzeige"), F("Display"), F("Display")) +MAKE_PSTR_LIST(ibaLanguage, F("language"), F("language"), F("Sprache"), F("Taal"), F("Språk")) +MAKE_PSTR_LIST(ibaClockOffset, F("clockoffset"), F("clock offset"), F("Uhrkorrektur"), F("Klokcorrectie"), F("Tidskorrigering")) +MAKE_PSTR_LIST(ibaBuildingType, F("building"), F("building type"), F("Gebäude"), F("Byggnadstyp")) +MAKE_PSTR_LIST(heatingPID, F("heatingpid"), F("heating PID"), F("Heizungs-PID"), F("Uppvärmning PID")) +MAKE_PSTR_LIST(ibaCalIntTemperature, F("intoffset"), F("internal temperature offset"), F("Korrektur interner Temperatur"), F("Korrigering interntemperatur")) +MAKE_PSTR_LIST(ibaMinExtTemperature, F("minexttemp"), F("minimal external temperature"), F("min. Aussentemperatur"), F("Min Extern Temperatur")) +MAKE_PSTR_LIST(backlight, F("backlight"), F("key backlight"), F("Gegenlicht"), F("Toetsverlichting"), F("Bakgrundsbelysning")) +MAKE_PSTR_LIST(damping, + F("damping"), + F("damping outdoor temperature"), + F("Dämpfung der Außentemperatur"), + F("Demping buitentemperatuur"), + F("Dämpning Utomhustemperatur")) +MAKE_PSTR_LIST(tempsensor1, F("inttemp1"), F("temperature sensor 1"), F("Temperatursensor 1"), F("Temperatuursensor 1"), F("Temperatursensor 1")) +MAKE_PSTR_LIST(tempsensor2, F("inttemp2"), F("temperature sensor 2"), F("Temperatursensor 2"), F("Temperatuursensor 2"), F("Temperatursensor 2")) +MAKE_PSTR_LIST(dampedoutdoortemp, + F("dampedoutdoortemp"), + F("damped outdoor temperature"), + F("gedämpfte Außentemperatur"), + F("Gedempte buitentemperatuur"), + F("Dämpad Utomhustemperatur")) +MAKE_PSTR_LIST(floordrystatus, F("floordry"), F("floor drying"), F("Estrichtrocknung"), F("Vloerdroogprogramma"), F("Golvtorkning")) +MAKE_PSTR_LIST(floordrytemp, + F("floordrytemp"), + F("floor drying temperature"), + F("Estrichtrocknungs Temperatur"), + F("Temperatuur vloerdroogprogramma"), + F("Golvtorkning Temperatur")) +MAKE_PSTR_LIST(brightness, F("brightness"), F("screen brightness"), F("Bildschirmhelligkeit"), F("Schermhelderheid"), F("Ljusstyrka")) +MAKE_PSTR_LIST(autodst, + F("autodst"), + F("automatic change daylight saving time"), + F("automatische Sommerzeit Umstellung"), + F("Automatische omschakeling zomer-wintertijd"), + F("Automatisk växling sommar/vinter-tid")) +MAKE_PSTR_LIST(preheating, + F("preheating"), + F("preheating in the clock program"), + F("Vorheizen im Zeitprogramm"), + F("Voorverwarming in het klokprogramma"), + F("Förvärmning i tidsprogram")) +MAKE_PSTR_LIST(offtemp, F("offtemp"), F("temperature when mode is off"), F("Temperatur bei AUS"), F("Temperatuur bij UIT"), F("Temperatur Avslagen")) +MAKE_PSTR_LIST(mixingvalves, F("mixingvalves"), F("mixing valves"), F("Mischventile"), F("Mengkleppen"), F("Blandningsventiler")) + +// thermostat ww +MAKE_PSTR_LIST(wwMode, F("wwmode"), F("mode"), F("Modus"), F("Modus"), F("Läge")) +MAKE_PSTR_LIST(wwSetTempLow, F("wwsettemplow"), F("set low temperature"), F("untere Solltemperatur"), F("Onderste streeftemperatuur"), F("Nedre Börvärde")) +MAKE_PSTR_LIST(wwWhenModeOff, + F("wwwhenmodeoff"), + F("when thermostat mode off"), + F("bei Thermostatmodus AUS"), + F("Als Thermostaat op UIT"), + F("när Termostatläge är AV")) +MAKE_PSTR_LIST(wwExtra1, F("wwextra1"), F("circuit 1 extra"), F("Kreis 1 Extra"), F("Circuit 1 extra"), F("Krets 1 Extra")) +MAKE_PSTR_LIST(wwExtra2, F("wwextra2"), F("circuit 2 extra"), F("Kreis 2 Extra"), F("Circuit 2 extra"), F("Kets 2 Extra")) + +MAKE_PSTR_LIST(wwCharge, F("wwcharge"), F("charge"), F("Laden"), F("Laden"), F("Ladda")) +MAKE_PSTR_LIST(wwChargeDuration, F("wwchargeduration"), F("charge duration"), F("Ladedauer"), F("Laadtijd"), F("Laddtid")) +MAKE_PSTR_LIST(wwDisinfect, F("wwdisinfect"), F("disinfection"), F("Desinfektion"), F("Desinfectie"), F("Desinfektion")) +MAKE_PSTR_LIST(wwDisinfectDay, F("wwdisinfectday"), F("disinfection day"), F("Desinfektionstag"), F("Desinfectiedag"), F("Desinfektionsdag")) +MAKE_PSTR_LIST(wwDisinfectHour, F("wwdisinfecthour"), F("disinfection hour"), F("Desinfektionsstunde"), F("Desinfectieuur"), F("Desinfektionstimme")) +MAKE_PSTR_LIST(wwDisinfectTime, F("wwdisinfecttime"), F("disinfection time"), F("Desinfektionszeit"), F("Desinfectietijd"), F("Desinfektionstid")) +MAKE_PSTR_LIST(wwDailyHeating, F("wwdailyheating"), F("daily heating"), F("täglich Heizen"), F("Dagelijks opwarmen"), F("Daglig Uppvärmning")) +MAKE_PSTR_LIST(wwDailyHeatTime, F("wwdailyheattime"), F("daily heating time"), F("tägliche Heizzeit"), F("Tijd dagelijkse opwarming"), F("Daglig Uppvärmningstid")) + +// thermostat hc +MAKE_PSTR_LIST(selRoomTemp, F("seltemp"), F("selected room temperature"), F("Sollwert Raumtemperatur"), F("Streeftemperatuur kamer"), F("Vald Rumstemperatur")) +MAKE_PSTR_LIST(roomTemp, F("currtemp"), F("current room temperature"), F("aktuelle Raumtemperatur"), F("Huidige kamertemperatuur"), F("Aktuell Rumstemperatur")) +MAKE_PSTR_LIST(mode, F("mode"), F("mode"), F("Modus"), F("Modus"), F("Läge")) +MAKE_PSTR_LIST(modetype, F("modetype"), F("mode type"), F("Modus Typ"), F("Type modus"), F("Typ av läge")) +MAKE_PSTR_LIST(fastheatup, F("fastheatup"), F("fast heatup"), F("schnelles Aufheizen"), F("Snel opwarmen"), F("Snabb Uppvärmning")) +MAKE_PSTR_LIST(daytemp, F("daytemp"), F("day temperature"), F("Tagestemperatur"), F("temperatuur dag"), F("Dagstemperatur")) +MAKE_PSTR_LIST(daylowtemp, F("daytemp2"), F("day temperature T2"), F("Tagestemperatur T2"), F("Temperatuur dag T2"), F("Dagstemperatur T2")) +MAKE_PSTR_LIST(daymidtemp, F("daytemp3"), F("day temperature T3"), F("Tagestemperatur T3"), F("Temperatuur dag T3"), F("Dagstemperatur T3")) +MAKE_PSTR_LIST(dayhightemp, F("daytemp4"), F("day temperature T4"), F("Tagestemperatur T4"), F("Temperatuur dag T4"), F("Dagstemperatur T4")) +MAKE_PSTR_LIST(heattemp, F("heattemp"), F("heat temperature"), F("Heizen Temperatur"), F("Temperatuur verwarming"), F("Temperatur Uppvärmning")) +MAKE_PSTR_LIST(nighttemp, F("nighttemp"), F("night temperature"), F("Nachttemperatur"), F("Nachttemperatuur"), F("Nattemperatur")) +MAKE_PSTR_LIST(nighttemp2, F("nighttemp"), F("night temperature T1"), F("Nachttemperatur T1"), F("Nachttemperatuur T1"), F("Nattemperatur T1")) +MAKE_PSTR_LIST(ecotemp, F("ecotemp"), F("eco temperature"), F("eco Temperatur"), F("Temperatuur eco"), F("Eko-temperatur")) +MAKE_PSTR_LIST(manualtemp, F("manualtemp"), F("manual temperature"), F("manuelle Temperatur"), F("temperatuur handmatig"), F("Temperatur Manuell")) +MAKE_PSTR_LIST(tempautotemp, + F("tempautotemp"), + F("temporary set temperature automode"), + F("zwischenzeitliche Solltemperatur"), + F("Streeftemperatuur automodus tijdelijk"), + F("Temporär Aktivering av Auto-läge")) +MAKE_PSTR_LIST(remoteseltemp, + F("remoteseltemp"), + F("temporary set temperature from remote"), + F("Temperatur von Fernsteuerung"), + F("Temperatuur van afstandsbedieding"), + F("Temperatur från fjärruppkoppling")) +MAKE_PSTR_LIST(comforttemp, F("comforttemp"), F("comfort temperature"), F("Komforttemperatur"), F("Comforttemperatuur"), F("Komforttemperatur")) +MAKE_PSTR_LIST(summertemp, F("summertemp"), F("summer temperature"), F("Sommertemperatur"), F("Zomertemperatuur"), F("Sommartemperatur")) +MAKE_PSTR_LIST(designtemp, F("designtemp"), F("design temperature"), F("Auslegungstemperatur"), F("Ontwerptemperatuur"), F("Design-temperatur")) +MAKE_PSTR_LIST(offsettemp, F("offsettemp"), F("offset temperature"), F("Temperaturanhebung"), F("Temperatuur offset"), F("Temperaturkorrigering")) +MAKE_PSTR_LIST(minflowtemp, F("minflowtemp"), F("min flow temperature"), F("min Vorlauftemperatur"), F("Min Flödestemperatur")) +MAKE_PSTR_LIST(maxflowtemp, F("maxflowtemp"), F("max flow temperature"), F("max Vorlauftemperatur"), F("Max Flödestemperatur")) +MAKE_PSTR_LIST(roominfluence, F("roominfluence"), F("room influence"), F("Raumeinfluss"), F("Ruimteinvloed"), F("Rumspåverkan")) +MAKE_PSTR_LIST(roominfl_factor, F("roominflfactor"), F("room influence factor"), F("Raumeinfluss Factor"), F("Factor ruimteinvloed"), F("Rumspåverkansfaktor")) +MAKE_PSTR_LIST(curroominfl, F("curroominfl"), F("current room influence"), F("aktueller Raumeinfluss"), F("Huidige ruimteinvloed"), F("Aktuell Rumspåverkan")) +MAKE_PSTR_LIST(nofrosttemp, F("nofrosttemp"), F("nofrost temperature"), F("Frostschutztemperatur"), F("Temperatuur vorstbeveiliging"), F("Temperatur Frostskydd")) +MAKE_PSTR_LIST(targetflowtemp, + F("targetflowtemp"), + F("target flow temperature"), + F("berechnete Vorlauftemperatur"), + F("Berekende aanvoertemperatuur"), + F("Målvärde Flödestemperatur")) +MAKE_PSTR_LIST(heatingtype, F("heatingtype"), F("heating type"), F("Heizungstyp"), F("Verwarmingstype"), F("Uppvärmningstyp")) +MAKE_PSTR_LIST(summersetmode, F("summersetmode"), F("set summer mode"), F("Einstellung Sommerbetrieb"), F("Instelling zomerbedrijf"), F("Aktivera Sommarläge")) +MAKE_PSTR_LIST(hpoperatingmode, + F("hpoperatingmode"), + F("heatpump operating mode"), + F("Wärmepumpe Betriebsmodus"), + F("Bedrijfsmodus warmtepomp"), + F("Värmepump Driftläge")) +MAKE_PSTR_LIST(hpoperatingstate, F("hpoperatingstate"), F("heatpump operating state"), F("WP Arbeitsweise"), F("Huidige modus warmtepomp"), F("Värmepump Driftstatus")) +MAKE_PSTR_LIST(controlmode, F("controlmode"), F("control mode"), F("Kontrollmodus"), F("Comtrolemodus"), F("Kontrolläge")) +MAKE_PSTR_LIST(control, F("control"), F("control device"), F("Fernsteuerung"), F("Afstandsbedieding"), F("Kontrollenhet")) +MAKE_PSTR_LIST(program, F("program"), F("program"), F("Programm"), F("Programma"), F("Program")) +MAKE_PSTR_LIST(pause, F("pause"), F("pause time"), F("Pausenzeit"), F("Pausetijd"), F("Paustid")) +MAKE_PSTR_LIST(party, F("party"), F("party time"), F("Partyzeit"), F("Partytijd"), F("Partytid")) +MAKE_PSTR_LIST(holidaytemp, F("holidaytemp"), F("holiday temperature"), F("Urlaubstemperatur"), F("Vakantietemperatuur"), F("Helgtemperatur")) +MAKE_PSTR_LIST(summermode, F("summermode"), F("summer mode"), F("Sommerbetrieb"), F("Zomerbedrijf"), F("Sommarläge")) +MAKE_PSTR_LIST(holidaymode, F("holidaymode"), F("holiday mode"), F("Urlaubsbetrieb"), F("Vakantiebedrijf"), F("Helgläge")) +MAKE_PSTR_LIST(flowtempoffset, + F("flowtempoffset"), + F("flow temperature offset for mixer"), + F("Vorlauftemperaturanhebung"), + F("Mixer aanvoertemperatuur offset"), + F("Temperaturkorrigering Flödestemp. Blandningsventil")) +MAKE_PSTR_LIST(reducemode, F("reducemode"), F("reduce mode"), F("Absenkmodus"), F("Gereduceerde modus"), F("Reducerat Läge")) +MAKE_PSTR_LIST(noreducetemp, + F("noreducetemp"), + F("no reduce below temperature"), + F("Absenkung unterbrechen unter"), + F("Reduceermodus onderbreken onder"), + F("Inaktivera reducering under")) +MAKE_PSTR_LIST(reducetemp, F("reducetemp"), F("off/reduce switch temperature"), F("Absenkmodus unter"), F("Onderste afschakeltemperatuur"), F("Avslag/Reducera under")) +MAKE_PSTR_LIST(vacreducetemp, + F("vacreducetemp"), + F("vacations off/reduce switch temperature"), + F("Urlaub Absenkmodus unter"), + F("Vakantiemodus onderste afschakeltemperatuur"), + F("Helg Avslag/Reducering under")) +MAKE_PSTR_LIST(vacreducemode, F("vacreducemode"), F("vacations reduce mode"), F("Urlaub Absenkmodus"), F("Vakantie afschakelmodus"), F("Helg reduceringsläge")) +MAKE_PSTR_LIST(nofrostmode, F("nofrostmode"), F("nofrost mode"), F("Frostschutz Modus"), F("Vorstbeveiligingsmodus"), F("Frostskyddsläge")) +MAKE_PSTR_LIST(remotetemp, + F("remotetemp"), + F("room temperature from remote"), + F("Raumtemperatur der Fernsteuerung"), + F("Ruimtetemperatuur van afstandsbediening"), + F("Rumstemperatur från fjärr")) + +MAKE_PSTR_LIST(wwHolidays, F("wwholidays"), F("holiday dates"), F("Feiertage"), F("Feestdagen"), F("Helgdagar")) +MAKE_PSTR_LIST(wwVacations, F("wwvacations"), F("vacation dates"), F("Urlaubstage"), F("Vakantiedagen"), F("Semesterdatum Varmvatten")) +MAKE_PSTR_LIST(holidays, F("holidays"), F("holiday dates"), F("Feiertage"), F("Feestdagen"), F("Helgdatum")) +MAKE_PSTR_LIST(vacations, F("vacations"), F("vacation dates"), F("Urlaubstage"), F("Vakantiedagen"), F("Semesterdatum")) +MAKE_PSTR_LIST(wwprio, F("wwprio"), F("dhw priority"), F("WW-Vorrang"), F("Prioriteit warm water"), F("Prioritera Varmvatten")) +MAKE_PSTR_LIST(nofrostmode1, F("nofrostmode1"), F("nofrost mode"), F("Frostschutz"), F("Vorstbeveiligingsmodus"), F("Frostskyddsläge")) +MAKE_PSTR_LIST(reducehours, F("reducehours"), F("duration for nighttemp"), F("Dauer Nachttemp."), F("Duur nachtverlaging"), F("Timmar Nattsänkning")) +MAKE_PSTR_LIST(reduceminutes, + F("reduceminutes"), + F("remaining time for nightmode"), + F("Restzeit Nachttemp."), + F("Resterende tijd nachtverlaging"), + F("Återstående Tid Nattläge")) +MAKE_PSTR_LIST(switchonoptimization, + F("switchonoptimization"), + F("switch-on optimization"), + F("Schaltoptimierung"), + F("Inschakeloptimalisering"), + F("Växlingsoptimering")) + +// heatpump +MAKE_PSTR_LIST(airHumidity, F("airhumidity"), F("relative air humidity"), F("relative Luftfeuchte"), F("Relatieve luchtvochtigheid"), F("Relativ Luftfuktighet")) +MAKE_PSTR_LIST(dewTemperature, F("dewtemperature"), F("dew point temperature"), F("Taupunkttemperatur"), F("Dauwpunttemperatuur"), F("Daggpunkt")) + +// mixer +MAKE_PSTR_LIST(flowSetTemp, + F("flowsettemp"), + F("setpoint flow temperature"), + F("Sollwert Vorlauftemperatur"), + F("Streefwaarde aanvoertemperatuur"), + F("Vald flödestemperatur")) +MAKE_PSTR_LIST(flowTempHc, + F("flowtemphc"), + F("flow temperature (TC1)"), + F("Vorlauftemperatur des HK (TC1)"), + F("Aanvoertemperatuut circuit (TC1)"), + F("Flödestemperatur (TC1)")) +MAKE_PSTR_LIST(pumpStatus, F("pumpstatus"), F("pump status (PC1)"), F("Pumpenstatus des HK (PC1)"), F("pompstatus circuit (PC1)"), F("Pumpstatus (PC1)")) +MAKE_PSTR_LIST(mixerStatus, + F("valvestatus"), + F("mixing valve actuator (VC1)"), + F("Mischerventil Position (VC1)"), + F("positie mixerklep (VC1)"), + F("Shuntventil Status (VC1)")) +MAKE_PSTR_LIST(flowTempVf, + F("flowtempvf"), + F("flow temperature in header (T0/Vf)"), + F("Vorlauftemperatur am Verteiler (T0/Vf)"), + F("aanvoertemperatuur verdeler (T0/Vf)"), + F("Flödestemperatur Fördelare (T0/Vf)")) +MAKE_PSTR_LIST(mixerSetTime, F("valvesettime"), F("time to set valve"), F("Zeit zum Einstellen des Ventils"), F("Inschakeltijd mengklep"), F("Inställningstid Ventil")) +// mixer prefixed with wwc +MAKE_PSTR_LIST(wwPumpStatus, + F("pumpstatus"), + F("pump status in assigned wwc (PC1)"), + F("Pumpenstatus des wwk (PC1)"), + F("Pompstatus in WW circuit (PC1)"), + F("Pumpstatus i VV-krets (PC1)")) +MAKE_PSTR_LIST(wwTempStatus, + F("wwtempstatus"), + F("temperature switch in assigned wwc (MC1)"), + F("Temperaturschalter des wwk (MC1)"), + F("Temperatuurschakeling in WW circuit (MC1)"), + F("Temperaturventil i VV-krets (MC1)")) +MAKE_PSTR_LIST(wwTemp, F("wwtemp"), F("current temperature"), F("aktuelle Temperatur"), F("huidige temperatuur"), F("Aktuell Temperatur")) +// mixer pool +MAKE_PSTR_LIST(poolSetTemp, F("poolsettemp"), F("pool set temperature"), F("Pool Solltemperatur"), F("Streeftemperatuur zwembad"), F("Pool Temperatur Börvärde")) +MAKE_PSTR_LIST(poolTemp, F("pooltemp"), F("pool temperature"), F("Pool Temperatur"), F("Zwembadtemperatuur"), F("Pooltemperatur")) +MAKE_PSTR_LIST(poolShuntStatus, + F("poolshuntstatus"), + F("pool shunt status opening/closing"), + F("Pool Ventil öffnen/schließen"), + F("Zwembadklep status openen/sluiten"), + F("Pool Shunt-status öppnen/stängd")) +MAKE_PSTR_LIST(poolShunt, + F("poolshunt"), + F("pool shunt open/close (0% = pool / 100% = heat)"), + F("Pool Ventil Öffnung"), + F("Mengklep zwembad stand"), + F("Pool Shunt Öppen/Stängd")) +MAKE_PSTR_LIST(hydrTemp, F("hydrTemp"), F("hydraulic header temperature"), F("Verteilertemperatur"), F("Temperatuur open verdeler"), F("Fördelartemperatur")) + +// solar +MAKE_PSTR_LIST(cylMiddleTemp, + F("cylmiddletemp"), + F("cylinder middle temperature (TS3)"), + F("Speichertemperatur Mitte (TS3)"), + F("Zonneboilertemperatuur midden (TS3)"), + F("Cylindertemperatur Mitten (TS3)")) +MAKE_PSTR_LIST(retHeatAssist, + F("retheatassist"), + F("return temperature heat assistance (TS4)"), + F("Rücklaufanhebungs-Temp. (TS4)"), + F("Retourtemperatuur verwarmingsassistentie (TS4)"), + F("Returtemperatur värmestöd (TS4)")) +MAKE_PSTR_LIST(m1Valve, + F("heatassistvalve"), + F("heat assistance valve (M1)"), + F("Ventil Heizungsunterstützung (M1)"), + F("Klep verwarmingsassistentie (M1)"), + F("Uppvärmningsstöd Ventil (M1)")) +MAKE_PSTR_LIST(m1Power, + F("heatassistpower"), + F("heat assistance valve power (M1)"), + F("Ventilleistung Heizungsunterstützung (M1)"), + F("Vermogen klep verwarmingsassistentie (M1)"), + F("Uppvärmningsstöd Ventil Effekt (M1)")) +MAKE_PSTR_LIST(pumpMinMod, F("pumpminmod"), F("minimum pump modulation"), F("minimale Pumpenmodulation"), F("Minimale pompmodulatie"), F("Min Pumpmodulering")) +MAKE_PSTR_LIST(maxFlow, F("maxflow"), F("maximum solar flow"), F("maximaler Durchfluss"), F("Maximale doorstroom solar"), F("Max Flöde Solpanel")) +MAKE_PSTR_LIST(solarPower, F("solarpower"), F("actual solar power"), F("aktuelle Solarleistung"), F("Huidig solar vermogen"), F("Aktuellt Sol-effekt")) +MAKE_PSTR_LIST(solarPumpTurnonDiff, + F("turnondiff"), + F("pump turn on difference"), + F("Einschalthysterese Pumpe"), + F("Inschakelhysterese pomp"), + F("Aktiveringshysteres Pump")) +MAKE_PSTR_LIST(solarPumpTurnoffDiff, + F("turnoffdiff"), + F("pump turn off difference"), + F("Ausschalthysterese Pumpe"), + F("Uitschakelhysterese pomp"), + F("Avslagshysteres Pump")) +MAKE_PSTR_LIST(pump2MinMod, + F("pump2minmod"), + F("minimum pump 2 modulation"), + F("minimale Modulation Pumpe 2"), + F("Minimale modulatie pomp 2"), + F("Min Modulering Pump 2")) +MAKE_PSTR_LIST(solarPump2TurnonDiff, + F("turnondiff2"), + F("pump 2 turn on difference"), + F("Einschalthysterese Pumpe 2"), + F("Inschakelhysterese pomp 2"), + F("Aktiveringshysteres Pump 2")) +MAKE_PSTR_LIST(solarPump2TurnoffDiff, + F("turnoffdiff2"), + F("pump 2 turn off difference"), + F("Ausschalthysterese Pumpe 2"), + F("Uitschakelhysterese pomp 2"), + F("Avslagshysteres Pump 2")) + +MAKE_PSTR_LIST(collectorTemp, + F("collectortemp"), + F("collector temperature (TS1)"), + F("Kollektortemperatur (TS1)"), + F("Collectortemperatuur (TS1)"), + F("Kollektor Temperatur (TS1)")) +MAKE_PSTR_LIST(collector2Temp, + F("collector2temp"), + F("collector 2 temperature (TS7)"), + F("Kollector 2 Temperatur (TS7)"), + F("Collector 2 temperatuur (TS7)"), + F("Kollektor 2 Temperatur (TS7)")) +MAKE_PSTR_LIST(cylBottomTemp, + F("cylbottomtemp"), + F("cylinder bottom temperature (TS2)"), + F("Speicher Bodentemperatur (TS2)"), + F("Bodemtemperatuur zonneboiler (TS2)"), + F("Cylindertemperatur Botten (TS2)")) +MAKE_PSTR_LIST(cyl2BottomTemp, + F("cyl2bottomtemp"), + F("second cylinder bottom temperature (TS5)"), + F("2. Speicher Bodentemperatur (TS5)"), + F("Bodemtemperatuur 2e boiler"), + F("Sekundär Cylindertemperatur Botten (TS5)")) +MAKE_PSTR_LIST(heatExchangerTemp, + F("heatexchangertemp"), + F("heat exchanger temperature (TS6)"), + F("wärmetauscher Temperatur (TS6)"), + F("Temperatuur warmtewisselaar (TS6)"), + F("Värmeväxlare Temperatur (TS6)")) +MAKE_PSTR_LIST(collectorMaxTemp, + F("collectormaxtemp"), + F("maximum collector temperature"), + F("maximale Kollektortemperatur"), + F("Maximale collectortemperatuur"), + F("Max Kollektortemperatur")) +MAKE_PSTR_LIST(collectorMinTemp, + F("collectormintemp"), + F("minimum collector temperature"), + F("minimale Kollektortemperatur"), + F("Minimale collectortemperatuur"), + F("Min Kollektortemperatur")) +MAKE_PSTR_LIST(cylMaxTemp, + F("cylmaxtemp"), + F("maximum cylinder temperature"), + F("maximale Speichertemperatur"), + F("maximale temperatuur zonneboiler"), + F("Max Cylindertemperatur")) +MAKE_PSTR_LIST(solarPumpMod, F("solarpumpmod"), F("pump modulation (PS1)"), F("Pumpenmodulation (PS1)"), F("Pompmodulatie (PS1)"), F("Pumpmodulering (PS1)")) +MAKE_PSTR_LIST(cylPumpMod, + F("cylpumpmod"), + F("cylinder pump modulation (PS5)"), + F("Speicherpumpenmodulation (PS5)"), + F("Modulatie zonneboilerpomp (PS5)"), + F("Cylinderpumpmodulering (PS5)")) +MAKE_PSTR_LIST(solarPump, F("solarpump"), F("pump (PS1)"), F("Pumpe (PS1)"), F("Pomp (PS1)"), F("Pump (PS1)")) +MAKE_PSTR_LIST(solarPump2, F("solarpump2"), F("pump 2 (PS4)"), F("Pumpe 2 (PS4)"), F("Pomp 2 (PS4)"), F("Pump 2 (PS4)")) +MAKE_PSTR_LIST(solarPump2Mod, F("solarpump2mod"), F("pump 2 modulation (PS4)"), F("pump 2 modulation (PS4)"), F("Modulatie pomp 2 (PS4)"), F("Pump 2 Modulering (PS4)")) +MAKE_PSTR_LIST(valveStatus, F("valvestatus"), F("valve status"), F("Ventilstatus"), F("Klepstatus"), F("Ventilstatus")) +MAKE_PSTR_LIST(cylHeated, F("cylheated"), F("cyl heated"), F("Speichertemperatur erreicht"), F("Boilertemperatuur behaald"), F("Värmepanna Uppvärmd")) +MAKE_PSTR_LIST(collectorShutdown, F("collectorshutdown"), F("collector shutdown"), F("Kollektorabschaltung"), F("Collector afschakeling"), F("Kollektor Avstängning")) +MAKE_PSTR_LIST(pumpWorkTime, F("pumpworktime"), F("pump working time"), F("Pumpenlaufzeit"), F("Pomplooptijd"), F("Pump Drifttid")) +MAKE_PSTR_LIST(pump2WorkTime, F("pump2worktime"), F("pump 2 working time"), F("Pumpe 2 Laufzeit"), F("Looptijd pomp 2"), F("Pump 2 Drifttid")) +MAKE_PSTR_LIST(m1WorkTime, + F("m1worktime"), + F("differential control working time"), + F("Differenzregelung Arbeitszeit"), + F("Verschilregeling arbeidstijd"), + F("Differentialreglering Drifttid")) +MAKE_PSTR_LIST(energyLastHour, F("energylasthour"), F("energy last hour"), F("Energie letzte Std"), F("Energie laatste uur"), F("Energi Senaste Timmen")) +MAKE_PSTR_LIST(energyTotal, F("energytotal"), F("total energy"), F("Gesamtenergie"), F("Totale energie"), F("Total Energi")) +MAKE_PSTR_LIST(energyToday, F("energytoday"), F("total energy today"), F("Energie heute"), F("Energie vandaag"), F("Total Energi Idag")) + +// solar ww +MAKE_PSTR_LIST(cyl1, F("cyl 1"), F("Zyl_1"), F("Cil 1"), F("Cyl 1")) +MAKE_PSTR_LIST(cyl2, F("cyl 2"), F("Zyl_2"), F("Cil 2"), F("Cyl 2")) +MAKE_PSTR_LIST(wwTemp1, F("wwtemp1"), F("temperature 1"), F("Temperatur 1"), F("Temperatuur 1"), F("Temperatur 1")) +MAKE_PSTR_LIST(wwTemp3, F("wwtemp3"), F("temperature 3"), F("Temperatur 3"), F("Temperatuur 2"), F("Temperatur 2")) +MAKE_PSTR_LIST(wwTemp4, F("wwtemp4"), F("temperature 4"), F("Temperatur 4"), F("Temperatuur 3"), F("Temperatur 3")) +MAKE_PSTR_LIST(wwTemp5, F("wwtemp5"), F("temperature 5"), F("Temperatur 5"), F("Temperatuur 5"), F("Temperatur 4")) +MAKE_PSTR_LIST(wwTemp7, F("wwtemp7"), F("temperature 7"), F("Temperatur 7"), F("Temperatuur 7"), F("Temperatur 5")) +MAKE_PSTR_LIST(wwPump, F("wwpump"), F("pump"), F("Pumpe"), F("Pomp"), F("Pump")) +// solar ww and mixer wwc +MAKE_PSTR_LIST(wwMinTemp, F("wwmintemp"), F("minimum temperature"), F("minimale Temperatur"), F("Minimale temperatuur"), F("Min Temperatur")) +MAKE_PSTR_LIST(wwRedTemp, F("wwredtemp"), F("reduced temperature"), F("redizierte Temperatur"), F("Gereduceerde temperatuur"), F("Reducerad Temperatur")) +MAKE_PSTR_LIST(wwDailyTemp, F("wwdailytemp"), F("daily temperature"), F("tägl. Temperatur"), F("Dagelijkse temperatuur"), F("Daglig temperatur")) +MAKE_PSTR_LIST(wwKeepWarm, F("wwkeepwarm"), F("keep warm"), F("Warmhalten"), F("Warm houde"), F("Varmhållning")) +MAKE_PSTR_LIST(wwStatus2, F("wwstatus2"), F("status 2"), F("Status 2"), F("Status 2"), F("Status 2")) +MAKE_PSTR_LIST(wwPumpMod, F("wwpumpmod"), F("pump modulation"), F("Pumpen Modulation"), F("Pompmodulatie"), F("Pumpmodulering")) +MAKE_PSTR_LIST(wwFlow, F("wwflow"), F("flow rate"), F("Flussrate"), F("Doorstroomsnelheid"), F("Flöde")) +// extra mixer ww +MAKE_PSTR_LIST(wwRequiredTemp, F("wwrequiredtemp"), F("required temperature"), F("benötigte Temperatur"), F("Benodigde temperatuur"), F("Nödvändig Temperatur")) +MAKE_PSTR_LIST(wwDiffTemp, + F("wwdifftemp"), + F("start differential temperature"), + F("Start Differential Temperatur"), + F("Start differentiele temperatuur"), + F("Start Differentialtemperatur")) + +// SM100 +MAKE_PSTR_LIST(heatTransferSystem, + F("heattransfersystem"), + F("heattransfer system"), + F("Wärmetransfer System"), + F("Warmteoverdrachtssysteem"), + F("Värmeöverföringssystem")) +MAKE_PSTR_LIST(externalCyl, F("externalcyl"), F("external cylinder"), F("Externer Speicher"), F("Externe boiler"), F("Extern Cylinder")) +MAKE_PSTR_LIST(thermalDisinfect, F("thermaldisinfect"), F("thermal disinfection"), F("Thermische Desinfektion"), F("Thermische desinfectie"), F("Termisk Desinfektion")) +MAKE_PSTR_LIST(heatMetering, F("heatmetering"), F("heatmetering"), F("Wärmemessung"), F("warmtemeting"), F("Värmemätning")) +MAKE_PSTR_LIST(solarIsEnabled, F("solarenabled"), F("solarmodule enabled"), F("Solarmodul aktiviert"), F("Solarmodule geactiveerd"), F("Solmodul Aktiverad")) + +// telegram 0x035A +MAKE_PSTR_LIST(solarPumpMode, F("solarpumpmode"), F("pump mode"), F("solar Pumpen Einst."), F("Modus zonneboilerpomp"), F("Sol Pumpläge")) +MAKE_PSTR_LIST(solarPumpKick, F("pumpkick"), F("pump kick"), F("Röhrenkollektorfunktion"), F("Modus buizencollector"), F("Sol Kollektorfunktion")) +MAKE_PSTR_LIST(plainWaterMode, F("plainwatermode"), F("plain water mode"), F("Südeuropafunktion"), F("Modus Zuid-Europa"), F("Sydeuropa-funktion")) +MAKE_PSTR_LIST(doubleMatchFlow, F("doublematchflow"), F("doublematchflow"), F("Double Match Flow"), F("Double Match Flow"), F("Dubbelmatchning Flöde")) +MAKE_PSTR_LIST(solarPump2Mode, F("pump2mode"), F("pump 2 mode"), F("Pumpe 2 Modus"), F("Modus pomp 2"), F("Pump 2 Läge")) +MAKE_PSTR_LIST(solarPump2Kick, F("pump2kick"), F("pump kick 2"), F("Pumpe 2 Startboost"), F("Startboost pomp 2"), F("Pump 2 Kollektorfunktion")) + +// telegram 0x035F +MAKE_PSTR_LIST(cylPriority, F("cylpriority"), F("cylinder priority"), F("Speicher Priorität"), F("Prioriteit boiler"), F("Cylinderprioritering")) + +// telegram 0x380 +MAKE_PSTR_LIST(climateZone, F("climatezone"), F("climate zone"), F("Klimazone"), F("klimaatzone"), F("Klimatzon")) +MAKE_PSTR_LIST(collector1Area, F("collector1area"), F("collector 1 area"), F("Kollektor 1 Fläche"), F("oppervlakte collector 1"), F("Kollektor 1 Area")) +MAKE_PSTR_LIST(collector1Type, F("collector1type"), F("collector 1 type"), F("Kollektor 1 Typ"), F("Type collector 1"), F("Kollektor 1 Typ")) +MAKE_PSTR_LIST(collector2Area, F("collector2area"), F("collector 2 area"), F("Kollektor 2 Fläche"), F("Oppervlakte collector 2"), F("Kollektor 2 Area")) +MAKE_PSTR_LIST(collector2Type, F("collector2type"), F("collector 2 type"), F("Kollektor 2 Typ"), F("Type collector 2"), F("Kollektor 2 Typ")) + +// telegram 0x0363 heatCounter +MAKE_PSTR_LIST(heatCntFlowTemp, + F("heatcntflowtemp"), + F("heat counter flow temperature"), + F("Wärmezähler Vorlauf-Temperatur"), + F("Aanvoertemperatuur warmteenergiemeter"), + F("Värmeräknare Flödestemperatur")) +MAKE_PSTR_LIST(heatCntRetTemp, + F("heatcntrettemp"), + F("heat counter return temperature"), + F("Wärmezähler Rücklauf-Temperatur"), + F("Retourtemperatuur warmteenergiemeter"), + F("Värmeräknare Returtemperatur")) +MAKE_PSTR_LIST(heatCnt, F("heatcnt"), F("heat counter impulses"), F("Wärmezähler Impulse"), F("Warmteenergiemeter pulsen"), F("Värmeräknare Impuls")) +MAKE_PSTR_LIST(swapFlowTemp, + F("swapflowtemp"), + F("swap flow temperature (TS14)"), + F("Austausch Vorlauf-Temperatur (TS14)"), + F("Aanvoertemperatuur verwisselaar (TS14)"), + F("Växlingstemperatur Flöde (TS14)")) +MAKE_PSTR_LIST(swapRetTemp, + F("swaprettemp"), + F("swap return temperature (TS15)"), + F("Austausch Rücklauf-Temperatur (TS15)"), + F("Retourtemperatuur verwisselaar (TS15)"), + F("Växlingstemperatur Returflöde (TS15)")) + +// switch +MAKE_PSTR_LIST(activated, F("activated"), F("activated"), F("Aktiviert"), F("Geactiveerd"), F("Aktiverad")) +MAKE_PSTR_LIST(status, F("status"), F("status"), F("Status"), F("Status"), F("Status")) + +// RF sensor, id 0x40, telegram 0x435 +MAKE_PSTR_LIST(RFTemp, F("rftemp"), F("RF room temperature sensor"), F("RF Raumtemperatur Sensor"), F("RF ruimtetemperatuur sensor"), F("RF Rumsgivare Temp")) + +/* +// unknown fields to track (SM10), only for testing +// **** NO TRANSLATION NEEDED **** +MAKE_PSTR_LIST(data11, F("data11"), F("unknown datafield 11")) +MAKE_PSTR_LIST(data12, F("data12"), F("unknown datafield 12")) +MAKE_PSTR_LIST(data8, F("data8"), F("unknown datafield 8")) +MAKE_PSTR_LIST(data0, F("data0"), F("unknown datafield 0")) +MAKE_PSTR_LIST(data1, F("data1"), F("unknown datafield 1")) +MAKE_PSTR_LIST(setting3, F("setting3"), F("unknown setting 3")) +MAKE_PSTR_LIST(setting4, F("setting4"), F("unknown setting 4")) +*/ diff --git a/src/mqtt.cpp b/src/mqtt.cpp index bbcf834c2..1198ca6ec 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -26,6 +26,7 @@ namespace emsesp { AsyncMqttClient * Mqtt::mqttClient_; // static parameters we make global +std::string Mqtt::system_hostname_; // copy from System::hostname() std::string Mqtt::mqtt_base_; uint8_t Mqtt::mqtt_qos_; bool Mqtt::mqtt_retain_; @@ -109,7 +110,7 @@ void Mqtt::subscribe(const std::string & topic) { } // resubscribe to all MQTT topics -// if it's already in the queue, ignore it +// if it's already in the queue then just ignore it void Mqtt::resubscribe() { if (mqtt_subfunctions_.empty()) { return; @@ -277,7 +278,7 @@ void Mqtt::on_message(const char * topic, const char * payload, size_t len) cons return; } - // check first againts any of our subscribed topics + // check first against any of our subscribed topics for (const auto & mf : mqtt_subfunctions_) { // add the base back char full_topic[MQTT_TOPIC_MAX_SIZE]; @@ -420,6 +421,9 @@ void Mqtt::load_settings() { publish_time_other_ = mqttSettings.publish_time_other * 1000; publish_time_sensor_ = mqttSettings.publish_time_sensor * 1000; }); + + // get a local copy of the system hostname + system_hostname_ = EMSESP::system_.hostname(); } void Mqtt::start() { @@ -576,28 +580,32 @@ void Mqtt::on_connect() { publish(F_(info), doc.as()); // topic called "info" if (ha_enabled_) { - queue_unsubscribe_message(discovery_prefix_ + "/climate/" + mqtt_base_ + "/#"); - queue_unsubscribe_message(discovery_prefix_ + "/sensor/" + mqtt_base_ + "/#"); - queue_unsubscribe_message(discovery_prefix_ + "/binary_sensor/" + mqtt_base_ + "/#"); - queue_unsubscribe_message(discovery_prefix_ + "/number/" + mqtt_base_ + "/#"); - queue_unsubscribe_message(discovery_prefix_ + "/select/" + mqtt_base_ + "/#"); - queue_unsubscribe_message(discovery_prefix_ + "/switch/" + mqtt_base_ + "/#"); + LOG_INFO(F("start removing topics %s/+/%s/#"), discovery_prefix_.c_str(), system_hostname_.c_str()); + queue_unsubscribe_message(discovery_prefix_ + "/climate/" + system_hostname_ + "/#"); + queue_unsubscribe_message(discovery_prefix_ + "/sensor/" + system_hostname_ + "/#"); + queue_unsubscribe_message(discovery_prefix_ + "/binary_sensor/" + system_hostname_ + "/#"); + queue_unsubscribe_message(discovery_prefix_ + "/number/" + system_hostname_ + "/#"); + queue_unsubscribe_message(discovery_prefix_ + "/select/" + system_hostname_ + "/#"); + queue_unsubscribe_message(discovery_prefix_ + "/switch/" + system_hostname_ + "/#"); EMSESP::reset_mqtt_ha(); // re-create all HA devices if there are any ha_status(); // create the EMS-ESP device in HA, which is MQTT retained ha_climate_reset(true); } else { - queue_subscribe_message(discovery_prefix_ + "/climate/" + mqtt_base_ + "/#"); - queue_subscribe_message(discovery_prefix_ + "/sensor/" + mqtt_base_ + "/#"); - queue_subscribe_message(discovery_prefix_ + "/binary_sensor/" + mqtt_base_ + "/#"); - queue_subscribe_message(discovery_prefix_ + "/number/" + mqtt_base_ + "/#"); - queue_subscribe_message(discovery_prefix_ + "/select/" + mqtt_base_ + "/#"); - queue_subscribe_message(discovery_prefix_ + "/switch/" + mqtt_base_ + "/#"); - LOG_INFO(F("start removing topics %s/+/%s/#"), discovery_prefix_.c_str(), mqtt_base_.c_str()); + // with disabled HA we subscribe and the broker sends all stored HA-emsesp-configs. + // In line 272 they are removed. If HA is enabled the subscriptions are removed. + // As described in the doc (https://emsesp.github.io/docs/#/Troubleshooting?id=home-assistant): + // disable HA, wait 5 minutes (to allow the broker to send all), than reenable HA again. + queue_subscribe_message(discovery_prefix_ + "/climate/" + system_hostname_ + "/#"); + queue_subscribe_message(discovery_prefix_ + "/sensor/" + system_hostname_ + "/#"); + queue_subscribe_message(discovery_prefix_ + "/binary_sensor/" + system_hostname_ + "/#"); + queue_subscribe_message(discovery_prefix_ + "/number/" + system_hostname_ + "/#"); + queue_subscribe_message(discovery_prefix_ + "/select/" + system_hostname_ + "/#"); + queue_subscribe_message(discovery_prefix_ + "/switch/" + system_hostname_ + "/#"); } // send initial MQTT messages for some of our services EMSESP::shower_.set_shower_state(false, true); // Send shower_activated as false - EMSESP::system_.send_heartbeat(); // send heatbeat + EMSESP::system_.send_heartbeat(); // send heartbeat // re-subscribe to all custom registered MQTT topics resubscribe(); @@ -641,7 +649,7 @@ void Mqtt::ha_status() { ids.add("ems-esp"); char topic[MQTT_TOPIC_MAX_SIZE]; - snprintf(topic, sizeof(topic), "sensor/%s/system/config", mqtt_base_.c_str()); + snprintf(topic, sizeof(topic), "sensor/%s/system/config", system_hostname_.c_str()); Mqtt::publish_ha(topic, doc.as()); // publish the config payload with retain flag // create the sensors - must match the MQTT payload keys @@ -810,7 +818,7 @@ void Mqtt::process_queue() { if (message->topic.find(discovery_prefix_) == 0) { strlcpy(topic, message->topic.c_str(), sizeof(topic)); // leave topic as it is } else { - snprintf(topic, MQTT_TOPIC_MAX_SIZE, "%s/%s", mqtt_base_.c_str(), message->topic.c_str()); + snprintf(topic, MQTT_TOPIC_MAX_SIZE, "%s/%s", mqtt_base_.c_str(), message->topic.c_str()); // uses base } // if this has already been published and we're waiting for an ACK, don't publish again @@ -919,7 +927,8 @@ void Mqtt::publish_ha_sensor_config(DeviceValue & dv, const std::string & model, } // calculate the min and max - int16_t dv_set_min, dv_set_max; + int16_t dv_set_min; + int16_t dv_set_max; (void)dv.get_min_max(dv_set_min, dv_set_max); // determine if we're creating the command topics which we use special HA configs @@ -928,7 +937,7 @@ void Mqtt::publish_ha_sensor_config(DeviceValue & dv, const std::string & model, publish_ha_sensor_config(dv.type, dv.tag, - dv.full_name, + dv.get_fullname(), dv.device_type, dv.short_name, dv.uom, @@ -949,27 +958,29 @@ void Mqtt::publish_system_ha_sensor_config(uint8_t type, const __FlashStringHelp JsonArray ids = dev_json.createNestedArray("ids"); ids.add("ems-esp"); - publish_ha_sensor_config(type, DeviceValueTAG::TAG_HEARTBEAT, name, EMSdevice::DeviceType::SYSTEM, entity, uom, false, false, nullptr, 0, 0, 0, dev_json); + auto fullname = read_flash_string(name); + + publish_ha_sensor_config(type, DeviceValueTAG::TAG_HEARTBEAT, fullname, EMSdevice::DeviceType::SYSTEM, entity, uom, false, false, nullptr, 0, 0, 0, dev_json); } // MQTT discovery configs // 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 -void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdevice::DeviceValueType - uint8_t tag, // EMSdevice::DeviceValueTAG - const __FlashStringHelper * name, // fullname - const uint8_t device_type, // EMSdevice::DeviceType - const __FlashStringHelper * entity, // shortname - const uint8_t uom, // EMSdevice::DeviceValueUOM (0=NONE) - const bool remove, // true if we want to remove this topic - const bool has_cmd, - const __FlashStringHelper * const * options, - uint8_t options_size, - const int16_t dv_set_min, - const int16_t dv_set_max, - const JsonObject & dev_json) { +void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdevice::DeviceValueType + uint8_t tag, // EMSdevice::DeviceValueTAG + const std::string & fullname, // fullname, already translated + const uint8_t device_type, // EMSdevice::DeviceType + const __FlashStringHelper * const entity, // same as shortname + const uint8_t uom, // EMSdevice::DeviceValueUOM (0=NONE) + const bool remove, // true if we want to remove this topic + const bool has_cmd, + const __FlashStringHelper * const ** options, + uint8_t options_size, + const int16_t dv_set_min, + const int16_t dv_set_max, + const JsonObject & dev_json) { // ignore if name (fullname) is empty - if (name == nullptr) { + if (fullname.empty()) { return; } @@ -977,7 +988,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, char device_name[50]; strlcpy(device_name, EMSdevice::device_type_2_device_name(device_type).c_str(), sizeof(device_name)); - // create entity by add the hc/wwc tag if present, seperating with a . + // create entity by add the hc/wwc tag if present, separating with a . char new_entity[50]; 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()); @@ -1006,29 +1017,28 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, case DeviceValueType::ULONG: // number - https://www.home-assistant.io/integrations/number.mqtt // https://developers.home-assistant.io/docs/core/entity/number - - snprintf(topic, sizeof(topic), "number/%s/%s/config", mqtt_base_.c_str(), uniq); + snprintf(topic, sizeof(topic), "number/%s/%s/config", system_hostname_.c_str(), uniq); break; case DeviceValueType::BOOL: // switch - https://www.home-assistant.io/integrations/switch.mqtt - snprintf(topic, sizeof(topic), "switch/%s/%s/config", mqtt_base_.c_str(), uniq); + snprintf(topic, sizeof(topic), "switch/%s/%s/config", system_hostname_.c_str(), uniq); break; case DeviceValueType::ENUM: // select - https://www.home-assistant.io/integrations/select.mqtt - snprintf(topic, sizeof(topic), "select/%s/%s/config", mqtt_base_.c_str(), uniq); + snprintf(topic, sizeof(topic), "select/%s/%s/config", system_hostname_.c_str(), uniq); break; default: // plain old sensor - snprintf(topic, sizeof(topic), "sensor/%s/%s/config", mqtt_base_.c_str(), uniq); + snprintf(topic, sizeof(topic), "sensor/%s/%s/config", system_hostname_.c_str(), uniq); break; } } else { // plain old read only device entity if (type == DeviceValueType::BOOL) { - snprintf(topic, sizeof(topic), "binary_sensor/%s/%s/config", mqtt_base_.c_str(), uniq); // binary sensor + snprintf(topic, sizeof(topic), "binary_sensor/%s/%s/config", system_hostname_.c_str(), uniq); // binary sensor } else { use_ha_sensor = true; - snprintf(topic, sizeof(topic), "sensor/%s/%s/config", mqtt_base_.c_str(), uniq); // normal HA sensor, not a boolean one + snprintf(topic, sizeof(topic), "sensor/%s/%s/config", system_hostname_.c_str(), uniq); // normal HA sensor, not a boolean one } } @@ -1065,7 +1075,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, if (type == DeviceValueType::ENUM) { JsonArray option_list = doc.createNestedArray("options"); for (uint8_t i = 0; i < options_size; i++) { - option_list.add(options[i]); + option_list.add(Helpers::translated_word(options[i])); } } else if (type != DeviceValueType::STRING) { // Must be Numeric.... @@ -1104,22 +1114,22 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, doc["stat_t"] = stat_t; // friendly name = - char short_name[70]; + char ha_name[70]; if (have_tag) { - snprintf(short_name, sizeof(short_name), "%s %s", EMSdevice::tag_to_string(tag).c_str(), read_flash_string(name).c_str()); + snprintf(ha_name, sizeof(ha_name), "%s %s", EMSdevice::tag_to_string(tag).c_str(), fullname.c_str()); } else { - snprintf(short_name, sizeof(short_name), "%s", read_flash_string(name).c_str()); + snprintf(ha_name, sizeof(ha_name), "%s", fullname.c_str()); } + ha_name[0] = toupper(ha_name[0]); // capitalize first letter + doc["name"] = ha_name; - // entity id = emsesp___ - char long_name[130]; - snprintf(long_name, sizeof(long_name), "%s_%s", device_name, short_name); - // snprintf(long_name, sizeof(long_name), "emsesp_%s_%s", device_name, short_name); //wouldn't it be better? - doc["object_id"] = long_name; - - // name (friendly name) = - short_name[0] = toupper(short_name[0]); // capitalize first letter - doc["name"] = short_name; + // 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 + // See https://github.com/emsesp/EMS-ESP32/issues/596 + // "__ " + char object_id[130]; + snprintf(object_id, sizeof(object_id), "%s_%s_%s", system_hostname_.c_str(), device_name, ha_name); + doc["object_id"] = object_id; // value template // if its nested mqtt format then use the appended entity name, otherwise take the original diff --git a/src/mqtt.h b/src/mqtt.h index 743870251..6d107cb89 100644 --- a/src/mqtt.h +++ b/src/mqtt.h @@ -92,19 +92,19 @@ class Mqtt { 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); - static void publish_ha_sensor_config(uint8_t type, - uint8_t tag, - const __FlashStringHelper * name, - const uint8_t device_type, - const __FlashStringHelper * entity, - const uint8_t uom, - const bool remove, - const bool has_cmd, - const __FlashStringHelper * const * options, - uint8_t options_size, - const int16_t dv_set_min, - const int16_t dv_set_max, - const JsonObject & dev_json); + static void publish_ha_sensor_config(uint8_t type, + uint8_t tag, + const std::string & fullname, + const uint8_t device_type, + const __FlashStringHelper * const entity, + const uint8_t uom, + const bool remove, + const bool has_cmd, + const __FlashStringHelper * const ** options, + uint8_t options_size, + const int16_t dv_set_min, + const int16_t dv_set_max, + 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_ha_climate_config(uint8_t tag, bool has_roomtemp, bool remove = false); @@ -286,6 +286,8 @@ class Mqtt { static bool ha_climate_reset_; // settings, copied over + static std::string system_hostname_; + static std::string mqtt_base_; static uint8_t mqtt_qos_; static bool mqtt_retain_; diff --git a/src/system.cpp b/src/system.cpp index b9d687b53..4a3d0217a 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -41,6 +41,11 @@ namespace emsesp { +// Languages supported. Note: the order is important and must match locale_translations.h +const char * const languages[] = {EMSESP_LOCALE_EN, EMSESP_LOCALE_DE, EMSESP_LOCALE_NL, EMSESP_LOCALE_SE, EMSESP_LOCALE_PL, EMSESP_LOCALE_NO}; + +size_t num_languages = sizeof(languages) / sizeof(const char *); + uuid::log::Logger System::logger_{F_(system), uuid::log::Facility::KERN}; #ifndef EMSESP_STANDALONE @@ -51,49 +56,20 @@ uuid::syslog::SyslogService System::syslog_; PButton System::myPButton_; bool System::restart_requested_ = false; -// send on/off to a gpio pin -// value: true = HIGH, false = LOW -bool System::command_pin(const char * value, const int8_t id) { -#ifndef EMSESP_STANDALONE - - if (!is_valid_gpio(id)) { - LOG_INFO(F("Invalid GPIO number")); - return false; - } - - bool v = false; - std::string v1 = {7, '\0'}; - int v2 = 0; - - if (id == 25 && Helpers::value2number(value, v2)) { - if (v2 >= 0 && v2 <= 255) { - dacWrite(id, v2); - return true; - } - } else if (Helpers::value2bool(value, v)) { - pinMode(id, OUTPUT); - digitalWrite(id, v); - // LOG_INFO(F("GPIO %d set to %s"), id, v ? "HIGH" : "LOW"); - return true; - } else if (Helpers::value2string(value, v1)) { - if (v1 == "input" || v1 == "in" || v1 == "-1") { - pinMode(id, INPUT); - v = digitalRead(id); - // LOG_INFO(F("GPIO %d set input, state %s"), id, v ? "HIGH" : "LOW"); - return true; +// find the index of the language +// 0 = EN, 1 = DE, etc... +uint8_t System::language_index() { + for (uint8_t i = 0; i < num_languages; i++) { + if (languages[i] == locale()) { + return i; } } - - // LOG_INFO(F("GPIO %d: invalid value"), id); -#endif - - return false; + return 0; // EN } // send raw to ems bool System::command_send(const char * value, const int8_t id) { - EMSESP::send_raw_telegram(value); // ignore id - return true; + return EMSESP::txservice_.send_raw(value); // ignore id } // fetch device values @@ -161,7 +137,7 @@ bool System::command_publish(const char * value, const int8_t id) { // syslog level bool System::command_syslog_level(const char * value, const int8_t id) { uint8_t s = 0xff; - if (Helpers::value2enum(value, s, FL_(enum_syslog_level))) { + if (Helpers::value2enum(value, s, FL_(list_syslog_level))) { bool changed = false; EMSESP::webSettingsService.update( [&](WebSettings & settings) { @@ -184,17 +160,17 @@ bool System::command_syslog_level(const char * value, const int8_t id) { bool System::command_watch(const char * value, const int8_t id) { uint8_t w = 0xff; uint16_t i = Helpers::hextoint(value); - if (Helpers::value2enum(value, w, FL_(enum_watch))) { + if (Helpers::value2enum(value, w, FL_(list_watch))) { if (w == 0 || EMSESP::watch() == EMSESP::Watch::WATCH_OFF) { EMSESP::watch_id(0); } if (Mqtt::publish_single() && w != EMSESP::watch()) { if (Mqtt::publish_single2cmd()) { Mqtt::publish(F("system/watch"), - EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(w) : read_flash_string(FL_(enum_watch)[w]).c_str()); + EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(w) : read_flash_string(FL_(list_watch)[w]).c_str()); } else { Mqtt::publish(F("system_data/watch"), - EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(w) : read_flash_string(FL_(enum_watch)[w]).c_str()); + EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(w) : read_flash_string(FL_(list_watch)[w]).c_str()); } } EMSESP::watch(w); @@ -275,6 +251,7 @@ void System::syslog_init() { syslog_.hostname(hostname().c_str()); // register the command + // TODO translate this Command::add(EMSdevice::DeviceType::SYSTEM, F_(syslog), System::command_syslog_level, F("change the syslog level"), CommandFlag::ADMIN_ONLY); } else if (was_enabled) { @@ -288,21 +265,21 @@ void System::syslog_init() { if (Mqtt::publish_single()) { if (Mqtt::publish_single2cmd()) { - Mqtt::publish(F("system/syslog"), syslog_enabled_ ? read_flash_string(FL_(enum_syslog_level)[syslog_level_ + 1]).c_str() : "off"); + Mqtt::publish(F("system/syslog"), syslog_enabled_ ? read_flash_string(FL_(list_syslog_level)[syslog_level_ + 1]).c_str() : "off"); if (EMSESP::watch_id() == 0 || EMSESP::watch() == 0) { Mqtt::publish(F("system/watch"), EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(EMSESP::watch()) - : read_flash_string(FL_(enum_watch)[EMSESP::watch()]).c_str()); + : read_flash_string(FL_(list_watch)[EMSESP::watch()]).c_str()); } else { Mqtt::publish(F("system/watch"), Helpers::hextoa(EMSESP::watch_id())); } } else { - Mqtt::publish(F("system_data/syslog"), syslog_enabled_ ? read_flash_string(FL_(enum_syslog_level)[syslog_level_ + 1]).c_str() : "off"); + Mqtt::publish(F("system_data/syslog"), syslog_enabled_ ? read_flash_string(FL_(list_syslog_level)[syslog_level_ + 1]).c_str() : "off"); if (EMSESP::watch_id() == 0 || EMSESP::watch() == 0) { Mqtt::publish(F("system_data/watch"), EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(EMSESP::watch()) - : read_flash_string(FL_(enum_watch)[EMSESP::watch()]).c_str()); + : read_flash_string(FL_(list_watch)[EMSESP::watch()]).c_str()); } else { Mqtt::publish(F("system_data/watch"), Helpers::hextoa(EMSESP::watch_id())); } @@ -342,6 +319,8 @@ void System::reload_settings() { eth_power_ = settings.eth_power; eth_phy_addr_ = settings.eth_phy_addr; eth_clock_mode_ = settings.eth_clock_mode; + + locale_ = settings.locale; }); } @@ -394,6 +373,7 @@ void System::start() { if (low_clock_) { setCpuFrequencyMhz(160); } + fstotal_ = LittleFS.totalBytes(); // read only once, it takes 500 ms to read #endif EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) { @@ -412,6 +392,12 @@ void System::start() { // button single click void System::button_OnClick(PButton & b) { LOG_DEBUG(F("Button pressed - single click")); + +#ifdef EMSESP_DEBUG +#ifndef EMSESP_STANDALONE + Test::listDir(LittleFS, FS_CONFIG_DIRECTORY, 3); +#endif +#endif } // button double click @@ -431,11 +417,6 @@ void System::button_OnVLongPress(PButton & b) { #ifndef EMSESP_STANDALONE LOG_WARNING(F("Performing factory reset...")); EMSESP::console_.loop(); - -#ifdef EMSESP_DEBUG - Test::listDir(LittleFS, FS_CONFIG_DIRECTORY, 3); -#endif - EMSESP::esp8266React.factoryReset(); #endif } @@ -675,11 +656,12 @@ void System::system_check() { // commands - takes static function pointers void System::commands_init() { - // Command::add(EMSdevice::DeviceType::SYSTEM, F_(pin), System::command_pin, F("set a GPIO on/off"), CommandFlag::ADMIN_ONLY); + // TODO these should be translated too Command::add(EMSdevice::DeviceType::SYSTEM, F_(send), System::command_send, F("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_(restart), System::command_restart, F("restart EMS-ESP"), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(watch), System::command_watch, F("watch incoming telegrams")); + // register syslog command in syslog init // Command::add(EMSdevice::DeviceType::SYSTEM, F_(syslog), System::command_syslog_level, F("set syslog level"), CommandFlag::ADMIN_ONLY); @@ -803,6 +785,7 @@ void System::show_system(uuid::console::Shell & shell) { shell.printfln(F(" SDK version: %s"), ESP.getSdkVersion()); shell.printfln(F(" CPU frequency: %lu MHz"), ESP.getCpuFreqMHz()); shell.printfln(F(" Free heap: %lu bytes"), (uint32_t)ESP.getFreeHeap()); + shell.printfln(F(" FS used/total: %lu/%lu (bytes)"), LittleFS.usedBytes(), FStotal()); shell.println(); shell.println("Network:"); @@ -1089,7 +1072,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & outp #ifndef EMSESP_STANDALONE if (EMSESP::system_.syslog_enabled_) { node["syslog started"] = syslog_.started(); - node["syslog level"] = FL_(enum_syslog_level)[syslog_.log_level() + 1]; + node["syslog level"] = FL_(list_syslog_level)[syslog_.log_level() + 1]; node["syslog ip"] = syslog_.ip(); node["syslog queue"] = syslog_.queued(); } @@ -1145,6 +1128,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & outp node = output.createNestedObject("Settings"); EMSESP::webSettingsService.read([&](WebSettings & settings) { node["board profile"] = settings.board_profile; + node["locale"] = settings.locale; node["tx mode"] = settings.tx_mode; node["ems bus id"] = settings.ems_bus_id; node["shower timer"] = settings.shower_timer; diff --git a/src/system.h b/src/system.h index 3db47a6ad..e0a0340b8 100644 --- a/src/system.h +++ b/src/system.h @@ -49,7 +49,6 @@ class System { void loop(); // commands - static bool command_pin(const char * value, const int8_t id); static bool command_send(const char * value, const int8_t id); static bool command_publish(const char * value, const int8_t id); static bool command_fetch(const char * value, const int8_t id); @@ -203,6 +202,16 @@ class System { return fahrenheit_; } + uint8_t language_index(); + + void locale(String locale) { + locale_ = locale; + } + + std::string locale() { + return std::string(locale_.c_str()); + } + void healthcheck(uint8_t healthcheck) { healthcheck_ = healthcheck; } @@ -211,6 +220,10 @@ class System { void wifi_reconnect(); void show_users(uuid::console::Shell & shell); + uint32_t FStotal() { + return fstotal_; + } + private: static uuid::log::Logger logger_; static bool restart_requested_; @@ -257,6 +270,7 @@ class System { // EMS-ESP settings // copies from WebSettings class in WebSettingsService.h and loaded with reload_settings() std::string hostname_ = FACTORY_WIFI_HOSTNAME; + String locale_; bool hide_led_; uint8_t led_gpio_; bool analog_enabled_; @@ -283,6 +297,9 @@ class System { int8_t eth_power_; uint8_t eth_phy_addr_; uint8_t eth_clock_mode_; + + uint32_t fstotal_; + }; } // namespace emsesp diff --git a/src/telegram.cpp b/src/telegram.cpp index 309fb3461..f96cdf43e 100644 --- a/src/telegram.cpp +++ b/src/telegram.cpp @@ -540,9 +540,9 @@ void TxService::read_request(const uint16_t type_id, const uint8_t dest, const u } // Send a raw telegram to the bus, telegram is a text string of hex values -void TxService::send_raw(const char * telegram_data) { +bool TxService::send_raw(const char * telegram_data) { if (telegram_data == nullptr) { - return; + return false; } // since the telegram data is a const, make a copy. add 1 to grab the \0 EOS @@ -562,6 +562,8 @@ void TxService::send_raw(const char * telegram_data) { if ((p = strtok(telegram, " ,"))) { // delimiter strlcpy(value, p, sizeof(value)); data[0] = (uint8_t)strtol(value, 0, 16); + } else { + return false; } // and iterate until end @@ -573,11 +575,13 @@ void TxService::send_raw(const char * telegram_data) { } } - if (count == 0) { - return; // nothing to send + // check valid length and src + if ((count < 4) || ((data[0] & 0x7F) != ems_bus_id())) { + return false; } add(Telegram::Operation::TX_RAW, data, count + 1, 0, true); // add to top/front of Tx queue + return true; } // add last Tx to tx queue and increment count @@ -596,10 +600,12 @@ void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const ui } else { increment_telegram_write_fail_count(); // another Tx fail } + LOG_ERROR(F("Last Tx %s operation failed after %d retries. Ignoring request: %s"), (operation == Telegram::Operation::TX_WRITE) ? F("Write") : F("Read"), MAXIMUM_TX_RETRIES, telegram_last_->to_string().c_str()); + if (operation == Telegram::Operation::TX_READ) { EMSESP::rxservice_.add_empty(telegram_last_->dest, telegram_last_->src, telegram_last_->type_id, telegram_last_->offset); } @@ -623,24 +629,18 @@ void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const ui } // send a request to read the next block of data from longer telegrams -uint16_t TxService::read_next_tx(uint8_t offset) { - // add to the top/front of the queue - uint8_t message_data[1] = {EMS_MAX_TELEGRAM_LENGTH}; // request all data, 32 bytes - if (telegram_last_->offset != offset) { - return 0; +uint16_t TxService::read_next_tx(const uint8_t offset, const uint8_t length) { + uint8_t old_length = telegram_last_->type_id > 0xFF ? length - 7 : length - 5; + uint8_t next_length = telegram_last_->type_id > 0xFF ? EMS_MAX_TELEGRAM_MESSAGE_LENGTH - 2 : EMS_MAX_TELEGRAM_MESSAGE_LENGTH; + uint8_t next_offset = telegram_last_->offset + old_length; + uint8_t message_data = (UINT8_MAX - next_offset) >= next_length ? next_length : UINT8_MAX - next_offset; + // check telegram, offset and overflow + // some telegrams only reply with one byte less, but have higher offsets (0x10) + if (old_length >= (next_length - 1) && telegram_last_->offset == offset) { + add(Telegram::Operation::TX_READ, telegram_last_->dest, telegram_last_->type_id, next_offset, &message_data, 1, 0, true); + return telegram_last_->type_id; } - - uint8_t add_offset = 25; // for EMS+ telegram increase offset by 25 - if (telegram_last_->type_id < 0x100) { // but for EMS1.0 by 27 - add_offset = 27; - } - - if (UINT8_MAX - telegram_last_->offset < add_offset) { // stop if new offset would overflow - return 0; - } - - add(Telegram::Operation::TX_READ, telegram_last_->dest, telegram_last_->type_id, telegram_last_->offset + add_offset, message_data, 1, 0, true); - return telegram_last_->type_id; + return 0; } // checks if a telegram is sent to us matches the last Tx request diff --git a/src/telegram.h b/src/telegram.h index 2312b5b3e..cafa60b42 100644 --- a/src/telegram.h +++ b/src/telegram.h @@ -304,12 +304,12 @@ class TxService : public EMSbus { const bool front = false); void add(const uint8_t operation, const uint8_t * data, const uint8_t length, const uint16_t validateid, const bool front = false); void read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset = 0, const uint8_t length = 0); - void send_raw(const char * telegram_data); + bool send_raw(const char * telegram_data); void send_poll() const; void retry_tx(const uint8_t operation, const uint8_t * data, const uint8_t length); bool is_last_tx(const uint8_t src, const uint8_t dest) const; uint16_t post_send_query(); - uint16_t read_next_tx(uint8_t offset); + uint16_t read_next_tx(const uint8_t offset, const uint8_t length); uint8_t retry_count() const { return retry_count_; diff --git a/src/test/test.cpp b/src/test/test.cpp index c69b437d9..7652fff36 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -304,13 +304,13 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const uint16_t temp; float doub; - temp = 0x0201; // decimal 513 - doub = Helpers::round2(temp, 10); // divide by 10 + temp = 0x0201; // decimal 513 + doub = Helpers::transformNumFloat(temp, 10); // divide by 10 shell.printfln("Round test from x%02X to %d to %f", temp, temp, doub); - doub = Helpers::round2(temp, 10); // divide by 10 + doub = Helpers::transformNumFloat(temp, 10); // divide by 10 shell.printfln("Round test div10 from x%02X to %d to %f", temp, temp, doub); temp = 0x63; - doub = Helpers::round2(temp, 2); // divide by 2 + doub = Helpers::transformNumFloat(temp, 2); // divide by 2 shell.printfln("Round test div2 from x%02X to %d to %f", temp, temp, doub); } @@ -399,7 +399,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const #if defined(EMSESP_STANDALONE) - DynamicJsonDocument doc(8000); // some absurb high number + DynamicJsonDocument doc(8000); // some absurd high number for (const auto & emsdevice : EMSESP::emsdevices) { if (emsdevice) { doc.clear(); @@ -448,7 +448,8 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const if (command == "boiler") { shell.printfln(F("Testing boiler...")); - Mqtt::ha_enabled(false); + // Mqtt::ha_enabled(false); + Mqtt::ha_enabled(true); Mqtt::nested_format(1); run_test("boiler"); @@ -615,7 +616,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const for (const auto & emsdevice : EMSESP::emsdevices) { if (emsdevice->unique_id() == 1) { // boiler std::string a = "07wwseltemp"; - emsdevice->mask_entity(a); + emsdevice->setCustomEntity(a); break; } } @@ -1045,7 +1046,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const EMSESP::show_device_values(shell); shell.invoke_command("call system publish"); - // EMSESP::send_raw_telegram("B0 00 FF 18 02 62 80 00 B8"); + // EMSESP::txservice_.send_raw("B0 00 FF 18 02 62 80 00 B8"); } if (command == "heatpump") { @@ -1070,7 +1071,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const rx_telegram({0xB0, 00, 0xFF, 0x18, 02, 0x62, 0x80, 00, 0xB8}); - EMSESP::send_raw_telegram("B0 00 FF 18 02 62 80 00 B8"); + EMSESP::txservice_.send_raw("B0 00 FF 18 02 62 80 00 B8"); uart_telegram("30 00 FF 0A 02 6A 04"); // SM100 pump on 1 uart_telegram("30 00 FF 00 02 64 00 00 00 04 00 00 FF 00 00 1E 0B 09 64 00 00 00 00"); // SM100 modulation diff --git a/src/uart/emsuart_esp32.h b/src/uart/emsuart_esp32.h index 39e40478d..ba3863925 100644 --- a/src/uart/emsuart_esp32.h +++ b/src/uart/emsuart_esp32.h @@ -27,7 +27,6 @@ #define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus extra for BRK #define EMSUART_NUM UART_NUM_2 // on the ESP32 we're using UART2 -#define EMSUART UART2 // for intr setting #define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit #define EMS_TXMODE_DEFAULT 1 diff --git a/src/version.h b/src/version.h index cbb32b902..f42124e29 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.4.2b5" +#define EMSESP_APP_VERSION "3.5.0b1" diff --git a/src/web/WebCustomizationService.cpp b/src/web/WebCustomizationService.cpp index 5673d285d..5a641e91a 100644 --- a/src/web/WebCustomizationService.cpp +++ b/src/web/WebCustomizationService.cpp @@ -31,8 +31,8 @@ WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * f securityManager, AuthenticationPredicates::IS_AUTHENTICATED) , _fsPersistence(WebCustomization::read, WebCustomization::update, this, fs, EMSESP_CUSTOMIZATION_FILE) - , _masked_entities_handler(MASKED_ENTITIES_PATH, - securityManager->wrapCallback(std::bind(&WebCustomizationService::masked_entities, this, _1, _2), + , _masked_entities_handler(CUSTOM_ENTITIES_PATH, + securityManager->wrapCallback(std::bind(&WebCustomizationService::custom_entities, this, _1, _2), AuthenticationPredicates::IS_AUTHENTICATED)) , _device_entities_handler(DEVICE_ENTITIES_PATH, securityManager->wrapCallback(std::bind(&WebCustomizationService::device_entities, this, _1, _2), @@ -85,6 +85,7 @@ void WebCustomization::read(WebCustomization & settings, JsonObject & root) { entityJson["product_id"] = entityCustomization.product_id; entityJson["device_id"] = entityCustomization.device_id; + // entries are in the form [|optional customname] e.g "08heatingactive|heating is on" JsonArray masked_entityJson = entityJson.createNestedArray("entity_ids"); for (std::string entity_id : entityCustomization.entity_ids) { masked_entityJson.add(entity_id); @@ -95,11 +96,26 @@ void WebCustomization::read(WebCustomization & settings, JsonObject & root) { // call on initialization and also when the page is saved via web UI // this loads the data into the internal class StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization & settings) { +#ifdef EMSESP_STANDALONE + // invoke some fake data for testing + const char * json = "{\"sensors\":[],\"analogs\":[],\"masked_entities\":[{\"product_id\":123,\"device_id\":8,\"entity_ids\":[\"08heatingactive|my custom " + "name for heating active\",\"08tapwateractive\"]}]}"; + + StaticJsonDocument<500> doc; + deserializeJson(doc, json); + root = doc.as(); + + Serial.println(COLOR_BRIGHT_MAGENTA); + Serial.print("Using custom file: "); + serializeJson(root, Serial); + Serial.println(COLOR_RESET); +#endif + // Dallas Sensor customization settings.sensorCustomizations.clear(); if (root["sensors"].is()) { for (const JsonObject sensorJson : root["sensors"].as()) { - // create each of the sensor, overwritting any previous settings + // create each of the sensor, overwriting any previous settings auto sensor = SensorCustomization(); sensor.id = sensorJson["id"].as(); sensor.name = sensorJson["name"].as(); @@ -112,7 +128,7 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization & settings.analogCustomizations.clear(); if (root["analogs"].is()) { for (const JsonObject analogJson : root["analogs"].as()) { - // create each of the sensor, overwritting any previous settings + // create each of the sensor, overwriting any previous settings auto sensor = AnalogCustomization(); sensor.gpio = analogJson["gpio"]; sensor.name = analogJson["name"].as(); @@ -160,7 +176,7 @@ void WebCustomizationService::reset_customization(AsyncWebServerRequest * reques #endif } -// send back a list of devices used to the customization web page +// send back a list of devices used in the customization web page void WebCustomizationService::devices(AsyncWebServerRequest * request) { auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN); JsonObject root = response->getRoot(); @@ -173,19 +189,7 @@ void WebCustomizationService::devices(AsyncWebServerRequest * request) { JsonObject obj = devices.createNestedObject(); obj["i"] = emsdevice->unique_id(); // its unique id obj["s"] = emsdevice->device_type_name() + " (" + emsdevice->name() + ")"; // shortname - - // device type name. We may have one than one (e.g. multiple thermostats) so postfix name with index - // code block not needed - see https://github.com/emsesp/EMS-ESP32/pull/586#issuecomment-1193779668 - /* - uint8_t device_index = EMSESP::device_index(emsdevice->device_type(), emsdevice->unique_id()); - if (device_index) { - char s[10]; - obj["t"] = Helpers::toLower(emsdevice->device_type_name()) + Helpers::smallitoa(s, device_index); - } else { - obj["t"] = Helpers::toLower(emsdevice->device_type_name()); - } - */ - obj["t"] = Helpers::toLower(emsdevice->device_type_name()); + obj["t"] = Helpers::toLower(emsdevice->device_type_name()); } } @@ -218,7 +222,7 @@ void WebCustomizationService::device_entities(AsyncWebServerRequest * request, J // takes a list of updated entities with new masks from the web UI // saves it in the customization service // and updates the entity list real-time -void WebCustomizationService::masked_entities(AsyncWebServerRequest * request, JsonVariant & json) { +void WebCustomizationService::custom_entities(AsyncWebServerRequest * request, JsonVariant & json) { if (json.is()) { // find the device using the unique_id for (const auto & emsdevice : EMSESP::emsdevices) { @@ -228,10 +232,10 @@ void WebCustomizationService::masked_entities(AsyncWebServerRequest * request, J uint8_t product_id = emsdevice->product_id(); uint8_t device_id = emsdevice->device_id(); - // and set the mask immediately for the changed entities + // and set the mask and custom names immediately for any listed entities JsonArray entity_ids_json = json["entity_ids"]; for (const JsonVariant id : entity_ids_json) { - emsdevice->mask_entity(id.as()); + emsdevice->setCustomEntity(id.as()); } // Save the list to the customization file @@ -256,9 +260,9 @@ void WebCustomizationService::masked_entities(AsyncWebServerRequest * request, J new_entry.product_id = product_id; new_entry.device_id = device_id; - // get list of entities that have masks + // get list of entities that have masks set or a custom fullname std::vector entity_ids; - emsdevice->getMaskedEntities(entity_ids); + emsdevice->getCustomEntities(entity_ids); new_entry.entity_ids = entity_ids; // add the record and save diff --git a/src/web/WebCustomizationService.h b/src/web/WebCustomizationService.h index d595c1f43..e5d7a9512 100644 --- a/src/web/WebCustomizationService.h +++ b/src/web/WebCustomizationService.h @@ -27,7 +27,7 @@ // POST #define DEVICE_ENTITIES_PATH "/rest/deviceEntities" -#define MASKED_ENTITIES_PATH "/rest/maskedEntities" +#define CUSTOM_ENTITIES_PATH "/rest/customEntities" #define RESET_CUSTOMIZATION_SERVICE_PATH "/rest/resetCustomizations" namespace emsesp { @@ -63,7 +63,7 @@ class EntityCustomization { public: uint8_t product_id; // device's product id uint8_t device_id; // device's device id - std::vector entity_ids; // array of entity ids with masks + std::vector entity_ids; // array of entity ids with masks and optional custom fullname }; class WebCustomization { @@ -93,7 +93,7 @@ class WebCustomizationService : public StatefulService { void devices(AsyncWebServerRequest * request); // POST - void masked_entities(AsyncWebServerRequest * request, JsonVariant & json); + void custom_entities(AsyncWebServerRequest * request, JsonVariant & json); void device_entities(AsyncWebServerRequest * request, JsonVariant & json); void reset_customization(AsyncWebServerRequest * request); diff --git a/src/web/WebDataService.cpp b/src/web/WebDataService.cpp index ea9520ed0..847990edf 100644 --- a/src/web/WebDataService.cpp +++ b/src/web/WebDataService.cpp @@ -149,7 +149,7 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) { obj["t"] = sensor.type(); if (sensor.type() != AnalogSensor::AnalogType::NOTUSED) { - obj["v"] = Helpers::round2(sensor.value(), 0); // is optional and is a float + obj["v"] = Helpers::transformNumFloat(sensor.value(), 0); // is optional and is a float } else { obj["v"] = 0; // must have a value for web sorting to work } diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index d8bf8d90a..878f6472c 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -37,6 +37,7 @@ WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, Securit } void WebSettings::read(WebSettings & settings, JsonObject & root) { + root["locale"] = settings.locale; root["tx_mode"] = settings.tx_mode; root["ems_bus_id"] = settings.ems_bus_id; root["syslog_enabled"] = settings.syslog_enabled; @@ -203,8 +204,17 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings) settings.low_clock = root["low_clock"] | false; check_flag(prev, settings.low_clock, ChangeFlags::RESTART); + String old_local = settings.locale; + settings.locale = root["locale"] | EMSESP_DEFAULT_LOCALE; + EMSESP::system_.locale(settings.locale); +#ifndef EMSESP_STANDALONE + if (!old_local.equals(settings.locale)) { + add_flags(ChangeFlags::MQTT); + } +#endif + // - // without checks... + // without checks or necessary restarts... // settings.trace_raw = root["trace_raw"] | EMSESP_DEFAULT_TRACELOG_RAW; EMSESP::trace_raw(settings.trace_raw); @@ -269,6 +279,10 @@ void WebSettingsService::onUpdate() { EMSESP::system_.led_init(true); // reload settings } + if (WebSettings::has_flags(WebSettings::ChangeFlags::MQTT)) { + emsesp::EMSESP::mqtt_.reset_mqtt(); // reload MQTT, init HA etc + } + WebSettings::reset_flags(); } diff --git a/src/web/WebSettingsService.h b/src/web/WebSettingsService.h index 299f4a428..a20e10c9a 100644 --- a/src/web/WebSettingsService.h +++ b/src/web/WebSettingsService.h @@ -29,6 +29,7 @@ namespace emsesp { class WebSettings { public: + String locale; uint8_t tx_mode; uint8_t ems_bus_id; bool shower_timer; @@ -81,6 +82,7 @@ class WebSettings { SHOWER = (1 << 4), // 16 LED = (1 << 5), // 32 BUTTON = (1 << 6), // 64 + MQTT = (1 << 7), // 128 RESTART = 0xFF }; diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index c70d4369f..e85eb8ccd 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -66,7 +66,7 @@ void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { #ifndef EMSESP_STANDALONE EMSESP::logger().info(F("Ethernet connected with IP=%s, speed %d Mbps"), ETH.localIP().toString().c_str(), ETH.linkSpeed()); #endif - // EMSESP::system_.send_heartbeat(); // send from mqtt start + // EMSESP::system_.send_heartbeat(); EMSESP::system_.syslog_init(); EMSESP::system_.ethernet_connected(true); mDNS_start(); @@ -107,7 +107,7 @@ void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { } else { EMSESP::logger().info(F("WiFi connected with IPv6=%s, hostname=%s"), WiFi.localIPv6().toString().c_str(), WiFi.getHostname()); } - // EMSESP::system_.send_heartbeat(); // send from mqtt start + // EMSESP::system_.send_heartbeat(); EMSESP::system_.syslog_init(); mDNS_start(); break; @@ -133,47 +133,47 @@ void WebStatusService::webStatusService(AsyncWebServerRequest * request) { JsonObject statJson; statJson = statsJson.createNestedObject(); - statJson["id"] = "EMS Telegrams Received (Rx)"; + statJson["id"] = "0"; statJson["s"] = EMSESP::rxservice_.telegram_count(); statJson["f"] = EMSESP::rxservice_.telegram_error_count(); statJson["q"] = EMSESP::rxservice_.quality(); statJson = statsJson.createNestedObject(); - statJson["id"] = "EMS Reads (Tx)"; + statJson["id"] = "1"; statJson["s"] = EMSESP::txservice_.telegram_read_count(); statJson["f"] = EMSESP::txservice_.telegram_read_fail_count(); statJson["q"] = EMSESP::txservice_.read_quality(); statJson = statsJson.createNestedObject(); - statJson["id"] = "EMS Writes (Tx)"; + statJson["id"] = "2"; statJson["s"] = EMSESP::txservice_.telegram_write_count(); statJson["f"] = EMSESP::txservice_.telegram_write_fail_count(); statJson["q"] = EMSESP::txservice_.write_quality(); if (EMSESP::dallassensor_.dallas_enabled()) { statJson = statsJson.createNestedObject(); - statJson["id"] = "Temperature Sensor Reads"; + statJson["id"] = "3"; statJson["s"] = EMSESP::dallassensor_.reads(); statJson["f"] = EMSESP::dallassensor_.fails(); statJson["q"] = EMSESP::dallassensor_.reads() == 0 ? 100 : 100 - (uint8_t)((100 * EMSESP::dallassensor_.fails()) / EMSESP::dallassensor_.reads()); } if (EMSESP::analog_enabled()) { statJson = statsJson.createNestedObject(); - statJson["id"] = "Analog Sensor Reads"; + statJson["id"] = "4"; statJson["s"] = EMSESP::analogsensor_.reads(); statJson["f"] = EMSESP::analogsensor_.fails(); statJson["q"] = EMSESP::analogsensor_.reads() == 0 ? 100 : 100 - (uint8_t)((100 * EMSESP::analogsensor_.fails()) / EMSESP::analogsensor_.reads()); } if (Mqtt::enabled()) { statJson = statsJson.createNestedObject(); - statJson["id"] = "MQTT Publishes"; + statJson["id"] = "5"; statJson["s"] = Mqtt::publish_count(); statJson["f"] = Mqtt::publish_fails(); statJson["q"] = Mqtt::publish_count() == 0 ? 100 : 100 - (uint8_t)((100 * Mqtt::publish_fails()) / (Mqtt::publish_count() + Mqtt::publish_fails())); } statJson = statsJson.createNestedObject(); - statJson["id"] = "API Calls"; + statJson["id"] = "6"; statJson["s"] = WebAPIService::api_count(); // + WebAPIService::api_fails(); statJson["f"] = WebAPIService::api_fails(); statJson["q"] = @@ -182,7 +182,7 @@ void WebStatusService::webStatusService(AsyncWebServerRequest * request) { #ifndef EMSESP_STANDALONE if (EMSESP::system_.syslog_enabled()) { statJson = statsJson.createNestedObject(); - statJson["id"] = "Syslog Messages"; + statJson["id"] = "7"; statJson["s"] = EMSESP::system_.syslog_count(); statJson["f"] = EMSESP::system_.syslog_fails(); statJson["q"] = EMSESP::system_.syslog_count() == 0