Offline mode new boards+components. #179
Workflow file for this run
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
# SPDX-FileCopyrightText: Brent Rubell for Adafruit Industries, 2025 | |
# | |
# SPDX-License-Identifier: MIT | |
name: WipperSnapper Release Workflow for "Offline Mode" Alpha Feature | |
on: | |
push: | |
branches: | |
- offline-mode | |
- offline-mode-* | |
pull_request: | |
branches: | |
- offline-mode | |
release: | |
types: [published] | |
branches: | |
- offline-mode | |
workflow_call: | |
secrets: | |
GH_REPO_TOKEN: | |
required: true | |
jobs: | |
clang: | |
name: 🔎 Clang | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: "3.x" | |
- uses: actions/checkout@v4 | |
- uses: actions/checkout@v4 | |
with: | |
repository: adafruit/ci-arduino | |
ref: ci-wippersnapper | |
path: ci | |
- name: pre-install | |
run: bash ci/actions_install.sh | |
- name: clang | |
run: python3 ci/run-clang-format.py -r -e "ci/*" -e "bin/*" -e src/nanopb -e src/protos -e src/pb.h -e src/provisioning/tinyusb src/ | |
test-offline-mode: | |
name: 🧪 Test Offline Mode | |
runs-on: ubuntu-latest | |
needs: clang | |
steps: | |
- name: Check out repository code | |
uses: actions/checkout@v4 | |
- name: Set up Python | |
uses: actions/setup-python@v5 | |
with: | |
python-version: '3.13' | |
- name: Install Python dependencies | |
run: | | |
python -m pip install --upgrade pip | |
pip install -r tests/requirements.txt | |
- name: Install Wokwi CI Server | |
uses: wokwi/wokwi-ci-server-action@v1 | |
- name: Install Wokwi CLI | |
run: curl -L https://wokwi.com/ci/install.sh | sh | |
- name: Install PIO Libraries for esp32dev target | |
run: pio pkg install --environment=esp32dev | |
- name: Build PlatformIO Project | |
run: platformio run --environment esp32dev | |
- name: Move new build file to test folder | |
run: cp .pio/build/esp32dev/firmware.elf tests/bin/offline/firmware.elf | |
- name: Run Wokwi Tests | |
run: pytest tests/test_offline.py --junitxml=report.xml -v | |
env: | |
WOKWI_CLI_TOKEN: ${{ secrets.WOKWI_CLI_TOKEN }} | |
- name: Publish Wokwi Test Results | |
uses: EnricoMi/publish-unit-test-result-action@v2 | |
if: always() | |
with: | |
files: | | |
/home/runner/work/Adafruit_Wippersnapper_Arduino/Adafruit_Wippersnapper_Arduino/report.xml | |
build-esp32sx: | |
name: 🏗️ ESP32-Sx | |
runs-on: ubuntu-latest | |
needs: [clang] | |
strategy: | |
fail-fast: false | |
matrix: | |
arduino-platform: | |
[ | |
"metroesp32s2", | |
"metro_esp32s3", | |
"feather_esp32s2", | |
"feather_esp32s2_tft", | |
"feather_esp32s2_reverse_tft", | |
"feather_esp32s3", | |
"feather_esp32s3_4mbflash_2mbpsram", | |
"feather_esp32s3_tft", | |
"qtpy_esp32s3", | |
"qtpy_esp32s2", | |
"feather_esp32s3_reverse_tft", | |
"qtpy_esp32s3_n4r2", | |
"esp32s3_devkitc_1_n8", | |
"xiao_esp32s3", | |
] | |
steps: | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: "3.x" | |
- uses: actions/checkout@v4 | |
- name: Get WipperSnapper version | |
run: | | |
git fetch --prune --unshallow --tags | |
git describe --dirty --tags | |
echo >>$GITHUB_ENV WS_VERSION=$(git describe --dirty --tags) | |
- uses: actions/checkout@v4 | |
with: | |
repository: adafruit/ci-arduino | |
ref: ci-wippersnapper | |
path: ci | |
- name: Checkout Board Definitions | |
uses: actions/checkout@v4 | |
with: | |
repository: adafruit/Wippersnapper_Boards | |
path: ws-boards | |
ref: offline-mode | |
- name: Install CI-Arduino | |
run: bash ci/actions_install.sh | |
- name: Install extra Arduino libraries | |
run: | | |
git clone --quiet https://github.com/milesburton/Arduino-Temperature-Control-Library.git /home/runner/Arduino/libraries/Arduino-Temperature-Control-Library | |
git clone --quiet https://github.com/pstolarz/OneWireNg.git /home/runner/Arduino/libraries/OneWireNg | |
git clone --quiet https://github.com/adafruit/Adafruit_HX8357_Library.git /home/runner/Arduino/libraries/Adafruit_HX8357_Library | |
git clone --quiet https://github.com/adafruit/Adafruit_ILI9341.git /home/runner/Arduino/libraries/Adafruit_ILI9341 | |
git clone --quiet https://github.com/adafruit/Adafruit_STMPE610.git /home/runner/Arduino/libraries/Adafruit_STMPE610 | |
git clone --quiet https://github.com/adafruit/Adafruit-ST7735-Library.git /home/runner/Arduino/libraries/Adafruit-ST7735-Library | |
git clone --quiet https://github.com/adafruit/Adafruit_TouchScreen.git /home/runner/Arduino/libraries/Adafruit_TouchScreen | |
git clone --quiet https://github.com/adafruit/Adafruit_TinyUSB_Arduino /home/runner/Arduino/libraries/Adafruit_TinyUSB_Arduino | |
git clone --depth 1 --branch wippersnapper https://github.com/brentru/lvgl.git /home/runner/Arduino/libraries/lvgl | |
git clone --depth 1 --branch development https://github.com/brentru/Adafruit_LvGL_Glue.git /home/runner/Arduino/libraries/Adafruit_LittlevGL_Glue_Library | |
- name: Download stable Nanopb | |
id: download-nanopb | |
continue-on-error: true | |
run: | | |
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.8.tar.gz | |
- if: ${{ failure() || steps.download-nanopb.outcome != 'success' }} | |
name: Restore cached nanopb | |
id: cache-nanopb-restore | |
uses: actions/cache/restore@v4 | |
env: | |
cache-name: cache-node-modules | |
with: | |
path: ./nanopb-0.4.8.tar.gz | |
key: nanopb-0.4.8.tar.gz | |
- if: ${{ steps.download-nanopb.outcome == 'success' }} | |
name: Save nanopb to cache | |
id: cache-nanopb-save | |
uses: actions/cache/save@v4 | |
env: | |
cache-name: cache-node-modules | |
with: | |
path: ./nanopb-0.4.8.tar.gz | |
key: nanopb-0.4.8.tar.gz | |
- name: Install stable Nanopb | |
run: | | |
tar -xf nanopb-0.4.8.tar.gz | |
# Copy files to WipperSnapper's src/nanopb directory | |
cp nanopb/pb_common.* nanopb/pb_encode.* nanopb/pb_decode.* src/nanopb | |
mv nanopb/pb.h src/nanopb/nanopb.pb.h | |
- name: List all files in Adafruit_LittlevGL_Glue_Library folder | |
run: | | |
ls /home/runner/Arduino/libraries/Adafruit_LittlevGL_Glue_Library | |
- name: Copy lv_conf.h file in Adafruit_LittlevGL_Glue_Library to the arduino library folder | |
run: | | |
cp /home/runner/Arduino/libraries/Adafruit_LittlevGL_Glue_Library/lv_conf.h /home/runner/Arduino/libraries | |
- name: Install Dependencies (esptool) | |
run: | | |
pip3 install esptool | |
- name: Build for ESP32-SX | |
run: | | |
python3 ci/build_platform.py ${{ matrix.arduino-platform }} --build_timeout 48000 | |
- name: list files (tree) | |
run: | | |
tree -L 7 -h | |
- name: Rename build artifacts to reflect the platform name | |
run: | | |
mv examples/*/build/*/Wippersnapper_demo_offline_netiface.ino.uf2 wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.uf2 | |
mv examples/*/build/*/Wippersnapper_demo_offline_netiface.ino.bin wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.bin | |
mv examples/*/build/*/Wippersnapper_demo_offline_netiface.ino.elf wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.elf | |
mv examples/*/build/*/Wippersnapper_demo_offline_netiface.ino.map wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.map | |
mv examples/*/build/*/Wippersnapper_demo_offline_netiface.ino.bootloader.bin wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.bootloader.bin | |
mv examples/*/build/*/Wippersnapper_demo_offline_netiface.ino.merged.bin wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.merged_auto.bin | |
mv examples/*/build/*/Wippersnapper_demo_offline_netiface.ino.partitions.bin wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.partitions.bin | |
- name: Get Board Flash Parameters | |
id: get_board_json | |
run: | | |
board_name=${{ matrix.arduino-platform }} | |
# Remove '_noota' suffix if present | |
board_name=${board_name%_noota} | |
# Remove 'wippersnapper_' prefix if present | |
board_name=${board_name#wippersnapper_} | |
# check folder name exists, otherwise do replace of underscore with dash, or blank | |
if [ ! -d "ws-boards/boards/${board_name}" ]; then | |
echo "Board definition folder ws-boards/boards/${board_name} does not exist, checking for alternative names." | |
if [ -d "ws-boards/boards/${board_name//_/-}" ]; then | |
board_name=${board_name//_/-} | |
echo "Found alternative board definition folder ws-boards/boards/${board_name//_/-}." | |
# Remove all underscores if still not found | |
elif [ -d "ws-boards/boards/${board_name//_}" ]; then | |
board_name=${board_name//_} | |
echo "Found alternative board definition folder ws-boards/boards/${board_name//_}." | |
else | |
echo "Error: Board definition folder ws-boards/boards/${board_name} does not exist." | |
exit 1 | |
fi | |
fi | |
content=$(cat ws-boards/boards/${board_name}/definition.json) | |
{ | |
echo 'boardJson<<EOF' | |
echo $content | |
echo EOF | |
} >> "$GITHUB_OUTPUT" | |
- name: fetch tinyuf2 combined.bin | |
id: get_tinyuf2 | |
continue-on-error: true | |
run: | | |
# check ${{fromJson(steps.get_board_json.outputs.boardJson).esptool.flashMode}} is not empty | |
if [ -z "${{fromJson(steps.get_board_json.outputs.boardJson).esptool.flashMode}}" ]; then | |
echo "Error: esptool.flashMode is not set in board definition, using KEEP for all settings." | |
fi | |
BOARD_NAME="${{fromJson(steps.get_board_json.outputs.boardJson).bootloaderBoardName || matrix.arduino-platform}}" | |
for attempt in 1 2; do | |
echo "Attempt $attempt: Fetching tinyuf2 release info for board $BOARD_NAME" | |
API_RESPONSE=$(curl --silent --fail https://api.github.com/repos/adafruit/tinyuf2/releases/latest) | |
if [ $? -ne 0 ]; then | |
echo "Attempt $attempt: curl failed to fetch release info." | |
if [ "$attempt" -eq 2 ]; then exit 1; else sleep 2; continue; fi | |
fi | |
DOWNLOAD_URL=$(echo "$API_RESPONSE" | jq -r '.assets[] | select(.browser_download_url | contains("tinyuf2-'$BOARD_NAME'-") and endswith(".zip")) | .browser_download_url // empty') | |
if [ -z "$DOWNLOAD_URL" ]; then | |
echo "Attempt $attempt: No matching tinyuf2 zip found for board $BOARD_NAME." | |
if [ "$attempt" -eq 2 ]; then exit 1; else sleep 2; continue; fi | |
fi | |
echo "Attempt $attempt: Downloading $DOWNLOAD_URL" | |
wget "$DOWNLOAD_URL" -O tinyuf2.zip | |
if [ $? -eq 0 ]; then | |
unzip -o tinyuf2.zip -d . | |
break | |
else | |
echo "Attempt $attempt: wget failed to download $DOWNLOAD_URL" | |
if [ "$attempt" -eq 2 ]; then exit 1; else sleep 2; fi | |
fi | |
done | |
- if: ${{ steps.get_tinyuf2.outcome == 'success' }} | |
name: move partition and bootloader files for tinyuf2 (to match flash_args) | |
run: | | |
# Copy files where they're expected to make flash_args happy | |
mkdir bootloader | |
cp bootloader.bin bootloader/bootloader.bin | |
mkdir partition_table | |
cp partition-table.bin partition_table/partition-table.bin | |
- if: ${{ steps.get_tinyuf2.outcome == 'success' }} | |
name: Create new_flash_args file from flash_args with added app bin + output file | |
run: | | |
# Create new_flash_args with esptool parameters first and output file | |
echo "--flash-mode ${{fromJson(steps.get_board_json.outputs.boardJson).esptool.flashMode || 'keep'}}" > new_flash_args | |
echo "--flash-freq ${{fromJson(steps.get_board_json.outputs.boardJson).esptool.flashFreq || 'keep'}}" >> new_flash_args | |
echo "--flash-size ${{fromJson(steps.get_board_json.outputs.boardJson).esptool.flashSize || 'keep'}}" >> new_flash_args | |
echo "-o wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.combined.bin" >> new_flash_args | |
# Append flash_args content to new_flash_args, skipping the first line | |
tail -n +2 flash_args >> new_flash_args | |
# Append main app to flash_args file | |
echo "0x10000 wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.bin" >> new_flash_args | |
- if: ${{ steps.get_tinyuf2.outcome == 'success' }} | |
name: Check boot_app0 file existence (esp32sx built from core, not-source) | |
id: check_files | |
uses: andstor/file-existence-action@v3 | |
with: | |
files: "/home/runner/.arduino15/packages/esp32/hardware/esp32/*/tools/partitions/boot_app0.bin" | |
- if: ${{ steps.get_tinyuf2.outcome == 'success' && steps.check_files.outputs.files_exists == 'true' }} | |
name: list arduino esp32 core files | |
run: | | |
ls /home/runner/.arduino15/packages/esp32/hardware/esp32/*/tools/partitions | |
- if: ${{ steps.get_tinyuf2.outcome == 'success' && steps.check_files.outputs.files_exists == 'false' }} | |
name: list arduino esp32 bsp core files | |
run: | | |
ls /home/runner/Arduino/hardware/espressif/esp32/tools/partitions | |
- if: ${{ steps.get_tinyuf2.outcome == 'success' && steps.check_files.outputs.files_exists == 'true' }} | |
name: boot_app0 file from arduino-cli core | |
run: cp /home/runner/.arduino15/packages/esp32/hardware/esp32/*/tools/partitions/boot_app0.bin wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.boot_app0.bin | |
- if: ${{ steps.get_tinyuf2.outcome == 'success' && steps.check_files.outputs.files_exists == 'false' }} | |
name: boot_app0 file from esp32 source bsp | |
run: cp /home/runner/Arduino/hardware/espressif/esp32/tools/partitions/boot_app0.bin wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.boot_app0.bin | |
- if: ${{ steps.get_tinyuf2.outcome == 'success' }} | |
name: Copy boot_app0 file to ota_data_initial.bin (overwrite tinyuf2 boot preference) | |
run: cp wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.boot_app0.bin ota_data_initial.bin | |
- if: ${{ steps.get_tinyuf2.outcome == 'success' }} | |
name: Create combined binary using Esptool merge-bin | |
run: | | |
echo ${{ steps.get_board_json.outputs.boardJson }} | |
echo ${{ fromJson(steps.get_board_json.outputs.boardJson) }} | |
python3 -m esptool --chip ${{fromJson(steps.get_board_json.outputs.boardJson).esptool.chip || fromJson(steps.get_board_json.outputs.boardJson).mcuName}} merge-bin @new_flash_args | |
- if: ${{ steps.get_tinyuf2.outcome == 'success' }} | |
name: Zip build artifacts | |
run: | | |
zip -r wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.zip wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.* | |
- if: ${{ steps.get_tinyuf2.outcome == 'success' }} | |
name: Upload build artifacts zip | |
uses: actions/upload-artifact@v4 | |
with: | |
name: build-files-${{ matrix.arduino-platform }}-zip | |
path: | | |
wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.zip | |
- name: upload build artifacts | |
uses: actions/upload-artifact@v4 | |
with: | |
name: build-files-${{ matrix.arduino-platform }}.${{ env.WS_VERSION }} | |
path: | | |
wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.uf2 | |
build-rp2040: | |
name: 🏗️ RP2040, RP2350 | |
runs-on: ubuntu-latest | |
needs: [clang] | |
strategy: | |
fail-fast: false | |
matrix: | |
arduino-platform: ["pico_rp2040_tinyusb", | |
"pico_rp2350_tinyusb", | |
"feather_rp2040_adalogger_tinyusb", | |
"metro_rp2350_tinyusb" | |
] | |
steps: | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: "3.x" | |
- uses: actions/checkout@v4 | |
- name: Get WipperSnapper version | |
run: | | |
git fetch --prune --unshallow --tags | |
git describe --dirty --tags | |
echo >>$GITHUB_ENV WS_VERSION=$(git describe --dirty --tags) | |
- uses: actions/checkout@v4 | |
with: | |
repository: adafruit/ci-arduino | |
ref: ci-wippersnapper | |
path: ci | |
- name: Install CI-Arduino | |
run: bash ci/actions_install.sh | |
# manually install OneWireNG/TempControlLib for OneWireNg (RP2040 Supported OneWire w/backwards compat.) | |
- name: Install extra Arduino libraries | |
run: | | |
git clone --quiet https://github.com/pstolarz/OneWireNg.git /home/runner/Arduino/libraries/OneWireNg | |
git clone --quiet https://github.com/pstolarz/Arduino-Temperature-Control-Library.git /home/runner/Arduino/libraries/Arduino-Temperature-Control-Library | |
git clone --quiet https://github.com/adafruit/Adafruit_TinyUSB_Arduino /home/runner/Arduino/libraries/Adafruit_TinyUSB_Arduino | |
- name: Download stable Nanopb | |
id: download-nanopb | |
continue-on-error: true | |
run: | | |
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.8.tar.gz | |
- if: ${{ failure() || steps.download-nanopb.outcome != 'success' }} | |
name: Restore cached nanopb | |
id: cache-nanopb-restore | |
uses: actions/cache/restore@v4 | |
env: | |
cache-name: cache-node-modules | |
with: | |
path: ./nanopb-0.4.8.tar.gz | |
key: nanopb-0.4.8.tar.gz | |
- if: ${{ steps.download-nanopb.outcome == 'success' }} | |
name: Save nanopb to cache | |
id: cache-nanopb-save | |
uses: actions/cache/save@v4 | |
env: | |
cache-name: cache-node-modules | |
with: | |
path: ./nanopb-0.4.8.tar.gz | |
key: nanopb-0.4.8.tar.gz | |
- name: Install stable Nanopb | |
run: | | |
tar -xf nanopb-0.4.8.tar.gz | |
# Copy files to WipperSnapper's src/nanopb directory | |
cp nanopb/pb_common.* nanopb/pb_encode.* nanopb/pb_decode.* src/nanopb | |
mv nanopb/pb.h src/nanopb/nanopb.pb.h | |
- name: build RP2040 platforms | |
run: python3 ci/build_platform.py ${{ matrix.arduino-platform }} --build_timeout 48000 | |
- name: Rename build artifacts to reflect the platform name | |
run: | | |
mv examples/*/build/*/Wippersnapper_demo_offline_nonetiface.ino.uf2 wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.uf2 | |
- name: upload build artifacts | |
uses: actions/upload-artifact@v4 | |
with: | |
name: build-files-${{ matrix.arduino-platform }}.${{ env.WS_VERSION }} | |
path: | | |
wippersnapper.${{ matrix.arduino-platform }}.${{ env.WS_VERSION }}.uf2 | |
merge-job-build-files: | |
name: Merge Artifacts for build-files | |
runs-on: ubuntu-latest | |
needs: [build-esp32sx, build-rp2040] | |
steps: | |
- name: Merge Artifacts from Builds | |
uses: actions/upload-artifact/merge@v4 | |
with: | |
name: build-files | |
pattern: build-files-!(dev)-* | |
delete-merged: true | |
release-wippersnapper: | |
name: 🚀 Upload Release Files | |
runs-on: ubuntu-latest | |
needs: merge-job-build-files | |
if: github.event_name == 'release' && startsWith(github.ref, 'refs/tags/') | |
steps: | |
- name: Download build artifacts from build-platform steps | |
uses: actions/download-artifact@v4 | |
with: | |
name: build-files | |
- name: List Files | |
run: ls | |
- name: Upload Assets to the GitHub Release | |
uses: softprops/action-gh-release@v1 | |
if: startsWith(github.ref, 'refs/tags/') | |
with: | |
files: | | |
wippersnapper.*.uf2 | |
wippersnapper.*.bin | |
wippersnapper.*.zip |