# MQTT Observer Firmware Observer firmware turns a MeshCore repeater or room server into an uplink that publishes the packets it hears to up to six MQTT brokers. ## Quick Start Guide You need the device, WiFi credentials, and a console: USB serial at 115200 baud, or a repeater admin login from the companion app. **1. Flash.** Use the [MeshCore Observer Flasher](https://observer.gessaman.com/): pick **MQTT Observer Firmware** and your device, then flash from Chrome or Edge. To build it yourself, see [Build Configuration](#build-configuration). **2. Set the radio** on a fresh flash. These must match the rest of your mesh: ```bash set radio 910.525,62.5,7,5 # ,,, set tx 22 ``` **3. Set the identity:** ```bash set name MyObserver set mqtt.iata SEA set prv.key <64_hex_chars> # optional: keep the identity of a node you are replacing ``` **4. Set WiFi.** The value is the rest of the line; do not add quotes. ```bash set wifi.ssid YourWiFiNetwork set wifi.pwd YourWiFiPassword ``` **5. Optional settings:** ```bash set mqtt3.preset meshmapper # add a broker (slots 1 and 2 default to Let's Mesh US and EU) set timezone America/New_York # published timestamps stay UTC either way set repeat off # receive-only observer ``` **6. Reboot and verify:** ```bash reboot get link.status get mqtt.status ``` The node joins WiFi, connects to each configured broker, and starts publishing. Its MQTT origin is the node name. ## Broker Presets Each of the six slots holds one preset: ```bash set mqtt3.preset meshmapper set mqtt3.preset none # disable the slot ``` Broker address, transport, and credentials ship in the firmware. The **Extra setup** column lists the presets that need more. Every preset except `meshrank` uses the `meshcore/{iata}/…` topic layout, so `mqtt.iata` must be set. `get mqtt.presets` lists what the running firmware ships. The table matches the current build. | Preset | Broker | Auth | Extra setup | |--------|--------|------|-------------| | `analyzer-us` | `wss://mqtt-us-v1.letsmesh.net:443/mqtt` | JWT | default slot 1 | | `analyzer-eu` | `wss://mqtt-eu-v1.letsmesh.net:443/mqtt` | JWT | default slot 2 | | `nz-analyzer` | `wss://meshcore-mqtt-1.baird.io:443` | JWT | | | `meshmapper` | `wss://mqtt.meshmapper.net:443/mqtt` | JWT | | | `meshrank` | `mqtts://meshrank.net:8883` | token in topic | `set mqttN.token ` | | `waev` | `wss://mqtt.waev.app:443/mqtt` | JWT | | | `meshomatic` | `wss://us-east.meshomatic.net:443/mqtt` | JWT | | | `cascadiamesh` | `wss://mqtt-v1.cascadiamesh.org:443/mqtt` | JWT | | | `tennmesh` | `mqtt://mqtt.tennmesh.com:1883` | user/pass (built in) | | | `nashmesh` | `mqtt://mqtt.nashme.sh:1883` | user/pass (built in) | | | `ctmesh` | `mqtt://mqtt.ctmesh.org:1883` | user/pass (built in) | | | `chimesh` | `wss://mqtt.chimesh.org:443` | JWT | | | `meshat.se` | `wss://meshcore-mqtt.meshat.se:443` | JWT | | | `eastidahomesh` | `mqtt://live.eastidahomesh.com:1883` | none | | | `coloradomesh` | `wss://mqtt.meshcore.coloradomesh.org:443` | JWT | | | `dutchmeshcore-1` | `wss://collector1.dutchmeshcore.nl:443/mqtt` | JWT | | | `dutchmeshcore-2` | `wss://collector2.dutchmeshcore.nl:443/mqtt` | JWT | | | `meshcore-ca-1` | `wss://mqtt1.meshcore.ca:443/mqtt` | JWT | | | `meshcore-ca-2` | `wss://mqtt2.meshcore.ca:443/mqtt` | JWT | | | `meshcore-fi` | `wss://mc-mqtt.meshcore.fi:443/` | JWT | | | `okimesh-1` | `wss://mqtt1.okimesh.org:9002/mqtt` | JWT | | | `okimesh-2` | `wss://mqtt2.okimesh.org:9002/mqtt` | JWT | | | `inwmesh` | `mqtts://scope.inwmesh.org:8883` | user/pass (per slot) | `set mqttN.username`, `set mqttN.password` | | `bostonmesh` | `wss://mqttmc01.bostonme.sh:443/mqtt` | JWT | | | `rflab` | `wss://mqtt.rflab.io:443` | JWT | | | `ipnt.uk` | `wss://mqtt.ipnt.uk:443` | JWT | | | `flmesh` | `wss://mcmqtt.jntconnections.com:443` | JWT | | | `corecomms` | `wss://mqtt.corecomms.net:443/mqtt` | JWT | | | `meshtexas` | `wss://mqtt.meshtexas.org:443/mqtt` | JWT | | | `mesh-chaun14` | `mqtt://mqtt.mesh.chaun14.fr:1884` | user/pass (username is the public key) | `set mqttN.password` | | `wcmesh` | `wss://mqtt.wcmesh.com:443` | JWT | | | `atvirastinklas` | `wss://mqtt-mc.atvirastinklas.lt:443` | JWT | | | `gomesh` | `wss://mqtt.gomesh.dev:443` | JWT | | | `idahomesh` | `wss://mqtt.idahomesh.org:443/mqtt` | JWT | | | `ntxmesh` | `wss://ntxmesh.dhovin.me:8883` | JWT | | | `bsmesh` | `wss://mqtt.bsmesh.de:8885` | JWT | | | `marwoj` | `mqtts://mqtt.marwoj.net:8883` | user/pass (built in) | | | `custom` | your broker | user/pass, or JWT when `mqttN.audience` is set | see [Custom Brokers](#custom-brokers) | | `none` | slot disabled | | | `wss://` is WebSocket over TLS, `mqtts://` is MQTT over TLS, and `mqtt://` is unencrypted. ### Slots and Memory Limits Fresh installs use `analyzer-us` in slot 1, `analyzer-eu` in slot 2, and `none` in 3-6. - **With PSRAM:** all six slots can be active. - **Without PSRAM:** at most two TLS slots (`wss://` or `mqtts://`); each needs about 40 KB of internal heap. Extra slots show as `(inactive)` in `get mqtt.status` and stay saved, so they activate if the settings move to a PSRAM board. - **Classic ESP32 without PSRAM** (Heltec V2): plan on one TLS slot. A second usually fails with `mbedtls_ssl_setup` / esp-tls `0x8017`. Set the other slot to `none`. **Neighbors publication** (`WITH_MQTT_NEIGHBORS`) is on for every PSRAM board, and for the ESP32-S3 boards without PSRAM that set `-D MQTT_NEIGHBORS_WITHOUT_PSRAM=1` (Heltec V3/WSL3, RAK3112, Heltec Tracker v1.1/v2). Those builds cap the table at 20 entries and spend about 7.4 KB of static DRAM (9.6 KB on room servers) plus up to 13 KB per publish, from the same heap TLS uses. Classic ESP32 builds leave it off. ## CLI Commands Commands work over serial and over a remote admin login unless marked *serial only*. ### MQTT Slots `N` is the slot number, 1-6. | Command | Purpose | |---------|---------| | `get/set mqttN.preset ` | Broker preset, `custom`, or `none` | | `get/set mqttN.server ` | Custom broker address | | `get/set mqttN.port <1-65535>` | Custom broker port (optional when the URL has a scheme) | | `get/set mqttN.username ` | For `custom` and per-slot presets such as `inwmesh` | | `get/set mqttN.password ` | Same; `get` shows the value on serial only | | `get/set mqttN.token ` | Per-slot token, e.g. MeshRank; `get` shows the value on serial only | | `get/set mqttN.topic