Repository navigation
Conversation
Companion and repeater firmware share /prefs.json, so a repeater's forwarding setting (repeat.disable = 0) carries over when a device is reflashed to companion. The client-repeat frequency allowlist was only checked in CMD_SET_RADIO_PARAMS, so the companion repeated at whatever frequency it booted on. Apply the allowlist when deciding to forward, and report the same effective value in the device-info frame. Check the frequency last applied to the radio rather than _prefs.freq, because CLI "set radio" stores new params without retuning until reboot. The stored flag is left alone, so a later prefs save can't flip a repeater's forwarding off when the device is flashed back.
…ePrefs The observer stack only worked inside CommonCLI hosts: /mqtt.json load/save lived on CommonCLI, the observer CLI was a set of CommonCLI members, and MQTTBridge read the repeater NodePrefs directly. A companion build has its own NodePrefs class of the same name, so it could host none of it. - ObserverConfig owns MQTTPrefs, /mqtt.json load/recovery/atomic save (moved verbatim from CommonCLI.cpp) and the observer CLI (CommonCLI_Observer.cpp -> ObserverCLI.cpp). Host hooks go through ObserverCallbacks; CommonCLI keeps its public API and forwards via a nested adapter. - MQTTBridge takes an MQTTBridgeHost (node name, radio params, forwarding, role) instead of NodePrefs; repeater and room server implement it. - Status messages gain an additive "role" field (repeater / room_server) so brokers can tell observer hosts apart. client_version is unchanged. No change to the /mqtt.json format or recovery behavior.
A companion build can now also run the MQTT observer, so one node serves the app over WiFi/TCP and uplinks heard packets to MQTT brokers (#77). - CompanionObserver wraps ObserverConfig and MQTTBridge behind a header that includes neither, keeping the repeater NodePrefs out of companion code. - /mqtt.json and the identity are shared with the repeater observer, so a node reflashed between the two roles keeps its MQTT/WiFi setup. A stored companion WiFi SSID is adopted into /mqtt.json once if it has none. - The observer network link owns WiFi; the app's TCP listener (port 5000) opens once the link has an address. - Observer commands (mqtt*, wifi.ssid/pwd, timezone, ...) are served by the companion CLI: USB serial console, the app's CLI command, and remote admin. - Status messages report role "companion"; OLED shows MQTT slots up. - New envs heltec_v4_companion_observer_wifi and Heltec_v3_companion_observer_wifi (not *_observer_mqtt, so release CI skips them for now). V3 has no PSRAM: 150 contacts, 32-frame offline queue, one broker slot (new MQTT_MAX_ACTIVE_SLOTS_NO_PSRAM override).
…een roles Covers configuration surfaces, what carries over when reflashing between the companion and repeater observer (/mqtt.json, identity, name, radio) and what does not (repeater-only /prefs.json keys, including the admin password), the shared repeat.disable setting with opposite defaults, and V3 limits.
The board from #77. PSRAM, so it keeps the normal companion limits.
…D edge cases - Echoed config in "unknown config"/"??" replies and the "set radio" copy were unbounded; long CLI lines (160-byte serial buffer, app CLI frames) overflowed the reply or a 132-byte stack buffer. Affects repeaters too. - The OLED polled getSlotStatusSnapshot(), which reads a slot's client the MQTT task may delete. New getSlotCounts() reads only the slot flags. - Pass the caller's sender_timestamp to the observer CLI so remote admin gets secrets masked, as on the repeater. - Restart the bridge after a private key import so the device ID and JWT username follow the new identity. - Do not adopt a 32-character companion SSID into /mqtt.json (31 max); a truncated SSID would join nothing.
The v1_<pubkey> username was cached for the bridge's lifetime, so after a companion private key import the CONNECT username kept the old key while tokens were signed by the new one. setDeviceID() now clears it on change.
…bserver Same output format as the repeater's memory reply, so heap tooling and habits carry over; it was missing because it lives in CommonCLI.
On a Heltec V4.2 with five brokers, internal heap fell to 29 KB free with a 14 KB largest block: the companion's contact table, offline queue and frame buffers (~120 KB) sat in internal DRAM next to WiFi and the MQTT slots. PSRAM is initialized at boot on this framework, so allocate the_mesh there (zeroed, as a static object would be) and keep a reference. Static internal RAM drops from 177 KB to 54 KB. Falls back to internal heap when no PSRAM is fitted. Only ESP32 PSRAM boards with WITH_MQTT_BRIDGE; stock companion builds are unchanged.
Both are fork additions that lived inline in the upstream-tracked CommonCLI.cpp, so the companion could not use them. NodeDiagCLI holds them for every host; CommonCLI delegates with one call (adapter over CommonCLICallbacks) and the companion radio implements NodeDiagHost in all builds. Output formats and the local-only rule for stats-radio-diag are unchanged. Replaces the interim memory copy in CompanionObserver.
…atic init The V4 (qio_qspi) framework config does not initialize PSRAM at boot; Arduino's psramInit() runs after static constructors, so the static-init PSRAM allocation silently fell back to internal heap and freed nothing. Construct the mesh at the start of setup() behind a pointer, with the_mesh as a macro over it. Measured on a Heltec V4.2 with five brokers: internal heap 36.8 KB free / 25.6 KB largest block before, 159.7 KB / 135 KB after.
Measured on hardware with the app connected and two TLS slots up: 51 KB internal heap free, 34.8 KB largest block, 36 KB minimum since boot, which leaves room for a TLS reconnect. One slot left 114 KB free. Contacts (150) and offline queue (32) stay trimmed.
…/companion-observer
The companion observer had its own start, restart and late-ack resume logic. It now uses the sequencer the repeater and room server share, with a disabled self-heal platform so a saved mqtt.selfheal setting can never reboot it.
…ver envs The repeater observer envs on these boards use adafruit-full, so a custom TLS broker that verified as a repeater could fail after a flash to the companion.
The network link brings WiFi up after setup(), so observer builds start the responder on the first link-up instead of in setup().
With time fixed at zero the driver could not have acted either way.
…/companion-observer
Push a compobs-alpha-* tag to build the *_companion_observer_wifi envs and publish them as a GitHub prerelease. No flasher manifests or OTA channel: companion observers refuse `ota`. The observer workflows still skip these envs, which do not match *observer_mqtt.
Same as heltec_v4_companion_observer_wifi plus the kit's sensor I2C bus (ENV_PIN_SDA=4, ENV_PIN_SCL=3), matching the expansion kit repeater envs.
…t repeat is active
Cherry-picked from fix/companion-mdns-rename (f60aa6085), keeping the observer's link-up mDNS start.
Setting the hostname sends a goodbye and re-announces every record, so a rename that only changes characters stripped from the hostname made the service briefly disappear for browsers. Update only the node-name TXT record in that case.
…not retry Arduino-ESP32 reconnects by itself only for a fixed list of disconnect reasons. After any other one, such as the vendor code 220 seen on a Meraki network, the station sat idle until the first 15 s rung of the reconnect ladder. Make one reconnect attempt 2 s after such a drop, once per outage; the ladder still handles every later attempt.
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.
Draft. Adds a companion radio firmware that also runs the MQTT observer, for #77. A node can be flashed between the repeater observer and the companion observer and keep its MQTT configuration and identity.
What changes
New role
heltec_v4_companion_observer_wifi,heltec_v4_expansionkit_companion_observer_wifi(adds the expansion kit's sensor I2C bus),Heltec_v3_companion_observer_wifi,Xiao_S3_WIO_companion_observer_wifi,Waveshare_S3_LR1121_companion_observer_wifi. They are not named*_observer_mqtt, so the release workflows do not build them.build-companion-observer-alpha.ymlbuilds only these envs when acompobs-alpha-*tag is pushed and publishes them as a GitHub prerelease, with no flasher manifests or OTA channel./mqtt.jsonand/identity/_mainas the repeater observer. With no WiFi SSID in/mqtt.jsonit adopts the companion's own WiFi credentials once.get/set mqtt.*,wifi.*,memory, diagnostics) is reachable from USB serial, the app's CLI command and remote admin.rolefield (repeater,room_server,companion) so brokers can tell the roles apart.client_versionis unchanged.Decoupling from the repeater
CommonCLIintoObserverConfig/ObserverCLI.cpp(renamed fromCommonCLI_Observer.cpp), behind anObserverCallbacksseam.MQTTBridgereads node name, radio parameters, forwarding state and role throughMQTTBridgeHostinstead of the repeater'sNodePrefs. The repeater and companion each have aNodePrefswith virtuals, so linking both was an ODR clash.memoryandstats-radio-diagmoved into a sharedNodeDiagCLI.CompanionObserverdrives the bridge throughObserverBridgeControl, the same start / restart / late-stop-ack sequencer the repeater and room server use, with a self-heal platform that is compiled out.Companion specifics
set mqtt.selfhealreturns an error and no reboot driver runs, because a phone may be attached. The saved value is left alone for a later repeater flash.ota check,ota updateand the upload portal are not supported in this version.setup(). On the Heltec V4 with five brokers that took free internal heap from about 37 KB to about 160 KB._meshcore._tcp). The network link brings WiFi up aftersetup(), so observer builds start the responder on the first link-up and retry a failed start on the next one. Plain companion builds are unchanged.adafruit-full), matching the repeater observer envs on those boards.Shared fixes found on the way
Behavior to be aware of
/prefs.jsonwith their own schema, and the upstream serializer drops keys it does not know. A companion settings save therefore resets repeater-only fields, including the repeater admin password, after a flash back. This matches upstream and is documented inMQTT_IMPLEMENTATION.md; it is not changed here.set(for examplemqtt.iata) restarts the bridge synchronously, about 5 to 6 s per slot, and the app link and mesh loop stall for that time. The repeater behaves the same way.rolefield.Testing
observer-firmware-devat34e658e20). New:ObserverBridgeControlwith the self-heal driver unsupported, on a moving clock (it fails if the platform is flipped to supported), androlebeside the widest crash and self-heal status fields.heltec_v4_companion_radio_wifi,Heltec_v3_repeater_observer_mqtt,heltec_v4_repeater_observer_mqtt,Heltec_v3_room_server_observer_mqtt.meshcore_<name>._meshcore._tcp.local.:5000after boot and again after a bridge restart. App TCP port 5000 accepted a connection.mqtt.selfhealvalue unchanged.observer-firmware-devand of theObserverBridgeControladoption; the findings (mDNS start latch, a test that could not fail) are fixed in the last two commits.Not tested
/bl/*files and logsfopen(/spiffs/contacts3) failed, so contact persistence was never validated there.Addresses #77.