Merge pull request #217 from proddy:dev

text changes, renamed status to bus_status in heartbeat, improved WebUI table layout, added Ethernet phy to custom profile board
This commit is contained in:
Proddy
2021-11-22 09:11:41 +01:00
committed by GitHub
16 changed files with 213 additions and 169 deletions

View File

@@ -21,6 +21,7 @@
- Support for non-standard Thermostats like Tado [#174](https://github.com/emsesp/EMS-ESP32/issues/174) - Support for non-standard Thermostats like Tado [#174](https://github.com/emsesp/EMS-ESP32/issues/174)
- Include MQTT connection status in 'api/system/info' - Include MQTT connection status in 'api/system/info'
- Include Network status in 'api/system/info' and also the MQTT topic `info` [#202](https://github.com/emsesp/EMS-ESP32/issues/202) - Include Network status in 'api/system/info' and also the MQTT topic `info` [#202](https://github.com/emsesp/EMS-ESP32/issues/202)
- Added Ethernet PHY module as an option in the Board Profile [#210](https://github.com/emsesp/EMS-ESP32/issues/210)
## Fixed ## Fixed
@@ -47,6 +48,7 @@
- Removed settings for MQTT subscribe format [#173](https://github.com/emsesp/EMS-ESP32/issues/173) - Removed settings for MQTT subscribe format [#173](https://github.com/emsesp/EMS-ESP32/issues/173)
- Improve Nefit Moduline 200 functionality [#183](https://github.com/emsesp/EMS-ESP32/issues/183) - Improve Nefit Moduline 200 functionality [#183](https://github.com/emsesp/EMS-ESP32/issues/183)
- `status` in the MQTT heartbeat renamed to `bus_status` - `status` in the MQTT heartbeat renamed to `bus_status`
- Layout changes in the WebUI, showing stripped table rows in Dashboard
## **BREAKING CHANGES** ## **BREAKING CHANGES**
@@ -57,4 +59,3 @@
- `txread` renamed to `txreads` and `txwrite` renamed to `txwrites` in MQTT heartbeat payload - `txread` renamed to `txreads` and `txwrite` renamed to `txwrites` in MQTT heartbeat payload
- 'dallas sensors' in api/system/info moved to the "System" section. Renamed "uptime (seconds)" and "reset reason" - 'dallas sensors' in api/system/info moved to the "System" section. Renamed "uptime (seconds)" and "reset reason"
- `status` in the MQTT heartbeat renamed to `bus_status` - `status` in the MQTT heartbeat renamed to `bus_status`

View File

@@ -10,9 +10,7 @@ export const BOARD_PROFILES: BoardProfiles = {
NODEMCU: 'NodeMCU 32S', NODEMCU: 'NodeMCU 32S',
'MH-ET': 'MH-ET Live D1 Mini', 'MH-ET': 'MH-ET Live D1 Mini',
LOLIN: 'Lolin D32', LOLIN: 'Lolin D32',
OLIMEX: 'Olimex ESP32-EVB', OLIMEX: 'Olimex ESP32-EVB'
TLK110: 'Generic Ethernet (TLK110)',
LAN8720: 'Generic Ethernet (LAN8720)'
}; };
export function boardProfileSelectItems() { export function boardProfileSelectItems() {

View File

@@ -59,19 +59,32 @@ export const DEVICE_DATA_ENDPOINT = ENDPOINT_ROOT + 'deviceData';
export const WRITE_VALUE_ENDPOINT = ENDPOINT_ROOT + 'writeValue'; export const WRITE_VALUE_ENDPOINT = ENDPOINT_ROOT + 'writeValue';
export const WRITE_SENSOR_ENDPOINT = ENDPOINT_ROOT + 'writeSensor'; export const WRITE_SENSOR_ENDPOINT = ENDPOINT_ROOT + 'writeSensor';
const StyledTableCell = withStyles((theme: Theme) => const StyledTableRow = withStyles((theme: Theme) =>
createStyles({ createStyles({
head: { root: {
backgroundColor: theme.palette.common.black, '&:nth-child(even)': {
color: theme.palette.common.white backgroundColor: '#4e4e4e'
}, },
body: { '&:hover': {
fontSize: 14 backgroundColor: theme.palette.info.light
}
},
selected: {
backgroundColor: theme.palette.common.white
} }
}) })
)(TableCell); )(TableRow);
const CustomTooltip = withStyles((theme: Theme) => ({ const StyledTableRowHeader = withStyles((theme: Theme) =>
createStyles({
head: {
backgroundColor: theme.palette.common.black
}
})
)(TableRow);
const StyledTooltip = withStyles((theme: Theme) => ({
tooltip: { tooltip: {
backgroundColor: theme.palette.secondary.main, backgroundColor: theme.palette.secondary.main,
color: 'white', color: 'white',
@@ -304,7 +317,7 @@ class EMSESPDataForm extends Component<
return (this.state.deviceData?.data || []).length === 0; return (this.state.deviceData?.data || []).length === 0;
}; };
renderDeviceItems() { renderDevices() {
const { width, data } = this.props; const { width, data } = this.props;
return ( return (
<TableContainer> <TableContainer>
@@ -325,7 +338,7 @@ class EMSESPDataForm extends Component<
onClick={() => this.handleRowClick(device.i)} onClick={() => this.handleRowClick(device.i)}
> >
<TableCell> <TableCell>
<CustomTooltip <StyledTooltip
title={ title={
'DeviceID:0x' + 'DeviceID:0x' +
('00' + device.d.toString(16).toUpperCase()).slice(-2) + ('00' + device.d.toString(16).toUpperCase()).slice(-2) +
@@ -343,7 +356,7 @@ class EMSESPDataForm extends Component<
> >
{device.t} {device.t}
</Button> </Button>
</CustomTooltip> </StyledTooltip>
</TableCell> </TableCell>
<TableCell align="right"> <TableCell align="right">
{device.b + ' ' + device.n}{' '} {device.b + ' ' + device.n}{' '}
@@ -371,7 +384,7 @@ class EMSESPDataForm extends Component<
); );
} }
renderSensorItems() { renderSensorData() {
const { data } = this.props; const { data } = this.props;
const me = this.props.authenticatedContext.me; const me = this.props.authenticatedContext.me;
return ( return (
@@ -383,26 +396,22 @@ class EMSESPDataForm extends Component<
{!this.noSensors() && ( {!this.noSensors() && (
<Table size="small" padding="normal"> <Table size="small" padding="normal">
<TableHead> <TableHead>
<TableRow> <StyledTableRowHeader>
<StyledTableCell <TableCell padding="checkbox" style={{ width: 18 }}></TableCell>
padding="checkbox" <TableCell>Dallas Sensor #</TableCell>
style={{ width: 18 }} <TableCell align="left">ID / Name</TableCell>
></StyledTableCell> <TableCell align="right">Temperature</TableCell>
<StyledTableCell>Sensor #</StyledTableCell> </StyledTableRowHeader>
<StyledTableCell align="left">ID / Name</StyledTableCell>
<StyledTableCell align="right">Temperature</StyledTableCell>
</TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{data.sensors.map((sensorData) => ( {data.sensors.map((sensorData) => (
<TableRow <StyledTableRow
key={sensorData.n} key={sensorData.n}
hover
onClick={() => this.sendSensor(sensorData)} onClick={() => this.sendSensor(sensorData)}
> >
<TableCell padding="checkbox" style={{ width: 18 }}> <TableCell padding="checkbox">
{me.admin && ( {me.admin && (
<CustomTooltip title="edit" placement="left-end"> <StyledTooltip title="edit" placement="left-end">
<IconButton <IconButton
edge="start" edge="start"
size="small" size="small"
@@ -411,7 +420,7 @@ class EMSESPDataForm extends Component<
> >
<EditIcon color="primary" fontSize="small" /> <EditIcon color="primary" fontSize="small" />
</IconButton> </IconButton>
</CustomTooltip> </StyledTooltip>
)} )}
</TableCell> </TableCell>
<TableCell component="th" scope="row"> <TableCell component="th" scope="row">
@@ -421,7 +430,7 @@ class EMSESPDataForm extends Component<
<TableCell align="right"> <TableCell align="right">
{formatValue(sensorData.t, DeviceValueUOM.DEGREES)} {formatValue(sensorData.t, DeviceValueUOM.DEGREES)}
</TableCell> </TableCell>
</TableRow> </StyledTableRow>
))} ))}
</TableBody> </TableBody>
</Table> </Table>
@@ -437,20 +446,23 @@ class EMSESPDataForm extends Component<
); );
} }
renderAnalog() { renderAnalogData() {
const { data } = this.props; const { data } = this.props;
return ( return (
<TableContainer> <TableContainer>
<p></p>
{data.analog > 0 && ( {data.analog > 0 && (
<Table size="small" padding="normal"> <Table size="small" padding="normal">
<TableHead> <TableHead>
<TableRow> <StyledTableRowHeader>
<StyledTableCell>Sensortype</StyledTableCell> <TableCell padding="normal" style={{ width: 18 }}></TableCell>
<StyledTableCell align="right">Value</StyledTableCell> <TableCell>Sensor Type</TableCell>
</TableRow> <TableCell align="right">Value</TableCell>
</StyledTableRowHeader>
</TableHead> </TableHead>
<TableBody> <TableBody>
<TableRow> <TableRow>
<TableCell padding="normal">&nbsp;&nbsp;</TableCell>
<TableCell component="th" scope="row"> <TableCell component="th" scope="row">
Analog Input Analog Input
</TableCell> </TableCell>
@@ -575,7 +587,7 @@ class EMSESPDataForm extends Component<
<p></p> <p></p>
<Box bgcolor="info.main" p={1} mt={1} mb={1}> <Box bgcolor="info.main" p={1} mt={1} mb={1}>
<Typography variant="body1" color="initial"> <Typography variant="body1" color="initial">
{deviceData.name} {deviceData.type}&nbsp;Data
</Typography> </Typography>
</Box> </Box>
{!this.noDeviceData() && ( {!this.noDeviceData() && (
@@ -584,17 +596,15 @@ class EMSESPDataForm extends Component<
size="small" size="small"
padding={isWidthDown('xs', width!) ? 'none' : 'normal'} padding={isWidthDown('xs', width!) ? 'none' : 'normal'}
> >
<TableHead></TableHead>
<TableBody> <TableBody>
{deviceData.data.map((item, i) => ( {deviceData.data.map((item, i) => (
<TableRow <StyledTableRow
hover
key={i} key={i}
onClick={() => this.sendCommand(item)} onClick={() => this.sendCommand(item)}
> >
<TableCell padding="checkbox" style={{ width: 18 }}> <TableCell padding="checkbox" style={{ width: 18 }}>
{item.c && this.props.authenticatedContext.me.admin && ( {item.c && this.props.authenticatedContext.me.admin && (
<CustomTooltip <StyledTooltip
title="change value" title="change value"
placement="left-end" placement="left-end"
> >
@@ -606,7 +616,7 @@ class EMSESPDataForm extends Component<
> >
<EditIcon color="primary" fontSize="small" /> <EditIcon color="primary" fontSize="small" />
</IconButton> </IconButton>
</CustomTooltip> </StyledTooltip>
)} )}
</TableCell> </TableCell>
<TableCell padding="none" component="th" scope="row"> <TableCell padding="none" component="th" scope="row">
@@ -615,7 +625,7 @@ class EMSESPDataForm extends Component<
<TableCell padding="none" align="right"> <TableCell padding="none" align="right">
{formatValue(item.v, item.u)} {formatValue(item.v, item.u)}
</TableCell> </TableCell>
</TableRow> </StyledTableRow>
))} ))}
</TableBody> </TableBody>
</Table> </Table>
@@ -637,10 +647,10 @@ class EMSESPDataForm extends Component<
return ( return (
<Fragment> <Fragment>
<br></br> <br></br>
{this.renderDeviceItems()} {this.renderDevices()}
{this.renderDeviceData()} {this.renderDeviceData()}
{this.renderSensorItems()} {this.renderSensorData()}
{this.renderAnalog()} {this.renderAnalogData()}
<br></br> <br></br>
<Box display="flex" flexWrap="wrap"> <Box display="flex" flexWrap="wrap">
<Box flexGrow={1} padding={1}> <Box flexGrow={1} padding={1}>

View File

@@ -93,6 +93,7 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
rx_gpio: json.rx_gpio, rx_gpio: json.rx_gpio,
tx_gpio: json.tx_gpio, tx_gpio: json.tx_gpio,
pbutton_gpio: json.pbutton_gpio, pbutton_gpio: json.pbutton_gpio,
phy_type: json.phy_type,
board_profile: event.target.value board_profile: event.target.value
}); });
this.setState({ processing: false }); this.setState({ processing: false });
@@ -306,7 +307,7 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
'Not a valid GPIO' 'Not a valid GPIO'
]} ]}
name="dallas_gpio" name="dallas_gpio"
label="Dallas GPIO (0=none)" label="Dallas GPIO (0=disabled)"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.dallas_gpio} value={data.dallas_gpio}
@@ -332,7 +333,7 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
'Not a valid GPIO' 'Not a valid GPIO'
]} ]}
name="led_gpio" name="led_gpio"
label="LED GPIO (0=none)" label="LED GPIO (0=disabled)"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.led_gpio} value={data.led_gpio}
@@ -341,6 +342,21 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
margin="normal" margin="normal"
/> />
</Grid> </Grid>
<Grid item xs={4}>
<SelectValidator
name="phy_type"
label="PHY Module Type"
value={data.phy_type}
fullWidth
variant="outlined"
onChange={handleValueChange('phy_type')}
margin="normal"
>
<MenuItem value={0}>No Ethernet</MenuItem>
<MenuItem value={1}>LAN8720</MenuItem>
<MenuItem value={2}>TLK110</MenuItem>
</SelectValidator>
</Grid>
</Grid> </Grid>
)} )}

View File

@@ -11,6 +11,7 @@ export interface EMSESPSettings {
shower_alert: boolean; shower_alert: boolean;
rx_gpio: number; rx_gpio: number;
tx_gpio: number; tx_gpio: number;
phy_type: number;
dallas_gpio: number; dallas_gpio: number;
dallas_parasite: boolean; dallas_parasite: boolean;
led_gpio: number; led_gpio: number;
@@ -72,7 +73,7 @@ export interface DeviceValue {
} }
export interface EMSESPDeviceData { export interface EMSESPDeviceData {
name: string; type: string;
data: DeviceValue[]; data: DeviceValue[];
} }

View File

@@ -291,7 +291,8 @@ const EMSESP_STATUS_ENDPOINT = REST_ENDPOINT_ROOT + 'emsespStatus'
const EMSESP_BOARDPROFILE_ENDPOINT = REST_ENDPOINT_ROOT + 'boardProfile' const EMSESP_BOARDPROFILE_ENDPOINT = REST_ENDPOINT_ROOT + 'boardProfile'
const WRITE_VALUE_ENDPOINT = REST_ENDPOINT_ROOT + 'writeValue' const WRITE_VALUE_ENDPOINT = REST_ENDPOINT_ROOT + 'writeValue'
const WRITE_SENSOR_ENDPOINT = REST_ENDPOINT_ROOT + 'writeSensor' const WRITE_SENSOR_ENDPOINT = REST_ENDPOINT_ROOT + 'writeSensor'
const emsesp_settings = {
emsesp_settings = {
tx_mode: 1, tx_mode: 1,
ems_bus_id: 11, ems_bus_id: 11,
syslog_enabled: false, syslog_enabled: false,
@@ -305,6 +306,7 @@ const emsesp_settings = {
shower_alert: false, shower_alert: false,
rx_gpio: 23, rx_gpio: 23,
tx_gpio: 5, tx_gpio: 5,
phy_type: 0,
dallas_gpio: 3, dallas_gpio: 3,
dallas_parasite: false, dallas_parasite: false,
led_gpio: 2, led_gpio: 2,
@@ -351,6 +353,7 @@ const emsesp_data = {
{ n: 1, i: '28-233D-9497-0C03', t: 25.7, o: 1.2 }, { n: 1, i: '28-233D-9497-0C03', t: 25.7, o: 1.2 },
{ n: 2, i: '28-243D-7437-1E3A', t: 26.1, o: 0 }, { n: 2, i: '28-243D-7437-1E3A', t: 26.1, o: 0 },
], ],
analog: 12,
} }
const emsesp_status = { const emsesp_status = {
@@ -362,7 +365,7 @@ const emsesp_status = {
} }
const emsesp_devicedata_1 = { const emsesp_devicedata_1 = {
name: 'Thermostat: RC20/Moduline 300', type: 'Thermostat',
data: [ data: [
{ {
v: '(0)', v: '(0)',
@@ -398,7 +401,7 @@ const emsesp_devicedata_1 = {
} }
const emsesp_devicedata_2 = { const emsesp_devicedata_2 = {
name: 'Boiler: Nefit GBx72/Trendline/Cerapur/Greenstar Si/27i', type: 'Boiler',
data: [ data: [
{ v: 'off', u: 0, n: 'heating active' }, { v: 'off', u: 0, n: 'heating active' },
{ v: 'off', u: 0, n: 'warm water active' }, { v: 'off', u: 0, n: 'warm water active' },
@@ -523,7 +526,7 @@ const emsesp_devicedata_2 = {
} }
const emsesp_devicedata_3 = { const emsesp_devicedata_3 = {
name: 'Controller: BC1', type: 'Controller',
data: [], data: [],
} }
@@ -650,6 +653,8 @@ app.get(EMSESP_SETTINGS_ENDPOINT, (req, res) => {
res.json(emsesp_settings) res.json(emsesp_settings)
}) })
app.post(EMSESP_SETTINGS_ENDPOINT, (req, res) => { app.post(EMSESP_SETTINGS_ENDPOINT, (req, res) => {
console.log(req.body)
emsesp_settings = req.body
res.json(emsesp_settings) res.json(emsesp_settings)
}) })
app.get(EMSESP_DATA_ENDPOINT, (req, res) => { app.get(EMSESP_DATA_ENDPOINT, (req, res) => {
@@ -705,6 +710,7 @@ app.post(EMSESP_BOARDPROFILE_ENDPOINT, (req, res) => {
rx_gpio: 3, rx_gpio: 3,
tx_gpio: 4, tx_gpio: 4,
pbutton_gpio: 5, pbutton_gpio: 5,
phy_type: 0,
} }
if (board_profile == 'S32') { if (board_profile == 'S32') {
@@ -714,6 +720,7 @@ app.post(EMSESP_BOARDPROFILE_ENDPOINT, (req, res) => {
data.rx_gpio = 23 data.rx_gpio = 23
data.tx_gpio = 5 data.tx_gpio = 5
data.pbutton_gpio = 0 data.pbutton_gpio = 0
data.phy_type = 0
} else if (board_profile == 'E32') { } else if (board_profile == 'E32') {
// BBQKees Gateway E32 // BBQKees Gateway E32
data.led_gpio = 2 data.led_gpio = 2
@@ -721,6 +728,7 @@ app.post(EMSESP_BOARDPROFILE_ENDPOINT, (req, res) => {
data.rx_gpio = 5 data.rx_gpio = 5
data.tx_gpio = 17 data.tx_gpio = 17
data.pbutton_gpio = 33 data.pbutton_gpio = 33
data.phy_type = 1
} else if (board_profile == 'MH-ET') { } else if (board_profile == 'MH-ET') {
// MH-ET Live D1 Mini // MH-ET Live D1 Mini
data.led_gpio = 2 data.led_gpio = 2
@@ -728,6 +736,7 @@ app.post(EMSESP_BOARDPROFILE_ENDPOINT, (req, res) => {
data.rx_gpio = 23 data.rx_gpio = 23
data.tx_gpio = 5 data.tx_gpio = 5
data.pbutton_gpio = 0 data.pbutton_gpio = 0
data.phy_type = 0
} else if (board_profile == 'NODEMCU') { } else if (board_profile == 'NODEMCU') {
// NodeMCU 32S // NodeMCU 32S
data.led_gpio = 2 data.led_gpio = 2
@@ -735,6 +744,7 @@ app.post(EMSESP_BOARDPROFILE_ENDPOINT, (req, res) => {
data.rx_gpio = 23 data.rx_gpio = 23
data.tx_gpio = 5 data.tx_gpio = 5
data.pbutton_gpio = 0 data.pbutton_gpio = 0
data.phy_type = 0
} else if (board_profile == 'LOLIN') { } else if (board_profile == 'LOLIN') {
// Lolin D32 // Lolin D32
data.led_gpio = 2 data.led_gpio = 2
@@ -742,6 +752,7 @@ app.post(EMSESP_BOARDPROFILE_ENDPOINT, (req, res) => {
data.rx_gpio = 17 data.rx_gpio = 17
data.tx_gpio = 16 data.tx_gpio = 16
data.pbutton_gpio = 0 data.pbutton_gpio = 0
data.phy_type = 0
} else if (board_profile == 'OLIMEX') { } else if (board_profile == 'OLIMEX') {
// Olimex ESP32-EVB (uses U1TXD/U1RXD/BUTTON, no LED or Dallas) // Olimex ESP32-EVB (uses U1TXD/U1RXD/BUTTON, no LED or Dallas)
data.led_gpio = 0 data.led_gpio = 0
@@ -749,21 +760,7 @@ app.post(EMSESP_BOARDPROFILE_ENDPOINT, (req, res) => {
data.rx_gpio = 36 data.rx_gpio = 36
data.tx_gpio = 4 data.tx_gpio = 4
data.pbutton_gpio = 34 data.pbutton_gpio = 34
// data = { 0, 0, 36, 4, 34}; data.phy_type = 1
} else if (board_profile == 'TLK110') {
// Generic Ethernet (TLK110)
data.led_gpio = 2
data.dallas_gpio = 4
data.rx_gpio = 5
data.tx_gpio = 17
data.pbutton_gpio = 33
} else if (board_profile == 'LAN8720') {
// Generic Ethernet (LAN8720)
data.led_gpio = 2
data.dallas_gpio = 4
data.rx_gpio = 5
data.tx_gpio = 17
data.pbutton_gpio = 33
} }
res.json(data) res.json(data)

View File

@@ -762,8 +762,8 @@ void Console::load_system_commands(unsigned int context) {
EMSESP::dallassensor_.update(arguments.front().c_str(), arguments[1].c_str(), offset); EMSESP::dallassensor_.update(arguments.front().c_str(), arguments[1].c_str(), offset);
}); });
EMSESPShell::commands EMSESPShell::commands->add_command(
->add_command(context, context,
CommandFlags::ADMIN, CommandFlags::ADMIN,
flash_string_vector{F_(set), F_(board_profile)}, flash_string_vector{F_(set), F_(board_profile)},
flash_string_vector{F_(name_mandatory)}, flash_string_vector{F_(name_mandatory)},
@@ -771,7 +771,7 @@ void Console::load_system_commands(unsigned int context) {
std::vector<uint8_t> data; // led, dallas, rx, tx, button std::vector<uint8_t> data; // led, dallas, rx, tx, button
std::string board_profile = Helpers::toUpper(arguments.front()); std::string board_profile = Helpers::toUpper(arguments.front());
if (!EMSESP::system_.load_board_profile(data, board_profile)) { if (!EMSESP::system_.load_board_profile(data, board_profile)) {
shell.println(F("Invalid board profile (S32, E32, MH-ET, NODEMCU, OLIMEX, TLK110, LAN8720, CUSTOM)")); shell.println(F("Invalid board profile (S32, E32, MH-ET, NODEMCU, OLIMEX, CUSTOM)"));
return; return;
} }
EMSESP::webSettingsService.update( EMSESP::webSettingsService.update(
@@ -782,10 +782,11 @@ void Console::load_system_commands(unsigned int context) {
settings.rx_gpio = data[2]; settings.rx_gpio = data[2];
settings.tx_gpio = data[3]; settings.tx_gpio = data[3];
settings.pbutton_gpio = data[4]; settings.pbutton_gpio = data[4];
settings.phy_type = data[5];
return StateUpdateResult::CHANGED; return StateUpdateResult::CHANGED;
}, },
"local"); "local");
shell.printfln("Loaded board profile %s (%d,%d,%d,%d,%d)", board_profile.c_str(), data[0], data[1], data[2], data[3], data[4]); shell.printfln("Loaded board profile %s (%d,%d,%d,%d,%d,%d)", board_profile.c_str(), data[0], data[1], data[2], data[3], data[4], data[5]);
EMSESP::system_.network_init(true); EMSESP::system_.network_init(true);
}); });
EMSESPShell::commands->add_command(context, EMSESPShell::commands->add_command(context,

View File

@@ -92,7 +92,7 @@
#define EMSESP_DEFAULT_BOARD_PROFILE "S32" // Gateway S32 #define EMSESP_DEFAULT_BOARD_PROFILE "S32" // Gateway S32
#endif #endif
// Default GPIO PIN definitions - based on Wemos/Nodemcu // Default GPIO PIN definitions
#ifndef EMSESP_DEFAULT_RX_GPIO #ifndef EMSESP_DEFAULT_RX_GPIO
#define EMSESP_DEFAULT_RX_GPIO 23 // D7 #define EMSESP_DEFAULT_RX_GPIO 23 // D7
@@ -114,6 +114,10 @@
#define EMSESP_DEFAULT_PBUTTON_GPIO 0 #define EMSESP_DEFAULT_PBUTTON_GPIO 0
#endif #endif
#ifndef EMSESP_DEFAULT_PHY_TYPE
#define EMSESP_DEFAULT_PHY_TYPE 0 // No Ethernet, just Wifi
#endif
// MQTT // MQTT
#ifndef EMSESP_DEFAULT_BOOL_FORMAT #ifndef EMSESP_DEFAULT_BOOL_FORMAT

View File

@@ -616,7 +616,7 @@ const std::string EMSdevice::get_value_uom(const char * key) {
// except additional data is stored in the JSON document needed for the Web UI like the UOM and command // except additional data is stored in the JSON document needed for the Web UI like the UOM and command
// v = value, u=uom, n=name, c=cmd // v = value, u=uom, n=name, c=cmd
void EMSdevice::generate_values_json_web(JsonObject & output) { void EMSdevice::generate_values_json_web(JsonObject & output) {
output["name"] = to_string_short(); output["type"] = device_type_name();
JsonArray data = output.createNestedArray("data"); JsonArray data = output.createNestedArray("data");
for (const auto & dv : devicevalues_) { for (const auto & dv : devicevalues_) {

View File

@@ -147,9 +147,9 @@ MAKE_PSTR(password_prompt, "Password: ")
MAKE_PSTR(unset, "<unset>") MAKE_PSTR(unset, "<unset>")
// command descriptions // command descriptions
MAKE_PSTR(info_cmd, "list all values") MAKE_PSTR(info_cmd, "lists all values")
MAKE_PSTR(commands_cmd, "list all commands") MAKE_PSTR(commands_cmd, "lists all commands")
MAKE_PSTR(entities_cmd, "list all entities") MAKE_PSTR(entities_cmd, "lists all entities")
MAKE_PSTR_WORD(number) MAKE_PSTR_WORD(number)
MAKE_PSTR_WORD(enum) MAKE_PSTR_WORD(enum)

View File

@@ -580,7 +580,7 @@ void Mqtt::ha_status() {
doc["stat_t"] = FJSON("~/heartbeat"); doc["stat_t"] = FJSON("~/heartbeat");
doc["name"] = FJSON("EMS-ESP status"); doc["name"] = FJSON("EMS-ESP status");
doc["ic"] = F_(icondevice); doc["ic"] = F_(icondevice);
doc["val_tpl"] = FJSON("{{value_json['status']}}"); doc["val_tpl"] = FJSON("{{value_json['bus_status']}}");
JsonObject dev = doc.createNestedObject("dev"); JsonObject dev = doc.createNestedObject("dev");
dev["name"] = F_(EMSESP); // "EMS-ESP" dev["name"] = F_(EMSESP); // "EMS-ESP"

View File

@@ -234,7 +234,7 @@ void System::syslog_start() {
syslog_.hostname(hostname().c_str()); syslog_.hostname(hostname().c_str());
// register the command // register the command
Command::add(EMSdevice::DeviceType::SYSTEM, F_(syslog_level), System::command_syslog_level, F("change syslog level"), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(syslog_level), System::command_syslog_level, F("changes syslog level"), CommandFlag::ADMIN_ONLY);
} else if (was_enabled) { } else if (was_enabled) {
// in case service is still running, this flushes the queue // in case service is still running, this flushes the queue
@@ -265,6 +265,9 @@ void System::get_settings() {
// Board profile // Board profile
board_profile_ = settings.board_profile; board_profile_ = settings.board_profile;
// Ethernet PHY
phy_type_ = settings.phy_type;
}); });
} }
@@ -593,9 +596,7 @@ void System::network_init(bool refresh) {
last_system_check_ = 0; // force the LED to go from fast flash to pulse last_system_check_ = 0; // force the LED to go from fast flash to pulse
send_heartbeat(); send_heartbeat();
// check board profile for those which use ethernet if (phy_type_ == PHY_type::PHY_TYPE_NONE) {
// ethernet uses lots of additional memory so we only start it when it's explicitly set in the config
if (!board_profile_.equals("E32") && !board_profile_.equals("TLK110") && !board_profile_.equals("LAN8720") && !board_profile_.equals("OLIMEX")) {
return; return;
} }
@@ -606,24 +607,14 @@ void System::network_init(bool refresh) {
eth_phy_type_t type; // Type of the Ethernet PHY (LAN8720 or TLK110) eth_phy_type_t type; // Type of the Ethernet PHY (LAN8720 or TLK110)
eth_clock_mode_t clock_mode; // ETH_CLOCK_GPIO0_IN or ETH_CLOCK_GPIO0_OUT, ETH_CLOCK_GPIO16_OUT, ETH_CLOCK_GPIO17_OUT for 50Hz inverted clock eth_clock_mode_t clock_mode; // ETH_CLOCK_GPIO0_IN or ETH_CLOCK_GPIO0_OUT, ETH_CLOCK_GPIO16_OUT, ETH_CLOCK_GPIO17_OUT for 50Hz inverted clock
if (board_profile_.equals("E32") || board_profile_.equals("LAN8720")) { if (phy_type_ == PHY_type::PHY_TYPE_LAN8720) {
// BBQKees Gateway E32 (LAN8720)
phy_addr = 1; phy_addr = 1;
power = 16; power = 16;
mdc = 23; mdc = 23;
mdio = 18; mdio = 18;
type = ETH_PHY_LAN8720; type = ETH_PHY_LAN8720;
clock_mode = ETH_CLOCK_GPIO0_IN; clock_mode = ETH_CLOCK_GPIO0_IN;
} else if (board_profile_.equals("OLIMEX")) { } else if (phy_type_ == PHY_type::PHY_TYPE_TLK110) {
// Olimex ESP32-EVB (LAN8720)
phy_addr = 0;
power = -1;
mdc = 23;
mdio = 18;
type = ETH_PHY_LAN8720;
clock_mode = ETH_CLOCK_GPIO0_IN;
} else if (board_profile_.equals("TLK110")) {
// Ethernet (TLK110)
phy_addr = 31; phy_addr = 31;
power = -1; power = -1;
mdc = 23; mdc = 23;
@@ -631,11 +622,20 @@ void System::network_init(bool refresh) {
type = ETH_PHY_TLK110; type = ETH_PHY_TLK110;
clock_mode = ETH_CLOCK_GPIO0_IN; clock_mode = ETH_CLOCK_GPIO0_IN;
} else { } else {
return; // invalid combi return; // no valid profile
} }
// bool have_ethernet = ETH.begin(phy_addr, power, mdc, mdio, type, clock_mode); // special case for Olimex ESP32-EVB (LAN8720) (different power and phy_addr)
(void)ETH.begin(phy_addr, power, mdc, mdio, type, clock_mode); if (board_profile_.equals("OLIMEX")) {
phy_addr = 0;
power = -1;
mdc = 23;
mdio = 18;
type = ETH_PHY_LAN8720;
clock_mode = ETH_CLOCK_GPIO0_IN;
}
ETH.begin(phy_addr, power, mdc, mdio, type, clock_mode);
} }
// check health of system, done every few seconds // check health of system, done every few seconds
@@ -672,17 +672,15 @@ void System::system_check() {
} }
// commands - takes static function pointers // commands - takes static function pointers
// these commands respond to the topic "system" and take a payload like {cmd:"", data:"", id:""}
// no individual subscribe for pin command because id is needed
void System::commands_init() { void System::commands_init() {
Command::add(EMSdevice::DeviceType::SYSTEM, Command::add(EMSdevice::DeviceType::SYSTEM,
F_(pin), F_(pin),
System::command_pin, System::command_pin,
F("set GPIO"), F("sets a GPIO on/off"),
CommandFlag::MQTT_SUB_FLAG_NOSUB | CommandFlag::ADMIN_ONLY); // dont create a MQTT topic for this CommandFlag::MQTT_SUB_FLAG_NOSUB | CommandFlag::ADMIN_ONLY); // dont create a MQTT topic for this
Command::add(EMSdevice::DeviceType::SYSTEM, F_(send), System::command_send, F("send a telegram"), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(send), System::command_send, F("sends a telegram"), CommandFlag::ADMIN_ONLY);
Command::add(EMSdevice::DeviceType::SYSTEM, F_(fetch), System::command_fetch, F("refresh all EMS values"), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(fetch), System::command_fetch, F("refreshes all EMS values"), CommandFlag::ADMIN_ONLY);
Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, F("restarts EMS-ESP"), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, F("restarts EMS-ESP"), CommandFlag::ADMIN_ONLY);
Command::add(EMSdevice::DeviceType::SYSTEM, F_(watch), System::command_watch, F("watch incoming telegrams")); Command::add(EMSdevice::DeviceType::SYSTEM, F_(watch), System::command_watch, F("watch incoming telegrams"));
@@ -691,12 +689,12 @@ void System::commands_init() {
} }
// these commands will return data in JSON format // these commands will return data in JSON format
Command::add(EMSdevice::DeviceType::SYSTEM, F_(info), System::command_info, F("system status")); Command::add(EMSdevice::DeviceType::SYSTEM, F_(info), System::command_info, F("show system status"));
Command::add(EMSdevice::DeviceType::SYSTEM, F_(settings), System::command_settings, F("list system settings")); Command::add(EMSdevice::DeviceType::SYSTEM, F_(settings), System::command_settings, F("shows system settings"));
Command::add(EMSdevice::DeviceType::SYSTEM, F_(commands), System::command_commands, F("list system commands")); Command::add(EMSdevice::DeviceType::SYSTEM, F_(commands), System::command_commands, F("shows system commands"));
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
Command::add(EMSdevice::DeviceType::SYSTEM, F("test"), System::command_test, F("run tests")); Command::add(EMSdevice::DeviceType::SYSTEM, F("test"), System::command_test, F("runs a specific test"));
#endif #endif
// MQTT subscribe "ems-esp/system/#" // MQTT subscribe "ems-esp/system/#"
@@ -930,29 +928,36 @@ bool System::command_settings(const char * value, const int8_t id, JsonObject &
EMSESP::webSettingsService.read([&](WebSettings & settings) { EMSESP::webSettingsService.read([&](WebSettings & settings) {
node = output.createNestedObject("Settings"); node = output.createNestedObject("Settings");
node["board_profile"] = settings.board_profile;
node["tx_mode"] = settings.tx_mode; node["tx_mode"] = settings.tx_mode;
node["ems_bus_id"] = settings.ems_bus_id; node["ems_bus_id"] = settings.ems_bus_id;
node["syslog_enabled"] = settings.syslog_enabled; node["syslog_enabled"] = settings.syslog_enabled;
node["syslog_level"] = settings.syslog_level; node["syslog_level"] = settings.syslog_level;
node["syslog_mark_interval"] = settings.syslog_mark_interval; node["syslog_mark_interval"] = settings.syslog_mark_interval;
node["syslog_host"] = settings.syslog_host; node["syslog_host"] = settings.syslog_host;
node["syslog_port"] = settings.syslog_port; node["syslog_port"] = settings.syslog_port;
node["master_thermostat"] = settings.master_thermostat; node["master_thermostat"] = settings.master_thermostat;
node["shower_timer"] = settings.shower_timer; node["shower_timer"] = settings.shower_timer;
node["shower_alert"] = settings.shower_alert; node["shower_alert"] = settings.shower_alert;
node["rx_gpio"] = settings.rx_gpio; node["rx_gpio"] = settings.rx_gpio;
node["tx_gpio"] = settings.tx_gpio; node["tx_gpio"] = settings.tx_gpio;
node["dallas_gpio"] = settings.dallas_gpio; node["dallas_gpio"] = settings.dallas_gpio;
node["dallas_parasite"] = settings.dallas_parasite; node["pbutton_gpio"] = settings.pbutton_gpio;
node["led_gpio"] = settings.led_gpio; node["led_gpio"] = settings.led_gpio;
node["phy_type"] = settings.phy_type;
node["hide_led"] = settings.hide_led; node["hide_led"] = settings.hide_led;
node["notoken_api"] = settings.notoken_api; node["notoken_api"] = settings.notoken_api;
node["dallas_parasite"] = settings.dallas_parasite;
node["dallas_format"] = settings.dallas_format; node["dallas_format"] = settings.dallas_format;
node["bool_format"] = settings.bool_format; node["bool_format"] = settings.bool_format;
node["enum_format"] = settings.enum_format; node["enum_format"] = settings.enum_format;
node["analog_enabled"] = settings.analog_enabled; node["analog_enabled"] = settings.analog_enabled;
node["pbutton_gpio"] = settings.pbutton_gpio;
node["board_profile"] = settings.board_profile;
}); });
return true; return true;
@@ -1013,14 +1018,14 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & outp
switch (EMSESP::bus_status()) { switch (EMSESP::bus_status()) {
case EMSESP::BUS_STATUS_OFFLINE: case EMSESP::BUS_STATUS_OFFLINE:
node["bus"] = (F("disconnected")); node["bus status"] = (F("disconnected"));
break; break;
case EMSESP::BUS_STATUS_TX_ERRORS: case EMSESP::BUS_STATUS_TX_ERRORS:
node["bus"] = (F("connected, instable tx")); node["bus status"] = (F("connected, instable tx"));
break; break;
case EMSESP::BUS_STATUS_CONNECTED: case EMSESP::BUS_STATUS_CONNECTED:
default: default:
node["bus"] = (F("connected")); node["bus status"] = (F("connected"));
break; break;
} }
@@ -1079,27 +1084,28 @@ bool System::command_test(const char * value, const int8_t id) {
#endif #endif
// takes a board profile and populates a data array with GPIO configurations // takes a board profile and populates a data array with GPIO configurations
// data = led, dallas, rx, tx, button // data = led, dallas, rx, tx, button, phy_type
// returns false if profile is not found // returns false if profile is not found
bool System::load_board_profile(std::vector<uint8_t> & data, const std::string & board_profile) { bool System::load_board_profile(std::vector<uint8_t> & data, const std::string & board_profile) {
if (board_profile == "S32") { if (board_profile == "S32") {
data = {2, 18, 23, 5, 0}; // BBQKees Gateway S32 data = {2, 18, 23, 5, 0, PHY_type::PHY_TYPE_NONE}; // BBQKees Gateway S32
} else if (board_profile == "E32") { } else if (board_profile == "E32") {
data = {2, 4, 5, 17, 33}; // BBQKees Gateway E32 data = {2, 4, 5, 17, 33, PHY_type::PHY_TYPE_LAN8720}; // BBQKees Gateway E32
} else if (board_profile == "MH-ET") { } else if (board_profile == "MH-ET") {
data = {2, 18, 23, 5, 0}; // MH-ET Live D1 Mini data = {2, 18, 23, 5, 0, PHY_type::PHY_TYPE_NONE}; // MH-ET Live D1 Mini
} else if (board_profile == "NODEMCU") { } else if (board_profile == "NODEMCU") {
data = {2, 18, 23, 5, 0}; // NodeMCU 32S data = {2, 18, 23, 5, 0, PHY_type::PHY_TYPE_NONE}; // NodeMCU 32S
} else if (board_profile == "LOLIN") { } else if (board_profile == "LOLIN") {
data = {2, 18, 17, 16, 0}; // Lolin D32 data = {2, 18, 17, 16, 0, PHY_type::PHY_TYPE_NONE}; // Lolin D32
} else if (board_profile == "OLIMEX") { } else if (board_profile == "OLIMEX") {
data = {0, 0, 36, 4, 34}; // Olimex ESP32-EVB (uses U1TXD/U1RXD/BUTTON, no LED or Dallas) data = {0, 0, 36, 4, 34, PHY_type::PHY_TYPE_LAN8720}; // Olimex ESP32-EVB (uses U1TXD/U1RXD/BUTTON, no LED or Dallas)
} else if (board_profile == "TLK110") {
data = {2, 4, 5, 17, 33}; // Generic Ethernet (TLK110)
} else if (board_profile == "LAN8720") {
data = {2, 4, 5, 17, 33}; // Generic Ethernet (LAN8720)
} else { } else {
data = {EMSESP_DEFAULT_LED_GPIO, EMSESP_DEFAULT_DALLAS_GPIO, EMSESP_DEFAULT_RX_GPIO, EMSESP_DEFAULT_TX_GPIO, EMSESP_DEFAULT_PBUTTON_GPIO}; data = {EMSESP_DEFAULT_LED_GPIO,
EMSESP_DEFAULT_DALLAS_GPIO,
EMSESP_DEFAULT_RX_GPIO,
EMSESP_DEFAULT_TX_GPIO,
EMSESP_DEFAULT_PBUTTON_GPIO,
EMSESP_DEFAULT_PHY_TYPE};
return (board_profile == "CUSTOM"); return (board_profile == "CUSTOM");
} }

View File

@@ -42,6 +42,8 @@ using uuid::console::Shell;
namespace emsesp { namespace emsesp {
enum PHY_type : uint8_t { PHY_TYPE_NONE = 0, PHY_TYPE_LAN8720, PHY_TYPE_TLK110 };
class System { class System {
public: public:
void start(uint32_t heap_start); void start(uint32_t heap_start);
@@ -181,6 +183,7 @@ class System {
bool low_clock_; bool low_clock_;
String board_profile_; String board_profile_;
uint8_t pbutton_gpio_; uint8_t pbutton_gpio_;
uint8_t phy_type_;
int8_t syslog_level_; int8_t syslog_level_;
uint32_t syslog_mark_interval_; uint32_t syslog_mark_interval_;
String syslog_host_; String syslog_host_;

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.3.0b9" #define EMSESP_APP_VERSION "3.3.0b10"

View File

@@ -50,6 +50,7 @@ void WebSettings::read(WebSettings & settings, JsonObject & root) {
root["shower_alert"] = settings.shower_alert; root["shower_alert"] = settings.shower_alert;
root["rx_gpio"] = settings.rx_gpio; root["rx_gpio"] = settings.rx_gpio;
root["tx_gpio"] = settings.tx_gpio; root["tx_gpio"] = settings.tx_gpio;
root["phy_type"] = settings.phy_type;
root["dallas_gpio"] = settings.dallas_gpio; root["dallas_gpio"] = settings.dallas_gpio;
root["dallas_parasite"] = settings.dallas_parasite; root["dallas_parasite"] = settings.dallas_parasite;
root["led_gpio"] = settings.led_gpio; root["led_gpio"] = settings.led_gpio;
@@ -81,7 +82,7 @@ void WebSettings::read(WebSettings & settings, JsonObject & root) {
// call on initialization and also when settings are updated via web or console // call on initialization and also when settings are updated via web or console
StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings) { StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings) {
// load default GPIO configuration based on board profile // load default GPIO configuration based on board profile
std::vector<uint8_t> data; // led, dallas, rx, tx, button std::vector<uint8_t> data; // led, dallas, rx, tx, button, phy_type
String old_board_profile = settings.board_profile; String old_board_profile = settings.board_profile;
settings.board_profile = root["board_profile"] | EMSESP_DEFAULT_BOARD_PROFILE; settings.board_profile = root["board_profile"] | EMSESP_DEFAULT_BOARD_PROFILE;
@@ -94,6 +95,7 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
uint8_t default_rx_gpio = data[2]; uint8_t default_rx_gpio = data[2];
uint8_t default_tx_gpio = data[3]; uint8_t default_tx_gpio = data[3];
uint8_t default_pbutton_gpio = data[4]; uint8_t default_pbutton_gpio = data[4];
uint8_t default_phy_type = data[5];
if (old_board_profile != settings.board_profile) { if (old_board_profile != settings.board_profile) {
EMSESP::logger().info(F("EMS-ESP version %s"), EMSESP_APP_VERSION); EMSESP::logger().info(F("EMS-ESP version %s"), EMSESP_APP_VERSION);
@@ -145,9 +147,6 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
settings.syslog_port = root["syslog_port"] | EMSESP_DEFAULT_SYSLOG_PORT; settings.syslog_port = root["syslog_port"] | EMSESP_DEFAULT_SYSLOG_PORT;
check_flag(prev, settings.syslog_port, ChangeFlags::SYSLOG); check_flag(prev, settings.syslog_port, ChangeFlags::SYSLOG);
settings.trace_raw = root["trace_raw"] | EMSESP_DEFAULT_TRACELOG_RAW;
EMSESP::trace_raw(settings.trace_raw);
// adc // adc
prev = settings.analog_enabled; prev = settings.analog_enabled;
settings.analog_enabled = root["analog_enabled"] | EMSESP_DEFAULT_ANALOG_ENABLED; settings.analog_enabled = root["analog_enabled"] | EMSESP_DEFAULT_ANALOG_ENABLED;
@@ -182,13 +181,19 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
settings.hide_led = root["hide_led"] | EMSESP_DEFAULT_HIDE_LED; settings.hide_led = root["hide_led"] | EMSESP_DEFAULT_HIDE_LED;
check_flag(prev, settings.hide_led, ChangeFlags::LED); check_flag(prev, settings.hide_led, ChangeFlags::LED);
//
// next ones are settings that don't need any follow-up actions
//
// these need reboots to be applied // these need reboots to be applied
settings.ems_bus_id = root["ems_bus_id"] | EMSESP_DEFAULT_EMS_BUS_ID; settings.ems_bus_id = root["ems_bus_id"] | EMSESP_DEFAULT_EMS_BUS_ID;
settings.master_thermostat = root["master_thermostat"] | EMSESP_DEFAULT_MASTER_THERMOSTAT; settings.master_thermostat = root["master_thermostat"] | EMSESP_DEFAULT_MASTER_THERMOSTAT;
settings.low_clock = root["low_clock"] | false; settings.low_clock = root["low_clock"] | false;
; settings.phy_type = root["phy_type"] | default_phy_type; // use whatever came from the board profile
settings.trace_raw = root["trace_raw"] | EMSESP_DEFAULT_TRACELOG_RAW;
EMSESP::trace_raw(settings.trace_raw);
// doesn't need any follow-up actions
settings.notoken_api = root["notoken_api"] | EMSESP_DEFAULT_NOTOKEN_API; settings.notoken_api = root["notoken_api"] | EMSESP_DEFAULT_NOTOKEN_API;
settings.solar_maxflow = root["solar_maxflow"] | EMSESP_DEFAULT_SOLAR_MAXFLOW; settings.solar_maxflow = root["solar_maxflow"] | EMSESP_DEFAULT_SOLAR_MAXFLOW;
@@ -275,6 +280,7 @@ void WebSettingsService::board_profile(AsyncWebServerRequest * request, JsonVari
root["rx_gpio"] = data[2]; root["rx_gpio"] = data[2];
root["tx_gpio"] = data[3]; root["tx_gpio"] = data[3];
root["pbutton_gpio"] = data[4]; root["pbutton_gpio"] = data[4];
root["phy_type"] = data[5];
} else { } else {
AsyncWebServerResponse * response = request->beginResponse(200); AsyncWebServerResponse * response = request->beginResponse(200);
request->send(response); request->send(response);

View File

@@ -60,6 +60,7 @@ class WebSettings {
uint8_t pbutton_gpio; uint8_t pbutton_gpio;
uint8_t solar_maxflow; uint8_t solar_maxflow;
String board_profile; String board_profile;
uint8_t phy_type;
uint8_t dallas_format; uint8_t dallas_format;
uint8_t bool_format; uint8_t bool_format;
uint8_t enum_format; uint8_t enum_format;