Skip to content

Add power-aware scanning for M5 variants#9

Merged
f1yaw4y merged 17 commits into
f1yaw4y:mainfrom
dougborg:pr/07-power-aware
Mar 8, 2026
Merged

Add power-aware scanning for M5 variants#9
f1yaw4y merged 17 commits into
f1yaw4y:mainfrom
dougborg:pr/07-power-aware

Conversation

@dougborg

@dougborg dougborg commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

Stack order: 7/8 — merge after #8 (PR6: scoring and OUI)

Summary

  • Add battery-aware scan parameter adjustment for M5 variants
  • Reduce scan intensity when battery is low to extend runtime
  • Display power state in variant UIs

Test plan

  • Compile for M5StickC Plus2 and M5Stack FIRE
  • Verify scan parameters adjust based on battery level
  • Verify power state displays correctly in UI

🤖 Generated with Claude Code

dougborg and others added 17 commits February 2, 2026 00:48
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Provides per-variant build/upload/flash/monitor targets for all 6
hardware variants, plus LittleFS data upload for variants with audio
assets. Uses GNU Make define/eval/call to generate targets from a
single template.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests compile natively with clang++/g++ — no ESP32 hardware needed.
Covers detectors, device tracker state machine, and threat analyzer
scoring pipeline (37 cases, 126 assertions) targeting the M5Stick
variant's pure-logic headers.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move DetectorTypes.h, Detectors.h, DeviceSignatures.h, EventBus.h,
ThreatAnalyzer.h, and TelemetryReporter.h from the M5Stick variant's
src/ into a new top-level common/ directory. Update Makefile to pass
-I common via build.extra_flags for all variants, update test includes,
and fix the M5Stick FQBN (m5stick_c_plus2 -> m5stack_stickc_plus2).

Merge AudioEvent (from M5Fire's EventBus.h) into the shared header so
other variants can adopt it when migrated.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Delete local copies of EventBus.h, DeviceSignatures.h, ThreatAnalyzer.h,
and TelemetryReporter.h from m5fire/src/. Replace legacy ThreatAnalyzer
(simple boolean matching) and TelemetryReporter (DynamicJsonDocument with
nested objects) implementations with the shared detector-based system.

Add ISR-safe deferred event processing with portMUX spinlocks for WiFi,
BLE, and threat events. Add ThreatAnalyzer::tick() heartbeat in loop()
and shouldAlert gate on triggerAlert().

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Delete local copies of EventBus.h, DeviceSignatures.h, ThreatAnalyzer.h,
and TelemetryReporter.h from mini12864/src/. Replace legacy ThreatAnalyzer
and TelemetryReporter implementations with shared detector-based system.

Add ISR-safe deferred event processing with portMUX spinlocks. Move
display notifications (Mini12864DisplayNotifyWifiFrame, ShowAlert) and
audio playback to the main loop's deferred handlers. Add tick() heartbeat
and shouldAlert gate.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Also fix Makefile build.extra_flags override that was clobbering
ESP32 core defines (-DESP32=ESP32 etc). Use build.defines instead,
which is included within build.extra_flags and starts empty.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move variant-specific src/ files into sketch directory to follow
Arduino convention. Keep Flipper's own TelemetryReporter (line-based
protocol for Flipper app). Fix radioType null-check for char array.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Dockerfile builds a debian:bookworm-slim image containing arduino-cli,
ESP32 core v3.0.7, all Arduino libraries (version-pinned), doctest.h,
and pre-warmed core caches for all 4 FQBNs. Source is bind-mounted at
runtime so the image is reusable across branches.

Also adds docker-compose.yml (build-all, test, shell, build-variant
services), entrypoint.sh (seeds doctest.h into bind-mount), .dockerignore,
and Makefile docker-* targets.

Fixes a portability bug in test/mocks/Arduino.h: adds <cstdio> for
snprintf, which macOS clang resolves transitively but Debian clang-14
does not.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Audit all dependency versions against latest available in the Arduino
library index, update where possible, and centralize pins in a single
versions.env file consumed by both Makefile (include) and Dockerfile
(--build-arg).

Version changes:
- Base image: debian:bookworm-slim → debian:trixie-slim (Debian 13)
- arduino-cli: unpinned → 1.4.1
- ArduinoJson: 7.3.0 → 7.4.2
- NimBLE-Arduino: 2.2.1 → 2.3.7
- M5Unified: 0.2.2 → 0.2.11
- Adafruit SSD1306: 2.5.13 → 2.5.16
- doctest: 2.4.11 → 2.4.12
- ESP32 core: 3.0.7 (unchanged — newer causes IRAM overflow)
- U8g2: 2.35.30 (unchanged — already latest in Arduino index)
- Adafruit GFX: 1.12.4 (unchanged — already latest)

Makefile install-deps now pins library versions from versions.env,
matching what the Dockerfile installs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move duplicated content (setup, architecture, telemetry, configuration,
troubleshooting, extending) from 6 variant READMEs into 8 shared docs/
files. Add new docs for build system and testing (previously undocumented).
Restructure CLAUDE.md as a scannable agent gateway with dispatch table.
Fix incorrect .ino filename reference in portable variant README.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Make RadioScanner timing values dynamic across all variants by replacing
static const members with static members initialized to battery-mode
defaults. Add setPerformanceMode() to switch between battery and
external-power scanning parameters.

M5Stick and M5Fire main loops now detect external power via
M5.Power.isCharging() and automatically switch to aggressive scanning
(200ms dwell, 3s BLE scan, 4s interval) and force the display awake.
Non-M5 variants get the API but remain at battery-mode defaults.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds power-aware scanning for M5 variants and consolidates shared code into a common/ directory. The PR implements automatic scan parameter adjustment based on external power detection, migrates duplicate headers to a shared location, adds comprehensive test infrastructure with doctest, introduces a Makefile-based build system with Docker support, and provides extensive documentation.

Changes:

  • Power-aware scanning that switches between high/low performance modes when external power is detected
  • Code consolidation moving shared headers (EventBus, ThreatAnalyzer, Detectors, etc.) to common/ directory
  • Test infrastructure with host-side unit tests, Arduino mocks, and build automation

Reviewed changes

Copilot reviewed 68 out of 71 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
m5stack/flocksquawk_m5stick/flocksquawk_m5stick.ino Added external power detection and scan parameter adjustment
m5stack/flocksquawk_m5fire/flocksquawk_m5fire.ino Added external power detection with battery saver integration
m5stack/*/src/RadioScanner.h Made scan parameters mutable and added setPerformanceMode()
common/ThreatAnalyzer.h New shared threat analysis implementation with device tracking
common/EventBus.h Shared event bus with updated ThreatEvent structure
common/Detectors.h Consolidated detector functions for WiFi and BLE
test/* Complete test suite with mocks and doctest framework
Makefile Build automation for all variants with Docker support
docs/* Comprehensive documentation for architecture, testing, configuration
versions.env Centralized dependency version management

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +609 to +617
// Check external power periodically and adjust scan/display modes
if (now - lastPowerCheckMs >= BATTERY_UPDATE_MS) {
bool onExternalPower = M5.Power.isCharging();
if (onExternalPower != lastOnExternalPower) {
RadioScannerManager::setPerformanceMode(onExternalPower);
lastOnExternalPower = onExternalPower;
}
lastPowerCheckMs = now;
}

Copilot AI Feb 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description states "Reduce scan intensity when battery is low to extend runtime" and "Verify scan parameters adjust based on battery level", but the implementation only checks if external power is connected via M5.Power.isCharging(), not the actual battery level. This means scan parameters switch to high performance mode whenever USB is plugged in, regardless of whether the battery is actually low. Consider either:

  1. Updating the PR description to accurately reflect that this is external-power detection, not battery-level detection
  2. Implementing actual battery level checking (e.g., M5.Power.getBatteryLevel()) to adjust scan parameters based on remaining charge

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will deploy, however, testing fails on my end. I tried to initially implement a similar feature and could not get it to work on the M5Stick

@f1yaw4y f1yaw4y merged commit 461ff60 into f1yaw4y:main Mar 8, 2026
5 of 6 checks passed
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.

3 participants