diff --git a/api/ble.py b/api/ble.py index 1c36a55..abddb48 100644 --- a/api/ble.py +++ b/api/ble.py @@ -181,7 +181,6 @@ def _is_match(mac: str, name: str) -> bool: # This is the actual function that does the magic #################################################### async def read_data(mac: str) -> Optional[SensorReading]: - try: address = await asyncio.wait_for( _discover_device(mac), @@ -193,43 +192,35 @@ async def read_data(mac: str) -> Optional[SensorReading]: if not address: return None - + + client: BleakClient | None = None try: - async with BleakClient(address, timeout=CONNECT_TIMEOUT) as client: - # NEW BLOCK ---------------------------------------------- - try: - await asyncio.wait_for(client.get_services(), - timeout=SERVICE_DISCOVERY_TIMEOUT) - except asyncio.TimeoutError: - log.warning("Service discovery timed out for %s", mac) - return None - - except Exception as e: - log.error(f"Discovery failed - {e}") + client = BleakClient(address, timeout=CONNECT_TIMEOUT) + await client.connect() + # service discovery + await asyncio.wait_for(client.get_services(), timeout=SERVICE_DISCOVERY_TIMEOUT) - #################################################### - # If we get here, services are available. - #################################################### - if MI_SERVICE_UUID.lower() not in ( - s.uuid.lower() for s in client.services - ): - log.error("Mi service not found on %s", mac) - return None + if MI_SERVICE_UUID.lower() not in (s.uuid.lower() for s in client.services): + log.error("Mi service not found on %s", mac) + return None - raw = await asyncio.wait_for( - client.read_gatt_char(TEMP_CHAR_UUID), - timeout=READ_TIMEOUT, - ) - temp, hum = _parse_sensor_data(raw) - log.info("Read from %s: %.1f°C, %d%%", mac, temp, hum) - return SensorReading(mac=mac, temperature=temp, humidity=hum) + raw = await asyncio.wait_for(client.read_gatt_char(TEMP_CHAR_UUID), timeout=READ_TIMEOUT) + temp, hum = _parse_sensor_data(raw) + log.info("Read from %s: %.1f°C, %d%%", mac, temp, hum) + return SensorReading(mac=mac, temperature=temp, humidity=hum) - except asyncio.TimeoutError: - # This is the *connect* timeout (BleakClient) - log.error("Connection to %s timed out after %.1fs", mac, CONNECT_TIMEOUT) except Exception as exc: log.exception("Error reading from %s: %s", mac, exc) - return None + return None + + finally: + # Safe disconnect – swallow any EOFError caused by a dropped DBus socket + if client is not None: + try: + await client.disconnect() + except Exception as e: + # Usually EOFError, just log and ignore + log.debug("Disconnect error (ignored): %s", e) ######################################################################################################## ### Test Function Section