python-eq3bt
python-eq3bt copied to clipboard
Asyncio errors in bleak
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!
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.
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
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.
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.
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.
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
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.
@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 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€
@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.