Skip to content

Commit

Permalink
Fix: restore JSON array access for HTTP power meter
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
schlimmchen committed May 7, 2024
1 parent 35491ca commit 3ef789c
Showing 1 changed file with 45 additions and 7 deletions.
52 changes: 45 additions & 7 deletions src/HttpPowerMeter.cpp
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit 3ef789c

Please sign in to comment.