JSONPATH updating Item state

  • Platform information:
    • Hardware: x86_64 Intel/8GB/14TB
    • OS: Ubuntu 14.04
    • openHAB version:Latest (apt-get)

I seem to be having a hard time getting my mind around httpget/postrequest and JSONPATH.

I am trying to update an item in Openhab from a URL that sends back json values.
information sent from aircon controller:

{
"AirStreamDeviceUId": "CB_ID",
"DeviceType": "ASH",
"SysOn": "on",
"SysMode": "cool",
"SysFan": "auto",
"SleepTimer": 0,
"UnitType": "Mitsubishi Electric",
"Supply": "21.9",
"Setpoint": "21.0",
"Temp": "21.9",
"RAS": "master",
"CtrlZone": 13,
"Tag1": "iZone Control Systems",
"Tag2": "",
"Warnings": "none",
"ACError": " OK",
"Id": 0,
"EcoLock": "true",
"EcoMax": "30.0",
"EcoMin": "15.0",
"NoOfConst": 1,
"NoOfZones": 8,
"SysType": "310",
"AirflowLock": "on",
"UnitLocked": "false",
"FreeAir": "disabled",
"FanAuto": "3-speed"
}

I need to use SysOn as the on/off state of my item.
I am using JSONPATH to get the info I need.
JSONPATH online evaluator shows “$…SysOn” (only 2 “.” it keeps showing as 3 for some reason) as the tranform I need.

I have tried this in rules but to no luck. I have also tried it as part of the item itself but again no luck.
I think the issue is that it returns “on” as a string not “ON” as a state.

Help very much appreciated.

EDIT:
Code in rule

rule "Aircon Polling"
when
        Time cron "10 0 0 ? * * *"
then
        var String json = sendHttpGetRequest("http://192.168.0.253/SystemSettings")
        var String temp = transform("JSONPATH", "$..SysOn", json)
        airconSystemOn.postUpdate(temp)
end

Show your code

Please try one dot:

var String temp = transform("JSONPATH", "$.SysOn", json)

This is due to the fact, that you didn’t mark the code as code:

$…SysOn (two dots) vs. $..SysOn (the very same text)

Be aware that discourse (the software which serves the community) will automatically change some typing, e.g. a # as first char in a line will build a topic:

Topic

To stop discourse doing that , you have to post code as code:

# Topic

Simply use Backticks (`) around these expressions. If posting a bunch of Code lines, use three Backticks in the line before and after the code:

```

Your code goes here

```

Thanks Udo,

I will keep that in mind.

I just tried 1 dot. It hasn’t updated from the controller itself again when a change happens.
Any other thoughts?

As You doing it in a rule, which is only triggered once a day…

Better doing it in an item. For this (as there are several values which might be interesting) use an http cache:
./services/http.cfg:

# http cache Item for air conditioning, updates once a minute
aircon.url=http://192.168.0.253/SystemSettings
aircon.updateInterval=60000

items:

Switch airconOn   "Air condition [%s]"     {http:"aircon:60000:JSONPATH($.SysOn)"}
Number airconTemp "Air condition [%.1f°C]" {http:"aircon:60000:JSONPATH($.Temp)"}
String airconMode "Air condition [%s]"     {http:"aircon:60000:JSONPATH($.SysMode)"}

Hang on… Once a day?
I got that cron expression from a cron generator and thought it should have been once every 10s.
That could be where the issue is.

What would the cron expression be for every 10secs?

I have also tried this in an item with an update of 10000. That still didn’t work. Although my code was:

Switch airconSystemOn           "Aircon Power"          <Heating>       (gAircon)       ["Switchable"]       {http = "<[http://192.168.0.253/SystemSettings:10000:JSONPATH($..SysOn)]"}

As for caching. I have thought of that. Unfortunately I need to access three separate url with 3 different results so instead of going the cache route for 2 and not the third I thought i would keep it all the same for the aircon and save caching for later on down the track if I need something else.

Every 10 Seconds would be

Time cron "0/10 * * * * ?"

This is Quartz cron, so the line is like

"s m h d M w y"

where

  • s is Seconds
  • m is Minutes
  • h is hours
  • d is Day of Month
  • M is Month
  • w is Day of Week
  • y is Year (this is optional)

For each paramater, you can use

  • a number (0 to 59)
  • a comma separated list (0,10,27,36 - without space)
  • regions 0-10,15-18
  • a frequency 0/10 (begin at 0, every 10 steps)
  • a * for "doesn’t matter
  • a ? when it comes to Day of week or Day of month. This is to indicate, you will have to use either Day of month or Day of week but not both of them.
  • several other expressions which will trigger e.g. only at the 3th monday of month, the last sunday of month, JAN,MAR,SEP or FRI-SUN is also possible (but you can use numbers for that, too

Ok.
Thank you for the cron expression. That gives me something I can look at.

Though it now has an error in the logs.

2018-09-09 18:25:00.006 [WARN ] [rthome.model.script.actions.BusEvent] - Cannot convert 'on' to a state type which item 'airconSystemOn' accepts: [OnOffType, UnDefType].

Ha… yes, that’s right, on != ON…
Please use a string item instead of Switch.
When using it in the rule, I guess there is something like .toUpperCase for strings, so it should work on the var temp.

When using it directly in items (my example above), you would have to use two transformations at once, so the only way to this is a Java Script:

Switch airconOn   "Air condition [%s]"     {http:"aircon:60000:JS(airconon.js)"}

./transform/airconon.js:

(function(dataString) {
var data = JSON.parse(dataString);
var airState = data['SysOn'].state.on;
var reply = "";
if (airState) reply = "ON";
if (!airState) reply = "OFF";
return reply;
})(input)
1 Like

I am happy to use a string item instead of switch but I am not sure how to compare strings or how to activate the rule with a string item. Edit: Nope. Scratch that part. Rule activation would be the same. Just how to deal with the strings in the rule
Would you have any pointers at all?

Here is my whole Rules file:

var String api = "https://192.168.0.253/SystemON"
var String onBody = "{\"SystemON\":\"on\"}"
var String offBody = "{\"SystemON\":\"off\"}"
var String body = ""

rule "Aircon Polling"
when
	Time cron "0/10 * * * * ?"
then
	var String json = sendHttpGetRequest("http://192.168.0.253/SystemSettings")
	var String temp = transform("JSONPATH", "$.SysOn", json)
	airconSystemOn.postUpdate(temp)
end

rule "Aircon Power Off"
when
    	Item airconSystemOn received command OFF
then
	body = "{\"SystemON\":\"off\"}"
	sendHttpPostRequest("http://192.168.0.253/SystemON", "application/json", body)
end

rule "Aircon Power On"
when
    	Item airconSystemOn received command ON
then
	body = "{\"SystemON\":\"on\"}"
    	sendHttpPostRequest("http://192.168.0.253/SystemON", "application/json", body)
end

rule "Aircon Mode Cool"
when
	Item airconMODECool received command ON
then
	body = "{\"SystemMODE\":\"cool\"}"
	airconMODEHeat.sendCommand(OFF)
	airconMODEVent.sendCommand(OFF)
	airconMODEDry.sendCommand(OFF)
	airconMODEAuto.sendCommand(OFF)
	sendHttpPostRequest("http://192.168.0.253/SystemMODE", "application/json", body)
end

rule "Aircon Mode Heat"
when
	Item airconMODEHeat received command ON
then
	body = "{\"SystemMODE\":\"heat\"}"
	airconMODEVent.sendCommand(OFF)
	airconMODEDry.sendCommand(OFF)
	airconMODEAuto.sendCommand(OFF)
	airconMODECool.sendCommand(OFF)
	sendHttpPostRequest("http://192.168.0.253/SystemMODE", "application/json", body)
end

rule "Aircon Mode Vent"
when
	Item airconMODEVent received command ON
then
//	body = "{\"SystemMODE\":\"vent\"}"
//	airconMODEDry.sendCommand(OFF)
//	airconMODEAuto.sendCommand(OFF)
//	airconMODECool.sendCommand(OFF)
//	airconMODEHeat.sendCommand(OFF)
//	sendHttpPostRequest("http://192.168.0.253/SystemMODE", "application/json", body)
	airconMODEVent.sendCommand(OFF)
end

rule "Aircon Mode Dry"
when
	Item airconMODEDry received command ON
then
	body = "{\"SystemMODE\":\"dry\"}"
	airconMODEAuto.sendCommand(OFF)
	airconMODECool.sendCommand(OFF)
	airconMODEHeat.sendCommand(OFF)
	airconMODEVent.sendCommand(OFF)
	sendHttpPostRequest("http://192.168.0.253/SystemMODE", "application/json", body)
end

rule "Aircon Mode Auto"
when
	Item airconMODEAuto received command ON
then
	body = "{\"SystemMODE\":\"auto\"}"
	airconMODECool.sendCommand(OFF)
	airconMODEHeat.sendCommand(OFF)
	airconMODEVent.sendCommand(OFF)
	airconMODEDry.sendCommand(OFF)
	sendHttpPostRequest("http://192.168.0.253/SystemMODE", "application/json", body)
end

rule "Aircon Fan Low"
when
	Item airconFANLow received command ON
then
	body = "{\"SystemFAN\":\"low\"}"
	airconFANMed.sendCommand(OFF)
	airconFANHigh.sendCommand(OFF)
	airconFANAuto.sendCommand(OFF)
	sendHttpPostRequest("http://192.168.0.253/SystemFAN", "application/json", body)
end

rule "Aircon Fan Med"
when
        Item airconFANMed received command ON
then
        body = "{\"SystemFAN\":\"medium\"}"
        airconFANHigh.sendCommand(OFF)
        airconFANAuto.sendCommand(OFF)
        airconFANLow.sendCommand(OFF)
        sendHttpPostRequest("http://192.168.0.253/SystemFAN", "application/json", body)
end

rule "Aircon Fan High"
when
        Item airconFANHigh received command ON
then
        body = "{\"SystemFAN\":\"high\"}"
        airconFANAuto.sendCommand(OFF)
        airconFANLow.sendCommand(OFF)
        airconFANMed.sendCommand(OFF)
        sendHttpPostRequest("http://192.168.0.253/SystemFAN", "application/json", body)
end

rule "Aircon Fan Auto"
when
        Item airconFANAuto received command ON
then
        body = "{\"SystemFAN\":\"auto\"}"
        airconFANLow.sendCommand(OFF)
        airconFANMed.sendCommand(OFF)
        airconFANHigh.sendCommand(OFF)
        sendHttpPostRequest("http://192.168.0.253/SystemFAN", "application/json", body)
end

rule "Aircon Zone1 Temp"
when
	Item airconZone1Temp received command
then
	var Number previous = airconZone1Temp.previousState(true).state
	if(receivedCommand == ON || receivedCommand == OFF) {airconZone1Temp.postUpdate(previous)}
	Thread::sleep(500)
	if(airconZone1Temp.state < 18) {airconZone1Temp.postUpdate(18)}
        if(airconZone1Temp.state > 30) {airconZone1Temp.postUpdate(30)}
	body = "{\"ZoneCommand\":{\"ZoneNo\":\"1\",\"Command\":\"" + airconZone1Temp.state.toString + "\"}}"
	sendHttpPostRequest("http://192.168.0.253/ZoneCommand", "application/json", body)
end

rule "Aircon Zone2 Temp"
when
        Item airconZone2Temp received command
then
	var Number previous = airconZone2Temp.previousState(true).state
        if(receivedCommand == ON || receivedCommand == OFF) {airconZone2Temp.postUpdate(previous)}
	Thread::sleep(500)
        if(airconZone2Temp.state < 18) {airconZone2Temp.postUpdate(18)}
        if(airconZone2Temp.state > 30) {airconZone2Temp.postUpdate(30)}
        body = "{\"ZoneCommand\":{\"ZoneNo\":\"2\",\"Command\":\"" + airconZone2Temp.state.toString + "\"}}"
        sendHttpPostRequest("http://192.168.0.253/ZoneCommand", "application/json", body)
end

rule "Aircon Zone3 Temp"
when
        Item airconZone3Temp received command
then
	var Number previous = airconZone3Temp.previousState(true).state
        if(receivedCommand == ON || receivedCommand == OFF) {airconZone3Temp.postUpdate(previous)}
        Thread::sleep(500)
	if(airconZone3Temp.state < 18) {airconZone3Temp.postUpdate(18)}
        if(airconZone3Temp.state > 30) {airconZone3Temp.postUpdate(30)}
        body = "{\"ZoneCommand\":{\"ZoneNo\":\"3\",\"Command\":\"" + airconZone3Temp.state.toString + "\"}}"
        sendHttpPostRequest("http://192.168.0.253/ZoneCommand", "application/json", body)
end

rule "Aircon Zone4 Temp"
when
        Item airconZone4Temp received command
then
	var Number previous = airconZone4Temp.previousState(true).state
        if(receivedCommand == ON || receivedCommand == OFF) {airconZone4Temp.postUpdate(previous)}
	Thread::sleep(500)
        if(airconZone4Temp.state < 18) {airconZone4Temp.postUpdate(18)}
        if(airconZone4Temp.state > 30) {airconZone4Temp.postUpdate(30)}
        body = "{\"ZoneCommand\":{\"ZoneNo\":\"4\",\"Command\":\"" + airconZone4Temp.state.toString + "\"}}"
        sendHttpPostRequest("http://192.168.0.253/ZoneCommand", "application/json", body)
end

rule "Aircon Zone5 Temp"
when
        Item airconZone5Temp received command
then
	var Number previous = airconZone5Temp.previousState(true).state
        if(receivedCommand == ON || receivedCommand == OFF) {airconZone5Temp.postUpdate(previous)}
        Thread::sleep(500)
	if(airconZone5Temp.state < 18) {airconZone5Temp.postUpdate(18)}
        if(airconZone5Temp.state > 30) {airconZone5Temp.postUpdate(30)}
        body = "{\"ZoneCommand\":{\"ZoneNo\":\"5\",\"Command\":\"" + airconZone5Temp.state.toString + "\"}}"
        sendHttpPostRequest("http://192.168.0.253/ZoneCommand", "application/json", body)
end

rule "Aircon Zone6 Temp"
when
        Item airconZone6Temp received command
then
	var Number previous = airconZone6Temp.previousState(true).state
        if(receivedCommand == ON || receivedCommand == OFF) {airconZone6Temp.postUpdate(previous)}
        Thread::sleep(500)
        if(airconZone6Temp.state < 18) {airconZone6Temp.postUpdate(18)}
        if(airconZone6Temp.state > 30) {airconZone6Temp.postUpdate(30)}
        body = "{\"ZoneCommand\":{\"ZoneNo\":\"6\",\"Command\":\"" + airconZone6Temp.state.toString + "\"}}"
        sendHttpPostRequest("http://192.168.0.253/ZoneCommand", "application/json", body)
end

rule "Aircon Zone7 Temp"
when
        Item airconZone7Temp received command
then
	var Number previous = airconZone7Temp.previousState(true).state
        if(receivedCommand == ON || receivedCommand == OFF) {airconZone7Temp.postUpdate(previous)}
        Thread::sleep(500)
        if(airconZone7Temp.state < 18) {airconZone7Temp.postUpdate(18)}
        if(airconZone7Temp.state > 30) {airconZone7Temp.postUpdate(30)}
        body = "{\"ZoneCommand\":{\"ZoneNo\":\"7\",\"Command\":\"" + airconZone7Temp.state.toString + "\"}}"
        sendHttpPostRequest("http://192.168.0.253/ZoneCommand", "application/json", body)
end

rule "Aircon Zone8 Temp"
when
        Item airconZone8Temp received command
then
	var Number previous = airconZone8Temp.previousState(true).state
        if(receivedCommand == ON || receivedCommand == OFF) {airconZone8Temp.postUpdate(previous)}
        Thread::sleep(500)
        if(airconZone8Temp.state < 18) {airconZone8Temp.postUpdate(18)}
	if(airconZone8Temp.state > 30) {airconZone8Temp.postUpdate(30)}
	body = "{\"ZoneCommand\":{\"ZoneNo\":\"8\",\"Command\":\"" + airconZone8Temp.state.toString + "\"}}"
        sendHttpPostRequest("http://192.168.0.253/ZoneCommand", "application/json", body)
end

All of those items activating the rules need a httpgetrequest similar to the airconSystemOn one.

Well, I think you did it fare more complex than necessary :slight_smile:

For example, take a look at the Mode. You are using five items, where you only need one item.

Number airconMODE "Mode is [MAP(airconmode.map):%s]"

The mapping file ./transform/airconmode.map :

1=Cool
2=Heat
3=Vent
4=Dry
5=Auto
-=-
NULL=-

and ONE Rule:

rule "Aircon Mode"
when
    Item airconMODE received command
then
    var String body
    switch (receivedCommand) {
        case 1: body = "{\"SystemMODE\":\"cool\"}"
        case 2: body = "{\"SystemMODE\":\"heat\"}"
        case 3: body = "{\"SystemMODE\":\"vent\"}"
        case 4: body = "{\"SystemMODE\":\"dry\"}"
        case 5: body = "{\"SystemMODE\":\"auto\"}"
        default: {
            logError("airconmode","Wrong Mode! {}",receivedCommand)
            return;
        }
    }
    sendHttpPostRequest("http://192.168.0.253/SystemMODE", "application/json", body)
end

In a Sitemap, you can chose to either use it as a Switch with multiple buttons:

String item=airconMODE mappings=[1="Cool",2="Heat",3="Vent"]
String item=airconMODE mappings=[4="Dry",5="Auto"]

Please take account to the fact, that I used 2 lines as there are 5 Buttons, which maybe will be to wide for some UIs, but as you can see, this is no problem at all, and this is 2 Lines vs. 5 Lines :wink:

But there is another option:

Selection item=airconMODE mappings=[1="Cool",2="Heat",3="Vent",4="Dry",5="Auto"]

This time all options in one Line, as this will draw a drop-down-selection.

Same is for Fan :slight_smile:

As you are already polling the System settings, I would rebuild the polling rule to set also the other items (a bunch of lines per Number item for Mode and Fan.

In question of zones, I would consider to use Grouping and only use one rule which fits all.

Thanks heaps for the help Udo.
I will try this approach and see what I can come up with. I’m using habpanel so I’m not sure how to get the multi button approach working with that but I will have a look.
I probably won’t have a chance to try properly until the weekend so I appreciate the help even if I can’t give this a go right now

You can use the Selection widget

Thanks for the help guys.
Everything is working now as should be.
I have used string items instead of 5 “mode” items and the same for some other stuff I have added into the system.
That works heaps better.

Vincent, I hadn’t checked the selection widget for HABPanel so thanks for that. Looks good

1 Like

You’re welcome,
Can you tick the solution, please?
hc_292