From 040954bb7084992c4fa8ea18331a0bd48e3e5357 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 28 Jan 2024 16:36:18 +0100 Subject: [PATCH] tidy up commands for temperature sensor --- src/command.cpp | 88 ++++++++++++--------------- src/emsesp.cpp | 19 +++--- src/system.cpp | 3 +- src/temperaturesensor.cpp | 104 +++++++++++++------------------- src/temperaturesensor.h | 6 +- src/test/test.cpp | 16 +++++ src/test/test.h | 4 +- src/version.h | 2 +- src/web/WebAPIService.cpp | 9 +-- src/web/WebSchedulerService.cpp | 1 + 10 files changed, 119 insertions(+), 133 deletions(-) diff --git a/src/command.cpp b/src/command.cpp index f64deefd4..93e472484 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -364,10 +364,10 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char * // report back. If not OK show output from error, other return the HTTP code if (return_code != CommandRet::OK) { - if (value == nullptr) { + if ((value == nullptr) || (strlen(value) == 0)) { LOG_ERROR("Command '%s' failed with code: %d", cmd, return_code); } else { - LOG_ERROR("Command '%s:%s' failed with code: %d", cmd, value, return_code); + LOG_ERROR("Command '%s/%s' failed with code: %d", cmd, value, return_code); } return message(return_code, "callback function failed", output); } @@ -442,7 +442,7 @@ bool Command::list(const uint8_t device_type, JsonObject output) { return false; } - // create a list of commands, sort them + // create a list of commands we have registered, and sort them std::list sorted_cmds; for (const auto & cf : cmdfunctions_) { if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN)) { @@ -451,6 +451,12 @@ bool Command::list(const uint8_t device_type, JsonObject output) { } sorted_cmds.sort(); + // force add info and commands for those non-EMS devices + if (device_type == EMSdevice::DeviceType::TEMPERATURESENSOR) { + output[F_(info)] = Helpers::translated_word(FL_(info_cmd)); + output[F_(commands)] = Helpers::translated_word(FL_(commands_cmd)); + } + for (const auto & cl : sorted_cmds) { for (const auto & cf : cmdfunctions_) { if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN) && cf.description_ && (cl == std::string(cf.cmd_))) { @@ -475,14 +481,24 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo return; } - // create list of command, and sort + // create list of commands we have registered std::list sorted_cmds; for (const auto & cf : cmdfunctions_) { if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN)) { sorted_cmds.push_back((cf.cmd_)); } } - sorted_cmds.sort(); + + // non EMS devices always have an info and commands command + bool show_info = (device_type == EMSdevice::DeviceType::TEMPERATURESENSOR || device_type == EMSdevice::DeviceType::ANALOGSENSOR + || device_type == EMSdevice::DeviceType::SCHEDULER || device_type == EMSdevice::DeviceType::CUSTOM); + + if (!verbose && show_info) { + sorted_cmds.push_back(F_(info)); + sorted_cmds.push_back(F_(commands)); + } + + sorted_cmds.sort(); // sort them // if not in verbose mode, just print them on a single line and exit if (!verbose) { @@ -495,7 +511,16 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo } // verbose mode - shell.println(); + shell.printfln("\n%s%s %s:%s", COLOR_BOLD_ON, COLOR_YELLOW, EMSdevice::device_type_2_device_name(device_type), COLOR_RESET); + + // we hard code 'info' and 'commmands' commands so print them first + if (show_info) { + shell.printf(" info:\t\t\t\t%slists all values %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN); + shell.println(COLOR_RESET); + shell.printf(" commands:\t\t\t%slists all commands %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN); + shell.println(COLOR_RESET); + } + for (const auto & cl : sorted_cmds) { // find and print the description for (const auto & cf : cmdfunctions_) { @@ -530,8 +555,6 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo } shell.println(); } - - shell.println(); } // see if a device_type is active and has associated commands @@ -599,69 +622,32 @@ void Command::show_devices(uuid::console::Shell & shell) { shell.println(); } -// output list of all commands to console +// 'show commmands' : output list of all commands to console // calls show with verbose mode set void Command::show_all(uuid::console::Shell & shell) { shell.printfln("Showing all available commands (%s*%s=authentication not required):", COLOR_BRIGHT_GREEN, COLOR_RESET); - // show system first - shell.print(COLOR_BOLD_ON); - shell.print(COLOR_YELLOW); - shell.printf(" %s: ", EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::SYSTEM)); - shell.print(COLOR_RESET); + // show system ones first show(shell, EMSdevice::DeviceType::SYSTEM, true); - - // show Custom Entities - shell.print(COLOR_BOLD_ON); - shell.print(COLOR_YELLOW); - shell.printf(" %s: ", EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::CUSTOM)); - shell.println(COLOR_RESET); - // TODO to remove later? - shell.printf(" info:\t\t\t\t%slists all values %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN); - shell.println(COLOR_RESET); - shell.printf(" commands:\t\t\t%slists all commands %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN); - shell.print(COLOR_RESET); show(shell, EMSdevice::DeviceType::CUSTOM, true); - - // show scheduler - shell.print(COLOR_BOLD_ON); - shell.print(COLOR_YELLOW); - shell.printf(" %s: ", EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::SCHEDULER)); - shell.println(COLOR_RESET); - // TODO to remove later? - shell.printf(" info:\t\t\t\t%slists all values %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN); - shell.println(COLOR_RESET); - shell.printf(" commands:\t\t\t%slists all commands %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN); - shell.print(COLOR_RESET); show(shell, EMSdevice::DeviceType::SCHEDULER, true); - // show sensors + // then sensors if (EMSESP::sensor_enabled()) { - shell.print(COLOR_BOLD_ON); - shell.print(COLOR_YELLOW); - shell.printf(" %s: ", EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::TEMPERATURESENSOR)); - shell.print(COLOR_RESET); show(shell, EMSdevice::DeviceType::TEMPERATURESENSOR, true); } - if (EMSESP::analog_enabled()) { - shell.print(COLOR_BOLD_ON); - shell.print(COLOR_YELLOW); - shell.printf(" %s: ", EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::ANALOGSENSOR)); - shell.print(COLOR_RESET); show(shell, EMSdevice::DeviceType::ANALOGSENSOR, true); } - // do this in the order of factory classes to keep a consistent order when displaying + // now EMS devices, do this in the order of factory classes to keep a consistent order when displaying for (const auto & device_class : EMSFactory::device_handlers()) { if (Command::device_has_commands(device_class.first)) { - shell.print(COLOR_BOLD_ON); - shell.print(COLOR_YELLOW); - shell.printf(" %s: ", EMSdevice::device_type_2_device_name(device_class.first)); - shell.print(COLOR_RESET); show(shell, device_class.first, true); } } + + shell.println(); } // Extract only the path component from the passed URI and normalized it diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 75ce6a14f..5b1faeb25 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -659,9 +659,10 @@ void EMSESP::publish_response(std::shared_ptr telegram) { buffer = nullptr; } -// builds json with the detail of each value, -// for a specific EMS device type or the sensors, scheduler and custom entities +// builds json with the detail of each value, for an EMS device +// for other types like sensors, scheduler, custom entities it will process single commands like 'info', 'values', 'commands'... bool EMSESP::get_device_value_info(JsonObject root, const char * cmd, const int8_t id, const uint8_t devicetype) { + // check first for EMS devices for (const auto & emsdevice : emsdevices) { if (emsdevice->device_type() == devicetype) { if (emsdevice->get_value_info(root, cmd, id)) { @@ -670,24 +671,24 @@ bool EMSESP::get_device_value_info(JsonObject root, const char * cmd, const int8 } } - // specific for the temperaturesensor + // temperaturesensor if (devicetype == DeviceType::TEMPERATURESENSOR) { - return EMSESP::temperaturesensor_.get_value_info(root, cmd, id); + return temperaturesensor_.get_value_info(root, cmd, id); } // analog sensor if (devicetype == DeviceType::ANALOGSENSOR) { - return EMSESP::analogsensor_.get_value_info(root, cmd, id); + return analogsensor_.get_value_info(root, cmd, id); } // scheduler if (devicetype == DeviceType::SCHEDULER) { - return EMSESP::webSchedulerService.get_value_info(root, cmd); + return webSchedulerService.get_value_info(root, cmd); } // custom entities if (devicetype == DeviceType::CUSTOM) { - return EMSESP::webCustomEntityService.get_value_info(root, cmd); + return webCustomEntityService.get_value_info(root, cmd); } char error[100]; @@ -1165,7 +1166,9 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const // Print to LOG showing we've added a new device LOG_INFO("Recognized new %s with deviceID 0x%02X", EMSdevice::device_type_2_device_name(device_type), device_id); - // add command commands for all devices, except for connect, controller and gateway + // add commands 'info', 'commands', 'values', 'entities' for all EMS devices + // and register the MQTT subscribe topic for this device + // except for connect, controller and gateway if ((device_type == DeviceType::CONNECT) || (device_type == DeviceType::CONTROLLER) || (device_type == DeviceType::GATEWAY)) { return true; } diff --git a/src/system.cpp b/src/system.cpp index c72a3cbfc..fc75fde48 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -125,9 +125,10 @@ bool System::command_allvalues(const char * value, const int8_t id, JsonObject o // Sensors device_output = output["Analog Sensors"].to(); + // TODO fix this also for analogsensor EMSESP::analogsensor_.command_info(nullptr, 0, device_output); device_output = output["Temperature Sensors"].to(); - EMSESP::temperaturesensor_.command_info(nullptr, 0, device_output); + EMSESP::temperaturesensor_.get_value_info(device_output, nullptr); return true; } diff --git a/src/temperaturesensor.cpp b/src/temperaturesensor.cpp index eeaa9bc80..ae77250b5 100644 --- a/src/temperaturesensor.cpp +++ b/src/temperaturesensor.cpp @@ -45,24 +45,6 @@ void TemperatureSensor::start() { LOG_INFO("Starting Temperature sensor service"); #endif - // Add API calls - Command::add( - EMSdevice::DeviceType::TEMPERATURESENSOR, - F_(info), - [&](const char * value, const int8_t id, JsonObject output) { return command_info(value, id, output); }, - FL_(info_cmd)); - Command::add( - EMSdevice::DeviceType::TEMPERATURESENSOR, - F_(values), - [&](const char * value, const int8_t id, JsonObject output) { return command_info(value, 0, output); }, - nullptr, - CommandFlag::HIDDEN); // this command is hidden - Command::add( - EMSdevice::DeviceType::TEMPERATURESENSOR, - F_(commands), - [&](const char * value, const int8_t id, JsonObject output) { return command_commands(value, id, output); }, - FL_(commands_cmd)); - char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; snprintf(topic, sizeof(topic), "%s/#", F_(temperaturesensor)); Mqtt::subscribe(EMSdevice::DeviceType::TEMPERATURESENSOR, topic, nullptr); // use empty function callback @@ -361,57 +343,56 @@ bool TemperatureSensor::updated_values() { return false; } -// list commands -bool TemperatureSensor::command_commands(const char * value, const int8_t id, JsonObject output) { - return Command::list(EMSdevice::DeviceType::TEMPERATURESENSOR, output); -} - -// creates JSON doc from values -// returns true if there are no sensors -bool TemperatureSensor::command_info(const char * value, const int8_t id, JsonObject output) { - if (sensors_.empty()) { - return true; - } - - for (const auto & sensor : sensors_) { - char val[10]; - if (id == -1) { // show number and id, info command - JsonObject dataSensor = output[sensor.name()].to(); - dataSensor["id"] = sensor.id(); - dataSensor["uom"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES); - dataSensor["type"] = F_(number); - if (Helpers::hasValue(sensor.temperature_c)) { - dataSensor["temp"] = serialized(Helpers::render_value(val, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0)); - } - } else if (id == 0 && Helpers::hasValue(sensor.temperature_c)) { // values command - output[sensor.name()] = serialized(Helpers::render_value(val, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0)); - } else if (Helpers::hasValue(sensor.temperature_c)) { - output[sensor.id()] = serialized(Helpers::render_value(val, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0)); - } - } - - return (output.size() > 0); -} - -// called from emsesp.cpp, similar to the emsdevice->get_value_info +// called from emsesp.cpp for commands bool TemperatureSensor::get_value_info(JsonObject output, const char * cmd, const int8_t id) { if (sensors_.empty()) { + return true; // no sensors, return true + } + + bool show_all = true; + if (Helpers::hasValue(cmd)) { + show_all = (strncmp(cmd, F_(info), 4) == 0); + } + + // see if we're showing all sensors + if (show_all) { + for (const auto & sensor : sensors_) { + JsonObject dataSensor = output[sensor.name()].to(); + dataSensor["id"] = sensor.id(); + dataSensor["offset"] = sensor.offset(); + if (Helpers::hasValue(sensor.temperature_c)) { + char val[10]; + dataSensor["value"] = serialized(Helpers::render_value(val, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0)); + } + dataSensor["type"] = F_(number); + dataSensor["uom"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES); + dataSensor["writeable"] = false; + } return true; } - // make a copy of the string command for parsing - char command_s[30]; - strlcpy(command_s, cmd, sizeof(command_s)); - char * attribute_s = nullptr; - // check specific attribute to fetch instead of the complete record - char * breakp = strchr(command_s, '/'); + // check of it a 'commmands' command + if (Helpers::toLower(cmd) == F_(commands)) { + return Command::list(EMSdevice::DeviceType::TEMPERATURESENSOR, output); + } + + // this is for a specific sensor + // make a copy of the string command for parsing, and lowercase it + char sensor_name[30] = {'\0'}; + char * attribute_s = nullptr; + strlcpy(sensor_name, cmd, sizeof(sensor_name)); + auto sensor_lowercase = Helpers::toLower(sensor_name); + + // check for a specific attribute to fetch instead of the complete record + char * breakp = strchr(sensor_name, '/'); if (breakp) { *breakp = '\0'; attribute_s = breakp + 1; } for (const auto & sensor : sensors_) { - if (Helpers::toLower(command_s) == Helpers::toLower(sensor.name().c_str()) || Helpers::toLower(command_s) == Helpers::toLower(sensor.id().c_str())) { + // match custom name or sensor ID + if (sensor_lowercase == Helpers::toLower(sensor.name().c_str()) || sensor_lowercase == Helpers::toLower(sensor.id().c_str())) { output["id"] = sensor.id(); output["name"] = sensor.name(); if (Helpers::hasValue(sensor.temperature_c)) { @@ -432,16 +413,17 @@ bool TemperatureSensor::get_value_info(JsonObject output, const char * cmd, cons return true; } else { char error[100]; - snprintf(error, sizeof(error), "cannot find attribute %s in entity %s", attribute_s, command_s); + snprintf(error, sizeof(error), "cannot find attribute %s in entity %s", attribute_s, sensor_name); output.clear(); output["message"] = error; return false; } } - return true; + return true; // found a match, exit } } - return false; + + return false; // not found } // publish a single sensor to MQTT diff --git a/src/temperaturesensor.h b/src/temperaturesensor.h index 98d10066f..0c354d278 100644 --- a/src/temperaturesensor.h +++ b/src/temperaturesensor.h @@ -83,7 +83,7 @@ class TemperatureSensor { void publish_values(const bool force); void reload(); bool updated_values(); - bool get_value_info(JsonObject output, const char * cmd, const int8_t id); + bool get_value_info(JsonObject output, const char * cmd, const int8_t id = -1); // return back reference to the sensor list, used by other classes std::vector sensors() const { @@ -112,8 +112,6 @@ class TemperatureSensor { bool update(const std::string & id, const std::string & name, int16_t offset); - bool command_info(const char * value, const int8_t id, JsonObject output); - #if defined(EMSESP_TEST) void test(); #endif @@ -155,8 +153,6 @@ class TemperatureSensor { uint64_t get_id(const uint8_t addr[]); void remove_ha_topic(const std::string & id); - bool command_commands(const char * value, const int8_t id, JsonObject output); - std::vector sensors_; // our list of active sensors #ifndef EMSESP_STANDALONE diff --git a/src/test/test.cpp b/src/test/test.cpp index 176e002f5..048424608 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -757,8 +757,24 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const if (command == "temperature") { shell.printfln("Testing adding Temperature sensor"); + shell.invoke_command("show commands"); + emsesp::EMSESP::temperaturesensor_.test(); + + shell.invoke_command("call temperaturesensor"); shell.invoke_command("show values"); + shell.invoke_command("call system allvalues"); + + shell.invoke_command("call temperaturesensor info"); + AsyncWebServerRequest request; + request.method(HTTP_GET); + request.url("/api/temperaturesensor/commands"); + EMSESP::webAPIService.webAPIService_get(&request); + request.url("/api/temperaturesensor/info"); + EMSESP::webAPIService.webAPIService_get(&request); + request.url("/api/temperaturesensor/01-0203-0405-0607"); + EMSESP::webAPIService.webAPIService_get(&request); + ok = true; } diff --git a/src/test/test.h b/src/test/test.h index fbfad38b9..f36f0adb4 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -27,7 +27,7 @@ namespace emsesp { -#define EMSESP_DEBUG_DEFAULT "general" +// #define EMSESP_DEBUG_DEFAULT "general" // #define EMSESP_DEBUG_DEFAULT "thermostat" // #define EMSESP_DEBUG_DEFAULT "solar" @@ -47,7 +47,7 @@ namespace emsesp { // #define EMSESP_DEBUG_DEFAULT "dv" // #define EMSESP_DEBUG_DEFAULT "lastcode" // #define EMSESP_DEBUG_DEFAULT "2thermostats" -// #define EMSESP_DEBUG_DEFAULT "temperature" +#define EMSESP_DEBUG_DEFAULT "temperature" // #define EMSESP_DEBUG_DEFAULT "analog" // #define EMSESP_DEBUG_DEFAULT "api_values" // #define EMSESP_DEBUG_DEFAULT "mqtt_post" diff --git a/src/version.h b/src/version.h index 9988523a9..b6f8dbe73 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.6.5-dev.10" +#define EMSESP_APP_VERSION "3.6.5-dev.11" diff --git a/src/web/WebAPIService.cpp b/src/web/WebAPIService.cpp index e2e311c01..f997cd5f8 100644 --- a/src/web/WebAPIService.cpp +++ b/src/web/WebAPIService.cpp @@ -152,12 +152,13 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject input) { #if defined(EMSESP_STANDALONE) Serial.print(COLOR_YELLOW); - Serial.print("web response code: "); - Serial.println(ret_codes[return_code]); + Serial.print("data: "); if (output.size()) { - serializeJsonPretty(output, Serial); + serializeJson(output, Serial); } - Serial.println(); + Serial.print(" (response code "); + Serial.print(ret_codes[return_code]); + Serial.println(")"); Serial.print(COLOR_RESET); #endif } diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp index d45c31b07..2c56164a0 100644 --- a/src/web/WebSchedulerService.cpp +++ b/src/web/WebSchedulerService.cpp @@ -134,6 +134,7 @@ bool WebSchedulerService::command_setvalue(const char * value, const std::string // process json output for info/commands and value_info bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) { + // check of it a 'commmands' command if (Helpers::toLower(cmd) == F_(commands)) { output[F_(info)] = Helpers::translated_word(FL_(info_cmd)); output[F_(commands)] = Helpers::translated_word(FL_(commands_cmd));