Feature: Allow device name to be customized #1174

This commit is contained in:
proddy
2024-07-02 20:05:39 +02:00
parent 46b79f4819
commit 3ae48f4d16
8 changed files with 172 additions and 85 deletions

View File

@@ -21,10 +21,11 @@
- Added scripts for OTA (scripts/upload.py and upload_cli.py) [#1738](https://github.com/emsesp/EMS-ESP32/issues/1738) - Added scripts for OTA (scripts/upload.py and upload_cli.py) [#1738](https://github.com/emsesp/EMS-ESP32/issues/1738)
- timeout for remote thermostat emulation [#1680](https://github.com/emsesp/EMS-ESP32/discussions/1680), [#1774](https://github.com/emsesp/EMS-ESP32/issues/1774) - timeout for remote thermostat emulation [#1680](https://github.com/emsesp/EMS-ESP32/discussions/1680), [#1774](https://github.com/emsesp/EMS-ESP32/issues/1774)
- CR120 thermostat as own model() [#1779](https://github.com/emsesp/EMS-ESP32/discussions/1779) - CR120 thermostat as own model() [#1779](https://github.com/emsesp/EMS-ESP32/discussions/1779)
- Modules - external linkable module library [#1778](https://github.com/emsesp/EMS-ESP32/issues/1778) - modules - external linkable module library [#1778](https://github.com/emsesp/EMS-ESP32/issues/1778)
- Scheduler onChange and Conditions [#1806](https://github.com/emsesp/EMS-ESP32/issues/1806) - scheduler onChange and Conditions [#1806](https://github.com/emsesp/EMS-ESP32/issues/1806)
- make remote control timeout editable [#1774](https://github.com/emsesp/EMS-ESP32/issues/1774) - make remote control timeout editable [#1774](https://github.com/emsesp/EMS-ESP32/issues/1774)
- added extra pump characteristics (mode and pressure for EMS+) by @SLTKA [#1802](https://github.com/emsesp/EMS-ESP32/pull/1802) - added extra pump characteristics (mode and pressure for EMS+) by @SLTKA [#1802](https://github.com/emsesp/EMS-ESP32/pull/1802)
- allow device name to be customized [#1174](https://github.com/emsesp/EMS-ESP32/issues/1174)
## Fixed ## Fixed

View File

@@ -34,14 +34,15 @@ class EMSdevice {
using process_function_p = std::function<void(std::shared_ptr<const Telegram>)>; using process_function_p = std::function<void(std::shared_ptr<const Telegram>)>;
// device_type defines which derived class to use, e.g. BOILER, THERMOSTAT etc.. // device_type defines which derived class to use, e.g. BOILER, THERMOSTAT etc..
EMSdevice(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand) EMSdevice(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * default_name, uint8_t flags, uint8_t brand)
: device_type_(device_type) : device_type_(device_type)
, device_id_(device_id) , device_id_(device_id)
, product_id_(product_id) , product_id_(product_id)
, name_(name) , default_name_(default_name)
, flags_(flags) , flags_(flags)
, brand_(brand) { , brand_(brand) {
strlcpy(version_, version, sizeof(version_)); strlcpy(version_, version, sizeof(version_));
custom_name_ = ""; // init custom name to blank
} }
// static functions, used outside the class like in console.cpp, command.cpp, emsesp.cpp, mqtt.cpp // static functions, used outside the class like in console.cpp, command.cpp, emsesp.cpp, mqtt.cpp
@@ -111,12 +112,18 @@ class EMSdevice {
return brand_; return brand_;
} }
inline void name(const char * name) { // set custom device name
name_ = name; inline void custom_name(std::string & custom_name) {
custom_name_ = custom_name;
} }
std::string name(); // returns either default or custom name if defined
inline const char * name() const { // default name
return name_; inline void default_name(const char * default_name) {
default_name_ = default_name;
}
inline const char * default_name() const {
return default_name_;
} }
inline uint8_t unique_id() const { inline uint8_t unique_id() const {
@@ -479,7 +486,8 @@ class EMSdevice {
uint8_t device_id_ = 0; uint8_t device_id_ = 0;
uint8_t product_id_ = 0; uint8_t product_id_ = 0;
char version_[6]; char version_[6];
const char * name_; // the long name for the EMS model const char * default_name_; // the fixed name the EMS model taken from the device library
std::string custom_name_; // custom name
uint8_t flags_ = 0; uint8_t flags_ = 0;
uint8_t brand_ = Brand::NO_BRAND; uint8_t brand_ = Brand::NO_BRAND;

View File

@@ -359,7 +359,7 @@ void EMSESP::dump_all_values(uuid::console::Shell & shell) {
// add the device and print out all the entities // add the device and print out all the entities
// for testing the mixer use ... if (device.product_id == 69) { // for testing the mixer use ... if (device.product_id == 69) {
emsdevices.push_back( emsdevices.push_back(
EMSFactory::add(device.device_type, device_id, device.product_id, "1.0", device.name, device.flags, EMSdevice::Brand::NO_BRAND)); EMSFactory::add(device.device_type, device_id, device.product_id, "1.0", device.default_name, device.flags, EMSdevice::Brand::NO_BRAND));
emsdevices.back()->dump_value_info(); emsdevices.back()->dump_value_info();
} }
} }
@@ -400,7 +400,7 @@ void EMSESP::dump_all_telegrams(uuid::console::Shell & shell) {
// add the device and print out all the entities // add the device and print out all the entities
emsdevices.push_back( emsdevices.push_back(
EMSFactory::add(device.device_type, device_id, device.product_id, "1.0", device.name, device.flags, EMSdevice::Brand::NO_BRAND)); EMSFactory::add(device.device_type, device_id, device.product_id, "1.0", device.default_name, device.flags, EMSdevice::Brand::NO_BRAND));
// add to our vector list // add to our vector list
emsdevices.back()->dump_telegram_info(telegram_functions_dump); emsdevices.back()->dump_telegram_info(telegram_functions_dump);
} }
@@ -1167,17 +1167,20 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
if (product_id == 0 || emsdevice->product_id() != 0) { // update only with valid product_id if (product_id == 0 || emsdevice->product_id() != 0) { // update only with valid product_id
return true; return true;
} }
LOG_DEBUG("Updating details for already active deviceID 0x%02X", device_id); LOG_DEBUG("Updating details for already active deviceID 0x%02X", device_id);
emsdevice->product_id(product_id); emsdevice->product_id(product_id);
emsdevice->version(version); emsdevice->version(version);
// only set brand if it doesn't already exist // only set brand if it doesn't already exist
if (emsdevice->brand() == EMSdevice::Brand::NO_BRAND) { if (emsdevice->brand() == EMSdevice::Brand::NO_BRAND) {
emsdevice->brand(brand); emsdevice->brand(brand);
} }
// find the name and flags in our database
// find the name and flags in our device library database
for (const auto & device : device_library_) { for (const auto & device : device_library_) {
if (device.product_id == product_id && device.device_type == emsdevice->device_type()) { if (device.product_id == product_id && device.device_type == emsdevice->device_type()) {
emsdevice->name(device.name); emsdevice->default_name(device.default_name); // custom name is set later
emsdevice->add_flags(device.flags); emsdevice->add_flags(device.flags);
} }
} }
@@ -1192,7 +1195,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
if (device.product_id == product_id) { if (device.product_id == product_id) {
// sometimes boilers share the same productID as controllers // sometimes boilers share the same productID as controllers
// so only add boilers if the device_id is 0x08 // so only add boilers if the device_id is 0x08
// cascaded boilers with 0x70.., map to heatsources // cascaded boilers with 0x70..., map to heatsources
if (device.device_type == DeviceType::BOILER) { if (device.device_type == DeviceType::BOILER) {
if (device_id == EMSdevice::EMS_DEVICE_ID_BOILER) { if (device_id == EMSdevice::EMS_DEVICE_ID_BOILER) {
device_p = &device; device_p = &device;
@@ -1204,7 +1207,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
break; break;
} }
} else { } else {
// it's not a boiler, but we have a match // it's not a boiler, but we still have a match
device_p = &device; device_p = &device;
break; break;
} }
@@ -1219,73 +1222,77 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
return false; // not found return false; // not found
} }
auto name = device_p->name; auto default_name = device_p->default_name;
auto device_type = device_p->device_type; auto device_type = device_p->device_type;
auto flags = device_p->flags; auto flags = device_p->flags;
// check for integrated modules with same product id, but different function (device_id) // check for integrated modules with same product id, but different function (device_id)
// and force set the correct device type and hardcoded name
if (device_type == DeviceType::HEATPUMP) { if (device_type == DeviceType::HEATPUMP) {
if (device_id == EMSdevice::EMS_DEVICE_ID_MODEM) { if (device_id == EMSdevice::EMS_DEVICE_ID_MODEM) {
device_type = DeviceType::GATEWAY; device_type = DeviceType::GATEWAY;
name = "WiFi module"; default_name = "WiFi module";
} else if (device_id == EMSdevice::EMS_DEVICE_ID_RFBASE) { } else if (device_id == EMSdevice::EMS_DEVICE_ID_RFBASE) {
device_type = DeviceType::CONNECT; device_type = DeviceType::CONNECT;
name = "Wireless sensor base"; default_name = "Wireless sensor base";
} }
} }
if (device_id >= EMSdevice::EMS_DEVICE_ID_DHW1 && device_id <= EMSdevice::EMS_DEVICE_ID_DHW8) { if (device_id >= EMSdevice::EMS_DEVICE_ID_DHW1 && device_id <= EMSdevice::EMS_DEVICE_ID_DHW8) {
device_type = DeviceType::WATER; device_type = DeviceType::WATER;
} }
// CR120 have version 22.xx, RC400/CW100 uses version 42.xx, see https://github.com/emsesp/EMS-ESP32/discussions/1779 // CR120 have version 22.xx, RC400/CW100 uses version 42.xx, see https://github.com/emsesp/EMS-ESP32/discussions/1779
if (product_id == 157 && version[0] == '2') { if (product_id == 157 && version[0] == '2') {
flags = DeviceFlags::EMS_DEVICE_FLAG_CR120; flags = DeviceFlags::EMS_DEVICE_FLAG_CR120;
name = "CR120"; default_name = "CR120";
} }
// empty reply to version, read a generic device from database // empty reply to version, read a generic device from database
if (product_id == 0) { if (product_id == 0) {
// check for known device IDs // check for known device IDs
if (device_id == EMSdevice::EMS_DEVICE_ID_RFSENSOR) { if (device_id == EMSdevice::EMS_DEVICE_ID_RFSENSOR) {
// see: https://github.com/emsesp/EMS-ESP32/issues/103#issuecomment-911717342 and https://github.com/emsesp/EMS-ESP32/issues/624 // see: https://github.com/emsesp/EMS-ESP32/issues/103#issuecomment-911717342 and https://github.com/emsesp/EMS-ESP32/issues/624
name = "RF room temperature sensor"; default_name = "RF room temperature sensor";
device_type = DeviceType::THERMOSTAT; device_type = DeviceType::THERMOSTAT;
} else if (device_id == EMSdevice::EMS_DEVICE_ID_ROOMTHERMOSTAT || device_id == EMSdevice::EMS_DEVICE_ID_TADO_OLD) { } else if (device_id == EMSdevice::EMS_DEVICE_ID_ROOMTHERMOSTAT || device_id == EMSdevice::EMS_DEVICE_ID_TADO_OLD) {
// see https://github.com/emsesp/EMS-ESP32/issues/174 // see https://github.com/emsesp/EMS-ESP32/issues/174
name = "Generic thermostat"; default_name = "Generic Thermostat";
device_type = DeviceType::THERMOSTAT; device_type = DeviceType::THERMOSTAT;
flags = DeviceFlags::EMS_DEVICE_FLAG_RC10 | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE; flags = DeviceFlags::EMS_DEVICE_FLAG_RC10 | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE;
} else if (device_id == EMSdevice::EMS_DEVICE_ID_RS232) { } else if (device_id == EMSdevice::EMS_DEVICE_ID_RS232) {
name = "RS232"; default_name = "RS232";
device_type = DeviceType::CONNECT; device_type = DeviceType::CONNECT;
} else if (device_id == EMSdevice::EMS_DEVICE_ID_TERMINAL) { } else if (device_id == EMSdevice::EMS_DEVICE_ID_TERMINAL) {
name = "Terminal"; default_name = "Terminal";
device_type = DeviceType::CONNECT; device_type = DeviceType::CONNECT;
} else if (device_id == EMSdevice::EMS_DEVICE_ID_SERVICEKEY) { } else if (device_id == EMSdevice::EMS_DEVICE_ID_SERVICEKEY) {
name = "Service Key"; default_name = "Service Key";
device_type = DeviceType::CONNECT; device_type = DeviceType::CONNECT;
} else if (device_id == EMSdevice::EMS_DEVICE_ID_CASCADE) { } else if (device_id == EMSdevice::EMS_DEVICE_ID_CASCADE) {
name = "Cascade"; default_name = "Cascade";
device_type = DeviceType::CONNECT; device_type = DeviceType::CONNECT;
} else if (device_id == EMSdevice::EMS_DEVICE_ID_EASYCOM } else if (device_id == EMSdevice::EMS_DEVICE_ID_EASYCOM
|| (device_id >= EMSdevice::EMS_DEVICE_ID_MODEM && device_id <= EMSdevice::EMS_DEVICE_ID_MODEM + 5)) { || (device_id >= EMSdevice::EMS_DEVICE_ID_MODEM && device_id <= EMSdevice::EMS_DEVICE_ID_MODEM + 5)) {
// see https://github.com/emsesp/EMS-ESP/issues/460#issuecomment-709553012 // see https://github.com/emsesp/EMS-ESP/issues/460#issuecomment-709553012
name = "Modem"; default_name = "Modem";
device_type = DeviceType::CONNECT; device_type = DeviceType::CONNECT;
} else if (device_id == EMSdevice::EMS_DEVICE_ID_CONVERTER) { } else if (device_id == EMSdevice::EMS_DEVICE_ID_CONVERTER) {
name = "Converter"; // generic default_name = "Converter"; // generic
} else if (device_id == EMSdevice::EMS_DEVICE_ID_CLOCK) { } else if (device_id == EMSdevice::EMS_DEVICE_ID_CLOCK) {
name = "Clock"; // generic default_name = "Clock"; // generic
device_type = DeviceType::CONTROLLER; device_type = DeviceType::CONTROLLER;
} else if (device_id == EMSdevice::EMS_DEVICE_ID_CONTROLLER) { } else if (device_id == EMSdevice::EMS_DEVICE_ID_CONTROLLER) {
name = "Generic Controller"; default_name = "Generic Controller";
device_type = DeviceType::CONTROLLER; device_type = DeviceType::CONTROLLER;
} else if (device_id == EMSdevice::EMS_DEVICE_ID_BOILER) { } else if (device_id == EMSdevice::EMS_DEVICE_ID_BOILER) {
name = "Generic Boiler"; default_name = "Generic Boiler";
device_type = DeviceType::BOILER; device_type = DeviceType::BOILER;
flags = DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP; flags = DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP;
LOG_WARNING("Unknown EMS boiler. Using generic profile. Please report on GitHub."); LOG_WARNING("Unknown EMS boiler. Using generic profile. Please report on GitHub.");
} else if (device_id >= 0x68 && device_id <= 0x6F) { } else if (device_id >= 0x68 && device_id <= 0x6F) {
// test for https://github.com/emsesp/EMS-ESP32/issues/882 // test for https://github.com/emsesp/EMS-ESP32/issues/882
name = "Cascaded Controller"; default_name = "Cascaded Controller";
device_type = DeviceType::CONTROLLER; device_type = DeviceType::CONTROLLER;
} else { } else {
LOG_WARNING("Unrecognized EMS device (device ID 0x%02X, no product ID). Please report on GitHub.", device_id); LOG_WARNING("Unrecognized EMS device (device ID 0x%02X, no product ID). Please report on GitHub.", device_id);
@@ -1293,10 +1300,21 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
} }
} }
LOG_DEBUG("Adding new device %s (deviceID 0x%02X, productID %d, version %s)", name, device_id, product_id, version); LOG_DEBUG("Adding new device %s (deviceID 0x%02X, productID %d, version %s)", default_name, device_id, product_id, version);
emsdevices.push_back(EMSFactory::add(device_type, device_id, product_id, version, name, flags, brand)); emsdevices.push_back(EMSFactory::add(device_type, device_id, product_id, version, default_name, flags, brand));
// assign a unique ID. Note that this is not actual unique after a restart as it's dependent on the order that devices are found // see if we have a custom device name in our Customizations list, and if so set it
webCustomizationService.read([&](WebCustomization & settings) {
for (EntityCustomization e : settings.entityCustomizations) {
if ((e.device_id == device_id) && (e.product_id == product_id)) {
LOG_DEBUG("Have customizations for %s with deviceID 0x%02X productID %d", e.custom_name.c_str(), device_id, product_id);
emsdevices.back()->custom_name(e.custom_name);
break;
}
}
});
// assign a unique ID. Note that this is not actual remain unique after a restart as it's dependent on the order that devices are found
// can't be 0 otherwise web won't work // can't be 0 otherwise web won't work
emsdevices.back()->unique_id(++unique_id_count_); emsdevices.back()->unique_id(++unique_id_count_);
@@ -1305,7 +1323,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
return a->device_type() < b->device_type(); return a->device_type() < b->device_type();
}); });
fetch_device_values(device_id); // go and fetch its data fetch_device_values(device_id); // go and fetch its device entity data
// Print to LOG showing we've added a new device // Print to LOG showing we've added a new device
LOG_INFO("Recognized new %s with deviceID 0x%02X", EMSdevice::device_type_2_device_name(device_type), device_id); LOG_INFO("Recognized new %s with deviceID 0x%02X", EMSdevice::device_type_2_device_name(device_type), device_id);

View File

@@ -252,7 +252,7 @@ class EMSESP {
struct Device_record { struct Device_record {
uint8_t product_id; uint8_t product_id;
EMSdevice::DeviceType device_type; EMSdevice::DeviceType device_type;
const char * name; const char * default_name;
uint8_t flags; uint8_t flags;
}; };
static std::vector<Device_record> device_library_; static std::vector<Device_record> device_library_;

View File

@@ -55,9 +55,9 @@ class EMSFactory {
} }
// Construct derived class returning an unique ptr // Construct derived class returning an unique ptr
static auto add(const uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand) static auto add(const uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * default_name, uint8_t flags, uint8_t brand)
-> std::unique_ptr<EMSdevice> { -> std::unique_ptr<EMSdevice> {
return std::unique_ptr<EMSdevice>(EMSFactory::makeRaw(device_type, device_id, product_id, version, name, flags, brand)); return std::unique_ptr<EMSdevice>(EMSFactory::makeRaw(device_type, device_id, product_id, version, default_name, flags, brand));
} }
virtual auto construct(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand) const virtual auto construct(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand) const

View File

@@ -24,6 +24,7 @@ bool WebCustomization::_start = true;
WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager) WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
: _fsPersistence(WebCustomization::read, WebCustomization::update, this, fs, EMSESP_CUSTOMIZATION_FILE) { : _fsPersistence(WebCustomization::read, WebCustomization::update, this, fs, EMSESP_CUSTOMIZATION_FILE) {
// GET
server->on(DEVICE_ENTITIES_PATH, server->on(DEVICE_ENTITIES_PATH,
HTTP_GET, HTTP_GET,
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { device_entities(request); }, AuthenticationPredicates::IS_AUTHENTICATED)); securityManager->wrapRequest([this](AsyncWebServerRequest * request) { device_entities(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
@@ -32,10 +33,15 @@ WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * f
HTTP_GET, HTTP_GET,
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { devices(request); }, AuthenticationPredicates::IS_AUTHENTICATED)); securityManager->wrapRequest([this](AsyncWebServerRequest * request) { devices(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
// POST
server->on(RESET_CUSTOMIZATION_SERVICE_PATH, server->on(RESET_CUSTOMIZATION_SERVICE_PATH,
HTTP_POST, HTTP_POST,
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { reset_customization(request); }, AuthenticationPredicates::IS_ADMIN)); securityManager->wrapRequest([this](AsyncWebServerRequest * request) { reset_customization(request); }, AuthenticationPredicates::IS_ADMIN));
server->on(WRITE_DEVICE_NAME_PATH,
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { writeDeviceName(request, json); },
AuthenticationPredicates::IS_AUTHENTICATED));
server->on(CUSTOMIZATION_ENTITIES_PATH, server->on(CUSTOMIZATION_ENTITIES_PATH,
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { customization_entities(request, json); }, securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { customization_entities(request, json); },
AuthenticationPredicates::IS_AUTHENTICATED)); AuthenticationPredicates::IS_AUTHENTICATED));
@@ -65,12 +71,13 @@ void WebCustomization::read(WebCustomization & customizations, JsonObject root)
sensorJson["type"] = sensor.type; // t sensorJson["type"] = sensor.type; // t
} }
// Masked entities customization // Masked entities customization and custom device name (optional)
JsonArray masked_entitiesJson = root["masked_entities"].to<JsonArray>(); JsonArray masked_entitiesJson = root["masked_entities"].to<JsonArray>();
for (const EntityCustomization & entityCustomization : customizations.entityCustomizations) { for (const EntityCustomization & entityCustomization : customizations.entityCustomizations) {
JsonObject entityJson = masked_entitiesJson.add<JsonObject>(); JsonObject entityJson = masked_entitiesJson.add<JsonObject>();
entityJson["product_id"] = entityCustomization.product_id; entityJson["product_id"] = entityCustomization.product_id;
entityJson["device_id"] = entityCustomization.device_id; entityJson["device_id"] = entityCustomization.device_id;
entityJson["custom_name"] = entityCustomization.custom_name;
// entries are in the form <XX><shortname>[optional customname] e.g "08heatingactive|heating is on" // entries are in the form <XX><shortname>[optional customname] e.g "08heatingactive|heating is on"
JsonArray masked_entityJson = entityJson["entity_ids"].to<JsonArray>(); JsonArray masked_entityJson = entityJson["entity_ids"].to<JsonArray>();
@@ -123,6 +130,7 @@ StateUpdateResult WebCustomization::update(JsonObject root, WebCustomization & c
auto emsEntity = EntityCustomization(); auto emsEntity = EntityCustomization();
emsEntity.product_id = masked_entities["product_id"]; emsEntity.product_id = masked_entities["product_id"];
emsEntity.device_id = masked_entities["device_id"]; emsEntity.device_id = masked_entities["device_id"];
emsEntity.custom_name = masked_entities["custom_name"].as<std::string>();
for (const JsonVariant masked_entity_id : masked_entities["entity_ids"].as<JsonArray>()) { for (const JsonVariant masked_entity_id : masked_entities["entity_ids"].as<JsonArray>()) {
if (masked_entity_id.is<std::string>()) { if (masked_entity_id.is<std::string>()) {
@@ -164,7 +172,7 @@ void WebCustomizationService::devices(AsyncWebServerRequest * request) {
if (emsdevice->has_entities()) { if (emsdevice->has_entities()) {
JsonObject obj = devices.add<JsonObject>(); JsonObject obj = devices.add<JsonObject>();
obj["i"] = emsdevice->unique_id(); // its unique id obj["i"] = emsdevice->unique_id(); // its unique id
obj["s"] = emsdevice->name(); obj["s"] = emsdevice->name(); // custom name
obj["tn"] = emsdevice->device_type_name(); // non-translated, lower-case obj["tn"] = emsdevice->device_type_name(); // non-translated, lower-case
obj["t"] = emsdevice->device_type(); // internal device type ID obj["t"] = emsdevice->device_type(); // internal device type ID
} }
@@ -211,6 +219,58 @@ void WebCustomizationService::device_entities(AsyncWebServerRequest * request) {
request->send(response); request->send(response);
} }
// renames a device
// takes the unique ID and the custom name
void WebCustomizationService::writeDeviceName(AsyncWebServerRequest * request, JsonVariant json) {
if (json.is<JsonObject>()) {
// find the device using the unique_id
for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice) {
uint8_t unique_device_id = json["id"];
// find product id and device id using the unique id
if (emsdevice->unique_id() == unique_device_id) {
uint8_t product_id = emsdevice->product_id();
uint8_t device_id = emsdevice->device_id();
auto custom_name = json["name"].as<std::string>();
// emsesp::EMSESP::logger().info("Found Device ID: %d, Product ID: %d", device_id, product_id);
// updates current record or creates a new one
bool entry_exists = false;
update([&](WebCustomization & settings) {
for (auto it = settings.entityCustomizations.begin(); it != settings.entityCustomizations.end();) {
if ((*it).product_id == product_id && (*it).device_id == device_id) {
(*it).custom_name = custom_name;
entry_exists = true;
break;
} else {
++it;
}
}
// if we don't have any customization for this device, create a new entry
if (!entry_exists) {
EntityCustomization new_entry;
new_entry.product_id = product_id;
new_entry.device_id = device_id;
new_entry.custom_name = custom_name;
settings.entityCustomizations.push_back(new_entry);
}
return StateUpdateResult::CHANGED;
});
// update the EMS Device record real-time
emsdevice->custom_name(custom_name);
}
}
}
}
AsyncWebServerResponse * response = request->beginResponse(200);
request->send(response);
}
// takes a list of updated entities with new masks from the web UI // takes a list of updated entities with new masks from the web UI
// saves it in the customization service // saves it in the customization service
// and updates the entity list real-time // and updates the entity list real-time
@@ -236,7 +296,6 @@ void WebCustomizationService::customization_entities(AsyncWebServerRequest * req
} else { } else {
emsdevice->setCustomizationEntity(id_s); emsdevice->setCustomizationEntity(id_s);
} }
// emsesp::EMSESP::logger().info(id.as<const char *>());
} }
// add deleted entities from file // add deleted entities from file
@@ -271,7 +330,7 @@ void WebCustomizationService::customization_entities(AsyncWebServerRequest * req
// Save the list to the customization file // Save the list to the customization file
update([&](WebCustomization & settings) { update([&](WebCustomization & settings) {
// see if we already have a mask list for this device, if so remove it // see if we already have a mask list for this device, if so remove the entry
for (auto it = settings.entityCustomizations.begin(); it != settings.entityCustomizations.end();) { for (auto it = settings.entityCustomizations.begin(); it != settings.entityCustomizations.end();) {
if ((*it).product_id == product_id && (*it).device_id == device_id) { if ((*it).product_id == product_id && (*it).device_id == device_id) {
it = settings.entityCustomizations.erase(it); it = settings.entityCustomizations.erase(it);
@@ -281,16 +340,14 @@ void WebCustomizationService::customization_entities(AsyncWebServerRequest * req
} }
} }
// create a new entry for this device if there are values // re-create a new entry
EntityCustomization new_entry; EntityCustomization new_entry;
new_entry.product_id = product_id; new_entry.product_id = product_id;
new_entry.device_id = device_id; new_entry.device_id = device_id;
new_entry.entity_ids = entity_ids; new_entry.entity_ids = entity_ids;
// add the record and save
settings.entityCustomizations.push_back(new_entry); settings.entityCustomizations.push_back(new_entry);
return StateUpdateResult::CHANGED;
return StateUpdateResult::CHANGED; // save the changes
}); });
break; break;
@@ -308,7 +365,6 @@ void WebCustomizationService::begin() {
_fsPersistence.readFromFS(); _fsPersistence.readFromFS();
} }
// hard coded tests // hard coded tests
#ifdef EMSESP_TEST #ifdef EMSESP_TEST
void WebCustomizationService::test() { void WebCustomizationService::test() {
@@ -321,11 +377,11 @@ void WebCustomizationService::test() {
sensor.offset = 0; sensor.offset = 0;
webCustomization.sensorCustomizations.push_back(sensor); webCustomization.sensorCustomizations.push_back(sensor);
sensor = SensorCustomization(); auto sensor2 = SensorCustomization();
sensor.id = "0B-0C0D-0E0F-1011"; sensor2.id = "0B-0C0D-0E0F-1011";
sensor.name = "test_sensor2"; sensor2.name = "test_sensor2";
sensor.offset = 4; sensor2.offset = 4;
webCustomization.sensorCustomizations.push_back(sensor); webCustomization.sensorCustomizations.push_back(sensor2);
// Analog sensors // Analog sensors
// This actually adds the sensors as we use customizations to store them // This actually adds the sensors as we use customizations to store them
@@ -353,6 +409,7 @@ void WebCustomizationService::test() {
auto emsEntity = EntityCustomization(); auto emsEntity = EntityCustomization();
emsEntity.product_id = 123; emsEntity.product_id = 123;
emsEntity.device_id = 8; emsEntity.device_id = 8;
emsEntity.custom_name = "Custom Name!!";
emsEntity.entity_ids.push_back("08heatingactive|is my heating on?"); emsEntity.entity_ids.push_back("08heatingactive|is my heating on?");
webCustomization.entityCustomizations.push_back(emsEntity); webCustomization.entityCustomizations.push_back(emsEntity);

View File

@@ -28,6 +28,7 @@
// POST // POST
#define CUSTOMIZATION_ENTITIES_PATH "/rest/customizationEntities" #define CUSTOMIZATION_ENTITIES_PATH "/rest/customizationEntities"
#define RESET_CUSTOMIZATION_SERVICE_PATH "/rest/resetCustomizations" #define RESET_CUSTOMIZATION_SERVICE_PATH "/rest/resetCustomizations"
#define WRITE_DEVICE_NAME_PATH "/rest/writeDeviceName"
namespace emsesp { namespace emsesp {
@@ -62,6 +63,7 @@ class EntityCustomization {
public: public:
uint8_t product_id; // device's product id uint8_t product_id; // device's product id
uint8_t device_id; // device's device id uint8_t device_id; // device's device id
std::string custom_name; // custom device name
std::vector<std::string> entity_ids; // array of entity ids with masks and optional custom fullname std::vector<std::string> entity_ids; // array of entity ids with masks and optional custom fullname
}; };
@@ -100,6 +102,7 @@ class WebCustomizationService : public StatefulService<WebCustomization> {
// POST // POST
void customization_entities(AsyncWebServerRequest * request, JsonVariant json); void customization_entities(AsyncWebServerRequest * request, JsonVariant json);
void writeDeviceName(AsyncWebServerRequest * request, JsonVariant json);
void reset_customization(AsyncWebServerRequest * request); // command void reset_customization(AsyncWebServerRequest * request); // command
}; };

View File

@@ -73,7 +73,7 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
obj["tn"] = emsdevice->device_type_2_device_name_translated(); // translated device type name obj["tn"] = emsdevice->device_type_2_device_name_translated(); // translated device type name
obj["t"] = emsdevice->device_type(); // device type number obj["t"] = emsdevice->device_type(); // device type number
obj["b"] = emsdevice->brand_to_char(); // brand obj["b"] = emsdevice->brand_to_char(); // brand
obj["n"] = emsdevice->name(); // name obj["n"] = emsdevice->name(); // custom name
obj["d"] = emsdevice->device_id(); // deviceid obj["d"] = emsdevice->device_id(); // deviceid
obj["p"] = emsdevice->product_id(); // productid obj["p"] = emsdevice->product_id(); // productid
obj["v"] = emsdevice->version(); // version obj["v"] = emsdevice->version(); // version