BLE服务器:如何清除注册的广告?

时间:2018-12-19 09:03:58

标签: python bluetooth-lowenergy dbus intel-edison

我正在尝试运行以下python脚本:https://github.com/Jumperr-labs/python-gatt-server(gatt-server-example.py),它是蓝牙低功耗服务器。

它在我的计算机上可以正常运行,但是当我尝试在intel-edison上运行它时,出现以下错误:

Failed to register advertisement: org.bluez.Error.NotPermitted: Maximum        
advertisements reached

Python-dbus和bluez已安装在此设备上(Bluez v5.50)。我正在寻找一种方法来清除注册的广告(如果有的话)并可以在此ined-edison上启动服务器。

2 个答案:

答案 0 :(得分:2)

如果您从github.com/edison-fw运行最新的Yocto映像并切换到最新的python3 example gatt server,则服务器将运行而不会出现错误。 Bluetoothctl type 'a stream = Eos | StrCons of 'a*(unit -> 'a stream) (*integers from n onwards*) let rec nums_from n = StrCons(n,fun () -> nums_from (n+1)) let rec filterStr (test : 'a -> bool) (s: 'a stream) = match s with |Eos -> Eos |StrCons(q,w) -> if test q then StrCons(q,fun ()-> filterStr test (w ())) else filterStr test (w ()) (*Remove all numbers mod p*) let sift p = filterStr (fun x -> x mod p <> 0) (*Sieves*) let rec sieves s = match s with |Eos ->Eos |StrCons(x,g) -> StrCons(x, fun ()-> sieves (sift x (g ()))) (*primes*) let allprimes = sieves (nums_from 2) let rec listify s n= if n =0 then [] else match s with |Eos -> [] |StrCons(q,w) -> q::(listify (w ()) (n-1)) let twodigitsprimes = filterStr (fun x -> x > 10&& x<100) allprimes let twodigitsprimeslist= listify twodigitsprimes 21 显示,杀死gatt服务器后,心率服务会自动注销。

答案 1 :(得分:1)

BlueZ API docs为错误提供了一些解释:

Methods     RegisterAdvertisement(object advertisement, dict options)

            Registers an advertisement object to be sent over the LE
            Advertising channel.  The service must be exported
            under interface LEAdvertisement1.

            ...

            If the maximum number of advertisement instances is
            reached it will result in NotPermitted error.

因此,错误来自RegisterAdvertisement调用:

ad_manager.RegisterAdvertisement(test_advertisement.get_path(), {},
                                 reply_handler=register_ad_cb, 
                                 error_handler=functools.partial(register_ad_error_cb, mainloop))

清除以前注册的广告的“强力”方法是始终在运行BLE服务器之前重新启动蓝牙服务。

# Restart bluetooth
$ systemctl restart bluetooth
$ systemctl status bluetooth
● bluetooth.service - Bluetooth service
   Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset
   Active: active (running) since Thu 2020-08-20 18:07:55 JST; 4s ago
...

# Start BLE server
$ python3 gatt-server.py

一种更“优雅”的方法是尝试确保您的BLE服务器实现具有正确关闭或清理的处理。尝试在服务器进程结束/退出时调用BlueZ广告管理器和GATT管理器API Unregister*方法:

您可能还需要quit创建的GLib.MainLoop

example-gatt-server中提到的accepted answer不能执行此操作,但是您也可以检查可以执行的example-advertisement代码(也来自BlueZ)这个:

def shutdown(timeout):
    print('Advertising for {} seconds...'.format(timeout))
    time.sleep(timeout)
    mainloop.quit()


def main(timeout=0):
    
    ...

    mainloop = GObject.MainLoop()

    ad_manager.RegisterAdvertisement(test_advertisement.get_path(), {},
                                     reply_handler=register_ad_cb,
                                     error_handler=register_ad_error_cb)

    if timeout > 0:
        threading.Thread(target=shutdown, args=(timeout,)).start()
    else:
        print('Advertising forever...')

    mainloop.run()  # blocks until mainloop.quit() is called

    ad_manager.UnregisterAdvertisement(test_advertisement)
    print('Advertisement unregistered')
    dbus.service.Object.remove_from_connection(test_advertisement)

请注意,当退出mainloop时,main函数将以清除调用结束。

https://github.com/Jumperr-labs/python-gatt-server中的代码只是BlueZ代码的移植/重新组织的版本。一种改进是修改advertisinggatt-server模块以添加适当的清除。

一种方法是通过使用SIGTERM信号(然后是catching that SIGTERM within the app)优雅地杀死BLE服务器进程。

# ----------------------------------------------------------------------
def terminate(signum, frame):
    adv_manager.UnregisterAdvertisement(...)
    gatt_manager.UnregisterApplication(...)
    main_loop.quit()
    return True
# ----------------------------------------------------------------------
signal.signal(signal.SIGTERM, terminate)