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 the user needs to interact with BLE peripherals through the testbench — scanning for devices, connecting by address, writing to GATT characteristics, or checking connection status. The Pi acts as a BLE-to-HTTP bridge using bleak. Also use when sending
$ npx -y skills add SensorsIot/Embedded-AI-Harness --skill testbench-ble --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/testbench-bleContext preview
The summary Claude sees to decide when to auto-load this skill.
Use this skill whenever the user needs to interact with BLE peripherals through the testbench — scanning for devices, connecting by address, writing to GATT characteristics, or checking connection status. The Pi acts as a BLE-to-HTTP bridge using bleak. Also use when sending
name: testbench-ble description: Use this skill whenever the user needs to interact with BLE peripherals through the testbench — scanning for devices, connecting by address, writing to GATT characteristics, or checking connection status. The Pi acts as a BLE-to-HTTP bridge using bleak. Also use when sending keystrokes to BLE HID devices, triggering OTA via BLE commands, or debugging BLE connectivity. Triggers on "BLE", "bluetooth", "GATT", "NUS", "Nordic UART", "BLE scan", "BLE write", "BLE connect".
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.
Request and response shapes: [FSD Appendix D.5](../../../docs/Harness-FSD.md#d5-ble-proxy).
**One BLE connection at a time** — connect to a second peripheral without disconnecting the first and the call fails rather than switching.
# Scan for BLE devices (5s timeout)
curl -X POST $TESTBENCH_URL/api/ble/scan \
-H 'Content-Type: application/json' \
-d '{"timeout": 5}'
# Scan with name filter
curl -X POST $TESTBENCH_URL/api/ble/scan \
-H 'Content-Type: application/json' \
-d '{"timeout": 5, "name_filter": "<device-name>"}'
# Connect by MAC address
curl -X POST $TESTBENCH_URL/api/ble/connect \
-H 'Content-Type: application/json' \
-d '{"address": "AA:BB:CC:DD:EE:FF"}'
# Write hex data to a GATT characteristic
curl -X POST $TESTBENCH_URL/api/ble/write \
-H 'Content-Type: application/json' \
-d '{"characteristic": "6e400002-b5a3-f393-e0a9-e50e24dcca9e", "data": "48656c6c6f", "response": true}'
# Check connection status
curl $TESTBENCH_URL/api/ble/status
# Disconnect
curl -X POST $TESTBENCH_URL/api/ble/disconnect| UUID | Role | |------|------| | `6e400001-b5a3-f393-e0a9-e50e24dcca9e` | NUS Service | | `6e400002-b5a3-f393-e0a9-e50e24dcca9e` | RX Characteristic (write to this) | | `6e400003-b5a3-f393-e0a9-e50e24dcca9e` | TX Characteristic (notifications from device) |
1. **Send a command via NUS:**
2. **Check if device is advertising:**
3. **Send binary command protocol:**
| Problem | Fix | |---------|-----| | "BLE not available" | `bleak` not installed on testbench Pi | | Scan returns empty | Increase timeout; check device is advertising | | Connect fails (409) | Already connected — disconnect first | | Write fails "invalid hex data" | Data must be hex string (e.g., `"48656c6c6f"` for "Hello") | | Device not found by name | Check exact advertised name; BLE names are case-sensitive |
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…