Skip to content
Development
Skill

/testbench-mqtt

Use this skill whenever tests involve MQTT communication — starting/stopping the mosquitto broker on the testbench Pi, publishing test messages, subscribing to topics, or verifying ESP32 MQTT client behavior. The broker runs on the Pi's WiFi AP network (192.168.4.1:1883) so DUTs

From plugin
embedded-ai-harness
27918 skills

Claude Code

$ npx -y skills add SensorsIot/Embedded-AI-Harness --skill testbench-mqtt --agent claude-code

SKILL.md

testbench-mqtt.SKILL.md
name: testbench-mqtt
description: Use this skill whenever tests involve MQTT communication — starting/stopping the mosquitto broker on the testbench Pi, publishing test messages, subscribing to topics, or verifying ESP32 MQTT client behavior. The broker runs on the Pi's WiFi AP network (192.168.4.1:1883) so DUTs can reach it without internet. Use for MQTT integration tests, pub/sub verification, and broker lifecycle management. Triggers on "MQTT", "broker", "mosquitto", "publish", "subscribe", "topic", "MQTT test".

ESP32 MQTT Broker

Base URL: `$TESTBENCH_URL` — see Step 0

Step 0: Point at a bench

There are several benches and their addresses move, so nothing here writes one down. `$BENCH` is not usable either — a container cannot resolve mDNS. Discover the bench and export its URL:

export TESTBENCH_URL=$(sudo python3 .claude/skills/esp-idf-handling/discover-testbench.py \
                         --url --name <bench-hostname>)
curl -s "$TESTBENCH_URL/api/info"        # confirm before anything else

`--url` refuses to guess when more than one bench answers, so `--name` is required whenever a second bench is powered on. `TESTBENCH_URL` is the same variable `pytest --wt-url` falls back to.

The testbench can run an MQTT broker (mosquitto) for testing ESP32 devices that use MQTT for communication. The broker is accessible to devices connected to the testbench's WiFi AP.

Endpoints

Request and response shapes: [FSD Appendix D.12](../../../docs/Harness-FSD.md#d12-mqtt-test-broker).

Examples

# Start the MQTT broker
curl -X POST $TESTBENCH_URL/api/mqtt/start

# Check broker status
curl $TESTBENCH_URL/api/mqtt/status

# Stop the MQTT broker
curl -X POST $TESTBENCH_URL/api/mqtt/stop

MQTT Broker Details

| Property | Value | |----------|-------| | Broker | the bench address (from the LAN) or `192.168.4.1` (from the testbench AP) | | Default port | `1883` | | Authentication | None (open broker for testing) |

Common Workflows

1. **Test ESP32 MQTT client:**

  • Ensure device is on testbench WiFi (see testbench-wifi)
  • `POST /api/mqtt/start` — start broker
  • Device connects to `192.168.4.1:1883`
  • Monitor device behavior via serial or UDP logs (see testbench-logging)
  • `POST /api/mqtt/stop` — stop broker when done

2. **Test MQTT disconnect/reconnect:**

  • Start broker, let device connect
  • `POST /api/mqtt/stop` — device loses MQTT
  • Monitor device's reconnection behavior
  • `POST /api/mqtt/start` — device should reconnect

**On a *shared* broker, don't stop it — isolate the one device.** If the broker also carries other devices (or the device under test uses a production broker over a tunnel rather than the bench mosquitto), stopping it is collateral damage. Cut MQTT for a single device with a source-scoped firewall rule on the broker host instead (needs root there):

   # black hole (timeout): device sees silence, its keepalive eventually fires the will
   iptables -I INPUT -s <device-ip> -p tcp --dport 1883 -j DROP
   # connection refused (TCP reset): device sees an immediate refusal
   iptables -I INPUT -s <device-ip> -p tcp --dport 1883 -j REJECT --reject-with tcp-reset

The two are different tests: `DROP` is the "broker went away" black hole that exercises the last-will keepalive timeout; `REJECT` is the "broker actively refuses" path. Delete the rule (`-D` instead of `-I`) to restore. Prefer this over `/api/mqtt/stop` whenever the broker is not exclusively the DUT's.

3. **Test MQTT + WiFi together:**

  • Start AP + broker
  • `POST /api/wifi/ap_stop` — device loses both WiFi and MQTT
  • `POST /api/wifi/ap_start` + `POST /api/mqtt/start` — restore both
  • Verify device recovers

A last-will topic is death-only — don't test for it "returning to online"

The MQTT Last Will is published by the **broker**, on the device's behalf, only when the connection drops uncleanly. A device typically registers a retained will like `<id>/LWT = offline` and signals *liveness* on a **separate** birth or status topic (e.g. `<id>/STATUS {"online":true}`, republished on every connect and periodically). Nothing ever writes `LWT = online` — the will topic stays `offline` from the last drop until the next one.

So when checking recovery after an outage, watch for the **birth/status message to be republished**, not for the will topic to flip back. And because the retained will persists, a stale `offline` cannot be told apart from a freshly fired one by reading the retained value — to prove a will *fired*, seed a sentinel first (`mosquitto_pub -t <id>/LWT -r -m sentinel`), then confirm the broker overwrites it with `offline` once the keepalive expires.

A retained status read mid-outage is a stale corpse

`mosquitto_sub -C 1` on a retained status/telemetry topic returns the **last published value**, which during (and right after) an outage is the copy from *before* the device dropped — its counters are frozen. Reading it to judge recovery gives a false negative: e.g. `mqtt_disconnects` still shows the pre-outage number because the device has not reconnected and republished yet.

Judge recovery by the device **resuming live publishing**, not by the retained value. Subscribe for longer than the publish cadence and require ≥2 arrivals (the immediate retained copy, then at least one fresh publish); only then read counters. An MQTT reconnect does **not** reset uptime, so "small uptime" cannot stand in for "fresh" — only a live arrival can.

Don't over-specify long black-hole durations

A spec that says "cut MQTT for 30 minutes" is usually testing "the device never restarts on MQTT loss." Unlike WiFi (which often has a restart-after-N-minutes rule), **MQTT loss typically has no restart timer at all** — so a few minutes proves "never restarts" exactly as well as 30, and the extra 25 just confirm the same nothing. Reserve long windows for behaviour actually gated on a long timer (a WiFi r

Read more
@sensorsiot
Ships withembedded-ai-harness

Spec to silicon, hands off. A horse is strong, fast, and willing — and useless for heavy loads until you harness it. The harness is not a part of the horse and not a part of the cart: it is the coupling that turns raw strength into pulled weight.

Stars on GitHub

Momentum

stars in total
279
Star history of SensorsIot/Embedded-AI-Harness on GitHub, a chart by star-history.com

Other skills on embedded-ai-harness.

build

build

Phase 3 of AI Closed-Loop Programming — the Build phase, and the driver of the whole loop: locate the project on the chain, name…

define

define

Phase 0 of AI Closed-Loop Programming — Definition: engineers the WHAT the loop converges on. Writes and evolves the FSD —…

grill-me

grill-me

Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills10d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc12d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react1d252k
@facebook@facebookInstall Skill

Questions about testbench-mqtt.

Which coding agents can use testbench-mqtt?
testbench-mqtt installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.