Skip to content

feat(power): add UPS battery monitoring - #2

Closed
johnpacino wants to merge 10 commits into
feat/iwr6843-configurable-capture-compressionfrom
feat/battery-power-display
Closed

feat(power): add UPS battery monitoring#2
johnpacino wants to merge 10 commits into
feat/iwr6843-configurable-capture-compressionfrom
feat/battery-power-display

Conversation

@johnpacino

@johnpacino johnpacino commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Note

This is stacked on upstream PR #200. Its base is PR200's head branch so this draft contains only the battery feature. Retarget it to upstream main after PR200 merges.

What does this PR do?

Adds optional battery and external-power monitoring to OpenFlight, initially supporting the Geekworm X1202 and X1206 UPS boards through --battery geekworm.

The feature introduces a generic PowerReader provider contract, a Linux power_supply reader, and a direct Geekworm MAX1704x/GPIO fallback. The existing WebSocket UI shows plugged-in, on-battery, low, critical, and unavailable states. Dismissible warnings appear at 20% and 10% while discharging, and throttled power_status records are written to session logs.

Raspberry Pi setup and operator documentation are organized under scripts/battery/ and docs/battery/. The setup enables native MAX17040 and charger telemetry and can install a shared Raspberry Pi taskbar compatibility package. It intentionally does not install automatic-shutdown or charging-control services.

Screenshots

OpenFlight battery status

OpenFlight showing a plugged-in battery at 78%

Indicator states

Plugged in On battery Low Critical Unavailable
Plugged in at 78% On battery at 64% Low battery at 20% Critical battery at 10% Battery telemetry unavailable

Warning dialogs

Low battery Critically low battery
Dismissible low-battery warning at 20% Dismissible critical-battery warning at 10%

Raspberry Pi taskbar

Raspberry Pi desktop showing the taskbar battery indicator and OpenFlight Battery Power launcher

Why was this required?

OpenFlight can run from UPS batteries, but previously gave the operator no indication that external power had been removed or that the battery was nearing depletion. That made an unexpected Pi power loss and filesystem damage more likely.

The hardware integration also needed to be provider-based rather than embedded as Geekworm-specific application behavior. Comparable UPS boards expose the same minimum information through different Linux drivers or I2C register maps, so the generic reader contract keeps UI state, warnings, retries, and logging independent of the selected board.

On the tested Geekworm configuration, the MAX17040 Linux driver exposes a standard capacity value rather than the charge or energy counters expected by Raspberry Pi's taskbar plugin. The included compatibility patch reads that standard value and clamps small full-charge overshoots to 100%.

Automated tests

Added and updated tests covering:

  • MAX1704x voltage/SOC decoding, GPIO6 external-power detection, and resource cleanup
  • Linux power_supply discovery, validation, and 100% clamping
  • Provider selection, unsupported providers, and Linux-to-direct-reader fallback
  • Monitor state thresholds, read-failure recovery, and session-log throttling
  • --battery geekworm forwarding and server argument validation
  • Idempotent Pi setup, conflicting overlays, EEPROM settings, package checksum, and relocated documentation
  • UI battery states and dismissible warning behavior

Validation performed:

  • uv run pytest tests/ -q - 1,315 passed, 8 skipped
  • uv run pylint src/openflight/ --fail-under=9 - 9.72/10
  • uv run ruff check src/openflight/ - passed
  • cd ui && npm test -- --run - 35 passed
  • cd ui && npm run build - passed
  • cd ui && npm run lint - passed
  • bash -n scripts/start-kiosk.sh scripts/setup/setup.sh scripts/battery/geekworm/setup.sh - passed

Manual (human) testing

Deployed the feature checkout to a separate directory on a Raspberry Pi 5 and built the production UI there. With a connected Geekworm UPS board:

  • Verified native battery capacity and voltage appeared under /sys/class/power_supply.
  • Verified charger/online changed between 1 and 0 when input power was connected and removed.
  • Confirmed the OpenFlight charger icon appeared while plugged in and disappeared after unplugging.
  • Confirmed a full battery displayed as 100% instead of the previous red -- state or Raspberry Pi taskbar 0% state.
  • Unplugged and reconnected input power repeatedly and observed the UI update without interrupting OpenFlight.
  • Ran the setup verifier and confirmed the device-tree overlays, max17040_battery and gpio_charger modules, EEPROM power settings, UPower device, patched taskbar package, and get_throttled=0x0.

Automatic shutdown was deliberately not exercised because this PR does not implement shutdown control.

Checklist

  • Single feature/fix — this PR is scoped to one thing with a clear story above
  • Automated tests included — new or updated tests cover this change
  • Manual testing described — I documented what I verified by hand above
  • Python tests pass (uv run pytest tests/ -v)
  • Pylint passes (uv run pylint src/openflight/ --fail-under=9)
  • Ruff passes (uv run ruff check src/openflight/)
  • UI builds (cd ui && npm run build)
  • UI lint passes (cd ui && npm run lint)
  • Updated docs or CHANGELOG if needed
  • No unrelated changes mixed in

@johnpacino

Copy link
Copy Markdown
Owner Author

Superseded by the upstream draft: open-flight#212

@johnpacino johnpacino closed this Aug 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant