Source code for herosdevices.hardware.bosch.bme

"""Module for BME sensors."""

from herosdevices.core.templates.i2c import I2CDeviceTemplate
from herosdevices.helper import log, mark_driver

try:
    from bme280 import BME280 as _BME280  # type: ignore[import-untyped]
except ModuleNotFoundError:
    _BME280 = None  # type: ignore[assignment,misc]


[docs] @mark_driver( state="beta", info="BME280 Environmental Sensor", product_page="https://www.bosch-sensortec.com/en/products/environmental-sensors/humidity-sensors-bme280", requires={"bme280": "pimoroni-bme280"}, ) class BME280(I2CDeviceTemplate): """BME280 Environmental Sensor via I2C.""" def __init__(self, bus_id: int = 1) -> None: """Create a new BME280 representation. Args: bus_id: I2C bus id (default 1). """ super().__init__(bus_id, keep_alive=True) self._device: _BME280 | None = None # type: ignore[valid-type] def _open(self) -> None: """Open the I2C bus and initialise the sensor with a dummy read. The first reading from the BME280 after power-on is unreliable, so it is discarded here. Cleans up and re-raises on any error. """ self.connection.open() try: self._device = _BME280(i2c_dev=self.connection.connection) # type: ignore[misc] self._device.update_sensor() # first reading is always garbage except Exception: self._close() raise def _close(self) -> None: """Close the I2C bus and reset the device handle. Safe to call even if the device was never opened or already closed. """ try: self.connection.close() except Exception: # noqa: BLE001 log.exception("Error closing BME280 device") finally: self._device = None
[docs] def measure(self) -> tuple[float, float, float]: """Return a single (temperature, pressure, humidity) reading. Opens the device on first call and keeps it open across calls. Closes the device and raises ValueError on any I2C or sensor error. Returns: Temperature in °C, pressure in hPa, humidity in %. Raises: ValueError: if the measurement fails. """ try: if self._device is None: self._open() assert self._device is not None self._device.update_sensor() temperature = self._device.temperature pressure = self._device.pressure humidity = self._device.humidity except Exception: # noqa: BLE001 log.warning("Error reading from BME280 sensor", exc_info=True) self._close() raise ValueError from None else: return temperature, pressure, humidity
def _observable_data(self) -> dict[str, tuple[float, str]] | None: try: temperature, pressure, humidity = self.measure() except ValueError: return None else: return {"temperature": (temperature, "degC"), "pressure": (pressure, "hPa"), "humidity": (humidity, "pct")}