Parsing JSON (from Awair) with JS

Thanks in advance for the help, sorry if this is a noob post.

  • Platform information:
    • Hardware: Virtual; 4c / 8GB
    • OS: Win10 1909
    • Java Runtime Environment: JRE v8 build 231
    • openHAB version: 2.4

SETUP: For almost a year, I have been pulling my Awair’s air sensor data from their API via the http1 binding and parsing it with JSONPATH (works great for the most part!). A sample below:

Awair.items:

String Stat_Awair_Temp_json “Stat_Awair_Temp_json [%s]” {http="<[AwairCache:288000:JSONPATH($.data[0].sensors[0].value)]"}
Number Stat_Awair_Temp “Stat_Awair_Temp [%d °F]” (Group_Awair)

Awair_Temperature.rules:

rule “Convert Awair_Temp JSON to Item Type Number”
when
Item Stat_Awair_Temp_json changed
then
// use the transformation service to retrieve the value
val newValue = transform(“JSONPATH”, “$.data[0].sensors[0].value”, Stat_Awair_Temp_json.state.toString)
// post the new value to the Number Item
Stat_Awair_Temp.postUpdate( newValue )
end

The problem is that the API doesn’t always return the sensors[#] the same, so sometimes I end up with humidity or CO2 data where my temperature data should be. Awair support suggested that I try parsing the returned data with JS instead of JSONPATH. Here’s what I’m trying to do now:

Awair.items:

String TESTTEMP “TESTTEMP [%s]” { http="<[AwairCache:288000:JS(GetTemp.js)]" }
Number TESTTEMPNUM “TESTTEMPNUM [%d °F]”

GetTemp.js:

(function(i) {
var sensors = i.data[0].sensors;
for (var sensor in sensors) {
if (sensors[sensor].comp == “temp”) {
return sensors[sensor].value;
}
}
})(input)

I’ve separately verified the ‘GetTemp.js’ code is good, as when I replace ‘input’ with the raw JSON the API gives, it parses no problem and returns the temperature value. However, when trying to run this in OHAB, it throws this error:

2020-07-10 13:19:25.184 [WARN ] [ab.binding.http.internal.HttpBinding] - Transformation ‘JS(GetTemp.js)’ threw an exception. [response={“data”:[{“timestamp”:“2020-07-10T18:19:15.000Z”,“score”:80.0,“sensors”:[{“comp”:“temp”,“value”:81.68000068664551},{“comp”:“humid”,“value”:57.36000061035156},{“comp”:“co2”,“value”:660.0},{“comp”:“voc”,“value”:411.0}],“indices”:[{“comp”:“temp”,“value”:1.0},{“comp”:“humid”,“value”:1.0},{“comp”:“co2”,“value”:0.0},{“comp”:“voc”,“value”:1.0}]}]}]
org.openhab.core.transform.TransformationException: An error occurred while executing script.
at org.openhab.core.transform.TransformationHelper$TransformationServiceDelegate.transform(TransformationHelper.java:67) ~[214:org.openhab.core.compat1x:2.4.0]
at org.openhab.binding.http.internal.HttpBinding.execute(HttpBinding.java:194) [212:org.openhab.binding.http:1.13.0]
at org.openhab.core.binding.AbstractActiveBinding$BindingActiveService.execute(AbstractActiveBinding.java:144) [214:org.openhab.core.compat1x:2.4.0]
at org.openhab.core.service.AbstractActiveService$RefreshThread.run(AbstractActiveService.java:166) [214:org.openhab.core.compat1x:2.4.0]

I’m sure I’ve just not configured something correctly; any help anyone can give is much appreciated!

Try the NGRE with Jython which is basically Python 2 . Python is very good at handling JSON and converting to a Python dictionary.
@rlkoshak and @5iver are the experts here.

Looks like your JSON is -

{“data”:[
   {“timestamp”:“2020-07-10T18:19:15.000Z”,“score”:80.0,“sensors”:[
      {“comp”:“temp”,“value”:81.68000068664551},
      {“comp”:“humid”,“value”:57.36000061035156},
      {“comp”:“co2”,“value”:660.0},
      {“comp”:“voc”,“value”:411.0} ],
   “indices”:[
      {“comp”:“temp”,“value”:1.0},
      {“comp”:“humid”,“value”:1.0},
      {“comp”:“co2”,“value”:0.0},
      {“comp”:“voc”,“value”:1.0} ]
   } ]
}

From your original http binding config
JSONPATH($.data[0].sensors[0].value)
I think you are trying to get hold of the ‘temp’ value 81.68… ?

Not quite sure what you mean there, the order of elements may change ??

That’s fine, let’s get it by key name instead of position
JSONPATH($.data[0].sensors[?(@.comp=='temp')].value)

This looks in first element of “data” list - then looks in sensors list for an entry with key “comp” equals “temp”, finally gets payload from “value” key

3 Likes

@rossko57 This was a plug n’ play solution for me. Thank you very much!!!

And @Bruce_Osborne thanks very much for your quick reply as well! :slight_smile:

*edit: yes, I’d originally been pulling the data in sensor order (0,1,2,3), however they will randomly change order sometimes (Awair support doesn’t know why either). So pulling it by its comp name makes much more sense.

1 Like

Hi

I also have the Awair sensor and I was just looking into how to create a new binding (I have absolutely no idea) with the intention of adding it. Is your implementation a binding we could use?

The change in the order of values is annoying - it messed up my Google App Script that I’m using to log the values and feed them into the Zipabox and I had to fix it in the same way.

1 Like