编辑 | blame | 历史 | 原始文档

JH2028 新协议服务通讯功能流程图

本文档描述 jh2028-new-service 的服务通讯主流程,覆盖 TCP 接收、设备识别、协议解码、本地缓存、大屏展示、MQTT 上报和阿里云上报。

0. 通讯角色说明

现场通讯里需要先区分两个角色:

  • 本程序是 TCP 服务端:本程序监听固定 IP 和端口,等待设备数据盒子主动连接。
  • 设备数据盒子是 TCP 客户端:盒子连接本程序后,持续发送设备透传数据。

因此,从 TCP 连接方向看:

设备数据盒子 TCP 客户端  --->  本程序 TCP 服务端

从数据流方向看:

设备/透传盒  --->  本程序  --->  MQTT / 阿里云 / 监测大屏

本程序启动后监听 config.tcp.hostconfig.tcp.port。设备列表中维护每台设备盒子的 ipdeviceIdname,程序根据 TCP 来源 IP 匹配设备编号。

1. 总体通讯流程

flowchart TD
    A[JH2028 设备] --> B[串口透传盒子]
    B -->|主动连接 TCP 服务端<br/>持续发送数据| C[本程序 TCP 服务端<br/>tcp-service.js]

    C --> D{来源 IP 是否在<br/>config.devices 中}
    D -->|否| D1[记录未知设备日志<br/>丢弃本包数据]
    D -->|是| E[绑定设备编号 deviceId]

    E --> F[接收二进制数据流]
    F --> G[按 55 AA 帧头和 LEN 拆包]
    G --> H{是否完整帧}
    H -->|否| H1[继续缓存等待后续数据]
    H -->|是| I[CRC8 校验]

    I --> J{CRC 是否正确}
    J -->|否| J1[记录校验失败日志<br/>丢弃该帧]
    J -->|是| K[协议解码<br/>decoder.js]

    K --> L{帧类型}
    L -->|实时数据<br/>CMDTYPE=01 CMDID=00| M[解析治疗/温度/压力/血液指标]
    L -->|血压数据<br/>CMDTYPE=01 CMDID=01| N[解析 N/O/P<br/>写入 M=接收时间]
    L -->|血压错误码| N1[只记录日志<br/>不更新缓存/不上报]
    L -->|未知命令| L1[记录不支持命令日志]

    M --> O[更新设备本地缓存<br/>state-cache.js]
    N --> O

    O --> P[生成完整上报数据<br/>包含最后一次实时数据和血压数据]
    P --> Q[刷新大屏快照<br/>dashboard-service.js]
    Q --> Q1[浏览器大屏<br/>SSE 实时更新/轮询兜底]

    P --> R{上报通道配置<br/>send.channels}
    R -->|mqtt| S[MQTT 上报<br/>mqtt-service.js]
    R -->|aliyun| T[阿里云上报<br/>aliyun-service.js]
    R -->|mqtt + aliyun| S
    R -->|mqtt + aliyun| T

    S --> U{上报结果}
    T --> U
    U -->|成功| U1[记录成功日志]
    U -->|失败| U2[记录失败日志<br/>不补发]

2. 服务启动流程

flowchart TD
    A[启动 app.js] --> B[读取 config.json]
    B --> C[校验 tcp/devices/protocol/send 配置]
    C --> D[初始化日志 logger]
    D --> E[加载物模型 alModel.json]
    E --> F[初始化 StateCache]

    F --> G{send.channels}
    G -->|包含 mqtt| H[初始化 MQTT 服务]
    G -->|包含 aliyun| I[初始化阿里云服务]
    G --> J[初始化 DashboardService]

    H --> K[启动 TCP 服务]
    I --> K
    J --> K

    K --> L[监听 TCP 端口<br/>默认 9000]
    J --> M[监听大屏端口<br/>默认 9100]

    L --> N[等待设备盒子接入]
    M --> O[等待浏览器访问]

3. 单包数据处理时序

sequenceDiagram
    participant Device as JH2028设备/透传盒子
    participant TCP as TCP服务
    participant Decoder as 协议解码器
    participant Cache as 本地状态缓存
    participant UI as 监测大屏
    participant MQTT as MQTT服务
    participant Aliyun as 阿里云服务

    Device->>TCP: 主动建立 TCP 连接
    Device->>TCP: 持续发送 55 AA 新协议数据帧
    TCP->>TCP: 根据来源 IP 匹配 deviceId
    TCP->>TCP: 数据流拆包,得到完整帧
    TCP->>Decoder: CRC8 校验并解码
    Decoder-->>TCP: 返回 realtime 或 bloodPressure 数据
    TCP->>Cache: 合并到设备最后一次完整缓存
    Cache-->>TCP: 返回完整 payload
    TCP->>UI: 推送最新设备状态和指标
    TCP->>MQTT: 按原 Topic 规则立即上报完整 payload
    TCP->>Aliyun: 获取/复用三元组并立即上报完整 payload
    MQTT-->>TCP: 返回上报结果
    Aliyun-->>TCP: 返回上报结果
    TCP->>TCP: 成功/失败均记录日志,失败不补发

4. 设备连接状态流程

stateDiagram-v2
    [*] --> 未连接
    未连接 --> 已连接: 设备盒子主动连接
    已连接 --> 等待数据: 已匹配设备 IP
    等待数据 --> 数据正常: 收到并成功解码一帧
    数据正常 --> 数据正常: 持续收到有效数据
    数据正常 --> 数据超时: 超过 staleDataMs 未更新
    数据超时 --> 数据正常: 再次收到有效数据
    已连接 --> 离线: socket close/error/timeout
    等待数据 --> 离线: socket close/error/timeout
    数据正常 --> 离线: socket close/error/timeout
    数据超时 --> 离线: socket close/error/timeout
    离线 --> 已连接: 设备盒子重新连接

5. 阿里云上报子流程

flowchart TD
    A[收到完整 payload] --> B{是否启用 aliyun 通道}
    B -->|否| B1[跳过阿里云上报]
    B -->|是| C{设备是否已有可用连接}

    C -->|有| H[调用 postProps 上报属性]
    C -->|没有| D[按 deviceId 请求三元组接口]

    D --> E{三元组是否完整}
    E -->|否| E1[记录失败日志<br/>本次不补发]
    E -->|是| F[创建阿里云 IoT Device 实例]
    F --> G[等待/复用连接]
    G --> H

    H --> I{postProps 是否成功}
    I -->|成功| I1[记录上报成功]
    I -->|失败| I2[记录失败原因<br/>不补发]

6. 大屏数据来源

flowchart LR
    A[config.devices<br/>设备清单] --> D[大屏快照]
    B[TCP 连接会话<br/>在线/离线/连接时间] --> D
    C[StateCache<br/>最后一次完整 payload] --> D

    D --> E[/api/snapshot]
    D --> F[/events SSE]
    E --> G[浏览器大屏]
    F --> G

7. 当前关键规则

  • 本程序是 TCP 服务端,设备数据盒子作为 TCP 客户端主动连接本程序。
  • 设备身份按 config.devices 中配置的来源 IP 匹配,不从报文中解析设备编号。
  • 服务端不回复设备,设备会持续主动发送数据。
  • 收到实时数据或血压数据后,立即合并缓存并上传完整 payload。
  • 血压数据接收时写入 M,值为服务端接收时间。
  • 平均压、心率不齐、血压错误码不上传;血压错误码只记录日志。
  • MQTT Topic 沿用老项目规则。
  • 阿里云三元组获取规则沿用老项目,deviceName = deviceId
  • 上报失败只记录日志,不做补发。
  • 大屏只读取内存状态,不影响 TCP 接收和上报链路。