12 KiB
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 }
可选。用于标识设备类别或型号。支持三种写法:
- 字符串:例如
"device_type_name";与{ "type_name": string }等价 - 对象
{ "type_id": UUID };UUID 为设备型号的唯一标识, 由平台分配 - 对象
{ "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)
可选。数字,范围 0–100,对应设备剩余电量百分比。
序列号 (seq)
可选。无符号整数。每上传一条消息递增 1,用于检测丢包或乱序。达到上限后循环计数(默认为 32 位无符号整数回绕)。
用户自定义信息 (user)
可选。任意键值对,为数据生产方保留的自定义信息区:
field 字段
标识符 (id)
必填。ASCII 字符串,仅允许字母、数字与下划线,且不得以数字开头。长度建议 1–64 字符。例如 temperature_sensor。
值 (value)
字段实际测量值,其类型必须与 metadata.data_type 完全对应,形态分三类:
- 标量 —
string | number | boolean | enum"value": 42 - 等间隔数组 (array) —
T[],通过sample_interval指定采样间隔"value": [1, 2, 3], "metadata": { "data_type": "array<number>", "sample_interval": 0.5 } - 非等间隔(irregular) —
{ v: T[], t: Timestamp[] }"value": { "v": [1,2,3], "t": [1715145600,1715145601,1715145603] }, "metadata": { "data_type": "irregular<number>" }t数组必须与v数组长度相同, 且t数组中的时间戳必须严格递增, 否则会被视为非法数据
null 与 undefined 不被支持,嵌套数组(如 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>`
null和undefined是非法的- 嵌套是非法的
标签 (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 信号丢失,无位置信息 |
| 128–511 | 预留 | — | 预留给未来通用错误 |
| 512–1023 | 应用 | — | 留给具体应用 / 产品线自定义 |
| 1024–65535 | 厂商自定义 | — | 厂商或项目私有错误码区间 |
错误信息 (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_type 为 enum: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;
}