Skip to content

Repository files navigation

S1ProHeartRate

面向 Windows 10/11 x64 的 Xiaomi Watch S1 Pro 原生 WPF 实时健康客户端。

当前已完成并通过真实手表验证:

Bluetooth Classic / RFCOMM SPP
→ Xiaomi SPP V1 协商
→ Xiaomi Authentication
→ AES-CCM 加密 Protobuf
→ RealTimeStats
→ 实时 BPM

项目使用 C#、WPF、.NET 10、Google.Protobuf、System.Security.Cryptography.AesCcm 和 Windows 原生 Bluetooth/RFCOMM API,不依赖 Android 或 Gadgetbridge 运行时。

配置

复制配置模板:

Copy-Item .\appsettings.example.json .\appsettings.json

编辑本机的 appsettings.json

{
  "DeviceMac": "AA:BB:CC:DD:EE:FF",
  "AuthKey": "",
  "AttemptWindowsPairing": false,
  "AutoReconnect": true,
  "ReconnectIntervalSeconds": 5
}
  • DeviceMac:手表的 48-bit Bluetooth Classic 地址。
  • AuthKey:16 bytes,即 32 个十六进制字符;也接受可选的 0x 前缀。
  • AttemptWindowsPairing:默认不主动发起 Windows 系统配对。
  • AutoReconnect:连接丢失后是否重新建立完整 RFCOMM、SPP 和认证会话。
  • ReconnectIntervalSeconds:重连间隔,范围 1~3600 秒。

appsettings.jsonMiFitnessLogs/、运行日志、构建输出和临时协议参考目录均被 .gitignore 排除。程序不会输出 AuthKey、完整 session key 或认证帧中的 nonce/HMAC;认证帧日志只保留方向和字节长度。

项目不会把真实的 appsettings.json 自动复制到 bin/ 或发布目录,避免把 AuthKey 意外打包。dotnet run 会从当前项目目录读取本机配置;分发应用时, 请由最终用户在程序目录手动创建 appsettings.json,不要把开发机配置放入 安装包或压缩包。

构建和运行

dotnet build
dotnet run

窗口启动后会读取 appsettings.json 并自动连接。主界面显示:

  • 实时心率与最近 60 个样本的趋势;
  • 今日步数、卡路里和站立小时;
  • RFCOMM/SPP、协议版本、AES-CCM 和会话状态;
  • 可滚动、可清空的十六进制协议日志。

仅在明确需要 Windows 系统配对时运行:

dotnet run -- --pair

点击主窗口关闭按钮或按 Alt+F4 时,程序默认隐藏到 Windows 系统托盘, RFCOMM 与实时心率采集继续运行。双击托盘图标可恢复主界面;托盘菜单还可 显示/隐藏心率悬浮窗。只有选择托盘菜单中的“退出”,或点击主界面的“断开”, 程序才会尽可能发送 realtime stats stop 并关闭 RFCOMM socket。“连接”按钮 会从 RFCOMM 开始重新建立完整的新会话。

Windows RFCOMM

标准 Serial Port Profile UUID:

00001101-0000-1000-8000-00805F9B34FB

主连接路径:

BluetoothDevice.FromBluetoothAddressAsync(MAC)
→ GetRfcommServicesAsync(BluetoothCacheMode.Uncached)
→ 找到标准 SPP 的 RfcommDeviceService
→ StreamSocket.ConnectAsync(
      ConnectionHostName,
      ConnectionServiceName,
      BluetoothEncryptionAllowNullAuthentication)

若 SDP 没有返回 SPP,程序不会立即退出,而会使用 Windows Winsock Bluetooth RFCOMM,以 SOCKADDR_BTH.serviceClassId = SPP_UUID 直接连接。

Xiaomi SPP V1

版本请求与 Gadgetbridge 当前实现一致:

BA DC FE 00 C0 03 00 00 00 00 EF

真实手表响应:

BA DC FE 00 00 06 00 01 00 00 00 02 0E EF

响应 payload 为 00 02 0E。Gadgetbridge 当前依据 payload 首字节判断: 小于 2 使用 V1,大于等于 2 切换到 V2,因此该手表使用 SPP V1。

V1 Protobuf 发送使用 raw channel 2,接收使用 channel 1。认证阶段 data type 为 2;认证完成后的业务命令 data type 为 1。

Xiaomi Authentication

认证流程:

type=1 subtype=26 + 16-byte phone nonce
→ watch nonce + watch HMAC
→ HMAC-SHA256 derivation context "miwear-auth"
→ encryption/decryption keys and nonce prefixes
→ constant-time watch HMAC verification
→ type=1 subtype=27
→ AES-CCM encrypted AuthDeviceInfo
→ authentication success

AES-CCM 使用 12-byte nonce 和 4-byte authentication tag。

实时心率

认证成功后发送:

Command {
  type = 8
  subtype = 45
}

V1 上行加密包使用递增的 32-bit packet counter 构造 AES-CCM nonce,并在 密文前放置 counter 的低 16 位小端值。收到 type=8 subtype=47 后解析:

Command.health.realTimeStats.heartRate

输出示例:

[HR] 78 BPM
[HR] 79 BPM
[HR] 80 BPM

退出时发送:

Command {
  type = 8
  subtype = 46
}

实机验证结果

2026-07-27 已使用真实 Xiaomi Watch S1 Pro 验证:

  • RFCOMM SPP 连接成功。
  • SPP V1 协商成功。
  • Watch nonce 和 HMAC 校验成功。
  • AES-CCM session 建立成功。
  • realtime stats start 加密发送成功。
  • 连续收到 subtype 47。
  • 连续收到并解析到有效的实时 BPM 样本。
  • WPF“断开”和托盘“退出”会执行 realtime stats stop 安全退出流程。
  • 主窗口关闭默认隐藏到系统托盘,实时心率连接保持运行。
  • WPF“连接”按钮可重新建立 RFCOMM、SPP、认证和实时统计会话。
  • dotnet build:0 个警告,0 个错误。

Windows 偶尔会在读取 pairing 元数据时返回 COMException 0x80004004, 但不影响后续 SDP 枚举、RFCOMM 连接和 Xiaomi 协议通信。

当前边界

项目目前包含连接、SPP、认证、加密 Protobuf、实时心率以及 WPF 状态面板和 实时趋势。未实现 OBS、通知、天气、音乐或运动历史同步。

About

Windows Xiaomi Watch S1 Pro realtime heart-rate client over Bluetooth Classic RFCOMM

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages