Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

How to reconnect when Disconnection appear : BLEHci.conn_failed_to_be_established [pc_ble_driver_py]

Hello, I am using the nordic nRF52840-DK with the package pc-ble-driver-py and the example heart_rate_collector.py.

My problem is that sometimes the Bluetooth connection can't connect to the device with this error : 

New connection, conn_handle: 0

Disconnected, conn_handle: 0, reason: BLEHci.conn_failed_to_be_established

I know that this error can sometimes occurred. But I would like to know how can I reconnect automatically just after this error ? 

Knowing that this error is problematic because it stop my python script lunched from a batch file.

Thanks in advance.

Gaetan

  • Hello,

    Please note that I am not that familiar with pc_ble_driver_py. I just know the SDK, but the principles are the same. 

    When it disconnects, is it because of range? Because in that case, it may not be able to reconnect either, if the scanner is not able to "hear" the advertisements from the peripheral. Also, make sure that the peripheral is still advertising after the disconnect events. 

    Why does the python script stop when you disconnect? Again, not that familiar with the pc_ble_driver_py, but when seeing it as a normal BLE application, can't you just keep scanning for the device whenever it fails to connect?

    BR,

    Edvin

  • Hello,

    I have check but the disconnection is not because of the range. Indeed, the driver works most of the time. 

    Also I already check if the peripherals keep advertising and it doesn't seem to be related because they keep advertising.

    Concerning the python script, it doesn't crash when I disconnect, It crash when a random disconnect appear.

    My question is this one, how to reconnect to the device after a random disconnection in my script.

    Gaetan

  • Again, pc_ble_driver_py is not my strong side.

    gaetan14 said:
    how to reconnect to the device after a random disconnection in my scrip

    How do you connect in the first place? I assume that it is some API that you have already used to connect to your device? Perhaps you can share with me what your current script looks like?

    Best regards,

    Edvin

  • import sys
    import time
    import logging
    import serial
    from queue import Queue, Empty
    from pc_ble_driver_py.observers import *
    
    TARGET_DEV_NAME = "Nordic_HRM"
    CONNECTIONS = 1
    CFG_TAG = 1
    
    global BLEDriver, BLEAdvData, BLEEvtID, BLEAdapter, BLEEnableParams, BLEGapTimeoutSrc, BLEUUID
    from pc_ble_driver_py import config
    
    config.__conn_ic_id__ = "NRF52"
    
    from pc_ble_driver_py.ble_driver import (
        BLEDriver,
        BLEAdvData,
        BLEEvtID,
        BLEEnableParams,
        BLEGapTimeoutSrc,
        BLEUUID,
        BLEUUIDBase,
        BLEGapScanParams,
        BLEConfigCommon,
        BLEConfig,
        BLEConfigConnGatt,
    )
    
    from pc_ble_driver_py.ble_adapter import BLEAdapter, BLEGapConnParams
    
    global nrf_sd_ble_api_ver
    nrf_sd_ble_api_ver = config.sd_api_ver_get()
    
    
    class HRCollector(BLEDriverObserver, BLEAdapterObserver):
        def __init__(self, adapter):
            super(HRCollector, self).__init__()
            self.adapter = adapter
            self.conn_q = Queue()
            self.adapter.observer_register(self)
            self.adapter.driver.observer_register(self)
            self.adapter.default_mtu = 250
    
        def open(self):
            self.adapter.driver.open()
            gatt_cfg = BLEConfigConnGatt()
            gatt_cfg.att_mtu = self.adapter.default_mtu
            gatt_cfg.tag = CFG_TAG
            self.adapter.driver.ble_cfg_set(BLEConfig.conn_gatt, gatt_cfg)
    
            self.adapter.driver.ble_enable()
    
        def close(self):
            self.adapter.driver.close()
    
        def connect_and_discover(self):
            scan_duration = 15
            params = BLEGapScanParams(interval_ms=200, window_ms=150, timeout_s=scan_duration)
    
            self.adapter.driver.ble_gap_scan_start(scan_params=params)
    
            try:
                new_conn = self.conn_q.get(timeout=scan_duration)
                self.adapter.service_discovery(new_conn)
    
                self.adapter.enable_notification(new_conn, BLEUUID(BLEUUID.Standard.battery_level))
                self.adapter.enable_notification(new_conn, BLEUUID(BLEUUID.Standard.heart_rate))
                return new_conn
            except Empty:
                print(f"No heart rate collector advertising with name {TARGET_DEV_NAME} found.")
                return None
    
        def on_gap_evt_connected(
                self, ble_driver, conn_handle, peer_addr, role, conn_params
        ):
            print("New connection: {}".format(conn_handle))
            self.conn_q.put(conn_handle)
    
        def on_gap_evt_disconnected(self, ble_driver, conn_handle, reason):
            print("Disconnected: {} {}".format(conn_handle, reason))
    
        def on_gap_evt_adv_report(
                self, ble_driver, conn_handle, peer_addr, rssi, adv_type, adv_data
        ):
            if BLEAdvData.Types.complete_local_name in adv_data.records:
                dev_name_list = adv_data.records[BLEAdvData.Types.complete_local_name]
    
            elif BLEAdvData.Types.short_local_name in adv_data.records:
                dev_name_list = adv_data.records[BLEAdvData.Types.short_local_name]
    
            else:
                return
    
            dev_name = "".join(chr(e) for e in dev_name_list)
            address_string = "".join("{0:02X}".format(b) for b in peer_addr.addr)
            print(
                "Received advertisment report, address: 0x{}, device_name: {}".format(
                    address_string, dev_name
                )
            )
    
            if dev_name == TARGET_DEV_NAME:
                conn_params = BLEGapConnParams(min_conn_interval_ms=100, max_conn_interval_ms=200, conn_sup_timeout_ms=4000, slave_latency=0)
                self.adapter.connect(peer_addr, conn_params=conn_params, tag=CFG_TAG)
    
        def on_notification(self, ble_adapter, conn_handle, uuid, data):
            if len(data) > 32:
                data = "({}...)".format(data[0:10])
            print("Connection: {}, {} = {}".format(conn_handle, uuid, data))
    
    
    def main():
        selected_serial_port = "COM60"
        print("Serial port used: {}".format(selected_serial_port))
        driver = BLEDriver(
            serial_port=selected_serial_port, auto_flash=False, baud_rate=1000000, log_severity_level="info"
        )
    
        adapter = BLEAdapter(driver)
        collector = HRCollector(adapter)
        collector.open()
        conn = collector.connect_and_discover()
    
        if conn is not None:
            time.sleep(15)
        if conn is None:
            print("disconnect")
            collector.close()
        collector.close()
    
    
    if __name__ == "__main__":
        main()

    In the first place, I connect the same way as the example heart_rate_collector.py. But unfortunately this script seems to have some issue with the connection

  • So you have this disconnected callback function:
    on_gap_evt_disconnected()

    Is that triggered when you fail to connect? If so, can you try to trigger a new connect from within this function, in addition to only printing  "Disconnected: {} {}"?

    BR,

    Edvin

Related