name: Automated CI Build of FoxMesh on: push: branches: - main workflow_dispatch: inputs: target_branch: description: 'Which branch do you want to build and test?' required: true default: 'main' jobs: build-and-test: runs-on: ubuntu-latest # Ensure this workflow only runs inside this reopsitory if: github.repository == 'tkuschel/FoxMesh' permissions: contents: write # We want also create official Releases steps: # 1. Checkout the target branch - name: Checkout Target branch uses: actions/checkout@v7 with: ref: ${{ github.event.inputs.target_branch || github.ref }} # 2. Set up Python environment - name: Set up Python 3.x uses: actions/setup-python@v7 with: python-version: '3.x' # 3. Cache global PlatformIO directories, uses a dynamic key based on platformio.ini - name: Cache PlatformIO uses: actions/cache@v6 with: path: | ~/.cache/pio ~/.platformio .pio key: ${{ runner.os }}-pio-${{ hashFiles('**/platformio.ini') }} restore-keys: | ${{ runner.os }}-pio- # 4. Install PlatformIO Core and the required intelhex extension in a single, quiet command - name: Install PlatformIO Core run: python -m pip install --quiet --upgrade pip platformio intelhex - name: Install ESP32 platform run: pio pkg install --silent --global --platform espressif32 - name: Compile the Project run: pio run # 11. Dynamically create the smart flashing scripts next to the T-Beam binary # with optional bootloader detection and group check # the table of flash addresses usually found at /partitions-4MB-safeboot.csv - name: Create Desktop Flashing Scripts run: | # ---------------------------------------------------------------------- # 0. Flash Address Configuration ← edit here to change the layout # ---------------------------------------------------------------------- FLASH_BOOTLOADER_ADDR="0x1000" FLASH_PARTITIONS_ADDR="0x8000" FLASH_OTADATA_ADDR="0xE000" FLASH_SAFEBOOT_ADDR="0x10000" FLASH_FIRMWARE_ADDR="0xC0000" # ---------------------------------------------------------------------- # 1. Universal Linux Shell Script # ---------------------------------------------------------------------- cat << 'EOF' > flash_esp32_board.sh #!/usr/bin/env bash GREEN='\033[0;32m' RED='\033[0;31m' YELLOW='\033[1;33m' NC='\033[0m' echo -e "${YELLOW}=== MeshCom Universal ESP32 Flashing Script ===${NC}" if ! command -v esptool &> /dev/null; then echo -e "${RED}Error: esptool is not installed.${NC}" echo "Please install it via your package manager or pip: 'pip install esptool'" echo "Linux Arch: 'sudo pacman -Sy && sudo pacman -S extra-testing/esptool'" exit 1 fi FIRMWARE = "firmware.bin" # Firmware File if [ ! -f "firmware.bin" ]; then echo -e "${RED}Error: No matching firmware binary found in this folder!${NC}" exit 1 fi echo -e "${GREEN}Selected Firmware:${NC} $FIRMWARE ($BOARD_NAME)" PORT=$(ls /dev/ttyUSB* /dev/ttyACM* 2>/dev/null | head -n 1) if [ -z "$PORT" ]; then echo -e "${RED}Error: No connected ESP32 Board (ttyUSB/ttyACM) found!${NC}" exit 1 fi echo -e "${GREEN}Detected Board on port:${NC} $PORT" # Dynamic Permission Check: Determine required group for the specific TTY device REQUIRED_GROUP=$(stat -c '%G' "$PORT") if [ "$REQUIRED_GROUP" != "root" ]; then if ! groups "$USER" | grep -q "\b${REQUIRED_GROUP}\b"; then echo -e "${RED}Error: You do not have permissions to access $PORT.${NC}" echo -e "The device belongs to the group: ${YELLOW}$REQUIRED_GROUP${NC}" echo -e "Please add your user to this group by running:" echo -e " ${GREEN}sudo usermod -aG $REQUIRED_GROUP \$USER${NC}" echo -e "After running the command, please log out and log back in for the changes to take effect." exit 1 fi fi # Build flash arguments from the address table (only include files that exist) FLASH_ARGS="" if [ -f "bootloader.bin" ]; then FLASH_ARGS="$FLASH_ARGS __BOOTLOADER_ADDR__ bootloader.bin" fi if [ -f "partitions.bin" ]; then FLASH_ARGS="$FLASH_ARGS __PARTITIONS_ADDR__ partitions.bin" fi if [ -f "otadata.bin" ]; then FLASH_ARGS="$FLASH_ARGS __OTADATA_ADDR__ otadata.bin" fi if [ -f "safeboot.bin" ]; then FLASH_ARGS="$FLASH_ARGS __SAFEBOOT_ADDR__ safeboot.bin" fi FLASH_ARGS="$FLASH_ARGS __FIRMWARE_ADDR__ $FIRMWARE" echo -e "${GREEN}Flashing:${NC}$FLASH_ARGS" esptool --chip esp32 --port "$PORT" --baud 921600 write-flash -z $FLASH_ARGS if [ $? -eq 0 ]; then echo -e "${GREEN}=== Success! $BOARD_NAME successfully updated ===${NC}" else echo -e "${RED}=== Flash failed! ===${NC}" exit 1 fi EOF # Substitute address placeholders with configured hex values sed -i \ -e "s|__BOOTLOADER_ADDR__|${FLASH_BOOTLOADER_ADDR}|g" \ -e "s|__PARTITIONS_ADDR__|${FLASH_PARTITIONS_ADDR}|g" \ -e "s|__OTADATA_ADDR__|${FLASH_OTADATA_ADDR}|g" \ -e "s|__SAFEBOOT_ADDR__|${FLASH_SAFEBOOT_ADDR}|g" \ -e "s|__FIRMWARE_ADDR__|${FLASH_FIRMWARE_ADDR}|g" \ flash_esp32_board.sh chmod +x flash_esp32_board.sh # ---------------------------------------------------- # 2. Universal Windows Batch Script # ---------------------------------------------------- cat << 'EOF' > flash_esp32_board.bat @echo off setlocal enabledelayedexpansion echo =================================================== echo === MeshCom Universal ESP32 Windows Flashing ====== echo =================================================== set "FIRMWARE=firmware.bin" set "BOARD_NAME=" if exist "firmeware.bin" ( set "BOARD_NAME=ESP32" ) if "%FIRMWARE%"="" ( echo [ERROR] No matching firmware binary found in this folder! pause exit /b 1 ) echo [INFO] Selected Firmware: %FIRMWARE% (%BOARD_NAME%) set "COMPORT=" for /f "tokens=2 delims=()" %%A in ('wmic path Win32_PnPEntity get Name ^| findstr /i "COM" ^| findstr /i "Silicon CP210 CH340 CH9102 USB-to-UART"') do set "COMPORT=%%A" if "%COMPORT%"=="" ( for /f "tokens=2 delims=()" %%A in ('wmic path Win32_PnPEntity get Name ^| findstr /i "(COM"') do set "COMPORT=%%A" ) if "%COMPORT%"=="" ( echo [ERROR] No ESP32 Board or USB-UART bridge detected! pause exit /b 1 ) echo [INFO] Detected Board on port: %COMPORT% set "FLASH_ARGS=" if exist "bootloader.bin" ( set "FLASH_ARGS=!FLASH_ARGS! __BOOTLOADER_ADDR__ bootloader.bin" ) if exist "partitions.bin" ( set "FLASH_ARGS=!FLASH_ARGS! __PARTITIONS_ADDR__ partitions.bin" ) if exist "otadata.bin" ( set "FLASH_ARGS=!FLASH_ARGS! __OTADATA_ADDR__ otadata.bin" ) if exist "safeboot.bin" ( set "FLASH_ARGS=!FLASH_ARGS! __SAFEBOOT_ADDR__ safeboot.bin" ) set "FLASH_ARGS=!FLASH_ARGS! __FIRMWARE_ADDR__ %FIRMWARE%" echo [INFO] Flashing: !FLASH_ARGS! esptool --chip esp32 --port %COMPORT% --baud 921600 write-flash -z !FLASH_ARGS! if %ERRORLEVEL% EQU 0 ( echo === SUCCESS! %BOARD_NAME% successfully updated === ) else ( echo [ERROR] Flash failed! ) pause EOF # Substitute address placeholders with configured hex values sed -i \ -e "s|__BOOTLOADER_ADDR__|${FLASH_BOOTLOADER_ADDR}|g" \ -e "s|__PARTITIONS_ADDR__|${FLASH_PARTITIONS_ADDR}|g" \ -e "s|__OTADATA_ADDR__|${FLASH_OTADATA_ADDR}|g" \ -e "s|__SAFEBOOT_ADDR__|${FLASH_SAFEBOOT_ADDR}|g" \ -e "s|__FIRMWARE_ADDR__|${FLASH_FIRMWARE_ADDR}|g" \ flash_esp32_board.bat # ---------------------------------------------------- # 3. Distribute Scripts into target build directories # ---------------------------------------------------- # mkdir -p .pio/build/ttgo_tbeam # mkdir -p .pio/build/ttgo-lora32-v21 # cp flash_esp32_board.sh .pio/build/ttgo_tbeam/ # cp flash_esp32_board.bat .pio/build/ttgo_tbeam/ # cp flash_esp32_board.sh .pio/build/ttgo-lora32-v21/ # cp flash_esp32_board.bat .pio/build/ttgo-lora32-v21/ # 12. Upload all compiled firmware artifacts with zip compression - name: Upload Compiled Firmware Artifacts uses: actions/upload-artifact@v7 with: name: firmware-build-${{ github.event.inputs.target_branch || github.ref_name }} path: | .pio/build/**/*.bin # flash_esp32_board.* retention-days: 10 # Artifacts will be automatically deleted after 10 days