mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-08 16:59:50 +03:00
Merge pull request #413 from proddy/dev
rename exclude_entities to masked_entities - fixes for #411
This commit is contained in:
@@ -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)
|
||||
- set mode has immediate effect [#395](https://github.com/emsesp/EMS-ESP32/issues/395)
|
||||
- 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
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ const UserForm: FC<UserFormProps> = ({ creating, validator, user, setUser, onDon
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog onClose={onCancelEditing} aria-labelledby="user-form-dialog-title" open={!!user} fullWidth maxWidth="sm">
|
||||
<Dialog onClose={onCancelEditing} open={!!user} fullWidth maxWidth="sm">
|
||||
{user && (
|
||||
<>
|
||||
<DialogTitle id="user-form-dialog-title">{creating ? 'Add' : 'Modify'} User</DialogTitle>
|
||||
|
||||
@@ -20,7 +20,8 @@ import {
|
||||
ListItem,
|
||||
ListItemText,
|
||||
Grid,
|
||||
useMediaQuery
|
||||
useMediaQuery,
|
||||
Tooltip
|
||||
} from '@mui/material';
|
||||
|
||||
import TableCell, { tableCellClasses } from '@mui/material/TableCell';
|
||||
@@ -524,8 +525,10 @@ const DashboardData: FC = () => {
|
||||
<StyledTableRow key={i} onClick={() => sendCommand(dv)}>
|
||||
<StyledTableCell padding="checkbox">
|
||||
{dv.c && me.admin && (
|
||||
<IconButton size="small" aria-label="Edit">
|
||||
<EditIcon color="primary" fontSize="small" />
|
||||
<IconButton size="small">
|
||||
<Tooltip title="Change value...">
|
||||
<EditIcon color="primary" fontSize="small" />
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
)}
|
||||
</StyledTableCell>
|
||||
@@ -569,7 +572,7 @@ const DashboardData: FC = () => {
|
||||
<StyledTableRow key={sensor_data.n} onClick={() => updateSensor(sensor_data)}>
|
||||
<StyledTableCell padding="checkbox">
|
||||
{me.admin && (
|
||||
<IconButton edge="start" size="small" aria-label="Edit">
|
||||
<IconButton edge="start" size="small">
|
||||
<EditIcon color="primary" fontSize="small" />
|
||||
</IconButton>
|
||||
)}
|
||||
@@ -605,7 +608,7 @@ const DashboardData: FC = () => {
|
||||
<StyledTableRow key={analog_data.i} onClick={() => updateAnalog(analog_data)}>
|
||||
<StyledTableCell padding="checkbox">
|
||||
{me.admin && (
|
||||
<IconButton edge="start" size="small" aria-label="Edit">
|
||||
<IconButton edge="start" size="small">
|
||||
<EditIcon color="primary" fontSize="small" />
|
||||
</IconButton>
|
||||
)}
|
||||
|
||||
@@ -12,7 +12,10 @@ import {
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle
|
||||
DialogTitle,
|
||||
ToggleButton,
|
||||
ToggleButtonGroup,
|
||||
Tooltip
|
||||
} from '@mui/material';
|
||||
|
||||
import TableCell, { tableCellClasses } from '@mui/material/TableCell';
|
||||
@@ -22,8 +25,11 @@ import { styled } from '@mui/material/styles';
|
||||
import { useSnackbar } from 'notistack';
|
||||
|
||||
import SaveIcon from '@mui/icons-material/Save';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
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 { ButtonRow, FormLoader, ValidatedTextField, SectionContent } from '../components';
|
||||
@@ -53,6 +59,7 @@ const SettingsCustomization: FC = () => {
|
||||
const [errorMessage, setErrorMessage] = useState<string>();
|
||||
const [selectedDevice, setSelectedDevice] = useState<number>(0);
|
||||
const [confirmReset, setConfirmReset] = useState<boolean>(false);
|
||||
const [masks, setMasks] = useState(() => ['1']);
|
||||
|
||||
const fetchDevices = useCallback(async () => {
|
||||
try {
|
||||
@@ -110,7 +117,8 @@ const SettingsCustomization: FC = () => {
|
||||
<>
|
||||
<Box color="warning.main">
|
||||
<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>
|
||||
</Box>
|
||||
<ValidatedTextField
|
||||
@@ -138,11 +146,13 @@ const SettingsCustomization: FC = () => {
|
||||
|
||||
const saveCustomization = async () => {
|
||||
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 {
|
||||
const response = await EMSESP.writeExcludeEntities({
|
||||
const response = await EMSESP.writeMaskedEntities({
|
||||
id: selectedDevice,
|
||||
entity_ids: exclude_entities
|
||||
entity_ids: masked_entities
|
||||
});
|
||||
if (response.status === 200) {
|
||||
enqueueSnackbar('Customization saved', { variant: 'success' });
|
||||
@@ -160,48 +170,94 @@ const SettingsCustomization: FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const toggleDeviceEntity = (id: number) => {
|
||||
setDeviceEntities(
|
||||
deviceEntities.map((o) => {
|
||||
if (o.i === id) {
|
||||
return { ...o, x: !o.x };
|
||||
}
|
||||
return o;
|
||||
})
|
||||
);
|
||||
const setMask = (de: DeviceEntity, newMask: string[]) => {
|
||||
var new_mask = 0;
|
||||
if (newMask.includes('1')) {
|
||||
new_mask |= 1;
|
||||
}
|
||||
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 (
|
||||
<>
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<StyledTableCell>
|
||||
({deviceEntities.reduce((a, v) => (v.x ? a + 1 : a), 0)}/{deviceEntities.length})
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<StyledTableCell align="center">OPTIONS</StyledTableCell>
|
||||
<StyledTableCell align="left">ENTITY NAME (CODE)</StyledTableCell>
|
||||
<StyledTableCell align="right">VALUE</StyledTableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{deviceEntities.map((de) => (
|
||||
<TableRow key={de.i}>
|
||||
<StyledTableCell padding="checkbox">
|
||||
<ToggleButtonGroup
|
||||
size="small"
|
||||
color="error"
|
||||
value={getMask(de)}
|
||||
onChange={(event, mask) => {
|
||||
setMask(de, mask);
|
||||
}}
|
||||
>
|
||||
<ToggleButton value="8" color="success" disabled={(de.m & 1) !== 0}>
|
||||
<Tooltip title="Favorite">
|
||||
<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 align="left">ENTITY NAME</StyledTableCell>
|
||||
<StyledTableCell>CODE</StyledTableCell>
|
||||
<StyledTableCell align="right">VALUE</StyledTableCell>
|
||||
<StyledTableCell>
|
||||
{de.n} ({de.s})
|
||||
</StyledTableCell>
|
||||
<StyledTableCell align="right">{formatValue(de.v)}</StyledTableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{deviceEntities.map((de) => (
|
||||
<TableRow
|
||||
key={de.i}
|
||||
onClick={() => toggleDeviceEntity(de.i)}
|
||||
sx={de.x ? { backgroundColor: '#f8696b' } : { backgroundColor: 'black' }}
|
||||
>
|
||||
<StyledTableCell padding="checkbox">{de.x && <CloseIcon fontSize="small" />}</StyledTableCell>
|
||||
<StyledTableCell component="th" scope="row">
|
||||
{de.n}
|
||||
</StyledTableCell>
|
||||
<StyledTableCell>{de.s}</StyledTableCell>
|
||||
<StyledTableCell align="right">{formatValue(de.v)}</StyledTableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
DeviceData,
|
||||
DeviceEntity,
|
||||
UniqueID,
|
||||
ExcludeEntities,
|
||||
MaskedEntities,
|
||||
WriteValue,
|
||||
WriteSensor,
|
||||
WriteAnalog,
|
||||
@@ -63,8 +63,8 @@ export function readDeviceEntities(unique_id: UniqueID): AxiosPromise<DeviceEnti
|
||||
return AXIOS_BIN.post('/deviceEntities', unique_id);
|
||||
}
|
||||
|
||||
export function writeExcludeEntities(excludeEntities: ExcludeEntities): AxiosPromise<void> {
|
||||
return AXIOS.post('/excludeEntities', excludeEntities);
|
||||
export function writeMaskedEntities(maskedEntities: MaskedEntities): AxiosPromise<void> {
|
||||
return AXIOS.post('/maskedEntities', maskedEntities);
|
||||
}
|
||||
|
||||
export function writeValue(writevalue: WriteValue): AxiosPromise<void> {
|
||||
|
||||
@@ -146,11 +146,12 @@ export interface DeviceEntity {
|
||||
v?: any; // value, in any format
|
||||
n: string; // name
|
||||
s: string; // shortname
|
||||
x: boolean; // excluded flag
|
||||
m: number; // mask
|
||||
w?: boolean; // writeable
|
||||
i: number; // unique id
|
||||
}
|
||||
|
||||
export interface ExcludeEntities {
|
||||
export interface MaskedEntities {
|
||||
id: number;
|
||||
entity_ids: string[];
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ const EMSESP_BOARDPROFILE_ENDPOINT = REST_ENDPOINT_ROOT + 'boardProfile'
|
||||
const EMSESP_WRITE_VALUE_ENDPOINT = REST_ENDPOINT_ROOT + 'writeValue'
|
||||
const EMSESP_WRITE_SENSOR_ENDPOINT = REST_ENDPOINT_ROOT + 'writeSensor'
|
||||
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'
|
||||
|
||||
settings = {
|
||||
@@ -344,19 +344,19 @@ const emsesp_devices = {
|
||||
i: 1,
|
||||
d: 23,
|
||||
p: 77,
|
||||
s: 'Thermostat1',
|
||||
s: 'Thermostat1 (RC20/Moduline 300)',
|
||||
},
|
||||
{
|
||||
i: 2,
|
||||
d: 8,
|
||||
p: 123,
|
||||
s: 'Boiler',
|
||||
s: 'Boiler (Nefit GBx72/Trendline/Cerapur/Greenstar Si/27i)',
|
||||
},
|
||||
{
|
||||
i: 4,
|
||||
d: 16,
|
||||
p: 165,
|
||||
s: 'Thermostat2',
|
||||
s: 'Thermostat2 (RC100/Moduline 1000/1010)',
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -450,7 +450,7 @@ const status = {
|
||||
|
||||
// Dashboard data
|
||||
const emsesp_devicedata_1 = {
|
||||
label: 'RC20/Moduline 300',
|
||||
label: 'Thermostat: RC20/Moduline 300',
|
||||
data: [
|
||||
{
|
||||
v: '(0)',
|
||||
@@ -567,28 +567,25 @@ const emsesp_devicedata_2 = {
|
||||
}
|
||||
|
||||
const emsesp_devicedata_4 = {
|
||||
label: 'RC100/Moduline 1000/1010',
|
||||
label: 'Thermostat: RC100/Moduline 1000/1010',
|
||||
data: [
|
||||
{
|
||||
v: 16,
|
||||
u: 1,
|
||||
n: 'hc2 selected room temperature',
|
||||
c: 'hc2/seltemp',
|
||||
x: false,
|
||||
},
|
||||
{
|
||||
v: 18.6,
|
||||
u: 1,
|
||||
n: 'hc2 current room temperature',
|
||||
c: '',
|
||||
x: true,
|
||||
},
|
||||
{
|
||||
v: 'off',
|
||||
u: 0,
|
||||
n: 'hc2 mode',
|
||||
c: 'hc2/mode',
|
||||
x: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -598,119 +595,121 @@ const emsesp_deviceentities_1 = [
|
||||
v: '(0)',
|
||||
n: 'error code',
|
||||
s: 'errorcode',
|
||||
x: false,
|
||||
m: 0,
|
||||
i: 1,
|
||||
},
|
||||
{
|
||||
v: '14:54:39 06/06/2021',
|
||||
n: 'date/time',
|
||||
s: 'datetime',
|
||||
x: false,
|
||||
m: 0,
|
||||
i: 2,
|
||||
},
|
||||
{
|
||||
v: 18.22,
|
||||
n: 'hc1 selected room temperature',
|
||||
s: 'hc1/seltemp',
|
||||
x: false,
|
||||
m: 0,
|
||||
w: true,
|
||||
i: 3,
|
||||
},
|
||||
{
|
||||
v: 22.6,
|
||||
n: 'hc1 current room temperature',
|
||||
s: 'hc1/curtemp',
|
||||
x: false,
|
||||
m: 0,
|
||||
i: 4,
|
||||
},
|
||||
{
|
||||
v: 'auto',
|
||||
n: 'hc1 mode',
|
||||
s: 'hc1/mode',
|
||||
x: false,
|
||||
m: 0,
|
||||
w: true,
|
||||
i: 5,
|
||||
},
|
||||
]
|
||||
|
||||
const emsesp_deviceentities_2 = [
|
||||
{ v: false, n: 'heating active', s: 'heatingactive', x: false, i: 1 },
|
||||
{ v: false, n: 'tapwater active', s: 'tapwateractive', x: false, i: 2 },
|
||||
{ v: 5, n: 'selected flow temperature', s: 'selflowtemp', x: false, i: 3 },
|
||||
{ v: 0, n: 'burner selected max power', s: 'selburnpow', x: false, i: 4 },
|
||||
{ v: 0, n: 'heating pump modulation', s: 'heatingpumpmod', x: false, i: 5 },
|
||||
{ n: 'heating pump 2 modulation', s: 'heatingpump2mod', x: true, i: 6 },
|
||||
{ n: 'outside temperature', s: 'outdoortemp', x: true, i: 7 },
|
||||
{ v: 53, n: 'current flow temperature', s: 'curflowtemp', x: false, i: 8 },
|
||||
{ v: 51.8, n: 'return temperature', s: 'rettemp', x: false, i: 9 },
|
||||
{ n: 'mixing switch temperature', s: 'switchtemp', x: true, i: 10 },
|
||||
{ v: 1.3, n: 'system pressure', s: 'syspress', x: false, i: 11 },
|
||||
{ v: 54.6, n: 'actual boiler temperature', s: 'boiltemp', x: false, i: 12 },
|
||||
{ n: 'exhaust temperature', s: 'exhausttemp', x: true, i: 13 },
|
||||
{ v: false, n: 'gas', s: 'burngas', x: false, i: 14 },
|
||||
{ v: false, n: 'gas stage 2', s: 'burngas2', x: false, i: 15 },
|
||||
{ v: 0, n: 'flame current', s: 'flamecurr', x: false, i: 16 },
|
||||
{ v: false, n: 'heating pump', s: 'heatingpump', x: false, i: 17 },
|
||||
{ v: false, n: 'fan', s: 'fanwork', x: false, i: 18 },
|
||||
{ v: false, n: 'ignition', s: 'ignwork', x: false, i: 19 },
|
||||
{ v: false, n: 'oil preheating', s: 'oilpreheat', x: false, i: 20 },
|
||||
{ v: true, n: 'heating activated', s: 'heatingactivated', x: false, i: 21 },
|
||||
{ v: 80, n: 'heating temperature', s: 'heatingtemp', x: false, i: 22 },
|
||||
{ v: 70, n: 'burner pump max power', s: 'pumpmodmax', x: false, i: 23 },
|
||||
{ v: 30, n: 'burner pump min power', s: 'pumpmodmin', x: false, i: 24 },
|
||||
{ v: 1, n: 'pump delay', s: 'pumpdelay', x: false, i: 25 },
|
||||
{ v: 10, n: 'burner min period', s: 'burnminperiod', x: false, i: 26 },
|
||||
{ v: 0, n: 'burner min power', s: 'burnminpower', x: false, i: 27 },
|
||||
{ v: 50, n: 'burner max power', s: 'burnmaxpower', x: false, i: 28 },
|
||||
{ v: -6, n: 'hysteresis on temperature', s: 'boilhyston', x: false, i: 29 },
|
||||
{ v: 6, n: 'hysteresis off temperature', s: 'boilhystoff', x: false, i: 30 },
|
||||
{ v: 0, n: 'set flow temperature', s: 'setflowtemp', x: false, i: 31 },
|
||||
{ v: 0, n: 'burner set power', s: 'setburnpow', x: false, i: 32 },
|
||||
{ v: 0, n: 'burner current power', s: 'curburnpow', x: false, i: 33 },
|
||||
{ v: 326323, n: 'burner starts', s: 'burnstarts', x: false, i: 34 },
|
||||
{ v: 553437, n: 'total burner operating time', s: 'burnworkmin', x: false, i: 35 },
|
||||
{ v: 451286, n: 'total heat operating time', s: 'heatworkmin', x: false, i: 36 },
|
||||
{ v: 4672175, n: 'total UBA operating time', s: 'ubauptime', x: false, i: 37 },
|
||||
{ v: '1C(210) 06.06.2020 12:07 (0 min)', n: 'last error code', s: 'lastcode', x: false, i: 38 },
|
||||
{ v: '0H', n: 'service code', s: 'servicecode', x: false, i: 39 },
|
||||
{ v: 203, n: 'service code number', s: 'servicecodenumber', x: false, i: 40 },
|
||||
{ v: 'H00', n: 'maintenance message', s: 'maintenancemessage', x: false, i: 41 },
|
||||
{ v: 'manual', n: 'maintenance scheduled', s: 'maintenance', x: false, i: 42 },
|
||||
{ v: 6000, n: 'time to next maintenance', s: 'maintenancetime', x: false, i: 43 },
|
||||
{ v: '01.01.2012', n: 'next maintenance date', s: 'maintenancedate', x: false, i: 44 },
|
||||
{ v: true, n: 'dhw turn on/off', s: 'wwtapactivated', x: false, i: 45 },
|
||||
{ v: 62, n: 'dhw set temperature', s: 'wwsettemp', x: false, i: 46 },
|
||||
{ v: 60, n: 'dhw selected temperature', s: 'wwseltemp', x: false, i: 47 },
|
||||
{ n: 'dhw selected lower temperature', s: 'wwseltemplow', x: true, i: 48 },
|
||||
{ n: 'dhw selected temperature for off', s: 'wwseltempoff', x: true, i: 49 },
|
||||
{ n: 'dhw single charge temperature', s: 'wwseltempsingle', x: true, i: 50 },
|
||||
{ v: 'flow', n: 'dhw type', s: 'wwtype', x: false, i: 51 },
|
||||
{ v: 'hot', n: 'dhw comfort', s: 'wwcomfort', x: false, i: 52 },
|
||||
{ v: 40, n: 'dhw flow temperature offset', s: 'wwflowtempoffset', x: false, i: 53 },
|
||||
{ v: 100, n: 'dhw max power', s: 'wwmaxpower', x: false, i: 54 },
|
||||
{ v: false, n: 'dhw circulation pump available', s: 'wwcircpump', x: false, i: 55 },
|
||||
{ v: '3-way valve', n: 'dhw charging type', s: 'wwchargetype', x: false, i: 56 },
|
||||
{ v: -5, n: 'dhw hysteresis on temperature', s: 'wwhyston', x: false, i: 57 },
|
||||
{ v: 0, n: 'dhw hysteresis off temperature', s: 'wwhystoff', x: false, i: 58 },
|
||||
{ v: 70, n: 'dhw disinfection temperature', s: 'wwdisinfectiontemp', x: false, i: 59 },
|
||||
{ v: 'off', n: 'dhw circulation pump mode', s: 'wwcircmode', x: false, i: 60 },
|
||||
{ v: false, n: 'dhw circulation active', s: 'wwcirc', x: false, i: 61 },
|
||||
{ v: 46.4, n: 'dhw current intern temperature', s: 'wwcurtemp', x: false, i: 62 },
|
||||
{ n: 'dhw current extern temperature', s: 'wwcurtemp2', x: true, i: 63 },
|
||||
{ v: 0, n: 'dhw current tap water flow', s: 'wwcurflow', x: false, i: 64 },
|
||||
{ v: 46.3, n: 'dhw storage intern temperature', s: 'wwstoragetemp1', x: false, i: 65 },
|
||||
{ n: 'dhw storage extern temperature', s: 'wwstoragetemp2', x: true, i: 66 },
|
||||
{ v: true, n: 'dhw activated', s: 'wwactivated', x: false, i: 67 },
|
||||
{ v: false, n: 'dhw one time charging', s: 'wwonetime', x: false, i: 68 },
|
||||
{ v: false, n: 'dhw disinfecting', s: 'wwdisinfecting', x: false, i: 69 },
|
||||
{ v: false, n: 'dhw charging', s: 'wwcharging', x: false, i: 70 },
|
||||
{ v: false, n: 'dhw recharging', s: 'wwrecharging', x: false, i: 71 },
|
||||
{ v: true, n: 'dhw temperature ok', s: 'wwtempok', x: false, i: 72 },
|
||||
{ v: false, n: 'dhw active', s: 'wwactive', x: false, i: 73 },
|
||||
{ v: true, n: 'dhw 3way valve active', s: 'ww3wayvalve', x: false, i: 74 },
|
||||
{ v: 0, n: 'dhw set pump power', s: 'wwsetpumppower', x: false, i: 75 },
|
||||
{ n: 'dhw mixer temperature', s: 'wwmixertemp', x: true, i: 76 },
|
||||
{ n: 'dhw cylinder middle temperature (TS3)', s: 'wwcylmiddletemp', x: true, i: 77 },
|
||||
{ v: 288768, n: 'dhw starts', s: 'wwstarts', x: false, i: 78 },
|
||||
{ v: 102151, n: 'dhw active time', s: 'wwworkm', x: false, i: 79 },
|
||||
{ v: false, n: 'heating active', s: 'heatingactive', m: 0, i: 1 },
|
||||
{ v: false, n: 'tapwater active', s: 'tapwateractive', m: 0, i: 2 },
|
||||
{ v: 5, n: 'selected flow temperature', s: 'selflowtemp', m: 0, i: 3 },
|
||||
{ v: 0, n: 'burner selected max power', s: 'selburnpow', m: 0, i: 4 },
|
||||
{ v: 0, n: 'heating pump modulation', s: 'heatingpumpmod', m: 0, i: 5 },
|
||||
{ n: 'heating pump 2 modulation', s: 'heatingpump2mod', m: 2, i: 6 },
|
||||
{ n: 'outside temperature', s: 'outdoortemp', m: 2, i: 7 },
|
||||
{ v: 53, n: 'current flow temperature', s: 'curflowtemp', m: 0, i: 8 },
|
||||
{ v: 51.8, n: 'return temperature', s: 'rettemp', m: 0, i: 9 },
|
||||
{ n: 'mixing switch temperature', s: 'switchtemp', m: 2, i: 10 },
|
||||
{ v: 1.3, n: 'system pressure', s: 'syspress', m: 0, i: 11 },
|
||||
{ v: 54.6, n: 'actual boiler temperature', s: 'boiltemp', m: 0, i: 12 },
|
||||
{ n: 'exhaust temperature', s: 'exhausttemp', m: 2, i: 13 },
|
||||
{ v: false, n: 'gas', s: 'burngas', m: 0, i: 14 },
|
||||
{ v: false, n: 'gas stage 2', s: 'burngas2', m: 0, i: 15 },
|
||||
{ v: 0, n: 'flame current', s: 'flamecurr', m: 0, i: 16 },
|
||||
{ v: false, n: 'heating pump', s: 'heatingpump', m: 0, i: 17 },
|
||||
{ v: false, n: 'fan', s: 'fanwork', m: 0, i: 18 },
|
||||
{ v: false, n: 'ignition', s: 'ignwork', m: 0, i: 19 },
|
||||
{ v: false, n: 'oil preheating', s: 'oilpreheat', m: 0, i: 20 },
|
||||
{ v: true, n: 'heating activated', s: 'heatingactivated', m: 0, i: 21 },
|
||||
{ v: 80, n: 'heating temperature', s: 'heatingtemp', m: 0, i: 22 },
|
||||
{ v: 70, n: 'burner pump max power', s: 'pumpmodmax', m: 0, i: 23 },
|
||||
{ v: 30, n: 'burner pump min power', s: 'pumpmodmin', m: 0, i: 24 },
|
||||
{ v: 1, n: 'pump delay', s: 'pumpdelay', m: 0, i: 25 },
|
||||
{ v: 10, n: 'burner min period', s: 'burnminperiod', m: 0, i: 26 },
|
||||
{ v: 0, n: 'burner min power', s: 'burnminpower', m: 0, i: 27 },
|
||||
{ v: 50, n: 'burner max power', s: 'burnmaxpower', m: 0, i: 28 },
|
||||
{ v: -6, n: 'hysteresis on temperature', s: 'boilhyston', m: 0, i: 29 },
|
||||
{ v: 6, n: 'hysteresis off temperature', s: 'boilhystoff', m: 0, i: 30 },
|
||||
{ v: 0, n: 'set flow temperature', s: 'setflowtemp', m: 0, i: 31 },
|
||||
{ v: 0, n: 'burner set power', s: 'setburnpow', m: 0, i: 32 },
|
||||
{ v: 0, n: 'burner current power', s: 'curburnpow', m: 0, i: 33 },
|
||||
{ v: 326323, n: 'burner starts', s: 'burnstarts', m: 0, i: 34 },
|
||||
{ v: 553437, n: 'total burner operating time', s: 'burnworkmin', m: 0, i: 35 },
|
||||
{ v: 451286, n: 'total heat operating time', s: 'heatworkmin', m: 0, i: 36 },
|
||||
{ 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', m: 0, i: 38 },
|
||||
{ v: '0H', n: 'service code', s: 'servicecode', m: 0, i: 39 },
|
||||
{ v: 203, n: 'service code number', s: 'servicecodenumber', m: 0, i: 40 },
|
||||
{ v: 'H00', n: 'maintenance message', s: 'maintenancemessage', m: 0, i: 41 },
|
||||
{ v: 'manual', n: 'maintenance scheduled', s: 'maintenance', m: 0, i: 42 },
|
||||
{ v: 6000, n: 'time to next maintenance', s: 'maintenancetime', m: 0, i: 43 },
|
||||
{ v: '01.01.2012', n: 'next maintenance date', s: 'maintenancedate', m: 0, i: 44 },
|
||||
{ v: true, n: 'dhw turn on/off', s: 'wwtapactivated', m: 0, i: 45 },
|
||||
{ v: 62, n: 'dhw set temperature', s: 'wwsettemp', m: 0, i: 46 },
|
||||
{ v: 60, n: 'dhw selected temperature', s: 'wwseltemp', m: 0, i: 47 },
|
||||
{ n: 'dhw selected lower temperature', s: 'wwseltemplow', m: 2, i: 48 },
|
||||
{ n: 'dhw selected temperature for off', s: 'wwseltempoff', m: 2, i: 49 },
|
||||
{ n: 'dhw single charge temperature', s: 'wwseltempsingle', m: 2, i: 50 },
|
||||
{ v: 'flow', n: 'dhw type', s: 'wwtype', m: 0, i: 51 },
|
||||
{ v: 'hot', n: 'dhw comfort', s: 'wwcomfort', m: 0, i: 52 },
|
||||
{ v: 40, n: 'dhw flow temperature offset', s: 'wwflowtempoffset', m: 0, i: 53 },
|
||||
{ v: 100, n: 'dhw max power', s: 'wwmaxpower', m: 0, i: 54 },
|
||||
{ v: false, n: 'dhw circulation pump available', s: 'wwcircpump', m: 0, i: 55 },
|
||||
{ v: '3-way valve', n: 'dhw charging type', s: 'wwchargetype', m: 0, i: 56 },
|
||||
{ v: -5, n: 'dhw hysteresis on temperature', s: 'wwhyston', m: 0, i: 57 },
|
||||
{ v: 0, n: 'dhw hysteresis off temperature', s: 'wwhystoff', m: 0, i: 58 },
|
||||
{ v: 70, n: 'dhw disinfection temperature', s: 'wwdisinfectiontemp', m: 0, i: 59 },
|
||||
{ v: 'off', n: 'dhw circulation pump mode', s: 'wwcircmode', m: 0, i: 60 },
|
||||
{ v: false, n: 'dhw circulation active', s: 'wwcirc', m: 0, i: 61 },
|
||||
{ v: 46.4, n: 'dhw current intern temperature', s: 'wwcurtemp', m: 0, i: 62 },
|
||||
{ n: 'dhw current extern temperature', s: 'wwcurtemp2', m: 2, i: 63 },
|
||||
{ v: 0, n: 'dhw current tap water flow', s: 'wwcurflow', m: 0, i: 64 },
|
||||
{ v: 46.3, n: 'dhw storage intern temperature', s: 'wwstoragetemp1', m: 0, i: 65 },
|
||||
{ n: 'dhw storage extern temperature', s: 'wwstoragetemp2', m: 2, i: 66 },
|
||||
{ v: true, n: 'dhw activated', s: 'wwactivated', m: 0, i: 67 },
|
||||
{ v: false, n: 'dhw one time charging', s: 'wwonetime', m: 0, i: 68 },
|
||||
{ v: false, n: 'dhw disinfecting', s: 'wwdisinfecting', m: 0, i: 69 },
|
||||
{ v: false, n: 'dhw charging', s: 'wwcharging', m: 0, i: 70 },
|
||||
{ v: false, n: 'dhw recharging', s: 'wwrecharging', m: 0, i: 71 },
|
||||
{ v: true, n: 'dhw temperature ok', s: 'wwtempok', m: 0, i: 72 },
|
||||
{ v: false, n: 'dhw active', s: 'wwactive', m: 0, i: 73 },
|
||||
{ v: true, n: 'dhw 3way valve active', s: 'ww3wayvalve', m: 0, i: 74 },
|
||||
{ v: 0, n: 'dhw set pump power', s: 'wwsetpumppower', m: 0, i: 75 },
|
||||
{ n: 'dhw mixer temperature', s: 'wwmixertemp', m: 2, i: 76 },
|
||||
{ n: 'dhw cylinder middle temperature (TS3)', s: 'wwcylmiddletemp', m: 2, i: 77 },
|
||||
{ v: 288768, n: 'dhw starts', s: 'wwstarts', m: 0, i: 78 },
|
||||
{ v: 102151, n: 'dhw active time', s: 'wwworkm', m: 0, i: 79 },
|
||||
]
|
||||
|
||||
const emsesp_deviceentities_4 = [
|
||||
@@ -718,20 +717,20 @@ const emsesp_deviceentities_4 = [
|
||||
v: 16,
|
||||
n: 'hc2 selected room temperature',
|
||||
s: 'hc2/seltemp',
|
||||
x: false,
|
||||
m: 0,
|
||||
i: 1,
|
||||
},
|
||||
{
|
||||
n: 'hc2 current room temperature',
|
||||
s: 'hc2/curtemp',
|
||||
x: true,
|
||||
m: 3,
|
||||
i: 2,
|
||||
},
|
||||
{
|
||||
v: 'off',
|
||||
n: 'hc2 mode',
|
||||
s: 'hc2/mode',
|
||||
x: true,
|
||||
m: 3,
|
||||
i: 3,
|
||||
},
|
||||
]
|
||||
@@ -925,8 +924,8 @@ rest_server.post(EMSESP_DEVICEENTITIES_ENDPOINT, (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
rest_server.post(EMSESP_EXCLUDE_ENTITIES_ENDPOINT, (req, res) => {
|
||||
console.log('exclude list for unique id ' + req.body.id + ' and entities:')
|
||||
rest_server.post(EMSESP_MASKED_ENTITIES_ENDPOINT, (req, res) => {
|
||||
console.log('list for unique id ' + req.body.id + ' and entities:')
|
||||
console.log(req.body.entity_ids)
|
||||
res.sendStatus(200)
|
||||
})
|
||||
|
||||
@@ -1251,13 +1251,13 @@ void Thermostat::process_RCTime(std::shared_ptr<const Telegram> telegram) {
|
||||
LOG_INFO(F("thermostat time correction from ntp"));
|
||||
}
|
||||
}
|
||||
#ifndef EMSESP_STANDALONE
|
||||
if (!ntp_ && tm_->tm_year > 110) { // emsesp clock not set, but thermostat clock
|
||||
struct timeval newnow = {.tv_sec = ttime};
|
||||
#ifndef EMSESP_STANDALONE
|
||||
settimeofday(&newnow, nullptr);
|
||||
#endif
|
||||
LOG_INFO(F("ems-esp time set from thermostat"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// process_RCError - type 0xA2 - error message - 14 bytes long
|
||||
|
||||
@@ -632,11 +632,16 @@ std::string EMSdevice::get_value_uom(const char * key) const {
|
||||
// prepare array of device values used for the WebUI
|
||||
// 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
|
||||
// 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) {
|
||||
output["label"] = to_string_short();
|
||||
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_) {
|
||||
// check conditions:
|
||||
// 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
|
||||
// this is used only for WebCustomizationService::device_entities()
|
||||
void EMSdevice::generate_values_web_all(JsonArray & output) {
|
||||
for (auto & dv : devicevalues_) {
|
||||
// also show commands and entities that have an empty full name
|
||||
@@ -854,6 +835,7 @@ void EMSdevice::generate_values_web_all(JsonArray & output) {
|
||||
} else {
|
||||
obj["n"] = "(hidden)";
|
||||
}
|
||||
|
||||
// shortname
|
||||
if (dv.tag >= DeviceValueTAG::TAG_HC1) {
|
||||
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;
|
||||
}
|
||||
|
||||
// is it marked as excluded?
|
||||
obj["x"] = dv.has_state(DeviceValueState::DV_WEB_EXCLUDE);
|
||||
obj["m"] = dv.state >> 4; // send back the mask state. We're only interested in the high nibble
|
||||
obj["w"] = dv.has_cmd; // if writable
|
||||
obj["i"] = dv.id; // add the unique ID
|
||||
}
|
||||
}
|
||||
|
||||
// add the unique ID
|
||||
obj["i"] = dv.id;
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -110,15 +110,17 @@ class DeviceValue {
|
||||
|
||||
// states of a device value
|
||||
enum DeviceValueState : uint8_t {
|
||||
// low nibble active state of the device value
|
||||
DV_DEFAULT = 0, // 0 - does not yet have a 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_CLIMATE_NO_RT = (1 << 2), // 3 - climate created without roomTemp
|
||||
// high nibble as mask for exclusions
|
||||
DV_WEB_EXCLUDE = (1 << 4), // 16 - not shown on web
|
||||
DV_API_MQTT_EXCLUDE = (1 << 5), // 32 - not shown on mqtt, API
|
||||
DV_READONLY = (1 << 6), // 64 - read only
|
||||
DV_FAVORITE = (1 << 7) // 128 - sort to front
|
||||
|
||||
// high nibble as mask for exclusions & special functions
|
||||
DV_WEB_EXCLUDE = (1 << 4), // 16 - not shown on web
|
||||
DV_API_MQTT_EXCLUDE = (1 << 5), // 32 - not shown on mqtt, API
|
||||
DV_READONLY = (1 << 6), // 64 - read only
|
||||
DV_FAVORITE = (1 << 7) // 128 - sort to front
|
||||
};
|
||||
|
||||
uint8_t device_type; // EMSdevice::DeviceType
|
||||
|
||||
@@ -1018,7 +1018,6 @@ bool System::command_customizations(const char * value, const int8_t id, JsonObj
|
||||
|
||||
JsonObject node = output.createNestedObject("Customizations");
|
||||
|
||||
// hide ssid from this list
|
||||
EMSESP::webCustomizationService.read([&](WebCustomization & settings) {
|
||||
// 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");
|
||||
for (const auto & entityCustomization : settings.entityCustomizations) {
|
||||
JsonObject entityJson = mask_entitiesJson.createNestedObject();
|
||||
|
||||
@@ -595,8 +595,8 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
EMSESP::system_.healthcheck(n);
|
||||
}
|
||||
|
||||
if (command == "exclude") {
|
||||
shell.printfln(F("Testing exclude entities"));
|
||||
if (command == "masked") {
|
||||
shell.printfln(F("Testing masked entities"));
|
||||
|
||||
Mqtt::ha_enabled(true);
|
||||
Mqtt::send_response(false);
|
||||
|
||||
@@ -31,12 +31,12 @@ namespace emsesp {
|
||||
// #define EMSESP_DEBUG_DEFAULT "mixer"
|
||||
// #define EMSESP_DEBUG_DEFAULT "web"
|
||||
// #define EMSESP_DEBUG_DEFAULT "mqtt"
|
||||
// #define EMSESP_DEBUG_DEFAULT "general"
|
||||
#define EMSESP_DEBUG_DEFAULT "general"
|
||||
// #define EMSESP_DEBUG_DEFAULT "boiler"
|
||||
// #define EMSESP_DEBUG_DEFAULT "mqtt2"
|
||||
// #define EMSESP_DEBUG_DEFAULT "mqtt_nested"
|
||||
#define EMSESP_DEBUG_DEFAULT "ha"
|
||||
// #define EMSESP_DEBUG_DEFAULT "exclude"
|
||||
// #define EMSESP_DEBUG_DEFAULT "ha"
|
||||
// #define EMSESP_DEBUG_DEFAULT "masked"
|
||||
// #define EMSESP_DEBUG_DEFAULT "board_profile"
|
||||
// #define EMSESP_DEBUG_DEFAULT "shower_alert"
|
||||
// #define EMSESP_DEBUG_DEFAULT "310"
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define EMSESP_APP_VERSION "3.4.0b9"
|
||||
#define EMSESP_APP_VERSION "3.4.0b10"
|
||||
|
||||
@@ -31,9 +31,9 @@ WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * f
|
||||
securityManager,
|
||||
AuthenticationPredicates::IS_AUTHENTICATED)
|
||||
, _fsPersistence(WebCustomization::read, WebCustomization::update, this, fs, EMSESP_CUSTOMIZATION_FILE)
|
||||
, _exclude_entities_handler(EXCLUDE_ENTITIES_PATH,
|
||||
securityManager->wrapCallback(std::bind(&WebCustomizationService::exclude_entities, this, _1, _2),
|
||||
AuthenticationPredicates::IS_AUTHENTICATED))
|
||||
, _masked_entities_handler(MASKED_ENTITIES_PATH,
|
||||
securityManager->wrapCallback(std::bind(&WebCustomizationService::masked_entities, this, _1, _2),
|
||||
AuthenticationPredicates::IS_AUTHENTICATED))
|
||||
, _device_entities_handler(DEVICE_ENTITIES_PATH,
|
||||
securityManager->wrapCallback(std::bind(&WebCustomizationService::device_entities, this, _1, _2),
|
||||
AuthenticationPredicates::IS_AUTHENTICATED)) {
|
||||
@@ -45,17 +45,17 @@ WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * f
|
||||
HTTP_POST,
|
||||
securityManager->wrapRequest(std::bind(&WebCustomizationService::reset_customization, this, _1), AuthenticationPredicates::IS_ADMIN));
|
||||
|
||||
_exclude_entities_handler.setMethod(HTTP_POST);
|
||||
_exclude_entities_handler.setMaxContentLength(2048);
|
||||
_exclude_entities_handler.setMaxJsonBufferSize(2048);
|
||||
server->addHandler(&_exclude_entities_handler);
|
||||
_masked_entities_handler.setMethod(HTTP_POST);
|
||||
_masked_entities_handler.setMaxContentLength(2048);
|
||||
_masked_entities_handler.setMaxJsonBufferSize(2048);
|
||||
server->addHandler(&_masked_entities_handler);
|
||||
|
||||
_device_entities_handler.setMethod(HTTP_POST);
|
||||
_device_entities_handler.setMaxContentLength(256);
|
||||
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) {
|
||||
// Dallas Sensor customization
|
||||
JsonArray sensorsJson = root.createNestedArray("sensors");
|
||||
@@ -78,21 +78,21 @@ void WebCustomization::read(WebCustomization & settings, JsonObject & root) {
|
||||
sensorJson["type"] = sensor.type; // t
|
||||
}
|
||||
|
||||
// Exclude entities customization
|
||||
JsonArray exclude_entitiesJson = root.createNestedArray("exclude_entities");
|
||||
// Masked entities customization
|
||||
JsonArray masked_entitiesJson = root.createNestedArray("masked_entities");
|
||||
for (const EntityCustomization & entityCustomization : settings.entityCustomizations) {
|
||||
JsonObject entityJson = exclude_entitiesJson.createNestedObject();
|
||||
JsonObject entityJson = masked_entitiesJson.createNestedObject();
|
||||
entityJson["product_id"] = entityCustomization.product_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) {
|
||||
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
|
||||
StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization & settings) {
|
||||
// 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();
|
||||
if (root["exclude_entities"].is<JsonArray>()) {
|
||||
for (const JsonObject exclude_entities : root["exclude_entities"].as<JsonArray>()) {
|
||||
if (root["masked_entities"].is<JsonArray>()) {
|
||||
for (const JsonObject masked_entities : root["masked_entities"].as<JsonArray>()) {
|
||||
auto new_entry = EntityCustomization();
|
||||
new_entry.product_id = exclude_entities["product_id"];
|
||||
new_entry.device_id = exclude_entities["device_id"];
|
||||
new_entry.product_id = masked_entities["product_id"];
|
||||
new_entry.device_id = masked_entities["device_id"];
|
||||
|
||||
for (const JsonVariant exclude_entity_id : exclude_entities["entity_ids"].as<JsonArray>()) {
|
||||
new_entry.entity_ids.push_back(exclude_entity_id.as<std::string>()); // add entity list
|
||||
for (const JsonVariant masked_entity_id : masked_entities["entity_ids"].as<JsonArray>()) {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -157,7 +160,7 @@ void WebCustomizationService::reset_customization(AsyncWebServerRequest * reques
|
||||
#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) {
|
||||
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN);
|
||||
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());
|
||||
if (device_index) {
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
|
||||
// send back list device entities
|
||||
// send back list of device entities
|
||||
void WebCustomizationService::device_entities(AsyncWebServerRequest * request, JsonVariant & json) {
|
||||
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) {
|
||||
if (emsdevice->unique_id() == json["id"]) {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
@@ -205,10 +208,10 @@ void WebCustomizationService::device_entities(AsyncWebServerRequest * request, J
|
||||
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
|
||||
// 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>()) {
|
||||
// find the device using the unique_id
|
||||
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||
@@ -218,7 +221,7 @@ void WebCustomizationService::exclude_entities(AsyncWebServerRequest * request,
|
||||
// first reset all the entity ids
|
||||
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"];
|
||||
std::vector<std::string> entity_ids;
|
||||
for (JsonVariant id : entity_ids_json) {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
// POST
|
||||
#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"
|
||||
|
||||
namespace emsesp {
|
||||
@@ -63,17 +63,16 @@ class EntityCustomization {
|
||||
public:
|
||||
uint8_t product_id; // device's product 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 {
|
||||
public:
|
||||
std::list<SensorCustomization> sensorCustomizations; // for sensor names and offsets
|
||||
std::list<AnalogCustomization> analogCustomizations; // for analog sensors
|
||||
std::list<EntityCustomization> entityCustomizations; // for a list of entities that should be excluded from the device list
|
||||
|
||||
static void read(WebCustomization & settings, JsonObject & root);
|
||||
static StateUpdateResult update(JsonObject & root, WebCustomization & settings);
|
||||
std::list<EntityCustomization> entityCustomizations; // for a list of entities that have a special mask set
|
||||
static void read(WebCustomization & settings, JsonObject & root);
|
||||
static StateUpdateResult update(JsonObject & root, WebCustomization & settings);
|
||||
};
|
||||
|
||||
class WebCustomizationService : public StatefulService<WebCustomization> {
|
||||
@@ -94,11 +93,11 @@ class WebCustomizationService : public StatefulService<WebCustomization> {
|
||||
void devices(AsyncWebServerRequest * request);
|
||||
|
||||
// POST
|
||||
void exclude_entities(AsyncWebServerRequest * request, JsonVariant & json);
|
||||
void masked_entities(AsyncWebServerRequest * request, JsonVariant & json);
|
||||
void device_entities(AsyncWebServerRequest * request, JsonVariant & json);
|
||||
void reset_customization(AsyncWebServerRequest * request);
|
||||
|
||||
AsyncCallbackJsonWebHandler _exclude_entities_handler, _device_entities_handler;
|
||||
AsyncCallbackJsonWebHandler _masked_entities_handler, _device_entities_handler;
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
Reference in New Issue
Block a user