Hardware-as-a-Service

Run your firmware on the real board.
Before you buy the board.

Submit a binary. It is checked, flashed to a real board on the bench, and its serial output streams back — from the browser, a curl, the Python SDK, or your editor. No order, no wait, no drivers.

bash
$ curl -H "Authorization: Bearer $PAT" -F firmware=@blink.bin
$ https://haas-lab.com/api/v1/jobs
✓ firmware checked against esp32c3-mini-v1
✓ queued — position 1, a board is free
▶ I (125) blink: GPIO configured on pin 2
Get started freeHow it works →

Live demo

Run the demo on a real board.

A precompiled ESP32-C3 program is checked against the board profile, flashed to one of the C3s on the bench, and its serial output is streamed back here as the board prints it: the chip it is, the serial number burned into its eFuse, its flash and its radio — evidence a simulator could not fake. No account needed — one demo per visitor every five minutes, so the bench stays free for everyone.

ready · esp32c3-mini-v1

checked against esp32c3-mini-v1 · flashed to a real ESP32-C3 SuperMini · serial streamed as it prints

System architecture

Cloud control. Local execution.

Jobs are coordinated in the cloud, while the device agent keeps the physical board behind the lab boundary.

Control plane · Cloudflare WorkersArtifact storage · CloudflareHardware boundary · Homelab

How it works

01

Submit firmware

A .bin built for the board's profile, from the dashboard, the API, the Python SDK or the MCP server. It is checked against that profile — size, image format, chip — before it goes anywhere near a board.

curl -F firmware=@blink.bin \
  -H "Authorization: Bearer $PAT" \
  https://haas-lab.com/api/v1/jobs
02

It runs on a real board

The bench takes the job, flashes the binary to the board its profile names, and captures everything that board prints. If every board is busy, you see your place in the queue, live.

QUEUED -> FLASHING -> RUNNING
  -> COMPLETED

profile  esp32c3-mini-v1
queue    position 2, live
03

Watch it, then automate it

Serial output streams to your browser as it happens and is kept with the job. Fetch the log from CI and fail the build on what the board said.

GET /api/v1/jobs/{id}/stream
  -> live serial output

GET /api/v1/jobs/{id}/serial
  -> the whole log

Automate from anywhere

The same API the dashboard uses. Personal access tokens come from the dashboard; the Python SDK and the MCP server speak it for you.

curl
# Flash a binary and read back what the board printed
curl -X POST \
  -H "Authorization: Bearer $PAT" \
  -F firmware=@blink.bin \
  https://haas-lab.com/api/v1/jobs

curl -H "Authorization: Bearer $PAT" \
  https://haas-lab.com/api/v1/jobs/<job-id>/serial
python
from haaslab import Client

client = Client(token="pat_...")

job = client.jobs.create("blink.bin")
job = client.jobs.wait(job.id, timeout=120)
print(client.jobs.serial(job.id))

Why haas-lab

No hardware purchase

Skip the dev board, USB cables, and driver nightmares. We own the hardware; you own the firmware.

Checked before it is flashed

Every binary is checked against the board's profile before it reaches the bench, and a job can only ever replace the application image — never the bootloader, never the partition table.

Automate from CI

One curl command in your GitHub Actions workflow. Get serial output as a build artifact, fail the build on assertion errors.

See it run before you order one

Sign in with Google or GitHub, or try the demo without an account. The bench is six ESP32-C3 boards today, and the public profile catalogue at/api/v1/device-profiles already describes the other targets the platform is built for. Nothing ships to you and nothing needs installing.