Commit Graph

706 Commits

Author SHA1 Message Date
yellowcooln 3baf1158cc Dispatch add-on sync after Docker publish 2026-05-14 23:06:00 -04: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
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
Lloyd 4d710a0210 fix/ui-tidy-dev 2026-05-08 17:08:01 +01:00
Lloyd 68656fccdd Merge pull request #231 from pyMC-dev/pr-227
Pr 227
2026-05-06 16:13:30 +01:00
Lloyd d250828197 feat: enhance MQTT connection handling with JWT refresh and error logging improvements 2026-05-06 13:53:12 +01:00
Lloyd bd7a305d7b feat: improve MQTT connection handling with enhanced reconnect logic and logging 2026-05-06 10:05:11 +01:00
Lloyd 5b20f5580a feat: enhance MQTT logging and error handling with payload summaries and improved disconnect messages 2026-05-06 09:53:44 +01:00
Lloyd e4efc8045d feat: implement resolve_storage_dir for consistent storage paths 2026-05-05 17:17:12 +01:00
Lloyd ebfc629218 Merge pull request #229 from dmduran12/fix/mqtt-packet-duration
fix(mqtt): publish Semtech-derived packet duration instead of hard-coded "0"
2026-05-05 09:18:36 +01:00
Daniel Duran 0251304407 fix(mqtt): publish Semtech-derived packet duration instead of hard-coded "0"
Every MQTT-published packet has shipped with duration="0" since the
PacketRecord factory was introduced. The repeater already computes LoRa
time-on-air via AirtimeManager.calculate_airtime() (the canonical
Semtech reference formula) for duty-cycle gating and TX delay, but the
result was thrown away after each packet - never stored on the
packet_record dict that flows to MQTT/SQLite/Glass/websocket.

What changes
- engine.py: RepeaterHandler._build_packet_record() now computes
  airtime_ms once per packet (Semtech formula via AirtimeManager) and
  stores it as packet_record['airtime_ms']. Single source of truth for
  every downstream consumer.
- storage_utils.py: PacketRecord.from_packet_record() reads the new
  airtime_ms field and serializes it as a rounded integer in the
  'duration' field of the published JSON. Falls back to 0 if the field
  is missing (backward compatibility for any older code path).
- storage_collector.py: _publish_packet_to_mqtt() simplified - no
  recomputation, no helper. The publish path is now a passthrough.

Why
MQTT consumers (firmware-compatible analyzers, dashboards, the upstream
meshcoretomqtt project) expect the same time-on-air value the firmware
emits. Hard-coded "0" makes airtime/utilization charts derived from the
mqtt stream useless and silently diverges from firmware behavior.

Plumbing the value through packet_record (instead of recomputing in the
publish path) means any future consumer - SQLite schema, web UI charts,
Glass telemetry - reads the same number without separate calculations.

Tests
tests/test_packet_duration.py - 5 tests covering:
- backward compat (legacy packet_record without airtime_ms => '0')
- airtime_ms field flows through to duration as rounded integer string
- explicit zero stays '0'
- AirtimeManager output matches an independently-implemented Semtech
  reference for typical MeshCore EU settings (SF8/62.5kHz/CR4-8)
- low-data-rate optimization branch (SF12/125kHz triggers DE=1)

Co-Authored-By: Oz <oz-agent@warp.dev>
2026-05-03 12:48:02 -07:00
Daniel Duran dfacfeade8 feat: bundled MC2MQTT broker presets (waev, letsmesh) + format family
Introduces a 'set format and forget' workflow for MQTT brokers. Users
reference a bundled preset by name inside the existing brokers: list,
and the package supplies the endpoints, audiences, and TLS settings.
Endpoint changes ship via 'pip install -U' instead of manual edits.

What changes
- New repeater/presets/ package with a tiny lazy YAML loader and two
  bundled presets: waev (mqtt-{a,b}.waev.app) and letsmesh (EU + US).
- New format-family constant MC2MQTT_FORMATS = ('meshcoretomqtt',
  'letsmesh', 'waev') replaces the inline tuple in topic resolution.
  The legacy 'mqtt' format keeps its custom-topic semantics unchanged.
- Two-pass broker assembly in mqtt_handler.py: pass 1 expands every
  {preset: <name>} entry inline; pass 2 collapses duplicates by name
  with later-wins semantics. Place override entries AFTER preset
  entries.
- Hard-coded LETSMESH_BROKERS constant deleted; its data now lives in
  repeater/presets/letsmesh.yaml.
- convert_letsmesh_to_broker_config() collapsed from ~70 to ~25 lines
  by emitting {preset: letsmesh} plus disable overrides for unwanted
  brokers. Honors broker_index in (-1, 0, 1), additional_brokers, and
  enabled flag exactly as before.
- update_mqtt_config API endpoint accepts {preset: <name>} entries and
  passes them through unchanged so the web UI can author them when the
  frontend is updated.
- config.yaml.example documents the preset entry shape, the override
  rule, and the format family hierarchy.
- pyproject.toml ships presets/*.yaml as package data.

How to use
  mqtt_brokers:
    iata_code: "LAX"
    brokers:
      - preset: waev

  # Override a single preset broker:
  brokers:
    - preset: waev
    - name: waev-b
      enabled: false

Tests
- tests/test_presets.py: 9 tests covering loader, expand/merge,
  MC2MQTT topic-family parity, and parametrized legacy migration.

Co-Authored-By: Oz <oz-agent@warp.dev>
2026-05-02 15:32:22 -07:00
Lloyd 11572f80c2 Merge pull request #222 from zindello/bugfix/restart-issues
Fix up the CapabilityBoundingSet to allow changing the GID and UID as…
2026-05-01 11:01:12 +01:00
Lloyd 86e5f783eb Merge pull request #221 from zindello/feat/add-ultrapeaterzero
Adding in UltraPeaterZero defintions
2026-05-01 11:00:12 +01:00
Joshua Mesilane f1933dd2b0 Fix up the CapabilityBoundingSet to allow changing the GID and UID as part of a polkit or sudo restart, also ensure dbus is running as on some minimised systems it might not be (hi dietpi!) 2026-05-01 19:49:15 +10:00
Joshua Mesilane 55ed40c79c Adding in UltraPeaterZero defintions 2026-05-01 16:38:58 +10:00
Lloyd 8bbef50e37 Merge pull request #219 from rightup/feat-gps
Feat gps
2026-04-30 20:52:57 +01:00
Rightup 2dd79614ef add map toggle and discord icon 2026-04-30 20:52:01 +01:00
Rightup 9d3d5e6ef0 refactor: update GPS configuration parameters and improve documentation 2026-04-30 20:28:50 +01:00
Rightup 972aefca16 bug:fixes to gps page 2026-04-29 20:40:53 +01:00
Lloyd f7a212f2ea Merge pull request #213 from yellowcooln/dev
Fix Buildroot OTA updates to use the repo upgrade path
2026-04-29 19:41:56 +01:00
Yellowcooln acb796199d Prefer repo Buildroot updater on embedded images 2026-04-29 14:14:40 -04:00
Yellowcooln 52cce9d51b Merge branch 'rightup:dev' into dev 2026-04-29 13:53:34 -04:00
Yellowcooln fe0d3d30af Fix Buildroot OTA upgrade path 2026-04-29 13:43:13 -04:00
Yellowcooln 56814bfc38 Support local embedded Buildroot installs 2026-04-29 13:27:04 -04:00
Lloyd bbaf8bd3f3 fix:gps-fixes 2026-04-29 17:31:10 +01:00
Lloyd 6720f6bdfe Merge pull request #212 from yellowcooln/dev
Improve Buildroot repeater config flow and Pico Pi radio timing wiring
2026-04-29 17:29:56 +01:00
Lloyd 187d033e18 Merge pull request #211 from mitchellmoss/feat-gps-location-update
Update repeater location from GPS fix
2026-04-29 16:10:27 +01:00
Mitchell Moss d83cb61fe7 Make GPS location persistence opt-in and fuzzed 2026-04-29 10:45:53 -04:00
Mitchell Moss da8f83964a Fix GPS location updates and status reporting 2026-04-29 09:58:13 -04:00
Mitchell Moss bf44efbfd9 feat: update repeater location from GPS fix 2026-04-29 09:36:05 -04:00
Yellowcooln 8856268ef2 Expose Buildroot image version 2026-04-29 09:27:56 -04:00