Add Companion lost-status replies and repair room mailbox test adapters

Save an opt-in off/no/yes answer to private Am I lost questions from known
chat contacts. Keep reply traffic and ACK state bounded, preserve pending
user delivery, and expose the setting through local CLI and ESP32 WebConfig.

Retain compact STM32 application/filesystem boundaries, qualify the Tag BLE
queue allowance, and exercise saved-image compatibility and browser controls.
Fix stale room mailbox protocol dependencies in the ACL/route test fixtures.

Validation: ten Companion builds, sanitized production-path regressions,
preference fault/compatibility tests, browser tests, and 86 capacity/build
recipe checks passed. No live radio was flashed for this feature.
This commit is contained in:
mikecarper committed 2026-10-10 19:24:42 -07:00
1 parent 2c1c2c8e99
commit 8031e60b55
46 files changed
+3663 -2020

No files matched your search

+1
View File
@@ -95,6 +95,7 @@ over the normal binary USB, BLE, or TCP connection:
| [`get public.key`](cli_commands.md#view-this-nodes-public-key) | Companion text terminal and binary command `0x42`; read-only, no private-key export feature required |
| `get prv.key` | Local terminal and binary command `0x42`; requires private key export enabled |
| `get password` | Reports that Companion has no admin password; infrastructure returns its password locally |
| [`get/set lost.reply`](companion_lost_reply.md) | Local Companion CLI and framed command `0x42` when `MESH_ENABLE_LOST_REPLY` is enabled; saved `off`, `no` or `yes` private-message auto response |
| `get wifi.pwd`, `get mqttN.password`, `get mqttN.token` | Local terminal and binary command `0x42`; corresponding WiFi/MQTT feature required |
| [`board`](cli_commands.md#show-the-hardware-name) | Every Companion text terminal and command `0x42` |
| [`version`](cli_commands.md#get-the-version) | Every Companion text terminal and protocol-v14 command `0x42`; returns the untruncated build identity |
+81
View File
@@ -0,0 +1,81 @@
<!-- meshcore-hosted-doc-link:start -->
<p class="meshcore-hosted-doc-link"><a href="https://mikecarper.github.io/MeshCore/companion_lost_reply/">View this page on MeshCore Docs</a>.</p>
<!-- meshcore-hosted-doc-link:end -->
# Companion lost-status auto response
Development Companion builds containing this feature can automatically answer a private `Am I lost?` message with `Yes`
or `No`. You choose the saved answer. The default is `off`, and the firmware
does not infer lost status from GPS, distance, or a missing phone connection.
This is included in nRF52, ESP32 and RP2040 Companion profiles, including
T1000-E and RAK Tag. Compact STM32 Companion images omit it to preserve their
existing application and filesystem boundaries. A custom build can explicitly
enable `MESH_ENABLE_LOST_REPLY=1` when its flash budget permits; the normal
flash and RAM checks still apply.
Configure it through a directly connected local Companion CLI:
~~~text
get lost.reply
set lost.reply no
set lost.reply yes
set lost.reply off
~~~
The setting survives reboot and takes effect immediately. USB, BLE and other
local Companion transports can use framed command `0x42`. Builds with a text
terminal also accept these commands there. LoRa CLI cannot read or change this
local setting. A failed save restores the previous answer and reports an error.
Older saved preference images load the new setting as `off`.
ESP32 Companions with WebConfig also have a **Lost-status auto reply**
selection on the radio configuration page. Choose Off, Reply No or Reply Yes
and save. The control is shown only on Companion firmware with this capability.
The existing mobile app protocol needs no new message type; a native app toggle
is not added by this firmware change.
## Dog tracker example
The owner's Companion stores the tracker as a normal radio contact. Set the
answer to `no` during normal operation. If the dog is lost, set it to `yes`.
When the tracker sends `Am I lost?` privately to that reachable Companion, it
receives the selected answer, even when the owner's phone is disconnected.
The same configured answer applies to all eligible contacts on this Companion.
A tracker client can use that answer to choose its reporting behavior, but its
check-in schedule, sleep/wake policy and GPS reporting must be configured in
the tracker client firmware. The tracker must stay awake for the separate
private answer; a delivery ACK for the question is not that answer. These plain
text answers have no request ID, so a delayed answer cannot be precisely
correlated with a newer check-in. The responding Companion must be powered on
and reachable when a question arrives. For mail that waits while a tracker sleeps,
use [a personal room mailbox](room_services.md#sleeping-tracker-example).
## Matching and traffic limits
Only an authenticated ordinary private message from a known persistent radio
contact is eligible. The contact must be an ordinary Companion/chat contact;
room-server and repeater contacts are excluded. Temporary unknown senders,
public channels, room chat posts and CLI messages do not trigger a response.
The exact phrase `am I lost` is matched without regard to ASCII letter case,
with an optional final question mark and surrounding whitespace. Extra words
or commands do not match. The reply is ordinary encrypted private text, `Yes`
or `No`, and neither answer can trigger another automatic reply.
Automatic responses are limited to one per contact per minute and one globally
per ten seconds. A bounded four-peer cache uses full public keys and the
incoming request timestamp to suppress retries. Its state clears on reboot.
The same retained request is not answered again; a fresh check uses a new
timestamp. An old retry can receive another answer after a newer request
replaces its saved timestamp or its peer slot is evicted. Queueing an answer
records the request even if later delivery fails. An unanswered poll means
unknown, and the tracker should trust replies only from its configured
Companion's full public key.
The responder leaves packet capacity for normal receive/ACK work, uses a free
ACK-tracking entry, and does not replace pending user messages or their
delivery deadlines. Busy packet or ACK capacity, or a failed send, can prevent an answer;
the tracker should retry later. A full offline app inbox does not disable the
responder. Normal message reception and notification behavior remain in place.
+8
View File
@@ -17,6 +17,7 @@ A reboot clears it.
| ESP32 without PSRAM | 256 |
| nRF52840 with at most 300 contact slots | 256 |
| nRF52840 with more than 300 contacts and the contact cache (non-mOTA-shared queue) | 256 total: up to 15 held DMs use slots until accepted |
| RAK WisMesh Tag ordinary BLE Companion | 240 total: up to 15 held DMs use slots until accepted |
| nRF52840 with more than 300 contacts but no contact cache | 208 ordinary frames plus a separate 15-DM queue |
| nRF52 Full Companion with the memory correction | 256 normally; 128 while mOTA owns shared storage |
| RP2040 | 256 |
@@ -60,6 +61,13 @@ Uncached high-contact profiles keep the conservative 208-frame default and
separate held queue. An explicit target `OFFLINE_QUEUE_SIZE` still takes
precedence.
The ordinary RAK WisMesh Tag BLE profile uses 240 frames to retain the runtime
RAM reserve for Bluetooth, filesystem buffers, and the main task. It keeps
350 contact slots and 40 group channels. All 240 slots are available when no
DMs are held; 15 held DMs leave 225 ordinary slots. This saves 2,832 bytes
compared with 256 frames. The Tag Full Companion retains 256 frames normally
and 128 while mOTA borrows queue storage.
Each queue slot currently costs 177 bytes. A 256-frame queue reserves 45,312
bytes, while a 512-frame queue reserves 90,624 bytes. There is no 256-frame
protocol limit: the queue length and indexes can represent 512 or more. The
+3
View File
@@ -105,6 +105,9 @@ Room Server provides the room-side queue and polling protocol. A tracker still
needs client firmware that schedules check-ins and interprets authenticated
commands. Ordinary mailbox text is never executed as a CLI command, and does
not itself enable a tracker, wake it remotely or change its GPS reporting rate.
For a reachable owner's Companion, the optional
[lost-status auto responder](companion_lost_reply.md) can also answer a private
`Am I lost?` question with a saved `Yes` or `No`.
### Wi-Fi mailbox management
+94
View File
@@ -0,0 +1,94 @@
<!-- meshcore-hosted-doc-link:start -->
<p class="meshcore-hosted-doc-link"><a href="https://mikecarper.github.io/MeshCore/test-results/companion_lost_reply/">View this page on MeshCore Docs</a>.</p>
<!-- meshcore-hosted-doc-link:end -->
# Companion lost-status response validation
Validated on 2026-10-10. These are production-path host tests, browser tests
and firmware builds. No lab radio was flashed for this feature; this report
does not qualify a sleeping tracker client or a live LoRa exchange.
## Automated checks
The responder test executes the actual private receive callback, message
composition/send functions, ACK handling and local CLI policy. Seven compiled
variants cover normal and shared one-key DM queues, a text terminal, explicit
STM32 enablement, default STM32 exclusion and explicit exclusion elsewhere.
AddressSanitizer and UndefinedBehaviorSanitizer checks passed.
Coverage includes exact question matching, Yes/No loop avoidance, known full
identities, temporary/unknown contacts, room/channel/CLI exclusions, a full
offline inbox, duplicate requests, cooldowns, clock wrap, busy packet/ACK
capacity, send failures and preservation of pending user messages/deadlines.
Queueing the response preserves the shared send timer. ACK reception retains
the existing shared-timer behavior; independent per-message expiry continues
to protect pending user deliveries.
Excluded builds have no responder state, automatic send, successful setting
command, save or WebConfig capability.
Saved preference tests cover all three values, all 256 stored byte values,
legacy images loading off, reboot, atomic save failures, recovery copies and
runtime adapter preservation. Existing CLI, delivery, inbox, notifications
and preference regression suites passed after updating adapters for the new
append-only preference byte.
WebConfig tests execute the actual JSON and settings handlers with
ArduinoJson. Chromium exercises Off -> No -> Yes -> Off, Companion-only
visibility and the absence of the control on infrastructure roles. Existing
browser, authorization, secret masking and generated asset checks passed.
Both new suites are included in the unit-test workflow.
## Capacity and reliability
The responder cache is 184 bytes on ARM and retains four complete public keys.
The saved preference uses an existing padding byte in the tested ARM preference
object and one new byte in its explicit storage image. No heap allocation is
introduced by the responder.
Compact STM32 Companion images exceeded their existing application boundary
when the responder was included. Those default to `MESH_ENABLE_LOST_REPLY=0`,
preserving their existing features and filesystem layout. Explicit opt-in is
tested synthetically and remains subject to the normal capacity checks.
The ordinary RAK WisMesh Tag BLE queue uses 240 frames, retaining 350 contacts
and 40 channels and saving 2,832 bytes. Source comparison showed that its prior
256-frame recipe was already below the current runtime RAM allowance before
the new 184-byte responder cache. Full retains its 256-frame shared queue.
Sanitized tests exercise real FIFO wrapping, downloads and held-DM isolation
at 240 slots, plus the production Full override.
Queueing an answer suppresses that request even if later delivery fails. A
tracker needs a fresh timestamp for a later poll, must stay awake for the
private answer, and must authenticate its configured Companion. Plain Yes/No
answers do not contain a poll ID, so delayed replies cannot be precisely
correlated with a newer poll. An unanswered poll means unknown.
## Firmware build qualification
All ten final builds passed flash and internal RAM policy checks. Compact
STM32 and both Full targets were also packaged using the normal
`v1.17.1.9-halo-keymind-cascade-dev` label. Ordinary targets used their normal
PlatformIO recipes. Full nRF52 UF2 boundaries and applicable Bluetooth DFU
handoff checks passed. These are local qualification artifacts, not new
published release assets.
| Companion target | Responder | Flash used / limit (bytes) | Link-time internal RAM available / required (bytes) |
| --- | --- | --- | --- |
| RAK 3x72 USB | Excluded | 228,924 / 229,376 | 24,728 / 17,408 |
| Tiny Relay USB | Excluded | 228,944 / 229,376 | 24,728 / 17,408 |
| Wio-E5 Mini USB | Excluded | 228,888 / 229,376 | 24,704 / 17,408 |
| Wio-E5 USB | Excluded | 229,008 / 229,376 | 24,736 / 17,408 |
| T1000-E Full | Included | 607,480 / 708,608 | 87,064 / 44,864 |
| RAK WisMesh Tag Full | Included | 649,408 / 712,704 | 82,112 / 44,864 |
| T1000-E USB | Included | 426,756 / 708,608 | 48,248 / 38,944 |
| Pico W USB | Included | 640,180 / 1,568,768 | 101,712 / 17,408 |
| Heltec V4 BLE | Included | 1,550,217 / 6,553,600 | 263,448 / 118,560 |
| RAK WisMesh Tag BLE | Included | 459,564 / 712,704 | 46,316 / 44,864 |
The STM32 historical-size table uses byte entries while retaining a 32-bit
input file size; exhaustive tests reject oversized aliases and partial
images. Tiny Relay and Wio-E5 use the size option already used by neighboring
STM32 recipes. Existing terminal help was combined into fewer writes while
retaining its text, order and 256-byte maximum per write. Supported images
also show the new lost-reply commands. Contacts, channels and filesystem
boundaries are unchanged on those compact boards.
+2
View File
@@ -40,6 +40,7 @@ Completed validation reports, experiments, and test guides are collected here. O
## Companion, USB, BLE, and display
- [Companion lost-status replies](companion_lost_reply.md)
- [Contact-cache and NimBLE RAM qualification](companion_contact_cache_results.md)
- [USB Companion ASCII default validation](companion_usb_ascii_validation.md)
- [USB Companion client compatibility](companion_usb_client_validation.md)
@@ -54,6 +55,7 @@ Completed validation reports, experiments, and test guides are collected here. O
## Build, storage, memory, and checklists
- [Personal room mailbox checks](room_mailboxes.md)
- [Stock nRF52 bootloader version audit](bootloader_version_stock_audit.md)
- [CLI setting dispatch audit](cli_settings_audit.md)
- [Hardware validation checklist](hardware_validation_checklist.md)