TestHub · Hardware-in-the-loop CI

Every pull request, tested on real boards.

A self-hosted test farm in your own lab. CI pipelines and developers run firmware tests on real hardware and emulators behind your firewall, and nothing in the lab has to be reachable from outside.

  • No open ports, no VPN
  • Your existing tests, unchanged
  • Results in the pull request
GitHub Actions · test-on-hardware
$ thub run --type hw \
    --label board:nucleo-f401re \
    --command './ci/test.sh' --wait
Job A-00123 → lab-hw-01   QUEUED → RUNNING
flash ok · uart captured · pytest
PASSED  tests=42  failed=0
→ comment posted on PR #128
Illustrative run.

The problem

Your boards sit in a closed lab. Your CI can’t reach them.

Manual pre-release testing

Flash, watch the log, repeat. Every release waits for someone at the bench.

Bugs that only real hardware shows

Timing, peripherals and power issues pass in simulation and ship to the field.

Benches nobody can share

Engineers collide on the same board, and remote developers can’t reach it at all.

How it works

One command. Same in CI and on a laptop.

The same thub run works in a pipeline step and on a developer’s machine, so any CI failure can be reproduced exactly.

AGENT · thub

CI pipelines and developers

A CLI and the only way to create jobs. GitHub Actions, GitLab, Bitbucket, Jenkins or a laptop.

COORDINATOR

Queue, scheduler, dashboard

The single source of truth and the only thing with a public HTTPS port. Logs stream live.

Your lab · no inbound traffic

CLIENT · HW

Flashes and tests a real board

CLIENT · SW

Runs an emulator in Docker

  1. 01 Submit

    thub run sends the job: type, labels, command, inputs.

  2. 02 Schedule

    It goes to an idle Client with matching type, labels and group. Never assigned twice.

  3. 03 Prepare

    The Client downloads the firmware and prepares the board or emulator.

  4. 04 Run

    Your command runs. Output and UART logs stream live to CI and the dashboard.

  5. 05 Verdict

    Exit code 0 passes the pipeline, anything else fails it. JUnit counts come back.

Use cases

One lab, every way your team tests

Hardware-in-the-loop CI

Every push builds firmware, then a lab Client flashes a real board through ST-Link, captures its UART and runs the tests.

Emulator test farms

QEMU, Renode or your simulator on Linux machines, in Docker if you like. Scale out by adding VMs.

Remote access for developers

Reproduce a CI failure from home on the exact bench where it happened.

Shared benches without collisions

Reserve a board for 30 minutes to 8 hours or a custom time. Only your jobs run on it, and it’s released when your time is up.

Dedicated pools

Groups and labels route jobs to the right hardware, such as a nightly pool apart from the PR pool.

Any command-line test suite

pytest, ctest, Robot Framework, a Dockerized runner or a flash-and-smoke script.

Remote bench

The lab bench, inside VS Code

Reserve a board from your editor, then flash, debug, read its serial ports and watch its camera as if it sat on your desk. The lab still allows nothing inbound, and everything ends with the reservation.

  • RESERVE30 minutes, 2, 4 or 8 hours, or a custom time. One HIL and one SIL reservation at once.
  • FLASHOne click or a build task, then verify the sections.
  • DEBUGF5 and the standard debug keys, with Cortex-Debug over SWD and OpenOCD.
  • UARTA VS Code terminal with timestamps, a log file or a plain TCP socket.
  • RTTSEGGER RTT logs in a terminal.
  • CAMERAIn VS Code, mpv, ffplay, VLC or the browser. Private to your reservation.
  • AUDITWho reserved which board, for how long, and how it ended.
VS Code · TestHub · Ports
lab-hw-01 · HIL
reserved for you until 16:00
  UART    dut1-uart      localhost:40001
  GDB     ST-Link #1     localhost:3333
  RTT     channel 0      localhost:19021
  CAMERA  bench camera   localhost:8890
  WEB     client:8080    localhost:48080
⚠ 10 minutes left · Extend +1 h · Release
Illustrative.

Features

Everything you need, in the VS Code extension

TestHub works where embedded developers already are: the editor. Every feature below runs in VS Code and talks to your own Coordinator.

Lab and reservations

  • Reserve a board from your editor, for 30 minutes, 2, 4, 8 hours or a custom time.
  • Hold one hardware (HIL) and one simulation (SIL) reservation at the same time.
  • Warnings 10 minutes before a reservation ends, with one-click extend (+1 hour) or release.
  • Only your jobs run on a board you hold; the board is released when your time is up.

Flash and debug from VS Code

  • Flash your firmware (ELF) to a remote board with one click or as a build task.
  • Flash after build: a successful build loads the board automatically, with an option to skip an unchanged image.
  • Verify after flashing (compare sections), then reset and run, stay halted, or start debugging.
  • Debug a remote board with F5 and the standard debug keys, using Cortex-Debug.
  • Pick which ST-Link (SWD probe) to flash or debug from its record in the tree.
  • Works over SWD through OpenOCD on the board’s Client; choose the OpenOCD target per board or per workspace.
  • Reattach the debugger if the link drops.

Serial and logs

  • Open a board’s UART as a VS Code terminal, with timestamps.
  • Log everything a serial terminal receives to a file.
  • Reach any UART from other tools as a plain TCP socket (for example pyserial).
  • RTT logs: read SEGGER RTT output from the board in a terminal, with saved search settings per board.

Camera

  • Watch a board’s camera inside VS Code, in an external player (mpv, ffplay, VLC) or in the browser.
  • Each camera stream is private to your reservation and stops when the reservation ends.

Ports and services

  • One Ports panel lists every local port of your connected boards: UARTs, GDB, RTT, camera and forwarded services.
  • Forward a service running on a board’s Client (for example a web UI) and open it inside VS Code.
  • Forwarded services are saved per board and restored on reconnect.

Setup and security

  • Sign in to your Coordinator with an access key, stored in VS Code’s secret storage.
  • The Agent CLI installs and updates itself in VS Code; no separate install is needed.
  • Works over Remote-SSH, WSL and dev containers: the tools run on the same machine as the extension.

STM32G491

Demo firmware included

An STM32G491 demo project: periodic UART tick message, LED control over UART (ON, OFF, BLINK), RTT logs and an independent watchdog that resets the board if it stops responding.

Limits, stated plainly

  • USB power control (power cycle, on, off) works only during a job of yours on the board. Reservation-wide power control isn’t available yet.
  • Forwarded services must listen on 127.0.0.1 on the Client host.

Hardware

Boards, flight controllers and simulators

Every target follows one pattern: name its USB port, flash with its own tool, check the result. Ready-made scripts and Client configs are in the examples repository.

TargetConnected byFlashed withChecked over
STM32 Nucleo-64ST-LINK/V2-1st-flashvirtual COM port
nRF52840 DKJ-Link OBnrfutilVCOM
ESP32-DevKitCCP2102N UARTesptoolUART
Arduino Uno R3ATmega16U2avrdudeUSB serial
Betaflight FCSTM32 USB / DFUdfu-utilBetaflight CLI
ArduPilot FCUSBuploader.pyMAVLink
RenodeSW Client, Docker—emulated UART
QEMUSW Client—semihosting, exit code

Plus USB power control through a smart USB hub during your jobs, several boards per Client, and scheduled nightly reboots.

CI/CD & code review

Results where reviewers already look

The pipeline step fails exactly when the tests do. Canceling the pipeline cancels the job. Failed tests land in the pull or merge request.

GitHub ActionsGitLabBitbucketJenkins

JUnit from pytest, ctest, Robot Framework, Maven and Gradle.

Pull request #128 · comment

✓ PassedA-00123 · lab-hw-01 · 3 m 12 s

42 tests · 0 failed · 0 skipped

- uses: andrianyablonskyy/thub-action@v1
  with:
    type: hw
    key: ${{ secrets.THUB_CI_TOKEN }}

Illustrative comment. The GitHub action also writes a Job Summary and a commit status.

Security

Built to pass your security review

  • Outbound only. Lab machines dial out over HTTPS. The firewall allows nothing inbound.
  • On-premises. Firmware, logs and job state stay in your network.
  • Least privilege. Jobs run as a service user, never as root. CI tokens never reach the lab.
  • SSO. GitHub and Google sign-in, limited to your organisations or domains.
  • Audit log. Every change and reservation, with who made it.

Deployment

Small to run, quick to start

One Coordinator, a single Node.js process with SQLite, serves tens of Clients and hundreds of jobs a day. A quick-start script brings up a Coordinator, a demo Client and a first job in minutes.

Docker amd64 · arm64ComposeKubernetesAnsiblesystemd

Start with a pilot

30 days in your lab, credited to the licence

We set TestHub up for you: up to 4 boards, one pipeline and hands-on support. The paid pilot is credited to the annual licence.

Book a free bench review →30 minutes with an engineer

Bench review

Show us your bench.

In 30 minutes we map your boards and pipeline to a TestHub setup and a pilot plan. Free.

info@adsystem.pro · +380 67 439 1881

We use your details only to reply to you.