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

@@ -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)) {