diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md
index f53d4b1ca..b6b3d9d48 100644
--- a/CHANGELOG_LATEST.md
+++ b/CHANGELOG_LATEST.md
@@ -17,6 +17,7 @@
- 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)
- boiler hpSetDiffPressure [#1563](https://github.com/emsesp/EMS-ESP32/issues/1563)
+- custom variables [#1423](https://github.com/emsesp/EMS-ESP32/issues/1423)
## Fixed
diff --git a/interface/src/project/SettingsCustomEntities.tsx b/interface/src/project/SettingsCustomEntities.tsx
index ee176d32c..dfda883f0 100644
--- a/interface/src/project/SettingsCustomEntities.tsx
+++ b/interface/src/project/SettingsCustomEntities.tsx
@@ -1,5 +1,6 @@
import AddIcon from '@mui/icons-material/Add';
import CancelIcon from '@mui/icons-material/Cancel';
+import RefreshIcon from '@mui/icons-material/Refresh';
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
import WarningIcon from '@mui/icons-material/Warning';
import { Button, Typography, Box } from '@mui/material';
@@ -44,6 +45,7 @@ const SettingsCustomEntities: FC = () => {
function hasEntityChanged(ei: EntityItem) {
return (
ei.id !== ei.o_id ||
+ ei.ram !== ei.o_ram ||
(ei?.name || '') !== (ei?.o_name || '') ||
ei.device_id !== ei.o_device_id ||
ei.type_id !== ei.o_type_id ||
@@ -52,7 +54,8 @@ const SettingsCustomEntities: FC = () => {
ei.factor !== ei.o_factor ||
ei.value_type !== ei.o_value_type ||
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)
.map((condensed_ei) => ({
id: condensed_ei.id,
+ ram: condensed_ei.ram,
name: condensed_ei.name,
device_id: condensed_ei.device_id,
type_id: condensed_ei.type_id,
@@ -126,7 +130,8 @@ const SettingsCustomEntities: FC = () => {
factor: condensed_ei.factor,
uom: condensed_ei.uom,
writeable: condensed_ei.writeable,
- value_type: condensed_ei.value_type
+ value_type: condensed_ei.value_type,
+ value: condensed_ei.value
}))
})
.then(() => {
@@ -174,14 +179,16 @@ const SettingsCustomEntities: FC = () => {
setSelectedEntityItem({
id: Math.floor(Math.random() * (Math.floor(200) - 100) + 100),
name: '',
- device_id: '',
- type_id: '',
+ ram: 0,
+ device_id: '0',
+ type_id: '0',
offset: 0,
factor: 1,
uom: 0,
value_type: 0,
writeable: false,
- deleted: false
+ deleted: false,
+ value: ''
});
setDialogOpen(true);
};
@@ -213,7 +220,7 @@ const SettingsCustomEntities: FC = () => {
{LL.ID_OF(LL.DEVICE())}
{LL.ID_OF(LL.TYPE(1))}
{LL.OFFSET()}
- {LL.VALUE(1) + ' ' + LL.TYPE(1)}
+ {LL.TYPE(1)}
{LL.VALUE(1)}
@@ -224,10 +231,10 @@ const SettingsCustomEntities: FC = () => {
{ei.name}
{ei.writeable && }
- | {showHex(ei.device_id as number, 2)} |
- {showHex(ei.type_id as number, 3)} |
- {ei.offset} |
- {DeviceValueTypeNames[ei.value_type]} |
+ {ei.ram === 1 ? '' : showHex(ei.device_id as number, 2)} |
+ {ei.ram === 1 ? '' : showHex(ei.type_id as number, 3)} |
+ {ei.ram === 1 ? '' : ei.offset} |
+ {ei.ram === 1 ? 'RAM' : DeviceValueTypeNames[ei.value_type]} |
{formatValue(ei.value, ei.uom)} |
))}
@@ -278,7 +285,10 @@ const SettingsCustomEntities: FC = () => {
- } variant="outlined" color="secondary" onClick={addEntityItem}>
+ } variant="outlined" color="secondary" onClick={fetchEntities}>
+ {LL.REFRESH()}
+
+ } variant="outlined" color="primary" onClick={addEntityItem}>
{LL.ADD(0)}
diff --git a/interface/src/project/SettingsCustomEntitiesDialog.tsx b/interface/src/project/SettingsCustomEntitiesDialog.tsx
index f0516f048..691f23b25 100644
--- a/interface/src/project/SettingsCustomEntitiesDialog.tsx
+++ b/interface/src/project/SettingsCustomEntitiesDialog.tsx
@@ -100,7 +100,7 @@ const SettingsCustomEntitiesDialog = ({
-
+
-
- }
- label={LL.WRITEABLE()}
- />
-
-
- 0x }}
- />
-
-
- 0x }}
- />
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
- {editItem.value_type !== DeviceValueType.BOOL && editItem.value_type !== DeviceValueType.STRING && (
- <>
-
-
-
-
-
- {DeviceValueUOM_s.map((val, i) => (
-
- ))}
-
-
- >
- )}
- {editItem.value_type === DeviceValueType.STRING && (
+ {editItem.ram === 1 && (
)}
+ {editItem.ram === 0 && (
+ <>
+
+ }
+ label={LL.WRITEABLE()}
+ />
+
+
+ 0x }}
+ />
+
+
+ 0x }}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {editItem.value_type !== DeviceValueType.BOOL && editItem.value_type !== DeviceValueType.STRING && (
+ <>
+
+
+
+
+
+ {DeviceValueUOM_s.map((val, i) => (
+
+ ))}
+
+
+ >
+ )}
+ {editItem.value_type === DeviceValueType.STRING && editItem.device_id !== '0' && (
+
+
+
+ )}
+ >
+ )}
diff --git a/interface/src/project/types.ts b/interface/src/project/types.ts
index 20d8a6518..41e8f6f56 100644
--- a/interface/src/project/types.ts
+++ b/interface/src/project/types.ts
@@ -325,6 +325,7 @@ export enum ScheduleFlag {
export interface EntityItem {
id: number; // unique number
+ ram: number;
name: string;
device_id: number | string;
type_id: number | string;
@@ -336,6 +337,7 @@ export interface EntityItem {
writeable: boolean;
deleted?: boolean;
o_id?: number;
+ o_ram?: number;
o_name?: string;
o_device_id?: number | string;
o_type_id?: number | string;
@@ -345,6 +347,7 @@ export interface EntityItem {
o_value_type?: number;
o_deleted?: boolean;
o_writeable?: boolean;
+ o_value?: any;
}
export interface Entities {
@@ -397,6 +400,6 @@ export const DeviceValueTypeNames = [
'ULONG',
'TIME',
'ENUM',
- 'STRING',
+ 'RAW',
'CMD'
];
diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp
index bb5919615..74195e884 100644
--- a/src/devices/boiler.cpp
+++ b/src/devices/boiler.cpp
@@ -488,7 +488,9 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
DeviceValueNumOp::DV_NUMOP_MUL50,
FL_(hpSetDiffPress),
DeviceValueUOM::MBAR,
- MAKE_CF_CB(set_hpDiffPress));
+ MAKE_CF_CB(set_hpDiffPress),
+ 150,
+ 750);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCompOn_, DeviceValueType::BOOL, FL_(hpCompOn), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpActivity_, DeviceValueType::ENUM, FL_(enum_hpactivity), FL_(hpActivity), DeviceValueUOM::NONE);
// register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpHeatingOn_, DeviceValueType::BOOL, FL_(hpHeatingOn), DeviceValueUOM::NONE);
diff --git a/src/version.h b/src/version.h
index e6a41a3b6..9988523a9 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1 +1 @@
-#define EMSESP_APP_VERSION "3.6.5-dev.9"
+#define EMSESP_APP_VERSION "3.6.5-dev.10"
diff --git a/src/web/WebCustomEntityService.cpp b/src/web/WebCustomEntityService.cpp
index 87623df46..ea0b5ae55 100644
--- a/src/web/WebCustomEntityService.cpp
+++ b/src/web/WebCustomEntityService.cpp
@@ -48,6 +48,7 @@ void WebCustomEntity::read(WebCustomEntity & webEntity, JsonObject root) {
for (const CustomEntityItem & entityItem : webEntity.customEntityItems) {
JsonObject ei = entity.add();
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["type_id"] = entityItem.type_id;
ei["offset"] = entityItem.offset;
@@ -88,6 +89,7 @@ StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & web
if (root["entities"].is()) {
for (const JsonObject ei : root["entities"].as()) {
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.type_id = ei["type_id"];
entityItem.offset = ei["offset"];
@@ -96,6 +98,14 @@ StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & web
entityItem.uom = ei["uom"];
entityItem.value_type = ei["value_type"];
entityItem.writeable = ei["writeable"];
+ entityItem.data = ei["value"].as();
+ 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) {
entityItem.value = EMS_VALUE_DEFAULT_BOOL;
@@ -107,7 +117,7 @@ StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & web
entityItem.value = EMS_VALUE_DEFAULT_SHORT;
} else if (entityItem.value_type == DeviceValueType::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;
}
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; });
for (CustomEntityItem & entityItem : *customEntityItems) {
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];
strlcpy(telegram, value, sizeof(telegram));
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) {
render_value(output, entity);
}
- return (output.size() != 0);
+ return true;
}
char command_s[30];
@@ -297,13 +309,15 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
output["readable"] = true;
output["writeable"] = entity.writeable;
output["visible"] = true;
- output["device_id"] = Helpers::hextoa(entity.device_id);
- output["type_id"] = Helpers::hextoa(entity.type_id);
- output["offset"] = entity.offset;
- if (entity.value_type != DeviceValueType::BOOL && entity.value_type != DeviceValueType::STRING) {
- output["factor"] = entity.factor;
- } else if (entity.value_type == DeviceValueType::STRING) {
- output["bytes"] = (uint8_t)entity.factor;
+ if (entity.ram == 0) {
+ output["device_id"] = Helpers::hextoa(entity.device_id);
+ output["type_id"] = Helpers::hextoa(entity.type_id);
+ output["offset"] = entity.offset;
+ if (entity.value_type != DeviceValueType::BOOL && entity.value_type != DeviceValueType::STRING) {
+ output["factor"] = entity.factor;
+ } else if (entity.value_type == DeviceValueType::STRING) {
+ output["bytes"] = (uint8_t)entity.factor;
+ }
}
render_value(output, entity, true);
if (attribute_s) {
@@ -547,10 +561,21 @@ void WebCustomEntityService::fetch() {
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; });
const uint8_t len[] = {1, 1, 1, 2, 2, 3, 3};
for (auto & entity : *customEntityItems) {
- 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]);
+ if (entity.device_id > 0 && entity.type_id > 0) { // ths excludes also RAM type
+ bool needFetch = true;
+ for (const auto & emsdevice : EMSESP::emsdevices) {
+ 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");
}
@@ -563,8 +588,8 @@ bool WebCustomEntityService::get_value(std::shared_ptr telegram)
const uint8_t len[] = {1, 1, 1, 2, 2, 3, 3};
for (auto & entity : *customEntityItems) {
if (entity.value_type == DeviceValueType::STRING && telegram->type_id == entity.type_id && telegram->src == entity.device_id
- && telegram->offset == entity.offset) {
- auto data = Helpers::data_to_hex(telegram->message_data, telegram->message_length);
+ && telegram->offset <= entity.offset && (telegram->offset + telegram->message_length) >= (entity.offset + (uint8_t)entity.factor)) {
+ auto data = Helpers::data_to_hex(telegram->message_data, (uint8_t)entity.factor);
if (entity.data != data) {
entity.data = data;
if (Mqtt::publish_single()) {
@@ -573,9 +598,8 @@ bool WebCustomEntityService::get_value(std::shared_ptr telegram)
has_change = true;
}
}
- }
- 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])) {
+ } else 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])) {
uint32_t value = 0;
for (uint8_t i = 0; i < len[entity.value_type]; i++) {
value = (value << 8) + telegram->message_data[i + entity.offset - telegram->offset];
diff --git a/src/web/WebCustomEntityService.h b/src/web/WebCustomEntityService.h
index ccb98afd8..228cd95c6 100644
--- a/src/web/WebCustomEntityService.h
+++ b/src/web/WebCustomEntityService.h
@@ -38,6 +38,7 @@ class CustomEntityItem {
bool writeable;
uint32_t value;
std::string data;
+ uint8_t ram;
};
class WebCustomEntity {