A comprehensive BLE (Bluetooth Low Energy) fitness device simulator that enables AI agents like Claude to control simulated heart rate monitors, treadmills, and cycling trainers via the Model Context Protocol (MCP).
pyBTMCP consists of three integrated components:
- ESP32 Firmware - Runs on ESP32 microcontrollers to simulate BLE fitness devices
- Python Backend - FastAPI server with MQTT broker for device communication
- MCP Server - Enables Claude and other AI agents to control devices
βββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββββββββ
β Claude/AI β β Docker Container β
β (MCP Client) ββββββΊβ βββββββββββ βββββββββ ββββββββββββ β
βββββββββββββββββββ β β MCP β β MQTT β β FastAPI β β
β β Server βββΊβBroker βββΊβ + Web β β
β βββββββββββ βββββ¬ββββ ββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββΌββββββββββββββββββββββββ
β ESP32 Devices β
β βββββββββββ βββββββββββ βββββββββββ β
β β HR β βTreadmillβ β Bike β β
β β Monitor β β β β Trainer β β
β βββββββββββ βββββββββββ βββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββ
- Docker
- (Optional) ESP32 development board for hardware simulation
docker build -t pybtmcp:latest .docker run -it --rm \
-p 1883:1883 \
-p 8000:8000 \
--name pybtmcp \
pybtmcp:latestThis starts:
- MQTT Broker on port 1883 (for ESP32 device connections)
- Web UI / API on port 8000 (browser interface)
- MCP Server on stdio (for Claude integration)
Open http://localhost:8000 in your browser to see connected devices and control them manually.
To use pyBTMCP with Claude Desktop, add it to your MCP configuration:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"ble-simulator": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-p", "1883:1883",
"-p", "8000:8000",
"--name", "pybtmcp",
"pybtmcp:latest"
]
}
}
}After saving the configuration, restart Claude Desktop. You should see the "ble-simulator" MCP server available.
To add pyBTMCP to Claude Code, run:
claude mcp add ble-simulator \
-s user \
-- docker run -i --rm -p 1883:1883 -p 8000:8000 --name pybtmcp pybtmcp:latestThis adds the MCP server to your user configuration. Use -s project instead to add it to the current project only.
To verify the server was added:
claude mcp listOnce configured, Claude can use these tools to control BLE devices:
List all connected ESP32 BLE simulator devices.
No parameters required
Configure an ESP32 to simulate a specific BLE device type.
| Parameter | Type | Required | Description |
|---|---|---|---|
| device_id | string | Yes | The ESP32 device ID |
| device_type | string | Yes | One of: heart_rate, treadmill, bike |
Set the simulated heart rate for a heart rate monitor device.
| Parameter | Type | Required | Description |
|---|---|---|---|
| device_id | string | Yes | The ESP32 device ID |
| bpm | integer | Yes | Heart rate (30-220 BPM) |
Set simulated values for a treadmill device.
| Parameter | Type | Required | Description |
|---|---|---|---|
| device_id | string | Yes | The ESP32 device ID |
| speed | number | No | Speed in km/h (0-25) |
| incline | number | No | Incline percentage (-5 to 30) |
Set simulated values for a bike/cycling trainer device.
| Parameter | Type | Required | Description |
|---|---|---|---|
| device_id | string | Yes | The ESP32 device ID |
| power | integer | No | Power in watts (0-2000) |
| cadence | integer | No | Cadence in RPM (0-200) |
| speed | number | No | Speed in km/h (0-80) |
Get the current status and values of a specific device.
| Parameter | Type | Required | Description |
|---|---|---|---|
| device_id | string | Yes | The ESP32 device ID |
The web interface at http://localhost:8000 provides:
- Real-time device status via WebSocket (live updates)
- Device type configuration (Heart Rate, Treadmill, Bike)
- Preset values for quick testing (Rest, Warm Up, Cardio, etc.)
- Manual sliders for fine-grained control
- Unit switching (Metric/Imperial)
- HR variation toggle for realistic heart rate simulation
The UI shows WebSocket connection status:
- π’ Live - Connected and receiving real-time updates
- π‘ Connecting... - Attempting to connect
- π΄ Disconnected - Using polling fallback
The FastAPI backend provides these endpoints:
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/devices |
List all devices |
| GET | /api/devices/{id} |
Get device by ID |
| POST | /api/devices/{id}/configure |
Configure device type |
| POST | /api/devices/{id}/values |
Set device values |
| GET | /health |
Health check |
| WS | /ws |
WebSocket for real-time updates |
API documentation is available at http://localhost:8000/docs (Swagger UI).
- ESP32 development board (ESP32-DevKitC, ESP32-WROOM, etc.)
- USB cable for programming
- Install PlatformIO
- Navigate to the firmware directory:
cd firmware/esp32_ble_sim - Build and upload:
pio run -t upload
- On first boot, the ESP32 creates a WiFi access point:
BLE-Sim-XXXX - Connect to the AP and open http://192.168.4.1
- Enter your WiFi credentials and MQTT broker address
- The device will restart and connect to your network
The ESP32 devices communicate via MQTT:
| Topic | Direction | Description |
|---|---|---|
ble-sim/{id}/status |
Device β Server | Device online status |
ble-sim/{id}/values |
Device β Server | Current sensor values |
ble-sim/{id}/config |
Server β Device | Device type configuration |
ble-sim/{id}/set |
Server β Device | Set sensor values |
-
Install dependencies:
pip install -r requirements.txt
-
Start an MQTT broker (e.g., Mosquitto):
mosquitto -c config/mosquitto.conf
-
Start the API server:
uvicorn src.api.main:app --reload --port 8000
-
Run the MCP server (for testing):
python -m src.mcp.server
| Variable | Default | Description |
|---|---|---|
| MQTT_HOST | localhost | MQTT broker hostname |
| MQTT_PORT | 1883 | MQTT broker port |
pyBTMCP/
βββ src/
β βββ mcp/
β β βββ server.py # MCP server implementation
β βββ api/
β β βββ main.py # FastAPI app + WebSocket
β β βββ routes.py # REST API routes
β β βββ mqtt_client.py # MQTT connection manager
β β βββ device_registry.py # Device state tracking
β βββ web/
β βββ static/
β βββ index.html # Web UI
βββ firmware/
β βββ esp32_ble_sim/ # PlatformIO ESP32 project
βββ config/
β βββ mosquitto.conf # MQTT broker config
βββ Dockerfile
βββ entrypoint.sh
βββ requirements.txt
βββ mcp-config.example.json # Example Claude Desktop config
| Device Type | BLE Service | Characteristics |
|---|---|---|
| Heart Rate Monitor | Heart Rate Service (0x180D) | Heart Rate Measurement |
| Treadmill | Fitness Machine Service (0x1826) | Treadmill Data |
| Bike Trainer | Cycling Power Service (0x1818) | Cycling Power Measurement |
- Ensure Docker is running
- Check the config file path is correct for your OS
- Restart Claude Desktop after saving config
- Check Docker logs:
docker logs pybtmcp
- Verify WiFi credentials are correct
- Ensure MQTT broker is reachable from ESP32's network
- Check MQTT broker is listening on port 1883
- Use
mosquitto_sub -t "ble-sim/#" -vto monitor MQTT traffic
- Check browser console for WebSocket errors
- Verify the container is running:
docker ps - The UI falls back to 5-second polling if WebSocket disconnects
MIT License