From 4ae406b3e18e2f753c7e45c3c9232ed54f807dd1 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Mon, 21 Mar 2022 19:24:11 +0100 Subject: [PATCH] Customizations to names with more options --- .../src/project/SettingsCustomization.tsx | 2 +- interface/src/project/types.ts | 2 +- src/command.cpp | 2 +- src/devices/thermostat.cpp | 4 +- src/emsdevice.cpp | 90 ++++++++++++------- src/emsdevice.h | 10 ++- src/emsdevicevalue.h | 10 ++- src/emsesp.cpp | 11 ++- src/emsesp.h | 1 + src/system.cpp | 10 +-- src/web/WebCustomizationService.cpp | 14 +-- src/web/WebCustomizationService.h | 6 +- 12 files changed, 103 insertions(+), 59 deletions(-) diff --git a/interface/src/project/SettingsCustomization.tsx b/interface/src/project/SettingsCustomization.tsx index e503a8362..7e4daf26d 100644 --- a/interface/src/project/SettingsCustomization.tsx +++ b/interface/src/project/SettingsCustomization.tsx @@ -138,7 +138,7 @@ const SettingsCustomization: FC = () => { const saveCustomization = async () => { if (deviceEntities && selectedDevice) { - const exclude_entities = deviceEntities.filter((de) => de.x).map((new_de) => new_de.i); + const exclude_entities = deviceEntities.filter((de) => de.x).map((new_de) => "07" + new_de.s); try { const response = await EMSESP.writeExcludeEntities({ id: selectedDevice, diff --git a/interface/src/project/types.ts b/interface/src/project/types.ts index 2da66b4a3..f1c32c030 100644 --- a/interface/src/project/types.ts +++ b/interface/src/project/types.ts @@ -150,7 +150,7 @@ export interface DeviceEntity { export interface ExcludeEntities { id: number; - entity_ids: number[]; + entity_ids: string[]; } export interface UniqueID { diff --git a/src/command.cpp b/src/command.cpp index 75ee3ccc1..43d3d24b6 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -281,7 +281,7 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char * return_code = ((cf->cmdfunction_json_)(value, id, output)) ? CommandRet::OK : CommandRet::ERROR; } - if (cf->cmdfunction_) { + if (cf->cmdfunction_ && !EMSESP::cmd_is_readonly(device_type, cmd, id)) { return_code = ((cf->cmdfunction_)(value, id)) ? CommandRet::OK : CommandRet::ERROR; } diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 6e3f10e0b..dcd3b633f 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -379,8 +379,8 @@ void Thermostat::add_ha_climate(std::shared_ptr hc) const { return; } - if (Helpers::hasValue(hc->selTemp) && is_visible(&hc->selTemp)) { - if (Helpers::hasValue(hc->roomTemp) && is_visible(&hc->roomTemp)) { + if (Helpers::hasValue(hc->selTemp) && is_readable(&hc->selTemp)) { + if (Helpers::hasValue(hc->roomTemp) && is_readable(&hc->roomTemp)) { hc->climate = 1; } else { hc->climate = 0; diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index c2ea986f0..d7a4a84b3 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -26,7 +26,7 @@ namespace emsesp { uint8_t EMSdevice::count_entities() { uint8_t count = 0; for (auto & dv : devicevalues_) { - if (dv.has_state(DeviceValueState::DV_VISIBLE) && dv.hasValue()) { + if (!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && dv.hasValue()) { count++; } } @@ -248,7 +248,7 @@ bool EMSdevice::is_fetch(uint16_t telegram_id) const { // called from the command 'entities' void EMSdevice::list_device_entries(JsonObject & output) const { for (const auto & dv : devicevalues_) { - if (dv.has_state(DeviceValueState::DV_VISIBLE) && dv.type != DeviceValueType::CMD && dv.full_name) { + if (!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && dv.type != DeviceValueType::CMD && dv.full_name) { // if we have a tag prefix it char key[50]; if (!EMSdevice::tag_to_mqtt(dv.tag).empty()) { @@ -399,15 +399,17 @@ void EMSdevice::register_device_value(uint8_t tag, uint8_t dv_id = get_next_dv_id(); // determine state - uint8_t state = DeviceValueState::DV_VISIBLE; // default to visible + uint8_t state = DeviceValueState::DV_DEFAULT; // scan through customizations to see if it's on the exclusion list by matching the productID and deviceID EMSESP::webCustomizationService.read([&](WebCustomization & settings) { for (EntityCustomization entityCustomization : settings.entityCustomizations) { if ((entityCustomization.product_id == product_id()) && (entityCustomization.device_id == device_id())) { - for (uint8_t entity_id : entityCustomization.entity_ids) { - if (entity_id == dv_id) { - state = DeviceValueState::DV_DEFAULT; // it's on the exclude list, turn off active and visible flags + std::string entity = tag < DeviceValueTAG::TAG_HC1 ? read_flash_string(short_name) : tag_to_string(tag) + "/" + read_flash_string(short_name); + for (std::string entity_id : entityCustomization.entity_ids) { + uint8_t flag = Helpers::hextoint(entity_id.substr(0, 2).c_str()); + if (entity_id.substr(2) == entity) { + state = flag << 4; // set state high bits to flag, turn off active and ha flags break; } } @@ -476,11 +478,33 @@ void EMSdevice::register_device_value(uint8_t tag, register_device_value(tag, value_p, type, options, name, uom, nullptr, 0, 0); } -// check if value is visible -bool EMSdevice::is_visible(const void * value_p) const { +// check if value is readable via mqtt/api +bool EMSdevice::is_readable(const void * value_p) const { for (const auto & dv : devicevalues_) { if (dv.value_p == value_p) { - return dv.has_state(DeviceValueState::DV_VISIBLE); + return !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE); + } + } + return false; +} + +// check if value/command is readonly +bool EMSdevice::is_readonly(const std::string cmd, const int8_t id) const { + uint8_t tag = id > 0 ? DeviceValueTAG::TAG_HC1 + id - 1 : DeviceValueTAG::TAG_NONE; + for (const auto & dv : devicevalues_) { + // check command name and tag, id -1 is default hc and only checks name + if (dv.has_cmd && read_flash_string(dv.short_name) == cmd && (dv.tag < DeviceValueTAG::TAG_HC1 || dv.tag == tag || id == -1)) { + return dv.has_state(DeviceValueState::DV_READONLY); + } + } + return true; // not found, no write +} + +// check if value has a registered command +bool EMSdevice::has_command(const void * value_p) const { + for (const auto & dv : devicevalues_) { + if (dv.value_p == value_p) { + return dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY); } } return false; @@ -493,7 +517,7 @@ void EMSdevice::publish_value(void * value_p) const { } for (const auto & dv : devicevalues_) { - if (dv.value_p == value_p && dv.has_state(DeviceValueState::DV_VISIBLE)) { + if (dv.value_p == value_p && !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE)) { char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; if (Mqtt::publish_single2cmd()) { if (dv.tag >= DeviceValueTAG::TAG_HC1 && dv.tag <= DeviceValueTAG::TAG_WWC4) { @@ -593,7 +617,7 @@ std::string EMSdevice::get_value_uom(const char * key) const { // look up key in our device value list for (const auto & dv : devicevalues_) { - if ((dv.has_state(DeviceValueState::DV_VISIBLE) && dv.full_name) && (read_flash_string(dv.full_name) == key_p)) { + if ((!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && dv.full_name) && (read_flash_string(dv.full_name) == key_p)) { // ignore TIME since "minutes" is already added to the string value if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) { break; @@ -618,7 +642,7 @@ void EMSdevice::generate_values_web(JsonObject & output) { // 1. full_name cannot be empty // 2. it must have a valid value, if it is not a command like 'reset' - if (dv.has_state(DeviceValueState::DV_VISIBLE) && dv.full_name && (dv.hasValue() || (dv.type == DeviceValueType::CMD))) { + if (!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && dv.full_name && (dv.hasValue() || (dv.type == DeviceValueType::CMD))) { JsonObject obj = data.createNestedObject(); // create the object, we know there is a value uint8_t fahrenheit = 0; @@ -682,7 +706,7 @@ void EMSdevice::generate_values_web(JsonObject & output) { } // add commands and options - if (dv.has_cmd) { + if (dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY)) { // add the name of the Command function if (dv.tag >= DeviceValueTAG::TAG_HC1) { obj["c"] = tag_to_mqtt(dv.tag) + "/" + read_flash_string(dv.short_name); @@ -725,21 +749,24 @@ 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_exclude_entities() { +void EMSdevice::reset_entity_masks() { for (auto & dv : devicevalues_) { - dv.add_state(DeviceValueState::DV_VISIBLE); + dv.state &= 0x0F; } } -// disable/exclude a device entity based on its unique id -void EMSdevice::exclude_entity(uint8_t id) { +// 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_) { - if (dv.id == id) { + 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("exclude_entity() Removing Visible for device value: "); Serial.println(read_flash_string(dv.full_name).c_str()); #endif - dv.remove_state(DeviceValueState::DV_VISIBLE); // this will remove from MQTT payloads and showing in web & console + dv.state = (dv.state & 0x0F) | (flag << 4); // set state high bits to flag, turn off active and ha flags return; } } @@ -830,7 +857,7 @@ void EMSdevice::generate_values_web_all(JsonArray & output) { } // is it marked as excluded? - obj["x"] = !dv.has_state(DeviceValueState::DV_VISIBLE); + obj["x"] = dv.has_state(DeviceValueState::DV_WEB_EXCLUDE); // add the unique ID obj["i"] = dv.id; @@ -985,8 +1012,9 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8 json["uom"] = uom_to_string(dv.uom); } - json["writeable"] = dv.has_cmd; - json["visible"] = dv.has_state(DeviceValueState::DV_VISIBLE); + json["readable"] = !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE); + json["writeable"] = dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY); + json["visible"] = !dv.has_state(DeviceValueState::DV_WEB_EXCLUDE); // if there is no value, mention it if (!json.containsKey(value)) { @@ -1030,11 +1058,11 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c // check conditions: // 1. it must have a valid value (state is active) - // 2. it must have be visible and have a full name + // 2. it must have a visible flag // 3. it must match the given tag filter or have an empty tag - bool conditions = ((tag_filter == DeviceValueTAG::TAG_NONE) || (tag_filter == dv.tag)) && dv.has_state(DeviceValueState::DV_ACTIVE); - bool visible = dv.has_state(DeviceValueState::DV_VISIBLE) && dv.full_name; - if (conditions && visible) { + // 4. it must not have the exclude flag set or outputs to console + if (dv.has_state(DeviceValueState::DV_ACTIVE) && dv.full_name && (tag_filter == DeviceValueTAG::TAG_NONE || tag_filter == dv.tag) + && (output_target == OUTPUT_TARGET::CONSOLE || !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE))) { has_values = true; // flagged if we actually have data // we have a tag if it matches the filter given, and that the tag name is not empty/"" @@ -1042,7 +1070,7 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c // create the name for the JSON key char name[80]; - if (output_target == OUTPUT_TARGET::API_VERBOSE) { + if (output_target == OUTPUT_TARGET::API_VERBOSE || output_target == OUTPUT_TARGET::CONSOLE) { if (have_tag) { snprintf(name, 80, "%s %s", tag_to_string(dv.tag).c_str(), read_flash_string(dv.full_name).c_str()); // prefix the tag } else { @@ -1155,7 +1183,7 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c } else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { uint32_t time_value = *(uint32_t *)(dv.value_p); time_value = Helpers::round2(time_value, divider); // sometimes we need to divide by 60 - if (output_target == EMSdevice::OUTPUT_TARGET::API_VERBOSE) { + if (output_target == OUTPUT_TARGET::API_VERBOSE || output_target == OUTPUT_TARGET::CONSOLE) { char time_s[40]; snprintf(time_s, sizeof(time_s), @@ -1187,7 +1215,7 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c void EMSdevice::mqtt_ha_entity_config_remove() { for (auto & dv : devicevalues_) { if (dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) - && ((!dv.has_state(DeviceValueState::DV_VISIBLE)) || (!dv.has_state(DeviceValueState::DV_ACTIVE)))) { + && ((dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE)) || (!dv.has_state(DeviceValueState::DV_ACTIVE)))) { dv.remove_state(DeviceValueState::DV_HA_CONFIG_CREATED); if (dv.short_name == FL_(climate)[0]) { Mqtt::publish_ha_climate_config(dv.tag, false, true); // delete topic (remove = true) @@ -1207,7 +1235,7 @@ void EMSdevice::mqtt_ha_entity_config_create() { // create climate if roomtemp is visible // create the discovery topic if if hasn't already been created, not a command (like reset) and is active and visible for (auto & dv : devicevalues_) { - if ((dv.short_name == FL_(climate)[0]) && dv.has_state(DeviceValueState::DV_VISIBLE) && dv.has_state(DeviceValueState::DV_ACTIVE)) { + if ((dv.short_name == FL_(climate)[0]) && !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE) && dv.has_state(DeviceValueState::DV_ACTIVE)) { if (*(int8_t *)(dv.value_p) == 1 && (!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) || dv.has_state(DeviceValueState::DV_HA_CLIMATE_NO_RT))) { dv.remove_state(DeviceValueState::DV_HA_CLIMATE_NO_RT); dv.add_state(DeviceValueState::DV_HA_CONFIG_CREATED); @@ -1220,7 +1248,7 @@ void EMSdevice::mqtt_ha_entity_config_create() { } } if (!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) && (dv.type != DeviceValueType::CMD) && dv.has_state(DeviceValueState::DV_ACTIVE) - && dv.has_state(DeviceValueState::DV_VISIBLE)) { + && !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE)) { // create_device_config is only done once for the EMS device. It can added to any entity, so we take the first Mqtt::publish_ha_sensor_config(dv, name(), brand_to_string(), false, create_device_config); dv.add_state(DeviceValueState::DV_HA_CONFIG_CREATED); diff --git a/src/emsdevice.h b/src/emsdevice.h index f538a7d28..d95f92862 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -183,8 +183,8 @@ class EMSdevice { char * show_telegram_handlers(char * result, const size_t len, const uint8_t handlers); void show_mqtt_handlers(uuid::console::Shell & shell) const; void list_device_entries(JsonObject & output) const; - void exclude_entity(uint8_t entity_id); - void reset_exclude_entities(); + void mask_entity(std::string entity_id); + void reset_entity_masks(); using process_function_p = std::function)>; @@ -195,7 +195,7 @@ class EMSdevice { bool get_value_info(JsonObject & root, const char * cmd, const int8_t id); void get_dv_info(JsonObject & json); - enum OUTPUT_TARGET : uint8_t { API_VERBOSE, API_SHORTNAMES, MQTT }; + enum OUTPUT_TARGET : uint8_t { API_VERBOSE, API_SHORTNAMES, MQTT, CONSOLE }; bool generate_values(JsonObject & output, const uint8_t tag_filter, const bool nested, const uint8_t output_target); void generate_values_web(JsonObject & output); void generate_values_web_all(JsonArray & output); @@ -242,7 +242,9 @@ class EMSdevice { void read_command(const uint16_t type_id, uint8_t offset = 0, uint8_t length = 0) const; - bool is_visible(const void * value_p) const; + bool is_readable(const void * value_p) const; + bool is_readonly(const std::string cmd, const int8_t id) const; + bool has_command(const void * value_p) const; void publish_value(void * value_p) const; void publish_all_values(); diff --git a/src/emsdevicevalue.h b/src/emsdevicevalue.h index e41533fd4..526490789 100644 --- a/src/emsdevicevalue.h +++ b/src/emsdevicevalue.h @@ -112,9 +112,13 @@ class DeviceValue { enum DeviceValueState : uint8_t { DV_DEFAULT = 0, // 0 - does not yet have a value DV_ACTIVE = (1 << 0), // 1 - has a validated real value - DV_VISIBLE = (1 << 1), // 2 - shown on web, console and on MQTT payload. Otherwise hidden - DV_HA_CONFIG_CREATED = (1 << 2), // 4 - set if the HA config topic has been created - DV_HA_CLIMATE_NO_RT = (1 << 3) // 8 - climate created without roomTemp + 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 + // high nibble as mask for exclusions + DV_WEB_EXCLUDE = (1 << 4), // 16 - not shown on web + DV_API_MQTT_EXCLUDE = (1 << 5), // 32 - not shown on mqtt, API + DV_READONLY = (1 << 6), // 64 - read only + DV_FAVORITE = (1 << 7) // 128 - sort to front }; uint8_t device_type; // EMSdevice::DeviceType diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 54ddc1991..d367b677a 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -106,6 +106,15 @@ void EMSESP::fetch_device_values_type(const uint8_t device_type) { } } +bool EMSESP::cmd_is_readonly(const uint8_t device_type, const char * cmd, const int8_t id) { + for (const auto & emsdevice : emsdevices) { + if (emsdevice && (emsdevice->device_type() == device_type)) { + return emsdevice->is_readonly(cmd, id); + } + } + return false; +} + // clears list of recognized devices void EMSESP::clear_all_devices() { // temporarily removed: clearing the list causes a crash, the associated commands and mqtt should also be removed. @@ -366,7 +375,7 @@ void EMSESP::show_device_values(uuid::console::Shell & shell) { DynamicJsonDocument doc(EMSESP_JSON_SIZE_XXLARGE_DYN); // use max size JsonObject json = doc.to(); - emsdevice->generate_values(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::API_VERBOSE); // verbose mode and nested + emsdevice->generate_values(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::CONSOLE); // verbose mode and nested // print line uint8_t id = 0; diff --git a/src/emsesp.h b/src/emsesp.h index 3395824d5..37d6053d8 100644 --- a/src/emsesp.h +++ b/src/emsesp.h @@ -128,6 +128,7 @@ class EMSESP { static void send_raw_telegram(const char * data); static bool device_exists(const uint8_t device_id); + static bool cmd_is_readonly(const uint8_t device_type, const char * cmd, const int8_t id); static uint8_t count_devices(const uint8_t device_type); static uint8_t count_devices(); diff --git a/src/system.cpp b/src/system.cpp index d6e62c559..ab29b4a68 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -1054,15 +1054,15 @@ bool System::command_customizations(const char * value, const int8_t id, JsonObj } // exclude entities - JsonArray exclude_entitiesJson = node.createNestedArray("exclude_entities"); + JsonArray mask_entitiesJson = node.createNestedArray("masked_entities"); for (const auto & entityCustomization : settings.entityCustomizations) { - JsonObject entityJson = exclude_entitiesJson.createNestedObject(); + JsonObject entityJson = mask_entitiesJson.createNestedObject(); entityJson["product_id"] = entityCustomization.product_id; entityJson["device_id"] = entityCustomization.device_id; - JsonArray exclude_entityJson = entityJson.createNestedArray("entity_ids"); - for (uint8_t entity_id : entityCustomization.entity_ids) { - exclude_entityJson.add(entity_id); + JsonArray mask_entityJson = entityJson.createNestedArray("entities"); + for (std::string entity_id : entityCustomization.entity_ids) { + mask_entityJson.add(entity_id); } } }); diff --git a/src/web/WebCustomizationService.cpp b/src/web/WebCustomizationService.cpp index 98e060ed3..44301e2a6 100644 --- a/src/web/WebCustomizationService.cpp +++ b/src/web/WebCustomizationService.cpp @@ -86,7 +86,7 @@ void WebCustomization::read(WebCustomization & settings, JsonObject & root) { entityJson["device_id"] = entityCustomization.device_id; JsonArray exclude_entityJson = entityJson.createNestedArray("entity_ids"); - for (uint8_t entity_id : entityCustomization.entity_ids) { + for (std::string entity_id : entityCustomization.entity_ids) { exclude_entityJson.add(entity_id); } } @@ -133,7 +133,7 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization & new_entry.device_id = exclude_entities["device_id"]; for (const JsonVariant exclude_entity_id : exclude_entities["entity_ids"].as()) { - new_entry.entity_ids.push_back(exclude_entity_id.as()); // add entity list + new_entry.entity_ids.push_back(exclude_entity_id.as()); // add entity list } settings.entityCustomizations.push_back(new_entry); // save the new object } @@ -216,14 +216,14 @@ void WebCustomizationService::exclude_entities(AsyncWebServerRequest * request, uint8_t unique_device_id = json["id"]; if (emsdevice->unique_id() == unique_device_id) { // first reset all the entity ids - emsdevice->reset_exclude_entities(); + emsdevice->reset_entity_masks(); // build a list of entities to exclude and then set the flag to non-visible - JsonArray entity_ids_json = json["entity_ids"]; - std::vector entity_ids; + JsonArray entity_ids_json = json["entity_ids"]; + std::vector entity_ids; for (JsonVariant id : entity_ids_json) { - uint8_t entity_id = id.as(); - emsdevice->exclude_entity(entity_id); // this will have immediate affect + std::string entity_id = id.as(); + emsdevice->mask_entity(entity_id); // this will have immediate affect entity_ids.push_back(entity_id); } diff --git a/src/web/WebCustomizationService.h b/src/web/WebCustomizationService.h index b2bd869da..1c34ac80d 100644 --- a/src/web/WebCustomizationService.h +++ b/src/web/WebCustomizationService.h @@ -61,9 +61,9 @@ class AnalogCustomization { // we use product_id and device_id to make the device unique class EntityCustomization { public: - uint8_t product_id; // device's product id - uint8_t device_id; // device's device id - std::vector entity_ids; // array of entity ids to exclude + uint8_t product_id; // device's product id + uint8_t device_id; // device's device id + std::vector entity_ids; // array of entity ids to exclude }; class WebCustomization {