mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
API extract individual attributes - #462
This commit is contained in:
@@ -37,6 +37,7 @@
|
|||||||
- Junkers ISM2 and IPM in warm water mode [#437](https://github.com/emsesp/EMS-ESP32/issues/437)
|
- Junkers ISM2 and IPM in warm water mode [#437](https://github.com/emsesp/EMS-ESP32/issues/437)
|
||||||
- Added Shower Alert trigger time and cold shot time [#436](https://github.com/emsesp/EMS-ESP32/issues/436)
|
- Added Shower Alert trigger time and cold shot time [#436](https://github.com/emsesp/EMS-ESP32/issues/436)
|
||||||
- Improved Table layout in Web UI (searching, filtering, sorting, exporting to CSV)
|
- Improved Table layout in Web UI (searching, filtering, sorting, exporting to CSV)
|
||||||
|
- API fetch individual attributes from an entity [#462](https://github.com/emsesp/EMS-ESP32/issues/462)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
|
|||||||
return message(CommandRet::ERROR, "unknown device", output);
|
return message(CommandRet::ERROR, "unknown device", output);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the next value on the path should be the command
|
// the next value on the path should be the command or entity name
|
||||||
const char * command_p = nullptr;
|
const char * command_p = nullptr;
|
||||||
if (num_paths == 2) {
|
if (num_paths == 2) {
|
||||||
command_p = p.paths()[1].c_str();
|
command_p = p.paths()[1].c_str();
|
||||||
@@ -104,7 +104,7 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// some commands may be prefixed with hc. or wwc. so extract these if they exist
|
// some commands may be prefixed with hc. wwc. or hc/ or wwc/ so extract these if they exist
|
||||||
// parse_command_string returns the extracted command
|
// parse_command_string returns the extracted command
|
||||||
command_p = parse_command_string(command_p, id_n);
|
command_p = parse_command_string(command_p, id_n);
|
||||||
if (command_p == nullptr) {
|
if (command_p == nullptr) {
|
||||||
@@ -189,7 +189,7 @@ const char * Command::parse_command_string(const char * command, int8_t & id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make a copy of the string command for parsing
|
// make a copy of the string command for parsing
|
||||||
char command_s[100];
|
char command_s[30];
|
||||||
strlcpy(command_s, command, sizeof(command_s));
|
strlcpy(command_s, command, sizeof(command_s));
|
||||||
|
|
||||||
// look for a delimeter and split the string
|
// look for a delimeter and split the string
|
||||||
@@ -202,7 +202,7 @@ const char * Command::parse_command_string(const char * command, int8_t & id) {
|
|||||||
p = command_s; // reset and look for _
|
p = command_s; // reset and look for _
|
||||||
breakp = strchr(p, '_');
|
breakp = strchr(p, '_');
|
||||||
if (!breakp) {
|
if (!breakp) {
|
||||||
return command;
|
return command; // no delimeter found, return the whole string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,10 +214,8 @@ const char * Command::parse_command_string(const char * command, int8_t & id) {
|
|||||||
} else if (!strncmp(command, "wwc", 3) && start_pos == 5) {
|
} else if (!strncmp(command, "wwc", 3) && start_pos == 5) {
|
||||||
id = command[start_pos - 2] - '0' + 8; // wwc1 has id 9
|
id = command[start_pos - 2] - '0' + 8; // wwc1 has id 9
|
||||||
} else {
|
} else {
|
||||||
#if defined(EMSESP_DEBUG)
|
id = 0; // special case for extracting the attributes
|
||||||
LOG_DEBUG(F("[DEBUG] Command parse error, unknown hc/wwc in %s"), command_s);
|
return command;
|
||||||
#endif
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (command + start_pos);
|
return (command + start_pos);
|
||||||
@@ -244,13 +242,12 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
|
|||||||
// see if there is a command registered
|
// see if there is a command registered
|
||||||
auto cf = find_command(device_type, cmd);
|
auto cf = find_command(device_type, cmd);
|
||||||
|
|
||||||
// check if its a call to and end-point to a device, i.e. has no value
|
// check if its a call to and end-point to a device
|
||||||
// except for system commands as this is a special device without any queryable entities (device values)
|
// except for system commands as this is a special device without any queryable entities (device values)
|
||||||
// exclude SYSTEM
|
|
||||||
if ((device_type > EMSdevice::DeviceType::SYSTEM) && (!value || !strlen(value))) {
|
if ((device_type > EMSdevice::DeviceType::SYSTEM) && (!value || !strlen(value))) {
|
||||||
if (!cf || !cf->cmdfunction_json_) {
|
if (!cf || !cf->cmdfunction_json_) {
|
||||||
#if defined(EMSESP_DEBUG)
|
#if defined(EMSESP_DEBUG)
|
||||||
LOG_DEBUG(F("[DEBUG] Calling %s command '%s' to retrieve values"), dname.c_str(), cmd);
|
LOG_DEBUG(F("[DEBUG] Calling %s command '%s' to retrieve attributes"), dname.c_str(), cmd);
|
||||||
#endif
|
#endif
|
||||||
return EMSESP::get_device_value_info(output, cmd, id, device_type) ? CommandRet::OK : CommandRet::ERROR; // entity = cmd
|
return EMSESP::get_device_value_info(output, cmd, id, device_type) ? CommandRet::OK : CommandRet::ERROR; // entity = cmd
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -915,13 +915,26 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
|
|||||||
tag = DeviceValueTAG::TAG_HC1 + id - 1;
|
tag = DeviceValueTAG::TAG_HC1 + id - 1;
|
||||||
} else if (id >= 9 && id <= 19) {
|
} else if (id >= 9 && id <= 19) {
|
||||||
tag = DeviceValueTAG::TAG_WWC1 + id - 9;
|
tag = DeviceValueTAG::TAG_WWC1 + id - 9;
|
||||||
} else if (id != -1) {
|
}
|
||||||
return false; // error
|
|
||||||
|
// make a copy of the string command for parsing
|
||||||
|
char command_s[30];
|
||||||
|
strlcpy(command_s, cmd, sizeof(command_s));
|
||||||
|
char * attribute_s = command_s;
|
||||||
|
|
||||||
|
// if id=0 then we have a specific attribute to fetch instead of the complete record
|
||||||
|
if (id == 0) {
|
||||||
|
char * p = command_s;
|
||||||
|
char * breakp = strchr(p, '/');
|
||||||
|
if (breakp) {
|
||||||
|
*breakp = '\0';
|
||||||
|
attribute_s = breakp + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// search device value with this tag
|
// search device value with this tag
|
||||||
for (auto & dv : devicevalues_) {
|
for (auto & dv : devicevalues_) {
|
||||||
if (strcmp(cmd, Helpers::toLower(read_flash_string(dv.short_name)).c_str()) == 0 && (tag <= 0 || tag == dv.tag)) {
|
if (strcmp(command_s, Helpers::toLower(read_flash_string(dv.short_name)).c_str()) == 0 && (tag <= 0 || tag == dv.tag)) {
|
||||||
int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0;
|
int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0;
|
||||||
uint8_t fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0;
|
uint8_t fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0;
|
||||||
|
|
||||||
@@ -1060,6 +1073,25 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
|
|||||||
json[value] = "not set";
|
json[value] = "not set";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if id is 0 then we're filtering on an attribute, go find it
|
||||||
|
if (id == 0) {
|
||||||
|
#if defined(EMSESP_DEBUG)
|
||||||
|
EMSESP::logger().debug(F("[DEBUG] Attribute '%s'"), attribute_s);
|
||||||
|
#endif
|
||||||
|
if (json.containsKey(attribute_s)) {
|
||||||
|
JsonVariant data = json[attribute_s];
|
||||||
|
output.clear();
|
||||||
|
output["api_data"] = data;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
char error[100];
|
||||||
|
snprintf(error, sizeof(error), "cannot find attribute %s in entity %s", attribute_s, command_s);
|
||||||
|
output.clear();
|
||||||
|
output["message"] = error;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -660,9 +660,20 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
|||||||
DynamicJsonDocument doc(2000);
|
DynamicJsonDocument doc(2000);
|
||||||
JsonVariant json;
|
JsonVariant json;
|
||||||
request.method(HTTP_GET);
|
request.method(HTTP_GET);
|
||||||
|
|
||||||
|
request.url("/api/boiler/values");
|
||||||
|
EMSESP::webAPIService.webAPIService_get(&request);
|
||||||
request.url("/api/boiler/wwcirc");
|
request.url("/api/boiler/wwcirc");
|
||||||
EMSESP::webAPIService.webAPIService_get(&request);
|
EMSESP::webAPIService.webAPIService_get(&request);
|
||||||
request.url("/api/boiler/values");
|
request.url("/api/boiler/wwcirc/fullname");
|
||||||
|
EMSESP::webAPIService.webAPIService_get(&request);
|
||||||
|
request.url("/api/boiler/selburnpow/value");
|
||||||
|
EMSESP::webAPIService.webAPIService_get(&request);
|
||||||
|
request.url("/api/boiler/wwchargetype/writeable");
|
||||||
|
EMSESP::webAPIService.webAPIService_get(&request);
|
||||||
|
request.url("/api/boiler/flamecurr/value");
|
||||||
|
EMSESP::webAPIService.webAPIService_get(&request);
|
||||||
|
request.url("/api/boiler/flamecurr/bad");
|
||||||
EMSESP::webAPIService.webAPIService_get(&request);
|
EMSESP::webAPIService.webAPIService_get(&request);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace emsesp {
|
|||||||
// #define EMSESP_DEBUG_DEFAULT "mixer"
|
// #define EMSESP_DEBUG_DEFAULT "mixer"
|
||||||
// #define EMSESP_DEBUG_DEFAULT "web"
|
// #define EMSESP_DEBUG_DEFAULT "web"
|
||||||
// #define EMSESP_DEBUG_DEFAULT "mqtt"
|
// #define EMSESP_DEBUG_DEFAULT "mqtt"
|
||||||
#define EMSESP_DEBUG_DEFAULT "general"
|
// #define EMSESP_DEBUG_DEFAULT "general"
|
||||||
// #define EMSESP_DEBUG_DEFAULT "boiler"
|
// #define EMSESP_DEBUG_DEFAULT "boiler"
|
||||||
// #define EMSESP_DEBUG_DEFAULT "mqtt2"
|
// #define EMSESP_DEBUG_DEFAULT "mqtt2"
|
||||||
// #define EMSESP_DEBUG_DEFAULT "mqtt_nested"
|
// #define EMSESP_DEBUG_DEFAULT "mqtt_nested"
|
||||||
@@ -48,7 +48,7 @@ namespace emsesp {
|
|||||||
// #define EMSESP_DEBUG_DEFAULT "2thermostats"
|
// #define EMSESP_DEBUG_DEFAULT "2thermostats"
|
||||||
// #define EMSESP_DEBUG_DEFAULT "dallas"
|
// #define EMSESP_DEBUG_DEFAULT "dallas"
|
||||||
// #define EMSESP_DEBUG_DEFAULT "analog"
|
// #define EMSESP_DEBUG_DEFAULT "analog"
|
||||||
// #define EMSESP_DEBUG_DEFAULT "api_values"
|
#define EMSESP_DEBUG_DEFAULT "api_values"
|
||||||
// #define EMSESP_DEBUG_DEFAULT "mqtt_post"
|
// #define EMSESP_DEBUG_DEFAULT "mqtt_post"
|
||||||
|
|
||||||
class Test {
|
class Test {
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "3.4.0b15"
|
#define EMSESP_APP_VERSION "3.4.0b16"
|
||||||
|
|||||||
@@ -120,6 +120,15 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject & input) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we're returning single values, just sent as plain text
|
||||||
|
// https://github.com/emsesp/EMS-ESP32/issues/462#issuecomment-1093877210
|
||||||
|
if (output.containsKey("api_data")) {
|
||||||
|
JsonVariant data = output["api_data"];
|
||||||
|
request->send(200, "text/plain", data.as<String>());
|
||||||
|
api_count_++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// send the json that came back from the command call
|
// send the json that came back from the command call
|
||||||
// FAIL, OK, NOT_FOUND, ERROR, NOT_ALLOWED = 400 (bad request), 200 (OK), 400 (not found), 400 (bad request), 401 (unauthorized)
|
// FAIL, OK, NOT_FOUND, ERROR, NOT_ALLOWED = 400 (bad request), 200 (OK), 400 (not found), 400 (bad request), 401 (unauthorized)
|
||||||
int ret_codes[5] = {400, 200, 400, 400, 401};
|
int ret_codes[5] = {400, 200, 400, 400, 401};
|
||||||
|
|||||||
Reference in New Issue
Block a user