diff --git a/gateway/gateway.py b/gateway/gateway.py index 4ddc3ad..5258b95 100644 --- a/gateway/gateway.py +++ b/gateway/gateway.py @@ -24,6 +24,13 @@ class Gateway: KEY_TEMP = 0x03 KEY_CO2 = 0x04 + # Sentinel value indicating sensor failure or not ready + INVALID_VALUE = 0xFFFFFFFF + + # Expected payload size in bytes: + # 4 keys (1B each) + window(1B) + humidity(1B) + temp(2B) + co2(4B) = 12 bytes + EXPECTED_PAYLOAD_SIZE = 12 + def __init__(self, config: dict): self.gateway_id = config["gateway_id"] self.mqtt_broker = config["mqtt"]["broker"] @@ -81,6 +88,9 @@ class Gateway: 0x02 : humidity (1 byte, integer %) 0x03 : temperature (2 bytes big-endian, integer / 10 = degrees C) 0x04 : CO2 ppm (4 bytes big-endian, integer) + + Values equal to 0xFFFFFFFF indicate sensor failure or not ready + and are discarded. """ result = {} i = 0 # no preamble to skip — company_id is not in raw bytes @@ -100,10 +110,16 @@ class Gateway: result["temp"] = raw / 10 i += 2 elif key == self.KEY_CO2 and i + 3 < len(data): - result["co2_ppm"] = int.from_bytes(data[i:i+4], byteorder='big') + co2 = int.from_bytes(data[i:i+4], byteorder='big') + # 0xFFFFFFFF indicates sensor not ready or failed + if co2 != self.INVALID_VALUE: + result["co2_ppm"] = co2 + else: + log.debug(f"CO2 sensor not ready — discarding value 0xFFFFFFFF") i += 4 else: - log.warning(f"Unknown key 0x{key:02x} at offset {i-1}") + # Unknown key — likely a non-Thingy device, ignore silently + log.debug(f"Unknown key 0x{key:02x} at offset {i-1}") break return result @@ -132,15 +148,19 @@ class Gateway: if 0xffff not in adv_data.manufacturer_data: return - # company_id 0xffff is defined in the firmware spec - # the raw bytes do not include the company_id itself raw = adv_data.manufacturer_data[0xffff] + # Filter on exact payload size to avoid false positives from + # other BLE devices using the same company_id + if len(raw) != self.EXPECTED_PAYLOAD_SIZE: + log.debug(f"{device.address} | ignored — unexpected payload size: {len(raw)}") + return + log.debug(f"{device.address} | Thingy detected, raw: {list(raw)}") data = self.decode_payload(raw) if not data: - log.warning(f"{device.address} | empty decoded payload") + log.debug(f"{device.address} | empty decoded payload — ignored") return log.debug(f"{device.address} | decoded: {data}")