antsar / python-turntouch

Python library for the Turn Touch bluetooth smart home remote.
3 stars 1 forks source link

Handling BTLEDisconnectError #4

Closed robbieh closed 4 years ago

robbieh commented 4 years ago

I'm finding that the listener can only run so long before getting this error: bluepy.btle.BTLEDisconnectError: Device disconnected and then it doesn't recover.

I'm calling .listen(only_one=False) but after that disconnect event, the next line of code never happens so I can't do anything to try to recover.

Ideally I'd like to be able to reconnect automatically.

antsar commented 4 years ago

Hi @robbieh, thank you for reporting this! Any idea how long it typically takes before you get this error? I haven't experienced it, but would be happy to try debugging.

robbieh commented 4 years ago

Great! Thank you. The time seems to vary a lot. I haven't measured, but in the 10 to 60 minute range.

I think my code is pretty simple. I have an MQTT client library reporting button presses to the broker. It works wonderfully! For that short while.

import turntouch
import paho.mqtt.client as mqtt
import threading
import time

mclient = mqtt.Client(client_id="turnTouch", clean_session=True, userdata=None, protocol=mqtt.MQTTv311, transport="tcp")
mclient.connect("mqtt.local")

class MyHandler(turntouch.DefaultActionHandler):
    def action_north(self):
        print("up")
        mclient.connect("mqtt.local")
        mclient.publish("turntouch/press","up")

tt = turntouch.TurnTouch('DF:BA:CD:62:23:91')
tt.handler = MyHandler()

while True:
    print("listening")
    tt.listen(only_one=False)
    print("disconnected")

I never get the "disconnected" line. The full stack trace is below. I kind of figured there are going to be BTLE disconnects in day-to-day use. I just can't figure out how to recover/reconnect.

Traceback (most recent call last):
  File "/home/robbie/Wrkspc/turntouch/python-turntouch/turntouch/turntouch.py", line 356, in listen
    self.waitForNotifications(self.LISTEN_PERIOD)
  File "/home/robbie/Wrkspc/turntouch/python-turntouch/venv/lib/python3.6/site-packages/bluepy/btle.py", line 560, in waitForNotifications
    resp = self._getResp(['ntfy','ind'], timeout)
  File "/home/robbie/Wrkspc/turntouch/python-turntouch/venv/lib/python3.6/site-packages/bluepy/btle.py", line 407, in _getResp
    resp = self._waitResp(wantType + ['ntfy', 'ind'], timeout)
  File "/home/robbie/Wrkspc/turntouch/python-turntouch/venv/lib/python3.6/site-packages/bluepy/btle.py", line 362, in _waitResp
    raise BTLEDisconnectError("Device disconnected", resp)
bluepy.btle.BTLEDisconnectError: Device disconnected

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/robbie/Wrkspc/turntouch/python-turntouch/turntouch/turntouch.py", line 364, in listen
    raise TurnTouchException(e)
turntouch.turntouch.TurnTouchException: Device disconnected

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/robbie/Wrkspc/turntouch/python-turntouch/turntouch/turntouch.py", line 385, in _enable_notification
    uuid=uuid)[0].getHandle()
  File "/home/robbie/Wrkspc/turntouch/python-turntouch/venv/lib/python3.6/site-packages/bluepy/btle.py", line 507, in getCharacteristics
    self._writeCmd(cmd + "\n")
  File "/home/robbie/Wrkspc/turntouch/python-turntouch/venv/lib/python3.6/site-packages/bluepy/btle.py", line 302, in _writeCmd
    raise BTLEInternalError("Helper not started (did you call connect()?)")
bluepy.btle.BTLEInternalError: Helper not started (did you call connect()?)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test.py", line 84, in <module>
    tt.listen(only_one=False)
  File "/home/robbie/Wrkspc/turntouch/python-turntouch/turntouch/turntouch.py", line 367, in listen
    self._enable_notifications(enabled=False)
  File "/home/robbie/Wrkspc/turntouch/python-turntouch/turntouch/turntouch.py", line 374, in _enable_notifications
    self.BUTTON_STATUS_CHARACTERISTIC_UUID, enabled)
  File "/home/robbie/Wrkspc/turntouch/python-turntouch/turntouch/turntouch.py", line 402, in _enable_notification
    .format(addr=self.addr, uuid=uuid))
turntouch.turntouch.TurnTouchException: Failed to enable notifications for device DF:BA:CD:62:23:91, characteristic 99c31525-dc4f-41b1-bb04-4e4deb81fadd
antsar commented 4 years ago

There's no retry mechanism built in to the library. We throw TurnTouchException (last line of your trace) on connection failures (doc). You can catch that, and reconnect. Here's how that might look with your code:

class MyHandler(turntouch.DefaultActionHandler):
    def action_north(self):
        print("up")

while True:
    try:
        print("connecting")
        tt = turntouch.TurnTouch('DF:BA:CD:62:23:91', handler=MyHandler())
        print("listening")
        tt.listen(only_one=False)
    except turntouch.TurnTouchException:
        print("disconnected")

I put the connection (turntouch.TurnTouch()) and the tt.listen() call inside the try. That way, connection errors are handled whether they occur during connection, or during listening.

This approach worked for me (TurnTouch Rev. 40, "Plugable" dongle, Linux).

Let me know if that makes sense / solves the problem for you!

robbieh commented 4 years ago

Thanks! I'm giving it a shot. So far, so good.

robbieh commented 4 years ago

So far, it has been rock solid. Thanks much!

robbieh commented 4 years ago

So far, it has been rock solid. Thanks much!