健身设备控制服务器

一个控制BLE FTMS健身设备并将完成的锻炼上传到Garmin Connect的服务器。

  • by aviman1109
  • Python
  • 本地部署
  • 1 星标
  • 更新于
在 GitHub 查看 aviman1109/fitness_machine_mcp

使用说明

健身机mcp

MCP服务器,控制BLE FTMS健身机并将完成的锻炼上传到Garmin Connect。

支持的设备类别:

  • 任何FTMS跑步机(测试:ADIDAS 1380--大多数固件不支持速度控制;倾斜+数据读取工作)
  • 任何具有功率目标设置的FTMS自行车训练器(测试:eHuntSun T-SoX——完全ERG控制,0-2000 W)
  • Garmin HRM Pro+--完整配置文件支持:
    • 心率+RR间期(用于HRV分析)
    • RSC(跑步速度和步频)——跑步步频+步幅
    • CSC(自行车速度和节奏)——自行车节奏回退
  • 任何带自行车动力服务的单面BLE踏板功率计(0x1818) (测试目标:Wahoo-Powrlink Zero——左踏板,×2双侧估计)

建筑

BLE FTMS device ──▶ fitness-machine-mcp ──▶ MCP client (Claude / any AI)
                                             │
                                   Garmin Connect upload (TCX)

快速入门(Docker)

docker run -d \
  --network host --privileged \
  -e TREADMILL_BLE_ADDR=XX:XX:XX:XX:XX:XX \
  -e TRAINER_BLE_ADDR=XX:XX:XX:XX:XX:XX \
  -e HRM_BLE_ADDR=XX:XX:XX:XX:XX:XX \
  -e GARMIN_TOKEN_PATH=/tokens/garmin \
  -v /path/to/tokens:/tokens \
  -p 38097:38097 \
  fitness-machine-mcp

--network host --privileged 在Linux上访问BLE需要。

环境变量

变量 默认值 描述
TREADMILL_BLE_ADDR -- FTMS跑步机的BLE MAC地址
TRAINER_BLE_ADDR -- FTMS自行车教练的BLE MAC地址
HRM_BLE_ADDR -- Garmin HRM Pro+的BLE MAC地址
POWER_METER_BLE_ADDR (空) 踏板功率计的BLE MAC——保持未设置跳过
POWER_METER_SIDE left 仪表踩在哪个踏板上(left 或 right);双边估算的功率加倍
GARMIN_TOKEN_PATH ~/.garmin-tokens Garmin Connect身份验证令牌目录的路径
TREADMILL_WORKOUTS_DIR /app/workouts 包含锻炼JSON文件的目录
PORT 38097 HTTP端口
MCP_HOST 0.0.0.0 绑定地址
MCP_PATH /mcp MCP端点路径
MCP_ALLOWED_HOSTS 127.0.0.1:*,localhost:* 允许的主机标头(逗号分隔)
MCP_ALLOWED_ORIGINS http://127.0.0.1:*,http://localhost:* 允许的CORS来源
OTEL_EXPORTER_OTLP_ENDPOINT (残疾) OpenTetry收集器端点
OTEL_SERVICE_NAME fitness-machine-mcp 遥测服务名称
OTEL_RESOURCE_ATTRIBUTES service.namespace=ftms-mcp 其他OTEL资源属性

MCP工具

工具 运动 描述
list_workouts 两者 列出可用的锻炼计划
get_workout(workout_id) 两者都有 完整的锻炼计划细节
create_workout(...) 两者 创建或更新锻炼计划
delete_workout(workout_id) 两者 删除锻炼计划
start_workout(workout_id) 两者 连接到设备并开始锻炼
get_status 两者 当前状态、指标、人力资源、距离
stop_workout 两者 紧急停止
set_speed(speed_kmh) running 直接速度超控(设备必须正在运行)
set_incline(incline_pct) 运行 直接倾斜超控
set_target_power(power_w) 循环 直接ERG功率超控

训练文件格式

跑步

{
  "name": "Z2 Run 45min",
  "sport": "running",
  "incline_pct": 1.0,
  "steps": [
    {"name": "Warm-up",   "duration_secs": 300,  "speed_kmh": 8.0},
    {"name": "Z2 Run",    "duration_secs": 2400, "speed_kmh": 10.0},
    {"name": "Cool-down", "duration_secs": 300,  "speed_kmh": 7.0}
  ]
}

自行车(ERG)

{
  "name": "Sweet Spot 60min",
  "sport": "cycling",
  "steps": [
    {"name": "Warm-up",   "duration_secs": 600,  "power_w": 140},
    {"name": "SS Block",  "duration_secs": 1800, "power_w": 210},
    {"name": "Cool-down", "duration_secs": 600,  "power_w": 120}
  ]
}

power_w 值以瓦特为单位。典型目标:55-75%FTP=耐力,88-95%FTP=最佳点。

自行车锻炼开始行为

当 start_workout 需要一个自行车计划:

  1. 培训师连接+ REQUEST_CONTROL + START_RESUME
  2. 状态变为 ready --HRM Pro+和功率计已经上线
  3. 服务器最多等待120秒,节奏>0(从功率计、HRM Pro+CSC或培训师内部检测到踏板——按优先级顺序)
  4. 一旦检测到踏板,锻炼计时器就会启动,并设置第一步的ERG功率

热身是 第一步 在训练JSON中。没有发动机喷射预热。

传感器数据优先级

度量 主要来源 回退
功率 踏板功率计(power_w_pm) 培训师FTMS(power_w)
Cadence 踏板功率计(cadence_rpm_pm) HRM Pro+CSC(cadence_rpm_csc) → 培训师(cadence_rpm)
心率 HRM Pro+(hr_bpm) 培训师FTMS
HRV(RR) HRM Pro+HR字符RR标志(rr_latest_ms) —
跑步节奏 HRM Pro+RSC(cadence_spm) —

所有字段始终存在于 get_status。零值表示源未连接或尚未报告。

TCX导出对功率和节奏使用最高优先级的非零值。

配对Wahoo零号电力线

  1. 安装踏板并旋转一次以唤醒仪表
  2. 在主机上:
    python3 -c "
    import asyncio
    from bleak import BleakScanner
    async def scan():
        devices = await BleakScanner.discover(timeout=10)
        for d in devices:
            print(d.address, d.name)
    asyncio.run(scan())
    "
    
  3. 查找名为的设备 WAHOO POWRLINK (或类似)并复制其MAC地址
  4. 添加到1Password保管库 Casper MCP → item fitness-machine → field power_meter_ble_addr
  5. 重新生成机密: bash ~/ai-platform/mcps/refresh-secrets.sh fitness-machine-mcp
  6. 重建容器: cd ~/ai-platform/mcps && docker compose up -d --build fitness-machine-mcp

FTMS速度控制注意事项

大多数消费者跑步机都宣传FTMS速度目标设置,但默默地忽略了该命令——固件只使用它来报告数据和接受倾斜变化。这是一个 全行业已知问题。此服务器会很好地处理它(记录警告,不会崩溃)。

自行车教练ERG(Set Target Power,操作码 0x05)在正确实现FTMS目标功能的设备上正常工作。

Garmin上传

已完成的训练将导出为TCX并自动上传:

  • 跑步→ Sport="Running",TPX扩展中的速度+节奏
  • 骑行→ Sport="Biking",电源在 <Watts> TPX扩展字段

通过以下方式进行预身份验证 加思 和点 GARMIN_TOKEN_PATH 在生成的令牌目录中。

监控

OpenTetry跟踪是可选的。集 OTEL_EXPORTER_OTLP_ENDPOINT 以启用跟踪导出。如果未设置,服务器将在没有遥测的情况下正常启动。

许可证

麻省理工学院