Merge branch 'ft_reacthooks' into dev

This commit is contained in:
proddy
2021-09-21 18:11:55 +02:00
31 changed files with 424 additions and 222 deletions

View File

@@ -22,3 +22,5 @@
- Syslog BOM only for utf-8 messages [#91](https://github.com/emsesp/EMS-ESP32/issues/91) - Syslog BOM only for utf-8 messages [#91](https://github.com/emsesp/EMS-ESP32/issues/91)
- Check for KM200 by device-id 0x48, remove tx-delay[#90](https://github.com/emsesp/EMS-ESP32/issues/90) - Check for KM200 by device-id 0x48, remove tx-delay[#90](https://github.com/emsesp/EMS-ESP32/issues/90)
- rename `fastheatupfactor` to `fastheatup` and add percent [#122] - rename `fastheatupfactor` to `fastheatup` and add percent [#122]
- "unit" renamed to "uom" in API call to recall a Device Value [**BREAKING CHANGE**]
- initial backend React changes to replace the class componentns (HOCs) with React Hooks

View File

@@ -33,7 +33,7 @@ CXX_STANDARD := -std=c++11
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# Defined Symbols # Defined Symbols
#---------------------------------------------------------------------- #----------------------------------------------------------------------
DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_DEFAULT_BOARD_PROFILE=\"LOLIN\" DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_DEFAULT_BOARD_PROFILE=\"LOLIN\"
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# Sources & Files # Sources & Files

View File

@@ -8,13 +8,13 @@
"name": "emsesp-react", "name": "emsesp-react",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@material-ui/core": "^4.11.4", "@material-ui/core": "^4.12.3",
"@material-ui/icons": "^4.11.2", "@material-ui/icons": "^4.11.2",
"@msgpack/msgpack": "^2.7.0", "@msgpack/msgpack": "^2.7.0",
"@types/lodash": "^4.14.168", "@types/lodash": "^4.14.172",
"@types/node": "^15.0.1", "@types/node": "^12.20.20",
"@types/react": "^17.0.4", "@types/react": "^17.0.19",
"@types/react-dom": "^17.0.3", "@types/react-dom": "^17.0.9",
"@types/react-material-ui-form-validator": "^2.1.0", "@types/react-material-ui-form-validator": "^2.1.0",
"@types/react-router": "^5.1.13", "@types/react-router": "^5.1.13",
"@types/react-router-dom": "^5.1.7", "@types/react-router-dom": "^5.1.7",
@@ -35,7 +35,7 @@
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
"sockette": "^2.0.6", "sockette": "^2.0.6",
"typescript": "4.2.4", "typescript": "4.3.5",
"zlib": "^1.0.5" "zlib": "^1.0.5"
}, },
"devDependencies": { "devDependencies": {
@@ -2050,13 +2050,13 @@
} }
}, },
"node_modules/@material-ui/core": { "node_modules/@material-ui/core": {
"version": "4.11.4", "version": "4.12.3",
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.4.tgz", "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz",
"integrity": "sha512-oqb+lJ2Dl9HXI9orc6/aN8ZIAMkeThufA5iZELf2LQeBn2NtjVilF5D2w7e9RpntAzDb4jK5DsVhkfOvFY/8fg==", "integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.4.4", "@babel/runtime": "^7.4.4",
"@material-ui/styles": "^4.11.4", "@material-ui/styles": "^4.11.4",
"@material-ui/system": "^4.11.3", "@material-ui/system": "^4.12.1",
"@material-ui/types": "5.1.0", "@material-ui/types": "5.1.0",
"@material-ui/utils": "^4.11.2", "@material-ui/utils": "^4.11.2",
"@types/react-transition-group": "^4.2.0", "@types/react-transition-group": "^4.2.0",
@@ -2137,9 +2137,9 @@
} }
}, },
"node_modules/@material-ui/system": { "node_modules/@material-ui/system": {
"version": "4.11.3", "version": "4.12.1",
"resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.11.3.tgz", "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz",
"integrity": "sha512-SY7otguNGol41Mu2Sg6KbBP1ZRFIbFLHGK81y4KYbsV2yIcaEPOmsCK6zwWlp+2yTV3J/VwT6oSBARtGIVdXPw==", "integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.4.4", "@babel/runtime": "^7.4.4",
"@material-ui/utils": "^4.11.2", "@material-ui/utils": "^4.11.2",
@@ -2148,6 +2148,20 @@
}, },
"engines": { "engines": {
"node": ">=8.0.0" "node": ">=8.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/material-ui"
},
"peerDependencies": {
"@types/react": "^16.8.6 || ^17.0.0",
"react": "^16.8.0 || ^17.0.0",
"react-dom": "^16.8.0 || ^17.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
} }
}, },
"node_modules/@material-ui/types": { "node_modules/@material-ui/types": {
@@ -2639,9 +2653,9 @@
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4="
}, },
"node_modules/@types/lodash": { "node_modules/@types/lodash": {
"version": "4.14.168", "version": "4.14.173",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.168.tgz", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.173.tgz",
"integrity": "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==" "integrity": "sha512-vv0CAYoaEjCw/mLy96GBTnRoZrSxkGE0BKzKimdR8P3OzrNYNvBgtW7p055A+E8C31vXNUhWKoFCbhq7gbyhFg=="
}, },
"node_modules/@types/material-ui": { "node_modules/@types/material-ui": {
"version": "0.21.8", "version": "0.21.8",
@@ -2658,9 +2672,9 @@
"integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==" "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA=="
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "15.0.1", "version": "12.20.25",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.1.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.25.tgz",
"integrity": "sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA==" "integrity": "sha512-hcTWqk7DR/HrN9Xe7AlJwuCaL13Vcd9/g/T54YrJz4Q3ESM5mr33YCzW2bOfzSIc3aZMeGBvbLGvgN6mIJ0I5Q=="
}, },
"node_modules/@types/normalize-package-data": { "node_modules/@types/normalize-package-data": {
"version": "2.4.0", "version": "2.4.0",
@@ -2688,9 +2702,9 @@
"integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==" "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug=="
}, },
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "17.0.4", "version": "17.0.22",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.4.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.22.tgz",
"integrity": "sha512-onz2BqScSFMoTRdJUZUDD/7xrusM8hBA2Fktk2qgaTYPCgPvWnDEgkrOs8hhPUf2jfcIXkJ5yK6VfYormJS3Jw==", "integrity": "sha512-kq/BMeaAVLJM6Pynh8C2rnr/drCK+/5ksH0ch9asz+8FW3DscYCIEFtCeYTFeIx/ubvOsMXmRfy7qEJ76gM96A==",
"dependencies": { "dependencies": {
"@types/prop-types": "*", "@types/prop-types": "*",
"@types/scheduler": "*", "@types/scheduler": "*",
@@ -2706,9 +2720,9 @@
} }
}, },
"node_modules/@types/react-dom": { "node_modules/@types/react-dom": {
"version": "17.0.3", "version": "17.0.9",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz",
"integrity": "sha512-4NnJbCeWE+8YBzupn/YrJxZ8VnjcJq5iR1laqQ1vkpQgBiA7bwk0Rp24fxsdNinzJY2U+HHS4dJJDPdoMjdJ7w==", "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==",
"dependencies": { "dependencies": {
"@types/react": "*" "@types/react": "*"
} }
@@ -19249,9 +19263,9 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.2.4", "version": "4.3.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
"integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@@ -23150,13 +23164,13 @@
} }
}, },
"@material-ui/core": { "@material-ui/core": {
"version": "4.11.4", "version": "4.12.3",
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.4.tgz", "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz",
"integrity": "sha512-oqb+lJ2Dl9HXI9orc6/aN8ZIAMkeThufA5iZELf2LQeBn2NtjVilF5D2w7e9RpntAzDb4jK5DsVhkfOvFY/8fg==", "integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==",
"requires": { "requires": {
"@babel/runtime": "^7.4.4", "@babel/runtime": "^7.4.4",
"@material-ui/styles": "^4.11.4", "@material-ui/styles": "^4.11.4",
"@material-ui/system": "^4.11.3", "@material-ui/system": "^4.12.1",
"@material-ui/types": "5.1.0", "@material-ui/types": "5.1.0",
"@material-ui/utils": "^4.11.2", "@material-ui/utils": "^4.11.2",
"@types/react-transition-group": "^4.2.0", "@types/react-transition-group": "^4.2.0",
@@ -23200,9 +23214,9 @@
} }
}, },
"@material-ui/system": { "@material-ui/system": {
"version": "4.11.3", "version": "4.12.1",
"resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.11.3.tgz", "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz",
"integrity": "sha512-SY7otguNGol41Mu2Sg6KbBP1ZRFIbFLHGK81y4KYbsV2yIcaEPOmsCK6zwWlp+2yTV3J/VwT6oSBARtGIVdXPw==", "integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==",
"requires": { "requires": {
"@babel/runtime": "^7.4.4", "@babel/runtime": "^7.4.4",
"@material-ui/utils": "^4.11.2", "@material-ui/utils": "^4.11.2",
@@ -23611,9 +23625,9 @@
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4="
}, },
"@types/lodash": { "@types/lodash": {
"version": "4.14.168", "version": "4.14.173",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.168.tgz", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.173.tgz",
"integrity": "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==" "integrity": "sha512-vv0CAYoaEjCw/mLy96GBTnRoZrSxkGE0BKzKimdR8P3OzrNYNvBgtW7p055A+E8C31vXNUhWKoFCbhq7gbyhFg=="
}, },
"@types/material-ui": { "@types/material-ui": {
"version": "0.21.8", "version": "0.21.8",
@@ -23630,9 +23644,9 @@
"integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==" "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA=="
}, },
"@types/node": { "@types/node": {
"version": "15.0.1", "version": "12.20.25",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.1.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.25.tgz",
"integrity": "sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA==" "integrity": "sha512-hcTWqk7DR/HrN9Xe7AlJwuCaL13Vcd9/g/T54YrJz4Q3ESM5mr33YCzW2bOfzSIc3aZMeGBvbLGvgN6mIJ0I5Q=="
}, },
"@types/normalize-package-data": { "@types/normalize-package-data": {
"version": "2.4.0", "version": "2.4.0",
@@ -23660,9 +23674,9 @@
"integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==" "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug=="
}, },
"@types/react": { "@types/react": {
"version": "17.0.4", "version": "17.0.22",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.4.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.22.tgz",
"integrity": "sha512-onz2BqScSFMoTRdJUZUDD/7xrusM8hBA2Fktk2qgaTYPCgPvWnDEgkrOs8hhPUf2jfcIXkJ5yK6VfYormJS3Jw==", "integrity": "sha512-kq/BMeaAVLJM6Pynh8C2rnr/drCK+/5ksH0ch9asz+8FW3DscYCIEFtCeYTFeIx/ubvOsMXmRfy7qEJ76gM96A==",
"requires": { "requires": {
"@types/prop-types": "*", "@types/prop-types": "*",
"@types/scheduler": "*", "@types/scheduler": "*",
@@ -23685,9 +23699,9 @@
} }
}, },
"@types/react-dom": { "@types/react-dom": {
"version": "17.0.3", "version": "17.0.9",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz",
"integrity": "sha512-4NnJbCeWE+8YBzupn/YrJxZ8VnjcJq5iR1laqQ1vkpQgBiA7bwk0Rp24fxsdNinzJY2U+HHS4dJJDPdoMjdJ7w==", "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==",
"requires": { "requires": {
"@types/react": "*" "@types/react": "*"
} }
@@ -37376,9 +37390,9 @@
} }
}, },
"typescript": { "typescript": {
"version": "4.2.4", "version": "4.3.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
"integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==" "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA=="
}, },
"unbox-primitive": { "unbox-primitive": {
"version": "1.0.1", "version": "1.0.1",

View File

@@ -3,13 +3,13 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@material-ui/core": "^4.11.4", "@material-ui/core": "^4.12.3",
"@material-ui/icons": "^4.11.2", "@material-ui/icons": "^4.11.2",
"@msgpack/msgpack": "^2.7.0", "@msgpack/msgpack": "^2.7.0",
"@types/lodash": "^4.14.168", "@types/lodash": "^4.14.172",
"@types/node": "^15.0.1", "@types/node": "^12.20.20",
"@types/react": "^17.0.4", "@types/react": "^17.0.19",
"@types/react-dom": "^17.0.3", "@types/react-dom": "^17.0.9",
"@types/react-material-ui-form-validator": "^2.1.0", "@types/react-material-ui-form-validator": "^2.1.0",
"@types/react-router": "^5.1.13", "@types/react-router": "^5.1.13",
"@types/react-router-dom": "^5.1.7", "@types/react-router-dom": "^5.1.7",
@@ -30,7 +30,7 @@
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
"sockette": "^2.0.6", "sockette": "^2.0.6",
"typescript": "4.2.4", "typescript": "4.3.5",
"zlib": "^1.0.5" "zlib": "^1.0.5"
}, },
"scripts": { "scripts": {

View File

@@ -22,25 +22,13 @@ interface UnauthenticatedRouteProps
| React.ComponentType<any>; | React.ComponentType<any>;
} }
type RenderComponent = (props: RouteComponentProps<any>) => React.ReactNode;
class UnauthenticatedRoute extends Route<UnauthenticatedRouteProps> { class UnauthenticatedRoute extends Route<UnauthenticatedRouteProps> {
public render() { public render() {
const { const { authenticationContext, features, ...rest } = this.props;
authenticationContext, if (authenticationContext.me) {
component: Component, return <Redirect to={Authentication.fetchLoginRedirect(features)} />;
features, }
...rest return <Route {...rest} />;
} = this.props;
const renderComponent: RenderComponent = (props) => {
if (authenticationContext.me) {
return <Redirect to={Authentication.fetchLoginRedirect(features)} />;
}
if (Component) {
return <Component {...props} />;
}
};
return <Route {...rest} render={renderComponent} />;
} }
} }

View File

@@ -0,0 +1,56 @@
import { FC } from 'react';
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
import { Button, LinearProgress, Typography } from '@material-ui/core';
const useStyles = makeStyles((theme: Theme) =>
createStyles({
loadingSettings: {
margin: theme.spacing(0.5)
},
loadingSettingsDetails: {
margin: theme.spacing(4),
textAlign: 'center'
},
button: {
marginRight: theme.spacing(2),
marginTop: theme.spacing(2)
}
})
);
interface FormLoaderProps {
errorMessage?: string;
loadData: () => void;
}
const FormLoader: FC<FormLoaderProps> = ({ errorMessage, loadData }) => {
const classes = useStyles();
if (errorMessage) {
return (
<div className={classes.loadingSettings}>
<Typography variant="h6" className={classes.loadingSettingsDetails}>
{errorMessage}
</Typography>
<Button
variant="contained"
color="secondary"
className={classes.button}
onClick={loadData}
>
Retry
</Button>
</div>
);
}
return (
<div className={classes.loadingSettings}>
<LinearProgress className={classes.loadingSettingsDetails} />
<Typography variant="h6" className={classes.loadingSettingsDetails}>
Loading&hellip;
</Typography>
</div>
);
};
export default FormLoader;

View File

@@ -5,6 +5,7 @@ export { default as HighlightAvatar } from './HighlightAvatar';
export { default as MenuAppBar } from './MenuAppBar'; export { default as MenuAppBar } from './MenuAppBar';
export { default as PasswordValidator } from './PasswordValidator'; export { default as PasswordValidator } from './PasswordValidator';
export { default as RestFormLoader } from './RestFormLoader'; export { default as RestFormLoader } from './RestFormLoader';
export { default as FormLoader } from './FormLoader';
export { default as SectionContent } from './SectionContent'; export { default as SectionContent } from './SectionContent';
export { default as WebSocketFormLoader } from './WebSocketFormLoader'; export { default as WebSocketFormLoader } from './WebSocketFormLoader';
export { default as ErrorButton } from './ErrorButton'; export { default as ErrorButton } from './ErrorButton';

View File

@@ -1,58 +1,31 @@
import { Component } from 'react'; import { FC } from 'react';
import { Features } from './types';
import { FeaturesContext } from './FeaturesContext';
import FullScreenLoading from '../components/FullScreenLoading'; import FullScreenLoading from '../components/FullScreenLoading';
import ApplicationError from '../components/ApplicationError'; import ApplicationError from '../components/ApplicationError';
import { FEATURES_ENDPOINT } from '../api'; import { FEATURES_ENDPOINT } from '../api';
import { useRest } from '../hooks';
interface FeaturesWrapperState { import { Features } from './types';
features?: Features; import { FeaturesContext } from './FeaturesContext';
error?: string;
}
class FeaturesWrapper extends Component<{}, FeaturesWrapperState> { const FeaturesWrapper: FC = ({ children }) => {
state: FeaturesWrapperState = {}; const { data: features, errorMessage: error } = useRest<Features>({
endpoint: FEATURES_ENDPOINT
});
componentDidMount() { if (features) {
this.fetchFeaturesDetails(); return (
<FeaturesContext.Provider value={{ features }}>
{children}
</FeaturesContext.Provider>
);
} }
fetchFeaturesDetails = () => { if (error) {
fetch(FEATURES_ENDPOINT) return <ApplicationError error={error} />;
.then((response) => {
if (response.status === 200) {
return response.json();
} else {
throw Error('Unexpected status code: ' + response.status);
}
})
.then((features) => {
this.setState({ features });
})
.catch((error) => {
this.setState({ error: error.message });
});
};
render() {
const { features, error } = this.state;
if (features) {
return (
<FeaturesContext.Provider
value={{
features
}}
>
{this.props.children}
</FeaturesContext.Provider>
);
}
if (error) {
return <ApplicationError error={error} />;
}
return <FullScreenLoading />;
} }
}
return <FullScreenLoading />;
};
export default FeaturesWrapper; export default FeaturesWrapper;

View File

@@ -0,0 +1,2 @@
export { default as useRest } from './useRest';
export { default as useAuthorizedRest } from './useAuthorizedRest';

View File

@@ -0,0 +1,12 @@
import { redirectingAuthorizedFetch } from '../authentication';
import useRest, { RestRequestOptions } from './useRest';
const useAuthorizedRest = <D>({
endpoint
}: Omit<RestRequestOptions, 'fetchFunction'>) =>
useRest<D>({
endpoint,
fetchFunction: redirectingAuthorizedFetch
});
export default useAuthorizedRest;

View File

@@ -0,0 +1,79 @@
import { useCallback, useEffect, useState } from 'react';
import { useSnackbar } from 'notistack';
export interface RestRequestOptions {
endpoint: string;
fetchFunction?: typeof fetch;
}
const useRest = <D>({
endpoint,
fetchFunction = fetch
}: RestRequestOptions) => {
const { enqueueSnackbar } = useSnackbar();
const [saving, setSaving] = useState<boolean>(false);
const [data, setData] = useState<D>();
const [errorMessage, setErrorMessage] = useState<string>();
const handleError = useCallback(
(error: any) => {
const errorMessage = error.message || 'Unknown error';
enqueueSnackbar('Problem fetching: ' + errorMessage, {
variant: 'error'
});
setErrorMessage(errorMessage);
},
[enqueueSnackbar]
);
const loadData = useCallback(async () => {
setData(undefined);
setErrorMessage(undefined);
try {
const response = await fetchFunction(endpoint);
if (response.status !== 200) {
throw Error('Invalid status code: ' + response.status);
}
setData(await response.json());
} catch (error) {
handleError(error);
}
}, [handleError, fetchFunction, endpoint]);
const save = useCallback(
async (data: D) => {
setSaving(true);
setErrorMessage(undefined);
try {
const response = await fetchFunction(endpoint, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
});
if (response.status !== 200) {
throw Error('Invalid status code: ' + response.status);
}
enqueueSnackbar('Update successful.', { variant: 'success' });
setData(await response.json());
} catch (error) {
handleError(error);
} finally {
setSaving(false);
}
},
[enqueueSnackbar, handleError, fetchFunction, endpoint]
);
const saveData = () => data && save(data);
useEffect(() => {
loadData();
}, [loadData]);
return { loadData, saveData, saving, setData, data, errorMessage } as const;
};
export default useRest;

View File

@@ -0,0 +1,33 @@
type UpdateEntity<S> = (state: (prevState: Readonly<S>) => S) => void;
export const extractEventValue = (
event: React.ChangeEvent<HTMLInputElement>
) => {
switch (event.target.type) {
case 'number':
return event.target.valueAsNumber;
case 'checkbox':
return event.target.checked;
default:
return event.target.value;
}
};
export const updateValue = <S>(updateEntity: UpdateEntity<S>) => (
event: React.ChangeEvent<HTMLInputElement>
) => {
updateEntity((prevState) => ({
...prevState,
[event.target.name]: extractEventValue(event)
}));
};
export const updateBooleanValue = <S>(updateEntity: UpdateEntity<S>) => (
name: string,
value?: boolean
) => {
updateEntity((prevState) => ({
...prevState,
[name]: value
}));
};

View File

@@ -0,0 +1 @@
export * from './binding';

View File

@@ -25,6 +25,10 @@
namespace uuid { namespace uuid {
std::string read_flash_string(const __FlashStringHelper * flash_str) { std::string read_flash_string(const __FlashStringHelper * flash_str) {
if (flash_str == nullptr) {
return std::string(""); // prevent crash
}
std::string str(::strlen_P(reinterpret_cast<PGM_P>(flash_str)), '\0'); std::string str(::strlen_P(reinterpret_cast<PGM_P>(flash_str)), '\0');
::strncpy_P(&str[0], reinterpret_cast<PGM_P>(flash_str), str.capacity() + 1); ::strncpy_P(&str[0], reinterpret_cast<PGM_P>(flash_str), str.capacity() + 1);

View File

@@ -35,7 +35,7 @@ class DummySettings {
uint8_t mqtt_qos = 0; uint8_t mqtt_qos = 0;
bool mqtt_retain = false; bool mqtt_retain = false;
bool enabled = true; bool enabled = true;
uint8_t nested_format = 1; uint8_t nested_format = 1; // 1=nested 2=single
uint8_t ha_climate_format = 1; uint8_t ha_climate_format = 1;
bool ha_enabled = true; bool ha_enabled = true;
String base = "ems-esp"; String base = "ems-esp";

View File

@@ -404,8 +404,6 @@ void EMSESPShell::add_console_commands() {
cmd_return = Command::call(device_type, cmd, arguments[2].c_str(), true, atoi(arguments[3].c_str()), json); cmd_return = Command::call(device_type, cmd, arguments[2].c_str(), true, atoi(arguments[3].c_str()), json);
} }
shell.printfln("size=%d measure=%d overflowed=%d", doc.size(), measureJson(doc), doc.overflowed()); // TODO remove debug
if (cmd_return == CommandRet::OK && json.size()) { if (cmd_return == CommandRet::OK && json.size()) {
serializeJsonPretty(doc, shell); serializeJsonPretty(doc, shell);
shell.println(); shell.println();

View File

@@ -142,10 +142,10 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_device_value(TAG_BOILER_DATA, &burnWorkMin_, DeviceValueType::TIME, nullptr, FL_(burnWorkMin), DeviceValueUOM::MINUTES); register_device_value(TAG_BOILER_DATA, &burnWorkMin_, DeviceValueType::TIME, nullptr, FL_(burnWorkMin), DeviceValueUOM::MINUTES);
register_device_value(TAG_BOILER_DATA, &heatWorkMin_, DeviceValueType::TIME, nullptr, FL_(heatWorkMin), DeviceValueUOM::MINUTES); register_device_value(TAG_BOILER_DATA, &heatWorkMin_, DeviceValueType::TIME, nullptr, FL_(heatWorkMin), DeviceValueUOM::MINUTES);
register_device_value(TAG_BOILER_DATA, &UBAuptime_, DeviceValueType::TIME, nullptr, FL_(UBAuptime), DeviceValueUOM::MINUTES); register_device_value(TAG_BOILER_DATA, &UBAuptime_, DeviceValueType::TIME, nullptr, FL_(UBAuptime), DeviceValueUOM::MINUTES);
register_device_value(TAG_BOILER_DATA, &lastCode_, DeviceValueType::TEXT, nullptr, FL_(lastCode), DeviceValueUOM::NONE); register_device_value(TAG_BOILER_DATA, &lastCode_, DeviceValueType::STRING, nullptr, FL_(lastCode), DeviceValueUOM::NONE);
register_device_value(TAG_BOILER_DATA, &serviceCode_, DeviceValueType::TEXT, nullptr, FL_(serviceCode), DeviceValueUOM::NONE); register_device_value(TAG_BOILER_DATA, &serviceCode_, DeviceValueType::STRING, nullptr, FL_(serviceCode), DeviceValueUOM::NONE);
register_device_value(TAG_BOILER_DATA, &serviceCodeNumber_, DeviceValueType::USHORT, nullptr, FL_(serviceCodeNumber), DeviceValueUOM::NONE); register_device_value(TAG_BOILER_DATA, &serviceCodeNumber_, DeviceValueType::USHORT, nullptr, FL_(serviceCodeNumber), DeviceValueUOM::NUM);
register_device_value(TAG_BOILER_DATA, &maintenanceMessage_, DeviceValueType::TEXT, nullptr, FL_(maintenanceMessage), DeviceValueUOM::NONE); register_device_value(TAG_BOILER_DATA, &maintenanceMessage_, DeviceValueType::STRING, nullptr, FL_(maintenanceMessage), DeviceValueUOM::NONE);
register_device_value(TAG_BOILER_DATA, register_device_value(TAG_BOILER_DATA,
&maintenanceType_, &maintenanceType_,
DeviceValueType::ENUM, DeviceValueType::ENUM,
@@ -156,7 +156,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_device_value( register_device_value(
TAG_BOILER_DATA, &maintenanceTime_, DeviceValueType::USHORT, nullptr, FL_(maintenanceTime), DeviceValueUOM::HOURS, MAKE_CF_CB(set_maintenancetime)); TAG_BOILER_DATA, &maintenanceTime_, DeviceValueType::USHORT, nullptr, FL_(maintenanceTime), DeviceValueUOM::HOURS, MAKE_CF_CB(set_maintenancetime));
register_device_value( register_device_value(
TAG_BOILER_DATA, &maintenanceDate_, DeviceValueType::TEXT, nullptr, FL_(maintenanceDate), DeviceValueUOM::NONE, MAKE_CF_CB(set_maintenancedate)); TAG_BOILER_DATA, &maintenanceDate_, DeviceValueType::STRING, nullptr, FL_(maintenanceDate), DeviceValueUOM::NONE, MAKE_CF_CB(set_maintenancedate));
// heatpump info // heatpump info
if (model() == EMS_DEVICE_FLAG_HEATPUMP) { if (model() == EMS_DEVICE_FLAG_HEATPUMP) {
register_device_value(TAG_BOILER_DATA, &upTimeControl_, DeviceValueType::TIME, FL_(div60), FL_(upTimeControl), DeviceValueUOM::MINUTES); register_device_value(TAG_BOILER_DATA, &upTimeControl_, DeviceValueType::TIME, FL_(div60), FL_(upTimeControl), DeviceValueUOM::MINUTES);
@@ -230,7 +230,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_device_value( register_device_value(
TAG_BOILER_DATA_WW, &wwComfort_, DeviceValueType::ENUM, FL_(enum_comfort), FL_(wwComfort), DeviceValueUOM::LIST, MAKE_CF_CB(set_warmwater_mode)); TAG_BOILER_DATA_WW, &wwComfort_, DeviceValueType::ENUM, FL_(enum_comfort), FL_(wwComfort), DeviceValueUOM::LIST, MAKE_CF_CB(set_warmwater_mode));
register_device_value( register_device_value(
TAG_BOILER_DATA_WW, &wwFlowTempOffset_, DeviceValueType::UINT, nullptr, FL_(wwFlowTempOffset), DeviceValueUOM::NONE, MAKE_CF_CB(set_wWFlowTempOffset)); TAG_BOILER_DATA_WW, &wwFlowTempOffset_, DeviceValueType::UINT, nullptr, FL_(wwFlowTempOffset), DeviceValueUOM::NUM, MAKE_CF_CB(set_wWFlowTempOffset));
register_device_value( register_device_value(
TAG_BOILER_DATA_WW, &wwMaxPower_, DeviceValueType::UINT, nullptr, FL_(wwMaxPower), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_warmwater_maxpower)); TAG_BOILER_DATA_WW, &wwMaxPower_, DeviceValueType::UINT, nullptr, FL_(wwMaxPower), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_warmwater_maxpower));
register_device_value( register_device_value(
@@ -261,7 +261,8 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_device_value( register_device_value(
TAG_BOILER_DATA_WW, &wwActivated_, DeviceValueType::BOOL, nullptr, FL_(wwActivated), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_activated)); TAG_BOILER_DATA_WW, &wwActivated_, DeviceValueType::BOOL, nullptr, FL_(wwActivated), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_activated));
register_device_value(TAG_BOILER_DATA_WW, &wwOneTime_, DeviceValueType::BOOL, nullptr, FL_(wwOneTime), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_onetime)); register_device_value(TAG_BOILER_DATA_WW, &wwOneTime_, DeviceValueType::BOOL, nullptr, FL_(wwOneTime), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_onetime));
register_device_value(TAG_BOILER_DATA_WW, &wwDisinfect_, DeviceValueType::BOOL, nullptr, FL_(wwDisinfect), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_disinfect)); register_device_value(
TAG_BOILER_DATA_WW, &wwDisinfect_, DeviceValueType::BOOL, nullptr, FL_(wwDisinfect), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_warmwater_disinfect));
register_device_value(TAG_BOILER_DATA_WW, &wwCharging_, DeviceValueType::BOOL, nullptr, FL_(wwCharging), DeviceValueUOM::BOOLEAN); register_device_value(TAG_BOILER_DATA_WW, &wwCharging_, DeviceValueType::BOOL, nullptr, FL_(wwCharging), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA_WW, &wwRecharging_, DeviceValueType::BOOL, nullptr, FL_(wwRecharging), DeviceValueUOM::BOOLEAN); register_device_value(TAG_BOILER_DATA_WW, &wwRecharging_, DeviceValueType::BOOL, nullptr, FL_(wwRecharging), DeviceValueUOM::BOOLEAN);
register_device_value(TAG_BOILER_DATA_WW, &wwTempOK_, DeviceValueType::BOOL, nullptr, FL_(wwTempOK), DeviceValueUOM::BOOLEAN); register_device_value(TAG_BOILER_DATA_WW, &wwTempOK_, DeviceValueType::BOOL, nullptr, FL_(wwTempOK), DeviceValueUOM::BOOLEAN);

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, &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::BOOLEAN); 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::NUM);
} }
} }

View File

@@ -64,7 +64,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
// special case for a device_id with 0x2A where it's not actual a solar module // special case for a device_id with 0x2A where it's not actual a solar module
if (device_id == 0x2A) { if (device_id == 0x2A) {
register_device_value(TAG_NONE, &type_, DeviceValueType::TEXT, nullptr, FL_(type), DeviceValueUOM::NONE); register_device_value(TAG_NONE, &type_, DeviceValueType::STRING, nullptr, FL_(type), DeviceValueUOM::NONE);
strlcpy(type_, "warm water circuit", sizeof(type_)); strlcpy(type_, "warm water circuit", sizeof(type_));
register_device_value(TAG_NONE, &wwTemp_1_, DeviceValueType::UINT, nullptr, FL_(wwTemp1), DeviceValueUOM::DEGREES); register_device_value(TAG_NONE, &wwTemp_1_, DeviceValueType::UINT, nullptr, FL_(wwTemp1), DeviceValueUOM::DEGREES);
register_device_value(TAG_NONE, &wwTemp_3_, DeviceValueType::UINT, nullptr, FL_(wwTemp3), DeviceValueUOM::DEGREES); register_device_value(TAG_NONE, &wwTemp_3_, DeviceValueType::UINT, nullptr, FL_(wwTemp3), DeviceValueUOM::DEGREES);
@@ -169,13 +169,13 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
MAKE_CF_CB(set_doubleMatchFlow)); // double Match Flow, 00=off MAKE_CF_CB(set_doubleMatchFlow)); // double Match Flow, 00=off
// telegram 0x380 // telegram 0x380
register_device_value(TAG_NONE, &climateZone_, DeviceValueType::UINT, nullptr, FL_(climateZone), DeviceValueUOM::NONE, MAKE_CF_CB(set_climateZone)); // climate zone identifier register_device_value(TAG_NONE, &climateZone_, DeviceValueType::UINT, nullptr, FL_(climateZone), DeviceValueUOM::NUM, MAKE_CF_CB(set_climateZone)); // climate zone identifier
register_device_value(TAG_NONE, register_device_value(TAG_NONE,
&collector1Area_, &collector1Area_,
DeviceValueType::USHORT, DeviceValueType::USHORT,
FL_(div10), FL_(div10),
FL_(collector1Area), FL_(collector1Area),
DeviceValueUOM::NONE, DeviceValueUOM::NUM,
MAKE_CF_CB(set_collector1Area)); // Area of collector field 1 MAKE_CF_CB(set_collector1Area)); // Area of collector field 1
register_device_value(TAG_NONE, register_device_value(TAG_NONE,
&collector1Type_, &collector1Type_,

View File

@@ -37,7 +37,7 @@ Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const
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::BOOLEAN); 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::NUM);
id_ = product_id; id_ = product_id;
} }

View File

@@ -2389,13 +2389,13 @@ bool Thermostat::set_roominfluence(const char * value, const int8_t id) {
void Thermostat::register_device_values() { void Thermostat::register_device_values() {
// Common for all thermostats // Common for all thermostats
register_device_value(TAG_THERMOSTAT_DATA, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE); register_device_value(TAG_THERMOSTAT_DATA, &id_, DeviceValueType::UINT, nullptr, FL_(ID), DeviceValueUOM::NONE);
register_device_value(TAG_THERMOSTAT_DATA, &errorCode_, DeviceValueType::TEXT, nullptr, FL_(errorCode), DeviceValueUOM::NONE); register_device_value(TAG_THERMOSTAT_DATA, &errorCode_, DeviceValueType::STRING, nullptr, FL_(errorCode), DeviceValueUOM::NONE);
register_device_value(TAG_THERMOSTAT_DATA, &lastCode_, DeviceValueType::TEXT, nullptr, FL_(lastCode), DeviceValueUOM::NONE); register_device_value(TAG_THERMOSTAT_DATA, &lastCode_, DeviceValueType::STRING, nullptr, FL_(lastCode), DeviceValueUOM::NONE);
switch (this->model()) { switch (this->model()) {
case EMS_DEVICE_FLAG_RC100: case EMS_DEVICE_FLAG_RC100:
case EMS_DEVICE_FLAG_RC300: case EMS_DEVICE_FLAG_RC300:
register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime)); register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime));
register_device_value(TAG_THERMOSTAT_DATA, &floordrystatus_, DeviceValueType::ENUM, FL_(enum_floordrystatus), FL_(floordrystatus), DeviceValueUOM::LIST); register_device_value(TAG_THERMOSTAT_DATA, &floordrystatus_, DeviceValueType::ENUM, FL_(enum_floordrystatus), FL_(floordrystatus), DeviceValueUOM::LIST);
register_device_value(TAG_THERMOSTAT_DATA, &dampedoutdoortemp2_, DeviceValueType::SHORT, FL_(div10), FL_(dampedoutdoortemp), DeviceValueUOM::DEGREES); register_device_value(TAG_THERMOSTAT_DATA, &dampedoutdoortemp2_, DeviceValueType::SHORT, FL_(div10), FL_(dampedoutdoortemp), DeviceValueUOM::DEGREES);
register_device_value(TAG_THERMOSTAT_DATA, &floordrytemp_, DeviceValueType::UINT, nullptr, FL_(floordrytemp), DeviceValueUOM::DEGREES); register_device_value(TAG_THERMOSTAT_DATA, &floordrytemp_, DeviceValueType::UINT, nullptr, FL_(floordrytemp), DeviceValueUOM::DEGREES);
@@ -2432,10 +2432,10 @@ void Thermostat::register_device_values() {
break; break;
case EMS_DEVICE_FLAG_RC20_N: case EMS_DEVICE_FLAG_RC20_N:
case EMS_DEVICE_FLAG_RC20: case EMS_DEVICE_FLAG_RC20:
register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime
break; break;
case EMS_DEVICE_FLAG_RC30_N: case EMS_DEVICE_FLAG_RC30_N:
register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime
register_device_value(TAG_THERMOSTAT_DATA, &ibaMainDisplay_, DeviceValueType::ENUM, FL_(enum_ibaMainDisplay), FL_(ibaMainDisplay), DeviceValueUOM::LIST); register_device_value(TAG_THERMOSTAT_DATA, &ibaMainDisplay_, DeviceValueType::ENUM, FL_(enum_ibaMainDisplay), FL_(ibaMainDisplay), DeviceValueUOM::LIST);
register_device_value(TAG_THERMOSTAT_DATA, &ibaLanguage_, DeviceValueType::ENUM, FL_(enum_ibaLanguage), FL_(ibaLanguage), DeviceValueUOM::LIST); register_device_value(TAG_THERMOSTAT_DATA, &ibaLanguage_, DeviceValueType::ENUM, FL_(enum_ibaLanguage), FL_(ibaLanguage), DeviceValueUOM::LIST);
register_device_value(TAG_THERMOSTAT_DATA, register_device_value(TAG_THERMOSTAT_DATA,
@@ -2443,7 +2443,7 @@ void Thermostat::register_device_values() {
DeviceValueType::UINT, DeviceValueType::UINT,
nullptr, nullptr,
FL_(ibaClockOffset), FL_(ibaClockOffset),
DeviceValueUOM::NONE); // offset (in sec) to clock, 0xff=-1s, 0x02=2s DeviceValueUOM::NUM); // offset (in sec) to clock, 0xff=-1s, 0x02=2s
register_device_value(TAG_THERMOSTAT_DATA, register_device_value(TAG_THERMOSTAT_DATA,
&ibaCalIntTemperature_, &ibaCalIntTemperature_,
DeviceValueType::INT, DeviceValueType::INT,
@@ -2471,7 +2471,7 @@ void Thermostat::register_device_values() {
TAG_THERMOSTAT_DATA, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode2), FL_(wwCircMode), DeviceValueUOM::LIST, MAKE_CF_CB(set_wwcircmode)); TAG_THERMOSTAT_DATA, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode2), FL_(wwCircMode), DeviceValueUOM::LIST, MAKE_CF_CB(set_wwcircmode));
break; break;
case EMS_DEVICE_FLAG_RC35: case EMS_DEVICE_FLAG_RC35:
register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime)); register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime));
register_device_value(TAG_THERMOSTAT_DATA, register_device_value(TAG_THERMOSTAT_DATA,
&ibaCalIntTemperature_, &ibaCalIntTemperature_,
DeviceValueType::INT, DeviceValueType::INT,
@@ -2518,7 +2518,7 @@ void Thermostat::register_device_values() {
DeviceValueType::UINT, DeviceValueType::UINT,
nullptr, nullptr,
FL_(wwDisinfectHour), FL_(wwDisinfectHour),
DeviceValueUOM::NONE, DeviceValueUOM::NUM,
MAKE_CF_CB(set_wwDisinfectHour), MAKE_CF_CB(set_wwDisinfectHour),
0, 0,
23); 23);
@@ -2527,14 +2527,14 @@ void Thermostat::register_device_values() {
TAG_THERMOSTAT_DATA, &wwOneTimeKey_, DeviceValueType::BOOL, nullptr, FL_(wwOneTimeKey), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_wwOneTimeKey)); TAG_THERMOSTAT_DATA, &wwOneTimeKey_, DeviceValueType::BOOL, nullptr, FL_(wwOneTimeKey), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_wwOneTimeKey));
break; break;
case EMS_DEVICE_FLAG_JUNKERS: case EMS_DEVICE_FLAG_JUNKERS:
register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime)); register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime));
break; break;
case EMS_DEVICE_FLAG_EASY: case EMS_DEVICE_FLAG_EASY:
// Easy TC100 have no date/time, see issue #100, not sure about CT200, so leave it. // Easy TC100 have no date/time, see issue #100, not sure about CT200, so leave it.
register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime
break; break;
default: default:
register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::TEXT, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime register_device_value(TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime
break; break;
} }
} }
@@ -2572,6 +2572,8 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
MAKE_CF_CB(set_temp), MAKE_CF_CB(set_temp),
5, 5,
29); 29);
// we add an extra key called "temp" which is identical to "seltemp". This is just for prettyness in the payload and makes it easier for consumers to understand
register_device_value( register_device_value(
tag, &hc->setpoint_roomTemp, DeviceValueType::SHORT, setpoint_temp_divider, FL_(temp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_temp), 5, 29); tag, &hc->setpoint_roomTemp, DeviceValueType::SHORT, setpoint_temp_divider, FL_(temp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_temp), 5, 29);
} }
@@ -2613,7 +2615,7 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
register_device_value(tag, &hc->offsettemp, DeviceValueType::INT, nullptr, FL_(offsettemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_offsettemp)); register_device_value(tag, &hc->offsettemp, DeviceValueType::INT, nullptr, FL_(offsettemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_offsettemp));
register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, nullptr, FL_(minflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minflowtemp)); register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, nullptr, FL_(minflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_minflowtemp));
register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, nullptr, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp)); register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, nullptr, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp));
register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT, nullptr, FL_(roominfluence), DeviceValueUOM::NONE, MAKE_CF_CB(set_roominfluence)); register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT, nullptr, FL_(roominfluence), DeviceValueUOM::NUM, MAKE_CF_CB(set_roominfluence));
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->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->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::LIST); register_device_value(tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::LIST);
@@ -2622,10 +2624,9 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
register_device_value(tag, &hc->summermode, DeviceValueType::BOOL, nullptr, FL_(summermode), DeviceValueUOM::BOOLEAN); 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::LIST, MAKE_CF_CB(set_controlmode)); tag, &hc->controlmode, DeviceValueType::ENUM, FL_(enum_controlmode), FL_(controlmode), DeviceValueUOM::LIST, 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::NUM, MAKE_CF_CB(set_program));
register_device_value(tag, &hc->tempautotemp, DeviceValueType::UINT, FL_(div2), FL_(tempautotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_tempautotemp)); register_device_value(tag, &hc->tempautotemp, DeviceValueType::UINT, FL_(div2), FL_(tempautotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_tempautotemp));
register_device_value( register_device_value(tag, &hc->fastHeatup, DeviceValueType::UINT, nullptr, FL_(fastheatup), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_fastheatup));
tag, &hc->fastHeatup, DeviceValueType::UINT, nullptr, FL_(fastheatup), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_fastheatup));
break; break;
case EMS_DEVICE_FLAG_CRF: case EMS_DEVICE_FLAG_CRF:
register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode5), FL_(mode), DeviceValueUOM::LIST); register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode5), FL_(mode), DeviceValueUOM::LIST);
@@ -2640,7 +2641,7 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype2), FL_(modetype), DeviceValueUOM::LIST); register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype2), FL_(modetype), DeviceValueUOM::LIST);
register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), FL_(daytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), FL_(daytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp));
register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(nighttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(nighttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp));
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::NUM, MAKE_CF_CB(set_program));
// RC25 additions, guess, not validated by users, see:https://github.com/emsesp/EMS-ESP32/issues/106 // RC25 additions, guess, not validated by users, see:https://github.com/emsesp/EMS-ESP32/issues/106
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));
register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, nullptr, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp)); register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, nullptr, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp));
@@ -2664,7 +2665,7 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
register_device_value(tag, &hc->summermode, DeviceValueType::BOOL, nullptr, FL_(summermode), DeviceValueUOM::BOOLEAN); register_device_value(tag, &hc->summermode, DeviceValueType::BOOL, nullptr, FL_(summermode), DeviceValueUOM::BOOLEAN);
register_device_value(tag, &hc->holidaymode, DeviceValueType::BOOL, nullptr, FL_(holidaymode), DeviceValueUOM::BOOLEAN, MAKE_CF_CB(set_holiday)); register_device_value(tag, &hc->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::NUM, 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));
register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, nullptr, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp)); register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, nullptr, FL_(maxflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_maxflowtemp));
register_device_value(tag, &hc->flowtempoffset, DeviceValueType::UINT, nullptr, FL_(flowtempoffset), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_flowtempoffset)); register_device_value(tag, &hc->flowtempoffset, DeviceValueType::UINT, nullptr, FL_(flowtempoffset), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_flowtempoffset));
@@ -2674,7 +2675,7 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
register_device_value( register_device_value(
tag, &hc->controlmode, DeviceValueType::ENUM, FL_(enum_controlmode2), FL_(controlmode), DeviceValueUOM::LIST, MAKE_CF_CB(set_controlmode)); tag, &hc->controlmode, DeviceValueType::ENUM, FL_(enum_controlmode2), FL_(controlmode), DeviceValueUOM::LIST, MAKE_CF_CB(set_controlmode));
register_device_value(tag, &hc->control, DeviceValueType::ENUM, FL_(enum_control), FL_(control), DeviceValueUOM::LIST, MAKE_CF_CB(set_control)); register_device_value(tag, &hc->control, DeviceValueType::ENUM, FL_(enum_control), FL_(control), DeviceValueUOM::LIST, MAKE_CF_CB(set_control));
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::NUM, MAKE_CF_CB(set_program));
register_device_value(tag, &hc->pause, DeviceValueType::UINT, nullptr, FL_(pause), DeviceValueUOM::HOURS, MAKE_CF_CB(set_pause)); register_device_value(tag, &hc->pause, DeviceValueType::UINT, nullptr, FL_(pause), DeviceValueUOM::HOURS, MAKE_CF_CB(set_pause));
register_device_value(tag, &hc->party, DeviceValueType::UINT, nullptr, FL_(party), DeviceValueUOM::HOURS, MAKE_CF_CB(set_party)); register_device_value(tag, &hc->party, DeviceValueType::UINT, nullptr, FL_(party), DeviceValueUOM::HOURS, MAKE_CF_CB(set_party));
register_device_value(tag, &hc->tempautotemp, DeviceValueType::UINT, FL_(div2), FL_(tempautotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_tempautotemp)); register_device_value(tag, &hc->tempautotemp, DeviceValueType::UINT, FL_(div2), FL_(tempautotemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_tempautotemp));

View File

@@ -370,7 +370,7 @@ bool EMSdevice::is_fetch(uint16_t telegram_id) {
// list of registered device entries, adding the HA entity if it exists // list of registered device entries, adding the HA entity if it exists
void EMSdevice::list_device_entries(JsonObject & json) { void EMSdevice::list_device_entries(JsonObject & json) {
for (const auto & dv : devicevalues_) { for (const auto & dv : devicevalues_) {
if (dv.full_name && dv.type != DeviceValueType::CMD) { if (dv_is_visible(dv) && dv.type != DeviceValueType::CMD) {
// if we have a tag prefix it // if we have a tag prefix it
char key[50]; char key[50];
if (!EMSdevice::tag_to_string(dv.tag).empty()) { if (!EMSdevice::tag_to_string(dv.tag).empty()) {
@@ -484,7 +484,7 @@ void EMSdevice::register_device_value(uint8_t tag,
int32_t min, int32_t min,
uint32_t max) { uint32_t max) {
// init the value depending on it's type // init the value depending on it's type
if (type == DeviceValueType::TEXT) { if (type == DeviceValueType::STRING) {
*(char *)(value_p) = {'\0'}; *(char *)(value_p) = {'\0'};
} else if (type == DeviceValueType::INT) { } else if (type == DeviceValueType::INT) {
*(int8_t *)(value_p) = EMS_VALUE_INT_NOTSET; *(int8_t *)(value_p) = EMS_VALUE_INT_NOTSET;
@@ -574,7 +574,7 @@ const std::string EMSdevice::get_value_uom(const char * key) {
// find the key (p) in the name // find the key (p) in the name
for (const auto & dv : devicevalues_) { for (const auto & dv : devicevalues_) {
if (dv.full_name != nullptr) { if (dv_is_visible(dv)) {
if (uuid::read_flash_string(dv.full_name) == p) { if (uuid::read_flash_string(dv.full_name) == p) {
// ignore TIME since "minutes" is already added to the string value // 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)) {
@@ -596,7 +596,7 @@ void EMSdevice::generate_values_json_web(JsonObject & json) {
for (const auto & dv : devicevalues_) { for (const auto & dv : devicevalues_) {
// ignore if full_name empty and also commands // ignore if full_name empty and also commands
if ((dv.full_name != nullptr) && (dv.type != DeviceValueType::CMD)) { if (dv_is_visible(dv) && dv.type != DeviceValueType::CMD) {
JsonObject obj; // create the object, if needed JsonObject obj; // create the object, if needed
// handle Booleans (true, false) // handle Booleans (true, false)
@@ -606,7 +606,7 @@ void EMSdevice::generate_values_json_web(JsonObject & json) {
} }
// handle TEXT strings // handle TEXT strings
else if ((dv.type == DeviceValueType::TEXT) && (Helpers::hasValue((char *)(dv.value_p)))) { else if ((dv.type == DeviceValueType::STRING) && (Helpers::hasValue((char *)(dv.value_p)))) {
obj = data.createNestedObject(); obj = data.createNestedObject();
obj["v"] = (char *)(dv.value_p); obj["v"] = (char *)(dv.value_p);
} }
@@ -633,7 +633,7 @@ void EMSdevice::generate_values_json_web(JsonObject & json) {
uint8_t divider = 0; uint8_t divider = 0;
uint8_t factor = 1; uint8_t factor = 1;
if (dv.options_size == 1) { if (dv.options_size == 1) {
const char * s = uuid::read_flash_string(dv.options[0]).c_str(); const char * s = uuid::read_flash_string(dv.options[0]).c_str();
if (s[0] == '*') { if (s[0] == '*') {
factor = Helpers::atoint(&s[1]); factor = Helpers::atoint(&s[1]);
} else { } else {
@@ -719,11 +719,13 @@ bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t
// search device value with this tag // search device value with this tag
for (auto & dv : devicevalues_) { for (auto & dv : devicevalues_) {
if (strcmp(cmd, Helpers::toLower(uuid::read_flash_string(dv.short_name)).c_str()) == 0 && (tag <= 0 || tag == dv.tag)) { // ignore any device values which have a uom of NONE as we use this to hide them
if ((dv.uom != DeviceValueUOM::NONE)
&& (strcmp(cmd, Helpers::toLower(uuid::read_flash_string(dv.short_name)).c_str()) == 0 && (tag <= 0 || tag == dv.tag))) {
uint8_t divider = 0; uint8_t divider = 0;
uint8_t factor = 1; uint8_t factor = 1;
if (dv.options_size == 1) { if (dv.options_size == 1) {
const char * s = uuid::read_flash_string(dv.options[0]).c_str(); const char * s = uuid::read_flash_string(dv.options[0]).c_str();
if (s[0] == '*') { if (s[0] == '*') {
factor = Helpers::atoint(&s[1]); factor = Helpers::atoint(&s[1]);
} else { } else {
@@ -737,7 +739,7 @@ bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t
json["name"] = dv.short_name; json["name"] = dv.short_name;
// prefix tag if it's included // prefix tag if it's included
if (dv.full_name != nullptr) { if (dv_is_visible(dv)) {
if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) { if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) {
json["fullname"] = dv.full_name; json["fullname"] = dv.full_name;
} else { } else {
@@ -849,7 +851,7 @@ bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t
json[max] = divider ? EMS_VALUE_ULONG_NOTSET / divider : EMS_VALUE_ULONG_NOTSET; json[max] = divider ? EMS_VALUE_ULONG_NOTSET / divider : EMS_VALUE_ULONG_NOTSET;
break; break;
case DeviceValueType::TEXT: case DeviceValueType::STRING:
if (Helpers::hasValue((char *)(dv.value_p))) { if (Helpers::hasValue((char *)(dv.value_p))) {
json[value] = (char *)(dv.value_p); json[value] = (char *)(dv.value_p);
} }
@@ -896,24 +898,29 @@ bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t
// For each value in the device create the json object pair and add it to given json // For each value in the device create the json object pair and add it to given json
// return false if empty // return false if empty
// this is used to create both the MQTT payloads and Console messages (console = true) // this is used to create both the MQTT payloads, Console messages and Web API calls
bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter, const bool nested, const bool console) { bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter, const bool nested, const uint8_t output_target) {
bool has_values = false; // to see if we've added a value. it's faster than doing a json.size() at the end bool has_values = false; // to see if we've added a value. it's faster than doing a json.size() at the end
uint8_t old_tag = 255; // NAN uint8_t old_tag = 255; // NAN
JsonObject json = root; JsonObject json = root;
for (auto & dv : devicevalues_) { for (auto & dv : devicevalues_) {
// conditions
bool condition;
condition = (tag_filter == DeviceValueTAG::TAG_NONE) || (tag_filter == dv.tag); // tag must be either empty or match a tag passed to this function
if (output_target != OUTPUT_TARGET::MQTT) {
condition &= dv_is_visible(dv); // value must be visible if outputting to API (web or console). This is for ID, hamode, hatemp etc
}
bool has_value = false; bool has_value = false;
// only show if tag is either empty (TAG_NONE) or matches a value
// and don't show if full_name is empty unless we're outputing for mqtt payloads if (condition) {
// for nested we use all values, dont show command only (have_cmd and no fullname)
if (((nested) || tag_filter == DeviceValueTAG::TAG_NONE || (tag_filter == dv.tag)) && (dv.full_name != nullptr || !console)
&& !(dv.full_name == nullptr && dv.has_cmd)) {
// we have a tag if it matches the filter given, and that the tag name is not empty/"" // we have a tag if it matches the filter given, and that the tag name is not empty/""
bool have_tag = ((dv.tag != tag_filter) && !tag_to_string(dv.tag).empty()); bool have_tag = ((dv.tag != tag_filter) && !tag_to_string(dv.tag).empty());
char name[80]; char name[80];
if (console) { if (output_target == OUTPUT_TARGET::API_VERBOSE) {
// prefix the tag in brackets, unless it's Boiler because we're naughty and use tag for the MQTT topic // prefix the tag in brackets, unless it's Boiler because we're naughty and use tag for the MQTT topic
if (have_tag) { if (have_tag) {
snprintf(name, 80, "%s %s", tag_to_string(dv.tag).c_str(), uuid::read_flash_string(dv.full_name).c_str()); snprintf(name, 80, "%s %s", tag_to_string(dv.tag).c_str(), uuid::read_flash_string(dv.full_name).c_str());
@@ -935,9 +942,8 @@ 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 how to render the value depending on the setting // see how to render the value depending on the setting
// when in console mode we always use on and off
uint8_t bool_format = EMSESP::bool_format(); uint8_t bool_format = EMSESP::bool_format();
if ((bool_format == BOOL_FORMAT_ONOFF) || console) { if (bool_format == BOOL_FORMAT_ONOFF) {
json[name] = *(uint8_t *)(dv.value_p) ? F_(on) : F_(off); json[name] = *(uint8_t *)(dv.value_p) ? F_(on) : F_(off);
} else if (bool_format == BOOL_FORMAT_ONOFF_CAP) { } else if (bool_format == BOOL_FORMAT_ONOFF_CAP) {
json[name] = *(uint8_t *)(dv.value_p) ? F_(ON) : F_(OFF); json[name] = *(uint8_t *)(dv.value_p) ? F_(ON) : F_(OFF);
@@ -950,7 +956,7 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter
} }
// handle TEXT strings // handle TEXT strings
else if ((dv.type == DeviceValueType::TEXT) && (Helpers::hasValue((char *)(dv.value_p)))) { else if ((dv.type == DeviceValueType::STRING) && (Helpers::hasValue((char *)(dv.value_p)))) {
json[name] = (char *)(dv.value_p); json[name] = (char *)(dv.value_p);
has_value = true; has_value = true;
} }
@@ -976,7 +982,7 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter
uint8_t divider = 0; uint8_t divider = 0;
uint8_t factor = 1; uint8_t factor = 1;
if (dv.options_size == 1) { if (dv.options_size == 1) {
const char * s = uuid::read_flash_string(dv.options[0]).c_str(); const char * s = uuid::read_flash_string(dv.options[0]).c_str();
if (s[0] == '*') { if (s[0] == '*') {
factor = Helpers::atoint(&s[1]); factor = Helpers::atoint(&s[1]);
} else { } else {
@@ -1023,7 +1029,7 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter
} 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 * factor; // sometimes we need to divide by 60 time_value = (divider) ? time_value / divider : time_value * factor; // sometimes we need to divide by 60
if (console) { if (output_target == EMSdevice::OUTPUT_TARGET::API_VERBOSE) {
char time_s[40]; char time_s[40];
snprintf(time_s, sizeof(time_s), "%d days %d hours %d minutes", (time_value / 1440), ((time_value % 1440) / 60), (time_value % 60)); snprintf(time_s, sizeof(time_s), "%d days %d hours %d minutes", (time_value / 1440), ((time_value % 1440) / 60), (time_value % 60));
json[name] = time_s; json[name] = time_s;

View File

@@ -39,7 +39,7 @@ enum DeviceValueType : uint8_t {
ULONG, ULONG,
TIME, // same as ULONG (32 bits) TIME, // same as ULONG (32 bits)
ENUM, ENUM,
TEXT, STRING,
CMD // special for commands only CMD // special for commands only
}; };
@@ -148,10 +148,6 @@ class EMSdevice {
, brand_(brand) { , brand_(brand) {
} }
inline uint8_t device_id() const {
return device_id_;
}
const std::string device_type_name() const; const std::string device_type_name() const;
static const std::string device_type_2_device_name(const uint8_t device_type); static const std::string device_type_2_device_name(const uint8_t device_type);
static uint8_t device_name_2_device_type(const char * topic); static uint8_t device_name_2_device_type(const char * topic);
@@ -160,6 +156,10 @@ class EMSdevice {
static const std::string tag_to_string(uint8_t tag); static const std::string tag_to_string(uint8_t tag);
static const std::string tag_to_mqtt(uint8_t tag); static const std::string tag_to_mqtt(uint8_t tag);
inline uint8_t device_id() const {
return device_id_;
}
inline uint8_t product_id() const { inline uint8_t product_id() const {
return product_id_; return product_id_;
} }
@@ -186,9 +186,8 @@ class EMSdevice {
return flags_; return flags_;
} }
// see enum DeviceType below
inline uint8_t device_type() const { inline uint8_t device_type() const {
return device_type_; return device_type_; // see enum DeviceType below
} }
inline void version(std::string & version) { inline void version(std::string & version) {
@@ -249,8 +248,11 @@ class EMSdevice {
const std::string get_value_uom(const char * key); const 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);
void generate_values_json_web(JsonObject & json); enum OUTPUT_TARGET : uint8_t { API_VERBOSE, API, MQTT };
bool generate_values_json(JsonObject & json, const uint8_t tag_filter, const bool nested, const uint8_t output_target);
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,
@@ -417,6 +419,8 @@ class EMSdevice {
} }
}; };
// DeviceValue holds all the attributes for a device value (also a device parameter)
struct DeviceValue { struct DeviceValue {
uint8_t device_type; // EMSdevice::DeviceType uint8_t device_type; // EMSdevice::DeviceType
uint8_t tag; // DeviceValueTAG::* uint8_t tag; // DeviceValueTAG::*
@@ -470,6 +474,10 @@ class EMSdevice {
void init_devicevalues(uint8_t size) { void init_devicevalues(uint8_t size) {
devicevalues_.reserve(size); devicevalues_.reserve(size);
} }
inline bool dv_is_visible(DeviceValue dv) {
return (dv.full_name);
}
}; };
} // namespace emsesp } // namespace emsesp

View File

@@ -299,7 +299,7 @@ void EMSESP::show_ems(uuid::console::Shell & shell) {
} }
// show EMS device values to the shell console // show EMS device values to the shell console
// generate_values_json is called in verbose mode (set to true) // generate_values_json is called in verbose mode
void EMSESP::show_device_values(uuid::console::Shell & shell) { void EMSESP::show_device_values(uuid::console::Shell & shell) {
if (emsdevices.empty()) { if (emsdevices.empty()) {
shell.printfln(F("No EMS devices detected. Try using 'scan devices' from the ems menu.")); shell.printfln(F("No EMS devices detected. Try using 'scan devices' from the ems menu."));
@@ -316,7 +316,7 @@ void EMSESP::show_device_values(uuid::console::Shell & shell) {
DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE_DYN); // use max size DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE_DYN); // use max size
JsonObject json = doc.to<JsonObject>(); JsonObject json = doc.to<JsonObject>();
emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true, true); // console mode and nested emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::API_VERBOSE); // verbose mode and nested
// print line // print line
uint8_t id = 0; uint8_t id = 0;
@@ -451,7 +451,7 @@ void EMSESP::publish_device_values(uint8_t device_type) {
JsonObject json = doc.to<JsonObject>(); JsonObject json = doc.to<JsonObject>();
bool need_publish = false; bool need_publish = false;
uint8_t nested = Mqtt::nested_format(); bool nested = (Mqtt::nested_format() == 1); // 1 is nested, 2 is single
// group by device type // group by device type
for (const auto & emsdevice : emsdevices) { for (const auto & emsdevice : emsdevices) {
@@ -461,13 +461,13 @@ void EMSESP::publish_device_values(uint8_t device_type) {
emsdevice->publish_mqtt_ha_sensor(); // create the configs for each value as a sensor emsdevice->publish_mqtt_ha_sensor(); // create the configs for each value as a sensor
} }
// if its a boiler, generate json for each group and publish it directly // if its a boiler, generate json for each group and publish it directly. not nested
if (device_type == DeviceType::BOILER) { if (device_type == DeviceType::BOILER) {
if (emsdevice->generate_values_json(json, DeviceValueTAG::TAG_BOILER_DATA, false)) { if (emsdevice->generate_values_json(json, DeviceValueTAG::TAG_BOILER_DATA, false, EMSdevice::OUTPUT_TARGET::MQTT)) {
Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_BOILER_DATA), json); Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_BOILER_DATA), json);
} }
doc.clear(); doc.clear();
if (emsdevice->generate_values_json(json, DeviceValueTAG::TAG_BOILER_DATA_WW, false)) { if (emsdevice->generate_values_json(json, DeviceValueTAG::TAG_BOILER_DATA_WW, false, EMSdevice::OUTPUT_TARGET::MQTT)) {
Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_BOILER_DATA_WW), json); Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_BOILER_DATA_WW), json);
} }
need_publish = false; need_publish = false;
@@ -478,15 +478,15 @@ void EMSESP::publish_device_values(uint8_t device_type) {
// only publish the single master thermostat // only publish the single master thermostat
if (emsdevice->device_id() == EMSESP::actual_master_thermostat()) { if (emsdevice->device_id() == EMSESP::actual_master_thermostat()) {
if (nested) { if (nested) {
need_publish |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true); // nested need_publish |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::MQTT); // nested
} else { } else {
if (emsdevice->generate_values_json(json, DeviceValueTAG::TAG_THERMOSTAT_DATA, false)) { // not nested if (emsdevice->generate_values_json(json, DeviceValueTAG::TAG_THERMOSTAT_DATA, false, EMSdevice::OUTPUT_TARGET::MQTT)) { // not nested
Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_NONE), json); Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_NONE), json);
} }
doc.clear(); doc.clear();
for (uint8_t hc_tag = TAG_HC1; hc_tag <= DeviceValueTAG::TAG_HC4; hc_tag++) { for (uint8_t hc_tag = TAG_HC1; hc_tag <= DeviceValueTAG::TAG_HC4; hc_tag++) {
if (emsdevice->generate_values_json(json, hc_tag, false)) { // not nested if (emsdevice->generate_values_json(json, hc_tag, false, EMSdevice::OUTPUT_TARGET::MQTT)) { // not nested
Mqtt::publish(Mqtt::tag_to_topic(device_type, hc_tag), json); Mqtt::publish(Mqtt::tag_to_topic(device_type, hc_tag), json);
} }
doc.clear(); doc.clear();
@@ -499,10 +499,10 @@ void EMSESP::publish_device_values(uint8_t device_type) {
// Mixer // Mixer
else if (device_type == DeviceType::MIXER) { else if (device_type == DeviceType::MIXER) {
if (nested) { if (nested) {
need_publish |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true); // nested need_publish |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::MQTT); // nested
} else { } else {
for (uint8_t hc_tag = TAG_HC1; hc_tag <= DeviceValueTAG::TAG_WWC4; hc_tag++) { for (uint8_t hc_tag = TAG_HC1; hc_tag <= DeviceValueTAG::TAG_WWC4; hc_tag++) {
if (emsdevice->generate_values_json(json, hc_tag, false)) { // not nested if (emsdevice->generate_values_json(json, hc_tag, false, EMSdevice::OUTPUT_TARGET::MQTT)) { // not nested
Mqtt::publish(Mqtt::tag_to_topic(device_type, hc_tag), json); Mqtt::publish(Mqtt::tag_to_topic(device_type, hc_tag), json);
} }
doc.clear(); doc.clear();
@@ -512,7 +512,7 @@ void EMSESP::publish_device_values(uint8_t device_type) {
} else { } else {
// for all other devices add the values to the json // for all other devices add the values to the json
need_publish |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true); // nested need_publish |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::MQTT); // nested
} }
} }
} }
@@ -992,12 +992,14 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, std::
Command::add_json( Command::add_json(
device_type, device_type,
F_(info), F_(info),
[device_type](const char * value, const int8_t id, JsonObject & json) { return command_info(device_type, json, id, true); }, [device_type](const char * value, const int8_t id, JsonObject & json) {
return command_info(device_type, json, id, EMSdevice::OUTPUT_TARGET::API_VERBOSE);
},
F_(info_cmd)); F_(info_cmd));
Command::add_json( Command::add_json(
device_type, device_type,
F("info_short"), F("info_short"),
[device_type](const char * value, const int8_t id, JsonObject & json) { return command_info(device_type, json, id, false); }, [device_type](const char * value, const int8_t id, JsonObject & json) { return command_info(device_type, json, id, EMSdevice::OUTPUT_TARGET::API); },
nullptr, nullptr,
CommandFlag::HIDDEN); // this command is hidden CommandFlag::HIDDEN); // this command is hidden
Command::add_json( Command::add_json(
@@ -1036,7 +1038,7 @@ bool EMSESP::command_commands(uint8_t device_type, JsonObject & json, const int8
// export all values to info command // export all values to info command
// value is ignored here // value is ignored here
// info command always shows in verbose mode, so full names are displayed // info command always shows in verbose mode, so full names are displayed
bool EMSESP::command_info(uint8_t device_type, JsonObject & json, const int8_t id, bool verbose) { bool EMSESP::command_info(uint8_t device_type, JsonObject & json, const int8_t id, const uint8_t output_target) {
bool has_value = false; bool has_value = false;
uint8_t tag; uint8_t tag;
if (id >= 1 && id <= 4) { if (id >= 1 && id <= 4) {
@@ -1049,10 +1051,13 @@ bool EMSESP::command_info(uint8_t device_type, JsonObject & json, const int8_t i
return false; return false;
} }
// if id=-1 it means we have no endpoint so default to API
uint8_t target = (id == -1) ? EMSdevice::OUTPUT_TARGET::API_VERBOSE : EMSdevice::OUTPUT_TARGET::API;
for (const auto & emsdevice : emsdevices) { for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_type) if (emsdevice && (emsdevice->device_type() == device_type)
&& ((device_type != DeviceType::THERMOSTAT) || (emsdevice->device_id() == EMSESP::actual_master_thermostat()))) { && ((device_type != DeviceType::THERMOSTAT) || (emsdevice->device_id() == EMSESP::actual_master_thermostat()))) {
has_value |= emsdevice->generate_values_json(json, tag, (id < 1), verbose && (id == -1)); // nested for id -1,0 & console for id -1 has_value |= emsdevice->generate_values_json(json, tag, (id < 1), target); // nested for id -1 and 0
} }
} }

View File

@@ -249,7 +249,7 @@ class EMSESP {
static void process_version(std::shared_ptr<const Telegram> telegram); static void process_version(std::shared_ptr<const Telegram> telegram);
static void publish_response(std::shared_ptr<const Telegram> telegram); static void publish_response(std::shared_ptr<const Telegram> telegram);
static void publish_all_loop(); static void publish_all_loop();
static bool command_info(uint8_t device_type, JsonObject & json, const int8_t id, bool verbose = true); static bool command_info(uint8_t device_type, JsonObject & json, const int8_t id, const uint8_t output_target);
static bool command_commands(uint8_t device_type, JsonObject & json, const int8_t id); static bool command_commands(uint8_t device_type, JsonObject & json, const int8_t id);
static bool command_entities(uint8_t device_type, JsonObject & json, const int8_t id); static bool command_entities(uint8_t device_type, JsonObject & json, const int8_t id);

View File

@@ -301,9 +301,9 @@ MAKE_PSTR_WORD(design)
MAKE_PSTR_WORD(tempauto) MAKE_PSTR_WORD(tempauto)
MAKE_PSTR_WORD(minflow) MAKE_PSTR_WORD(minflow)
MAKE_PSTR_WORD(maxflow) MAKE_PSTR_WORD(maxflow)
MAKE_PSTR_WORD(rc3x) MAKE_PSTR_WORD(rc3x)
MAKE_PSTR_WORD(rc20) MAKE_PSTR_WORD(rc20)
MAKE_PSTR(internal_temperature, "internal temperature") MAKE_PSTR(internal_temperature, "internal temperature")
MAKE_PSTR(internal_setpoint, "internal setpoint") MAKE_PSTR(internal_setpoint, "internal setpoint")
MAKE_PSTR(external_temperature, "external temperature") MAKE_PSTR(external_temperature, "external temperature")
@@ -365,12 +365,11 @@ MAKE_PSTR_LIST(enum_collectortype, F("flat"), F("vacuum"))
// MQTT topics and full text for values and commands // MQTT topics and full text for values and commands
MAKE_PSTR(homeassistant, "homeassistant/") MAKE_PSTR(homeassistant, "homeassistant/")
// id used to store the device ID, goes into MQTT payload // id used to store the device ID. empty full name so only gets displayed in the MQTT payload
// empty full name to prevent being shown in web or console
MAKE_PSTR_LIST(ID, F_(id)) MAKE_PSTR_LIST(ID, F_(id))
// Boiler // Boiler
// extra commands, no output // extra commands, with no json output
MAKE_PSTR_LIST(wwtapactivated, F("wwtapactivated"), F("turn on/off DHW by going into maintenance mode")) MAKE_PSTR_LIST(wwtapactivated, F("wwtapactivated"), F("turn on/off DHW by going into maintenance mode"))
MAKE_PSTR_LIST(reset, F("reset"), F("reset messages")) MAKE_PSTR_LIST(reset, F("reset"), F("reset messages"))
@@ -523,14 +522,13 @@ MAKE_PSTR_LIST(wwMaxTemp, F("wwmaxtemp"), F("maximum temperature"))
MAKE_PSTR_LIST(wwOneTimeKey, F("wwonetimekey"), F("one time key function")) MAKE_PSTR_LIST(wwOneTimeKey, F("wwonetimekey"), F("one time key function"))
// thermostat // thermostat
// extra commands // commands, with no long name so they only appear in the MQTT payloads
MAKE_PSTR_LIST(switchtime, F("switchtime"), F("single program switchtime"))
// extra commands, with no long name so they don't show up in WebUI
MAKE_PSTR_LIST(temp, F("temp")) MAKE_PSTR_LIST(temp, F("temp"))
MAKE_PSTR_LIST(hatemp, F("hatemp")) MAKE_PSTR_LIST(hatemp, F("hatemp"))
MAKE_PSTR_LIST(hamode, F("hamode")) MAKE_PSTR_LIST(hamode, F("hamode"))
// mqtt values / commands // mqtt values / commands
MAKE_PSTR_LIST(switchtime, F("switchtime"), F("single program switchtime"))
MAKE_PSTR_LIST(dateTime, F("datetime"), F("date/time")) MAKE_PSTR_LIST(dateTime, F("datetime"), F("date/time"))
MAKE_PSTR_LIST(errorCode, F("errorcode"), F("error code")) MAKE_PSTR_LIST(errorCode, F("errorcode"), F("error code"))
MAKE_PSTR_LIST(ibaMainDisplay, F("display"), F("display")) MAKE_PSTR_LIST(ibaMainDisplay, F("display"), F("display"))

View File

@@ -174,11 +174,11 @@ class Mqtt {
} }
static uint8_t nested_format() { static uint8_t nested_format() {
return nested_format_; return nested_format_; // nested_format is 1 if nested, otherwise 2 for single topics
} }
static void nested_format(uint8_t nested_format) { static void nested_format(uint8_t nested_format) {
nested_format_ = nested_format; nested_format_ = nested_format; // nested_format is 1 if nested, otherwise 2 for single topics
} }
static bool ha_enabled() { static bool ha_enabled() {

View File

@@ -981,7 +981,10 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & json
obj["type"] = emsdevice->device_type_name(); obj["type"] = emsdevice->device_type_name();
obj["name"] = emsdevice->to_string(); obj["name"] = emsdevice->to_string();
char result[200]; char result[200];
obj["handlers"] = emsdevice->show_telegram_handlers(result); (void)emsdevice->show_telegram_handlers(result);
if (result[0] != '\0') {
obj["handlers"] = result; // don't show hanlders if there aren't any
}
} }
} }
} }

View File

@@ -482,8 +482,9 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
// first with nested // first with nested
Mqtt::nested_format(1); Mqtt::nested_format(1);
shell.invoke_command("call system publish"); shell.invoke_command("call system publish");
shell.invoke_command("show mqtt");
// then without nested // then without nested - single mode
Mqtt::nested_format(2); Mqtt::nested_format(2);
shell.invoke_command("call system publish"); shell.invoke_command("call system publish");
shell.invoke_command("show mqtt"); shell.invoke_command("show mqtt");
@@ -829,6 +830,9 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
if (command == "mqtt") { if (command == "mqtt") {
shell.printfln(F("Testing MQTT...")); shell.printfln(F("Testing MQTT..."));
Mqtt::ha_enabled(false);
Mqtt::enabled(true);
// add a boiler // add a boiler
add_device(0x08, 123); // Nefit Trendline add_device(0x08, 123); // Nefit Trendline
@@ -841,6 +845,8 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
uart_telegram("98 00 FF 00 01 A5 00 CF 21 2E 00 00 2E 24 03 25 03 03 01 03 25 00 C8 00 00 11 01 03"); // without CRC uart_telegram("98 00 FF 00 01 A5 00 CF 21 2E 00 00 2E 24 03 25 03 03 01 03 25 00 C8 00 00 11 01 03"); // without CRC
uart_telegram_withCRC("98 00 FF 00 01 A5 00 CF 21 2E 00 00 2E 24 03 25 03 03 01 03 25 00 C8 00 00 11 01 03 13"); // with CRC uart_telegram_withCRC("98 00 FF 00 01 A5 00 CF 21 2E 00 00 2E 24 03 25 03 03 01 03 25 00 C8 00 00 11 01 03 13"); // with CRC
shell.invoke_command("call system publish");
shell.invoke_command("show mqtt");
shell.loop_all(); shell.loop_all();
char boiler_topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char boiler_topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
@@ -853,11 +859,11 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
strcpy(thermostat_topic, "ems-esp/thermostat"); strcpy(thermostat_topic, "ems-esp/thermostat");
strcpy(system_topic, "ems-esp/system"); strcpy(system_topic, "ems-esp/system");
EMSESP::mqtt_.incoming(boiler_topic, ""); // test if ignore empty payloads // invalid format EMSESP::mqtt_.incoming(boiler_topic, ""); // test if ignore empty payloads
EMSESP::mqtt_.incoming(boiler_topic, "12345"); // invalid format EMSESP::mqtt_.incoming(boiler_topic, "12345"); // error: invalid format
EMSESP::mqtt_.incoming("bad_topic", "12345"); // no matching topic EMSESP::mqtt_.incoming("bad_topic", "12345"); // error: no matching topic
EMSESP::mqtt_.incoming(boiler_topic, "{\"cmd\":\"garbage\",\"data\":22.52}"); // should report error EMSESP::mqtt_.incoming(boiler_topic, "{\"cmd\":\"garbage\",\"data\":22.52}"); // error: should report error
EMSESP::mqtt_.incoming(boiler_topic, "{\"cmd\":\"comfort\",\"data\":\"eco\"}"); EMSESP::mqtt_.incoming(boiler_topic, "{\"cmd\":\"comfort\",\"data\":\"eco\"}");
EMSESP::mqtt_.incoming(boiler_topic, "{\"cmd\":\"wwactivated\",\"data\":\"1\"}"); // with quotes EMSESP::mqtt_.incoming(boiler_topic, "{\"cmd\":\"wwactivated\",\"data\":\"1\"}"); // with quotes
@@ -948,12 +954,23 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
if (command == "api") { if (command == "api") {
#if defined(EMSESP_STANDALONE) #if defined(EMSESP_STANDALONE)
shell.printfln(F("Testing RESTful API...")); shell.printfln(F("Testing RESTful API..."));
Mqtt::ha_enabled(false); Mqtt::ha_enabled(true);
Mqtt::enabled(false); Mqtt::enabled(false);
run_test("general"); run_test("general");
AsyncWebServerRequest request; AsyncWebServerRequest request;
// GET // GET
request.url("/api/thermostat");
EMSESP::webAPIService.webAPIService_get(&request);
request.url("/api/thermostat/info");
EMSESP::webAPIService.webAPIService_get(&request);
// these next 2 should fail
request.url("/api/boiler/id");
EMSESP::webAPIService.webAPIService_get(&request);
request.url("/api/thermostat/hamode");
EMSESP::webAPIService.webAPIService_get(&request);
request.method(HTTP_GET); request.method(HTTP_GET);
request.url("/api/thermostat/seltemp"); request.url("/api/thermostat/seltemp");
EMSESP::webAPIService.webAPIService_get(&request); EMSESP::webAPIService.webAPIService_get(&request);
@@ -994,7 +1011,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
EMSESP::webAPIService.webAPIService_post(&request, json); EMSESP::webAPIService.webAPIService_post(&request, json);
// 3 // 3
char data3[] = "{\"device\":\"thermostat\", \"name\":\"temp\",\"value\":11}"; char data3[] = "{\"device\":\"thermostat\", \"name\":\"temp\",\"value\":13}";
deserializeJson(doc, data3); deserializeJson(doc, data3);
json = doc.as<JsonVariant>(); json = doc.as<JsonVariant>();
request.url("/api"); request.url("/api");

View File

@@ -33,8 +33,8 @@ namespace emsesp {
// #define EMSESP_DEBUG_DEFAULT "general" // #define EMSESP_DEBUG_DEFAULT "general"
// #define EMSESP_DEBUG_DEFAULT "boiler" // #define EMSESP_DEBUG_DEFAULT "boiler"
// #define EMSESP_DEBUG_DEFAULT "mqtt2" // #define EMSESP_DEBUG_DEFAULT "mqtt2"
// #define EMSESP_DEBUG_DEFAULT "mqtt_nested" #define EMSESP_DEBUG_DEFAULT "mqtt_nested"
#define EMSESP_DEBUG_DEFAULT "ha" // #define EMSESP_DEBUG_DEFAULT "ha"
// #define EMSESP_DEBUG_DEFAULT "board_profile" // #define EMSESP_DEBUG_DEFAULT "board_profile"
// #define EMSESP_DEBUG_DEFAULT "shower_alert" // #define EMSESP_DEBUG_DEFAULT "shower_alert"
// #define EMSESP_DEBUG_DEFAULT "310" // #define EMSESP_DEBUG_DEFAULT "310"

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.2.2b6" #define EMSESP_APP_VERSION "v3.2.2b7"