- Updated byte representations in tests to use lowercase hex format for consistency.
- Reformatted code for better readability, including line breaks and indentation adjustments.
- Consolidated multiple lines into single lines where appropriate to enhance clarity.
- Ensured that all test cases maintain consistent formatting and style across the test suite.
Adds a new sensor type for the LAFVIN UPS Module 3S, an INA219-based
uninterruptible power supply for Raspberry Pi. Reports pack voltage,
current, power, estimated state-of-charge, and charge state for a
3S Li-ion/LiPo battery configuration (9.0–12.6 V range).
The INA219 address defaults to 0x41 (as wired on the LAFVIN board)
and shunt resistance is configurable for accurate current readings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The HAT (E) uses a dedicated BMS MCU (not an INA219) at I2C address 0x2D.
It exposes charge state, pack voltage/current, per-cell voltages, remaining
capacity in mAh, and time-to-empty/full estimates directly via I2C registers.
Tested on Raspberry Pi 4B with pyMC_Repeater running pymc-battery-writer.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
nmea_gps.py reads NMEA 0183 sentences directly from a serial GPS receiver
(/dev/serial0 by default) and exposes fix status, position, motion, accuracy,
and satellite fields as sensor readings.
Parses GGA, RMC, and GSA sentence types using stdlib only (no pynmea2
dependency) — pyserial is already required by the repeater.
Designed for use when the repeater's built-in GPS service is disabled
(gps.enabled: false). Both cannot share the serial port simultaneously.
With gps.api_fallback_to_config_location: true the repeater continues
advertising the manually-configured location while the sensor plugin handles
raw GPS data.
Returns: fix_valid, fix_quality, fix_type, latitude, longitude, altitude_m,
speed_kmh, course_degrees, hdop, pdop, vdop, satellites_used, utc_datetime.
Position and motion fields are null when fix_valid is false to avoid
reporting config-fallback coordinates as real GPS data.
Tested on Raspberry Pi 3B+ (DietPi) with a u-blox GPS module on /dev/serial0.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- shtc3.py: SHTC3 temperature/humidity sensor (RAK1901 WisBlock module,
I2C 0x70). Uses smbus2 i2c_rdwr for raw I2C reads since SHTC3 requires
16-bit command words with no register-byte prefix. Returns temperature_c,
temperature_f, humidity_pct.
- waveshare_ups_d.py: Waveshare UPS HAT (D) battery monitor via INA219 at
I2C 0x43. Uses the HAT's actual shunt (0.01 Ω, CAL=26868) rather than the
generic INA219 defaults. Returns bus_voltage_v, shunt_voltage_mv,
current_ma, power_mw, battery_percent (piecewise-linear SoC for 21700
cell), and charge_state (charging/discharging/idle). Sign convention
matches Waveshare sample code: negative current = charging.
Both plug-ins tested on Raspberry Pi 3B+ (DietPi) with RAK1901 WisBlock
sensor and Waveshare UPS HAT (D).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bit 0 of byte 2 is the T_VALID/H_VALID flag (datasheet Figure 32/33,
page 23 example: t_valid = (t_val>>16) & 0x1). The previous code checked
bit 1 (CRC LSB), which caused sporadic timeouts when the CRC happened to
have a 0 in that position.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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 <noreply@anthropic.com>
Adds support for the ENS210 relative humidity and temperature sensor
as a new plug-in under repeater/sensors/ens210.py. Also adds a
commented configuration example to config.yaml.example and a
contributor guide at docs/adding_sensors.md explaining how to add
further sensor plug-ins.
## Implementation notes
### Why smbus2 instead of an Adafruit/CircuitPython library
The ENS210 has no maintained Adafruit CircuitPython driver. The
available third-party options are either unmaintained or bring in the
full Blinka/CircuitPython hardware-abstraction stack as a dependency.
smbus2 is a thin, widely-packaged wrapper around the Linux i2c-dev
kernel interface that is already present on Raspberry Pi OS and most
Debian-based systems. It has no transitive dependencies and adds no
abstraction cost.
The ENS210 protocol is simple enough that direct register access is
preferable: two writes to start a measurement (REG_SENS_RUN + REG_SENS_START)
and two three-byte block reads to retrieve temperature and humidity.
The status/validity bit is checked inline rather than relying on a
library to surface it. There is no value a higher-level driver would
add here.
### Read strategy
A fixed post-trigger delay is unreliable — the sensor datasheet quotes
~130 ms typical conversion time but the actual ready time varies. The
implementation instead polls the data-valid status bit (bit 1 of the
third byte in each register block) every 50 ms for up to
read_timeout_seconds (default 1.0 s), breaking as soon as both T and
H report valid data. This is the same approach used in the validated
reference script.
The I2C bus is opened and closed on every read rather than kept open
across poll cycles. Keeping a persistent SMBus handle caused subsequent
reads to time out, consistent with the Linux i2c-dev file descriptor
accumulating state between transactions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>