Render values in Web natively #70

This commit is contained in:
proddy
2021-06-07 21:19:52 +02:00
parent db43f2d711
commit 8dd18aa24d
23 changed files with 946 additions and 724 deletions

View File

@@ -9,12 +9,13 @@
## Fixed
- HA thermostat mode was not in sync with actual mode [#66](https://github.com/emsesp/EMS-ESP32/issues/66)
- Don't publish rssi if Wifi is disabled and ethernet is being used
## Changed
- `info` command always shows full names in API. For short names query the device or name directly, e.g. `http://ems-esp/api/boiler`
- free memory is shown in kilobytes
- boiler's warm water entities have ww added to the Home Assistant entity name [#67](https://github.com/emsesp/EMS-ESP32/issues/67)
- improved layout and rendering of device values in the WebUI, also the edit value screen
## Removed

View File

@@ -10,6 +10,7 @@
"dependencies": {
"@material-ui/core": "^4.11.4",
"@material-ui/icons": "^4.11.2",
"@msgpack/msgpack": "^2.7.0",
"@types/lodash": "^4.14.168",
"@types/node": "^15.0.1",
"@types/react": "^17.0.4",
@@ -2175,6 +2176,14 @@
"node": ">=8.0.0"
}
},
"node_modules/@msgpack/msgpack": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.7.0.tgz",
"integrity": "sha512-mlRYq9FSsOd4m+3wZWatemn3hGFZPWNJ4JQOdrir4rrMK2PyIk26idKBoUWrqF3HJJHl+5GpRU+M0wEruJwecg==",
"engines": {
"node": ">= 10"
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
@@ -4578,21 +4587,25 @@
}
},
"node_modules/browserslist": {
"version": "4.16.3",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.3.tgz",
"integrity": "sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==",
"version": "4.16.6",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz",
"integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==",
"dependencies": {
"caniuse-lite": "^1.0.30001181",
"colorette": "^1.2.1",
"electron-to-chromium": "^1.3.649",
"caniuse-lite": "^1.0.30001219",
"colorette": "^1.2.2",
"electron-to-chromium": "^1.3.723",
"escalade": "^3.1.1",
"node-releases": "^1.1.70"
"node-releases": "^1.1.71"
},
"bin": {
"browserslist": "cli.js"
},
"engines": {
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
}
},
"node_modules/bser": {
@@ -4835,9 +4848,13 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001208",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001208.tgz",
"integrity": "sha512-OE5UE4+nBOro8Dyvv0lfx+SRtfVIOM9uhKqFmJeUbGriqhhStgp1A0OyBpgy3OUF8AhYCT+PVwPC1gMl2ZcQMA=="
"version": "1.0.30001235",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001235.tgz",
"integrity": "sha512-zWEwIVqnzPkSAXOUlQnPW2oKoYb2aLQ4Q5ejdjBcnH63rfypaW34CxaeBn1VMya2XaEU3P/R2qHpWyj+l0BT1A==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
}
},
"node_modules/capture-exit": {
"version": "2.0.0",
@@ -6613,9 +6630,9 @@
"integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0="
},
"node_modules/dns-packet": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz",
"integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==",
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz",
"integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==",
"dependencies": {
"ip": "^1.1.0",
"safe-buffer": "^5.0.1"
@@ -6837,9 +6854,9 @@
}
},
"node_modules/electron-to-chromium": {
"version": "1.3.712",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.712.tgz",
"integrity": "sha512-3kRVibBeCM4vsgoHHGKHmPocLqtFAGTrebXxxtgKs87hNUzXrX2NuS3jnBys7IozCnw7viQlozxKkmty2KNfrw=="
"version": "1.3.749",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.749.tgz",
"integrity": "sha512-F+v2zxZgw/fMwPz/VUGIggG4ZndDsYy0vlpthi3tjmDZlcfbhN5mYW0evXUsBr2sUtuDANFtle410A9u/sd/4A=="
},
"node_modules/elliptic": {
"version": "6.5.4",
@@ -13248,9 +13265,9 @@
"integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
},
"node_modules/nanoid": {
"version": "3.1.22",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.22.tgz",
"integrity": "sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ==",
"version": "3.1.23",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
"integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -14860,11 +14877,10 @@
}
},
"node_modules/postcss-initial": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.2.tgz",
"integrity": "sha512-ugA2wKonC0xeNHgirR4D3VWHs2JcU08WAi1KFLVcnb7IN89phID6Qtg2RIctWbnvp1TM2BOmDtX8GGLCKdR8YA==",
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.4.tgz",
"integrity": "sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg==",
"dependencies": {
"lodash.template": "^4.5.0",
"postcss": "^7.0.2"
}
},
@@ -15566,24 +15582,20 @@
}
},
"node_modules/postcss-safe-parser/node_modules/postcss": {
"version": "8.2.9",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.9.tgz",
"integrity": "sha512-b+TmuIL4jGtCHtoLi+G/PisuIl9avxs8IZMSmlABRwNz5RLUUACrC+ws81dcomz1nRezm5YPdXiMEzBEKgYn+Q==",
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.0.tgz",
"integrity": "sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ==",
"dependencies": {
"colorette": "^1.2.2",
"nanoid": "^3.1.22",
"source-map": "^0.6.1"
"nanoid": "^3.1.23",
"source-map-js": "^0.6.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/postcss-safe-parser/node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"engines": {
"node": ">=0.10.0"
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
}
},
"node_modules/postcss-selector-matches": {
@@ -16948,9 +16960,9 @@
"integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
},
"node_modules/resolve-url-loader": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.2.tgz",
"integrity": "sha512-QEb4A76c8Mi7I3xNKXlRKQSlLBwjUV/ULFMP+G7n3/7tJZ8MG5wsZ3ucxP1Jz8Vevn6fnJsxDx9cIls+utGzPQ==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.3.tgz",
"integrity": "sha512-WbDSNFiKPPLem1ln+EVTE+bFUBdTTytfQZWbmghroaFNFaAVmGq0Saqw6F/306CwgPXsGwXVxbODE+3xAo/YbA==",
"dependencies": {
"adjust-sourcemap-loader": "3.0.0",
"camelcase": "5.3.1",
@@ -17966,6 +17978,14 @@
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz",
"integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-resolve": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
@@ -20710,9 +20730,9 @@
}
},
"node_modules/webpack-dev-server/node_modules/ws": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
"integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
"integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
"dependencies": {
"async-limiter": "~1.0.0"
}
@@ -21489,11 +21509,23 @@
}
},
"node_modules/ws": {
"version": "7.4.4",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz",
"integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==",
"version": "7.4.6",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
"engines": {
"node": ">=8.3.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xdg-basedir": {
@@ -23497,6 +23529,11 @@
"react-is": "^16.8.0 || ^17.0.0"
}
},
"@msgpack/msgpack": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.7.0.tgz",
"integrity": "sha512-mlRYq9FSsOd4m+3wZWatemn3hGFZPWNJ4JQOdrir4rrMK2PyIk26idKBoUWrqF3HJJHl+5GpRU+M0wEruJwecg=="
},
"@nodelib/fs.scandir": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
@@ -25598,15 +25635,15 @@
}
},
"browserslist": {
"version": "4.16.3",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.3.tgz",
"integrity": "sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==",
"version": "4.16.6",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz",
"integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==",
"requires": {
"caniuse-lite": "^1.0.30001181",
"colorette": "^1.2.1",
"electron-to-chromium": "^1.3.649",
"caniuse-lite": "^1.0.30001219",
"colorette": "^1.2.2",
"electron-to-chromium": "^1.3.723",
"escalade": "^3.1.1",
"node-releases": "^1.1.70"
"node-releases": "^1.1.71"
}
},
"bser": {
@@ -25812,9 +25849,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001208",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001208.tgz",
"integrity": "sha512-OE5UE4+nBOro8Dyvv0lfx+SRtfVIOM9uhKqFmJeUbGriqhhStgp1A0OyBpgy3OUF8AhYCT+PVwPC1gMl2ZcQMA=="
"version": "1.0.30001235",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001235.tgz",
"integrity": "sha512-zWEwIVqnzPkSAXOUlQnPW2oKoYb2aLQ4Q5ejdjBcnH63rfypaW34CxaeBn1VMya2XaEU3P/R2qHpWyj+l0BT1A=="
},
"capture-exit": {
"version": "2.0.0",
@@ -27268,9 +27305,9 @@
"integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0="
},
"dns-packet": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz",
"integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==",
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz",
"integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==",
"requires": {
"ip": "^1.1.0",
"safe-buffer": "^5.0.1"
@@ -27477,9 +27514,9 @@
"integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA=="
},
"electron-to-chromium": {
"version": "1.3.712",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.712.tgz",
"integrity": "sha512-3kRVibBeCM4vsgoHHGKHmPocLqtFAGTrebXxxtgKs87hNUzXrX2NuS3jnBys7IozCnw7viQlozxKkmty2KNfrw=="
"version": "1.3.749",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.749.tgz",
"integrity": "sha512-F+v2zxZgw/fMwPz/VUGIggG4ZndDsYy0vlpthi3tjmDZlcfbhN5mYW0evXUsBr2sUtuDANFtle410A9u/sd/4A=="
},
"elliptic": {
"version": "6.5.4",
@@ -32656,9 +32693,9 @@
"integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
},
"nanoid": {
"version": "3.1.22",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.22.tgz",
"integrity": "sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ=="
"version": "3.1.23",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
"integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw=="
},
"nanomatch": {
"version": "1.2.13",
@@ -33963,11 +34000,10 @@
}
},
"postcss-initial": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.2.tgz",
"integrity": "sha512-ugA2wKonC0xeNHgirR4D3VWHs2JcU08WAi1KFLVcnb7IN89phID6Qtg2RIctWbnvp1TM2BOmDtX8GGLCKdR8YA==",
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.4.tgz",
"integrity": "sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg==",
"requires": {
"lodash.template": "^4.5.0",
"postcss": "^7.0.2"
}
},
@@ -34569,19 +34605,14 @@
},
"dependencies": {
"postcss": {
"version": "8.2.9",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.9.tgz",
"integrity": "sha512-b+TmuIL4jGtCHtoLi+G/PisuIl9avxs8IZMSmlABRwNz5RLUUACrC+ws81dcomz1nRezm5YPdXiMEzBEKgYn+Q==",
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.0.tgz",
"integrity": "sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ==",
"requires": {
"colorette": "^1.2.2",
"nanoid": "^3.1.22",
"source-map": "^0.6.1"
"nanoid": "^3.1.23",
"source-map-js": "^0.6.2"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
}
}
},
@@ -35699,9 +35730,9 @@
"integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
},
"resolve-url-loader": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.2.tgz",
"integrity": "sha512-QEb4A76c8Mi7I3xNKXlRKQSlLBwjUV/ULFMP+G7n3/7tJZ8MG5wsZ3ucxP1Jz8Vevn6fnJsxDx9cIls+utGzPQ==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.3.tgz",
"integrity": "sha512-WbDSNFiKPPLem1ln+EVTE+bFUBdTTytfQZWbmghroaFNFaAVmGq0Saqw6F/306CwgPXsGwXVxbODE+3xAo/YbA==",
"requires": {
"adjust-sourcemap-loader": "3.0.0",
"camelcase": "5.3.1",
@@ -36573,6 +36604,11 @@
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
},
"source-map-js": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz",
"integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug=="
},
"source-map-resolve": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
@@ -39090,9 +39126,9 @@
}
},
"ws": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
"integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
"integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
"requires": {
"async-limiter": "~1.0.0"
}
@@ -39543,9 +39579,10 @@
}
},
"ws": {
"version": "7.4.4",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz",
"integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw=="
"version": "7.4.6",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
"requires": {}
},
"xdg-basedir": {
"version": "4.0.0",

View File

@@ -5,6 +5,7 @@
"dependencies": {
"@material-ui/core": "^4.11.4",
"@material-ui/icons": "^4.11.2",
"@msgpack/msgpack": "^2.7.0",
"@types/lodash": "^4.14.168",
"@types/node": "^15.0.1",
"@types/react": "^17.0.4",

View File

@@ -1,6 +1,11 @@
import React, { Component, Fragment } from 'react';
import { withStyles, Theme, createStyles } from '@material-ui/core/styles';
import parseMilliseconds from 'parse-ms';
import { Decoder } from '@msgpack/msgpack';
const decoder = new Decoder();
import {
Table,
TableBody,
@@ -37,7 +42,9 @@ import {
EMSESPDevices,
EMSESPDeviceData,
Device,
DeviceValue
DeviceValue,
DeviceValueUOM,
DeviceValueUOM_s
} from './EMSESPtypes';
import ValueForm from './ValueForm';
@@ -85,25 +92,48 @@ interface EMSESPDevicesFormState {
processing: boolean;
deviceData?: EMSESPDeviceData;
selectedDevice?: number;
devicevalue?: DeviceValue;
edit_devicevalue?: DeviceValue;
}
type EMSESPDevicesFormProps = RestFormProps<EMSESPDevices> &
AuthenticatedContextProps &
WithWidthProps;
function formatTemp(t: string) {
if (t == null) {
return 'n/a';
export const formatDuration = (duration_min: number) => {
const { days, hours, minutes } = parseMilliseconds(duration_min * 60000);
let formatted = '';
if (days) {
formatted += pluralize(days, 'day');
}
return t + ' °C';
if (hours) {
formatted += pluralize(hours, 'hour');
}
if (minutes) {
formatted += pluralize(minutes, 'minute');
}
return formatted;
};
function formatUnit(u: string) {
if (u == null) {
return u;
const pluralize = (count: number, noun: string, suffix = 's') =>
` ${count} ${noun}${count !== 1 ? suffix : ''} `;
function formatValue(value: any, uom: number) {
switch (uom) {
case DeviceValueUOM.HOURS:
return formatDuration(value * 60);
case DeviceValueUOM.MINUTES:
return formatDuration(value);
case DeviceValueUOM.NONE:
return value;
case DeviceValueUOM.NUM:
return new Intl.NumberFormat().format(value);
case DeviceValueUOM.BOOLEAN:
return value ? 'on' : 'off';
default:
return (
new Intl.NumberFormat().format(value) + ' ' + DeviceValueUOM_s[uom]
);
}
return ' ' + u;
}
class EMSESPDevicesForm extends Component<
@@ -119,25 +149,26 @@ class EMSESPDevicesForm extends Component<
event: React.ChangeEvent<HTMLInputElement>
) => {
this.setState({
devicevalue: {
...this.state.devicevalue!,
edit_devicevalue: {
...this.state.edit_devicevalue!,
[name]: extractEventValue(event)
}
});
};
cancelEditingValue = () => {
this.setState({
devicevalue: undefined
});
this.setState({ edit_devicevalue: undefined });
};
doneEditingValue = () => {
const { devicevalue } = this.state;
const { edit_devicevalue, selectedDevice } = this.state;
redirectingAuthorizedFetch(WRITE_VALUE_ENDPOINT, {
method: 'POST',
body: JSON.stringify({ devicevalue: devicevalue }),
body: JSON.stringify({
id: selectedDevice,
devicevalue: edit_devicevalue
}),
headers: {
'Content-Type': 'application/json'
}
@@ -165,23 +196,13 @@ class EMSESPDevicesForm extends Component<
});
});
if (devicevalue) {
this.setState({
devicevalue: undefined
});
if (edit_devicevalue) {
this.setState({ edit_devicevalue: undefined });
}
};
sendCommand = (i: number) => {
this.setState({
devicevalue: {
id: this.state.selectedDevice!,
data: this.state.deviceData?.data[i]!,
uom: this.state.deviceData?.data[i + 1]!,
name: this.state.deviceData?.data[i + 2]!,
cmd: this.state.deviceData?.data[i + 3]!
}
});
sendCommand = (dv: DeviceValue) => {
this.setState({ edit_devicevalue: dv });
};
noDevices = () => {
@@ -290,7 +311,7 @@ class EMSESPDevicesForm extends Component<
</TableCell>
<TableCell align="center">{sensorData.id}</TableCell>
<TableCell align="right">
{formatTemp(sensorData.temp)}
{formatValue(sensorData.temp, DeviceValueUOM.DEGREES)}
</TableCell>
</TableRow>
))}
@@ -318,7 +339,7 @@ class EMSESPDevicesForm extends Component<
>
<DialogTitle>Confirm Scan Devices</DialogTitle>
<DialogContent dividers>
Are you sure you want to initiate a scan on the EMS bus for all new
Are you sure you want to start a scan on the EMS bus for all new
devices?
</DialogContent>
<DialogActions>
@@ -384,11 +405,12 @@ class EMSESPDevicesForm extends Component<
})
.then((response) => {
if (response.status === 200) {
return response.json();
return response.arrayBuffer();
}
throw Error('Unexpected response code: ' + response.status);
})
.then((json) => {
.then((arrayBuffer) => {
const json: any = decoder.decode(arrayBuffer);
this.setState({ deviceData: json });
})
.catch((error) => {
@@ -429,14 +451,10 @@ class EMSESPDevicesForm extends Component<
>
<TableHead></TableHead>
<TableBody>
{deviceData.data.map((item, i) => {
if (i % 4) {
return null;
} else {
return (
{deviceData.data.map((item, i) => (
<TableRow hover key={i}>
<TableCell padding="checkbox" style={{ width: 18 }}>
{deviceData.data[i + 3] && me.admin && (
{item.c && me.admin && (
<CustomTooltip
title="change value"
placement="left-end"
@@ -445,7 +463,7 @@ class EMSESPDevicesForm extends Component<
edge="start"
size="small"
aria-label="Edit"
onClick={() => this.sendCommand(i)}
onClick={() => this.sendCommand(item)}
>
<EditIcon color="primary" fontSize="small" />
</IconButton>
@@ -453,16 +471,13 @@ class EMSESPDevicesForm extends Component<
)}
</TableCell>
<TableCell padding="none" component="th" scope="row">
{deviceData.data[i + 2]}
{item.n}
</TableCell>
<TableCell padding="none" align="right">
{deviceData.data[i]}
{formatUnit(deviceData.data[i + 1])}
{formatValue(item.v, item.u)}
</TableCell>
</TableRow>
);
}
})}
))}
</TableBody>
</Table>
</TableContainer>
@@ -479,7 +494,7 @@ class EMSESPDevicesForm extends Component<
}
render() {
const { devicevalue } = this.state;
const { edit_devicevalue } = this.state;
return (
<Fragment>
<br></br>
@@ -509,9 +524,9 @@ class EMSESPDevicesForm extends Component<
</Box>
</Box>
{this.renderScanDevicesDialog()}
{devicevalue && (
{edit_devicevalue && (
<ValueForm
devicevalue={devicevalue}
devicevalue={edit_devicevalue}
onDoneEditing={this.doneEditingValue}
onCancelEditing={this.cancelEditingValue}
handleValueChange={this.handleValueChange}

View File

@@ -58,15 +58,54 @@ export interface EMSESPDevices {
sensors: Sensor[];
}
export interface EMSESPDeviceData {
name: string;
data: string[];
export interface DeviceValue {
v: any;
u: number;
n: string;
c: string;
}
export interface DeviceValue {
id: number;
data: string;
uom: string;
export interface EMSESPDeviceData {
name: string;
cmd: string;
data: DeviceValue[];
}
export enum DeviceValueUOM {
NONE = 0,
DEGREES,
PERCENT,
LMIN,
KWH,
WH,
HOURS,
MINUTES,
UA,
BAR,
KW,
W,
KB,
SECONDS,
DBM,
NUM,
BOOLEAN
}
export const DeviceValueUOM_s = [
'',
'°C',
'%',
'l/min',
'kWh',
'Wh',
'hours',
'minutes',
'uA',
'bar',
'kW',
'W',
'KB',
'seconds',
'dBm',
'number',
'on/off'
];

View File

@@ -2,53 +2,21 @@
/*
Async Response to use with ArduinoJson and AsyncWebServer
Written by Andrew Melvin (SticilFace) with help from me-no-dev and BBlanchon.
Example of callback in use
server.on("/json", HTTP_ANY, [](AsyncWebServerRequest * request) {
AsyncJsonResponse * response = new AsyncJsonResponse();
JsonObject& root = response->getRoot();
root["key1"] = "key number one";
JsonObject& nested = root.createNestedObject("nested");
nested["key1"] = "key number one";
response->setLength();
request->send(response);
});
--------------------
Async Request to use with ArduinoJson and AsyncWebServer
Written by Arsène von Wyss (avonwyss)
Example
AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/rest/endpoint");
handler->onRequest([](AsyncWebServerRequest *request, JsonVariant &json) {
JsonObject& jsonObj = json.as<JsonObject>();
// ...
});
server.addHandler(handler);
*/
#ifndef ASYNC_JSON_H_
#define ASYNC_JSON_H_
#include <ArduinoJson.h>
#include <ESPAsyncWebServer.h>
#include <Print.h>
#if ARDUINOJSON_VERSION_MAJOR == 5
#define ARDUINOJSON_5_COMPATIBILITY
#else
#define DYNAMIC_JSON_DOCUMENT_SIZE 1024
#endif
constexpr const char * JSON_MIMETYPE = "application/json";
/*
* Json Response
* */
*/
class ChunkPrint : public Print {
private:
@@ -82,30 +50,14 @@ class ChunkPrint : public Print {
}
};
class AsyncJsonResponse : public AsyncAbstractResponse {
class MsgpackAsyncJsonResponse : public AsyncAbstractResponse {
protected:
#ifdef ARDUINOJSON_5_COMPATIBILITY
DynamicJsonBuffer _jsonBuffer;
#else
DynamicJsonDocument _jsonBuffer;
#endif
JsonVariant _root;
bool _isValid;
public:
#ifdef ARDUINOJSON_5_COMPATIBILITY
AsyncJsonResponse(bool isArray = false)
: _isValid{false} {
_code = 200;
_contentType = JSON_MIMETYPE;
if (isArray)
_root = _jsonBuffer.createArray();
else
_root = _jsonBuffer.createObject();
}
#else
AsyncJsonResponse(bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
MsgpackAsyncJsonResponse(bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
: _jsonBuffer(maxJsonBufferSize)
, _isValid{false} {
_code = 200;
@@ -115,9 +67,8 @@ class AsyncJsonResponse : public AsyncAbstractResponse {
else
_root = _jsonBuffer.createNestedObject();
}
#endif
~AsyncJsonResponse() {
~MsgpackAsyncJsonResponse() {
}
JsonVariant & getRoot() {
return _root;
@@ -126,12 +77,7 @@ class AsyncJsonResponse : public AsyncAbstractResponse {
return _isValid;
}
size_t setLength() {
#ifdef ARDUINOJSON_5_COMPATIBILITY
_contentLength = _root.measureLength();
#else
_contentLength = measureJson(_root);
#endif
_contentLength = measureMsgPack(_root);
if (_contentLength) {
_isValid = true;
}
@@ -144,33 +90,66 @@ class AsyncJsonResponse : public AsyncAbstractResponse {
size_t _fillBuffer(uint8_t * data, size_t len) {
ChunkPrint dest(data, _sentLength, len);
serializeMsgPack(_root, dest);
// serializeJson(_root, Serial); // for testing proddy
// Serial.println();
return len;
}
};
#ifdef ARDUINOJSON_5_COMPATIBILITY
_root.printTo(dest);
#else
class AsyncJsonResponse : public AsyncAbstractResponse {
protected:
DynamicJsonDocument _jsonBuffer;
JsonVariant _root;
bool _isValid;
public:
AsyncJsonResponse(bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
: _jsonBuffer(maxJsonBufferSize)
, _isValid{false} {
_code = 200;
_contentType = JSON_MIMETYPE;
if (isArray)
_root = _jsonBuffer.createNestedArray();
else
_root = _jsonBuffer.createNestedObject();
}
~AsyncJsonResponse() {
}
JsonVariant & getRoot() {
return _root;
}
bool _sourceValid() const {
return _isValid;
}
size_t setLength() {
_contentLength = measureJson(_root);
if (_contentLength) {
_isValid = true;
}
return _contentLength;
}
size_t getSize() {
return _jsonBuffer.size();
}
size_t _fillBuffer(uint8_t * data, size_t len) {
ChunkPrint dest(data, _sentLength, len);
serializeJson(_root, dest);
#endif
return len;
}
};
class PrettyAsyncJsonResponse : public AsyncJsonResponse {
public:
#ifdef ARDUINOJSON_5_COMPATIBILITY
PrettyAsyncJsonResponse(bool isArray = false)
: AsyncJsonResponse{isArray} {
}
#else
PrettyAsyncJsonResponse(bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
: AsyncJsonResponse{isArray, maxJsonBufferSize} {
}
#endif
size_t setLength() {
#ifdef ARDUINOJSON_5_COMPATIBILITY
_contentLength = _root.measurePrettyLength();
#else
_contentLength = measureJsonPretty(_root);
#endif
if (_contentLength) {
_isValid = true;
}
@@ -178,13 +157,9 @@ class PrettyAsyncJsonResponse : public AsyncJsonResponse {
}
size_t _fillBuffer(uint8_t * data, size_t len) {
ChunkPrint dest(data, _sentLength, len);
#ifdef ARDUINOJSON_5_COMPATIBILITY
_root.prettyPrintTo(dest);
#else
serializeJsonPretty(_root, dest);
// serializeJson(_root, Serial); // for testing
// serializeJson(_root, Serial); // for testing proddy
// Serial.println();
#endif
return len;
}
};
@@ -204,14 +179,6 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
size_t _maxContentLength;
public:
#ifdef ARDUINOJSON_5_COMPATIBILITY
AsyncCallbackJsonWebHandler(const String & uri, ArJsonRequestHandlerFunction onRequest)
: _uri(uri)
, _method(HTTP_POST | HTTP_PUT | HTTP_PATCH)
, _onRequest(onRequest)
, _maxContentLength(16384) {
}
#else
AsyncCallbackJsonWebHandler(const String & uri, ArJsonRequestHandlerFunction onRequest, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
: _uri(uri)
, _method(HTTP_POST | HTTP_PUT | HTTP_PATCH)
@@ -219,7 +186,6 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
, maxJsonBufferSize(maxJsonBufferSize)
, _maxContentLength(16384) {
}
#endif
void setMethod(WebRequestMethodComposite method) {
_method = method;
@@ -251,17 +217,10 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
virtual void handleRequest(AsyncWebServerRequest * request) override final {
if (_onRequest) {
if (request->_tempObject != NULL) {
#ifdef ARDUINOJSON_5_COMPATIBILITY
DynamicJsonBuffer jsonBuffer;
JsonVariant json = jsonBuffer.parse((uint8_t *)(request->_tempObject));
if (json.success()) {
#else
DynamicJsonDocument jsonBuffer(this->maxJsonBufferSize);
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t *)(request->_tempObject));
if (!error) {
JsonVariant json = jsonBuffer.as<JsonVariant>();
#endif
_onRequest(request, json);
return;
}
@@ -288,4 +247,5 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
return _onRequest ? false : true;
}
};
#endif

View File

@@ -87,6 +87,52 @@ class PrettyAsyncJsonResponse {
}
};
class MsgpackAsyncJsonResponse {
protected:
DynamicJsonDocument _jsonBuffer;
JsonVariant _root;
bool _isValid;
public:
MsgpackAsyncJsonResponse(bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
: _jsonBuffer(maxJsonBufferSize)
, _isValid{false} {
if (isArray)
_root = _jsonBuffer.createNestedArray();
else
_root = _jsonBuffer.createNestedObject();
}
~MsgpackAsyncJsonResponse() {
}
JsonVariant & getRoot() {
return _root;
}
bool _sourceValid() const {
return _isValid;
}
size_t setLength() {
return 0;
}
void setContentType(const char * s) {
}
size_t getSize() {
return _jsonBuffer.size();
}
size_t _fillBuffer(uint8_t * data, size_t len) {
return len;
}
void setCode(uint16_t) {
}
};
class AsyncJsonResponse {
protected:
DynamicJsonDocument _jsonBuffer;

View File

@@ -12,6 +12,7 @@ class AsyncWebServerRequest;
class AsyncWebServerResponse;
class AsyncJsonResponse;
class PrettyAsyncJsonResponse;
class MsgpackAsyncJsonResponse;
class AsyncWebParameter {
private:
@@ -98,6 +99,7 @@ class AsyncWebServerRequest {
void send(AsyncWebServerResponse * response){};
void send(AsyncJsonResponse * response){};
void send(PrettyAsyncJsonResponse * response){};
void send(MsgpackAsyncJsonResponse * response){};
void send(int code, const String & contentType = String(), const String & content = String()){};
void send(int code, const String & contentType, const __FlashStringHelper *){};

View File

@@ -9,10 +9,19 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@msgpack/msgpack": "^2.7.0",
"express": "^4.17.1",
"nodemon": "^2.0.7"
}
},
"node_modules/@msgpack/msgpack": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.7.0.tgz",
"integrity": "sha512-mlRYq9FSsOd4m+3wZWatemn3hGFZPWNJ4JQOdrir4rrMK2PyIk26idKBoUWrqF3HJJHl+5GpRU+M0wEruJwecg==",
"engines": {
"node": ">= 10"
}
},
"node_modules/@sindresorhus/is": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
@@ -1593,6 +1602,11 @@
}
},
"dependencies": {
"@msgpack/msgpack": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.7.0.tgz",
"integrity": "sha512-mlRYq9FSsOd4m+3wZWatemn3hGFZPWNJ4JQOdrir4rrMK2PyIk26idKBoUWrqF3HJJHl+5GpRU+M0wEruJwecg=="
},
"@sindresorhus/is": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",

View File

@@ -11,6 +11,7 @@
"author": "proddy",
"license": "ISC",
"dependencies": {
"@msgpack/msgpack": "^2.7.0",
"express": "^4.17.1",
"nodemon": "^2.0.7"
}

View File

@@ -1,6 +1,9 @@
const express = require('express')
const path = require('path')
const msgpack = require('@msgpack/msgpack')
// import { encode } from "@msgpack/msgpack";
const app = express()
const port = process.env.PORT || 3080
@@ -284,7 +287,10 @@ const emsesp_alldevices = {
version: '01.03',
},
],
sensors: [],
sensors: [
{ no: 1, id: '28-233D-9497-0C03', temp: '25.7' },
{ no: 2, id: '28-243D-7437-1E3A', temp: '26.1' },
],
}
const emsesp_status = {
status: 0,
@@ -293,273 +299,408 @@ const emsesp_status = {
rx_quality: 100,
tx_quality: 100,
}
const emsesp_devicedata_1 = {
name: 'Thermostat: RC20/Moduline 300',
data: [
'16:28:21 01/04/2021',
'',
'date/time',
'datetime',
'(0)',
'',
'error code',
'',
15,
'°C',
'(hc1) setpoint room temperature',
'temp',
20.5,
'°C',
'(hc1) current room temperature',
'',
'auto',
'',
'(hc1) mode',
'mode',
{
v: '(0)',
u: 0,
n: 'error code',
c: '',
},
{
v: '14:54:39 06/06/2021',
u: 0,
n: 'date/time',
c: '',
},
{
v: 18,
u: 1,
n: '(hc1) selected room temperature',
c: 'hc1/seltemp',
},
{
v: 22.6,
u: 1,
n: '(hc1) current room temperature',
c: '',
},
{
v: 'auto',
u: 0,
n: '(hc1) mode',
c: 'hc1/mode',
},
],
}
const emsesp_devicedata_2 = {
name: 'Boiler: Nefit GBx72/Trendline/Cerapur/Greenstar Si/27i',
data: [
'off',
'',
'heating active',
'',
'off',
'',
'warm water active',
'',
5,
'°C',
'selected flow temperature',
'selflowtemp',
0,
'%',
'burner selected max power',
'',
0,
'%',
'heating pump modulation',
'',
42.7,
'°C',
'current flow temperature',
'',
39,
'°C',
'return temperature',
'',
1.2,
'bar',
'system pressure',
'',
45.3,
'°C',
'max boiler temperature',
'',
'off',
'',
'gas',
'',
0,
'uA',
'flame current',
'',
'off',
'',
'heating pump',
'',
'off',
'',
'fan',
'',
'off',
'',
'ignition',
'',
'on',
'',
'heating activated',
'',
75,
'°C',
'heating temperature',
'',
90,
'%',
'burner pump max power',
'',
55,
'%',
'burner pump min power',
'',
1,
null,
'pump delay',
'',
10,
null,
'burner min period',
'',
0,
'%',
'burner min power',
'',
75,
'%',
'burner max power',
'',
-6,
'°C',
'hysteresis on temperature',
'',
6,
'°C',
'hysteresis off temperature',
'',
0,
'%',
'burner current power',
'',
295740,
'',
'burner # starts',
'',
'344 days 2 hours 8 minutes',
null,
'total burner operating time',
'',
'279 days 11 hours 55 minutes',
null,
'total heat operating time',
'',
'2946 days 19 hours 8 minutes',
null,
'total UBA operating time',
'',
'1C(210) 06.06.2020 12:07',
'',
'last error code',
'',
'0H',
'',
'service code',
'',
203,
'',
'service code number',
'',
'01.01.2012',
'',
'maintenance set date',
'',
'off',
'',
'maintenance scheduled',
'',
6000,
'hours',
'maintenance set time',
'',
60,
'°C',
'(warm water) selected temperature',
'',
62,
'°C',
'(warm water) set temperature',
'',
'flow',
'',
'(warm water) type',
'',
'hot',
'',
'(warm water) comfort',
'',
40,
'',
'(warm water) flow temperature offset',
'',
100,
'%',
'(warm water) max power',
'',
'off',
'',
'(warm water) circulation pump available',
'',
'3-way valve',
'',
'(warm water) charging type',
'',
70,
'°C',
'(warm water) disinfection temperature',
'',
'off',
'',
'(warm water) circulation pump freq',
'',
'off',
'',
'(warm water) circulation active',
'',
34.7,
'°C',
'(warm water) current intern temperature',
'',
0,
'l/min',
'(warm water) current tap water flow',
'',
34.6,
'°C',
'(warm water) storage intern temperature',
'',
'on',
'',
'(warm water) activated',
'',
'off',
'',
'(warm water) one time charging',
'',
'off',
'',
'(warm water) disinfecting',
'',
'off',
'',
'(warm water) charging',
'',
'off',
'',
'(warm water) recharging',
'',
'on',
'',
'(warm water) temperature ok',
'',
'off',
'',
'(warm water) active',
'',
'on',
'',
'(warm water) heating',
'',
262387,
'',
'(warm water) # starts',
'',
'64 days 14 hours 13 minutes',
null,
'(warm water) active time',
'',
{
v: false,
u: 16,
n: 'heating active',
c: '',
},
{
v: false,
u: 16,
n: 'warm water active',
c: '',
},
{
v: 5,
u: 1,
n: 'selected flow temperature',
c: 'selflowtemp',
},
{
v: 0,
u: 2,
n: 'burner selected max power',
c: 'selburnpow',
},
{
v: 0,
u: 2,
n: 'heating pump modulation',
c: '',
},
{
v: 51,
u: 1,
n: 'current flow temperature',
c: '',
},
{
v: 49.8,
u: 1,
n: 'return temperature',
c: '',
},
{
v: 1.1,
u: 9,
n: 'system pressure',
c: '',
},
{
v: 52.7,
u: 1,
n: 'boiler temperature',
c: '',
},
{
v: false,
u: 16,
n: 'gas',
c: '',
},
{
v: 0,
u: 8,
n: 'flame current',
c: '',
},
{
v: false,
u: 16,
n: 'heating pump',
c: '',
},
{
v: false,
u: 16,
n: 'fan',
c: '',
},
{
v: false,
u: 16,
n: 'ignition',
c: '',
},
{
v: true,
u: 16,
n: 'heating activated',
c: 'heatingactivated',
},
{
v: 75,
u: 1,
n: 'heating temperature',
c: 'heatingtemp',
},
{
v: 90,
u: 2,
n: 'burner pump max power',
c: 'pumpmodmax',
},
{
v: 55,
u: 2,
n: 'burner pump min power',
c: 'pumpmodmin',
},
{
v: 1,
u: 7,
n: 'pump delay',
c: 'pumpdelay',
},
{
v: 10,
u: 7,
n: 'burner min period',
c: 'burnminperiod',
},
{
v: 0,
u: 2,
n: 'burner min power',
c: 'burnminpower',
},
{
v: 75,
u: 2,
n: 'burner max power',
c: 'burnmaxpower',
},
{
v: -6,
u: 1,
n: 'hysteresis on temperature',
c: 'boilhyston',
},
{
v: 6,
u: 1,
n: 'hysteresis off temperature',
c: 'boilhystoff',
},
{
v: 0,
u: 2,
n: 'burner current power',
c: '',
},
{
v: 303226,
u: 15,
n: '# burner starts',
c: '',
},
{
v: 510634,
u: 7,
n: 'total burner operating time',
c: '',
},
{
v: 415235,
u: 7,
n: 'total heat operating time',
c: '',
},
{
v: 4338730,
u: 7,
n: 'total UBA operating time',
c: '',
},
{
v: '1C(210) 06.06.2020 12:07',
u: 0,
n: 'last error code',
c: '',
},
{
v: '0H',
u: 0,
n: 'service code',
c: '',
},
{
v: 203,
u: 0,
n: 'service code number',
c: '',
},
{
v: '01.01.2012',
u: 0,
n: 'maintenance set date',
c: '',
},
{
v: 'off',
u: 0,
n: 'maintenance scheduled',
c: 'maintenance',
},
{
v: 6000,
u: 6,
n: 'maintenance set time',
c: '',
},
{
v: 60,
u: 1,
n: '(ww) selected temperature',
c: '',
},
{
v: 62,
u: 1,
n: '(ww) set temperature',
c: 'wwsettemp',
},
{
v: 'flow',
u: 0,
n: '(ww) type',
c: '',
},
{
v: 'hot',
u: 0,
n: '(ww) comfort',
c: 'wwcomfort',
},
{
v: 40,
u: 0,
n: '(ww) flow temperature offset',
c: 'wwflowtempoffset',
},
{
v: 100,
u: 2,
n: '(ww) max power',
c: 'wwmaxpower',
},
{
v: false,
u: 16,
n: '(ww) circulation pump available',
c: 'wwcircpump',
},
{
v: 'charge pump',
u: 0,
n: '(ww) charging type',
c: '',
},
{
v: 70,
u: 1,
n: '(ww) disinfection temperature',
c: 'wwdisinfectiontemp',
},
{
v: 'off',
u: 0,
n: '(ww) circulation pump frequency',
c: 'wwcircmode',
},
{
v: false,
u: 16,
n: '(ww) circulation active',
c: 'wwcirc',
},
{
v: 44.4,
u: 1,
n: '(ww) current intern temperature',
c: '',
},
{
v: 0,
u: 3,
n: '(ww) current tap water flow',
c: '',
},
{
v: 44.4,
u: 1,
n: '(ww) storage intern temperature',
c: '',
},
{
v: true,
u: 16,
n: '(ww) activated',
c: 'wwactivated',
},
{
v: false,
u: 16,
n: '(ww) one time charging',
c: 'wwonetime',
},
{
v: false,
u: 16,
n: '(ww) disinfecting',
c: '',
},
{
v: false,
u: 16,
n: '(ww) charging',
c: '',
},
{
v: false,
u: 16,
n: '(ww) recharging',
c: '',
},
{
v: true,
u: 16,
n: '(ww) temperature ok',
c: '',
},
{
v: false,
u: 16,
n: '(ww) active',
c: '',
},
{
v: true,
u: 16,
n: '(ww) heating',
c: '',
},
{
v: 268671,
u: 15,
n: '(ww) # starts',
c: '',
},
{
v: 95399,
u: 7,
n: '(ww) active time',
c: '',
},
],
}
const emsesp_devicedata_3 = {
name: 'Controller: BC1',
data: [],
}
// NETWORK
app.get(NETWORK_STATUS_ENDPOINT, (req, res) => {
res.json(network_status)
@@ -672,16 +813,27 @@ app.get(EMSESP_STATUS_ENDPOINT, (req, res) => {
app.post(EMSESP_DEVICEDATA_ENDPOINT, (req, res) => {
const id = req.body.id
if (id == 1) {
res.json(emsesp_devicedata_1)
const encoded = msgpack.encode(emsesp_devicedata_1)
res.write(encoded, 'binary')
res.end(null, 'binary')
}
if (id == 2) {
res.json(emsesp_devicedata_2)
const encoded = msgpack.encode(emsesp_devicedata_2)
res.write(encoded, 'binary')
res.end(null, 'binary')
}
if (id == 3) {
const encoded = msgpack.encode(emsesp_devicedata_3)
res.write(encoded, 'binary')
res.end(null, 'binary')
}
})
app.post(WRITE_VALUE_ENDPOINT, (req, res) => {
const devicevalue = req.body.devicevalue
const id = req.body.id
console.log(id)
console.log(devicevalue)
res.sendStatus(200)

View File

@@ -26,7 +26,7 @@ WebDevicesService::WebDevicesService(AsyncWebServer * server, SecurityManager *
: _device_dataHandler(DEVICE_DATA_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDevicesService::device_data, this, _1, _2), AuthenticationPredicates::IS_AUTHENTICATED))
, _writevalue_dataHandler(WRITE_VALUE_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDevicesService::write_value, this, _1, _2), AuthenticationPredicates::IS_AUTHENTICATED)) {
securityManager->wrapCallback(std::bind(&WebDevicesService::write_value, this, _1, _2), AuthenticationPredicates::IS_ADMIN)) {
server->on(EMSESP_DEVICES_SERVICE_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebDevicesService::all_devices, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
@@ -83,9 +83,10 @@ void WebDevicesService::all_devices(AsyncWebServerRequest * request) {
}
// The unique_id is the unique record ID from the Web table to identify which device to load
// Compresses the JSON using MsgPack https://msgpack.org/index.html
void WebDevicesService::device_data(AsyncWebServerRequest * request, JsonVariant & json) {
if (json.is<JsonObject>()) {
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XXLARGE_DYN);
MsgpackAsyncJsonResponse * response = new MsgpackAsyncJsonResponse(false, EMSESP_JSON_SIZE_XXLARGE_DYN);
for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice) {
if (emsdevice->unique_id() == json["id"]) {
@@ -108,27 +109,20 @@ void WebDevicesService::device_data(AsyncWebServerRequest * request, JsonVariant
// takes a command and its data value from a specific Device, from the Web
void WebDevicesService::write_value(AsyncWebServerRequest * request, JsonVariant & json) {
// only issue commands if the API is enabled
EMSESP::webSettingsService.read([&](WebSettings & settings) {
if (!settings.notoken_api) {
request->send(403); // forbidden error
return;
}
});
if (json.is<JsonObject>()) {
JsonObject dv = json["devicevalue"];
uint8_t id = json["id"];
// using the unique ID from the web find the real device type
for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice) {
if (emsdevice->unique_id() == dv["id"].as<int>()) {
const char * cmd = dv["cmd"];
if (emsdevice->unique_id() == id) {
const char * cmd = dv["c"];
uint8_t device_type = emsdevice->device_type();
bool ok = false;
char s[10];
// the data could be in any format, but we need string
JsonVariant data = dv["data"];
JsonVariant data = dv["v"];
if (data.is<const char *>()) {
ok = Command::call(device_type, cmd, data.as<const char *>());
} else if (data.is<int>()) {
@@ -139,16 +133,17 @@ void WebDevicesService::write_value(AsyncWebServerRequest * request, JsonVariant
ok = Command::call(device_type, cmd, data.as<bool>() ? "true" : "false");
}
if (ok) {
request->send(200);
// send "Write command sent to device" or "Write command failed"
AsyncWebServerResponse * response = request->beginResponse(ok ? 200 : 204);
request->send(response);
return;
}
return; // found device, quit
}
}
}
request->send(204); // no content error
}
AsyncWebServerResponse * response = request->beginResponse(204); // Write command failed
request->send(response);
}
} // namespace emsesp

View File

@@ -86,7 +86,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
}
// MQTT commands for boiler topic
register_device_value(
TAG_BOILER_DATA, &dummybool_, DeviceValueType::BOOL, nullptr, FL_(wwtapactivated), DeviceValueUOM::NONE, MAKE_CF_CB(set_tapwarmwater_activated));
TAG_BOILER_DATA, &dummybool_, DeviceValueType::BOOL, nullptr, FL_(wwtapactivated), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_tapwarmwater_activated));
register_device_value(TAG_BOILER_DATA, &dummy8u_, DeviceValueType::ENUM, FL_(enum_reset), FL_(reset), DeviceValueUOM::NONE, MAKE_CF_CB(set_reset));
// add values
@@ -96,8 +96,8 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_device_value(TAG_BOILER_DATA, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE);
id_ = product_id;
register_device_value(TAG_BOILER_DATA, &heatingActive_, DeviceValueType::BOOL, nullptr, FL_(heatingActive), DeviceValueUOM::NONE);
register_device_value(TAG_BOILER_DATA, &tapwaterActive_, DeviceValueType::BOOL, nullptr, FL_(tapwaterActive), DeviceValueUOM::NONE);
register_device_value(TAG_BOILER_DATA, &heatingActive_, DeviceValueType::BOOL, nullptr, FL_(heatingActive), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA, &tapwaterActive_, DeviceValueType::BOOL, nullptr, FL_(tapwaterActive), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA, &selFlowTemp_, DeviceValueType::UINT, nullptr, FL_(selFlowTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_flow_temp));
register_device_value(TAG_BOILER_DATA, &selBurnPow_, DeviceValueType::UINT, nullptr, FL_(selBurnPow), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_burn_power));
register_device_value(TAG_BOILER_DATA, &heatingPumpMod_, DeviceValueType::UINT, nullptr, FL_(heatingPumpMod), DeviceValueUOM::PERCENT);
@@ -109,13 +109,13 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_device_value(TAG_BOILER_DATA, &sysPress_, DeviceValueType::UINT, FL_(div10), FL_(sysPress), DeviceValueUOM::BAR);
register_device_value(TAG_BOILER_DATA, &boilTemp_, DeviceValueType::USHORT, FL_(div10), FL_(boilTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA, &exhaustTemp_, DeviceValueType::USHORT, FL_(div10), FL_(exhaustTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA, &burnGas_, DeviceValueType::BOOL, nullptr, FL_(burnGas), DeviceValueUOM::NONE);
register_device_value(TAG_BOILER_DATA, &burnGas_, DeviceValueType::BOOL, nullptr, FL_(burnGas), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA, &flameCurr_, DeviceValueType::USHORT, FL_(div10), FL_(flameCurr), DeviceValueUOM::UA);
register_device_value(TAG_BOILER_DATA, &heatingPump_, DeviceValueType::BOOL, nullptr, FL_(heatingPump), DeviceValueUOM::NONE);
register_device_value(TAG_BOILER_DATA, &fanWork_, DeviceValueType::BOOL, nullptr, FL_(fanWork), DeviceValueUOM::NONE);
register_device_value(TAG_BOILER_DATA, &ignWork_, DeviceValueType::BOOL, nullptr, FL_(ignWork), DeviceValueUOM::NONE);
register_device_value(TAG_BOILER_DATA, &heatingPump_, DeviceValueType::BOOL, nullptr, FL_(heatingPump), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA, &fanWork_, DeviceValueType::BOOL, nullptr, FL_(fanWork), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA, &ignWork_, DeviceValueType::BOOL, nullptr, FL_(ignWork), DeviceValueUOM::BOOLEAN);
register_device_value(
TAG_BOILER_DATA, &heatingActivated_, DeviceValueType::BOOL, nullptr, FL_(heatingActivated), DeviceValueUOM::NONE, MAKE_CF_CB(set_heating_activated));
TAG_BOILER_DATA, &heatingActivated_, DeviceValueType::BOOL, nullptr, FL_(heatingActivated), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_heating_activated));
register_device_value(TAG_BOILER_DATA, &heatingTemp_, DeviceValueType::UINT, nullptr, FL_(heatingTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_heating_temp));
register_device_value(TAG_BOILER_DATA, &pumpModMax_, DeviceValueType::UINT, nullptr, FL_(pumpModMax), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_max_pump));
register_device_value(TAG_BOILER_DATA, &pumpModMin_, DeviceValueType::UINT, nullptr, FL_(pumpModMin), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_min_pump));
@@ -190,8 +190,8 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_device_value(
TAG_DEVICE_DATA_WW, &wWMaxPower_, DeviceValueType::UINT, nullptr, FL_(wWMaxPower), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_warmwater_maxpower));
register_device_value(
TAG_DEVICE_DATA_WW, &wWCircPump_, DeviceValueType::BOOL, nullptr, FL_(wWCircPump), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_circulation_pump));
register_device_value(TAG_DEVICE_DATA_WW, &wWChargeType_, DeviceValueType::BOOL, FL_(enum_charge), FL_(wWChargeType), DeviceValueUOM::NONE);
TAG_DEVICE_DATA_WW, &wWCircPump_, DeviceValueType::BOOL, nullptr, FL_(wWCircPump), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_circulation_pump));
register_device_value(TAG_DEVICE_DATA_WW, &wWChargeType_, DeviceValueType::ENUM, FL_(enum_charge), FL_(wWChargeType), DeviceValueUOM::NONE);
register_device_value(TAG_DEVICE_DATA_WW,
&wWDisinfectionTemp_,
DeviceValueType::UINT,
@@ -206,21 +206,21 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
FL_(wWCircMode),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_warmwater_circulation_mode));
register_device_value(TAG_DEVICE_DATA_WW, &wWCirc_, DeviceValueType::BOOL, nullptr, FL_(wWCirc), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_circulation));
register_device_value(TAG_DEVICE_DATA_WW, &wWCirc_, DeviceValueType::BOOL, nullptr, FL_(wWCirc), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_circulation));
register_device_value(TAG_DEVICE_DATA_WW, &wWCurTemp_, DeviceValueType::USHORT, FL_(div10), FL_(wWCurTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_DEVICE_DATA_WW, &wWCurTemp2_, DeviceValueType::USHORT, FL_(div10), FL_(wWCurTemp2), DeviceValueUOM::DEGREES);
register_device_value(TAG_DEVICE_DATA_WW, &wWCurFlow_, DeviceValueType::UINT, FL_(div10), FL_(wWCurFlow), DeviceValueUOM::LMIN);
register_device_value(TAG_DEVICE_DATA_WW, &wWStorageTemp1_, DeviceValueType::USHORT, FL_(div10), FL_(wWStorageTemp1), DeviceValueUOM::DEGREES);
register_device_value(TAG_DEVICE_DATA_WW, &wWStorageTemp2_, DeviceValueType::USHORT, FL_(div10), FL_(wWStorageTemp2), DeviceValueUOM::DEGREES);
register_device_value(
TAG_DEVICE_DATA_WW, &wWActivated_, DeviceValueType::BOOL, nullptr, FL_(wWActivated), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_activated));
register_device_value(TAG_DEVICE_DATA_WW, &wWOneTime_, DeviceValueType::BOOL, nullptr, FL_(wWOneTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_onetime));
register_device_value(TAG_DEVICE_DATA_WW, &wWDisinfecting_, DeviceValueType::BOOL, nullptr, FL_(wWDisinfecting), DeviceValueUOM::NONE);
register_device_value(TAG_DEVICE_DATA_WW, &wWCharging_, DeviceValueType::BOOL, nullptr, FL_(wWCharging), DeviceValueUOM::NONE);
register_device_value(TAG_DEVICE_DATA_WW, &wWRecharging_, DeviceValueType::BOOL, nullptr, FL_(wWRecharging), DeviceValueUOM::NONE);
register_device_value(TAG_DEVICE_DATA_WW, &wWTempOK_, DeviceValueType::BOOL, nullptr, FL_(wWTempOK), DeviceValueUOM::NONE);
register_device_value(TAG_DEVICE_DATA_WW, &wWActive_, DeviceValueType::BOOL, nullptr, FL_(wWActive), DeviceValueUOM::NONE);
register_device_value(TAG_DEVICE_DATA_WW, &wWHeat_, DeviceValueType::BOOL, nullptr, FL_(wWHeat), DeviceValueUOM::NONE);
TAG_DEVICE_DATA_WW, &wWActivated_, DeviceValueType::BOOL, nullptr, FL_(wWActivated), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_activated));
register_device_value(TAG_DEVICE_DATA_WW, &wWOneTime_, DeviceValueType::BOOL, nullptr, FL_(wWOneTime), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_onetime));
register_device_value(TAG_DEVICE_DATA_WW, &wWDisinfecting_, DeviceValueType::BOOL, nullptr, FL_(wWDisinfecting), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_DEVICE_DATA_WW, &wWCharging_, DeviceValueType::BOOL, nullptr, FL_(wWCharging), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_DEVICE_DATA_WW, &wWRecharging_, DeviceValueType::BOOL, nullptr, FL_(wWRecharging), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_DEVICE_DATA_WW, &wWTempOK_, DeviceValueType::BOOL, nullptr, FL_(wWTempOK), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_DEVICE_DATA_WW, &wWActive_, DeviceValueType::BOOL, nullptr, FL_(wWActive), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_DEVICE_DATA_WW, &wWHeat_, DeviceValueType::BOOL, nullptr, FL_(wWHeat), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_DEVICE_DATA_WW, &wWSetPumpPower_, DeviceValueType::UINT, nullptr, FL_(wWSetPumpPower), DeviceValueUOM::PERCENT);
register_device_value(TAG_DEVICE_DATA_WW, &mixerTemp_, DeviceValueType::USHORT, FL_(div10), FL_(mixerTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_DEVICE_DATA_WW, &tankMiddleTemp_, DeviceValueType::USHORT, FL_(div10), FL_(tankMiddleTemp), DeviceValueUOM::DEGREES);
@@ -311,7 +311,6 @@ void Boiler::check_active(const bool force) {
}
// 0x33
// Boiler(0x08) -> Me(0x0B), UBAParameterWW(0x33), data: 08 FF 30 FB FF 28 FF 07 46 00 00
void Boiler::process_UBAParameterWW(std::shared_ptr<const Telegram> telegram) {
// has_update(telegram->read_bitvalue(wwEquipt_,0,3)); // 8=boiler has ww
has_update(telegram->read_value(wWActivated_, 1)); // 0xFF means on
@@ -322,8 +321,7 @@ void Boiler::process_UBAParameterWW(std::shared_ptr<const Telegram> telegram) {
has_update(telegram->read_value(wWCircPump_, 6)); // 0xFF means on
has_update(telegram->read_value(wWCircMode_, 7)); // 1=1x3min 6=6x3min 7=continuous
has_update(telegram->read_value(wWDisinfectionTemp_, 8));
has_update(telegram->read_value(wWChargeType_,
10)); // 0 = charge pump, 0xff = 3-way valve
has_update(telegram->read_bitvalue(wWChargeType_, 10, 0)); // 0 = charge pump, 0xff = 3-way valve
telegram->read_value(wWComfort_, 9);
if (wWComfort_ == 0x00) {
@@ -1175,7 +1173,7 @@ bool Boiler::set_warmwater_circulation_pump(const char * value, const int8_t id)
return true;
}
// Set the mode of circulation, 1x3min, ... 6x3min, continuos
// Set the mode of circulation, 1x3min, ... 6x3min, continuous
// true = on, false = off
bool Boiler::set_warmwater_circulation_mode(const char * value, const int8_t id) {
int v = 0;
@@ -1187,7 +1185,7 @@ bool Boiler::set_warmwater_circulation_mode(const char * value, const int8_t id)
if (v < 7) {
LOG_INFO(F("Setting warm water circulation mode %dx3min"), v);
} else if (v == 7) {
LOG_INFO(F("Setting warm water circulation mode continuos"));
LOG_INFO(F("Setting warm water circulation mode continuous"));
} else {
LOG_WARNING(F("Set warm water circulation mode: Invalid value"));
return false;

View File

@@ -60,7 +60,7 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
register_device_value(tag, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE);
register_device_value(tag, &flowSetTemp_, DeviceValueType::UINT, nullptr, FL_(flowSetTemp), DeviceValueUOM::DEGREES);
register_device_value(tag, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempHc), DeviceValueUOM::DEGREES);
register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, FL_(pumpStatus), DeviceValueUOM::NONE);
register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, FL_(pumpStatus), DeviceValueUOM::BOOLEAN);
register_device_value(tag, &status_, DeviceValueType::INT, nullptr, FL_(mixerStatus), DeviceValueUOM::PERCENT);
register_device_value(tag, &flowTempVf_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempVf), DeviceValueUOM::DEGREES);
} else {
@@ -69,7 +69,7 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
uint8_t tag = TAG_WWC1 + hc_ - 1;
register_device_value(tag, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE);
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, &pumpStatus_, DeviceValueType::BOOL, nullptr, FL_(wwPumpStatus), DeviceValueUOM::BOOLEAN);
register_device_value(tag, &status_, DeviceValueType::INT, nullptr, FL_(wwTempStatus), DeviceValueUOM::NONE);
}

View File

@@ -80,12 +80,11 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
register_device_value(TAG_NONE, &collectorTemp_, DeviceValueType::SHORT, FL_(div10), FL_(collectorTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_NONE, &tankBottomTemp_, DeviceValueType::SHORT, FL_(div10), FL_(tankBottomTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_NONE, &solarPump_, DeviceValueType::BOOL, nullptr, FL_(solarPump), DeviceValueUOM::NONE);
register_device_value(TAG_NONE, &solarPump_, DeviceValueType::BOOL, nullptr, FL_(solarPump), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_NONE, &pumpWorkTime_, DeviceValueType::TIME, nullptr, FL_(pumpWorkTime), DeviceValueUOM::MINUTES);
register_device_value(TAG_NONE, &tankMaxTemp_, DeviceValueType::UINT, nullptr, FL_(tankMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_TankMaxTemp));
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM10) {
// register_device_value(TAG_NONE, &collectorMaxTemp_, DeviceValueType::UINT, nullptr, FL_(collectorMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_CollectorMaxTemp));
register_device_value(TAG_NONE, &solarPumpModulation_, DeviceValueType::UINT, nullptr, FL_(solarPumpModulation), DeviceValueUOM::PERCENT);
register_device_value(TAG_NONE, &solarPumpMinMod_, DeviceValueType::UINT, nullptr, FL_(pumpMinMod), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_PumpMinMod));
register_device_value(
@@ -96,17 +95,16 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
TAG_NONE, &collectorMaxTemp_, DeviceValueType::UINT, nullptr, FL_(collectorMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_CollectorMaxTemp));
register_device_value(
TAG_NONE, &collectorMinTemp_, DeviceValueType::UINT, nullptr, FL_(collectorMinTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_CollectorMinTemp));
register_device_value(TAG_NONE, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::NONE);
// register_device_value(TAG_NONE, &tankHeated_, DeviceValueType::BOOL, nullptr, FL_(tankHeated), DeviceValueUOM::NONE);
register_device_value(TAG_NONE, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_NONE, &solarPower_, DeviceValueType::ULONG, nullptr, FL_(solarPower), DeviceValueUOM::W);
register_device_value(TAG_NONE, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH);
register_device_value(TAG_NONE, &maxFlow_, DeviceValueType::UINT, FL_(div10), FL_(maxFlow), DeviceValueUOM::LMIN, MAKE_CF_CB(set_SM10MaxFlow));
register_device_value(TAG_DEVICE_DATA_WW, &wwMinTemp_, DeviceValueType::UINT, nullptr, FL_(wwMinTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_wwMinTemp));
register_device_value(TAG_NONE, &solarIsEnabled_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::NONE, MAKE_CF_CB(set_solarEnabled));
register_device_value(TAG_NONE, &solarIsEnabled_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_solarEnabled));
}
if (flags == EMSdevice::EMS_DEVICE_FLAG_ISM) {
register_device_value(TAG_NONE, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::NONE);
register_device_value(TAG_NONE, &tankHeated_, DeviceValueType::BOOL, nullptr, FL_(tankHeated), DeviceValueUOM::NONE);
register_device_value(TAG_NONE, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_NONE, &tankHeated_, DeviceValueType::BOOL, nullptr, FL_(tankHeated), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_NONE, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH);
}
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) {
@@ -119,9 +117,9 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
register_device_value(TAG_NONE, &tankBottomTemp2_, DeviceValueType::SHORT, FL_(div10), FL_(tank2BottomTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_NONE, &heatExchangerTemp_, DeviceValueType::SHORT, FL_(div10), FL_(heatExchangerTemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_NONE, &cylinderPumpModulation_, DeviceValueType::UINT, nullptr, FL_(cylinderPumpModulation), DeviceValueUOM::PERCENT);
register_device_value(TAG_NONE, &valveStatus_, DeviceValueType::BOOL, nullptr, FL_(valveStatus), DeviceValueUOM::NONE);
register_device_value(TAG_NONE, &tankHeated_, DeviceValueType::BOOL, nullptr, FL_(tankHeated), DeviceValueUOM::NONE);
register_device_value(TAG_NONE, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::NONE);
register_device_value(TAG_NONE, &valveStatus_, DeviceValueType::BOOL, nullptr, FL_(valveStatus), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_NONE, &tankHeated_, DeviceValueType::BOOL, nullptr, FL_(tankHeated), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_NONE, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::BOOLEAN);
register_device_value(
TAG_NONE, &collectorMaxTemp_, DeviceValueType::UINT, nullptr, FL_(collectorMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_CollectorMaxTemp));
register_device_value(
@@ -131,12 +129,12 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
register_device_value(TAG_NONE, &energyTotal_, DeviceValueType::ULONG, FL_(div10), FL_(energyTotal), DeviceValueUOM::KWH);
register_device_value(
TAG_NONE, &heatTransferSystem_, DeviceValueType::BOOL, nullptr, FL_(heatTransferSystem), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatTransferSystem));
register_device_value(TAG_NONE, &externalTank_, DeviceValueType::BOOL, nullptr, FL_(externalTank), DeviceValueUOM::NONE, MAKE_CF_CB(set_externalTank));
TAG_NONE, &heatTransferSystem_, DeviceValueType::BOOL, nullptr, FL_(heatTransferSystem), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_heatTransferSystem));
register_device_value(TAG_NONE, &externalTank_, DeviceValueType::BOOL, nullptr, FL_(externalTank), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_externalTank));
register_device_value(
TAG_NONE, &thermalDisinfect_, DeviceValueType::BOOL, nullptr, FL_(thermalDisinfect), DeviceValueUOM::NONE, MAKE_CF_CB(set_thermalDisinfect));
register_device_value(TAG_NONE, &heatMetering_, DeviceValueType::BOOL, nullptr, FL_(heatMetering), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatMetering));
register_device_value(TAG_NONE, &solarIsEnabled_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::NONE, MAKE_CF_CB(set_solarEnabled));
TAG_NONE, &thermalDisinfect_, DeviceValueType::BOOL, nullptr, FL_(thermalDisinfect), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_thermalDisinfect));
register_device_value(TAG_NONE, &heatMetering_, DeviceValueType::BOOL, nullptr, FL_(heatMetering), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_heatMetering));
register_device_value(TAG_NONE, &solarIsEnabled_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_solarEnabled));
// telegram 0x035A
register_device_value(
@@ -146,21 +144,21 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
DeviceValueType::BOOL,
nullptr,
FL_(solarPumpKick),
DeviceValueUOM::NONE,
DeviceValueUOM::BOOLEAN,
MAKE_CF_CB(set_solarPumpKick)); // pump kick for vacuum collector, 00=off
register_device_value(TAG_NONE,
&plainWaterMode_,
DeviceValueType::BOOL,
nullptr,
FL_(plainWaterMode),
DeviceValueUOM::NONE,
DeviceValueUOM::BOOLEAN,
MAKE_CF_CB(set_plainWaterMode)); // system does not use antifreeze, 00=off
register_device_value(TAG_NONE,
&doubleMatchFlow_,
DeviceValueType::BOOL,
nullptr,
FL_(doubleMatchFlow),
DeviceValueUOM::NONE,
DeviceValueUOM::BOOLEAN,
MAKE_CF_CB(set_doubleMatchFlow)); // double Match Flow, 00=off
// telegram 0x380

View File

@@ -35,7 +35,7 @@ Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const
register_telegram_type(0x1E, F("WM10TempMessage"), false, MAKE_PF_CB(process_WM10TempMessage));
register_device_value(TAG_NONE, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE);
register_device_value(TAG_NONE, &activated_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::NONE);
register_device_value(TAG_NONE, &activated_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_NONE, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempHc), DeviceValueUOM::DEGREES);
register_device_value(TAG_NONE, &status_, DeviceValueType::INT, nullptr, FL_(status), DeviceValueUOM::NONE);
id_ = product_id;

View File

@@ -2306,7 +2306,7 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
register_device_value(tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::NONE);
register_device_value(
tag, &hc->summer_setmode, DeviceValueType::ENUM, FL_(enum_summermode), FL_(summermode), DeviceValueUOM::NONE, MAKE_CF_CB(set_summermode));
register_device_value(tag, &hc->summermode, DeviceValueType::BOOL, nullptr, FL_(summermode), DeviceValueUOM::NONE);
register_device_value(tag, &hc->summermode, DeviceValueType::BOOL, nullptr, FL_(summermode), DeviceValueUOM::BOOLEAN);
register_device_value(
tag, &hc->controlmode, DeviceValueType::ENUM, FL_(enum_controlmode), FL_(controlmode), DeviceValueUOM::NONE, MAKE_CF_CB(set_controlmode));
register_device_value(tag, &hc->program, DeviceValueType::UINT, nullptr, FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program));
@@ -2338,8 +2338,8 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
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));
register_device_value(tag, &hc->summermode, DeviceValueType::BOOL, nullptr, FL_(summermode), DeviceValueUOM::NONE);
register_device_value(tag, &hc->holidaymode, DeviceValueType::BOOL, nullptr, FL_(holidaymode), DeviceValueUOM::NONE, MAKE_CF_CB(set_holiday));
register_device_value(tag, &hc->summermode, DeviceValueType::BOOL, nullptr, FL_(summermode), DeviceValueUOM::BOOLEAN);
register_device_value(tag, &hc->holidaymode, DeviceValueType::BOOL, nullptr, FL_(holidaymode), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_holiday));
register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT, nullptr, FL_(nofrosttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nofrosttemp));
register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT, nullptr, FL_(roominfluence), DeviceValueUOM::NONE, MAKE_CF_CB(set_roominfluence));
register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, nullptr, FL_(minflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minflowtemp));

View File

@@ -39,7 +39,8 @@ static const __FlashStringHelper * DeviceValueUOM_s[] __attribute__((__aligned__
F_(kb),
F_(seconds),
F_(dbm),
F_(num)
F_(num),
F_(bool)
};
@@ -543,7 +544,7 @@ std::string EMSdevice::get_value_uom(const char * key) {
for (const auto & dv : devicevalues_) {
if (dv.full_name != nullptr) {
if (uuid::read_flash_string(dv.full_name) == p) {
// ignore TIME since "minutes" is already included
// ignore TIME since "minutes" is already added to the string value
if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) {
break;
}
@@ -555,37 +556,34 @@ std::string EMSdevice::get_value_uom(const char * key) {
return std::string{}; // not found
}
// prepare array of device values, as 3 elements serialized (name, value, uom) in array to send to Web UI
// returns number of elements
bool EMSdevice::generate_values_json_web(JsonObject & json) {
// prepare array of device values used for the Web UI
// v = value, u=uom, n=name, c=cmd
void EMSdevice::generate_values_json_web(JsonObject & json) {
json["name"] = to_string_short();
JsonArray data = json.createNestedArray("data");
uint8_t num_elements = 0;
for (const auto & dv : devicevalues_) {
// ignore if full_name empty
if (dv.full_name != nullptr) {
JsonObject obj; // create the object, if needed
// handle Booleans (true, false)
if ((dv.type == DeviceValueType::BOOL) && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
// see if we have options for the bool's
if (dv.options_size == 2) {
data.add(*(uint8_t *)(dv.value_p) ? dv.options[0] : dv.options[1]);
} else {
// always render booleans as on or off
data.add(*(uint8_t *)(dv.value_p) ? F_(on) : F_(off));
}
obj = data.createNestedObject();
obj["v"] = *(bool *)(dv.value_p);
}
// handle TEXT strings
else if ((dv.type == DeviceValueType::TEXT) && (Helpers::hasValue((char *)(dv.value_p)))) {
data.add((char *)(dv.value_p));
obj = data.createNestedObject();
obj["v"] = (char *)(dv.value_p);
}
// handle ENUMs
else if ((dv.type == DeviceValueType::ENUM) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) {
if (*(uint8_t *)(dv.value_p) < dv.options_size) {
data.add(dv.options[*(uint8_t *)(dv.value_p)]);
obj = data.createNestedObject();
obj["v"] = dv.options[*(uint8_t *)(dv.value_p)];
}
}
@@ -596,83 +594,55 @@ bool EMSdevice::generate_values_json_web(JsonObject & json) {
// the nested if's is necessary due to the way the ArduinoJson templates are pre-processed by the compiler
uint8_t divider = (dv.options_size == 1) ? Helpers::atoint(uuid::read_flash_string(dv.options[0]).c_str()) : 0;
// INT
if ((dv.type == DeviceValueType::INT) && Helpers::hasValue(*(int8_t *)(dv.value_p))) {
if (divider) {
data.add(Helpers::round2(*(int8_t *)(dv.value_p), divider));
} else {
data.add(*(int8_t *)(dv.value_p));
}
obj = data.createNestedObject();
obj["v"] = (divider) ? Helpers::round2(*(int8_t *)(dv.value_p), divider) : *(int8_t *)(dv.value_p);
} else if ((dv.type == DeviceValueType::UINT) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) {
if (divider) {
data.add(Helpers::round2(*(uint8_t *)(dv.value_p), divider));
} else {
data.add(*(uint8_t *)(dv.value_p));
}
obj = data.createNestedObject();
obj["v"] = (divider) ? Helpers::round2(*(uint8_t *)(dv.value_p), divider) : *(uint8_t *)(dv.value_p);
} else if ((dv.type == DeviceValueType::SHORT) && Helpers::hasValue(*(int16_t *)(dv.value_p))) {
if (divider) {
data.add(Helpers::round2(*(int16_t *)(dv.value_p), divider));
} else {
data.add(*(int16_t *)(dv.value_p));
}
obj = data.createNestedObject();
obj["v"] = (divider) ? Helpers::round2(*(int16_t *)(dv.value_p), divider) : *(int16_t *)(dv.value_p);
} else if ((dv.type == DeviceValueType::USHORT) && Helpers::hasValue(*(uint16_t *)(dv.value_p))) {
if (divider) {
data.add(Helpers::round2(*(uint16_t *)(dv.value_p), divider));
} else {
data.add(*(uint16_t *)(dv.value_p));
}
obj = data.createNestedObject();
obj["v"] = (divider) ? Helpers::round2(*(uint16_t *)(dv.value_p), divider) : *(uint16_t *)(dv.value_p);
} else if ((dv.type == DeviceValueType::ULONG) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) {
if (divider) {
data.add(Helpers::round2(*(uint32_t *)(dv.value_p), divider));
} else {
data.add(*(uint32_t *)(dv.value_p));
}
obj = data.createNestedObject();
obj["v"] = (divider) ? Helpers::round2(*(uint32_t *)(dv.value_p), divider) : *(uint32_t *)(dv.value_p);
} else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) {
uint32_t time_value = *(uint32_t *)(dv.value_p);
time_value = (divider) ? time_value / divider : time_value; // sometimes we need to divide by 60
char time_s[40];
snprintf_P(time_s, 40, PSTR("%d days %d hours %d minutes"), (time_value / 1440), ((time_value % 1440) / 60), (time_value % 60));
data.add(time_s);
obj = data.createNestedObject();
obj["v"] = (divider) ? time_value / divider : time_value; // sometimes we need to divide by 60
}
}
// check if we've added a data element by comparing the size
// then add the remaining elements
uint8_t sz = data.size();
if (sz > num_elements) {
// check if we've added a data element then add the remaining elements
if (obj.containsKey("v")) {
// add the unit of measure (uom)
if (dv.uom == DeviceValueUOM::MINUTES) {
data.add(nullptr); // use null for time/date
} else {
data.add(uom_to_string(dv.uom));
}
obj["u"] = dv.uom;
// add name, prefixing the tag if it exists
if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) {
data.add(dv.full_name);
obj["n"] = dv.full_name;
} else {
char name[50];
snprintf_P(name, sizeof(name), "(%s) %s", tag_to_string(dv.tag).c_str(), uuid::read_flash_string(dv.full_name).c_str());
data.add(name);
obj["n"] = name;
}
// add the name of the Command function if it exists
if (dv.has_cmd) {
if (dv.tag >= DeviceValueTAG::TAG_HC1) {
data.add(tag_to_string(dv.tag) + "/" + uuid::read_flash_string(dv.short_name));
obj["c"] = tag_to_string(dv.tag) + "/" + uuid::read_flash_string(dv.short_name);
} else {
data.add(dv.short_name);
obj["c"] = dv.short_name;
}
} else {
data.add("");
}
num_elements = sz + 3; // increase count by 3
obj["c"] = "";
}
}
}
}
return (num_elements != 0);
}
bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t id) {
@@ -778,9 +748,7 @@ bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t
break;
case DeviceValueType::BOOL: {
if (Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
if (dv.options_size == 2) {
json[value] = (bool)(*(uint8_t *)(dv.value_p)) ? dv.options[0] : dv.options[1];
} else if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF) {
if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF) {
json[value] = (bool)(*(uint8_t *)(dv.value_p)) ? F_(on) : F_(off);
} else if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF_CAP) {
json[value] = (bool)(*(uint8_t *)(dv.value_p)) ? F_(ON) : F_(OFF);
@@ -794,10 +762,8 @@ bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t
json[min] = 0;
json[max] = 1;
JsonArray enum_ = json.createNestedArray(F_(enum));
if (dv.options_size == 2) {
enum_.add(dv.options[1]);
enum_.add(dv.options[0]);
} else if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF) {
if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF) {
enum_.add(F_(off));
enum_.add(F_(on));
} else if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF_CAP) {
@@ -885,11 +851,6 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter
// handle Booleans (true, false)
if ((dv.type == DeviceValueType::BOOL) && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
// see if we have options for the bool's
if (dv.options_size == 2 && Mqtt::bool_format() != BOOL_FORMAT_10) {
json[name] = *(uint8_t *)(dv.value_p) ? dv.options[0] : dv.options[1];
has_value = true;
} else {
// see how to render the value depending on the setting
// when in console mode we always use on and off
if ((Mqtt::bool_format() == BOOL_FORMAT_ONOFF) || console) {
@@ -909,7 +870,7 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter
json[name] = (uint8_t)(*(uint8_t *)(dv.value_p)) ? 1 : 0;
has_value = true;
}
}
}
// handle TEXT strings

View File

@@ -48,22 +48,23 @@ enum DeviceValueType : uint8_t {
// sequence is important!
enum DeviceValueUOM : uint8_t {
NONE = 0,
DEGREES,
PERCENT,
LMIN,
KWH,
WH,
HOURS,
MINUTES,
UA,
BAR,
KW,
W,
KB,
SECONDS,
DBM,
NUM
NONE = 0, // 0
DEGREES, // 1
PERCENT, // 2
LMIN, // 3
KWH, // 4
WH, // 5
HOURS, // 6
MINUTES, // 7
UA, // 8
BAR, // 9
KW, // 10
W, // 11
KB, // 12
SECONDS, // 13
DBM, // 14
NUM, // 15
BOOLEAN // 16
};
@@ -244,7 +245,7 @@ class EMSdevice {
std::string get_value_uom(const char * key);
bool get_value_info(JsonObject & root, const char * cmd, const int8_t id);
bool generate_values_json(JsonObject & json, const uint8_t tag_filter, const bool nested, const bool console = false);
bool generate_values_json_web(JsonObject & json);
void generate_values_json_web(JsonObject & json);
void register_device_value(uint8_t tag,
void * value_p,

View File

@@ -172,6 +172,7 @@ MAKE_PSTR(kb, "KB")
MAKE_PSTR(seconds, "seconds")
MAKE_PSTR(dbm, "dBm")
MAKE_PSTR(num, " ") // this is hack so HA renders numbers correctly
MAKE_PSTR(bool, " ") // this is hack so HA renders numbers correctly
// TAG mapping - maps to DeviceValueTAG_s in emsdevice.cpp
// use empty string if want to suppress showing tags
@@ -220,7 +221,7 @@ MAKE_PSTR_WORD(3x3min)
MAKE_PSTR_WORD(4x3min)
MAKE_PSTR_WORD(5x3min)
MAKE_PSTR_WORD(6x3min)
MAKE_PSTR_WORD(continuos)
MAKE_PSTR_WORD(continuous)
MAKE_PSTR(3wayvalve, "3-way valve")
MAKE_PSTR(chargepump, "charge pump")
MAKE_PSTR_WORD(hot)
@@ -235,7 +236,7 @@ MAKE_PSTR_WORD(error)
// boiler lists
MAKE_PSTR_LIST(enum_off_time_date, F_(off), F_(time), F_(date))
MAKE_PSTR_LIST(enum_freq, F_(off), F_(1x3min), F_(2x3min), F_(3x3min), F_(4x3min), F_(5x3min), F_(6x3min), F_(continuos))
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_(3wayvalve), F_(chargepump))
MAKE_PSTR_LIST(enum_comfort, F_(hot), F_(eco), F_(intelligent))
MAKE_PSTR_LIST(enum_flow, F_(off), F_(flow), F_(bufferedflow), F_(buffer), F_(layeredbuffer))

View File

@@ -333,29 +333,30 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
run_test("boiler");
run_test("thermostat");
// test call
DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE_DYN);
JsonObject json = doc.to<JsonObject>();
Command::call(EMSdevice::DeviceType::BOILER, "info", nullptr, -1, json);
#if defined(EMSESP_STANDALONE)
DynamicJsonDocument doc(8000); // some absurb high number
for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice) {
doc.clear();
JsonObject json = doc.to<JsonObject>();
Command::call(emsdevice->device_type(), "info", nullptr, -1, json);
Serial.print(COLOR_YELLOW);
if (json.size() != 0) {
serializeJson(doc, Serial);
}
shell.println();
Serial.print(COLOR_RESET);
#endif
for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice) {
DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE_DYN);
doc.clear();
JsonObject root = doc.to<JsonObject>();
emsdevice->generate_values_json_web(root);
#if defined(EMSESP_STANDALONE)
Serial.print(COLOR_BRIGHT_MAGENTA);
serializeJson(doc, Serial);
Serial.print(COLOR_RESET);
Serial.println();
Serial.print("** memoryUsage=");
Serial.print(doc.memoryUsage());
@@ -364,10 +365,9 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
Serial.print(" measureJson=");
Serial.print(measureJson(doc));
Serial.println(" **");
Serial.print(COLOR_RESET);
}
}
#endif
}
}
return;
}

View File

@@ -29,8 +29,8 @@ namespace emsesp {
// #define EMSESP_DEBUG_DEFAULT "thermostat"
// #define EMSESP_DEBUG_DEFAULT "solar"
// #define EMSESP_DEBUG_DEFAULT "mixer"
// #define EMSESP_DEBUG_DEFAULT "web"
#define EMSESP_DEBUG_DEFAULT "general"
#define EMSESP_DEBUG_DEFAULT "web"
// #define EMSESP_DEBUG_DEFAULT "general"
// #define EMSESP_DEBUG_DEFAULT "boiler"
// #define EMSESP_DEBUG_DEFAULT "mqtt2"
// #define EMSESP_DEBUG_DEFAULT "mqtt_nested"

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.1.1b4"
#define EMSESP_APP_VERSION "3.1.1b5"