.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())"