ukBaz / python-bluezero

A simple Python interface to Bluez
MIT License
387 stars 112 forks source link

Force disconnect clients from peripheral #386

Closed margorski closed 1 year ago

margorski commented 1 year ago

Hello, I have a BLE peripheral created using python-bluezero. More or less based on currenct cpu_temperature.py. Nothing unusual. One service, three characteristics, each with read and value and that's it.

Everything works fine, the only problem is disconnecting clients when the script is stopped. I run the script on rPI and connect to this using a mobile phone using nRF Connect or my own application. When I'm connected to the peripheral and I stop the peripheral script, on the client I didn't get any notification, and still it is shown that I'm connected. On the other hand when I turn off rPI (by turning the power down) then on mobile I am immediately disconnected. I would like to achieve the same thing when the script is stopped.

I tried to set the powered variable of the dongle to False: dongle.powered = False

It worked nice. But on the script restart attempt, there was an error as the device was powered down. And it looks like overkill for what I want to achieve. I searched for an API to disconnect existing connections but didn't find anything.

Below code, but it looks almost the same as cpu_temperature example.

  print("Starting Bluetooth service with ", self.__get_localname(), " and ", str(self.__adapter_address), " address")
        self.__blue_peripheral = peripheral.Peripheral(self.__adapter_address,
                                            local_name=self.__get_localname(),
                                            appearance=1344)    
        self.__blue_peripheral.add_service(srv_id=SRV_ID, uuid=SRVC_UUID_BLUE, primary=True)
        self.__blue_peripheral.add_characteristic(srv_id=SRV_ID, chr_id=CHR_ID_CONFIGURATION, uuid=CHRC_UUID_CONFIGURATION,
                                        value=[], notifying=False,
                                        flags=['read', 'notify'],
                                        read_callback=read_configuration,
                                        notify_callback=notify_callback
                                        )    
        self.__blue_peripheral.add_characteristic(srv_id=SRV_ID, chr_id=CHR_ID_STATUS, uuid=CHRC_STATUS_UUID,
                                        value=[], notifying=False,
                                        flags=['read', 'notify'],
                                        read_callback=read_status,
                                        write_callback=None,
                                        notify_callback=notify_callback
                                        )
        self.__blue_peripheral.add_characteristic(srv_id=SRV_ID, chr_id=CHR_ID_SENSORS, uuid=CHRC_UUID_SENSORS,
                                        value=[], notifying=False,
                                        flags=['read', 'notify'],
                                        read_callback=read_sensors,
                                        write_callback=None,
                                        notify_callback=notify_callback
                                        )                                       
        self.__blue_peripheral.publish()

How I could force connected clients to disconnect?

ukBaz commented 1 year ago

My initial thought on this is that you want something to run after publish is terminated. I've done an experiment with a function called disconnect_all()

    # Publish peripheral and start event loop
    cpu_monitor.publish()
    disconnect_all()

The function goes through the known devices, if they are connected, disconnect them.

def disconnect_all():
    print()
    for dev in device.Device.available():
        print("checking", dev.name)
        if dev.connected:
            print("\tDisconnecting", dev.name)
            dev.disconnect()

You'll need to add from bluezero import device at the top of the file. When I was connected with nRF Connect and did a ctrl-c on the Raspberry Pi it disconnected before terminating the script.

margorski commented 1 year ago

That works perfectly. Thank you for your help.