mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-08 08:49:52 +03:00
Merge branch 'dev' of https://github.com/emsesp/EMS-ESP32 into dev
This commit is contained in:
@@ -473,15 +473,24 @@ uint8_t WebCustomEntityService::count_entities() {
|
||||
}
|
||||
|
||||
// send to dashboard, msgpack don't like serialized, use number
|
||||
void WebCustomEntityService::generate_value_web(JsonObject output) {
|
||||
JsonArray data = output["data"].to<JsonArray>();
|
||||
void WebCustomEntityService::generate_value_web(JsonObject output, const bool is_dashboard) {
|
||||
JsonArray nodes = output["nodes"].to<JsonArray>();
|
||||
uint8_t index = 0;
|
||||
|
||||
for (const CustomEntityItem & entity : *customEntityItems_) {
|
||||
bool include = false;
|
||||
JsonObject obj = data.add<JsonObject>(); // create the object, we know there is a value
|
||||
obj["id"] = "00" + entity.name;
|
||||
obj["u"] = entity.uom;
|
||||
bool include = false;
|
||||
JsonObject root_obj = nodes.add<JsonObject>(); // create the object, we know there is a value
|
||||
|
||||
JsonObject obj;
|
||||
if (is_dashboard) {
|
||||
root_obj["id"] = (EMSdevice::DeviceTypeUniqueID::CUSTOM_UID * 100) + index; // make unique
|
||||
obj = root_obj["dv"].to<JsonObject>();
|
||||
} else {
|
||||
obj = root_obj;
|
||||
}
|
||||
|
||||
obj["id"] = "00" + entity.name;
|
||||
obj["u"] = entity.uom;
|
||||
|
||||
if (entity.writeable) {
|
||||
obj["c"] = entity.name;
|
||||
@@ -549,7 +558,7 @@ void WebCustomEntityService::generate_value_web(JsonObject output) {
|
||||
if (include) {
|
||||
index++;
|
||||
} else {
|
||||
data.remove(index);
|
||||
nodes.remove(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ class WebCustomEntityService : public StatefulService<WebCustomEntity> {
|
||||
void fetch();
|
||||
void render_value(JsonObject output, CustomEntityItem & entity, const bool useVal = false, const bool web = false, const bool add_uom = false);
|
||||
void show_values(JsonObject output);
|
||||
void generate_value_web(JsonObject output);
|
||||
void generate_value_web(JsonObject output, const bool is_dashboard = false);
|
||||
|
||||
uint8_t count_entities();
|
||||
void ha_reset() {
|
||||
|
||||
@@ -162,8 +162,15 @@ void WebCustomizationService::reset_customization(AsyncWebServerRequest * reques
|
||||
// send back list of device entities
|
||||
void WebCustomizationService::device_entities(AsyncWebServerRequest * request) {
|
||||
uint8_t id;
|
||||
|
||||
// for testing we hardcode the id to 1 - the boiler
|
||||
#if defined(EMSESP_STANDALONE) && defined(EMSESP_TEST)
|
||||
if (1) {
|
||||
id = 1;
|
||||
#else
|
||||
if (request->hasParam(F_(id))) {
|
||||
id = Helpers::atoint(request->getParam(F_(id))->value().c_str()); // get id from url
|
||||
#endif
|
||||
|
||||
auto * response = new AsyncJsonResponse(true, true); // array and msgpack
|
||||
|
||||
@@ -178,7 +185,12 @@ void WebCustomizationService::device_entities(AsyncWebServerRequest * request) {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
JsonArray output = response->getRoot();
|
||||
emsdevice->generate_values_web_customization(output);
|
||||
#else
|
||||
JsonDocument doc;
|
||||
JsonArray output = doc.to<JsonArray>();
|
||||
emsdevice->generate_values_web_customization(output);
|
||||
#endif
|
||||
|
||||
#if defined(EMSESP_DEBUG)
|
||||
size_t length = response->setLength();
|
||||
EMSESP::logger().debug("Customizations buffer used: %d", length);
|
||||
@@ -348,13 +360,13 @@ void WebCustomizationService::test() {
|
||||
webCustomization.sensorCustomizations.clear();
|
||||
auto sensor = SensorCustomization();
|
||||
sensor.id = "01_0203_0405_0607";
|
||||
sensor.name = "test_sensor1";
|
||||
sensor.name = "test_tempsensor1";
|
||||
sensor.offset = 0;
|
||||
webCustomization.sensorCustomizations.push_back(sensor);
|
||||
|
||||
auto sensor2 = SensorCustomization();
|
||||
sensor2.id = "0B_0C0D_0E0F_1011";
|
||||
sensor2.name = "test_sensor2";
|
||||
sensor2.name = "test_tempsensor2";
|
||||
sensor2.offset = 4;
|
||||
webCustomization.sensorCustomizations.push_back(sensor2);
|
||||
|
||||
@@ -363,7 +375,7 @@ void WebCustomizationService::test() {
|
||||
webCustomization.analogCustomizations.clear();
|
||||
auto analog = AnalogCustomization();
|
||||
analog.gpio = 36;
|
||||
analog.name = "test_analog1";
|
||||
analog.name = "test_analogsensor1";
|
||||
analog.offset = 0;
|
||||
analog.factor = 0.1;
|
||||
analog.uom = 17;
|
||||
@@ -372,22 +384,60 @@ void WebCustomizationService::test() {
|
||||
|
||||
analog = AnalogCustomization();
|
||||
analog.gpio = 37;
|
||||
analog.name = "test_analog2";
|
||||
analog.name = "test_analogsensor2";
|
||||
analog.offset = 0;
|
||||
analog.factor = 1;
|
||||
analog.uom = 0;
|
||||
analog.type = 1;
|
||||
webCustomization.analogCustomizations.push_back(analog);
|
||||
|
||||
// EMS entities
|
||||
analog = AnalogCustomization();
|
||||
analog.gpio = 38;
|
||||
analog.name = "test_analogsensor3";
|
||||
analog.offset = 0;
|
||||
analog.factor = 1;
|
||||
analog.uom = 0;
|
||||
analog.type = 0; // disabled, not-used
|
||||
webCustomization.analogCustomizations.push_back(analog);
|
||||
|
||||
// EMS entities, mark some as favorites
|
||||
webCustomization.entityCustomizations.clear();
|
||||
auto emsEntity = EntityCustomization();
|
||||
emsEntity.product_id = 123;
|
||||
emsEntity.device_id = 8;
|
||||
emsEntity.custom_name = "Custom Name!!";
|
||||
emsEntity.custom_name = "My Custom Boiler";
|
||||
emsEntity.entity_ids.push_back("08heatingactive|is my heating on?");
|
||||
emsEntity.entity_ids.push_back("08tapwateractive");
|
||||
emsEntity.entity_ids.push_back("08selflowtemp|<90");
|
||||
webCustomization.entityCustomizations.push_back(emsEntity);
|
||||
|
||||
// since custom device name is loaded at discovery, we need to force it here
|
||||
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||
if (emsdevice->is_device_id(emsEntity.device_id)) {
|
||||
emsdevice->custom_name(emsEntity.custom_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ...and the same with the custom masks and names for entity values. It's done in EMSdevice::add_device_value()
|
||||
// so we need to force it here
|
||||
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||
if (emsdevice->is_device_id(emsEntity.device_id)) {
|
||||
// find the device value and set the mask and custom name to match the above fake data
|
||||
for (auto & dv : emsdevice->devicevalues_) {
|
||||
if (strcmp(dv.short_name, "heatingactive") == 0) {
|
||||
dv.state = DeviceValueState::DV_FAVORITE; // set as favorite
|
||||
dv.custom_fullname = "is my heating on?";
|
||||
} else if (strcmp(dv.short_name, "tapwateractive") == 0) {
|
||||
dv.state = DeviceValueState::DV_FAVORITE; // set as favorite
|
||||
} else if (strcmp(dv.short_name, "selflowtemp") == 0) {
|
||||
dv.state = DeviceValueState::DV_FAVORITE; // set as favorite
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return StateUpdateResult::CHANGED; // persist the changes
|
||||
});
|
||||
|
||||
|
||||
@@ -43,9 +43,13 @@ WebDataService::WebDataService(AsyncWebServer * server, SecurityManager * securi
|
||||
server->on(EMSESP_SENSOR_DATA_SERVICE_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { sensor_data(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
|
||||
server->on(EMSESP_DASHBOARD_DATA_SERVICE_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { dashboard_data(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
}
|
||||
|
||||
// this is used in the dashboard and contains all ems device information
|
||||
// this is used in the Devices page and contains all EMS device information
|
||||
// /coreData endpoint
|
||||
void WebDataService::core_data(AsyncWebServerRequest * request) {
|
||||
auto * response = new AsyncJsonResponse(false);
|
||||
@@ -74,7 +78,7 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
|
||||
uint8_t customEntities = EMSESP::webCustomEntityService.count_entities();
|
||||
if (customEntities) {
|
||||
JsonObject obj = devices.add<JsonObject>();
|
||||
obj["id"] = 99; // the last unique id
|
||||
obj["id"] = EMSdevice::DeviceTypeUniqueID::CUSTOM_UID;
|
||||
obj["tn"] = Helpers::translated_word(FL_(custom_device)); // translated device type name
|
||||
obj["t"] = EMSdevice::DeviceType::CUSTOM; // device type number
|
||||
obj["b"] = Helpers::translated_word(FL_(na)); // brand
|
||||
@@ -150,6 +154,7 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) {
|
||||
}
|
||||
|
||||
// The unique_id is the unique record ID from the Web table to identify which device to load
|
||||
// endpoint /rest/deviceData?id=n
|
||||
// Compresses the JSON using MsgPack https://msgpack.org/index.html
|
||||
void WebDataService::device_data(AsyncWebServerRequest * request) {
|
||||
uint8_t id;
|
||||
@@ -189,7 +194,7 @@ void WebDataService::device_data(AsyncWebServerRequest * request) {
|
||||
}
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
if (id == 99) {
|
||||
if (id == EMSdevice::DeviceTypeUniqueID::CUSTOM_UID) {
|
||||
JsonObject output = response->getRoot();
|
||||
EMSESP::webCustomEntityService.generate_value_web(output);
|
||||
response->setLength();
|
||||
@@ -219,84 +224,76 @@ void WebDataService::write_device_value(AsyncWebServerRequest * request, JsonVar
|
||||
}
|
||||
|
||||
// using the unique ID from the web find the real device type
|
||||
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||
if (emsdevice->unique_id() == unique_id) {
|
||||
// create JSON for output
|
||||
auto * response = new AsyncJsonResponse(false);
|
||||
JsonObject output = response->getRoot();
|
||||
|
||||
// the data could be in any format, but we need string
|
||||
// authenticated is always true
|
||||
uint8_t return_code = CommandRet::NOT_FOUND;
|
||||
uint8_t device_type = emsdevice->device_type();
|
||||
// parse the command as it could have a hc or dhw prefixed, e.g. hc2/seltemp
|
||||
int8_t id = -1; // default
|
||||
if (device_type >= EMSdevice::DeviceType::BOILER) {
|
||||
cmd = Command::parse_command_string(cmd, id); // extract hc or dhw
|
||||
uint8_t device_type = EMSdevice::DeviceType::UNKNOWN;
|
||||
switch (unique_id) {
|
||||
case EMSdevice::DeviceTypeUniqueID::CUSTOM_UID:
|
||||
device_type = EMSdevice::DeviceType::CUSTOM;
|
||||
break;
|
||||
case EMSdevice::DeviceTypeUniqueID::SCHEDULER_UID:
|
||||
device_type = EMSdevice::DeviceType::SCHEDULER;
|
||||
break;
|
||||
case EMSdevice::DeviceTypeUniqueID::TEMPERATURESENSOR_UID:
|
||||
device_type = EMSdevice::DeviceType::TEMPERATURESENSOR;
|
||||
break;
|
||||
case EMSdevice::DeviceTypeUniqueID::ANALOGSENSOR_UID:
|
||||
device_type = EMSdevice::DeviceType::ANALOGSENSOR;
|
||||
break;
|
||||
default:
|
||||
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||
if (emsdevice->unique_id() == unique_id) {
|
||||
device_type = emsdevice->device_type();
|
||||
break;
|
||||
}
|
||||
if (data.is<const char *>()) {
|
||||
return_code = Command::call(device_type, cmd, data.as<const char *>(), true, id, output);
|
||||
} else if (data.is<int>()) {
|
||||
char s[10];
|
||||
return_code = Command::call(device_type, cmd, Helpers::render_value(s, data.as<int32_t>(), 0), true, id, output);
|
||||
} else if (data.is<float>()) {
|
||||
char s[10];
|
||||
return_code = Command::call(device_type, cmd, Helpers::render_value(s, data.as<float>(), 1), true, id, output);
|
||||
} else if (data.is<bool>()) {
|
||||
return_code = Command::call(device_type, cmd, data.as<bool>() ? "true" : "false", true, id, output);
|
||||
}
|
||||
|
||||
// write log
|
||||
if (return_code != CommandRet::OK) {
|
||||
EMSESP::logger().err("Write command failed %s (%s)", (const char *)output["message"], Command::return_code_string(return_code));
|
||||
} else {
|
||||
#if defined(EMSESP_DEBUG)
|
||||
EMSESP::logger().debug("Write command successful");
|
||||
#endif
|
||||
}
|
||||
|
||||
response->setCode((return_code == CommandRet::OK) ? 200 : 400); // bad request
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// special check for custom entities (which have a unique id of 99)
|
||||
if (unique_id == 99) {
|
||||
auto * response = new AsyncJsonResponse(false);
|
||||
JsonObject output = response->getRoot();
|
||||
uint8_t return_code = CommandRet::NOT_FOUND;
|
||||
uint8_t device_type = EMSdevice::DeviceType::CUSTOM;
|
||||
// parse the command as it could have a hc or dhw prefixed, e.g. hc2/seltemp
|
||||
int8_t id = -1;
|
||||
if (device_type >= EMSdevice::DeviceType::BOILER) {
|
||||
cmd = Command::parse_command_string(cmd, id); // extract hc or dhw
|
||||
}
|
||||
if (data.is<const char *>()) {
|
||||
return_code = Command::call(device_type, cmd, data.as<const char *>(), true, id, output);
|
||||
} else if (data.is<int>()) {
|
||||
char s[10];
|
||||
return_code = Command::call(device_type, cmd, Helpers::render_value(s, data.as<int32_t>(), 0), true, id, output);
|
||||
} else if (data.is<float>()) {
|
||||
char s[10];
|
||||
return_code = Command::call(device_type, cmd, Helpers::render_value(s, data.as<float>(), 1), true, id, output);
|
||||
}
|
||||
if (return_code != CommandRet::OK) {
|
||||
EMSESP::logger().err("Write command failed %s (%s)", (const char *)output["message"], Command::return_code_string(return_code));
|
||||
} else {
|
||||
#if defined(EMSESP_DEBUG)
|
||||
EMSESP::logger().debug("Write command successful");
|
||||
#endif
|
||||
}
|
||||
|
||||
response->setCode((return_code == CommandRet::OK) ? 200 : 400); // bad request
|
||||
response->setLength();
|
||||
if (device_type == EMSdevice::DeviceType::UNKNOWN) {
|
||||
EMSESP::logger().warning("Write command failed, bad device id: %d", unique_id);
|
||||
AsyncWebServerResponse * response = request->beginResponse(400); // bad request
|
||||
request->send(response);
|
||||
return;
|
||||
}
|
||||
// create JSON for output
|
||||
auto * response = new AsyncJsonResponse(false);
|
||||
JsonObject output = response->getRoot();
|
||||
// the data could be in any format, but we need string
|
||||
// authenticated is always true
|
||||
uint8_t return_code = CommandRet::NOT_FOUND;
|
||||
// parse the command as it could have a hc or dhw prefixed, e.g. hc2/seltemp
|
||||
int8_t id = -1; // default
|
||||
if (device_type >= EMSdevice::DeviceType::BOILER) {
|
||||
cmd = Command::parse_command_string(cmd, id); // extract hc or dhw
|
||||
}
|
||||
if (data.is<const char *>()) {
|
||||
return_code = Command::call(device_type, cmd, data.as<const char *>(), true, id, output);
|
||||
} else if (data.is<int>()) {
|
||||
char s[10];
|
||||
return_code = Command::call(device_type, cmd, Helpers::render_value(s, data.as<int32_t>(), 0), true, id, output);
|
||||
} else if (data.is<float>()) {
|
||||
char s[10];
|
||||
return_code = Command::call(device_type, cmd, Helpers::render_value(s, data.as<float>(), 1), true, id, output);
|
||||
} else if (data.is<bool>()) {
|
||||
return_code = Command::call(device_type, cmd, data.as<bool>() ? "true" : "false", true, id, output);
|
||||
}
|
||||
|
||||
// write log
|
||||
if (return_code != CommandRet::OK) {
|
||||
// is already logged by command and message contains code
|
||||
// EMSESP::logger().err("Write command failed %s (%s)", (const char *)output["message"], Command::return_code_string(return_code));
|
||||
} else {
|
||||
#if defined(EMSESP_DEBUG)
|
||||
EMSESP::logger().debug("Write command successful");
|
||||
#endif
|
||||
}
|
||||
|
||||
response->setCode((return_code == CommandRet::OK) ? 200 : 400); // bad request
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
return;
|
||||
}
|
||||
|
||||
EMSESP::logger().warning("Write command failed, bad json");
|
||||
|
||||
// if we reach here, fail
|
||||
AsyncWebServerResponse * response = request->beginResponse(400); // bad request
|
||||
request->send(response);
|
||||
@@ -346,4 +343,131 @@ void WebDataService::write_analog_sensor(AsyncWebServerRequest * request, JsonVa
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
// this is used in the dashboard and contains all ems device information
|
||||
// /dashboardData endpoint
|
||||
void WebDataService::dashboard_data(AsyncWebServerRequest * request) {
|
||||
auto * response = new AsyncJsonResponse(true, true); // its an Array and also msgpack'd
|
||||
|
||||
#if defined(EMSESP_STANDALONE)
|
||||
JsonDocument doc;
|
||||
JsonArray root = doc.to<JsonArray>();
|
||||
#else
|
||||
JsonArray root = response->getRoot();
|
||||
#endif
|
||||
|
||||
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||
if (emsdevice->count_entities_fav()) {
|
||||
JsonObject obj = root.add<JsonObject>();
|
||||
obj["id"] = emsdevice->unique_id(); // it's unique id
|
||||
obj["n"] = emsdevice->name(); // custom name
|
||||
obj["t"] = emsdevice->device_type(); // device type number
|
||||
emsdevice->generate_values_web(obj, true); // is_dashboard = true
|
||||
}
|
||||
}
|
||||
|
||||
// add custom entities, if we have any
|
||||
if (EMSESP::webCustomEntityService.count_entities()) {
|
||||
JsonObject obj = root.add<JsonObject>();
|
||||
obj["id"] = EMSdevice::DeviceTypeUniqueID::CUSTOM_UID; // it's unique id
|
||||
obj["t"] = EMSdevice::DeviceType::CUSTOM; // device type number
|
||||
EMSESP::webCustomEntityService.generate_value_web(obj, true);
|
||||
}
|
||||
|
||||
// add temperature sensors
|
||||
if (EMSESP::temperaturesensor_.have_sensors()) {
|
||||
JsonObject obj = root.add<JsonObject>();
|
||||
obj["id"] = EMSdevice::DeviceTypeUniqueID::TEMPERATURESENSOR_UID; // it's unique id
|
||||
obj["t"] = EMSdevice::DeviceType::TEMPERATURESENSOR; // device type number
|
||||
JsonArray nodes = obj["nodes"].to<JsonArray>();
|
||||
uint8_t count = 0;
|
||||
for (const auto & sensor : EMSESP::temperaturesensor_.sensors()) {
|
||||
JsonObject node = nodes.add<JsonObject>();
|
||||
node["id"] = (EMSdevice::DeviceTypeUniqueID::TEMPERATURESENSOR_UID * 100) + count++;
|
||||
|
||||
JsonObject dv = node["dv"].to<JsonObject>();
|
||||
dv["id"] = "00" + sensor.name();
|
||||
if (EMSESP::system_.fahrenheit()) {
|
||||
if (Helpers::hasValue(sensor.temperature_c)) {
|
||||
dv["v"] = (float)sensor.temperature_c * 0.18 + 32;
|
||||
}
|
||||
dv["u"] = DeviceValueUOM::FAHRENHEIT;
|
||||
} else {
|
||||
if (Helpers::hasValue(sensor.temperature_c)) {
|
||||
dv["v"] = (float)sensor.temperature_c / 10;
|
||||
}
|
||||
dv["u"] = DeviceValueUOM::DEGREES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add analog sensors, count excludes disabled entries
|
||||
if (EMSESP::analog_enabled() && EMSESP::analogsensor_.count_entities(false)) {
|
||||
JsonObject obj = root.add<JsonObject>();
|
||||
obj["id"] = EMSdevice::DeviceTypeUniqueID::ANALOGSENSOR_UID; // it's unique id
|
||||
obj["t"] = EMSdevice::DeviceType::ANALOGSENSOR; // device type number
|
||||
JsonArray nodes = obj["nodes"].to<JsonArray>();
|
||||
uint8_t count = 0;
|
||||
for (const auto & sensor : EMSESP::analogsensor_.sensors()) {
|
||||
if (sensor.type() != AnalogSensor::AnalogType::NOTUSED) { // ignore disabled
|
||||
JsonObject node = nodes.add<JsonObject>();
|
||||
node["id"] = (EMSdevice::DeviceTypeUniqueID::ANALOGSENSOR_UID * 100) + count++;
|
||||
|
||||
JsonObject dv = node["dv"].to<JsonObject>();
|
||||
dv["id"] = "00" + sensor.name();
|
||||
if (sensor.type() == AnalogSensor::AnalogType::DIGITAL_OUT || sensor.type() == AnalogSensor::AnalogType::DIGITAL_IN) {
|
||||
char s[12];
|
||||
dv["v"] = Helpers::render_boolean(s, sensor.value() != 0, true);
|
||||
JsonArray l = dv["l"].to<JsonArray>();
|
||||
l.add(Helpers::render_boolean(s, false, true));
|
||||
l.add(Helpers::render_boolean(s, true, true));
|
||||
} else {
|
||||
dv["v"] = Helpers::transformNumFloat(sensor.value(), 0);
|
||||
dv["u"] = sensor.uom();
|
||||
}
|
||||
if (sensor.type() == AnalogSensor::AnalogType::COUNTER || sensor.type() >= AnalogSensor::AnalogType::DIGITAL_OUT) {
|
||||
dv["c"] = sensor.name();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// show scheduler, with name, on/off
|
||||
if (EMSESP::webSchedulerService.count_entities()) {
|
||||
JsonObject obj = root.add<JsonObject>();
|
||||
obj["id"] = EMSdevice::DeviceTypeUniqueID::SCHEDULER_UID; // it's unique id
|
||||
obj["t"] = EMSdevice::DeviceType::SCHEDULER; // device type number
|
||||
JsonArray nodes = obj["nodes"].to<JsonArray>();
|
||||
uint8_t count = 0;
|
||||
|
||||
EMSESP::webSchedulerService.read([&](const WebScheduler & webScheduler) {
|
||||
for (const ScheduleItem & scheduleItem : webScheduler.scheduleItems) {
|
||||
// only add if we have a name - we don't need a u (UOM) for this
|
||||
if (!scheduleItem.name.empty()) {
|
||||
JsonObject node = nodes.add<JsonObject>();
|
||||
node["id"] = (EMSdevice::DeviceTypeUniqueID::SCHEDULER_UID * 100) + count++;
|
||||
|
||||
JsonObject dv = node["dv"].to<JsonObject>();
|
||||
dv["id"] = "00" + scheduleItem.name;
|
||||
dv["c"] = scheduleItem.name;
|
||||
char s[12];
|
||||
dv["v"] = Helpers::render_boolean(s, scheduleItem.active, true);
|
||||
JsonArray l = dv["l"].to<JsonArray>();
|
||||
l.add(Helpers::render_boolean(s, false, true));
|
||||
l.add(Helpers::render_boolean(s, true, true));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#if defined(EMSESP_TEST) && defined(EMSESP_STANDALONE)
|
||||
Serial.println();
|
||||
Serial.print("All dashboard_data: ");
|
||||
serializeJson(root, Serial);
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
@@ -23,6 +23,7 @@
|
||||
#define EMSESP_CORE_DATA_SERVICE_PATH "/rest/coreData"
|
||||
#define EMSESP_DEVICE_DATA_SERVICE_PATH "/rest/deviceData"
|
||||
#define EMSESP_SENSOR_DATA_SERVICE_PATH "/rest/sensorData"
|
||||
#define EMSESP_DASHBOARD_DATA_SERVICE_PATH "/rest/dashboardData"
|
||||
|
||||
// POST
|
||||
#define EMSESP_WRITE_DEVICE_VALUE_SERVICE_PATH "/rest/writeDeviceValue"
|
||||
@@ -44,6 +45,7 @@ class WebDataService {
|
||||
void core_data(AsyncWebServerRequest * request);
|
||||
void sensor_data(AsyncWebServerRequest * request);
|
||||
void device_data(AsyncWebServerRequest * request);
|
||||
void dashboard_data(AsyncWebServerRequest * request);
|
||||
|
||||
// POST
|
||||
void write_device_value(AsyncWebServerRequest * request, JsonVariant json);
|
||||
|
||||
@@ -49,10 +49,10 @@ void WebSchedulerService::begin() {
|
||||
// and also calls when the Scheduler web page is refreshed
|
||||
void WebScheduler::read(WebScheduler & webScheduler, JsonObject root) {
|
||||
JsonArray schedule = root["schedule"].to<JsonArray>();
|
||||
uint8_t counter = 0;
|
||||
uint8_t counter = 1;
|
||||
for (const ScheduleItem & scheduleItem : webScheduler.scheduleItems) {
|
||||
JsonObject si = schedule.add<JsonObject>();
|
||||
si["id"] = counter++; // id is only used to render the table and must be unique
|
||||
si["id"] = counter++; // id is only used to render the table and must be unique. 0 is for Dashboard
|
||||
si["flags"] = scheduleItem.flags;
|
||||
si["active"] = scheduleItem.flags != SCHEDULEFLAG_SCHEDULE_IMMEDIATE ? scheduleItem.active : false;
|
||||
si["time"] = scheduleItem.flags != SCHEDULEFLAG_SCHEDULE_IMMEDIATE ? scheduleItem.time : "";
|
||||
@@ -71,33 +71,31 @@ StateUpdateResult WebScheduler::update(JsonObject root, WebScheduler & webSchedu
|
||||
EMSESP::webSchedulerService.ha_reset();
|
||||
|
||||
// build up the list of schedule items
|
||||
if (root["schedule"].is<JsonArray>()) {
|
||||
for (const JsonObject schedule : root["schedule"].as<JsonArray>()) {
|
||||
// create each schedule item, overwriting any previous settings
|
||||
// ignore the id (as this is only used in the web for table rendering)
|
||||
auto si = ScheduleItem();
|
||||
si.active = schedule["active"];
|
||||
si.flags = schedule["flags"];
|
||||
si.time = si.flags == SCHEDULEFLAG_SCHEDULE_IMMEDIATE ? "" : schedule["time"].as<std::string>();
|
||||
si.cmd = schedule["cmd"].as<std::string>();
|
||||
si.value = schedule["value"].as<std::string>();
|
||||
si.name = schedule["name"].as<std::string>();
|
||||
for (const JsonObject schedule : root["schedule"].as<JsonArray>()) {
|
||||
// create each schedule item, overwriting any previous settings
|
||||
// ignore the id (as this is only used in the web for table rendering)
|
||||
auto si = ScheduleItem();
|
||||
si.active = schedule["active"];
|
||||
si.flags = schedule["flags"];
|
||||
si.time = si.flags == SCHEDULEFLAG_SCHEDULE_IMMEDIATE ? "" : schedule["time"].as<std::string>();
|
||||
si.cmd = schedule["cmd"].as<std::string>();
|
||||
si.value = schedule["value"].as<std::string>();
|
||||
si.name = schedule["name"].as<std::string>();
|
||||
|
||||
// calculated elapsed minutes
|
||||
si.elapsed_min = Helpers::string2minutes(si.time);
|
||||
si.retry_cnt = 0xFF; // no startup retries
|
||||
// calculated elapsed minutes
|
||||
si.elapsed_min = Helpers::string2minutes(si.time);
|
||||
si.retry_cnt = 0xFF; // no startup retries
|
||||
|
||||
webScheduler.scheduleItems.push_back(si); // add to list
|
||||
if (!webScheduler.scheduleItems.back().name.empty()) {
|
||||
Command::add(
|
||||
EMSdevice::DeviceType::SCHEDULER,
|
||||
webScheduler.scheduleItems.back().name.c_str(),
|
||||
[webScheduler](const char * value, const int8_t id) {
|
||||
return EMSESP::webSchedulerService.command_setvalue(value, id, webScheduler.scheduleItems.back().name.c_str());
|
||||
},
|
||||
FL_(schedule_cmd),
|
||||
CommandFlag::ADMIN_ONLY);
|
||||
}
|
||||
webScheduler.scheduleItems.push_back(si); // add to list
|
||||
if (!webScheduler.scheduleItems.back().name.empty()) {
|
||||
Command::add(
|
||||
EMSdevice::DeviceType::SCHEDULER,
|
||||
webScheduler.scheduleItems.back().name.c_str(),
|
||||
[webScheduler](const char * value, const int8_t id) {
|
||||
return EMSESP::webSchedulerService.command_setvalue(value, id, webScheduler.scheduleItems.back().name.c_str());
|
||||
},
|
||||
FL_(schedule_cmd),
|
||||
CommandFlag::ADMIN_ONLY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,6 +549,19 @@ void WebSchedulerService::test() {
|
||||
si.elapsed_min = 0;
|
||||
si.retry_cnt = 0xFF; // no startup retries
|
||||
|
||||
webScheduler.scheduleItems.push_back(si);
|
||||
|
||||
// test 2
|
||||
si = ScheduleItem();
|
||||
si.active = false;
|
||||
si.flags = 1;
|
||||
si.time = "13:00";
|
||||
si.cmd = "system/message";
|
||||
si.value = "20";
|
||||
si.name = ""; // to make sure its excluded from Dashboard
|
||||
si.elapsed_min = 0;
|
||||
si.retry_cnt = 0xFF; // no startup retries
|
||||
|
||||
webScheduler.scheduleItems.push_back(si);
|
||||
already_added = true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user