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

345 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`)
```typescript
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`)
```typescript
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`)
```typescript
interface MessageMetadata {
enums?: EnumDefinition[];
location?: Location;
battery?: number;
seq?: number;
user?: Record<string, any>;
}
```
#### 全局枚举 (`enums`)
可选。全局枚举定义表,用于在字段 `metadata.data_type` 中以 `enum:<id>` 形式引用。
```typescript
type EnumDefinition = { id: string; value: Record<string, number> };
```
示例:
```jsonc
"metadata": {
"enums": [
{
"id": "air_quality",
"value": { "good": 1, "moderate": 2, "bad": 3 }
}
]
}
```
#### 位置信息 (`location`)
可选。表示消息采集时的设备地理位置:
```jsonc
{
"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`
```jsonc
"value": 42
```
2. **等间隔数组 (array)** — `T[]`,通过 `sample_interval` 指定采样间隔
```jsonc
"value": [1, 2, 3],
"metadata": { "data_type": "array<number>", "sample_interval": 0.5 }
```
3. **非等间隔irregular** — `{ v: T[], t: Timestamp[] }`
```jsonc
"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`)
```haskell
newtype Enum = number
```
##### 原始型別 (`primitive`)
```haskell
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` 如下:
```typescript
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 信号丢失,无位置信息 |
| 128511 | 预留 | — | 预留给未来通用错误 |
| 5121023 | 应用 | — | 留给具体应用 / 产品线自定义 |
| 102465535 | 厂商自定义 | — | 厂商或项目私有错误码区间 |
#### 错误信息 (`error_msg`)
可选。UTF-8 字符串,对 `error_code` 进行人类可读的补充说明。
#### 置信度 (`confidence`)
```typescript
type Confidence = number | number[]
```
数组形式 (`number[]`) 仅对数组 (等间隔/非等间隔) 有意义, 表示每个采样点的置信度, 其长度应与采样点数量相同; 若不指定, 则默认为 1
#### 采样间隔 (`sample_interval`)
可选。采样间隔, 用于描述 `value` 为等间隔数组时, 数组中每个元素的时间间隔 (建议所有等间隔数组都显式填写该字段)
```typescript
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 * 1000`ms (各个 field 不允许小数)
- 若使用 `number`, 则表示采样间隔为 `number` 秒 (允许小数)
若不指定, 则默认为 1s
示例:`"sample_interval": 0.5`(两次采样间隔 0.5 秒)
#### 单位 (`unit`)
可选。测量值单位。推荐使用 [UCUM](https://ucum.org/ucum) 码(如 `"Cel"` 代表摄氏度),也支持自由字符串。
示例:`"unit": "Cel"`
#### 内联枚举 (`enum`)
可选。当 `data_type` 为 `enum:this` 及其衍生类型时, 用于定义内联枚举值
```typescript
type InlineEnum = Record<string, number>
```
#### 用户自定义信息 (`user`)
可选。任意键值对,为数据生产方保留的自定义信息区:
```typescript
type UserData = Record<string, any>
```
## 伪代码类型定义
以下以 TypeScript 伪代码展示核心结构,帮助快速对接实现:
```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;
}
```