-
Notifications
You must be signed in to change notification settings - Fork 282
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bleak not disconnecting automatically when run and stopped/interrupted with PyCharm #613
Comments
How does PyCharm end the Python process when you press the stop button? SIGINT, SIGTERM, SIGKILL, etc.? |
Hi @dlech ! |
It seems like this should raise a Does it disconnect if you just run the program from a regular terminal window instead of through PyChrarm? |
Hi @dlech I have added the following signal handler thanks to your hint. import logging
import asyncio
import bleak.exc
import signal
from signal import SIGINT
from bleak import BleakClient, discover
logging.basicConfig(level=logging.INFO)
UUID_C = 'f0001132-0451-4000-b000-000000000000'
UUID_W = 'f0001131-0451-4000-b000-000000000000'
addr = '60:a4:23:d4:5e:8c'
disconnected_event = asyncio.Event()
def handler(signal_received, frame):
# Handle any cleanup here
print('SIGINT or CTRL-C detected. Exiting gracefully')
disconnected_event.set()
exit(0)
def notification_handler(_, data):
print(data)
async def main(mac):
signal.signal(SIGINT, handler)
try:
def disconnected_callback(client):
print("Disconnected callback called!")
disconnected_event.set()
async with BleakClient(mac, disconnected_callback=disconnected_callback) as client:
print('connected to {}'.format(mac))
# await client.start_notify(UUID_C, notification_handler)
# this blinks some LEDs in my hardware device :)
# v = b'LED \r'
while 1:
print('.')
# await client.write_gatt_char(UUID_W, v)
await asyncio.sleep(3)
except bleak.exc.BleakError as ex:
print('-- {}'.format(ex))
if __name__ == "__main__":
asyncio.run(main(addr)) These seems to work with another hardware design I have. I left the one I wrote this issue for at home so I cannot test right now. I will keep you updated, just tell me if you think this is clearly NOT the solution. |
Adding a signal handler should not be necessary. (Also, @ mentioning me creates extra notifications, so please don't use it on every post - only use it if you really need to get my attention) |
Did not know about the @ thing, sorry :) will totally avoid it. |
Using it occasionally is no problem.
Since the signal handler calls |
I see the same behaviour as OP, but in a plain terminal session, no PyCharm.
My code to read heart rate measurement notifications from a fitness tracker: import asyncio
import sys
import bleak
HEART_RATE_MEASUREMENT_UUID = "0000{0:x}-0000-1000-8000-00805f9b34fb".format(0x2A37)
def heart_rate_changed(handle: int, data: bytearray):
print(f"Heart rate: {data[1]}")
async def run(address):
try:
async with bleak.BleakClient(address) as client:
print(f"Connected to {address}")
await client.start_notify(HEART_RATE_MEASUREMENT_UUID, heart_rate_changed)
print(f"Notifications started...")
while True:
await asyncio.sleep(1)
except asyncio.exceptions.TimeoutError:
print(f"Can't connect to device {address}. Does it run a GATT server?")
if __name__ == "__main__":
if len(sys.argv) == 2:
ADDRESS = sys.argv[1]
loop = asyncio.get_event_loop()
loop.run_until_complete(run(ADDRESS))
else:
print("Please specify the BLE MAC address on the command line.") If the device isn't connected before the program starts, notifications work. If I press Ctrl+C and run the program again, the device isn't found because it's still connected in the background. If I disconnect the device with $ python3 heart-rate.py EB:76:55:B9:56:18
Connected to EB:76:55:B9:56:18
Notifications started...
Heart rate: 67
Heart rate: 68
Heart rate: 68
Heart rate: 68
Heart rate: 67
^CTraceback (most recent call last):
File "heart-rate.py", line 32, in <module>
loop.run_until_complete(run(ADDRESS))
File "/usr/lib/python3.8/asyncio/base_events.py", line 603, in run_until_complete
self.run_forever()
File "/usr/lib/python3.8/asyncio/base_events.py", line 570, in run_forever
self._run_once()
File "/usr/lib/python3.8/asyncio/base_events.py", line 1823, in _run_once
event_list = self._selector.select(timeout)
File "/usr/lib/python3.8/selectors.py", line 468, in select
fd_event_list = self._selector.poll(timeout, max_ev)
KeyboardInterrupt
$ python3 heart-rate.py EB:76:55:B9:56:18
Traceback (most recent call last):
File "heart-rate.py", line 32, in <module>
loop.run_until_complete(run(ADDRESS))
File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "heart-rate.py", line 15, in run
async with bleak.BleakClient(address) as client:
File "/home/koan/.local/lib/python3.8/site-packages/bleak/backends/client.py", line 61, in __aenter__
await self.connect()
File "/home/koan/.local/lib/python3.8/site-packages/bleak/backends/bluezdbus/client.py", line 137, in connect
raise BleakError(bleak.exc.BleakError: Device with address EB:76:55:B9:56:18 was not found.
$ bluetoothctl disconnect EB:76:55:B9:56:18
Attempting to disconnect from EB:76:55:B9:56:18
[CHG] Device EB:76:55:B9:56:18 ServicesResolved: no
Successful disconnected
$ python3 heart-rate.py EB:76:55:B9:56:18
Connected to EB:76:55:B9:56:18
Notifications started...
Heart rate: 65
Heart rate: 65
Heart rate: 65 |
In order to make disconnecting work correctly after an unhandled exception, replace: loop = asyncio.get_event_loop()
loop.run_until_complete(run(ADDRESS)) with asyncio.run(run(ADDRESS)) |
Cool, this works, thanks! I should have looked closer at OP's code. |
I just tried to reproduce the issue using a fresh install of:
and The device disconnected as expected when pressing the stop button in PyCharm. So I'm not sure why your PyCharm would be different. |
bluetoothctl -v
) in case of Linux: 5.56Description
I connect to my BLE hardware device using python3 and Bleak and I send a LED command every 5 seconds indefinitely. The device blinks its LEDs and answers back. It works perfectly. However, when I stop the code (I use Pycharm and I press the red stop button), the snippet never works again unless I reset the Bluetooth subsystem (systemctl restart bluetooth). It seems I am suffering from the issue in line #348 of client.py in master branch, which states something like " Otherwise BlueZ will keep the device connected even after Python exits". I think I can confirm this since, when I run the code again it comes up with the error "bleak.exc.BleakError: Device with address <my_mac_below> was not found." It cannot be found because it is not advertising since it is still connected in the background :(
Also, in my hardware device logging subsystem, I see Bleak never tells it to disconnect. My other apps with other frameworks automatically disconnect if code is no longer working. I have seen this issue around the forum but tested some of the suggestions (some of the branches are not existing anymore) and it does not seem to be solved. Maybe I am missing some parameters on BleakClient()? Gonna check issue #377 again meanwhile.
This seems a great project. Let me know if I can do some testing around all this.
What I Did
Please see my code example :) I simply activate notifications on UUID_C. Then I write commands on UUID_W.
The text was updated successfully, but these errors were encountered: