Merge pull request #413 from proddy/dev

rename exclude_entities to masked_entities - fixes for #411
This commit is contained in:
Proddy
2022-03-27 22:19:35 +02:00
committed by GitHub
16 changed files with 302 additions and 234 deletions

View File

@@ -30,6 +30,7 @@
- sync time with thermostat [#386](https://github.com/emsesp/EMS-ESP32/issues/386), [#408](https://github.com/emsesp/EMS-ESP32/issues/408) - sync time with thermostat [#386](https://github.com/emsesp/EMS-ESP32/issues/386), [#408](https://github.com/emsesp/EMS-ESP32/issues/408)
- set mode has immediate effect [#395](https://github.com/emsesp/EMS-ESP32/issues/395) - set mode has immediate effect [#395](https://github.com/emsesp/EMS-ESP32/issues/395)
- min/max in web value setting - min/max in web value setting
- Extend customization to select if an entity is to be shown in the WebUI or forced as read-only [#317](https://github.com/emsesp/EMS-ESP32/issues/317)
### Fixed ### Fixed

View File

@@ -46,7 +46,7 @@ const UserForm: FC<UserFormProps> = ({ creating, validator, user, setUser, onDon
}; };
return ( return (
<Dialog onClose={onCancelEditing} aria-labelledby="user-form-dialog-title" open={!!user} fullWidth maxWidth="sm"> <Dialog onClose={onCancelEditing} open={!!user} fullWidth maxWidth="sm">
{user && ( {user && (
<> <>
<DialogTitle id="user-form-dialog-title">{creating ? 'Add' : 'Modify'} User</DialogTitle> <DialogTitle id="user-form-dialog-title">{creating ? 'Add' : 'Modify'} User</DialogTitle>

View File

@@ -20,7 +20,8 @@ import {
ListItem, ListItem,
ListItemText, ListItemText,
Grid, Grid,
useMediaQuery useMediaQuery,
Tooltip
} from '@mui/material'; } from '@mui/material';
import TableCell, { tableCellClasses } from '@mui/material/TableCell'; import TableCell, { tableCellClasses } from '@mui/material/TableCell';
@@ -524,8 +525,10 @@ const DashboardData: FC = () => {
<StyledTableRow key={i} onClick={() => sendCommand(dv)}> <StyledTableRow key={i} onClick={() => sendCommand(dv)}>
<StyledTableCell padding="checkbox"> <StyledTableCell padding="checkbox">
{dv.c && me.admin && ( {dv.c && me.admin && (
<IconButton size="small" aria-label="Edit"> <IconButton size="small">
<Tooltip title="Change value...">
<EditIcon color="primary" fontSize="small" /> <EditIcon color="primary" fontSize="small" />
</Tooltip>
</IconButton> </IconButton>
)} )}
</StyledTableCell> </StyledTableCell>
@@ -569,7 +572,7 @@ const DashboardData: FC = () => {
<StyledTableRow key={sensor_data.n} onClick={() => updateSensor(sensor_data)}> <StyledTableRow key={sensor_data.n} onClick={() => updateSensor(sensor_data)}>
<StyledTableCell padding="checkbox"> <StyledTableCell padding="checkbox">
{me.admin && ( {me.admin && (
<IconButton edge="start" size="small" aria-label="Edit"> <IconButton edge="start" size="small">
<EditIcon color="primary" fontSize="small" /> <EditIcon color="primary" fontSize="small" />
</IconButton> </IconButton>
)} )}
@@ -605,7 +608,7 @@ const DashboardData: FC = () => {
<StyledTableRow key={analog_data.i} onClick={() => updateAnalog(analog_data)}> <StyledTableRow key={analog_data.i} onClick={() => updateAnalog(analog_data)}>
<StyledTableCell padding="checkbox"> <StyledTableCell padding="checkbox">
{me.admin && ( {me.admin && (
<IconButton edge="start" size="small" aria-label="Edit"> <IconButton edge="start" size="small">
<EditIcon color="primary" fontSize="small" /> <EditIcon color="primary" fontSize="small" />
</IconButton> </IconButton>
)} )}

View File

@@ -12,7 +12,10 @@ import {
Dialog, Dialog,
DialogActions, DialogActions,
DialogContent, DialogContent,
DialogTitle DialogTitle,
ToggleButton,
ToggleButtonGroup,
Tooltip
} from '@mui/material'; } from '@mui/material';
import TableCell, { tableCellClasses } from '@mui/material/TableCell'; import TableCell, { tableCellClasses } from '@mui/material/TableCell';
@@ -22,8 +25,11 @@ import { styled } from '@mui/material/styles';
import { useSnackbar } from 'notistack'; import { useSnackbar } from 'notistack';
import SaveIcon from '@mui/icons-material/Save'; import SaveIcon from '@mui/icons-material/Save';
import CloseIcon from '@mui/icons-material/Close';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
import FavoriteBorderOutlinedIcon from '@mui/icons-material/FavoriteBorderOutlined';
import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore'; import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore';
import { ButtonRow, FormLoader, ValidatedTextField, SectionContent } from '../components'; import { ButtonRow, FormLoader, ValidatedTextField, SectionContent } from '../components';
@@ -53,6 +59,7 @@ const SettingsCustomization: FC = () => {
const [errorMessage, setErrorMessage] = useState<string>(); const [errorMessage, setErrorMessage] = useState<string>();
const [selectedDevice, setSelectedDevice] = useState<number>(0); const [selectedDevice, setSelectedDevice] = useState<number>(0);
const [confirmReset, setConfirmReset] = useState<boolean>(false); const [confirmReset, setConfirmReset] = useState<boolean>(false);
const [masks, setMasks] = useState(() => ['1']);
const fetchDevices = useCallback(async () => { const fetchDevices = useCallback(async () => {
try { try {
@@ -110,7 +117,8 @@ const SettingsCustomization: FC = () => {
<> <>
<Box color="warning.main"> <Box color="warning.main">
<Typography variant="body2"> <Typography variant="body2">
Customize which entities to exclude from all all services (MQTT, API). This will have immediate effect. You can mark an entity as a favorite to be listed first in the Web Dashboard, or remove it from the
Dashboard, or disable it's write operation or exclude it from the MQTT and API outputs.
</Typography> </Typography>
</Box> </Box>
<ValidatedTextField <ValidatedTextField
@@ -138,11 +146,13 @@ const SettingsCustomization: FC = () => {
const saveCustomization = async () => { const saveCustomization = async () => {
if (deviceEntities && selectedDevice) { if (deviceEntities && selectedDevice) {
const exclude_entities = deviceEntities.filter((de) => de.x).map((new_de) => "07" + new_de.s); const masked_entities = deviceEntities
.filter((de) => de.m)
.map((new_de) => new_de.m.toString(16).padStart(2, '0') + new_de.s);
try { try {
const response = await EMSESP.writeExcludeEntities({ const response = await EMSESP.writeMaskedEntities({
id: selectedDevice, id: selectedDevice,
entity_ids: exclude_entities entity_ids: masked_entities
}); });
if (response.status === 200) { if (response.status === 200) {
enqueueSnackbar('Customization saved', { variant: 'success' }); enqueueSnackbar('Customization saved', { variant: 'success' });
@@ -160,48 +170,94 @@ const SettingsCustomization: FC = () => {
return; return;
} }
const toggleDeviceEntity = (id: number) => { const setMask = (de: DeviceEntity, newMask: string[]) => {
setDeviceEntities( var new_mask = 0;
deviceEntities.map((o) => { if (newMask.includes('1')) {
if (o.i === id) { new_mask |= 1;
return { ...o, x: !o.x };
} }
return o; if (newMask.includes('2')) {
}) new_mask |= 2;
); }
if (newMask.includes('4')) {
new_mask |= 4;
}
if (newMask.includes('8')) {
new_mask |= 8;
}
de.m = new_mask;
setMasks(newMask);
};
const getMask = (de: DeviceEntity) => {
var new_masks = [];
if ((de.m & 1) === 1) {
new_masks.push('1');
}
if ((de.m & 2) === 2) {
new_masks.push('2');
}
if ((de.m & 4) === 4) {
new_masks.push('4');
}
if ((de.m & 8) === 8) {
new_masks.push('8');
}
return new_masks;
}; };
return ( return (
<>
<Table size="small"> <Table size="small">
<TableHead> <TableHead>
<TableRow> <TableRow>
<StyledTableCell> <StyledTableCell align="center">OPTIONS</StyledTableCell>
({deviceEntities.reduce((a, v) => (v.x ? a + 1 : a), 0)}/{deviceEntities.length}) <StyledTableCell align="left">ENTITY NAME (CODE)</StyledTableCell>
</StyledTableCell>
<StyledTableCell align="left">ENTITY NAME</StyledTableCell>
<StyledTableCell>CODE</StyledTableCell>
<StyledTableCell align="right">VALUE</StyledTableCell> <StyledTableCell align="right">VALUE</StyledTableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{deviceEntities.map((de) => ( {deviceEntities.map((de) => (
<TableRow <TableRow key={de.i}>
key={de.i} <StyledTableCell padding="checkbox">
onClick={() => toggleDeviceEntity(de.i)} <ToggleButtonGroup
sx={de.x ? { backgroundColor: '#f8696b' } : { backgroundColor: 'black' }} size="small"
color="error"
value={getMask(de)}
onChange={(event, mask) => {
setMask(de, mask);
}}
> >
<StyledTableCell padding="checkbox">{de.x && <CloseIcon fontSize="small" />}</StyledTableCell> <ToggleButton value="8" color="success" disabled={(de.m & 1) !== 0}>
<StyledTableCell component="th" scope="row"> <Tooltip title="Favorite">
{de.n} <FavoriteBorderOutlinedIcon fontSize="small" />
</Tooltip>
</ToggleButton>
<ToggleButton value="4" disabled={!de.w}>
<Tooltip title="Force read-only">
<EditOffOutlinedIcon fontSize="small" />
</Tooltip>
</ToggleButton>
<ToggleButton value="2">
<Tooltip title="Exclude in MQTT and API">
<CommentsDisabledOutlinedIcon fontSize="small" />
</Tooltip>
</ToggleButton>
<ToggleButton value="1">
<Tooltip title="Don't show Web Dashboard">
<VisibilityOffOutlinedIcon fontSize="small" />
</Tooltip>
</ToggleButton>
</ToggleButtonGroup>
</StyledTableCell>
<StyledTableCell>
{de.n}&nbsp;({de.s})
</StyledTableCell> </StyledTableCell>
<StyledTableCell>{de.s}</StyledTableCell>
<StyledTableCell align="right">{formatValue(de.v)}</StyledTableCell> <StyledTableCell align="right">{formatValue(de.v)}</StyledTableCell>
</TableRow> </TableRow>
))} ))}
</TableBody> </TableBody>
</Table> </Table>
</>
); );
}; };

View File

@@ -12,7 +12,7 @@ import {
DeviceData, DeviceData,
DeviceEntity, DeviceEntity,
UniqueID, UniqueID,
ExcludeEntities, MaskedEntities,
WriteValue, WriteValue,
WriteSensor, WriteSensor,
WriteAnalog, WriteAnalog,
@@ -63,8 +63,8 @@ export function readDeviceEntities(unique_id: UniqueID): AxiosPromise<DeviceEnti
return AXIOS_BIN.post('/deviceEntities', unique_id); return AXIOS_BIN.post('/deviceEntities', unique_id);
} }
export function writeExcludeEntities(excludeEntities: ExcludeEntities): AxiosPromise<void> { export function writeMaskedEntities(maskedEntities: MaskedEntities): AxiosPromise<void> {
return AXIOS.post('/excludeEntities', excludeEntities); return AXIOS.post('/maskedEntities', maskedEntities);
} }
export function writeValue(writevalue: WriteValue): AxiosPromise<void> { export function writeValue(writevalue: WriteValue): AxiosPromise<void> {

View File

@@ -146,11 +146,12 @@ export interface DeviceEntity {
v?: any; // value, in any format v?: any; // value, in any format
n: string; // name n: string; // name
s: string; // shortname s: string; // shortname
x: boolean; // excluded flag m: number; // mask
w?: boolean; // writeable
i: number; // unique id i: number; // unique id
} }
export interface ExcludeEntities { export interface MaskedEntities {
id: number; id: number;
entity_ids: string[]; entity_ids: string[];
} }

View File

@@ -302,7 +302,7 @@ const EMSESP_BOARDPROFILE_ENDPOINT = REST_ENDPOINT_ROOT + 'boardProfile'
const EMSESP_WRITE_VALUE_ENDPOINT = REST_ENDPOINT_ROOT + 'writeValue' const EMSESP_WRITE_VALUE_ENDPOINT = REST_ENDPOINT_ROOT + 'writeValue'
const EMSESP_WRITE_SENSOR_ENDPOINT = REST_ENDPOINT_ROOT + 'writeSensor' const EMSESP_WRITE_SENSOR_ENDPOINT = REST_ENDPOINT_ROOT + 'writeSensor'
const EMSESP_WRITE_ANALOG_ENDPOINT = REST_ENDPOINT_ROOT + 'writeAnalog' const EMSESP_WRITE_ANALOG_ENDPOINT = REST_ENDPOINT_ROOT + 'writeAnalog'
const EMSESP_EXCLUDE_ENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'excludeEntities' const EMSESP_MASKED_ENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'maskedEntities'
const EMSESP_RESET_CUSTOMIZATIONS_ENDPOINT = REST_ENDPOINT_ROOT + 'resetCustomizations' const EMSESP_RESET_CUSTOMIZATIONS_ENDPOINT = REST_ENDPOINT_ROOT + 'resetCustomizations'
settings = { settings = {
@@ -344,19 +344,19 @@ const emsesp_devices = {
i: 1, i: 1,
d: 23, d: 23,
p: 77, p: 77,
s: 'Thermostat1', s: 'Thermostat1 (RC20/Moduline 300)',
}, },
{ {
i: 2, i: 2,
d: 8, d: 8,
p: 123, p: 123,
s: 'Boiler', s: 'Boiler (Nefit GBx72/Trendline/Cerapur/Greenstar Si/27i)',
}, },
{ {
i: 4, i: 4,
d: 16, d: 16,
p: 165, p: 165,
s: 'Thermostat2', s: 'Thermostat2 (RC100/Moduline 1000/1010)',
}, },
], ],
} }
@@ -450,7 +450,7 @@ const status = {
// Dashboard data // Dashboard data
const emsesp_devicedata_1 = { const emsesp_devicedata_1 = {
label: 'RC20/Moduline 300', label: 'Thermostat: RC20/Moduline 300',
data: [ data: [
{ {
v: '(0)', v: '(0)',
@@ -567,28 +567,25 @@ const emsesp_devicedata_2 = {
} }
const emsesp_devicedata_4 = { const emsesp_devicedata_4 = {
label: 'RC100/Moduline 1000/1010', label: 'Thermostat: RC100/Moduline 1000/1010',
data: [ data: [
{ {
v: 16, v: 16,
u: 1, u: 1,
n: 'hc2 selected room temperature', n: 'hc2 selected room temperature',
c: 'hc2/seltemp', c: 'hc2/seltemp',
x: false,
}, },
{ {
v: 18.6, v: 18.6,
u: 1, u: 1,
n: 'hc2 current room temperature', n: 'hc2 current room temperature',
c: '', c: '',
x: true,
}, },
{ {
v: 'off', v: 'off',
u: 0, u: 0,
n: 'hc2 mode', n: 'hc2 mode',
c: 'hc2/mode', c: 'hc2/mode',
x: true,
}, },
], ],
} }
@@ -598,119 +595,121 @@ const emsesp_deviceentities_1 = [
v: '(0)', v: '(0)',
n: 'error code', n: 'error code',
s: 'errorcode', s: 'errorcode',
x: false, m: 0,
i: 1, i: 1,
}, },
{ {
v: '14:54:39 06/06/2021', v: '14:54:39 06/06/2021',
n: 'date/time', n: 'date/time',
s: 'datetime', s: 'datetime',
x: false, m: 0,
i: 2, i: 2,
}, },
{ {
v: 18.22, v: 18.22,
n: 'hc1 selected room temperature', n: 'hc1 selected room temperature',
s: 'hc1/seltemp', s: 'hc1/seltemp',
x: false, m: 0,
w: true,
i: 3, i: 3,
}, },
{ {
v: 22.6, v: 22.6,
n: 'hc1 current room temperature', n: 'hc1 current room temperature',
s: 'hc1/curtemp', s: 'hc1/curtemp',
x: false, m: 0,
i: 4, i: 4,
}, },
{ {
v: 'auto', v: 'auto',
n: 'hc1 mode', n: 'hc1 mode',
s: 'hc1/mode', s: 'hc1/mode',
x: false, m: 0,
w: true,
i: 5, i: 5,
}, },
] ]
const emsesp_deviceentities_2 = [ const emsesp_deviceentities_2 = [
{ v: false, n: 'heating active', s: 'heatingactive', x: false, i: 1 }, { v: false, n: 'heating active', s: 'heatingactive', m: 0, i: 1 },
{ v: false, n: 'tapwater active', s: 'tapwateractive', x: false, i: 2 }, { v: false, n: 'tapwater active', s: 'tapwateractive', m: 0, i: 2 },
{ v: 5, n: 'selected flow temperature', s: 'selflowtemp', x: false, i: 3 }, { v: 5, n: 'selected flow temperature', s: 'selflowtemp', m: 0, i: 3 },
{ v: 0, n: 'burner selected max power', s: 'selburnpow', x: false, i: 4 }, { v: 0, n: 'burner selected max power', s: 'selburnpow', m: 0, i: 4 },
{ v: 0, n: 'heating pump modulation', s: 'heatingpumpmod', x: false, i: 5 }, { v: 0, n: 'heating pump modulation', s: 'heatingpumpmod', m: 0, i: 5 },
{ n: 'heating pump 2 modulation', s: 'heatingpump2mod', x: true, i: 6 }, { n: 'heating pump 2 modulation', s: 'heatingpump2mod', m: 2, i: 6 },
{ n: 'outside temperature', s: 'outdoortemp', x: true, i: 7 }, { n: 'outside temperature', s: 'outdoortemp', m: 2, i: 7 },
{ v: 53, n: 'current flow temperature', s: 'curflowtemp', x: false, i: 8 }, { v: 53, n: 'current flow temperature', s: 'curflowtemp', m: 0, i: 8 },
{ v: 51.8, n: 'return temperature', s: 'rettemp', x: false, i: 9 }, { v: 51.8, n: 'return temperature', s: 'rettemp', m: 0, i: 9 },
{ n: 'mixing switch temperature', s: 'switchtemp', x: true, i: 10 }, { n: 'mixing switch temperature', s: 'switchtemp', m: 2, i: 10 },
{ v: 1.3, n: 'system pressure', s: 'syspress', x: false, i: 11 }, { v: 1.3, n: 'system pressure', s: 'syspress', m: 0, i: 11 },
{ v: 54.6, n: 'actual boiler temperature', s: 'boiltemp', x: false, i: 12 }, { v: 54.6, n: 'actual boiler temperature', s: 'boiltemp', m: 0, i: 12 },
{ n: 'exhaust temperature', s: 'exhausttemp', x: true, i: 13 }, { n: 'exhaust temperature', s: 'exhausttemp', m: 2, i: 13 },
{ v: false, n: 'gas', s: 'burngas', x: false, i: 14 }, { v: false, n: 'gas', s: 'burngas', m: 0, i: 14 },
{ v: false, n: 'gas stage 2', s: 'burngas2', x: false, i: 15 }, { v: false, n: 'gas stage 2', s: 'burngas2', m: 0, i: 15 },
{ v: 0, n: 'flame current', s: 'flamecurr', x: false, i: 16 }, { v: 0, n: 'flame current', s: 'flamecurr', m: 0, i: 16 },
{ v: false, n: 'heating pump', s: 'heatingpump', x: false, i: 17 }, { v: false, n: 'heating pump', s: 'heatingpump', m: 0, i: 17 },
{ v: false, n: 'fan', s: 'fanwork', x: false, i: 18 }, { v: false, n: 'fan', s: 'fanwork', m: 0, i: 18 },
{ v: false, n: 'ignition', s: 'ignwork', x: false, i: 19 }, { v: false, n: 'ignition', s: 'ignwork', m: 0, i: 19 },
{ v: false, n: 'oil preheating', s: 'oilpreheat', x: false, i: 20 }, { v: false, n: 'oil preheating', s: 'oilpreheat', m: 0, i: 20 },
{ v: true, n: 'heating activated', s: 'heatingactivated', x: false, i: 21 }, { v: true, n: 'heating activated', s: 'heatingactivated', m: 0, i: 21 },
{ v: 80, n: 'heating temperature', s: 'heatingtemp', x: false, i: 22 }, { v: 80, n: 'heating temperature', s: 'heatingtemp', m: 0, i: 22 },
{ v: 70, n: 'burner pump max power', s: 'pumpmodmax', x: false, i: 23 }, { v: 70, n: 'burner pump max power', s: 'pumpmodmax', m: 0, i: 23 },
{ v: 30, n: 'burner pump min power', s: 'pumpmodmin', x: false, i: 24 }, { v: 30, n: 'burner pump min power', s: 'pumpmodmin', m: 0, i: 24 },
{ v: 1, n: 'pump delay', s: 'pumpdelay', x: false, i: 25 }, { v: 1, n: 'pump delay', s: 'pumpdelay', m: 0, i: 25 },
{ v: 10, n: 'burner min period', s: 'burnminperiod', x: false, i: 26 }, { v: 10, n: 'burner min period', s: 'burnminperiod', m: 0, i: 26 },
{ v: 0, n: 'burner min power', s: 'burnminpower', x: false, i: 27 }, { v: 0, n: 'burner min power', s: 'burnminpower', m: 0, i: 27 },
{ v: 50, n: 'burner max power', s: 'burnmaxpower', x: false, i: 28 }, { v: 50, n: 'burner max power', s: 'burnmaxpower', m: 0, i: 28 },
{ v: -6, n: 'hysteresis on temperature', s: 'boilhyston', x: false, i: 29 }, { v: -6, n: 'hysteresis on temperature', s: 'boilhyston', m: 0, i: 29 },
{ v: 6, n: 'hysteresis off temperature', s: 'boilhystoff', x: false, i: 30 }, { v: 6, n: 'hysteresis off temperature', s: 'boilhystoff', m: 0, i: 30 },
{ v: 0, n: 'set flow temperature', s: 'setflowtemp', x: false, i: 31 }, { v: 0, n: 'set flow temperature', s: 'setflowtemp', m: 0, i: 31 },
{ v: 0, n: 'burner set power', s: 'setburnpow', x: false, i: 32 }, { v: 0, n: 'burner set power', s: 'setburnpow', m: 0, i: 32 },
{ v: 0, n: 'burner current power', s: 'curburnpow', x: false, i: 33 }, { v: 0, n: 'burner current power', s: 'curburnpow', m: 0, i: 33 },
{ v: 326323, n: 'burner starts', s: 'burnstarts', x: false, i: 34 }, { v: 326323, n: 'burner starts', s: 'burnstarts', m: 0, i: 34 },
{ v: 553437, n: 'total burner operating time', s: 'burnworkmin', x: false, i: 35 }, { v: 553437, n: 'total burner operating time', s: 'burnworkmin', m: 0, i: 35 },
{ v: 451286, n: 'total heat operating time', s: 'heatworkmin', x: false, i: 36 }, { v: 451286, n: 'total heat operating time', s: 'heatworkmin', m: 0, i: 36 },
{ v: 4672175, n: 'total UBA operating time', s: 'ubauptime', x: false, i: 37 }, { v: 4672175, n: 'total UBA operating time', s: 'ubauptime', m: 0, i: 37 },
{ v: '1C(210) 06.06.2020 12:07 (0 min)', n: 'last error code', s: 'lastcode', x: false, i: 38 }, { v: '1C(210) 06.06.2020 12:07 (0 min)', n: 'last error code', s: 'lastcode', m: 0, i: 38 },
{ v: '0H', n: 'service code', s: 'servicecode', x: false, i: 39 }, { v: '0H', n: 'service code', s: 'servicecode', m: 0, i: 39 },
{ v: 203, n: 'service code number', s: 'servicecodenumber', x: false, i: 40 }, { v: 203, n: 'service code number', s: 'servicecodenumber', m: 0, i: 40 },
{ v: 'H00', n: 'maintenance message', s: 'maintenancemessage', x: false, i: 41 }, { v: 'H00', n: 'maintenance message', s: 'maintenancemessage', m: 0, i: 41 },
{ v: 'manual', n: 'maintenance scheduled', s: 'maintenance', x: false, i: 42 }, { v: 'manual', n: 'maintenance scheduled', s: 'maintenance', m: 0, i: 42 },
{ v: 6000, n: 'time to next maintenance', s: 'maintenancetime', x: false, i: 43 }, { v: 6000, n: 'time to next maintenance', s: 'maintenancetime', m: 0, i: 43 },
{ v: '01.01.2012', n: 'next maintenance date', s: 'maintenancedate', x: false, i: 44 }, { v: '01.01.2012', n: 'next maintenance date', s: 'maintenancedate', m: 0, i: 44 },
{ v: true, n: 'dhw turn on/off', s: 'wwtapactivated', x: false, i: 45 }, { v: true, n: 'dhw turn on/off', s: 'wwtapactivated', m: 0, i: 45 },
{ v: 62, n: 'dhw set temperature', s: 'wwsettemp', x: false, i: 46 }, { v: 62, n: 'dhw set temperature', s: 'wwsettemp', m: 0, i: 46 },
{ v: 60, n: 'dhw selected temperature', s: 'wwseltemp', x: false, i: 47 }, { v: 60, n: 'dhw selected temperature', s: 'wwseltemp', m: 0, i: 47 },
{ n: 'dhw selected lower temperature', s: 'wwseltemplow', x: true, i: 48 }, { n: 'dhw selected lower temperature', s: 'wwseltemplow', m: 2, i: 48 },
{ n: 'dhw selected temperature for off', s: 'wwseltempoff', x: true, i: 49 }, { n: 'dhw selected temperature for off', s: 'wwseltempoff', m: 2, i: 49 },
{ n: 'dhw single charge temperature', s: 'wwseltempsingle', x: true, i: 50 }, { n: 'dhw single charge temperature', s: 'wwseltempsingle', m: 2, i: 50 },
{ v: 'flow', n: 'dhw type', s: 'wwtype', x: false, i: 51 }, { v: 'flow', n: 'dhw type', s: 'wwtype', m: 0, i: 51 },
{ v: 'hot', n: 'dhw comfort', s: 'wwcomfort', x: false, i: 52 }, { v: 'hot', n: 'dhw comfort', s: 'wwcomfort', m: 0, i: 52 },
{ v: 40, n: 'dhw flow temperature offset', s: 'wwflowtempoffset', x: false, i: 53 }, { v: 40, n: 'dhw flow temperature offset', s: 'wwflowtempoffset', m: 0, i: 53 },
{ v: 100, n: 'dhw max power', s: 'wwmaxpower', x: false, i: 54 }, { v: 100, n: 'dhw max power', s: 'wwmaxpower', m: 0, i: 54 },
{ v: false, n: 'dhw circulation pump available', s: 'wwcircpump', x: false, i: 55 }, { v: false, n: 'dhw circulation pump available', s: 'wwcircpump', m: 0, i: 55 },
{ v: '3-way valve', n: 'dhw charging type', s: 'wwchargetype', x: false, i: 56 }, { v: '3-way valve', n: 'dhw charging type', s: 'wwchargetype', m: 0, i: 56 },
{ v: -5, n: 'dhw hysteresis on temperature', s: 'wwhyston', x: false, i: 57 }, { v: -5, n: 'dhw hysteresis on temperature', s: 'wwhyston', m: 0, i: 57 },
{ v: 0, n: 'dhw hysteresis off temperature', s: 'wwhystoff', x: false, i: 58 }, { v: 0, n: 'dhw hysteresis off temperature', s: 'wwhystoff', m: 0, i: 58 },
{ v: 70, n: 'dhw disinfection temperature', s: 'wwdisinfectiontemp', x: false, i: 59 }, { v: 70, n: 'dhw disinfection temperature', s: 'wwdisinfectiontemp', m: 0, i: 59 },
{ v: 'off', n: 'dhw circulation pump mode', s: 'wwcircmode', x: false, i: 60 }, { v: 'off', n: 'dhw circulation pump mode', s: 'wwcircmode', m: 0, i: 60 },
{ v: false, n: 'dhw circulation active', s: 'wwcirc', x: false, i: 61 }, { v: false, n: 'dhw circulation active', s: 'wwcirc', m: 0, i: 61 },
{ v: 46.4, n: 'dhw current intern temperature', s: 'wwcurtemp', x: false, i: 62 }, { v: 46.4, n: 'dhw current intern temperature', s: 'wwcurtemp', m: 0, i: 62 },
{ n: 'dhw current extern temperature', s: 'wwcurtemp2', x: true, i: 63 }, { n: 'dhw current extern temperature', s: 'wwcurtemp2', m: 2, i: 63 },
{ v: 0, n: 'dhw current tap water flow', s: 'wwcurflow', x: false, i: 64 }, { v: 0, n: 'dhw current tap water flow', s: 'wwcurflow', m: 0, i: 64 },
{ v: 46.3, n: 'dhw storage intern temperature', s: 'wwstoragetemp1', x: false, i: 65 }, { v: 46.3, n: 'dhw storage intern temperature', s: 'wwstoragetemp1', m: 0, i: 65 },
{ n: 'dhw storage extern temperature', s: 'wwstoragetemp2', x: true, i: 66 }, { n: 'dhw storage extern temperature', s: 'wwstoragetemp2', m: 2, i: 66 },
{ v: true, n: 'dhw activated', s: 'wwactivated', x: false, i: 67 }, { v: true, n: 'dhw activated', s: 'wwactivated', m: 0, i: 67 },
{ v: false, n: 'dhw one time charging', s: 'wwonetime', x: false, i: 68 }, { v: false, n: 'dhw one time charging', s: 'wwonetime', m: 0, i: 68 },
{ v: false, n: 'dhw disinfecting', s: 'wwdisinfecting', x: false, i: 69 }, { v: false, n: 'dhw disinfecting', s: 'wwdisinfecting', m: 0, i: 69 },
{ v: false, n: 'dhw charging', s: 'wwcharging', x: false, i: 70 }, { v: false, n: 'dhw charging', s: 'wwcharging', m: 0, i: 70 },
{ v: false, n: 'dhw recharging', s: 'wwrecharging', x: false, i: 71 }, { v: false, n: 'dhw recharging', s: 'wwrecharging', m: 0, i: 71 },
{ v: true, n: 'dhw temperature ok', s: 'wwtempok', x: false, i: 72 }, { v: true, n: 'dhw temperature ok', s: 'wwtempok', m: 0, i: 72 },
{ v: false, n: 'dhw active', s: 'wwactive', x: false, i: 73 }, { v: false, n: 'dhw active', s: 'wwactive', m: 0, i: 73 },
{ v: true, n: 'dhw 3way valve active', s: 'ww3wayvalve', x: false, i: 74 }, { v: true, n: 'dhw 3way valve active', s: 'ww3wayvalve', m: 0, i: 74 },
{ v: 0, n: 'dhw set pump power', s: 'wwsetpumppower', x: false, i: 75 }, { v: 0, n: 'dhw set pump power', s: 'wwsetpumppower', m: 0, i: 75 },
{ n: 'dhw mixer temperature', s: 'wwmixertemp', x: true, i: 76 }, { n: 'dhw mixer temperature', s: 'wwmixertemp', m: 2, i: 76 },
{ n: 'dhw cylinder middle temperature (TS3)', s: 'wwcylmiddletemp', x: true, i: 77 }, { n: 'dhw cylinder middle temperature (TS3)', s: 'wwcylmiddletemp', m: 2, i: 77 },
{ v: 288768, n: 'dhw starts', s: 'wwstarts', x: false, i: 78 }, { v: 288768, n: 'dhw starts', s: 'wwstarts', m: 0, i: 78 },
{ v: 102151, n: 'dhw active time', s: 'wwworkm', x: false, i: 79 }, { v: 102151, n: 'dhw active time', s: 'wwworkm', m: 0, i: 79 },
] ]
const emsesp_deviceentities_4 = [ const emsesp_deviceentities_4 = [
@@ -718,20 +717,20 @@ const emsesp_deviceentities_4 = [
v: 16, v: 16,
n: 'hc2 selected room temperature', n: 'hc2 selected room temperature',
s: 'hc2/seltemp', s: 'hc2/seltemp',
x: false, m: 0,
i: 1, i: 1,
}, },
{ {
n: 'hc2 current room temperature', n: 'hc2 current room temperature',
s: 'hc2/curtemp', s: 'hc2/curtemp',
x: true, m: 3,
i: 2, i: 2,
}, },
{ {
v: 'off', v: 'off',
n: 'hc2 mode', n: 'hc2 mode',
s: 'hc2/mode', s: 'hc2/mode',
x: true, m: 3,
i: 3, i: 3,
}, },
] ]
@@ -925,8 +924,8 @@ rest_server.post(EMSESP_DEVICEENTITIES_ENDPOINT, (req, res) => {
} }
}) })
rest_server.post(EMSESP_EXCLUDE_ENTITIES_ENDPOINT, (req, res) => { rest_server.post(EMSESP_MASKED_ENTITIES_ENDPOINT, (req, res) => {
console.log('exclude list for unique id ' + req.body.id + ' and entities:') console.log('list for unique id ' + req.body.id + ' and entities:')
console.log(req.body.entity_ids) console.log(req.body.entity_ids)
res.sendStatus(200) res.sendStatus(200)
}) })

View File

@@ -1251,13 +1251,13 @@ void Thermostat::process_RCTime(std::shared_ptr<const Telegram> telegram) {
LOG_INFO(F("thermostat time correction from ntp")); LOG_INFO(F("thermostat time correction from ntp"));
} }
} }
#ifndef EMSESP_STANDALONE
if (!ntp_ && tm_->tm_year > 110) { // emsesp clock not set, but thermostat clock if (!ntp_ && tm_->tm_year > 110) { // emsesp clock not set, but thermostat clock
struct timeval newnow = {.tv_sec = ttime}; struct timeval newnow = {.tv_sec = ttime};
#ifndef EMSESP_STANDALONE
settimeofday(&newnow, nullptr); settimeofday(&newnow, nullptr);
#endif
LOG_INFO(F("ems-esp time set from thermostat")); LOG_INFO(F("ems-esp time set from thermostat"));
} }
#endif
} }
// process_RCError - type 0xA2 - error message - 14 bytes long // process_RCError - type 0xA2 - error message - 14 bytes long

View File

@@ -632,11 +632,16 @@ std::string EMSdevice::get_value_uom(const char * key) const {
// prepare array of device values used for the WebUI // prepare array of device values used for the WebUI
// this is loosely based of the function generate_values used for the MQTT and Console // this is loosely based of the function generate_values used for the MQTT and Console
// 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, h=help string, s=step, m=min, x=max
void EMSdevice::generate_values_web(JsonObject & output) { void EMSdevice::generate_values_web(JsonObject & output) {
output["label"] = to_string_short(); output["label"] = to_string_short();
JsonArray data = output.createNestedArray("data"); JsonArray data = output.createNestedArray("data");
// sort the device values
std::sort(devicevalues_.begin(), devicevalues_.end(), [](const emsesp::DeviceValue & a, const emsesp::DeviceValue & b) {
return a.has_state(DeviceValueState::DV_FAVORITE);
});
for (auto & dv : devicevalues_) { for (auto & dv : devicevalues_) {
// check conditions: // check conditions:
// 1. full_name cannot be empty // 1. full_name cannot be empty
@@ -752,32 +757,8 @@ void EMSdevice::generate_values_web(JsonObject & output) {
} }
} }
// reset all entities to being visible
// this is called before loading in the exclude entities list from the customization service
void EMSdevice::reset_entity_masks() {
for (auto & dv : devicevalues_) {
dv.state &= 0x0F;
}
}
// disable/exclude/mask_out a device entity based on the id
void EMSdevice::mask_entity(std::string entity_id) {
// first character contains mask flags
uint8_t flag = Helpers::hextoint(entity_id.substr(0, 2).c_str());
for (auto & dv : devicevalues_) {
std::string entity = dv.tag < DeviceValueTAG::TAG_HC1 ? read_flash_string(dv.short_name) : tag_to_string(dv.tag) + "/" + read_flash_string(dv.short_name);
if (entity == entity_id.substr(2)) {
#if defined(EMSESP_USE_SERIAL)
Serial.print("mask_entity() Removing Visible for device value: ");
Serial.println(read_flash_string(dv.full_name).c_str());
#endif
dv.state = (dv.state & 0x0F) | (flag << 4); // set state high bits to flag, turn off active and ha flags
return;
}
}
}
// as generate_values_web() but stripped down to only show all entities and their state // as generate_values_web() but stripped down to only show all entities and their state
// this is used only for WebCustomizationService::device_entities()
void EMSdevice::generate_values_web_all(JsonArray & output) { void EMSdevice::generate_values_web_all(JsonArray & output) {
for (auto & dv : devicevalues_) { for (auto & dv : devicevalues_) {
// also show commands and entities that have an empty full name // also show commands and entities that have an empty full name
@@ -854,6 +835,7 @@ void EMSdevice::generate_values_web_all(JsonArray & output) {
} else { } else {
obj["n"] = "(hidden)"; obj["n"] = "(hidden)";
} }
// shortname // shortname
if (dv.tag >= DeviceValueTAG::TAG_HC1) { if (dv.tag >= DeviceValueTAG::TAG_HC1) {
obj["s"] = tag_to_string(dv.tag) + "/" + read_flash_string(dv.short_name); obj["s"] = tag_to_string(dv.tag) + "/" + read_flash_string(dv.short_name);
@@ -861,11 +843,34 @@ void EMSdevice::generate_values_web_all(JsonArray & output) {
obj["s"] = dv.short_name; obj["s"] = dv.short_name;
} }
// is it marked as excluded? obj["m"] = dv.state >> 4; // send back the mask state. We're only interested in the high nibble
obj["x"] = dv.has_state(DeviceValueState::DV_WEB_EXCLUDE); obj["w"] = dv.has_cmd; // if writable
obj["i"] = dv.id; // add the unique ID
}
}
// add the unique ID // reset all entities to being visible
obj["i"] = dv.id; // this is called before loading in the exclude entities list from the customization service
void EMSdevice::reset_entity_masks() {
for (auto & dv : devicevalues_) {
dv.state &= 0x0F;
}
}
// disable/exclude/mask_out a device entity based on the id
void EMSdevice::mask_entity(std::string entity_id) {
// first character contains mask flags
uint8_t flag = Helpers::hextoint(entity_id.substr(0, 2).c_str());
for (auto & dv : devicevalues_) {
std::string entity = dv.tag < DeviceValueTAG::TAG_HC1 ? read_flash_string(dv.short_name) : tag_to_string(dv.tag) + "/" + read_flash_string(dv.short_name);
if (entity == entity_id.substr(2)) {
#if defined(EMSESP_USE_SERIAL)
Serial.print("mask_entity() Removing Visible for device value: ");
Serial.println(read_flash_string(dv.full_name).c_str());
#endif
dv.state = (dv.state & 0x0F) | (flag << 4); // set state high bits to flag, turn off active and ha flags
return;
}
} }
} }

View File

@@ -110,11 +110,13 @@ class DeviceValue {
// states of a device value // states of a device value
enum DeviceValueState : uint8_t { enum DeviceValueState : uint8_t {
// low nibble active state of the device value
DV_DEFAULT = 0, // 0 - does not yet have a value DV_DEFAULT = 0, // 0 - does not yet have a value
DV_ACTIVE = (1 << 0), // 1 - has a validated real value DV_ACTIVE = (1 << 0), // 1 - has a validated real value
DV_HA_CONFIG_CREATED = (1 << 1), // 2 - set if the HA config topic has been created DV_HA_CONFIG_CREATED = (1 << 1), // 2 - set if the HA config topic has been created
DV_HA_CLIMATE_NO_RT = (1 << 2), // 3 - climate created without roomTemp DV_HA_CLIMATE_NO_RT = (1 << 2), // 3 - climate created without roomTemp
// high nibble as mask for exclusions
// high nibble as mask for exclusions & special functions
DV_WEB_EXCLUDE = (1 << 4), // 16 - not shown on web DV_WEB_EXCLUDE = (1 << 4), // 16 - not shown on web
DV_API_MQTT_EXCLUDE = (1 << 5), // 32 - not shown on mqtt, API DV_API_MQTT_EXCLUDE = (1 << 5), // 32 - not shown on mqtt, API
DV_READONLY = (1 << 6), // 64 - read only DV_READONLY = (1 << 6), // 64 - read only

View File

@@ -1018,7 +1018,6 @@ bool System::command_customizations(const char * value, const int8_t id, JsonObj
JsonObject node = output.createNestedObject("Customizations"); JsonObject node = output.createNestedObject("Customizations");
// hide ssid from this list
EMSESP::webCustomizationService.read([&](WebCustomization & settings) { EMSESP::webCustomizationService.read([&](WebCustomization & settings) {
// sensors // sensors
JsonArray sensorsJson = node.createNestedArray("sensors"); JsonArray sensorsJson = node.createNestedArray("sensors");
@@ -1053,7 +1052,7 @@ bool System::command_customizations(const char * value, const int8_t id, JsonObj
} }
} }
// exclude entities // masked entities
JsonArray mask_entitiesJson = node.createNestedArray("masked_entities"); JsonArray mask_entitiesJson = node.createNestedArray("masked_entities");
for (const auto & entityCustomization : settings.entityCustomizations) { for (const auto & entityCustomization : settings.entityCustomizations) {
JsonObject entityJson = mask_entitiesJson.createNestedObject(); JsonObject entityJson = mask_entitiesJson.createNestedObject();

View File

@@ -595,8 +595,8 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
EMSESP::system_.healthcheck(n); EMSESP::system_.healthcheck(n);
} }
if (command == "exclude") { if (command == "masked") {
shell.printfln(F("Testing exclude entities")); shell.printfln(F("Testing masked entities"));
Mqtt::ha_enabled(true); Mqtt::ha_enabled(true);
Mqtt::send_response(false); Mqtt::send_response(false);

View File

@@ -31,12 +31,12 @@ namespace emsesp {
// #define EMSESP_DEBUG_DEFAULT "mixer" // #define EMSESP_DEBUG_DEFAULT "mixer"
// #define EMSESP_DEBUG_DEFAULT "web" // #define EMSESP_DEBUG_DEFAULT "web"
// #define EMSESP_DEBUG_DEFAULT "mqtt" // #define EMSESP_DEBUG_DEFAULT "mqtt"
// #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 "exclude" // #define EMSESP_DEBUG_DEFAULT "masked"
// #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.4.0b9" #define EMSESP_APP_VERSION "3.4.0b10"

View File

@@ -31,8 +31,8 @@ WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * f
securityManager, securityManager,
AuthenticationPredicates::IS_AUTHENTICATED) AuthenticationPredicates::IS_AUTHENTICATED)
, _fsPersistence(WebCustomization::read, WebCustomization::update, this, fs, EMSESP_CUSTOMIZATION_FILE) , _fsPersistence(WebCustomization::read, WebCustomization::update, this, fs, EMSESP_CUSTOMIZATION_FILE)
, _exclude_entities_handler(EXCLUDE_ENTITIES_PATH, , _masked_entities_handler(MASKED_ENTITIES_PATH,
securityManager->wrapCallback(std::bind(&WebCustomizationService::exclude_entities, this, _1, _2), securityManager->wrapCallback(std::bind(&WebCustomizationService::masked_entities, this, _1, _2),
AuthenticationPredicates::IS_AUTHENTICATED)) AuthenticationPredicates::IS_AUTHENTICATED))
, _device_entities_handler(DEVICE_ENTITIES_PATH, , _device_entities_handler(DEVICE_ENTITIES_PATH,
securityManager->wrapCallback(std::bind(&WebCustomizationService::device_entities, this, _1, _2), securityManager->wrapCallback(std::bind(&WebCustomizationService::device_entities, this, _1, _2),
@@ -45,17 +45,17 @@ WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * f
HTTP_POST, HTTP_POST,
securityManager->wrapRequest(std::bind(&WebCustomizationService::reset_customization, this, _1), AuthenticationPredicates::IS_ADMIN)); securityManager->wrapRequest(std::bind(&WebCustomizationService::reset_customization, this, _1), AuthenticationPredicates::IS_ADMIN));
_exclude_entities_handler.setMethod(HTTP_POST); _masked_entities_handler.setMethod(HTTP_POST);
_exclude_entities_handler.setMaxContentLength(2048); _masked_entities_handler.setMaxContentLength(2048);
_exclude_entities_handler.setMaxJsonBufferSize(2048); _masked_entities_handler.setMaxJsonBufferSize(2048);
server->addHandler(&_exclude_entities_handler); server->addHandler(&_masked_entities_handler);
_device_entities_handler.setMethod(HTTP_POST); _device_entities_handler.setMethod(HTTP_POST);
_device_entities_handler.setMaxContentLength(256); _device_entities_handler.setMaxContentLength(256);
server->addHandler(&_device_entities_handler); server->addHandler(&_device_entities_handler);
} }
// this creates the customization file, saving to the FS // this creates the customization file, saving it to the FS
void WebCustomization::read(WebCustomization & settings, JsonObject & root) { void WebCustomization::read(WebCustomization & settings, JsonObject & root) {
// Dallas Sensor customization // Dallas Sensor customization
JsonArray sensorsJson = root.createNestedArray("sensors"); JsonArray sensorsJson = root.createNestedArray("sensors");
@@ -78,21 +78,21 @@ void WebCustomization::read(WebCustomization & settings, JsonObject & root) {
sensorJson["type"] = sensor.type; // t sensorJson["type"] = sensor.type; // t
} }
// Exclude entities customization // Masked entities customization
JsonArray exclude_entitiesJson = root.createNestedArray("exclude_entities"); JsonArray masked_entitiesJson = root.createNestedArray("masked_entities");
for (const EntityCustomization & entityCustomization : settings.entityCustomizations) { for (const EntityCustomization & entityCustomization : settings.entityCustomizations) {
JsonObject entityJson = exclude_entitiesJson.createNestedObject(); JsonObject entityJson = masked_entitiesJson.createNestedObject();
entityJson["product_id"] = entityCustomization.product_id; entityJson["product_id"] = entityCustomization.product_id;
entityJson["device_id"] = entityCustomization.device_id; entityJson["device_id"] = entityCustomization.device_id;
JsonArray exclude_entityJson = entityJson.createNestedArray("entity_ids"); JsonArray masked_entityJson = entityJson.createNestedArray("entity_ids");
for (std::string entity_id : entityCustomization.entity_ids) { for (std::string entity_id : entityCustomization.entity_ids) {
exclude_entityJson.add(entity_id); masked_entityJson.add(entity_id);
} }
} }
} }
// call on initialization and also when the page is saved via web // call on initialization and also when the page is saved via web UI
// this loads the data into the internal class // this loads the data into the internal class
StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization & settings) { StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization & settings) {
// Dallas Sensor customization // Dallas Sensor customization
@@ -124,17 +124,20 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization &
} }
} }
// load array of entities id's to exclude, building up the object class // load array of entities id's with masks, building up the object class
settings.entityCustomizations.clear(); settings.entityCustomizations.clear();
if (root["exclude_entities"].is<JsonArray>()) { if (root["masked_entities"].is<JsonArray>()) {
for (const JsonObject exclude_entities : root["exclude_entities"].as<JsonArray>()) { for (const JsonObject masked_entities : root["masked_entities"].as<JsonArray>()) {
auto new_entry = EntityCustomization(); auto new_entry = EntityCustomization();
new_entry.product_id = exclude_entities["product_id"]; new_entry.product_id = masked_entities["product_id"];
new_entry.device_id = exclude_entities["device_id"]; new_entry.device_id = masked_entities["device_id"];
for (const JsonVariant exclude_entity_id : exclude_entities["entity_ids"].as<JsonArray>()) { for (const JsonVariant masked_entity_id : masked_entities["entity_ids"].as<JsonArray>()) {
new_entry.entity_ids.push_back(exclude_entity_id.as<std::string>()); // add entity list if (masked_entity_id.is<std::string>()) {
new_entry.entity_ids.push_back(masked_entity_id.as<std::string>()); // add entity list
} }
}
settings.entityCustomizations.push_back(new_entry); // save the new object settings.entityCustomizations.push_back(new_entry); // save the new object
} }
} }
@@ -157,7 +160,7 @@ void WebCustomizationService::reset_customization(AsyncWebServerRequest * reques
#endif #endif
} }
// send back a short list devices used in the customization page // send back a list of devices used to the customization web page
void WebCustomizationService::devices(AsyncWebServerRequest * request) { void WebCustomizationService::devices(AsyncWebServerRequest * request) {
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN); auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN);
JsonObject root = response->getRoot(); JsonObject root = response->getRoot();
@@ -172,9 +175,9 @@ void WebCustomizationService::devices(AsyncWebServerRequest * request) {
uint8_t device_index = EMSESP::device_index(emsdevice->device_type(), emsdevice->unique_id()); uint8_t device_index = EMSESP::device_index(emsdevice->device_type(), emsdevice->unique_id());
if (device_index) { if (device_index) {
char s[10]; char s[10];
obj["s"] = emsdevice->device_type_name() + Helpers::smallitoa(s, device_index); obj["s"] = emsdevice->device_type_name() + Helpers::smallitoa(s, device_index) + " (" + emsdevice->name() + ")";
} else { } else {
obj["s"] = emsdevice->device_type_name(); obj["s"] = emsdevice->device_type_name() + " (" + emsdevice->name() + ")";
} }
} }
} }
@@ -183,10 +186,10 @@ void WebCustomizationService::devices(AsyncWebServerRequest * request) {
request->send(response); request->send(response);
} }
// send back list device entities // send back list of device entities
void WebCustomizationService::device_entities(AsyncWebServerRequest * request, JsonVariant & json) { void WebCustomizationService::device_entities(AsyncWebServerRequest * request, JsonVariant & json) {
if (json.is<JsonObject>()) { if (json.is<JsonObject>()) {
auto * response = new MsgpackAsyncJsonResponse(true, EMSESP_JSON_SIZE_XXLARGE_DYN); auto * response = new MsgpackAsyncJsonResponse(true, EMSESP_JSON_SIZE_XXXLARGE_DYN);
for (const auto & emsdevice : EMSESP::emsdevices) { for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice->unique_id() == json["id"]) { if (emsdevice->unique_id() == json["id"]) {
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
@@ -205,10 +208,10 @@ void WebCustomizationService::device_entities(AsyncWebServerRequest * request, J
request->send(response); request->send(response);
} }
// takes a list of excluded ids send from the webUI // takes a list of masked ids send from the webUI
// saves it in the customization service // saves it in the customization service
// and updates the entity list real-time // and updates the entity list real-time
void WebCustomizationService::exclude_entities(AsyncWebServerRequest * request, JsonVariant & json) { void WebCustomizationService::masked_entities(AsyncWebServerRequest * request, JsonVariant & json) {
if (json.is<JsonObject>()) { if (json.is<JsonObject>()) {
// find the device using the unique_id // find the device using the unique_id
for (const auto & emsdevice : EMSESP::emsdevices) { for (const auto & emsdevice : EMSESP::emsdevices) {
@@ -218,7 +221,7 @@ void WebCustomizationService::exclude_entities(AsyncWebServerRequest * request,
// first reset all the entity ids // first reset all the entity ids
emsdevice->reset_entity_masks(); emsdevice->reset_entity_masks();
// build a list of entities to exclude and then set the flag to non-visible // build a list of entities
JsonArray entity_ids_json = json["entity_ids"]; JsonArray entity_ids_json = json["entity_ids"];
std::vector<std::string> entity_ids; std::vector<std::string> entity_ids;
for (JsonVariant id : entity_ids_json) { for (JsonVariant id : entity_ids_json) {

View File

@@ -27,7 +27,7 @@
// POST // POST
#define DEVICE_ENTITIES_PATH "/rest/deviceEntities" #define DEVICE_ENTITIES_PATH "/rest/deviceEntities"
#define EXCLUDE_ENTITIES_PATH "/rest/excludeEntities" #define MASKED_ENTITIES_PATH "/rest/maskedEntities"
#define RESET_CUSTOMIZATION_SERVICE_PATH "/rest/resetCustomizations" #define RESET_CUSTOMIZATION_SERVICE_PATH "/rest/resetCustomizations"
namespace emsesp { namespace emsesp {
@@ -63,15 +63,14 @@ class EntityCustomization {
public: public:
uint8_t product_id; // device's product id uint8_t product_id; // device's product id
uint8_t device_id; // device's device id uint8_t device_id; // device's device id
std::vector<std::string> entity_ids; // array of entity ids to exclude std::vector<std::string> entity_ids; // array of entity ids with masks
}; };
class WebCustomization { class WebCustomization {
public: public:
std::list<SensorCustomization> sensorCustomizations; // for sensor names and offsets std::list<SensorCustomization> sensorCustomizations; // for sensor names and offsets
std::list<AnalogCustomization> analogCustomizations; // for analog sensors std::list<AnalogCustomization> analogCustomizations; // for analog sensors
std::list<EntityCustomization> entityCustomizations; // for a list of entities that should be excluded from the device list std::list<EntityCustomization> entityCustomizations; // for a list of entities that have a special mask set
static void read(WebCustomization & settings, JsonObject & root); static void read(WebCustomization & settings, JsonObject & root);
static StateUpdateResult update(JsonObject & root, WebCustomization & settings); static StateUpdateResult update(JsonObject & root, WebCustomization & settings);
}; };
@@ -94,11 +93,11 @@ class WebCustomizationService : public StatefulService<WebCustomization> {
void devices(AsyncWebServerRequest * request); void devices(AsyncWebServerRequest * request);
// POST // POST
void exclude_entities(AsyncWebServerRequest * request, JsonVariant & json); void masked_entities(AsyncWebServerRequest * request, JsonVariant & json);
void device_entities(AsyncWebServerRequest * request, JsonVariant & json); void device_entities(AsyncWebServerRequest * request, JsonVariant & json);
void reset_customization(AsyncWebServerRequest * request); void reset_customization(AsyncWebServerRequest * request);
AsyncCallbackJsonWebHandler _exclude_entities_handler, _device_entities_handler; AsyncCallbackJsonWebHandler _masked_entities_handler, _device_entities_handler;
}; };
} // namespace emsesp } // namespace emsesp