Problem using Paho mqtt from Jsr223 (Jython)

I am trying to set up a mqtt client from my jsr223 script. The story behind why is a longer story, which I will omit here.

I have found a sample which work in Python, but when I am calling the same code from my OpenHAB Jsr223 Python script, it thows an exception. I have tried all combinations here below, and none of them seem to work in Jython, where all of them works in Python.

#Work in Python
pahoClient = paho.Client()

#Work in Python
pahoClient = paho.Client("", True, None, paho.MQTTv31)

#Work in Python
pahoClient = paho.Client("", True, None, paho.MQTTv31, "tcp")

#Work in Python
pahoClient = paho.Client("", True, None, paho.MQTTv311, "tcp")

I receive the following exception:

sys.exc_info()[0]: '<class '_socket.error'>'
sys.exc_info()[1]: '[Errno 92] Protocol not available'```

If I use "websocket" instead of "tcp" it fails in Python. But as far as I remeber I havn't configured that in mosquitto..., 

OpenHAB runs as root. 
Any suggestions?

It could be a Jython bug. Doing a quick search for jython "[Errno 92] Protocol not available" I found the following reports that mention that type of error.

https://hg.python.org/jython/rev/b2c98eeaa744
https://hg.python.org/jython/rev/b3b82ef080a9

The good news is that there was a bug fix. The bad news is that the fix was made after the latest release of Jython. However, the somewhat good news is that the fix is in Python code so you can patch it yourself relatively easily based on the information in the bug reports. The file to patch is in your <python.home>/Lib directory and it’s called ‘_socket.py’. I’d try changing just changing the _realsocket and _socketobject proto argument default value in the init methods. I wouldn’t try to apply the entire patch since it may depend on other patches. Move the _socket.pyc (compiled file) to a backup file and try running your code again after restarting openHAB. It should compile your patch and use that module.

Another option is to create the MQTT client in the Jython command line interpreter first. This would avoid waiting around for openHAB to restart as you are trying some experiments.

Hmmm. No success. Might be because of my lack of python knowledge.
I changed argument default of proto two places in _realsocket from None to 0. In _socketobject it was already 0. I also tried changing it in exported socket class, which didn’t help.

I didn’t find any .pyc files in the directory. Instead the name seems to be: _socket$py.class

But anyway thanks for your help. I will take a closer look, when I have better time. Unless you can see some obvious mistake

Yeah, that’s right. For Jython the compiled files have a “$py.class” suffix. If you see a new _socket$py.class file that means it was recompiled.

The patch I saw changed the default in _socketobject from 0 to None (the opposite of _realsocket).

I have now tried to change it the two places you suggested, but i still get the error, so it might be something else.

Thanks for your suggestion.
Is it possible to combine the usage of python and javascripts in OpenHAB? That might be a solution for me.

The answer to this is yes, so I believe that I will go ahead using that approach :slight_smile:

In case you still want to use Jython, I found a workaround for the problem with a small change to the paho/mqtt/client.py file. Typically this is located in the Lib/site-packages directory of the Jython installation but it may be elsewhere if you did a nonstandard installation.

There’s a line that looks like (line 267 in my file)…

    listensock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_IP)

It worked for me to remove the third argument:

    listensock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

After that, I was able to connect to an MQTT broker and receive messages. This was the test program:

from paho.mqtt.client import Client

class TestClient(Client):
  def __init__(self, *args, **kwargs):
    super(TestClient, self).__init__(*args, **kwargs)
    self.monitor('on_connect')
    self.monitor('on_subscribe')
    self.monitor('on_message')

  def monitor(self, name):
    def dump_info(self, *args):
      print name, args
    setattr(self, name, dump_info)

client = TestClient()
client.connect("broker.hivemq.com")
client.subscribe("ohtest")

client.loop_forever()

Cool. That would definately make life a lot easier.

It works like a charm.
Thanks for your time!

Great! I’m glad I could help.