Commit Graph
83 Commits
Author SHA1 Message Date
mikecarper 95aca52b4e Add per-profile TX routing and bridge filtering
Persist Companion TX preferences per contact and channel. Default repeater,
room, and sensor replies to both active TX profiles, with a reply-only force
option for an RX-only secondary profile. Track both reply copies before a
temporary-radio handoff and account for OTA copies under queue backpressure.

Add bridge/crossover filter modes and the third built-in wardriving filter,
plus compact filter CLI syntax, documentation, and CI coverage.

Fix quoted target names being interpreted as slot/key selectors, partial
recovery of invalid saved reply settings, filter suspension during tempradio2,
and unnecessary packet allocation while OTA traffic is throttled.

Validation: 1,477 native tests, 52 Python integration tests, 29 filter UI tests,
and five firmware builds covering ESP32, nRF52, and STM32 passed.
2026-09-15 01:58:43 -07:00
mikecarper 794cf15395 Preserve Full USB packet logging and verify packaged firmware 2026-09-13 15:34:00 -07:00
mikecarper a7f58dd437 Refresh 1.17.1.6 picker metadata and preserve capacity directions 2026-09-13 12:51:12 -07:00
mikecarper fff92f0588 Report portable-slot exclusions alongside release failures 2026-09-13 11:31:05 -07:00
mikecarper 2dcc8ac6d7 Publish qualified partial release matrices with explicit failure reports 2026-09-13 09:19:17 -07:00
mikecarper fa010196b1 Merge PR #7 with reviewed ExpressLRS power and memory fixes
Integrate ExpressLRS TX module support and its stacked ESP32 heap changes.
Use the approved Linkflow calibration (17-30 dBm), preserve the PA drive
and output path after radio recovery, and keep LoRa OTA enabled.

Preserve stored ACLs and filters on allocation failure, release owned
client/filter buffers, service heap OTA contexts on Companions, release
self-serving workspaces after TempRadio, and reset staged-resume state
when a context is released. Keep manual staging and active operations
alive. Account for all moved allocations in the runtime RAM gate.

Validation: 1,393 native cases; radio-power, heap-context, ACL persistence,
shared-queue transfer, display/inbox, radio receive, and memory regressions.
Firmware builds passed for Linkflow, Heltec V2 Companion, T-Beam MQTT
repeater, Heltec V4 R8 MQTT repeater, RAK4631 repeater, and Indicator Full.
Physical verification awaits access to the currently offline lab Pi.
2026-09-10 22:06:16 -07:00
mikecarper 602dbfe3d9 Fix inherited nRF52 USB READY hang in build-local TinyUSB driver 2026-09-10 02:37:15 -07:00
MUSTARDTIGERFPV c6d71b969a Enable the on-demand mOTA context for every classic ESP32 build
Move OTA_HEAP_CONTEXT from two hand-edited envs to a pre-script gated on
build.mcu == "esp32", so every classic ESP32 image gets it and none can drift.
S2/S3/C-series and nRF52 keep the .bss singleton: they have no equivalent
static-DRAM ceiling, so there a guaranteed-present workspace is the better
trade for what is ultimately a recovery path. It has to be a build flag rather
than a header default, because OTA_HEAP_CONTEXT must hold the same value in
every translation unit that sees OtaContext.h - OtaContext.cpp included - and a
header test on CONFIG_IDF_TARGET_ESP32 would depend on include order relative
to sdkconfig.h. The script defers to OTA_SHARED_COMPANION_QUEUE where a Full
Companion recipe already owns the storage.

Fix a gap this exposes in the roles that now use it. Only CLI entry points
acquire the context, so once it was released, a repeater with the temporary
radio profile up would no longer serve or announce its own firmware - LoRa OTA
would look enabled and silently do nothing. ota_service_temp_radio_context()
holds the workspace for exactly the temp-radio window and hands it back
outside it, which is where the saving was coming from anyway. Wired into the
repeater, room server and sensor loops; the Companion keeps its own
acquire-on-host-demand policy, since its context is borrowed from the offline
message queue and must not be taken speculatively.

Static DRAM, classic ESP32 (bytes occupied of a 124,580 region):
  Heltec_v2_repeater                   108,332 -> 70,732
  Heltec_v2_room_server                 83,716 -> 68,300
  Heltec_v2_companion_radio_ble        123,236 -> 107,772  (was failing on main)
  Tbeam_SX1262_repeater                 86,932 -> 71,468
  Tbeam_SX1262_repeater_observer_mqtt  121,132 -> 83,532   (was failing)
2026-09-09 01:24:00 -07:00
mikecarper b9138c13b2 Allow local CLI maintenance across direct connections 2026-09-08 21:44:57 -07:00
mikecarper 5e6a74be50 Enable the shared terminal on WiFi-only Companions 2026-09-08 19:56:12 -07:00
mikecarper d178cf1474 Share the Companion terminal with the WiFi console 2026-09-08 19:48:15 -07:00
mikecarper cb79dcd4e3 Preserve MQTT settings across slot changes 2026-09-08 18:55:00 -07:00
mikecarper aa8caa4ed2 Unify device controls and restore the WiFi console 2026-09-08 18:36:23 -07:00
mikecarper eeea15ef01 Use compact message text and sender lines on all small displays 2026-09-08 13:36:40 -07:00
mikecarper a7f088290b Add a V4 Picopixel message font trial with longer previews 2026-09-08 13:22:53 -07:00
mikecarper b68aa1c685 Enable dual WiFi OTA slots for the smaller 4 MiB NimBLE trials 2026-09-08 12:36:43 -07:00
mikecarper e0a229fb91 Publish memory-corrected 1.17.1.5 catalogs and picker directions 2026-09-08 02:53:48 -07:00
mikecarper aa20e9278e Gate every firmware build on runtime RAM and share nRF52 mOTA storage 2026-09-08 02:09:26 -07:00
mikecarper 27616e2e5b Report nRF52 LoRa mOTA capabilities and storage requirements 2026-09-06 23:50:24 -07:00
mikecarper b781b3df89 Show role-specific feature commands in firmware picker 2026-09-06 04:52:02 -07:00
mikecarper 2630379365 Stage 1.17.1.5 local release assets and document OTAFIX 2.4.6 2026-09-05 14:04:39 -07:00
mikecarper 49dcba5c6e Add retained-RAM staging for nRF52 mOTA 2026-09-05 12:08:21 -07:00
mikecarper d4c8890eae Match Halo Keymind Cascade dev release naming and include WM1110 DFU packages 2026-09-05 09:08:42 -07:00
mikecarper 02020513f4 Prepare 1.17.1.5 USA Cascade release and verify update capabilities 2026-09-05 08:59:50 -07:00
mikecarper f8dfcaa240 Enforce classic ESP32 memory budgets and safe image merging 2026-09-05 08:22:56 -07:00
mikecarper 7782bd562f Embed fixed ESP32 firmware identity 2026-09-03 12:16:40 -07:00
mikecarper 9e874917b4 Fix Windows Full firmware builds 2026-09-02 11:41:24 -07:00
mikecarper fcd1f8cc6c Unify companion BLE and WiFi setup flows 2026-09-01 01:25:00 -07:00
mikecarper 8f413b0610 Add SenseCAP Indicator N16R2 profile 2026-08-31 18:29:38 -07:00
mikecarper 9fd580c89e Harden marathon-tested OTA and hardware paths
Add durable TempRadio, ACL, clock, bridge, GPS/I2C, USB logging, and Indicator recovery safeguards together with expanded automation, build/profile contracts, release metadata, and the hardware validation ledger.
2026-08-30 19:26:15 -07:00
mikecarper e26d48e4ca Fix ESP32 Full Companion partition policy 2026-08-29 20:26:27 -07:00
mikecarper 6d6c89e411 fix: harden ESP-NOW and full companion networking
Add selectable shared ESP-NOW channels, raw/wrapped bridge compatibility, and bounded fragmentation for maximum-size packets.\n\nGive ESP32 Full profiles WiFi coexistence, stabilize WebConfig and USB terminal lifecycles, and keep disabled bridges stopped during observer updates.\n\nUpdate generated UI, firmware selection, documentation, and regression coverage.
2026-08-28 16:36:34 -07:00
mikecarper d6519baa0f feat: consolidate full companion runtime profiles 2026-08-28 08:47:26 -07:00
mikecarper 1d836c0473 feat: unify companion builds and USB runtime modes 2026-08-27 15:06:26 -07:00
mikecarper f1515ef1c6 feat: retain multi-channel voltage telemetry 2026-08-25 22:51:22 -07:00
mikecarper c95a6249be feat: order flood rules by channel specificity 2026-08-25 21:58:08 -07:00
mikecarper 8705e7f551 feat: add selective flood retry rules 2026-08-25 21:38:23 -07:00
mikecarper ba2170d21b feat: add capability-aware firmware build profiles 2026-08-25 20:07:09 -07:00
mikecarper 177eb06745 Add shared-slot nRF52 bootloader updates 2026-08-21 00:55:01 -07:00
mikecarper 7a4da3ccfb Fix Cascade power saving, USB Companion, and mOTA flows 2026-08-18 14:02:10 -07:00
mikecarper a514b2a6d5 Stabilize T-Beam full companion startup 2026-08-16 11:00:55 -07:00
mikecarper 933697f65c Fix Companion device power saving 2026-08-15 17:58:37 -07:00
mikecarper 9161dfd7d5 Expose RX power saving in WebConfig 2026-08-15 09:07:41 -07:00
mikecarper 7605b12cc7 Merge remote-tracking branch 'review/observer-firmware' into keymindCascade
# Conflicts:
#	.github/workflows/build-observer-firmwares.yml
#	.gitignore
#	MQTT_IMPLEMENTATION.md
#	MQTT_INTERNALS.md
#	README.md
#	STABILITY_TESTABILITY_HANDOFF.md
#	docs/cli_commands.md
#	examples/companion_radio/MyMesh.cpp
#	examples/simple_repeater/MyMesh.cpp
#	examples/simple_repeater/UITask.cpp
#	examples/simple_room_server/MyMesh.cpp
#	examples/simple_room_server/UITask.cpp
#	examples/simple_sensor/SensorMesh.cpp
#	platformio.ini
#	scripts/generate_webconfig_html.py
#	scripts/webconfig_mock_server.py
#	src/helpers/CommonCLI.cpp
#	src/helpers/CommonCLI.h
#	src/helpers/JWTHelper.cpp
#	src/helpers/MQTTDefaults.h
#	src/helpers/MQTTMessageBuilder.cpp
#	src/helpers/MQTTPayloadBuilder.h
#	src/helpers/MQTTPresets.h
#	src/helpers/bridges/MQTTBridge.h
#	src/helpers/esp32/WebConfigServer.cpp
#	src/helpers/esp32/WebConfigServer.h
#	src/helpers/ui/SH1106Display.cpp
#	variants/lilygo_tbeam_SX1262/platformio.ini
#	variants/lilygo_tbeam_SX1276/platformio.ini
#	variants/lilygo_tlora_v2_1/platformio.ini
#	variants/thinknode_m7/platformio.ini
#	webui/index.html
2026-08-14 08:53:02 -07:00
mikecarper e92794eabc Decode raw telemetry packets 2026-08-14 00:01:38 -07:00
mikecarper 137ebc24f1 Add Windows terminal chat launcher 2026-08-12 15:04:57 -07:00
mikecarper 88ba5b26cb Add full Companion OTA source builds 2026-08-10 12:39:07 -07:00
agessaman 8abe26ba7b fix(webconfig): stop the CLI reading secrets, and enforce the setup password
Two findings from review, both real, both mine.

The CLI could read secrets the portal has never exposed. CommonCLI splits its
surface by CALLER, not by command: a serial caller (sender_timestamp 0, physical
access) reads secrets in plaintext, a remote one gets "******** (serial only)".
Its own comments say so — "Serial only (WiFi creds grant LAN access); remote
sees set/unset". execCommand passes 0, which is what makes `erase`, `stats-*`
and `set freq` reachable at all, and with it the terminal inherited the serial
console's plaintext answers for an HTTP request: `get prv.key` returned this
node's identity, `get wifi.pwd` the operator's network.

Worse in setup mode, which authenticates by proximity to an open AP — and `start
webconfig ap` can be run on an already-configured node, so the secrets are real
by then, not blank.

I had reasoned that the AP was the trust boundary either way because the wizard
can already rewrite these. That conflated two capabilities: replacing a WiFi
password does not reveal the current one, and replacing an identity does not
reveal the existing private key. /api/config has always masked these on read
(wcIsSecretKey); the CLI simply broke that rule. Now only the READ is masked —
the command surface stays whole — in CommonCLI's own words, keeping the
set/unset signal that is the useful part.

Onboarding could also skip the mandatory password. handleConfigPost refuses to
arm a reboot during initial setup without one; the CLI only warned in the
browser, which a pasted script or a direct POST ignores, so a node could reboot
onto the LAN still holding the factory credential. Same rule now applies at
POST. It is satisfied by a `password` command anywhere in the session rather
than only in the same request, so the natural two-step console flow still works
— the form batch always sends both together and never needed that memory.

wcIsSecretReadCommand lives in WebConfigKeys.h beside the rest of the secret
classification, pinned by three host tests: what must be masked, what must not,
and that only reads are touched. 17 keys + 24 batch tests pass; the audit checks
a masked read round-trips as masked.
2026-08-08 14:05:02 -07:00
agessaman 20826dcccf feat(webconfig): trim the displayed version to base, build and channel
The full embedded string is v1.16.0.5-observer-beta-dev-a1b2c3d. The -observer
tag is on every observer build and the commit is for machines, so neither tells
a person anything at a glance. Both the page header and the console banner now
show base + published build number + channel, paired with the build date the
way `ver` pairs them:

  v1.16.0.5-dev (6 Jun 2026)
  v1.16.0.5 (6 Jun 2026)

`ver` still prints the whole string, commit included, for when that is what you
need. The channel suffix follows the release filenames rather than the embedded
tag — build.sh writes FILENAME_CHANNEL_TAG "-dev" for the same builds it tags
"-observer-beta-dev" internally, so "-dev" is the name these already carry.

Carrying the build date meant /api/status had to report it; WebConfigServer now
takes FIRMWARE_BUILD_DATE alongside FIRMWARE_VERSION, from the same defines
`ver` reads.

A local build has neither build number nor channel to show, so the fact worth
knowing about it moves to the second line: "local build, OTA not configured".
build.sh deliberately leaves OTA_MANIFEST_BASE undefined there, and a bare
version number gives no hint that the node cannot update itself.
2026-08-08 09:01:29 -07:00
agessaman cac91c91d8 feat(webconfig): print the full firmware version and name the channel
The console showed "v1.16.0" — the version was there but buried in the header
line beside role and board, and on the build under test it genuinely had no more
to show: `pio run` never goes through build.sh, so no build number, no commit,
no OTA config.

The banner now prints FIRMWARE_VERSION whole and on its own line. Nothing was
truncating it; build.sh composes base[.build][-observer][-channel]-hash, so a CI
build already carries the published build number as a 4th component and the
commit as the trailing token — the two things that actually identify a build.

It also names the channel, which the version string encodes but does not spell
out (OTA_CHANNEL_TAG=beta-dev -> "-observer-beta-dev-"):

  v1.16.0.5-observer-beta-dev-a1b2c3d   (dev channel)
  v1.16.0.5-observer-beta-a1b2c3d       (beta channel)
  v1.16.0.5-observer-a1b2c3d            (release channel)
  v1.16.0                               (local build — not from CI, OTA not
                                         configured)

That last one earns its wording: build.sh deliberately leaves OTA_MANIFEST_BASE
undefined on local builds so such a node cannot update itself, and nothing about
a bare version number says so.

The mock reports a build.sh-shaped version now (--fw-version switches channel),
and `ver` answers from the same string /api/status does, as both do on-device.
2026-08-08 08:53:56 -07:00