Commit Graph

735 Commits

Author SHA1 Message Date
Lloyd cbfcb69c07 Merge pull request #255 from CarlsonCustoms/add-shtc3-waveshare-sensors
Add SHTC3 and Waveshare UPS HAT (D) sensor plug-ins
2026-05-19 11:12:04 +01:00
Zack Carlson f88d3c52be Revert "Add NMEA GPS sensor plug-in"
This reverts commit 8b0607aa1c.
2026-05-18 22:55:05 -07:00
Zack Carlson 8b0607aa1c Add NMEA GPS sensor plug-in
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>
2026-05-18 22:50:17 -07:00
Zack Carlson 9c1661f097 Add SHTC3 and Waveshare UPS HAT (D) sensor plug-ins
- 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>
2026-05-18 22:32:20 -07:00
Lloyd 13ea672597 Merge pull request #254 from yellowcooln/dev
docker: improve container restart handling, publishing, and config mounting
2026-05-18 21:10:34 +01:00
Yellowcooln f21aba0ac4 docker: mount config directory in compose 2026-05-18 13:25:23 -04:00
Yellowcooln 11e2b90c18 ci: route docker publish by repository owner 2026-05-18 12:43:19 -04:00
Yellowcooln ab8ae30e7d web: clarify docker restart update messaging 2026-05-18 12:40:43 -04:00
Yellowcooln 7b6babd9f5 service: restart containers by exiting process 2026-05-18 12:12:18 -04:00
Lloyd 193b428cc2 Merge pull request #252 from yellowcooln/patch-2
docker: bootstrap config on startup and include rootless container fixes
2026-05-18 16:19:58 +01:00
Lloyd 8c354db99c Merge pull request #253 from pyMC-dev/wip/null-radio-before-pr250
Wip/null radio before pr250
2026-05-18 16:18:05 +01:00
Lloyd e0dbecd51c feat: update default radio type to null in config example 2026-05-18 15:59:49 +01:00
Yellowcooln c03d4ddc2b docker: merge config from example on boot 2026-05-18 10:48:39 -04:00
Yellowcooln 72a8755399 docker: bootstrap config and run rootless 2026-05-18 10:23:37 -04:00
Yellowcooln a08c4d093c Update repository conditions in docker-publish.yml
Had old repo path, Changing to 

pyMC-dev/pyMC_Repeater
2026-05-18 10:10:32 -04:00
Lloyd 0e1031227e update ui for setup 2026-05-18 14:50:45 +01:00
Lloyd 56113c22ec feat: update radio status handling to show radio errors 2026-05-18 14:34:42 +01:00
Lloyd 052474cf48 feat: add connection type for KISS and pymc modems in radio settings 2026-05-18 14:15:46 +01:00
itk80 d7f2d2cc66 setup wizard: pymc_tcp / pymc_usb hardware tiles
Lets a fresh repeater install pick the pymc_usb (USB-CDC) or pymc_tcp
(Wi-Fi/Ethernet) external modem from the first-run /setup wizard
instead of requiring the user to hand-edit config.yaml after install.

radio-settings.json gets two new hardware entries; setup_wizard()
in api_endpoints.py handles them in dedicated branches that mirror
the existing KISS pattern (placeholders if the SPA doesn't yet send
modem-specific inputs, request body overrides if it does).

For pymc_tcp the wizard writes a sentinel host placeholder
('REPLACE_WITH_MODEM_HOST') so the YAML stays valid; on startup
get_radio_for_board() then errors with a clear pointer at
pymc_tcp.host (existing behavior from the PR #240 branch). pymc_usb
defaults to /dev/ttyACM0 at 921600 baud — matches the USB-CDC
device path documented in pymc_usb's README + pymc_driver.

Five new tests in tests/test_setup_wizard_pymc.py verify both
default and overridden code paths plus a KISS regression guard.
2026-05-18 13:00:00 +01:00
Lloyd 13b8004ad5 wip: null-radio defaults and needs_setup updates 2026-05-18 13:00:00 +01:00
Lloyd f4d89484de Merge pull request #251 from yellowcooln/chore/manual-docker-workflow
ci: restrict docker publish workflow for forks
2026-05-18 09:19:53 +01:00
Yellowcooln 5f430858f2 ci: restrict docker publish workflow 2026-05-17 22:29:37 -04:00
Lloyd baec25b7bb Merge pull request #247 from yellowcooln/addon-sync-workflow
Derive Docker image version from git metadata and dispatch HA add-on sync
2026-05-16 13:38:57 +01:00
yellowcooln 2d875ae2fb Derive Docker dev version from git metadata 2026-05-15 11:18:15 -04:00
Lloyd ce1acabd34 fix: parse sync_word as integer in get_radio_for_board function 2026-05-15 14:04:18 +01:00
Lloyd 4f278f121f Merge pull request #243 from dmduran12/patch-1
Add Southern California radio preset
2026-05-15 11:10:24 +01:00
Lloyd a7ae704fd9 Merge pull request #245 from dmduran12/broker_template-UIsync
feat(presets): expose bundled broker presets via GET /api/broker_presets
2026-05-15 10:25:19 +01:00
yellowcooln 3baf1158cc Dispatch add-on sync after Docker publish 2026-05-14 23:06:00 -04:00
dmduran12 7a0aec7b60 feat(presets): expose bundled broker presets via GET /api/broker_presets
Adds a new read-only endpoint that serves the bundled `repeater/presets/*.yaml`
catalogue so the admin UI can render a network picker without bundling its own
copy of the broker dicts. The UI side of this is paired with
pyMC-dev/pyMC-RepeaterUI#TBD which retires src/assets/broker-templates.json
in favour of authClient.get('/api/broker_presets').

Why
The UI previously shipped a separate JSON snapshot of every supported MC2MQTT
network. The JSON and these YAML files drifted: the Waev entry on the UI side
pointed at mqtt-a.waev.app with audience mqtt.waev.app (single primary, no
failover) while the YAML side here listed two brokers (A + B). The result was
that operators picking 'Waev' from the dropdown silently lost the redundancy
this preset is meant to provide.

What changes

repeater/presets/*.yaml
- Add optional top-level `display_name` and `website` fields. The loader
  treats them as advisory metadata for the UI; the runtime connection code
  never reads them. `display_name` falls back to the titlecased filename
  stem if absent so existing third-party presets keep rendering.

repeater/presets/waev.yaml
- Collapse from two broker entries (waev-a, waev-b) to a single broker on
  `mqtt.waev.app`. The Waev edge Worker (see waev/src/router.ts:
  MQTT_PRIMARY_FAILOVER_TIMEOUT_MS) already does server-side A/B failover on
  the alias host with a 1500 ms timeout. Two independent client connections
  would defeat the dedup-on-pubkey-hash contract on the waev ingest side.
  Operators who want to pin to a specific container can edit host/audience
  after import.

repeater/presets/meshmapper.yaml (new)
- Port of the historical MeshMapper entry from the UI's deprecated JSON.
  Single broker on mqtt.meshmapper.cc, format: letsmesh (matches the
  published wire contract; bump to a dedicated value if/when wire-level
  differentiation lands).

repeater/web/api_endpoints.py
- New `broker_presets` CherryPy handler at `GET /api/broker_presets`.
  Unauthenticated to match the existing `mqtt_status` precedent — the
  response carries only public hostnames + TLS hints, no PII. Imports the
  presets module lazily so a broken YAML never blocks process startup.
  Response shape:
    {
      success: true,
      data: [{ id, name, website?, brokers: [ ... raw YAML dicts ... ] }, …]
    }

tests/test_presets.py
- Locks the new metadata fields (display_name, website) on all three presets.
- Locks the Waev single-alias-broker design with an explicit comment tying
  the test to the waev Worker failover code.
- Adds MeshMapper coverage parallel to the other public-network presets.
- Adds a stub-instance test that drives the new `broker_presets` method on
  an APIEndpoints stand-in (bypassing the heavyweight `__init__`) and
  asserts the UI-ready response shape.

Verification
- New endpoint serves the expected three presets (letsmesh: 2 brokers,
  meshmapper: 1, waev: 1) when exercised end-to-end against a local mock
  that imports the real preset loader.
- Existing legacy-config migration tests (broker_index 0/1/-1 → preset +
  overrides) still pass — the override pipeline is untouched.

Co-Authored-By: Oz <oz-agent@warp.dev>
2026-05-14 15:14:10 -07:00
Lloyd 5b95be3db5 refactor: remove sync word configuration from radio settings 2026-05-14 17:20:13 +01:00
Lloyd 2510bed9a4 feat: ui speed enhance 2026-05-14 13:54:59 +01:00
Treehouse⚡️ d5903c372b Add Southern California radio preset 2026-05-13 10:44:20 -07:00
Lloyd af9799d24b Merge pull request #242 from yellowcooln/patch-1
Update Docker image repository in workflow
2026-05-13 17:06:52 +01:00
Yellowcooln 446d2bf006 Update Docker image repository in workflow 2026-05-13 12:05:34 -04:00
Lloyd e03174d5b2 Merge pull request #241 from yellowcooln/docker-image
Automate Docker publishing for main and dev branches
2026-05-13 16:57:31 +01:00
yellowcooln ca7dd38060 ci: automate docker publish on main and dev 2026-05-13 11:43:26 -04:00
Lloyd c70f360179 Merge pull request #240 from itk80/feat/pymc-tcp-usb-radio
config: add pymc_tcp / pymc_usb radio_type branches
2026-05-13 16:39:08 +01:00
itk80 541b25b47c config: add pymc_tcp / pymc_usb radio_type branches
Wires the TCPLoRaRadio and USBLoRaRadio drivers that landed in pyMC_core
on 2026-05-13 (PR pyMC-dev/pyMC_core#68) into get_radio_for_board() so
they can be selected from a repeater config file without any code change
in main.py / api_endpoints.

Both branches follow the existing pattern: read host/port (TCP) or
serial port (USB) plus auth/LBT options from their own config section,
share the LoRa parameters from the common `radio` section, fall back to
the firmware-default sync word 0x12, and surface ImportError as a clear
RuntimeError if the installed pymc_core is too old to ship the drivers.

config.yaml.example documents both sections and updates the radio_type
header comment with the full supported list. Five new tests in
tests/test_radio_config.py monkeypatch the radio classes and verify the
section/parameter wiring + missing-required-field errors.

No web UI / endpoint changes — the deployment this targets edits the
config file directly. A GUI wizard for these radio types can land
separately if there's appetite.
2026-05-13 17:30:09 +02:00
Lloyd 0e7bb05208 Refactor INA219 sensor integration. 2026-05-13 12:34:05 +01:00
Lloyd 9dbf5459c8 Merge pull request #238 from zindello/feat/add-sensor-ens210
Feat/add sensor ens210
2026-05-13 12:27:17 +01:00
Joshua Mesilane a01d59381b fix(ens210): check correct VALID bit in T_VAL/H_VAL polling
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>
2026-05-13 17:07:28 +10:00
Joshua Mesilane 7865e9cb4b 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 <noreply@anthropic.com>
2026-05-13 16:33:37 +10:00
Joshua Mesilane 3f7b6d5cdc fix: add smbus2 dependency, i2c-tools, and use hex I2C addresses in docs
- Add smbus2>=0.4.0 to pyproject.toml core dependencies so it is always
  present in the venv rather than relying on runtime auto-install
- Add i2c-tools to apt-get installs in both install and upgrade paths
  so /dev/i2c-* devices are accessible and i2cdetect is available for
  diagnostics (service user was already being added to the i2c group)
- Switch ENS210 config examples to hex I2C address notation (0x43) to
  match datasheets and i2cdetect output; update contributor docs guidance
  accordingly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:54:32 +10:00
Joshua Mesilane 9bfe1259da feat: add ENS210 temperature/humidity sensor plug-in
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>
2026-05-13 11:46:26 +10:00
Lloyd 66532a0647 feat: Add sensor plugin framework and Sensors 2026-05-12 14:18:33 +01:00
Lloyd eb5d971c72 fix: filter neighbors to include only zero-hop repeaters in response 2026-05-11 16:26:15 +01:00
Lloyd 43648da939 fix:add Pagination to contacts table 2026-05-11 14:27:28 +01:00
Lloyd f04f581163 fix:Neighbors get function 2026-05-11 13:59:12 +01:00
Lloyd 941c355deb feat: add pagination support and count retrieval for adverts by contact type 2026-05-11 13:54:55 +01:00
Lloyd f3946685c2 bug/further fixes to ui initla loading 2026-05-11 13:39:48 +01:00