python-eq3bt icon indicating copy to clipboard operation
python-eq3bt copied to clipboard

Asyncio errors in bleak

Open sqall01 opened this issue 3 years ago • 10 comments

Hi,

I do not know if this issue is related to some of the already open ones since I do not use eq3cli. However, the underlying issue could be the same.

Since the switch to bleak, I can no longer connect to my thermostats. I can simply reproduce the error by executing:

from eq3bt import Thermostat
test = Thermostat("00:1a:22:12:26:ee")
test.update()

The output is the following:

>>> from eq3bt import Thermostat

>>> test = Thermostat("00:1a:22:12:26:ee")

>>> test.update()
Task exception was never retrieved
future: <Task finished name='Task-9' coro=<BleakConnection.on_notification() done, defined at /home/sqall/syncfolder/projekte/alertR/thermostat_service/venv_bleak/lib/python3.8/site-packages/eq3bt/bleakconnection.py:77> exception=TypeError("unsupported operand type(s) for +: 'BleakGATTCharacteristicBlueZDBus' and 'int'")>
Traceback (most recent call last):
  File "/home/sqall/syncfolder/projekte/alertR/thermostat_service/venv_bleak/lib/python3.8/site-packages/eq3bt/bleakconnection.py", line 119, in make_request
    self._loop.run_until_complete(self.wait_for_response(timeout))
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/home/sqall/syncfolder/projekte/alertR/thermostat_service/venv_bleak/lib/python3.8/site-packages/eq3bt/bleakconnection.py", line 101, in wait_for_response
    await asyncio.wait_for(self._notifyevent.wait(), timeout)
  File "/usr/lib/python3.8/asyncio/tasks.py", line 494, in wait_for
    return fut.result()
  File "/usr/lib/python3.8/asyncio/locks.py", line 309, in wait
    await fut
RuntimeError: Task <Task pending name='Task-7' coro=<Event.wait() running at /usr/lib/python3.8/asyncio/locks.py:309> cb=[_release_waiter(<Future pendi...8e2f51700>()]>)() at /usr/lib/python3.8/asyncio/tasks.py:429]> got Future <Future pending> attached to a different loop

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/sqall/syncfolder/projekte/alertR/thermostat_service/venv_bleak/lib/python3.8/site-packages/eq3bt/bleakconnection.py", line 80, in on_notification
    handle = handle + 1
TypeError: unsupported operand type(s) for +: 'BleakGATTCharacteristicBlueZDBus' and 'int'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/sqall/syncfolder/projekte/alertR/thermostat_service/venv_bleak/lib/python3.8/site-packages/eq3bt/eq3btsmart.py", line 217, in update
    self._conn.make_request(PROP_WRITE_HANDLE, value)
  File "/home/sqall/syncfolder/projekte/alertR/thermostat_service/venv_bleak/lib/python3.8/site-packages/eq3bt/bleakconnection.py", line 119, in make_request
    self._loop.run_until_complete(self.wait_for_response(timeout))
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/home/sqall/syncfolder/projekte/alertR/thermostat_service/venv_bleak/lib/python3.8/site-packages/eq3bt/bleakconnection.py", line 101, in wait_for_response
    await asyncio.wait_for(self._notifyevent.wait(), timeout)
  File "/usr/lib/python3.8/asyncio/tasks.py", line 494, in wait_for
    return fut.result()
  File "/usr/lib/python3.8/asyncio/locks.py", line 309, in wait
    await fut
RuntimeError: Task <Task pending name='Task-7' coro=<Event.wait() running at /usr/lib/python3.8/asyncio/locks.py:309> cb=[_release_waiter(<Future pendi...8e2f51700>()]>)() at /usr/lib/python3.8/asyncio/tasks.py:429]> got Future <Future pending> attached to a different loop

I am running a xubuntu 20.04 machine with Python 3.8.10 (default, Jun 22 2022, 20:18:18) and have the following packages installed in my python environment:

Package       Version
------------- -------
async-timeout 4.0.2  
bleak         0.18.1 
click         8.1.3  
construct     2.10.68
dbus-fast     1.17.0 
pip           20.0.2 
pkg-resources 0.0.0  
python-eq3bt  0.2    
setuptools    44.0.0 
wheel         0.34.2

Everything works fine if I downgrade to version 0.1.12 which uses bluepy.

Well, since I thought this was a problem in bleak, I got involved in this issue https://github.com/hbldh/bleak/issues/946 However, the maintainer says this is a problem in the asyncio loop of the python-eq3bt library (see here: https://github.com/hbldh/bleak/issues/946#issuecomment-1264696635 ).

Thanks!

sqall01 avatar Oct 03 '22 11:10 sqall01

Hey,

would you mind checking if the current git master is working for you? The only change to the released 0.2 is that the event loop should be now only created when none already exists (#58).

Alternatively, as a stopgap solution you could pass the wanted connection class to use bluepy or gattlib instead of bleak, see https://github.com/rytilahti/python-eq3bt/blob/master/eq3bt/eq3cli.py#L33-L46 how the eq3cli does it.

rytilahti avatar Oct 03 '22 12:10 rytilahti

Hey,

I checked out the master branch and executing everything again. But it still does not work.

>>> from eq3bt import Thermostat
>>> test = Thermostat("00:1a:22:12:26:ee")
>>> test.update()
Task exception was never retrieved
future: <Task finished name='Task-9' coro=<BleakConnection.on_notification() done, defined at /home/sqall/Desktop/test/python-eq3bt/eq3bt/bleakconnection.py:82> exception=TypeError("unsupported operand type(s) for +: 'BleakGATTCharacteristicBlueZDBus' and 'int'")>
Traceback (most recent call last):
  File "/home/sqall/Desktop/test/python-eq3bt/eq3bt/bleakconnection.py", line 124, in make_request
    self._loop.run_until_complete(self.wait_for_response(timeout))
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/home/sqall/Desktop/test/python-eq3bt/eq3bt/bleakconnection.py", line 106, in wait_for_response
    await asyncio.wait_for(self._notifyevent.wait(), timeout)
  File "/usr/lib/python3.8/asyncio/tasks.py", line 494, in wait_for
    return fut.result()
  File "/usr/lib/python3.8/asyncio/locks.py", line 309, in wait
    await fut
RuntimeError: Task <Task pending name='Task-7' coro=<Event.wait() running at /usr/lib/python3.8/asyncio/locks.py:309> cb=[_release_waiter(<Future pendi...5fa9d06d0>()]>)() at /usr/lib/python3.8/asyncio/tasks.py:429]> got Future <Future pending> attached to a different loop

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/sqall/Desktop/test/python-eq3bt/eq3bt/bleakconnection.py", line 85, in on_notification
    handle = handle + 1
TypeError: unsupported operand type(s) for +: 'BleakGATTCharacteristicBlueZDBus' and 'int'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/sqall/Desktop/test/python-eq3bt/eq3bt/eq3btsmart.py", line 217, in update
    self._conn.make_request(PROP_WRITE_HANDLE, value)
  File "/home/sqall/Desktop/test/python-eq3bt/eq3bt/bleakconnection.py", line 124, in make_request
    self._loop.run_until_complete(self.wait_for_response(timeout))
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/home/sqall/Desktop/test/python-eq3bt/eq3bt/bleakconnection.py", line 106, in wait_for_response
    await asyncio.wait_for(self._notifyevent.wait(), timeout)
  File "/usr/lib/python3.8/asyncio/tasks.py", line 494, in wait_for
    return fut.result()
  File "/usr/lib/python3.8/asyncio/locks.py", line 309, in wait
    await fut
RuntimeError: Task <Task pending name='Task-7' coro=<Event.wait() running at /usr/lib/python3.8/asyncio/locks.py:309> cb=[_release_waiter(<Future pendi...5fa9d06d0>()]>)() at /usr/lib/python3.8/asyncio/tasks.py:429]> got Future <Future pending> attached to a different loop

sqall01 avatar Oct 04 '22 09:10 sqall01

Alternatively, as a stopgap solution you could pass the wanted connection class to use bluepy or gattlib instead of bleak, see https://github.com/rytilahti/python-eq3bt/blob/master/eq3bt/eq3cli.py#L33-L46 how the eq3cli does it.

Thanks for this pointer. I did so in my code and it works. However, there is a minor "inconvenience". The code looks now like this:

import eq3bt
from eq3bt.connection import BTLEConnection
[...]
  # Give manually the connection class as per default bleak is used which does not work
  self._thermostat = eq3bt.Thermostat(self._mac, connection_cls=BTLEConnection)

The class BTLEConnection and BleakConnection are not exposed via the __init__.py and thus have to be accessed manually. It would be nice to expose them also via the __init__.py since you give the possibility in the Thermostat class to pass them as argument.

sqall01 avatar Oct 06 '22 06:10 sqall01

I am using this module within HomeAssist and can confirm that the 'async error' prevents the HomeAssist plugin from working. With gattlib I can make it work most of the time (often get timeouts too) from CLI but I can not control which backend the HomeAssist plugin uses.

nica-f avatar Nov 28 '22 06:11 nica-f

I can confirm, that BLEAK connection is still not working with python-eq3bt installed from master branch.

eq3cli --mac 00:1A:22:0E:10:F2
ERROR:asyncio:Task exception was never retrieved
future: <Task finished name='Task-10' coro=<BleakConnection.on_notification() done, defined at /usr/local/lib/python3.10/site-packages/eq3bt/bleakconnection.py:77> exception=TypeError("unsupported operand type(s) for +: 'BleakGATTCharacteristicBlueZDBus' and 'int'")>
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/eq3bt/bleakconnection.py", line 80, in on_notification
    handle = handle + 1
TypeError: unsupported operand type(s) for +: 'BleakGATTCharacteristicBlueZDBus' and 'int'
Traceback (most recent call last):
  File "/usr/local/bin/eq3cli", line 8, in <module>
    sys.exit(cli())
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1635, in invoke
    rv = super().invoke(ctx)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/eq3bt/eq3cli.py", line 51, in cli
    ctx.invoke(state)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/eq3bt/eq3cli.py", line 199, in state
    click.echo(dev)
  File "/usr/local/lib/python3.10/site-packages/click/utils.py", line 258, in echo
    out: t.Optional[t.Union[str, bytes]] = str(message)
  File "/usr/local/lib/python3.10/site-packages/eq3bt/eq3btsmart.py", line 108, in __str__
    self._conn.mac, self.target_temperature, self.mode_readable, away_end
  File "/usr/local/lib/python3.10/site-packages/eq3bt/eq3btsmart.py", line 320, in mode_readable
    if mode.MANUAL:
AttributeError: 'NoneType' object has no attribute 'MANUAL'

However, it works well with backend bluepy.

eq3cli --mac 00:1A:22:0E:10:F2 --backend bluepy
[00:1A:22:0E:10:F2] Target 20.0 (mode: manual (20.0C) dst, away: no)
Locked: False
Batter low: False
Window open: False
Window open temp: 12.0
Window open time: 0:15:00
Boost: False
Current target temp: 20.0
Current comfort temp: 21.0
Current eco temp: 17.0
Current temp offset: 0.0
Current mode: manual (20.0C) dst
Valve: 0

As reported elsewhere, downgrading to 0.1.12 works:

pip install https://github.com/rytilahti/python-eq3bt/archive/refs/tags/0.1.12.zip
eq3cli --mac 00:1A:22:0E:10:F2
[00:1A:22:0E:10:F2] Target 20.0 (mode: manual (20.0C) dst, away: no)
Locked: False
Batter low: False
Window open: False
Window open temp: 12.0
Window open time: 0:15:00
Boost: False
Current target temp: 20.0
Current comfort temp: 21.0
Current eco temp: 17.0
Current temp offset: 0.0
Current mode: manual (20.0C) dst
Valve: 0

I have two valves, both paired and trusted in bluetoothctl. One has firmware 1.46, the other 1.20. Both show the exact same behavior (bleak not working, bluepy working).

It would be wonderful to have these valves working again in home-assistant (runs in docker on DietPi - variant of Debian). It stubbornly upgrades to 0.2.

Do you need some additional info? I am ready to do some testing.

peslun avatar Nov 29 '22 00:11 peslun

I feel bad for mining this repo with links to my fork, but it looks like it's hard to find:

https://github.com/dbuezas/eq3btsmart

This one works in the latest home assistant versions and adds a bunch of improvements and goodies

dbuezas avatar Nov 29 '22 01:11 dbuezas

I understand dbuezas, but I am a simple user that needs that his TRV works. The breaking change in 2022.8 or .9 made me very unhappy.

Your fork works and so does finally also my setup in HA again, thanks.

peslun avatar Nov 29 '22 21:11 peslun

@sqall01 you are right that the API is not the nicest, the problem is the optional dependencies I didn't want to force everyone to install. Constructing a nicer API would have required much more effort than I was willing to put into this project, especially as I'm not actively using these ever since I relinquished mine excluding one test device to you :-)

@dbuezas feel free to create an issue (and/or a PR to the README) to inform homeassistant users about the state of affairs and a link to your custom integration. Also, if you wish to take over the maintainership of this project, or the homeassistant integration, I'd be very thankful for that. If you do not aim to get your custom integration to be included in the homeassistant core, please let me know.

Also, if either of you wants to have a single pre-1.20 fw device, let me know and I'll find a way to get it to you.

rytilahti avatar Dec 11 '22 22:12 rytilahti

@rytilahti thank you! Yes, I intend to get it to the core once BTProxies start working, but my fork can't do cli at all so this repo should stay here :). Regarding the device, I do need another one, but their price has increased a lot lately, you can probably sell it for 50€

dbuezas avatar Dec 12 '22 06:12 dbuezas

@rytilahti it is unfortunate that you do not use the thermostats anymore. I have them all around my apartment and am quite happy with them. The heat control is self-build, but works like a charm. And funny thing is: I build it out of fun. But it actually now saved more money in heating costs than the hardware costed me while I was building it :laughing:

@dbuezas what the actual fuck? I just checked the prices for new thermostats. Around 75€ from the vendor. I should have bought more of them when they were around 20€ as they were when I bought them.

sqall01 avatar Dec 15 '22 07:12 sqall01