From 7865e9cb4bf6fba9daec4233d659c77dc709ba57 Mon Sep 17 00:00:00 2001 From: Joshua Mesilane Date: Wed, 13 May 2026 16:33:37 +1000 Subject: [PATCH] fix: standardise sensor module structure and docs - Use multi-line ensure_python_modules list format in ens210.py, matching the established pattern from ina219.py - Fix auto_install_packages indentation in ina219.py docstring - Remove smbus2 from pyproject.toml core dependencies; sensor packages are handled at runtime via ensure_python_modules/auto_install_packages - Update docs/adding_sensors.md template and guidance to match Co-Authored-By: Claude Sonnet 4.6 --- docs/adding_sensors.md | 8 ++++++-- pyproject.toml | 1 - repeater/sensors/ens210.py | 6 +++++- repeater/sensors/ina219.py | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/docs/adding_sensors.md b/docs/adding_sensors.md index ca3ed65..28e672e 100644 --- a/docs/adding_sensors.md +++ b/docs/adding_sensors.md @@ -58,7 +58,11 @@ class MySensor(SensorBase): self.some_option = self.settings.get("some_option", "default") self.available = False - if not self.ensure_python_modules([("import_name", "pip-package-name")]): + if not self.ensure_python_modules( + [ + ("import_name", "pip-package-name"), + ] + ): return # logs a warning; sensor will report unavailable try: @@ -87,7 +91,7 @@ Key rules: - **`sensor_type`** class attribute must match the string passed to `@SensorRegistry.register`. - **`self.settings`** is the `settings:` block from the sensor's config entry (a plain dict). -- **`ensure_python_modules`** handles missing dependencies gracefully. Pass a list of `(import_name, pip_package)` tuples. Returns `False` and logs a warning if any are missing and `auto_install_packages` is `false`; installs them if `true`. +- **`ensure_python_modules`** handles missing dependencies gracefully. Pass a multi-line list of `(import_name, pip_package)` tuples. Returns `False` and logs a warning if any are missing and `auto_install_packages` is `false`; installs them via pip if `true`. Sensor-specific packages belong here — do **not** add them to `pyproject.toml`. - **`_read`** must return a flat `dict[str, Any]`. The base class wraps it in a standard envelope (`name`, `type`, `ok`, `timestamp`, `data`, optional `error`). - **`_read`** must raise `RuntimeError` on failure — the base class catches it, marks `ok=False`, and logs it without crashing the polling loop. - All hardware initialisation belongs in `__init__`, not in `_read`. Keep `_read` fast. diff --git a/pyproject.toml b/pyproject.toml index aa08873..b189948 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,6 @@ dependencies = [ "pyserial>=3.5", "pyjwt>=2.8.0", "ws4py>=0.6.0", - "smbus2>=0.4.0", ] diff --git a/repeater/sensors/ens210.py b/repeater/sensors/ens210.py index 35eb3d5..221ab9f 100644 --- a/repeater/sensors/ens210.py +++ b/repeater/sensors/ens210.py @@ -42,7 +42,11 @@ class ENS210Sensor(SensorBase): self._poll_attempts = max(1, int(float(self.settings.get("read_timeout_seconds", 1.0)) / self._poll_interval)) self.available = False - if not self.ensure_python_modules([("smbus2", "smbus2")]): + if not self.ensure_python_modules( + [ + ("smbus2", "smbus2"), + ] + ): return try: diff --git a/repeater/sensors/ina219.py b/repeater/sensors/ina219.py index 0d8866f..9a0b9cf 100644 --- a/repeater/sensors/ina219.py +++ b/repeater/sensors/ina219.py @@ -7,7 +7,7 @@ Config example: - type: ina219 name: "power_monitor" enabled: true - auto_install_packages: false + auto_install_packages: false settings: i2c_address: 0x40 # Default INA219 I2C address max_expected_amps: 2.0