End-to-End Example: STM32 + GitHub Actions + BenchCI Cloud¶
This page shows the full path from firmware build to real hardware validation.
STM32 firmware
↓
GitHub Actions build
↓
BenchCI Cloud run
↓
Cloud-connected Agent
↓
real hardware bench
↓
results in CLI + dashboard
Goal¶
By the end of this example, a CI workflow will:
build firmware
upload the firmware artifact
ask BenchCI to run a hardware test
flash the board through a registered Agent
collect results and logs
show the run in the BenchCI dashboard
Prerequisites¶
You need:
a BenchCI account and active workspace
a hardware machine connected to the DUT
a working
bench.yamla working
suite.yamla registered cloud Agent
a GitHub repository containing your firmware project
Verify the bench is visible:
benchci benches list
Example result:
my-bench online idle
1. Verify local hardware execution¶
On the hardware-connected machine:
benchci run \
--bench bench.yaml \
--suite suite.yaml \
--artifact build/fw.elf \
--verbose
Do not continue until this works locally.
This prevents CI debugging from hiding basic bench problems such as wrong UART ports, missing flash tools, invalid GPIO lines, or firmware that does not print the expected output.
2. Start the cloud Agent¶
On the hardware-connected machine:
benchci agent cloud \
--backend https://api.benchci.dev \
--token YOUR_AGENT_TOKEN \
--bench bench.yaml \
--bench-id my-bench \
--agent-name "STM32 Lab Agent"
The Agent makes outbound requests to the BenchCI backend.
Your lab machine does not need a public inbound port.
3. Add GitHub secrets¶
In GitHub:
Settings → Secrets and variables → Actions → New repository secret
Add:
BENCHCI_EMAIL=engineer@company.com
BENCHCI_PASSWORD=your-password
BENCHCI_API_URL=https://api.benchci.dev
BENCHCI_BENCH_ID=my-bench
Use a dedicated CI account when possible.
4. Add GitHub Actions workflow¶
Create:
.github/workflows/hardware-ci.yml
Example:
name: Hardware CI
on:
push:
branches:
- main
pull_request:
jobs:
build-firmware:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install ARM toolchain
run: |
sudo apt-get update
sudo apt-get install -y make gcc-arm-none-eabi binutils-arm-none-eabi
- name: Build firmware
run: |
make
mkdir -p build
cp path/to/firmware.elf build/firmware.elf
- name: Upload firmware artifact
uses: actions/upload-artifact@v4
with:
name: firmware
path: build/firmware.elf
hardware-test:
runs-on: ubuntu-24.04
needs: build-firmware
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download firmware artifact
uses: actions/download-artifact@v4
with:
name: firmware
path: build
- name: Install BenchCI
run: |
python -m pip install --upgrade pip
pip install --upgrade benchci
- name: Login to BenchCI
run: |
benchci login \
--email "$BENCHCI_EMAIL" \
--password "$BENCHCI_PASSWORD" \
--api-url "$BENCHCI_API_URL"
env:
BENCHCI_EMAIL: ${{ secrets.BENCHCI_EMAIL }}
BENCHCI_PASSWORD: ${{ secrets.BENCHCI_PASSWORD }}
BENCHCI_API_URL: ${{ secrets.BENCHCI_API_URL }}
- name: Run hardware test
run: |
benchci run \
--cloud \
--bench-id "$BENCHCI_BENCH_ID" \
--suite suite.yaml \
--artifact build/firmware.elf \
--verbose
env:
BENCHCI_BENCH_ID: ${{ secrets.BENCHCI_BENCH_ID }}
- name: Upload BenchCI results
if: always()
uses: actions/upload-artifact@v4
with:
name: benchci-results
path: benchci-results/
Update these paths for your project:
path/to/firmware.elf
suite.yaml
5. Push and inspect the run¶
After pushing:
GitHub builds firmware
the firmware artifact is passed to the hardware-test job
BenchCI logs in
BenchCI schedules the run on the selected bench
the Agent flashes firmware and executes the suite
BenchCI downloads results into
benchci-results/GitHub uploads results as workflow artifacts
6. Inspect in the dashboard¶
Open:
https://app.benchci.dev
Use the dashboard to inspect:
run status
bench assignment
agent assignment
event timeline
failure context
artifacts
Example suite.yaml¶
version: "1"
suite:
name: firmware_smoke
tests:
- name: boot_ok
steps:
- expect_uart:
node: dut
transport: console
contains: "[BOOT] OK"
within_ms: 3000
- name: ping
steps:
- send_uart:
node: dut
transport: console
data: "PING\n"
- expect_uart:
node: dut
transport: console
contains: "PONG"
within_ms: 1000
Expected artifacts¶
BenchCI writes results into:
benchci-results/
Typical contents include:
results.json
flash.log
transport-*.log
gpio.log
power.log
The exact logs depend on your bench and suite.
Why this example matters¶
This is the workflow BenchCI is designed for:
software CI discipline
+
real hardware validation
A pull request can now build firmware, schedule a real hardware run, flash a device, validate behavior, and return machine-readable results.