Pydbus plus de notifications en même temps
Je souhaite recevoir les données des capteurs des appareils BLE via des notifications via pydbus. J'utilise GLib avec une boucle principale liée à une partie de mon code:
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()
Lorsque je souhaite recevoir les notifications, les deux signaux arrivent presque en même temps et une seule fonction de rappel de notification (la première notification arrivée) s'exécute.
Comment pourrais-je résoudre ce problème? Je pensais à une file d'attente de messages.
ÉDITER:
fonction sensor1:
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)))
Fonction sensor2:
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)
Les données sensor2 sont envoyées avant sensor1 pour que les données sensor2 arrivent en premier Les deux données arrivent du même appareil, je n'ai pas encore ajouté les autres appareils.
Réponses
Merci pour chaque aide!
Après de nombreuses tentatives, j'ai remarqué que le problème venait de mon serveur. Les données des deux capteurs ont été envoyées à partir d'un appareil avec une différence d'environ 10 ms et l'envoi du message n'était pas en mode Notification mais en Indication.
Je ne l'ai pas remarqué auparavant, car je n'ai envoyé qu'une seule donnée de capteur avec 2 secondes de différence, mais le problème est survenu lorsque j'essayais d'envoyer 2 messages presque simultanément.
Après l'avoir défini sur Notification, le serveur pouvait envoyer des messages rapidement (il n'avait pas besoin d'accusé de réception).
Je sais que cette erreur n'a pas été causée par pydbus à la fin, mais par ma faute. J'espère que si quelqu'un trouve un problème similaire, il devra également vérifier le côté expéditeur (serveur).
Je ne sais pas si cela est utile ou non, mais je n'ai pas pu reproduire le problème. J'ai deux micro: bits BBC et je me suis abonné aux notifications du bouton A sur les deux. J'ai écrasé les boutons aussi près que possible et les deux sont apparus sans problème.
Voici le code que j'ai utilisé pour l'expérience. Il est légèrement plus long que ce qui est peut-être idéal comme exemple mais je l'ai créé en modifiant un exemple existant. Il ne devrait pas avoir besoin de trop de modifications pour s'exécuter avec votre appareil et voir si vous rencontrez le même problème.
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()
Voici un exemple de sortie de l'une des exécutions. Cela me semblait fiable.
(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
Cela a été fait à la hâte, alors faites-moi savoir si quelque chose n'est pas clair.