python-3.x 使用pydbus捕获所有BLE广告电报

3pmvbmvn  于 4个月前  发布在  Python
关注(0)|答案(1)|浏览(59)

我有一个商业伙伴提供的加速传感器,当被触发时,每秒发送大约20个BLE广告。我安装了Bluez 5.66,我正在运行一个pydbus应用程序,它来自这篇文章Active BLE Scanning (BlueZ) - Issue with DBus
顺便说一句,感谢@uKbaz和他所有关于这个主题的教程。

import argparse
from gi.repository import GLib
from pydbus import SystemBus
import datetime

DEVICE_INTERFACE = 'org.bluez.Device1'

remove_list = set()

def stop_scan():
    """Stop device discovery and quit event loop"""
    adapter.StopDiscovery()
    mainloop.quit()

def on_iface_added(owner, path, iface, signal, interfaces_and_properties):
    """
    Event handler for D-Bus interface added.
    Test to see if it is a new Bluetooth device
    """
    iface_path, iface_props = interfaces_and_properties
    if DEVICE_INTERFACE in iface_props:
        on_device_found(iface_path, iface_props[DEVICE_INTERFACE])

def on_properties_changed(owner, path, iface, signal, interfaces_and_properties):
    """
    Event handler for D-Bus interface properties changed.
    Manufacturing data or Service Data change
    """
    iface_path, iface_props, leftover = interfaces_and_properties
    if DEVICE_INTERFACE in interfaces_and_properties:
        on_device_found(path, iface_props)

def on_device_found(device_path, device_props):
    """
    Handle new Bluetooth device being discover.
    If it is a beacon of type iBeacon, Eddystone, AltBeacon
    then process it
    """
    address = device_props.get('Address')
    
    address_type = device_props.get('AddressType')
    name = device_props.get('Name')
    alias = device_props.get('Alias')
    paired = device_props.get('Paired')
    trusted = device_props.get('Trusted')
    rssi = device_props.get('RSSI')
    service_data = device_props.get('ServiceData')
    manufacturer_data = device_props.get('ManufacturerData')
    
    if address == 'D7:6F:3F:5E:F4:BF' or "D7_6F_3F_5E_F4_BF" in device_path:
    
        print(str(datetime.datetime.now()) + " MAC: " + str(address) + 
              " RSSI:" + str(rssi) + " MData:" + str(manufacturer_data))
        adapter.RemoveDevice(device_path)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--duration', type=int, default=0,
                        help='Duration of scan [0 for continuous]')
    args = parser.parse_args()
    bus = SystemBus()
    adapter = bus.get('org.bluez', '/org/bluez/hci0')
    #adapter = bus.get('org.bluez', '/org/bluez/hci1')
    bus.subscribe(iface='org.freedesktop.DBus.ObjectManager',
                  signal='InterfacesAdded',
                  signal_fired=on_iface_added)
    
    # bus.subscribe(iface='org.freedesktop.DBus.Properties',
    #               signal='PropertiesChanged',
    #               signal_fired=on_properties_changed)

    mainloop = GLib.MainLoop()

    if args.duration > 0:
        GLib.timeout_add_seconds(args.duration, stop_scan)
    adapter.SetDiscoveryFilter({'DuplicateData': GLib.Variant.new_boolean(True), 
                                "Transport":GLib.Variant.new_string("le")})
    
    adapter.StartDiscovery()

    try:
        print('\n\tUse CTRL-C to stop discovery\n')
        mainloop.run()
    except KeyboardInterrupt:
        stop_scan()

字符串
该应用程序正在扫描新设备。如果发现新设备,它会抓取相关数据,并从适配器的设备列表中删除该设备,以便再次发现。通常该应用程序可以工作,但我每9-12秒只看到一个广告,这是远远不够的。
这里是最新的输出被分割成时间戳,RSSI,MAC和制造数据。第一个字节是校验和,后面是ID字节,总是108(0x 6C),类型字节,总是5(0x 05)在我的情况下。接下来的四个字节是相当有趣的,因为他们代表了自启动以来发送的广告计数。正如人们所看到的,我错过了大约180..220两个发现之间的电报。

2023-12-14 12:29:43.101505 MAC: D7:6F:3F:5E:F4:BF RSSI:-42 MData:{22272: [4, 108, 5, 0, 0, 135, 40, 255, 6, 91, 219, 250, 26, 113, 63, 208, 95, 198, 254, 145, 167, 63, 252, 8, 61, 44, 64]}
2023-12-14 12:29:52.786266 MAC: D7:6F:3F:5E:F4:BF RSSI:-50 MData:{62720: [172, 108, 5, 0, 0, 135, 228, 6, 244, 242, 147, 225, 202, 207, 177, 231, 113, 8, 69, 128, 139, 156, 1, 191, 159, 180, 64]}
2023-12-14 12:30:03.416085 MAC: D7:6F:3F:5E:F4:BF RSSI:-54 MData:{46336: [155, 108, 5, 0, 0, 136, 178, 23, 254, 79, 104, 76, 238, 62, 128, 39, 134, 13, 60, 204, 68, 50, 229, 175, 192, 148, 64]}
2023-12-14 12:30:15.044914 MAC: D7:6F:3F:5E:F4:BF RSSI:-46 MData:{19712: [183, 108, 5, 0, 0, 137, 148, 255, 78, 78, 84, 9, 52, 187, 96, 8, 222, 234, 64, 19, 115, 152, 0, 13, 222, 72, 64]}
2023-12-14 12:30:25.915247 MAC: D7:6F:3F:5E:F4:BF RSSI:-42 MData:{57856: [63, 108, 5, 0, 0, 138, 104, 43, 102, 106, 174, 150, 40, 251, 252, 20, 128, 245, 178, 191, 247, 116, 194, 65, 222, 208, 64]}
2023-12-14 12:30:47.678187 MAC: D7:6F:3F:5E:F4:BF RSSI:-42 MData:{21504: [48, 108, 5, 0, 0, 140, 15, 0, 192, 220, 0, 5, 2, 47, 240, 20, 7, 190, 191, 160, 55, 8, 1, 127, 107, 188, 64]}
2023-12-14 12:30:58.415692 MAC: D7:6F:3F:5E:F4:BF RSSI:-52 MData:{43776: [37, 108, 5, 0, 0, 140, 223, 62, 128, 238, 232, 244, 19, 191, 227, 192, 28, 214, 77, 16, 223, 152, 46, 2, 78, 168, 64]}
2023-12-14 12:31:20.841068 MAC: D7:6F:3F:5E:F4:BF RSSI:-50 MData:{36352: [96, 108, 5, 0, 0, 142, 148, 210, 191, 112, 95, 76, 253, 1, 205, 91, 240, 1, 53, 160, 8, 13, 214, 63, 192, 76, 64]}


首先,我认为可能需要调整扫描窗口和/或间隔,但它们都设置为11,250 ms,这应该会导致连续扫描。我想测试的一件事是将扫描类型更改为被动扫描,这可能会加速发现过程,但我在bluez文档中找不到任何函数来设置它。https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc
在这里,你可以看到btmon的启动日志,它与应用程序并行运行:

= Note: Linux version 4.19.94 (aarch64)                                          
= Note: Bluetooth subsystem version 2.22                                         
= New Index: E8:48:B8:C8:20:00 (Primary,USB,hci1)                                
= Open Index: E8:48:B8:C8:20:00                                                  
= Index Info: E8:48:B8:C8:20:00 (Realtek Semiconductor Corporation)              
= New Index: 08:BF:B8:53:93:6F (Primary,USB,hci0)                                
= Open Index: 08:BF:B8:53:93:6F                                                  
= Index Info: 08:BF:B8:53:93:6F (Realtek Semiconductor Corporation)              
@ MGMT Open: bluetoothd (privileged) version 1.14                                
@ MGMT Command: Start Discovery (0x0023) plen 1                                  
        Address type: 0x07
          BR/EDR
          LE Public
          LE Random
< HCI Command: LE Set Random Address (0x08|0x0005) plen 6                        
        Address: 34:7A:C0:B9:B5:80 (Non-Resolvable)
> HCI Event: Command Complete (0x0e) plen 4                                      
      LE Set Random Address (0x08|0x0005) ncmd 2
        Status: Success (0x00)
< HCI Command: LE Set Extended Scan Parameters (0x08|0x0041) plen 8              
        Own address type: Random (0x01)
        Filter policy: Accept all advertisement (0x00)
        PHYs: 0x01
        Entry 0: LE 1M
          Type: Active (0x01)
          Interval: 11.250 msec (0x0012)
          Window: 11.250 msec (0x0012)
> HCI Event: Command Complete (0x0e) plen 4                                      
      LE Set Extended Scan Parameters (0x08|0x0041) ncmd 2
        Status: Success (0x00)
< HCI Command: LE Set Extended Scan Enable (0x08|0x0042) plen 6                  
        Extended scan: Enabled (0x01)
        Filter duplicates: Enabled (0x01)
        Duration: 0 msec (0x0000)
        Period: 0.00 sec (0x0000)
> HCI Event: Command Complete (0x0e) plen 4                                      
      LE Set Extended Scan Enable (0x08|0x0042) ncmd 2
        Status: Success (0x00)
@ MGMT Event: Command Complete (0x0001) plen 4                                   
      Start Discovery (0x0023) plen 1
        Status: Success (0x00)
        Address type: 0x07
          BR/EDR
          LE Public
          LE Random
@ MGMT Event: Discovering (0x0013) plen 2                                        
        Address type: 0x07
          BR/EDR
          LE Public
          LE Random
        Discovery: Enabled (0x01)


我还试图保留设备一旦发现,只是检查属性更改,这将触发每当制造商或服务数据被发现(如果我正确的文档).但它也没有帮助. https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/org.bluez.Adapter.rst

:bool DuplicateData (Default true):

        Disables duplicate detection of advertisement data.

        When enabled PropertiesChanged signals will be generated for
        either ManufacturerData and ServiceData everytime they are
        discovered.


这可能是硬件的问题吗?我已经连接了两个BT加密狗,其中只有第一个被使用。一个加密狗是从TP Link和一个是从华硕,但都使用realtek芯片组RTL 8761 B。
你们中有没有人有更进一步的想法如何捕捉更多的电报?我知道这是不可能捕捉所有的,但也许80-90%将是完美的。
非常感谢你!

mtb9vblg

mtb9vblg1#

好吧,首先,我不认为你可以得到所有的广告使用Bluez.但你可以接近.
这样做:

  • 只订阅Properties Changed信号,忽略InterfaceAdded。也不要做RemoveDevice...
  • 向SetDiscoveryFilter添加RSSI参数,值为-100
  • DuplicateData的值必须为True.但您已经有了该值。

如果你这样做,你应该至少每秒得到几个事件。

import argparse
from gi.repository import GLib
from pydbus import SystemBus
import datetime

DEVICE_INTERFACE = 'org.bluez.Device1'

def stop_scan():
    """Stop device discovery and quit event loop"""
    adapter.StopDiscovery()
    mainloop.quit()

def on_properties_changed(owner, path, iface, signal, interfaces_and_properties):
    iface_path, propsChanged, leftover = interfaces_and_properties
    if DEVICE_INTERFACE in interfaces_and_properties:
        on_device_found(path, propsChanged)

def on_device_found(device_path, device_props):
    address = get_address(device_path)
    rssi = device_props.get('RSSI')
    service_data = device_props.get('ServiceData')
    manufacturer_data = device_props.get('ManufacturerData')
    
    if address == 'D7:6F:3F:5E:F4:BF':
        print(str(datetime.datetime.now()) + " " + str(address) + 
              " RSSI:" + str(rssi) + " MData:" + str(manufacturer_data))

def get_address(device_path):
    return device_path.split("/")[-1].replace("dev_", "").replace("_",":")
    
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--duration', type=int, default=0,
                        help='Duration of scan [0 for continuous]')
    args = parser.parse_args()
    bus = SystemBus()
    adapter = bus.get('org.bluez', '/org/bluez/hci0')    
    bus.subscribe(iface='org.freedesktop.DBus.Properties',
                   signal='PropertiesChanged',
                   arg0 = DEVICE_INTERFACE,
                   signal_fired=on_properties_changed)

    mainloop = GLib.MainLoop()

    if args.duration > 0:
        GLib.timeout_add_seconds(args.duration, stop_scan)
    adapter.SetDiscoveryFilter({"DuplicateData": GLib.Variant.new_boolean(True), 
                                "Transport":GLib.Variant.new_string("le"), 
                                "RSSI": GLib.Variant.new_int16(-100)})
    
    adapter.StartDiscovery()

    try:
        print('\n\tUse CTRL-C to stop discovery\n')
        mainloop.run()
    except KeyboardInterrupt:
        stop_scan()

字符串

相关问题