Skip to content

ThinkNode M6: give the status LED something to indicate - #3289

Open
andyhoobing wants to merge 2 commits into
meshcore-dev:devfrom
andyhoobing:m6-status-led
Open

ThinkNode M6: give the status LED something to indicate#3289
andyhoobing wants to merge 2 commits into
meshcore-dev:devfrom
andyhoobing:m6-status-led

Conversation

@andyhoobing

@andyhoobing andyhoobing commented Aug 24, 2026

Copy link
Copy Markdown

Split out of #3287 as one self-contained fix, per the one-fix-per-PR guideline.
The companion PR (#3288) covers the M6 GPS defaults and shares no files with
this one — the two are independent and can be reviewed or merged in any order.

Problem

The ThinkNode M6 has two LEDs on the bottom face of the enclosure, next to the
USB-C port. Only the blue one was driven (LoRa TX activity). The red one — the
enclosure's power LED — was configured as an output in initVariant() and then
never touched again, so half the board's user-visible indication was dead.

Change

The red LED now indicates state:

  • solid through boot,
  • a three-flash signature on both LEDs at onBootComplete(),
  • then a low-duty heartbeat: one blink per 5s while running, two once
    the GNSS has a fix.

powerOff() clears it too. This makes a deployed node diagnosable through a
sealed outdoor case without attaching a laptop, which is the whole point on a
device with no screen or button.

Blink length is 150ms. I tried 40ms first and it is genuinely easy to miss at
arm's length in daylight. Duty cycle is still ~3%, which is nothing against a
6W solar panel.

Implementation note

The heartbeat is driven from a small EnvironmentSensorManager subclass — the
same pattern thinknode_m1 already uses — because its loop() already runs
every iteration in every example sketch, and it is the one place holding the
live GNSS state.

That means no core changes and no shared example changes: the repeater, room
server and companion builds all pick the behaviour up automatically.

Testing

ThinkNode_M6_repeater and ThinkNode_M6_room_server both build against dev.

Confirmed on real ThinkNode M6 hardware: with the GNSS holding a fix (11 sats),
the red LED double-blinks as intended, visually verified by the device owner.

To be precise about what that does and does not cover: the no-fix single-blink
and the boot flash run through the same updateStatusLed() path and the same
gps_fix argument, but were not separately observed — only the fix-acquired
double blink was.


Authored with assistance from Claude (see Co-Authored-By trailers).

The M6 has two LEDs on the bottom face of the enclosure, next to the
USB-C port. Only the blue one was driven (LoRa TX activity). The red one
-- the enclosure's power LED -- was configured as an output in
initVariant() and then never touched again.

It now indicates state: solid through boot, a three-flash signature at
onBootComplete(), then a low-duty heartbeat -- one blink per 5s while
running, two once the GNSS has a fix. That makes a deployed node
diagnosable through a sealed case without attaching a laptop. powerOff()
clears it too.

Blink length is 150ms: 40ms was tried first and is genuinely easy to miss
at arm's length in daylight. Duty cycle is still ~3%, which is nothing on
a 6W solar panel.

The heartbeat is driven from a small EnvironmentSensorManager subclass --
the same pattern thinknode_m1 already uses -- because its loop() already
runs every iteration in every example sketch and it is the one place
holding the live GNSS state. No core or shared example changes are
needed, and the repeater, room server and companion builds all pick it up
automatically.

Verified: ThinkNode_M6_repeater and ThinkNode_M6_room_server build, and
the behaviour was confirmed on real M6 hardware.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7b3E6KcBEGZ2zr2jZMrBL
ThinkNodeM6Board.cpp is one of the few files in the tree that already
matches .clang-format exactly, and the lines I added regressed that with
double spaces before trailing comments. Reformat just those lines so the
file stays clean.

The other files this branch touches are left alone deliberately: they are
a long way from clang-format clean upstream (ThinkNodeM6Board.h differs
by 20 lines before any change of mine), so matching the surrounding style
is the right call per CONTRIBUTING.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7b3E6KcBEGZ2zr2jZMrBL
@andyhoobing
andyhoobing marked this pull request as ready for review August 24, 2026 02:35
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