UART-controlled ESP32 peripheral for automated E2E Bluetooth testing. Dual-mode (Classic BT + BLE) via Bluedroid on original ESP32. Firmware (ESP-IDF v5.x, 2511 lines C): - NDJSON protocol over UART1 (115200 baud) - System commands: ping, reset, get_info, get_status - Classic BT: GAP, SPP, all 4 SSP pairing modes - BLE: GATTS, advertising, GATT service/characteristic management - 6 device personas: headset, speaker, keyboard, sensor, phone, bare - Event reporter: thread-safe async event queue to host Python MCP server (FastMCP, 1626 lines): - Async serial client with command/response correlation - Event queue with wait_for pattern matching - Tools: connection, configure, classic, ble, persona, events - MCP resources: esp32://status, esp32://events, esp32://personas Tests: 74 unit tests passing, 5 integration test stubs (skip without hardware)
63 lines
1.7 KiB
Makefile
63 lines
1.7 KiB
Makefile
.PHONY: help flash monitor menuconfig build clean test lint format serve
|
|
|
|
IDF_PATH ?= $(HOME)/esp/esp-idf
|
|
SERIAL_PORT ?= /dev/ttyUSB0
|
|
SERIAL_BAUD ?= 115200
|
|
FIRMWARE_DIR := firmware
|
|
|
|
help: ## Show this help
|
|
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \
|
|
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
|
|
|
|
# --- Firmware ---
|
|
|
|
build: ## Build ESP32 firmware
|
|
cd $(FIRMWARE_DIR) && idf.py build
|
|
|
|
flash: ## Flash firmware to ESP32
|
|
cd $(FIRMWARE_DIR) && idf.py -p $(SERIAL_PORT) flash
|
|
|
|
monitor: ## Open serial monitor (ESP-IDF)
|
|
cd $(FIRMWARE_DIR) && idf.py -p $(SERIAL_PORT) monitor
|
|
|
|
flash-monitor: ## Flash and open monitor
|
|
cd $(FIRMWARE_DIR) && idf.py -p $(SERIAL_PORT) flash monitor
|
|
|
|
menuconfig: ## Open ESP-IDF menuconfig
|
|
cd $(FIRMWARE_DIR) && idf.py menuconfig
|
|
|
|
clean-firmware: ## Clean firmware build
|
|
cd $(FIRMWARE_DIR) && idf.py fullclean
|
|
|
|
# --- Python MCP Server ---
|
|
|
|
serve: ## Run MCP server (for development)
|
|
uv run mcbluetooth-esp32
|
|
|
|
test: ## Run Python tests
|
|
uv run pytest tests/ -v
|
|
|
|
test-unit: ## Run unit tests only (no hardware)
|
|
uv run pytest tests/ -v --ignore=tests/integration
|
|
|
|
test-integration: ## Run integration tests (requires ESP32)
|
|
uv run pytest tests/integration/ -v
|
|
|
|
lint: ## Lint Python code
|
|
uv run ruff check src/ tests/
|
|
|
|
format: ## Format Python code
|
|
uv run ruff format src/ tests/
|
|
|
|
# --- Utilities ---
|
|
|
|
raw-monitor: ## Raw serial monitor with screen
|
|
screen $(SERIAL_PORT) $(SERIAL_BAUD)
|
|
|
|
ping: ## Quick ping test via Python
|
|
uv run python -c "import asyncio; from mcbluetooth_esp32.serial_client import SerialClient; \
|
|
async def t(): \
|
|
c = SerialClient('$(SERIAL_PORT)'); await c.connect(); \
|
|
r = await c.send_command('ping'); print(r); await c.disconnect(); \
|
|
asyncio.run(t())"
|