diff --git a/.github/workflows/custom_build.yml b/.github/workflows/custom_build.yml index 8ed3792..29b83dc 100644 --- a/.github/workflows/custom_build.yml +++ b/.github/workflows/custom_build.yml @@ -165,6 +165,15 @@ jobs: exit 1 fi + - name: Download Meshtastic ESP OTA companion (if applicable) + shell: bash + run: | + set -e + ROOT=$(cat /tmp/fw-src-root.txt) + cd "$ROOT" + BUILD_DIR=".pio/build/${{ inputs.target_env }}" + bash "${{ github.workspace }}/scripts/download-meshtastic-ota.sh" "$ROOT/$BUILD_DIR" + - name: Package and upload firmware bundle id: pio env: diff --git a/.github/workflows/custom_build_test.yml b/.github/workflows/custom_build_test.yml index 8ed3792..29b83dc 100644 --- a/.github/workflows/custom_build_test.yml +++ b/.github/workflows/custom_build_test.yml @@ -165,6 +165,15 @@ jobs: exit 1 fi + - name: Download Meshtastic ESP OTA companion (if applicable) + shell: bash + run: | + set -e + ROOT=$(cat /tmp/fw-src-root.txt) + cd "$ROOT" + BUILD_DIR=".pio/build/${{ inputs.target_env }}" + bash "${{ github.workspace }}/scripts/download-meshtastic-ota.sh" "$ROOT/$BUILD_DIR" + - name: Package and upload firmware bundle id: pio env: diff --git a/scripts/download-meshtastic-ota.sh b/scripts/download-meshtastic-ota.sh new file mode 100755 index 0000000..573c7d3 --- /dev/null +++ b/scripts/download-meshtastic-ota.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# Download BLE/unified OTA companion image into PlatformIO BUILD_DIR when Meshtastic *.mt.json is present. +# No-op for non-Meshtastic builds (no mt.json). Mirrors vendor/meshtastic-firmware/.github/workflows/build_firmware.yml. +set -euo pipefail + +BUILD_DIR="${1:?usage: download-meshtastic-ota.sh BUILD_DIR}" + +shopt -s nullglob +mt_json=( "$BUILD_DIR"/*.mt.json ) +shopt -u nullglob + +if [ "${#mt_json[@]}" -eq 0 ]; then + echo "No *.mt.json in $BUILD_DIR — skip OTA download" + exit 0 +fi + +# Prefer firmware-*.mt.json when multiple (same heuristic as emit-flash-manifest.py) +MT_JSON="" +for f in "${mt_json[@]}"; do + base=$(basename "$f") + if [[ "$base" =~ ^firmware-.+\.mt\.json$ ]]; then + MT_JSON=$f + break + fi +done +if [ -z "$MT_JSON" ]; then + MT_JSON="${mt_json[0]}" +fi + +MCU=$(python3 -c "import json,sys; print((json.load(open(sys.argv[1], encoding='utf-8')).get('mcu') or '').lower())" "$MT_JSON") + +case "$MCU" in + esp32|esp32s3) + dest="$BUILD_DIR/mt-${MCU}-ota.bin" + if [ -f "$dest" ]; then + echo "OTA already present: $dest" + exit 0 + fi + url="https://github.com/meshtastic/esp32-unified-ota/releases/latest/download/mt-${MCU}-ota.bin" + echo "Downloading $url -> $dest" + curl -fsSL -o "$dest" "$url" + ;; + esp32c3|esp32c6) + dest="$BUILD_DIR/bleota-c3.bin" + if [ -f "$dest" ]; then + echo "OTA already present: $dest" + exit 0 + fi + url="https://github.com/meshtastic/firmware-ota/releases/latest/download/firmware-c3.bin" + echo "Downloading $url -> $dest" + curl -fsSL -o "$dest" "$url" + ;; + *) + echo "MCU '$MCU' — no Meshtastic GitHub OTA download rule; skip" + exit 0 + ;; +esac diff --git a/scripts/emit-flash-manifest.py b/scripts/emit-flash-manifest.py index 15c9ab9..7507e21 100644 --- a/scripts/emit-flash-manifest.py +++ b/scripts/emit-flash-manifest.py @@ -8,7 +8,7 @@ targetFamily from PlatformIO when missing. Otherwise, if Meshtastic-style *.mt.json is present, synthesize a manifest from partition table + on-disk split artifacts (no *.factory.bin — USB bundles omit the merged image). Only LittleFS rows use optional:true (Mesh Forge: -Reset device storage). +Reset device storage). OTA slots accept mt-*-ota.bin (ESP32/S3) or bleota-c3.bin (C3/C6). Optional args: PROJECT_ROOT TARGET_ENV — merged PIO config for that env fills targetFamily (and platform/board) for the USB flasher UI. @@ -230,6 +230,12 @@ def emit_from_mt(build_dir: str, mt: dict) -> dict | None: if off is not None: add(n, off, optional=False) + # ESP32-C3/C6 Meshtastic workflow uses bleota-c3.bin at ota_1 (see build_firmware.yml). + if "bleota-c3.bin" in names: + off = ota1_offset(parts) + if off is not None: + add("bleota-c3.bin", off, optional=False) + if not images: return None