蓝牙设备接入

家用健康设备通过晓葆检测插件(XB_HealthHub)以微信小程序插件形式接入。 厂家提供蓝牙协议文档或 SDK,由插件完成 BLE 连接、数据采集、结果上报全流程, 宿主小程序无需感知设备细节。

概述

检测插件以标准化架构分层管理设备接入:

  • UI 层:只订阅检测状态,不直接操作蓝牙 API
  • MeasureSession:管理一次完整检测的生命周期(状态机)
  • BleManager:GATT 连接/断连/分包/心跳,不感知业务协议
  • DeviceDriver:帧解析、指令生成、结果构建,不操作 UI,不发网络请求
  • DeviceRegistry:广播名/SN → Driver 的静态映射表

新增设备不改现有层:只需新增 Driver 类 + 在 Registry 注册一行, UI 层、BleManager、上报链路均不变。

接入模式选择

模式适用场景用户体验典型能力
Pattern A有蓝牙协议文档,可自解析帧格式即测即得,几十秒内出结果血压、血糖、血氧等直出指标
Pattern B1厂商提供微信插件 SDK,需云端算法同步返回结果稍等几秒,云端算完后出结果体成分分析等需云算法的检测
Pattern B2厂商提供端侧 SDK 采集,云算法异步回调结果采集结束后「报告生成中」,稍后 Webhook 补齐心电等需异步算法与报告文件的检测

Pattern A — BLE 直连自解析

插件直接通过 BLE GATT 接收设备数据帧,由 Driver 自行解析,无需厂商 SDK 或云端算法。 适合有完整蓝牙协议文档的设备型号。

接入步骤:

  1. 厂商提供蓝牙协议文档(Service UUID、Characteristic UUID、帧格式、CRC 算法)
  2. 晓葆研发实现 Driver,核心方法:
    • getBleConfig():返回 serviceId / writeCharId / notifyCharId
    • getPacketConfig():帧头字节 + 帧长度计算函数(用于分包重组)
    • generateCmd(action):生成 start/stop 指令 ArrayBuffer
    • parseFrame(frame):解析完整帧,返回 metrics + liveData + _done 标志
    • buildResult():构建最终 MeasureResult
  3. 在 DeviceRegistry 注册广播名与 Driver 的映射关系
  4. 厂商提供样机与联调环境,走接入 Checklist 验收

帧解析契约:

// parseFrame 返回值结构
{
  metrics:  {},           // 中间帧暂无最终指标时为 {}
  liveData: { ... },      // 实时展示字段(与 devices.js liveFeedback.liveField 对应)
  _done:    true | false, // 测量完成标志
  rawHex:   '...',        // 完整帧原始字节(可选,用于问题复现)
}

// 设备错误帧
{ _error: true, errorCode: 'E_DEV_XXX' }

// 非业务帧(忽略)
null

Pattern B1 — 厂商插件 + 云算法(同步)

厂商提供官方微信小程序插件或 SDK,插件采集原始数据(如体重 + 阻抗)后, 由晓葆服务端调用厂商云算法同步计算结果,写入 MeasureResult。

  • 厂商 API 凭证由晓葆服务端持有,不下发到插件
  • 插件只上传原始采集值,不直连厂商云
  • 算法 API 需报备晓葆服务端 IP 至厂商白名单
  • 用户体验:采集完成后稍等几秒,指标一次性展示

Pattern B2 — 端 SDK + 云算法(异步回调)

厂商提供端侧采集 SDK,插件用 SDK 采集完整原始数据(如波形), 上传晓葆服务端后异步调厂商算法云,算法结果通过回调写入平台。

  • 厂商 API 凭证由晓葆服务端持有
  • 算法云通过 callBackPath(晓葆服务端提供)异步推送结果
  • 会话状态机扩展:measuring → device_storing → uploading_to_vendor → waiting_vendor_result → uploading → done
  • 宿主通过 Webhook report.generated 事件接收最终报告
  • 可支持两阶段推送:初报(快)+ 报告就绪(含 PDF 等附件,稍慢)

用户身份协议

插件启动时通过 URL 参数获取用户身份,支持两种模式。 宿主服务端负责生成跳转签名,不在前端生成

两种用户档案模式

模式参数适用场景档案来源
resolvethirdUserId第三方渠道(如远盟、新华保险)插件调 /open/v1/integrations/{channel}/resolve-user
xiaobao_sessionsessionToken健康站、晓葆自有品牌 App插件调 /open/v1/plugin/resolve-session

跳转参数(完整)

wx.navigateTo({
  url: `plugin://xiaobao-measure/index?${qs.stringify({
    // 必填·鉴权(宿主服务端生成)
    appKey,
    timestamp,  // Unix 秒级时间戳
    nonce,      // 随机字符串
    sign,       // HMAC-SHA256 签名

    // 必填·用户身份(二选一)
    thirdUserId,   // resolve 模式
    sessionToken,  // xiaobao_session 模式

    // 可选·检测配置
    deviceKey,   // 不传则进入设备选择页
    measureMode, // 仅 HOME_MULTI_BIO_MONITOR:BP | BG
    deviceSn,    // 健康站扫码时指定设备 SN
    stationId,   // 健康站 ID

    // 可选·UI(不纳入签名)
    env,      // prod | sandbox
    title,    // 自定义检测页标题
    noSound,  // 1=静音
    metadata, // 自定义字符串,原样透传至 Webhook 与报告详情 API
  })}`
})

签名生成规则(宿主服务端)

// 待签字符串 = appKey + timestamp + nonce(按此顺序拼接,无分隔符)
const signStr = appKey + timestamp + nonce;

// 签名 = HMAC-SHA256(signStr, appSecret),结果取十六进制小写
const sign = hmacSha256(signStr, appSecret);
安全注意appSecret 只能存在于宿主服务端,不得写入小程序前端代码。 UI 参数(env/title/noSound/scene/metadata)不纳入签名计算。

检测结束回传(Storage)

插件检测结束后写入 wx.setStorageSync,宿主在 onShow 中读取并清除:

// 读取
const result = wx.getStorageSync('xiaobao_measure_result');
wx.removeStorageSync('xiaobao_measure_result');

// 结构
{
  status:    'success' | 'cancel' | 'error',
  measureId: 'xxx',    // 本次检测唯一 ID,关联 Webhook 回调
  deviceKey: 'HOME_MULTI_BIO_MONITOR',
  summary:   '收缩压 128 / 舒张压 82',  // 供宿主 toast 展示
}

数据规范

MeasureResult 数据契约

所有 Driver 输出统一结构,上层不感知设备差异:

interface MeasureResult {
  deviceSn:     string            // 设备序列号(BLE 广播名作为展示 SN)
  deviceKey:    string            // 对应平台 device_key
  measureMode?: string            // BP | BG | SPO2 | ECG | BCA;多模式设备必填
  measuredAt:   number            // Unix 毫秒时间戳
  metrics:      Record<string, number>  // 结构化指标,key 见下方命名约定
  rawFile?:     string            // Pattern B:原始波形文件本地路径
  waveData?:    number[]          // ECG 实时波形点(仅页面绘制,不上报)
  rawHex?:      string            // 原始字节备份(用于问题复现)
}

measureMode 枚举

device_keymeasureMode中文
HOME_MULTI_BIO_MONITORBP / BG血压 / 血糖
HOME_SPO2_RINGSPO2血氧
HEARTLOG_ECG_RECORDERECG心电
BODY_COMPOSITION_ANALYSISBCA人体成分

metrics 命名约定

metrics 的 key 以平台设备指标标准码(standard_indicator_code)为准。 新设备接入前须在平台指标库完成映射并发布;具体字段由各设备型号独立配置,本规范不枚举品类指标清单。

liveData 实时字段

Driver 的 parseFrame 可在 liveData 中返回实时数据, 供检测过程中动态展示。通用保留字段:

字段类型含义
batteryPctnumber电量百分比(0–100,Driver 内归一化)
signalOkboolean信号是否有效
probeOffboolean探头 / 传感器是否脱落

报告回传

检测完成并上报开放平台后,平台通过 Webhook 向宿主服务端推送事件。 宿主需在控制台配置 Webhook 地址并完成验签。

核心事件:report.generated

{
  "event":      "report.generated",
  "deliveryId": "evt_abc123",      // Webhook 投递唯一 ID(幂等键)
  "timestamp":  1722000000,
  "data": {
    "measureId":   "msr_xxx",
    "deviceKey":   "YOUR_DEVICE_KEY",
    "measureMode": "BP",
    "measuredAt":  1722000000000,   // Unix 毫秒
    "metrics": {
      "indicator_code_a": 128,
      "indicator_code_b": 82
    },
    "thirdUserId": "user_from_channel",  // resolve 模式时存在
    "metadata":    "your-custom-string"  // 原样透传
  }
}

Pattern B2 两阶段推送

Pattern B2(云算法异步回调)报告推送分两个阶段:

阶段事件包含内容时间
初报report.generated基础 metrics(部分指标)采集完成后数秒内
报告就绪report.ready全量指标 + 报告文件 URL(如 PDF)+ H5 报告页 URL算法回调后(数秒至数十秒)

用户身份在 Webhook 中的体现

接入场景Webhook 中的用户标识字段
第三方渠道(resolve 模式)thirdUserId
健康站 / 晓葆品牌 App晓葆用户体系 ID

接入 Checklist

厂商 / 商务(立项前)

  • 明确设备型号与出货量,是否独家
  • 确认能提供蓝牙协议文档(Pattern A)或 SDK + 样机(Pattern B)
  • 判断接入模式(Pattern A / B1 / B2)
  • Pattern B2 需评估厂商算法云稳定性与回调 SLA

运营(上线前)

  • 在控制台为对应 appKey 开通设备白名单(device_whitelist
  • 确认微信插件版本与 request 合法域名
  • Pattern B:确认厂商凭证已配置,晓葆服务端 IP 已加入厂商白名单
  • 准备联调账号与沙箱 Webhook 地址

研发(实现与验收)

  • 新增 Driver 文件,实现必要接口,写单元测试(≥ 90% 覆盖核心帧类型)
  • 在 DeviceRegistry 注册广播名 + Driver 映射
  • 在 devices.js 补充 UI 配置(liveFeedback.liveField
  • 确认 metrics key 与平台指标库 standard_indicator_code 一致
  • Pattern B:服务端厂商代理接口 + 队列配置

联合验收(上线门槛)

  • 沙箱走通:连接 → 测量 → 结果页 → Webhook 落库
  • 覆盖:正常值、边界值、断连重试、低电量、用户中途退出
  • Pattern B2:额外验收 PDF 生成与异步回调时延
  • 合作方确认 metrics 字段满足展示与落库需求