Add custom variables #1423

This commit is contained in:
MichaelDvP
2024-01-20 17:57:01 +01:00
parent 9fd7b2553c
commit c0e77698aa
7 changed files with 200 additions and 129 deletions

View File

@@ -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

View File

@@ -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}&nbsp; {ei.name}&nbsp;
{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>

View File

@@ -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>

View File

@@ -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'
]; ];

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.6.5-dev.9" #define EMSESP_APP_VERSION "3.6.5-dev.10"

View File

@@ -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];

View File

@@ -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 {