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 the next act, design and…
Use this skill whenever you need to control the testbench's WiFi radio for testing — starting a SoftAP for DUTs to connect to, joining a DUT's captive portal as a station, scanning for networks, relaying HTTP requests to devices on the WiFi network, or provisioning DUT WiFi
$ npx -y skills add SensorsIot/Embedded-AI-Harness --skill testbench-wifi --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/testbench-wifiContext preview
The summary Claude sees to decide when to auto-load this skill.
Use this skill whenever you need to control the testbench's WiFi radio for testing — starting a SoftAP for DUTs to connect to, joining a DUT's captive portal as a station, scanning for networks, relaying HTTP requests to devices on the WiFi network, or provisioning DUT WiFi
name: testbench-wifi description: Use this skill whenever you need to control the testbench's WiFi radio for testing — starting a SoftAP for DUTs to connect to, joining a DUT's captive portal as a station, scanning for networks, relaying HTTP requests to devices on the WiFi network, or provisioning DUT WiFi credentials. Essential for any test that involves WiFi connectivity, captive portal flows, or HTTP communication with devices on the isolated test network (192.168.4.x). Triggers on "wifi", "AP", "station", "scan", "provision", "captive portal", "enter-portal", "HTTP relay", "wifi test", "SoftAP".
Base URL: `$TESTBENCH_URL` — see Step 0
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 has two WiFi operating modes:
| Mode | wlan0 usage | WiFi endpoints | |------|-------------|----------------| | **wifi-testing** (default) | Test instrument (AP/STA/scan) | Active | | **serial-interface** | Joins WiFi for additional LAN | Disabled |
# Check current mode
curl $TESTBENCH_URL/api/wifi/mode
# Switch to wifi-testing mode
curl -X POST $TESTBENCH_URL/api/wifi/mode \
-H 'Content-Type: application/json' \
-d '{"mode": "wifi-testing"}'
# Switch to serial-interface mode (joins a WiFi network)
curl -X POST $TESTBENCH_URL/api/wifi/mode \
-H 'Content-Type: application/json' \
-d '{"mode": "serial-interface", "ssid": "MyNetwork", "pass": "password"}'Request and response shapes: [FSD Appendix D.4](../../../docs/Harness-FSD.md#d4-wifi-instrument), plus `/api/enter-portal` in [D.2](../../../docs/Harness-FSD.md#d2-serial-management).
**AP and STA are mutually exclusive** — one radio. Starting the AP drops any STA association and vice versa, so a test that needs both must sequence them.
# Start AP
curl -X POST $TESTBENCH_URL/api/wifi/ap_start \
-H 'Content-Type: application/json' \
-d '{"ssid": "TestAP", "pass": "testpass123", "channel": 6}'
# Check AP status and connected clients
curl $TESTBENCH_URL/api/wifi/ap_status
# Stop AP
curl -X POST $TESTBENCH_URL/api/wifi/ap_stopAP and STA are mutually exclusive — starting one stops the other.
# Join a network
curl -X POST $TESTBENCH_URL/api/wifi/sta_join \
-H 'Content-Type: application/json' \
-d '{"ssid": "MyNetwork", "pass": "password", "timeout": 15}'
# Disconnect
curl -X POST $TESTBENCH_URL/api/wifi/sta_leavecurl $TESTBENCH_URL/api/wifi/scan
To test a device's behavior when WiFi connectivity is lost and restored:
# 1. Ensure device is connected to testbench AP
curl -X POST $TESTBENCH_URL/api/wifi/ap_start \
-H 'Content-Type: application/json' \
-d '{"ssid": "TestAP", "pass": "testpass123"}'
# 2. Stop AP — device loses WiFi
curl -X POST $TESTBENCH_URL/api/wifi/ap_stop
# 3. Monitor device behavior (serial or UDP logs)
# ... wait for desired duration ...
# 4. Restart AP — device should reconnect
curl -X POST $TESTBENCH_URL/api/wifi/ap_start \
-H 'Content-Type: application/json' \
-d '{"ssid": "TestAP", "pass": "testpass123"}'
# 5. Wait for device to reconnect
curl "$TESTBENCH_URL/api/wifi/events?timeout=30"**IMPORTANT:** Devices on the testbench AP (192.168.4.x) are NOT directly reachable from the development machine. Always use this relay to make HTTP requests to device endpoints (e.g. `/status`, `/ota`). The response body is base64-encoded — decode it to get the actual JSON.
# GET request to device
curl -X POST $TESTBENCH_URL/api/wifi/http \
-H 'Content-Type: application/json' \
-d '{"method": "GET", "url": "http://192.168.4.2/status", "timeout": 10}'
# POST with base64-encoded body
BODY=$(echo -n '{"key":"value"}' | base64)
curl -X POST $TESTBENCH_URL/api/wifi/http \
-H 'Content-Type: application/json' \
-d "{\"method\": \"POST\", \"url\": \"http://192.168.4.2/config\", \"headers\": {\"Content-Type\": \"application/json\"}, \"body\": \"$BODY\", \"timeout\": 10}"
# Decode the base64 response body
curl -s -X POST $TESTBENCH_URL/api/wifi/http \
-H 'Content-Type: application/json' \
-d '{"method": "GET", "url": "http://192.168.4.x:8080/endpoint", "timeout": 10}' \
| python3 -c "import json,sys,base64; r=json.load(sys.stdin); print(base64.b64decode(r['body']).decode())"Long-poll for STA_CONNECT / STA_DISCONNECT events:
curl "$TESTBENCH_URL/api/wifi/events?timeout=30"
Ensures a device is connected to the testbench AP. If the device has no WiFi credentials, the testbench provisions it via the device's captive portal.
curl -X POST $TESTBENCH_URL/api/enter-portal \
-H 'Content-Type: application/json' \
-d '{"portal_ssid": "<DUT-portal-SSID>", "ssid": "TestAP", "password": "testpass123"}'| Field | Description | |-------|-------------| | `portal_ssid` | Device's captive portal SoftAP name | | `ssid` | Testbench's AP SSID (filled into the device's portal form) | | `password` | Testbench's AP password (filled into the device's portal form) |
**Procedure:** 1. Starts testbench AP (using `ssid`/`password`) if not already running 2. Waits for the device to connect (it may already have credentials) 3. If device doesn't connect, testbench joins the device's captive portal So
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.
Phase 3 of AI Closed-Loop Programming — the Build phase, and the driver of the whole loop: locate the project on the chain, name the next act, design and…
Phase 2 of AI Closed-Loop Programming — Commissioning: prove the project's OWN never-seen-working parts (its board, its wiring, its peers/simulators), so that…
Phase 0 of AI Closed-Loop Programming — Definition: engineers the WHAT the loop converges on. Writes and evolves the FSD — atomic, falsifiable,…
Complete ESP-IDF lifecycle: project setup, build, flash, monitor, and OTA. Automatically detects whether a testbench is available or the device is connected…
PlatformIO lifecycle for ESP32 firmware: platformio.ini, environment selection, build, upload and serial monitor, on local USB or through the testbench. Covers…
Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree. Use when user wants to…