Skip to content

Commit cf50619

Browse files
Updated the readme and added the workflow file
1 parent 70571eb commit cf50619

File tree

3 files changed

+330
-0
lines changed

3 files changed

+330
-0
lines changed

.github/workflows/ci.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# This is a basic workflow to help you get started with Actions
2+
3+
name: ESP-IDF CI on Raspberry Pi
4+
5+
# Controls when the workflow will run
6+
on:
7+
# Triggers the workflow on push or pull request events but only for the "main" branch
8+
push:
9+
branches: [ "main" ]
10+
pull_request:
11+
branches: [ "main" ]
12+
13+
# Allows you to run this workflow manually from the Actions tab
14+
workflow_dispatch:
15+
16+
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
17+
jobs:
18+
# This workflow contains a single job called "build"
19+
build:
20+
# The type of runner that the job will run on
21+
runs-on: self-hosted
22+
23+
# Steps represent a sequence of tasks that will be executed as part of the job
24+
steps:
25+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
26+
- uses: actions/checkout@v4
27+
28+
- name: Set target
29+
shell: bash
30+
working-directory: test
31+
run: |
32+
. ~/esp/esp-idf/export.sh
33+
idf.py set-target esp32s3
34+
35+
- name: Build the Project
36+
shell: bash
37+
working-directory: test
38+
run: |
39+
. ~/esp/esp-idf/export.sh
40+
idf.py build
41+
42+
- name: Run Unit tests
43+
shell: bash
44+
working-directory: test
45+
run: |
46+
. ~/esp/esp-idf/export.sh
47+
pytest pytest_esp32_test.py --port /dev/ttyUSB0

README.md

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
# **Automated ESP32 Testing with GitHub Actions on Raspberry Pi**
2+
This tutorial demonstrates how to automate **ESP-IDF firmware testing** using **GitHub Actions** and a **Raspberry Pi** configured as a **self-hosted runner**.
3+
An **ESP32-S3** board is physically connected to the Raspberry Pi via USB.
4+
5+
This tutorial continues from **[Stage 3 — VS Code Pytest Testing](https://github.com/ChandimaJayaneththi/esp32_hw_testing_series/blob/main/stage3_pytest_testing/README.md)**.
6+
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**.
7+
8+
Whenever new code is pushed to the GitHub repository, the workflow automatically:
9+
10+
1. Builds the ESP-IDF project on the Raspberry Pi.
11+
2. Flashes the ESP32-S3 over USB.
12+
3. Runs the Unity/Pytest tests on real hardware.
13+
14+
This setup allows **true hardware-in-the-loop continuous integration (CI)** for embedded firmware.
15+
16+
---
17+
18+
## Overview
19+
20+
| Component | Description |
21+
|------------|--------------|
22+
| **Raspberry Pi** | Acts as a self-hosted GitHub Actions runner. |
23+
| **ESP32-S3** | Device under test, connected via USB to the Pi. |
24+
| **ESP-IDF v5.5.1** | Installed on Raspberry Pi. |
25+
| **pytest-embedded** | For running firmware tests automatically. |
26+
| **GitHub Account & Repository** | To host the workflow and source code. |
27+
| **Stable Internet Connection** | For Raspberry Pi to communicate with GitHub. |
28+
29+
### GitHub Actions
30+
31+
**GitHub Actions** is GitHub’s built-in automation and CI/CD (Continuous Integration/Continuous Deployment) platform.
32+
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.
33+
34+
#### In this project, GitHub Actions is used to:
35+
- Automatically **build and test ESP-IDF firmware** each time code changes.
36+
- Ensure **code quality and stability** before merging.
37+
- Run **real hardware tests** on an **ESP32-S3 connected to a Raspberry Pi**, without manual flashing or monitoring.
38+
39+
This automation greatly improves productivity and reliability by catching bugs early — just like CI pipelines in large-scale software projects.
40+
41+
---
42+
43+
## Setup
44+
45+
1. **Clone the repository**
46+
47+
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.
48+
49+
```bash
50+
git clone https://github.com/ChandimaJayaneththi/esp32_github_actions_ci_rpi.git
51+
```
52+
Then, create your own GitHub repository (you can name it something like esp32_ci_rpi_runner) and push the cloned project into it
53+
54+
2. **Ensure the Raspberry Pi has internet access and ESP-IDF installed with Pytest:**
55+
56+
```bash
57+
cd ~/esp/esp-idf
58+
./install.sh --enable-pytest
59+
```
60+
- Confirm ESP-IDF installation
61+
```bash
62+
cd ~/esp/esp-idf
63+
. ./export.sh
64+
idf.py --version
65+
```
66+
3. **Connect your ESP32-S3 to the Raspberry Pi via USB**
67+
68+
- Check available ports:
69+
```bash
70+
ls /dev/tty*
71+
```
72+
Example output: /dev/ttyUSB0
73+
74+
4. **ESP32-S3 Hardware configuration**
75+
76+
| Test | Pin Connections | Notes |
77+
|------|------------------|-------|
78+
| **GPIO Test** | `GPIO4 → GPIO5` | Use a jumper wire |
79+
| **ADC Test** | `GPIO6 → GPIO1` (ADC1_CH0) | Jumper wire required |
80+
| **UART Test** | `GPIO17 → GPIO16` | UART1 loopback connection |
81+
82+
🔸 This wiring applies to the **ESP32-S3-DevKitC-1** board.
83+
🔸 Adjust pins if using another ESP32 variant.
84+
85+
---
86+
87+
## Project Structure
88+
89+
```bash
90+
esp32_github_actions_ci_rpi/
91+
├── components/
92+
│ ├── test_peripheral/
93+
│ │ ├── test/test_peripheral.c
94+
│ │ ├── CMakeLists.txt
95+
│ │ └── include/
96+
│ │ └── peripheral.h
97+
│ └── peripheral/
98+
│ ├── peripheral.c
99+
│ └── CMakeLists.txt
100+
├── test/
101+
│ ├── pytest_esp32_test.py
102+
│ ├── pytest.ini
103+
│ └── main/
104+
│ ├── unit_test_peripheral.c
105+
│ └── CMakeLists.txt
106+
├── .github/
107+
│ └── workflows/
108+
│ └── ci.yml # GitHub Actions Workflow file
109+
├── CMakeLists.txt
110+
└── README.md
111+
```
112+
---
113+
114+
## GitHub Self-Hosted Runner Setup (on Raspberry Pi)
115+
1. Go to your repository on GitHub → Settings → Actions → Runners
116+
2. Click `New self-hosted runner`
117+
3. Select `Runner image` as `Linux`
118+
4. Select the `Architecture` according to your Raspberry Pi
119+
- Please confirm the architecture of your Raspberry Pi before configure it using
120+
```bash
121+
uname -a
122+
```
123+
Output examples:
124+
- armv7l → 32-bit ARM (e.g. Raspberry Pi 3 running 32-bit OS)
125+
- aarch64 → 64-bit ARM (e.g. Raspberry Pi 4/5 running 64-bit OS)
126+
5. Run the commands one by one listed under `Download` and `Configure` sections to install, configure and run the GitHub action runner.
127+
6. Once it is successfully done, you can see the Raspberry Pi runner and the status of it on GitHub → Settings → Actions → Runners
128+
129+
130+
**Reference**: [Managing self-hosted runners](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners)
131+
132+
---
133+
134+
## GitHub Actions Workflow (.github/workflows/ci.yml)
135+
Below is the CI workflow file used to automate build, flash, and test steps:
136+
137+
```yaml
138+
name: ESP-IDF CI on Raspberry Pi
139+
140+
on:
141+
push:
142+
branches: [ "main" ]
143+
pull_request:
144+
branches: [ "main" ]
145+
146+
workflow_dispatch:
147+
148+
jobs:
149+
build:
150+
runs-on: self-hosted
151+
152+
steps:
153+
uses: actions/checkout@v4
154+
155+
- name: Set target
156+
working-directory: test
157+
run: |
158+
. ~/esp/esp-idf/export.sh
159+
idf.py set-target esp32s3
160+
161+
- name: Build the Project
162+
working-directory: test
163+
run: |
164+
. ~/esp/esp-idf/export.sh
165+
idf.py build
166+
167+
- name: Run Unit tests
168+
working-directory: test
169+
run: |
170+
. ~/esp/esp-idf/export.sh
171+
pytest pytest_esp32_test.py --port <PORT>
172+
```
173+
**Note:** Replace "PORT" with the correct COM port the ESP32 is connected to.
174+
175+
### Workflow Breakdown
176+
1. `name`:Defines the workflow’s display name in GitHub Actions
177+
2. `on`: Specifies when the workflow should trigger.
178+
- Runs automatically on every push or pull request to the main branch.
179+
- Can also be started manually from the Actions tab using `workflow_dispatch`.
180+
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
181+
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.
182+
- Checkout repository — uses actions/checkout@v4 to download the code into the runner.
183+
- Set target — loads the ESP-IDF environment and sets the build target to ESP32-S3.
184+
- Build the Project — compiles the ESP-IDF project.
185+
- Run Unit tests — runs automated unit tests on the ESP32-S3 through the connected serial port
186+
187+
---
188+
189+
## Running the CI Workflow
190+
1. Trigger the workflow ether commit and push your latest code or manually from the Actions tab.
191+
2. Go to your repository → Actions tab
192+
- You’ll see a workflow named "ESP-IDF CI on Raspberry Pi" automatically start.
193+
3. The workflow will:
194+
- Build the firmware on the Raspberry Pi
195+
- Flash the ESP32-S3
196+
- Run Pytest tests on hardware
197+
198+
---
199+
200+
## Expected Output on GitHub Actions
201+
202+
![GitHub action output](images/ci_results.png)
203+
204+
You will see the following logs under `Run Unit tests` section
205+
```log
206+
2025-11-02 04:18:59 #### Running all the registered tests #####
207+
2025-11-02 04:18:59
208+
2025-11-02 04:18:59 Running GPIO output/input loopback test...
209+
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
210+
2025-11-02 04:18:59
211+
2025-11-02 04:18:59 -----------------------
212+
2025-11-02 04:18:59 1 Tests 0 Failures 0 Ignored
213+
2025-11-02 04:18:59 OK
214+
2025-11-02 04:19:00 Running ADC reading test...
215+
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
216+
2025-11-02 04:19:01
217+
2025-11-02 04:19:01 -----------------------
218+
2025-11-02 04:19:01 1 Tests 0 Failures 0 Ignored
219+
2025-11-02 04:19:01 OK
220+
2025-11-02 04:19:02 Running UART TX/RX test...
221+
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
222+
2025-11-02 04:19:02
223+
2025-11-02 04:19:02 -----------------------
224+
2025-11-02 04:19:02 1 Tests 0 Failures 0 Ignored
225+
2025-11-02 04:19:02 OK
226+
2025-11-02 04:19:02
227+
2025-11-02 04:19:02 #### Starting interactive test menu #####
228+
2025-11-02 04:19:02
229+
2025-11-02 04:19:02
230+
2025-11-02 04:19:02
231+
2025-11-02 04:19:02 Press ENTER to see the list of tests.
232+
233+
============================================================
234+
Testing GPIO Output/Input Loopback
235+
============================================================
236+
GPIO test PASSED
237+
GPIO pins are functioning correctly
238+
Digital I/O is reliable
239+
240+
============================================================
241+
Testing ADC Reading
242+
============================================================
243+
ADC test PASSED
244+
ADC readings are within expected range
245+
Analog measurements are reliable
246+
247+
============================================================
248+
Testing UART TX/RX
249+
============================================================
250+
UART test PASSED
251+
UART communication is working
252+
TX/RX loopback successful
253+
254+
============================================================
255+
FINAL TEST SUMMARY
256+
============================================================
257+
Passed: 3/3 - GPIO, ADC, UART
258+
Failed: 0/3 - None
259+
260+
ALL TESTS PASSED - System is fully operational
261+
============================================================
262+
.
263+
264+
============================== 1 passed in 9.28s ===============================
265+
```
266+
---
267+
268+
## Notes
269+
This project was tested on:
270+
- Board: ESP32-S3-DevKitC-1
271+
- ESP-IDF: v5.5.1 with Pytest
272+
- Raspberry Pi HW: Raspberry Pi 3 Model B
273+
- OS: Debian GNU/Linux 13 (trixie)
274+
---
275+
276+
## What You’ll Learn
277+
278+
279+
280+
---
281+
282+
## License
283+
MIT License © 2025 — Chandima Jayaneththi

images/ci_results.png

31.9 KB
Loading

0 commit comments

Comments
 (0)