Skip to content

Ignore disconnect callbacks before first successful connection#119

Open
eputtone wants to merge 1 commit into
Jakeler:mainfrom
eputtone:fix/pi-disconnect-shutdown
Open

Ignore disconnect callbacks before first successful connection#119
eputtone wants to merge 1 commit into
Jakeler:mainfrom
eputtone:fix/pi-disconnect-shutdown

Conversation

@eputtone

@eputtone eputtone commented Apr 4, 2026

Copy link
Copy Markdown

Description

On Linux/BlueZ, disconnect callbacks can occur during failed connection attempts before a stable connection is established.

Currently, these callbacks call stop_loop() unconditionally. That can cause the application to shut down prematurely even if a subsequent connection attempt succeeds.

This change ignores disconnect callbacks until after the first successful connection has completed, while preserving the existing behavior for disconnects after connection.

Example

Raspberry Pi 3+ / Broadcom chip (BCM4345C0) / Raspberry Pi OS Lite 13 when running ble_serial over Wifi + SSH. The problem does not occur when using cable connection.

Before the suggested change:

# python -m ble_serial -v -t 30 -d XX:XX:XX:XX:XX:XX
11:58:40.609 | DEBUG | main.py: Running: Namespace(verbose=1, timeout=30.0, adapter='hci0', mtu=20, gap_role='client', gap_name=None, device='XX:XX:XX:XX:XX:XX', addr_type='public', service_uuid=None, read_uuid=None, write_uuid=None, mode='rw', write_with_response=False, filename=None, binlog=False, port='/tmp/ttyBLE', tcp_host='127.0.0.1', tcp_port=None)
11:58:40.610 | DEBUG | selector_events.py: Using selector: EpollSelector
11:58:40.612 | INFO | linux_pty.py: Port endpoint created on /tmp/ttyBLE -> /dev/pts/1
11:58:40.612 | INFO | ble_client.py: Receiver set up
11:58:40.802 | INFO | ble_client.py: Trying to connect with XX:XX:XX:XX:XX:XX: 12150AF00399
11:58:41.910 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
11:58:41.911 | INFO | ble_client.py: Stopping Bluetooth event loop
11:58:42.509 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
11:58:42.509 | INFO | ble_client.py: Stopping Bluetooth event loop
11:58:43.489 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
11:58:43.489 | INFO | ble_client.py: Stopping Bluetooth event loop
11:58:44.280 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
11:58:44.281 | INFO | ble_client.py: Stopping Bluetooth event loop
11:58:45.040 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
11:58:45.040 | INFO | ble_client.py: Stopping Bluetooth event loop
11:58:45.759 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
11:58:45.759 | INFO | ble_client.py: Stopping Bluetooth event loop
11:58:46.510 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
11:58:46.511 | INFO | ble_client.py: Stopping Bluetooth event loop
11:58:47.299 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
11:58:47.299 | INFO | ble_client.py: Stopping Bluetooth event loop
11:58:48.070 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
11:58:48.071 | INFO | ble_client.py: Stopping Bluetooth event loop
11:58:49.020 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
11:58:49.021 | INFO | ble_client.py: Stopping Bluetooth event loop
11:58:50.110 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
11:58:50.111 | INFO | ble_client.py: Stopping Bluetooth event loop
11:58:51.199 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
11:58:51.199 | INFO | ble_client.py: Stopping Bluetooth event loop
11:58:52.000 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
11:58:52.001 | INFO | ble_client.py: Stopping Bluetooth event loop
11:58:52.720 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
11:58:52.721 | INFO | ble_client.py: Stopping Bluetooth event loop
11:58:54.873 | INFO | ble_client.py: Device XX:XX:XX:XX:XX:XX connected
11:58:54.875 | DEBUG | ble_client.py: No write-without-response uuid specified, trying builtin list
11:58:54.877 | DEBUG | ble_client.py: Characteristic candidates for write-without-response: 
	0000ff02-0000-1000-8000-00805f9b34fb (Handle: 20): Vendor specific ['read', 'write-without-response']
	0000ff01-0000-1000-8000-00805f9b34fb (Handle: 16): Vendor specific ['read', 'notify']
11:58:54.879 | INFO | ble_client.py: Found write-without-response characteristic 0000ff02-0000-1000-8000-00805f9b34fb (H. 20)
11:58:54.880 | DEBUG | ble_client.py: No notify uuid specified, trying builtin list
11:58:54.881 | DEBUG | ble_client.py: Characteristic candidates for notify: 
	0000ff02-0000-1000-8000-00805f9b34fb (Handle: 20): Vendor specific ['read', 'write-without-response']
	0000ff01-0000-1000-8000-00805f9b34fb (Handle: 16): Vendor specific ['read', 'notify']
11:58:54.883 | INFO | ble_client.py: Found notify characteristic 0000ff01-0000-1000-8000-00805f9b34fb (H. 16)
11:58:55.092 | INFO | main.py: Running main loop!
11:58:55.094 | DEBUG | main.py: Completed Tasks: [(<coroutine object BLE_client.send_loop at 0x75666e98>, None)]
11:58:55.095 | DEBUG | main.py: Pending Tasks: [<coroutine object BLE_client.check_loop at 0x757829e8>, <coroutine object UART.run_loop at 0x75666bf8>]
11:58:55.096 | WARNING | main.py: Shutdown initiated
11:58:55.096 | INFO | linux_pty.py: Serial reader and symlink removed
11:58:57.501 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
11:58:57.502 | INFO | ble_client.py: Stopping Bluetooth event loop
11:58:57.504 | INFO | ble_client.py: Bluetooth disconnected
11:58:57.505 | INFO | main.py: Shutdown complete.

With the proposed change:

python -m ble_serial -v -t 30 -d XX:XX:XX:XX:XX:XX
12:01:42.688 | DEBUG | main.py: Running: Namespace(verbose=1, timeout=30.0, adapter='hci0', mtu=20, gap_role='client', gap_name=None, device='XX:XX:XX:XX:XX:XX', addr_type='public', service_uuid=None, read_uuid=None, write_uuid=None, mode='rw', write_with_response=False, filename=None, binlog=False, port='/tmp/ttyBLE', tcp_host='127.0.0.1', tcp_port=None)
12:01:42.689 | DEBUG | selector_events.py: Using selector: EpollSelector
12:01:42.690 | INFO | linux_pty.py: Port endpoint created on /tmp/ttyBLE -> /dev/pts/1
12:01:42.691 | INFO | ble_client.py: Receiver set up
12:01:42.905 | INFO | ble_client.py: Trying to connect with XX:XX:XX:XX:XX:XX: 12150AF00399
12:01:43.430 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
12:01:43.430 | DEBUG | ble_client.py: Ignoring pre-connect disconnect callback
12:01:44.160 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
12:01:44.160 | DEBUG | ble_client.py: Ignoring pre-connect disconnect callback
12:01:44.922 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
12:01:44.922 | DEBUG | ble_client.py: Ignoring pre-connect disconnect callback
12:01:45.742 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
12:01:45.742 | DEBUG | ble_client.py: Ignoring pre-connect disconnect callback
12:01:46.710 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
12:01:46.711 | DEBUG | ble_client.py: Ignoring pre-connect disconnect callback
12:01:47.539 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
12:01:47.539 | DEBUG | ble_client.py: Ignoring pre-connect disconnect callback
12:01:48.119 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
12:01:48.119 | DEBUG | ble_client.py: Ignoring pre-connect disconnect callback
12:01:49.770 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
12:01:49.771 | DEBUG | ble_client.py: Ignoring pre-connect disconnect callback
12:01:50.580 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
12:01:50.581 | DEBUG | ble_client.py: Ignoring pre-connect disconnect callback
12:01:51.380 | WARNING | ble_client.py: Device XX:XX:XX:XX:XX:XX disconnected
12:01:51.381 | DEBUG | ble_client.py: Ignoring pre-connect disconnect callback
12:01:53.694 | INFO | ble_client.py: Device XX:XX:XX:XX:XX:XX connected
12:01:53.695 | DEBUG | ble_client.py: No write-without-response uuid specified, trying builtin list
12:01:53.695 | DEBUG | ble_client.py: Characteristic candidates for write-without-response: 
	0000ff02-0000-1000-8000-00805f9b34fb (Handle: 20): Vendor specific ['read', 'write-without-response']
	0000ff01-0000-1000-8000-00805f9b34fb (Handle: 16): Vendor specific ['read', 'notify']
12:01:53.696 | INFO | ble_client.py: Found write-without-response characteristic 0000ff02-0000-1000-8000-00805f9b34fb (H. 20)
12:01:53.697 | DEBUG | ble_client.py: No notify uuid specified, trying builtin list
12:01:53.697 | DEBUG | ble_client.py: Characteristic candidates for notify: 
	0000ff02-0000-1000-8000-00805f9b34fb (Handle: 20): Vendor specific ['read', 'write-without-response']
	0000ff01-0000-1000-8000-00805f9b34fb (Handle: 16): Vendor specific ['read', 'notify']
12:01:53.699 | INFO | ble_client.py: Found notify characteristic 0000ff01-0000-1000-8000-00805f9b34fb (H. 16)
12:01:53.920 | INFO | main.py: Running main loop!

Related btmon log. Due to radio interference from WIFI or poor coordination between BlueZ + brcmfmac, establishing the connection fails at Connection Failed to be Established (0x3e). But with large enough timeout, connection will eventually succeed.

< HCI Command: LE Create Connection (0x08|0x000d) plen 25                                                              #19 [hci0] 7.677274
        Scan interval: 60.000 msec (0x0060)
        Scan window: 60.000 msec (0x0060)
        Filter policy: Accept list is not used (0x00)
        Peer address type: Public (0x00)
        Peer address: XX:XX:XX:XX:XX:XX (Iton Technology Corp.)
        Own address type: Public (0x00)
        Min connection interval: 25.00 msec (0x0014)
        Max connection interval: 50.00 msec (0x0028)
        Connection latency: 0 (0x0000)
        Supervision timeout: 10000 msec (0x03e8)
        Min connection length: 0.000 msec (0x0000)
        Max connection length: 0.000 msec (0x0000)
> HCI Event: Command Status (0x0f) plen 4                                                                              #20 [hci0] 7.677809
      LE Create Connection (0x08|0x000d) ncmd 1
        Status: Success (0x00)
> HCI Event: LE Meta Event (0x3e) plen 19                                                                              #21 [hci0] 7.864809
      LE Connection Complete (0x01)
        Status: Success (0x00)
        Handle: 64
        Role: Central (0x00)
        Peer address type: Public (0x00)
        Peer address: XX:XX:XX:XX:XX:XX (Iton Technology Corp.)
        Connection interval: 48.75 msec (0x0027)
        Connection latency: 0 (0x0000)
        Supervision timeout: 10000 msec (0x03e8)
        Central clock accuracy: 0x00
@ MGMT Event: Device Connected (0x000b) plen 34                                                                   {0x0001} [hci0] 7.864855
        LE Address: XX:XX:XX:XX:XX:XX (Iton Technology Corp.)
        Flags: 0x00000008
          Connection Locally Initiated
        Data length: 21
        Flags: 0x06
          LE General Discoverable Mode
          BR/EDR Not Supported
        16-bit Service UUIDs (partial): 1 entry
          Unknown (0xff00)
        Name (complete): 12150AF00399
btmon[1587]: @ RAW Open: btmon (privileged) version 2.22                                                                 {0x0002} 7.866041
btmon[1587]: @ RAW Close: btmon                                                                                          {0x0002} 7.866059
< HCI Command: LE Read Remote Used Features (0x08|0x0016) plen 2                                                       #22 [hci0] 7.922815
        Handle: 64 Address: XX:XX:XX:XX:XX:XX (Iton Technology Corp.)
> HCI Event: Command Status (0x0f) plen 4                                                                              #23 [hci0] 7.923126
      LE Read Remote Used Features (0x08|0x0016) ncmd 1
        Status: Success (0x00)
> HCI Event: LE Meta Event (0x3e) plen 12                                                                              #24 [hci0] 8.179215
      LE Read Remote Used Features (0x04)
        Status: Connection Failed to be Established (0x3e)
        Handle: 64 Address: XX:XX:XX:XX:XX:XX (Iton Technology Corp.)
        Features: 0x3f 0x00 0x00 0x08 0x00 0x00 0x00 0x00
          LE Encryption
          Connection Parameter Request Procedure
          Extended Reject Indication
          Peripheral-initiated Features Exchange
          LE Ping
          LE Data Packet Length Extension
          Remote Public Key Validation
> HCI Event: Disconnect Complete (0x05) plen 4                                                                         #25 [hci0] 8.179840
        Status: Success (0x00)
        Handle: 64 Address: XX:XX:XX:XX:XX:XX (Iton Technology Corp.)
        Reason: Connection Failed to be Established (0x3e)
@ MGMT Event: Device Disconnected (0x000c) plen 8                                                                 {0x0001} [hci0] 8.232864
        LE Address: XX:XX:XX:XX:XX:XX (Iton Technology Corp.)
        Reason: Unspecified (0x00)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant