Observer firmware - #3360
Open
benocd wants to merge 524 commits into
Open
Conversation
Enhanced the firmware versioning system by appending a build number suffix when available, allowing for better tracking of published builds. This change improves the OTA update process by providing clearer versioning information in the embedded firmware string.
Improved the otaFromManifestImpl method to handle dry run scenarios by allowing HTTP fetches without TLS, reducing heap usage on no-PSRAM boards. This change ensures better compatibility and reliability during OTA checks while maintaining security for actual updates.
Updated the otaFromManifestImpl method to enhance the display of available and current firmware versions. The changes ensure that the short commit hash is included in the status messages, providing clearer versioning information during OTA checks.
Implemented functionality to generate and compare partition-table signatures during OTA updates. This enhancement ensures that the target build's partition layout matches the device's actual layout, improving the reliability of OTA updates and preventing issues related to partition changes.
Updated the build-observer-firmwares workflow to exclude .partsig files when uploading release assets. This change prevents issues with the slim-manifest generator and ensures that only relevant firmware files are published, improving the integrity of the release process.
Implemented new commands for configuring and diagnosing NTP server settings in the MQTT bridge. Users can now set a custom NTP server and probe connectivity to configured servers. This enhancement improves time synchronization reliability for JWT authentication and provides better diagnostics for NTP connectivity issues.
Remove unused MQTTMessageBuilder members (getPacketTypeString,
formatTimestamp/Time/Date stubs, JSON_BUFFER_SIZE constant) for a
small flash saving with no behavior change.
Replace the per-byte snprintf("%02X") in bytesToHex with a nibble
lookup table, avoiding a format-string parse up to ~512x per publish
on the MQTT task. Output is byte-for-byte identical uppercase hex.
feat(mqtt): add rflab.io WebSocket broker preset
Improved error handling in the MQTT client to log specific reasons for connection refusals, including detailed return codes. This change ensures that users are informed of authentication issues and server availability problems, enhancing the debugging experience.
Refactored the CommonCLI class to separate observer-related command handling into CommonCLI_Observer.cpp. This change improves code organization and maintainability by isolating MQTT, WiFi, and other observer-specific commands from the main CLI logic.
Refactored the handling of observer-related settings by moving them from NodePrefs to a new MQTTPrefs structure. This change centralizes MQTT, WiFi, timezone, SNMP, and alert configurations, improving code organization and maintainability. The new structure allows for better separation of concerns and prepares the codebase for future enhancements.
…ation Updated MQTT configuration to succeed when port is defined in mqttN.server but not explicitly set in mqttN.port. Updated documentation to specify that when a full URL with a scheme is provided, the port setting is optional. Added an example for local development using a plain WebSocket URL, enhancing clarity for users configuring custom MQTT brokers.
CoreComms is a map, analyzer, and mesh health platform created by EastMe.sh
The NodePrefs->MQTTPrefs split (2eb41ba) left the promised one-time migration of the old /com_prefs trailing block unimplemented, so users upgrading an observer node silently lost SNMP, radio-watchdog, and fault-alert configuration (alerts reset to off; PSK/hashtag/region wiped). loadPrefsInt now detects an old-format /com_prefs by its size, skips the legacy zero-filled MQTT gap (6-slot or 3-slot era), and recovers the trailing observer block into a LegacyObserverTail (reusing the old firmware's byte291/292 heuristic and per-field availability guards). loadMQTTPrefs applies those values when the loaded /mqtt_prefs predates the appended observer fields, and both files are rewritten once in the current layout. rx_boosted_gain/flood_max_* are also recovered from the correct offsets (previously read from inside the old gap and reset). Verified with a host-side harness that round-trips the real old-firmware savePrefs (from 2eb41ba^) through the new load path across upgrade, fresh-install, upstream-format, 3-slot-era, truncated, and legacy-variant cases, plus a non-MQTT-build variant. Updates the stale migration comments and documents the CommonCLI_Observer seam in MQTT_IMPLEMENTATION.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # src/helpers/bridges/MQTTBridge.cpp
The Files section (source layout, upstream integration seams, and on-device settings migration) is developer-facing detail that sat near the top of the otherwise user-facing MQTT_IMPLEMENTATION.md. Move it to a new MQTT_INTERNALS.md and link it from the bottom of the main doc. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…l fields
The /mqtt_prefs format was detected purely by struct size, which is fragile
(size collisions across eras) and forced the vestigial `_legacy_*` fields to
be retained forever to preserve byte offsets. With ~several thousand observer
devices deployed from the rolling `observer-mqtt-latest` flasher, this is the
last safe moment to fix it before the observer-settings split ships.
/mqtt_prefs now leads with an 8-byte MQTTPrefsHeader (magic {0xF5,'M','Q','P'},
version, payload_len) followed by the raw payload. The magic's non-ASCII lead
byte cannot collide with a legacy file (whose payload starts with the
mqtt_origin string), so versioned and headerless files are cleanly separable.
An unrecognized (newer) version leaves the file untouched and falls back to
defaults rather than misreading it.
MQTTPrefs is compacted: the six `_legacy_*` fields are removed. Every deployed
headerless layout — pre-slot (OldMQTTPrefs), 3-slot (ThreeSlotMQTTPrefs), and
the shipped 6-slot flex layout (new Legacy6SlotMQTTPrefs) — is field-copied
into the compact struct and re-saved with the header once, on first boot.
Future fields append to the payload and stay backward compatible.
Verified with a host harness that generates a byte-exact deployed flex
/mqtt_prefs (the flex MQTTPrefs is confirmed identical to Legacy6SlotMQTTPrefs,
2904 bytes) and round-trips it through the new load path, plus pre-slot/3-slot
migration, unknown-version safety, magic/origin collision-safety, and the
combined /com_prefs observer-tail recovery. Observer + room-server + no-MQTT
ESP32 targets build.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Commit 22eb9b8 ("Revert 'Merge remote-tracking branch origin/dev...'") reverted an entire upstream merge to escape a bad merge state, dropping 860 lines across 66 files. Among the collateral never reconciled on a later re-merge was eb4fa03's token-bucket duty-cycle enforcement — the mechanism that keeps nodes under a configured airtime budget (and EU 868 MHz nodes under the legally-mandated duty cycle). The fork had fallen back to fixed per-packet spacing (getAirtimeBudgetFactor reverted to 2.0), losing the windowed enforcement. This was never an intentional design choice, so restoring it re-aligns the fork with upstream and REDUCES the merge-conflict surface: Dispatcher.{h,cpp} now diverge from upstream by watchdog additions only (77 insertions, 0 deletions) instead of rewriting checkSend()/loop(). Restored from upstream: updateTxBudget/tx_budget_ms/duty_cycle_window_ms/ getRemainingTxBudget/getDutyCycleWindowMs and the windowed budget logic in Dispatcher; getOutboundTotal() and the 0xFFFFFFFF count-all sentinel in StaticPoolPacketManager; the getOutboundTotal() call in StatsFormatHelper. Re-applied the fork's MQTT radio-watchdog on top as pure additions (#ifdef WITH_MQTT_BRIDGE), keeping formatRadioDiag. Stored airtime_factor settings keep their meaning: fork's t*factor spacing and upstream's 1/(1+factor) windowed budget yield the same steady-state duty cycle; upstream additionally allows short bursts within the window. Phase 2 (CAD / radio_fem_rxgain, which touch NodePrefs persistence and per-board FEM wiring) is documented in RESTORE_UPSTREAM_NOTES.md, not done here. Builds: Heltec_v3 observer + plain repeater. NEEDS ON-DEVICE duty-cycle validation before merge. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ream parity) Continues restoring features dropped by the 22eb9b8 revert. Both were upstream-tested code, not intentional fork removals. CAD (hardware Channel Activity Detection / listen-before-talk before TX), fully restored and functional: - NodePrefs.cad_enabled + `set cad on/off` / `get cad` CLI (default off) - RadioLibWrapper: _cad_enabled + setCADEnabled() + the scanChannel()/CAD branch in isChannelActive() (Phase 1 already restored the Dispatcher hook) - getCADEnabled() overrides in the repeater/room/sensor apps (return the pref) and companion (always on, matching upstream) radio_fem_rxgain: the NodePrefs field + /com_prefs persistence are restored here at upstream's exact offsets (293 fem, 294 cad), which makes /com_prefs byte-identical to upstream through the tail. The field is persisted and defaults on (upstream default), but the per-board LNA *driving* + the `radio.fem.rxgain` CLI are deferred to the FEM-hardware change (they depend on board methods and want per-board bench testing). The new-format /com_prefs tail grows from 3 to 5 bytes; the old-format detection threshold and the host migration harness are updated accordingly (all scenarios pass, incl. the non-MQTT-build variant). Builds: Heltec_v3 repeater, repeater-observer, room-observer. (sensor / plain-room / companion fail only on the pre-existing Timezone.h include issue, unrelated to these changes.)
Completes the FEM RX-gain restoration begun in the CAD/prefs change, which persisted radio_fem_rxgain but didn't yet drive the hardware. Also dropped by the 22eb9b8 revert; restored to match upstream. - MainBoard: setLoRaFemLnaEnabled()/canControlLoRaFemLna()/isLoRaFemLnaEnabled() virtuals (default: can't control — non-FEM boards report unsupported) - heltec_v4: board overrides driving loRaFEMControl; LoRaFEMControl gains the isLNAEnabled() getter (it already tracked lna_enabled and drove the FEM) - CLI: `set radio.fem.rxgain on/off` / `get radio.fem.rxgain` (guarded by canControlLoRaFemLna, so it reports "unsupported" on non-FEM boards) - app startup applies the persisted pref: board.setLoRaFemLnaEnabled( _prefs.radio_fem_rxgain), beside setRxBoostedGainMode Default is ON (upstream), so on FEM boards the LNA is enabled after upgrade — a real reception behavior change to confirm on hardware. The other FEM variants (heltec_t096/tower_v2/tracker_v2) need the same small board-override addition; until then `radio.fem.rxgain` reports unsupported there (no regression — status quo). Builds: heltec_v4 repeater-observer + room-observer (FEM board), Heltec_v3 repeater (non-FEM, base virtuals no-op). NEEDS on-device validation on a Heltec V4.
…ayouts The unknown-version path kept defaults at boot but any later savePrefs() (every CLI set command) rewrote /mqtt_prefs as v1 with defaults, destroying the newer config after a firmware downgrade. Latch _mqtt_prefs_hold when an unsupported version is seen and refuse to write while it is set — checked before the NRF52/STM32 open path, which deletes the file first. Also pin the frozen legacy /mqtt_prefs layouts (472/1464/2904 bytes + 8-byte header) with static_asserts so every target build re-verifies the deployed fleet's file offsets, and null-check _obs in AlertReporter::onLoop.
…efs tail size performChannelScan was restored as protected non-virtual but upstream declares it public virtual — match upstream verbatim so the hunk disappears from the merge surface. Also replace the bare 'extra > 5' tail threshold with COM_PREFS_TAIL_BYTES, tied by comment to the trailing writes in savePrefs(), so the next upstream field append updates one named constant.
…rrides companion_radio has its own NodePrefs without radio_fem_rxgain (matching upstream, which doesn't wire companion either), so the startup call added in e905451 broke every companion build: MyMesh.cpp:973: error: 'struct NodePrefs' has no member named 'radio_fem_rxgain' It went unnoticed behind the pre-existing companion build failures. Also port upstream's FEM LNA overrides for heltec_t096 and heltec_tracker_v2 verbatim (board overrides + isLNAEnabled/const getters), so all three boards upstream wires now match instead of reporting unsupported. Both variant files compile; those targets still fail overall on the pre-existing non-observer MQTT-source build-config issue (unchanged with this work stashed).
… the pool Load-testing the restored token bucket at 'set dutycycle 1' showed MQTT capture dropping to exactly the TX rate. Queued retransmissions hold static- pool packets with no expiry, so throttling parks the whole pool in the send queue; Dispatcher::checkRecv() then discards received packets before logRx() ever feeds the bridge — each completed TX frees exactly one packet for exactly one more RX. Observer builds now use RxReservePacketManager (fork-owned header): once the free pool drops below a quarter of the pool, outbound packets are refused and freed, so RX allocation and MQTT capture continue at full rate while the node sheds repeat load it has no TX budget for anyway. Non-observer builds keep upstream pool behavior via the same factory; StaticPoolPacketManager stays byte-identical to upstream.
… stale expiry Device testing at 'set dutycycle 1' on a busy mesh showed the node becoming un-administrable within ~2 minutes: the shed policy dropped its own CLI responses along with repeats, and parked retransmissions (which never expire) absorbed every budget refill. RxReservePacketManager now sheds by priority below the RX reserve — only pri > 1 outbound (multi-hop flood repeats, adverts, trace) is refused, so the node's own responses/ACKs (pri 0) and login/PATH replies (pri 1) still queue; below an emergency floor (reserve/2) everything is shed to protect capture. Queued packets untransmitted 30 s past their scheduled time are expired at dequeue via a pointer-keyed age table (the pool is a fixed set of packets, so pool_size slots cover every key). Under normal load the queue drains in milliseconds and neither policy triggers.
…fusals
Five findings from review, all confirmed against the source.
Failure classification (P2). Testing replies for an "Err" prefix passed five
other shapes off as success: "Unknown command", "unknown config: x", "??: x",
"Can't find GPS", "(ERR: clock cannot go backwards)" and "File system erase:
Err". They rendered green, and worse, left _batch_all_ok true — so a queued
reboot went ahead after commands that had failed, defeating the gate entirely.
Rather than lengthen one guess, the two questions are now asked separately,
each erring safe:
- colour asks "does this look like a failure", against every shape CommonCLI
actually emits, enumerated in WebConfigBatch.h and pinned by a host test
that uses the literal strings. Getting this wrong is cosmetic.
- the reboot gate asks something narrower and answerable: "did every setting
I asked for take". Only `set`/`password` gate it, and only on the "OK"
prefix every setter keeps. Diagnostics no longer gate a reboot at all, so a
harmless `memory` cannot strand one and no guess is made about "> value".
Reboot deferral (P2). CommonCLI dispatches on a six-byte prefix, so `reboot
now` and `rebooted` reach Board::reboot() too. Matching exactly meant those
variants skipped both the confirmation and the deferral and took the node down
mid-drain — the precise failure deferral exists to prevent. Both sides now
anchor the way the firmware dispatches, and the UI's risk matcher with them.
Three commands the portal cannot honestly serve are refused at POST with a
reason, and dropped from autocomplete, instead of running and lying:
- `start ota` builds a second AsyncWebServer on port 80 with no bind check
and answers "Started" regardless; the portal already holds that port, so it
could only leak the allocation and inhibit sleep.
- `clock sync` takes its time from the caller's timestamp, which a web
request has none of, so CommonCLI always rejected it. `time <epoch>` works
and remains offered.
- bare `log` and `get acl` write their real output to Serial and hand back a
stub the terminal showed as success; `log` also streams a whole file from
the loop task, stalling the mesh and radio while it does.
The mock now emits the same failure shapes it used to fake as successes, so
these are reproducible off-hardware. 24 batch + 14 keys tests pass; audit
reports 119/119 answered, 0 missing, 4/4 refused with a reason.
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.
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.
…assword 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.
Station G3 observer envs were missing OTA_MANIFEST_BASE, so ota check reported online OTA unsupported even though CI publishes the manifests.
…manifest-base fix(station-g3): enable online OTA for observer builds
Add idahomesh broker preset
Keep built-in preset names in parity with observer-firmware after meshcore-dev#41.
Adding build_date to the WebConfigServer constructor broke every *_room_server_observer_mqtt target: simple_room_server constructs the portal as well, and only simple_repeater was updated. Nothing caught it because every build run to that point had been a repeater target.
A worktree checked out inside the repo, caught by a `git add -A` and recorded as a gitlink. Same problem df07083 fixed for .build-wt-028a5dca, and the same fix: untrack it and widen the ignore rule, which only covered .build-wt-*. It is not harmless. The gitlink pointed at a different commit than the worktree had checked out, so `git status` was permanently dirty — which is how it nearly got re-committed here, and it makes CI checkouts warn about a submodule path with no .gitmodules entry. The worktree directory is gone; branch fix/station-g3-ota-manifest-base and its commit are untouched. That branch still carries one commit not on prod — 5000391, which adds OTA_MANIFEST_BASE to the station_g3 variant. It belongs on prod, whose build.sh does not yet inject that flag, and must NOT come to dev, where build.sh does and an .ini declaration cannot be overridden (SCons reorders -U/-D) — it would pin dev and beta builds to the production manifest.
LilyGo_TLora_V2_1_1_6 observer builds failed to link:
undefined reference to `WebConfigServer::MAX_BATCH'
in handleStatus and handleCliPost
An in-class initialiser is only a declaration under C++11, which is what the
xtensa-esp32 toolchain builds with. Every previous use of MAX_BATCH was a
comparison, which reads the value and needs no symbol. Reporting it as
status.max_cmds, and naming it in the "too many commands" error, passes it to
ArduinoJson — which takes `const T&` — and binding a reference odr-uses it.
It linked on most targets because the compiler folded the reference away, and
failed on the ones where it did not. A cast at the two call sites would have
silenced it just as narrowly; defining the symbols is what stops the next use
from depending on the same luck. MAX_BODY and STOP_WARN_MS get the same
treatment for the same reason, before they are the next to be passed by
reference.
Feat/webconfig cli
The flasher's /webconfig page frames webui/index.html — the real page this firmware serves — and runs it against a browser simulator, so visitors drive the actual product rather than looking at screenshots of it. That only stays true if the page travels with the docs, so it joins the .md files this workflow already syncs, and the flasher's build-webconfig-demo.py re-injects the simulator. Triggers on webui/index.html alongside the existing markdown paths. Still gated on observer-firmware, so nothing publishes until the portal CLI reaches the release channel at v1.17.0; the flasher carries a hand-copied page until then.
Picks up upstream MeshCore 1.17.0 and the dev commits that followed it. Notable upstream content: - 1.17.0 version/build-date bump in the example MyMesh headers. - anon_req hardening: reply_path_len is now uint8_t with an isValidPathLen() bounds check and a 0xFF sentinel; reply_path_hash_size is gone. - LR2021 support (Meshnology W12, Seeed MeshTracker X1) incl. side detectors, multi-SF and the new `extra.sf` get/set CLI. - CustomLFS 0.2.2 -> 0.2.3 (GD25Q64C support). - kiss_modem envs for several nRF52 variants; ThinkNode M6 GPS/flash fixes. Conflicts resolved: - platformio.ini: took upstream's CustomLFS 0.2.3, kept our lib_ignore for the vendored PsychicMqttClient. - CommonCLI.h: kept both upstream's USE_LR2021 configSideDetectors() hook and our fault-alert callbacks. NodePrefs gains upstream's extra_sf[4], which is not registered with ConfigSerializer, so /prefs.json layout is unchanged. Verified: 275/275 native host tests pass; Heltec_v3_repeater_observer_mqtt, Heltec_v3_repeater and heltec_v4_repeater_observer_mqtt all build.
Both channels move together: the beta workflow's FIRMWARE_VERSION must equal
production's, since a node compares its embedded base against its own channel's
manifest and a mismatch would read as permanently behind.
Resets the per-base build counter to N=1 on both channels. Nodes still on
v1.16.0.N take the diff_base branch in ESP32Board's OTA comparison ('different
base version is always an update'), so the counter going backwards does not
strand them; the build-number arithmetic only runs when the base matches.
The flasher repo's config.json version key still needs the matching bump.
The planned wholesale dev -> prod merge at upstream MeshCore 1.17.0. Production now adopts the dev lineage in full; the two release channels stay separated by workflow, not by branch content. Resolution: prod's tree is now identical to observer-firmware-dev. Prod's 23 observer commits were sibling hand-ports of features dev implements more fully (neighbors, max-active-slots, retain policy, MeshRank routing, SNMP, deferred OTA), so dev's implementation wins throughout. Verified no prod-only content was lost: MQTT broker presets are at parity (34 both sides), and the sensor_base build flags that prod added for Heltec/RAK3112/Xiao S3 WIO are all present. Three files auto-merged into an inconsistent mix and were forced to dev: - examples/simple_repeater/MyMesh.h: kept BOTH lineages' WITH_MQTT_NEIGHBORS blocks, redeclaring neighbor_discover[] and declaring sendAnonRegionsReq() twice with different return types. Would not have compiled. - src/helpers/MQTTDefaults.h: duplicate neighbors default assignments (dev already sets them further down). - .wt-station-g3-prod: stray tracked build worktree, untracked on dev and covered by dev's .gitignore '.wt-*/' rule. Prod's station-g3 OTA hotfix (5000391) hardcoded the production manifest URL in build_flags; dropped in favour of dev's env, since build.sh already defaults OTA_MANIFEST_BASE to the production URL when the beta workflow does not override it. Verified on the built binary. Channels after this merge: - observer-firmware -> v1.17.0, tag observer-mqtt-latest, manifest /v - observer-firmware-dev -> v1.17.0, tag observer-mqtt-beta-latest, manifest /beta/v The beta workflow now also lives on prod but only triggers on the dev branch.
Nine commits reducing the MQTT bridge's internal-DRAM footprint, plus four fixes that rode with them (invalid path encodings, stale-JWT scan after a clock correction, setup-retry interval measured from the failure, retried setup consuming the reconnect allowance). Touches no prefs surface -- nothing in NodePrefs, MQTTPrefs, or ConfigSerializer -- so /prefs.json layout is unaffected and there is no fleet config risk. Soak evidence: every soak branch already contained this work in full. Device 1 has run it 69.6 h with 325,852 publishes, 0 errors and 0 reboots. The caveat worth carrying: that long-duration evidence is all on the reduced-TLS framework (OUT_CONTENT_LEN 4096). Device 3 is now soaking it on the stock framework, which is where the allocation-ordering interaction with the full 16 KiB record buffers actually gets exercised.
…isplay-117 fix(observer): recover T-Beam Supreme display startup
Documents why the largest allocatable block on a non-PSRAM observer walks down in 16 KiB steps at every TLS reconnect, and what to do about it. The framework builds mbedTLS with the symmetric buffer configuration (CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN 16384), so each broker slot holds two 16 KiB record buffers in internal DRAM and two slots cost 64 KiB on a board with about 80 KiB free. Confirmed against the sdkconfig the Heltec env actually links, not the IDF 5.3 libs package that belongs to the esp32c6 env. Rebuilding only the mbedTLS archives with an asymmetric outbound buffer of 4 KiB is ABI-safe, because in_buf/out_buf are heap pointers sized in ssl_setup() and no public struct embeds a CONTENT_LEN-sized array. Dropping KEEP_PEER_CERTIFICATE is not, since it changes mbedtls_ssl_session layout, so it is excluded. Also records two traps worth not rediscovering: esp32-arduino-lib-builder's release/v4.4 clones its dependencies at master and no longer resolves, and pointing platform_packages at a file:// framework copy overwrites the shared package for every other project on the machine.
Brings in the external FEM gain preferences (fem_txgain, PR meshcore-dev#3137 plus the companion-side port), the AGC reset rxgain fix, the LR2021 preamble/IRQ timeout logic, and assorted variant fixes (T096, T-Echo Card TCXO, promicro pinmap, minewsemi, R1 Neo). Conflict resolutions: - SH1106Display: both sides fixed T-Beam Supreme startup independently. Kept our _initialized guard and DISPLAY_ADDRESS_ALT override, took upstream's SA0-pair fallback and its unconditional display.begin() so the frame buffer is allocated even when no panel answers. - MyMesh/SensorMesh/CommonCLI: took upstream's fem_txgain default and wiring, kept our comments and the observer-side prefs layout. Also fixes CustomLLCC68Wrapper, which upstream missed when sx126xResetAGC gained its rx_boost_gain parameter. No variant builds that wrapper today, so neither tree failed to compile.
Picks up upstream MeshCore 1.17.1. Notable upstream content: - 1.17.1 version/build-date bump in the example MyMesh headers. - nRF52: combine radio entropy with CC310 RNG. - Companion FEM prefs: load/save of fem_ properties commented out until they can be set from the client. - Scoped reply routing: replies no longer dropped when flood.max.unscoped is low (RoutingPolicy + unit tests). - nRF52 unused-pin sweep (T1, T-Echo Lite, MeshPocket). No conflicts.
Both channels move together so a node comparing its embedded base against its own channel's manifest does not read as permanently behind. Resets the per-base build counter to N=1 on both channels. Nodes still on v1.17.0.N take the diff_base branch in ESP32Board's OTA comparison, so the counter going backwards does not strand them.
Promotes the v1.17.1 upstream sync and observer-firmware-dev work onto the production channel. Conflict in SH1106Display.cpp: kept the observer-firmware-dev begin() that always runs Adafruit init and falls back across the 0x3C/0x3D SA0 pair, rather than the earlier production DISPLAY_ADDRESS_ALT-only probe.
The rolling-release body is what the flasher dropdown serves as changelog. Drop the stale v1.16.0 experimental blurb and describe the current observer surface: MeshCore 1.17.1, web config, in-channel OTA, and neighbors.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
build for Heltec Wireless Stick v2.1