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引起的,而是我的错。我希望如果有人发现类似的问题,他们也应该检查发送方(服务器)。
我想使用 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引起的,而是我的错。我希望如果有人发现类似的问题,他们也应该检查发送方(服务器)。