Pydbus 更多通知同时处理

Pydbus more notifications same time handling

我想使用 pydbus 通过通知从 BLE 设备接收传感器数据。 我在主循环中使用 GLib 链接了我的部分代码:

def sensor1_handler(iface, prop_changed, prop_removed):
    if 'Value' in prop_changed:
       
        """Handle values"""
       
def sensor2_handler(iface, prop_changed, prop_removed):
    if 'Value' in prop_changed:
       """Handle values"""

sensor1=bus.get("org.bluez", "/org/bluez/hciX/dev_XX_XX_XX_XX_XX_XX/serviceYYYY/charYYYY")
sensor2=bus.get("org.bluez", "/org/bluez/hciX/dev_XX_XX_XX_XX_XX_XX/serviceYYYY/charYYYY")
sensor1.onPropertiesChanged = sensor1_handler
sensor2.onPropertiesChanged = sensor2_handler

sensor2.StartNotify()
sensor1.StartNotify()

当我想接收通知时,两个信号几乎同时到达,只有一个(第一个到达的通知)通知回调函数运行。

我该如何解决这个问题?我在考虑消息队列。

编辑:

传感器 1 函数:

def sensor1_handler(iface, prop_changed, prop_removed):
    if 'Value' in prop_changed:
        temperatureLSB = prop_changed['Value'][1]
        temperatureMSB = prop_changed['Value'][0]
        humidityLSB = prop_changed['Value'][3]
        humidityMSB = prop_changed['Value'][2]
        temperature = temperatureLSB | (temperatureMSB << 8)
        humidity = humidityLSB | (humidityMSB << 8)
        print(-45+175*(temperature/(pow(2,16)-1)))
        print(100*(humidity/(pow(2,16)-1)))

传感器 2 函数:

def sensor2_handler(iface, prop_changed, prop_removed):
    if 'Value' in prop_changed:
        iaqLSB = prop_changed['Value'][1]
        iaqMSB = prop_changed['Value'][0]
        iaq = iaqLSB | (iaqMSB << 8)
        print(iaq)

sensor2 数据先于 sensor1 发送,因此 sensor2 数据先到达。这两个数据来自同一个设备,我还没有添加其他设备。

不确定这是否有帮助,但我无法重现该问题。我有两个 BBC micro:bits 并且已经在他们两个上订阅了来自按钮 A 的通知。我一直在尽可能接近地同时按下按钮,并且都没有问题地出现。

下面是我用于实验的代码。作为示例,它比理想情况稍长,但我是通过修改现有示例创建的。它应该不需要对您的设备进行太多修改运行,看看您是否有同样的问题。

from time import sleep
from gi.repository import GLib

import pydbus

bus = pydbus.SystemBus()

mngr = bus.get('org.bluez', '/')

DEV1 = 'DC:DB:16:6B:8C:5F'
DEV2 = 'DE:82:35:E7:43:BE'

def get_characteristic_path(dev_path, uuid):
    mng_objs = mngr.GetManagedObjects()
    for path in mng_objs:
        chr_uuid = mng_objs[path].get('org.bluez.GattCharacteristic1', {}).get('UUID')
        if path.startswith(dev_path) and chr_uuid == uuid:
           return path

class MyRemoteDevice:
    CHAR_UUID = 'e95dda90-251d-470a-a062-fa1922dfa9a8'

    def __init__(self, mac_addr):
        device_path = f"/org/bluez/hci0/dev_{mac_addr.replace(':', '_')}"
        self.device = bus.get('org.bluez', device_path)

        # Placeholder for characteristic details
        self.characteristic = None

    def _get_gatt_details(self):
        char_path = get_characteristic_path(self.device._path, MyRemoteDevice.CHAR_UUID)
        self.characteristic = bus.get('org.bluez', char_path)


    def connect(self):
        self.device.Connect()
        while not self.device.ServicesResolved:
            sleep(0.25)
        self._get_gatt_details()

    def disconnect(self):
        self.characteristic.StopNotify()
        self.device.Disconnect()

    def read(self):
        return self.characteristic.ReadValue({})

    def write(self, new_value):
        self.characteristic.WriteValue(new_value, {})

    def _notify_handler(self, iface, prop_changed, prop_removed):
        value = prop_changed.get('Value', [])
        if value:
            print(f'{self.device.Address} is {int.from_bytes(value, byteorder="little")}')

    def start_notify(self):
        self.characteristic.onPropertiesChanged = self._notify_handler
        self.characteristic.StartNotify()


my_first_dev = MyRemoteDevice(DEV1)
my_second_dev = MyRemoteDevice(DEV2)

my_first_dev.connect()
my_second_dev.connect()

print(my_first_dev.read())
print(my_second_dev.read())

my_first_dev.start_notify()
my_second_dev.start_notify()

mainloop = GLib.MainLoop()

try:
    mainloop.run()
except KeyboardInterrupt:
    mainloop.quit()
    my_first_dev.disconnect()
    my_second_dev.disconnect()

这是 运行 之一的示例输出。这对我来说似乎很可靠。

(venv) pi@raspberrypi:~/stack_overflow $ python two_notifications.py 
[0]
[0]
DC:DB:16:6B:8C:5F is 1
DE:82:35:E7:43:BE is 1
DC:DB:16:6B:8C:5F is 2
DE:82:35:E7:43:BE is 2
DC:DB:16:6B:8C:5F is 0
DE:82:35:E7:43:BE is 0
DC:DB:16:6B:8C:5F is 1
DE:82:35:E7:43:BE is 1
DC:DB:16:6B:8C:5F is 0
DE:82:35:E7:43:BE is 0
DC:DB:16:6B:8C:5F is 1
DE:82:35:E7:43:BE is 1
DC:DB:16:6B:8C:5F is 2
DE:82:35:E7:43:BE is 2
DE:82:35:E7:43:BE is 0
DC:DB:16:6B:8C:5F is 0
DE:82:35:E7:43:BE is 1
DC:DB:16:6B:8C:5F is 1
DE:82:35:E7:43:BE is 2
DC:DB:16:6B:8C:5F is 2
DC:DB:16:6B:8C:5F is 0
DE:82:35:E7:43:BE is 0

完成的有点匆忙,如果有任何不清楚的地方,请告诉我。

谢谢大家的帮助!

经过多次尝试,我发现问题出在我的服务器端。 两个传感器数据是从一台设备发送的,相差约 10 毫秒,消息发送不是通知模式而是指示。

我之前没有注意到,因为我只发送了 1 个传感器数据,相差 2 秒,但是当我试图几乎同时发送 2 个消息时出现了问题。

设置为Notification后,服务器可以快速发送消息(不需要确认)。

我知道这个错误最终不是pydbus引起的,而是我的错。我希望如果有人发现类似的问题,他们也应该检查发送方(服务器)。