diff --git a/interface/src/project/CustomEntitiesDialog.tsx b/interface/src/project/CustomEntitiesDialog.tsx index c7831eb7f..285ae9fff 100644 --- a/interface/src/project/CustomEntitiesDialog.tsx +++ b/interface/src/project/CustomEntitiesDialog.tsx @@ -64,7 +64,7 @@ const CustomEntitiesDialog = ({ } }, [open, selectedItem]); - const handleClose = (event: {}, reason: 'backdropClick' | 'escapeKeyDown') => { + const handleClose = (event: object, reason: 'backdropClick' | 'escapeKeyDown') => { if (reason !== 'backdropClick') { onClose(); } diff --git a/interface/src/project/CustomizationDialog.tsx b/interface/src/project/CustomizationDialog.tsx index 6b266b9e5..bd7ac45b2 100644 --- a/interface/src/project/CustomizationDialog.tsx +++ b/interface/src/project/CustomizationDialog.tsx @@ -54,7 +54,7 @@ const CustomizationDialog = ({ } }, [open, selectedItem]); - const handleClose = (event: {}, reason: 'backdropClick' | 'escapeKeyDown') => { + const handleClose = (event: object, reason: 'backdropClick' | 'escapeKeyDown') => { if (reason !== 'backdropClick') { onClose(); } diff --git a/interface/src/project/SchedulerDialog.tsx b/interface/src/project/SchedulerDialog.tsx index e3aeb72b2..2fdb95e22 100644 --- a/interface/src/project/SchedulerDialog.tsx +++ b/interface/src/project/SchedulerDialog.tsx @@ -147,7 +147,7 @@ const SchedulerDialog = ({ ); - const handleClose = (event: {}, reason: 'backdropClick' | 'escapeKeyDown') => { + const handleClose = (event: object, reason: 'backdropClick' | 'escapeKeyDown') => { if (reason !== 'backdropClick') { onClose(); } diff --git a/interface/src/project/SensorsAnalogDialog.tsx b/interface/src/project/SensorsAnalogDialog.tsx index da7655466..1249e9637 100644 --- a/interface/src/project/SensorsAnalogDialog.tsx +++ b/interface/src/project/SensorsAnalogDialog.tsx @@ -57,7 +57,7 @@ const SensorsAnalogDialog = ({ } }, [open, selectedItem]); - const handleClose = (event: {}, reason: 'backdropClick' | 'escapeKeyDown') => { + const handleClose = (event: object, reason: 'backdropClick' | 'escapeKeyDown') => { if (reason !== 'backdropClick') { onClose(); } diff --git a/interface/src/project/SensorsTemperatureDialog.tsx b/interface/src/project/SensorsTemperatureDialog.tsx index c5042b80c..433b3bdbf 100644 --- a/interface/src/project/SensorsTemperatureDialog.tsx +++ b/interface/src/project/SensorsTemperatureDialog.tsx @@ -52,7 +52,7 @@ const SensorsTemperatureDialog = ({ } }, [open, selectedItem]); - const handleClose = (event: {}, reason: 'backdropClick' | 'escapeKeyDown') => { + const handleClose = (event: object, reason: 'backdropClick' | 'escapeKeyDown') => { if (reason !== 'backdropClick') { onClose(); } diff --git a/src/command.cpp b/src/command.cpp index 1bb3f878c..d6d12fb88 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -35,7 +35,7 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec p.parse(path); if (!p.paths().size()) { - return message(CommandRet::ERROR, "invalid path", output); + return json_message(CommandRet::ERROR, "invalid path", output); } // check first if it's from API, if so strip the "api/" @@ -48,7 +48,7 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec strlcpy(new_path, path, sizeof(new_path)); p.parse(new_path + Mqtt::base().length() + 1); // re-parse the stripped path } else { - return message(CommandRet::ERROR, "unrecognized path", output); // error + return json_message(CommandRet::ERROR, "unrecognized path", output); // error } } @@ -56,7 +56,7 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec // if there is only a path (URL) and no body then error! size_t num_paths = p.paths().size(); if (!num_paths && !input.size()) { - return message(CommandRet::ERROR, "missing command in path", output); + return json_message(CommandRet::ERROR, "missing command in path", output); } std::string cmd_s; @@ -78,8 +78,11 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec // validate the device, make sure it exists uint8_t device_type = EMSdevice::device_name_2_device_type(device_s); if (!device_has_commands(device_type)) { - LOG_DEBUG("Command failed: unknown device '%s'", device_s); - return message(CommandRet::NOT_FOUND, "unknown device", output); + char err[100]; + snprintf(err, sizeof(err), "unknown device %s", device_s); + LOG_WARNING("Command failed: %s", err); + output["message"] = err; + return CommandRet::NOT_FOUND; } // the next value on the path should be the command or entity name @@ -114,7 +117,7 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec if (num_paths < (id_n > 0 ? 4 : 3)) { command_p = device_type == EMSdevice::DeviceType::SYSTEM ? F_(info) : F_(values); } else { - return message(CommandRet::NOT_FOUND, "missing or bad command", output); + return json_message(CommandRet::NOT_FOUND, "missing or bad command", output); } } @@ -199,7 +202,7 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec } else if (data.isNull()) { return_code = Command::call(device_type, command_p, "", is_admin, id_n, output); // empty, will do a query instead } else { - return message(CommandRet::ERROR, "cannot parse command", output); // can't process + return json_message(CommandRet::ERROR, "cannot parse command", output); // can't process } return return_code; } @@ -334,10 +337,12 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char * // first see if there is a command registered and it's valid auto cf = find_command(device_type, device_id, cmd, flag); if (!cf) { - LOG_WARNING("Command failed: unknown command '%s'", cmd ? cmd : ""); + std::string err = std::string("unknown command ") + cmd; + LOG_WARNING("Command failed: %s", err.c_str()); + // if we don't alread have a message set, set it to invalid command if (!output["message"]) { - output["message"] = "unknown command"; + output["message"] = err; } return CommandRet::ERROR; } @@ -355,9 +360,9 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char * auto description = Helpers::translated_word(cf->description_); char info_s[100]; if (strlen(description)) { - snprintf(info_s, sizeof(info_s), "'%s/%s' (%s)", dname, cmd, description); + snprintf(info_s, sizeof(info_s), "%s/%s (%s)", dname, cmd, description); } else { - snprintf(info_s, sizeof(info_s), "'%s/%s'", dname, cmd); + snprintf(info_s, sizeof(info_s), "%s/%s", dname, cmd); } // call the function based on command function type @@ -380,9 +385,9 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char * if (return_code != CommandRet::OK) { char error[100]; if (single_command) { - snprintf(error, sizeof(error), "Command '%s' failed (%s)", cmd, return_code_string(return_code)); + snprintf(error, sizeof(error), "Command %s failed (%s)", cmd, return_code_string(return_code)); } else { - snprintf(error, sizeof(error), "Command '%s: %s' failed (%s)", cmd, value, return_code_string(return_code)); + snprintf(error, sizeof(error), "Command %s: %s failed (%s)", cmd, value, return_code_string(return_code)); } output.clear(); output["message"] = error; @@ -683,6 +688,16 @@ void Command::show_all(uuid::console::Shell & shell) { shell.println(); } +uint8_t Command::json_message(uint8_t error_code, const char * message, const JsonObject output) { + output.clear(); + output["message"] = message; + return error_code; +} + +// +// SUrlParser class +// + // Extract only the path component from the passed URI and normalized it // e.g. //one/two////three/// becomes /one/two/three std::string SUrlParser::path() { diff --git a/src/command.h b/src/command.h index 45827b644..564d43b21 100644 --- a/src/command.h +++ b/src/command.h @@ -143,11 +143,7 @@ class Command { static std::vector cmdfunctions_; // the list of commands - inline static uint8_t message(uint8_t error_code, const char * message, const JsonObject output) { - output.clear(); - output["message"] = message; - return error_code; - } + static uint8_t json_message(uint8_t error_code, const char * message, const JsonObject output); }; class SUrlParser { diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index df55e7a67..d2f255ef2 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -1599,7 +1599,7 @@ bool EMSdevice::get_value_info(JsonObject output, const char * cmd, const int8_t // if we're filtering on an attribute, go find it if (attribute_s) { #if defined(EMSESP_DEBUG) - EMSESP::logger().debug("[DEBUG] fetching single attribute '%s'", attribute_s); + EMSESP::logger().debug("[DEBUG] fetching single attribute %s", attribute_s); #endif if (json.containsKey(attribute_s)) { std::string data = json[attribute_s].as(); diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 2978fbc7c..ba181a051 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -743,7 +743,7 @@ void EMSESP::publish_response(std::shared_ptr telegram) { } // builds json with the detail of each value, for a given EMS device -// for other types like sensors, scheduler, custom entities it will process single commands like 'info', 'values', 'commands'... +// for other types like sensors, scheduler, custom entities it will process single commands like 'info', 'values', 'commands', 'entities'... bool EMSESP::get_device_value_info(JsonObject root, const char * cmd, const int8_t id, const uint8_t devicetype) { // check first for EMS devices bool found_device = false; @@ -755,9 +755,8 @@ bool EMSESP::get_device_value_info(JsonObject root, const char * cmd, const int8 } } } - // if the EMS device was valid, but the cmd not found show an error + // if the EMS device was valid, but the cmd not found exit. it will be handled upstream. if (found_device) { - root["message"] = std::string("unknown command ") + cmd; return false; } @@ -1712,14 +1711,14 @@ void EMSESP::loop() { // if we're doing an OTA upload, skip everything except from console refresh if (!system_.upload_status()) { // service loops - webLogService.loop(); // log in Web UI - rxservice_.loop(); // process any incoming Rx telegrams - shower_.loop(); // check for shower on/off - temperaturesensor_.loop(); // read sensor temperatures - analogsensor_.loop(); // read analog sensor values - publish_all_loop(); // with HA messages in parts to avoid flooding the mqtt queue - mqtt_.loop(); // sends out anything in the MQTT queue - webModulesService.loop(); // loop through the external library modules + webLogService.loop(); // log in Web UI + rxservice_.loop(); // process any incoming Rx telegrams + shower_.loop(); // check for shower on/off + temperaturesensor_.loop(); // read sensor temperatures + analogsensor_.loop(); // read analog sensor values + publish_all_loop(); // with HA messages in parts to avoid flooding the mqtt queue + mqtt_.loop(); // sends out anything in the MQTT queue + webModulesService.loop(); // loop through the external library modules // force a query on the EMS devices to fetch latest data at a set interval (1 min) scheduled_fetch_values(); diff --git a/src/test/test.cpp b/src/test/test.cpp index b19f732d2..c79aea1a5 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -1053,20 +1053,17 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const // This next batch should all fail // - Serial.printf("%s**** Testing bad urls ****\n%s", COLOR_RED, COLOR_RESET); Serial.println(); + Serial.printf("%s**** Testing bad urls ****\n%s", COLOR_RED, COLOR_RESET); + + request.url("/api/boiler2"); + EMSESP::webAPIService.webAPIService(&request); // boiler request.url("/api/boiler/bad"); EMSESP::webAPIService.webAPIService(&request); request.url("/api/boiler/bad/value"); EMSESP::webAPIService.webAPIService(&request); - request.url("/api/boiler2/bad"); - EMSESP::webAPIService.webAPIService(&request); - request.url("/api/boiler/bad"); - EMSESP::webAPIService.webAPIService(&request); - request.url("/api/boiler/bad/value"); - EMSESP::webAPIService.webAPIService(&request); request.url("/api/boiler/comfort/valu"); EMSESP::webAPIService.webAPIService(&request); diff --git a/src/test/test.h b/src/test/test.h index 5f672358f..93fa81e01 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -41,7 +41,7 @@ namespace emsesp { // #define EMSESP_DEBUG_DEFAULT "310" // #define EMSESP_DEBUG_DEFAULT "render" // #define EMSESP_DEBUG_DEFAULT "api" -// #define EMSESP_DEBUG_DEFAULT "api3" +#define EMSESP_DEBUG_DEFAULT "api3" // #define EMSESP_DEBUG_DEFAULT "crash" // #define EMSESP_DEBUG_DEFAULT "dv" // #define EMSESP_DEBUG_DEFAULT "lastcode" diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp index 94843d067..c52613cf5 100644 --- a/src/web/WebSchedulerService.cpp +++ b/src/web/WebSchedulerService.cpp @@ -38,7 +38,9 @@ void WebSchedulerService::begin() { char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; snprintf(topic, sizeof(topic), "%s/#", F_(scheduler)); Mqtt::subscribe(EMSdevice::DeviceType::SCHEDULER, topic, nullptr); // use empty function callback +#ifndef EMSESP_STANDALONE xTaskCreate((TaskFunction_t)scheduler_task, "scheduler_task", 4096, NULL, 3, NULL); +#endif } // this creates the scheduler file, saving it to the FS @@ -529,7 +531,9 @@ void WebSchedulerService::scheduler_task(void * pvParameters) { EMSESP::webSchedulerService.loop(); } } +#ifndef EMSESP_STANDALONE vTaskDelete(NULL); +#endif } // hard coded tests @@ -600,7 +604,7 @@ void WebSchedulerService::test() { test_value = "(custom/seltemp - boiler/flowtempoffset) * 2.8 + 5"; command("test10", test_cmd.c_str(), compute(test_value).c_str()); - // TODO add some HTTP/URI tests + // TODO add some more HTTP/URI tests test_cmd = "{\"method\":\"POST\",\"url\":\"http://192.168.1.42:8123/api/services/script/test_notify2\", \"header\":{\"authorization\":\"Bearer " "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhMmNlYWI5NDgzMmI0ODE2YWQ2NzU4MjkzZDE2YWMxZSIsImlhdCI6MTcyMTM5MTI0NCwiZXhwIjoyMDM2NzUxMjQ0fQ." "S5sago1tEI6lNhrDCO0dM_WsVQHkD_laAjcks8tWAqo\"}}";