Parse the response from a TCP request

Hi,
I defined different items with corresponding map files like

Switch lights_wall “Lights Wall” [ “Lighting” ] {tcp=“>[ON:192.168.178.32:1139:MAP(wall_lights.map)], >[OFF:192.168.178.32:1139:MAP(wall_lights.map)]”}

where the map files look like

ON=3H34GJ67NH001
OFF=3H34GJ67NH001

The sending part works as expected. The response I get gives information about all available values and status and is JSON formated. Now I want to parse this response. How can I achieve this? Currently I got following warning in the openHAB2 log:

2020-11-27 18:48:41.568 [WARN ] [ing.tcp.protocol.internal.TCPBinding] - Cannot parse input {“d”:[0,0,1,0,1,1,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1],“a”:[24,20,22,20,0,20,90,0,24,20,0,47,46,37,47,1,1,1,1,1]} to match command ON on item lights_wall

It is possible to run a script or something else to parse the JSON and perform several actions?

Thanks for your help

Yes it is possible.

What device are you tying to control (interested)?

I would use a JS transformation.

the command 3H34GJ67NH001 looks like it is a toggle so you will never know if its on or off is this correct?

Yes it is a toggle and I use the response to receive the current state of the items.

Last year I bought a house where an old Crestron controller was used for controlling the lights and so on. Because it is very hard to extend by third party stuff, I decided to use a Raspi with OH to expand the system. The controller supports simple TCP communication. I wrote a Simpl+ module (Crestron Programming Language) to handle the communication. Everything works very fine except the fact I had no information about the current status. This I want to change now.

Do you have an example for the JS transformation?

Here try this I like a challenge

Create these items

Switch 0_Digital_IO "Light in Garage"
Switch 2_Digital_IO "Fire Works Display"
...
Switch 24_Digital_IO "Toilet Exhaust Fan"

Rule

rule "Transform json message to items"
when
    Item Incoming_json changed // Name of the item you have on the incoming json
then
  val dString = transform("JSONPATH", "$.d", Incoming_json.state.toString)
  val d_array = dString.replace('[','').replace(']','').replace(' ','')
  val d_buffer =  d_array.split(",") 

  d_buffer.forEach[ num , index | 
   var state = transform("MAP", "onoff.map", num)
   var item = index + "_Digital_IO"
   item.sendCommand(state)
  ]

end

Transformation File
onoff.map

Mine is

1=ON
ON=1
On=ON
on=ON
0=OFF
OFF=0
Off=OFF
off=OFF
=Error

I love challenges :wink:

Many thanks! I will try later and will give feedback :blush:

Should a add an item to receive the response to? This is the part I don’t understand from the rule part:

Item Incoming_json changed // Name of the item you have on the incoming json

I change Incoming_json to one of my items. I my example light_kitchen. Now I can see that the rule is fired on change. To check what the content of light_kitchen.state.toString is, I logged it. Unfortunately I got only the current status from the state property
2020-11-28 19:40:14.761 [INFO ] [ome.model.script.cp2e_response.rules] - receive value: ON
Instead of ON I would expect here the JSON string response. I think I got something wrong here. Should I add new item to receive the JSON response on?

The item should be a string item I used this one to test

String Incoming_json {channel="mqtt:topic:test:json"}

I am not sure how you ask your system for the string, what Crestron controller do you have.

I have a series 2 controller.

I designed the following: An item which sends a TCP command to the controller via the TCP binding
Switch myitem "My Item" <light> ["Lightning"] {tcp=">[ON:X.X.X.X:X:MAP(my.map)], >[OFF:X.X.X.X:X:MAP(my.map)]"} depending on the mapping in the my.map file a string is send to the controller. The controller parse the string and do sth. As response I create a JSON string which contains the current status of all items within the controller. The response is successfully transferred to the OH2 as I show in the log. Now I want to parse this response.
If I have to use a string item for the rule part, how can I pass the response string to this item?

Try

String Incoming_json  {tcp="<[*:192.168.178.32:1139:]"}

Unfortunately this doesn’t work. The string receive nothing.
Another thing I do not understand is, that if I toggle one switch, all switches receives the response:
2020-11-29 10:15:52.519 [WARN ] [rm.AbstractFileTransformationService] - Could not transform '{"d":[0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1],"a":[22,70,20,70,21,20,70,20,22,70,21,41,44,34,41,1,1,1,1,1]}' with the file 'plug_living.map' : Target value not found in map for '{"d":[0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1],"a":[22,70,20,70,21,20,70,20,22,70,21,41,44,34,41,1,1,1,1,1]}' 2020-11-29 10:15:52.522 [WARN ] [ing.tcp.protocol.internal.TCPBinding] - Cannot parse input {"d":[0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1],"a":[22,70,20,70,21,20,70,20,22,70,21,41,44,34,41,1,1,1,1,1]} to match command ON on item plug_live 2020-11-29 10:15:52.527 [WARN ] [rm.AbstractFileTransformationService] - Could not transform '{"d":[0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1],"a":[22,70,20,70,21,20,70,20,22,70,21,41,44,34,41,1,1,1,1,1]}' with the file 'plug_living.map' : Target value not found in map for '{"d":[0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1],"a":[22,70,20,70,21,20,70,20,22,70,21,41,44,34,41,1,1,1,1,1]}'
and so on…

EDIT: IT WORKS!!! I had to change the arrow directory :slight_smile: from < to >

Good I glad you got it working.

Can you change the commands in the controller from toggle to accept different commands for ON OFF?

Now that you are receiving the state of all the digital inputs you could also do the analogue ones. Are you using any of those inputs?

Many thanks for your support!

Yes I will change the TCP interface of the controller to directly reacting on ON and OFF. I am currently have to transfer all GUI to OH because my Crestron touch panel is not working anymore. Therefore I will use all the analog values as well now. I plan to write the complete rule today.

Do you have any hint on how to suppress the response from the controller on the switch items? If I extend the map files by =ERROR a error is logged, correct? But in my case I want no reaction.

Ok here is a rule you can use to do both

Ok here it is in text but I changed the names of the items to have the number at the end.

rule "Transform json message to items and numbers"
when
    Item Incoming_json changed
then
  val Digital_String = transform("JSONPATH", "$.d", Incoming_json.state.toString) // Get the string of data for only Digital Inputs
  val Digital_Array = Digital_String.replace('[','').replace(']','').replace(' ','') // Remove characters we don't want  
  val Digital_Buffer =  Digital_Array.split(",") // Spit the array to crate a buffer  

  val Analogue_String = transform("JSONPATH", "$.a", Incoming_json.state.toString) // Analogue String
  val Analogue_Array = Analogue_String.replace('[', '').replace(']', '') // Remove characters we don't want  
  val Analogue_buffer =  Analogue_Array.split(",")  // Spit the array to crate a buffer  

  Digital_Buffer.forEach[ Binary , Index | 
   var state = transform("MAP", "onoff.map", Binary)
   var item = "Digital_IO_" + Index
   item.sendCommand(state)
  ]
 
  Analogue_buffer.forEach[ Value, Index | 

   var item = "Analogue_IO_" + Index
   item.sendCommand(Value)
  ]

end

Items for you to make it easy

// Items are defined using the following syntax:
// itemtype itemname "labeltext [stateformat]" <iconname> (group1, group2, ...) ["tag1", "tag2", ...] {bindingconfig}

Switch Digital_IO_0
Switch Digital_IO_1
Switch Digital_IO_2
Switch Digital_IO_3
Switch Digital_IO_4
Switch Digital_IO_5
Switch Digital_IO_6
Switch Digital_IO_7
Switch Digital_IO_8
Switch Digital_IO_9
Switch Digital_IO_10
Switch Digital_IO_11
Switch Digital_IO_12
Switch Digital_IO_13
Switch Digital_IO_14
Switch Digital_IO_15
Switch Digital_IO_16
Switch Digital_IO_17
Switch Digital_IO_18
Switch Digital_IO_19
Switch Digital_IO_20
Switch Digital_IO_21
Switch Digital_IO_22
Switch Digital_IO_23
Switch Digital_IO_24

Number Analogue_IO_0
Number Analogue_IO_1
Number Analogue_IO_2
Number Analogue_IO_3
Number Analogue_IO_4
Number Analogue_IO_5
Number Analogue_IO_6
Number Analogue_IO_7
Number Analogue_IO_8
Number Analogue_IO_9
Number Analogue_IO_10
Number Analogue_IO_11
Number Analogue_IO_12
Number Analogue_IO_13
Number Analogue_IO_14
Number Analogue_IO_15
Number Analogue_IO_16
Number Analogue_IO_17
Number Analogue_IO_18
Number Analogue_IO_19
Number Analogue_IO_20
Number Analogue_IO_21
Number Analogue_IO_22
Number Analogue_IO_23
Number Analogue_IO_24

In the rule you may need to use postUpdate instead of sendCommand

Otherwise when you turn on the switch it may create a loop of commands and bring you system to its knees.

1 Like

Thanks a lot! Everything works as expected now!

1 Like