Files
whtp/schema.md

20 KiB
Raw Blame History

WH Telemetry Protocol Specification

概述

WH Telemetry ProtocolWHTP是一套专为物联网场景设计的轻量级、强自描述性遥测数据上行协议采用 JSON 作为数据承载格式。WHTP 面向传感器数据、遥测采集、边缘网关等设备与云端的数据交互,兼顾数据结构规范、易于解析与灵活拓展,适用于农业、环境监测、工业自动化等多种场景。

核心特点

  • 自描述:字段类型、单位、置信度、枚举、错误信息等全部可内嵌于消息,无需依赖外部 schema 即可独立解析
  • 结构统一:所有遥测消息采用统一的数据结构,便于前端/平台/存储适配与二次开发
  • 严格类型:禁止 null、嵌套数组所有值类型需显式声明保证数据一致性与可校验性
  • 批量与单点兼容支持标量、等间隔数组与非等间隔irregular三种采样模式灵活适配各类采集需求
  • 可扩展性预留元数据metadata与用户自定义信息user支持平台与业务个性化扩展
  • 错误与置信机制:内建错误码、错误信息与置信度表达,方便数据质量管理与自动化校验

消息结构总览

  • 根级字段:描述消息身份、设备、时间、环境等全局信息
  • 字段组fields每个测量项field携带唯一 ID、测量值value、类型元信息metadata

Note

本文档假设读者熟悉 Typescript 类型系统, 以及 JSON 格式, 并使用 Typescript 作为伪代码/类型定义语言

Note

请配合 JSON Schema 使用 (见 schema.json), 以获得更好的类型推导与校验体验

根级字段

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

版本

version 描述协议主版本号, 必填, 其类型为 number, 仅表示协议主版本号。当前版本为 1

消息类型

msg_type 描述消息类型, 必填, 其类型为 string, 目前仅允许 "telemetry",用于上传遥测数据。

消息模式

mode 描述消息模式, 可选, 其类型为 string, 默认 "descriptive"

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

设备ID

dev_id 描述设备唯一标识, 必填, 其类型为 string, 采用 NanoID 格式(如 2B1oj2S5k7kS8mL_QaCs),在设备生命周期内保持不变。

设备类型

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

dev_type 描述设备型号, 必填, 其类型为 DeviceType, 用于标识设备类别或型号。支持三种写法:

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

Note

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

  • 对于长期稳定的系统, 推荐使用 { "type_id": NanoID } 格式, 作为稳定的唯一标识符
  • 对于临时场景, 可以使用 string{ "type_name": string } 格式

根级时间戳

timestamp 描述消息生成时刻, 其类型为 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"

所有时间字段(如顶层 timestamp、field 级 timestamp、irregular timestamp[])应采用以下格式之一:

  • number:默认解释为 UNIX 秒UTC
  • object:显式指定格式,支持以下键:
    • unix_s → UNIX 秒
    • unix_ms → UNIX 毫秒
    • unix_us → UNIX 微秒
    • unix_ns → UNIX 纳秒
    • iso8601ISO8601 标准格式(必须为 UTC以 Z 结尾或包含 +00:00 时区偏移)

Warning

"timestamp": "2025-01-01T00:00:00Z" 为非法, 应使用 "timestamp": { "iso8601": "2025-01-01T00:00:00Z" }"timestamp": 1715145600

Note

根级 (root-level) 时间戳表示消息生成或入队时刻, 字段级 (field-level) 时间戳表示实际数据采样时刻, 应使用字段级时间戳进行所有时间序列分析

字段描述组

fields 描述消息中包含的测量项, 其类型为 Field[], 数组中每个元素代表一个测量项, 其 id 在同一条消息内必须唯一, 关于 Field 对象的定义详见后文 字段描述项 章节

根级元数据

metadata 描述根级 (消息级) 元数据, 其类型为 MessageMetadata

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

Note

user 字段之外的 metadata 字段为已定义 (well-defined) 字段; 用户应优先使用已定义字段, 若不能满足需求才可使用 用户自定义字段

全局枚举

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

metadata.enums 字段类型为 EnumDefinition[], 用于在字段 fields[*].metadata.data_type 中以 enum:<id> 形式引用, 如

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

等价于

enum AirQuality {
  GOOD = 1,
  MODERATE = 2,
  BAD = 3,
}

详见 枚举类型

位置信息

metadata.location 字段类型为 Location, 表示消息采集时的设备地理位置, 如

type Location = {
  coordinates: [number, number]; // 经度 (longitude)、纬度 (latitude)(度); 顺序不可颠倒
  coordinate_system?: "wgs84" | "gcj02" | "bd09"; // 可选,指定坐标系, 默认 "gcj02"
  accuracy?: number; // 可选,水平精度(米)
  altitude?: number; // 可选,海拔高度(米)
}

示例

{
  "coordinates": [120.123456, 24.123456], // 经度、纬度(度)
  "coordinate_system": "wgs84",
  "accuracy": 10,
  "altitude": 100
}

电量

metadata.battery 字段类型为数字, 表示设备剩余电量百分比, 其范围为 0100

序列号

metadata.seq 字段类型为无符号整数, 每上传一条消息递增 1, 用于检测丢包或乱序, 达到上限后循环计数(默认为 32 位无符号整数回绕)

根级用户自定义字段

metadata.user 字段为任意键值对, 为数据生产方保留的自定义信息区, 其类型为 UserData

type UserData = Record<string, any>

字段描述项

每个字段 (field) 描述一个测量项, 其类型为 Field

字段标识符

id 描述字段标识符, 必填, 其类型为 string, ASCII 字符串,仅允许字母、数字与下划线,且不得以数字开头。长度建议 164 字符。例如 temperature_sensor

字段值

value 描述字段值, 其类型必须与 metadata.data_type 完全对应, 详见 "数据类型" 章节

标量 (scalar)

string | number | boolean | enum<id>, 如

{
  "id": "example_number",
  "value": 42,
  "metadata": { "data_type": "number" }
}
{
  "id": "example_string",
  "value": "hello",
  "metadata": { "data_type": "string" }
}
{
  "id": "example_enum",
  "value": 1, // interpreted as "good"
  "metadata": { "data_type": "enum:this", "enum": { "good": 1, "moderate": 2, "bad": 3 } }
}

Note

枚举类型 enum:this 表示该字段使用内联枚举, 其定义见下文 "枚举类型" 章节

等间隔数组 (array)

T[],通过 sample_interval 指定采样间隔, T 为标量类型, 如

{
 "id": "example_array",
 "value": [1, 2, 3],
 "metadata": { "data_type": "array<number>", "sample_interval": 0.5 }
}

Note

强烈建议所有等间隔数组都显式填写 sample_interval 字段, 若不填写则默认采样间隔为 1s

非等间隔irregular

{ v: T[], t: Timestamp[] }, T 为标量类型, 如

{
 "id": "example_irregular",
 "value": { "v": [1,2,3], "t": [1715145600,1715145601,1715145603] },
 "metadata": { "data_type": "irregular<number>" }
}

t 数组必须与 v 数组长度相同, 且 t 数组中的时间戳必须严格递增, 否则会被视为非法数据

Important

  • nullundefined 为非法值
  • 嵌套数组(如 array<array<number>>)为非法类型

字段级元数据

field 级字段元数据, 用于描述 value 的类型, 采样间隔, 单位, 标签, 置信度, 错误码, 错误信息, 内联枚举, 用户自定义信息等, 其类型为 FieldMetadata

数据类型

data_type 用于描述 value 的类型, 其类型为 DataType

type DataType = 
    | ScalarType
    | ArrayType ScalarType
    | IrregularType ScalarType

所有合法的 data_type 的值如下:

type DataTypeLiteral =
    | "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>`

Important

  • nullundefined 为非法值
  • 嵌套数组(如 array<array<number>>)为非法类型

下面分别介绍各个类型

原始型別

协议中的 原始型别primitive 直接对应于 JSON 支持的基本数据类型。所有字段的最基本取值都必须属于原始型别。

type PrimitiveType = string | number | boolean

其中:

  • string:任意长度的 UTF-8 文本字符串
  • numberIEEE-754 双精度浮点数
  • boolean:布尔值,仅允许 true 或 false不支持 0/1 或字符串)
枚举类型

在本协议中,枚举类型 (enum, Enumeration) 本质上是一种特殊的 number 类型。其取值必须限定在一组预先定义的枚举值中。枚举的具体定义可以来源于:

  • 全局定义:metadata.enums(适用于多个字段复用的场景)
  • 字段内联定义:fields[*].metadata.enum(只对当前字段有效)

每个枚举值都必须对应唯一的数值number。在类型系统中枚举类型可以视为带有标签约束的 number:

newtype Enum = number
标量类型

标量类型 (scalar) 为 string | number | boolean | Enum 的统称, 其定义见上文

type ScalarType = PrimitiveType | Enum
等间隔数组类型

本协议中的数组类型在 field 中的含义为 等采样率 的数组 (array), 其定义为:

type ArrayType<T> = T[] // array<T>
非等间隔数组类型

本协议中的非等间隔数组类型在 field 中的含义为 非等采样率采样率未知 的数组, 其定义为:

type IrregularType<T> = { v: T[], t: Timestamp[] } // irregular<T>

t 数组必须与 v 数组长度相同, 且 t 数组中的时间戳必须严格递增, 否则会被视为非法数据

等间隔数组与非等间隔数组统称为批量 (batch) 数据

type BatchType<T> = ArrayType<T> | IrregularType<T>

字段时间戳

timestamp 描述字段时间戳, 可选, 其类型为 Timestamp, 若不存在则取 root.timestamp 的值; 表示该字段 采样时刻 的时间戳

标签

label 描述字段展示名, 可选, 其类型为 string, 便于人机界面直观呈现。实际是否使用/如何使用由数据消费方决定。

示例:"label": "温度"

错误码

error_code 描述错误码, 可选, 其类型为 number, 非零整数。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 描述错误信息, 可选, 其类型为 string, 对 error_code 进行人类可读的补充说明。

置信度

type Confidence = number | number[]

confidence 描述置信度, 可选, 其类型为 Confidence, 用于表征 value 数据的可靠性,其取值类型可为单个数值(number)或数值数组(number[]),具体规则如下:

  • 当 confidence 为单个数值时,表示该字段所有采样点共用相同的置信度。此形式适用于任意类型的 value包括单点和批量数据
  • 当 confidence 为数值数组时,表示每个采样点各自的置信度。此形式仅适用于批量数据(即 value 为数组或不等间隔序列);此时 confidence 数组长度必须与采样点数量严格一致。

置信度的取值范围为 0 至 1其中 0 表示完全不可信1 表示完全可信100%)。

Note

当一个字段包含非零的 error_code 时, 强烈建议将置信度设置为 0 以表示该字段值不可靠

Warning

  • 对于单值scalar数据不应填写数组形式的置信度若填写则无意义解析器将会忽略
  • 对于批量数据,既可填写单一置信度(所有采样点共享),也可填写置信度数组(每个采样点单独指定)
  • 如未指定 confidence 字段,则默认所有采样点的置信度为 1

采样间隔

sample_interval 描述采样间隔, 可选, 其类型为 SampleInterval, 用于描述 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 秒)

Important

强烈建议所有等间隔数组都显式填写 sample_interval 字段

单位

unit 描述单位, 可选, 其类型为 string, 推荐使用 UCUM 码(如 "Cel" 代表摄氏度),也支持自由字符串。

示例:"unit": "Cel"

内联枚举

enum 描述内联枚举, 可选, 其类型为 InlineEnum, 当 data_typeenum:this 及其衍生类型时, 用于定义内联枚举值, 详见 枚举类型

type InlineEnum = Record<string, number>

字段级用户自定义字段

user 描述字段级用户自定义字段, 可选, 类型定义同 根级用户自定义字段

伪代码类型定义

以下以 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 InlineEnum = Record<string, number>
type EnumDefinition = { id: string; value: InlineEnum };

// Field 元数据
interface FieldMetadata {
  data_type: string;
  timestamp?: Timestamp;
  sample_interval?: SampleInterval; // valid only when data_type is array<T> 
  unit?: string;
  label?: string;
  confidence?: number | number[];
  error_code?: number;
  error_msg?: string;
  enum?: InlineEnum; // 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;
}