[JSR223] [JYTHON] Jython with requests successful?

Tags: #<Tag:0x00007f616f8ac898> #<Tag:0x00007f616f8ac758>

normal python works, however my openhab is inside a docker, so I’m guessing it’s a completely different environment.

From my point of view it is a problem with jython

Python 2 or 3? Jython is Pythoin 2 based.

Both python 2.7.5 and 3.6.8 work.

Here’s the code

import requests
def uv_protection_time():
    token = "xxxx" 
    params= {"lat": xxxxx, "lng": xxxxx, "from": 3, "to": 3, "alt": 100}
    r = requests.get("https://api.openuv.io/api/v1/protection", params=params, headers={"x-access-token": token})
    jsondata = r.json()
    print (jsondata['result']['from_time'])

uv_protection_time()

i will open an issue with jython

I’m using @5iver’s jar from [beta testers wanted!] Jython addon w/ helper libraries to have jython support on my installation.

Another similar issue I came across with jython and requests is that python < 2.7.9 doesn’t support SNI. Whilst there is a solution to this, it involves using pyOpenSSL which in turns, requires a cryptography module which is a compiled module, and apparently jython doesn’t support this

I hope I’m wrong and that there’s a solution to this. I have spent hours trying.

My main requirements are:

  • Need to perform HTTPS GET/POST
  • Using a custom header, e.g. “x-access-token: XXXXX”, “Authorization: XYZ SubscriberID=XXXXX”, etc.

AFAIK, the Openhab HTTP Action doesn’t support custom headers. Is there work on making it support custom headers?

I am reluctant to use HTTP Binding v1, so I haven’t even tried to see if it would work

There’s a HTTP Binding v2 WIP mentioned in here somewhere - but it seems to be abandoned at the moment.

If we could update Jython to python version 2.7.9+ that would be great too.

The jython project is not affiliated to OH and that are only at 2.7.1. We have no control or input into their development.

In OH3, I/we will be looking into integrating GraalVM into OH, which should allow for a much more modern Python and the possibility of other lanaguages. This has been discussed a few times in the forum. I still have this topic open in another tab (haven’t given up on this!) and might get to look at it this weekend. Another option for you is to use Java libraries. While custom headers may not be allowed with the Action, I’m sure the library supports them.

1 Like

Do you have any examples of using Java libraries from jython?

In the mean time I am resorting to using the command line curl, with Exec.executeCommandLine()

Pretty much all of the core modules use OH or Java libraries. Just import them as you would a Python library.

This is what I have used too.

I think python requests supports custom headers.

https://2.python-requests.org/en/master/

Definitely. However, I ran into problems with the requests module. One error was as reported in the OP. Another error was the lack of support for SNI as I explained several posts above. So requests is a no go for me unfortunately.

You could use HABApp and the normal request module since it’s python >= 3.6.

1 Like

Do you have a helper class to deal with curl / executeCommandLine? If none exists, I might write one. It would be super simple, but it would avoid code duplications. I’m thinking something like

curl = Curl("https://www.something.com")
curl.add_header(....)
curl.set_params(....)
curl.add_data(...) to be called multiple times - for POST), or curl.set_data(pass the data in a list)
curl.get() or curl.post()

In the background it will deal with executeCommandLine’s weird “@@” thing :smiley:

Is the requests error only within jython? On my system i get an error using requests within jython. If i use pur python it works like a charm.

To day i opend an issue at jythons github page

Wow, I’ve never heard of HABApp. Took a quick look at it. It seems like a viable solution. Must investigate more.

1 Like

Correct. See Post #9

I doubt if they can do much, but I’d be curious to know. It would take a while to trickle down to OpenHAB too, so it’s a very very long shot. For the time being curl works perfectly for me. Just need to write a helper class for it to make it nicer to use.

No… I’m familiar enough with curl and OH’s requirements that I haven’t needed one.

If there were to be a fix in Jython, it would be immediately available in OH. You can manually install whatever version of Jython you’d like. I’ve experienced errors causing rules not to run in 2.7.1 and 2.7.2b2. Oddly, the 2.7.2a1+ build that I made never had an issue.

1 Like

I can confirm, the Java HTTP libraries support them. You can see examples (Rules DSL but the Java will still be the same) at:

You could also use executeCommandLine or subprocess (subprocess works a bit better in my experience) to call curl as a work around. Here is an example using subprocess and wget (I’m just grabbing an icon).

from core.rules import rule
from core.triggers import when
from configuration import weather_icon_path
import subprocess
from javax.imageio import ImageIO
from java.io import File

@rule("Weather Icon",
      description="Copy the current weather conditions icon",
      tags=["weather"])
@when("Item vWeather_Conditions_Icon changed")
@when("System started")
def cond_icon(event):
    """
    Download the weather conditions icon from DarkSky and convert it from gif to
    png.
    """
    # OpenWeatherMap
#    cond_icon.log.info("Fetching weather conditions icon to {} from {}"
#                  .format(weather_icon_path, items["vWeather_Conditions_Icon"]))
#
#    results = subprocess.check_output(['/usr/bin/wget', '-q', '-O',
#                                       weather_icon_path,
#                                       str(items["vWeather_Conditions_Icon"])])
#
#    input_file  = File(weather_icon_path)
#    if not input_file.exists():
#        cond_icon.log.warn("Failed to fetch the weather icon!")
#        return
#
#    output_file = File(weather_icon_path.replace('gif', 'png'))
#    ImageIO.write( ImageIO.read(input_file), 'png', output_file)
#
#    results = subprocess.check_output(['rm', weather_icon_path])

    # DarkSky
    cond_icon.log.info("Fetching the weather conditions icon... {}".format(ir.getItem("vWeather_Conditions_Icon").state))
    dl = subprocess.Popen(['/usr/bin/wget', '-qO-',
                  'http://argus:8080/rest/items/vWeather_Conditions_Icon/state'],
                  stdout=subprocess.PIPE)
    dd = subprocess.Popen(['/bin/dd', 'bs=22', 'skip=1'], stdin=dl.stdout, stdout=subprocess.PIPE)
    dl.wait()
    f = open(weather_icon_path, "w")
    subprocess.call(['/usr/bin/base64', '-d'], stdout=f, stdin=dd.stdout)
    dd.wait()

Note, the ImageIO class I use to convert the gif to png is a Java class.

If you make a helper I strongly recommend using subprocess instead of executeCommandLine. It can be quite challenging if not impossible to get executeCommandLine to work sometimes. The way the arguments are pass as an array or tuple in subprocess helps avoid the whole @@ nonsense. In fact, if you look at the simple command I try to run in the commented out OpenWeatherMap example above, I never was able to get that simple wget to run using executeCommandLine. I used subprocess out of desperation and was very happy with how easy it was to use.