Commit Graph
3704 Commits
Author SHA1 Message Date
agessaman 3b11540e15 feat(mqtt): add gomesh to broker presets table 2026-08-07 20:54:56 -07:00
agessaman aad3b09cae docs(mqtt): add atvirastinklas to broker presets table 2026-08-07 15:43:05 -07:00
Adam Gessaman dbee39b598 feat(mqtt): add MQTT preset for atvirastinklas
Add new MQTT preset for atvirastinklas.
2026-08-07 15:42:21 -07:00
agessaman b27b475d3c feat(variants): add I2C sensor pins to Heltec/RAK3112 observers
Match Heltec_v3_sensor and RAK_3112_sensor Wire1 pins (33/34) so
external sensors work on observer_mqtt builds.
2026-08-07 15:12:17 -07:00
Martynas Zilinskas 2436229591 Update MQTT preset for atvirastinklas to use GTS_ROOT_R4 certificate 2026-08-07 18:07:41 +03:00
Martynas Zilinskas da7b51f181 Add new MQTT preset for atvirastinklas. 2026-08-07 17:53:58 +03:00
agessaman f156c0bd2a fix(boards): restore Station G2 GPS UART pin mapping
Match MCU RX=7 / TX=15 used by G3 and Meshtastic; the prior
values were an accidental revert of 0920dc66.
2026-08-06 09:02:19 -07:00
Adam Gessaman c4a7601329 Merge pull request #39 from clartek/patch-1
Add new MQTT presets for okimesh
2026-08-05 20:00:17 -07:00
agessaman 73faa30cfa feat(mqtt): increase built-in MQTT preset count to 31 2026-08-05 19:58:47 -07:00
Josh Clarke c0adb67033 Add new MQTT presets for okimesh 2026-08-05 22:37:03 -04:00
agessaman 0bfc281a91 docs(handoff): record the 2026-08-03 upstream merge
13 commits, 6 files, zero conflicts. Records the byte-identical smoke-build
baseline, the LR1110 RX-timeout fix and the global nRF52 CC310 crypto switch,
and the fact that the ESP32-only smoke pair could not see either.
2026-08-03 11:28:18 -07:00
agessaman 45379ad742 fix(build): restore nRF52 builds broken by observer-only dependencies
Three fork-introduced dependencies had leaked into non-ESP32 builds, breaking
every nRF52 and RP2040 target since 7e4f75c9 (2026-04-10):

- The `memory` CLI command called ESP.getFreeHeap()/heap_caps_* unguarded from
  shared CommonCLI.cpp. ESP32 output is unchanged; other platforms now report
  newlib arena stats, omitting min-ever-free and largest-free-block rather than
  substituting numbers that mean something different.
- The vendored PsychicMqttClient (ESP-IDF esp-mqtt) was pulled in by the LDF on
  nRF52; nrf52_base now lib_ignores it, matching how RP2040 variants ignore BLE.
- JWTHelper.cpp and MQTTMessageBuilder.cpp are excluded in arduino_base, but 22
  variants re-glob helpers/*.cpp after inheriting it, which undoes the exclusion.
  Guarding the file contents on WITH_MQTT_BRIDGE is robust against any variant's
  filter, and matches helpers/esp32/WebConfigServer.cpp.

Verified: RAK4631 repeater + room server, Heltec T114, T1000-E, Wio WM1110,
Xiao nRF52 and ThinkNode M1 all build. ESP32 observer builds are byte-identical
to before (RAM and flash), and the native suite stays at 267/267.

RP2040 still fails separately: four boards declare the pre-force_ap
startOTAUpdate signature. Not addressed here.
2026-08-03 11:27:36 -07:00
agessaman 126a2564ed Merge remote-tracking branch 'upstream/dev' into observer-firmware-dev 2026-08-03 11:02:13 -07:00
agessaman 716f54d4d8 docs(handoff): scope the neighbors pool bug to the dev channel
The starvation needs ArduinoJson v7's fixed 4096-byte pool blocks plus dev's
custom budget-capped allocator. Production is still on v6 (MQTTMessageBuilder
uses createNestedArray, removed in 7.0), where DynamicJsonDocument(10240) is a
real compact slot pool needing ~3.8 KB for 50 entries, so prod is unaffected
and needs no hand-port.

Also notes that prod pins no ArduinoJson version at all.
2026-08-03 10:58:31 -07:00
agessaman 28e586f027 merge: non-PSRAM neighbors support into observer-firmware-dev
Enables neighbors publication on the ESP32-S3 non-PSRAM observer envs via a
per-variant MQTT_NEIGHBORS_WITHOUT_PSRAM opt-in, and fixes a pre-existing JSON
pool-budget bug that silently dropped the publish on PSRAM boards with roughly
40+ neighbours.

Bench-verified 2026-08-03 at the 2-wss-slot non-PSRAM maximum.
2026-08-03 10:55:41 -07:00
agessaman 46ee60da90 docs(handoff): record non-PSRAM neighbors hardware verification
Bench run 2026-08-03 on a non-PSRAM ESP32-S3 observer at the 2-wss-slot
non-PSRAM maximum: periodic publish succeeded, min-ever free internal heap
53776 B, payload 1252 B of the 4096 B buffer.

Also records the pre-existing PSRAM pool-budget bug found while verifying,
and the two scenarios still untested on hardware: the >20-neighbour
truncation path, and a publish coinciding with a slot reconnect.
2026-08-03 10:54:43 -07:00
agessaman a3a0a94dc4 feat(mqtt-neighbors): support non-PSRAM observer boards
Neighbors publication was gated on BOARD_HAS_PSRAM. Removing that gate alone
was not enough: the feature built but was inert without PSRAM, because three
allocation sites asked for MALLOC_CAP_SPIRAM (which returns null with no
PSRAM), the bridge's persistent buffer was allocated inside a BOARD_HAS_PSRAM
block, and neighborDiscoverReady() rejected every pass at runtime on
psramFound(). The entry table also did not fit: finishNeighborDiscover put
pubkey_hex[50][65] plus entries[50] on the stack, a 4752-byte frame against
the mesh loop task's 8 KB.

- Gate on MAX_NEIGHBOURS plus PSRAM or an explicit per-variant
  MQTT_NEIGHBORS_WITHOUT_PSRAM opt-in.
- Move the entry table and its hex strings into one heap block sized to the
  pass; the frame drops from 4752 to 304 bytes.
- Prefer PSRAM and fall back to internal DRAM in the mesh-side allocations
  and the ArduinoJson pool; hoist the bridge's persistent buffer out of the
  BOARD_HAS_PSRAM block (psram_malloc already falls back).
- Keep the runtime psramFound() check only where the buffers are sized for
  PSRAM, so a board whose PSRAM failed to init still refuses.
- Size for internal DRAM without PSRAM: 4 KB text buffer and 20 entries per
  publish, keeping the pool to a single block and the peak near 13 KB rather
  than ~35 KB. Oversized tables truncate and report total_neighbors as before.

Enabled on the ESP32-S3 observer envs (Heltec V3/WSL3, RAK3112, Heltec
Tracker v1.1/v2). Left off for the classic ESP32 T-LoRa V2.1-1.6, which is
already limited to one active TLS slot.

Costs ~7.4 KB static DRAM on repeaters and ~9.6 KB on room servers. The
prefs layout is unchanged, so this is neutral for existing devices.
2026-08-03 10:29:54 -07:00
agessaman 34037f202d fix(mqtt-neighbors): budget the JSON pool separately from the publish buffer
ArduinoJson v7 hands out document-pool blocks in fixed 4096-byte chunks, so
the pool is not bounded by the size of the text it serialises to. Budgeting
it at NEIGHBORS_JSON_BUFFER_SIZE starved it once the table grew: a 50-entry
table needs 12541 B of pool against the 10240 B cap, and a starved allocator
sets doc.overflowed(), which makes buildNeighborsMessage return 0 and drop
the entire publish rather than truncating the tail.

Repeaters with roughly 40 or more neighbours therefore published no neighbors
message at all, silently, while smaller tables published normally.

Give the pool its own NEIGHBORS_DOC_POOL_BUDGET and add an explicit
NEIGHBORS_MAX_PUBLISH_ENTRIES cap alongside the existing text-size check.
2026-08-03 10:29:32 -07:00
Huw Duddy 9d902e634a Merge pull request #3076 from MDamon/fix/lr1110-rx-timeout
LR1110: fix startReceive() passing an IRQ bit as the RX timeout 🤖🤖
2026-08-03 23:02:52 +10:00
Huw Duddy 5d940a1dc9 Clean up comments in startReceive method
Removed unnecessary comments regarding RX timeout and IRQ mask.
2026-08-03 22:57:34 +10:00
Liam Cottle d6ee3a17f6 Merge pull request #3098 from jirogit/fix/unit-c6l-flash-mode-dio
fix: M5Stack Unit C6L boot failure caused by flash_mode=qio
2026-08-03 19:45:38 +12:00
ripplebiz 626a82fd30 Merge pull request #2824 from NickDunklee/rak-advert-hw-encryption
feat: use nrf52 hardware crypto where we can
2026-08-02 15:35:33 +10:00
me ae1b610a94 fix: M5Stack Unit C6L merged.bin fails to boot (flash_mode qio->dio)
Board manifest for esp32-c6-devkitm-1 defaults build.flash_mode to qio,
which this module's flash chip does not support -- causes a boot
crash-loop (repeated USB-Serial-JTAG reconnects) on real hardware.
Override with board_build.flash_mode = dio in the common M5Stack_Unit_C6L
section so it applies to all envs (ble/usb/repeater/room_server).
2026-08-01 22:20:20 -07:00
agessaman 37444be7b5 feat(thinknode-m7): add repeater and room server observer variants
Adds ThinkNode_M7_repeater_observer_mqtt and
ThinkNode_M7_room_server_observer_mqtt, following the Station G3 observer
overlay: adafruit-full cert bundle, MQTT bridge + SNMP, pinned observer
lib_deps, and the quieter default logging profile.

WiFi-only for now. The M7 has an onboard CH390 Ethernet controller (used by
ThinkNode_M7_companion_radio_ethernet, and an lwIP netif so the MQTT data path
would work over it), but the bridge's link management is bound to the WiFi
station API, so Ethernet cannot carry MQTT yet.

The board has PSRAM, so MAX_NEIGHBOURS=50 enables WITH_MQTT_NEIGHBORS —
verified present in both images. Builds use 46.5% of the 3.19 MB app slot at
13.7% RAM, and build.sh emits the full artifact set (.bin, -merged.bin,
.partsig). The partition table is inherited from [ThinkNode_M7] unchanged, so
no merged first flash is needed; its signature is byte-identical to the T-Beam
Supreme observer builds (both default_8MB.csv).

Also fixes two pre-existing build failures on this board:

- [ThinkNode_M7] re-added a blanket helpers/*.cpp after arduino_base excludes
  the MQTT-only sources, so every M7 env failed on a missing Timezone.h. The
  glob was otherwise fully redundant with the base, so it is dropped rather
  than re-excluding the two files.
- ThinkNode_M7_companion_radio_ethernet sets DISPLAY_CLASS=NullDisplayDriver
  but never compiled NullDisplayDriver.cpp, which defines UIColor::window_bkg,
  so it failed at link. The ble and wifi envs both already list it.

All nine M7 envs now build. Observer env discovery picks up both new envs, and
the ArduinoJson pin check covers both new sections.
2026-07-31 09:34:42 -07:00
agessaman 5828a3c563 fix(mqtt-neighbors): report unusable heard ages as null
A neighbour heard before the clock is set carries the firmware's unset-clock
default (1715770351, 15 May 2024). Subtracting that from an NTP-synced clock
published ages of ~806 days for neighbours that had just answered a live scope
query, and a backwards clock step reported 0, i.e. "heard just now".

- finishNeighborDiscover() reports the age as unknown ("heard_secs_ago": null)
  when the stored stamp and the current clock come from different epochs, or
  when the clock has stepped backwards
- handleNeighborDiscoverResponse() re-stamps heard_timestamp on a zero-hop scope
  reply, in both the snapshot and the live table, so entries heal once per
  discovery cycle instead of waiting for the neighbour's next advert
- publish ordering places usable ages ahead of unknown ones so a poisoned stamp
  cannot displace fresh entries when the JSON buffer truncates
- document the null case, and the always-present total_neighbors /
  queried_neighbors / truncated fields the payload sample omitted
- add UPSTREAM_BUGS.md, tracking the monotonic-uptime fix to propose upstream
  plus the unclamped subtraction in the companion and CLI readouts

Containment only: upstream still stamps neighbours from the wall clock at
packet-reception time, which on a cold boot always precedes NTP.
2026-07-31 08:54:39 -07:00
agessaman d8fd3defc4 fix(xiao_s3_wio): restore environment sensor support
The [Xiao_S3_WIO] base block lost its sensor wiring when upstream
3dd6dc02 ("xiao_s3: use environment sensor manager and add sensor
role") was resolved to our side in a later merge. Only the .ini half
was dropped -- target.h/target.cpp kept the EnvironmentSensorManager,
so builds still compiled helpers/sensors with an empty SENSOR_TABLE:
no ENV_INCLUDE_* macros meant the table held only its sentinel, so
begin() scanned the I2C bus and initialized nothing and querySensors()
emitted nothing above channel 1.

Reported as an INA226 missing from channel 2 on a MQTT Observer build,
working on stock firmware. Affected every Xiao_S3_WIO env, including
the dedicated Xiao_S3_WIO_sensor role.

Restores sensor_base build_flags/lib_deps, -UENV_INCLUDE_GPS and the
PIN_BOARD_SDA/SCL defines, making the base block identical to upstream
again. Also picks up the commented rs232 pin relocation from the same
upstream commit, since 5,6 is now the I2C bus.

Flash on Xiao_S3_WIO_repeater_observer_mqtt: 42.7% -> 44.3%.
2026-07-30 21:13:50 -07:00
agessaman d502bbaf5b chore(scripts): remove compiled Python cache file for webconfig_mock_server 2026-07-30 15:36:10 -07:00
agessaman fe3b5f8a0f feat(station-g3): add repeater and room server observer variants
Adds Station_G3_ESP32_repeater_observer_mqtt and
Station_G3_ESP32_room_server_observer_mqtt, mirroring the known-good
Station G2 observer envs. The two boards are the same family — ESP32-S3,
qio_opi, PSRAM, 16 MB flash, SH1106 display — so the overlay ports across
unchanged: default_16MB.csv partitions, adafruit-full cert bundle,
MQTT bridge + SNMP, and the same lib_deps pinning.

Verified the G3 partition signature is byte-identical to the G2 observer's,
so the OTA partition-compatibility gate treats them the same. Both envs
build clean (1.67 MB of the 6.25 MB app slot, 28% RAM) and produce the full
CI artifact set via build.sh: .bin, -merged.bin and .partsig. Observer env
discovery now finds 32 envs (was 30) and the ArduinoJson pin check covers
both new sections.

Docs: added the G3 build commands and the two partition-table rows to
MQTT_IMPLEMENTATION.md.
2026-07-30 15:21:20 -07:00
agessaman 4b390dfcec merge: pick up .gitignore pycache rule from observer-firmware-dev 2026-07-30 15:07:43 -07:00
agessaman 69ec2866c5 chore(.gitignore): ignore Python cache files in scripts directory 2026-07-30 15:01:31 -07:00
agessaman 612c52132c merge: upstream/dev into observer-firmware-dev (2026-07-30, db232808)
Absorbs 106 upstream commits. Seven files conflicted; the substantive one
was upstream's new JSON ConfigSerializer (PR #2982), which replaces the
binary /com_prefs layout with /prefs.json and makes NodePrefs a
ConfigSerializer subclass.

Prefs migration
- Adopt upstream's ConfigSerializer. writeCommonPrefsImage() and its
  documented offsets (0-294) are deleted, along with the now-unreachable
  saveCommonPrefsImageAtomically()/CommonPrefsFileStore atomic rename path.
- Load order is /prefs.json, then /com_prefs, then /node_prefs. Upstream
  dropped the /node_prefs fallback; it is restored here so devices that
  never advanced past that filename keep their config.
- Legacy files are never removed, so migration cannot destroy its own
  source and a deferred or failed save simply retries next boot.
- /com_prefs is treated as a format migration only, not an "upgrade", so
  it does not trip the bridge.source tx->rx flip on existing nodes.
- The MQTTPrefsAtomicStore legacy gate is retained: the observer tail
  recovered from an old-format file still commits to /mqtt_prefs before
  /prefs.json is written.
- MQTTPrefs and /mqtt_prefs are untouched; savePrefs keeps its save_mqtt
  parameter and now returns upstream's bool.

Fixes to upstream code
- RadioPrefs::structure() bound both "rxgain" and "fem_rxgain" to
  rx_boosted_gain, so radio_fem_rxgain was never persisted. Bound to the
  correct field.
- discovery_mod_timestamp was dropped from structure(); it gates
  'since'-filtered DISCOVER replies and is set on every config change, so
  losing it would silently stop discovery responses after a reboot. Added
  as "disc_mod".

Merge artifacts repaired
- Restored bblanchon/ArduinoJson to the native test env; a clean but wrong
  auto-merge at the lib_deps block boundary dropped it and broke all 19
  host test suites.
- Migrated the fork's WebConfig UITask screens off the removed
  DisplayDriver::Color enum to upstream's UIColor element types.
- Removed duplicate getCADEnabled() definitions in companion MyMesh.cpp
  and simple_sensor SensorMesh.cpp that both sides had added.
- Dropped memset(&_prefs, 0, ...) in the four example meshes; NodePrefs now
  has a vtable. guard gains an initializer that memset used to provide.

Other resolutions
- simple_room_server keeps both the fork's discover.* commands and
  upstream's new room.post.
- docs/payloads.md taken from upstream, undoing content earlier merges had
  reverted (Control data section, split login tables).

Verified: 273/273 host tests pass across native and native_kiss_modem;
Heltec v3 repeater, repeater_observer_mqtt, room_server_observer_mqtt,
sensor, and companion_radio_ble all build clean.
2026-07-30 14:56:23 -07:00
agessaman dd7d13497b docs: trim MQTT guide redundancy and split out internals
Port the observer doc cleanup from observer-firmware (4beb5472) onto dev,
keeping dev-specific content intact.

- move internal mechanics into MQTT_INTERNALS.md: deferred construction,
  runtime slot memory, backoff/circuit breaker, message building, command
  namespacing, and the legacy prefs key mapping
- drop the duplicated First-Time Setup, Command Architecture, and SNMP
  Monitoring sections, folding their unique steps into Quick Start
- condense the partition/NVS prose and merge the five custom-broker
  examples into one Custom Brokers section
- promote the preset list to a top-level Broker Presets section with an
  Extra setup column, and document the presets the table was missing:
  meshcore-fi, corecomms, mesh-chaun14, wcmesh, and meshtexas
- fix the coloradomesh port (443, not 1883)
- point flasher and changelog links at observer.gessaman.com
- restore the nbr: status field, which the code still emits, and correct
  the neighbors topic to QoS 0 retained per allow_retain

Dev-specific content is preserved as-is: per-slot packet filters, the Web
Configuration Portal, local testing without hardware, MeshRank's raw
exclusion, and neighbors default_scope.
2026-07-30 12:06:18 -07:00
Mike Damon 78723d2565 LR1110: fix startReceive() passing an IRQ bit as the RX timeout
CustomLR1110::startReceive() passed RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED
(1<<4 = 16) as RadioLib's first argument, which is the RX *timeout*, not an
IRQ mask. At the LR11x0's 30.52us tick that armed the receiver for ~488us, so
it dropped out of RX before any packet could arrive and the node received
nothing at all -- while transmitting normally.

Symptoms on a SenseCAP T1000-E: tx_air_secs rising, rx_air_secs stuck at 0,
recv_errors 0, and the noise floor pinned at the -120 clamp because
getCurrentRSSI() never sampled a live receiver.

Pass RADIOLIB_LR11X0_RX_TIMEOUT_INF (continuous RX), which is what
LR11x0::startReceive() itself uses, keeping the PREAMBLE_DETECTED flag in the
reported IRQ flags as intended.

Introduced in ea5d7c8b ("LR1110: add PREAMBLE_DETECTED to reported irq flags").
Verified on two T1000-E units: with only the repeater fixed it began receiving
(last_rssi -29, SNR 17.0) while the unfixed companion stayed deaf; fixing both
brought up the link in each direction.
2026-07-30 12:14:39 -04:00
ripplebiz db232808aa Merge pull request #2688 from Che177/feature/room-server-system-posts
room_server: add room.post command for server-originated posts
2026-07-30 13:08:18 +10:00
ripplebiz 57ddada3ba Merge pull request #3004 from axhoff/agent/preserve-utf8-advert-names
Preserve UTF-8 boundaries in advert names
2026-07-30 12:59:59 +10:00
ripplebiz b797ca198e Merge pull request #3060 from entr0p1/fix/mesh-debug-active
Clean up debugs left on in platform.ini files
2026-07-30 12:35:22 +10:00
agessaman 616fe96d1e feat(mqtt): publish all message types except raw to MeshRank
MeshRank slots previously took packets only. The broker tolerates status and
neighbors (and its maintainer intends to look at using the neighbors data), so
those now publish under meshrank/uplink/{token}/{device}/{type}, using the same
type suffixes as the MeshCore layout. Raw stays excluded: it is the
highest-volume topic and the broker does not consume it, so `set mqtt.raw on`
has no effect on a MeshRank slot.

All MeshRank gating funnels through the topic router, so relaxing that single
guard was sufficient - publishStatusToSlot, publishStatus, publishRaw,
publishNeighbors, and eligiblePacketSlots already skip slots that cannot form a
topic. A per-slot token is still required. Because eligiblePacketSlots resolves
topic support before serialising, raw JSON is never built for a MeshRank slot
rather than built and discarded.

observer-firmware sends raw to MeshRank; this supersedes that decision, so raw
must stay excluded when the branches merge. MeshRankTakesEveryTypeExceptRaw
fails if a merge re-enables it.
2026-07-29 15:51:28 -07:00
agessaman 8b16af3830 feat(mqtt): add default_scope to neighbor discovery JSON handling
Enhance the neighbor discovery JSON structure by introducing a
default_scope field, which indicates the region name this node
floods to by default. This change improves clarity in the
neighbor discovery process and aligns with the unscoped flood
behavior when no default region is set. Updates include
modifications to the MyMesh class and related message building
functions to accommodate the new field.
2026-07-29 15:00:32 -07:00
ripplebiz 6e39cff8a1 Merge pull request #3063 from oltaco/unify-irq-timeout
Unify IRQ timeout logic across all applicable radio types
2026-07-29 23:52:48 +10:00
ripplebiz 279ac78122 Merge pull request #3049 from liamcottle/feature/ethernet
Refactor Companion Interfaces + Add ThinkNode M7 Ethernet Support
2026-07-29 23:45:51 +10:00
taco 79eb7f5d8d LLCC68: add IRQ timeout logic 2026-07-29 23:34:01 +10:00
taco a3732e1c65 SX1268: add IRQ timeout logic 2026-07-29 23:34:01 +10:00
taco a5c323cc19 STM32WLx: add IRQ timeout logic 2026-07-29 23:33:51 +10:00
taco a7426de0bf LR1110: fix unnecessary IRQ clear 2026-07-29 23:18:15 +10:00
ripplebiz 9f73fbf870 Merge pull request #3062 from oltaco/fix-irq-clear
Fix unnecessary IRQ clearing
2026-07-29 22:37:30 +10:00
taco 20f55a4f42 fix unnecessary IRQ clear 2026-07-29 21:39:56 +10:00
entr0p1 d7f378b489 Clean up debugs left on in platform.ini files 2026-07-29 18:27:15 +10:00
Che177 5a04e060a5 room_server: use standard mesh debug logging 2026-07-28 21:57:42 -07:00
Adam Gessaman 971a3b1464 Merge pull request #38 from agessaman/feat/packet-filters
Enhance MQTT slot filters with named types and downgrade support
2026-07-28 09:10:46 -07:00
agessaman ecbb5005e9 feat(mqtt): implement downgrade contract for MQTT preferences
Enhance the MQTT preferences handling by establishing a downgrade
contract that ensures compatibility between different firmware versions.
This contract allows nodes to read settings from newer builds while
safeguarding against data loss during downgrades. The implementation
includes updates to the classification logic, ensuring that longer
payloads from newer versions are handled correctly without rejecting
files, thus preserving critical WiFi credentials and broker settings.
2026-07-28 09:03:19 -07:00