fix(gateway): fix BLE filtering and MQTT connection validation
BLE filtering: - Replace UUID service filter with company_id 0xffff filter in manufacturer_data — Zephyr firmware does not announce a service UUID - Remove preamble skip in decode_payload (i=0 instead of i=2) since company_id is handled by the BLE stack and not in raw bytes - Fix endianness: switch temperature and CO2 decoding from little-endian to big-endian to match Zephyr firmware implementation MQTT validation: - Add on_connect callback to confirm successful connection to broker - Log error with reason code if connection fails - Add on_publish callback to confirm message delivery to broker - Replace synchronous connected log with async connecting log Validated end-to-end: Thingy:52 data received and confirmed by broker
This commit is contained in:
@@ -54,22 +54,36 @@ class Gateway:
|
|||||||
self.mqttc.tls_set()
|
self.mqttc.tls_set()
|
||||||
log.info("TLS enabled")
|
log.info("TLS enabled")
|
||||||
|
|
||||||
|
# Callback to confirm connection to broker
|
||||||
|
def on_connect(client, userdata, flags, reason_code, properties):
|
||||||
|
if reason_code == 0:
|
||||||
|
log.info("Successfully connected to MQTT broker")
|
||||||
|
else:
|
||||||
|
log.error(f"Failed to connect to MQTT broker — reason code: {reason_code}")
|
||||||
|
|
||||||
|
# Callback to confirm message delivery to broker
|
||||||
|
def on_publish(client, userdata, mid, reason_code, properties):
|
||||||
|
log.info(f"Message confirmed by broker — mid: {mid}")
|
||||||
|
|
||||||
|
self.mqttc.on_connect = on_connect
|
||||||
|
self.mqttc.on_publish = on_publish
|
||||||
|
|
||||||
self.mqttc.connect(self.mqtt_broker, self.mqtt_port)
|
self.mqttc.connect(self.mqtt_broker, self.mqtt_port)
|
||||||
self.mqttc.loop_start()
|
self.mqttc.loop_start()
|
||||||
log.info("MQTT client connected")
|
log.info("MQTT client connecting...")
|
||||||
|
|
||||||
def decode_payload(self, data: bytes) -> dict:
|
def decode_payload(self, data: bytes) -> dict:
|
||||||
"""Decode key/value pairs from BLE advertising payload.
|
"""Decode key/value pairs from BLE advertising payload.
|
||||||
|
|
||||||
Format per firmware spec:
|
Format per firmware spec (no preamble in raw bytes — company_id
|
||||||
2 bytes preamble (company id = 0xffff) — skipped
|
is handled by the BLE stack and not included in manufacturer data):
|
||||||
0x01 : window open (1 byte, 0 or 1)
|
0x01 : window open (1 byte, 0 or 1)
|
||||||
0x02 : humidity (1 byte, integer %)
|
0x02 : humidity (1 byte, integer %)
|
||||||
0x03 : temperature (2 bytes big-endian, integer / 10 = degrees C)
|
0x03 : temperature (2 bytes big-endian, integer / 10 = degrees C)
|
||||||
0x04 : CO2 ppm (4 bytes big-endian, integer)
|
0x04 : CO2 ppm (4 bytes big-endian, integer)
|
||||||
"""
|
"""
|
||||||
result = {}
|
result = {}
|
||||||
i = 2 # skip 2-byte preamble (company id 0xffff)
|
i = 0 # no preamble to skip — company_id is not in raw bytes
|
||||||
while i < len(data):
|
while i < len(data):
|
||||||
key = data[i]
|
key = data[i]
|
||||||
i += 1
|
i += 1
|
||||||
@@ -114,15 +128,13 @@ class Gateway:
|
|||||||
log.info(f"Published to {topic} : {payload}")
|
log.info(f"Published to {topic} : {payload}")
|
||||||
|
|
||||||
def on_device_found(self, device, adv_data):
|
def on_device_found(self, device, adv_data):
|
||||||
"""BLE scan callback — filters on Adrien's preamble (0xffff) in manufacturer data."""
|
"""BLE scan callback — filters on company_id 0xffff in manufacturer data."""
|
||||||
if not adv_data.manufacturer_data:
|
if 0xffff not in adv_data.manufacturer_data:
|
||||||
return
|
return
|
||||||
|
|
||||||
raw = list(adv_data.manufacturer_data.values())[0]
|
# company_id 0xffff is defined in the firmware spec
|
||||||
|
# the raw bytes do not include the company_id itself
|
||||||
# Filter on preamble 0xffff (company id defined in firmware spec)
|
raw = adv_data.manufacturer_data[0xffff]
|
||||||
if len(raw) < 2 or raw[0] != 0xff or raw[1] != 0xff:
|
|
||||||
return
|
|
||||||
|
|
||||||
log.debug(f"{device.address} | Thingy detected, raw: {list(raw)}")
|
log.debug(f"{device.address} | Thingy detected, raw: {list(raw)}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user