Fix: restore JSON array access for HTTP power meter

this implements accessing array members in an ArduinoJSON object
following the FirebaseJson syntax. the FirebaseJson lib was previously
removed to save flash memory, and logic was implemented to find a JSON
node using the FirebaseJson path syntax, restoring the functionality.
however, array access was not implemented.

this change also addresses leading and trailing and double forward
slashes in the path expression.

moreover, much more expressive error messages are now generated in case
the path could not be resolved.
This commit is contained in:
Bernhard Kirchen 2024-05-07 20:39:18 +02:00 committed by Bernhard Kirchen
parent 35491cafed
commit 3ef789c6a2

View File

@ -233,23 +233,61 @@ bool HttpPowerMeterClass::tryGetFloatValueForPhase(int phase, String jsonPath, U
int end = jsonPath.indexOf(delimiter);
auto value = root.as<JsonVariantConst>();
auto getNext = [this, &value, &jsonPath, &start](String const& key) -> bool {
// handle double forward slashes and paths starting or ending with a slash
if (key.isEmpty()) { return true; }
if (key[0] == '[' && key[key.length() - 1] == ']') {
if (!value.is<JsonArrayConst>()) {
snprintf_P(httpPowerMeterError, sizeof(httpPowerMeterError),
PSTR("[HttpPowerMeter] Cannot access non-array JSON node "
"using array index '%s' (JSON path '%s', position %i)"),
key.c_str(), jsonPath.c_str(), start);
return false;
}
auto idx = key.substring(1, key.length() - 1).toInt();
value = value[idx];
if (value.isNull()) {
snprintf_P(httpPowerMeterError, sizeof(httpPowerMeterError),
PSTR("[HttpPowerMeter] Unable to access JSON array "
"index %li (JSON path '%s', position %i)"),
idx, jsonPath.c_str(), start);
return false;
}
return true;
}
value = value[key];
if (value.isNull()) {
snprintf_P(httpPowerMeterError, sizeof(httpPowerMeterError),
PSTR("[HttpPowerMeter] Unable to access JSON key "
"'%s' (JSON path '%s', position %i)"),
key.c_str(), jsonPath.c_str(), start);
return false;
}
return true;
};
// NOTE: "Because ArduinoJson implements the Null Object Pattern, it is
// always safe to read the object: if the key doesn't exist, it returns an
// empty value."
while (end != -1) {
String key = jsonPath.substring(start, end);
value = value[key];
if (!getNext(jsonPath.substring(start, end))) { return false; }
start = end + 1;
end = jsonPath.indexOf(delimiter, start);
}
String lastKey = jsonPath.substring(start);
value = value[lastKey];
if (!getNext(jsonPath.substring(start))) { return false; }
if (value.isNull()) {
if (!value.is<float>()) {
snprintf_P(httpPowerMeterError, sizeof(httpPowerMeterError),
PSTR("[HttpPowerMeter] Unable to find a value for phase %i with JSON path \"%s\""),
phase+1, jsonPath.c_str());
PSTR("[HttpPowerMeter] not a float: '%s'"),
value.as<String>().c_str());
return false;
}