test with single radio - mqtt success at broker
This commit is contained in:
@@ -44,6 +44,7 @@ runs:
|
||||
# companion-wifi-v1.15.0
|
||||
# repeater-bridge-espnow-v1.15.0
|
||||
# observer-eastmesh-bridge-espnow-v2026.5.1
|
||||
# observer-eastmesh-bridge-mqtt-v2026.7.0
|
||||
# observer-eastmesh-v2026.5.1
|
||||
# with OFFICIAL_MESHCORE_VERSION=v1.15.0 configured as a GitHub variable.
|
||||
#
|
||||
@@ -85,6 +86,12 @@ runs:
|
||||
exit 1
|
||||
fi
|
||||
EASTMESH_VERSION="${BASH_REMATCH[1]}"
|
||||
elif [[ "$GIT_TAG_NAME" =~ ^observer-eastmesh-bridge-mqtt-(v[[:alnum:]._-]+)$ ]]; then
|
||||
if [[ -z "$STATIC_OFFICIAL_VERSION" ]]; then
|
||||
echo "OFFICIAL_MESHCORE_VERSION must be set for EastMesh release tags" >&2
|
||||
exit 1
|
||||
fi
|
||||
EASTMESH_VERSION="${BASH_REMATCH[1]}"
|
||||
elif [[ "$GIT_TAG_NAME" =~ ^companion-wifi-(v[[:alnum:]._-]+)$ ]]; then
|
||||
FIRMWARE_VERSION="${BASH_REMATCH[1]}"
|
||||
elif [[ "$GIT_TAG_NAME" =~ ^repeater-bridge-espnow-(v[[:alnum:]._-]+)$ ]]; then
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
name: EastMesh Build Observer MQTT Bridge Firmwares
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- "observer-eastmesh-bridge-mqtt-v*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
OFFICIAL_MESHCORE_VERSION: ${{ vars.OFFICIAL_MESHCORE_VERSION }}
|
||||
PLATFORMIO_BUILD_FLAGS: -UMQTT_DEBUG
|
||||
steps:
|
||||
- name: Clone Repo
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Build Environment
|
||||
uses: ./.github/actions/setup-build-environment
|
||||
|
||||
- name: Build Firmwares
|
||||
run: /usr/bin/env bash eastmesh-build.sh build-observer-mqtt-bridge-firmwares
|
||||
|
||||
- name: Upload Workflow Artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: observer-bridge-mqtt-firmwares
|
||||
path: out
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v3
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
name: Observer EastMesh Firmware with MQTT Bridge ${{ env.RELEASE_VERSION }}
|
||||
body: ""
|
||||
draft: true
|
||||
files: out/*
|
||||
@@ -172,6 +172,7 @@ Current tag formats:
|
||||
git tag companion-wifi-v1.15.0
|
||||
git tag repeater-bridge-espnow-v1.15.0
|
||||
git tag observer-eastmesh-bridge-espnow-v2026.5.1
|
||||
git tag observer-eastmesh-bridge-mqtt-v2026.7.0
|
||||
git tag observer-eastmesh-v2026.5.1
|
||||
```
|
||||
|
||||
@@ -180,8 +181,9 @@ Rules:
|
||||
- `companion-wifi` tags use the upstream MeshCore version directly
|
||||
- `repeater-bridge-espnow` tags use the upstream MeshCore version directly
|
||||
- `observer-eastmesh-bridge-espnow` tags use the EastMesh release version in the tag
|
||||
- `observer-eastmesh-bridge-mqtt` tags use the EastMesh release version in the tag
|
||||
- `observer-eastmesh` tags use the EastMesh release version in the tag
|
||||
- GitHub Actions variable `OFFICIAL_MESHCORE_VERSION` supplies the upstream base version for Observer EastMesh and Observer ESP-NOW EastMesh release builds
|
||||
- GitHub Actions variable `OFFICIAL_MESHCORE_VERSION` supplies the upstream base version for Observer EastMesh, Observer ESP-NOW EastMesh, and Observer MQTT Bridge EastMesh release builds
|
||||
- if the upstream MeshCore release version changes, update `OFFICIAL_MESHCORE_VERSION` in GitHub before cutting release tags
|
||||
|
||||
Typical release flow:
|
||||
|
||||
@@ -18,6 +18,8 @@ CoreScope (<https://core.eastmesh.au>) offers visibility into the network, inclu
|
||||
- native WiFi
|
||||
- MQTT over WSS with JWT auth
|
||||
- optional local HTTPS config panel on supported ESP32 targets
|
||||
- `*_repeater_observer_mqtt_bridge` firmware targets that add a **bidirectional MQTT mesh bridge** to a peer broker (separate from MQTT uplink)
|
||||
- `*_repeater_observer_espnow` firmware targets that add a local ESP-NOW mesh bridge
|
||||
- `*_companion_radio_wifi` firmware targets for WiFi-connected companion devices
|
||||
- EastMesh-specific release workflows and versioning on top of upstream MeshCore releases
|
||||
- docs and release guidance for EastMesh users instead of the full upstream MeshCore docs set
|
||||
@@ -127,6 +129,8 @@ uv run --group docs zensical build
|
||||
- shared EastMesh observer env definitions
|
||||
- [`examples/simple_repeater/MyMesh.cpp`](./examples/simple_repeater/MyMesh.cpp)
|
||||
- repeater CLI wiring, MQTT command surface, and web allowlist integration
|
||||
- [`src/helpers/bridges/MQTTBridge.cpp`](./src/helpers/bridges/MQTTBridge.cpp)
|
||||
- bidirectional MQTT mesh bridge (peer broker TCP, topic `meshcore/bridge/packets`)
|
||||
- [`src/helpers/mqtt/MQTTUplink.cpp`](./src/helpers/mqtt/MQTTUplink.cpp)
|
||||
- MQTT uplink implementation, HTTPS web panel, WSS/JWT handling, and repeater WiFi control
|
||||
- [`examples/companion_radio`](./examples/companion_radio)
|
||||
@@ -158,6 +162,121 @@ uv run --group docs zensical build
|
||||
- owner public key and email
|
||||
- local web panel enablement
|
||||
|
||||
### MQTT Mesh Bridge (Observer)
|
||||
|
||||
The `observer-eastmesh-bridge-mqtt` release track (`*_repeater_observer_mqtt_bridge`) bridges **raw mesh packets** between repeaters through a **peer MQTT broker you run** (for example Mosquitto on a LAN PC). This is **not** the same as MQTT uplink to EastMesh/MeshMapper:
|
||||
|
||||
| | MQTT uplink (observer) | MQTT mesh bridge |
|
||||
| --- | --- | --- |
|
||||
| Purpose | Publish JSON telemetry to curated brokers | Forward encrypted mesh packets between radios |
|
||||
| Brokers | `eastmesh-au`, `meshmapper`, custom WSS | Your peer broker (`host:port`, TCP) |
|
||||
| Topic | `meshcore/<iata>/...` (per IATA) | `meshcore/bridge/packets` (fixed) |
|
||||
| Default on bridge builds | Off by default (enable in web panel / CLI) | On when `bridge.enabled` is on |
|
||||
|
||||
**First supported target:** `Xiao_S3_WIO_repeater_observer_mqtt_bridge`
|
||||
|
||||
**Related track:** `observer-eastmesh-bridge-espnow` (`*_repeater_observer_espnow`) uses ESP-NOW instead of MQTT for local bridging.
|
||||
|
||||
Build example:
|
||||
|
||||
```bash
|
||||
uv run pio run -e Xiao_S3_WIO_repeater_observer_mqtt_bridge
|
||||
```
|
||||
|
||||
Flash (update):
|
||||
|
||||
```bash
|
||||
uv run pio run -e Xiao_S3_WIO_repeater_observer_mqtt_bridge -t upload --upload-port COM10
|
||||
```
|
||||
|
||||
After a **full flash erase**, flash the merged image at `0x0` instead of only `firmware.bin`:
|
||||
|
||||
```bash
|
||||
uv run pio run -e Xiao_S3_WIO_repeater_observer_mqtt_bridge -t mergebin
|
||||
uv run pio pkg exec -p tool-esptoolpy -- esptool.py --chip esp32s3 --port COM10 write_flash 0x0 .pio/build/Xiao_S3_WIO_repeater_observer_mqtt_bridge/firmware-merged.bin
|
||||
```
|
||||
|
||||
#### Peer Mosquitto broker (LAN)
|
||||
|
||||
Each bridge node connects to the **same** peer broker with the **same** credentials and `bridge.secret`.
|
||||
|
||||
1. Install [Mosquitto](https://mosquitto.org/download/) on a machine reachable from both repeaters (for example `192.168.1.145`).
|
||||
2. Edit `mosquitto.conf` (Windows service install: `C:\Program Files\Mosquitto\mosquitto.conf`) and add:
|
||||
|
||||
```conf
|
||||
listener 1883 0.0.0.0
|
||||
allow_anonymous false
|
||||
password_file C:\Program Files\Mosquitto\passwd
|
||||
```
|
||||
|
||||
For lab/testing only, `allow_anonymous true` works without a password file.
|
||||
|
||||
3. Create a user (admin CMD):
|
||||
|
||||
```cmd
|
||||
cd "C:\Program Files\Mosquitto"
|
||||
mosquitto_passwd -c passwd bridgeuser
|
||||
```
|
||||
|
||||
4. Restart the **service** (do not run a second `mosquitto -v` while the service owns port 1883):
|
||||
|
||||
```powershell
|
||||
Restart-Service mosquitto
|
||||
```
|
||||
|
||||
5. Confirm LAN listen and open the firewall:
|
||||
|
||||
```cmd
|
||||
netstat -ano | findstr ":1883"
|
||||
```
|
||||
|
||||
Expect `0.0.0.0:1883`, not only `127.0.0.1:1883`.
|
||||
|
||||
6. Test from another machine:
|
||||
|
||||
```cmd
|
||||
mosquitto_pub -h 192.168.1.145 -p 1883 -u bridgeuser -P your-password -t test -m hello
|
||||
mosquitto_sub -h 192.168.1.145 -p 1883 -u bridgeuser -P your-password -t meshcore/bridge/packets -v
|
||||
```
|
||||
|
||||
Binary garbage on `meshcore/bridge/packets` is normal — payloads are XOR-encrypted mesh frames, not text.
|
||||
|
||||
#### Repeater configuration
|
||||
|
||||
Configure **both** bridge nodes identically for broker access; use the same `bridge.secret` on every node in the bridge group.
|
||||
|
||||
Serial or web panel CLI:
|
||||
|
||||
```text
|
||||
set wifi.ssid YourNetwork
|
||||
set wifi.pwd YourWiFiPassword
|
||||
set bridge.peer.host 192.168.1.145
|
||||
set bridge.peer.port 1883
|
||||
set bridge.peer.username bridgeuser
|
||||
set bridge.peer.password your-password
|
||||
set bridge.secret your-shared-bridge-secret
|
||||
```
|
||||
|
||||
Web panel: **MQTT Settings** → **Mesh bridge peer MQTT** (`host:port`, username, password). The section appears when `get bridge.type` returns `mqtt`.
|
||||
|
||||
Useful checks:
|
||||
|
||||
```text
|
||||
get bridge.type
|
||||
get bridge.peer.host
|
||||
get bridge.enabled
|
||||
```
|
||||
|
||||
Default admin password on dev builds is usually `password` unless you changed it.
|
||||
|
||||
Packets use magic `0xC03E`, a Fletcher checksum, XOR encryption with `bridge.secret`, then publish/subscribe on `meshcore/bridge/packets`. Duplicate detection limits loops when both nodes see the same traffic.
|
||||
|
||||
More detail:
|
||||
|
||||
- [Custom CLI — MQTT bridge settings](./eastmesh-docs/custom-cli.md)
|
||||
- [Web panel — MQTT settings and bridge peer fields](./eastmesh-docs/web-panel.md)
|
||||
- [Releases — track comparison](./eastmesh-docs/releases.md)
|
||||
|
||||
### Local Web Panel
|
||||
|
||||
On supported `*_repeater_observer` ESP32 targets, the repeater can expose a local HTTPS config panel over WiFi.
|
||||
@@ -197,6 +316,7 @@ These rescue commands are only available after entering `CLI Rescue`:
|
||||
- `.github/workflows/eastmesh-build-observer-firmwares.yml`
|
||||
- `.github/workflows/eastmesh-build-repeater-bridge-espnow-firmwares.yml`
|
||||
- `.github/workflows/eastmesh-build-observer-espnow-firmwares.yml`
|
||||
- `.github/workflows/eastmesh-build-observer-mqtt-bridge-firmwares.yml`
|
||||
- `.github/workflows/eastmesh-pr-build-check.yml`
|
||||
- `.github/workflows/eastmesh-push-build-check.yml`
|
||||
- `.github/workflows/eastmesh-github-pages.yml`
|
||||
@@ -209,6 +329,7 @@ The current release workflows intentionally focus only on:
|
||||
- `repeater-bridge-espnow`
|
||||
- `observer-eastmesh`
|
||||
- `observer-eastmesh-bridge-espnow`
|
||||
- `observer-eastmesh-bridge-mqtt`
|
||||
|
||||
## Release Tags
|
||||
|
||||
@@ -219,6 +340,7 @@ git tag companion-wifi-v1.14.1
|
||||
git tag repeater-bridge-espnow-v1.15.0
|
||||
git tag observer-eastmesh-v2026.5.1
|
||||
git tag observer-eastmesh-bridge-espnow-v2026.5.1
|
||||
git tag observer-eastmesh-bridge-mqtt-v2026.7.0
|
||||
```
|
||||
|
||||
Companion WiFi uses the upstream MeshCore version in the tag.
|
||||
@@ -242,3 +364,4 @@ Current docs pages:
|
||||
- [Download and Flash Releases](./eastmesh-docs/releases.md)
|
||||
- [Build Locally With uv](./eastmesh-docs/local-builds.md)
|
||||
- [Custom CLI Commands](./eastmesh-docs/custom-cli.md)
|
||||
- [Web Panel](./eastmesh-docs/web-panel.md)
|
||||
|
||||
+8
-1
@@ -19,11 +19,13 @@ Push one or more of the following tag formats to trigger the matching firmware r
|
||||
- `companion-wifi-v1.15.0`
|
||||
- `repeater-bridge-espnow-v1.15.0`
|
||||
- `observer-eastmesh-bridge-espnow-v2026.5.1`
|
||||
- `observer-eastmesh-bridge-mqtt-v2026.7.0`
|
||||
- `observer-eastmesh-v2026.5.1`
|
||||
|
||||
Use the upstream MeshCore version in `companion-wifi-v1.15.0`.
|
||||
Use the upstream MeshCore version in `repeater-bridge-espnow-v1.15.0`.
|
||||
Use the EastMesh release version in `observer-eastmesh-bridge-espnow-v2026.5.1`.
|
||||
Use the EastMesh release version in `observer-eastmesh-bridge-mqtt-v2026.7.0`.
|
||||
Use the EastMesh release version in `observer-eastmesh-v2026.5.1`.
|
||||
|
||||
Each tag triggers a separate workflow:
|
||||
@@ -31,6 +33,7 @@ Each tag triggers a separate workflow:
|
||||
- `companion-wifi-v*` builds companion WiFi firmware
|
||||
- `repeater-bridge-espnow-v*` builds repeater ESP-NOW bridge firmware
|
||||
- `observer-eastmesh-bridge-espnow-v*` builds Observer ESP-NOW firmware
|
||||
- `observer-eastmesh-bridge-mqtt-v*` builds Observer MQTT bridge firmware
|
||||
- `observer-eastmesh-v*` builds Observer firmware
|
||||
|
||||
You can push one, or more tags on the same commit, and they will all build separately.
|
||||
@@ -42,6 +45,7 @@ During the GitHub Actions build:
|
||||
- `companion-wifi` uses the version in the tag as `FIRMWARE_VERSION`
|
||||
- `repeater-bridge-espnow` uses the version in the tag as `FIRMWARE_VERSION`
|
||||
- `observer-eastmesh-bridge-espnow` uses `OFFICIAL_MESHCORE_VERSION` as `FIRMWARE_VERSION` and the EastMesh version from the tag as `EASTMESH_VERSION`
|
||||
- `observer-eastmesh-bridge-mqtt` uses `OFFICIAL_MESHCORE_VERSION` as `FIRMWARE_VERSION` and the EastMesh version from the tag as `EASTMESH_VERSION`
|
||||
- `observer-eastmesh` uses `OFFICIAL_MESHCORE_VERSION` as `FIRMWARE_VERSION` and the EastMesh version from the tag as `EASTMESH_VERSION`
|
||||
|
||||
The resulting version string depends on the workflow:
|
||||
@@ -49,6 +53,7 @@ The resulting version string depends on the workflow:
|
||||
- `companion-wifi`: `v1.15.0-<commit>`
|
||||
- `repeater-bridge-espnow`: `v1.15.0-<commit>`
|
||||
- `observer-eastmesh-bridge-espnow`: `v1.15.0-eastmesh-v2026.5.1-<commit>`
|
||||
- `observer-eastmesh-bridge-mqtt`: `v1.15.0-eastmesh-v2026.7.0-<commit>`
|
||||
- `observer-eastmesh`: `v1.15.0-eastmesh-v2026.5.1-<commit>`
|
||||
|
||||
Example:
|
||||
@@ -76,8 +81,9 @@ Example:
|
||||
git tag companion-wifi-v1.15.0
|
||||
git tag repeater-bridge-espnow-v1.15.0
|
||||
git tag observer-eastmesh-bridge-espnow-v2026.5.1
|
||||
git tag observer-eastmesh-bridge-mqtt-v2026.7.0
|
||||
git tag observer-eastmesh-v2026.5.1
|
||||
git push origin companion-wifi-v1.15.0 repeater-bridge-espnow-v1.15.0 observer-eastmesh-bridge-espnow-v2026.5.1 observer-eastmesh-v2026.5.1
|
||||
git push origin companion-wifi-v1.15.0 repeater-bridge-espnow-v1.15.0 observer-eastmesh-bridge-espnow-v2026.5.1 observer-eastmesh-bridge-mqtt-v2026.7.0 observer-eastmesh-v2026.5.1
|
||||
```
|
||||
|
||||
## Supported Tags
|
||||
@@ -85,4 +91,5 @@ git push origin companion-wifi-v1.15.0 repeater-bridge-espnow-v1.15.0 observer-e
|
||||
- `companion-wifi-v1.15.0`
|
||||
- `repeater-bridge-espnow-v1.15.0`
|
||||
- `observer-eastmesh-bridge-espnow-v2026.5.1`
|
||||
- `observer-eastmesh-bridge-mqtt-v2026.7.0`
|
||||
- `observer-eastmesh-v2026.5.1`
|
||||
|
||||
@@ -37,6 +37,7 @@ Commands:
|
||||
build-repeater-bridge-espnow-firmwares: Build all repeater ESP-NOW bridge firmwares for all build targets.
|
||||
build-observer-firmwares: Build all observer firmwares for all build targets.
|
||||
build-observer-espnow-firmwares: Build all observer ESP-NOW firmwares for all build targets.
|
||||
build-observer-mqtt-bridge-firmwares: Build all observer MQTT bridge firmwares for all build targets.
|
||||
build-room-server-firmwares: Build all chat room server firmwares for all build targets.
|
||||
|
||||
Examples:
|
||||
@@ -64,6 +65,9 @@ $ sh eastmesh-build.sh build-observer-firmwares
|
||||
Build all observer ESP-NOW firmwares
|
||||
$ sh eastmesh-build.sh build-observer-espnow-firmwares
|
||||
|
||||
Build all observer MQTT bridge firmwares
|
||||
$ sh eastmesh-build.sh build-observer-mqtt-bridge-firmwares
|
||||
|
||||
Build all chat room server firmwares
|
||||
$ sh eastmesh-build.sh build-room-server-firmwares
|
||||
|
||||
@@ -327,6 +331,12 @@ build_repeater_observer_espnow_firmwares() {
|
||||
|
||||
}
|
||||
|
||||
build_repeater_observer_mqtt_bridge_firmwares() {
|
||||
|
||||
build_all_firmwares_by_suffix "_repeater_observer_mqtt_bridge"
|
||||
|
||||
}
|
||||
|
||||
build_room_server_firmwares() {
|
||||
|
||||
# # build specific room server firmwares
|
||||
@@ -380,6 +390,8 @@ elif [[ $1 == "build-observer-firmwares" ]]; then
|
||||
build_repeater_observer_firmwares
|
||||
elif [[ $1 == "build-observer-espnow-firmwares" ]]; then
|
||||
build_repeater_observer_espnow_firmwares
|
||||
elif [[ $1 == "build-observer-mqtt-bridge-firmwares" ]]; then
|
||||
build_repeater_observer_mqtt_bridge_firmwares
|
||||
elif [[ $1 == "build-room-server-firmwares" ]]; then
|
||||
build_room_server_firmwares
|
||||
fi
|
||||
|
||||
@@ -26,7 +26,8 @@ For bridge repeaters, think local radio linking between nearby repeaters:
|
||||
- use bridge firmware when two local repeaters need to exchange traffic across different MeshCore radio configs, such as `Australia (Narrow)` and `Australia (Mid)`
|
||||
- pure ESP-NOW bridge repeaters do not need MQTT, the EastMesh web panel, or a screen
|
||||
- prioritise stable power, suitable antennas, and placement over display features
|
||||
- use `observer-eastmesh-bridge-espnow` only when the same repeater also needs MQTT uplink; otherwise `repeater-bridge-espnow` keeps the role simpler
|
||||
- use `observer-eastmesh-bridge-espnow` only when the same repeater also needs MQTT uplink and a local ESP-NOW bridge; otherwise `repeater-bridge-espnow` keeps the role simpler
|
||||
- use `observer-eastmesh-bridge-mqtt` when the same repeater needs MQTT uplink and bidirectional MQTT mesh bridging through a peer broker
|
||||
|
||||
Other notes:
|
||||
|
||||
@@ -52,6 +53,7 @@ The tables below are built from the repo's PlatformIO board metadata and variant
|
||||
- `companion-wifi` boards are for app-connected companion devices.
|
||||
- `observer-eastmesh` boards are for Wi-Fi repeaters that publish to MQTT.
|
||||
- `repeater-bridge-espnow` and `observer-eastmesh-bridge-espnow` boards are for local ESP-NOW bridge use between nearby repeaters on different MeshCore radio configs.
|
||||
- `observer-eastmesh-bridge-mqtt` boards bridge mesh packets through a shared MQTT topic at a peer broker you configure.
|
||||
|
||||
Bridge firmware is not MQTT-over-WAN or VPN bridging. Use it when two local repeaters need to exchange traffic across radio configs such as `Australia (Narrow)` and `Australia (Mid)`.
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ OK
|
||||
|
||||
### MQTT Bridge Settings For Observer MQTT Bridge Builds
|
||||
|
||||
These commands are available on observer builds that compile with the MQTT mesh bridge transport (for example `Xiao_S3_WIO_repeater_observer_espnow` when built with `WITH_MQTT_BRIDGE`).
|
||||
These commands are available on `*_repeater_observer_mqtt_bridge` firmware targets (release track `observer-eastmesh-bridge-mqtt`).
|
||||
|
||||
The MQTT bridge forwards raw mesh packets over a shared topic at a peer MQTT broker. It is separate from MQTT uplink publishing to EastMesh or MeshMapper brokers.
|
||||
|
||||
@@ -167,9 +167,13 @@ The MQTT bridge forwards raw mesh packets over a shared topic at a peer MQTT bro
|
||||
- `set bridge.peer.host <host>`: sets the peer MQTT broker host and restarts the bridge.
|
||||
- `get bridge.peer.port`: shows the configured peer MQTT broker port (defaults to `1883` when unset).
|
||||
- `set bridge.peer.port <port>`: sets the peer MQTT broker port and restarts the bridge.
|
||||
- `get bridge.peer.username` / `set bridge.peer.username <username>`: optional peer MQTT broker username.
|
||||
- `get bridge.peer.password` / `set bridge.peer.password <password>`: optional peer MQTT broker password (`get` returns `set` or `-`, not the stored value).
|
||||
- `get bridge.secret` / `set bridge.secret <secret>`: shared XOR key used by all bridge nodes on the same bridge network.
|
||||
|
||||
Both bridge nodes must use the same peer broker address, port, and `bridge.secret`. Mesh packets are published and subscribed on topic `meshcore/bridge/packets`.
|
||||
Both bridge nodes must use the same peer broker address, port, credentials, and `bridge.secret`.
|
||||
|
||||
On `*_repeater_observer_mqtt_bridge` builds, MQTT uplink brokers are **disabled by default** so the mesh bridge client is not competing with EastMesh/MeshMapper WSS uplink at boot. Enable uplink brokers manually in MQTT Settings when needed.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -178,6 +182,10 @@ Example:
|
||||
OK
|
||||
> set bridge.peer.port 1883
|
||||
OK
|
||||
> set bridge.peer.username meshbridge
|
||||
OK
|
||||
> set bridge.peer.password your-mqtt-password
|
||||
OK
|
||||
> set bridge.secret my-shared-secret
|
||||
OK
|
||||
```
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
# MeshCore EastMesh Docs
|
||||
|
||||
MeshCore-EastMesh keeps the upstream MeshCore firmware intact and publishes four firmware tracks, depending on how the device needs to connect:
|
||||
MeshCore-EastMesh keeps the upstream MeshCore firmware intact and publishes five firmware tracks, depending on how the device needs to connect:
|
||||
|
||||
- `companion-wifi`: use this for Wi-Fi-connected companion devices. It stays closest to upstream MeshCore and adds the EastMesh Wi-Fi rescue/configuration commands.
|
||||
- `repeater-bridge-espnow`: use this when you need a plain upstream-style repeater ESP-NOW bridge without MQTT uplink or the EastMesh web panel.
|
||||
- `observer-eastmesh`: use this for a Wi-Fi repeater that should publish to an MQTT broker and, on supported ESP32 boards, offer the optional local web panel for setup and troubleshooting.
|
||||
- `observer-eastmesh-bridge-espnow`: use this when one repeater needs both MQTT uplink and ESP-NOW bridge duties, including bridge channel/secret controls for keeping the bridge aligned with Wi-Fi.
|
||||
- `observer-eastmesh-bridge-mqtt`: use this when one repeater needs both MQTT uplink and bidirectional MQTT mesh bridging through a peer broker you configure in the web panel or CLI.
|
||||
|
||||
!!! note "Bridge tracks are local radio bridges"
|
||||
|
||||
The bridge tracks are for bridging two nearby repeaters that operate on different MeshCore radio configs, for example one repeater on `Australia (Narrow)` and another on `Australia (Mid)`.
|
||||
The ESP-NOW bridge tracks are for bridging two nearby repeaters that operate on different MeshCore radio configs, for example one repeater on `Australia (Narrow)` and another on `Australia (Mid)`.
|
||||
|
||||
They are not MQTT-over-WAN, VPN, or internet bridge releases. MQTT is still the uplink/visibility path for MQTT firmware; it is not used to tunnel mesh traffic between distant sites.
|
||||
The MQTT bridge track uses a shared topic at a peer MQTT broker for mesh packet bridging. It is separate from MQTT uplink publishing to EastMesh or MeshMapper.
|
||||
|
||||
Bridge tracks are not MQTT-over-WAN, VPN, or internet tunnel releases.
|
||||
|
||||
If you want guidance first, start with:
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ uv run pio run -e heltec_v4_repeater_observer
|
||||
uv run pio run -e heltec_v4_companion_radio_wifi
|
||||
uv run pio run -e heltec_v4_repeater_bridge_espnow
|
||||
uv run pio run -e heltec_v4_repeater_observer_espnow
|
||||
uv run pio run -e Xiao_S3_WIO_repeater_observer_mqtt_bridge
|
||||
```
|
||||
|
||||
Flash a target:
|
||||
@@ -82,7 +83,7 @@ This produces versioned artifacts in `out/`.
|
||||
Versioning rule:
|
||||
|
||||
- `companion-wifi` and `repeater-bridge-espnow` use the upstream MeshCore version as `FIRMWARE_VERSION`
|
||||
- `observer-eastmesh` and `observer-eastmesh-bridge-espnow` use the upstream MeshCore version as `FIRMWARE_VERSION` plus the EastMesh release version as `EASTMESH_VERSION`
|
||||
- `observer-eastmesh`, `observer-eastmesh-bridge-espnow`, and `observer-eastmesh-bridge-mqtt` use the upstream MeshCore version as `FIRMWARE_VERSION` plus the EastMesh release version as `EASTMESH_VERSION`
|
||||
|
||||
## Supported `repeater_observer` Boards
|
||||
|
||||
@@ -143,6 +144,20 @@ T_Beam_S3_Supreme_SX1262_repeater_bridge_espnow
|
||||
T_Beam_S3_Supreme_SX1262_repeater_observer_espnow
|
||||
```
|
||||
|
||||
## Supported `repeater_observer_mqtt_bridge` Boards
|
||||
|
||||
At present only the Xiao S3 WIO observer MQTT bridge target is defined:
|
||||
|
||||
```text
|
||||
Xiao_S3_WIO_repeater_observer_mqtt_bridge
|
||||
```
|
||||
|
||||
List all observer MQTT bridge targets:
|
||||
|
||||
```bash
|
||||
bash eastmesh-build.sh list | grep '_repeater_observer_mqtt_bridge'
|
||||
```
|
||||
|
||||
Bridge firmware is for local ESP-NOW bridge use between nearby repeaters. It is not MQTT-over-WAN or VPN bridging.
|
||||
|
||||
## Supported `companion_radio_wifi` Boards
|
||||
|
||||
@@ -22,7 +22,7 @@ If you are not sure which track you need, start with `companion-wifi` for app-co
|
||||
|
||||
## Pick Your Track
|
||||
|
||||
EastMesh publishes four release tracks:
|
||||
EastMesh publishes five release tracks:
|
||||
|
||||
| Track | Use it when | Firmware filename suffix |
|
||||
| ----- | ----------- | ------------------------ |
|
||||
@@ -30,12 +30,15 @@ EastMesh publishes four release tracks:
|
||||
| `observer-eastmesh` | You want a repeater with Wi-Fi and MQTT uplink, usually feeding broker visibility such as EastMesh/CoreScope. | `*_repeater_observer` |
|
||||
| `repeater-bridge-espnow` | You want a local ESP-NOW bridge between nearby repeaters, without MQTT uplink or the EastMesh web panel. | `*_repeater_bridge_espnow` |
|
||||
| `observer-eastmesh-bridge-espnow` | You want one repeater to provide both MQTT uplink and local ESP-NOW bridge duties. | `*_repeater_observer_espnow` |
|
||||
| `observer-eastmesh-bridge-mqtt` | You want one repeater to provide both MQTT uplink and bidirectional MQTT mesh bridging to a peer broker. | `*_repeater_observer_mqtt_bridge` |
|
||||
|
||||
!!! note "Bridge firmware is not a WAN bridge"
|
||||
|
||||
Bridge tracks are for bridging two nearby repeaters that operate on different MeshCore radio configs, for example `Australia (Narrow)` and `Australia (Mid)`.
|
||||
ESP-NOW bridge tracks are for bridging two nearby repeaters that operate on different MeshCore radio configs, for example `Australia (Narrow)` and `Australia (Mid)`.
|
||||
|
||||
They do not use MQTT to tunnel mesh traffic over the internet, WAN links, or VPNs.
|
||||
The MQTT bridge track forwards mesh packets through a shared topic at a peer MQTT broker you configure. It is separate from MQTT uplink publishing to EastMesh or MeshMapper.
|
||||
|
||||
Bridge tracks do not use MQTT uplink brokers to tunnel mesh traffic over the internet, WAN links, or VPNs.
|
||||
|
||||
## Pick The Right Asset
|
||||
|
||||
@@ -48,6 +51,7 @@ Examples:
|
||||
- `heltec_v4_repeater_observer-v1.15.0-eastmesh-v2026.5.1-abcdef-merged.bin`
|
||||
- `heltec_v4_repeater_bridge_espnow-v1.15.0-abcdef.bin`
|
||||
- `heltec_v4_repeater_observer_espnow-v1.15.0-eastmesh-v2026.5.1-abcdef.bin`
|
||||
- `Xiao_S3_WIO_repeater_observer_mqtt_bridge-v1.15.0-eastmesh-v2026.7.0-abcdef.bin`
|
||||
|
||||
The important part is the board/env prefix:
|
||||
|
||||
@@ -55,6 +59,7 @@ The important part is the board/env prefix:
|
||||
- `*_repeater_observer`
|
||||
- `*_repeater_bridge_espnow`
|
||||
- `*_repeater_observer_espnow`
|
||||
- `*_repeater_observer_mqtt_bridge`
|
||||
|
||||
## Which File To Flash
|
||||
|
||||
@@ -187,6 +192,19 @@ Typical first steps after flashing:
|
||||
- set `bridge.channel` to match that Wi-Fi channel
|
||||
- set the same `bridge.secret` on every local ESP-NOW bridge node that should talk together
|
||||
|
||||
### Observer MQTT Bridge
|
||||
|
||||
`repeater_observer_mqtt_bridge` builds combine the observer role with bidirectional MQTT mesh bridging.
|
||||
|
||||
Typical first steps after flashing:
|
||||
|
||||
- set `wifi.ssid`
|
||||
- set `wifi.pwd`
|
||||
- set `mqtt.iata`
|
||||
- confirm `get mqtt.status`
|
||||
- set `bridge.peer.host` and `bridge.peer.port` to your peer MQTT broker
|
||||
- set the same `bridge.secret` on every MQTT bridge node that should talk together
|
||||
|
||||
### Repeater ESP-NOW Bridge
|
||||
|
||||
`repeater_bridge_espnow` builds are for local ESP-NOW bridge nodes without MQTT uplink.
|
||||
|
||||
@@ -255,7 +255,7 @@ This section includes:
|
||||
- `mqtt.email`: owner contact email.
|
||||
- MQTT brokers: **Primary MQTT** and **Secondary MQTT** dropdowns, each selecting one of `eastmesh-au`, `meshmapper`, `Custom`, the retired `letsmesh-eu`/`letsmesh-us`, or `None`. The two slots enforce the two-broker maximum, and a broker chosen in one slot is disabled in the other.
|
||||
- custom MQTT `host:port`, TCP/WSS transport, username, and password fields, shown when `Custom` is selected in either slot.
|
||||
- mesh bridge peer MQTT `host:port`, shown on MQTT bridge builds (`get bridge.type` returns `mqtt`). This is separate from MQTT uplink brokers and points at the shared peer broker used for bidirectional mesh packet bridging.
|
||||
- mesh bridge peer MQTT `host:port`, optional username and password, shown on MQTT bridge builds (`get bridge.type` returns `mqtt`). This is separate from MQTT uplink brokers and points at the shared peer broker used for bidirectional mesh packet bridging.
|
||||
|
||||
`UNSET - To be configured` is the default for new observer installs until a real saved value exists.
|
||||
|
||||
@@ -270,7 +270,7 @@ Notes:
|
||||
- turning off a connected MQTT server publishes retained offline status before the client disconnects
|
||||
- changing `mqtt.iata` away from a configured value publishes retained offline status to the old status topic, restarts connected broker clients, and reconnects under the new topic path
|
||||
- at most two MQTT brokers can be enabled at once
|
||||
- on MQTT bridge builds, both bridge nodes must use the same peer broker host, port, and `bridge.secret`
|
||||
- on MQTT bridge builds, both bridge nodes must use the same peer broker host, port, credentials, and `bridge.secret`
|
||||
|
||||
## `/stats` Overview
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ tracks:
|
||||
- repeater-bridge-espnow
|
||||
- observer-eastmesh
|
||||
- observer-eastmesh-bridge-espnow
|
||||
- observer-eastmesh-bridge-mqtt
|
||||
generated_from: "Adjacent git tag comparisons plus non-merge commit subjects."
|
||||
|
||||
releases:
|
||||
@@ -393,3 +394,27 @@ releases:
|
||||
breaking_changes:
|
||||
- "`get mqtt.status` output changed from per-broker fields to `p:`/`s:` broker slots; anything parsing the previous format must be updated."
|
||||
- "Saved LetsMesh EU/US broker selections are cleared once on upgrade; re-enable a broker such as MeshMapper if a second uplink is required."
|
||||
|
||||
- track: observer-eastmesh-bridge-mqtt
|
||||
version: "2026.7.0"
|
||||
tag: "observer-eastmesh-bridge-mqtt-v2026.7.0"
|
||||
date: "2026-06-24"
|
||||
previous_version: null
|
||||
summary: "Introduces the observer-eastmesh-bridge-mqtt release track with bidirectional MQTT mesh bridging and web-panel peer broker configuration."
|
||||
changes:
|
||||
- type: added
|
||||
area: bridge
|
||||
text: "Added `WITH_MQTT_BRIDGE` and `MQTTBridge` for bidirectional mesh packet transport over a shared MQTT topic at a peer broker."
|
||||
- type: added
|
||||
area: cli
|
||||
text: "Added `get/set bridge.peer.host` and `get/set bridge.peer.port` for configuring the peer MQTT broker used by the mesh bridge."
|
||||
- type: added
|
||||
area: web
|
||||
text: "Added mesh bridge peer MQTT host:port controls to the web panel on MQTT bridge builds."
|
||||
- type: added
|
||||
area: release
|
||||
text: "Added the `observer-eastmesh-bridge-mqtt-v*` release tag format, PlatformIO `*_repeater_observer_mqtt_bridge` environments, and CI build workflow."
|
||||
- type: added
|
||||
area: boards
|
||||
text: "Added `Xiao_S3_WIO_repeater_observer_mqtt_bridge` as the first supported observer MQTT bridge target."
|
||||
breaking_changes: []
|
||||
|
||||
@@ -109,7 +109,13 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
||||
if (file.available() >= (int)sizeof(_prefs->bridge_peer_port)) {
|
||||
file.read((uint8_t *)&_prefs->bridge_peer_port, sizeof(_prefs->bridge_peer_port)); // 360
|
||||
}
|
||||
// next: 362
|
||||
if (file.available() >= (int)sizeof(_prefs->bridge_peer_username)) {
|
||||
file.read((uint8_t *)&_prefs->bridge_peer_username, sizeof(_prefs->bridge_peer_username)); // 362
|
||||
}
|
||||
if (file.available() >= (int)sizeof(_prefs->bridge_peer_password)) {
|
||||
file.read((uint8_t *)&_prefs->bridge_peer_password, sizeof(_prefs->bridge_peer_password)); // 427
|
||||
}
|
||||
// next: 523
|
||||
|
||||
// sanitise bad pref values
|
||||
_prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
|
||||
@@ -211,7 +217,9 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
|
||||
file.write((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 295
|
||||
file.write((uint8_t *)&_prefs->bridge_peer_host, sizeof(_prefs->bridge_peer_host)); // 296
|
||||
file.write((uint8_t *)&_prefs->bridge_peer_port, sizeof(_prefs->bridge_peer_port)); // 360
|
||||
// next: 362
|
||||
file.write((uint8_t *)&_prefs->bridge_peer_username, sizeof(_prefs->bridge_peer_username)); // 362
|
||||
file.write((uint8_t *)&_prefs->bridge_peer_password, sizeof(_prefs->bridge_peer_password)); // 427
|
||||
// next: 523
|
||||
|
||||
file.close();
|
||||
}
|
||||
@@ -812,6 +820,16 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
_callbacks->restartBridge();
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
} else if (memcmp(config, "bridge.peer.username ", 21) == 0) {
|
||||
StrHelper::strncpy(_prefs->bridge_peer_username, &config[21], sizeof(_prefs->bridge_peer_username));
|
||||
_callbacks->restartBridge();
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
} else if (memcmp(config, "bridge.peer.password ", 21) == 0) {
|
||||
StrHelper::strncpy(_prefs->bridge_peer_password, &config[21], sizeof(_prefs->bridge_peer_password));
|
||||
_callbacks->restartBridge();
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
} else if (memcmp(config, "bridge.secret ", 14) == 0) {
|
||||
StrHelper::strncpy(_prefs->bridge_secret, &config[14], sizeof(_prefs->bridge_secret));
|
||||
_callbacks->restartBridge();
|
||||
@@ -960,6 +978,10 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
sprintf(reply, "> %s", _prefs->bridge_peer_host);
|
||||
} else if (memcmp(config, "bridge.peer.port", 16) == 0) {
|
||||
sprintf(reply, "> %u", _prefs->bridge_peer_port != 0 ? _prefs->bridge_peer_port : 1883);
|
||||
} else if (memcmp(config, "bridge.peer.username", 20) == 0) {
|
||||
sprintf(reply, "> %s", _prefs->bridge_peer_username[0] ? _prefs->bridge_peer_username : "-");
|
||||
} else if (memcmp(config, "bridge.peer.password", 20) == 0) {
|
||||
sprintf(reply, "> %s", _prefs->bridge_peer_password[0] ? "set" : "-");
|
||||
} else if (memcmp(config, "bridge.secret", 13) == 0) {
|
||||
sprintf(reply, "> %s", _prefs->bridge_secret);
|
||||
#endif
|
||||
|
||||
@@ -67,6 +67,8 @@ struct NodePrefs { // persisted to file
|
||||
uint16_t fan_timeout_secs;
|
||||
char bridge_peer_host[64]; // peer MQTT broker host (MQTT bridge only)
|
||||
uint16_t bridge_peer_port; // peer MQTT broker port (MQTT bridge only, default 1883)
|
||||
char bridge_peer_username[65]; // peer MQTT broker username (MQTT bridge only)
|
||||
char bridge_peer_password[96]; // peer MQTT broker password (MQTT bridge only)
|
||||
};
|
||||
|
||||
class CommonCLICallbacks {
|
||||
|
||||
@@ -49,7 +49,7 @@ const char *MQTTBridge::kBridgeTopic = "meshcore/bridge/packets";
|
||||
|
||||
MQTTBridge::MQTTBridge(NodePrefs *prefs, mesh::PacketManager *mgr, mesh::RTCClock *rtc)
|
||||
: BridgeBase(prefs, mgr, rtc), _client(nullptr), _connected(false), _started(false),
|
||||
_next_connect_attempt(0), _reconnect_failures(0) {
|
||||
_pending_destroy(false), _next_connect_attempt(0), _reconnect_failures(0) {
|
||||
_instance = this;
|
||||
_client_id[0] = 0;
|
||||
}
|
||||
@@ -72,6 +72,13 @@ void MQTTBridge::destroyClient() {
|
||||
}
|
||||
_connected = false;
|
||||
_started = false;
|
||||
_pending_destroy = false;
|
||||
}
|
||||
|
||||
void MQTTBridge::scheduleClientDestroy() {
|
||||
_connected = false;
|
||||
_started = false;
|
||||
_pending_destroy = true;
|
||||
}
|
||||
|
||||
void MQTTBridge::begin() {
|
||||
@@ -108,9 +115,7 @@ void MQTTBridge::onMqttConnected() {
|
||||
}
|
||||
|
||||
void MQTTBridge::onMqttDisconnected() {
|
||||
_connected = false;
|
||||
_started = false;
|
||||
destroyClient();
|
||||
scheduleClientDestroy();
|
||||
_next_connect_attempt = millis() + connectRetryDelayMillis(_reconnect_failures);
|
||||
if (_reconnect_failures < 255) {
|
||||
++_reconnect_failures;
|
||||
@@ -130,6 +135,9 @@ void MQTTBridge::mqttEventHandler(void *handler_args, esp_event_base_t, int32_t
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
bridge->onMqttDisconnected();
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
bridge->onMqttDisconnected();
|
||||
break;
|
||||
case MQTT_EVENT_DATA: {
|
||||
auto *event = static_cast<esp_mqtt_event_handle_t>(event_data);
|
||||
if (event != nullptr && event->data_len > 0) {
|
||||
@@ -160,6 +168,12 @@ bool MQTTBridge::ensureClient() {
|
||||
cfg.broker.address.port = peerPort(_prefs);
|
||||
cfg.broker.address.transport = MQTT_TRANSPORT_OVER_TCP;
|
||||
cfg.credentials.client_id = _client_id;
|
||||
if (_prefs->bridge_peer_username[0] != 0) {
|
||||
cfg.credentials.username = _prefs->bridge_peer_username;
|
||||
}
|
||||
if (_prefs->bridge_peer_password[0] != 0) {
|
||||
cfg.credentials.authentication.password = _prefs->bridge_peer_password;
|
||||
}
|
||||
cfg.session.keepalive = 30;
|
||||
cfg.network.reconnect_timeout_ms = 10000;
|
||||
cfg.network.timeout_ms = 10000;
|
||||
@@ -171,6 +185,12 @@ bool MQTTBridge::ensureClient() {
|
||||
cfg.port = peerPort(_prefs);
|
||||
cfg.transport = MQTT_TRANSPORT_OVER_TCP;
|
||||
cfg.client_id = _client_id;
|
||||
if (_prefs->bridge_peer_username[0] != 0) {
|
||||
cfg.username = _prefs->bridge_peer_username;
|
||||
}
|
||||
if (_prefs->bridge_peer_password[0] != 0) {
|
||||
cfg.password = _prefs->bridge_peer_password;
|
||||
}
|
||||
cfg.keepalive = 30;
|
||||
cfg.buffer_size = MAX_MQTT_PACKET_SIZE;
|
||||
cfg.out_buffer_size = MAX_MQTT_PACKET_SIZE;
|
||||
@@ -201,6 +221,11 @@ void MQTTBridge::loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_pending_destroy) {
|
||||
destroyClient();
|
||||
return;
|
||||
}
|
||||
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (_client != nullptr) {
|
||||
destroyClient();
|
||||
@@ -208,12 +233,14 @@ void MQTTBridge::loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_client == nullptr) {
|
||||
if (_next_connect_attempt != 0 && millis() < _next_connect_attempt) {
|
||||
return;
|
||||
}
|
||||
ensureClient();
|
||||
if (_client != nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_next_connect_attempt != 0 && millis() < _next_connect_attempt) {
|
||||
return;
|
||||
}
|
||||
ensureClient();
|
||||
}
|
||||
|
||||
void MQTTBridge::handleMqttData(const uint8_t *data, size_t len) {
|
||||
|
||||
@@ -28,12 +28,14 @@ private:
|
||||
esp_mqtt_client_handle_t _client;
|
||||
bool _connected;
|
||||
bool _started;
|
||||
bool _pending_destroy;
|
||||
unsigned long _next_connect_attempt;
|
||||
uint8_t _reconnect_failures;
|
||||
char _client_id[24];
|
||||
|
||||
void xorCrypt(uint8_t *data, size_t len);
|
||||
void destroyClient();
|
||||
void scheduleClientDestroy();
|
||||
bool ensureClient();
|
||||
void handleMqttData(const uint8_t *data, size_t len);
|
||||
void onMqttConnected();
|
||||
|
||||
@@ -13,7 +13,12 @@ constexpr uint32_t kFixedStatusIntervalMs = 300000;
|
||||
void MQTTPrefsStore::setDefaults(MQTTPrefs& prefs) {
|
||||
memset(&prefs, 0, sizeof(prefs));
|
||||
prefs.magic = kMagic;
|
||||
#if defined(WITH_MQTT_BRIDGE)
|
||||
prefs.enabled_mask = 0x00;
|
||||
prefs.mqtt_bridge_uplink_migrated = 1;
|
||||
#else
|
||||
prefs.enabled_mask = 0x01;
|
||||
#endif
|
||||
prefs.packets_enabled = 1;
|
||||
prefs.raw_enabled = 0;
|
||||
prefs.status_enabled = 1;
|
||||
@@ -83,6 +88,13 @@ bool MQTTPrefsStore::load(FILESYSTEM* fs, MQTTPrefs& prefs) {
|
||||
prefs.brokers_migrated = 1;
|
||||
save(fs, prefs);
|
||||
}
|
||||
#if defined(WITH_MQTT_BRIDGE)
|
||||
if (!prefs.mqtt_bridge_uplink_migrated) {
|
||||
prefs.enabled_mask = 0;
|
||||
prefs.mqtt_bridge_uplink_migrated = 1;
|
||||
save(fs, prefs);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ struct MQTTPrefs {
|
||||
// Appended fields must stay at the end: older prefs files are shorter and
|
||||
// read back as zero here, which drives one-time migrations (see load()).
|
||||
uint8_t brokers_migrated;
|
||||
uint8_t mqtt_bridge_uplink_migrated;
|
||||
};
|
||||
|
||||
class MQTTPrefsStore {
|
||||
|
||||
@@ -1033,7 +1033,24 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
<button id="refreshBridgePeerEndpointBtn" class="iconbtn" title="Refresh bridge peer MQTT host and port">↻</button>
|
||||
<button id="saveBridgePeerEndpointBtn" class="savebtn">Save</button>
|
||||
</div>
|
||||
<div class="panel-note">Both bridge nodes must use the same peer broker, port, and bridge secret.</div>
|
||||
<div class="panel-note">Both bridge nodes must use the same peer broker, port, credentials, and bridge secret.</div>
|
||||
<div class="row">
|
||||
<div class="field-card">
|
||||
<label class="label" for="bridgePeerUsername">Username</label>
|
||||
<div class="inline-actions">
|
||||
<input id="bridgePeerUsername" placeholder="optional" maxlength="64">
|
||||
<button class="iconbtn" data-load-cmd="get bridge.peer.username" data-load-input="bridgePeerUsername" title="Refresh bridge peer MQTT username">↻</button>
|
||||
<button class="savebtn" data-prefix="set bridge.peer.username " data-input="bridgePeerUsername">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field-card">
|
||||
<label class="label" for="bridgePeerPassword">Password</label>
|
||||
<div class="inline-actions two-actions">
|
||||
<input id="bridgePeerPassword" type="password" placeholder="optional" maxlength="95">
|
||||
<button class="savebtn" data-prefix="set bridge.peer.password " data-input="bridgePeerPassword">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1230,6 +1247,7 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
function parseClientEnv(clientEnv) {
|
||||
const env = String(clientEnv || "").trim();
|
||||
const suffixes = [
|
||||
{ suffix:"_repeater_observer_mqtt_bridge", firmware:"repeater_observer_mqtt_bridge" },
|
||||
{ suffix:"_repeater_observer_espnow", firmware:"repeater_observer_espnow" },
|
||||
{ suffix:"_repeater_observer", firmware:"repeater_observer" },
|
||||
{ suffix:"_repeater_bridge_espnow", firmware:"repeater_bridge_espnow" },
|
||||
@@ -2860,6 +2878,7 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
const input = document.getElementById("bridgePeerEndpoint");
|
||||
if (!input) return;
|
||||
input.value = host ? `${host}:${port}` : "";
|
||||
await loadField("get bridge.peer.username", "bridgePeerUsername", null, options);
|
||||
}
|
||||
async function saveBridgePeerEndpoint() {
|
||||
const input = document.getElementById("bridgePeerEndpoint");
|
||||
|
||||
@@ -1154,8 +1154,17 @@ build_src_filter = ${env:WHY2025_badge_repeater_observer.build_src_filter}
|
||||
|
||||
[env:Xiao_S3_WIO_repeater_observer_espnow]
|
||||
extends = env:Xiao_S3_WIO_repeater_observer
|
||||
build_flags =
|
||||
${env:Xiao_S3_WIO_repeater_observer.build_flags}
|
||||
-D WITH_ESPNOW_BRIDGE=1
|
||||
build_src_filter = ${env:Xiao_S3_WIO_repeater_observer.build_src_filter}
|
||||
+<helpers/bridges/ESPNowBridge.cpp>
|
||||
|
||||
[env:Xiao_S3_WIO_repeater_observer_mqtt_bridge]
|
||||
extends = env:Xiao_S3_WIO_repeater_observer
|
||||
build_flags =
|
||||
${env:Xiao_S3_WIO_repeater_observer.build_flags}
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-UMQTT_DEBUG
|
||||
build_src_filter = ${env:Xiao_S3_WIO_repeater_observer.build_src_filter}
|
||||
+<helpers/bridges/MQTTBridge.cpp>
|
||||
|
||||
Reference in New Issue
Block a user