HTTP Binding or sendHttpGetRequest

I have a working HTTP Binding Item configured making successful request returning JSON through a Transformation setting a Number Item. This is all working.

However, I only want to use this Number Item for a short 30 minute window each weekday morning with updates about every 5 minutes. I know I can use the Update Interval on the HTTP Binding, but as it is currently defined it is running as part of the HTTP Service and therefore running continuously. I would like to limit when I retrieve this data to be a good web user.

I’m looking at the sendHttpGetRequest option, but I haven’t found a good example of defining an Item and only calling it in a rule for a specific window of time. Does it work the same as the HTTP Binding? Or do I need to introduce a Timer to delay the Update Interval?

Is there a better way?

1 Like

Use the cron builder to create a cron expression that you use in a Time cron triggered Rule and put the sendHttpGetRequest and transform into that rule.

Thanks Rich,

That’s the direction I was heading. I hadn’t thought about using the minutes parameter (below), I was thinking I would have to use a Thread::sleep, but I’ve read plenty of your comments about long sleeps to be shy of that method.

I’ll start experimenting with the Item definition, transformation, and surfacing the result.

when
        Time cron "0 0,10,20,25 6 ? * MON-FRI"
then

Having issues getting a valid response from the web provider. My HTTP Service Item works fine, but I cannot get the sendHttpGetRequest to return a valid response. Are there header differences between the two methods? URL encoding? Something is just not making sense here. I would share the urls, but I’m trying to stay off the radar for now.

Ok, I’m getting much closer. I am now looking for a good example of passing a URL with a Referer Header from a rule using sendHttpGetRequest. Then parsing the returned JSON. If anybody has a good working example with these I think I’ll be out of the woods.

I used this Rule before the binding was ready.

Here’s an example of what I’m trying to do. Again, I have this working when defined as an Item to the Http Service, but I really don’t want to be making this url request every 5 minutes. So the approach is to put it into a rule and call it via cron at only the times I want to update the Item defined outside of the rule.

I cannot figure out how to pass the Referer header through the sendHttpGetRequest. The url is not correctly parsed when I include it in the string.

Do I need to assemble the header onto the string going into the sendHttpGetRequest? I’ve tried about every permutation that I can think of.

rule "Retrieve Time Rule"
when
        Time cron "0 0,10,20,25 6 ? * MON-FRI"
then
        logInfo("TTRule", "Getting TT Now")
        url = "[https://www.YYYYY.com/Server/TTRequest?param1=n:100&param2=m:200&returnJSON=true&timeout=50000{Referer=https://www.YYYYY.com}]"

        var String json = sendHttpGetRequest(url)
        var ttime = transform(json, "ttsja.js", time)

        logInfo("TTRule", "Returned value" + ttime)

        TT_SJA.postUpdate(ttime)
end

When I used it, I used the url string as I used it in the http binding.
Did you try it manually in the browser?

The issue is that the site requires the Referer header to be populated/faked.

I have not found a way to use a Header in the sendHttpGetRequest function.

Here’s an example of what I get. When I run this same code with a vanilla request to http;//www.google.com, then it works fine. The sendHttpGetRequest doesn’t support Headers like the HTTP Service does, at least that I can tell.

        var String url = "https://www.google.com{Referer=https://www.google.com}"
        logInfo("TTime", "Making Get Request")
        logInfo("TTime", "URL:" + url)
        var String _json = sendHttpGetRequest(url)
2018-02-07 15:43:12.122 [INFO ] [marthome.model.script.TTime] - Making Get Request  
2018-02-07 15:43:12.124 [INFO ] [marthome.model.script.TTime] - URL:https://www.google.com{Referer=https://www.google.com}
2018-02-07 15:43:12.126 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Retrieve TTime': Illegal character in scheme name at index 8: https://www.google.com{Referer=https://www.google.com}

I’m sorry, but I have no clue on that one.

I’ve all but confirmed that Headers cannot be sent using the sendHttpGetRequest method. I’ve looked at the codes in GitHub and I see where HTTP Binding does parse out the Headers, but there is nothing in sendHttpGetRequest. Doesn’t look good.

Hi everyone, my first post but also my first real issue after years of using Openhab =)

I have a pretty simple use case where I need to call an HTTP endpoint and provide HTTP headers. Which I thought should be pretty straight forward but apparently not.

It works using http binding in .items. I have 30+ items where I need to do HTTP GET and I don’t want to copy / paste the URL and header information all over the item configuration. The URL also contains a deviceId query param so I can’t use the cache url configuration in http.cfg.

So I thought why not implement this in a rule. Once an item state changes I will call the HTTP GET and provide the needed headers. But this does not seem possible to do using sendHttpGetRequest. I guess the send method/function comes from an import of org.eclipse.smarthome.model.script.actions.Http

The sendHttpGetRequest() is using a HttpUtil class which has support for HTTP headers.

So I can think of five different approaches to solve this, in order of preference.

  1. Extend Http with an overloaded method that takes HTTP headers the way HttpUtil does. Can’t find any existing issue or PR on github regarding this…

  2. Use HttpUtil directly in my rule/script file. Can’t get this to work. Anyone know if it’s possible to import classes / functionality from org.eclipse.smarthome.io.net.http or 3rd party (jetty) into a rule or script?

  3. Use exec binding and curl

  4. Copy / paste URL and header information to 30+ places in .item files and use http1 binding.

  5. Introduce a new runtime component at home which need to act as a bridge/proxy between Openhab and my HTTP endpoint and add the needed HTTP headers.

I am surprised this is not available yet out of the box because most APIs require some sort of token provided in a HTTP header.

Or am I missing something completely and this is possible to do already today?

Or a python script

I had to get some data with a header too, although it was only one item, the string returned after JSONPATH transform needed another transformation so I would have needed another item.
I use node-red for some functionality that can be difficult to achieve with OH but very easy with node-red

And the node-red code/json:

[
    {
        "id": "a9eebb8d.fba3d",
        "type": "tab",
        "label": "Flow 1",
        "disabled": false,
        "info": ""
    },
    {
        "id": "ef747923.2a1e58",
        "type": "http request",
        "z": "a9eebb8d.fba3d",
        "name": "",
        "method": "GET",
        "ret": "txt",
        "url": "https://api.github.com/repos/arendst/Sonoff-Tasmota/tags",
        "tls": "",
        "x": 470,
        "y": 180,
        "wires": [
            [
                "a18dec1.b59151"
            ]
        ]
    },
    {
        "id": "51d65b1.b6e1b24",
        "type": "inject",
        "z": "a9eebb8d.fba3d",
        "name": "",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "repeat": "86400",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "x": 130,
        "y": 180,
        "wires": [
            [
                "77c832d0.ad9ffc"
            ]
        ]
    },
    {
        "id": "a6a9456f.54c2d",
        "type": "debug",
        "z": "a9eebb8d.fba3d",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "x": 910,
        "y": 140,
        "wires": []
    },
    {
        "id": "77c832d0.ad9ffc",
        "type": "function",
        "z": "a9eebb8d.fba3d",
        "name": "",
        "func": "msg.headers = {};\nmsg.headers['User-Agent'] = 'Mozilla/5.0';\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "x": 310,
        "y": 180,
        "wires": [
            [
                "ef747923.2a1e58"
            ]
        ]
    },
    {
        "id": "a18dec1.b59151",
        "type": "json",
        "z": "a9eebb8d.fba3d",
        "name": "",
        "property": "payload",
        "action": "",
        "pretty": false,
        "x": 610,
        "y": 180,
        "wires": [
            [
                "fc4afeeb.804d38"
            ]
        ]
    },
    {
        "id": "fc4afeeb.804d38",
        "type": "function",
        "z": "a9eebb8d.fba3d",
        "name": "",
        "func": "msg.payload=msg.payload[0].name.substr(1);\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 730,
        "y": 180,
        "wires": [
            [
                "a6a9456f.54c2d",
                "8f1e7830.423998"
            ]
        ]
    },
    {
        "id": "8f1e7830.423998",
        "type": "openhab2-out",
        "z": "a9eebb8d.fba3d",
        "name": "",
        "controller": "c022f913.0793f",
        "itemname": "Sonoff_Current_FW_Available",
        "topic": "ItemUpdate",
        "payload": "",
        "x": 950,
        "y": 180,
        "wires": [
            []
        ]
    },
    {
        "id": "c022f913.0793f",
        "type": "openhab2-controller",
        "z": "",
        "name": "Openhab",
        "protocol": "http",
        "host": "localhost",
        "port": "8080",
        "path": "",
        "username": "",
        "password": ""
    }
]
  1. It sure would be a nice contribution to OH.

  2. See OAuth2 using just OH Rules and myopenhab.org and iCloud device data integration in openHAB for a couple of examples of using core Java HTTP classes to issue HTTP requests with full support for headers.

  3. Would probably be the easiest approach.

  4. OK, this would probably be pretty easy too.

  5. Since I already have such a beast (https://github.com/rkoshak/sensorReporter) I would probably do it this way largely because 3 wouldn’t be an option since I run in Docker.

I think that most of the time when anything more than a straight call is required someone ends up writing a binding. Header stuff can be provided for sendHttpPostRequest I think (maybe it was Put). But no one has bothered to submit a PR to add this to the other ones.

1 Like

Thanks for your help and confirmation on my questions and alternatives. I am running Docker as well so I’ll probably look into adding another runtime component. Now I have a reason to start looking into Node Red as a “rules engine” :+1: the things I’ve read on the forum seems promising.