diff --git a/ChangeLog.md b/ChangeLog.md index 81234fa1..39c50ce2 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -21,7 +21,7 @@ * added some PIC calibration data to "ebuspicloader" verbose output * added support for upcoming adapter 3 firmware enhancements * added config override path -* added support for adding message definition, retrieving data types and raw messages to HTTP port +* added support for adding message definition, retrieving data types and raw messages, and decode data types from raw values to HTTP port * added "--mqttverbose" option ## Breaking Changes diff --git a/contrib/html/openapi.yaml b/contrib/html/openapi.yaml index 1ce78dd2..e8889e0a 100644 --- a/contrib/html/openapi.yaml +++ b/contrib/html/openapi.yaml @@ -157,6 +157,32 @@ paths: application/json;charset=utf-8: schema: $ref: '#/components/schemas/RawMessages' + /decode: + get: + summary: Decode raw data with the specified field defintion. + parameters: + - name: def + in: query + description: the field definition (starting with type). + allowEmptyValue: false + required: true + schema: + type: string + - name: raw + in: query + description: the raw symbols to decode as hex sequence. + required: true + allowEmptyValue: false + schema: + type: string + pattern: '^([0-9a-f][0-9a-f])+$' + responses: + 200: + description: Success + content: + application/json;charset=utf-8: + schema: + $ref: '#/components/schemas/FieldValue' /{file}: get: summary: Retrieve a particular file. diff --git a/src/ebusd/mainloop.cpp b/src/ebusd/mainloop.cpp index 6012a53e..e46e989a 100644 --- a/src/ebusd/mainloop.cpp +++ b/src/ebusd/mainloop.cpp @@ -2259,6 +2259,56 @@ result_t MainLoop::executeGet(const vector& args, bool* connected, ostri return formatHttpResult(ret, type, ostream); } + if (uri == "/decode") { + string def; + string raw; + if (args.size() > argPos) { + string query = args[argPos]; + istringstream stream(query); + string token; + while (getline(stream, token, '&')) { + size_t pos = token.find('='); + string qname, value; + if (pos != string::npos) { + qname = token.substr(0, pos); + value = token.substr(pos + 1); + } else { + qname = token; + } + if (qname == "def") { + def = value; + } else if (qname == "raw") { + raw = value; + } + if (ret != RESULT_OK) { + break; + } + } + } + if (ret == RESULT_OK) { + time_t now; + time(&now); + istringstream defstr("#\n" + def); // ensure first line is not used for determining col names + string errorDescription; + DataFieldTemplates* templates = getTemplates("*"); + LoadableDataFieldSet fields("", templates); + ret = fields.readFromStream(&defstr, "temporary", now, true, nullptr, &errorDescription); + if (ret == RESULT_OK) { + const SingleDataField* field = fields[0]; + SlaveSymbolString slave; + slave.push_back(0); // dummy length + ret = slave.parseHex(raw); + if (ret == RESULT_OK) { + slave.adjustHeader(); + ret = field->read(slave, 0, false, nullptr, 0, OF_JSON|OF_SHORT, 0, ostream); + } + } + type = 6; + } + *connected = false; + return formatHttpResult(ret, type, ostream); + } + if (uri.length() < 1 || uri[0] != '/' || uri.find("//") != string::npos || uri.find("..") != string::npos) { ret = RESULT_ERR_INVALID_ARG; } else {