Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

When the program exits, Bleak BLE connection is not released. #1222

Closed
zapta opened this issue Feb 16, 2023 · 3 comments
Closed

When the program exits, Bleak BLE connection is not released. #1222

zapta opened this issue Feb 16, 2023 · 3 comments

Comments

@zapta
Copy link

zapta commented Feb 16, 2023

  • bleak version: 0.19.5
  • Python version: 3.10.6
  • Operating System: Ubuntu 22.04.1 LTS
  • BlueZ version (bluetoothctl -v) in case of Linux: bluetoothctl: 5.64

Description

If a bleak program exits, the BLE connection is still maintained forever. I encountered it only on linux. On Windows the connection is terminated about 30 secs later and IIRC, on macosc, it terminated immediately. Same if I connect from the nRF Connect app on my phone.

To reproduce

  1. Have a connectable BLE device and identify it's address. (E.g. the ESP32 device marked '2' I email a week or two ago).
  2. Create a python file with the test program below and edit the device address.
  3. Run the program once, it will connect to the device and exit.
  4. Check if the connection is still maintained. For example, look at the device connection indicator if available (fast blinking LED in ESP32 '2'), and test if the device returned to advertising mode or not. With Linux, the device stay connected for ever.
  5. Turn off Bluetooth on Linux and observe how the connection on the device is disconnected.

What I Did

Test program:

import asyncio
import platform
import sys
from bleak import BleakClient, BleakScanner

# Adapt to your actual device.
device_address = "0C:8B:95:F2:B4:36"

print(f"OS: {platform.platform()}", flush=True)
print(f"Platform:: {platform.uname()}", flush=True)
print(f"Python {sys.version}", flush=True)

async def test():
    global client
    print(f"Trying to connect to {device_address}", flush=True)
    device = await BleakScanner.find_device_by_address(device_address, timeout=10.0)
    assert device
    client = BleakClient(device)
    assert client
    await client.connect(timeout=10.0)
    assert client.is_connected
    print(f"Connected", flush=True)
    print(f"Test done", flush=True)

event_loop = asyncio.new_event_loop()
event_loop.run_until_complete(test())

Logs

user@linux:/projects/ble_stepper_motor_analyzer/repo/app/test$ python3 connection_cleanup.py
OS: Linux-5.19.0-32-generic-x86_64-with-glibc2.35
Platform:: uname_result(system='Linux', node='linux', release='5.19.0-32-generic', version='#33
22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Mon Jan 30 17:03:34 UTC 2', machine='x86_64')
Python 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0]
Trying to connect to 0C:8B:95:F2:B4:36
2023-02-16 09:13:04,096 bleak.backends.bluezdbus.manager DEBUG: initial properties: {'/org/bluez': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.AgentManager1': {}, 'org.bluez.ProfileManager1': {}}, '/org/bluez/hci0': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.Adapter1': {'Address': 'EC:63:D7:F1:C7:8B', 'AddressType': 'public', 'Name': 'linux', 'Alias': 'linux', 'Class': 0, 'Powered': True, 'Discoverable': False, 'DiscoverableTimeout': 180, 'Pairable': False, 'PairableTimeout': 0, 'Discovering': False, 'UUIDs': ['00001133-0000-1000-8000-00805f9b34fb', '0000110e-0000-1000-8000-00805f9b34fb', '00001105-0000-1000-8000-00805f9b34fb', '00001132-0000-1000-8000-00805f9b34fb', '00001200-0000-1000-8000-00805f9b34fb', '00001104-0000-1000-8000-00805f9b34fb', '00005005-0000-1000-8000-0002ee000001', '00001108-0000-1000-8000-00805f9b34fb', '0000110c-0000-1000-8000-00805f9b34fb', '00001801-0000-1000-8000-00805f9b34fb', '0000112f-0000-1000-8000-00805f9b34fb', '0000110b-0000-1000-8000-00805f9b34fb', '0000180a-0000-1000-8000-00805f9b34fb', '00001800-0000-1000-8000-00805f9b34fb', '0000111f-0000-1000-8000-00805f9b34fb', '0000110a-0000-1000-8000-00805f9b34fb', '00001106-0000-1000-8000-00805f9b34fb'], 'Modalias': 'usb:v1D6Bp0246d0540', 'Roles': ['central', 'peripheral']}, 'org.freedesktop.DBus.Properties': {}, 'org.bluez.GattManager1': {}, 'org.bluez.Media1': {}, 'org.bluez.NetworkServer1': {}, 'org.bluez.LEAdvertisingManager1': {'ActiveInstances': 0, 'SupportedInstances': 5, 'SupportedIncludes': ['tx-power', 'appearance', 'local-name']}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.Device1': {'Address': '0C:8B:95:F2:B4:36', 'AddressType': 'public', 'Name': 'STP-0C8B95F2B436', 'Alias': 'STP-0C8B95F2B436', 'Paired': False, 'Trusted': False, 'Blocked': False, 'LegacyPairing': False, 'Connected': False, 'UUIDs': ['00001800-0000-1000-8000-00805f9b34fb', '00001801-0000-1000-8000-00805f9b34fb', '6b6a78d7-8ee0-4a26-ba7b-62e357dd9720'], 'Adapter': '/org/bluez/hci0', 'ServicesResolved': False}, 'org.freedesktop.DBus.Properties': {}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.GattService1': {'UUID': '6b6a78d7-8ee0-4a26-ba7b-62e357dd9720', 'Device': '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36', 'Primary': True, 'Includes': []}, 'org.freedesktop.DBus.Properties': {}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028/char003c': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.GattCharacteristic1': {'UUID': '0000ff07-0000-1000-8000-00805f9b34fb', 'Service': '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028', 'Value': bytearray(b''), 'Flags': ['read']}, 'org.freedesktop.DBus.Properties': {}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028/char003a': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.GattCharacteristic1': {'UUID': '0000ff06-0000-1000-8000-00805f9b34fb', 'Service': '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028', 'Value': bytearray(b''), 'Flags': ['write']}, 'org.freedesktop.DBus.Properties': {}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028/char0038': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.GattCharacteristic1': {'UUID': '0000ff05-0000-1000-8000-00805f9b34fb', 'Service': '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028', 'Value': bytearray(b''), 'Flags': ['read']}, 'org.freedesktop.DBus.Properties': {}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028/char0036': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.GattCharacteristic1': {'UUID': '0000ff04-0000-1000-8000-00805f9b34fb', 'Service': '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028', 'Value': bytearray(b''), 'Flags': ['read']}, 'org.freedesktop.DBus.Properties': {}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028/char0034': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.GattCharacteristic1': {'UUID': '0000ff03-0000-1000-8000-00805f9b34fb', 'Service': '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028', 'Value': bytearray(b''), 'Flags': ['read']}, 'org.freedesktop.DBus.Properties': {}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028/char0031': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.GattCharacteristic1': {'UUID': '0000ff02-0000-1000-8000-00805f9b34fb', 'Service': '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028', 'Value': bytearray(b''), 'Notifying': False, 'Flags': ['read', 'notify'], 'NotifyAcquired': False}, 'org.freedesktop.DBus.Properties': {}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028/char0031/desc0033': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.GattDescriptor1': {'UUID': '00002902-0000-1000-8000-00805f9b34fb', 'Characteristic': '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028/char0031', 'Value': bytearray(b'')}, 'org.freedesktop.DBus.Properties': {}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028/char002f': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.GattCharacteristic1': {'UUID': '0000ff01-0000-1000-8000-00805f9b34fb', 'Service': '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028', 'Value': bytearray(b''), 'Flags': ['read']}, 'org.freedesktop.DBus.Properties': {}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028/char002d': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.GattCharacteristic1': {'UUID': '00002a29-0000-1000-8000-00805f9b34fb', 'Service': '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028', 'Value': bytearray(b''), 'Flags': ['read']}, 'org.freedesktop.DBus.Properties': {}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028/char002b': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.GattCharacteristic1': {'UUID': '00002a26-0000-1000-8000-00805f9b34fb', 'Service': '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028', 'Value': bytearray(b''), 'Flags': ['read']}, 'org.freedesktop.DBus.Properties': {}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028/char0029': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.GattCharacteristic1': {'UUID': '00002a24-0000-1000-8000-00805f9b34fb', 'Service': '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0028', 'Value': bytearray(b''), 'Flags': ['read']}, 'org.freedesktop.DBus.Properties': {}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0001': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.GattService1': {'UUID': '00001801-0000-1000-8000-00805f9b34fb', 'Device': '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36', 'Primary': True, 'Includes': []}, 'org.freedesktop.DBus.Properties': {}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0001/char0002': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.GattCharacteristic1': {'UUID': '00002a05-0000-1000-8000-00805f9b34fb', 'Service': '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0001', 'Value': bytearray(b''), 'Notifying': False, 'Flags': ['indicate']}, 'org.freedesktop.DBus.Properties': {}}, '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0001/char0002/desc0004': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.GattDescriptor1': {'UUID': '00002902-0000-1000-8000-00805f9b34fb', 'Characteristic': '/org/bluez/hci0/dev_0C_8B_95_F2_B4_36/service0001/char0002', 'Value': bytearray(b'')}, 'org.freedesktop.DBus.Properties': {}}}
2023-02-16 09:13:04,217 bleak.backends.bluezdbus.manager DEBUG: received D-Bus signal: org.freedesktop.DBus.Properties.PropertiesChanged (/org/bluez/hci0): ['org.bluez.Adapter1', {'Discovering': <dbus_fast.signature.Variant ('b', True)>}, []]
2023-02-16 09:13:04,269 bleak.backends.bluezdbus.manager DEBUG: received D-Bus signal: org.freedesktop.DBus.ObjectManager.InterfacesAdded (/): ['/org/bluez/hci0/dev_30_E2_83_7C_F3_11', {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.Device1': {'Address': <dbus_fast.signature.Variant ('s', 30:E2:83:7C:F3:11)>, 'AddressType': <dbus_fast.signature.Variant ('s', public)>, 'Name': <dbus_fast.signature.Variant ('s', BLE Device-7CF311)>, 'Alias': <dbus_fast.signature.Variant ('s', BLE Device-7CF311)>, 'Paired': <dbus_fast.signature.Variant ('b', False)>, 'Trusted': <dbus_fast.signature.Variant ('b', False)>, 'Blocked': <dbus_fast.signature.Variant ('b', False)>, 'LegacyPairing': <dbus_fast.signature.Variant ('b', False)>, 'RSSI': <dbus_fast.signature.Variant ('n', -71)>, 'Connected': <dbus_fast.signature.Variant ('b', False)>, 'UUIDs': <dbus_fast.signature.Variant ('as', ['0000ff12-0000-1000-8000-00805f9b34fb'])>, 'Adapter': <dbus_fast.signature.Variant ('o', /org/bluez/hci0)>, 'ServicesResolved': <dbus_fast.signature.Variant ('b', False)>}, 'org.freedesktop.DBus.Properties': {}}]
2023-02-16 09:13:04,386 bleak.backends.bluezdbus.manager DEBUG: received D-Bus signal: org.freedesktop.DBus.Properties.PropertiesChanged (/org/bluez/hci0/dev_0C_8B_95_F2_B4_36): ['org.bluez.Device1', {'RSSI': <dbus_fast.signature.Variant ('n', -50)>, 'TxPower': <dbus_fast.signature.Variant ('n', 3)>}, []]
2023-02-16 09:13:04,394 bleak.backends.bluezdbus.manager DEBUG: received D-Bus signal: org.freedesktop.DBus.Properties.PropertiesChanged (/org/bluez/hci0/dev_0C_8B_95_F2_B4_36): ['org.bluez.Device1', {}, ['TxPower', 'RSSI']]
2023-02-16 09:13:04,395 bleak.backends.bluezdbus.manager DEBUG: received D-Bus signal: org.freedesktop.DBus.Properties.PropertiesChanged (/org/bluez/hci0/dev_30_E2_83_7C_F3_11): ['org.bluez.Device1', {}, ['RSSI']]
2023-02-16 09:13:04,397 bleak.backends.bluezdbus.manager DEBUG: received D-Bus signal: org.freedesktop.DBus.Properties.PropertiesChanged (/org/bluez/hci0): ['org.bluez.Adapter1', {'Discovering': <dbus_fast.signature.Variant ('b', False)>}, []]
2023-02-16 09:13:04,402 bleak.backends.bluezdbus.client DEBUG: Connecting to device @ 0C:8B:95:F2:B4:36
2023-02-16 09:13:04,414 bleak.backends.bluezdbus.client DEBUG: Connecting to BlueZ path /org/bluez/hci0/dev_0C_8B_95_F2_B4_36
2023-02-16 09:13:04,517 bleak.backends.bluezdbus.manager DEBUG: received D-Bus signal: org.freedesktop.DBus.Properties.PropertiesChanged (/org/bluez/hci0/dev_0C_8B_95_F2_B4_36): ['org.bluez.Device1', {'Connected': <dbus_fast.signature.Variant ('b', True)>}, []]
2023-02-16 09:13:05,171 bleak.backends.bluezdbus.manager DEBUG: received D-Bus signal: org.freedesktop.DBus.Properties.PropertiesChanged (/org/bluez/hci0/dev_0C_8B_95_F2_B4_36): ['org.bluez.Device1', {'ServicesResolved': <dbus_fast.signature.Variant ('b', True)>}, []]
Connected
Test done
user@linux:~/projects/ble_stepper_motor_analyzer/repo/app/test$

@dlech
Copy link
Collaborator

dlech commented Feb 16, 2023

If you want this behavior, you need to use asyncio.run(test()) and async with BleakClient(device) as client:.

@zapta
Copy link
Author

zapta commented Feb 16, 2023

Thanks @dlech, I presume you mean the code below which indeed work. In my actual program I have seperate function to establish the connection, interacting with the device and closing the connection, so I would like to have a global client variable that the various pieces can use.

How do I break the code in 'async with BleakClient(device) as client:' to three three separate parts with a global variable for the client? (similar to the 'client' variable in my original code above).

(My app uses pyqtgraph which is a framework with inversion of control so I am not in control of the mail code, just getting callbacks on certain events).

import asyncio
import platform
import sys
import time
import signal
from bleak import BleakClient, BleakScanner
import signal

# Adapt to your actual device.
device_address = "0C:8B:95:F2:B4:36"

signal.signal(signal.SIGINT, lambda number, frame: sys.exit())

print(f"OS: {platform.platform()}", flush=True)
print(f"Platform:: {platform.uname()}", flush=True)
print(f"Python {sys.version}", flush=True)

async def test():
    #global client
    print(f"Trying to connect to {device_address}", flush=True)
    device = await BleakScanner.find_device_by_address(device_address, timeout=10.0)
    assert device
    async with BleakClient(device) as client:
        assert client.is_connected
        print(f"Connected", flush=True)
        print(f"Waiting 5 secs...", flush=True)
        time.sleep(5.0)
        print(f"Closing...", flush=True)
        assert client.is_connected
        await client.disconnect()
        print(f"Test done", flush=True)

asyncio.run(test())

@dlech
Copy link
Collaborator

dlech commented Feb 16, 2023

You can create tasks and use asyncio.gather() to run 3 tasks in parallel

Repository owner locked and limited conversation to collaborators Feb 19, 2023
@dlech dlech converted this issue into discussion #1233 Feb 19, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants