Files
whtp/READMD.md
2025-07-07 16:44:08 +08:00

12 KiB
Raw Blame History

WH Telemetry Protocol

WH Telemetry Protocol简称 WHTP是一套以 JSON 为载体的遥测数据上行协议,强调自描述能力与轻量化设计,适用于物联网设备与云端之间的高效数据传输。

总览

WHTP 消息由根级字段与 fields 数组两部分组成。根级字段描述消息本身及其环境;fields 数组承载具体测量项。根级字段概览如下:

字段 必选 类型 说明
version number 协议主版本号
msg_type string 消息类别,目前仅 "telemetry"
mode string 工作模式,"descriptive"(默认)或 "strict"
dev_id string 设备唯一标识UUID v4
dev_type string / object 设备型号标识
timestamp Timestamp 消息生成时刻
fields Field[] 采集字段数组
metadata object 消息级元数据

消息字段

Version (version)

必填。正整数,仅表示协议主版本号。当前版本为 1

消息类型 (msg_type)

必填。字符串。目前仅允许 "telemetry",用于上传遥测数据。

消息模式 (mode)

可选,字符串,默认 "descriptive"

  • descriptive —— 自描述模式,允许在字段 metadata 中携带全部上下文信息,消息本身即可被独立解析。
  • strict —— 严格模式,不允许出现字段级 metadata,字段定义需通过外部文档约定,适用于带宽受限或固定 Schema 场景。(目前无实际意义, 需要与二进制协议配合)

设备 ID (dev_id)

必填。设备唯一标识,采用 UUID v4 格式(如 148413b4-c352-49a9-9c48-9d15276a99e7),在设备生命周期内保持不变。

设备类型 (dev_type)

type DeviceType = string | { type_id: string } | { type_name: string }

可选。用于标识设备类别或型号。支持三种写法:

  1. 字符串:例如 "device_type_name";与 { "type_name": string } 等价
  2. 对象 { "type_id": UUID }UUID 为设备型号的唯一标识, 由平台分配
  3. 对象 { "type_name": string }

以上三种写法在语义上等价,由数据生产方按需选择。

消息时间戳 (timestamp)

type Timestamp =
  | number // UNIX seconds (default), same as `{ unix_s: number }`
  | { unix_s: number }
  | { unix_ms: number }
  | { unix_us: number }
  | { unix_ns: number }
  | { iso8601: string } // e.g. "2025-01-01T00:00:00Z"

field 字段 (fields)

必填。Field 对象数组,数组中每个元素代表一个测量项,其 id 在同一条消息内必须唯一。关于 Field 对象的定义详见后文 "field 字段" 章节。

消息元数据 (metadata)

interface MessageMetadata {
  enums?: EnumDefinition[];
  location?: Location;
  battery?: number;
  seq?: number;
  user?: Record<string, any>;
}

全局枚举 (enums)

可选。全局枚举定义表,用于在字段 metadata.data_type 中以 enum:<id> 形式引用。

type EnumDefinition = { id: string; value: Record<string, number> };

示例:

"metadata": {
  "enums": [
    {
      "id": "air_quality",
      "value": { "good": 1, "moderate": 2, "bad": 3 }
    }
  ]
}

位置信息 (location)

可选。表示消息采集时的设备地理位置:

{
  "coordinates": [24.123456, 120.123456], // 纬度、经度(度)
  "coordinate_system": "wgs84",           // 可选,指定坐标系, 默认 "gcj02" 可选项为 wgs84, gcj02, bd09
  "accuracy": 10,                          // 可选,水平精度(米)
  "altitude": 100                          // 可选,海拔高度(米)
}

电量 (battery)

可选。数字,范围 0100对应设备剩余电量百分比。

序列号 (seq)

可选。无符号整数。每上传一条消息递增 1用于检测丢包或乱序。达到上限后循环计数默认为 32 位无符号整数回绕)。

用户自定义信息 (user)

可选。任意键值对,为数据生产方保留的自定义信息区:

field 字段

标识符 (id)

必填。ASCII 字符串,仅允许字母、数字与下划线,且不得以数字开头。长度建议 164 字符。例如 temperature_sensor

值 (value)

字段实际测量值,其类型必须与 metadata.data_type 完全对应,形态分三类:

  1. 标量string | number | boolean | enum
    "value": 42
    
  2. 等间隔数组 (array)T[],通过 sample_interval 指定采样间隔
    "value": [1, 2, 3],
    "metadata": { "data_type": "array<number>", "sample_interval": 0.5 }
    
  3. 非等间隔irregular{ v: T[], t: Timestamp[] }
    "value": { "v": [1,2,3], "t": [1715145600,1715145601,1715145603] },
    "metadata": { "data_type": "irregular<number>" }
    
    t 数组必须与 v 数组长度相同, 且 t 数组中的时间戳必须严格递增, 否则会被视为非法数据

nullundefined 不被支持,嵌套数组(如 array<array<number>>)亦非法。

元数据 (metadata)

数据类型 (data_type)

枚举类型 (enums)
newtype Enum = number
原始型別 (primitive)
type PrimitiveType = string | number | boolean

type ScalarType = string | number | boolean | Enum
type ArrayType T = T[] -- array<T>
type IrregularType T = { v: T[], t: Timestamp[] } -- irregular<T>

type DataType = 
    | ScalarType
    | ArrayType ScalarType
    | IrregularType ScalarType
总结

所有合法的 data_type 如下:

type DataType =
    | "string"
    | "number"
    | "boolean"
    | `enum:${string}`     // global enum
    | "enum:this"          // inline enum
    | `array<string>`
    | `array<number>`
    | `array<boolean>`
    | `array<enum:${string}>`
    | `array<enum:this>`
    | `irregular<string>`
    | `irregular<number>`
    | `irregular<boolean>`
    | `irregular<enum:${string}>`
    | `irregular<enum:this>`
  • nullundefined 是非法的
  • 嵌套是非法的

标签 (label)

可选。字段展示名UTF-8 字符串,便于人机界面直观呈现。

示例:"label": "温度"

错误码 (error_code)

可选。非零整数。0 表示无错误;其他值与以下错误码表对应,用于描述测量异常。

代码 分类 名称 描述
0 通用 OK 无错误(不应在 error_code 字段出现,仅表字段正常)
1 通用 UNKNOWN_ERROR 未知错误,无法归类
2 通用 UNSUPPORTED_DATA_TYPE 不支持的数据类型或格式
3 通用 INVALID_VALUE 字段值非法(超范围、格式错等)
16 设备 DEVICE_BUSY 设备繁忙,暂无法提供数据
17 设备 DEVICE_INIT_FAILED 设备初始化失败
32 传输 PACKET_LOST 报文丢失(重传失败)
33 传输 CRC_ERROR 校验和 / CRC 错误
48 供电 LOW_BATTERY 电量过低,测量值可能不可靠
64 传感器 SENSOR_DISCONNECTED 传感器掉线或未接入
65 传感器 SENSOR_MALFUNCTION 传感器故障(无响应、数据乱流等)
66 传感器 SENSOR_OUT_OF_RANGE 超出测量范围
80 校准 CALIBRATION_REQUIRED 需要校准或校准过期
96 存储 STORAGE_FULL 本地存储空间不足
112 GNSS GPS_FIX_LOST GNSS 信号丢失,无位置信息
128511 预留 预留给未来通用错误
5121023 应用 留给具体应用 / 产品线自定义
102465535 厂商自定义 厂商或项目私有错误码区间

错误信息 (error_msg)

可选。UTF-8 字符串,对 error_code 进行人类可读的补充说明。

置信度 (confidence)

type Confidence = number | number[]

数组形式 (number[]) 仅对数组 (等间隔/非等间隔) 有意义, 表示每个采样点的置信度, 其长度应与采样点数量相同; 若不指定, 则默认为 1

采样间隔 (sample_interval)

可选。采样间隔, 用于描述 value 为等间隔数组时, 数组中每个元素的时间间隔 (建议所有等间隔数组都显式填写该字段)

type TimeDelta = { ms?: number, s?: number, m?: number, h?: number, d?: number, w?: number }
type SampleInterval = 
    | number // seconds
    | TimeDelta
  • 若使用 TimeDelta, 则总采样间隔为 ms + s * 1000 + m * 60 * 1000 + h * 60 * 60 * 1000 + d * 24 * 60 * 60 * 1000 + w * 7 * 24 * 60 * 60 * 1000ms (各个 field 不允许小数)
  • 若使用 number, 则表示采样间隔为 number 秒 (允许小数)

若不指定, 则默认为 1s

示例:"sample_interval": 0.5(两次采样间隔 0.5 秒)

单位 (unit)

可选。测量值单位。推荐使用 UCUM 码(如 "Cel" 代表摄氏度),也支持自由字符串。

示例:"unit": "Cel"

内联枚举 (enum)

可选。当 data_typeenum:this 及其衍生类型时, 用于定义内联枚举值

type InlineEnum = Record<string, number>

用户自定义信息 (user)

可选。任意键值对,为数据生产方保留的自定义信息区:

type UserData = Record<string, any>

伪代码类型定义

以下以 TypeScript 伪代码展示核心结构,帮助快速对接实现:

// 时间戳
type Timestamp =
  | number // UNIX seconds
  | { unix_s: number }
  | { unix_ms: number }
  | { unix_us: number }
  | { unix_ns: number }
  | { iso8601: string };

// 采样间隔
type SampleInterval = number | { ms?: number; s?: number; m?: number; h?: number; d?: number; w?: number };

// 枚举定义
type EnumDefinition = { id: string; value: Record<string, number> };

// Field 元数据
interface FieldMetadata {
  data_type: string;
  timestamp?: Timestamp;
  sample_interval?: SampleInterval;
  unit?: string;
  label?: string;
  confidence?: number | number[];
  error_code?: number;
  error_msg?: string;
  enum?: Record<string, number>; // inline enum when data_type === "enum:this"
  user?: Record<string, any>;
}

// Field
interface Field {
  id: string;
  value: DataType;
  metadata: FieldMetadata;
}

// 根消息
interface Message {
  version: 1;
  msg_type: "telemetry";
  mode?: "descriptive" | "strict"; // 仅支持 descriptive 模式
  dev_id: string;
  dev_type?: string | { type_id: string } | { type_name: string };
  timestamp: Timestamp;
  fields: Field[];
  metadata?: MessageMetadata;
}