Merge branch 'dev11' into dev

This commit is contained in:
MichaelDvP
2023-05-10 18:47:07 +02:00
162 changed files with 9895 additions and 7470 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

@@ -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
@@ -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);
@@ -75,40 +76,37 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
// list is already sorted by device type
JsonArray devices = root.createNestedArray("devices");
char buffer[3];
for (const auto & emsdevice : EMSESP::emsdevices) {
// ignore controller
if (emsdevice && (emsdevice->device_type() != EMSdevice::DeviceType::CONTROLLER || emsdevice->count_entities() > 0)) {
JsonObject obj = devices.createNestedObject();
obj["id"] = Helpers::smallitoa(buffer, emsdevice->unique_id()); // a unique id as a string
obj["tn"] = emsdevice->device_type_2_device_name_translated(); // translated device type name
obj["t"] = emsdevice->device_type(); // device type number
obj["b"] = emsdevice->brand_to_char(); // brand
obj["n"] = emsdevice->name(); // name
obj["d"] = emsdevice->device_id(); // deviceid
obj["p"] = emsdevice->product_id(); // productid
obj["v"] = emsdevice->version(); // version
obj["e"] = emsdevice->count_entities(); // number of entities (device values)
obj["id"] = emsdevice->unique_id(); // a unique id
obj["tn"] = emsdevice->device_type_2_device_name_translated(); // translated device type name
obj["t"] = emsdevice->device_type(); // device type number
obj["b"] = emsdevice->brand_to_char(); // brand
obj["n"] = emsdevice->name(); // name
obj["d"] = emsdevice->device_id(); // deviceid
obj["p"] = emsdevice->product_id(); // productid
obj["v"] = emsdevice->version(); // version
obj["e"] = emsdevice->count_entities(); // number of entities (device values)
}
}
// add any custom entities
if (EMSESP::webEntityService.count_entities()) {
JsonObject obj = devices.createNestedObject();
obj["id"] = "99"; // the last unique id as a string
obj["tn"] = "Custom"; // translated device type name
obj["t"] = EMSdevice::DeviceType::CUSTOM; // device type number
obj["b"] = 0; // brand
obj["n"] = Helpers::translated_word(FL_(custom_device)); // name
obj["d"] = 0; // deviceid
obj["p"] = 0; // productid
obj["v"] = 0; // version
obj["e"] = EMSESP::webEntityService.count_entities(); // number of entities (device values)
obj["id"] = 99; // the last unique id
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
obj["n"] = Helpers::translated_word(FL_(custom_device_name)); // name
obj["d"] = 0; // deviceid
obj["p"] = 0; // productid
obj["v"] = 0; // version
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);
@@ -116,15 +114,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
@@ -145,32 +142,29 @@ 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
}
}
}
root["analog_enabled"] = EMSESP::analogsensor_.analog_enabled();
response->setLength();
request->send(response);
}
@@ -227,7 +221,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"];
@@ -314,9 +308,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;
@@ -330,7 +324,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);
@@ -338,18 +332,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

@@ -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
@@ -33,20 +33,22 @@ void WebEntityService::begin() {
EMSESP::logger().info("Starting custom entity service");
}
// this creates the scheduler file, saving it to the FS
// and also calls when the Scheduler web page is refreshed
// this creates the entity file, saving it to the FS
// and also calls when the Entity web page is refreshed
void WebEntity::read(WebEntity & webEntity, JsonObject & root) {
JsonArray entity = root.createNestedArray("entity");
JsonArray entity = root.createNestedArray("entities");
uint8_t counter = 0;
for (const EntityItem & entityItem : webEntity.entityItems) {
JsonObject ei = entity.createNestedObject();
ei["device_id"] = Helpers::hextoa(entityItem.device_id, false);
ei["type_id"] = Helpers::hextoa(entityItem.type_id, false);
ei["offset"] = entityItem.offset;
ei["factor"] = entityItem.factor;
ei["name"] = entityItem.name;
ei["uom"] = entityItem.uom;
ei["val_type"] = entityItem.valuetype;
ei["write"] = entityItem.writeable;
JsonObject ei = entity.createNestedObject();
ei["id"] = counter++; // id is only used to render the table and must be unique
ei["device_id"] = entityItem.device_id;
ei["type_id"] = entityItem.type_id;
ei["offset"] = entityItem.offset;
ei["factor"] = entityItem.factor;
ei["name"] = entityItem.name;
ei["uom"] = entityItem.uom;
ei["value_type"] = entityItem.value_type;
ei["writeable"] = entityItem.writeable;
EMSESP::webEntityService.render_value(ei, entityItem, true, true);
}
}
@@ -59,33 +61,34 @@ StateUpdateResult WebEntity::update(JsonObject & root, WebEntity & webEntity) {
}
webEntity.entityItems.clear();
if (root["entity"].is<JsonArray>()) {
for (const JsonObject ei : root["entity"].as<JsonArray>()) {
auto entityItem = EntityItem();
entityItem.device_id = Helpers::hextoint(ei["device_id"]);
entityItem.type_id = Helpers::hextoint(ei["type_id"]);
entityItem.offset = ei["offset"];
entityItem.factor = ei["factor"];
entityItem.name = ei["name"].as<std::string>();
entityItem.uom = ei["uom"];
entityItem.valuetype = ei["val_type"];
entityItem.writeable = ei["write"];
if (root["entities"].is<JsonArray>()) {
for (const JsonObject ei : root["entities"].as<JsonArray>()) {
auto entityItem = EntityItem();
entityItem.device_id = ei["device_id"]; // send as numeric, will be converted to string in web
entityItem.type_id = ei["type_id"];
entityItem.offset = ei["offset"];
entityItem.factor = ei["factor"];
entityItem.name = ei["name"].as<std::string>();
entityItem.uom = ei["uom"];
entityItem.value_type = ei["value_type"];
entityItem.writeable = ei["writeable"];
if (entityItem.valuetype == DeviceValueType::BOOL) {
entityItem.val = EMS_VALUE_DEFAULT_BOOL;
} else if (entityItem.valuetype == DeviceValueType::INT) {
entityItem.val = EMS_VALUE_DEFAULT_INT;
} else if (entityItem.valuetype == DeviceValueType::UINT) {
entityItem.val = EMS_VALUE_DEFAULT_UINT;
} else if (entityItem.valuetype == DeviceValueType::SHORT) {
entityItem.val = EMS_VALUE_DEFAULT_SHORT;
} else if (entityItem.valuetype == DeviceValueType::USHORT) {
entityItem.val = EMS_VALUE_DEFAULT_USHORT;
} else { // if (entityItem.valuetype == DeviceValueType::ULONG || entityItem.valuetype == DeviceValueType::TIME) {
entityItem.val = EMS_VALUE_DEFAULT_ULONG;
if (entityItem.value_type == DeviceValueType::BOOL) {
entityItem.value = EMS_VALUE_DEFAULT_BOOL;
} else if (entityItem.value_type == DeviceValueType::INT) {
entityItem.value = EMS_VALUE_DEFAULT_INT;
} else if (entityItem.value_type == DeviceValueType::UINT) {
entityItem.value = EMS_VALUE_DEFAULT_UINT;
} else if (entityItem.value_type == DeviceValueType::SHORT) {
entityItem.value = EMS_VALUE_DEFAULT_SHORT;
} else if (entityItem.value_type == DeviceValueType::USHORT) {
entityItem.value = EMS_VALUE_DEFAULT_USHORT;
} else { // if (entityItem.value_type == DeviceValueType::ULONG || entityItem.valuetype == DeviceValueType::TIME) {
entityItem.value = EMS_VALUE_DEFAULT_ULONG;
}
webEntity.entityItems.push_back(entityItem); // add to list
if (entityItem.writeable) {
Command::add(
EMSdevice::DeviceType::CUSTOM,
@@ -106,7 +109,7 @@ bool WebEntityService::command_setvalue(const char * value, const std::string na
EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; });
for (EntityItem & entityItem : *entityItems) {
if (entityItem.name == name) {
if (entityItem.valuetype == DeviceValueType::BOOL) {
if (entityItem.value_type == DeviceValueType::BOOL) {
bool v;
if (!Helpers::value2bool(value, v)) {
return false;
@@ -118,9 +121,9 @@ bool WebEntityService::command_setvalue(const char * value, const std::string na
return false;
}
int v = f / entityItem.factor;
if (entityItem.valuetype == DeviceValueType::UINT || entityItem.valuetype == DeviceValueType::INT) {
if (entityItem.value_type == DeviceValueType::UINT || entityItem.value_type == DeviceValueType::INT) {
EMSESP::send_write_request(entityItem.type_id, entityItem.device_id, entityItem.offset, v, 0);
} else if (entityItem.valuetype == DeviceValueType::USHORT || entityItem.valuetype == DeviceValueType::SHORT) {
} else if (entityItem.value_type == DeviceValueType::USHORT || entityItem.value_type == DeviceValueType::SHORT) {
uint8_t v1[2] = {(uint8_t)(v >> 8), (uint8_t)(v & 0xFF)};
EMSESP::send_write_request(entityItem.type_id, entityItem.device_id, entityItem.offset, v1, 2, 0);
} else {
@@ -128,6 +131,7 @@ bool WebEntityService::command_setvalue(const char * value, const std::string na
EMSESP::send_write_request(entityItem.type_id, entityItem.device_id, entityItem.offset, v1, 3, 0);
}
}
publish_single(entityItem);
if (EMSESP::mqtt_.get_publish_onchange(0)) {
publish();
@@ -142,44 +146,44 @@ bool WebEntityService::command_setvalue(const char * value, const std::string na
void WebEntityService::render_value(JsonObject & output, EntityItem entity, const bool useVal, const bool web) {
char payload[12];
std::string name = useVal ? "value" : entity.name;
switch (entity.valuetype) {
switch (entity.value_type) {
case DeviceValueType::BOOL:
if ((uint8_t)entity.val != EMS_VALUE_BOOL_NOTSET) {
if ((uint8_t)entity.value != EMS_VALUE_BOOL_NOTSET) {
if (web) {
output[name] = Helpers::render_boolean(payload, (uint8_t)entity.val, true);
output[name] = Helpers::render_boolean(payload, (uint8_t)entity.value, true);
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
output[name] = (uint8_t)entity.val ? true : false;
output[name] = (uint8_t)entity.value ? true : false;
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
output[name] = (uint8_t)entity.val ? 1 : 0;
output[name] = (uint8_t)entity.value ? 1 : 0;
} else {
output[name] = Helpers::render_boolean(payload, (uint8_t)entity.val);
output[name] = Helpers::render_boolean(payload, (uint8_t)entity.value);
}
}
break;
case DeviceValueType::INT:
if ((int8_t)entity.val != EMS_VALUE_INT_NOTSET) {
output[name] = serialized(Helpers::render_value(payload, entity.factor * (int8_t)entity.val, 2));
if ((int8_t)entity.value != EMS_VALUE_INT_NOTSET) {
output[name] = serialized(Helpers::render_value(payload, entity.factor * (int8_t)entity.value, 2));
}
break;
case DeviceValueType::UINT:
if ((uint8_t)entity.val != EMS_VALUE_UINT_NOTSET) {
output[name] = serialized(Helpers::render_value(payload, entity.factor * (uint8_t)entity.val, 2));
if ((uint8_t)entity.value != EMS_VALUE_UINT_NOTSET) {
output[name] = serialized(Helpers::render_value(payload, entity.factor * (uint8_t)entity.value, 2));
}
break;
case DeviceValueType::SHORT:
if ((int16_t)entity.val != EMS_VALUE_SHORT_NOTSET) {
output[name] = serialized(Helpers::render_value(payload, entity.factor * (int16_t)entity.val, 2));
if ((int16_t)entity.value != EMS_VALUE_SHORT_NOTSET) {
output[name] = serialized(Helpers::render_value(payload, entity.factor * (int16_t)entity.value, 2));
}
break;
case DeviceValueType::USHORT:
if ((uint16_t)entity.val != EMS_VALUE_USHORT_NOTSET) {
output[name] = serialized(Helpers::render_value(payload, entity.factor * (uint16_t)entity.val, 2));
if ((uint16_t)entity.value != EMS_VALUE_USHORT_NOTSET) {
output[name] = serialized(Helpers::render_value(payload, entity.factor * (uint16_t)entity.value, 2));
}
break;
case DeviceValueType::ULONG:
case DeviceValueType::TIME:
if (entity.val != EMS_VALUE_ULONG_NOTSET) {
output[name] = serialized(Helpers::render_value(payload, entity.factor * entity.val, 2));
if (entity.value != EMS_VALUE_ULONG_NOTSET) {
output[name] = serialized(Helpers::render_value(payload, entity.factor * entity.value, 2));
}
break;
default:
@@ -334,6 +338,7 @@ uint8_t WebEntityService::count_entities() {
if (entityItems->size() == 0) {
return 0;
}
DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE);
JsonObject output = doc.to<JsonObject>();
uint8_t count = 0;
@@ -347,6 +352,7 @@ uint8_t WebEntityService::count_entities() {
// send to dashboard, msgpack don't like serialized, use number
void WebEntityService::generate_value_web(JsonObject & output) {
EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; });
output["label"] = (std::string) "Custom Entities";
JsonArray data = output.createNestedArray("data");
uint8_t index = 0;
@@ -357,39 +363,40 @@ void WebEntityService::generate_value_web(JsonObject & output) {
if (entity.writeable) {
obj["c"] = entity.name;
}
switch (entity.valuetype) {
switch (entity.value_type) {
case DeviceValueType::BOOL: {
char s[12];
obj["v"] = Helpers::render_boolean(s, (uint8_t)entity.val, true);
obj["v"] = Helpers::render_boolean(s, (uint8_t)entity.value, true);
JsonArray l = obj.createNestedArray("l");
l.add(Helpers::render_boolean(s, false, true));
l.add(Helpers::render_boolean(s, true, true));
break;
}
case DeviceValueType::INT:
if ((int8_t)entity.val != EMS_VALUE_INT_NOTSET) {
obj["v"] = Helpers::transformNumFloat(entity.factor * (int8_t)entity.val, 0);
if ((int8_t)entity.value != EMS_VALUE_INT_NOTSET) {
obj["v"] = Helpers::transformNumFloat(entity.factor * (int8_t)entity.value, 0);
}
break;
case DeviceValueType::UINT:
if ((uint8_t)entity.val != EMS_VALUE_UINT_NOTSET) {
obj["v"] = Helpers::transformNumFloat(entity.factor * (uint8_t)entity.val, 0);
if ((uint8_t)entity.value != EMS_VALUE_UINT_NOTSET) {
obj["v"] = Helpers::transformNumFloat(entity.factor * (uint8_t)entity.value, 0);
}
break;
case DeviceValueType::SHORT:
if ((int16_t)entity.val != EMS_VALUE_SHORT_NOTSET) {
obj["v"] = Helpers::transformNumFloat(entity.factor * (int16_t)entity.val, 0);
if ((int16_t)entity.value != EMS_VALUE_SHORT_NOTSET) {
obj["v"] = Helpers::transformNumFloat(entity.factor * (int16_t)entity.value, 0);
}
break;
case DeviceValueType::USHORT:
if ((uint16_t)entity.val != EMS_VALUE_USHORT_NOTSET) {
obj["v"] = Helpers::transformNumFloat(entity.factor * (uint16_t)entity.val, 0);
if ((uint16_t)entity.value != EMS_VALUE_USHORT_NOTSET) {
obj["v"] = Helpers::transformNumFloat(entity.factor * (uint16_t)entity.value, 0);
}
break;
case DeviceValueType::ULONG:
case DeviceValueType::TIME:
if (entity.val != EMS_VALUE_ULONG_NOTSET) {
obj["v"] = Helpers::transformNumFloat(entity.factor * entity.val, 0);
if (entity.value != EMS_VALUE_ULONG_NOTSET) {
obj["v"] = Helpers::transformNumFloat(entity.factor * entity.value, 0);
}
break;
default:
@@ -420,13 +427,13 @@ bool WebEntityService::get_value(std::shared_ptr<const Telegram> telegram) {
const uint8_t len[] = {1, 1, 1, 2, 2, 3, 3};
for (auto & entity : *entityItems) {
if (telegram->type_id == entity.type_id && telegram->src == entity.device_id && telegram->offset <= entity.offset
&& (telegram->offset + telegram->message_length) >= (entity.offset + len[entity.valuetype])) {
uint32_t val = 0;
for (uint8_t i = 0; i < len[entity.valuetype]; i++) {
val = (val << 8) + telegram->message_data[i + entity.offset - telegram->offset];
&& (telegram->offset + telegram->message_length) >= (entity.offset + len[entity.value_type])) {
uint32_t value = 0;
for (uint8_t i = 0; i < len[entity.value_type]; i++) {
value = (value << 8) + telegram->message_data[i + entity.offset - telegram->offset];
}
if (val != entity.val) {
entity.val = val;
if (value != entity.value) {
entity.value = value;
if (Mqtt::publish_single()) {
publish_single(entity);
} else if (EMSESP::mqtt_.get_publish_onchange(0)) {

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
@@ -21,21 +21,22 @@
#define WebEntityService_h
#define EMSESP_ENTITY_FILE "/config/emsespEntity.json"
#define EMSESP_ENTITY_SERVICE_PATH "/rest/entity" // GET and POST
#define EMSESP_ENTITY_SERVICE_PATH "/rest/entities" // GET and POST
namespace emsesp {
class EntityItem {
public:
uint8_t id;
uint8_t device_id;
uint16_t type_id;
uint8_t offset;
int8_t valuetype;
int8_t value_type;
uint8_t uom;
std::string name;
double factor;
bool writeable;
uint32_t val;
uint32_t value;
};
class WebEntity {
@@ -66,7 +67,7 @@ class WebEntityService : public StatefulService<WebEntity> {
HttpEndpoint<WebEntity> _httpEndpoint;
FSPersistence<WebEntity> _fsPersistence;
std::list<EntityItem> * entityItems; // pointer to the list of schedule events
std::list<EntityItem> * entityItems; // pointer to the list of entity items
bool ha_registered_ = false;
};

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
@@ -56,7 +56,7 @@ StateUpdateResult WebScheduler::update(JsonObject & root, WebScheduler & webSche
#ifdef EMSESP_STANDALONE
// invoke some fake data for testing
const char * json =
"{[{\"id\":\"01\",\"active\":true,\"flags\":31,\"time\": \"07:30\",\"cmd\": \"hc1/mode\",\"value\": \"day\",\"name\": \"turn on central heating\"}]}";
"{[{\"id\":1,\"active\":true,\"flags\":31,\"time\": \"07:30\",\"cmd\": \"hc1/mode\",\"value\": \"day\",\"name\": \"turn on central heating\"}]}";
StaticJsonDocument<500> doc;
deserializeJson(doc, json);
root = doc.as<JsonObject>();

View File

@@ -29,7 +29,6 @@ namespace emsesp {
class ScheduleItem {
public:
std::string id; // unqiue id
boolean active;
uint8_t flags;
uint16_t elapsed_min; // total mins from 00:00

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();