Skip to content

feat(hardware): parse sync packet v2 -- node MAC and health - #1807

Open
clonea1 wants to merge 1 commit into
ruvnet:mainfrom
clonea1:contrib/hardware-sync-packet
Open

feat(hardware): parse sync packet v2 -- node MAC and health#1807
clonea1 wants to merge 1 commit into
ruvnet:mainfrom
clonea1:contrib/hardware-sync-packet

Conversation

@clonea1

@clonea1 clonea1 commented Sep 4, 2026

Copy link
Copy Markdown

The v1 ESP-NOW sync packet carries timing only, so a node's identity on the
mesh is inferred rather than stated, and its condition is not reported at all.
Two consequences: the server guesses which node a sync came from, and a node
that is overheating, has rebooted, or is running low on heap looks identical to
a healthy one until it stops responding entirely.

v2 extends the packet to 38 bytes, adding the node's own MAC and a NodeHealth
block: die temperature, thermal state, transmit power, minimum heap seen, and
the reset reason.

The reset reason is the useful part operationally. reset_reason_name() renders
it, and rebooted_badly() distinguishes a panic or watchdog reset from a
deliberate software restart -- a node that reboots quietly and rejoins looks
healthy from the outside, and the distinction is what separates "somebody
updated it" from "it is crashing".

Version-gated so a v1 node keeps parsing exactly as before, and a padded v1
packet explicitly yields no MAC rather than reading whatever happened to sit in
those bytes. Both cases are covered by tests.


Rebased onto current main before opening: staged before today's seven merges, so it needed replaying to avoid reading as a revert of them. Clean rebase, no files deleted.

The v1 ESP-NOW sync packet carries timing only, so a node's identity on the
mesh is inferred rather than stated, and its condition is not reported at all.
Two consequences: the server guesses which node a sync came from, and a node
that is overheating, has rebooted, or is running low on heap looks identical to
a healthy one until it stops responding entirely.

v2 extends the packet to 38 bytes, adding the node's own MAC and a NodeHealth
block: die temperature, thermal state, transmit power, minimum heap seen, and
the reset reason.

The reset reason is the useful part operationally. reset_reason_name() renders
it, and rebooted_badly() distinguishes a panic or watchdog reset from a
deliberate software restart -- a node that reboots quietly and rejoins looks
healthy from the outside, and the distinction is what separates "somebody
updated it" from "it is crashing".

Version-gated so a v1 node keeps parsing exactly as before, and a padded v1
packet explicitly yields no MAC rather than reading whatever happened to sit in
those bytes. Both cases are covered by tests.

Co-Authored-By: claude-flow <ruv@ruv.net>
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