mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-08 08:49:52 +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)
|
- 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
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -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} ({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>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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> {
|
||||||
|
|||||||
@@ -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[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "3.4.0b9"
|
#define EMSESP_APP_VERSION "3.4.0b10"
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user