mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 16:29:51 +03:00
Merge branch 'dev_' into dev_no_master_thermostat
This commit is contained in:
@@ -183,45 +183,49 @@ const MqttSettingsForm: FC = () => {
|
||||
control={<Checkbox name="send_response" checked={data.send_response} onChange={updateFormValue} />}
|
||||
label="Publish command output to a 'response' topic"
|
||||
/>
|
||||
<Grid container spacing={1} direction="row" justifyContent="flex-start" alignItems="flex-start">
|
||||
<Grid item>
|
||||
<BlockFormControlLabel
|
||||
control={<Checkbox name="publish_single" checked={data.publish_single} onChange={updateFormValue} />}
|
||||
label="Publish single value topics on change"
|
||||
/>
|
||||
</Grid>
|
||||
{data.publish_single && (
|
||||
{!data.ha_enabled && (
|
||||
<Grid container spacing={1} direction="row" justifyContent="flex-start" alignItems="flex-start">
|
||||
<Grid item>
|
||||
<BlockFormControlLabel
|
||||
control={
|
||||
<Checkbox name="publish_single2cmd" checked={data.publish_single2cmd} onChange={updateFormValue} />
|
||||
}
|
||||
label="Publish to command topics (ioBroker)"
|
||||
control={<Checkbox name="publish_single" checked={data.publish_single} onChange={updateFormValue} />}
|
||||
label="Publish single value topics on change"
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid container spacing={1} direction="row" justifyContent="flex-start" alignItems="flex-start">
|
||||
<Grid item>
|
||||
<BlockFormControlLabel
|
||||
control={<Checkbox name="ha_enabled" checked={data.ha_enabled} onChange={updateFormValue} />}
|
||||
label="Enable MQTT Discovery (Home Assistant, Domoticz)"
|
||||
/>
|
||||
{data.publish_single && (
|
||||
<Grid item>
|
||||
<BlockFormControlLabel
|
||||
control={
|
||||
<Checkbox name="publish_single2cmd" checked={data.publish_single2cmd} onChange={updateFormValue} />
|
||||
}
|
||||
label="Publish to command topics (ioBroker)"
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
{data.ha_enabled && (
|
||||
<Grid item xs={6}>
|
||||
<ValidatedTextField
|
||||
name="discovery_prefix"
|
||||
label="Prefix for the Discovery topics"
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={data.discovery_prefix}
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
)}
|
||||
{!data.publish_single && (
|
||||
<Grid container spacing={1} direction="row" justifyContent="flex-start" alignItems="flex-start">
|
||||
<Grid item>
|
||||
<BlockFormControlLabel
|
||||
control={<Checkbox name="ha_enabled" checked={data.ha_enabled} onChange={updateFormValue} />}
|
||||
label="Enable MQTT Discovery (Home Assistant, Domoticz)"
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
{data.ha_enabled && (
|
||||
<Grid item xs={6}>
|
||||
<ValidatedTextField
|
||||
name="discovery_prefix"
|
||||
label="Prefix for the Discovery topics"
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={data.discovery_prefix}
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
)}
|
||||
<Typography sx={{ pt: 2 }} variant="h6" color="primary">
|
||||
Publish Intervals (in seconds, 0=automatic)
|
||||
</Typography>
|
||||
|
||||
@@ -32,11 +32,14 @@ import { extractErrorMessage, formatDateTime, formatLocalDateTime, useRest } fro
|
||||
import { AuthenticatedContext } from '../../contexts/authentication';
|
||||
|
||||
export const isNtpActive = ({ status }: NTPStatus) => status === NTPSyncStatus.NTP_ACTIVE;
|
||||
export const isNtpEnabled = ({ status }: NTPStatus) => status !== NTPSyncStatus.NTP_DISABLED;
|
||||
|
||||
export const ntpStatusHighlight = ({ status }: NTPStatus, theme: Theme) => {
|
||||
switch (status) {
|
||||
case NTPSyncStatus.NTP_INACTIVE:
|
||||
case NTPSyncStatus.NTP_DISABLED:
|
||||
return theme.palette.info.main;
|
||||
case NTPSyncStatus.NTP_INACTIVE:
|
||||
return theme.palette.error.main;
|
||||
case NTPSyncStatus.NTP_ACTIVE:
|
||||
return theme.palette.success.main;
|
||||
default:
|
||||
@@ -46,6 +49,8 @@ export const ntpStatusHighlight = ({ status }: NTPStatus, theme: Theme) => {
|
||||
|
||||
export const ntpStatus = ({ status }: NTPStatus) => {
|
||||
switch (status) {
|
||||
case NTPSyncStatus.NTP_DISABLED:
|
||||
return 'Disabled';
|
||||
case NTPSyncStatus.NTP_INACTIVE:
|
||||
return 'Inactive';
|
||||
case NTPSyncStatus.NTP_ACTIVE:
|
||||
@@ -143,7 +148,7 @@ const NTPStatusForm: FC = () => {
|
||||
<ListItemText primary="Status" secondary={ntpStatus(data)} />
|
||||
</ListItem>
|
||||
<Divider variant="inset" component="li" />
|
||||
{isNtpActive(data) && (
|
||||
{isNtpEnabled(data) && (
|
||||
<>
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -13,13 +13,14 @@ const FirmwareFileUpload: FC<UploadFirmwareProps> = ({ uploadFirmware }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<MessageBox
|
||||
message="Upload a new firmware (.bin) file below to replace the existing firmware"
|
||||
level="warning"
|
||||
my={2}
|
||||
/>
|
||||
{!uploading && (
|
||||
<MessageBox
|
||||
message="Upload a new firmware (.bin) file below to replace the existing firmware"
|
||||
level="warning"
|
||||
my={2}
|
||||
/>
|
||||
)}
|
||||
<SingleUpload
|
||||
// accept="application/octet-stream"
|
||||
accept=".bin"
|
||||
onDrop={uploadFile}
|
||||
onCancel={cancelUpload}
|
||||
|
||||
@@ -37,6 +37,10 @@ import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import SendIcon from '@mui/icons-material/TrendingFlat';
|
||||
import SaveIcon from '@mui/icons-material/Save';
|
||||
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
|
||||
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
|
||||
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
|
||||
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
|
||||
import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
|
||||
|
||||
import DeviceIcon from './DeviceIcon';
|
||||
|
||||
@@ -62,7 +66,8 @@ import {
|
||||
AnalogType,
|
||||
AnalogTypeNames,
|
||||
Sensor,
|
||||
Analog
|
||||
Analog,
|
||||
DeviceEntityMask
|
||||
} from './types';
|
||||
|
||||
const StyledTableCell = styled(TableCell)(({ theme }) => ({
|
||||
@@ -153,6 +158,8 @@ const DashboardData: FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const isCmdOnly = (dv: DeviceValue) => dv.v === undefined && dv.c;
|
||||
|
||||
function formatValue(value: any, uom: number) {
|
||||
if (value === undefined) {
|
||||
return '';
|
||||
@@ -213,12 +220,12 @@ const DashboardData: FC = () => {
|
||||
if (deviceValue) {
|
||||
return (
|
||||
<Dialog open={deviceValue !== undefined} onClose={() => setDeviceValue(undefined)}>
|
||||
<DialogTitle>Change Value</DialogTitle>
|
||||
<DialogTitle>{isCmdOnly(deviceValue) ? 'Run Command' : 'Change Value'}</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
{deviceValue.l && (
|
||||
<ValidatedTextField
|
||||
name="v"
|
||||
label={deviceValue.n}
|
||||
label={deviceValue.n.slice(2)}
|
||||
value={deviceValue.v}
|
||||
autoFocus
|
||||
sx={{ width: '30ch' }}
|
||||
@@ -233,13 +240,13 @@ const DashboardData: FC = () => {
|
||||
{!deviceValue.l && (
|
||||
<ValidatedTextField
|
||||
name="v"
|
||||
label={deviceValue.n}
|
||||
label={deviceValue.n.slice(2)}
|
||||
value={deviceValue.u ? numberValue(deviceValue.v) : deviceValue.v}
|
||||
autoFocus
|
||||
sx={{ width: '30ch' }}
|
||||
type={deviceValue.u ? 'number' : 'text'}
|
||||
onChange={updateValue(setDeviceValue)}
|
||||
inputProps={{ step: deviceValue.s }}
|
||||
inputProps={deviceValue.u ? { min: deviceValue.m, max: deviceValue.x, step: deviceValue.s } : {}}
|
||||
InputProps={{
|
||||
startAdornment: <InputAdornment position="start">{DeviceValueUOM_s[deviceValue.u]}</InputAdornment>
|
||||
}}
|
||||
@@ -485,26 +492,24 @@ const DashboardData: FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const hasMask = (entityName: string, mask: number) => (parseInt(entityName.slice(0, 2), 16) & mask) === mask;
|
||||
|
||||
const sendCommand = (dv: DeviceValue) => {
|
||||
if (dv.c && me.admin) {
|
||||
if (dv.c && me.admin && !hasMask(dv.n, DeviceEntityMask.DV_READONLY)) {
|
||||
setDeviceValue(dv);
|
||||
}
|
||||
};
|
||||
|
||||
const renderNameCell = (dv: DeviceValue) => {
|
||||
if (dv.v === undefined && dv.c) {
|
||||
return (
|
||||
<StyledTableCell component="th" scope="row" sx={{ color: 'yellow' }}>
|
||||
command: {dv.n}
|
||||
</StyledTableCell>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<StyledTableCell component="th" scope="row">
|
||||
{dv.n}
|
||||
</StyledTableCell>
|
||||
);
|
||||
};
|
||||
const renderNameCell = (dv: DeviceValue) => (
|
||||
<>
|
||||
{dv.n.slice(2)}
|
||||
{hasMask(dv.n, DeviceEntityMask.DV_FAVORITE) && <FavoriteBorderIcon color="success" sx={{ fontSize: 12 }} />}
|
||||
{hasMask(dv.n, DeviceEntityMask.DV_READONLY) && <EditOffOutlinedIcon color="primary" sx={{ fontSize: 12 }} />}
|
||||
{hasMask(dv.n, DeviceEntityMask.DV_API_MQTT_EXCLUDE) && (
|
||||
<CommentsDisabledOutlinedIcon color="primary" sx={{ fontSize: 12 }} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -515,7 +520,7 @@ const DashboardData: FC = () => {
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<StyledTableCell padding="checkbox" style={{ width: 18 }}></StyledTableCell>
|
||||
<StyledTableCell align="left">ENTITY NAME/COMMAND</StyledTableCell>
|
||||
<StyledTableCell align="left">ENTITY NAME</StyledTableCell>
|
||||
<StyledTableCell align="right">VALUE</StyledTableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
@@ -523,14 +528,18 @@ const DashboardData: FC = () => {
|
||||
{deviceData.data.map((dv, i) => (
|
||||
<StyledTableRow key={i} onClick={() => sendCommand(dv)}>
|
||||
<StyledTableCell padding="checkbox">
|
||||
{dv.c && me.admin && (
|
||||
<IconButton size="small" aria-label="Edit">
|
||||
{dv.c && me.admin && !hasMask(dv.n, DeviceEntityMask.DV_READONLY) && (
|
||||
<IconButton size="small">
|
||||
<EditIcon color="primary" fontSize="small" />
|
||||
</IconButton>
|
||||
)}
|
||||
</StyledTableCell>
|
||||
{renderNameCell(dv)}
|
||||
<StyledTableCell align="right">{formatValue(dv.v, dv.u)}</StyledTableCell>
|
||||
<StyledTableCell component="th" scope="row">
|
||||
{renderNameCell(dv)}
|
||||
</StyledTableCell>
|
||||
<StyledTableCell align="right">
|
||||
{isCmdOnly(dv) ? <PlayArrowIcon color="primary" sx={{ fontSize: 14 }} /> : formatValue(dv.v, dv.u)}
|
||||
</StyledTableCell>
|
||||
</StyledTableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
@@ -569,7 +578,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 +614,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,9 @@ import {
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle
|
||||
DialogTitle,
|
||||
ToggleButton,
|
||||
ToggleButtonGroup
|
||||
} from '@mui/material';
|
||||
|
||||
import TableCell, { tableCellClasses } from '@mui/material/TableCell';
|
||||
@@ -22,8 +24,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';
|
||||
@@ -36,12 +41,7 @@ import { DeviceShort, Devices, DeviceEntity } from './types';
|
||||
|
||||
const StyledTableCell = styled(TableCell)(({ theme }) => ({
|
||||
[`&.${tableCellClasses.head}`]: {
|
||||
backgroundColor: '#607d8b',
|
||||
color: theme.palette.common.white,
|
||||
fontSize: 11
|
||||
},
|
||||
[`&.${tableCellClasses.body}`]: {
|
||||
fontSize: 11
|
||||
backgroundColor: '#607d8b'
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -54,6 +54,9 @@ const SettingsCustomization: FC = () => {
|
||||
const [selectedDevice, setSelectedDevice] = useState<number>(0);
|
||||
const [confirmReset, setConfirmReset] = useState<boolean>(false);
|
||||
|
||||
// eslint-disable-next-line
|
||||
const [masks, setMasks] = useState(() => ['']);
|
||||
|
||||
const fetchDevices = useCallback(async () => {
|
||||
try {
|
||||
setDevices((await EMSESP.readDevices()).data);
|
||||
@@ -62,9 +65,14 @@ const SettingsCustomization: FC = () => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const setInitialMask = (data: DeviceEntity[]) => {
|
||||
setDeviceEntities(data.map((de) => ({ ...de, om: de.m })));
|
||||
};
|
||||
|
||||
const fetchDeviceEntities = async (unique_id: number) => {
|
||||
try {
|
||||
setDeviceEntities((await EMSESP.readDeviceEntities({ id: unique_id })).data);
|
||||
const data = (await EMSESP.readDeviceEntities({ id: unique_id })).data;
|
||||
setInitialMask(data);
|
||||
} catch (error: any) {
|
||||
setErrorMessage(extractErrorMessage(error, 'Problem fetching device entities'));
|
||||
}
|
||||
@@ -109,8 +117,22 @@ const SettingsCustomization: FC = () => {
|
||||
return (
|
||||
<>
|
||||
<Box color="warning.main">
|
||||
<Typography variant="body2">
|
||||
Customize which entities to exclude from all all services (MQTT, API). This will have immediate effect.
|
||||
<Typography variant="body2">Select a device and customize each of its entities using the options:</Typography>
|
||||
<Typography mt={1} ml={2} display="block" variant="body2" sx={{ alignItems: 'center', display: 'flex' }}>
|
||||
<FavoriteBorderOutlinedIcon color="success" sx={{ fontSize: 13 }} />
|
||||
mark it as favorite to be listed at the top of the Dashboard
|
||||
</Typography>
|
||||
<Typography ml={2} display="block" variant="body2" sx={{ alignItems: 'center', display: 'flex' }}>
|
||||
<EditOffOutlinedIcon color="secondary" sx={{ fontSize: 13 }} />
|
||||
make it read-only, only if it has write operation available
|
||||
</Typography>
|
||||
<Typography ml={2} display="block" variant="body2" sx={{ alignItems: 'center', display: 'flex' }}>
|
||||
<CommentsDisabledOutlinedIcon color="secondary" sx={{ fontSize: 13 }} />
|
||||
excluded it from MQTT and API outputs
|
||||
</Typography>
|
||||
<Typography ml={2} mb={1} display="block" variant="body2" sx={{ alignItems: 'center', display: 'flex' }}>
|
||||
<VisibilityOffOutlinedIcon color="secondary" sx={{ fontSize: 13 }} />
|
||||
hide it from the Dashboard
|
||||
</Typography>
|
||||
</Box>
|
||||
<ValidatedTextField
|
||||
@@ -138,11 +160,22 @@ const SettingsCustomization: FC = () => {
|
||||
|
||||
const saveCustomization = async () => {
|
||||
if (deviceEntities && selectedDevice) {
|
||||
const exclude_entities = deviceEntities.filter((de) => de.x).map((new_de) => new_de.i);
|
||||
const masked_entities = deviceEntities
|
||||
.filter((de) => de.m !== de.om)
|
||||
.map((new_de) => new_de.m.toString(16).padStart(2, '0') + new_de.s);
|
||||
|
||||
if (masked_entities.length > 50) {
|
||||
enqueueSnackbar(
|
||||
'Too many selected entities (' + masked_entities.length + '). Limit is 50. Please Save in batches',
|
||||
{ variant: 'warning' }
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
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' });
|
||||
@@ -152,6 +185,7 @@ const SettingsCustomization: FC = () => {
|
||||
} catch (error: any) {
|
||||
enqueueSnackbar(extractErrorMessage(error, 'Problem sending entity list'), { variant: 'error' });
|
||||
}
|
||||
setInitialMask(deviceEntities);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -160,48 +194,76 @@ 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;
|
||||
for (let entry of newMask) {
|
||||
new_mask |= Number(entry);
|
||||
}
|
||||
de.m = new_mask;
|
||||
setMasks(newMask);
|
||||
};
|
||||
|
||||
const getMask = (de: DeviceEntity) => {
|
||||
var new_masks = [];
|
||||
if ((de.m & 1) === 1 || de.n === '') {
|
||||
new_masks.push('1');
|
||||
}
|
||||
if ((de.m & 2) === 2) {
|
||||
new_masks.push('2');
|
||||
}
|
||||
if ((de.m & 4) === 4 && de.w) {
|
||||
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" padding="normal">
|
||||
<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.s} hover>
|
||||
<StyledTableCell padding="none">
|
||||
<ToggleButtonGroup
|
||||
size="small"
|
||||
color="secondary"
|
||||
value={getMask(de)}
|
||||
onChange={(event, mask) => {
|
||||
setMask(de, mask);
|
||||
}}
|
||||
>
|
||||
<ToggleButton value="8" color="success" disabled={(de.m & 1) !== 0 || de.n === ''}>
|
||||
<FavoriteBorderOutlinedIcon sx={{ fontSize: 14 }} />
|
||||
</ToggleButton>
|
||||
<ToggleButton value="4" disabled={!de.w}>
|
||||
<EditOffOutlinedIcon sx={{ fontSize: 14 }} />
|
||||
</ToggleButton>
|
||||
<ToggleButton value="2">
|
||||
<CommentsDisabledOutlinedIcon sx={{ fontSize: 14 }} />
|
||||
</ToggleButton>
|
||||
<ToggleButton value="1">
|
||||
<VisibilityOffOutlinedIcon sx={{ fontSize: 14 }} />
|
||||
</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> {
|
||||
@@ -83,7 +83,6 @@ export function resetCustomizations(): AxiosPromise<void> {
|
||||
return AXIOS.post('/resetCustomizations');
|
||||
}
|
||||
|
||||
// EMS-ESP API calls
|
||||
export function API(apiCall: APIcall): AxiosPromise<void> {
|
||||
return AXIOS_API.post('/', apiCall);
|
||||
}
|
||||
|
||||
@@ -130,8 +130,10 @@ export interface DeviceValue {
|
||||
n: string; // name
|
||||
c: string; // command
|
||||
l: string[]; // list
|
||||
h?: string; // help text
|
||||
s?: string; // steps for up/down
|
||||
h?: string; // help text, optional
|
||||
s?: string; // steps for up/down, optional
|
||||
m?: string; // min, optional
|
||||
x?: string; // max, optional
|
||||
}
|
||||
|
||||
export interface DeviceData {
|
||||
@@ -143,13 +145,14 @@ export interface DeviceEntity {
|
||||
v?: any; // value, in any format
|
||||
n: string; // name
|
||||
s: string; // shortname
|
||||
x: boolean; // excluded flag
|
||||
i: number; // unique id
|
||||
m: number; // mask
|
||||
om?: number; // original mask before edits
|
||||
w: boolean; // writeable
|
||||
}
|
||||
|
||||
export interface ExcludeEntities {
|
||||
export interface MaskedEntities {
|
||||
id: number;
|
||||
entity_ids: number[];
|
||||
entity_ids: string[];
|
||||
}
|
||||
|
||||
export interface UniqueID {
|
||||
@@ -280,3 +283,11 @@ export interface WriteAnalog {
|
||||
uom: number;
|
||||
type: number;
|
||||
}
|
||||
|
||||
export enum DeviceEntityMask {
|
||||
DV_DEFAULT = 0,
|
||||
DV_WEB_EXCLUDE = 1,
|
||||
DV_API_MQTT_EXCLUDE = 2,
|
||||
DV_READONLY = 4,
|
||||
DV_FAVORITE = 8
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export enum NTPSyncStatus {
|
||||
NTP_INACTIVE = 0,
|
||||
NTP_ACTIVE = 1
|
||||
NTP_DISABLED = 0,
|
||||
NTP_INACTIVE = 1,
|
||||
NTP_ACTIVE = 2
|
||||
}
|
||||
|
||||
export interface NTPStatus {
|
||||
|
||||
Reference in New Issue
Block a user