Black Lives Matter - Action and Equality. ... Adafruit joins the Stop Hate for Profit campaign.
0

mqtt_client.py raises RuntimeError
Moderators: adafruit_support_bill, adafruit

Forum rules
If you're posting code, please make sure your code does not include your Adafruit IO Active Key or WiFi network credentials.
Please be positive and constructive with your questions and comments.

mqtt_client.py raises RuntimeError

by krambriw on Sat Feb 20, 2016 11:30 am

This is an irritating error. Suddenly, this exception is raised and a current connection/subscription is lost. Any idea why this happens? I have not called a disconnect in the code.

Kind regards

Code: Select all | TOGGLE FULL SIZE
16:26:03   Exception in thread Thread-436:
16:26:03   Traceback (most recent call last):
16:26:03     File "threading.pyc", line 532, in __bootstrap_inner
16:26:03     File "threading.pyc", line 484, in run
16:26:03     File "C:\Program Files (x86)\EventGhost\plugins\Adafruit MQTT Client\Adafruit_IO\paho\mqtt\client.py", line 2287, in _thread_main
16:26:03       self.loop_forever()
16:26:03     File "C:\Program Files (x86)\EventGhost\plugins\Adafruit MQTT Client\Adafruit_IO\paho\mqtt\client.py", line 1261, in loop_forever
16:26:03       rc = self.loop(timeout, max_packets)
16:26:03     File "C:\Program Files (x86)\EventGhost\plugins\Adafruit MQTT Client\Adafruit_IO\paho\mqtt\client.py", line 811, in loop
16:26:03       rc = self.loop_read(max_packets)
16:26:03     File "C:\Program Files (x86)\EventGhost\plugins\Adafruit MQTT Client\Adafruit_IO\paho\mqtt\client.py", line 1075, in loop_read
16:26:03       return self._loop_rc_handle(rc)
16:26:03     File "C:\Program Files (x86)\EventGhost\plugins\Adafruit MQTT Client\Adafruit_IO\paho\mqtt\client.py", line 1382, in _loop_rc_handle
16:26:03       self.on_disconnect(self, self._userdata, rc)
16:26:03     File "C:\Program Files (x86)\EventGhost\plugins\Adafruit MQTT Client\Adafruit_IO\mqtt_client.py", line 80, in _mqtt_disconnect
16:26:03       raise RuntimeError('Unexpected disconnect with rc: {0}'.format(rc))
16:26:03   RuntimeError: Unexpected disconnect with rc: 1
16:26:03   

krambriw
 
Posts: 22
Joined: Fri Feb 19, 2016 6:07 pm

Re: mqtt_client.py raises RuntimeError

by krambriw on Sun Feb 21, 2016 4:13 am

I made a temporary work-around by modifying the code in module mqtt_client.py

When connection is lost, instead of raising an exception, I send an event 'disconnect' to the subscribed feed. The user needs to detect this particular event and re-initiate the connection. Automatic re-connection can work fine with this change as shown in the sample from my log below

Preparing to make subscribed feed available to function _mqtt_disconnect
Code: Select all | TOGGLE FULL SIZE
        # Modified by krambriw 2015-02-21
        # -to support sending disconnection error events
        self.feed_id = None


Defining self.feed_id = feed_id
Code: Select all | TOGGLE FULL SIZE
    def subscribe(self, feed_id):
        """Subscribe to changes on the specified feed.  When the feed is updated
        the on_message function will be called with the feed_id and new value.
        """
        # Modified by krambriw 2015-02-21
        # - making feed_id available to all functions
        self.feed_id = feed_id
        self._client.subscribe('{0}/feeds/{1}'.format(self._username, feed_id))


Modified function _mqtt_disconnect
Code: Select all | TOGGLE FULL SIZE
    def _mqtt_disconnect(self, client, userdata, rc):
        logger.debug('Client on_disconnect called.')
        self._connected = False
        # If this was an unexpected disconnect (non-zero result code) then raise
        # an exception.
        # Modified by krambriw 2015-02-21
        # - sending disconnection error events instead of raising exceptions

        #if rc != 0:
        #    raise RuntimeError('Unexpected disconnect with rc: {0}'.format(rc))
        if rc != 0:
            self.on_message(self, self.feed_id, 'disconnect')
        #
        #
        # Call the on_disconnect callback if available.
        if self.on_disconnect is not None:
            self.on_disconnect(self)


From my log
09:02:02 Please wait, Adafruit-IO MQTT client is starting up...
09:02:02 Communication with Adafruit-IO started...
09:02:02 Adafruit_IO.wktest u"my message"
09:09:46 disconnect received
09:09:46 Communication with Adafruit-IO stopped...
09:09:47 Communication with Adafruit-IO started...
09:09:47 Adafruit_IO.wktest u"my message"

krambriw
 
Posts: 22
Joined: Fri Feb 19, 2016 6:07 pm

Re: mqtt_client.py raises RuntimeError

by krambriw on Sun Feb 21, 2016 7:25 am

It seems that connections are closed by the server on a regular interval (5 min). Is this by purpose?

09:21:32 Adafruit_IO.wktest u"my message"
09:21:32 Main.OnInit
09:23:02 System.Idle
09:26:32 disconnect received
09:26:34 Adafruit_IO.wktest u"my message"
09:27:06 System.UnMute '44.00'
09:31:34 disconnect received
09:31:35 Adafruit_IO.wktest u"my message"
09:36:36 disconnect received
09:36:37 Adafruit_IO.wktest u"my message"
09:41:37 disconnect received
09:41:39 Adafruit_IO.wktest u"my message"
09:46:39 disconnect received
09:46:40 Adafruit_IO.wktest u"my message"
09:51:40 disconnect received
09:51:42 Adafruit_IO.wktest u"my message"
09:56:42 disconnect received
09:56:44 Adafruit_IO.wktest u"my message"
10:01:44 disconnect received
10:01:45 Adafruit_IO.wktest u"my message"
10:06:45 disconnect received
10:06:47 Adafruit_IO.wktest u"my message"
10:11:47 disconnect received
10:11:48 Adafruit_IO.wktest u"my message"
10:16:49 disconnect received
10:16:50 Adafruit_IO.wktest u"my message"
10:20:09 Adafruit_IO.wktest u"my message"
10:25:09 disconnect received
10:25:10 Adafruit_IO.wktest u"my message"
10:30:10 disconnect received
10:30:12 Adafruit_IO.wktest u"my message"
10:35:12 disconnect received
10:35:13 Adafruit_IO.wktest u"my message"
10:40:13 disconnect received
10:40:15 Adafruit_IO.wktest u"my message"
10:45:15 disconnect received
10:45:17 Adafruit_IO.wktest u"my message"
10:50:17 disconnect received
10:50:18 Adafruit_IO.wktest u"my message"
10:55:18 disconnect received
10:55:20 Adafruit_IO.wktest u"my message"
11:00:20 disconnect received
11:00:22 Adafruit_IO.wktest u"my message"
11:05:22 disconnect received
11:05:23 Adafruit_IO.wktest u"my message"
11:10:23 disconnect received
11:10:25 Adafruit_IO.wktest u"my message"
11:15:25 disconnect received
11:15:27 Adafruit_IO.wktest u"my message"
11:20:27 disconnect received
11:20:28 Adafruit_IO.wktest u"my message"
11:25:28 disconnect received
11:25:30 Adafruit_IO.wktest u"my message"
11:30:30 disconnect received
11:30:32 Adafruit_IO.wktest u"my message"
11:35:32 disconnect received
11:35:33 Adafruit_IO.wktest u"my message"
11:40:33 disconnect received
11:40:35 Adafruit_IO.wktest u"my message"
11:45:35 disconnect received
11:45:37 Adafruit_IO.wktest u"my message"

krambriw
 
Posts: 22
Joined: Fri Feb 19, 2016 6:07 pm

Re: mqtt_client.py raises RuntimeError

by adafruit2 on Tue Feb 23, 2016 12:29 am

yes there is a 5 minute timeout, you can ping or publish to reset
https://learn.adafruit.com/mqtt-adafrui ... the-server

adafruit2
Site Admin
 
Posts: 19221
Joined: Fri Mar 11, 2005 7:36 pm

Re: mqtt_client.py raises RuntimeError

by krambriw on Tue Feb 23, 2016 2:16 am

Hi, ok, I thought I did it correctly but maybe misunderstood

Is that needed on a per feed/topic basis?

That is, in my current implementation I am connecting & subscribing to a feed/topic named 'test1' and several times per minute publishing to 'test2'.

To avoid being kicked out, is it then required that I also publish 'something' to 'test1' at least once every five minutes?

krambriw
 
Posts: 22
Joined: Fri Feb 19, 2016 6:07 pm

Re: mqtt_client.py raises RuntimeError

by adafruit2 on Tue Feb 23, 2016 10:57 am

its per connection

adafruit2
Site Admin
 
Posts: 19221
Joined: Fri Mar 11, 2005 7:36 pm

Re: mqtt_client.py raises RuntimeError

by eric_w_page on Thu Feb 25, 2016 3:09 am

krambriw, thanks for your work on this. I'm dealing with the same issue. Where did you change the mqtt_client.py code? It looks like your code is on Windows and I"m on a Pi (Jessie version of Linux). Did you root down to the where you saw the error message?
Code: Select all | TOGGLE FULL SIZE
File "C:\Program Files (x86)\EventGhost\plugins\Adafruit MQTT Client\Adafruit_IO\mqtt_client.py", line 80, in _mqtt_disconnect

and then change that code that was written by Adafruit? or did you change it somewhere else? It's definitely hacky but if it works, I'm happy. Just concerned about the ineveitalbe breakage when the code gets updated.

Did you find any alternative/better solutions to this?

eric_w_page
 
Posts: 11
Joined: Thu Oct 08, 2015 2:12 am

Re: mqtt_client.py raises RuntimeError

by krambriw on Thu Feb 25, 2016 3:35 am

Hello Eric,
Yes, it is a hack and unless adafruit themselves are considering the problem and making a solution, I am aware we/you need to re-apply the hack after each update.

Right, I am running this on Windows and I made the code change in adafruits library, in the file mqtt_client.py. I could not find a better solution because this is the file where the exception is raised. It should be around line 80 unless you have a very different version. Anyway, I have attached the modified file so you could run it in an editor, maybe make file compare to see the changes clearer.
mqtt_client.zip
(2.86 KiB) Downloaded 34 times


What this hack does is sending an event instead of raising an exception. This is more handy since now you have something to act on. In may case I have a Python software that catches events from io.adafruit.com and the specific section looks like this:

Code: Select all | TOGGLE FULL SIZE
        def message(client, feed_id, payload):
            msg = feed_id
            pl = payload
           
            if pl <> 'disconnect':
                if (self.oldEvent <> msg+pl or self.repeat):
                    eg.TriggerEvent(
                        msg,
                        payload = pl,
                        prefix=self.prefix
                    )
                    self.oldEvent = msg+pl
               
            if pl == 'disconnect':
                client.disconnect()
                disconnected
                if not self.started and not self.inProgress:
                    goInit()


To goInit() looks like this:

Code: Select all | TOGGLE FULL SIZE
        def goInit():
            while self.client == None:
                try:
                    self.client = goConnect()
                except:
                    pass
                time.sleep(0.1)


        def goConnect():
            # Create an MQTT client instance.
            client = MQTTClient(adafruitUser, adafruitIOkey)
            # Setup the callback functions defined above.
            client.on_connect    = connected
            client.on_disconnect = disconnected
            client.on_message    = message
            # Connect to the Adafruit IO server and start subscribing.
            client.connect()
            client.loop_background()
            return client



I am not claiming that this is 100% perfect (I started with this project 2 days ago) but so far it seems to work very well.

When I receive the event 'disconnect' (due to the hack) I start the process of cleaning up the 'dead' session and begin a new trial to connect (there are a number of flags involved to avoid too many retries simultaneously etc)

Kind regards,
Walter

krambriw
 
Posts: 22
Joined: Fri Feb 19, 2016 6:07 pm

Re: mqtt_client.py raises RuntimeError

by eric_w_page on Thu Feb 25, 2016 10:38 pm

super helpful, Walter. Thank you. I'm new to Pi, Python, and writing software in general so it's been quite the experience. I had to modify your code to account for the fact that, I think, you call the modified Adafruit code via a class whereas I'm not. What I've done ain't pretty but it looks to be mostly working now! Thanks for the help

eric_w_page
 
Posts: 11
Joined: Thu Oct 08, 2015 2:12 am

Please be positive and constructive with your questions and comments.