diff --git a/.github/actions/setup-build-environment/action.yml b/.github/actions/setup-build-environment/action.yml index 88b665e5..bf55051a 100644 --- a/.github/actions/setup-build-environment/action.yml +++ b/.github/actions/setup-build-environment/action.yml @@ -42,11 +42,16 @@ runs: # Active release tag formats: # companion-wifi-v1.2.3 + # repeater-bridge-espnow-v1.2.3 + # repeater-mqtt-bridge-eastmesh-v1.0.1 # repeater-mqtt-eastmesh-v1.0.1 # with OFFICIAL_MESHCORE_VERSION=v1.2.3 configured as a GitHub variable. # # This exports: # companion-wifi-v1.2.3 -> FIRMWARE_VERSION=v1.2.3, RELEASE_VERSION=v1.2.3 + # repeater-bridge-espnow-v1.2.3 -> FIRMWARE_VERSION=v1.2.3, RELEASE_VERSION=v1.2.3 + # repeater-mqtt-bridge-eastmesh-v1.0.1 -> FIRMWARE_VERSION=v1.2.3, EASTMESH_VERSION=v1.0.1, + # RELEASE_VERSION=v1.2.3-eastmesh-v1.0.1 # repeater-mqtt-eastmesh-v1.0.1 -> FIRMWARE_VERSION=v1.2.3, EASTMESH_VERSION=v1.0.1, # RELEASE_VERSION=v1.2.3-eastmesh-v1.0.1 - name: Extract Version Info @@ -74,8 +79,16 @@ runs: exit 1 fi EASTMESH_VERSION="${BASH_REMATCH[1]}" + elif [[ "$GIT_TAG_NAME" =~ ^repeater-mqtt-bridge-eastmesh-(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 + FIRMWARE_VERSION="${BASH_REMATCH[1]}" else echo "Unsupported release tag format: $GIT_TAG_NAME" >&2 exit 1 diff --git a/.github/workflows/eastmesh-build-companion-wifi-firmwares.yml b/.github/workflows/eastmesh-build-companion-wifi-firmwares.yml index 67233139..7cee5f71 100644 --- a/.github/workflows/eastmesh-build-companion-wifi-firmwares.yml +++ b/.github/workflows/eastmesh-build-companion-wifi-firmwares.yml @@ -24,7 +24,7 @@ jobs: uses: ./.github/actions/setup-build-environment - name: Build Firmwares - run: /usr/bin/env bash build.sh build-companion-wifi-firmwares + run: /usr/bin/env bash eastmesh-build.sh build-companion-wifi-firmwares - name: Upload Workflow Artifacts uses: actions/upload-artifact@v7 diff --git a/.github/workflows/eastmesh-build-repeater-bridge-espnow-firmwares.yml b/.github/workflows/eastmesh-build-repeater-bridge-espnow-firmwares.yml new file mode 100644 index 00000000..cc3e8cc2 --- /dev/null +++ b/.github/workflows/eastmesh-build-repeater-bridge-espnow-firmwares.yml @@ -0,0 +1,42 @@ +name: EastMesh Build Repeater ESP-NOW Bridge Firmwares + +permissions: + contents: write + +on: + workflow_dispatch: + push: + tags: + - 'repeater-bridge-espnow-v*' + +jobs: + + build: + runs-on: ubuntu-latest + env: + OFFICIAL_MESHCORE_VERSION: ${{ vars.OFFICIAL_MESHCORE_VERSION }} + 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-repeater-bridge-espnow-firmwares + + - name: Upload Workflow Artifacts + uses: actions/upload-artifact@v7 + with: + name: repeater-bridge-espnow-firmwares + path: out + + - name: Create Release + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/') + with: + name: Repeater ESP-NOW Bridge Firmware ${{ env.RELEASE_VERSION }} + body: "" + draft: true + files: out/* diff --git a/.github/workflows/eastmesh-build-repeater-mqtt-bridge-firmwares.yml b/.github/workflows/eastmesh-build-repeater-mqtt-bridge-firmwares.yml new file mode 100644 index 00000000..29c1b472 --- /dev/null +++ b/.github/workflows/eastmesh-build-repeater-mqtt-bridge-firmwares.yml @@ -0,0 +1,43 @@ +name: EastMesh Build Repeater MQTT Bridge Firmwares + +permissions: + contents: write + +on: + workflow_dispatch: + push: + tags: + - 'repeater-mqtt-bridge-eastmesh-*' + +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-repeater-mqtt-bridge-firmwares + + - name: Upload Workflow Artifacts + uses: actions/upload-artifact@v7 + with: + name: repeater-mqtt-bridge-firmwares + path: out + + - name: Create Release + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/') + with: + name: Repeater MQTT Bridge Firmware ${{ env.RELEASE_VERSION }} + body: "" + draft: true + files: out/* diff --git a/.github/workflows/eastmesh-build-repeater-mqtt-firmwares.yml b/.github/workflows/eastmesh-build-repeater-mqtt-firmwares.yml index ff6927e3..49e64a6c 100644 --- a/.github/workflows/eastmesh-build-repeater-mqtt-firmwares.yml +++ b/.github/workflows/eastmesh-build-repeater-mqtt-firmwares.yml @@ -25,7 +25,7 @@ jobs: uses: ./.github/actions/setup-build-environment - name: Build Firmwares - run: /usr/bin/env bash build.sh build-repeater-mqtt-firmwares + run: /usr/bin/env bash eastmesh-build.sh build-repeater-mqtt-firmwares - name: Upload Workflow Artifacts uses: actions/upload-artifact@v7 diff --git a/AGENTS.md b/AGENTS.md index 1b9aad7f..9791c2a0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -81,7 +81,7 @@ Do not assume `pio` is installed globally. List build targets: ```bash -bash build.sh list +bash eastmesh-build.sh list ``` Build a single target: @@ -98,8 +98,8 @@ Build with release-style metadata: ```bash export FIRMWARE_VERSION=v1.14.1 export EASTMESH_VERSION=v1.0.1 -bash build.sh build-firmware heltec_v4_repeater_mqtt -bash build.sh build-firmware T_Beam_S3_Supreme_SX1262_repeater_mqtt +bash eastmesh-build.sh build-firmware heltec_v4_repeater_mqtt +bash eastmesh-build.sh build-firmware T_Beam_S3_Supreme_SX1262_repeater_mqtt ``` Flash a target: @@ -111,7 +111,8 @@ uv run pio run -e T_Beam_S3_Supreme_SX1262_repeater_mqtt -t upload --upload-port ## Key Files -- `build.sh` — build wrapper +- `eastmesh-build.sh` — EastMesh build wrapper +- `build.sh` — upstream MeshCore build wrapper retained for merge hygiene - `platformio.ini` - `variants/eastmesh_mqtt/platformio.ini` - `examples/simple_repeater/MyMesh.cpp` @@ -169,14 +170,18 @@ Current tag formats: ```bash git tag companion-wifi-v1.2.3 +git tag repeater-bridge-espnow-v1.2.3 +git tag repeater-mqtt-bridge-eastmesh-v1.0.1 git tag repeater-mqtt-eastmesh-v1.0.1 ``` Rules: - `companion-wifi` tags use the upstream MeshCore version directly +- `repeater-bridge-espnow` tags use the upstream MeshCore version directly +- `repeater-mqtt-bridge` tags use the EastMesh release version in the tag - `repeater-mqtt` tags use the EastMesh release version in the tag -- GitHub Actions variable `OFFICIAL_MESHCORE_VERSION` supplies the upstream base version for repeater MQTT release builds +- GitHub Actions variable `OFFICIAL_MESHCORE_VERSION` supplies the upstream base version for repeater MQTT and repeater MQTT bridge release builds - if the upstream MeshCore release version changes, update `OFFICIAL_MESHCORE_VERSION` in GitHub before cutting release tags Typical release flow: diff --git a/README.md b/README.md index 61d16555..9020598f 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ uv sync List available build targets: ```bash -bash build.sh list +bash eastmesh-build.sh list ``` Build a single target: @@ -90,7 +90,7 @@ Build with release-style version metadata: ```bash export FIRMWARE_VERSION=v1.14.1 export EASTMESH_VERSION=v1.0.1 -bash build.sh build-firmware heltec_v4_repeater_mqtt +bash eastmesh-build.sh build-firmware heltec_v4_repeater_mqtt ``` Flash a target: @@ -114,9 +114,11 @@ uv run --group docs zensical build ## Key Files -- [`build.sh`](./build.sh) - - main local build wrapper +- [`eastmesh-build.sh`](./eastmesh-build.sh) + - EastMesh local/release build wrapper - injects `FIRMWARE_VERSION`, `CLIENT_VERSION`, and EastMesh release metadata +- [`build.sh`](./build.sh) + - upstream MeshCore build wrapper retained to reduce future merge conflicts - [`pyproject.toml`](./pyproject.toml) - Python tooling and docs dependencies - [`platformio.ini`](./platformio.ini) diff --git a/RELEASE.md b/RELEASE.md index 15afe2d7..4f730224 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -17,14 +17,20 @@ This value becomes the base `FIRMWARE_VERSION` used by the release workflows. Push one or more of the following tag formats to trigger the matching firmware release workflow: - `companion-wifi-v1.2.3` +- `repeater-bridge-espnow-v1.2.3` +- `repeater-mqtt-bridge-eastmesh-v1.0.1` - `repeater-mqtt-eastmesh-v1.0.1` Use the upstream MeshCore version in `companion-wifi-v1.2.3`. +Use the upstream MeshCore version in `repeater-bridge-espnow-v1.2.3`. +Use the EastMesh release version in `repeater-mqtt-bridge-eastmesh-v1.0.1`. Use the EastMesh release version in `repeater-mqtt-eastmesh-v1.0.1`. Each tag triggers a separate workflow: - `companion-wifi-v*` builds companion WiFi firmware +- `repeater-bridge-espnow-v*` builds repeater ESP-NOW bridge firmware +- `repeater-mqtt-bridge-eastmesh-*` builds repeater MQTT bridge firmware - `repeater-mqtt-eastmesh-*` builds repeater MQTT firmware You can push one, or more tags on the same commit, and they will all build separately. @@ -34,12 +40,15 @@ You can push one, or more tags on the same commit, and they will all build separ During the GitHub Actions build: - `companion-wifi` uses the version in the tag as `FIRMWARE_VERSION` -- `repeater-mqtt` uses `OFFICIAL_MESHCORE_VERSION` as `FIRMWARE_VERSION` -- `repeater-mqtt` uses the EastMesh version from the tag as `EASTMESH_VERSION` +- `repeater-bridge-espnow` uses the version in the tag as `FIRMWARE_VERSION` +- `repeater-mqtt-bridge` uses `OFFICIAL_MESHCORE_VERSION` as `FIRMWARE_VERSION` and the EastMesh version from the tag as `EASTMESH_VERSION` +- `repeater-mqtt` 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: - `companion-wifi`: `v1.2.3-` +- `repeater-bridge-espnow`: `v1.2.3-` +- `repeater-mqtt-bridge`: `v1.2.3-eastmesh-v1.0.1-` - `repeater-mqtt`: `v1.2.3-eastmesh-v1.0.1-` Example: @@ -65,11 +74,15 @@ Example: ```bash git tag companion-wifi-v1.2.3 +git tag repeater-bridge-espnow-v1.2.3 +git tag repeater-mqtt-bridge-eastmesh-v1.0.1 git tag repeater-mqtt-eastmesh-v1.0.1 -git push origin companion-wifi-v1.2.3 repeater-mqtt-eastmesh-v1.0.1 +git push origin companion-wifi-v1.2.3 repeater-bridge-espnow-v1.2.3 repeater-mqtt-bridge-eastmesh-v1.0.1 repeater-mqtt-eastmesh-v1.0.1 ``` ## Supported Tags - `companion-wifi-v1.2.3` +- `repeater-bridge-espnow-v1.2.3` +- `repeater-mqtt-bridge-eastmesh-v1.0.1` - `repeater-mqtt-eastmesh-v1.0.1` diff --git a/build.sh b/build.sh index 2129518e..313c4c47 100755 --- a/build.sh +++ b/build.sh @@ -1,25 +1,5 @@ #!/usr/bin/env bash -require_uv() { - if ! command -v uv >/dev/null 2>&1; then - echo "uv is required. Install it from https://docs.astral.sh/uv/" >&2 - exit 1 - fi -} - -sync_python_tooling() { - uv sync --locked --no-group docs >/dev/null - uv venv --allow-existing --seed >/dev/null -} - -run_python() { - uv run --no-sync python "$@" -} - -run_pio() { - uv run --no-sync pio "$@" -} - global_usage() { cat - <: Build all firmwares for build targets containing the string given for . build-companion-firmwares: Build all companion firmwares for all build targets. - build-companion-wifi-firmwares: Build all companion WiFi firmwares for all build targets. build-repeater-firmwares: Build all repeater firmwares for all build targets. - build-repeater-mqtt-firmwares: Build all repeater MQTT firmwares for all build targets. build-room-server-firmwares: Build all chat room server firmwares for all build targets. Examples: @@ -47,15 +25,9 @@ $ sh build.sh build-matching-firmwares Build all companion firmwares $ sh build.sh build-companion-firmwares -Build all companion WiFi firmwares -$ sh build.sh build-companion-wifi-firmwares - Build all repeater firmwares $ sh build.sh build-repeater-firmwares -Build all repeater MQTT firmwares -$ sh build.sh build-repeater-mqtt-firmwares - Build all chat room server firmwares $ sh build.sh build-room-server-firmwares @@ -77,7 +49,7 @@ EOF # get a list of pio env names that start with "env:" get_pio_envs() { - run_pio project config | grep 'env:' | sed 's/env://' + pio project config | grep 'env:' | sed 's/env://' } # Catch cries for help before doing anything else. @@ -93,10 +65,7 @@ case $1 in esac # cache project config json for use in get_platform_for_env() -require_uv -sync_python_tooling - -PIO_CONFIG_JSON=$(run_pio project config --json-output) +PIO_CONFIG_JSON=$(pio project config --json-output) # $1 should be the string to find (case insensitive) get_pio_envs_containing_string() { @@ -124,7 +93,7 @@ get_pio_envs_ending_with_string() { # $1 should be the environment name get_platform_for_env() { local env_name=$1 - echo "$PIO_CONFIG_JSON" | run_python -c " + echo "$PIO_CONFIG_JSON" | python3 -c " import sys, json, re data = json.load(sys.stdin) for section, options in data: @@ -146,21 +115,6 @@ disable_debug_flags() { fi } -get_firmware_build_date() { - local env_name="$1" - local header="examples/simple_repeater/MyMesh.h" - - if [[ "$env_name" == *companion_radio* ]]; then - header="examples/companion_radio/MyMesh.h" - elif [[ "$env_name" == *room_server* ]]; then - header="examples/simple_room_server/MyMesh.h" - elif [[ "$env_name" == *sensor* ]]; then - header="examples/simple_sensor/SensorMesh.h" - fi - - sed -n 's/^[[:space:]]*#define[[:space:]][[:space:]]*FIRMWARE_BUILD_DATE[[:space:]][[:space:]]*"\([^"]*\)".*/\1/p' "$header" | head -n 1 -} - # build firmware for the provided pio env in $1 build_firmware() { # get env platform for post build actions @@ -169,12 +123,8 @@ build_firmware() { # get git commit sha COMMIT_HASH=$(git rev-parse --short HEAD) - # use the same fallback build date as direct PlatformIO builds - FIRMWARE_BUILD_DATE=$(get_firmware_build_date "$1") - if [ -z "$FIRMWARE_BUILD_DATE" ]; then - echo "FIRMWARE_BUILD_DATE could not be read for $1" - exit 1 - fi + # set firmware build date + FIRMWARE_BUILD_DATE=$(date '+%d-%b-%Y') # get FIRMWARE_VERSION, which should be provided by the environment if [ -z "$FIRMWARE_VERSION" ]; then @@ -182,41 +132,33 @@ build_firmware() { exit 1 fi - # set artifact version string - # e.g: v1.2.3-eastmesh-v1.0.1-abcdef - FIRMWARE_VERSION_BASE="${FIRMWARE_VERSION}" - if [ -n "$EASTMESH_VERSION" ]; then - FIRMWARE_VERSION_BASE="${FIRMWARE_VERSION_BASE}-eastmesh-${EASTMESH_VERSION}" - fi - FIRMWARE_VERSION_STRING="${FIRMWARE_VERSION_BASE}-${COMMIT_HASH}" - CLIENT_VERSION_STRING="eastmesh-${COMMIT_HASH}" - if [ -n "$EASTMESH_VERSION" ]; then - CLIENT_VERSION_STRING="eastmesh-${EASTMESH_VERSION}-${COMMIT_HASH}" - fi + # set firmware version string + # e.g: v1.0.0-abcdef + FIRMWARE_VERSION_STRING="${FIRMWARE_VERSION}-${COMMIT_HASH}" # craft filename # e.g: RAK_4631_Repeater-v1.0.0-SHA FIRMWARE_FILENAME="$1-${FIRMWARE_VERSION_STRING}" - # add build metadata to end of existing platformio build flags in environment vars - export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFIRMWARE_BUILD_DATE='\"${FIRMWARE_BUILD_DATE}\"' -DFIRMWARE_VERSION='\"${FIRMWARE_VERSION}\"' -DCLIENT_VERSION='\"${CLIENT_VERSION_STRING}\"'" + # add firmware version info to end of existing platformio build flags in environment vars + export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFIRMWARE_BUILD_DATE='\"${FIRMWARE_BUILD_DATE}\"' -DFIRMWARE_VERSION='\"${FIRMWARE_VERSION_STRING}\"'" # disable debug flags if requested disable_debug_flags # build firmware target - run_pio run -e $1 + pio run -e $1 # build merge-bin for esp32 fresh install, copy .bins to out folder (e.g: Heltec_v3_room_server-v1.0.0-SHA.bin) if [ "$ENV_PLATFORM" == "ESP32_PLATFORM" ]; then - run_pio run -t mergebin -e $1 + pio run -t mergebin -e $1 cp .pio/build/$1/firmware.bin out/${FIRMWARE_FILENAME}.bin 2>/dev/null || true cp .pio/build/$1/firmware-merged.bin out/${FIRMWARE_FILENAME}-merged.bin 2>/dev/null || true fi # build .uf2 for nrf52 boards, copy .uf2 and .zip to out folder (e.g: RAK_4631_Repeater-v1.0.0-SHA.uf2) if [ "$ENV_PLATFORM" == "NRF52_PLATFORM" ]; then - run_python bin/uf2conv/uf2conv.py .pio/build/$1/firmware.hex -c -o .pio/build/$1/firmware.uf2 -f 0xADA52840 + python3 bin/uf2conv/uf2conv.py .pio/build/$1/firmware.hex -c -o .pio/build/$1/firmware.uf2 -f 0xADA52840 cp .pio/build/$1/firmware.uf2 out/${FIRMWARE_FILENAME}.uf2 2>/dev/null || true cp .pio/build/$1/firmware.zip out/${FIRMWARE_FILENAME}.zip 2>/dev/null || true fi @@ -286,18 +228,6 @@ build_companion_firmwares() { } -build_companion_wifi_firmwares() { - - build_all_firmwares_by_suffix "_companion_radio_wifi" - -} - -build_repeater_mqtt_firmwares() { - - build_all_firmwares_by_suffix "_repeater_mqtt" - -} - build_room_server_firmwares() { # # build specific room server firmwares @@ -341,12 +271,8 @@ elif [[ $1 == "build-firmwares" ]]; then build_firmwares elif [[ $1 == "build-companion-firmwares" ]]; then build_companion_firmwares -elif [[ $1 == "build-companion-wifi-firmwares" ]]; then - build_companion_wifi_firmwares elif [[ $1 == "build-repeater-firmwares" ]]; then build_repeater_firmwares -elif [[ $1 == "build-repeater-mqtt-firmwares" ]]; then - build_repeater_mqtt_firmwares elif [[ $1 == "build-room-server-firmwares" ]]; then build_room_server_firmwares fi diff --git a/eastmesh-build.sh b/eastmesh-build.sh new file mode 100755 index 00000000..ed88070e --- /dev/null +++ b/eastmesh-build.sh @@ -0,0 +1,385 @@ +#!/usr/bin/env bash + +require_uv() { + if ! command -v uv >/dev/null 2>&1; then + echo "uv is required. Install it from https://docs.astral.sh/uv/" >&2 + exit 1 + fi +} + +sync_python_tooling() { + uv sync --locked --no-group docs >/dev/null + uv venv --allow-existing --seed >/dev/null +} + +run_python() { + uv run --no-sync python "$@" +} + +run_pio() { + uv run --no-sync pio "$@" +} + +global_usage() { + cat - < [target] + +Commands: + help|usage|-h|--help: Shows this message. + list|-l: List firmwares available to build. + build-firmware : Build the firmware for the given build target. + build-firmwares: Build all firmwares for all targets. + build-matching-firmwares : Build all firmwares for build targets containing the string given for . + build-companion-firmwares: Build all companion firmwares for all build targets. + build-companion-wifi-firmwares: Build all companion WiFi firmwares for all build targets. + build-repeater-firmwares: Build all repeater firmwares for all build targets. + build-repeater-bridge-espnow-firmwares: Build all repeater ESP-NOW bridge firmwares for all build targets. + build-repeater-mqtt-firmwares: Build all repeater MQTT firmwares for all build targets. + build-repeater-mqtt-bridge-firmwares: Build all repeater MQTT bridge firmwares for all build targets. + build-room-server-firmwares: Build all chat room server firmwares for all build targets. + +Examples: +Build firmware for the "RAK_4631_repeater" device target +$ sh eastmesh-build.sh build-firmware RAK_4631_repeater + +Build all firmwares for device targets containing the string "RAK_4631" +$ sh eastmesh-build.sh build-matching-firmwares + +Build all companion firmwares +$ sh eastmesh-build.sh build-companion-firmwares + +Build all companion WiFi firmwares +$ sh eastmesh-build.sh build-companion-wifi-firmwares + +Build all repeater firmwares +$ sh eastmesh-build.sh build-repeater-firmwares + +Build all repeater ESP-NOW bridge firmwares +$ sh eastmesh-build.sh build-repeater-bridge-espnow-firmwares + +Build all repeater MQTT firmwares +$ sh eastmesh-build.sh build-repeater-mqtt-firmwares + +Build all repeater MQTT bridge firmwares +$ sh eastmesh-build.sh build-repeater-mqtt-bridge-firmwares + +Build all chat room server firmwares +$ sh eastmesh-build.sh build-room-server-firmwares + +Environment Variables: + DISABLE_DEBUG=1: Disables all debug logging flags (MESH_DEBUG, MESH_PACKET_LOGGING, etc.) + If not set, debug flags from variant platformio.ini files are used. + +Examples: +Build without debug logging: +$ export FIRMWARE_VERSION=v1.0.0 +$ export DISABLE_DEBUG=1 +$ sh eastmesh-build.sh build-firmware RAK_4631_repeater + +Build with debug logging (default, uses flags from variant files): +$ export FIRMWARE_VERSION=v1.0.0 +$ sh eastmesh-build.sh build-firmware RAK_4631_repeater +EOF +} + +# get a list of pio env names that start with "env:" +get_pio_envs() { + run_pio project config --json-output | run_python -c " +import json +import sys + +for section, _options in json.load(sys.stdin): + if section.startswith('env:'): + print(section[4:]) +" +} + +# Catch cries for help before doing anything else. +case $1 in + help|usage|-h|--help) + global_usage + exit 1 + ;; + list|-l) + require_uv + sync_python_tooling + get_pio_envs + exit 0 + ;; +esac + +# cache project config json for use in get_platform_for_env() +require_uv +sync_python_tooling + +PIO_CONFIG_JSON=$(run_pio project config --json-output) + +# $1 should be the string to find (case insensitive) +get_pio_envs_containing_string() { + shopt -s nocasematch + envs=($(get_pio_envs)) + for env in "${envs[@]}"; do + if [[ "$env" == *${1}* ]]; then + echo $env + fi + done +} + +# $1 should be the string to find (case insensitive) +get_pio_envs_ending_with_string() { + shopt -s nocasematch + envs=($(get_pio_envs)) + for env in "${envs[@]}"; do + if [[ "$env" == *${1} ]]; then + echo $env + fi + done +} + +# get platform flag for a given environment +# $1 should be the environment name +get_platform_for_env() { + local env_name=$1 + echo "$PIO_CONFIG_JSON" | run_python -c " +import sys, json, re +data = json.load(sys.stdin) +for section, options in data: + if section == 'env:$env_name': + for key, value in options: + if key == 'build_flags': + for flag in value: + match = re.search(r'(ESP32_PLATFORM|NRF52_PLATFORM|STM32_PLATFORM|RP2040_PLATFORM)', flag) + if match: + print(match.group(1)) + sys.exit(0) +" +} + +# disable all debug logging flags if DISABLE_DEBUG=1 is set +disable_debug_flags() { + if [ "$DISABLE_DEBUG" == "1" ]; then + export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UMESH_DEBUG -UBLE_DEBUG_LOGGING -UWIFI_DEBUG_LOGGING -UBRIDGE_DEBUG -UGPS_NMEA_DEBUG -UCORE_DEBUG_LEVEL -UESPNOW_DEBUG_LOGGING -UDEBUG_RP2040_WIRE -UDEBUG_RP2040_SPI -UDEBUG_RP2040_CORE -UDEBUG_RP2040_PORT -URADIOLIB_DEBUG_SPI -UCFG_DEBUG -URADIOLIB_DEBUG_BASIC -URADIOLIB_DEBUG_PROTOCOL" + fi +} + +get_firmware_build_date() { + local env_name="$1" + local header="examples/simple_repeater/MyMesh.h" + + if [[ "$env_name" == *companion_radio* ]]; then + header="examples/companion_radio/MyMesh.h" + elif [[ "$env_name" == *room_server* ]]; then + header="examples/simple_room_server/MyMesh.h" + elif [[ "$env_name" == *sensor* ]]; then + header="examples/simple_sensor/SensorMesh.h" + fi + + sed -n 's/^[[:space:]]*#define[[:space:]][[:space:]]*FIRMWARE_BUILD_DATE[[:space:]][[:space:]]*"\([^"]*\)".*/\1/p' "$header" | head -n 1 +} + +# build firmware for the provided pio env in $1 +build_firmware() { + # get env platform for post build actions + ENV_PLATFORM=($(get_platform_for_env $1)) + + # get git commit sha + COMMIT_HASH=$(git rev-parse --short HEAD) + + # use the same fallback build date as direct PlatformIO builds + FIRMWARE_BUILD_DATE=$(get_firmware_build_date "$1") + if [ -z "$FIRMWARE_BUILD_DATE" ]; then + echo "FIRMWARE_BUILD_DATE could not be read for $1" + exit 1 + fi + + # get FIRMWARE_VERSION, which should be provided by the environment + if [ -z "$FIRMWARE_VERSION" ]; then + echo "FIRMWARE_VERSION must be set in environment" + exit 1 + fi + + # set artifact version string + # e.g: v1.2.3-eastmesh-v1.0.1-abcdef + FIRMWARE_VERSION_BASE="${FIRMWARE_VERSION}" + if [ -n "$EASTMESH_VERSION" ]; then + FIRMWARE_VERSION_BASE="${FIRMWARE_VERSION_BASE}-eastmesh-${EASTMESH_VERSION}" + fi + FIRMWARE_VERSION_STRING="${FIRMWARE_VERSION_BASE}-${COMMIT_HASH}" + CLIENT_VERSION_STRING="eastmesh-${COMMIT_HASH}" + if [ -n "$EASTMESH_VERSION" ]; then + CLIENT_VERSION_STRING="eastmesh-${EASTMESH_VERSION}-${COMMIT_HASH}" + fi + + # craft filename + # e.g: RAK_4631_Repeater-v1.0.0-SHA + FIRMWARE_FILENAME="$1-${FIRMWARE_VERSION_STRING}" + + # add build metadata to end of existing platformio build flags in environment vars + export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFIRMWARE_BUILD_DATE='\"${FIRMWARE_BUILD_DATE}\"' -DFIRMWARE_VERSION='\"${FIRMWARE_VERSION}\"' -DCLIENT_VERSION='\"${CLIENT_VERSION_STRING}\"'" + + # disable debug flags if requested + disable_debug_flags + + # build firmware target + run_pio run -e $1 + + # build merge-bin for esp32 fresh install, copy .bins to out folder (e.g: Heltec_v3_room_server-v1.0.0-SHA.bin) + if [ "$ENV_PLATFORM" == "ESP32_PLATFORM" ]; then + run_pio run -t mergebin -e $1 + cp .pio/build/$1/firmware.bin out/${FIRMWARE_FILENAME}.bin 2>/dev/null || true + cp .pio/build/$1/firmware-merged.bin out/${FIRMWARE_FILENAME}-merged.bin 2>/dev/null || true + fi + + # build .uf2 for nrf52 boards, copy .uf2 and .zip to out folder (e.g: RAK_4631_Repeater-v1.0.0-SHA.uf2) + if [ "$ENV_PLATFORM" == "NRF52_PLATFORM" ]; then + run_python bin/uf2conv/uf2conv.py .pio/build/$1/firmware.hex -c -o .pio/build/$1/firmware.uf2 -f 0xADA52840 + cp .pio/build/$1/firmware.uf2 out/${FIRMWARE_FILENAME}.uf2 2>/dev/null || true + cp .pio/build/$1/firmware.zip out/${FIRMWARE_FILENAME}.zip 2>/dev/null || true + fi + + # for stm32, copy .bin and .hex to out folder + if [ "$ENV_PLATFORM" == "STM32_PLATFORM" ]; then + cp .pio/build/$1/firmware.bin out/${FIRMWARE_FILENAME}.bin 2>/dev/null || true + cp .pio/build/$1/firmware.hex out/${FIRMWARE_FILENAME}.hex 2>/dev/null || true + fi + + # for rp2040, copy .bin and .uf2 to out folder + if [ "$ENV_PLATFORM" == "RP2040_PLATFORM" ]; then + cp .pio/build/$1/firmware.bin out/${FIRMWARE_FILENAME}.bin 2>/dev/null || true + cp .pio/build/$1/firmware.uf2 out/${FIRMWARE_FILENAME}.uf2 2>/dev/null || true + fi + +} + +# firmwares containing $1 will be built +build_all_firmwares_matching() { + envs=($(get_pio_envs_containing_string "$1")) + for env in "${envs[@]}"; do + build_firmware $env + done +} + +# firmwares ending with $1 will be built +build_all_firmwares_by_suffix() { + envs=($(get_pio_envs_ending_with_string "$1")) + for env in "${envs[@]}"; do + build_firmware $env + done +} + +build_repeater_firmwares() { + +# # build specific repeater firmwares +# build_firmware "Heltec_v2_repeater" +# build_firmware "Heltec_v3_repeater" +# build_firmware "Xiao_C3_Repeater_sx1262" +# build_firmware "Xiao_S3_WIO_Repeater" +# build_firmware "LilyGo_T3S3_sx1262_Repeater" +# build_firmware "RAK_4631_Repeater" + + # build all repeater firmwares + build_all_firmwares_by_suffix "_repeater" + +} + +build_repeater_bridge_espnow_firmwares() { + + build_all_firmwares_by_suffix "_repeater_bridge_espnow" + +} + +build_companion_firmwares() { + +# # build specific companion firmwares +# build_firmware "Heltec_v2_companion_radio_usb" +# build_firmware "Heltec_v2_companion_radio_ble" +# build_firmware "Heltec_v3_companion_radio_usb" +# build_firmware "Heltec_v3_companion_radio_ble" +# build_firmware "Xiao_S3_WIO_companion_radio_ble" +# build_firmware "LilyGo_T3S3_sx1262_companion_radio_usb" +# build_firmware "LilyGo_T3S3_sx1262_companion_radio_ble" +# build_firmware "RAK_4631_companion_radio_usb" +# build_firmware "RAK_4631_companion_radio_ble" +# build_firmware "t1000e_companion_radio_ble" + + # build all companion firmwares + build_all_firmwares_by_suffix "_companion_radio_usb" + build_all_firmwares_by_suffix "_companion_radio_ble" + +} + +build_companion_wifi_firmwares() { + + build_all_firmwares_by_suffix "_companion_radio_wifi" + +} + +build_repeater_mqtt_firmwares() { + + build_all_firmwares_by_suffix "_repeater_mqtt" + +} + +build_repeater_mqtt_bridge_firmwares() { + + build_all_firmwares_by_suffix "_repeater_mqtt_bridge" + +} + +build_room_server_firmwares() { + +# # build specific room server firmwares +# build_firmware "Heltec_v3_room_server" +# build_firmware "RAK_4631_room_server" + + # build all room server firmwares + build_all_firmwares_by_suffix "_room_server" + +} + +build_firmwares() { + build_companion_firmwares + build_repeater_firmwares + build_room_server_firmwares +} + +# clean build dir +rm -rf out +mkdir -p out + +# handle script args +if [[ $1 == "build-firmware" ]]; then + TARGETS=${@:2} + if [ "$TARGETS" ]; then + for env in $TARGETS; do + build_firmware $env + done + else + echo "usage: $0 build-firmware " + exit 1 + fi +elif [[ $1 == "build-matching-firmwares" ]]; then + if [ "$2" ]; then + build_all_firmwares_matching $2 + else + echo "usage: $0 build-matching-firmwares " + exit 1 + fi +elif [[ $1 == "build-firmwares" ]]; then + build_firmwares +elif [[ $1 == "build-companion-firmwares" ]]; then + build_companion_firmwares +elif [[ $1 == "build-companion-wifi-firmwares" ]]; then + build_companion_wifi_firmwares +elif [[ $1 == "build-repeater-firmwares" ]]; then + build_repeater_firmwares +elif [[ $1 == "build-repeater-bridge-espnow-firmwares" ]]; then + build_repeater_bridge_espnow_firmwares +elif [[ $1 == "build-repeater-mqtt-firmwares" ]]; then + build_repeater_mqtt_firmwares +elif [[ $1 == "build-repeater-mqtt-bridge-firmwares" ]]; then + build_repeater_mqtt_bridge_firmwares +elif [[ $1 == "build-room-server-firmwares" ]]; then + build_room_server_firmwares +fi diff --git a/eastmesh-docs/custom-cli.md b/eastmesh-docs/custom-cli.md index 84421883..c07e74aa 100644 --- a/eastmesh-docs/custom-cli.md +++ b/eastmesh-docs/custom-cli.md @@ -63,13 +63,43 @@ Legacy dotted aliases are also accepted: ### WiFi Settings For MQTT Repeaters -- `get wifi.status`: shows SSID, connection state, raw WiFi status code, and IP when connected. +- `get wifi.status`: shows SSID, connection state, raw WiFi status code, IP, channel, and signal when connected. - `get wifi.ssid`: shows the configured WiFi SSID. - `set wifi.ssid `: sets the WiFi SSID. - `set wifi.pwd `: sets the WiFi password. - `get wifi.powersaving`: shows the current WiFi power save mode. - `set wifi.powersaving none|min|max`: sets WiFi power saving mode. +### ESP-NOW Bridge Settings For MQTT Bridge Repeaters + +These commands are available on `*_repeater_mqtt_bridge` firmware targets. + +- `get bridge.channel`: shows the configured ESP-NOW bridge channel. +- `set bridge.channel `: sets the ESP-NOW bridge channel and restarts the bridge. Use a value from `1` to `14`. +- `get bridge.secret`: shows the configured ESP-NOW bridge secret. +- `set bridge.secret `: sets the shared ESP-NOW bridge secret and restarts the bridge. + +After running `set bridge.channel`, expect the bridge and web panel connection to drop briefly while the radio restarts. On current MQTT bridge test builds, this can look like the board rebooted. + +For `*_repeater_mqtt_bridge` builds that are connected to WiFi, the ESP-NOW bridge channel must match the active 2.4 GHz WiFi channel: + +1. Run `get wifi.status`. +2. Read the `channel:` value from the connected WiFi status. +3. Run `get bridge.channel`. +4. If the values differ, run `set bridge.channel ` using the WiFi channel value. +5. Use the same `bridge.channel` and `bridge.secret` on every ESP-NOW bridge node that should talk together. + +Example: + +```text +> get wifi.status +> ssid:EastMesh-IoT status:connected code:3 state:connected ip:192.168.1.50 channel:6 rssi:-61 quality:78% signal:good +> get bridge.channel +> 1 +> set bridge.channel 6 +OK +``` + ### Web Panel Controls - `get web` @@ -141,7 +171,7 @@ To enter `CLI Rescue`: - long-press the user button within the first 8 seconds after boot - wait for `========= CLI Rescue =========` -- `get wifi.status`: shows configured SSID, connection status, raw WiFi status code, and IP when connected. +- `get wifi.status`: shows configured SSID, connection status, raw WiFi status code, IP, channel, and signal when connected. - `get wifi.ssid`: shows the configured WiFi SSID. - `get wifi.powersaving`: shows the current WiFi power saving mode. - `set wifi.ssid `: saves a WiFi SSID and immediately retries connection. diff --git a/eastmesh-docs/local-builds.md b/eastmesh-docs/local-builds.md index 4951b478..c00261b8 100644 --- a/eastmesh-docs/local-builds.md +++ b/eastmesh-docs/local-builds.md @@ -17,7 +17,7 @@ uv sync List build targets: ```bash -bash build.sh list +bash eastmesh-build.sh list ``` Plain PlatformIO build for a single target: @@ -47,7 +47,7 @@ Companion WiFi: ```bash export FIRMWARE_VERSION=v1.14.1 -bash build.sh build-firmware heltec_v4_companion_radio_wifi +bash eastmesh-build.sh build-firmware heltec_v4_companion_radio_wifi ``` Repeater MQTT: @@ -55,7 +55,7 @@ Repeater MQTT: ```bash export FIRMWARE_VERSION=v1.14.1 export EASTMESH_VERSION=v1.0.1 -bash build.sh build-firmware heltec_v4_repeater_mqtt +bash eastmesh-build.sh build-firmware heltec_v4_repeater_mqtt ``` This produces versioned artifacts in `out/`. diff --git a/eastmesh-docs/web-panel.md b/eastmesh-docs/web-panel.md index 33185a5b..d97dd712 100644 --- a/eastmesh-docs/web-panel.md +++ b/eastmesh-docs/web-panel.md @@ -59,7 +59,7 @@ Some constrained targets disable the web panel to stay within flash limits. If y Useful CLI commands: -- `get wifi.status`: shows WiFi state and IP address when connected. +- `get wifi.status`: shows WiFi state, IP address, channel, and signal when connected. - `get web.status`: shows whether the web panel is up and which URL to use. Example: diff --git a/release-notes.yml b/release-notes.yml index 1e61e9fa..ff46764c 100644 --- a/release-notes.yml +++ b/release-notes.yml @@ -1,7 +1,9 @@ schema_version: 1 tracks: - companion-wifi + - repeater-bridge-espnow - repeater-mqtt + - repeater-mqtt-bridge generated_from: "Adjacent git tag comparisons plus non-merge commit subjects." releases: @@ -581,3 +583,63 @@ releases: area: build text: "Aligned release-style builds with direct PlatformIO builds by using the firmware source build date instead of stamping the current build day into `ver` output." breaking_changes: [] + + - track: repeater-bridge-espnow + version: "1.15.0" + tag: "repeater-bridge-espnow-v1.15.0" + date: "2026-05-05" + previous_version: null + summary: "Adds a tagged release workflow for upstream-versioned repeater ESP-NOW bridge firmware artifacts." + changes: + - type: added + area: release + text: "Added the `repeater-bridge-espnow-v*` release tag format and workflow for building repeater ESP-NOW bridge firmware artifacts using the official upstream MeshCore version." + - type: fixed + area: build + text: "Kept pure ESP-NOW bridge targets out of the web-panel link path so they no longer fail with unresolved web service symbols." + - type: docs + area: release + text: "Updated release guidance to document the repeater ESP-NOW bridge tag format and versioning rule." + breaking_changes: [] + + - track: repeater-mqtt + version: "1.4.0" + tag: "repeater-mqtt-eastmesh-v1.4.0" + date: "2026-05-05" + previous_version: "1.3.15" + summary: "Adds bridge firmware release plumbing and hardens web-panel feature defaults so non-web bridge targets build cleanly." + changes: + - type: added + area: release + text: "Documented the expanded bridge firmware release tracks alongside the existing repeater MQTT release flow." + - type: fixed + area: web-panel + text: "Scoped the default web-panel enablement to MQTT uplink builds so non-web ESP32 bridge targets do not compile calls to web services that are not linked." + - type: changed + area: build + text: "Tightened EastMesh build target discovery so generated `${env:...}` references are not mistaken for PlatformIO environments." + breaking_changes: [] + + - track: repeater-mqtt-bridge + version: "1.4.0" + tag: "repeater-mqtt-bridge-eastmesh-v1.4.0" + date: "2026-05-05" + previous_version: null + summary: "First EastMesh repeater MQTT bridge release track, combining MQTT uplink builds with ESP-NOW bridge firmware artifacts." + changes: + - type: added + area: build + text: "Added `*_repeater_mqtt_bridge` build coverage for EastMesh MQTT repeater targets." + - type: added + area: release + text: "Added the `repeater-mqtt-bridge-eastmesh-v*` release tag format and draft-release workflow for MQTT bridge firmware artifacts." + - type: added + area: cli + text: "Exposed the active Wi-Fi channel in `get wifi.status` so MQTT bridge operators can align `bridge.channel` with the connected 2.4 GHz Wi-Fi channel." + - type: docs + area: cli + text: "Added MQTT bridge CLI guidance for `get/set bridge.channel`, `get/set bridge.secret`, and channel alignment with `get wifi.status`." + - type: fixed + area: web-panel + text: "Kept the web service suspended during OTA start so the Start OTA path does not tear down the panel while OTA is taking over port `80`." + breaking_changes: [] diff --git a/src/helpers/NetworkService.cpp b/src/helpers/NetworkService.cpp index a3483c0b..d383881b 100644 --- a/src/helpers/NetworkService.cpp +++ b/src/helpers/NetworkService.cpp @@ -180,9 +180,9 @@ void NetworkService::formatWifiStatusReply(char* reply, size_t reply_size) const if (wifi_status == WL_CONNECTED) { const int rssi_dbm = WiFi.RSSI(); snprintf(reply, reply_size, - "> ssid:%s status:%s code:%d state:%s ip:%s rssi:%d quality:%d%% signal:%s", + "> ssid:%s status:%s code:%d state:%s ip:%s channel:%d rssi:%d quality:%d%% signal:%s", _prefs.wifi_ssid, status, static_cast(wifi_status), state, WiFi.localIP().toString().c_str(), - rssi_dbm, getWifiQualityPercent(rssi_dbm), getWifiQualityLabel(rssi_dbm)); + WiFi.channel(), rssi_dbm, getWifiQualityPercent(rssi_dbm), getWifiQualityLabel(rssi_dbm)); } else { snprintf(reply, reply_size, "> ssid:%s status:%s code:%d state:%s", _prefs.wifi_ssid[0] ? _prefs.wifi_ssid : "-", status, static_cast(wifi_status), state); diff --git a/src/helpers/web/WebPanelServer.h b/src/helpers/web/WebPanelServer.h index e1d0ce58..73918e50 100644 --- a/src/helpers/web/WebPanelServer.h +++ b/src/helpers/web/WebPanelServer.h @@ -4,7 +4,7 @@ #if defined(ESP_PLATFORM) #include - #if !defined(WITH_WEB_PANEL) + #if defined(WITH_MQTT_UPLINK) && !defined(WITH_WEB_PANEL) #define WITH_WEB_PANEL 1 #endif #if WITH_WEB_PANEL diff --git a/src/helpers/web/WebService.cpp b/src/helpers/web/WebService.cpp index 2f588d11..f0323dd4 100644 --- a/src/helpers/web/WebService.cpp +++ b/src/helpers/web/WebService.cpp @@ -98,16 +98,16 @@ void WebService::formatWebStatusReply(char* reply, size_t reply_size) const { #if defined(ESP_PLATFORM) && WITH_WEB_PANEL void WebService::ensureWebServer() { - if (_runner == nullptr || _prefs.web_enabled == 0 || _network == nullptr || !_network->isWifiConnected()) { - _panel.stop(); - return; - } if (_suspended_for_ota) { if (_panel.isRunning()) { _panel.stopRedirectServer(); } return; } + if (_runner == nullptr || _prefs.web_enabled == 0 || _network == nullptr || !_network->isWifiConnected()) { + _panel.stop(); + return; + } if (_panel.isRunning()) { return; } diff --git a/variants/eastmesh_mqtt/platformio.ini b/variants/eastmesh_mqtt/platformio.ini index 82096f15..23044d7d 100644 --- a/variants/eastmesh_mqtt/platformio.ini +++ b/variants/eastmesh_mqtt/platformio.ini @@ -863,3 +863,267 @@ build_flags = lib_deps = ${Xiao_S3_WIO.lib_deps} ${esp32_ota.lib_deps} + +[env:Ebyte_EoRa-S3_Repeater_mqtt_bridge] +extends = env:Ebyte_EoRa-S3_Repeater_mqtt +build_flags = + ${env:Ebyte_EoRa-S3_Repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Ebyte_EoRa-S3_Repeater_mqtt.build_src_filter} + + + +[env:Generic_E22_sx1262_repeater_mqtt_bridge] +extends = env:Generic_E22_sx1262_repeater_mqtt +build_flags = + ${env:Generic_E22_sx1262_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Generic_E22_sx1262_repeater_mqtt.build_src_filter} + + + +[env:Generic_E22_sx1268_repeater_mqtt_bridge] +extends = env:Generic_E22_sx1268_repeater_mqtt +build_flags = + ${env:Generic_E22_sx1268_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Generic_E22_sx1268_repeater_mqtt.build_src_filter} + + + +[env:Heltec_E213_repeater_mqtt_bridge] +extends = env:Heltec_E213_repeater_mqtt +build_flags = + ${env:Heltec_E213_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Heltec_E213_repeater_mqtt.build_src_filter} + + + +[env:Heltec_E290_repeater_mqtt_bridge] +extends = env:Heltec_E290_repeater_mqtt +build_flags = + ${env:Heltec_E290_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Heltec_E290_repeater_mqtt.build_src_filter} + + + +[env:Heltec_T190_repeater_mqtt_bridge] +extends = env:Heltec_T190_repeater_mqtt +build_flags = + ${env:Heltec_T190_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Heltec_T190_repeater_mqtt.build_src_filter} + + + +[env:heltec_tracker_v2_repeater_mqtt_bridge] +extends = env:heltec_tracker_v2_repeater_mqtt +build_flags = + ${env:heltec_tracker_v2_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:heltec_tracker_v2_repeater_mqtt.build_src_filter} + + + +[env:Heltec_v2_repeater_mqtt_bridge] +extends = env:Heltec_v2_repeater_mqtt +build_flags = + ${env:Heltec_v2_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Heltec_v2_repeater_mqtt.build_src_filter} + + + +[env:Heltec_v3_repeater_mqtt_bridge] +extends = env:Heltec_v3_repeater_mqtt +build_flags = + ${env:Heltec_v3_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Heltec_v3_repeater_mqtt.build_src_filter} + + + +[env:heltec_v4_repeater_mqtt_bridge] +extends = env:heltec_v4_repeater_mqtt +build_flags = + ${env:heltec_v4_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:heltec_v4_repeater_mqtt.build_src_filter} + + + +[env:heltec_v4_tft_repeater_mqtt_bridge] +extends = env:heltec_v4_tft_repeater_mqtt +build_flags = + ${env:heltec_v4_tft_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:heltec_v4_tft_repeater_mqtt.build_src_filter} + + + +[env:Heltec_Wireless_Paper_repeater_mqtt_bridge] +extends = env:Heltec_Wireless_Paper_repeater_mqtt +build_flags = + ${env:Heltec_Wireless_Paper_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Heltec_Wireless_Paper_repeater_mqtt.build_src_filter} + + + +[env:Heltec_Wireless_Tracker_repeater_mqtt_bridge] +extends = env:Heltec_Wireless_Tracker_repeater_mqtt +build_flags = + ${env:Heltec_Wireless_Tracker_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Heltec_Wireless_Tracker_repeater_mqtt.build_src_filter} + + + +[env:Heltec_WSL3_repeater_mqtt_bridge] +extends = env:Heltec_WSL3_repeater_mqtt +build_flags = + ${env:Heltec_WSL3_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Heltec_WSL3_repeater_mqtt.build_src_filter} + + + +[env:LilyGo_T3S3_sx1262_repeater_mqtt_bridge] +extends = env:LilyGo_T3S3_sx1262_repeater_mqtt +build_flags = + ${env:LilyGo_T3S3_sx1262_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:LilyGo_T3S3_sx1262_repeater_mqtt.build_src_filter} + + + +[env:LilyGo_T3S3_sx1276_repeater_mqtt_bridge] +extends = env:LilyGo_T3S3_sx1276_repeater_mqtt +build_flags = + ${env:LilyGo_T3S3_sx1276_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:LilyGo_T3S3_sx1276_repeater_mqtt.build_src_filter} + + + +[env:LilyGo_TBeam_1W_repeater_mqtt_bridge] +extends = env:LilyGo_TBeam_1W_repeater_mqtt +build_flags = + ${env:LilyGo_TBeam_1W_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:LilyGo_TBeam_1W_repeater_mqtt.build_src_filter} + + + +[env:LilyGo_TDeck_repeater_mqtt_bridge] +extends = env:LilyGo_TDeck_repeater_mqtt +build_flags = + ${env:LilyGo_TDeck_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:LilyGo_TDeck_repeater_mqtt.build_src_filter} + + + +[env:LilyGo_Tlora_C6_repeater_mqtt_bridge] +extends = env:LilyGo_Tlora_C6_repeater_mqtt +build_flags = + ${env:LilyGo_Tlora_C6_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:LilyGo_Tlora_C6_repeater_mqtt.build_src_filter} + + + +[env:M5Stack_Unit_C6L_repeater_mqtt_bridge] +extends = env:M5Stack_Unit_C6L_repeater_mqtt +build_flags = + ${env:M5Stack_Unit_C6L_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:M5Stack_Unit_C6L_repeater_mqtt.build_src_filter} + + + +[env:Meshadventurer_sx1262_repeater_mqtt_bridge] +extends = env:Meshadventurer_sx1262_repeater_mqtt +build_flags = + ${env:Meshadventurer_sx1262_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Meshadventurer_sx1262_repeater_mqtt.build_src_filter} + + + +[env:Meshadventurer_sx1268_repeater_mqtt_bridge] +extends = env:Meshadventurer_sx1268_repeater_mqtt +build_flags = + ${env:Meshadventurer_sx1268_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Meshadventurer_sx1268_repeater_mqtt.build_src_filter} + + + +[env:nibble_screen_connect_repeater_mqtt_bridge] +extends = env:nibble_screen_connect_repeater_mqtt +build_flags = + ${env:nibble_screen_connect_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:nibble_screen_connect_repeater_mqtt.build_src_filter} + + + +[env:RAK_3112_repeater_mqtt_bridge] +extends = env:RAK_3112_repeater_mqtt +build_flags = + ${env:RAK_3112_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:RAK_3112_repeater_mqtt.build_src_filter} + + + +[env:Station_G2_repeater_mqtt_bridge] +extends = env:Station_G2_repeater_mqtt +build_flags = + ${env:Station_G2_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Station_G2_repeater_mqtt.build_src_filter} + + + +[env:Station_G2_logging_repeater_mqtt_bridge] +extends = env:Station_G2_logging_repeater_mqtt +build_flags = + ${env:Station_G2_logging_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Station_G2_logging_repeater_mqtt.build_src_filter} + + + +[env:T_Beam_S3_Supreme_SX1262_repeater_mqtt_bridge] +extends = env:T_Beam_S3_Supreme_SX1262_repeater_mqtt +build_flags = + ${env:T_Beam_S3_Supreme_SX1262_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:T_Beam_S3_Supreme_SX1262_repeater_mqtt.build_src_filter} + + + +[env:Tbeam_SX1262_repeater_mqtt_bridge] +extends = env:Tbeam_SX1262_repeater_mqtt +build_flags = + ${env:Tbeam_SX1262_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Tbeam_SX1262_repeater_mqtt.build_src_filter} + + + +[env:Tbeam_SX1276_repeater_mqtt_bridge] +extends = env:Tbeam_SX1276_repeater_mqtt +build_flags = + ${env:Tbeam_SX1276_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Tbeam_SX1276_repeater_mqtt.build_src_filter} + + + +[env:ThinkNode_M2_Repeater_mqtt_bridge] +extends = env:ThinkNode_M2_Repeater_mqtt +build_flags = + ${env:ThinkNode_M2_Repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:ThinkNode_M2_Repeater_mqtt.build_src_filter} + + + +[env:ThinkNode_M5_Repeater_mqtt_bridge] +extends = env:ThinkNode_M5_Repeater_mqtt +build_flags = + ${env:ThinkNode_M5_Repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:ThinkNode_M5_Repeater_mqtt.build_src_filter} + + + +[env:WHY2025_badge_repeater_mqtt_bridge] +extends = env:WHY2025_badge_repeater_mqtt +build_flags = + ${env:WHY2025_badge_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:WHY2025_badge_repeater_mqtt.build_src_filter} + + + +[env:Xiao_S3_WIO_repeater_mqtt_bridge] +extends = env:Xiao_S3_WIO_repeater_mqtt +build_flags = + ${env:Xiao_S3_WIO_repeater_mqtt.build_flags} + -D WITH_ESPNOW_BRIDGE=1 +build_src_filter = ${env:Xiao_S3_WIO_repeater_mqtt.build_src_filter} + +