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
18018 skills
Install
$ npx -y skills add SensorsIot/Embedded-AI-Harness --skill testbench-mqtt --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/testbench-mqtt

Context preview

The summary Claude sees to decide when to auto-load this skill.

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

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
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.

Get the whole plugin
Stats
181
Stars
54
Forks
Maintained
Maintenance
Python
Language
MIT
License
1mo ago
Last commit
8mo ago
Created

Repo: SensorsIot/Embedded-AI-Harness

Other skills on embedded-ai-harness.