mirror of
https://github.com/mattintech/pyBTMCP.git
synced 2026-07-11 13:01:53 +00:00
v1.4.0: BLE disconnect simulation with teardown support
Features:
- Add BLE disconnect simulation to test client reconnection behavior
- Support immediate disconnect, timed advertising pause, and full BLE teardown
- Add preset test buttons in admin UI (Quick Drop, 5s Pause, BLE Restart, 10s Restart)
- Add simulate_ble_disconnect MCP tool with duration_ms and teardown params
- Add POST /devices/{id}/disconnect API endpoint
Fixes:
- Fix treadmill distance not updating in admin UI (publish values periodically)
- Fix HR variation sending to non-heart_rate devices
- Fix BLE connection ID 0 being treated as "not connected"
- Clean up misleading startup log messages
Firmware: 1.1.0, API: 1.4.0, UI: 1.5.0
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -152,6 +152,32 @@ async def list_tools() -> list[Tool]:
|
||||
"required": ["device_id"],
|
||||
},
|
||||
),
|
||||
Tool(
|
||||
name="simulate_ble_disconnect",
|
||||
description="Simulate a BLE client disconnection to test reconnection behavior",
|
||||
inputSchema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"device_id": {
|
||||
"type": "string",
|
||||
"description": "The ESP32 device ID",
|
||||
},
|
||||
"duration_ms": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 60000,
|
||||
"default": 0,
|
||||
"description": "How long to pause advertising after disconnect (0 = immediate resume)",
|
||||
},
|
||||
"teardown": {
|
||||
"type": "boolean",
|
||||
"default": False,
|
||||
"description": "Full BLE stack teardown - device completely disappears from scans",
|
||||
},
|
||||
},
|
||||
"required": ["device_id"],
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -287,6 +313,38 @@ async def call_tool(name: str, arguments: dict) -> list[TextContent]:
|
||||
text=f"Device {device_id} not found"
|
||||
)]
|
||||
|
||||
elif name == "simulate_ble_disconnect":
|
||||
device_id = arguments["device_id"]
|
||||
duration_ms = arguments.get("duration_ms", 0)
|
||||
teardown = arguments.get("teardown", False)
|
||||
|
||||
payload = {}
|
||||
if duration_ms > 0:
|
||||
payload["duration_ms"] = duration_ms
|
||||
if teardown:
|
||||
payload["teardown"] = True
|
||||
|
||||
await mqtt_client.publish(
|
||||
f"ble-sim/{device_id}/disconnect",
|
||||
json.dumps(payload)
|
||||
)
|
||||
|
||||
if teardown:
|
||||
return [TextContent(
|
||||
type="text",
|
||||
text=f"BLE stack teardown on {device_id}, will reinit in {duration_ms if duration_ms > 0 else 3000}ms"
|
||||
)]
|
||||
elif duration_ms > 0:
|
||||
return [TextContent(
|
||||
type="text",
|
||||
text=f"Disconnected BLE on {device_id}, advertising paused for {duration_ms}ms"
|
||||
)]
|
||||
else:
|
||||
return [TextContent(
|
||||
type="text",
|
||||
text=f"Disconnected BLE on {device_id}, advertising resumed immediately"
|
||||
)]
|
||||
|
||||
else:
|
||||
return [TextContent(
|
||||
type="text",
|
||||
|
||||
Reference in New Issue
Block a user