mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
Add custom variables #1423
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
- boiler Bosch C1200W, id 12, [#1536](https://github.com/emsesp/EMS-ESP32/issues/1536)
|
- boiler Bosch C1200W, id 12, [#1536](https://github.com/emsesp/EMS-ESP32/issues/1536)
|
||||||
- mixer MM100 telegram 0x2CC [#1554](https://github.com/emsesp/EMS-ESP32/issues/1554)
|
- mixer MM100 telegram 0x2CC [#1554](https://github.com/emsesp/EMS-ESP32/issues/1554)
|
||||||
- boiler hpSetDiffPressure [#1563](https://github.com/emsesp/EMS-ESP32/issues/1563)
|
- boiler hpSetDiffPressure [#1563](https://github.com/emsesp/EMS-ESP32/issues/1563)
|
||||||
|
- custom variables [#1423](https://github.com/emsesp/EMS-ESP32/issues/1423)
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import AddIcon from '@mui/icons-material/Add';
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
||||||
import WarningIcon from '@mui/icons-material/Warning';
|
import WarningIcon from '@mui/icons-material/Warning';
|
||||||
import { Button, Typography, Box } from '@mui/material';
|
import { Button, Typography, Box } from '@mui/material';
|
||||||
@@ -44,6 +45,7 @@ const SettingsCustomEntities: FC = () => {
|
|||||||
function hasEntityChanged(ei: EntityItem) {
|
function hasEntityChanged(ei: EntityItem) {
|
||||||
return (
|
return (
|
||||||
ei.id !== ei.o_id ||
|
ei.id !== ei.o_id ||
|
||||||
|
ei.ram !== ei.o_ram ||
|
||||||
(ei?.name || '') !== (ei?.o_name || '') ||
|
(ei?.name || '') !== (ei?.o_name || '') ||
|
||||||
ei.device_id !== ei.o_device_id ||
|
ei.device_id !== ei.o_device_id ||
|
||||||
ei.type_id !== ei.o_type_id ||
|
ei.type_id !== ei.o_type_id ||
|
||||||
@@ -52,7 +54,8 @@ const SettingsCustomEntities: FC = () => {
|
|||||||
ei.factor !== ei.o_factor ||
|
ei.factor !== ei.o_factor ||
|
||||||
ei.value_type !== ei.o_value_type ||
|
ei.value_type !== ei.o_value_type ||
|
||||||
ei.writeable !== ei.o_writeable ||
|
ei.writeable !== ei.o_writeable ||
|
||||||
ei.deleted !== ei.o_deleted
|
ei.deleted !== ei.o_deleted ||
|
||||||
|
(ei.value || '') !== (ei.o_value || '')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +122,7 @@ const SettingsCustomEntities: FC = () => {
|
|||||||
.filter((ei) => !ei.deleted)
|
.filter((ei) => !ei.deleted)
|
||||||
.map((condensed_ei) => ({
|
.map((condensed_ei) => ({
|
||||||
id: condensed_ei.id,
|
id: condensed_ei.id,
|
||||||
|
ram: condensed_ei.ram,
|
||||||
name: condensed_ei.name,
|
name: condensed_ei.name,
|
||||||
device_id: condensed_ei.device_id,
|
device_id: condensed_ei.device_id,
|
||||||
type_id: condensed_ei.type_id,
|
type_id: condensed_ei.type_id,
|
||||||
@@ -126,7 +130,8 @@ const SettingsCustomEntities: FC = () => {
|
|||||||
factor: condensed_ei.factor,
|
factor: condensed_ei.factor,
|
||||||
uom: condensed_ei.uom,
|
uom: condensed_ei.uom,
|
||||||
writeable: condensed_ei.writeable,
|
writeable: condensed_ei.writeable,
|
||||||
value_type: condensed_ei.value_type
|
value_type: condensed_ei.value_type,
|
||||||
|
value: condensed_ei.value
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@@ -174,14 +179,16 @@ const SettingsCustomEntities: FC = () => {
|
|||||||
setSelectedEntityItem({
|
setSelectedEntityItem({
|
||||||
id: Math.floor(Math.random() * (Math.floor(200) - 100) + 100),
|
id: Math.floor(Math.random() * (Math.floor(200) - 100) + 100),
|
||||||
name: '',
|
name: '',
|
||||||
device_id: '',
|
ram: 0,
|
||||||
type_id: '',
|
device_id: '0',
|
||||||
|
type_id: '0',
|
||||||
offset: 0,
|
offset: 0,
|
||||||
factor: 1,
|
factor: 1,
|
||||||
uom: 0,
|
uom: 0,
|
||||||
value_type: 0,
|
value_type: 0,
|
||||||
writeable: false,
|
writeable: false,
|
||||||
deleted: false
|
deleted: false,
|
||||||
|
value: ''
|
||||||
});
|
});
|
||||||
setDialogOpen(true);
|
setDialogOpen(true);
|
||||||
};
|
};
|
||||||
@@ -213,7 +220,7 @@ const SettingsCustomEntities: FC = () => {
|
|||||||
<HeaderCell stiff>{LL.ID_OF(LL.DEVICE())}</HeaderCell>
|
<HeaderCell stiff>{LL.ID_OF(LL.DEVICE())}</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.ID_OF(LL.TYPE(1))}</HeaderCell>
|
<HeaderCell stiff>{LL.ID_OF(LL.TYPE(1))}</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.OFFSET()}</HeaderCell>
|
<HeaderCell stiff>{LL.OFFSET()}</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.VALUE(1) + ' ' + LL.TYPE(1)}</HeaderCell>
|
<HeaderCell stiff>{LL.TYPE(1)}</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.VALUE(1)}</HeaderCell>
|
<HeaderCell stiff>{LL.VALUE(1)}</HeaderCell>
|
||||||
</HeaderRow>
|
</HeaderRow>
|
||||||
</Header>
|
</Header>
|
||||||
@@ -224,10 +231,10 @@ const SettingsCustomEntities: FC = () => {
|
|||||||
{ei.name}
|
{ei.name}
|
||||||
{ei.writeable && <EditOutlinedIcon color="primary" sx={{ fontSize: 12 }} />}
|
{ei.writeable && <EditOutlinedIcon color="primary" sx={{ fontSize: 12 }} />}
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>{showHex(ei.device_id as number, 2)}</Cell>
|
<Cell>{ei.ram === 1 ? '' : showHex(ei.device_id as number, 2)}</Cell>
|
||||||
<Cell>{showHex(ei.type_id as number, 3)}</Cell>
|
<Cell>{ei.ram === 1 ? '' : showHex(ei.type_id as number, 3)}</Cell>
|
||||||
<Cell>{ei.offset}</Cell>
|
<Cell>{ei.ram === 1 ? '' : ei.offset}</Cell>
|
||||||
<Cell>{DeviceValueTypeNames[ei.value_type]}</Cell>
|
<Cell>{ei.ram === 1 ? 'RAM' : DeviceValueTypeNames[ei.value_type]}</Cell>
|
||||||
<Cell>{formatValue(ei.value, ei.uom)}</Cell>
|
<Cell>{formatValue(ei.value, ei.uom)}</Cell>
|
||||||
</Row>
|
</Row>
|
||||||
))}
|
))}
|
||||||
@@ -278,7 +285,10 @@ const SettingsCustomEntities: FC = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button startIcon={<AddIcon />} variant="outlined" color="secondary" onClick={addEntityItem}>
|
<Button startIcon={<RefreshIcon />} variant="outlined" color="secondary" onClick={fetchEntities}>
|
||||||
|
{LL.REFRESH()}
|
||||||
|
</Button>
|
||||||
|
<Button startIcon={<AddIcon />} variant="outlined" color="primary" onClick={addEntityItem}>
|
||||||
{LL.ADD(0)}
|
{LL.ADD(0)}
|
||||||
</Button>
|
</Button>
|
||||||
</ButtonRow>
|
</ButtonRow>
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ const SettingsCustomEntitiesDialog = ({
|
|||||||
<Box flexWrap="nowrap" whiteSpace="nowrap" />
|
<Box flexWrap="nowrap" whiteSpace="nowrap" />
|
||||||
</Box>
|
</Box>
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid item xs={8}>
|
<Grid item xs={4}>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors}
|
||||||
name="name"
|
name="name"
|
||||||
@@ -111,122 +111,154 @@ const SettingsCustomEntitiesDialog = ({
|
|||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={4} mt={3}>
|
|
||||||
<BlockFormControlLabel
|
|
||||||
control={<Checkbox checked={editItem.writeable} onChange={updateFormValue} name="writeable" />}
|
|
||||||
label={LL.WRITEABLE()}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={4}>
|
|
||||||
<ValidatedTextField
|
|
||||||
fieldErrors={fieldErrors}
|
|
||||||
name="device_id"
|
|
||||||
label={LL.ID_OF(LL.DEVICE())}
|
|
||||||
margin="normal"
|
|
||||||
type="string"
|
|
||||||
fullWidth
|
|
||||||
value={editItem.device_id as string}
|
|
||||||
onChange={updateFormValue}
|
|
||||||
inputProps={{ style: { textTransform: 'uppercase' } }}
|
|
||||||
InputProps={{ startAdornment: <InputAdornment position="start">0x</InputAdornment> }}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={4}>
|
|
||||||
<ValidatedTextField
|
|
||||||
fieldErrors={fieldErrors}
|
|
||||||
name="type_id"
|
|
||||||
label={LL.ID_OF(LL.TYPE(1))}
|
|
||||||
margin="normal"
|
|
||||||
fullWidth
|
|
||||||
value={editItem.type_id}
|
|
||||||
onChange={updateFormValue}
|
|
||||||
inputProps={{ style: { textTransform: 'uppercase' } }}
|
|
||||||
InputProps={{ startAdornment: <InputAdornment position="start">0x</InputAdornment> }}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={4}>
|
|
||||||
<ValidatedTextField
|
|
||||||
fieldErrors={fieldErrors}
|
|
||||||
name="offset"
|
|
||||||
label={LL.OFFSET()}
|
|
||||||
margin="normal"
|
|
||||||
fullWidth
|
|
||||||
type="number"
|
|
||||||
value={editItem.offset}
|
|
||||||
onChange={updateFormValue}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={4}>
|
<Grid item xs={4}>
|
||||||
<TextField
|
<TextField
|
||||||
name="value_type"
|
name="ram"
|
||||||
label={LL.VALUE(1) + ' ' + LL.TYPE(1)}
|
label={LL.VALUE(1) + ' ' + LL.TYPE(1)}
|
||||||
value={editItem.value_type}
|
value={editItem.ram}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
fullWidth
|
fullWidth
|
||||||
select
|
select
|
||||||
>
|
>
|
||||||
<MenuItem value={DeviceValueType.BOOL}>BOOL</MenuItem>
|
<MenuItem value={0}>EMS-{LL.VALUE(1)}</MenuItem>
|
||||||
<MenuItem value={DeviceValueType.INT}>INT</MenuItem>
|
<MenuItem value={1}>RAM-{LL.VALUE(1)}</MenuItem>
|
||||||
<MenuItem value={DeviceValueType.UINT}>UINT</MenuItem>
|
|
||||||
<MenuItem value={DeviceValueType.SHORT}>SHORT</MenuItem>
|
|
||||||
<MenuItem value={DeviceValueType.USHORT}>USHORT</MenuItem>
|
|
||||||
<MenuItem value={DeviceValueType.ULONG}>ULONG</MenuItem>
|
|
||||||
<MenuItem value={DeviceValueType.TIME}>TIME</MenuItem>
|
|
||||||
<MenuItem value={DeviceValueType.STRING}>RAW</MenuItem>
|
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
{editItem.ram === 1 && (
|
||||||
{editItem.value_type !== DeviceValueType.BOOL && editItem.value_type !== DeviceValueType.STRING && (
|
|
||||||
<>
|
|
||||||
<Grid item xs={4}>
|
|
||||||
<TextField
|
|
||||||
name="factor"
|
|
||||||
label={LL.FACTOR()}
|
|
||||||
value={editItem.factor}
|
|
||||||
variant="outlined"
|
|
||||||
onChange={updateFormValue}
|
|
||||||
fullWidth
|
|
||||||
margin="normal"
|
|
||||||
type="number"
|
|
||||||
inputProps={{ step: '0.001' }}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={4}>
|
|
||||||
<TextField
|
|
||||||
name="uom"
|
|
||||||
label={LL.UNIT()}
|
|
||||||
value={editItem.uom}
|
|
||||||
margin="normal"
|
|
||||||
fullWidth
|
|
||||||
onChange={updateFormValue}
|
|
||||||
select
|
|
||||||
>
|
|
||||||
{DeviceValueUOM_s.map((val, i) => (
|
|
||||||
<MenuItem key={i} value={i}>
|
|
||||||
{val}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</TextField>
|
|
||||||
</Grid>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{editItem.value_type === DeviceValueType.STRING && (
|
|
||||||
<Grid item xs={4}>
|
<Grid item xs={4}>
|
||||||
<TextField
|
<TextField
|
||||||
name="factor"
|
name="value"
|
||||||
label="Bytes"
|
label={LL.STARTVALUE()}
|
||||||
value={editItem.factor}
|
value={editItem.value}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
fullWidth
|
fullWidth
|
||||||
margin="normal"
|
margin="normal"
|
||||||
type="number"
|
|
||||||
inputProps={{ min: '1', max: '27', step: '1' }}
|
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
|
{editItem.ram === 0 && (
|
||||||
|
<>
|
||||||
|
<Grid item xs={4} mt={3}>
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={<Checkbox checked={editItem.writeable} onChange={updateFormValue} name="writeable" />}
|
||||||
|
label={LL.WRITEABLE()}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors}
|
||||||
|
name="device_id"
|
||||||
|
label={LL.ID_OF(LL.DEVICE())}
|
||||||
|
margin="normal"
|
||||||
|
type="string"
|
||||||
|
fullWidth
|
||||||
|
value={editItem.device_id as string}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
inputProps={{ style: { textTransform: 'uppercase' } }}
|
||||||
|
InputProps={{ startAdornment: <InputAdornment position="start">0x</InputAdornment> }}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors}
|
||||||
|
name="type_id"
|
||||||
|
label={LL.ID_OF(LL.TYPE(1))}
|
||||||
|
margin="normal"
|
||||||
|
fullWidth
|
||||||
|
value={editItem.type_id}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
inputProps={{ style: { textTransform: 'uppercase' } }}
|
||||||
|
InputProps={{ startAdornment: <InputAdornment position="start">0x</InputAdornment> }}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors}
|
||||||
|
name="offset"
|
||||||
|
label={LL.OFFSET()}
|
||||||
|
margin="normal"
|
||||||
|
fullWidth
|
||||||
|
type="number"
|
||||||
|
value={editItem.offset}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<TextField
|
||||||
|
name="value_type"
|
||||||
|
label={LL.VALUE(1) + ' ' + LL.TYPE(1)}
|
||||||
|
value={editItem.value_type}
|
||||||
|
variant="outlined"
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
fullWidth
|
||||||
|
select
|
||||||
|
>
|
||||||
|
<MenuItem value={DeviceValueType.BOOL}>BOOL</MenuItem>
|
||||||
|
<MenuItem value={DeviceValueType.INT}>INT</MenuItem>
|
||||||
|
<MenuItem value={DeviceValueType.UINT}>UINT</MenuItem>
|
||||||
|
<MenuItem value={DeviceValueType.SHORT}>SHORT</MenuItem>
|
||||||
|
<MenuItem value={DeviceValueType.USHORT}>USHORT</MenuItem>
|
||||||
|
<MenuItem value={DeviceValueType.ULONG}>ULONG</MenuItem>
|
||||||
|
<MenuItem value={DeviceValueType.TIME}>TIME</MenuItem>
|
||||||
|
<MenuItem value={DeviceValueType.STRING}>RAW</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{editItem.value_type !== DeviceValueType.BOOL && editItem.value_type !== DeviceValueType.STRING && (
|
||||||
|
<>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<TextField
|
||||||
|
name="factor"
|
||||||
|
label={LL.FACTOR()}
|
||||||
|
value={editItem.factor}
|
||||||
|
variant="outlined"
|
||||||
|
onChange={updateFormValue}
|
||||||
|
fullWidth
|
||||||
|
margin="normal"
|
||||||
|
type="number"
|
||||||
|
inputProps={{ step: '0.001' }}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<TextField
|
||||||
|
name="uom"
|
||||||
|
label={LL.UNIT()}
|
||||||
|
value={editItem.uom}
|
||||||
|
margin="normal"
|
||||||
|
fullWidth
|
||||||
|
onChange={updateFormValue}
|
||||||
|
select
|
||||||
|
>
|
||||||
|
{DeviceValueUOM_s.map((val, i) => (
|
||||||
|
<MenuItem key={i} value={i}>
|
||||||
|
{val}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{editItem.value_type === DeviceValueType.STRING && editItem.device_id !== '0' && (
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<TextField
|
||||||
|
name="factor"
|
||||||
|
label="Bytes"
|
||||||
|
value={editItem.factor}
|
||||||
|
variant="outlined"
|
||||||
|
onChange={updateFormValue}
|
||||||
|
fullWidth
|
||||||
|
margin="normal"
|
||||||
|
type="number"
|
||||||
|
inputProps={{ min: '1', max: '27', step: '1' }}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
||||||
|
|||||||
@@ -325,6 +325,7 @@ export enum ScheduleFlag {
|
|||||||
|
|
||||||
export interface EntityItem {
|
export interface EntityItem {
|
||||||
id: number; // unique number
|
id: number; // unique number
|
||||||
|
ram: number;
|
||||||
name: string;
|
name: string;
|
||||||
device_id: number | string;
|
device_id: number | string;
|
||||||
type_id: number | string;
|
type_id: number | string;
|
||||||
@@ -336,6 +337,7 @@ export interface EntityItem {
|
|||||||
writeable: boolean;
|
writeable: boolean;
|
||||||
deleted?: boolean;
|
deleted?: boolean;
|
||||||
o_id?: number;
|
o_id?: number;
|
||||||
|
o_ram?: number;
|
||||||
o_name?: string;
|
o_name?: string;
|
||||||
o_device_id?: number | string;
|
o_device_id?: number | string;
|
||||||
o_type_id?: number | string;
|
o_type_id?: number | string;
|
||||||
@@ -345,6 +347,7 @@ export interface EntityItem {
|
|||||||
o_value_type?: number;
|
o_value_type?: number;
|
||||||
o_deleted?: boolean;
|
o_deleted?: boolean;
|
||||||
o_writeable?: boolean;
|
o_writeable?: boolean;
|
||||||
|
o_value?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Entities {
|
export interface Entities {
|
||||||
@@ -397,6 +400,6 @@ export const DeviceValueTypeNames = [
|
|||||||
'ULONG',
|
'ULONG',
|
||||||
'TIME',
|
'TIME',
|
||||||
'ENUM',
|
'ENUM',
|
||||||
'STRING',
|
'RAW',
|
||||||
'CMD'
|
'CMD'
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "3.6.5-dev.9"
|
#define EMSESP_APP_VERSION "3.6.5-dev.10"
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ void WebCustomEntity::read(WebCustomEntity & webEntity, JsonObject root) {
|
|||||||
for (const CustomEntityItem & entityItem : webEntity.customEntityItems) {
|
for (const CustomEntityItem & entityItem : webEntity.customEntityItems) {
|
||||||
JsonObject ei = entity.add<JsonObject>();
|
JsonObject ei = entity.add<JsonObject>();
|
||||||
ei["id"] = counter++; // id is only used to render the table and must be unique
|
ei["id"] = counter++; // id is only used to render the table and must be unique
|
||||||
|
ei["ram"] = entityItem.ram;
|
||||||
ei["device_id"] = entityItem.device_id;
|
ei["device_id"] = entityItem.device_id;
|
||||||
ei["type_id"] = entityItem.type_id;
|
ei["type_id"] = entityItem.type_id;
|
||||||
ei["offset"] = entityItem.offset;
|
ei["offset"] = entityItem.offset;
|
||||||
@@ -88,6 +89,7 @@ StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & web
|
|||||||
if (root["entities"].is<JsonArray>()) {
|
if (root["entities"].is<JsonArray>()) {
|
||||||
for (const JsonObject ei : root["entities"].as<JsonArray>()) {
|
for (const JsonObject ei : root["entities"].as<JsonArray>()) {
|
||||||
auto entityItem = CustomEntityItem();
|
auto entityItem = CustomEntityItem();
|
||||||
|
entityItem.ram = ei["ram"] | 0;
|
||||||
entityItem.device_id = ei["device_id"]; // send as numeric, will be converted to string in web
|
entityItem.device_id = ei["device_id"]; // send as numeric, will be converted to string in web
|
||||||
entityItem.type_id = ei["type_id"];
|
entityItem.type_id = ei["type_id"];
|
||||||
entityItem.offset = ei["offset"];
|
entityItem.offset = ei["offset"];
|
||||||
@@ -96,6 +98,14 @@ StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & web
|
|||||||
entityItem.uom = ei["uom"];
|
entityItem.uom = ei["uom"];
|
||||||
entityItem.value_type = ei["value_type"];
|
entityItem.value_type = ei["value_type"];
|
||||||
entityItem.writeable = ei["writeable"];
|
entityItem.writeable = ei["writeable"];
|
||||||
|
entityItem.data = ei["value"].as<std::string>();
|
||||||
|
if (entityItem.ram == 1) {
|
||||||
|
entityItem.device_id = 0;
|
||||||
|
entityItem.type_id = 0;
|
||||||
|
entityItem.uom = 0;
|
||||||
|
entityItem.value_type = DeviceValueType::STRING;
|
||||||
|
entityItem.writeable = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (entityItem.value_type == DeviceValueType::BOOL) {
|
if (entityItem.value_type == DeviceValueType::BOOL) {
|
||||||
entityItem.value = EMS_VALUE_DEFAULT_BOOL;
|
entityItem.value = EMS_VALUE_DEFAULT_BOOL;
|
||||||
@@ -107,7 +117,7 @@ StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & web
|
|||||||
entityItem.value = EMS_VALUE_DEFAULT_SHORT;
|
entityItem.value = EMS_VALUE_DEFAULT_SHORT;
|
||||||
} else if (entityItem.value_type == DeviceValueType::USHORT) {
|
} else if (entityItem.value_type == DeviceValueType::USHORT) {
|
||||||
entityItem.value = EMS_VALUE_DEFAULT_USHORT;
|
entityItem.value = EMS_VALUE_DEFAULT_USHORT;
|
||||||
} else { // if (entityItem.value_type == DeviceValueType::ULONG || entityItem.value_type == DeviceValueType::TIME) {
|
} else if (entityItem.value_type == DeviceValueType::ULONG || entityItem.value_type == DeviceValueType::TIME) {
|
||||||
entityItem.value = EMS_VALUE_DEFAULT_ULONG;
|
entityItem.value = EMS_VALUE_DEFAULT_ULONG;
|
||||||
}
|
}
|
||||||
if (entityItem.factor == 0) {
|
if (entityItem.factor == 0) {
|
||||||
@@ -134,7 +144,9 @@ bool WebCustomEntityService::command_setvalue(const char * value, const std::str
|
|||||||
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; });
|
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; });
|
||||||
for (CustomEntityItem & entityItem : *customEntityItems) {
|
for (CustomEntityItem & entityItem : *customEntityItems) {
|
||||||
if (Helpers::toLower(entityItem.name) == Helpers::toLower(name)) {
|
if (Helpers::toLower(entityItem.name) == Helpers::toLower(name)) {
|
||||||
if (entityItem.value_type == DeviceValueType::STRING) {
|
if (entityItem.ram == 1) {
|
||||||
|
entityItem.data = value;
|
||||||
|
} else if (entityItem.value_type == DeviceValueType::STRING) {
|
||||||
char telegram[84];
|
char telegram[84];
|
||||||
strlcpy(telegram, value, sizeof(telegram));
|
strlcpy(telegram, value, sizeof(telegram));
|
||||||
uint8_t data[EMS_MAX_TELEGRAM_LENGTH];
|
uint8_t data[EMS_MAX_TELEGRAM_LENGTH];
|
||||||
@@ -274,7 +286,7 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
|
|||||||
for (const CustomEntityItem & entity : *customEntityItems) {
|
for (const CustomEntityItem & entity : *customEntityItems) {
|
||||||
render_value(output, entity);
|
render_value(output, entity);
|
||||||
}
|
}
|
||||||
return (output.size() != 0);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
char command_s[30];
|
char command_s[30];
|
||||||
@@ -297,13 +309,15 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
|
|||||||
output["readable"] = true;
|
output["readable"] = true;
|
||||||
output["writeable"] = entity.writeable;
|
output["writeable"] = entity.writeable;
|
||||||
output["visible"] = true;
|
output["visible"] = true;
|
||||||
output["device_id"] = Helpers::hextoa(entity.device_id);
|
if (entity.ram == 0) {
|
||||||
output["type_id"] = Helpers::hextoa(entity.type_id);
|
output["device_id"] = Helpers::hextoa(entity.device_id);
|
||||||
output["offset"] = entity.offset;
|
output["type_id"] = Helpers::hextoa(entity.type_id);
|
||||||
if (entity.value_type != DeviceValueType::BOOL && entity.value_type != DeviceValueType::STRING) {
|
output["offset"] = entity.offset;
|
||||||
output["factor"] = entity.factor;
|
if (entity.value_type != DeviceValueType::BOOL && entity.value_type != DeviceValueType::STRING) {
|
||||||
} else if (entity.value_type == DeviceValueType::STRING) {
|
output["factor"] = entity.factor;
|
||||||
output["bytes"] = (uint8_t)entity.factor;
|
} else if (entity.value_type == DeviceValueType::STRING) {
|
||||||
|
output["bytes"] = (uint8_t)entity.factor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
render_value(output, entity, true);
|
render_value(output, entity, true);
|
||||||
if (attribute_s) {
|
if (attribute_s) {
|
||||||
@@ -547,10 +561,21 @@ void WebCustomEntityService::fetch() {
|
|||||||
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; });
|
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; });
|
||||||
const uint8_t len[] = {1, 1, 1, 2, 2, 3, 3};
|
const uint8_t len[] = {1, 1, 1, 2, 2, 3, 3};
|
||||||
for (auto & entity : *customEntityItems) {
|
for (auto & entity : *customEntityItems) {
|
||||||
EMSESP::send_read_request(entity.type_id,
|
if (entity.device_id > 0 && entity.type_id > 0) { // ths excludes also RAM type
|
||||||
entity.device_id,
|
bool needFetch = true;
|
||||||
entity.offset,
|
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||||
entity.value_type == DeviceValueType::STRING ? (uint8_t)entity.factor : len[entity.value_type]);
|
if (entity.value_type != DeviceValueType::STRING && emsdevice->is_device_id(entity.device_id) && emsdevice->is_fetch(entity.type_id)) {
|
||||||
|
needFetch = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needFetch) {
|
||||||
|
EMSESP::send_read_request(entity.type_id,
|
||||||
|
entity.device_id,
|
||||||
|
entity.offset,
|
||||||
|
entity.value_type == DeviceValueType::STRING ? (uint8_t)entity.factor : len[entity.value_type]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// EMSESP::logger().debug("fetch custom entities");
|
// EMSESP::logger().debug("fetch custom entities");
|
||||||
}
|
}
|
||||||
@@ -563,8 +588,8 @@ bool WebCustomEntityService::get_value(std::shared_ptr<const Telegram> telegram)
|
|||||||
const uint8_t len[] = {1, 1, 1, 2, 2, 3, 3};
|
const uint8_t len[] = {1, 1, 1, 2, 2, 3, 3};
|
||||||
for (auto & entity : *customEntityItems) {
|
for (auto & entity : *customEntityItems) {
|
||||||
if (entity.value_type == DeviceValueType::STRING && telegram->type_id == entity.type_id && telegram->src == entity.device_id
|
if (entity.value_type == DeviceValueType::STRING && telegram->type_id == entity.type_id && telegram->src == entity.device_id
|
||||||
&& telegram->offset == entity.offset) {
|
&& telegram->offset <= entity.offset && (telegram->offset + telegram->message_length) >= (entity.offset + (uint8_t)entity.factor)) {
|
||||||
auto data = Helpers::data_to_hex(telegram->message_data, telegram->message_length);
|
auto data = Helpers::data_to_hex(telegram->message_data, (uint8_t)entity.factor);
|
||||||
if (entity.data != data) {
|
if (entity.data != data) {
|
||||||
entity.data = data;
|
entity.data = data;
|
||||||
if (Mqtt::publish_single()) {
|
if (Mqtt::publish_single()) {
|
||||||
@@ -573,9 +598,8 @@ bool WebCustomEntityService::get_value(std::shared_ptr<const Telegram> telegram)
|
|||||||
has_change = true;
|
has_change = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (entity.value_type != DeviceValueType::STRING && telegram->type_id == entity.type_id && telegram->src == entity.device_id
|
||||||
if (entity.value_type != DeviceValueType::STRING && telegram->type_id == entity.type_id && telegram->src == entity.device_id
|
&& telegram->offset <= entity.offset && (telegram->offset + telegram->message_length) >= (entity.offset + len[entity.value_type])) {
|
||||||
&& telegram->offset <= entity.offset && (telegram->offset + telegram->message_length) >= (entity.offset + len[entity.value_type])) {
|
|
||||||
uint32_t value = 0;
|
uint32_t value = 0;
|
||||||
for (uint8_t i = 0; i < len[entity.value_type]; i++) {
|
for (uint8_t i = 0; i < len[entity.value_type]; i++) {
|
||||||
value = (value << 8) + telegram->message_data[i + entity.offset - telegram->offset];
|
value = (value << 8) + telegram->message_data[i + entity.offset - telegram->offset];
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class CustomEntityItem {
|
|||||||
bool writeable;
|
bool writeable;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
std::string data;
|
std::string data;
|
||||||
|
uint8_t ram;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WebCustomEntity {
|
class WebCustomEntity {
|
||||||
|
|||||||
Reference in New Issue
Block a user