JSON Handling in rules?

Hi to all sophisticated programmers,

more and more often the result of requests is a json string that could be parsed. The transform command is an appropriate way to access parts of the json string, but there must be more. I search google an found many information but one that i am able to transfer to openhab rules. What i am looking for is quite simple.

1.) Parse a json string into an object and access the information
2.) Build a json object and insert / retrieve information
3.) Export a json object to a string to do something with the string

It woulkd be great if someone could give me a hint to the right direction.

Thanks
Thomas

Hi,

You need the JSONPATH transformation for this.

Below you can find an example on how to parse a JSON object in to multiple items:

rule "Calculate location Dries"

when 
    Item mqtt_PhoneDries_PositionRaw changed
then
    val String json = (mqtt_PhoneDries_PositionRaw.state as StringType).toString
	val String type = transform("JSONPATH", "$._type", json)
	if (type == "location") {
		val String lat  = transform("JSONPATH", "$.lat", json)
		val String lon  = transform("JSONPATH", "$.lon", json)
		val String acc  = transform("JSONPATH", "$.acc", json)
		val String batt = transform("JSONPATH", "$.batt", json)
		
		mqtt_PhoneDries_Latitude.postUpdate(lat)
		mqtt_PhoneDries_Longitude.postUpdate(lon)
		mqtt_PhoneDries_Location.postUpdate(lat + "," + lon)
		mqtt_PhoneDries_Accuracy.postUpdate(acc)
		mqtt_PhoneDries_Battery.postUpdate(batt)
		mqtt_PhoneDries_LastUpdate.postUpdate(new DateTimeType())		

If you would like to store JSON data in an item (so the opposite direction), this might be an interesting topic.

[EDIT]
I re-read your post. Obviously you are well aware about JSONPATH. Ignore my post…
[/EDIT]

1 Like

Experimenting with JSON feeds

Using http://jsonpath.com/? to check the value “location”

rule "get WIJ next live train"
when
        // just a trigger
        Item CH1 changed
then
 var String json = sendHttpGetRequest("https://transportapi.com/v3/uk/train/station/WIJ/live.json?limit=10&api_key=b0ff1186e7e90369d423c1be16b1ae88&app_id=d476e439")

 var String value = transform("JSONPATH", "$.departures.all.0.mode", json)

 logInfo("JSON WIJ","*: mode" + value )
end

I get a full dump of the JSON return in openhab.log with a

2018-04-08 00:01:16.370 [ERROR] [ore.transform.actions.Transformation] - Error executing the transformation 'JSONPATH': Invalid path '$.departures.all.0.mode' in '{"dat < lots more JSON stuff >

I have tried a HTTP binding version with gives similar results, its working via HTTPS just the JSONPATH part is wrong i guess, I was temped to try a external script to get the value ( mode ) is just a test value for now which = train

I will continue reading the JSON entries in the community for other ideas

Can you hide your API key in the previous post and change it… :slight_smile:
Then can you post the json so that we can have a look, please?
But could it be $.departures.all[0].mode ?

1 Like

its a “issued test API key” , i did re check :wink: from https://www.transportapi.com/

{"date":"2018-04-08","time_of_day":"10:06","request_time":"2018-04-08T10:06:26+01:00","station_name":"Totton","station_code":"TTN","departures":{"all":[{"mode":"bus","service":"24671105","train_uid":"Q62142","platform":null,"operator":"SW","operator_name":"South Western Railway","aimed_departure_time":"10:23","aimed_arrival_time":"10:23","aimed_pass_time":null,"origin_name":"Southampton Central","destination_name":"New Milton","source":"Network Rail","category":"BR","service_timetable":{"id":"https://transportapi.com/v3/uk/train/service/train_uid:Q62142/2018-04-08/timetable.json?app_id=d476e439&app_key=b0ff1186e7e90369d423c1be16b1ae88&live=true"},"status":"BUS","expected_arrival_time":"10:23","expected_departure_time":"10:23","best_arrival_estimate_mins":16,"best_departure_estimate_mins":16},{"mode":"bus","service":"24671105","train_uid":"Q62087","platform":null,"operator":"SW","operator_name":"South Western Railway","aimed_departure_time":"10:30","aimed_arrival_time":"10:30","aimed_pass_time":null,"origin_name":"Poole","destination_name":"Southampton Central","source":"Network Rail","category":"BR","service_timetable":{"id":"https://transportapi.com/v3/uk/train/service/train_uid:Q62087/2018-04-08/timetable.json?app_id=d476e439&app_key=b0ff1186e7e90369d423c1be16b1ae88&live=true"},"status":"BUS","expected_arrival_time":"10:30","expected_departure_time":"10:30","best_arrival_estimate_mins":23,"best_departure_estimate_mins":23},{"mode":"bus","service":"24671105","train_uid":"Q62240","platform":null,"operator":"SW","operator_name":"South Western Railway","aimed_departure_time":"10:53","aimed_arrival_time":"10:53","aimed_pass_time":null,"origin_name":"Southampton Central","destination_name":"Poole","source":"Network Rail","category":"BR","service_timetable":{"id":"https://transportapi.com/v3/uk/train/service/train_uid:Q62240/2018-04-08/timetable.json?app_id=d476e439&app_key=b0ff1186e7e90369d423c1be16b1ae88&live=true"},"status":"BUS","expected_arrival_time":"10:53","expected_departure_time":"10:53","best_arrival_estimate_mins":46,"best_departure_estimate_mins":46},{"mode":"bus","service":"24671105","train_uid":"Q62143","platform":null,"operator":"SW","operator_name":"South Western Railway","aimed_departure_time":"11:02","aimed_arrival_time":"11:02","aimed_pass_time":null,"origin_name":"New Milton","destination_name":"Southampton Central","source":"Network Rail","category":"BR","service_timetable":{"id":"https://transportapi.com/v3/uk/train/service/train_uid:Q62143/2018-04-08/timetable.json?app_id=d476e439&app_key=b0ff1186e7e90369d423c1be16b1ae88&live=true"},"status":"BUS","expected_arrival_time":"11:02","expected_departure_time":"11:02","best_arrival_estimate_mins":55,"best_departure_estimate_mins":55},{"mode":"bus","service":"24671105","train_uid":"Q62144","platform":null,"operator":"SW","operator_name":"South Western Railway","aimed_departure_time":"11:23","aimed_arrival_time":"11:23","aimed_pass_time":null,"origin_name":"Southampton Central","destination_name":"New Milton","source":"Network Rail","category":"BR","service_timetable":{"id":"https://transportapi.com/v3/uk/train/service/train_uid:Q62144/2018-04-08/timetable.json?app_id=d476e439&app_key=b0ff1186e7e90369d423c1be16b1ae88&live=true"},"status":"BUS","expected_arrival_time":"11:23","expected_departure_time":"11:23","best_arrival_estimate_mins":76,"best_departure_estimate_mins":76}]}}

$.departures.all[0].mode

gives me “bus”, is that what you are looking for?

Ive been reading some docs on JSONPATH, maybe a more fault tolerant script might be a better approach as the returned JSON from this source can be so varied as there is a huge amount of available data , Yes “bus” for the first mode of transport available from WIJ, well it was at that time

You may then want to have a look at a javascript transform
You can parse the json into a javascript object and then do all sort of processing with it

I will hunt for some examples, these Rules and Transforms are new/different for me, But have learnt loads ways of processing data :smiley:

Create a file called mystrom.js in your transform folder
With the following content:

(function(i) {
    var data = JSON.parse(i);
    var transportmode = data.departures.all[0].mode
    if (transport != 'train') {
        result = 'true'
    } else {
        result = 'false'
    }
    return result;
})(input)

This will return a string true or false if the first available mode of transport is a train or not
Play with it
Have fun

1 Like

so would all the data (from the fetched JSON string) be available to that function, as in i could do three or four things and push the results back, with alterations obviously

or single use call like below

var String train = transform("JS", "mystrom.js", json)

the var “transportmode” and if (“transport” got me for a while :wink:

I guess if (transport == ‘train’)

“true” or “false” returned in value :+1:

You will need to create different javascript transform for each result wanted
The advantage is that you can process complicated jsons.
Sorry about the typo

(function(i) {
    var data = JSON.parse(i);
    var transportmode = data.departures.all[0].mode
    if (transportmode != 'train') {
        result = 'true'
    } else {
        result = 'false'
    }
    return result;
})(input)

ive been doing two atm, no worries about the code, it made me learn

(function(i) {
    var data = JSON.parse(i);
    var transport = data.departures.all[0].mode
        var nextd = data.departures.all[0].destination_name
        if (transport == 'bus') {
        result = 'true '+nextd+' '+transport
    } else {
        result = 'false'
    }
    return result;
})(input)

Cool you got it!! :slight_smile:
Try to keep your code tidy with the indentations and be consistent.
Don’t hesitate to use long variable names that mean something When you come back next year and look at your code, you want to be able to read it.
Another good practice is to start variable names in small letters but if you have two words in it then capitalize the second one, for example: transportMode, nextDestination.
I was guilty of not doing that earlier and also not to read my code back.

If you get good habits from the beginning, you’re halfway there.
Good luck!!

(function(i) {
    var data = JSON.parse(i);
    var transportMode = data.departures.all[0].mode
    var nextDestination = data.departures.all[0].destination_name
    if (transportMode == 'bus') {
        result = 'true ' + nextDestination + ' ' + transportMode
    } else {
        result = 'false'
    }
    return result;
})(input)

Good luck and enjoy. It is a lot of fun!!

1 Like