ukBaz / python-bluezero

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

Restart Advertisement after Unregistering #339

Closed gaurav-Lilly closed 3 years ago

gaurav-Lilly commented 3 years ago

Hi ukbaz,

I am using r-pi 3 with python. In one of the scenario , the requirement is

But my query is, how can i restart the advertisement and reconnect ? Also, when i call UnregisterApp() , only then peripheral disconnects from the central. is that the correct way ? is there any other way where a central can disconnect ?

ukBaz commented 3 years ago

I am not sure I fully understand your questions.

When the client/central app disconnects, then it disconnects. I don't think you would normally stop the app at that point. Normally a Bluetooth peripheral would just sit there with the app running.

Stopping the advertising after 30 seconds. I am assuming this is because you want the device to then be "invisible" to new connections.

There are various parameters to set timeouts on discoverable, pairable, and adverts that you could experiment with.

I just did a very quick experiment with the following to hide and restart advertisements on the BLE UART example in the library

def hide_device(params):
    dongle, ad_man, advert = params
    print('hiding device')
    dongle.discoverable = False
    dongle.pairable = False
    ad_man.unregister_advertisement(advert)
    return False

def restart_advert(params):
    dongle, ad_man, advert = params
    print('restart advert')
    dongle.discoverable = True
    dongle.pairable = True
    ad_man.register_advertisement(advert)
    return False

I called this functions with a timer from the main() function but these could be called from other events

    async_tools.add_timer_seconds(20, hide_device,
                                  (ble_uart.dongle,
                                  ble_uart.ad_manager,
                                  ble_uart.advert))
    async_tools.add_timer_seconds(40, restart_advert,
                                  (ble_uart.dongle,
                                  ble_uart.ad_manager,
                                  ble_uart.advert))
    ble_uart.publish()

I'm sure these could be improved and more logic added etc, but it seemed to do the trick for me. Is this what you were looking for?

gaurav-Lilly commented 3 years ago

Thanks much for giving ideas on ways to stop advertising. But i am still looking to resolve my second query , which is:

ukBaz commented 3 years ago

I don't understand the statement:

if i receive a sessionEnd request from central, i have to disconnect with the central immediately

To make sure I'm visualising the same thing as you; I am thinking of a phone as the central device and the RPi as the peripheral.

Are you talking about, if the phone sends a disconnect, then you want the peripheral to disconnect? Because that should happen by default as that is what disconnect does.

If you are asking about how does the peripheral initiate the disconnect, then it is very similar, it is Device.disconnect. As an example, I have modified the on_connect method in the BLE UART example to disconnect any central that is connected 20 seconds after connections:

class UARTDevice:
    tx_obj = None

    @classmethod
    def on_connect(cls, ble_device: device.Device):
        print("Connected to " + str(ble_device.address))
        async_tools.add_timer_seconds(20, ble_device.disconnect)

Repeatedly using unregister_application and register_application does not seem to be the correct way to control the connections.

Did I answer your question this time?

ukBaz commented 3 years ago

@gaurav-Lilly Is this done? Can I close the ticket?

gaurav-Lilly commented 3 years ago

Yes absolutely, the code that worked for my use case:

for path, interfaces in objects.items():
            if "org.bluez.Device1" not in interfaces:
                continue
            properties = interfaces["org.bluez.Device1"]
            device = bluezutils.find_device(properties["Address"], None)
            device.Disconnect()