Also extend the compat scanner to catch datetime.UTC used as an
attribute (datetime.datetime.now(datetime.UTC)) in addition to
direct imports, so this form cannot be reintroduced undetected.
Co-Authored-By: Zindello <josh@zindello.com.au>
Replace the try/except UTC shim in mqtt_handler.py with timezone.utc
directly, consistent with the api_endpoints.py fix. Add a static AST
scan that fails if datetime.UTC is reintroduced anywhere in the codebase,
guarding against future regressions on Python 3.10 (LuckFox Pico Ultra).
Co-Authored-By: Zindello <josh@zindello.com.au>
datetime.UTC was introduced in Python 3.11. timezone.utc is available
since Python 3.2 and is functionally identical.
Co-Authored-By: Zindello <josh@zindello.com.au>
datetime.UTC was added in Python 3.11. Fall back to timezone.utc on
older interpreters, matching the existing pattern in mqtt_handler.py.
Co-Authored-By: Zindello <josh@zindello.com.au>
- Introduced tests for TraceHelper and DiscoveryHelper to validate packet forwarding and discovery request handling.
- Implemented tests for LoginHelper to ensure identity registration and login packet processing.
- Added tests for IdentityManager to cover identity registration, lookup, and filtering.
- Created tests for MeshCLI to verify command handling, configuration setting, and error paths.
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>
- Add pre-restart config preflight to RestartModal with pass/warning/fail result panel and "Restart Anyway" confirmation for warnings
- Add Site Identification (site_name) config field shown as browser title and login page caption
- Add GET /api/validate_config and GET /api/site_info backend endpoints
- Sync document.title with site_name via system store watchEffect
- Fix authRegression.test.ts TS2367 type narrowing error
- add new radio hardware and radio settings tabs
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>