Using http to get/push state on a IPX800

Hello,

Long time lurker of what Openhab can do compare to other home automation solutions. I ran it for a while but then decided to migrate to k8s (yes, I like problems) and now what to put Openhab back into the home stack.

  • Platform information:
    • OS: talos 1.8.4
    • openHAB version: docker build version 5.0.0 SNAPSHOT
  • Issue of the topic: Using http binding and jsonpath/map transformations to get/push commands on a GCE IPX800v4

I’ve been browsing doc and forums for a while and my setup is rather simple compare to a lot of what’s been achieve so far in this forum.
I’ve read a thread to explain how to use this http binding and some webhooks to have realtime update, I have no need for realtime update and prefer to keep it simple. I’m sure I’ve done this succesfully in the past but with my migration to k8s I’ve put openhab on hold for a while (it was v3 back then).
The “push” commands are working like a charm, aka I bind a switch on a UI to that light, and commands are pushed to the IPX (my light turn on and off!)
However, when I change something from IPX side (I use the physical switch, or IPX gui/api), the binding “sees” it set the item state to UNDEF

UID: http:url:6ad004add1
label: IPX
thingTypeUID: http:url
configuration:
  authMode: BASIC
  ignoreSSLErrors: false
  baseURL: http://192.168.4.225/api/xdevices.json?key=apikey&
  delay: 0
  stateMethod: GET
  refresh: 300
  commandMethod: POST
  contentType: application/json
  timeout: 3000
  bufferSize: 2048
location: basement
channels:
  - id: last-failure
    channelTypeUID: http:request-date-time
    label: Last Failure
    configuration: {}
  - id: last-success
    channelTypeUID: http:request-date-time
    label: Last Success
    configuration: {}
  - id: light_wc
    channelTypeUID: http:switch
    label: light switch
    description: ""
    configuration:
      onValue: SetR=15
      mode: READWRITE
      offValue: ClearR=15
      stateExtension: Get=R
      commandExtension: "%2$s"
      stateTransformation:
        - JSONPATH($.R15)∩MAP(ipx_switch_value.map)
label: IPX light switch
type: Switch
icon: ""
groupNames: []
tags:
  - Light
  - Switch

map content for transformations

0=OFF
1=ON
2025-06-18 05:59:51.861 [TRACE] [ttp.internal.http.RefreshingUrlCache] - Requesting refresh (retry=false) from 'http://192.168.4.225/api/xdevices.json?key=apikey&Get=R' with timeout 3000ms
2025-06-18 05:59:51.862 [TRACE] [ttp.internal.http.RefreshingUrlCache] - Sending to 'http://192.168.4.225/api/xdevices.json?key=apikey&Get=R': Method = {GET}, Headers = {Accept-Encoding: gzip, User-Agent: Jetty/9.4.57.v20241219}, Content = {null}
2025-06-18 05:59:51.871 [TRACE] [p.internal.http.HttpResponseListener] - Received from 'http://192.168.4.225/api/xdevices.json?key=apikey&Get=R': Code = {200}, Headers = {Access-Control-Allow-Origin: *, Connection: close, Content-Type: application/json, Cache-Control: no-cache}, Content = {{
    "product": "IPX800_V4",
    "status": "Success",
    "R1": 0,
    "R2": 0,
    "R3": 0,
    "R4": 0,
    "R5": 0,
    "R6": 0,
    "R7": 0,
    "R8": 0,
    "R9": 0,
    "R10": 0,
    "R11": 0,
    "R12": 0,
    "R13": 0,
    "R14": 0,
    "R15": 1
}}
2025-06-18 05:59:51.871 [DEBUG] [ternal.JSonPathTransformationService] - about to transform '{
    "product": "IPX800_V4",
    "status": "Success",
    "R1": 0,
    "R2": 0,
    "R3": 0,
    "R4": 0,
    "R5": 0,
    "R6": 0,
    "R7": 0,
    "R8": 0,
    "R9": 0,
    "R10": 0,
    "R11": 0,
    "R12": 0,
    "R13": 0,
    "R14": 0,
    "R15": 1
}' by the function '$.R15'
2025-06-18 05:59:51.872 [DEBUG] [ternal.JSonPathTransformationService] - transformation resulted in '1'
2025-06-18 05:59:51.872 [DEBUG] [ap.internal.MapTransformationService] - Transformation resulted in 'ON'
2025-06-18 05:59:51.873 [TRACE] [.HttpDynamicStateDescriptionProvider] - returning new stateDescription for http:url:6ad004add1:light_wc
2025-06-18 05:58:14.410 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'IPX_light_switch' predicted to become OFF
2025-06-18 05:58:14.411 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'IPX_light_switch' changed from ON to OFF
2025-06-18 05:59:51.873 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'IPX_light_switch' changed from OFF to UNDEF

I’ve tried some many config that I’m started to get lost now if I’m might be chasing something impossible without the webhook mentionned here. I don’t really care if there is a delay between someone pressing a real world switch and it getting reflected in openhab ui.

Thanks!

The JSON is nested. There are two {{ at the start, not the usual one. So your JSONPATH might be failing, causing the full JSON to be passed to your MAP. But the logs seem to indicate that it might be working.

However, you have both the Map transformation and the onValue and offValue properties configured, and those are expecting SetR=15 for ON and ClearR=15 for OFF meaning that even if the JSONPATH is working (which it might be), the binding is trying to do an additional map to these values and since none of them match, it sets the state to UNDEF.

I suggest:

  • removing the chained Map transformation
  • set the onValue to 1 and the offValue to 0
  • set a commandTransformation that uses Map to convert ON to SetR=15 and OFF to ClearR=15

The webhook binding will let the IPX800 make HTTP GET calls into OH to set the states or command Items. This would be independent of the HTTP binding. The HTTP binding will poll the IPX800 every five minutes given the current Thing configuration.

I’ve just looked at the yaml version of the things file, the only difference is ‘stateTransformation’

      stateTransformation:
        - MAP:ipx_switch_value.map
        - JSONPATH:$.R15

So I adapted around your answer, here is how it ended up to have it working:

UID: http:url:6ad004add1
label: IPX
thingTypeUID: http:url
configuration:
  authMode: BASIC
  ignoreSSLErrors: false
  baseURL: http://192.168.4.225/api/xdevices.json?key=apikey&
  delay: 10
  stateMethod: GET
  refresh: 5
  commandMethod: POST
  contentType: text/plain
  timeout: 3000
  bufferSize: 2048
location: basement
channels:
  - id: last-failure
    channelTypeUID: http:request-date-time
    label: Last Failure
    configuration: {}
  - id: last-success
    channelTypeUID: http:request-date-time
    label: Last Success
    configuration: {}
  - id: light_wc
    channelTypeUID: http:switch
    label: light switch
    description: ""
    configuration:
      mode: READWRITE
      onValue: "1"
      commandTransformation:
        - MAP(ipx_switch_value_set.map)
      offValue: "0"
      stateExtension: Get=R
      commandExtension: "%2$s"
      stateTransformation:
        - JSONPATH($.R15)

Content of map:

1=SetR=15
0=ClearR=15

Thanks for the fast answer!

Another question here around IPX800, when I want to deal with dimmers.

I’ve seen I can use inline JS, but either I’m using it wrong, or I have a syntax issue because I cannot have it validated by the ui from config or code.

Am I allowed to define a channel as bellow?:

UID: http:url:6ad004add1
label: IPX
thingTypeUID: http:url
configuration:
  authMode: BASIC
  ignoreSSLErrors: false
  baseURL: http://192.168.4.225/api/xdevices.json?key=apikey&
  delay: 10
  stateMethod: GET
  refresh: 5
  commandMethod: POST
  contentType: text/plain
  timeout: 3000
  bufferSize: 2048
location: basement
channels:
  - id: light_d_bathroom
    channelTypeUID: http:dimmer
    label: light dimmer
    description: ""
    configuration:
      step: "25"
      offValue: "0"
      stateExtension: Get=G
      commandExtension: SetG04=%2$s
      stateTransformation:
        - JS:|input.G4.Etat === "OFF" ? 0 : input.G4.Valeur

I’ve tried with parenthesis but I get the same “result”, usually the statetransformation isn’t used at all.

With the example above, I get this value in code tab then in the config form tab:

{JS:|input.G4.Etat === "OFF" ? 0=input.G4.Valeur}

Example json of the IPX800 body for the dimmers :

{{
    "product": "IPX800_V4",
    "status": "Success",
    "G1": 
        {"Etat":"OFF",
        "Valeur":80},
    "G2": 
        {"Etat":"OFF",
        "Valeur":100},
    "G3": 
        {"Etat":"OFF",
        "Valeur":49},
    "G4": 
        {"Etat":"OFF",
        "Valeur":50}
}}

The input is a String. You have to parse it before you can navigate it like an object. And I’m pretty sure that’s not a proper syntax for a ternary operation.

JS: | (JSON.parse(input).G4.Etat == "OFF") ? 0 : JSON.parse(input).G4.Valeur

Thank you!

You must have been a monk in a previous life to be so patient with our issues :slight_smile:

To be fair with myself, I figured out the parsing part yesterday late night after I got so pissed with the formatting/linting issue and moved all the “code” to an external js file and use JS(myfile.js).

Here is the channel final code

  - id: light_d_bathroom
    channelTypeUID: http:dimmer
    label: light dimmer
    description: ""
    configuration:
      step: "25"
      offValue: "0"
      stateExtension: Get=G
      commandExtension: SetG04=%2$s
      stateTransformation:
        - 'JS: | (JSON.parse(input).G4.Etat == "OFF") ? 0 :
          JSON.parse(input).G4.Valeur'