Optimize WebUI rendering when using Dialog Boxes #1116

This commit is contained in:
Proddy
2023-04-28 12:46:59 +02:00
parent b9402d3a01
commit cfe8c410ae
59 changed files with 1446 additions and 1120 deletions

View File

@@ -57,17 +57,17 @@ WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * f
// this creates the customization file, saving it to the FS
void WebCustomization::read(WebCustomization & settings, JsonObject & root) {
// Dallas Sensor customization
JsonArray sensorsJson = root.createNestedArray("sensors");
// Temperature Sensor customization
JsonArray sensorsJson = root.createNestedArray("ts");
for (const SensorCustomization & sensor : settings.sensorCustomizations) {
JsonObject sensorJson = sensorsJson.createNestedObject();
sensorJson["id"] = sensor.id; // is
sensorJson["id"] = sensor.id; // ID of chip
sensorJson["name"] = sensor.name; // n
sensorJson["offset"] = sensor.offset; // o
}
// Analog Sensor customization
JsonArray analogJson = root.createNestedArray("analogs");
JsonArray analogJson = root.createNestedArray("as");
for (const AnalogCustomization & sensor : settings.analogCustomizations) {
JsonObject sensorJson = analogJson.createNestedObject();
sensorJson["gpio"] = sensor.gpio; // g
@@ -98,7 +98,7 @@ void WebCustomization::read(WebCustomization & settings, JsonObject & root) {
StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization & settings) {
#ifdef EMSESP_STANDALONE
// invoke some fake data for testing
const char * json = "{\"sensors\":[],\"analogs\":[],\"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\"]}]}";
StaticJsonDocument<500> doc;
@@ -111,10 +111,10 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization &
Serial.println(COLOR_RESET);
#endif
// Dallas Sensor customization
// Temperature Sensor customization
settings.sensorCustomizations.clear();
if (root["sensors"].is<JsonArray>()) {
for (const JsonObject sensorJson : root["sensors"].as<JsonArray>()) {
if (root["ts"].is<JsonArray>()) {
for (const JsonObject sensorJson : root["ts"].as<JsonArray>()) {
// create each of the sensor, overwriting any previous settings
auto sensor = SensorCustomization();
sensor.id = sensorJson["id"].as<std::string>();
@@ -126,8 +126,8 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization &
// Analog Sensor customization
settings.analogCustomizations.clear();
if (root["analogs"].is<JsonArray>()) {
for (const JsonObject analogJson : root["analogs"].as<JsonArray>()) {
if (root["as"].is<JsonArray>()) {
for (const JsonObject analogJson : root["as"].as<JsonArray>()) {
// create each of the sensor, overwriting any previous settings
auto sensor = AnalogCustomization();
sensor.gpio = analogJson["gpio"];

View File

@@ -32,7 +32,7 @@
namespace emsesp {
// Customization for dallas sensor
// Customization for temperature sensor
class SensorCustomization {
public:
std::string id;

View File

@@ -25,12 +25,13 @@ using namespace std::placeholders; // for `_1` etc
WebDataService::WebDataService(AsyncWebServer * server, SecurityManager * securityManager)
: _device_data_handler(DEVICE_DATA_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDataService::device_data, this, _1, _2), AuthenticationPredicates::IS_AUTHENTICATED))
, _write_value_handler(WRITE_VALUE_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDataService::write_value, this, _1, _2), AuthenticationPredicates::IS_ADMIN))
, _write_sensor_handler(WRITE_SENSOR_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDataService::write_sensor, this, _1, _2), AuthenticationPredicates::IS_ADMIN))
, _write_analog_handler(WRITE_ANALOG_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDataService::write_analog, this, _1, _2), AuthenticationPredicates::IS_ADMIN)) {
, _write_value_handler(WRITE_DEVICE_VALUE_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDataService::write_device_value, this, _1, _2), AuthenticationPredicates::IS_ADMIN))
, _write_temperature_handler(WRITE_TEMPERATURE_SENSOR_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDataService::write_temperature_sensor, this, _1, _2),
AuthenticationPredicates::IS_ADMIN))
, _write_analog_handler(WRITE_ANALOG_SENSOR_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDataService::write_analog_sensor, this, _1, _2), AuthenticationPredicates::IS_ADMIN)) {
server->on(CORE_DATA_SERVICE_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebDataService::core_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
@@ -51,9 +52,9 @@ WebDataService::WebDataService(AsyncWebServer * server, SecurityManager * securi
_write_value_handler.setMaxContentLength(256);
server->addHandler(&_write_value_handler);
_write_sensor_handler.setMethod(HTTP_POST);
_write_sensor_handler.setMaxContentLength(256);
server->addHandler(&_write_sensor_handler);
_write_temperature_handler.setMethod(HTTP_POST);
_write_temperature_handler.setMaxContentLength(256);
server->addHandler(&_write_temperature_handler);
_write_analog_handler.setMethod(HTTP_POST);
_write_analog_handler.setMaxContentLength(256);
@@ -103,11 +104,7 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
obj["e"] = EMSESP::webEntityService.count_entities(); // number of entities (device values)
}
// sensors stuff
root["s_n"] = Helpers::translated_word(FL_(sensors_device));
root["active_sensors"] = EMSESP::dallassensor_.no_sensors() + (EMSESP::analogsensor_.analog_enabled() ? EMSESP::analogsensor_.no_sensors() : 0);
root["analog_enabled"] = EMSESP::analogsensor_.analog_enabled();
root["connected"] = EMSESP::bus_status() != 2;
root["connected"] = EMSESP::bus_status() != 2;
response->setLength();
request->send(response);
@@ -115,15 +112,14 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
// sensor data - sends back to web
// /sensorData endpoint
// the "sensors" and "analogs" are arrays and must exist
void WebDataService::sensor_data(AsyncWebServerRequest * request) {
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XXLARGE);
JsonObject root = response->getRoot();
// dallas sensors
JsonArray sensors = root.createNestedArray("sensors");
if (EMSESP::dallassensor_.have_sensors()) {
for (const auto & sensor : EMSESP::dallassensor_.sensors()) {
// temperature sensors
JsonArray sensors = root.createNestedArray("ts");
if (EMSESP::temperaturesensor_.have_sensors()) {
for (const auto & sensor : EMSESP::temperaturesensor_.sensors()) {
JsonObject obj = sensors.createNestedObject();
obj["id"] = sensor.id(); // id as string
obj["n"] = sensor.name(); // name
@@ -144,28 +140,23 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) {
}
// analog sensors
JsonArray analogs = root.createNestedArray("analogs");
JsonArray analogs = root.createNestedArray("as");
if (EMSESP::analog_enabled() && EMSESP::analogsensor_.have_sensors()) {
uint8_t count = 0;
char buffer[3];
for (const auto & sensor : EMSESP::analogsensor_.sensors()) {
// don't send if it's marked for removal
if (sensor.type() != AnalogSensor::AnalogType::MARK_DELETED) {
count++;
JsonObject obj = analogs.createNestedObject();
obj["id"] = Helpers::smallitoa(buffer, count); // needed for sorting table
obj["g"] = sensor.gpio();
obj["n"] = sensor.name();
obj["u"] = sensor.uom();
obj["o"] = sensor.offset();
obj["f"] = sensor.factor();
obj["t"] = sensor.type();
JsonObject obj = analogs.createNestedObject();
obj["id"] = ++count; // needed for sorting table
obj["g"] = sensor.gpio();
obj["n"] = sensor.name();
obj["u"] = sensor.uom();
obj["o"] = sensor.offset();
obj["f"] = sensor.factor();
obj["t"] = sensor.type();
if (sensor.type() != AnalogSensor::AnalogType::NOTUSED) {
obj["v"] = Helpers::transformNumFloat(sensor.value(), 0); // is optional and is a float
} else {
obj["v"] = 0; // must have a value for web sorting to work
}
if (sensor.type() != AnalogSensor::AnalogType::NOTUSED) {
obj["v"] = Helpers::transformNumFloat(sensor.value(), 0); // is optional and is a float
} else {
obj["v"] = 0; // must have a value for web sorting to work
}
}
}
@@ -226,7 +217,7 @@ void WebDataService::device_data(AsyncWebServerRequest * request, JsonVariant &
// takes a command and its data value from a specific EMS Device, from the Web
// assumes the service has been checked for admin authentication
void WebDataService::write_value(AsyncWebServerRequest * request, JsonVariant & json) {
void WebDataService::write_device_value(AsyncWebServerRequest * request, JsonVariant & json) {
if (json.is<JsonObject>()) {
JsonObject dv = json["devicevalue"];
uint8_t unique_id = json["id"];
@@ -313,9 +304,9 @@ void WebDataService::write_value(AsyncWebServerRequest * request, JsonVariant &
request->send(response);
}
// takes a dallas sensor name and optional offset from the WebUI and update the customization settings
// via the Dallas service
void WebDataService::write_sensor(AsyncWebServerRequest * request, JsonVariant & json) {
// takes a temperaturesensor name and optional offset from the WebUI and update the customization settings
// via the temperaturesensor service
void WebDataService::write_temperature_sensor(AsyncWebServerRequest * request, JsonVariant & json) {
bool ok = false;
if (json.is<JsonObject>()) {
JsonObject sensor = json;
@@ -329,7 +320,7 @@ void WebDataService::write_sensor(AsyncWebServerRequest * request, JsonVariant &
if (EMSESP::system_.fahrenheit()) {
offset10 = offset / 0.18;
}
ok = EMSESP::dallassensor_.update(id, name, offset10);
ok = EMSESP::temperaturesensor_.update(id, name, offset10);
}
AsyncWebServerResponse * response = request->beginResponse(ok ? 200 : 204);
@@ -337,18 +328,19 @@ void WebDataService::write_sensor(AsyncWebServerRequest * request, JsonVariant &
}
// update the analog record, or create a new one
void WebDataService::write_analog(AsyncWebServerRequest * request, JsonVariant & json) {
void WebDataService::write_analog_sensor(AsyncWebServerRequest * request, JsonVariant & json) {
bool ok = false;
if (json.is<JsonObject>()) {
JsonObject analog = json;
uint8_t gpio = analog["gpio"]; // this is the unique key, the GPIO
std::string name = analog["name"];
double factor = analog["factor"];
double offset = analog["offset"];
uint8_t uom = analog["uom"];
int8_t type = analog["type"];
ok = EMSESP::analogsensor_.update(gpio, name, offset, factor, uom, type);
uint8_t gpio = analog["gpio"];
std::string name = analog["name"];
double factor = analog["factor"];
double offset = analog["offset"];
uint8_t uom = analog["uom"];
int8_t type = analog["type"];
bool deleted = analog["deleted"];
ok = EMSESP::analogsensor_.update(gpio, name, offset, factor, uom, type, deleted);
}
AsyncWebServerResponse * response = request->beginResponse(ok ? 200 : 204);

View File

@@ -1,7 +1,7 @@
/*
* EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2023 Paul Derbyshire
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
@@ -26,9 +26,9 @@
#define SENSOR_DATA_SERVICE_PATH "/rest/sensorData"
// POST
#define WRITE_VALUE_SERVICE_PATH "/rest/writeValue"
#define WRITE_SENSOR_SERVICE_PATH "/rest/writeSensor"
#define WRITE_ANALOG_SERVICE_PATH "/rest/writeAnalog"
#define WRITE_DEVICE_VALUE_SERVICE_PATH "/rest/writeDeviceValue"
#define WRITE_TEMPERATURE_SENSOR_SERVICE_PATH "/rest/writeTemperatureSensor"
#define WRITE_ANALOG_SENSOR_SERVICE_PATH "/rest/writeAnalogSensor"
namespace emsesp {
@@ -47,12 +47,12 @@ class WebDataService {
// POST
void device_data(AsyncWebServerRequest * request, JsonVariant & json);
void write_value(AsyncWebServerRequest * request, JsonVariant & json);
void write_sensor(AsyncWebServerRequest * request, JsonVariant & json);
void write_analog(AsyncWebServerRequest * request, JsonVariant & json);
void write_device_value(AsyncWebServerRequest * request, JsonVariant & json);
void write_temperature_sensor(AsyncWebServerRequest * request, JsonVariant & json);
void write_analog_sensor(AsyncWebServerRequest * request, JsonVariant & json);
void scan_devices(AsyncWebServerRequest * request);
AsyncCallbackJsonWebHandler _device_data_handler, _write_value_handler, _write_sensor_handler, _write_analog_handler;
AsyncCallbackJsonWebHandler _device_data_handler, _write_value_handler, _write_temperature_handler, _write_analog_handler;
};
} // namespace emsesp

View File

@@ -176,13 +176,13 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
settings.pbutton_gpio = root["pbutton_gpio"] | default_pbutton_gpio;
check_flag(prev, settings.pbutton_gpio, ChangeFlags::BUTTON);
// dallas
// temperaturesensor
prev = settings.dallas_gpio;
settings.dallas_gpio = root["dallas_gpio"] | default_dallas_gpio;
check_flag(prev, settings.dallas_gpio, ChangeFlags::DALLAS);
check_flag(prev, settings.dallas_gpio, ChangeFlags::SENSOR);
prev = settings.dallas_parasite;
settings.dallas_parasite = root["dallas_parasite"] | EMSESP_DEFAULT_DALLAS_PARASITE;
check_flag(prev, settings.dallas_parasite, ChangeFlags::DALLAS);
check_flag(prev, settings.dallas_parasite, ChangeFlags::SENSOR);
// shower
prev = settings.shower_timer;
@@ -301,8 +301,8 @@ void WebSettingsService::onUpdate() {
EMSESP::shower_.start();
}
if (WebSettings::has_flags(WebSettings::ChangeFlags::DALLAS)) {
EMSESP::dallassensor_.start();
if (WebSettings::has_flags(WebSettings::ChangeFlags::SENSOR)) {
EMSESP::temperaturesensor_.start();
}
if (WebSettings::has_flags(WebSettings::ChangeFlags::UART)) {

View File

@@ -79,7 +79,7 @@ class WebSettings {
UART = (1 << 0), // 1
SYSLOG = (1 << 1), // 2
ADC = (1 << 2), // 4 - analog
DALLAS = (1 << 3), // 8
SENSOR = (1 << 3), // 8
SHOWER = (1 << 4), // 16
LED = (1 << 5), // 32
BUTTON = (1 << 6), // 64

View File

@@ -124,7 +124,7 @@ void WebStatusService::webStatusService(AsyncWebServerRequest * request) {
root["tx_mode"] = EMSESP::txservice_.tx_mode();
root["uptime"] = EMSbus::bus_uptime();
root["num_devices"] = EMSESP::count_devices(); // excluding Controller
root["num_sensors"] = EMSESP::dallassensor_.no_sensors();
root["num_sensors"] = EMSESP::temperaturesensor_.no_sensors();
root["num_analogs"] = EMSESP::analogsensor_.no_sensors();
JsonArray statsJson = root.createNestedArray("stats");
@@ -148,12 +148,13 @@ void WebStatusService::webStatusService(AsyncWebServerRequest * request) {
statJson["f"] = EMSESP::txservice_.telegram_write_fail_count();
statJson["q"] = EMSESP::txservice_.write_quality();
if (EMSESP::dallassensor_.dallas_enabled()) {
if (EMSESP::temperaturesensor_.sensor_enabled()) {
statJson = statsJson.createNestedObject();
statJson["id"] = 3;
statJson["s"] = EMSESP::dallassensor_.reads();
statJson["f"] = EMSESP::dallassensor_.fails();
statJson["q"] = EMSESP::dallassensor_.reads() == 0 ? 100 : 100 - (uint8_t)((100 * EMSESP::dallassensor_.fails()) / EMSESP::dallassensor_.reads());
statJson["s"] = EMSESP::temperaturesensor_.reads();
statJson["f"] = EMSESP::temperaturesensor_.fails();
statJson["q"] =
EMSESP::temperaturesensor_.reads() == 0 ? 100 : 100 - (uint8_t)((100 * EMSESP::temperaturesensor_.fails()) / EMSESP::temperaturesensor_.reads());
}
if (EMSESP::analog_enabled()) {
statJson = statsJson.createNestedObject();