@thejrsoft/subway-protocol 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ACK_MESSAGES_IMPLEMENTATION_SUMMARY.md +128 -0
- package/ACK_MESSAGE_DESIGN.md +457 -0
- package/CHANGELOG.md +58 -0
- package/COMMAND_VALIDATION_RULES.md +178 -0
- package/DOCUMENTATION_REORGANIZATION_SUMMARY.md +81 -0
- package/DOCUMENTATION_STRUCTURE.md +106 -0
- package/GATEWAY_MIGRATION_GUIDE.md +130 -0
- package/GATEWAY_PROTOCOL_COMPARISON.md +216 -0
- package/INTEGRATION_GUIDE.md +190 -0
- package/OPTIONAL_FIELDS_WITHOUT_DEFAULTS.md +97 -0
- package/PROTOCOL_UTILS_USAGE.md +278 -0
- package/README.md +237 -0
- package/TYPE_FIXES_SUMMARY.md +210 -0
- package/UPDATE_ENUM_VALUES.md +139 -0
- package/dist/asyncapi-sync.d.ts +47 -0
- package/dist/asyncapi-sync.d.ts.map +1 -0
- package/dist/asyncapi-sync.js +85 -0
- package/dist/asyncapi-sync.js.map +1 -0
- package/dist/command-factory.d.ts +62 -0
- package/dist/command-factory.d.ts.map +1 -0
- package/dist/command-factory.js +137 -0
- package/dist/command-factory.js.map +1 -0
- package/dist/command-types.d.ts +27 -0
- package/dist/command-types.d.ts.map +1 -0
- package/dist/command-types.js +31 -0
- package/dist/command-types.js.map +1 -0
- package/dist/index.d.ts +403 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +413 -0
- package/dist/index.js.map +1 -0
- package/dist/message-validator.d.ts +102 -0
- package/dist/message-validator.d.ts.map +1 -0
- package/dist/message-validator.js +640 -0
- package/dist/message-validator.js.map +1 -0
- package/dist/protocol-utils.d.ts +108 -0
- package/dist/protocol-utils.d.ts.map +1 -0
- package/dist/protocol-utils.js +293 -0
- package/dist/protocol-utils.js.map +1 -0
- package/docs/01-protocol/README.md +45 -0
- package/docs/01-protocol/design-rationale.md +198 -0
- package/docs/01-protocol/message-types.md +669 -0
- package/docs/01-protocol/specification.md +1466 -0
- package/docs/02-commands/README.md +56 -0
- package/docs/02-commands/batch-command.md +435 -0
- package/docs/02-commands/complex-command.md +537 -0
- package/docs/02-commands/simple-command.md +332 -0
- package/docs/02-commands/typed-commands.md +362 -0
- package/docs/03-architecture/README.md +66 -0
- package/docs/03-architecture/device-protocol.md +430 -0
- package/docs/03-architecture/edge-proxy.md +727 -0
- package/docs/03-architecture/routing-flow.md +893 -0
- package/docs/04-integration/README.md +144 -0
- package/docs/04-integration/backend-guide.md +551 -0
- package/docs/04-integration/edge-guide.md +684 -0
- package/docs/04-integration/gateway-guide.md +180 -0
- package/docs/04-integration/migration-guide.md +226 -0
- package/docs/05-examples/README.md +141 -0
- package/docs/05-examples/progress-update-examples.md +757 -0
- package/docs/06-reference/README.md +67 -0
- package/docs/06-reference/api.md +572 -0
- package/docs/06-reference/faq.md +302 -0
- package/docs/06-reference/glossary.md +232 -0
- package/examples/backend-upgrade.ts +279 -0
- package/examples/edge-multi-device.ts +513 -0
- package/examples/gateway-upgrade.ts +150 -0
- package/examples/protocol-implementation.ts +715 -0
- package/package.json +48 -0
- package/scripts/validate-asyncapi.ts +78 -0
- package/src/__tests__/protocol.test.ts +297 -0
- package/src/asyncapi-sync.ts +84 -0
- package/src/command-factory.ts +183 -0
- package/src/command-types.ts +72 -0
- package/src/edge-proxy.ts +494 -0
- package/src/gateway-extensions.ts +278 -0
- package/src/index.ts +792 -0
- package/src/message-validator.ts +726 -0
- package/src/protocol-utils.ts +355 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,1466 @@
|
|
|
1
|
+
# JRSoft Subway WebSocket 协议规范 v1.0
|
|
2
|
+
|
|
3
|
+
## 目录
|
|
4
|
+
1. [概述](#概述)
|
|
5
|
+
2. [设计原则](#设计原则)
|
|
6
|
+
3. [消息格式](#消息格式)
|
|
7
|
+
4. [连接生命周期](#连接生命周期)
|
|
8
|
+
5. [消息类型详解](#消息类型详解)
|
|
9
|
+
6. [错误处理](#错误处理)
|
|
10
|
+
7. [安全性](#安全性)
|
|
11
|
+
8. [性能优化](#性能优化)
|
|
12
|
+
9. [版本管理](#版本管理)
|
|
13
|
+
10. [命令系统架构](#命令系统架构)
|
|
14
|
+
11. [程序上传流程示例](#程序上传流程示例)
|
|
15
|
+
|
|
16
|
+
## 概述
|
|
17
|
+
|
|
18
|
+
JRSoft Subway 使用 WebSocket 协议进行实时双向通信。Gateway 作为中心节点,连接和管理所有客户端:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
WebSocket WebSocket
|
|
22
|
+
┌─────────┐ ──────────▶ ┌─────────┐ ──────────▶ ┌─────────┐
|
|
23
|
+
│ Device │ │ Edge │ │ │
|
|
24
|
+
└─────────┘ └─────────┘ │ │
|
|
25
|
+
│ Gateway │ ◀────── Backend
|
|
26
|
+
┌─────────┐ ──────────▶ ┌─────────┐ ──────────▶ │ │
|
|
27
|
+
│ Device │ WebSocket │ Edge │ WebSocket │ │
|
|
28
|
+
└─────────┘ └─────────┘ └─────────┘
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 客户端类型
|
|
32
|
+
|
|
33
|
+
1. **Device** - 物理设备(地铁设备、控制器等),通过 WebSocket 连接到 Edge
|
|
34
|
+
2. **Backend** - 后端服务(WebAPI、管理系统),直接连接 Gateway
|
|
35
|
+
3. **Edge** - 边缘计算节点,作为本地 Gateway,一个 Edge 可以管理多个设备并连接到中央 Gateway
|
|
36
|
+
4. **Gateway** - 中心路由网关,管理所有客户端连接和消息路由
|
|
37
|
+
|
|
38
|
+
### Edge 设备管理模式
|
|
39
|
+
|
|
40
|
+
一个 Edge 节点可以管理一套或多套隧道媒体广告播放系统的设备端:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
┌─────────────────────────────────────────┐
|
|
44
|
+
│ Edge (edge-001) │
|
|
45
|
+
│ │
|
|
46
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
47
|
+
│ │ 设备端 │ │ 设备端 │ │ 设备端 │ │
|
|
48
|
+
│ │ (td-01) │ │ (td-01) │ │ (td-01)│ │
|
|
49
|
+
│ └──────────┘ └──────────┘ └──────────┘ │
|
|
50
|
+
│ │
|
|
51
|
+
└─────────────────────────────────────────┘
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 设计原则
|
|
55
|
+
|
|
56
|
+
1. **简单性优先** - 基础功能使用最简单的消息格式
|
|
57
|
+
2. **渐进增强** - 高级功能通过可选字段实现
|
|
58
|
+
3. **统一标准** - 所有组件使用相同的协议版本
|
|
59
|
+
4. **明确语义** - 每个消息类型有清晰的用途
|
|
60
|
+
5. **故障隔离** - 单个客户端故障不影响其他客户端
|
|
61
|
+
|
|
62
|
+
## 长时间运行操作的设计思路
|
|
63
|
+
|
|
64
|
+
### 统一的进度上报机制
|
|
65
|
+
|
|
66
|
+
对于需要较长时间执行的操作,协议提供了统一的进度上报机制:
|
|
67
|
+
|
|
68
|
+
1. **Batch类型、Complex类型命令**(如健康检查、状态监控)
|
|
69
|
+
- 使用标准的 `command` 消息发起
|
|
70
|
+
- 执行过程中通过 `progress_update` 报告各阶段结果
|
|
71
|
+
- 最终通过 `command_response` 标志执行结束
|
|
72
|
+
- 适用于:需要多步骤执行并返回中间结果的命令
|
|
73
|
+
|
|
74
|
+
2. **程序上传流程**
|
|
75
|
+
- 使用专门的 `program` 消息发起(区别于普通命令)
|
|
76
|
+
- 通过 `progress_update` 报告各阶段进度(下载、解压、预处理、创建帧、上传、统计)
|
|
77
|
+
- 携带 `context` 确保每个进度更新可追溯
|
|
78
|
+
- 最终通过简化的 `program_response` 标志流程结束
|
|
79
|
+
- 适用于:文件传输类的长时间操作
|
|
80
|
+
|
|
81
|
+
### 进度更新消息的设计
|
|
82
|
+
|
|
83
|
+
`progress_update` 消息设计为通用的进度报告机制:
|
|
84
|
+
- **status** - 表示当前状态(pending、in_progress、paused、completed、failed、cancelled)
|
|
85
|
+
- **phase** - 表示当前所处阶段
|
|
86
|
+
- **progress** - 百分比进度(0-100)
|
|
87
|
+
- **sourceType** - 区分是设备命令结果还是系统消息
|
|
88
|
+
- **command** - 记录相关的设备操作(可选)
|
|
89
|
+
- **report** - 结构化日志信息,包含级别、消息、代码和附加数据
|
|
90
|
+
- **context** - 程序上传时的上下文信息(可选)
|
|
91
|
+
|
|
92
|
+
### 流程结束标志
|
|
93
|
+
|
|
94
|
+
所有长时间运行的操作都有明确的结束标志:
|
|
95
|
+
- Batch命令、Complex命令:`command_response` 消息
|
|
96
|
+
- 程序上传:`program_response` 消息
|
|
97
|
+
- 结束消息包含最终状态(completed、failed、timeout、cancelled)
|
|
98
|
+
|
|
99
|
+
## 消息格式
|
|
100
|
+
|
|
101
|
+
### 基础消息结构
|
|
102
|
+
|
|
103
|
+
所有消息都基于 JSON 格式,包含以下基础字段:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
interface BaseMessage {
|
|
107
|
+
type: MessageType; // 必需:消息类型(枚举)
|
|
108
|
+
timestamp: string; // 必需:ISO 8601 时间戳
|
|
109
|
+
version: string; // 必需:协议版本 "1.0"
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 消息分类
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
消息
|
|
117
|
+
├── 连接管理
|
|
118
|
+
│ ├── register / register_ack
|
|
119
|
+
│ ├── unregister / unregister_ack
|
|
120
|
+
│ └── heartbeat / heartbeat_ack
|
|
121
|
+
├── 命令执行
|
|
122
|
+
│ ├── command / command_response
|
|
123
|
+
│ └── progress_update (支持阶段、状态、日志、设备命令)
|
|
124
|
+
├── 程序管理
|
|
125
|
+
│ ├── program (程序上传请求)
|
|
126
|
+
│ └── program_response (程序上传最终响应)
|
|
127
|
+
└── 系统消息
|
|
128
|
+
└── error
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## 连接生命周期
|
|
132
|
+
|
|
133
|
+
### 1. 连接建立
|
|
134
|
+
|
|
135
|
+
```sequence
|
|
136
|
+
Client->Gateway: WebSocket Connect
|
|
137
|
+
Gateway->Client: Connection Established
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 2. 客户端注册
|
|
141
|
+
|
|
142
|
+
```sequence
|
|
143
|
+
Client->Gateway: register
|
|
144
|
+
Gateway->Client: register_ack
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Backend 注册:**
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"type": "REGISTER",
|
|
151
|
+
"clientId": "backend-server",
|
|
152
|
+
"clientType": "BACKEND",
|
|
153
|
+
"clientInfo": {
|
|
154
|
+
"version": "1.0.0",
|
|
155
|
+
"platform": "nodejs",
|
|
156
|
+
"capabilities": ["command", "program", "Ubatch"]
|
|
157
|
+
},
|
|
158
|
+
"timestamp": "2024-01-20T10:00:00Z",
|
|
159
|
+
"version": "1.0"
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Edge 注册场景:**
|
|
164
|
+
|
|
165
|
+
Edge 节点有两种注册场景:
|
|
166
|
+
|
|
167
|
+
**场景1:Edge 先启动,设备端已连接,然后 Gateway 重启**
|
|
168
|
+
```
|
|
169
|
+
1. Edge 与多个设备端保持 WebSocket 连接
|
|
170
|
+
2. Gateway 重启或网络恢复
|
|
171
|
+
3. Edge 检测到 Gateway 可用,连接并注册自己
|
|
172
|
+
4. Edge 为每个已连接的设备端发送注册消息(包含 Edge 信息)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**场景2:Gateway 在线,Edge 启动后注册**
|
|
176
|
+
```
|
|
177
|
+
1. Gateway 已在线运行
|
|
178
|
+
2. Edge 启动并连接到 Gateway
|
|
179
|
+
3. Edge 先注册自己
|
|
180
|
+
4. 设备端连接到 Edge 后,Edge 为其发送注册消息
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Edge 自身注册消息:**
|
|
184
|
+
```json
|
|
185
|
+
{
|
|
186
|
+
"type": "REGISTER",
|
|
187
|
+
"clientId": "edge-001",
|
|
188
|
+
"clientType": "EDGE",
|
|
189
|
+
"clientInfo": {
|
|
190
|
+
"version": "1.0.0",
|
|
191
|
+
"platform": "edge-proxy",
|
|
192
|
+
"capabilities": ["device_proxy", "batch_command", "status_report"]
|
|
193
|
+
},
|
|
194
|
+
"timestamp": "2024-01-20T10:00:00Z",
|
|
195
|
+
"version": "1.0"
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Edge 为设备端注册(包含 Edge 信息):**
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"type": "REGISTER",
|
|
203
|
+
"clientId": "td-01", // 设备端 ID
|
|
204
|
+
"clientType": "DEVICE",
|
|
205
|
+
"edgeInfo": { // Edge 信息
|
|
206
|
+
"edgeId": "edge-001",
|
|
207
|
+
"edgeVersion": "1.0.0",
|
|
208
|
+
"connectionTime": "2024-01-20T09:59:00Z"
|
|
209
|
+
},
|
|
210
|
+
"clientInfo": {
|
|
211
|
+
"version": "1.0.0",
|
|
212
|
+
"deviceType": "media_player",
|
|
213
|
+
"capabilities": ["play", "stop", "status_report"]
|
|
214
|
+
},
|
|
215
|
+
"timestamp": "2024-01-20T10:00:01Z",
|
|
216
|
+
"version": "1.0"
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**注册确认:**
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"type": "REGISTER_ACK",
|
|
224
|
+
"clientId": "device001",
|
|
225
|
+
"success": true,
|
|
226
|
+
"sessionId": "sess-123456", // 可选
|
|
227
|
+
"timestamp": "2024-01-20T10:00:01Z"
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### 3. 心跳维持
|
|
232
|
+
|
|
233
|
+
```sequence
|
|
234
|
+
Client->Gateway: heartbeat
|
|
235
|
+
Gateway->Client: heartbeat_ack
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
心跳间隔:30秒
|
|
239
|
+
超时断开:90秒(3个心跳周期)
|
|
240
|
+
|
|
241
|
+
**心跳消息:**
|
|
242
|
+
```json
|
|
243
|
+
{
|
|
244
|
+
"type": "HEARTBEAT",
|
|
245
|
+
"clientId": "device001",
|
|
246
|
+
"sequence": 123, // 可选:序列号
|
|
247
|
+
"timestamp": "2024-01-20T10:00:30Z",
|
|
248
|
+
"version": "1.0"
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**心跳确认:**
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"type": "HEARTBEAT_ACK",
|
|
256
|
+
"clientId": "device001",
|
|
257
|
+
"sequence": 123, // 可选:与请求相同的序列号
|
|
258
|
+
"timestamp": "2024-01-20T10:00:30Z",
|
|
259
|
+
"version": "1.0"
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### 4. 连接断开
|
|
264
|
+
|
|
265
|
+
```sequence
|
|
266
|
+
Client->Gateway: unregister
|
|
267
|
+
Gateway->Client: unregister_ack
|
|
268
|
+
Client->Gateway: Close Connection
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**注销消息:**
|
|
272
|
+
```json
|
|
273
|
+
{
|
|
274
|
+
"type": "UNREGISTER",
|
|
275
|
+
"clientId": "device001",
|
|
276
|
+
"reason": "shutdown", // 可选:shutdown, maintenance, error
|
|
277
|
+
"timestamp": "2024-01-20T11:00:00Z",
|
|
278
|
+
"version": "1.0"
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**注销确认:**
|
|
283
|
+
```json
|
|
284
|
+
{
|
|
285
|
+
"type": "UNREGISTER_ACK",
|
|
286
|
+
"clientId": "device001",
|
|
287
|
+
"success": true,
|
|
288
|
+
"timestamp": "2024-01-20T11:00:00Z",
|
|
289
|
+
"version": "1.0"
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## 消息类型详解
|
|
294
|
+
|
|
295
|
+
### 1. 命令执行流程
|
|
296
|
+
|
|
297
|
+
Gateway 作为命令路由中心,支持多种命令模式。命令支持两种类型定义方式:
|
|
298
|
+
|
|
299
|
+
1. **强类型命令**:基于 C# 模型生成的类型安全命令
|
|
300
|
+
2. **通用命令**:灵活的键值对参数命令
|
|
301
|
+
|
|
302
|
+
强类型命令示例:
|
|
303
|
+
```typescript
|
|
304
|
+
// 使用强类型工厂创建命令
|
|
305
|
+
import { createLedSwitchCommand } from '@jrsoft/subway-protocol';
|
|
306
|
+
|
|
307
|
+
const command = createLedSwitchCommand(
|
|
308
|
+
'req-123', // requestRef
|
|
309
|
+
'device-001', // targetClientId
|
|
310
|
+
1, // deviceId
|
|
311
|
+
'ON', // switch: 'ON' | 'OFF'
|
|
312
|
+
'write' // operationType
|
|
313
|
+
);
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
#### a) Simple 类型命令
|
|
317
|
+
|
|
318
|
+
Simple 类型命令是最基本的命令类型,一次请求对应一次响应。
|
|
319
|
+
|
|
320
|
+
**命令路由流程:**
|
|
321
|
+
|
|
322
|
+
```sequence
|
|
323
|
+
Backend->Gateway: command
|
|
324
|
+
Gateway->Edge: command
|
|
325
|
+
Edge->Device: command
|
|
326
|
+
Device->Edge: command_response
|
|
327
|
+
Edge->Gateway: command_response
|
|
328
|
+
Gateway->Backend: command_response
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**关键设计:**
|
|
332
|
+
- Gateway 作为中央路由器,根据 `targetClientId` 决定路由到哪个 Edge
|
|
333
|
+
- 所有设备都通过 Edge 接入(Edge 是设备的接入点)
|
|
334
|
+
- Gateway 负责管理多个 Edge 的连接
|
|
335
|
+
- Edge 负责管理本地设备的连接
|
|
336
|
+
- 全程使用 `command` 消息类型,无需转换
|
|
337
|
+
- 通过 `requestRef` 关联请求和响应
|
|
338
|
+
|
|
339
|
+
**命令请求示例:**
|
|
340
|
+
|
|
341
|
+
```json
|
|
342
|
+
{
|
|
343
|
+
"type": "COMMAND",
|
|
344
|
+
"requestRef": "req-123",
|
|
345
|
+
"targetClientId": "td-01", // 设备ID
|
|
346
|
+
"command": {
|
|
347
|
+
"commandType": "SIMPLE",
|
|
348
|
+
"commandCode": "SET_COLOR",
|
|
349
|
+
"deviceType": "pillar",
|
|
350
|
+
"deviceId": 1,
|
|
351
|
+
"operationType": "WRITE",
|
|
352
|
+
"parameters": {
|
|
353
|
+
"color": "#FF0000"
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
"priority": "HIGH",
|
|
357
|
+
"timeout": 10000,
|
|
358
|
+
"callback": "http://backend/api/callback/req-123",
|
|
359
|
+
"timestamp": "2024-01-20T10:00:00Z",
|
|
360
|
+
"version": "1.0"
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**targetClientId 格式说明:**
|
|
365
|
+
- 直接使用设备ID:`"td-01"`、`"td-02"` 等
|
|
366
|
+
- Backend 只需指定目标设备ID,无需知道 Edge 节点
|
|
367
|
+
- Gateway 维护设备到 Edge 的路由表,自动路由到正确的 Edge
|
|
368
|
+
- Edge 接收到命令后,转发给对应的设备
|
|
369
|
+
|
|
370
|
+
**Simple 命令响应格式:**
|
|
371
|
+
|
|
372
|
+
Simple 命令的响应遵循请求的反向路径返回:
|
|
373
|
+
|
|
374
|
+
```json
|
|
375
|
+
{
|
|
376
|
+
"type": "COMMAND_RESPONSE",
|
|
377
|
+
"requestRef": "req-123", // 与请求的 requestRef 相同
|
|
378
|
+
"status": "COMPLETED", // 命令执行状态
|
|
379
|
+
"result": {
|
|
380
|
+
"deviceType": "pillar",
|
|
381
|
+
"deviceId": 1,
|
|
382
|
+
"commandCode": "SET_COLOR",
|
|
383
|
+
"operationType": "WRITE",
|
|
384
|
+
"data": {
|
|
385
|
+
"previousColor": "#00FF00",
|
|
386
|
+
"currentColor": "#FF0000",
|
|
387
|
+
"executedAt": "2024-01-20T10:00:01Z"
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
"executionTime": 150, // 执行时间(毫秒)
|
|
391
|
+
"timestamp": "2024-01-20T10:00:01Z",
|
|
392
|
+
"version": "1.0"
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
**失败响应示例:**
|
|
397
|
+
```json
|
|
398
|
+
{
|
|
399
|
+
"type": "COMMAND_RESPONSE",
|
|
400
|
+
"requestRef": "req-123",
|
|
401
|
+
"status": "FAILED",
|
|
402
|
+
"result": {
|
|
403
|
+
"deviceType": "pillar",
|
|
404
|
+
"deviceId": 1,
|
|
405
|
+
"commandCode": "SET_COLOR",
|
|
406
|
+
"operationType": "WRITE",
|
|
407
|
+
"data": {
|
|
408
|
+
"Uerror": "Invalid color format",
|
|
409
|
+
"providedColor": "#GGGGGG"
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
"report": {
|
|
413
|
+
"level": "ERROR",
|
|
414
|
+
"message": "颜色格式无效",
|
|
415
|
+
"code": "INVALID_COLOR_FORMAT"
|
|
416
|
+
},
|
|
417
|
+
"timestamp": "2024-01-20T10:00:01Z",
|
|
418
|
+
"version": "1.0"
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
**响应路由:**
|
|
423
|
+
- 设备生成响应后,按原路径返回
|
|
424
|
+
- Edge(如果有)转发响应到 Gateway
|
|
425
|
+
- Gateway 根据 `requestRef` 路由响应到发起方(Backend)
|
|
426
|
+
- 如配置了 `callback`,Gateway 还会通过 HTTP POST 推送响应
|
|
427
|
+
|
|
428
|
+
#### b) Batch 类型命令(持续响应)
|
|
429
|
+
|
|
430
|
+
Batch 类型命令是向同一设备端的多个同一类型的子硬件(如编号为1-480的光柱)发送相同命令
|
|
431
|
+
|
|
432
|
+
```json
|
|
433
|
+
{
|
|
434
|
+
"type": "COMMAND",
|
|
435
|
+
"requestRef": "req-123",
|
|
436
|
+
"targetClientId": "td-01", // 设备ID(批量命令作用于该设备下的多个子硬件)
|
|
437
|
+
"command": {
|
|
438
|
+
"commandType": "BATCH", // 标识为 batch 类型命令
|
|
439
|
+
"commandCode": "TRAIN_LENGTH",
|
|
440
|
+
"deviceType": "pillar",
|
|
441
|
+
"deviceId": "1-10,30-40,51,52,53,54", // 子硬件范围:1到10,30到40,以及51,52,53,54;0代表所有同类型设备
|
|
442
|
+
"operationType": "WRITE",
|
|
443
|
+
"parameters": {
|
|
444
|
+
"switch": "ON" // 必须是 "ON" 或 "OFF"
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
"priority": "HIGH",
|
|
448
|
+
"timeout": 10000,
|
|
449
|
+
"callback": "http://backend/api/callback/req-123"
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
**Batch 命令执行模式:**
|
|
454
|
+
|
|
455
|
+
批量命令采用与程序上传相同的执行模式,通过 `progress_update` 报告每个设备的执行状态:
|
|
456
|
+
|
|
457
|
+
**进度更新示例(每个设备执行后):**
|
|
458
|
+
```json
|
|
459
|
+
{
|
|
460
|
+
"type": "PROGRESS_UPDATE",
|
|
461
|
+
"requestRef": "req-123",
|
|
462
|
+
"status": "IN_PROGRESS",
|
|
463
|
+
"phase": "executing",
|
|
464
|
+
"progress": 25, // 25% 完成 (6/24 设备)
|
|
465
|
+
"sourceType": "COMMAND",
|
|
466
|
+
"command": {
|
|
467
|
+
"commandType": "SIMPLE",
|
|
468
|
+
"commandCode": "SET_COLOR",
|
|
469
|
+
"deviceType": "pillar",
|
|
470
|
+
"deviceId": 3,
|
|
471
|
+
"operationType": "WRITE",
|
|
472
|
+
"result": {
|
|
473
|
+
"Uerror": "Device not responding"
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
"report": {
|
|
477
|
+
"level": "ERROR",
|
|
478
|
+
"message": "设备 3 执行失败",
|
|
479
|
+
"code": "DEVICE_TIMEOUT"
|
|
480
|
+
},
|
|
481
|
+
"timestamp": "2024-01-20T10:00:00Z",
|
|
482
|
+
"version": "1.0"
|
|
483
|
+
}
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
**最终响应(所有设备完成后):**
|
|
487
|
+
```json
|
|
488
|
+
{
|
|
489
|
+
"type": "COMMAND_RESPONSE",
|
|
490
|
+
"requestRef": "req-123",
|
|
491
|
+
"status": "COMPLETED",
|
|
492
|
+
"result": {
|
|
493
|
+
"deviceType": "pillar",
|
|
494
|
+
"deviceId": "1-10,30-40,51-54", // 原始批量目标
|
|
495
|
+
"commandCode": "SET_COLOR",
|
|
496
|
+
"operationType": "WRITE",
|
|
497
|
+
"data": {
|
|
498
|
+
"message": "批量命令执行完成",
|
|
499
|
+
"targetCount": 24,
|
|
500
|
+
"successCount": 23,
|
|
501
|
+
"failureCount": 1
|
|
502
|
+
}
|
|
503
|
+
},
|
|
504
|
+
"summary": {
|
|
505
|
+
"total": 24,
|
|
506
|
+
"successful": 23,
|
|
507
|
+
"Ufailed": 1,
|
|
508
|
+
"failedTargets": [3]
|
|
509
|
+
},
|
|
510
|
+
"executionTime": 2500,
|
|
511
|
+
"timestamp": "2024-01-20T10:00:02Z",
|
|
512
|
+
"version": "1.0"
|
|
513
|
+
}
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
#### c) Complex 类型命令(持续响应)
|
|
517
|
+
|
|
518
|
+
Complex 类型命令是发送一个指令后,设备端会持续返回多个响应,直到完成。典型应用:一键检测、监播数据导出、系统日志。
|
|
519
|
+
|
|
520
|
+
**命令示例:**
|
|
521
|
+
|
|
522
|
+
```json
|
|
523
|
+
{
|
|
524
|
+
"type": "COMMAND",
|
|
525
|
+
"requestRef": "health-check-001",
|
|
526
|
+
"targetClientId": "td-01",
|
|
527
|
+
"command": {
|
|
528
|
+
"commandType": "COMPLEX",
|
|
529
|
+
"commandCode": "HealthCheck",
|
|
530
|
+
"parameters": {
|
|
531
|
+
"switchStatus": true,
|
|
532
|
+
"switchConfigInformation": true,
|
|
533
|
+
"synchronizerStatus": true,
|
|
534
|
+
"pillarStatus": true
|
|
535
|
+
}
|
|
536
|
+
},
|
|
537
|
+
"priority": "NORMAL",
|
|
538
|
+
"timeout": 30000
|
|
539
|
+
}
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
**Complex命令设计思路:**
|
|
543
|
+
- Complex类型命令用于需要持续响应的场景,如健康检查、监播数据导出、系统日志等
|
|
544
|
+
- 设备可以在执行过程中发送多个 `progress_update` 消息报告不同阶段的结果
|
|
545
|
+
- 最终必须发送一个 `command_response` 消息表示命令执行结束
|
|
546
|
+
- 所有消息通过 `requestRef` 关联到原始命令请求
|
|
547
|
+
|
|
548
|
+
**设备端持续响应流程:**
|
|
549
|
+
```sequence
|
|
550
|
+
Backend->Gateway: HealthCheck command
|
|
551
|
+
Gateway->Edge: command
|
|
552
|
+
Edge->Device: command
|
|
553
|
+
Device->Edge: progress_update (检查开关状态)
|
|
554
|
+
Edge->Gateway: progress_update
|
|
555
|
+
Gateway->Backend: progress_update
|
|
556
|
+
Device->Edge: progress_update (读取配置信息)
|
|
557
|
+
Edge->Gateway: progress_update
|
|
558
|
+
Gateway->Backend: progress_update
|
|
559
|
+
Device->Edge: progress_update (检查同步器)
|
|
560
|
+
Edge->Gateway: progress_update
|
|
561
|
+
Gateway->Backend: progress_update
|
|
562
|
+
Device->Edge: progress_update (检查立柱状态)
|
|
563
|
+
Edge->Gateway: progress_update
|
|
564
|
+
Gateway->Backend: progress_update
|
|
565
|
+
Device->Edge: command_response (最终结果)
|
|
566
|
+
Edge->Gateway: command_response
|
|
567
|
+
Gateway->Backend: command_response
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### 2. 程序上传流程(持续响应)
|
|
571
|
+
|
|
572
|
+
**程序上传设计思路:**
|
|
573
|
+
- 程序上传是独立于普通命令的特殊流程,使用专门的 `program` 和 `program_response` 消息类型
|
|
574
|
+
- 整个上传过程分为多个阶段:下载、解压、预处理、创建帧、上传到设备、统计
|
|
575
|
+
- 使用 `progress_update` 消息持续报告各阶段进度,包含:
|
|
576
|
+
- `sourceType` 区分是命令操作结果还是系统类型结果
|
|
577
|
+
- `context` 携带程序上下文信息,确保每个进度更新都能追溯到具体程序
|
|
578
|
+
- `command` 记录涉及的设备操作(如读取配置、写入数据)
|
|
579
|
+
- `report` 提供结构化的日志信息,支持不同级别和错误代码
|
|
580
|
+
- 最终发送 `program_response` 作为整个流程的结束标志,仅包含必要的状态信息
|
|
581
|
+
|
|
582
|
+
程序上传是长时间运行的操作,需要进度反馈:
|
|
583
|
+
|
|
584
|
+
```sequence
|
|
585
|
+
Backend->Gateway: program
|
|
586
|
+
Gateway->Edge: program
|
|
587
|
+
Edge->Device: program
|
|
588
|
+
Device->Edge: progress_update (10%)
|
|
589
|
+
Edge->Gateway: progress_update (10%)
|
|
590
|
+
Gateway->Backend: progress_update (10%)
|
|
591
|
+
Device->Edge: progress_update (50%)
|
|
592
|
+
Edge->Gateway: progress_update (50%)
|
|
593
|
+
Gateway->Backend: progress_update (50%)
|
|
594
|
+
Device->Edge: progress_update (100%)
|
|
595
|
+
Edge->Gateway: progress_update (100%)
|
|
596
|
+
Gateway->Backend: progress_update (100%)
|
|
597
|
+
Device->Edge: program_response
|
|
598
|
+
Edge->Gateway: program_response
|
|
599
|
+
Gateway->Backend: program_response
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
**程序上传请求:**
|
|
603
|
+
```json
|
|
604
|
+
{
|
|
605
|
+
"type": "PROGRAM",
|
|
606
|
+
"requestRef": "prog-123",
|
|
607
|
+
"targetClientId": "td-01",
|
|
608
|
+
"command": {
|
|
609
|
+
"commandCode": "UPLOAD_PROGRAM",
|
|
610
|
+
"parameters": {
|
|
611
|
+
"deviceId": "td-01",
|
|
612
|
+
"taskId": "1234567890123456789", // Snowflake ID
|
|
613
|
+
"programId": "1234567890123456788", // Snowflake ID
|
|
614
|
+
"programName": "春节活动广告",
|
|
615
|
+
"programNumber": 3, // 1-10
|
|
616
|
+
"programType": "DYNAMIC", // dynamic|static
|
|
617
|
+
"width": 800,
|
|
618
|
+
"height": 480,
|
|
619
|
+
"direction": "LEFT_TO_RIGHT", // left_to_right|right_to_left
|
|
620
|
+
"publishTime": "2024-02-01T08:00:00", // 上刊时间
|
|
621
|
+
"unpublishTime": "2024-02-15T22:00:00", // 下刊时间
|
|
622
|
+
"downloadUrl": "https://cdn.example.com/programs/v1.0.1.zip",
|
|
623
|
+
"checksum": "sha256:abcd1234...",
|
|
624
|
+
"hashAlgorithm": "SHA256",
|
|
625
|
+
"fileSize": 10485760
|
|
626
|
+
}
|
|
627
|
+
},
|
|
628
|
+
"priority": "NORMAL",
|
|
629
|
+
"timeout": 1800000 // 30分钟
|
|
630
|
+
}
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
**进度更新:**
|
|
634
|
+
|
|
635
|
+
进度更新消息用于长时间运行的操作(如程序上传),提供实时进度反馈。详细的进度更新消息格式请参考后面的《9. 程序上传流程示例》章节。
|
|
636
|
+
|
|
637
|
+
基本格式:
|
|
638
|
+
```json
|
|
639
|
+
{
|
|
640
|
+
"type": "PROGRESS_UPDATE",
|
|
641
|
+
"requestRef": "prog-123",
|
|
642
|
+
"status": "IN_PROGRESS", // pending, in_progress, paused, completed, failed, cancelled
|
|
643
|
+
"phase": "DOWNLOAD", // 预定义阶段: DOWNLOAD, DECOMPRESS, PREPROCESS, FRAMES, UPLOAD, STATS (支持自定义阶段)
|
|
644
|
+
"progress": 45, // 0-100 的进度百分比
|
|
645
|
+
"sourceType": "COMMAND", // command(命令操作结果)或 system(系统类型结果)
|
|
646
|
+
"context": { // 可选:程序上下文信息(用于程序上传相关的进度更新)
|
|
647
|
+
"taskId": "1234567890123456789",
|
|
648
|
+
"programId": "1234567890123456788",
|
|
649
|
+
"programName": "春节活动广告",
|
|
650
|
+
"programNumber": 3,
|
|
651
|
+
"programType": "DYNAMIC"
|
|
652
|
+
},
|
|
653
|
+
"command": { // 可选:设备操作记录
|
|
654
|
+
"commandType": "SIMPLE",
|
|
655
|
+
"commandCode": "READ_STATUS",
|
|
656
|
+
"deviceType": "synchronizer",
|
|
657
|
+
"deviceId": 1,
|
|
658
|
+
"operationType": "READ",
|
|
659
|
+
"result": { "status": "ready" }
|
|
660
|
+
},
|
|
661
|
+
"report": { // 必需:日志信息
|
|
662
|
+
"level": "INFO",
|
|
663
|
+
"message": "正在下载节目文件...",
|
|
664
|
+
"code": "DOWNLOAD_PROGRESS",
|
|
665
|
+
"data": { "bytesDownloaded": 23592960, "totalBytes": 52428800 }
|
|
666
|
+
},
|
|
667
|
+
"timestamp": "2024-01-20T10:05:00Z",
|
|
668
|
+
"version": "1.0"
|
|
669
|
+
}
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
**字段说明:**
|
|
673
|
+
| 字段 | 类型 | 必需 | 说明 |
|
|
674
|
+
|------|------|------|------|
|
|
675
|
+
| type | string | 是 | 固定为 "Uprogress_update" |
|
|
676
|
+
| requestRef | string | 是 | 原始请求的引用ID |
|
|
677
|
+
| status | string | 是 | 状态:pending, in_progress, paused, completed, failed, cancelled |
|
|
678
|
+
| phase | string | 是 | 阶段:downloading, decompressing, preprocessing, createFrames, uploading, statistics |
|
|
679
|
+
| progress | number | 是 | 进度百分比 (0-100) |
|
|
680
|
+
| sourceType | string | 是 | 来源类型:command(命令操作结果)或 system(系统类型结果) |
|
|
681
|
+
| context | object | 否 | 程序上下文信息(用于程序上传相关的进度更新) |
|
|
682
|
+
| command | object | 否 | 设备操作记录(当涉及设备读写时) |
|
|
683
|
+
| report | object | 是 | 日志信息(包含级别、消息、代码和数据) |
|
|
684
|
+
| timestamp | string | 是 | ISO 8601 格式时间戳 |
|
|
685
|
+
| version | string | 是 | 协议版本 "1.0" |
|
|
686
|
+
|
|
687
|
+
**阶段说明:**
|
|
688
|
+
- `downloading` - 下载文件
|
|
689
|
+
- `decompressing` - 解压文件
|
|
690
|
+
- `preprocessing` - 预处理
|
|
691
|
+
- `createFrames` - 创建帧
|
|
692
|
+
- `uploading` - 上传到设备
|
|
693
|
+
- `statistics` - 统计信息
|
|
694
|
+
|
|
695
|
+
**程序上下文字段说明:**
|
|
696
|
+
| 字段 | 类型 | 说明 |
|
|
697
|
+
|------|------|------|
|
|
698
|
+
| taskId | string | 任务ID (Snowflake ID) |
|
|
699
|
+
| programId | string | 程序ID (Snowflake ID) |
|
|
700
|
+
| programName | string | 程序名称 |
|
|
701
|
+
| programNumber | number | 程序编号 (1-10) |
|
|
702
|
+
| programType | string | 程序类型:dynamic(动态)或 static(静态)|
|
|
703
|
+
|
|
704
|
+
**日志信息字段说明:**
|
|
705
|
+
| 字段 | 类型 | 必需 | 说明 |
|
|
706
|
+
|------|------|------|------|
|
|
707
|
+
| level | string | 是 | 日志级别:debug, info, warning, error, critical |
|
|
708
|
+
| message | string | 是 | 日志消息内容 |
|
|
709
|
+
| code | string | 否 | 标准化的消息代码 |
|
|
710
|
+
| data | object | 否 | 额外的数据对象 |
|
|
711
|
+
|
|
712
|
+
**程序上传响应:**
|
|
713
|
+
|
|
714
|
+
程序上传完成后,设备会返回最终的响应消息(作为整个流程结束的标志):
|
|
715
|
+
|
|
716
|
+
```json
|
|
717
|
+
{
|
|
718
|
+
"type": "PROGRAM_RESPONSE",
|
|
719
|
+
"requestRef": "prog-123",
|
|
720
|
+
"status": "COMPLETED", // completed, failed, timeout, cancelled
|
|
721
|
+
"context": {
|
|
722
|
+
"taskId": "1234567890123456789",
|
|
723
|
+
"programId": "1234567890123456788",
|
|
724
|
+
"programName": "春节活动广告",
|
|
725
|
+
"programNumber": 3,
|
|
726
|
+
"programType": "DYNAMIC"
|
|
727
|
+
},
|
|
728
|
+
"report": { // 可选:日志信息
|
|
729
|
+
"level": "INFO",
|
|
730
|
+
"message": "程序上传并激活成功"
|
|
731
|
+
},
|
|
732
|
+
"executionTime": 180000, // 可选:总执行时间(毫秒)
|
|
733
|
+
"timestamp": "2024-01-20T10:30:00Z",
|
|
734
|
+
"version": "1.0"
|
|
735
|
+
}
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
**字段说明:**
|
|
739
|
+
| 字段 | 类型 | 必需 | 说明 |
|
|
740
|
+
|------|------|------|------|
|
|
741
|
+
| type | string | 是 | 固定为 "Uprogram_response" |
|
|
742
|
+
| requestRef | string | 是 | 原始请求的引用ID |
|
|
743
|
+
| status | string | 是 | 状态:completed, failed, timeout, cancelled |
|
|
744
|
+
| context | object | 是 | 程序上下文信息(包含taskId, programId等) |
|
|
745
|
+
| report | object | 否 | 日志信息(使用ReportMessage结构) |
|
|
746
|
+
| executionTime | number | 否 | 总执行时间(毫秒) |
|
|
747
|
+
| timestamp | string | 是 | ISO 8601 格式时间戳 |
|
|
748
|
+
| version | string | 是 | 协议版本 "1.0" |
|
|
749
|
+
|
|
750
|
+
### 3. 设备状态查询
|
|
751
|
+
|
|
752
|
+
Gateway 维护所有连接设备的状态:
|
|
753
|
+
|
|
754
|
+
**查询单个设备:**
|
|
755
|
+
```json
|
|
756
|
+
{
|
|
757
|
+
"type": "COMMAND",
|
|
758
|
+
"requestRef": "query-001",
|
|
759
|
+
"targetClientId": "Ugateway", // 特殊值,查询Gateway
|
|
760
|
+
"command": {
|
|
761
|
+
"commandType": "SIMPLE",
|
|
762
|
+
"commandCode": "GET_DEVICE_STATUS",
|
|
763
|
+
"deviceType": "Ugateway",
|
|
764
|
+
"deviceId": 0,
|
|
765
|
+
"operationType": "READ",
|
|
766
|
+
"parameters": {
|
|
767
|
+
"targetClientId": "device001"
|
|
768
|
+
}
|
|
769
|
+
},
|
|
770
|
+
"priority": "NORMAL",
|
|
771
|
+
"timeout": 5000
|
|
772
|
+
}
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
**查询所有设备:**
|
|
776
|
+
```json
|
|
777
|
+
{
|
|
778
|
+
"type": "COMMAND",
|
|
779
|
+
"requestRef": "query-002",
|
|
780
|
+
"targetClientId": "Ugateway",
|
|
781
|
+
"command": {
|
|
782
|
+
"commandType": "SIMPLE",
|
|
783
|
+
"commandCode": "LIST_DEVICES",
|
|
784
|
+
"deviceType": "Ugateway",
|
|
785
|
+
"deviceId": 0,
|
|
786
|
+
"operationType": "READ",
|
|
787
|
+
"parameters": {
|
|
788
|
+
"filter": {
|
|
789
|
+
"status": "online",
|
|
790
|
+
"clientType": "DEVICE"
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
},
|
|
794
|
+
"priority": "NORMAL",
|
|
795
|
+
"timeout": 5000
|
|
796
|
+
}
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
## 错误处理
|
|
800
|
+
|
|
801
|
+
### 错误消息格式
|
|
802
|
+
|
|
803
|
+
```json
|
|
804
|
+
{
|
|
805
|
+
"type": "ERROR",
|
|
806
|
+
"code": "DEVICE_OFFLINE",
|
|
807
|
+
"message": "Target device is not connected",
|
|
808
|
+
"severity": "medium", // low, medium, high, critical
|
|
809
|
+
"category": "Udevice", // device, command, protocol, system
|
|
810
|
+
"context": {
|
|
811
|
+
"clientId": "device001",
|
|
812
|
+
"requestRef": "req-123",
|
|
813
|
+
"operation": "command"
|
|
814
|
+
},
|
|
815
|
+
"retryable": true,
|
|
816
|
+
"timestamp": "2024-01-20T10:00:00Z",
|
|
817
|
+
"version": "1.0"
|
|
818
|
+
}
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
**严重级别说明:**
|
|
822
|
+
- `low` - 信息性错误,不影响系统运行
|
|
823
|
+
- `medium` - 一般错误,影响单个操作
|
|
824
|
+
- `high` - 严重错误,影响多个操作或组件
|
|
825
|
+
- `critical` - 关键错误,影响系统稳定性
|
|
826
|
+
|
|
827
|
+
**错误类别:**
|
|
828
|
+
- `device` - 设备相关错误
|
|
829
|
+
- `command` - 命令执行错误
|
|
830
|
+
- `protocol` - 协议格式或版本错误
|
|
831
|
+
- `system` - 系统级错误
|
|
832
|
+
|
|
833
|
+
### 错误代码规范
|
|
834
|
+
|
|
835
|
+
```
|
|
836
|
+
错误代码格式:[类别]_[具体错误]
|
|
837
|
+
|
|
838
|
+
设备错误 (DEVICE_)
|
|
839
|
+
├── DEVICE_OFFLINE - 设备离线
|
|
840
|
+
├── DEVICE_NOT_FOUND - 设备不存在
|
|
841
|
+
├── DEVICE_BUSY - 设备忙
|
|
842
|
+
└── DEVICE_ERROR - 设备内部错误
|
|
843
|
+
|
|
844
|
+
命令错误 (COMMAND_)
|
|
845
|
+
├── COMMAND_TIMEOUT - 命令超时
|
|
846
|
+
├── COMMAND_INVALID - 无效命令
|
|
847
|
+
├── COMMAND_FAILED - 命令执行失败
|
|
848
|
+
└── COMMAND_CANCELLED - 命令被取消
|
|
849
|
+
|
|
850
|
+
协议错误 (PROTOCOL_)
|
|
851
|
+
├── PROTOCOL_INVALID - 消息格式错误
|
|
852
|
+
├── PROTOCOL_VERSION - 版本不兼容
|
|
853
|
+
└── PROTOCOL_SEQUENCE - 消息顺序错误
|
|
854
|
+
|
|
855
|
+
系统错误 (SYSTEM_)
|
|
856
|
+
├── SYSTEM_OVERLOAD - 系统过载
|
|
857
|
+
├── SYSTEM_MAINTENANCE - 系统维护
|
|
858
|
+
└── SYSTEM_ERROR - 内部错误
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
### 命令失败响应示例
|
|
862
|
+
|
|
863
|
+
```json
|
|
864
|
+
{
|
|
865
|
+
"type": "COMMAND_RESPONSE",
|
|
866
|
+
"requestRef": "cmd-fail-001",
|
|
867
|
+
"status": "FAILED",
|
|
868
|
+
"result": {
|
|
869
|
+
"deviceType": "pillar",
|
|
870
|
+
"deviceId": 5,
|
|
871
|
+
"commandCode": "TRAIN_LENGTH",
|
|
872
|
+
"operationType": "WRITE",
|
|
873
|
+
"data": {
|
|
874
|
+
"attemptedValue": 8,
|
|
875
|
+
"currentValue": 6,
|
|
876
|
+
"errorReason": "Invalid train length"
|
|
877
|
+
}
|
|
878
|
+
},
|
|
879
|
+
"report": {
|
|
880
|
+
"level": "ERROR",
|
|
881
|
+
"message": "命令执行失败:列车长度设置无效",
|
|
882
|
+
"code": "COMMAND_FAILED",
|
|
883
|
+
"data": {
|
|
884
|
+
"retryable": false,
|
|
885
|
+
"maxLength": 6,
|
|
886
|
+
"attemptedLength": 8
|
|
887
|
+
}
|
|
888
|
+
},
|
|
889
|
+
"executionTime": 45,
|
|
890
|
+
"timestamp": "2024-01-20T10:05:00Z",
|
|
891
|
+
"version": "1.0"
|
|
892
|
+
}
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
### 错误处理策略
|
|
896
|
+
|
|
897
|
+
1. **自动重试** - 对于 `retryable: true` 的错误
|
|
898
|
+
2. **降级处理** - 批量操作失败时降级为单个操作
|
|
899
|
+
3. **熔断保护** - 连续失败时暂停发送
|
|
900
|
+
4. **错误聚合** - 相似错误合并上报
|
|
901
|
+
|
|
902
|
+
## 安全性
|
|
903
|
+
|
|
904
|
+
### 1. 认证机制
|
|
905
|
+
|
|
906
|
+
虽然基础协议不强制认证,但建议实现:
|
|
907
|
+
|
|
908
|
+
```json
|
|
909
|
+
{
|
|
910
|
+
"type": "REGISTER",
|
|
911
|
+
"clientId": "device001",
|
|
912
|
+
"auth": { // 可选
|
|
913
|
+
"method": "token",
|
|
914
|
+
"credentials": "Bearer eyJhbGc..."
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
```
|
|
918
|
+
|
|
919
|
+
### 2. 消息完整性
|
|
920
|
+
|
|
921
|
+
对于关键命令,支持消息签名:
|
|
922
|
+
|
|
923
|
+
```json
|
|
924
|
+
{
|
|
925
|
+
"type": "COMMAND",
|
|
926
|
+
"requestRef": "secure-req-123",
|
|
927
|
+
"signature": "sha256:1234abcd...", // 可选
|
|
928
|
+
// ... 其他字段
|
|
929
|
+
}
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
### 3. 访问控制
|
|
933
|
+
|
|
934
|
+
Gateway 实现基于客户端类型的访问控制:
|
|
935
|
+
|
|
936
|
+
- **Backend**: 可以发送命令给任何 Edge 管理的设备
|
|
937
|
+
- **Edge**: 可以转发其管理的设备状态,执行来自 Backend 的命令
|
|
938
|
+
- **Device**: 不直接连接 Gateway,由 Edge 代理所有通信
|
|
939
|
+
|
|
940
|
+
## 性能优化
|
|
941
|
+
|
|
942
|
+
### 1. 消息压缩
|
|
943
|
+
|
|
944
|
+
对于大型消息(>1KB),Gateway 支持压缩:
|
|
945
|
+
|
|
946
|
+
```
|
|
947
|
+
WebSocket Header: Compression: gzip
|
|
948
|
+
```
|
|
949
|
+
|
|
950
|
+
### 2. 批量处理
|
|
951
|
+
|
|
952
|
+
支持批量消息以减少往返次数:
|
|
953
|
+
|
|
954
|
+
```json
|
|
955
|
+
{
|
|
956
|
+
"type": "Ubatch", // 批量类型
|
|
957
|
+
"messages": [
|
|
958
|
+
{ "type": "COMMAND", ... },
|
|
959
|
+
{ "type": "COMMAND", ... },
|
|
960
|
+
{ "type": "COMMAND", ... }
|
|
961
|
+
]
|
|
962
|
+
}
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
### 3. 消息优先级
|
|
966
|
+
|
|
967
|
+
Gateway 根据优先级处理消息:
|
|
968
|
+
|
|
969
|
+
- **critical**: 立即处理
|
|
970
|
+
- **high**: 优先处理
|
|
971
|
+
- **normal**: 标准队列
|
|
972
|
+
- **low**: 空闲时处理
|
|
973
|
+
|
|
974
|
+
## 版本管理
|
|
975
|
+
|
|
976
|
+
|
|
977
|
+
### 版本要求
|
|
978
|
+
|
|
979
|
+
当前协议版本为 1.0,所有组件必须使用相同版本。
|
|
980
|
+
|
|
981
|
+
## 命令系统架构
|
|
982
|
+
|
|
983
|
+
### 强类型命令支持
|
|
984
|
+
|
|
985
|
+
协议支持两种命令定义方式:
|
|
986
|
+
|
|
987
|
+
1. **强类型命令** - 基于 C# 模型生成的类型安全命令
|
|
988
|
+
2. **通用命令** - 灵活的键值对参数命令
|
|
989
|
+
|
|
990
|
+
**注意**:不同命令类型的字段要求:
|
|
991
|
+
- **Simple 类型**:需要 commandCode, deviceType, deviceId, operationType, parameters
|
|
992
|
+
- **Batch 类型**:需要 commandCode, deviceType, deviceId(可为范围字符串), operationType, parameters
|
|
993
|
+
- **Complex 类型**:只需要 commandCode, parameters(不需要 deviceType, deviceId 和 operationType)
|
|
994
|
+
|
|
995
|
+
```typescript
|
|
996
|
+
// 强类型命令定义
|
|
997
|
+
export interface LedSwitchCommand {
|
|
998
|
+
commandCode: 'LedSwitch';
|
|
999
|
+
deviceType: 'pillar';
|
|
1000
|
+
deviceId: number;
|
|
1001
|
+
operationType: 'read' | 'write';
|
|
1002
|
+
parameters?: {
|
|
1003
|
+
switch: 'ON' | 'OFF';
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
// 使用强类型工厂
|
|
1008
|
+
const command = createLedSwitchCommand(
|
|
1009
|
+
'req-123', 'device-001', 15, 'ON', 'write'
|
|
1010
|
+
);
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
### 批量命令支持
|
|
1014
|
+
|
|
1015
|
+
向同一设备端的多个同类型子硬件发送相同命令:
|
|
1016
|
+
|
|
1017
|
+
```json
|
|
1018
|
+
{
|
|
1019
|
+
"command": {
|
|
1020
|
+
"commandCode": "SET_COLOR",
|
|
1021
|
+
"deviceType": "light_column",
|
|
1022
|
+
"parameters": {
|
|
1023
|
+
"targets": "1-10,30-40,51,52,53,54", // 范围表示法
|
|
1024
|
+
"Ubatch": true,
|
|
1025
|
+
"color": "#FF0000"
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
## 10. 程序上传流程示例
|
|
1032
|
+
|
|
1033
|
+
完整的程序上传流程及其进度更新:
|
|
1034
|
+
|
|
1035
|
+
### 10.1 初始程序上传命令
|
|
1036
|
+
```json
|
|
1037
|
+
{
|
|
1038
|
+
"type": "PROGRAM",
|
|
1039
|
+
"requestRef": "prog-upload-001",
|
|
1040
|
+
"targetClientId": "device-001",
|
|
1041
|
+
"command": {
|
|
1042
|
+
"commandCode": "UPLOAD_PROGRAM",
|
|
1043
|
+
"parameters": {
|
|
1044
|
+
"deviceId": "device-001",
|
|
1045
|
+
"taskId": "1234567890123456789",
|
|
1046
|
+
"programId": "1234567890123456788",
|
|
1047
|
+
"programName": "春节活动广告",
|
|
1048
|
+
"programNumber": 1,
|
|
1049
|
+
"programType": "DYNAMIC",
|
|
1050
|
+
"width": 1920,
|
|
1051
|
+
"height": 1080,
|
|
1052
|
+
"direction": "LEFT_TO_RIGHT",
|
|
1053
|
+
"publishTime": "2024-02-01T00:00:00Z",
|
|
1054
|
+
"unpublishTime": "2024-02-15T23:59:59Z",
|
|
1055
|
+
"downloadUrl": "https://example.com/programs/spring-festival.zip",
|
|
1056
|
+
"checksum": "a1b2c3d4e5f6...",
|
|
1057
|
+
"hashAlgorithm": "SHA256",
|
|
1058
|
+
"fileSize": 52428800
|
|
1059
|
+
}
|
|
1060
|
+
},
|
|
1061
|
+
"priority": "HIGH",
|
|
1062
|
+
"timeout": 1800000,
|
|
1063
|
+
"timestamp": "2024-01-20T10:00:00Z",
|
|
1064
|
+
"version": "1.0"
|
|
1065
|
+
}
|
|
1066
|
+
```
|
|
1067
|
+
|
|
1068
|
+
### 10.2 进度更新序列
|
|
1069
|
+
|
|
1070
|
+
#### 阶段1:下载文件
|
|
1071
|
+
```json
|
|
1072
|
+
{
|
|
1073
|
+
"type": "PROGRESS_UPDATE",
|
|
1074
|
+
"requestRef": "prog-upload-001",
|
|
1075
|
+
"status": "IN_PROGRESS",
|
|
1076
|
+
"phase": "DOWNLOAD",
|
|
1077
|
+
"progress": 0,
|
|
1078
|
+
"sourceType": "SYSTEM",
|
|
1079
|
+
"context": {
|
|
1080
|
+
"taskId": "1234567890123456789",
|
|
1081
|
+
"programId": "1234567890123456788",
|
|
1082
|
+
"programName": "春节活动广告",
|
|
1083
|
+
"programNumber": 3,
|
|
1084
|
+
"programType": "DYNAMIC"
|
|
1085
|
+
},
|
|
1086
|
+
"report": {
|
|
1087
|
+
"level": "INFO",
|
|
1088
|
+
"message": "开始下载节目文件..."
|
|
1089
|
+
},
|
|
1090
|
+
"timestamp": "2024-01-20T10:00:01Z",
|
|
1091
|
+
"version": "1.0"
|
|
1092
|
+
}
|
|
1093
|
+
```
|
|
1094
|
+
|
|
1095
|
+
```json
|
|
1096
|
+
{
|
|
1097
|
+
"type": "PROGRESS_UPDATE",
|
|
1098
|
+
"requestRef": "prog-upload-001",
|
|
1099
|
+
"status": "IN_PROGRESS",
|
|
1100
|
+
"phase": "DOWNLOAD",
|
|
1101
|
+
"progress": 50,
|
|
1102
|
+
"sourceType": "SYSTEM",
|
|
1103
|
+
"report": {
|
|
1104
|
+
"level": "DEBUG",
|
|
1105
|
+
"message": "已下载 25MB / 50MB",
|
|
1106
|
+
"data": {
|
|
1107
|
+
"downloadSpeed": "5.2MB/s",
|
|
1108
|
+
"remainingTime": 10,
|
|
1109
|
+
"serverLatency": 32
|
|
1110
|
+
}
|
|
1111
|
+
},
|
|
1112
|
+
"timestamp": "2024-01-20T10:00:30Z",
|
|
1113
|
+
"version": "1.0"
|
|
1114
|
+
}
|
|
1115
|
+
```
|
|
1116
|
+
|
|
1117
|
+
#### 阶段2:解压文件
|
|
1118
|
+
```json
|
|
1119
|
+
{
|
|
1120
|
+
"type": "PROGRESS_UPDATE",
|
|
1121
|
+
"requestRef": "prog-upload-001",
|
|
1122
|
+
"status": "IN_PROGRESS",
|
|
1123
|
+
"phase": "DECOMPRESS",
|
|
1124
|
+
"progress": 15,
|
|
1125
|
+
"sourceType": "SYSTEM",
|
|
1126
|
+
"report": {
|
|
1127
|
+
"level": "INFO",
|
|
1128
|
+
"message": "正在解压节目文件..."
|
|
1129
|
+
},
|
|
1130
|
+
"timestamp": "2024-01-20T10:01:00Z",
|
|
1131
|
+
"version": "1.0"
|
|
1132
|
+
}
|
|
1133
|
+
```
|
|
1134
|
+
|
|
1135
|
+
#### 阶段3:预处理
|
|
1136
|
+
```json
|
|
1137
|
+
{
|
|
1138
|
+
"type": "PROGRESS_UPDATE",
|
|
1139
|
+
"requestRef": "prog-upload-001",
|
|
1140
|
+
"status": "IN_PROGRESS",
|
|
1141
|
+
"phase": "PREPROCESS",
|
|
1142
|
+
"progress": 20,
|
|
1143
|
+
"sourceType": "SYSTEM",
|
|
1144
|
+
"report": {
|
|
1145
|
+
"level": "INFO",
|
|
1146
|
+
"message": "正在验证节目内容..."
|
|
1147
|
+
},
|
|
1148
|
+
"timestamp": "2024-01-20T10:01:30Z",
|
|
1149
|
+
"version": "1.0"
|
|
1150
|
+
}
|
|
1151
|
+
```
|
|
1152
|
+
|
|
1153
|
+
#### 预处理中的警告日志
|
|
1154
|
+
```json
|
|
1155
|
+
{
|
|
1156
|
+
"type": "PROGRESS_UPDATE",
|
|
1157
|
+
"requestRef": "prog-upload-001",
|
|
1158
|
+
"status": "IN_PROGRESS",
|
|
1159
|
+
"phase": "PREPROCESS",
|
|
1160
|
+
"progress": 25,
|
|
1161
|
+
"sourceType": "SYSTEM",
|
|
1162
|
+
"report": {
|
|
1163
|
+
"message": "发现节目格式问题,正在尝试修复...",
|
|
1164
|
+
"level": "WARNING",
|
|
1165
|
+
"code": "FORMAT_ISSUE_DETECTED",
|
|
1166
|
+
"data": {
|
|
1167
|
+
"issue": "invalid_resolution",
|
|
1168
|
+
"expected": "1920x1080",
|
|
1169
|
+
"actual": "1920x1088",
|
|
1170
|
+
"action": "auto_crop"
|
|
1171
|
+
}
|
|
1172
|
+
},
|
|
1173
|
+
"timestamp": "2024-01-20T10:01:35Z",
|
|
1174
|
+
"version": "1.0"
|
|
1175
|
+
}
|
|
1176
|
+
```
|
|
1177
|
+
|
|
1178
|
+
#### 阶段4:创建帧(包含设备读取)
|
|
1179
|
+
```json
|
|
1180
|
+
{
|
|
1181
|
+
"type": "PROGRESS_UPDATE",
|
|
1182
|
+
"requestRef": "prog-upload-001",
|
|
1183
|
+
"status": "IN_PROGRESS",
|
|
1184
|
+
"phase": "FRAMES",
|
|
1185
|
+
"progress": 40,
|
|
1186
|
+
"sourceType": "COMMAND",
|
|
1187
|
+
"report": {
|
|
1188
|
+
"level": "INFO",
|
|
1189
|
+
"message": "正在读取设备配置..."
|
|
1190
|
+
},
|
|
1191
|
+
"context": {
|
|
1192
|
+
"taskId": "1234567890123456789",
|
|
1193
|
+
"programId": "1234567890123456788",
|
|
1194
|
+
"programName": "春节活动广告",
|
|
1195
|
+
"programNumber": 3,
|
|
1196
|
+
"programType": "DYNAMIC"
|
|
1197
|
+
},
|
|
1198
|
+
"command": {
|
|
1199
|
+
"commandType": "SIMPLE",
|
|
1200
|
+
"commandCode": "READ_DISPLAY_CONFIG",
|
|
1201
|
+
"deviceType": "display",
|
|
1202
|
+
"deviceId": 1,
|
|
1203
|
+
"operationType": "READ",
|
|
1204
|
+
"result": {
|
|
1205
|
+
"resolution": "1920x1080",
|
|
1206
|
+
"colorDepth": 24,
|
|
1207
|
+
"refreshRate": 60
|
|
1208
|
+
}
|
|
1209
|
+
},
|
|
1210
|
+
"timestamp": "2024-01-20T10:02:00Z",
|
|
1211
|
+
"version": "1.0"
|
|
1212
|
+
}
|
|
1213
|
+
```
|
|
1214
|
+
|
|
1215
|
+
#### 阶段5:上传到设备(包含设备写入)
|
|
1216
|
+
```json
|
|
1217
|
+
{
|
|
1218
|
+
"type": "PROGRESS_UPDATE",
|
|
1219
|
+
"requestRef": "prog-upload-001",
|
|
1220
|
+
"status": "IN_PROGRESS",
|
|
1221
|
+
"phase": "UPLOAD",
|
|
1222
|
+
"progress": 60,
|
|
1223
|
+
"sourceType": "COMMAND",
|
|
1224
|
+
"report": {
|
|
1225
|
+
"level": "INFO",
|
|
1226
|
+
"message": "正在写入节目数据到设备..."
|
|
1227
|
+
},
|
|
1228
|
+
"command": {
|
|
1229
|
+
"commandType": "SIMPLE",
|
|
1230
|
+
"commandCode": "WRITE_PROGRAM_DATA",
|
|
1231
|
+
"deviceType": "storage",
|
|
1232
|
+
"deviceId": 1,
|
|
1233
|
+
"operationType": "WRITE",
|
|
1234
|
+
"result": {
|
|
1235
|
+
"blocksWritten": 512,
|
|
1236
|
+
"totalBlocks": 1024,
|
|
1237
|
+
"writeSpeed": "10MB/s"
|
|
1238
|
+
}
|
|
1239
|
+
},
|
|
1240
|
+
"timestamp": "2024-01-20T10:03:00Z",
|
|
1241
|
+
"version": "1.0"
|
|
1242
|
+
}
|
|
1243
|
+
```
|
|
1244
|
+
|
|
1245
|
+
#### 阶段6:统计信息
|
|
1246
|
+
```json
|
|
1247
|
+
{
|
|
1248
|
+
"type": "PROGRESS_UPDATE",
|
|
1249
|
+
"requestRef": "prog-upload-001",
|
|
1250
|
+
"status": "COMPLETED",
|
|
1251
|
+
"phase": "STATS",
|
|
1252
|
+
"progress": 100,
|
|
1253
|
+
"sourceType": "COMMAND",
|
|
1254
|
+
"report": {
|
|
1255
|
+
"level": "INFO",
|
|
1256
|
+
"message": "节目上传完成"
|
|
1257
|
+
},
|
|
1258
|
+
"command": {
|
|
1259
|
+
"commandType": "SIMPLE",
|
|
1260
|
+
"commandCode": "FINALIZE_PROGRAM",
|
|
1261
|
+
"deviceType": "controller",
|
|
1262
|
+
"deviceId": 1,
|
|
1263
|
+
"operationType": "WRITE",
|
|
1264
|
+
"result": {
|
|
1265
|
+
"programId": "1234567890123456788",
|
|
1266
|
+
"programNumber": 1,
|
|
1267
|
+
"totalFrames": 7200,
|
|
1268
|
+
"checksum": "a1b2c3d4e5f6..."
|
|
1269
|
+
}
|
|
1270
|
+
},
|
|
1271
|
+
"report": {
|
|
1272
|
+
"level": "INFO",
|
|
1273
|
+
"code": "UPLOAD_STATS",
|
|
1274
|
+
"data": {
|
|
1275
|
+
"totalTime": 240,
|
|
1276
|
+
"downloadTime": 60,
|
|
1277
|
+
"processTime": 120,
|
|
1278
|
+
"uploadTime": 60,
|
|
1279
|
+
"averageSpeed": "218KB/s",
|
|
1280
|
+
"peakMemoryUsage": "256MB"
|
|
1281
|
+
}
|
|
1282
|
+
},
|
|
1283
|
+
"timestamp": "2024-01-20T10:04:00Z",
|
|
1284
|
+
"version": "1.0"
|
|
1285
|
+
}
|
|
1286
|
+
```
|
|
1287
|
+
|
|
1288
|
+
### 10.3 最终响应
|
|
1289
|
+
```json
|
|
1290
|
+
{
|
|
1291
|
+
"type": "PROGRAM_RESPONSE",
|
|
1292
|
+
"requestRef": "prog-upload-001",
|
|
1293
|
+
"status": "COMPLETED",
|
|
1294
|
+
"context": {
|
|
1295
|
+
"taskId": "1234567890123456789",
|
|
1296
|
+
"programId": "1234567890123456788",
|
|
1297
|
+
"programName": "春节活动广告",
|
|
1298
|
+
"programNumber": 3,
|
|
1299
|
+
"programType": "DYNAMIC"
|
|
1300
|
+
},
|
|
1301
|
+
"report": {
|
|
1302
|
+
"level": "INFO",
|
|
1303
|
+
"message": "程序上传成功"
|
|
1304
|
+
},
|
|
1305
|
+
"executionTime": 240000,
|
|
1306
|
+
"timestamp": "2024-01-20T10:04:01Z",
|
|
1307
|
+
"version": "1.0"
|
|
1308
|
+
}
|
|
1309
|
+
```
|
|
1310
|
+
|
|
1311
|
+
#### 失败响应示例
|
|
1312
|
+
```json
|
|
1313
|
+
{
|
|
1314
|
+
"type": "PROGRAM_RESPONSE",
|
|
1315
|
+
"requestRef": "prog-upload-002",
|
|
1316
|
+
"status": "FAILED",
|
|
1317
|
+
"context": {
|
|
1318
|
+
"taskId": "1234567890123456789",
|
|
1319
|
+
"programId": "1234567890123456788",
|
|
1320
|
+
"programName": "春节活动广告",
|
|
1321
|
+
"programNumber": 3,
|
|
1322
|
+
"programType": "DYNAMIC"
|
|
1323
|
+
},
|
|
1324
|
+
"report": {
|
|
1325
|
+
"level": "ERROR",
|
|
1326
|
+
"message": "设备存储空间不足",
|
|
1327
|
+
"code": "INSUFFICIENT_STORAGE",
|
|
1328
|
+
"data": {
|
|
1329
|
+
"availableSpace": 10485760,
|
|
1330
|
+
"requiredSpace": 52428800,
|
|
1331
|
+
"retryable": false
|
|
1332
|
+
}
|
|
1333
|
+
},
|
|
1334
|
+
"executionTime": 180000,
|
|
1335
|
+
"timestamp": "2024-01-20T10:03:00Z",
|
|
1336
|
+
"version": "1.0"
|
|
1337
|
+
}
|
|
1338
|
+
```
|
|
1339
|
+
|
|
1340
|
+
### 10.4 错误状态示例
|
|
1341
|
+
|
|
1342
|
+
#### 暂停状态
|
|
1343
|
+
```json
|
|
1344
|
+
{
|
|
1345
|
+
"type": "PROGRESS_UPDATE",
|
|
1346
|
+
"requestRef": "prog-upload-001",
|
|
1347
|
+
"status": "PAUSED",
|
|
1348
|
+
"phase": "UPLOAD",
|
|
1349
|
+
"progress": 75,
|
|
1350
|
+
"sourceType": "SYSTEM",
|
|
1351
|
+
"report": {
|
|
1352
|
+
"level": "WARNING",
|
|
1353
|
+
"message": "程序上传已暂停"
|
|
1354
|
+
},
|
|
1355
|
+
"timestamp": "2024-01-20T10:03:30Z",
|
|
1356
|
+
"version": "1.0"
|
|
1357
|
+
}
|
|
1358
|
+
```
|
|
1359
|
+
|
|
1360
|
+
#### 失败状态
|
|
1361
|
+
```json
|
|
1362
|
+
{
|
|
1363
|
+
"type": "PROGRESS_UPDATE",
|
|
1364
|
+
"requestRef": "prog-upload-001",
|
|
1365
|
+
"status": "FAILED",
|
|
1366
|
+
"phase": "UPLOAD",
|
|
1367
|
+
"progress": 75,
|
|
1368
|
+
"sourceType": "COMMAND",
|
|
1369
|
+
"report": {
|
|
1370
|
+
"level": "ERROR",
|
|
1371
|
+
"message": "设备写入失败:内存空间不足",
|
|
1372
|
+
"code": "DEVICE_WRITE_ERROR"
|
|
1373
|
+
},
|
|
1374
|
+
"command": {
|
|
1375
|
+
"commandType": "SIMPLE",
|
|
1376
|
+
"commandCode": "WRITE_MEMORY",
|
|
1377
|
+
"deviceType": "storage",
|
|
1378
|
+
"deviceId": 1,
|
|
1379
|
+
"operationType": "WRITE",
|
|
1380
|
+
"result": {
|
|
1381
|
+
"Uerror": "INSUFFICIENT_SPACE",
|
|
1382
|
+
"availableSpace": 512,
|
|
1383
|
+
"requiredSpace": 2048
|
|
1384
|
+
}
|
|
1385
|
+
},
|
|
1386
|
+
"report": {
|
|
1387
|
+
"level": "ERROR",
|
|
1388
|
+
"code": "DEVICE_WRITE_ERROR",
|
|
1389
|
+
"data": {
|
|
1390
|
+
"retryCount": 3,
|
|
1391
|
+
"lastAttempt": "2024-01-20T10:01:58Z"
|
|
1392
|
+
}
|
|
1393
|
+
},
|
|
1394
|
+
"timestamp": "2024-01-20T10:02:00Z",
|
|
1395
|
+
"version": "1.0"
|
|
1396
|
+
}
|
|
1397
|
+
```
|
|
1398
|
+
|
|
1399
|
+
#### 取消状态
|
|
1400
|
+
```json
|
|
1401
|
+
{
|
|
1402
|
+
"type": "PROGRESS_UPDATE",
|
|
1403
|
+
"requestRef": "prog-upload-001",
|
|
1404
|
+
"status": "CANCELLED",
|
|
1405
|
+
"phase": "DOWNLOAD",
|
|
1406
|
+
"progress": 30,
|
|
1407
|
+
"sourceType": "SYSTEM",
|
|
1408
|
+
"report": {
|
|
1409
|
+
"level": "WARNING",
|
|
1410
|
+
"message": "用户取消了程序上传"
|
|
1411
|
+
},
|
|
1412
|
+
"timestamp": "2024-01-20T10:00:45Z",
|
|
1413
|
+
"version": "1.0"
|
|
1414
|
+
}
|
|
1415
|
+
```
|
|
1416
|
+
|
|
1417
|
+
## 11. 协议版本
|
|
1418
|
+
|
|
1419
|
+
当前协议版本为 `1.0`。所有消息都必须包含 `version` 字段。
|
|
1420
|
+
|
|
1421
|
+
## 12. 附录:命令代码参考
|
|
1422
|
+
|
|
1423
|
+
### 通用命令
|
|
1424
|
+
- `PING` - 连通性测试
|
|
1425
|
+
- `GET_INFO` - 获取设备信息
|
|
1426
|
+
|
|
1427
|
+
### 强类型命令(C# 模型定义)
|
|
1428
|
+
- `LedSwitch` - LED 开关控制
|
|
1429
|
+
- `BlockPlay` - 区块播放控制
|
|
1430
|
+
- `HealthCheck` - 健康检查
|
|
1431
|
+
- `MeterEnergy` - 能耗计量
|
|
1432
|
+
- `PowerSwitch` - 电源开关
|
|
1433
|
+
- `ProgramBrightness` - 亮度调节
|
|
1434
|
+
- `SpeedCorrection` - 速度校正
|
|
1435
|
+
- `TimeSynchronization` - 时间同步
|
|
1436
|
+
- 更多命令参见 C# 模型项目
|
|
1437
|
+
- `GET_STATUS` - 获取设备状态
|
|
1438
|
+
- `RESET` - 重置设备
|
|
1439
|
+
|
|
1440
|
+
### 控制命令
|
|
1441
|
+
- `START` - 启动
|
|
1442
|
+
- `STOP` - 停止
|
|
1443
|
+
- `PAUSE` - 暂停
|
|
1444
|
+
- `RESUME` - 恢复
|
|
1445
|
+
|
|
1446
|
+
### 配置命令
|
|
1447
|
+
- `GET_CONFIG` - 读取配置
|
|
1448
|
+
- `SET_CONFIG` - 设置配置
|
|
1449
|
+
- `SAVE_CONFIG` - 保存配置
|
|
1450
|
+
- `RESTORE_CONFIG` - 恢复配置
|
|
1451
|
+
|
|
1452
|
+
### 数据命令
|
|
1453
|
+
- `READ_REGISTER` - 读取寄存器
|
|
1454
|
+
- `WRITE_REGISTER` - 写入寄存器
|
|
1455
|
+
- `READ_MEMORY` - 读取内存
|
|
1456
|
+
- `WRITE_MEMORY` - 写入内存
|
|
1457
|
+
|
|
1458
|
+
### 程序命令
|
|
1459
|
+
- `UPLOAD_PROGRAM` - 上传程序
|
|
1460
|
+
- `VERIFY_PROGRAM` - 验证程序
|
|
1461
|
+
- `ACTIVATE_PROGRAM` - 激活程序
|
|
1462
|
+
- `DELETE_PROGRAM` - 删除程序
|
|
1463
|
+
|
|
1464
|
+
---
|
|
1465
|
+
|
|
1466
|
+
*本规范为 JRSoft Subway 项目的核心协议定义,所有组件实现必须遵循此规范。*
|