mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
refactor custom vs customizations
This commit is contained in:
@@ -65,7 +65,9 @@ const SettingsCustomization: FC = () => {
|
|||||||
|
|
||||||
const { data: devices } = useRequest(EMSESP.readDevices);
|
const { data: devices } = useRequest(EMSESP.readDevices);
|
||||||
|
|
||||||
const { send: writeCustomEntities } = useRequest((data) => EMSESP.writeCustomEntities(data), { immediate: false });
|
const { send: writeCustomizationEntities } = useRequest((data) => EMSESP.writeCustomizationEntities(data), {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
|
||||||
const { send: readDeviceEntities, onSuccess: onSuccess } = useRequest((data) => EMSESP.readDeviceEntities(data), {
|
const { send: readDeviceEntities, onSuccess: onSuccess } = useRequest((data) => EMSESP.readDeviceEntities(data), {
|
||||||
initialData: [],
|
initialData: [],
|
||||||
@@ -312,7 +314,7 @@ const SettingsCustomization: FC = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await writeCustomEntities({ id: devices?.devices[selectedDevice].i, entity_ids: masked_entities }).catch(
|
await writeCustomizationEntities({ id: devices?.devices[selectedDevice].i, entity_ids: masked_entities }).catch(
|
||||||
(error) => {
|
(error) => {
|
||||||
if (error.message === 'Reboot required') {
|
if (error.message === 'Reboot required') {
|
||||||
setRestartNeeded(true);
|
setRestartNeeded(true);
|
||||||
|
|||||||
@@ -33,12 +33,12 @@ const SettingsEntities: FC = () => {
|
|||||||
data: entities,
|
data: entities,
|
||||||
send: fetchEntities,
|
send: fetchEntities,
|
||||||
error
|
error
|
||||||
} = useRequest(EMSESP.readEntities, {
|
} = useRequest(EMSESP.readCustomEntities, {
|
||||||
initialData: [],
|
initialData: [],
|
||||||
force: true
|
force: true
|
||||||
});
|
});
|
||||||
|
|
||||||
const { send: writeEntities } = useRequest((data) => EMSESP.writeEntities(data), { immediate: false });
|
const { send: writeEntities } = useRequest((data) => EMSESP.writeCustomEntities(data), { immediate: false });
|
||||||
|
|
||||||
function hasEntityChanged(ei: EntityItem) {
|
function hasEntityChanged(ei: EntityItem) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export const readDeviceEntities = (id: number) =>
|
|||||||
});
|
});
|
||||||
export const readDevices = () => alovaInstance.Get<Devices>('/rest/devices');
|
export const readDevices = () => alovaInstance.Get<Devices>('/rest/devices');
|
||||||
export const resetCustomizations = () => alovaInstance.Post('/rest/resetCustomizations');
|
export const resetCustomizations = () => alovaInstance.Post('/rest/resetCustomizations');
|
||||||
export const writeCustomEntities = (data: any) => alovaInstance.Post('/rest/customEntities', data);
|
export const writeCustomizationEntities = (data: any) => alovaInstance.Post('/rest/customizationEntities', data);
|
||||||
|
|
||||||
// SettingsScheduler
|
// SettingsScheduler
|
||||||
export const readSchedule = () =>
|
export const readSchedule = () =>
|
||||||
@@ -85,8 +85,8 @@ export const readSchedule = () =>
|
|||||||
export const writeSchedule = (data: any) => alovaInstance.Post('/rest/schedule', data);
|
export const writeSchedule = (data: any) => alovaInstance.Post('/rest/schedule', data);
|
||||||
|
|
||||||
// SettingsEntities
|
// SettingsEntities
|
||||||
export const readEntities = () =>
|
export const readCustomEntities = () =>
|
||||||
alovaInstance.Get<EntityItem[]>('/rest/entities', {
|
alovaInstance.Get<EntityItem[]>('/rest/customentities', {
|
||||||
name: 'entities',
|
name: 'entities',
|
||||||
transformData(data: any) {
|
transformData(data: any) {
|
||||||
return data.entities.map((ei: EntityItem) => ({
|
return data.entities.map((ei: EntityItem) => ({
|
||||||
@@ -104,4 +104,4 @@ export const readEntities = () =>
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
export const writeEntities = (data: any) => alovaInstance.Post('/rest/entities', data);
|
export const writeCustomEntities = (data: any) => alovaInstance.Post('/rest/customentities', data);
|
||||||
|
|||||||
@@ -347,7 +347,7 @@ const EMSESP_BOARDPROFILE_ENDPOINT = REST_ENDPOINT_ROOT + 'boardProfile';
|
|||||||
const EMSESP_WRITE_VALUE_ENDPOINT = REST_ENDPOINT_ROOT + 'writeDeviceValue';
|
const EMSESP_WRITE_VALUE_ENDPOINT = REST_ENDPOINT_ROOT + 'writeDeviceValue';
|
||||||
const EMSESP_WRITE_SENSOR_ENDPOINT = REST_ENDPOINT_ROOT + 'writeTemperatureSensor';
|
const EMSESP_WRITE_SENSOR_ENDPOINT = REST_ENDPOINT_ROOT + 'writeTemperatureSensor';
|
||||||
const EMSESP_WRITE_ANALOG_ENDPOINT = REST_ENDPOINT_ROOT + 'writeAnalogSensor';
|
const EMSESP_WRITE_ANALOG_ENDPOINT = REST_ENDPOINT_ROOT + 'writeAnalogSensor';
|
||||||
const EMSESP_CUSTOM_ENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'customEntities';
|
const EMSESP_CUSTOMIZATION_ENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'customizationEntities';
|
||||||
const EMSESP_RESET_CUSTOMIZATIONS_ENDPOINT = REST_ENDPOINT_ROOT + 'resetCustomizations';
|
const EMSESP_RESET_CUSTOMIZATIONS_ENDPOINT = REST_ENDPOINT_ROOT + 'resetCustomizations';
|
||||||
const EMSESP_WRITE_SCHEDULE_ENDPOINT = REST_ENDPOINT_ROOT + 'schedule';
|
const EMSESP_WRITE_SCHEDULE_ENDPOINT = REST_ENDPOINT_ROOT + 'schedule';
|
||||||
const EMSESP_WRITE_ENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'entities';
|
const EMSESP_WRITE_ENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'entities';
|
||||||
@@ -2355,7 +2355,7 @@ function updateMask(entity, de, dd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rest_server.post(EMSESP_CUSTOM_ENTITIES_ENDPOINT, (req, res) => {
|
rest_server.post(EMSESP_CUSTOMIZATION_ENTITIES_ENDPOINT, (req, res) => {
|
||||||
const id = req.body.id;
|
const id = req.body.id;
|
||||||
console.log('customization id = ' + id);
|
console.log('customization id = ' + id);
|
||||||
console.log(req.body.entity_ids);
|
console.log(req.body.entity_ids);
|
||||||
|
|||||||
@@ -1074,7 +1074,7 @@ void EMSdevice::set_climate_minmax(uint8_t tag, int16_t min, uint16_t max) {
|
|||||||
|
|
||||||
// set mask per device entity based on the id which is prefixed with the 2 char hex mask value
|
// set mask per device entity based on the id which is prefixed with the 2 char hex mask value
|
||||||
// returns true if the entity has a mask set (not 0 the default)
|
// returns true if the entity has a mask set (not 0 the default)
|
||||||
void EMSdevice::setCustomEntity(const std::string & entity_id) {
|
void EMSdevice::setCustomizationEntity(const std::string & entity_id) {
|
||||||
for (auto & dv : devicevalues_) {
|
for (auto & dv : devicevalues_) {
|
||||||
char entity_name[70];
|
char entity_name[70];
|
||||||
if (dv.tag < DeviceValueTAG::TAG_HC1) {
|
if (dv.tag < DeviceValueTAG::TAG_HC1) {
|
||||||
@@ -1126,7 +1126,7 @@ void EMSdevice::setCustomEntity(const std::string & entity_id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// populate a string vector with entities that have masks set or have a custom name
|
// populate a string vector with entities that have masks set or have a custom name
|
||||||
void EMSdevice::getCustomEntities(std::vector<std::string> & entity_ids) {
|
void EMSdevice::getCustomizationEntities(std::vector<std::string> & entity_ids) {
|
||||||
for (const auto & dv : devicevalues_) {
|
for (const auto & dv : devicevalues_) {
|
||||||
char name[100];
|
char name[100];
|
||||||
name[0] = '\0';
|
name[0] = '\0';
|
||||||
|
|||||||
@@ -191,8 +191,8 @@ class EMSdevice {
|
|||||||
void add_handlers_ignored(const uint16_t handler);
|
void add_handlers_ignored(const uint16_t handler);
|
||||||
|
|
||||||
void set_climate_minmax(uint8_t tag, int16_t min, uint16_t max);
|
void set_climate_minmax(uint8_t tag, int16_t min, uint16_t max);
|
||||||
void setCustomEntity(const std::string & entity_id);
|
void setCustomizationEntity(const std::string & entity_id);
|
||||||
void getCustomEntities(std::vector<std::string> & entity_ids);
|
void getCustomizationEntities(std::vector<std::string> & entity_ids);
|
||||||
|
|
||||||
void register_telegram_type(const uint16_t telegram_type_id, const char * telegram_type_name, bool fetch, const process_function_p cb);
|
void register_telegram_type(const uint16_t telegram_type_id, const char * telegram_type_name, bool fetch, const process_function_p cb);
|
||||||
bool handle_telegram(std::shared_ptr<const Telegram> telegram);
|
bool handle_telegram(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|||||||
@@ -32,13 +32,13 @@ ESP8266React EMSESP::esp8266React(&webServer, &dummyFS);
|
|||||||
WebSettingsService EMSESP::webSettingsService = WebSettingsService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager());
|
WebSettingsService EMSESP::webSettingsService = WebSettingsService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager());
|
||||||
WebCustomizationService EMSESP::webCustomizationService = WebCustomizationService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager());
|
WebCustomizationService EMSESP::webCustomizationService = WebCustomizationService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager());
|
||||||
WebSchedulerService EMSESP::webSchedulerService = WebSchedulerService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager());
|
WebSchedulerService EMSESP::webSchedulerService = WebSchedulerService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager());
|
||||||
WebEntityService EMSESP::webEntityService = WebEntityService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager());
|
WebCustomEntityService EMSESP::webCustomEntityService = WebCustomEntityService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager());
|
||||||
#else
|
#else
|
||||||
ESP8266React EMSESP::esp8266React(&webServer, &LittleFS);
|
ESP8266React EMSESP::esp8266React(&webServer, &LittleFS);
|
||||||
WebSettingsService EMSESP::webSettingsService = WebSettingsService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager());
|
WebSettingsService EMSESP::webSettingsService = WebSettingsService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager());
|
||||||
WebCustomizationService EMSESP::webCustomizationService = WebCustomizationService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager());
|
WebCustomizationService EMSESP::webCustomizationService = WebCustomizationService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager());
|
||||||
WebSchedulerService EMSESP::webSchedulerService = WebSchedulerService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager());
|
WebSchedulerService EMSESP::webSchedulerService = WebSchedulerService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager());
|
||||||
WebEntityService EMSESP::webEntityService = WebEntityService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager());
|
WebCustomEntityService EMSESP::webCustomEntityService = WebCustomEntityService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
WebStatusService EMSESP::webStatusService = WebStatusService(&webServer, EMSESP::esp8266React.getSecurityManager());
|
WebStatusService EMSESP::webStatusService = WebStatusService(&webServer, EMSESP::esp8266React.getSecurityManager());
|
||||||
@@ -481,7 +481,7 @@ void EMSESP::publish_all(bool force) {
|
|||||||
publish_device_values(EMSdevice::DeviceType::MIXER);
|
publish_device_values(EMSdevice::DeviceType::MIXER);
|
||||||
publish_other_values(); // switch and heat pump, ...
|
publish_other_values(); // switch and heat pump, ...
|
||||||
webSchedulerService.publish();
|
webSchedulerService.publish();
|
||||||
webEntityService.publish();
|
webCustomEntityService.publish();
|
||||||
publish_sensor_values(true); // includes temperature and analog sensors
|
publish_sensor_values(true); // includes temperature and analog sensors
|
||||||
system_.send_heartbeat();
|
system_.send_heartbeat();
|
||||||
}
|
}
|
||||||
@@ -514,7 +514,7 @@ void EMSESP::publish_all_loop() {
|
|||||||
case 5:
|
case 5:
|
||||||
publish_other_values(); // switch and heat pump
|
publish_other_values(); // switch and heat pump
|
||||||
webSchedulerService.publish(true);
|
webSchedulerService.publish(true);
|
||||||
webEntityService.publish(true);
|
webCustomEntityService.publish(true);
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
publish_sensor_values(true, true);
|
publish_sensor_values(true, true);
|
||||||
@@ -605,7 +605,7 @@ void EMSESP::publish_other_values() {
|
|||||||
// publish_device_values(EMSdevice::DeviceType::ALERT);
|
// publish_device_values(EMSdevice::DeviceType::ALERT);
|
||||||
// publish_device_values(EMSdevice::DeviceType::PUMP);
|
// publish_device_values(EMSdevice::DeviceType::PUMP);
|
||||||
// publish_device_values(EMSdevice::DeviceType::GENERIC);
|
// publish_device_values(EMSdevice::DeviceType::GENERIC);
|
||||||
webEntityService.publish();
|
webCustomEntityService.publish();
|
||||||
}
|
}
|
||||||
|
|
||||||
// publish both the temperature and analog sensor values
|
// publish both the temperature and analog sensor values
|
||||||
@@ -657,7 +657,8 @@ void EMSESP::publish_response(std::shared_ptr<const Telegram> telegram) {
|
|||||||
buffer = nullptr;
|
buffer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// builds json with the detail of each value, for a specific EMS device type or the temperature sensor
|
// builds json with the detail of each value,
|
||||||
|
// for a specific EMS device type or the sensors, scheduler and custom entities
|
||||||
bool EMSESP::get_device_value_info(JsonObject & root, const char * cmd, const int8_t id, const uint8_t devicetype) {
|
bool EMSESP::get_device_value_info(JsonObject & root, const char * cmd, const int8_t id, const uint8_t devicetype) {
|
||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if (emsdevice->device_type() == devicetype) {
|
if (emsdevice->device_type() == devicetype) {
|
||||||
@@ -684,7 +685,7 @@ bool EMSESP::get_device_value_info(JsonObject & root, const char * cmd, const in
|
|||||||
|
|
||||||
// own entities
|
// own entities
|
||||||
if (devicetype == DeviceType::CUSTOM) {
|
if (devicetype == DeviceType::CUSTOM) {
|
||||||
return EMSESP::webEntityService.get_value_info(root, cmd);
|
return EMSESP::webCustomEntityService.get_value_info(root, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
char error[100];
|
char error[100];
|
||||||
@@ -895,7 +896,7 @@ bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for custom entities reding this telegram
|
// Check for custom entities reding this telegram
|
||||||
webEntityService.get_value(telegram);
|
webCustomEntityService.get_value(telegram);
|
||||||
|
|
||||||
// check for common types, like the Version(0x02)
|
// check for common types, like the Version(0x02)
|
||||||
if (telegram->type_id == EMSdevice::EMS_TYPE_VERSION) {
|
if (telegram->type_id == EMSdevice::EMS_TYPE_VERSION) {
|
||||||
@@ -1414,7 +1415,7 @@ void EMSESP::scheduled_fetch_values() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
webEntityService.fetch();
|
webCustomEntityService.fetch();
|
||||||
no = 0;
|
no = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1497,7 +1498,7 @@ void EMSESP::start() {
|
|||||||
|
|
||||||
webCustomizationService.begin(); // load the customizations
|
webCustomizationService.begin(); // load the customizations
|
||||||
webSchedulerService.begin(); // load the scheduler events
|
webSchedulerService.begin(); // load the scheduler events
|
||||||
webEntityService.begin(); // load the custom telegram reads
|
webCustomEntityService.begin(); // load the custom telegram reads
|
||||||
|
|
||||||
// start telnet service if it's enabled
|
// start telnet service if it's enabled
|
||||||
// default idle is 10 minutes, default write timeout is 0 (automatic)
|
// default idle is 10 minutes, default write timeout is 0 (automatic)
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
#include "web/WebSchedulerService.h"
|
#include "web/WebSchedulerService.h"
|
||||||
#include "web/WebAPIService.h"
|
#include "web/WebAPIService.h"
|
||||||
#include "web/WebLogService.h"
|
#include "web/WebLogService.h"
|
||||||
#include "web/WebEntityService.h"
|
#include "web/WebCustomEntityService.h"
|
||||||
|
|
||||||
#include "emsdevicevalue.h"
|
#include "emsdevicevalue.h"
|
||||||
#include "emsdevice.h"
|
#include "emsdevice.h"
|
||||||
@@ -235,7 +235,7 @@ class EMSESP {
|
|||||||
static WebLogService webLogService;
|
static WebLogService webLogService;
|
||||||
static WebCustomizationService webCustomizationService;
|
static WebCustomizationService webCustomizationService;
|
||||||
static WebSchedulerService webSchedulerService;
|
static WebSchedulerService webSchedulerService;
|
||||||
static WebEntityService webEntityService;
|
static WebCustomEntityService webCustomEntityService;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::string device_tostring(const uint8_t device_id);
|
static std::string device_tostring(const uint8_t device_id);
|
||||||
|
|||||||
@@ -1031,7 +1031,7 @@ bool System::check_restore() {
|
|||||||
saveSettings(EMSESP_SCHEDULER_FILE, "Schedule", input);
|
saveSettings(EMSESP_SCHEDULER_FILE, "Schedule", input);
|
||||||
} else if (settings_type == "entities") {
|
} else if (settings_type == "entities") {
|
||||||
// it's a entity file, just replace it and there's no need to reboot
|
// it's a entity file, just replace it and there's no need to reboot
|
||||||
saveSettings(EMSESP_ENTITY_FILE, "Entities", input);
|
saveSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", input);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("Unrecognized file uploaded");
|
LOG_ERROR("Unrecognized file uploaded");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "3.6.2-dev.0"
|
#define EMSESP_APP_VERSION "3.6.2-dev.1"
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ void WebAPIService::getEntities(AsyncWebServerRequest * request) {
|
|||||||
|
|
||||||
root["type"] = "entities";
|
root["type"] = "entities";
|
||||||
|
|
||||||
System::extractSettings(EMSESP_ENTITY_FILE, "Entities", root);
|
System::extractSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", root);
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|||||||
@@ -22,13 +22,19 @@ namespace emsesp {
|
|||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
WebEntityService::WebEntityService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
WebCustomEntityService::WebCustomEntityService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _httpEndpoint(WebEntity::read, WebEntity::update, this, server, EMSESP_ENTITY_SERVICE_PATH, securityManager, AuthenticationPredicates::IS_AUTHENTICATED)
|
: _httpEndpoint(WebCustomEntity::read,
|
||||||
, _fsPersistence(WebEntity::read, WebEntity::update, this, fs, EMSESP_ENTITY_FILE, FS_BUFFER_SIZE) {
|
WebCustomEntity::update,
|
||||||
|
this,
|
||||||
|
server,
|
||||||
|
EMSESP_CUSTOMENTITY_SERVICE_PATH,
|
||||||
|
securityManager,
|
||||||
|
AuthenticationPredicates::IS_AUTHENTICATED)
|
||||||
|
, _fsPersistence(WebCustomEntity::read, WebCustomEntity::update, this, fs, EMSESP_CUSTOMENTITY_FILE, FS_BUFFER_SIZE) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the settings when the service starts
|
// load the settings when the service starts
|
||||||
void WebEntityService::begin() {
|
void WebCustomEntityService::begin() {
|
||||||
_fsPersistence.readFromFS();
|
_fsPersistence.readFromFS();
|
||||||
EMSESP::logger().info("Starting Custom entity service");
|
EMSESP::logger().info("Starting Custom entity service");
|
||||||
Mqtt::subscribe(EMSdevice::DeviceType::CUSTOM, "custom/#", nullptr); // use empty function callback
|
Mqtt::subscribe(EMSdevice::DeviceType::CUSTOM, "custom/#", nullptr); // use empty function callback
|
||||||
@@ -36,10 +42,10 @@ void WebEntityService::begin() {
|
|||||||
|
|
||||||
// this creates the entity file, saving it to the FS
|
// this creates the entity file, saving it to the FS
|
||||||
// and also calls when the Entity web page is refreshed
|
// and also calls when the Entity web page is refreshed
|
||||||
void WebEntity::read(WebEntity & webEntity, JsonObject & root) {
|
void WebCustomEntity::read(WebCustomEntity & webEntity, JsonObject & root) {
|
||||||
JsonArray entity = root.createNestedArray("entities");
|
JsonArray entity = root.createNestedArray("entities");
|
||||||
uint8_t counter = 0;
|
uint8_t counter = 0;
|
||||||
for (const EntityItem & entityItem : webEntity.entityItems) {
|
for (const CustomEntityItem & entityItem : webEntity.customEntityItems) {
|
||||||
JsonObject ei = entity.createNestedObject();
|
JsonObject ei = entity.createNestedObject();
|
||||||
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["device_id"] = entityItem.device_id;
|
ei["device_id"] = entityItem.device_id;
|
||||||
@@ -50,22 +56,38 @@ void WebEntity::read(WebEntity & webEntity, JsonObject & root) {
|
|||||||
ei["uom"] = entityItem.uom;
|
ei["uom"] = entityItem.uom;
|
||||||
ei["value_type"] = entityItem.value_type;
|
ei["value_type"] = entityItem.value_type;
|
||||||
ei["writeable"] = entityItem.writeable;
|
ei["writeable"] = entityItem.writeable;
|
||||||
EMSESP::webEntityService.render_value(ei, entityItem, true, true);
|
EMSESP::webCustomEntityService.render_value(ei, entityItem, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// call on initialization and also when the Entity web page is updated
|
// call on initialization and also when the Entity web page is updated
|
||||||
// this loads the data into the internal class
|
// this loads the data into the internal class
|
||||||
StateUpdateResult WebEntity::update(JsonObject & root, WebEntity & webEntity) {
|
StateUpdateResult WebCustomEntity::update(JsonObject & root, WebCustomEntity & webCustomEntity) {
|
||||||
for (EntityItem & entityItem : webEntity.entityItems) {
|
#ifdef EMSESP_STANDALONE
|
||||||
|
// invoke some fake data for testing
|
||||||
|
// clang-format off
|
||||||
|
/* prettier-ignore */
|
||||||
|
const char * json =
|
||||||
|
"{\"entities\": [{\"id\":0,\"device_id\":8,\"type_id\":24,\"offset\":0,\"factor\":1,\"name\":\"boiler_flowtemp\",\"uom\":1,\"value_type\":1,\"writeable\":true}]}";
|
||||||
|
// clang-format on
|
||||||
|
StaticJsonDocument<500> doc;
|
||||||
|
deserializeJson(doc, json);
|
||||||
|
root = doc.as<JsonObject>();
|
||||||
|
Serial.println(COLOR_BRIGHT_MAGENTA);
|
||||||
|
Serial.print(" Using fake custom entity file: ");
|
||||||
|
serializeJson(root, Serial);
|
||||||
|
Serial.println(COLOR_RESET);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (CustomEntityItem & entityItem : webCustomEntity.customEntityItems) {
|
||||||
Command::erase_command(EMSdevice::DeviceType::CUSTOM, entityItem.name.c_str());
|
Command::erase_command(EMSdevice::DeviceType::CUSTOM, entityItem.name.c_str());
|
||||||
}
|
}
|
||||||
webEntity.entityItems.clear();
|
webCustomEntity.customEntityItems.clear();
|
||||||
EMSESP::webEntityService.ha_reset();
|
EMSESP::webCustomEntityService.ha_reset();
|
||||||
|
|
||||||
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 = EntityItem();
|
auto entityItem = CustomEntityItem();
|
||||||
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"];
|
||||||
@@ -91,13 +113,13 @@ StateUpdateResult WebEntity::update(JsonObject & root, WebEntity & webEntity) {
|
|||||||
if (entityItem.factor == 0) {
|
if (entityItem.factor == 0) {
|
||||||
entityItem.factor = 1;
|
entityItem.factor = 1;
|
||||||
}
|
}
|
||||||
webEntity.entityItems.push_back(entityItem); // add to list
|
webCustomEntity.customEntityItems.push_back(entityItem); // add to list
|
||||||
if (entityItem.writeable) {
|
if (entityItem.writeable) {
|
||||||
Command::add(
|
Command::add(
|
||||||
EMSdevice::DeviceType::CUSTOM,
|
EMSdevice::DeviceType::CUSTOM,
|
||||||
webEntity.entityItems.back().name.c_str(),
|
webCustomEntity.customEntityItems.back().name.c_str(),
|
||||||
[webEntity](const char * value, const int8_t id) {
|
[webCustomEntity](const char * value, const int8_t id) {
|
||||||
return EMSESP::webEntityService.command_setvalue(value, webEntity.entityItems.back().name);
|
return EMSESP::webCustomEntityService.command_setvalue(value, webCustomEntity.customEntityItems.back().name);
|
||||||
},
|
},
|
||||||
FL_(entity_cmd),
|
FL_(entity_cmd),
|
||||||
CommandFlag::ADMIN_ONLY);
|
CommandFlag::ADMIN_ONLY);
|
||||||
@@ -108,9 +130,9 @@ StateUpdateResult WebEntity::update(JsonObject & root, WebEntity & webEntity) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set value by api command
|
// set value by api command
|
||||||
bool WebEntityService::command_setvalue(const char * value, const std::string name) {
|
bool WebCustomEntityService::command_setvalue(const char * value, const std::string name) {
|
||||||
EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; });
|
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; });
|
||||||
for (EntityItem & entityItem : *entityItems) {
|
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.value_type == DeviceValueType::STRING) {
|
||||||
char telegram[84];
|
char telegram[84];
|
||||||
@@ -160,7 +182,7 @@ bool WebEntityService::command_setvalue(const char * value, const std::string na
|
|||||||
}
|
}
|
||||||
|
|
||||||
// output of a single value
|
// output of a single value
|
||||||
void WebEntityService::render_value(JsonObject & output, EntityItem entity, const bool useVal, const bool web) {
|
void WebCustomEntityService::render_value(JsonObject & output, CustomEntityItem entity, const bool useVal, const bool web) {
|
||||||
char payload[12];
|
char payload[12];
|
||||||
std::string name = useVal ? "value" : entity.name;
|
std::string name = useVal ? "value" : entity.name;
|
||||||
switch (entity.value_type) {
|
switch (entity.value_type) {
|
||||||
@@ -215,26 +237,33 @@ void WebEntityService::render_value(JsonObject & output, EntityItem entity, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
// process json output for info/commands and value_info
|
// process json output for info/commands and value_info
|
||||||
bool WebEntityService::get_value_info(JsonObject & output, const char * cmd) {
|
bool WebCustomEntityService::get_value_info(JsonObject & output, const char * cmd) {
|
||||||
EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; });
|
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; });
|
||||||
if (entityItems->size() == 0) {
|
|
||||||
return false;
|
// if no entries, return a message instead of an error
|
||||||
|
// https://github.com/emsesp/EMS-ESP32/issues/1297
|
||||||
|
if (customEntityItems->size() == 0) {
|
||||||
|
output["message"] = "no entries";
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Helpers::toLower(cmd) == "commands") {
|
if (Helpers::toLower(cmd) == "commands") {
|
||||||
output["info"] = "list all values";
|
output["info"] = "list all values";
|
||||||
output["commands"] = "list all commands";
|
output["commands"] = "list all commands";
|
||||||
for (const auto & entity : *entityItems) {
|
for (const auto & entity : *customEntityItems) {
|
||||||
output[entity.name] = "custom entitiy";
|
output[entity.name] = "custom entitiy";
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(cmd) == 0 || Helpers::toLower(cmd) == "values" || Helpers::toLower(cmd) == "info") {
|
if (strlen(cmd) == 0 || Helpers::toLower(cmd) == "values" || Helpers::toLower(cmd) == "info") {
|
||||||
// list all names
|
// list all names
|
||||||
for (const EntityItem & entity : *entityItems) {
|
for (const CustomEntityItem & entity : *customEntityItems) {
|
||||||
render_value(output, entity);
|
render_value(output, entity);
|
||||||
}
|
}
|
||||||
return (output.size() != 0);
|
return (output.size() != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
char command_s[30];
|
char command_s[30];
|
||||||
strlcpy(command_s, cmd, sizeof(command_s));
|
strlcpy(command_s, cmd, sizeof(command_s));
|
||||||
char * attribute_s = nullptr;
|
char * attribute_s = nullptr;
|
||||||
@@ -244,7 +273,8 @@ bool WebEntityService::get_value_info(JsonObject & output, const char * cmd) {
|
|||||||
*breakp = '\0';
|
*breakp = '\0';
|
||||||
attribute_s = breakp + 1;
|
attribute_s = breakp + 1;
|
||||||
}
|
}
|
||||||
for (const auto & entity : *entityItems) {
|
|
||||||
|
for (const auto & entity : *customEntityItems) {
|
||||||
if (Helpers::toLower(entity.name) == Helpers::toLower(command_s)) {
|
if (Helpers::toLower(entity.name) == Helpers::toLower(command_s)) {
|
||||||
output["name"] = entity.name;
|
output["name"] = entity.name;
|
||||||
if (entity.uom > 0) {
|
if (entity.uom > 0) {
|
||||||
@@ -276,16 +306,18 @@ bool WebEntityService::get_value_info(JsonObject & output, const char * cmd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output.size()) {
|
if (output.size()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
output["message"] = "unknown command";
|
output["message"] = "unknown command";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// publish single value
|
// publish single value
|
||||||
void WebEntityService::publish_single(const EntityItem & entity) {
|
void WebCustomEntityService::publish_single(const CustomEntityItem & entity) {
|
||||||
if (!Mqtt::enabled() || !Mqtt::publish_single()) {
|
if (!Mqtt::enabled() || !Mqtt::publish_single()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -302,19 +334,19 @@ void WebEntityService::publish_single(const EntityItem & entity) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// publish to Mqtt
|
// publish to Mqtt
|
||||||
void WebEntityService::publish(const bool force) {
|
void WebCustomEntityService::publish(const bool force) {
|
||||||
if (force) {
|
if (force) {
|
||||||
ha_registered_ = false;
|
ha_registered_ = false;
|
||||||
}
|
}
|
||||||
if (!Mqtt::enabled()) {
|
if (!Mqtt::enabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; });
|
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; });
|
||||||
if (entityItems->size() == 0) {
|
if (customEntityItems->size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Mqtt::publish_single() && force) {
|
if (Mqtt::publish_single() && force) {
|
||||||
for (const EntityItem & entityItem : *entityItems) {
|
for (const CustomEntityItem & entityItem : *customEntityItems) {
|
||||||
publish_single(entityItem);
|
publish_single(entityItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -322,7 +354,7 @@ void WebEntityService::publish(const bool force) {
|
|||||||
DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE);
|
DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE);
|
||||||
JsonObject output = doc.to<JsonObject>();
|
JsonObject output = doc.to<JsonObject>();
|
||||||
bool ha_created = ha_registered_;
|
bool ha_created = ha_registered_;
|
||||||
for (const EntityItem & entityItem : *entityItems) {
|
for (const CustomEntityItem & entityItem : *customEntityItems) {
|
||||||
render_value(output, entityItem);
|
render_value(output, entityItem);
|
||||||
// create HA config
|
// create HA config
|
||||||
if (Mqtt::ha_enabled() && !ha_registered_) {
|
if (Mqtt::ha_enabled() && !ha_registered_) {
|
||||||
@@ -396,39 +428,39 @@ void WebEntityService::publish(const bool force) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// count only entities with valid value or command to show in dashboard
|
// count only entities with valid value or command to show in dashboard
|
||||||
uint8_t WebEntityService::count_entities() {
|
uint8_t WebCustomEntityService::count_entities() {
|
||||||
EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; });
|
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; });
|
||||||
if (entityItems->size() == 0) {
|
if (customEntityItems->size() == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE);
|
DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE);
|
||||||
JsonObject output = doc.to<JsonObject>();
|
JsonObject output = doc.to<JsonObject>();
|
||||||
uint8_t count = 0;
|
uint8_t count = 0;
|
||||||
for (const EntityItem & entity : *entityItems) {
|
for (const CustomEntityItem & entity : *customEntityItems) {
|
||||||
render_value(output, entity);
|
render_value(output, entity);
|
||||||
count += (output.containsKey(entity.name) || entity.writeable) ? 1 : 0;
|
count += (output.containsKey(entity.name) || entity.writeable) ? 1 : 0;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t WebEntityService::has_commands() {
|
uint8_t WebCustomEntityService::has_commands() {
|
||||||
EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; });
|
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; });
|
||||||
uint8_t count = 0;
|
uint8_t count = 0;
|
||||||
for (const EntityItem & entity : *entityItems) {
|
for (const CustomEntityItem & entity : *customEntityItems) {
|
||||||
count += entity.writeable ? 1 : 0;
|
count += entity.writeable ? 1 : 0;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send to dashboard, msgpack don't like serialized, use number
|
// send to dashboard, msgpack don't like serialized, use number
|
||||||
void WebEntityService::generate_value_web(JsonObject & output) {
|
void WebCustomEntityService::generate_value_web(JsonObject & output) {
|
||||||
EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; });
|
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; });
|
||||||
|
|
||||||
output["label"] = (std::string) "Custom Entities";
|
output["label"] = (std::string) "Custom Entities";
|
||||||
JsonArray data = output.createNestedArray("data");
|
JsonArray data = output.createNestedArray("data");
|
||||||
uint8_t index = 0;
|
uint8_t index = 0;
|
||||||
for (const EntityItem & entity : *entityItems) {
|
for (const CustomEntityItem & entity : *customEntityItems) {
|
||||||
JsonObject obj = data.createNestedObject(); // create the object, we know there is a value
|
JsonObject obj = data.createNestedObject(); // create the object, we know there is a value
|
||||||
obj["id"] = "00" + entity.name;
|
obj["id"] = "00" + entity.name;
|
||||||
obj["u"] = entity.uom;
|
obj["u"] = entity.uom;
|
||||||
@@ -493,10 +525,10 @@ void WebEntityService::generate_value_web(JsonObject & output) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fetch telegram, called from emsesp::fetch
|
// fetch telegram, called from emsesp::fetch
|
||||||
void WebEntityService::fetch() {
|
void WebCustomEntityService::fetch() {
|
||||||
EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; });
|
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 : *entityItems) {
|
for (auto & entity : *customEntityItems) {
|
||||||
EMSESP::send_read_request(entity.type_id,
|
EMSESP::send_read_request(entity.type_id,
|
||||||
entity.device_id,
|
entity.device_id,
|
||||||
entity.offset,
|
entity.offset,
|
||||||
@@ -506,12 +538,12 @@ void WebEntityService::fetch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// called on process telegram, read from telegram
|
// called on process telegram, read from telegram
|
||||||
bool WebEntityService::get_value(std::shared_ptr<const Telegram> telegram) {
|
bool WebCustomEntityService::get_value(std::shared_ptr<const Telegram> telegram) {
|
||||||
bool has_change = false;
|
bool has_change = false;
|
||||||
EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; });
|
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; });
|
||||||
// read-length of BOOL, INT, UINT, SHORT, USHORT, ULONG, TIME
|
// read-length of BOOL, INT, UINT, SHORT, USHORT, ULONG, TIME
|
||||||
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 : *entityItems) {
|
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) {
|
||||||
auto data = Helpers::data_to_hex(telegram->message_data, telegram->message_length);
|
auto data = Helpers::data_to_hex(telegram->message_data, telegram->message_length);
|
||||||
@@ -17,15 +17,15 @@
|
|||||||
*/
|
*/
|
||||||
#include "../telegram.h"
|
#include "../telegram.h"
|
||||||
|
|
||||||
#ifndef WebEntityService_h
|
#ifndef WebCustomEntityService_h
|
||||||
#define WebEntityService_h
|
#define WebCustomEntityService_h
|
||||||
|
|
||||||
#define EMSESP_ENTITY_FILE "/config/emsespEntity.json"
|
#define EMSESP_CUSTOMENTITY_FILE "/config/emsespEntity.json"
|
||||||
#define EMSESP_ENTITY_SERVICE_PATH "/rest/entities" // GET and POST
|
#define EMSESP_CUSTOMENTITY_SERVICE_PATH "/rest/customentities" // GET and POST
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
class EntityItem {
|
class CustomEntityItem {
|
||||||
public:
|
public:
|
||||||
uint8_t id;
|
uint8_t id;
|
||||||
uint8_t device_id;
|
uint8_t device_id;
|
||||||
@@ -40,26 +40,26 @@ class EntityItem {
|
|||||||
std::string data;
|
std::string data;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WebEntity {
|
class WebCustomEntity {
|
||||||
public:
|
public:
|
||||||
std::list<EntityItem> entityItems;
|
std::list<CustomEntityItem> customEntityItems;
|
||||||
|
|
||||||
static void read(WebEntity & webEntity, JsonObject & root);
|
static void read(WebCustomEntity & webEntity, JsonObject & root);
|
||||||
static StateUpdateResult update(JsonObject & root, WebEntity & webEntity);
|
static StateUpdateResult update(JsonObject & root, WebCustomEntity & webEntity);
|
||||||
};
|
};
|
||||||
|
|
||||||
class WebEntityService : public StatefulService<WebEntity> {
|
class WebCustomEntityService : public StatefulService<WebCustomEntity> {
|
||||||
public:
|
public:
|
||||||
WebEntityService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
|
WebCustomEntityService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
|
||||||
|
|
||||||
void begin();
|
void begin();
|
||||||
void publish_single(const EntityItem & entity);
|
void publish_single(const CustomEntityItem & entity);
|
||||||
void publish(const bool force = false);
|
void publish(const bool force = false);
|
||||||
bool command_setvalue(const char * value, const std::string name);
|
bool command_setvalue(const char * value, const std::string name);
|
||||||
bool get_value_info(JsonObject & output, const char * cmd);
|
bool get_value_info(JsonObject & output, const char * cmd);
|
||||||
bool get_value(std::shared_ptr<const Telegram> telegram);
|
bool get_value(std::shared_ptr<const Telegram> telegram);
|
||||||
void fetch();
|
void fetch();
|
||||||
void render_value(JsonObject & output, EntityItem entity, const bool useVal = false, const bool web = false);
|
void render_value(JsonObject & output, CustomEntityItem entity, const bool useVal = false, const bool web = false);
|
||||||
uint8_t count_entities();
|
uint8_t count_entities();
|
||||||
uint8_t has_commands();
|
uint8_t has_commands();
|
||||||
void generate_value_web(JsonObject & output);
|
void generate_value_web(JsonObject & output);
|
||||||
@@ -69,11 +69,11 @@ class WebEntityService : public StatefulService<WebEntity> {
|
|||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HttpEndpoint<WebEntity> _httpEndpoint;
|
HttpEndpoint<WebCustomEntity> _httpEndpoint;
|
||||||
FSPersistence<WebEntity> _fsPersistence;
|
FSPersistence<WebCustomEntity> _fsPersistence;
|
||||||
|
|
||||||
std::list<EntityItem> * entityItems; // pointer to the list of entity items
|
std::list<CustomEntityItem> * customEntityItems; // pointer to the list of entity items
|
||||||
bool ha_registered_ = false;
|
bool ha_registered_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
@@ -31,8 +31,8 @@ WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * f
|
|||||||
securityManager,
|
securityManager,
|
||||||
AuthenticationPredicates::IS_AUTHENTICATED)
|
AuthenticationPredicates::IS_AUTHENTICATED)
|
||||||
, _fsPersistence(WebCustomization::read, WebCustomization::update, this, fs, EMSESP_CUSTOMIZATION_FILE)
|
, _fsPersistence(WebCustomization::read, WebCustomization::update, this, fs, EMSESP_CUSTOMIZATION_FILE)
|
||||||
, _masked_entities_handler(CUSTOM_ENTITIES_PATH,
|
, _masked_entities_handler(CUSTOMIZATION_ENTITIES_PATH,
|
||||||
securityManager->wrapCallback(std::bind(&WebCustomizationService::custom_entities, this, _1, _2),
|
securityManager->wrapCallback(std::bind(&WebCustomizationService::customization_entities, this, _1, _2),
|
||||||
AuthenticationPredicates::IS_AUTHENTICATED)) {
|
AuthenticationPredicates::IS_AUTHENTICATED)) {
|
||||||
server->on(DEVICE_ENTITIES_PATH,
|
server->on(DEVICE_ENTITIES_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
@@ -54,10 +54,10 @@ WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * f
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this creates the customization file, saving it to the FS
|
// this creates the customization file, saving it to the FS
|
||||||
void WebCustomization::read(WebCustomization & settings, JsonObject & root) {
|
void WebCustomization::read(WebCustomization & customizations, JsonObject & root) {
|
||||||
// Temperature Sensor customization
|
// Temperature Sensor customization
|
||||||
JsonArray sensorsJson = root.createNestedArray("ts");
|
JsonArray sensorsJson = root.createNestedArray("ts");
|
||||||
for (const SensorCustomization & sensor : settings.sensorCustomizations) {
|
for (const SensorCustomization & sensor : customizations.sensorCustomizations) {
|
||||||
JsonObject sensorJson = sensorsJson.createNestedObject();
|
JsonObject sensorJson = sensorsJson.createNestedObject();
|
||||||
sensorJson["id"] = sensor.id; // ID of chip
|
sensorJson["id"] = sensor.id; // ID of chip
|
||||||
sensorJson["name"] = sensor.name; // n
|
sensorJson["name"] = sensor.name; // n
|
||||||
@@ -66,7 +66,7 @@ void WebCustomization::read(WebCustomization & settings, JsonObject & root) {
|
|||||||
|
|
||||||
// Analog Sensor customization
|
// Analog Sensor customization
|
||||||
JsonArray analogJson = root.createNestedArray("as");
|
JsonArray analogJson = root.createNestedArray("as");
|
||||||
for (const AnalogCustomization & sensor : settings.analogCustomizations) {
|
for (const AnalogCustomization & sensor : customizations.analogCustomizations) {
|
||||||
JsonObject sensorJson = analogJson.createNestedObject();
|
JsonObject sensorJson = analogJson.createNestedObject();
|
||||||
sensorJson["gpio"] = sensor.gpio; // g
|
sensorJson["gpio"] = sensor.gpio; // g
|
||||||
sensorJson["name"] = sensor.name; // n
|
sensorJson["name"] = sensor.name; // n
|
||||||
@@ -78,7 +78,7 @@ void WebCustomization::read(WebCustomization & settings, JsonObject & root) {
|
|||||||
|
|
||||||
// Masked entities customization
|
// Masked entities customization
|
||||||
JsonArray masked_entitiesJson = root.createNestedArray("masked_entities");
|
JsonArray masked_entitiesJson = root.createNestedArray("masked_entities");
|
||||||
for (const EntityCustomization & entityCustomization : settings.entityCustomizations) {
|
for (const EntityCustomization & entityCustomization : customizations.entityCustomizations) {
|
||||||
JsonObject entityJson = masked_entitiesJson.createNestedObject();
|
JsonObject entityJson = masked_entitiesJson.createNestedObject();
|
||||||
entityJson["product_id"] = entityCustomization.product_id;
|
entityJson["product_id"] = entityCustomization.product_id;
|
||||||
entityJson["device_id"] = entityCustomization.device_id;
|
entityJson["device_id"] = entityCustomization.device_id;
|
||||||
@@ -93,24 +93,22 @@ void WebCustomization::read(WebCustomization & settings, JsonObject & root) {
|
|||||||
|
|
||||||
// call on initialization and also when the page is saved via web UI
|
// call on initialization and also when the page is saved via web UI
|
||||||
// this loads the data into the internal class
|
// this loads the data into the internal class
|
||||||
StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization & settings) {
|
StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization & customizations) {
|
||||||
#ifdef EMSESP_STANDALONE
|
#ifdef EMSESP_STANDALONE
|
||||||
// invoke some fake data for testing
|
// invoke some fake data for testing
|
||||||
const char * json = "{\"ts\":[],\"as\":[],\"masked_entities\":[{\"product_id\":123,\"device_id\":8,\"entity_ids\":[\"08heatingactive|my custom "
|
const char * json = "{\"ts\":[],\"as\":[],\"masked_entities\":[{\"product_id\":123,\"device_id\":8,\"entity_ids\":[\"08heatingactive|my custom "
|
||||||
"name for heating active\",\"08tapwateractive\"]}]}";
|
"name for heating active\",\"08tapwateractive\"]}]}";
|
||||||
|
|
||||||
StaticJsonDocument<500> doc;
|
StaticJsonDocument<500> doc;
|
||||||
deserializeJson(doc, json);
|
deserializeJson(doc, json);
|
||||||
root = doc.as<JsonObject>();
|
root = doc.as<JsonObject>();
|
||||||
|
|
||||||
Serial.println(COLOR_BRIGHT_MAGENTA);
|
Serial.println(COLOR_BRIGHT_MAGENTA);
|
||||||
Serial.print("Using custom file: ");
|
Serial.print(" Using fake customization file: ");
|
||||||
serializeJson(root, Serial);
|
serializeJson(root, Serial);
|
||||||
Serial.println(COLOR_RESET);
|
Serial.println(COLOR_RESET);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Temperature Sensor customization
|
// Temperature Sensor customization
|
||||||
settings.sensorCustomizations.clear();
|
customizations.sensorCustomizations.clear();
|
||||||
if (root["ts"].is<JsonArray>()) {
|
if (root["ts"].is<JsonArray>()) {
|
||||||
for (const JsonObject sensorJson : root["ts"].as<JsonArray>()) {
|
for (const JsonObject sensorJson : root["ts"].as<JsonArray>()) {
|
||||||
// create each of the sensor, overwriting any previous settings
|
// create each of the sensor, overwriting any previous settings
|
||||||
@@ -118,12 +116,12 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization &
|
|||||||
sensor.id = sensorJson["id"].as<std::string>();
|
sensor.id = sensorJson["id"].as<std::string>();
|
||||||
sensor.name = sensorJson["name"].as<std::string>();
|
sensor.name = sensorJson["name"].as<std::string>();
|
||||||
sensor.offset = sensorJson["offset"];
|
sensor.offset = sensorJson["offset"];
|
||||||
settings.sensorCustomizations.push_back(sensor); // add to list
|
customizations.sensorCustomizations.push_back(sensor); // add to list
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Analog Sensor customization
|
// Analog Sensor customization
|
||||||
settings.analogCustomizations.clear();
|
customizations.analogCustomizations.clear();
|
||||||
if (root["as"].is<JsonArray>()) {
|
if (root["as"].is<JsonArray>()) {
|
||||||
for (const JsonObject analogJson : root["as"].as<JsonArray>()) {
|
for (const JsonObject analogJson : root["as"].as<JsonArray>()) {
|
||||||
// create each of the sensor, overwriting any previous settings
|
// create each of the sensor, overwriting any previous settings
|
||||||
@@ -134,12 +132,12 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization &
|
|||||||
sensor.factor = analogJson["factor"];
|
sensor.factor = analogJson["factor"];
|
||||||
sensor.uom = analogJson["uom"];
|
sensor.uom = analogJson["uom"];
|
||||||
sensor.type = analogJson["type"];
|
sensor.type = analogJson["type"];
|
||||||
settings.analogCustomizations.push_back(sensor); // add to list
|
customizations.analogCustomizations.push_back(sensor); // add to list
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load array of entities id's with masks, building up the object class
|
// load array of entities id's with masks, building up the object class
|
||||||
settings.entityCustomizations.clear();
|
customizations.entityCustomizations.clear();
|
||||||
if (root["masked_entities"].is<JsonArray>()) {
|
if (root["masked_entities"].is<JsonArray>()) {
|
||||||
for (const JsonObject masked_entities : root["masked_entities"].as<JsonArray>()) {
|
for (const JsonObject masked_entities : root["masked_entities"].as<JsonArray>()) {
|
||||||
auto new_entry = EntityCustomization();
|
auto new_entry = EntityCustomization();
|
||||||
@@ -152,7 +150,7 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization &
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.entityCustomizations.push_back(new_entry); // save the new object
|
customizations.entityCustomizations.push_back(new_entry); // save the new object
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +234,7 @@ void WebCustomizationService::device_entities(AsyncWebServerRequest * request) {
|
|||||||
// 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
|
||||||
void WebCustomizationService::custom_entities(AsyncWebServerRequest * request, JsonVariant & json) {
|
void WebCustomizationService::customization_entities(AsyncWebServerRequest * request, JsonVariant & json) {
|
||||||
bool need_reboot = false;
|
bool need_reboot = false;
|
||||||
if (json.is<JsonObject>()) {
|
if (json.is<JsonObject>()) {
|
||||||
// find the device using the unique_id
|
// find the device using the unique_id
|
||||||
@@ -256,7 +254,7 @@ void WebCustomizationService::custom_entities(AsyncWebServerRequest * request, J
|
|||||||
entity_ids.push_back(id_s);
|
entity_ids.push_back(id_s);
|
||||||
need_reboot = true;
|
need_reboot = true;
|
||||||
} else {
|
} else {
|
||||||
emsdevice->setCustomEntity(id_s);
|
emsdevice->setCustomizationEntity(id_s);
|
||||||
}
|
}
|
||||||
// emsesp::EMSESP::logger().info(id.as<const char *>());
|
// emsesp::EMSESP::logger().info(id.as<const char *>());
|
||||||
}
|
}
|
||||||
@@ -287,7 +285,7 @@ void WebCustomizationService::custom_entities(AsyncWebServerRequest * request, J
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
// get list of entities that have masks set or a custom fullname
|
// get list of entities that have masks set or a custom fullname
|
||||||
emsdevice->getCustomEntities(entity_ids);
|
emsdevice->getCustomizationEntities(entity_ids);
|
||||||
|
|
||||||
// Save the list to the customization file
|
// Save the list to the customization file
|
||||||
EMSESP::webCustomizationService.update(
|
EMSESP::webCustomizationService.update(
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#define DEVICE_ENTITIES_PATH "/rest/deviceEntities"
|
#define DEVICE_ENTITIES_PATH "/rest/deviceEntities"
|
||||||
|
|
||||||
// POST
|
// POST
|
||||||
#define CUSTOM_ENTITIES_PATH "/rest/customEntities"
|
#define CUSTOMIZATION_ENTITIES_PATH "/rest/customizationEntities"
|
||||||
#define RESET_CUSTOMIZATION_SERVICE_PATH "/rest/resetCustomizations"
|
#define RESET_CUSTOMIZATION_SERVICE_PATH "/rest/resetCustomizations"
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
@@ -71,8 +71,8 @@ class WebCustomization {
|
|||||||
std::list<SensorCustomization> sensorCustomizations; // for sensor names and offsets
|
std::list<SensorCustomization> sensorCustomizations; // for sensor names and offsets
|
||||||
std::list<AnalogCustomization> analogCustomizations; // for analog sensors
|
std::list<AnalogCustomization> analogCustomizations; // for analog sensors
|
||||||
std::list<EntityCustomization> entityCustomizations; // for a list of entities that have a special mask set
|
std::list<EntityCustomization> entityCustomizations; // for a list of entities that have a special mask set
|
||||||
static void read(WebCustomization & settings, JsonObject & root);
|
static void read(WebCustomization & customizations, JsonObject & root);
|
||||||
static StateUpdateResult update(JsonObject & root, WebCustomization & settings);
|
static StateUpdateResult update(JsonObject & root, WebCustomization & customizations);
|
||||||
};
|
};
|
||||||
|
|
||||||
class WebCustomizationService : public StatefulService<WebCustomization> {
|
class WebCustomizationService : public StatefulService<WebCustomization> {
|
||||||
@@ -94,7 +94,7 @@ class WebCustomizationService : public StatefulService<WebCustomization> {
|
|||||||
void device_entities(AsyncWebServerRequest * request);
|
void device_entities(AsyncWebServerRequest * request);
|
||||||
|
|
||||||
// POST
|
// POST
|
||||||
void custom_entities(AsyncWebServerRequest * request, JsonVariant & json);
|
void customization_entities(AsyncWebServerRequest * request, JsonVariant & json);
|
||||||
void reset_customization(AsyncWebServerRequest * request); // command
|
void reset_customization(AsyncWebServerRequest * request); // command
|
||||||
|
|
||||||
AsyncCallbackJsonWebHandler _masked_entities_handler;
|
AsyncCallbackJsonWebHandler _masked_entities_handler;
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add any custom entities
|
// add any custom entities
|
||||||
if (EMSESP::webEntityService.count_entities()) {
|
if (EMSESP::webCustomEntityService.count_entities()) {
|
||||||
JsonObject obj = devices.createNestedObject();
|
JsonObject obj = devices.createNestedObject();
|
||||||
obj["id"] = 99; // the last unique id
|
obj["id"] = 99; // the last unique id
|
||||||
obj["tn"] = Helpers::translated_word(FL_(custom_device)); // translated device type name
|
obj["tn"] = Helpers::translated_word(FL_(custom_device)); // translated device type name
|
||||||
@@ -210,7 +210,7 @@ void WebDataService::device_data(AsyncWebServerRequest * request) {
|
|||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
if (id == 99) {
|
if (id == 99) {
|
||||||
JsonObject output = response->getRoot();
|
JsonObject output = response->getRoot();
|
||||||
EMSESP::webEntityService.generate_value_web(output);
|
EMSESP::webCustomEntityService.generate_value_web(output);
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -57,12 +57,13 @@ StateUpdateResult WebScheduler::update(JsonObject & root, WebScheduler & webSche
|
|||||||
#ifdef EMSESP_STANDALONE
|
#ifdef EMSESP_STANDALONE
|
||||||
// invoke some fake data for testing
|
// invoke some fake data for testing
|
||||||
const char * json =
|
const char * json =
|
||||||
"{[{\"id\":1,\"active\":true,\"flags\":31,\"time\": \"07:30\",\"cmd\": \"hc1/mode\",\"value\": \"day\",\"name\": \"turn on central heating\"}]}";
|
"{\"schedule\": [{\"id\":1,\"active\":true,\"flags\":31,\"time\": \"07:30\",\"cmd\": \"hc1mode\",\"value\": \"day\",\"name\": \"turn on "
|
||||||
|
"central heating\"}]}";
|
||||||
StaticJsonDocument<500> doc;
|
StaticJsonDocument<500> doc;
|
||||||
deserializeJson(doc, json);
|
deserializeJson(doc, json);
|
||||||
root = doc.as<JsonObject>();
|
root = doc.as<JsonObject>();
|
||||||
Serial.println(COLOR_BRIGHT_MAGENTA);
|
Serial.println(COLOR_BRIGHT_MAGENTA);
|
||||||
Serial.print("Using custom file: ");
|
Serial.print(" Using fake scheduler file: ");
|
||||||
serializeJson(root, Serial);
|
serializeJson(root, Serial);
|
||||||
Serial.println(COLOR_RESET);
|
Serial.println(COLOR_RESET);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user