Skip to content

Automated ESP32 testing using GitHub Actions with a Raspberry Pi self-hosted runner. This project builds, flashes, and tests ESP-IDF firmware automatically on real ESP32-S3 hardware using Unity and Pytest.

License

Notifications You must be signed in to change notification settings

ChandimaJayaneththi/esp32_github_actions_ci_rpi

Repository files navigation

Automated ESP32 Testing with GitHub Actions on Raspberry Pi

This tutorial demonstrates how to automate ESP-IDF firmware testing using GitHub Actions and a Raspberry Pi configured as a self-hosted runner.
An ESP32-S3 board is physically connected to the Raspberry Pi via USB, which serves as the testing host.

This tutorial continues from Stage 3 — VS Code Pytest Testing.
It uses the same ESP-IDF project and test structure, but instead of manually running the tests inside VS Code, everything is automated using GitHub Actions.

Whenever new code is pushed to the GitHub repository, the workflow automatically:

  1. Builds the ESP-IDF project on the Raspberry Pi.
  2. Flashes the ESP32-S3 over USB.
  3. Runs the Unity/Pytest tests on real hardware.

This setup allows true hardware-in-the-loop continuous integration (CI) for embedded firmware.


Overview

Component Description
Raspberry Pi Acts as a self-hosted GitHub Actions runner.
ESP32-S3 Device under test, connected via USB to the Pi.
ESP-IDF v5.5.1 Installed on Raspberry Pi.
pytest-embedded For running firmware tests automatically.
GitHub Account & Repository To host the workflow and source code.
Stable Internet Connection For Raspberry Pi to communicate with GitHub.

GitHub Actions

GitHub Actions is GitHub’s built-in automation and CI/CD (Continuous Integration/Continuous Deployment) platform.
It allows you to define workflows that automatically run tasks whenever specific events occur in your repository — such as pushing new code, creating a pull request, or publishing a release.

In this project, GitHub Actions is used to:

  • Automatically build and test ESP-IDF firmware each time code changes.
  • Ensure code quality and stability before merging.
  • Run real hardware tests on an ESP32-S3 connected to a Raspberry Pi, without manual flashing or monitoring.

This automation greatly improves productivity and reliability by catching bugs early — just like CI pipelines in large-scale software projects.

Reference: GitHub Actions


Setup

  1. Clone the repository

    To follow this tutorial, first clone this repository which contains the complete project setup, including the ESP-IDF test code and the GitHub Actions workflow file.

    git clone https://github.com/ChandimaJayaneththi/esp32_github_actions_ci_rpi.git

    Next, create your own GitHub repository (for example, esp32_ci_rpi_runner) and push the cloned project into it

  2. Ensure the Raspberry Pi has internet access and ESP-IDF installed with Pytest:

    cd ~/esp/esp-idf
    ./install.sh --enable-pytest
    • Confirm ESP-IDF installation
      cd ~/esp/esp-idf
      . ./export.sh
      idf.py --version
  3. Connect your ESP32-S3 to the Raspberry Pi via USB

    • Check available ports:
      ls /dev/tty*
      Example output: /dev/ttyUSB0
  4. ESP32-S3 Hardware configuration

    Test Pin Connections Notes
    GPIO Test GPIO4 → GPIO5 Use a jumper wire
    ADC Test GPIO6 → GPIO1 (ADC1_CH0) Jumper wire required
    UART Test GPIO17 → GPIO16 UART1 loopback connection

    🔸 This wiring applies to the ESP32-S3-DevKitC-1 board.
    🔸 Adjust pins if using another ESP32 variant.


Project Structure

esp32_github_actions_ci_rpi/
├── components/
│   ├── test_peripheral/
│   │   ├── test/test_peripheral.c
│   │   ├── CMakeLists.txt
│   │   └── include/
│   │       └── peripheral.h
│   └── peripheral/
│       ├── peripheral.c
│       └── CMakeLists.txt
├── test/
│   ├── pytest_esp32_test.py
│   ├── pytest.ini
│   └── main/
│       ├── unit_test_peripheral.c
│       └── CMakeLists.txt
├── .github/
│   └── workflows/
│       └── ci.yml # GitHub Actions Workflow file
├── CMakeLists.txt
└── README.md

GitHub Self-Hosted Runner Setup (on Raspberry Pi)

  1. Go to your repository on GitHub → Settings → Actions → Runners
  2. Click New self-hosted runner
  3. Select Runner image as Linux
  4. Select the Architecture according to your Raspberry Pi
    • Please confirm the architecture of your Raspberry Pi before configure it using
      uname -a
      Output examples:
      • armv7l → 32-bit ARM (e.g. Raspberry Pi 3 running 32-bit OS)
      • aarch64 → 64-bit ARM (e.g. Raspberry Pi 4/5 running 64-bit OS)
  5. Run the commands one by one listed under Download and Configure sections to install, configure and run the GitHub action runner.
  6. Once it is successfully done, you can see the Raspberry Pi runner and the status of it on GitHub → Settings → Actions → Runners

Reference: Managing self-hosted runners


GitHub Actions Workflow (.github/workflows/ci.yml)

Below is the CI workflow file used to automate build, flash, and test steps:

name: ESP-IDF CI on Raspberry Pi

on:
    push:
        branches: [ "main" ]
    pull_request:
        branches: [ "main" ]

    workflow_dispatch:

jobs:
  build:
    runs-on: self-hosted

    steps:
        uses: actions/checkout@v4

      - name: Set target
        working-directory: test
        run: |
          . ~/esp/esp-idf/export.sh
          idf.py set-target esp32s3
    
      - name: Build the Project
        working-directory: test
        run: |
          . ~/esp/esp-idf/export.sh
          idf.py build
    
      - name: Run Unit tests
        working-directory: test
        run: |
          . ~/esp/esp-idf/export.sh
          pytest pytest_esp32_test.py --port <PORT>

Note: Replace "PORT" with the correct device (for example, /dev/ttyUSB0).

Workflow Breakdown

  1. name:Defines the workflow’s display name in GitHub Actions
  2. on: Specifies when the workflow should trigger.
    • Runs automatically on every push or pull request to the main branch.
    • Can also be started manually from the Actions tab using workflow_dispatch.
  3. jobs: Each job groups a set of steps to be executed on a specific runner. In this case, the job runs on a self-hosted runner
  4. steps: Each step defines a task in the CI process. Inside each steps, the run keyword executes shell commands in the runner’s environment.
    • Checkout repository — uses actions/checkout@v4 to download the code into the runner.
    • Set target — loads the ESP-IDF environment and sets the build target to ESP32-S3.
    • Build the Project — compiles the ESP-IDF project.
    • Run Unit tests — runs automated unit tests on the ESP32-S3 through the connected serial port

Running the CI Workflow

  1. Trigger the workflow either commit and push your latest code or manually from the Actions tab.
  2. Go to your repository → Actions tab
    • You’ll see a workflow named "ESP-IDF CI on Raspberry Pi" automatically start.
  3. The workflow will:
    • Build the firmware on the Raspberry Pi
    • Flash the ESP32-S3
    • Run Pytest tests on hardware

Expected Output on GitHub Actions

GitHub action output

You will see the following logs under Run Unit tests section

2025-11-02 04:18:59 #### Running all the registered tests #####
2025-11-02 04:18:59 
2025-11-02 04:18:59 Running GPIO output/input loopback test...
2025-11-02 04:18:59 /home/chandi/actions-runner/_work/esp32_github_ci_testing/esp32_github_ci_testing/components/test_peripheral/test/test_peripheral.c:19:GPIO output/input loopback test:PASS
2025-11-02 04:18:59 
2025-11-02 04:18:59 -----------------------
2025-11-02 04:18:59 1 Tests 0 Failures 0 Ignored 
2025-11-02 04:18:59 OK
2025-11-02 04:19:00 Running ADC reading test...
2025-11-02 04:19:01 /home/chandi/actions-runner/_work/esp32_github_ci_testing/esp32_github_ci_testing/components/test_peripheral/test/test_peripheral.c:31:ADC reading test:PASS
2025-11-02 04:19:01 
2025-11-02 04:19:01 -----------------------
2025-11-02 04:19:01 1 Tests 0 Failures 0 Ignored 
2025-11-02 04:19:01 OK
2025-11-02 04:19:02 Running UART TX/RX test...
2025-11-02 04:19:02 /home/chandi/actions-runner/_work/esp32_github_ci_testing/esp32_github_ci_testing/components/test_peripheral/test/test_peripheral.c:44:UART TX/RX test:PASS
2025-11-02 04:19:02 
2025-11-02 04:19:02 -----------------------
2025-11-02 04:19:02 1 Tests 0 Failures 0 Ignored 
2025-11-02 04:19:02 OK
2025-11-02 04:19:02 
2025-11-02 04:19:02 #### Starting interactive test menu #####
2025-11-02 04:19:02 
2025-11-02 04:19:02 
2025-11-02 04:19:02 
2025-11-02 04:19:02 Press ENTER to see the list of tests.

============================================================
Testing GPIO Output/Input Loopback
============================================================
GPIO test PASSED
  GPIO pins are functioning correctly
  Digital I/O is reliable

============================================================
Testing ADC Reading
============================================================
ADC test PASSED
  ADC readings are within expected range
  Analog measurements are reliable

============================================================
Testing UART TX/RX
============================================================
UART test PASSED
  UART communication is working
  TX/RX loopback successful

============================================================
FINAL TEST SUMMARY
============================================================
Passed: 3/3 - GPIO, ADC, UART
Failed: 0/3 - None

ALL TESTS PASSED - System is fully operational
============================================================
.

============================== 1 passed in 9.28s ===============================

Notes

This project was tested on:

  • Board: ESP32-S3-DevKitC-1
  • ESP-IDF: v5.5.1 with Pytest
  • Raspberry Pi HW: Raspberry Pi 3 Model B
  • OS: Debian GNU/Linux 13 (trixie)

What You’ll Learn

By the end of this tutorial, you will understand how to:

  • Set up a Raspberry Pi as a self-hosted GitHub Actions runner.
  • Configure ESP-IDF and Pytest to work seamlessly in an automated CI environment.
  • Use GitHub Actions to build, flash, and test ESP32 firmware automatically.
  • Run hardware-in-the-loop (HIL) testing directly from GitHub whenever new code is pushed.
  • Extend this setup for continuous testing and integration in embedded firmware projects.

License

MIT License © 2025 — Chandima Jayaneththi

About

Automated ESP32 testing using GitHub Actions with a Raspberry Pi self-hosted runner. This project builds, flashes, and tests ESP-IDF firmware automatically on real ESP32-S3 hardware using Unity and Pytest.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published