π€ ESP32_S3_32 firmware v1.28.0 (pyDirect@2333a2d81095537c2fd97714a9caβ¦ #511
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Bundle Firmware Workflow | |
| # Merges firmware components (from pyDirect) with VFS device-scripts into deployable .bin files | |
| # | |
| # Triggers: | |
| # - Push to boards/firmware/components/** (new firmware from pyDirect CI) | |
| # - Push to boards/firmware/device-scripts/** (VFS content changes) | |
| # - Manual trigger | |
| name: Bundle Firmware | |
| on: | |
| push: | |
| paths: | |
| - 'boards/firmware/components/**' | |
| - 'boards/firmware/device-scripts/**' | |
| branches: [main] | |
| workflow_dispatch: | |
| # Only one bundle job at a time β later pushes cancel in-progress runs | |
| concurrency: | |
| group: bundle-firmware | |
| cancel-in-progress: true | |
| jobs: | |
| bundle: | |
| name: Build merged firmware | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout scriptostudio | |
| uses: actions/checkout@v4 | |
| - name: Install tools | |
| run: | | |
| # Install mklittlefs | |
| wget -q https://github.com/earlephilhower/mklittlefs/releases/download/4.1.0/x86_64-linux-gnu-mklittlefs-42acb97.tar.gz | |
| tar -xzf x86_64-linux-gnu-mklittlefs-42acb97.tar.gz --strip-components=1 | |
| sudo mv mklittlefs /usr/local/bin/ | |
| chmod +x /usr/local/bin/mklittlefs | |
| # Install esptool | |
| pip install esptool | |
| - name: Verify components exist | |
| run: | | |
| COMPONENTS="boards/firmware/components" | |
| if [ ! -d "$COMPONENTS" ] || [ -z "$(ls -A $COMPONENTS 2>/dev/null)" ]; then | |
| echo "β No firmware components found in $COMPONENTS" | |
| echo " Components are pushed by pyDirect CI. Run the pyDirect build first." | |
| exit 1 | |
| fi | |
| echo "π¦ Found variants:" | |
| ls -1 "$COMPONENTS" | |
| - name: List VFS contents | |
| run: | | |
| echo "π Device scripts to be bundled into VFS:" | |
| find boards/firmware/device-scripts -type f | sort | |
| echo "" | |
| echo "π Total files: $(find boards/firmware/device-scripts -type f | wc -l)" | |
| - name: Determine version | |
| id: version | |
| run: | | |
| # Read MicroPython base version from pyDirect build-info | |
| BUILD_INFO="boards/firmware/components/build-info.json" | |
| if [ -f "$BUILD_INFO" ]; then | |
| MPY_VERSION=$(python3 -c "import json; print(json.load(open('$BUILD_INFO'))['version'])") | |
| PYDIRECT_COMMIT=$(python3 -c "import json; print(json.load(open('$BUILD_INFO'))['commit'])") | |
| else | |
| MPY_VERSION="unknown" | |
| PYDIRECT_COMMIT="${{ github.sha }}" | |
| fi | |
| # Read current platform version | |
| PLATFORM_FILE="boards/firmware/platform-version.json" | |
| CURRENT=$(python3 -c "import json; print(json.load(open('$PLATFORM_FILE'))['version'])") | |
| echo "Current platform version: $CURRENT" | |
| # Auto-bump based on conventional commits since last firmware tag | |
| LAST_TAG=$(git tag -l 'firmware-*' --sort=-creatordate | head -1 || echo "") | |
| if [ -n "$LAST_TAG" ]; then | |
| COMMITS=$(git log "$LAST_TAG"..HEAD --oneline 2>/dev/null || echo "") | |
| else | |
| COMMITS=$(git log --oneline -20 2>/dev/null || echo "") | |
| fi | |
| # Parse semver components | |
| IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT" | |
| # Check for feat: (minor bump) or fix: (patch bump) | |
| if echo "$COMMITS" | grep -qiE '^[a-f0-9]+ feat(\(|:)'; then | |
| MINOR=$((MINOR + 1)) | |
| PATCH=0 | |
| echo "πΌ Minor bump (feat: detected)" | |
| elif echo "$COMMITS" | grep -qiE '^[a-f0-9]+ fix(\(|:)'; then | |
| PATCH=$((PATCH + 1)) | |
| echo "π§ Patch bump (fix: detected)" | |
| else | |
| PATCH=$((PATCH + 1)) | |
| echo "π§ Patch bump (default)" | |
| fi | |
| VERSION="${MAJOR}.${MINOR}.${PATCH}" | |
| echo "New platform version: $VERSION" | |
| # Write back the bumped version | |
| python3 -c " | |
| import json | |
| with open('$PLATFORM_FILE', 'r+') as f: | |
| d = json.load(f) | |
| d['version'] = '$VERSION' | |
| f.seek(0); json.dump(d, f, indent=2); f.write('\n'); f.truncate() | |
| " | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "mpy_version=$MPY_VERSION" >> "$GITHUB_OUTPUT" | |
| echo "commit=$PYDIRECT_COMMIT" >> "$GITHUB_OUTPUT" | |
| TAG="firmware-${VERSION}-$(date -u +%Y%m%d%H%M%S)" | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| - name: Bake firmware version into VFS | |
| run: | | |
| # Bake the *bumped* platform version into firmware-version.json so | |
| # the device reports the same version as the bundled image. Schema: | |
| # platform_version - semver of the platform release (e.g. "1.4.0") | |
| # micropython - MicroPython base version | |
| # built - ISO-8601 build timestamp | |
| # commit - pyDirect commit baked in | |
| # origin - "gha" for CI builds, "local" for hand-built | |
| VERSION="${{ steps.version.outputs.version }}" | |
| MPY_VERSION="${{ steps.version.outputs.mpy_version }}" | |
| COMMIT="${{ steps.version.outputs.commit }}" | |
| cat > boards/firmware/device-scripts/firmware-version.json << EOF | |
| {"platform_version": "$VERSION", "micropython": "$MPY_VERSION", "built": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", "commit": "$COMMIT", "origin": "gha"} | |
| EOF | |
| echo "π Baked firmware-version.json: $(cat boards/firmware/device-scripts/firmware-version.json)" | |
| - name: Build merged firmware for each variant | |
| run: | | |
| COMPONENTS="boards/firmware/components" | |
| DEVICE_SCRIPTS="boards/firmware/device-scripts" | |
| FIRMWARE_DIR="boards/firmware" | |
| for variant_dir in "$COMPONENTS"/*/; do | |
| VARIANT=$(basename "$variant_dir") | |
| echo "π¦ Processing variant: $VARIANT" | |
| BOOTLOADER="$variant_dir/bootloader.bin" | |
| PARTITION_TABLE="$variant_dir/partition-table.bin" | |
| FIRMWARE="$variant_dir/micropython.bin" | |
| PARTITION_CSV=$(find "$variant_dir" -name "partitions*.csv" | head -1) | |
| # Verify all components present | |
| for f in "$BOOTLOADER" "$PARTITION_TABLE" "$FIRMWARE" "$PARTITION_CSV"; do | |
| if [ ! -f "$f" ]; then | |
| echo "β Missing: $f" | |
| exit 1 | |
| fi | |
| done | |
| # Parse VFS partition offset and size from CSV | |
| VFS_LINE=$(grep "^vfs," "$PARTITION_CSV") | |
| VFS_OFFSET=$(echo "$VFS_LINE" | cut -d',' -f4 | xargs) | |
| VFS_SIZE=$(echo "$VFS_LINE" | cut -d',' -f5 | xargs) | |
| if [[ "$VFS_SIZE" == 0x* ]]; then | |
| VFS_SIZE=$((VFS_SIZE)) | |
| fi | |
| echo " VFS offset: $VFS_OFFSET, size: $VFS_SIZE bytes" | |
| # Create VFS partition from device-scripts | |
| VFS_IMAGE="/tmp/vfs-${VARIANT}.bin" | |
| mklittlefs \ | |
| -c "$DEVICE_SCRIPTS" \ | |
| -b 4096 -p 256 \ | |
| -s "$VFS_SIZE" \ | |
| "$VFS_IMAGE" | |
| echo " β VFS image: $(du -h "$VFS_IMAGE" | cut -f1)" | |
| # Detect chip and flash size from variant name | |
| CHIP="esp32s3" | |
| if [[ "$VARIANT" == *"P4"* ]]; then CHIP="esp32p4"; fi | |
| FLASH_MB=$(echo "$VARIANT" | sed 's/_[A-Z]*$//' | grep -oE '[0-9]+$') | |
| FLASH_SIZE="${FLASH_MB}MB" | |
| # Detect bootloader offset (P4 uses 0x2000, others use 0x0) | |
| BOOT_OFFSET="0x0" | |
| if [[ "$CHIP" == "esp32p4" ]]; then | |
| BOOT_OFFSET="0x2000" | |
| fi | |
| # Merge all parts into deployable firmware (output to /tmp, not repo) | |
| MERGED="/tmp/${VARIANT}-merged.bin" | |
| esptool.py --chip "$CHIP" merge_bin \ | |
| --fill-flash-size "$FLASH_SIZE" \ | |
| --flash_mode dio \ | |
| --flash_freq 80m \ | |
| --flash_size "$FLASH_SIZE" \ | |
| -o "$MERGED" \ | |
| $BOOT_OFFSET "$BOOTLOADER" \ | |
| 0x8000 "$PARTITION_TABLE" \ | |
| 0x10000 "$FIRMWARE" \ | |
| $VFS_OFFSET "$VFS_IMAGE" | |
| echo " β Created: $MERGED ($(du -h "$MERGED" | cut -f1))" | |
| done | |
| - name: Create firmware release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.version.outputs.tag }} | |
| name: "Firmware ${{ steps.version.outputs.version }}" | |
| body: | | |
| Platform version: `${{ steps.version.outputs.version }}` | |
| MicroPython base: `${{ steps.version.outputs.mpy_version }}` | |
| pyDirect commit: `${{ steps.version.outputs.commit }}` | |
| Built: ${{ github.event.head_commit.timestamp || github.event.repository.updated_at }} | |
| files: /tmp/*-merged.bin | |
| make_latest: true | |
| - name: Update firmware for same-origin serving | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| MPY_VERSION="${{ steps.version.outputs.mpy_version }}" | |
| COMMIT="${{ steps.version.outputs.commit }}" | |
| TAG="${{ steps.version.outputs.tag }}" | |
| REPO="${{ github.repository }}" | |
| # Copy merged bins to boards/firmware/ for same-origin serving via GitHub Pages | |
| # (GitHub Releases don't support CORS, so browser fetch() can't download from there) | |
| cp /tmp/*-merged.bin boards/firmware/ | |
| echo "π¦ Firmware binaries for same-origin serving:" | |
| ls -lh boards/firmware/*-merged.bin | |
| # Write latest.json with same-origin paths | |
| cat > boards/firmware/latest.json << EOF | |
| { | |
| "version": "$VERSION", | |
| "micropython_version": "$MPY_VERSION", | |
| "updated": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", | |
| "pyDirect_commit": "$COMMIT", | |
| "scriptostudio_commit": "${{ github.sha }}", | |
| "release_tag": "$TAG", | |
| "release_url": "https://github.com/${REPO}/releases/tag/${TAG}", | |
| "variants": [ | |
| { "id": "ESP32_S3_8", "chip": "esp32s3", "flash": "8MB", "file": "ESP32_S3_8-merged.bin", "url": "/boards/firmware/ESP32_S3_8-merged.bin" }, | |
| { "id": "ESP32_S3_8_OCT", "chip": "esp32s3", "flash": "8MB", "file": "ESP32_S3_8_OCT-merged.bin", "url": "/boards/firmware/ESP32_S3_8_OCT-merged.bin" }, | |
| { "id": "ESP32_S3_16", "chip": "esp32s3", "flash": "16MB", "file": "ESP32_S3_16-merged.bin", "url": "/boards/firmware/ESP32_S3_16-merged.bin" }, | |
| { "id": "ESP32_S3_32", "chip": "esp32s3", "flash": "32MB", "file": "ESP32_S3_32-merged.bin", "url": "/boards/firmware/ESP32_S3_32-merged.bin" }, | |
| { "id": "ESP32_P4_16", "chip": "esp32p4", "flash": "16MB", "file": "ESP32_P4_16-merged.bin", "url": "/boards/firmware/ESP32_P4_16-merged.bin" }, | |
| { "id": "ESP32_P4_32", "chip": "esp32p4", "flash": "32MB", "file": "ESP32_P4_32-merged.bin", "url": "/boards/firmware/ESP32_P4_32-merged.bin" } | |
| ] | |
| } | |
| EOF | |
| echo "π latest.json:" | |
| cat boards/firmware/latest.json | |
| - name: Commit firmware and latest.json | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add boards/firmware/latest.json boards/firmware/platform-version.json boards/firmware/*-merged.bin | |
| git commit -m "π€ Firmware ${{ steps.version.outputs.version }} β release ${{ steps.version.outputs.tag }}" || echo "No changes" | |
| git pull --rebase --autostash | |
| git push |