HTTP Blockly help and clarification

Long story short, I created a simple device based on ESP8266 to control my Somfy RTS awning. The device responds to:

http://192.168.30.209/stop
http://192.168.30.209/up
http://192.168.30.209/down

I worked a bit with the HTTP binding to get the correct commands sent via a rollershutter item, but never got it to work. I ended up creating 3 unlinked switch items that trigger the commands via rule. Which leads to creating a simple rule with Blockly to execute. Since all 3 switches are part of group, I wanted one rule to iterate through status of each and send commands (and also update a UI widget). The only HTTP block is:

image

or

image

The inline script stack block of course fits into the Logic block, but the HTTP does not. This lead to playing around to create a few blocks:

image

image

Both the inline script block and the blocks I created work fine, just wondering if there is a proper way to get the stock HTTP Block to work in my scenerio (asking as a JS novice). Here is the final generated rule:

if (items.getItem('DeckAwningStopRTS').state == 'ON') {
  if (items.getItem('DeckAwningDownRTS').state == 'ON') {
    items.getItem('DeckAwningDownRTS').sendCommand('OFF');
  }
  if (items.getItem('DeckAwningUpRTS').state == 'ON') {
    items.getItem('DeckAwningUpRTS').sendCommand('OFF');
  }
  actions.HTTP.sendHttpGetRequest('http://192.168.30.209' + '/' + 'stop', 3000);
  items.getItem('DeckAwningStopRTS').sendCommand('OFF');
} else if (items.getItem('DeckAwningDownRTS').state == 'ON') {
  if (items.getItem('DeckAwningUpRTS').state == 'ON') {
    items.getItem('DeckAwningUpRTS').sendCommand('OFF');
  }
  actions.HTTP.sendHttpGetRequest('http://192.168.30.209' + '/' + 'down', 3000);
} else if (items.getItem('DeckAwningUpRTS').state == 'ON') {
  if (items.getItem('DeckAwningDownRTS').state == 'ON') {
    items.getItem('DeckAwningDownRTS').sendCommand('OFF');
  }
  actions.HTTP.sendHttpGetRequest('http://192.168.30.209' + '/' + 'up', 3000);
}

Again, some of these commands drive widget behavior, but I’m sure as they change within the group they are triggering the rule multiple times. Doesn’t seem to be a problem as it works fine. Just feels like there is a more elegant way.

The HTTP block doesn’t click in because it’s not a standalone block. It returns something, namely what ever was pulled from the HTTP GET request. Assign that to a variable and then it should click in place.

But something simple like this should be relatively trivial to set up with the HTTP binding. That should be the simplest approach. But you’ll want to be careful to configure it as a command only channel, meaning you do not fill in any of the state properties.

With the 3 switches, it seems exhausting. You can also use widget to directly trigger urlActions or pass an argument to Script.actionRuleContext: "{'cmd':'up'}"

I wouldn’t use three switches. I’d use one String Item and command “stop”, “up”, and “down” to it. Or maybe use a Rollershutter Item since that takes STOP/UP/DOWN as a command already. But then there’d need to be a MAP transformation to convert from STOP to stop.

The transformed command will be included in the URL using %2$. So the base URL for the HTTP Thing would be http://192.168.30.209 and the commandExtension would be %2$. Everything else should work as the default.

If using a Roillershutter Item and a rollershutter Channel type, you’d additionally fill in the upValue with “up”, downValue with “down” and stopValue with “stop”.

Then yo9u’d have just the one Item, no rules and it should just work.

This was my expectation, and drove the design of the ESP8266. Unless I set it up incorrectly, this method doesn’t work.

version: 1
things:
  http:url:1b43efadca:
    label: Deck Awning RTS
    config:
      baseURL: http://192.168.30.209/
      refresh: 30
      timeout: 3000
      delay: 0
      bufferSize: 2048
      authMode: BASIC
      stateMethod: GET
      commandMethod: GET
      contentType: application/json
      ignoreSSLErrors: false
    channels:
      last-failure:
        type: request-date-time
        label: Last Failure
      last-success:
        type: request-date-time
        label: Last Success
      DeckAwningRollershutterRTS:
        type: rollershutter
        label: Deck Awning Rollershutter RTS
        description: ""
        config:
          commandExtension: '%2$'
          upValue: up
          downValue: down
          stopValue: stop
          mode: READWRITE

Event log when rollershutter item is activated:

2026-01-22 14:43:26.832 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'DeckAwningRollershutterRTS' predicted to become UP
2026-01-22 14:43:26.833 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'DeckAwningRollershutterRTS' changed from UNDEF to 0 (source: org.openhab.core.autoupdate.optimistic)
2026-01-22 14:43:34.752 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'DeckAwningRollershutterRTS' changed from 0 to UNDEF (source: org.openhab.core.thing$http:url:1b43efadca:DeckAwningRollershutterRTS)

Does the Thing not make the HTTP call? That’s the only thing that I’d expect to happen and the only thing that I’d expect to work.

The events.log is kind of irrelevant because the device doesn’t report its current state. There is no way to sync up the actual state of the Item with the device so what I see in events.log is what I would expect.

I’d probably set autoupdate=false on that Item so there is no longer that “predeicted to become”. Just leave the Item as UNDEF because the actual state of the Item will never have any meaning anyway.

If your device does report its current state, that needs to be on a different URL endpoint that returns an integer between 0 and 100. Something like http://192.168.30.209/state and then you’d configure the stateExtension to state. Then the binding will update the Item based on what ever number is returned. But without that, this Item’s state will always be UNDEF.

The awning isn’t moving, so either there is no call or it isn’t formatted correctly. With Binding in TRACE:

2026-01-22 15:18:03.258 [TRACE] [nding.http.internal.HttpThingHandler] - Sending to 'http://192.168.30.209/%252$': Method = {GET}, Headers = {Accept-Encoding: gzip, User-Agent: Jetty/9.4.57.v20241219}, Content = {null}
2026-01-22 15:18:03.380 [TRACE] [p.internal.http.HttpResponseListener] - Received from 'http://192.168.30.209/%252$': Code = {404}, Headers = {Content-Type: text/plain, Content-Length: 183, Connection: keep-alive, Keep-Alive: timeout=2000}, Content = {Not Found

Available endpoints:
  /        - Web interface
  /up      - Open awning
  /down    - Close awning
  /stop    - Stop awning
  /prog    - Pair mode
  /status  - JSON status
}

Agree. State is not important. UP, DOWN, STOP are what RTS accepts, and it is one way. My device only (by design) converts the http call to RTS.

You’re getting a 404 error back from the request because your command extension is not being properly parsed (/%252 is not one of your endpoints).

You need to add the javaformat that you want to the injected string variable. In this case just s:

commandExtension: '%2$s'

should do the trick.

Missed a simple line in the HTTP binding docs. Instead of %2$, use %2$s. Rollershutter works fine now. Thanks.

Posted about the same time. Thanks.

1 Like

maybe of interest: You can use the great rollershutter-profile from the marketplace to enable the position-state for your stateless shutters.

https://www.openhab.org/addons/transformations/rollershutterposition/

You just have to enter the up- and down-duration in the profile and the rest is handled by the profile. The shutter behaves like a two-way shutter that you can send to any position.

With a small rule the position even survives system reboots.