MQTT Formatting payload (nested vs single) is a pull-down option

This commit is contained in:
proddy
2021-04-04 09:33:04 +02:00
parent 84e76e2bd7
commit 7fa93a8de0
13 changed files with 761 additions and 491 deletions

View File

@@ -1,11 +1,12 @@
# Changelog # Changelog
## Added ## Added
- Mock API to simulate an ESP, for testing web
## Fixed ## Fixed
## Changed ## Changed
- Icon for Network
- MQTT Formatting payload (nested vs single) is a pull-down option
- moved mqtt-topics and texts to local_EN, all topics lower case - moved mqtt-topics and texts to local_EN, all topics lower case
## Removed ## Removed

View File

@@ -1,22 +1,31 @@
import React from 'react'; import React from "react";
import { TextValidator, ValidatorForm, SelectValidator } from 'react-material-ui-form-validator'; import {
TextValidator,
ValidatorForm,
SelectValidator,
} from "react-material-ui-form-validator";
import { Checkbox, TextField, Typography } from '@material-ui/core'; import { Checkbox, TextField, Typography } from "@material-ui/core";
import SaveIcon from '@material-ui/icons/Save'; import SaveIcon from "@material-ui/icons/Save";
import MenuItem from '@material-ui/core/MenuItem'; import MenuItem from "@material-ui/core/MenuItem";
import { RestFormProps, FormActions, FormButton, BlockFormControlLabel, PasswordValidator } from '../components'; import {
import { isIP, isHostname, or, isPath } from '../validators'; RestFormProps,
FormActions,
FormButton,
BlockFormControlLabel,
PasswordValidator,
} from "../components";
import { isIP, isHostname, or, isPath } from "../validators";
import { MqttSettings } from './types'; import { MqttSettings } from "./types";
type MqttSettingsFormProps = RestFormProps<MqttSettings>; type MqttSettingsFormProps = RestFormProps<MqttSettings>;
class MqttSettingsForm extends React.Component<MqttSettingsFormProps> { class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
componentDidMount() { componentDidMount() {
ValidatorForm.addValidationRule('isIPOrHostname', or(isIP, isHostname)); ValidatorForm.addValidationRule("isIPOrHostname", or(isIP, isHostname));
ValidatorForm.addValidationRule('isPath', isPath); ValidatorForm.addValidationRule("isPath", isPath);
} }
render() { render() {
@@ -27,44 +36,57 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
control={ control={
<Checkbox <Checkbox
checked={data.enabled} checked={data.enabled}
onChange={handleValueChange('enabled')} onChange={handleValueChange("enabled")}
value="enabled" value="enabled"
/> />
} }
label="Enable MQTT" label="Enable MQTT"
/> />
<TextValidator <TextValidator
validators={['required', 'isIPOrHostname']} validators={["required", "isIPOrHostname"]}
errorMessages={['Host is required', "Not a valid IP address or hostname"]} errorMessages={[
"Host is required",
"Not a valid IP address or hostname",
]}
name="host" name="host"
label="Host" label="Host"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.host} value={data.host}
onChange={handleValueChange('host')} onChange={handleValueChange("host")}
margin="normal" margin="normal"
/> />
<TextValidator <TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']} validators={[
errorMessages={['Port is required', "Must be a number", "Must be greater than 0 ", "Max value is 65535"]} "required",
"isNumber",
"minNumber:0",
"maxNumber:65535",
]}
errorMessages={[
"Port is required",
"Must be a number",
"Must be greater than 0 ",
"Max value is 65535",
]}
name="port" name="port"
label="Port" label="Port"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.port} value={data.port}
type="number" type="number"
onChange={handleValueChange('port')} onChange={handleValueChange("port")}
margin="normal" margin="normal"
/> />
<TextValidator <TextValidator
validators={['required', 'isPath']} validators={["required", "isPath"]}
errorMessages={['Base is required', "Not a valid Path"]} errorMessages={["Base is required", "Not a valid Path"]}
name="base" name="base"
label="Base" label="Base"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.base} value={data.base}
onChange={handleValueChange('base')} onChange={handleValueChange("base")}
margin="normal" margin="normal"
/> />
<TextField <TextField
@@ -73,7 +95,7 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.username} value={data.username}
onChange={handleValueChange('username')} onChange={handleValueChange("username")}
margin="normal" margin="normal"
/> />
<PasswordValidator <PasswordValidator
@@ -82,7 +104,7 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.password} value={data.password}
onChange={handleValueChange('password')} onChange={handleValueChange("password")}
margin="normal" margin="normal"
/> />
<TextField <TextField
@@ -91,28 +113,40 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.client_id} value={data.client_id}
onChange={handleValueChange('client_id')} onChange={handleValueChange("client_id")}
margin="normal" margin="normal"
/> />
<TextValidator <TextValidator
validators={['required', 'isNumber', 'minNumber:1', 'maxNumber:65535']} validators={[
errorMessages={['Keep alive is required', "Must be a number", "Must be greater than 0", "Max value is 65535"]} "required",
"isNumber",
"minNumber:1",
"maxNumber:65535",
]}
errorMessages={[
"Keep alive is required",
"Must be a number",
"Must be greater than 0",
"Max value is 65535",
]}
name="keep_alive" name="keep_alive"
label="Keep Alive (seconds)" label="Keep Alive (seconds)"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.keep_alive} value={data.keep_alive}
type="number" type="number"
onChange={handleValueChange('keep_alive')} onChange={handleValueChange("keep_alive")}
margin="normal" margin="normal"
/> />
<SelectValidator name="mqtt_qos" <SelectValidator
name="mqtt_qos"
label="QoS" label="QoS"
value={data.mqtt_qos} value={data.mqtt_qos}
fullWidth fullWidth
variant="outlined" variant="outlined"
onChange={handleValueChange('mqtt_qos')} onChange={handleValueChange("mqtt_qos")}
margin="normal"> margin="normal"
>
<MenuItem value={0}>0 (default)</MenuItem> <MenuItem value={0}>0 (default)</MenuItem>
<MenuItem value={1}>1</MenuItem> <MenuItem value={1}>1</MenuItem>
<MenuItem value={2}>2</MenuItem> <MenuItem value={2}>2</MenuItem>
@@ -121,7 +155,7 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
control={ control={
<Checkbox <Checkbox
checked={data.clean_session} checked={data.clean_session}
onChange={handleValueChange('clean_session')} onChange={handleValueChange("clean_session")}
value="clean_session" value="clean_session"
/> />
} }
@@ -131,55 +165,63 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
control={ control={
<Checkbox <Checkbox
checked={data.mqtt_retain} checked={data.mqtt_retain}
onChange={handleValueChange('mqtt_retain')} onChange={handleValueChange("mqtt_retain")}
value="mqtt_retain" value="mqtt_retain"
/> />
} }
label="Retain Flag" label="Retain Flag"
/> />
<br></br> <br></br>
<Typography variant="h6" color="primary" > <Typography variant="h6" color="primary">
Formatting Formatting
</Typography> </Typography>
<BlockFormControlLabel <SelectValidator
control={ name="nested_format"
<Checkbox label="Topic/Payload Format"
checked={data.nested_format} value={data.nested_format}
onChange={handleValueChange('nested_format')} fullWidth
value="nested_format" variant="outlined"
/> onChange={handleValueChange("nested_format")}
} margin="normal"
label="Nested format (Thermostat & Mixer only)" >
/> <MenuItem value={1}>nested on a single topic</MenuItem>
<SelectValidator name="dallas_format" <MenuItem value={2}>as individual topics</MenuItem>
</SelectValidator>
<SelectValidator
name="dallas_format"
label="Dallas Sensor Payload Grouping" label="Dallas Sensor Payload Grouping"
value={data.dallas_format} value={data.dallas_format}
fullWidth fullWidth
variant="outlined" variant="outlined"
onChange={handleValueChange('dallas_format')} onChange={handleValueChange("dallas_format")}
margin="normal"> margin="normal"
>
<MenuItem value={1}>by Sensor ID</MenuItem> <MenuItem value={1}>by Sensor ID</MenuItem>
<MenuItem value={2}>by Number</MenuItem> <MenuItem value={2}>by Number</MenuItem>
</SelectValidator> </SelectValidator>
<SelectValidator name="bool_format" <SelectValidator
name="bool_format"
label="Boolean Format" label="Boolean Format"
value={data.bool_format} value={data.bool_format}
fullWidth fullWidth
variant="outlined" variant="outlined"
onChange={handleValueChange('bool_format')} onChange={handleValueChange("bool_format")}
margin="normal"> margin="normal"
>
<MenuItem value={1}>"on"/"off"</MenuItem> <MenuItem value={1}>"on"/"off"</MenuItem>
<MenuItem value={2}>true/false</MenuItem> <MenuItem value={2}>true/false</MenuItem>
<MenuItem value={3}>1/0</MenuItem> <MenuItem value={3}>1/0</MenuItem>
<MenuItem value={4}>"ON"/"OFF"</MenuItem> <MenuItem value={4}>"ON"/"OFF"</MenuItem>
</SelectValidator> </SelectValidator>
<SelectValidator name="subscribe_format" <SelectValidator
name="subscribe_format"
label="Subscribe Format" label="Subscribe Format"
value={data.subscribe_format} value={data.subscribe_format}
fullWidth fullWidth
variant="outlined" variant="outlined"
onChange={handleValueChange('subscribe_format')} onChange={handleValueChange("subscribe_format")}
margin="normal"> margin="normal"
>
<MenuItem value={0}>general device topic</MenuItem> <MenuItem value={0}>general device topic</MenuItem>
<MenuItem value={1}>individual topics, main heating circuit</MenuItem> <MenuItem value={1}>individual topics, main heating circuit</MenuItem>
<MenuItem value={2}>individual topics, all heating circuits</MenuItem> <MenuItem value={2}>individual topics, all heating circuits</MenuItem>
@@ -188,103 +230,170 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
control={ control={
<Checkbox <Checkbox
checked={data.ha_enabled} checked={data.ha_enabled}
onChange={handleValueChange('ha_enabled')} onChange={handleValueChange("ha_enabled")}
value="ha_enabled" value="ha_enabled"
/> />
} }
label="Home Assistant MQTT Discovery" label="Use Home Assistant MQTT Discovery"
/> />
{ data.ha_enabled && {data.ha_enabled && (
<SelectValidator name="ha_climate_format" <SelectValidator
name="ha_climate_format"
label="Thermostat Room Temperature" label="Thermostat Room Temperature"
value={data.ha_climate_format} value={data.ha_climate_format}
fullWidth fullWidth
variant="outlined" variant="outlined"
onChange={handleValueChange('ha_climate_format')} onChange={handleValueChange("ha_climate_format")}
margin="normal"> margin="normal"
>
<MenuItem value={1}>use Current temperature (default)</MenuItem> <MenuItem value={1}>use Current temperature (default)</MenuItem>
<MenuItem value={2}>use Setpoint temperature</MenuItem> <MenuItem value={2}>use Setpoint temperature</MenuItem>
<MenuItem value={3}>Fix to 0</MenuItem> <MenuItem value={3}>Fix to 0</MenuItem>
</SelectValidator> </SelectValidator>
} )}
<br></br> <br></br>
<Typography variant="h6" color="primary" > <Typography variant="h6" color="primary">
Publish Intervals Publish Intervals
</Typography> </Typography>
<TextValidator <TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']} validators={[
errorMessages={['Publish time is required', "Must be a number", "Must be 0 or greater", "Max value is 65535"]} "required",
"isNumber",
"minNumber:0",
"maxNumber:65535",
]}
errorMessages={[
"Publish time is required",
"Must be a number",
"Must be 0 or greater",
"Max value is 65535",
]}
name="publish_time_boiler" name="publish_time_boiler"
label="Boiler Publish Interval (seconds, 0=on change)" label="Boiler Publish Interval (seconds, 0=on change)"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.publish_time_boiler} value={data.publish_time_boiler}
type="number" type="number"
onChange={handleValueChange('publish_time_boiler')} onChange={handleValueChange("publish_time_boiler")}
margin="normal" margin="normal"
/> />
<TextValidator <TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']} validators={[
errorMessages={['Publish time is required', "Must be a number", "Must be 0 or greater", "Max value is 65535"]} "required",
"isNumber",
"minNumber:0",
"maxNumber:65535",
]}
errorMessages={[
"Publish time is required",
"Must be a number",
"Must be 0 or greater",
"Max value is 65535",
]}
name="publish_time_thermostat" name="publish_time_thermostat"
label="Thermostat Publish Interval (seconds, 0=on change)" label="Thermostat Publish Interval (seconds, 0=on change)"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.publish_time_thermostat} value={data.publish_time_thermostat}
type="number" type="number"
onChange={handleValueChange('publish_time_thermostat')} onChange={handleValueChange("publish_time_thermostat")}
margin="normal" margin="normal"
/> />
<TextValidator <TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']} validators={[
errorMessages={['Publish time is required', "Must be a number", "Must be 0 or greater", "Max value is 65535"]} "required",
"isNumber",
"minNumber:0",
"maxNumber:65535",
]}
errorMessages={[
"Publish time is required",
"Must be a number",
"Must be 0 or greater",
"Max value is 65535",
]}
name="publish_time_solar" name="publish_time_solar"
label="Solar Publish Interval (seconds, 0=on change)" label="Solar Publish Interval (seconds, 0=on change)"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.publish_time_solar} value={data.publish_time_solar}
type="number" type="number"
onChange={handleValueChange('publish_time_solar')} onChange={handleValueChange("publish_time_solar")}
margin="normal" margin="normal"
/> />
<TextValidator <TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']} validators={[
errorMessages={['Publish time is required', "Must be a number", "Must be 0 or greater", "Max value is 65535"]} "required",
"isNumber",
"minNumber:0",
"maxNumber:65535",
]}
errorMessages={[
"Publish time is required",
"Must be a number",
"Must be 0 or greater",
"Max value is 65535",
]}
name="publish_time_mixer" name="publish_time_mixer"
label="Mixer Publish Interval (seconds, 0=on change)" label="Mixer Publish Interval (seconds, 0=on change)"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.publish_time_mixer} value={data.publish_time_mixer}
type="number" type="number"
onChange={handleValueChange('publish_time_mixer')} onChange={handleValueChange("publish_time_mixer")}
margin="normal" margin="normal"
/> />
<TextValidator <TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']} validators={[
errorMessages={['Publish time is required', "Must be a number", "Must be 0 or greater", "Max value is 65535"]} "required",
"isNumber",
"minNumber:0",
"maxNumber:65535",
]}
errorMessages={[
"Publish time is required",
"Must be a number",
"Must be 0 or greater",
"Max value is 65535",
]}
name="publish_time_sensor" name="publish_time_sensor"
label="Sensors Publish Interval (seconds, 0=on change)" label="Sensors Publish Interval (seconds, 0=on change)"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.publish_time_sensor} value={data.publish_time_sensor}
type="number" type="number"
onChange={handleValueChange('publish_time_sensor')} onChange={handleValueChange("publish_time_sensor")}
margin="normal" margin="normal"
/> />
<TextValidator <TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']} validators={[
errorMessages={['Publish time is required', "Must be a number", "Must be 0 or greater", "Max value is 65535"]} "required",
"isNumber",
"minNumber:0",
"maxNumber:65535",
]}
errorMessages={[
"Publish time is required",
"Must be a number",
"Must be 0 or greater",
"Max value is 65535",
]}
name="publish_time_other" name="publish_time_other"
label="All other Modules Publish Interval (seconds, 0=on change)" label="All other Modules Publish Interval (seconds, 0=on change)"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.publish_time_other} value={data.publish_time_other}
type="number" type="number"
onChange={handleValueChange('publish_time_other')} onChange={handleValueChange("publish_time_other")}
margin="normal" margin="normal"
/> />
<FormActions> <FormActions>
<FormButton startIcon={<SaveIcon />} variant="contained" color="primary" type="submit"> <FormButton
startIcon={<SaveIcon />}
variant="contained"
color="primary"
type="submit"
>
Save Save
</FormButton> </FormButton>
</FormActions> </FormActions>

View File

@@ -40,6 +40,6 @@ export interface MqttSettings {
mqtt_retain: boolean; mqtt_retain: boolean;
ha_enabled: boolean; ha_enabled: boolean;
ha_climate_format: number; ha_climate_format: number;
nested_format: boolean; nested_format: number;
subscribe_format: number; subscribe_format: number;
} }

View File

@@ -1,417 +1,577 @@
import React from 'react'; import React from "react";
import { ValidatorForm, TextValidator, SelectValidator } from 'react-material-ui-form-validator'; import {
ValidatorForm,
TextValidator,
SelectValidator,
} from "react-material-ui-form-validator";
import { Checkbox, Typography, Box, Link, withWidth, WithWidthProps } from '@material-ui/core'; import {
import SaveIcon from '@material-ui/icons/Save'; Checkbox,
import MenuItem from '@material-ui/core/MenuItem'; Typography,
Box,
Link,
withWidth,
WithWidthProps,
} from "@material-ui/core";
import SaveIcon from "@material-ui/icons/Save";
import MenuItem from "@material-ui/core/MenuItem";
import Grid from '@material-ui/core/Grid'; import Grid from "@material-ui/core/Grid";
import { redirectingAuthorizedFetch, withAuthenticatedContext, AuthenticatedContextProps } from "../authentication"; import {
redirectingAuthorizedFetch,
withAuthenticatedContext,
AuthenticatedContextProps,
} from "../authentication";
import { RestFormProps, FormActions, FormButton, BlockFormControlLabel } from '../components'; import {
RestFormProps,
FormActions,
FormButton,
BlockFormControlLabel,
} from "../components";
import { isIP, optional } from '../validators'; import { isIP, optional } from "../validators";
import { EMSESPSettings } from './EMSESPtypes'; import { EMSESPSettings } from "./EMSESPtypes";
import { boardProfileSelectItems } from './EMSESPBoardProfiles'; import { boardProfileSelectItems } from "./EMSESPBoardProfiles";
import { ENDPOINT_ROOT } from "../api"; import { ENDPOINT_ROOT } from "../api";
export const BOARD_PROFILE_ENDPOINT = ENDPOINT_ROOT + "boardProfile"; export const BOARD_PROFILE_ENDPOINT = ENDPOINT_ROOT + "boardProfile";
type EMSESPSettingsFormProps = RestFormProps<EMSESPSettings> & AuthenticatedContextProps & WithWidthProps; type EMSESPSettingsFormProps = RestFormProps<EMSESPSettings> &
AuthenticatedContextProps &
WithWidthProps;
interface EMSESPSettingsFormState { interface EMSESPSettingsFormState {
processing: boolean; processing: boolean;
} }
class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> { class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
state: EMSESPSettingsFormState = {
processing: false,
};
state: EMSESPSettingsFormState = { componentDidMount() {
processing: false ValidatorForm.addValidationRule("isOptionalIP", optional(isIP));
} }
componentDidMount() { changeBoardProfile = (event: React.ChangeEvent<HTMLSelectElement>) => {
ValidatorForm.addValidationRule('isOptionalIP', optional(isIP)); const { data, setData } = this.props;
} setData({
...data,
board_profile: event.target.value,
});
changeBoardProfile = (event: React.ChangeEvent<HTMLSelectElement>) => { if (event.target.value === "CUSTOM") return;
const { data, setData } = this.props;
this.setState({ processing: true });
redirectingAuthorizedFetch(BOARD_PROFILE_ENDPOINT, {
method: "POST",
body: JSON.stringify({ code: event.target.value }),
headers: {
"Content-Type": "application/json",
},
})
.then((response) => {
if (response.status === 200) {
return response.json();
}
throw Error("Unexpected response code: " + response.status);
})
.then((json) => {
this.props.enqueueSnackbar("Profile loaded", { variant: "success" });
setData({ setData({
...data, ...data,
board_profile: event.target.value led_gpio: json.led_gpio,
dallas_gpio: json.dallas_gpio,
rx_gpio: json.rx_gpio,
tx_gpio: json.tx_gpio,
pbutton_gpio: json.pbutton_gpio,
board_profile: event.target.value,
}); });
this.setState({ processing: false });
if (event.target.value === "CUSTOM") })
return; .catch((error) => {
this.props.enqueueSnackbar(
this.setState({ processing: true }); error.message || "Problem fetching board profile",
redirectingAuthorizedFetch(BOARD_PROFILE_ENDPOINT, { { variant: "warning" }
method: "POST",
body: JSON.stringify({ code: event.target.value }),
headers: {
"Content-Type": "application/json",
},
})
.then((response) => {
if (response.status === 200) {
return response.json();
}
throw Error("Unexpected response code: " + response.status);
})
.then((json) => {
this.props.enqueueSnackbar("Profile loaded", { variant: 'success' });
setData({
...data,
led_gpio: json.led_gpio,
dallas_gpio: json.dallas_gpio,
rx_gpio: json.rx_gpio,
tx_gpio: json.tx_gpio,
pbutton_gpio: json.pbutton_gpio,
board_profile: event.target.value
});
this.setState({ processing: false });
})
.catch((error) => {
this.props.enqueueSnackbar(
error.message || "Problem fetching board profile",
{ variant: "warning" }
);
this.setState({ processing: false });
});
};
render() {
const { data, saveData, handleValueChange } = this.props;
return (
<ValidatorForm onSubmit={saveData}>
<Box bgcolor="info.main" p={2} mt={2} mb={2}>
<Typography variant="body1">
Modify any of the EMS-ESP settings here. For help refer to the <Link target="_blank" href="https://emsesp.github.io/docs/#/Configure-firmware32?id=ems-esp-settings" color="primary">{'online documentation'}</Link>.
</Typography>
</Box>
<br></br>
<Typography variant="h6" color="primary" >
EMS Bus
</Typography>
<Grid container spacing={1} direction="row" justify="flex-start" alignItems="flex-start">
<Grid item xs={5}>
<SelectValidator name="tx_mode"
label="Tx Mode"
value={data.tx_mode}
fullWidth
variant="outlined"
onChange={handleValueChange('tx_mode')}
margin="normal">
<MenuItem value={0}>Off</MenuItem>
<MenuItem value={1}>EMS</MenuItem>
<MenuItem value={2}>EMS+</MenuItem>
<MenuItem value={3}>HT3</MenuItem>
<MenuItem value={4}>Hardware</MenuItem>
</SelectValidator>
</Grid>
<Grid item xs={6}>
<SelectValidator name="ems_bus_id"
label="Bus ID"
value={data.ems_bus_id}
fullWidth
variant="outlined"
onChange={handleValueChange('ems_bus_id')}
margin="normal">
<MenuItem value={0x0B}>Service Key (0x0B)</MenuItem>
<MenuItem value={0x0D}>Modem (0x0D)</MenuItem>
<MenuItem value={0x0A}>Terminal (0x0A)</MenuItem>
<MenuItem value={0x0F}>Time Module (0x0F)</MenuItem>
<MenuItem value={0x12}>Alarm Module (0x12)</MenuItem>
</SelectValidator>
</Grid>
<Grid item xs={6}>
<TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:120']}
errorMessages={['Tx delay is required', "Must be a number", "Must be 0 or higher", "Max value is 120"]}
name="tx_delay"
label="Tx start delay (seconds)"
fullWidth
variant="outlined"
value={data.tx_delay}
type="number"
onChange={handleValueChange('tx_delay')}
margin="normal"
/>
</Grid>
</Grid>
<br></br>
<Typography variant="h6" color="primary" >
Board Profile
</Typography>
<Box color="warning.main" p={0} mt={0} mb={0}>
<Typography variant="body2">
<i>Select a pre-configured board layout to automatically set the GPIO pins, or set your own custom configuration</i>
</Typography>
</Box>
<SelectValidator name="board_profile"
label="Board Profile"
value={data.board_profile}
fullWidth
variant="outlined"
onChange={this.changeBoardProfile}
margin="normal">
{boardProfileSelectItems()}
<MenuItem key={"CUSTOM"} value={"CUSTOM"}>Custom...</MenuItem>
</SelectValidator>
{ (data.board_profile === "CUSTOM") &&
<Grid container spacing={1} direction="row" justify="flex-start" alignItems="flex-start">
<Grid item xs={4}>
<TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40', 'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$']}
errorMessages={['GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40", "Not a valid GPIO"]}
name="rx_gpio"
label="Rx GPIO"
fullWidth
variant="outlined"
value={data.rx_gpio}
type="number"
onChange={handleValueChange('rx_gpio')}
margin="normal"
/>
</Grid>
<Grid item xs={4}>
<TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40', 'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$']}
errorMessages={['GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40", "Not a valid GPIO"]}
name="tx_gpio"
label="Tx GPIO"
fullWidth
variant="outlined"
value={data.tx_gpio}
type="number"
onChange={handleValueChange('tx_gpio')}
margin="normal"
/>
</Grid>
<Grid item xs={4}>
<TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40', 'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$']}
errorMessages={['GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40", "Not a valid GPIO"]}
name="pbutton_gpio"
label="Button GPIO"
fullWidth
variant="outlined"
value={data.pbutton_gpio}
type="number"
onChange={handleValueChange('pbutton_gpio')}
margin="normal"
/>
</Grid>
<Grid item xs={4}>
<TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40', 'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$']}
errorMessages={['GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40", "Not a valid GPIO"]}
name="dallas_gpio"
label="Dallas GPIO (0=none)"
fullWidth
variant="outlined"
value={data.dallas_gpio}
type="number"
onChange={handleValueChange('dallas_gpio')}
margin="normal"
/>
</Grid>
<Grid item xs={4}>
<TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40', 'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$']}
errorMessages={['GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40", "Not a valid GPIO"]}
name="led_gpio"
label="LED GPIO (0=none)"
fullWidth
variant="outlined"
value={data.led_gpio}
type="number"
onChange={handleValueChange('led_gpio')}
margin="normal"
/>
</Grid>
</Grid>
}
<br></br>
<Typography variant="h6" color="primary" >
Options
</Typography>
{ data.dallas_gpio !== 0 &&
<BlockFormControlLabel
control={
<Checkbox
checked={data.dallas_parasite}
onChange={handleValueChange('dallas_parasite')}
value="dallas_parasite"
/>
}
label="Enable Dallas parasite mode"
/>
}
{ data.led_gpio !== 0 &&
<BlockFormControlLabel
control={
<Checkbox
checked={data.hide_led}
onChange={handleValueChange('hide_led')}
value="hide_led"
/>
}
label = "Hide LED"
/>
}
<Grid container spacing={0} direction="row" justify="flex-start" alignItems="flex-start">
<BlockFormControlLabel
control={
<Checkbox
checked={data.shower_timer}
onChange={handleValueChange('shower_timer')}
value="shower_timer"
/>
}
label="Shower Timer"
/>
{/* <BlockFormControlLabel
control={
<Checkbox
checked={data.shower_alert}
onChange={handleValueChange('shower_alert')}
value="shower_alert"
/>
}
label="Shower Alert"
/> */}
</Grid>
<BlockFormControlLabel
control={
<Checkbox
checked={data.api_enabled}
onChange={handleValueChange('api_enabled')}
value="api_enabled"
/>
}
label="Enable API write commands"
/>
<BlockFormControlLabel
control={
<Checkbox
checked={data.analog_enabled}
onChange={handleValueChange('analog_enabled')}
value="analog_enabled"
/>
}
label="Enable ADC"
/>
<br></br>
<Typography variant="h6" color="primary" >
Syslog
</Typography>
<BlockFormControlLabel
control={
<Checkbox
checked={data.syslog_enabled}
onChange={handleValueChange('syslog_enabled')}
value="syslog_enabled"
/>
}
label="Enable Syslog"
/>
{ data.syslog_enabled &&
<Grid container spacing={1} direction="row" justify="flex-start" alignItems="flex-start">
<Grid item xs={5}>
<TextValidator
validators={['isOptionalIP']}
errorMessages={["Not a valid IP address"]}
name="syslog_host"
label="IP"
fullWidth
variant="outlined"
value={data.syslog_host}
onChange={handleValueChange('syslog_host')}
margin="normal"
/>
</Grid>
<Grid item xs={6}>
<TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']}
errorMessages={['Port is required', "Must be a number", "Must be greater than 0 ", "Max value is 65535"]}
name="syslog_port"
label="Port"
fullWidth
variant="outlined"
value={data.syslog_port}
type="number"
onChange={handleValueChange('syslog_port')}
margin="normal"
/>
</Grid>
<Grid item xs={5}>
<SelectValidator name="syslog_level"
label="Log Level"
value={data.syslog_level}
fullWidth
variant="outlined"
onChange={handleValueChange('syslog_level')}
margin="normal">
<MenuItem value={-1}>OFF</MenuItem>
<MenuItem value={3}>ERR</MenuItem>
<MenuItem value={5}>NOTICE</MenuItem>
<MenuItem value={6}>INFO</MenuItem>
<MenuItem value={7}>DEBUG</MenuItem>
<MenuItem value={8}>ALL</MenuItem>
</SelectValidator>
</Grid>
<Grid item xs={6}>
<TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']}
errorMessages={['Syslog Mark is required', "Must be a number", "Must be 0 or higher", "Max value is 10"]}
name="syslog_mark_interval"
label="Mark Interval seconds (0=off)"
fullWidth
variant="outlined"
value={data.syslog_mark_interval}
type="number"
onChange={handleValueChange('syslog_mark_interval')}
margin="normal"
/>
</Grid>
<BlockFormControlLabel
control={
<Checkbox
checked={data.trace_raw}
onChange={handleValueChange('trace_raw')}
value="trace_raw"
/>
}
label="Output EMS telegrams in raw format"
/>
</Grid>
}
<br></br>
<FormActions>
<FormButton startIcon={<SaveIcon />} variant="contained" color="primary" type="submit">
Save
</FormButton>
</FormActions>
</ValidatorForm >
); );
} this.setState({ processing: false });
});
};
render() {
const { data, saveData, handleValueChange } = this.props;
return (
<ValidatorForm onSubmit={saveData}>
<Box bgcolor="info.main" p={2} mt={2} mb={2}>
<Typography variant="body1">
Modify any of the EMS-ESP settings here. For help refer to the{" "}
<Link
target="_blank"
href="https://emsesp.github.io/docs/#/Configure-firmware32?id=ems-esp-settings"
color="primary"
>
{"online documentation"}
</Link>
.
</Typography>
</Box>
<br></br>
<Typography variant="h6" color="primary">
EMS Bus
</Typography>
<Grid
container
spacing={1}
direction="row"
justify="flex-start"
alignItems="flex-start"
>
<Grid item xs={5}>
<SelectValidator
name="tx_mode"
label="Tx Mode"
value={data.tx_mode}
fullWidth
variant="outlined"
onChange={handleValueChange("tx_mode")}
margin="normal"
>
<MenuItem value={0}>Off</MenuItem>
<MenuItem value={1}>EMS</MenuItem>
<MenuItem value={2}>EMS+</MenuItem>
<MenuItem value={3}>HT3</MenuItem>
<MenuItem value={4}>Hardware</MenuItem>
</SelectValidator>
</Grid>
<Grid item xs={6}>
<SelectValidator
name="ems_bus_id"
label="Bus ID"
value={data.ems_bus_id}
fullWidth
variant="outlined"
onChange={handleValueChange("ems_bus_id")}
margin="normal"
>
<MenuItem value={0x0b}>Service Key (0x0B)</MenuItem>
<MenuItem value={0x0d}>Modem (0x0D)</MenuItem>
<MenuItem value={0x0a}>Terminal (0x0A)</MenuItem>
<MenuItem value={0x0f}>Time Module (0x0F)</MenuItem>
<MenuItem value={0x12}>Alarm Module (0x12)</MenuItem>
</SelectValidator>
</Grid>
<Grid item xs={6}>
<TextValidator
validators={[
"required",
"isNumber",
"minNumber:0",
"maxNumber:120",
]}
errorMessages={[
"Tx delay is required",
"Must be a number",
"Must be 0 or higher",
"Max value is 120",
]}
name="tx_delay"
label="Tx start delay (seconds)"
fullWidth
variant="outlined"
value={data.tx_delay}
type="number"
onChange={handleValueChange("tx_delay")}
margin="normal"
/>
</Grid>
</Grid>
<br></br>
<Typography variant="h6" color="primary">
Board Profile
</Typography>
<Box color="warning.main" p={0} mt={0} mb={0}>
<Typography variant="body2">
<i>
Select a pre-configured board layout to automatically set the GPIO
pins, or set your own custom configuration
</i>
</Typography>
</Box>
<SelectValidator
name="board_profile"
label="Board Profile"
value={data.board_profile}
fullWidth
variant="outlined"
onChange={this.changeBoardProfile}
margin="normal"
>
{boardProfileSelectItems()}
<MenuItem key={"CUSTOM"} value={"CUSTOM"}>
Custom...
</MenuItem>
</SelectValidator>
{data.board_profile === "CUSTOM" && (
<Grid
container
spacing={1}
direction="row"
justify="flex-start"
alignItems="flex-start"
>
<Grid item xs={4}>
<TextValidator
validators={[
"required",
"isNumber",
"minNumber:0",
"maxNumber:40",
"matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$",
]}
errorMessages={[
"GPIO is required",
"Must be a number",
"Must be 0 or higher",
"Max value is 40",
"Not a valid GPIO",
]}
name="rx_gpio"
label="Rx GPIO"
fullWidth
variant="outlined"
value={data.rx_gpio}
type="number"
onChange={handleValueChange("rx_gpio")}
margin="normal"
/>
</Grid>
<Grid item xs={4}>
<TextValidator
validators={[
"required",
"isNumber",
"minNumber:0",
"maxNumber:40",
"matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$",
]}
errorMessages={[
"GPIO is required",
"Must be a number",
"Must be 0 or higher",
"Max value is 40",
"Not a valid GPIO",
]}
name="tx_gpio"
label="Tx GPIO"
fullWidth
variant="outlined"
value={data.tx_gpio}
type="number"
onChange={handleValueChange("tx_gpio")}
margin="normal"
/>
</Grid>
<Grid item xs={4}>
<TextValidator
validators={[
"required",
"isNumber",
"minNumber:0",
"maxNumber:40",
"matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$",
]}
errorMessages={[
"GPIO is required",
"Must be a number",
"Must be 0 or higher",
"Max value is 40",
"Not a valid GPIO",
]}
name="pbutton_gpio"
label="Button GPIO"
fullWidth
variant="outlined"
value={data.pbutton_gpio}
type="number"
onChange={handleValueChange("pbutton_gpio")}
margin="normal"
/>
</Grid>
<Grid item xs={4}>
<TextValidator
validators={[
"required",
"isNumber",
"minNumber:0",
"maxNumber:40",
"matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$",
]}
errorMessages={[
"GPIO is required",
"Must be a number",
"Must be 0 or higher",
"Max value is 40",
"Not a valid GPIO",
]}
name="dallas_gpio"
label="Dallas GPIO (0=none)"
fullWidth
variant="outlined"
value={data.dallas_gpio}
type="number"
onChange={handleValueChange("dallas_gpio")}
margin="normal"
/>
</Grid>
<Grid item xs={4}>
<TextValidator
validators={[
"required",
"isNumber",
"minNumber:0",
"maxNumber:40",
"matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$",
]}
errorMessages={[
"GPIO is required",
"Must be a number",
"Must be 0 or higher",
"Max value is 40",
"Not a valid GPIO",
]}
name="led_gpio"
label="LED GPIO (0=none)"
fullWidth
variant="outlined"
value={data.led_gpio}
type="number"
onChange={handleValueChange("led_gpio")}
margin="normal"
/>
</Grid>
</Grid>
)}
<br></br>
<Typography variant="h6" color="primary">
Options
</Typography>
{data.led_gpio !== 0 && (
<BlockFormControlLabel
control={
<Checkbox
checked={data.hide_led}
onChange={handleValueChange("hide_led")}
value="hide_led"
/>
}
label="Hide LED"
/>
)}
{data.dallas_gpio !== 0 && (
<BlockFormControlLabel
control={
<Checkbox
checked={data.dallas_parasite}
onChange={handleValueChange("dallas_parasite")}
value="dallas_parasite"
/>
}
label="Enable Dallas parasite mode"
/>
)}
<BlockFormControlLabel
control={
<Checkbox
checked={data.api_enabled}
onChange={handleValueChange("api_enabled")}
value="api_enabled"
/>
}
label="Enable API write commands"
/>
<BlockFormControlLabel
control={
<Checkbox
checked={data.analog_enabled}
onChange={handleValueChange("analog_enabled")}
value="analog_enabled"
/>
}
label="Enable ADC"
/>
<Grid
container
spacing={0}
direction="row"
justify="flex-start"
alignItems="flex-start"
>
<BlockFormControlLabel
control={
<Checkbox
checked={data.shower_timer}
onChange={handleValueChange("shower_timer")}
value="shower_timer"
/>
}
label="Enable Shower Timer"
/>
<BlockFormControlLabel
control={
<Checkbox
checked={data.shower_alert}
onChange={handleValueChange("shower_alert")}
value="shower_alert"
/>
}
label="Enable Shower Alert"
/>
</Grid>
<br></br>
<Typography variant="h6" color="primary">
Syslog
</Typography>
<BlockFormControlLabel
control={
<Checkbox
checked={data.syslog_enabled}
onChange={handleValueChange("syslog_enabled")}
value="syslog_enabled"
/>
}
label="Enable Syslog"
/>
{data.syslog_enabled && (
<Grid
container
spacing={1}
direction="row"
justify="flex-start"
alignItems="flex-start"
>
<Grid item xs={5}>
<TextValidator
validators={["isOptionalIP"]}
errorMessages={["Not a valid IP address"]}
name="syslog_host"
label="IP"
fullWidth
variant="outlined"
value={data.syslog_host}
onChange={handleValueChange("syslog_host")}
margin="normal"
/>
</Grid>
<Grid item xs={6}>
<TextValidator
validators={[
"required",
"isNumber",
"minNumber:0",
"maxNumber:65535",
]}
errorMessages={[
"Port is required",
"Must be a number",
"Must be greater than 0 ",
"Max value is 65535",
]}
name="syslog_port"
label="Port"
fullWidth
variant="outlined"
value={data.syslog_port}
type="number"
onChange={handleValueChange("syslog_port")}
margin="normal"
/>
</Grid>
<Grid item xs={5}>
<SelectValidator
name="syslog_level"
label="Log Level"
value={data.syslog_level}
fullWidth
variant="outlined"
onChange={handleValueChange("syslog_level")}
margin="normal"
>
<MenuItem value={-1}>OFF</MenuItem>
<MenuItem value={3}>ERR</MenuItem>
<MenuItem value={5}>NOTICE</MenuItem>
<MenuItem value={6}>INFO</MenuItem>
<MenuItem value={7}>DEBUG</MenuItem>
<MenuItem value={8}>ALL</MenuItem>
</SelectValidator>
</Grid>
<Grid item xs={6}>
<TextValidator
validators={[
"required",
"isNumber",
"minNumber:0",
"maxNumber:65535",
]}
errorMessages={[
"Syslog Mark is required",
"Must be a number",
"Must be 0 or higher",
"Max value is 10",
]}
name="syslog_mark_interval"
label="Mark Interval seconds (0=off)"
fullWidth
variant="outlined"
value={data.syslog_mark_interval}
type="number"
onChange={handleValueChange("syslog_mark_interval")}
margin="normal"
/>
</Grid>
<BlockFormControlLabel
control={
<Checkbox
checked={data.trace_raw}
onChange={handleValueChange("trace_raw")}
value="trace_raw"
/>
}
label="Output EMS telegrams in raw format"
/>
</Grid>
)}
<br></br>
<FormActions>
<FormButton
startIcon={<SaveIcon />}
variant="contained"
color="primary"
type="submit"
>
Save
</FormButton>
</FormActions>
</ValidatorForm>
);
}
} }
export default withAuthenticatedContext(withWidth()(EMSESPSettingsForm)); export default withAuthenticatedContext(withWidth()(EMSESPSettingsForm));

View File

@@ -90,7 +90,7 @@ class MqttSettings {
uint8_t bool_format; uint8_t bool_format;
uint8_t ha_climate_format; uint8_t ha_climate_format;
bool ha_enabled; bool ha_enabled;
bool nested_format; uint8_t nested_format;
uint8_t subscribe_format; uint8_t subscribe_format;
static void read(MqttSettings & settings, JsonObject & root); static void read(MqttSettings & settings, JsonObject & root);

View File

@@ -33,7 +33,7 @@ class DummySettings {
bool mqtt_retain = false; bool mqtt_retain = false;
bool enabled = true; bool enabled = true;
uint8_t dallas_format = 1; uint8_t dallas_format = 1;
bool nested_format = true; uint8_t nested_format = 1;
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

@@ -72,7 +72,7 @@ const mqtt_settings = {
"client_id": "ems-esp32", "keep_alive": 60, "clean_session": true, "max_topic_length": 128, "client_id": "ems-esp32", "keep_alive": 60, "clean_session": true, "max_topic_length": 128,
"publish_time_boiler": 10, "publish_time_thermostat": 10, "publish_time_solar": 10, "publish_time_mixer": 10, "publish_time_boiler": 10, "publish_time_thermostat": 10, "publish_time_solar": 10, "publish_time_mixer": 10,
"publish_time_other": 10, "publish_time_sensor": 10, "mqtt_qos": 0, "mqtt_retain": false, "dallas_format": 1, "publish_time_other": 10, "publish_time_sensor": 10, "mqtt_qos": 0, "mqtt_retain": false, "dallas_format": 1,
"bool_format": 1, "ha_climate_format": 1, "ha_enabled": true, "nested_format": true, "subscribe_format": 0 "bool_format": 1, "ha_climate_format": 1, "ha_enabled": true, "nested_format": 1, "subscribe_format": 0
}; };
const mqtt_status = { const mqtt_status = {
"enabled": true, "connected": true, "client_id": "ems-esp32", "disconnect_reason": 0, "mqtt_fails": 0 "enabled": true, "connected": true, "client_id": "ems-esp32", "disconnect_reason": 0, "mqtt_fails": 0

View File

@@ -145,7 +145,7 @@
#endif #endif
#ifndef EMSESP_DEFAULT_NESTED_FORMAT #ifndef EMSESP_DEFAULT_NESTED_FORMAT
#define EMSESP_DEFAULT_NESTED_FORMAT true #define EMSESP_DEFAULT_NESTED_FORMAT 1
#endif #endif
#ifndef EMSESP_DEFAULT_SUBSCRIBE_FORMAT #ifndef EMSESP_DEFAULT_SUBSCRIBE_FORMAT

View File

@@ -376,7 +376,7 @@ void Thermostat::register_mqtt_ha_config_hc(uint8_t hc_num) {
doc["~"] = Mqtt::base(); // ems-esp doc["~"] = Mqtt::base(); // ems-esp
char topic_t[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
if (Mqtt::nested_format()) { if (Mqtt::nested_format() == 1) {
snprintf_P(topic_t, sizeof(topic_t), PSTR("~/%s"), Mqtt::tag_to_topic(EMSdevice::DeviceType::THERMOSTAT, DeviceValueTAG::TAG_NONE).c_str()); snprintf_P(topic_t, sizeof(topic_t), PSTR("~/%s"), Mqtt::tag_to_topic(EMSdevice::DeviceType::THERMOSTAT, DeviceValueTAG::TAG_NONE).c_str());
char mode_str_tpl[40]; char mode_str_tpl[40];
@@ -1148,7 +1148,7 @@ bool Thermostat::set_building(const char * value, const int8_t id) {
if ((model() == EMS_DEVICE_FLAG_RC300) || (model() == EMS_DEVICE_FLAG_RC100)) { if ((model() == EMS_DEVICE_FLAG_RC300) || (model() == EMS_DEVICE_FLAG_RC100)) {
if (Helpers::value2enum(value, bd, FL_(enum_ibaBuildingType))) { if (Helpers::value2enum(value, bd, FL_(enum_ibaBuildingType))) {
LOG_INFO(F("Setting building to %s"), value); LOG_INFO(F("Setting building to %s"), value);
write_command(0x240, 9, bd , 0x240); write_command(0x240, 9, bd, 0x240);
return true; return true;
} }
} else { } else {

View File

@@ -435,7 +435,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;
bool nested = Mqtt::nested_format(); uint8_t nested = Mqtt::nested_format();
// group by device type // group by device type
for (const auto & emsdevice : emsdevices) { for (const auto & emsdevice : emsdevices) {

View File

@@ -39,7 +39,7 @@ uint8_t Mqtt::dallas_format_;
uint8_t Mqtt::bool_format_; uint8_t Mqtt::bool_format_;
uint8_t Mqtt::ha_climate_format_; uint8_t Mqtt::ha_climate_format_;
bool Mqtt::ha_enabled_; bool Mqtt::ha_enabled_;
bool Mqtt::nested_format_; uint8_t Mqtt::nested_format_;
uint8_t Mqtt::subscribe_format_; uint8_t Mqtt::subscribe_format_;
std::deque<Mqtt::QueuedMqttMessage> Mqtt::mqtt_messages_; std::deque<Mqtt::QueuedMqttMessage> Mqtt::mqtt_messages_;
@@ -898,7 +898,7 @@ void Mqtt::publish_mqtt_ha_sensor(uint8_t type, // EMSdevice
DynamicJsonDocument doc(EMSESP_JSON_SIZE_HA_CONFIG); DynamicJsonDocument doc(EMSESP_JSON_SIZE_HA_CONFIG);
bool have_tag = !EMSdevice::tag_to_string(tag).empty() && (device_type != EMSdevice::DeviceType::BOILER); // ignore boiler bool have_tag = !EMSdevice::tag_to_string(tag).empty() && (device_type != EMSdevice::DeviceType::BOILER); // ignore boiler
bool is_nested = nested_format_ || (device_type == EMSdevice::DeviceType::BOILER); // boiler never uses nested bool is_nested = (nested_format_ == 1) || (device_type == EMSdevice::DeviceType::BOILER); // boiler never uses nested
// create entity by add the tag if present, seperating with a . // create entity by add the tag if present, seperating with a .
char new_entity[50]; char new_entity[50];
@@ -1005,7 +1005,7 @@ const std::string Mqtt::tag_to_topic(uint8_t device_type, uint8_t tag) {
} }
// if there is a tag add it // if there is a tag add it
if ((EMSdevice::tag_to_mqtt(tag).empty()) || (nested_format_ && (device_type != EMSdevice::DeviceType::BOILER))) { if ((EMSdevice::tag_to_mqtt(tag).empty()) || ((nested_format_ == 1) && (device_type != EMSdevice::DeviceType::BOILER))) {
return EMSdevice::device_type_2_device_name(device_type) + "_data"; return EMSdevice::device_type_2_device_name(device_type) + "_data";
} else { } else {
return EMSdevice::device_type_2_device_name(device_type) + "_data_" + EMSdevice::tag_to_mqtt(tag); return EMSdevice::device_type_2_device_name(device_type) + "_data_" + EMSdevice::tag_to_mqtt(tag);

View File

@@ -158,11 +158,11 @@ class Mqtt {
return bool_format_; return bool_format_;
} }
static bool nested_format() { static uint8_t nested_format() {
return nested_format_; return nested_format_;
} }
static void nested_format(bool nested_format) { static void nested_format(uint8_t nested_format) {
nested_format_ = nested_format; nested_format_ = nested_format;
} }
@@ -274,7 +274,7 @@ class Mqtt {
static uint8_t bool_format_; static uint8_t bool_format_;
static uint8_t ha_climate_format_; static uint8_t ha_climate_format_;
static bool ha_enabled_; static bool ha_enabled_;
static bool nested_format_; static uint8_t nested_format_;
static uint8_t subscribe_format_; static uint8_t subscribe_format_;
}; };

View File

@@ -376,7 +376,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
if (command == "boiler") { if (command == "boiler") {
shell.printfln(F("Testing boiler...")); shell.printfln(F("Testing boiler..."));
Mqtt::ha_enabled(false); Mqtt::ha_enabled(false);
Mqtt::nested_format(true); Mqtt::nested_format(1);
run_test("boiler"); run_test("boiler");
shell.invoke_command("show devices"); shell.invoke_command("show devices");
@@ -414,8 +414,8 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
if (command == "ha") { if (command == "ha") {
shell.printfln(F("Testing HA discovery")); shell.printfln(F("Testing HA discovery"));
Mqtt::ha_enabled(true); Mqtt::ha_enabled(true);
// Mqtt::nested_format(true); // Mqtt::nested_format(1);
Mqtt::nested_format(false); Mqtt::nested_format(2);
// run_test("boiler"); // run_test("boiler");
run_test("thermostat"); run_test("thermostat");
@@ -436,11 +436,11 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
run_test("mixer"); run_test("mixer");
// first with nested // first with nested
Mqtt::nested_format(true); Mqtt::nested_format(1);
shell.invoke_command("call system publish"); shell.invoke_command("call system publish");
// then without nested // then without nested
Mqtt::nested_format(false); 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");
} }