本文档描述 EdgeWeb 对外提供的 HTTP 接口。默认服务地址为:
http://<设备地址>:8080
实际监听地址、端口、令牌和 TLS 配置由 EdgeWeb 配置决定。
1. 通用约定
1.1 API 前缀
业务接口统一使用:
/api/v1
EdgeWeb 控制台静态页面不使用该前缀。
1.2 JSON 响应结构
REST 接口统一返回 JSON:
{
"code": 0,
"message": "ok",
"data": {}
}
code = 0表示请求成功。code != 0表示请求失败。- 客户端应同时检查 HTTP 状态码和
code。 - HTTP 200 不应作为唯一的业务成功判断依据。
1.3 认证
除健康检查和静态页面外,接口需要只读令牌或控制令牌。
推荐使用 Bearer Token:
Authorization: Bearer <token>
也可以使用:
X-API-Token: <token>
权限说明:
| 权限 | 能力 |
|---|---|
| Public | 无需令牌 |
| Read | 只读令牌或控制令牌均可调用 |
| Control | 仅控制令牌可调用 |
未配置任何令牌时,仅静态页面和健康检查可用。
1.4 POST 请求
POST 接口必须指定:
Content-Type: application/json
控制类请求建议携带唯一的幂等键:
Idempotency-Key: <unique-printable-ascii-key>
要求:
- 最大长度为 128 个字符。
- 只能包含可打印 ASCII 字符。
- 相同幂等键和相同请求体会返回已有操作结果。
- 相同幂等键用于不同请求体时返回 HTTP 409。
1.5 分页
告警和历史接口采用从 1 开始的页码:
page=1&pageSize=30
page最小值为 1。pageSize允许范围为 1~100。
1.6 CORS
需要跨域访问时,应配置一个精确的可信来源。不支持使用 *。同源访问 EdgeWeb 控制台时不需要配置 CORS。
2. 接口总览
| 方法 | 路径 | 权限 | 用途 |
|---|---|---|---|
| GET | / |
Public | EdgeWeb 控制台首页 |
| GET | /styles.css |
Public | 控制台样式 |
| GET | /app.js |
Public | 控制台脚本 |
| GET | /pages/* |
Public | 控制台静态资源 |
| GET | /api/v1/health |
Public | 服务健康检查 |
| GET | /api/v1/reports/stream |
Read | 实时 SSE 数据流 |
| GET | /api/v1/devices |
Read | 设备列表快照 |
| GET | /api/v1/device/points |
Read | 设备点位及当前值 |
| GET | /api/v1/device/datas |
Read | 设备点位及当前值,兼容路径 |
| GET | /api/v1/device/state |
Read | 设备状态 |
| GET | /api/v1/device/cycle-self |
Read | 设备自循环状态 |
| GET | /api/v1/device/data |
Read | 单点当前值 |
| POST | /api/v1/device/data/query |
Read | 批量查询当前值 |
| POST | /api/v1/device/read |
Control | 请求设备读取点位 |
| POST | /api/v1/device/write |
Control | 写入单设备点位或批量写入单设备点位 |
| POST | /api/v1/device/write-multi |
Control | 跨设备批量写入 |
| POST | /api/v1/device/control |
Control | 下发设备控制命令 |
| GET | /api/v1/operations/status |
Control | 查询异步操作状态 |
| GET | /api/v1/alarms |
Read | 查询当前或历史告警 |
| POST | /api/v1/alarms/confirm |
Control | 确认告警 |
| GET | /api/v1/history/devices |
Read | 查询已配置历史记录的设备 |
| GET | /api/v1/history |
Read | 查询设备历史数据 |
| POST | /api/v1/channels/control |
Control | 启动或停止通信通道 |
3. 健康检查
GET /api/v1/health
无需认证。
成功响应:
{
"code": 0,
"message": "ok",
"data": {
"service": "edgeweb",
"version": "v1",
"readAccessConfigured": true,
"controlAccessConfigured": true,
"tlsConfigured": false
}
}
4. 设备接口
4.1 设备列表
GET /api/v1/devices
返回当前配置的设备快照及设备状态。
响应数据中的设备对象包含以下常用字段:
| 字段 | 类型 | 说明 |
|---|---|---|
deviceId |
uint32 | 设备 ID |
name |
string | 设备名称 |
address |
string | 设备地址 |
deviceType |
number | 设备类型 |
type |
number | 兼容字段,值与 deviceType 相同 |
ports |
string\[\] | 设备关联通道名称 |
protocols |
number\[\] | 各关联通道的协议类型 |
channelStates |
number\[\] | 各关联通道的当前状态 |
linkModes |
number\[\] | 各关联通道的连接模式 |
bindMasterMode |
number | 主从绑定模式 |
bindMasterId |
uint32 | 绑定主设备 ID |
pollInterval |
number | 轮询间隔 |
cmdBufferTime |
number | 命令缓冲时间 |
batchReadBegin |
number | 批量读取起始配置 |
state |
number | 设备运行状态 |
dataCount |
number | 已配置点位数量,可能不存在 |
响应示例:
{
"code": 0,
"message": "ok",
"data": {
"updatedAt": 1784196000000,
"items": [
{
"deviceId": 1,
"name": "NET001-001",
"address": "1",
"deviceType": 10,
"type": 10,
"ports": ["NET001"],
"protocols": [1],
"channelStates": [1],
"linkModes": [0],
"state": 1,
"dataCount": 5
}
],
"devices": [
{
"deviceId": 1,
"name": "NET001-001",
"address": "1",
"deviceType": 10,
"type": 10,
"ports": ["NET001"],
"protocols": [1],
"channelStates": [1],
"linkModes": [0],
"state": 1,
"dataCount": 5
}
]
}
}
devices 是兼容字段,内容与 items 相同。客户端新接入时应优先使用 items。
设备状态值:
| 值 | 含义 |
|---|---|
| 0 | 未运行或空状态 |
| 1 | 正常运行 |
| 2 | 运行错误 |
| 3 | 手动停止 |
| 4 | 链路错误停止 |
| 5 | 轮询运行 |
4.2 设备点位列表
GET /api/v1/device/points?deviceId=1
返回指定设备的全部配置点位和当前缓存值。/api/v1/device/datas 是兼容路径,响应相同。
参数:
| 参数 | 必填 | 类型 | 说明 |
|---|---|---|---|
deviceId |
是 | uint32 | 设备 ID |
点位对象包含以下常用字段:
| 字段 | 类型 | 说明 |
|---|---|---|
dataId |
uint32 | 点位 ID |
name |
string | 点位名称 |
value |
string | 当前缓存值 |
unit |
string | 单位 |
range |
string | 量程或取值范围 |
showType |
number | 显示类型 |
tagColor |
string | 标签颜色 |
cmdValue |
string | 控制值配置 |
enumOptions |
array | 枚举选项,包含 value 和 name |
响应示例:
{
"code": 0,
"message": "ok",
"data": {
"deviceId": 1,
"items": [
{
"dataId": 1,
"name": "温度",
"value": "25.6",
"unit": "℃",
"range": "0~100",
"showType": 0,
"enumOptions": []
}
],
"datas": [
{
"dataId": 1,
"name": "温度",
"value": "25.6",
"unit": "℃",
"range": "0~100",
"showType": 0,
"enumOptions": []
}
]
}
}
datas 是兼容字段,内容与 items 相同。客户端新接入时应优先使用 items。
4.3 设备状态
GET /api/v1/device/state?deviceId=1
参数:
| 参数 | 必填 | 类型 | 说明 |
|---|---|---|---|
deviceId |
是 | uint32 | 设备 ID |
{
"code": 0,
"message": "ok",
"data": {
"deviceId": 1,
"state": 1
}
}
4.4 自循环状态
GET /api/v1/device/cycle-self?deviceId=1
参数:
| 参数 | 必填 | 类型 | 说明 |
|---|---|---|---|
deviceId |
是 | uint32 | 设备 ID |
{
"code": 0,
"message": "ok",
"data": {
"deviceId": 1,
"cycling": true
}
}
4.5 单点当前值
GET /api/v1/device/data?deviceId=1&dataId=10
参数:
| 参数 | 必填 | 类型 | 说明 |
|---|---|---|---|
deviceId |
是 | uint32 | 设备 ID |
dataId |
是 | uint32 | 点位 ID |
{
"code": 0,
"message": "ok",
"data": {
"deviceId": 1,
"dataId": 10,
"value": "25.6"
}
}
4.6 批量查询当前值
POST /api/v1/device/data/query
该接口只读取缓存值,使用 Read 权限。
请求体:
{
"items": [
{"deviceId": 1, "dataId": 10},
{"deviceId": 2, "dataId": 20}
]
}
响应:
{
"code": 0,
"message": "ok",
"data": {
"items": [
{"deviceId": 1, "dataId": 10, "value": "25.6"},
{"deviceId": 2, "dataId": 20, "value": "100"}
]
}
}
批量数量不能超过服务端配置的上限。
4.7 请求设备读取
POST /api/v1/device/read
该接口会向设备下发读取请求,需要 Control 权限。
请求体:
{
"deviceId": 1,
"dataIds": [10, 11, 12]
}
成功响应:
{
"code": 0,
"message": "ok",
"data": {
"operationId": "123",
"status": "succeeded",
"result": "OK"
}
}
4.8 写入单点
POST /api/v1/device/write
请求体:
{
"deviceId": 1,
"dataId": 10,
"value": "30"
}
浏览器示例:
const response = await fetch("/api/v1/device/write", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Token": controlToken,
"Idempotency-Key": crypto.randomUUID()
},
body: JSON.stringify({ deviceId: 1, dataId: 10, value: "30" })
});
const result = await response.json();
if (!response.ok || result.code !== 0) {
throw new Error(result.message);
}
4.9 单设备批量写入
POST /api/v1/device/write
请求体:
{
"deviceId": 1,
"datas": [
{"dataId": 10, "value": "30"},
{"dataId": 11, "value": "1"}
]
}
4.10 跨设备批量写入
POST /api/v1/device/write-multi
请求体:
{
"datas": [
{"deviceId": 1, "dataId": 10, "value": "30"},
{"deviceId": 2, "dataId": 20, "value": "100"}
]
}
响应会包含每个设备的执行结果:
{
"code": 0,
"message": "ok",
"data": {
"operationId": "123",
"status": "succeeded",
"results": [
{"deviceId": 1, "succeeded": true, "result": "OK"},
{"deviceId": 2, "succeeded": true, "result": "OK"}
]
}
}
4.11 设备控制
POST /api/v1/device/control
请求体:
{
"deviceId": 1,
"cmdType": 1
}
cmdType 为当前 MThings 版本定义的设备控制命令编号。外部客户端应以目标版本公开的命令编号为准,不要跨版本假设编号含义。
成功响应:
{
"code": 0,
"message": "accepted",
"data": {
"operationId": "123",
"status": "succeeded",
"accepted": true
}
}
5. 操作状态
设备读取、写入、控制、告警确认和通道控制由服务端串行执行。响应数据会包含:
{
"operationId": "123",
"status": "succeeded"
}
可能的状态:
| 状态 | 说明 |
|---|---|
pending |
等待执行 |
accepted |
命令已接受 |
succeeded |
执行成功 |
failed |
执行失败 |
cancelled |
执行前连接已断开 |
GET /api/v1/operations/status?operationId=123
该接口需要 Control 权限。
请求超时时,如果响应中包含:
{
"operationId": "123",
"outcomeUnknown": true
}
不要直接重试控制类请求,应先查询操作状态,避免重复控制设备或通道。
6. 实时事件流
GET /api/v1/reports/stream
使用 Server-Sent Events(SSE)持续推送设备和通道变化。
可选过滤参数可以重复出现:
/api/v1/reports/stream?deviceId=1&deviceId=2&event=device-data&event=device-state
支持的事件:
| SSE 事件名 | 内容 |
|---|---|
device-data |
单设备实时数据 |
device-state |
单设备状态变化 |
curve-data |
曲线数据 |
self-data |
自定义循环数据 |
multi-device-data |
多设备数据 |
device-list |
设备清单发生变化,客户端应重新获取 /api/v1/devices |
channel-state |
通道状态变化 |
stream-reset |
请求的历史事件已不在缓存中,应重新获取完整快照 |
device-data 示例:
id: 101
event: device-data
data: {"code":0,"message":"ok","data":{"deviceId":1,"datas":[{"dataId":10,"offset":0,"value":"25.6"}]}}
channel-state 示例:
id: 102
event: channel-state
data: {"code":0,"message":"ok","data":{"channel":"NET001","state":1,"time":1784196000000}}
浏览器原生 EventSource 不能设置认证请求头,因此应使用 fetch 流式读取:
const response = await fetch("/api/v1/reports/stream", {
headers: { "X-API-Token": readToken }
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { value, done } = await reader.read();
if (done) break;
const text = decoder.decode(value, { stream: true });
// 按空行拆分 SSE 消息,并解析 event/data 字段。
}
服务端会定期发送心跳注释。客户端重连时可以发送:
Last-Event-ID: 101
服务端会尝试从有限的事件缓存中重放后续事件。
7. 告警接口
7.1 查询告警
GET /api/v1/alarms
查询当前告警或历史告警。
参数:
| 参数 | 必填 | 默认值 | 说明 |
|---|---|---|---|
scope |
否 | active |
active 或 history |
page |
否 | 1 |
页码 |
pageSize |
否 | 30 |
每页数量,最大 100 |
响应:
{
"code": 0,
"message": "ok",
"data": {
"page": 1,
"pageSize": 30,
"total": 1,
"pageCount": 1,
"items": [
{
"alarmId": 1,
"name": "温度过高",
"type": "温度",
"level": 0,
"triggered": true,
"confirmed": false,
"triggerTime": "2026-07-16 10:00:00",
"confirmTime": "",
"recoverTime": "",
"snapshot": "温度=86.4"
}
]
}
}
告警级别:
| 值 | 含义 |
|---|---|
| 0 | 严重告警 |
| 1 | 一般告警 |
| 2 | 提示告警 |
7.2 确认告警
POST /api/v1/alarms/confirm
该接口需要 Control 权限。
请求体:
{
"alarmId": 1
}
成功响应:
{
"code": 0,
"message": "ok",
"data": {
"operationId": "123",
"status": "succeeded",
"alarmId": 1,
"confirmed": true
}
}
8. 历史数据接口
8.1 历史设备列表
GET /api/v1/history/devices
仅返回已配置历史记录点位的设备。
{
"code": 0,
"message": "ok",
"data": {
"items": [
{
"deviceId": 1,
"name": "NET001-001",
"pointCount": 5
}
]
}
}
8.2 查询历史数据
GET /api/v1/history
参数:
| 参数 | 必填 | 格式/默认值 | 说明 |
|---|---|---|---|
deviceId |
是 | uint32 | 设备 ID |
date |
是 | yyyyMMdd |
数据日期 |
startTime |
否 | HH:mm:ss |
开始时间 |
endTime |
否 | HH:mm:ss |
结束时间 |
page |
否 | 1 |
页码 |
pageSize |
否 | 30 |
每页数量,最大 100 |
startTime 和 endTime 必须同时提供。
响应中的列由设备当日历史数据动态决定:
{
"code": 0,
"message": "ok",
"data": {
"page": 1,
"pageSize": 30,
"total": 2,
"pageCount": 1,
"columns": [
{"field": "id", "name": "ID"},
{"field": "dtime", "name": "Date Time"},
{"field": "D_10", "dataId": 10, "name": "温度"}
],
"rows": [
["2", "2026-07-16 10:00:10", "25.7"],
["1", "2026-07-16 10:00:00", "25.6"]
],
"summary": [
{
"dataId": 10,
"name": "温度",
"max": "25.7",
"min": "25.6",
"average": "25.65"
}
]
}
}
注意:
rows中的值与columns位置一一对应。summary按全部筛选结果计算,不只统计当前页。- 指定日期没有历史数据时返回失败,不会创建空数据。
9. 通道接口
POST /api/v1/channels/control
启动或停止通信通道。该接口需要 Control 权限。
请求体:
{
"channel": "NET001",
"action": "launch"
}
action 允许值:
| 值 | 含义 |
|---|---|
launch |
启动通道 |
stop |
停止通道 |
成功响应:
{
"code": 0,
"message": "ok",
"data": {
"operationId": "123",
"status": "succeeded",
"channel": "NET001",
"action": "launch"
}
}
10. 静态页面
GET /
返回 EdgeWeb 控制台首页。
同时支持:
GET /styles.css
GET /app.js
GET /pages/<relative-path>
静态资源使用 Cache-Control: no-cache,并设置 Content Security Policy。
11. 常见错误
| HTTP 状态 | 常见原因 |
|---|---|
| 400 | 参数缺失、格式错误、批量数量超限 |
| 401 | 未提供令牌 |
| 403 | 令牌错误或权限不足 |
| 404 | 路由或操作记录不存在 |
| 409 | 设备或通道操作失败、幂等键冲突 |
| 411 | POST 未提供 Content-Length |
| 413 | 请求体超过限制 |
| 415 | POST 不是 application/json |
| 417 | 不支持 Expect 请求头 |
| 431 | 请求头超过限制 |
| 503 | 连接数或请求队列已满 |
| 504 | 设备请求超时 |
常见业务错误码:
| 错误码 | 说明 |
|---|---|
| 1001~1009 | HTTP 解析、大小和超时错误 |
| 2001 | 请求参数无效 |
| 2002 | 未认证 |
| 2003 | 无权限 |
| 2004 | 路由不存在 |
| 2005 | 服务繁忙 |
| 2006 | 设备或通道操作失败 |
| 2007 | 操作记录不存在 |
| 2008 | 幂等键无效或冲突 |
| 2009 | SSE 历史不可用 |
12. 推荐调用流程
EdgeWeb 或移动客户端推荐按以下顺序接入:
- 调用
/api/v1/health检查服务和权限配置。 - 使用只读令牌调用
/api/v1/devices获取设备完整快照。 - 选择设备后调用
/api/v1/device/points获取点位结构和初值。 - 连接
/api/v1/reports/stream,增量更新设备状态、通道状态和实时值。 - 收到
device-list时重新获取设备和当前点位快照。 - 控制类操作使用控制令牌和唯一
Idempotency-Key。 - 控制类操作超时且结果未知时,先通过
/api/v1/operations/status查询。 - 告警和历史数据使用服务端分页,避免一次请求大量记录。