Solved: How to parse a JSON string into different OH Items?

Dear forum,

I am in the process of switching from OH1 to OH2. So far so good. While reworking rules and such, I found that there is a new Ebusd version that has in build MQTT support. Great for me, this reduces a lot of overhead compared to my “old” way of transmitting data from Ebus to OH.
What works:

  • OH2 in general, incl. MQTT messages that are sent and received
  • Ebusd in general. It understands the messages from my heating system and sends them via MQTT
  • Bringing the messages into OH2 String Items

What I am gloriously failing at is:

Parsing the contents of these String Items into separate Items that make sense. I can tell Ebusd to send the messages in two variants:

Ebusd MQTT output variant 1 - colon separated string (taken from Mosquitto subscription in verbose):

WP/ehp/SourceTempInput 10.38;ok

leading to the Karaf Log entry:

UG_HZ_SourceTempInput_IN changed from 10.56;ok to 10.50;ok

Ebusd MQTT output variant 2 - JSON string (taken from Mosquitto subscription in verbose):

WP/ehp/SourceTempInput {
     "temp": {"value": 10.50},
     "sensor": {"value": "ok"}}

leading to the Karaf Log entry:

UG_HZ_SourceTempInput_IN changed from {
     "temp": {"value": 10.50},
     "sensor": {"value": "ok"}} to {
     "temp": {"value": 10.19},
     "sensor": {"value": "ok"}}

The MQTT messages can contain more or less entries, but the principle should be the same.

Is there an easy way of decoding the messages into Items?

Thanks,
Christian

Hi,

I think you need the JsonPath transformation for this.
I use it for the following. I have an item with this value “mqtt_PhoneKris_PositionRaw changed from NULL to {”_type":“location”,“tid”:“12”,“acc”:52,“batt”:93,“conn”:“w”,“lat”:50.8993193,“lon”:5.4414403,“t”:“c”,“tst”:1508683525}"

And I transform it to multiple items using this rule:

rule "Locatie Kris berekenen"

when 
    Item mqtt_PhoneKris_PositionRaw changed
then
    val String json = (mqtt_PhoneKris_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_PhoneKris_Latitude.postUpdate(lat)
		mqtt_PhoneKris_Longitude.postUpdate(lon)
		mqtt_PhoneKris_Location.postUpdate(lat + "," + lon)
		mqtt_PhoneKris_Accuracy.postUpdate(acc)
		mqtt_PhoneKris_Battery.postUpdate(batt)
		mqtt_PhoneKris_LastUpdate.postUpdate(new DateTimeType())		
	}
end

2 Likes

Like @Dries already said, transform should solve the Problem for you.

You can use JSONPATH as already suggested or another transformation like JavaScript to get out the things you need.

But of course JSONPATH would be the preferred way, since your ecosystem can produce json messages already.

I would suggest you to take a general look @ http://docs.openhab.org/addons/transformations.html for further information.

Maybe you will find some other useful things that can help you during you oh migration.

Dear Dries,

thanks for the input, after some fiddeling it works. I got some errors in the Karaf Log stating that the “state” of my item is NULL. It was resolved by changing the JSON “filter” term to the right one :slight_smile: (here: $.temp.value)

For reference:

Items:

String UG_HZ_SourceTempInput_IN         "WPRohdaten"   { mqtt="<[mqttbroker:/WP/ehp/SourceTempInput:state:JS(trim.js)]" }
        /*
        /WP/ehp/SourceTempInput {
        "temp": {"value": 10.12},
        "sensor": {"value": "ok"}}
        */
        Number  UG_HZ_SourceTempInput           "Quellentemperatur [%.1f °C]"

Rule:

rule "Separator /WP/ehp/SourceTempInput"
        /*
        /WP/ehp/SourceTempInput {
        "temp": {"value": 10.12},
        "sensor": {"value": "ok"}}
        */
    when 
        Item UG_HZ_SourceTempInput_IN changed 
    then
        var String temperature  = transform("JSONPATH", "$.temp.value", (UG_HZ_SourceTempInput_IN.state).toString)
        UG_HZ_SourceTempInput.postUpdate(temperature)
end

Thanks,
Christian