feat(miniprogram): BLE 设备同步模块 — 扫描+连接+数据上传
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

- Task 18: BLE 类型定义(NormalizedReading/DeviceAdapter/BLEDevice)+ BLEManager 连接管理器
- Task 19: XiaomiBandAdapter 心率读取适配器(标准 HRS Service 0x180D)
- Task 20: device-sync API 层 + 设备同步页面 + app.config 路由注册
This commit is contained in:
iven
2026-04-27 07:53:12 +08:00
parent d1ab8074a3
commit 215fb35e0e
9 changed files with 1011 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
import type { DeviceAdapter, NormalizedReading } from '../types';
/**
* 小米手环 BLE 适配器
*
* 支持 Mi Band 7/8 等型号,使用标准 Heart Rate Service 读取心率数据。
* 未来可扩展步数0xFEE1、睡眠等 Mi Band 专有 Service。
*/
// 标准 BLE Heart Rate Service
const HRS_SERVICE = '0000180D-0000-1000-8000-00805F9B34FB';
const HRM_CHARACTERISTIC = '00002A37-0000-1000-8000-00805F9B34FB';
// 小米 Mi Band 专有 Service步数/活动量)
// const MI_BAND_SERVICE = '0000FEE1-0000-1000-8000-8000-00805F9B34FB';
/** 解析心率测量值Heart Rate Measurement 格式) */
function parseHeartRate(data: ArrayBuffer): number | null {
const view = new DataView(data);
if (view.byteLength < 2) return null;
const flags = view.getUint8(0);
// Bit 0: Heart Rate Format — 0 = UINT8, 1 = UINT16
const isUINT16 = (flags & 0x01) !== 0;
if (isUINT16) {
if (view.byteLength < 3) return null;
return view.getUint16(1, true); // little-endian
}
return view.getUint8(1);
}
export const XiaomiBandAdapter: DeviceAdapter = {
name: 'Xiaomi Band',
supportedModels: [
'Mi Band',
'Mi Smart Band',
'Xiaomi Band',
'Xiaomi Smart Band',
'MI BAND',
'MiBand',
],
serviceUUIDs: [HRS_SERVICE],
notifyCharacteristics: [
{ service: HRS_SERVICE, characteristic: HRM_CHARACTERISTIC },
],
readCharacteristics: [
{ service: HRS_SERVICE, characteristic: HRM_CHARACTERISTIC },
],
parseNotification(
_serviceUUID: string,
charUUID: string,
data: ArrayBuffer,
): NormalizedReading | null {
if (charUUID.toUpperCase().includes('2A37')) {
const hr = parseHeartRate(data);
if (hr !== null && hr > 0 && hr < 300) {
return {
device_type: 'heart_rate',
values: { heart_rate: hr },
measured_at: new Date().toISOString(),
};
}
}
return null;
},
parseReadResponse(
_serviceUUID: string,
_charUUID: string,
_data: ArrayBuffer,
): NormalizedReading | null {
// 读取模式暂不支持,使用通知模式获取数据
return null;
},
};
export default XiaomiBandAdapter;