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 ## Fixed
- HA thermostat mode was not in sync with actual mode [#66](https://github.com/emsesp/EMS-ESP32/issues/66) - 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 ## 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` - `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 - 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) - 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 ## Removed

View File

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

View File

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

View File

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

View File

@@ -58,15 +58,54 @@ export interface EMSESPDevices {
sensors: Sensor[]; sensors: Sensor[];
} }
export interface EMSESPDeviceData { export interface DeviceValue {
name: string; v: any;
data: string[]; u: number;
n: string;
c: string;
} }
export interface DeviceValue { export interface EMSESPDeviceData {
id: number;
data: string;
uom: string;
name: string; 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 Async Response to use with ArduinoJson and AsyncWebServer
Written by Andrew Melvin (SticilFace) with help from me-no-dev and BBlanchon. 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_ #ifndef ASYNC_JSON_H_
#define ASYNC_JSON_H_ #define ASYNC_JSON_H_
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <Print.h> #include <Print.h>
#if ARDUINOJSON_VERSION_MAJOR == 5
#define ARDUINOJSON_5_COMPATIBILITY
#else
#define DYNAMIC_JSON_DOCUMENT_SIZE 1024 #define DYNAMIC_JSON_DOCUMENT_SIZE 1024
#endif
constexpr const char * JSON_MIMETYPE = "application/json"; constexpr const char * JSON_MIMETYPE = "application/json";
/* /*
* Json Response * Json Response
* */ */
class ChunkPrint : public Print { class ChunkPrint : public Print {
private: private:
@@ -82,30 +50,14 @@ class ChunkPrint : public Print {
} }
}; };
class AsyncJsonResponse : public AsyncAbstractResponse { class MsgpackAsyncJsonResponse : public AsyncAbstractResponse {
protected: protected:
#ifdef ARDUINOJSON_5_COMPATIBILITY
DynamicJsonBuffer _jsonBuffer;
#else
DynamicJsonDocument _jsonBuffer; DynamicJsonDocument _jsonBuffer;
#endif JsonVariant _root;
bool _isValid;
JsonVariant _root;
bool _isValid;
public: public:
#ifdef ARDUINOJSON_5_COMPATIBILITY MsgpackAsyncJsonResponse(bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
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)
: _jsonBuffer(maxJsonBufferSize) : _jsonBuffer(maxJsonBufferSize)
, _isValid{false} { , _isValid{false} {
_code = 200; _code = 200;
@@ -115,9 +67,8 @@ class AsyncJsonResponse : public AsyncAbstractResponse {
else else
_root = _jsonBuffer.createNestedObject(); _root = _jsonBuffer.createNestedObject();
} }
#endif
~AsyncJsonResponse() { ~MsgpackAsyncJsonResponse() {
} }
JsonVariant & getRoot() { JsonVariant & getRoot() {
return _root; return _root;
@@ -126,12 +77,7 @@ class AsyncJsonResponse : public AsyncAbstractResponse {
return _isValid; return _isValid;
} }
size_t setLength() { size_t setLength() {
#ifdef ARDUINOJSON_5_COMPATIBILITY _contentLength = measureMsgPack(_root);
_contentLength = _root.measureLength();
#else
_contentLength = measureJson(_root);
#endif
if (_contentLength) { if (_contentLength) {
_isValid = true; _isValid = true;
} }
@@ -144,33 +90,66 @@ class AsyncJsonResponse : public AsyncAbstractResponse {
size_t _fillBuffer(uint8_t * data, size_t len) { size_t _fillBuffer(uint8_t * data, size_t len) {
ChunkPrint dest(data, _sentLength, len); ChunkPrint dest(data, _sentLength, len);
serializeMsgPack(_root, dest);
// serializeJson(_root, Serial); // for testing proddy
// Serial.println();
return len;
}
};
#ifdef ARDUINOJSON_5_COMPATIBILITY class AsyncJsonResponse : public AsyncAbstractResponse {
_root.printTo(dest); protected:
#else 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); serializeJson(_root, dest);
#endif
return len; return len;
} }
}; };
class PrettyAsyncJsonResponse : public AsyncJsonResponse { class PrettyAsyncJsonResponse : public AsyncJsonResponse {
public: public:
#ifdef ARDUINOJSON_5_COMPATIBILITY
PrettyAsyncJsonResponse(bool isArray = false)
: AsyncJsonResponse{isArray} {
}
#else
PrettyAsyncJsonResponse(bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE) PrettyAsyncJsonResponse(bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
: AsyncJsonResponse{isArray, maxJsonBufferSize} { : AsyncJsonResponse{isArray, maxJsonBufferSize} {
} }
#endif
size_t setLength() { size_t setLength() {
#ifdef ARDUINOJSON_5_COMPATIBILITY
_contentLength = _root.measurePrettyLength();
#else
_contentLength = measureJsonPretty(_root); _contentLength = measureJsonPretty(_root);
#endif
if (_contentLength) { if (_contentLength) {
_isValid = true; _isValid = true;
} }
@@ -178,13 +157,9 @@ class PrettyAsyncJsonResponse : public AsyncJsonResponse {
} }
size_t _fillBuffer(uint8_t * data, size_t len) { size_t _fillBuffer(uint8_t * data, size_t len) {
ChunkPrint dest(data, _sentLength, len); ChunkPrint dest(data, _sentLength, len);
#ifdef ARDUINOJSON_5_COMPATIBILITY
_root.prettyPrintTo(dest);
#else
serializeJsonPretty(_root, dest); serializeJsonPretty(_root, dest);
// serializeJson(_root, Serial); // for testing // serializeJson(_root, Serial); // for testing proddy
// Serial.println(); // Serial.println();
#endif
return len; return len;
} }
}; };
@@ -204,14 +179,6 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
size_t _maxContentLength; size_t _maxContentLength;
public: 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) AsyncCallbackJsonWebHandler(const String & uri, ArJsonRequestHandlerFunction onRequest, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
: _uri(uri) : _uri(uri)
, _method(HTTP_POST | HTTP_PUT | HTTP_PATCH) , _method(HTTP_POST | HTTP_PUT | HTTP_PATCH)
@@ -219,7 +186,6 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
, maxJsonBufferSize(maxJsonBufferSize) , maxJsonBufferSize(maxJsonBufferSize)
, _maxContentLength(16384) { , _maxContentLength(16384) {
} }
#endif
void setMethod(WebRequestMethodComposite method) { void setMethod(WebRequestMethodComposite method) {
_method = method; _method = method;
@@ -251,17 +217,10 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
virtual void handleRequest(AsyncWebServerRequest * request) override final { virtual void handleRequest(AsyncWebServerRequest * request) override final {
if (_onRequest) { if (_onRequest) {
if (request->_tempObject != NULL) { 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); DynamicJsonDocument jsonBuffer(this->maxJsonBufferSize);
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t *)(request->_tempObject)); DeserializationError error = deserializeJson(jsonBuffer, (uint8_t *)(request->_tempObject));
if (!error) { if (!error) {
JsonVariant json = jsonBuffer.as<JsonVariant>(); JsonVariant json = jsonBuffer.as<JsonVariant>();
#endif
_onRequest(request, json); _onRequest(request, json);
return; return;
} }
@@ -288,4 +247,5 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
return _onRequest ? false : true; return _onRequest ? false : true;
} }
}; };
#endif #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 { class AsyncJsonResponse {
protected: protected:
DynamicJsonDocument _jsonBuffer; DynamicJsonDocument _jsonBuffer;

View File

@@ -12,6 +12,7 @@ class AsyncWebServerRequest;
class AsyncWebServerResponse; class AsyncWebServerResponse;
class AsyncJsonResponse; class AsyncJsonResponse;
class PrettyAsyncJsonResponse; class PrettyAsyncJsonResponse;
class MsgpackAsyncJsonResponse;
class AsyncWebParameter { class AsyncWebParameter {
private: private:
@@ -98,6 +99,7 @@ class AsyncWebServerRequest {
void send(AsyncWebServerResponse * response){}; void send(AsyncWebServerResponse * response){};
void send(AsyncJsonResponse * response){}; void send(AsyncJsonResponse * response){};
void send(PrettyAsyncJsonResponse * 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 = String(), const String & content = String()){};
void send(int code, const String & contentType, const __FlashStringHelper *){}; void send(int code, const String & contentType, const __FlashStringHelper *){};
@@ -194,9 +196,9 @@ class AsyncWebServerResponse {
virtual ~AsyncWebServerResponse(); virtual ~AsyncWebServerResponse();
}; };
typedef std::function<void(AsyncWebServerRequest * request)> ArRequestHandlerFunction; typedef std::function<void(AsyncWebServerRequest * request)> ArRequestHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final)> ArUploadHandlerFunction; typedef std::function<void(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final)> ArUploadHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, uint8_t * data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction; typedef std::function<void(AsyncWebServerRequest * request, uint8_t * data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction;
class AsyncWebServer { class AsyncWebServer {
protected: protected:

View File

@@ -9,10 +9,19 @@
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@msgpack/msgpack": "^2.7.0",
"express": "^4.17.1", "express": "^4.17.1",
"nodemon": "^2.0.7" "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": { "node_modules/@sindresorhus/is": {
"version": "0.14.0", "version": "0.14.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
@@ -1593,6 +1602,11 @@
} }
}, },
"dependencies": { "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": { "@sindresorhus/is": {
"version": "0.14.0", "version": "0.14.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",

View File

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

View File

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

View File

@@ -26,7 +26,7 @@ WebDevicesService::WebDevicesService(AsyncWebServer * server, SecurityManager *
: _device_dataHandler(DEVICE_DATA_SERVICE_PATH, : _device_dataHandler(DEVICE_DATA_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDevicesService::device_data, this, _1, _2), AuthenticationPredicates::IS_AUTHENTICATED)) securityManager->wrapCallback(std::bind(&WebDevicesService::device_data, this, _1, _2), AuthenticationPredicates::IS_AUTHENTICATED))
, _writevalue_dataHandler(WRITE_VALUE_SERVICE_PATH, , _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, server->on(EMSESP_DEVICES_SERVICE_PATH,
HTTP_GET, HTTP_GET,
securityManager->wrapRequest(std::bind(&WebDevicesService::all_devices, this, _1), AuthenticationPredicates::IS_AUTHENTICATED)); 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 // 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) { void WebDevicesService::device_data(AsyncWebServerRequest * request, JsonVariant & json) {
if (json.is<JsonObject>()) { 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) { for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice) { if (emsdevice) {
if (emsdevice->unique_id() == json["id"]) { 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 // takes a command and its data value from a specific Device, from the Web
void WebDevicesService::write_value(AsyncWebServerRequest * request, JsonVariant & json) { 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>()) { if (json.is<JsonObject>()) {
JsonObject dv = json["devicevalue"]; JsonObject dv = json["devicevalue"];
uint8_t id = json["id"];
// using the unique ID from the web find the real device type // using the unique ID from the web find the real device type
for (const auto & emsdevice : EMSESP::emsdevices) { for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice) { if (emsdevice) {
if (emsdevice->unique_id() == dv["id"].as<int>()) { if (emsdevice->unique_id() == id) {
const char * cmd = dv["cmd"]; const char * cmd = dv["c"];
uint8_t device_type = emsdevice->device_type(); uint8_t device_type = emsdevice->device_type();
bool ok = false; bool ok = false;
char s[10]; char s[10];
// the data could be in any format, but we need string // the data could be in any format, but we need string
JsonVariant data = dv["data"]; JsonVariant data = dv["v"];
if (data.is<const char *>()) { if (data.is<const char *>()) {
ok = Command::call(device_type, cmd, data.as<const char *>()); ok = Command::call(device_type, cmd, data.as<const char *>());
} else if (data.is<int>()) { } 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"); ok = Command::call(device_type, cmd, data.as<bool>() ? "true" : "false");
} }
if (ok) { // send "Write command sent to device" or "Write command failed"
request->send(200); AsyncWebServerResponse * response = request->beginResponse(ok ? 200 : 204);
} request->send(response);
return; // found device, quit return;
} }
} }
} }
request->send(204); // no content error
} }
AsyncWebServerResponse * response = request->beginResponse(204); // Write command failed
request->send(response);
} }
} // namespace emsesp } // 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 // MQTT commands for boiler topic
register_device_value( 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)); register_device_value(TAG_BOILER_DATA, &dummy8u_, DeviceValueType::ENUM, FL_(enum_reset), FL_(reset), DeviceValueUOM::NONE, MAKE_CF_CB(set_reset));
// add values // 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); register_device_value(TAG_BOILER_DATA, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE);
id_ = product_id; id_ = product_id;
register_device_value(TAG_BOILER_DATA, &heatingActive_, DeviceValueType::BOOL, nullptr, FL_(heatingActive), 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::NONE); 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, &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, &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); 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, &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, &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, &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, &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, &heatingPump_, DeviceValueType::BOOL, nullptr, FL_(heatingPump), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA, &fanWork_, DeviceValueType::BOOL, nullptr, FL_(fanWork), DeviceValueUOM::NONE); 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::NONE); register_device_value(TAG_BOILER_DATA, &ignWork_, DeviceValueType::BOOL, nullptr, FL_(ignWork), DeviceValueUOM::BOOLEAN);
register_device_value( 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, &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, &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)); 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( register_device_value(
TAG_DEVICE_DATA_WW, &wWMaxPower_, DeviceValueType::UINT, nullptr, FL_(wWMaxPower), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_warmwater_maxpower)); TAG_DEVICE_DATA_WW, &wWMaxPower_, DeviceValueType::UINT, nullptr, FL_(wWMaxPower), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_warmwater_maxpower));
register_device_value( register_device_value(
TAG_DEVICE_DATA_WW, &wWCircPump_, DeviceValueType::BOOL, nullptr, FL_(wWCircPump), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_circulation_pump)); 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::BOOL, FL_(enum_charge), FL_(wWChargeType), DeviceValueUOM::NONE); register_device_value(TAG_DEVICE_DATA_WW, &wWChargeType_, DeviceValueType::ENUM, FL_(enum_charge), FL_(wWChargeType), DeviceValueUOM::NONE);
register_device_value(TAG_DEVICE_DATA_WW, register_device_value(TAG_DEVICE_DATA_WW,
&wWDisinfectionTemp_, &wWDisinfectionTemp_,
DeviceValueType::UINT, DeviceValueType::UINT,
@@ -206,21 +206,21 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
FL_(wWCircMode), FL_(wWCircMode),
DeviceValueUOM::NONE, DeviceValueUOM::NONE,
MAKE_CF_CB(set_warmwater_circulation_mode)); 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, &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, &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, &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, &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, &wWStorageTemp2_, DeviceValueType::USHORT, FL_(div10), FL_(wWStorageTemp2), DeviceValueUOM::DEGREES);
register_device_value( register_device_value(
TAG_DEVICE_DATA_WW, &wWActivated_, DeviceValueType::BOOL, nullptr, FL_(wWActivated), DeviceValueUOM::NONE, MAKE_CF_CB(set_warmwater_activated)); 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::NONE, MAKE_CF_CB(set_warmwater_onetime)); 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::NONE); 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::NONE); 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::NONE); 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::NONE); 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::NONE); 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::NONE); 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, &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, &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); 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 // 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) { 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_bitvalue(wwEquipt_,0,3)); // 8=boiler has ww
has_update(telegram->read_value(wWActivated_, 1)); // 0xFF means on 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(wWCircPump_, 6)); // 0xFF means on
has_update(telegram->read_value(wWCircMode_, 7)); // 1=1x3min 6=6x3min 7=continuous 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(wWDisinfectionTemp_, 8));
has_update(telegram->read_value(wWChargeType_, has_update(telegram->read_bitvalue(wWChargeType_, 10, 0)); // 0 = charge pump, 0xff = 3-way valve
10)); // 0 = charge pump, 0xff = 3-way valve
telegram->read_value(wWComfort_, 9); telegram->read_value(wWComfort_, 9);
if (wWComfort_ == 0x00) { if (wWComfort_ == 0x00) {
@@ -1175,7 +1173,7 @@ bool Boiler::set_warmwater_circulation_pump(const char * value, const int8_t id)
return true; return true;
} }
// Set the mode of circulation, 1x3min, ... 6x3min, continuos // Set the mode of circulation, 1x3min, ... 6x3min, continuous
// true = on, false = off // true = on, false = off
bool Boiler::set_warmwater_circulation_mode(const char * value, const int8_t id) { bool Boiler::set_warmwater_circulation_mode(const char * value, const int8_t id) {
int v = 0; int v = 0;
@@ -1187,7 +1185,7 @@ bool Boiler::set_warmwater_circulation_mode(const char * value, const int8_t id)
if (v < 7) { if (v < 7) {
LOG_INFO(F("Setting warm water circulation mode %dx3min"), v); LOG_INFO(F("Setting warm water circulation mode %dx3min"), v);
} else if (v == 7) { } else if (v == 7) {
LOG_INFO(F("Setting warm water circulation mode continuos")); LOG_INFO(F("Setting warm water circulation mode continuous"));
} else { } else {
LOG_WARNING(F("Set warm water circulation mode: Invalid value")); LOG_WARNING(F("Set warm water circulation mode: Invalid value"));
return false; 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, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE);
register_device_value(tag, &flowSetTemp_, DeviceValueType::UINT, nullptr, FL_(flowSetTemp), DeviceValueUOM::DEGREES); 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, &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, &status_, DeviceValueType::INT, nullptr, FL_(mixerStatus), DeviceValueUOM::PERCENT);
register_device_value(tag, &flowTempVf_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempVf), DeviceValueUOM::DEGREES); register_device_value(tag, &flowTempVf_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempVf), DeviceValueUOM::DEGREES);
} else { } 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; uint8_t tag = TAG_WWC1 + hc_ - 1;
register_device_value(tag, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE); 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, &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); 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, &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, &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, &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)); 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) { 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, &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(TAG_NONE, &solarPumpMinMod_, DeviceValueType::UINT, nullptr, FL_(pumpMinMod), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_PumpMinMod));
register_device_value( 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)); TAG_NONE, &collectorMaxTemp_, DeviceValueType::UINT, nullptr, FL_(collectorMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_CollectorMaxTemp));
register_device_value( register_device_value(
TAG_NONE, &collectorMinTemp_, DeviceValueType::UINT, nullptr, FL_(collectorMinTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_CollectorMinTemp)); 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, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::BOOLEAN);
// register_device_value(TAG_NONE, &tankHeated_, DeviceValueType::BOOL, nullptr, FL_(tankHeated), DeviceValueUOM::NONE);
register_device_value(TAG_NONE, &solarPower_, DeviceValueType::ULONG, nullptr, FL_(solarPower), DeviceValueUOM::W); 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, &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_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_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) { 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, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_NONE, &tankHeated_, DeviceValueType::BOOL, nullptr, FL_(tankHeated), DeviceValueUOM::NONE); 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); register_device_value(TAG_NONE, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH);
} }
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) { 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, &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, &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, &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, &valveStatus_, DeviceValueType::BOOL, nullptr, FL_(valveStatus), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_NONE, &tankHeated_, DeviceValueType::BOOL, nullptr, FL_(tankHeated), DeviceValueUOM::NONE); 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::NONE); register_device_value(TAG_NONE, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::BOOLEAN);
register_device_value( register_device_value(
TAG_NONE, &collectorMaxTemp_, DeviceValueType::UINT, nullptr, FL_(collectorMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_CollectorMaxTemp)); TAG_NONE, &collectorMaxTemp_, DeviceValueType::UINT, nullptr, FL_(collectorMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_CollectorMaxTemp));
register_device_value( 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, &energyTotal_, DeviceValueType::ULONG, FL_(div10), FL_(energyTotal), DeviceValueUOM::KWH);
register_device_value( register_device_value(
TAG_NONE, &heatTransferSystem_, DeviceValueType::BOOL, nullptr, FL_(heatTransferSystem), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatTransferSystem)); 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::NONE, MAKE_CF_CB(set_externalTank)); register_device_value(TAG_NONE, &externalTank_, DeviceValueType::BOOL, nullptr, FL_(externalTank), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_externalTank));
register_device_value( register_device_value(
TAG_NONE, &thermalDisinfect_, DeviceValueType::BOOL, nullptr, FL_(thermalDisinfect), DeviceValueUOM::NONE, MAKE_CF_CB(set_thermalDisinfect)); 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::NONE, MAKE_CF_CB(set_heatMetering)); 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::NONE, MAKE_CF_CB(set_solarEnabled)); register_device_value(TAG_NONE, &solarIsEnabled_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_solarEnabled));
// telegram 0x035A // telegram 0x035A
register_device_value( 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, DeviceValueType::BOOL,
nullptr, nullptr,
FL_(solarPumpKick), FL_(solarPumpKick),
DeviceValueUOM::NONE, DeviceValueUOM::BOOLEAN,
MAKE_CF_CB(set_solarPumpKick)); // pump kick for vacuum collector, 00=off MAKE_CF_CB(set_solarPumpKick)); // pump kick for vacuum collector, 00=off
register_device_value(TAG_NONE, register_device_value(TAG_NONE,
&plainWaterMode_, &plainWaterMode_,
DeviceValueType::BOOL, DeviceValueType::BOOL,
nullptr, nullptr,
FL_(plainWaterMode), FL_(plainWaterMode),
DeviceValueUOM::NONE, DeviceValueUOM::BOOLEAN,
MAKE_CF_CB(set_plainWaterMode)); // system does not use antifreeze, 00=off MAKE_CF_CB(set_plainWaterMode)); // system does not use antifreeze, 00=off
register_device_value(TAG_NONE, register_device_value(TAG_NONE,
&doubleMatchFlow_, &doubleMatchFlow_,
DeviceValueType::BOOL, DeviceValueType::BOOL,
nullptr, nullptr,
FL_(doubleMatchFlow), FL_(doubleMatchFlow),
DeviceValueUOM::NONE, DeviceValueUOM::BOOLEAN,
MAKE_CF_CB(set_doubleMatchFlow)); // double Match Flow, 00=off MAKE_CF_CB(set_doubleMatchFlow)); // double Match Flow, 00=off
// telegram 0x380 // 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_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, &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, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempHc), DeviceValueUOM::DEGREES);
register_device_value(TAG_NONE, &status_, DeviceValueType::INT, nullptr, FL_(status), DeviceValueUOM::NONE); register_device_value(TAG_NONE, &status_, DeviceValueType::INT, nullptr, FL_(status), DeviceValueUOM::NONE);
id_ = product_id; 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->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::NONE);
register_device_value( register_device_value(
tag, &hc->summer_setmode, DeviceValueType::ENUM, FL_(enum_summermode), FL_(summermode), DeviceValueUOM::NONE, MAKE_CF_CB(set_summermode)); 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( register_device_value(
tag, &hc->controlmode, DeviceValueType::ENUM, FL_(enum_controlmode), FL_(controlmode), DeviceValueUOM::NONE, MAKE_CF_CB(set_controlmode)); 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)); 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->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->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->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->summermode, DeviceValueType::BOOL, nullptr, FL_(summermode), DeviceValueUOM::BOOLEAN);
register_device_value(tag, &hc->holidaymode, DeviceValueType::BOOL, nullptr, FL_(holidaymode), DeviceValueUOM::NONE, MAKE_CF_CB(set_holiday)); 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->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->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)); 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_(kb),
F_(seconds), F_(seconds),
F_(dbm), 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_) { for (const auto & dv : devicevalues_) {
if (dv.full_name != nullptr) { if (dv.full_name != nullptr) {
if (uuid::read_flash_string(dv.full_name) == p) { 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)) { if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) {
break; break;
} }
@@ -555,37 +556,34 @@ std::string EMSdevice::get_value_uom(const char * key) {
return std::string{}; // not found return std::string{}; // not found
} }
// prepare array of device values, as 3 elements serialized (name, value, uom) in array to send to Web UI // prepare array of device values used for the Web UI
// returns number of elements // v = value, u=uom, n=name, c=cmd
bool EMSdevice::generate_values_json_web(JsonObject & json) { void EMSdevice::generate_values_json_web(JsonObject & json) {
json["name"] = to_string_short(); json["name"] = to_string_short();
JsonArray data = json.createNestedArray("data"); JsonArray data = json.createNestedArray("data");
uint8_t num_elements = 0;
for (const auto & dv : devicevalues_) { for (const auto & dv : devicevalues_) {
// ignore if full_name empty // ignore if full_name empty
if (dv.full_name != nullptr) { if (dv.full_name != nullptr) {
JsonObject obj; // create the object, if needed
// handle Booleans (true, false) // handle Booleans (true, false)
if ((dv.type == DeviceValueType::BOOL) && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) { if ((dv.type == DeviceValueType::BOOL) && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
// see if we have options for the bool's obj = data.createNestedObject();
if (dv.options_size == 2) { obj["v"] = *(bool *)(dv.value_p);
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));
}
} }
// handle TEXT strings // handle TEXT strings
else if ((dv.type == DeviceValueType::TEXT) && (Helpers::hasValue((char *)(dv.value_p)))) { 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 // handle ENUMs
else if ((dv.type == DeviceValueType::ENUM) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) { else if ((dv.type == DeviceValueType::ENUM) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) {
if (*(uint8_t *)(dv.value_p) < dv.options_size) { 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 // 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; 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 ((dv.type == DeviceValueType::INT) && Helpers::hasValue(*(int8_t *)(dv.value_p))) {
if (divider) { obj = data.createNestedObject();
data.add(Helpers::round2(*(int8_t *)(dv.value_p), divider)); obj["v"] = (divider) ? Helpers::round2(*(int8_t *)(dv.value_p), divider) : *(int8_t *)(dv.value_p);
} else {
data.add(*(int8_t *)(dv.value_p));
}
} else if ((dv.type == DeviceValueType::UINT) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) { } else if ((dv.type == DeviceValueType::UINT) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) {
if (divider) { obj = data.createNestedObject();
data.add(Helpers::round2(*(uint8_t *)(dv.value_p), divider)); obj["v"] = (divider) ? Helpers::round2(*(uint8_t *)(dv.value_p), divider) : *(uint8_t *)(dv.value_p);
} else {
data.add(*(uint8_t *)(dv.value_p));
}
} else if ((dv.type == DeviceValueType::SHORT) && Helpers::hasValue(*(int16_t *)(dv.value_p))) { } else if ((dv.type == DeviceValueType::SHORT) && Helpers::hasValue(*(int16_t *)(dv.value_p))) {
if (divider) { obj = data.createNestedObject();
data.add(Helpers::round2(*(int16_t *)(dv.value_p), divider)); obj["v"] = (divider) ? Helpers::round2(*(int16_t *)(dv.value_p), divider) : *(int16_t *)(dv.value_p);
} else {
data.add(*(int16_t *)(dv.value_p));
}
} else if ((dv.type == DeviceValueType::USHORT) && Helpers::hasValue(*(uint16_t *)(dv.value_p))) { } else if ((dv.type == DeviceValueType::USHORT) && Helpers::hasValue(*(uint16_t *)(dv.value_p))) {
if (divider) { obj = data.createNestedObject();
data.add(Helpers::round2(*(uint16_t *)(dv.value_p), divider)); obj["v"] = (divider) ? Helpers::round2(*(uint16_t *)(dv.value_p), divider) : *(uint16_t *)(dv.value_p);
} else {
data.add(*(uint16_t *)(dv.value_p));
}
} else if ((dv.type == DeviceValueType::ULONG) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { } else if ((dv.type == DeviceValueType::ULONG) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) {
if (divider) { obj = data.createNestedObject();
data.add(Helpers::round2(*(uint32_t *)(dv.value_p), divider)); obj["v"] = (divider) ? Helpers::round2(*(uint32_t *)(dv.value_p), divider) : *(uint32_t *)(dv.value_p);
} else {
data.add(*(uint32_t *)(dv.value_p));
}
} else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { } else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) {
uint32_t time_value = *(uint32_t *)(dv.value_p); uint32_t time_value = *(uint32_t *)(dv.value_p);
time_value = (divider) ? time_value / divider : time_value; // sometimes we need to divide by 60 obj = data.createNestedObject();
char time_s[40]; obj["v"] = (divider) ? time_value / divider : time_value; // sometimes we need to divide by 60
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);
} }
} }
// check if we've added a data element by comparing the size // check if we've added a data element then add the remaining elements
// then add the remaining elements if (obj.containsKey("v")) {
uint8_t sz = data.size();
if (sz > num_elements) {
// add the unit of measure (uom) // add the unit of measure (uom)
if (dv.uom == DeviceValueUOM::MINUTES) { obj["u"] = dv.uom;
data.add(nullptr); // use null for time/date
} else {
data.add(uom_to_string(dv.uom));
}
// add name, prefixing the tag if it exists // add name, prefixing the tag if it exists
if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) { if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) {
data.add(dv.full_name); obj["n"] = dv.full_name;
} else { } else {
char name[50]; 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()); 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 // add the name of the Command function if it exists
if (dv.has_cmd) { if (dv.has_cmd) {
if (dv.tag >= DeviceValueTAG::TAG_HC1) { 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 { } else {
data.add(dv.short_name); obj["c"] = dv.short_name;
} }
} else { } else {
data.add(""); obj["c"] = "";
} }
num_elements = sz + 3; // increase count by 3
} }
} }
} }
return (num_elements != 0);
} }
bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t id) { 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; break;
case DeviceValueType::BOOL: { case DeviceValueType::BOOL: {
if (Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) { if (Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
if (dv.options_size == 2) { if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF) {
json[value] = (bool)(*(uint8_t *)(dv.value_p)) ? dv.options[0] : dv.options[1];
} else if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF) {
json[value] = (bool)(*(uint8_t *)(dv.value_p)) ? F_(on) : F_(off); json[value] = (bool)(*(uint8_t *)(dv.value_p)) ? F_(on) : F_(off);
} else if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF_CAP) { } else if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF_CAP) {
json[value] = (bool)(*(uint8_t *)(dv.value_p)) ? F_(ON) : F_(OFF); 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[min] = 0;
json[max] = 1; json[max] = 1;
JsonArray enum_ = json.createNestedArray(F_(enum)); JsonArray enum_ = json.createNestedArray(F_(enum));
if (dv.options_size == 2) {
enum_.add(dv.options[1]); if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF) {
enum_.add(dv.options[0]);
} else if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF) {
enum_.add(F_(off)); enum_.add(F_(off));
enum_.add(F_(on)); enum_.add(F_(on));
} else if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF_CAP) { } else if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF_CAP) {
@@ -885,31 +851,26 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter
// handle Booleans (true, false) // handle Booleans (true, false)
if ((dv.type == DeviceValueType::BOOL) && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) { if ((dv.type == DeviceValueType::BOOL) && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
// see if we have options for the bool's // see how to render the value depending on the setting
if (dv.options_size == 2 && Mqtt::bool_format() != BOOL_FORMAT_10) { // when in console mode we always use on and off
json[name] = *(uint8_t *)(dv.value_p) ? dv.options[0] : dv.options[1]; if ((Mqtt::bool_format() == BOOL_FORMAT_ONOFF) || console) {
// on or off as strings
json[name] = *(uint8_t *)(dv.value_p) ? F_(on) : F_(off);
has_value = true;
} else if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF_CAP) {
// on or off as strings
json[name] = *(uint8_t *)(dv.value_p) ? F_(ON) : F_(OFF);
has_value = true;
} else if (Mqtt::bool_format() == BOOL_FORMAT_TRUEFALSE) {
// true or false values (as real booleans, not strings)
json[name] = (bool)(*(uint8_t *)(dv.value_p)) ? true : false;
has_value = true; has_value = true;
} else { } else {
// see how to render the value depending on the setting // numerical 1 or 0
// when in console mode we always use on and off json[name] = (uint8_t)(*(uint8_t *)(dv.value_p)) ? 1 : 0;
if ((Mqtt::bool_format() == BOOL_FORMAT_ONOFF) || console) { has_value = true;
// on or off as strings
json[name] = *(uint8_t *)(dv.value_p) ? F_(on) : F_(off);
has_value = true;
} else if (Mqtt::bool_format() == BOOL_FORMAT_ONOFF_CAP) {
// on or off as strings
json[name] = *(uint8_t *)(dv.value_p) ? F_(ON) : F_(OFF);
has_value = true;
} else if (Mqtt::bool_format() == BOOL_FORMAT_TRUEFALSE) {
// true or false values (as real booleans, not strings)
json[name] = (bool)(*(uint8_t *)(dv.value_p)) ? true : false;
has_value = true;
} else {
// numerical 1 or 0
json[name] = (uint8_t)(*(uint8_t *)(dv.value_p)) ? 1 : 0;
has_value = true;
}
} }
} }
// handle TEXT strings // handle TEXT strings

View File

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

View File

@@ -172,6 +172,7 @@ MAKE_PSTR(kb, "KB")
MAKE_PSTR(seconds, "seconds") MAKE_PSTR(seconds, "seconds")
MAKE_PSTR(dbm, "dBm") MAKE_PSTR(dbm, "dBm")
MAKE_PSTR(num, " ") // this is hack so HA renders numbers correctly 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 // TAG mapping - maps to DeviceValueTAG_s in emsdevice.cpp
// use empty string if want to suppress showing tags // use empty string if want to suppress showing tags
@@ -220,7 +221,7 @@ MAKE_PSTR_WORD(3x3min)
MAKE_PSTR_WORD(4x3min) MAKE_PSTR_WORD(4x3min)
MAKE_PSTR_WORD(5x3min) MAKE_PSTR_WORD(5x3min)
MAKE_PSTR_WORD(6x3min) MAKE_PSTR_WORD(6x3min)
MAKE_PSTR_WORD(continuos) MAKE_PSTR_WORD(continuous)
MAKE_PSTR(3wayvalve, "3-way valve") MAKE_PSTR(3wayvalve, "3-way valve")
MAKE_PSTR(chargepump, "charge pump") MAKE_PSTR(chargepump, "charge pump")
MAKE_PSTR_WORD(hot) MAKE_PSTR_WORD(hot)
@@ -235,7 +236,7 @@ MAKE_PSTR_WORD(error)
// boiler lists // boiler lists
MAKE_PSTR_LIST(enum_off_time_date, F_(off), F_(time), F_(date)) 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_charge, F_(3wayvalve), F_(chargepump))
MAKE_PSTR_LIST(enum_comfort, F_(hot), F_(eco), F_(intelligent)) 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)) 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("boiler");
run_test("thermostat"); 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) #if defined(EMSESP_STANDALONE)
Serial.print(COLOR_YELLOW);
if (json.size() != 0) {
serializeJson(doc, Serial);
}
shell.println();
Serial.print(COLOR_RESET);
#endif
DynamicJsonDocument doc(8000); // some absurb high number
for (const auto & emsdevice : EMSESP::emsdevices) { for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice) { if (emsdevice) {
DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE_DYN); 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);
doc.clear();
JsonObject root = doc.to<JsonObject>(); JsonObject root = doc.to<JsonObject>();
emsdevice->generate_values_json_web(root); emsdevice->generate_values_json_web(root);
#if defined(EMSESP_STANDALONE)
Serial.print(COLOR_BRIGHT_MAGENTA); Serial.print(COLOR_BRIGHT_MAGENTA);
serializeJson(doc, Serial); serializeJson(doc, Serial);
Serial.print(COLOR_RESET);
Serial.println(); Serial.println();
Serial.print("** memoryUsage="); Serial.print("** memoryUsage=");
Serial.print(doc.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=");
Serial.print(measureJson(doc)); Serial.print(measureJson(doc));
Serial.println(" **"); Serial.println(" **");
Serial.print(COLOR_RESET);
#endif
} }
} }
#endif
return; return;
} }

View File

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

View File

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