add test data

This commit is contained in:
Proddy
2024-01-21 18:27:58 +01:00
parent 2a3838771a
commit 79d7142e5f
6 changed files with 155 additions and 52 deletions

View File

@@ -307,13 +307,19 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "general") { if (command == "general") {
shell.printfln("Testing adding a boiler, thermostat and sensors..."); shell.printfln("Testing adding a boiler, thermostat, all sensors, scheduler and custom entities...");
test("general"); test("general");
// add sensors // add analog and temperatire sensors
emsesp::EMSESP::analogsensor_.test(); emsesp::EMSESP::analogsensor_.test();
emsesp::EMSESP::temperaturesensor_.test(); emsesp::EMSESP::temperaturesensor_.test();
// scheduler
EMSESP::webSchedulerService.test();
// custom entities
EMSESP::webCustomEntityService.test();
// shell.invoke_command("show devices"); // shell.invoke_command("show devices");
// shell.invoke_command("show values"); // shell.invoke_command("show values");
shell.invoke_command("call system allvalues"); shell.invoke_command("call system allvalues");
@@ -331,16 +337,40 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
} }
if (command == "custom_entities") { if (command == "custom_entities") {
shell.printfln("custom entities..."); shell.printfln("Adding custom entities...");
test("general");
// add some dummy entities
EMSESP::webCustomEntityService.test();
#ifdef EMSESP_STANDALONE #ifdef EMSESP_STANDALONE
AsyncWebServerRequest request; AsyncWebServerRequest request;
request.method(HTTP_GET); request.method(HTTP_GET);
request.url("/api/custom"); request.url("/api/custom");
request.url("/api/custom/boiler_flowtemp");
request.url("/api/custom/boiler_flowtemp2");
EMSESP::webAPIService.webAPIService_get(&request); EMSESP::webAPIService.webAPIService_get(&request);
request.url("/api/custom/test_custom");
EMSESP::webAPIService.webAPIService_get(&request);
request.url("/api/custom/test_read_only");
EMSESP::webAPIService.webAPIService_get(&request);
request.url("/api/custom/test_ram");
EMSESP::webAPIService.webAPIService_get(&request);
shell.invoke_command("call custom info");
#endif
ok = true;
}
if (command == "scheduler") {
shell.printfln("Adding Scheduler items...");
// add some dummy entities
EMSESP::webSchedulerService.test();
#ifdef EMSESP_STANDALONE
AsyncWebServerRequest request;
request.method(HTTP_GET);
request.url("/api/scheduler");
EMSESP::webAPIService.webAPIService_get(&request);
shell.invoke_command("call scheduler info");
#endif #endif
ok = true; ok = true;
} }
@@ -574,7 +604,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
test("boiler"); test("boiler");
test("thermostat"); test("thermostat");
JsonDocument doc; // some absurd high number JsonDocument doc;
for (const auto & emsdevice : EMSESP::emsdevices) { for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice) { if (emsdevice) {
doc.clear(); doc.clear();
@@ -784,25 +814,26 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
ok = true; ok = true;
} }
if (command == "custom") { if (command == "customization") {
shell.printfln("Testing custom entities"); shell.printfln("Testing customization renaming entity");
Mqtt::ha_enabled(true); Mqtt::ha_enabled(true);
// Mqtt::send_response(false); // Mqtt::send_response(false);
test("thermostat"); test("thermostat");
// before
// shell.invoke_command("call thermostat seltemp"); // shell.invoke_command("call thermostat seltemp");
// shell.invoke_command("call system publish"); // shell.invoke_command("call system publish");
// toggle mode // find thermostat
for (const auto & emsdevice : EMSESP::emsdevices) { for (const auto & emsdevice : EMSESP::emsdevices) {
Serial.print("Custom: "); if (emsdevice->unique_id() == 1) {
Serial.print(emsdevice->device_type_name()); Serial.println();
Serial.print(" uniqueid="); Serial.print("Custom: ");
Serial.println(emsdevice->unique_id()); Serial.print(emsdevice->device_type_name());
Serial.print(" uniqueid=");
if (emsdevice->unique_id() == 1) { // thermostat Serial.println(emsdevice->unique_id());
std::string a = "00hc1/seltemp|new name>5<52"; std::string a = "00hc1/seltemp|new name>5<52";
emsdevice->setCustomizationEntity(a); emsdevice->setCustomizationEntity(a);
break; break;

View File

@@ -52,11 +52,12 @@ namespace emsesp {
// #define EMSESP_DEBUG_DEFAULT "api_values" // #define EMSESP_DEBUG_DEFAULT "api_values"
// #define EMSESP_DEBUG_DEFAULT "mqtt_post" // #define EMSESP_DEBUG_DEFAULT "mqtt_post"
// #define EMSESP_DEBUG_DEFAULT "api_wwmode" // #define EMSESP_DEBUG_DEFAULT "api_wwmode"
// #define EMSESP_DEBUG_DEFAULT "custom" // #define EMSESP_DEBUG_DEFAULT "customization"
// #define EMSESP_DEBUG_DEFAULT "entity_dump" // #define EMSESP_DEBUG_DEFAULT "entity_dump"
// #define EMSESP_DEBUG_DEFAULT "memory" // #define EMSESP_DEBUG_DEFAULT "memory"
// #define EMSESP_DEBUG_DEFAULT "coldshot" // #define EMSESP_DEBUG_DEFAULT "coldshot"
// #define EMSESP_DEBUG_DEFAULT "custom_entities" // #define EMSESP_DEBUG_DEFAULT "custom_entities"
// #define EMSESP_DEBUG_DEFAULT "scheduler"
// #define EMSESP_DEBUG_DEFAULT "heat_exchange" // #define EMSESP_DEBUG_DEFAULT "heat_exchange"
class Test { class Test {

View File

@@ -36,7 +36,7 @@ WebCustomEntityService::WebCustomEntityService(AsyncWebServer * server, FS * fs,
// load the settings when the service starts // load the settings when the service starts
void WebCustomEntityService::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
} }
@@ -61,31 +61,17 @@ void WebCustomEntity::read(WebCustomEntity & webEntity, JsonObject root) {
} }
} }
// call on initialization and also when the Entity web page is updated // call on initialization and also when the Entity web page is updated/saved
// this loads the data into the internal class // this loads the data into the internal class
StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & webCustomEntity) { StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & webCustomEntity) {
#ifdef EMSESP_STANDALONE // reset everything to start fresh
// 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
JsonDocument doc;
deserializeJson(doc, json);
root = doc.as<JsonObject>();
Serial.print(COLOR_BRIGHT_MAGENTA);
Serial.print(" Using fake custom entity file: ");
serializeJson(root, Serial);
Serial.println(COLOR_RESET);
#endif
for (CustomEntityItem & entityItem : webCustomEntity.customEntityItems) { 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());
} }
webCustomEntity.customEntityItems.clear(); webCustomEntity.customEntityItems.clear();
EMSESP::webCustomEntityService.ha_reset(); EMSESP::webCustomEntityService.ha_reset();
// rebuild the list
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 = CustomEntityItem(); auto entityItem = CustomEntityItem();
@@ -120,10 +106,13 @@ StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & web
} else if (entityItem.value_type == DeviceValueType::ULONG || entityItem.value_type == DeviceValueType::TIME) { } else if (entityItem.value_type == DeviceValueType::ULONG || entityItem.value_type == DeviceValueType::TIME) {
entityItem.value = EMS_VALUE_DEFAULT_ULONG; entityItem.value = EMS_VALUE_DEFAULT_ULONG;
} }
if (entityItem.factor == 0) { if (entityItem.factor == 0) {
entityItem.factor = 1; entityItem.factor = 1;
} }
webCustomEntity.customEntityItems.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,
@@ -262,15 +251,16 @@ void WebCustomEntityService::show_values(JsonObject output) {
} }
} }
// process json output for info/commands and value_info // process json output for info/commands and value_info
bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd) { bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd) {
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; }); EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; });
// if it's commands...
if (Helpers::toLower(cmd) == F_(commands)) { if (Helpers::toLower(cmd) == F_(commands)) {
output[F_(info)] = Helpers::translated_word(FL_(info_cmd)); output[F_(info)] = Helpers::translated_word(FL_(info_cmd));
output[F_(commands)] = Helpers::translated_word(FL_(commands_cmd)); output[F_(commands)] = Helpers::translated_word(FL_(commands_cmd));
for (const auto & entity : *customEntityItems) { for (const auto & entity : *customEntityItems) {
output[entity.name] = "custom entitiy"; output[entity.name] = "custom entity";
} }
return true; return true;
} }
@@ -281,6 +271,7 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
return true; return true;
} }
// if it's info or values...
if (strlen(cmd) == 0 || Helpers::toLower(cmd) == F_(values) || Helpers::toLower(cmd) == F_(info)) { if (strlen(cmd) == 0 || Helpers::toLower(cmd) == F_(values) || Helpers::toLower(cmd) == F_(info)) {
// list all names // list all names
for (const CustomEntityItem & entity : *customEntityItems) { for (const CustomEntityItem & entity : *customEntityItems) {
@@ -350,12 +341,14 @@ void WebCustomEntityService::publish_single(const CustomEntityItem & entity) {
if (!Mqtt::enabled() || !Mqtt::publish_single()) { if (!Mqtt::enabled() || !Mqtt::publish_single()) {
return; return;
} }
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
if (Mqtt::publish_single2cmd()) { if (Mqtt::publish_single2cmd()) {
snprintf(topic, sizeof(topic), "%s/%s", "custom", entity.name.c_str()); snprintf(topic, sizeof(topic), "%s/%s", "custom", entity.name.c_str());
} else { } else {
snprintf(topic, sizeof(topic), "%s/%s", "custom_data", entity.name.c_str()); snprintf(topic, sizeof(topic), "%s/%s", "custom_data", entity.name.c_str());
} }
JsonDocument doc; JsonDocument doc;
JsonObject output = doc.to<JsonObject>(); JsonObject output = doc.to<JsonObject>();
render_value(output, entity, true); render_value(output, entity, true);
@@ -473,6 +466,7 @@ uint8_t WebCustomEntityService::count_entities() {
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;
} }
@@ -482,6 +476,7 @@ uint8_t WebCustomEntityService::has_commands() {
for (const CustomEntityItem & entity : *customEntityItems) { for (const CustomEntityItem & entity : *customEntityItems) {
count += entity.writeable ? 1 : 0; count += entity.writeable ? 1 : 0;
} }
return count; return count;
} }
@@ -547,6 +542,7 @@ void WebCustomEntityService::generate_value_web(JsonObject output) {
default: default:
break; break;
} }
// show only entities with value or command // show only entities with value or command
if (!obj.containsKey("v") && !obj.containsKey("c")) { if (!obj.containsKey("v") && !obj.containsKey("c")) {
data.remove(index); data.remove(index);
@@ -560,6 +556,7 @@ void WebCustomEntityService::generate_value_web(JsonObject output) {
void WebCustomEntityService::fetch() { void WebCustomEntityService::fetch() {
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; }); 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 : *customEntityItems) { for (auto & entity : *customEntityItems) {
if (entity.device_id > 0 && entity.type_id > 0) { // ths excludes also RAM type if (entity.device_id > 0 && entity.type_id > 0) { // ths excludes also RAM type
bool needFetch = true; bool needFetch = true;
@@ -615,11 +612,64 @@ bool WebCustomEntityService::get_value(std::shared_ptr<const Telegram> telegram)
// EMSESP::logger().debug("custom entity %s received with value %d", entity.name.c_str(), (int)entity.val); // EMSESP::logger().debug("custom entity %s received with value %d", entity.name.c_str(), (int)entity.val);
} }
} }
if (has_change) { if (has_change) {
publish(); publish();
return true; return true;
} }
return false; return false;
} }
// hard coded tests
#ifdef EMSESP_TEST
void WebCustomEntityService::test() {
update(
[&](WebCustomEntity & webCustomEntity) {
// test 1
auto entityItem = CustomEntityItem();
entityItem.ram = 0;
entityItem.device_id = 8;
entityItem.type_id = 24;
entityItem.offset = 0;
entityItem.factor = 1;
entityItem.name = "test_custom";
entityItem.uom = 1;
entityItem.value_type = 1;
entityItem.writeable = true;
entityItem.data = "70";
webCustomEntity.customEntityItems.push_back(entityItem);
// test 2
entityItem.ram = 0;
entityItem.device_id = 8;
entityItem.type_id = 18;
entityItem.offset = 0;
entityItem.factor = 1;
entityItem.name = "test_read_only";
entityItem.uom = 3;
entityItem.value_type = 2;
entityItem.writeable = false;
entityItem.data = "12";
webCustomEntity.customEntityItems.push_back(entityItem);
// test 2
entityItem.ram = 1;
entityItem.device_id = 0;
entityItem.type_id = 0;
entityItem.offset = 0;
entityItem.factor = 1;
entityItem.name = "test_ram";
entityItem.uom = 0;
entityItem.value_type = 8;
entityItem.writeable = true;
entityItem.data = "14";
webCustomEntity.customEntityItems.push_back(entityItem);
return StateUpdateResult::CHANGED; // persist the changes
},
"local");
}
#endif
} // namespace emsesp } // namespace emsesp

View File

@@ -38,7 +38,7 @@ class CustomEntityItem {
bool writeable; bool writeable;
uint32_t value; uint32_t value;
std::string data; std::string data;
uint8_t ram; uint8_t ram;
}; };
class WebCustomEntity { class WebCustomEntity {
@@ -70,6 +70,10 @@ class WebCustomEntityService : public StatefulService<WebCustomEntity> {
ha_registered_ = false; ha_registered_ = false;
} }
#if defined(EMSESP_TEST)
void test();
#endif
private: private:
HttpEndpoint<WebCustomEntity> _httpEndpoint; HttpEndpoint<WebCustomEntity> _httpEndpoint;
FSPersistence<WebCustomEntity> _fsPersistence; FSPersistence<WebCustomEntity> _fsPersistence;

View File

@@ -54,26 +54,15 @@ void WebScheduler::read(WebScheduler & webScheduler, JsonObject root) {
// call on initialization and also when the Schedule web page is saved // call on initialization and also when the Schedule web page is saved
// this loads the data into the internal class // this loads the data into the internal class
StateUpdateResult WebScheduler::update(JsonObject root, WebScheduler & webScheduler) { StateUpdateResult WebScheduler::update(JsonObject root, WebScheduler & webScheduler) {
#ifdef EMSESP_STANDALONE
// invoke some fake data for testing
const char * json =
"{\"schedule\": [{\"id\":1,\"active\":true,\"flags\":31,\"time\": \"07:30\",\"cmd\": \"hc1mode\",\"value\": \"day\",\"name\": \"turn on "
"central heating\"}]}";
JsonDocument doc;
deserializeJson(doc, json);
root = doc.as<JsonObject>();
Serial.print(COLOR_BRIGHT_MAGENTA);
Serial.print(" Using fake scheduler file: ");
serializeJson(root, Serial);
Serial.println(COLOR_RESET);
#endif
for (ScheduleItem & scheduleItem : webScheduler.scheduleItems) { for (ScheduleItem & scheduleItem : webScheduler.scheduleItems) {
Command::erase_command(EMSdevice::DeviceType::SCHEDULER, scheduleItem.name.c_str()); Command::erase_command(EMSdevice::DeviceType::SCHEDULER, scheduleItem.name.c_str());
} }
// reset the list
webScheduler.scheduleItems.clear(); webScheduler.scheduleItems.clear();
EMSESP::webSchedulerService.ha_reset(); EMSESP::webSchedulerService.ha_reset();
// build up the list of schedule items
if (root["schedule"].is<JsonArray>()) { if (root["schedule"].is<JsonArray>()) {
for (const JsonObject schedule : root["schedule"].as<JsonArray>()) { for (const JsonObject schedule : root["schedule"].as<JsonArray>()) {
// create each schedule item, overwriting any previous settings // create each schedule item, overwriting any previous settings
@@ -425,4 +414,28 @@ void WebSchedulerService::loop() {
} }
} }
// hard coded tests
#if defined(EMSESP_TEST)
void WebSchedulerService::test() {
update(
[&](WebScheduler & webScheduler) {
// test 1
auto si = ScheduleItem();
si.active = true;
si.flags = 1;
si.time = "12:00";
si.cmd = "test";
si.value = "10";
si.name = "test_scheduler";
si.elapsed_min = 0;
si.retry_cnt = 0xFF; // no startup retries
webScheduler.scheduleItems.push_back(si);
return StateUpdateResult::CHANGED; // persist the changes
},
"local");
}
#endif
} // namespace emsesp } // namespace emsesp

View File

@@ -62,6 +62,10 @@ class WebSchedulerService : public StatefulService<WebScheduler> {
ha_registered_ = false; ha_registered_ = false;
} }
#if defined(EMSESP_TEST)
void test();
#endif
// make all functions public so we can test in the debug and standalone mode // make all functions public so we can test in the debug and standalone mode
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
private: private: