MeshGrid Node (Build 149)
This is the current node firmware. It keeps the same encrypted mesh used with the phone app. Since the last published binary (Build 136), delivery on a busy channel, phone-link reporting, stored state, battery indication, radio recovery, and encryption memory safety were tightened. Ciphertext on the mesh is unchanged from Build 147.
Install
- Preferred: flash MeshGrid_ESP32_BUILD149_flash0x0.bin at address 0x0.
- Application only: flash MeshGrid_ESP32_BUILD149_app_0x10000.bin at 0x10000. This leaves the bootloader, partitions, and usually the stored settings in place.
- After a full erase, provision the node before use.
- On boot, the log should show Build 149.
What changed since Build 136
Mesh delivery
- Incoming bytes are handled before a send, and a send waits while a peer frame is still arriving.
- A full frame at the buffer limit is kept when more bytes are waiting, instead of being dropped.
- Boot leaves the installed radio profile as it is.
- A peer that restarts its message numbers is treated as a new session, not as a duplicate.
- Broadcast chat, alerts, and shapes stay broadcasts. They are no longer rewritten into a one-peer message from a small local neighbor list.
- A duplicate still cancels a pending relay.
- A message counts as on the air only after the radio accepts it, not when it is only queued.
- A signal probe must look like “#” plus digits. Ordinary numbered chat keeps normal acknowledgement and recovery.
- Automatic resend waits out a long broadcast hold and sends one copy, instead of stacking extra copies on top of a send that has not finished.
- Direct broadcasts can be acknowledged once. Replies are staggered by node so two nodes sending together are less likely to collide. That acknowledgement is not retried forever.
- A two-node mesh uses fixed, non-overlapping send slots.
Phone link
- The firmware build number is sent only after the phone has enabled notifications, and the phone can ask for it again.
- A notification counts as delivered only when notifications are enabled, the payload fits the negotiated size, and the stack reports success.
Stored state and identity
- Replay state, pending messages, and the boot epoch are marked saved only after the write commits. Failures are counted.
- Flash writes wait while a peer frame, airtime, or an acknowledgement is in progress.
- If a required task cannot start, the node resets instead of continuing half-initialized.
- A roster record is accepted only when it is complete.
- If key derivation fails, the node does not fall back to using the raw master secret as a traffic key.
- If a message id cannot be reserved, the send waits instead of inventing one.
- Replay ordering stays correct when the epoch counter wraps.
Power, health, and time
- Battery is sampled on a timer even when the phone is disconnected. The hard low-battery warning uses the calibrated reading. The displayed percent can rise again as the battery recovers.
- Disconnect duration is stored in seconds.
- The unused color status light is no longer driven.
- Recovery follows receive silence, not transmit activity. Separate clocks show transmit, raw receive, valid mesh receive, and peer acknowledgement.
- When a fresh UTC time fix is available, scheduled send slots share one clock, so nodes that booted at different moments stay in phase. Without a fresh time fix, slots stay on the local clock.
Encryption
- The authenticated encryption path was made memory-safe. Bytes on the mesh do not change versus Build 147.