Appearance
4. 接口参考
本章按功能分组给出 DASS2 的 HTTP 接口契约。所有接口:
- BaseURL:
http://<设备地址>:8085 - 路径前缀:
/v1 - 鉴权:除标注「免认证」者外,均需携带
beegosessionID+ 同名用户 Cookie(见 2.3) - 响应:统一信封
{"code","msg","count","data"},成功为code:0+msg:"ok"(见 2.2)
4.0 分组总览
| 组 | 主题 | 前缀 | 本章 |
|---|---|---|---|
| 1 | 登录与鉴权 | /v1/login /v1/logout /v1/isLogin /v1/lang /v1/setLang | 4.1 |
| 2 | 采集服务管理 | /v1/das/* | 4.2 |
| 3 | 驱动管理 | /v1/driver/* | 4.3 |
| 4 | 采集测点 | /v1/point/* | 4.4 |
| 5 | 上传点 | /v1/upoint/* | 4.5 |
| 6 | 系统信息与资源 | /v1/baseInfo /v1/resource /v1/flow /v1/mqtt/* /v1/system/license | 4.6 |
| 7 | 实时与历史数据 | /v1/calcModel/* /v1/opconsole/* | 4.7 |
| 8 | 系统运维 | /v1/system/* | 4.8 |
编排约定:核心链路接口给出完整字段表与示例;次要接口给出字段表与响应结构;纯管理界面用途的接口合并为表格列出,但保证路径完整。
【警告】标注 ⚠️破坏性 的接口会删除数据或中断业务,执行前请阅读 7.6。
4.1 登录与鉴权
4.1.1 POST /v1/login — 登录
| 项 | 值 |
|---|---|
| 实现 | MainController.Login(controllers/default.go:74) |
| 路由 | beego.Router("/v1/login/", &controllers.MainController{}, "*:Login") |
| 鉴权 | 免认证(URL 含 login) |
| Content-Type | application/x-www-form-urlencoded |
请求字段:
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
username | form | string | 是 | 用户名。前后空格会被 trim |
password | form | string | 是 | md5(明文) 的小写 hex,32 位 |
响应字段:
| 字段 | 类型 | 说明 |
|---|---|---|
code | int | 0 成功;-1 失败 |
msg | string | "ok" / "error" |
count | int | 恒为 0,不要拿来判成功 |
data.User | object | 用户对象(Password 被清空,含 Menus 菜单树) |
data.IsFirst | bool | 是否首次启动 |
响应头下发 3 个 Cookie(beegosessionID / lang / <用户名>),见 2.3.2。
失败情况:
| 场景 | 响应 |
|---|---|
| 用户名或密码为空 | {"code":-1,"count":0,"data":"只允许POST方法","msg":"error"}(实测:非 POST 时)。空值走密码错误的同分支 |
| 密码错误 | {"code":-1,"count":0,"data":"账号或密码错误","msg":"error"} |
| 非 POST 方法 | {"code":-1,"count":0,"data":"只允许POST方法","msg":"error"} |
【注意】该方法不区分「用户不存在」「密码错」「传了明文密码」——三种情况都回同一句
账号或密码错误(有意的防枚举设计),排障时不要指望靠报错定位。
4.1.2 POST|GET /v1/logout/ — 注销
| 项 | 值 |
|---|---|
| 实现 | MainController.Logout(controllers/default.go:142) |
| 鉴权 | 免认证(URL 含 logout)——但代码里会直接取 session |
请求参数:无。
响应:成功 {"code":0,"count":1,"data":"注销成功","msg":"ok"}
【警告】未登录时调用会返回 HTTP 500(实测)。原因是
Logout()第一行就执行self.GetSession("user").(*system.User),session 为空时类型断言 panic。注销前请确保处于登录态,或容忍 500。
4.1.3 GET /v1/isLogin/ — 判断登录态
| 项 | 值 |
|---|---|
| 实现 | MainController.IsLogin(controllers/default.go:153) |
| 鉴权 | 需认证("isLogin" 含大写 L,匹配不到白名单的 login) |
响应:已登录 {"code":0,"count":1,"data":{"User":{...},"IsFirst":false},"msg":"ok"}
未登录:HTTP 302 重定向到 /(不是 401,也不是 JSON)。
【注意】该接口可用于「轻量探测登录态 + 拿菜单树」,但必须处理 302。
4.1.4 语言设置
| 方法 | 路径 | 实现 | 说明 |
|---|---|---|---|
| 任意 | /v1/lang | BaseController.Language | 返回当前语言 |
| 任意 | /v1/setLang | BaseController.SetLangVer | 设置语言并写 lang Cookie |
参数:lang(query,zh-CN / en-US)。
【警告】带有效
?lang=xx调用任意/v1接口时,Prepare会先返回 302 到去掉 query 的同一路径。用 curl 记得加-L,否则拿到的是空的重定向响应而不是业务数据。
4.2 采集服务管理(/v1/das/*)
采集服务是 DASS2 的核心对象:一条采集服务 = 一个驱动实例 + 一组配置 + 一组测点。{id} 即 2.4 所述的 dasId。
4.2.1 GET /v1/das — 查询采集服务列表
| 项 | 值 |
|---|---|
| 实现 | DasController.Get(controllers/data/das.go:57) |
| 鉴权 | 需认证 |
请求参数:
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | path | int | 否 | 指定 dasId 精确查询 |
type | query | string | 否 | 驱动名模糊匹配 |
destType | query | string | 否 | 驱动类型:das / upload |
desc | query | string | 否 | 描述模糊匹配 |
offset | query | int | 否 | 缺省时被置为 1000(注意,不是 0) |
limit | query | int | 否 | 限制条数 |
响应字段:见 2.4 的完整字段表(id / name / type / driverType / port / desc / host / isLink / nodeName / status / total / timeout)。
【注意】
offset缺省被置为1000是刻意的兜底(保证一次能捞全),但它意味着默认不分页。服务很多时请注意offset语义与 4.3 的驱动列表不一致。
4.2.2 POST /v1/das — 创建采集服务
| 项 | 值 |
|---|---|
| 实现 | DasController.Post(controllers/data/das.go:112) |
| 鉴权 | 需认证 |
| Content-Type | application/x-www-form-urlencoded |
请求字段(平铺表单,不是 JSON):
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
das_name | form | string | 是 | 服务名。必须匹配 ^[A-Za-z0-9_]+$,长度 ≤ MaxLengthServiceName(实测 11),全局唯一 |
das_desc | form | string | 是 | 服务描述,不能为空 |
driver_name | form | string | 是 | 驱动名(来自 GET /v1/driver 的 name) |
| (驱动配置字段) | form | string | 视驱动 | 其余键 = GET /v1/driver/conf/{driverId} 返回项的 key,如 node_name、isLink 等。密码类字段需 base64(AES(明文)) |
后端自动填充(不要传):web_listen_address = :<自动分配的端口>、web_path = ../www、node_name 会拼节点并转大写、isLink 缺省为 "true"。
端口分配:采集服务从 5000~7500、上传服务从 7500~10000 自动分配(与《使用手册》一致;实测实例为 5480 / 9486)。
响应:成功返回建好的服务对象(data 含 id / name / isLink / host 等)。建服务后会自动启动该服务。
失败情况:
| 场景 | data |
|---|---|
超过服务数上限(Service.MaxNumber,实测 10) | 超过服务数量限制 |
| 服务名为空 | 服务名不能为空 |
| 服务名超长 | 服务名称超过长度限制 |
| 服务名格式非法 | 服务名格式错误 |
| 服务名已存在 | 服务已存在 |
| 驱动不存在 | 驱动不存在 |
| 描述为空 | 描述信息不能为空 |
| 设备型号与授权不匹配 | 设备授权不匹配 |
【提示】建服务前必须先调
GET /v1/driver/conf/{driverId}?scope=addServer与?scope=advanced,把两段的key拼成表单字段;否则会因缺少驱动必需配置而失败。详见 4.3。
4.2.3 DELETE /v1/das/{id} — 删除采集服务 ⚠️破坏性
| 项 | 值 |
|---|---|
| 实现 | DasController.Delete(controllers/data/das.go:304) |
| 鉴权 | 需认证 |
路径参数:id = dasId。
响应:成功 {"code":0,"count":1,"data":"删除成功","msg":"ok"}
动作:删除实时库节点 → 完整删除服务文件与数据库记录 → 清内存状态 → 通知云端。
限制:W3.DATAPOINT 节点不支持删除,返回 W3.DATAPOINT节点不支持删除。
4.2.4 GET /v1/das/conf/{id} — 读取服务配置
| 项 | 值 |
|---|---|
| 实现 | DasController.GetConf(controllers/data/das.go:650) |
| 鉴权 | 需认证 |
响应(实测 count: 17):data 是配置项数组,每项字段:
| 字段 | 类型 | 说明 |
|---|---|---|
key | string | 配置项名(改配置时的表单字段名) |
value | string | 当前值。密码类为 base64(AES(明文)) |
name | string | 中文名 |
ed | string | 说明 / 取值提示 |
exScope | string | 作用域:advance / advanced |
textType | string | 控件/校验类型:select / disable / ispassword / password / 空 |
textData | string | 枚举候选,a|b|c 形式 |
driver / model / flag / id / data1 / data2 | — | 辅助字段 |
特殊分支:id == 10000 时返回云平台连接配置(services.GetMagusCloudDasConf()),不走服务查询。
失败情况:dasId 不存在时返回 {"code":0,"count":0,"data":"DAS服务配置错误…no row found","msg":"error"} —— 注意 code 是 0(见 7.2)。
4.2.5 GET /v1/das/conf/third?name={服务名} — 按服务名读配置
同 4.2.4,但用 name(query)寻址。适合按名字定位而不知道 dasId 的场景。
4.2.6 PUT /v1/das/conf/{id} — 更新服务配置
| 项 | 值 |
|---|---|
| 实现 | DasController.PutConf(controllers/data/das.go:784) |
| 鉴权 | 需认证 |
| Content-Type | application/x-www-form-urlencoded |
请求字段:平铺表单,键名 = 4.2.4 返回项的 key。其中 desc 键会同时更新服务描述。
行为:与驱动的模板配置比对,缺失的 key 自动补插;保存后自动重启该服务使配置生效。
响应:成功 {"code":0,"count":1,"data":"修改成功","msg":"ok"}
【注意】改配置会重启服务(业务会短暂中断)。批量改多个服务时注意叠加影响。
4.2.7 服务启停与重启
| 接口 | 实现 | 说明 |
|---|---|---|
POST /v1/das/stop/{id} | DasController.Stop(das.go:434) | 停止采集服务 |
POST /v1/das/boot/{id} | BootDasController.Boot(das.go:507) | 启动采集服务 |
POST /v1/das/reboot/{id} | DasController.Reboot(das.go:575) | 重启(内部 stop → 等 2 秒 → boot) |
响应:成功 {"code":0,"count":1,"data":"<中文成功文案>","msg":"ok"}
幂等反馈(是失败语义但属正常):
| 场景 | data |
|---|---|
| 服务已在运行 | 采集已经运行 |
| 服务已停止 | 采集已经停止 |
双机热备限制(见 7.21):
| 角色 | 被禁止 | 文案 |
|---|---|---|
| master | stop / reboot | 主机禁止停止服务 |
| slave | boot | 备机禁止启动服务 |
【警告】这三个路由注册为
*:方法,用 GET 访问也会真的执行(见 7.5)。
【警告】/v1/das/boot/{id}的{id}必须是数字dasId。代码里虽有按name查的分支,但路由只定义了:id,该分支不可达(见 7.17)。
4.2.8 GET /v1/das/deviceLink/{id} — 查询设备连接状态
| 项 | 值 |
|---|---|
| 实现 | DasController.GetDeviceStatus(controllers/data/das.go:1146) |
| 鉴权 | 需认证 |
响应(实测):{"code":0,"count":1,"data":true,"msg":"ok"}
data 为布尔值:true 表示该采集服务与设备的链路正常。
【注意】这个接口比列表里的
status更可信:/v1/das的status来自内存态,进程还在但链路断了时仍可能显示running。做健康检查请用本接口。
4.2.9 日志相关接口
| 方法 | 路径 | 实现 | 请求参数 | 说明 |
|---|---|---|---|---|
| 任意 | /v1/das/log/exist/{id} | LogIsExist(das.go:961) | id=dasId | 判断日志文件是否存在 |
| 任意 | /v1/das/log/{id} | DownloadLog(das.go:905) | id=dasId | 下载服务日志(文件流) |
| 任意 | /v1/das/displayLog/{id} | LogList(das.go:985) | id=dasId | 列出日志文件 |
| 任意 | /v1/das/downloadFile | DownloadLogs(das.go:946) | fileName(query) | 按文件名下载日志 |
| 任意 | /v1/das/runtime/{id} | RuntimeLog(das.go:1044) | id=dasId | 服务实时运行日志(反代到采集服务自身端口的 /sys/logs) |
POST | /v1/das/serviceLog | ServiceLog(das.go:1170) | JSON body {"sn":"<服务名>"} | 列出该服务的日志文件 |
日志清单响应:data 为文件信息数组,元素含 Name / Size / IsDir / ModTime / Mode / Dir。
【注意】
/v1/das/runtime/{id}是反向代理:DASS2 内部再请求http://127.0.0.1:<该服务端口>/sys/logs,因此它的响应结构由采集服务自己的 Web 接口决定,不受 DASS2 统一信封约束。采集服务未运行时该接口会失败。
【注意】/v1/das/serviceLog与/v1/das/conf/?:sn(POST 取配置)用的是 JSON 请求体,而/v1/das的创建/改配置用的是表单——同一前缀下 Content-Type 约定不统一。
4.2.10 POST /v1/das/conf/{sn} — 按 SN 取配置(JSON 体)
| 项 | 值 |
|---|---|
| 实现 | DasController.GetConfBySN(controllers/data/das.go:1201) |
| 请求体 | {"sn":"<服务名>"} |
| 鉴权 | 需认证 |
另有 /v1/das/conf/encrypt/{sn}(GetConfEncryptBySN,das.go:1280)——新增版本,不过滤密码加密字段。
4.2.11 其它
| 方法 | 路径 | 实现 | 说明 |
|---|---|---|---|
GET | /v1/das/app | AppGet(das.go:391) | 关键字查询(desc / offset / limit;offset 缺省 10000) |
| 任意 | /v1/das/validate/{name} | ValidateDasController.Validate(das.go:1010) | 校验服务名是否合规(建服务前预校验) |
POST | /v1/das/history/{id} | HistoryRecall(das.go:1090) | 历史回补。参数 time,格式为 开始时间 - 结束时间(用 - 分隔,两侧各一个空格) |
| 任意 | /v1/das/link | OPLinkPool(das.go:1128) | 实时库连接信息(HOST/PORT/User/Pwd/Version) |
DELETE | /v1/das/delete/{id} | DeleteLocalServer(das.go:359) | 双机热备:仅删除本机服务记录,不动实时库 |
【警告】
/v1/das/link返回实时库明文口令(Pwd),与 7.11 同类问题,不要外传响应内容。
【注意】HistoryRecall要求服务处于running状态,否则报采集已经停止,无法下发命令;time参数用固定分隔串切分,格式不合法会直接数组越界。
4.3 驱动管理(/v1/driver/*)
4.3.1 驱动是什么
驱动 = dastemplate/<驱动名>/ 下的可执行程序(或动态库)+ Version.ini 元数据 + config.csv 参数模板。
一条采集服务 = 某个驱动的可执行文件 + 一组配置参数跑起来的进程。
驱动的三个来源:
| 来源 | 说明 |
|---|---|
| 出厂内置 | 随镜像的 dastemplate/ 目录预置,不经 HTTP 接口 |
| 接口上传 | POST /v1/driver,本组唯一的写入入口 |
| 应用市场 | GET /v1/driver/appMarketURL 只返回市场地址,前端跳转过去;市场下载安装不走这三个路由 |
4.3.2 GET /v1/driver — 查询驱动列表
| 项 | 值 |
|---|---|
| 实现 | DriverController.Get(controllers/data/driver.go:44) |
| 鉴权 | 需认证 |
请求参数:
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | path | int | 否 | 驱动 ID 精确匹配。非数字按 0 处理(等价于查全部) |
type | query | string | 否 | 驱动类型模糊匹配(das / upload) |
name | query | string | 否 | 驱动名模糊匹配 |
desc | query | string | 否 | 描述模糊匹配 |
limit | query | int | 否 | 实为 SQL 的起始行偏移 |
offset | query | int | 否 | 实为 SQL 的每页条数;传 0 或缺省被强制为 20 |
响应(实测):
json
{"code":0,"count":2,"data":[
{"desc":"GB_Demo_Jenkins 更新说明:new","fileName":"GB_Demo_Jenkins.v3.0.0-beta3.20250418.arm.tar.gz",
"id":97,"isAuth":false,"name":"GB_Demo_Jenkins","protocal_version":"",
"publishTime":"2025-04-18 13:50:54","type":"das",
"uploadTime":"2017-04-18 22:33:42","version":"v3.0.0-beta3"},
{"desc":"upload mqtt。","fileName":"OP2_MQTT_JC.v3.0.5.20250925.arm.tar.gz",
"id":96,"isAuth":false,"name":"OP2_MQTT_JC","protocal_version":"",
"publishTime":"2025-08-18 11:46:14","type":"upload",
"uploadTime":"2017-04-18 22:11:40","version":"V3.0.4"}
],"msg":"ok"}| 字段 | 类型 | 说明 |
|---|---|---|
id | int | 驱动 ID,/v1/driver/conf/{id} 要用它 |
name | string | 驱动名,建服务时的 driver_name |
type | string | das=采集 / upload=上传 |
version | string | 驱动版本 |
fileName | string | 上传时的原始包名 |
desc | string | 描述 |
uploadTime / publishTime | string | 上传时间 / 发布时间 |
isAuth | bool | 恒为 false(后端 SQL 未查询该列,不是真实授权状态) |
protocal_version | string | 拼写少一个 o(应为 protocol_version),对应驱动包 Version.ini 的 commStyle |
【警告】分页参数与 SQL 语义相反(
LIMIT <limit>,<offset>):limit是"跳过几条"、offset是"取几条"。而且不带参数时offset被强制为 20 → 生成LIMIT 0,20,能查到 20 条;但?offset=0也会被改成 20。要取第 2 页请传?limit=20&offset=20。
【注意】该接口的name/type/desc会直接拼接进 SQL 的LIKE子句,未参数化(见 7.24)。
4.3.3 POST /v1/driver — 上传驱动包
| 项 | 值 |
|---|---|
| 实现 | DriverController.Post(controllers/data/driver.go:89) |
| 鉴权 | 需认证 |
| Content-Type | multipart/form-data |
请求参数:
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
driver | form(file) | file | 是 | 文件字段名固定为 driver |
响应:成功 {"code":0,"count":1,"data":"上传成功","msg":"ok"};失败 {"code":-1,"count":1,"data":"<错误文案>","msg":"error"}
包格式与内容要求:
| 项 | 要求 |
|---|---|
| 容器格式 | .tar.gz(gzip + tar),不是 zip |
| 目录结构 | dastemplate/<驱动名>/ 下必须有 Version.ini 与同名可执行文件;可选 config.csv、lib/*.so |
Version.ini 键 | name(驱动名)、type(必须 das 或 upload)、suffix、version、alias_name、description、publish_time、commStyle、platform |
platform 取值 | qualcomm / arm / linux / windows / loongson / all;校验是子串包含,all 恒通过 |
| 可执行文件后缀 | .exe / .dll / .so / .jar |
常见失败文案:
| 场景 | data |
|---|---|
| 平台不兼容 | Get driver package not compatible with platform. |
type 既非 das 也非 upload | , 请上传采集或上传驱动程序包 |
| 缺少可执行文件 | The driver executable file does not exist. |
缺少 Version.ini | can not found Version.ini. |
扩展名非 .tar.gz | 文件格式必须是tar.gz |
【警告】同名驱动上传 = 覆盖升级,无法拒绝。而且上传成功后会把所有正在使用该驱动的采集服务停掉 → 换可执行文件 → 重启,属于有业务影响的操作。
【警告】该接口还做了部署级副作用:解压落盘、重建example_conf配置模板、Linux 下把lib/*.so拷到/usr/lib/。这不是"传个文件"。
【注意】校验顺序是先解压落盘、后做业务校验——校验失败时文件已经留在磁盘上(只回滚数据库)。
4.3.4 GET /v1/driver/conf/{id} — 读取驱动配置字段(建服务前必做)
| 项 | 值 |
|---|---|
| 实现 | DriverConfController.Get(controllers/data/driver.go:185) |
| 鉴权 | 需认证 |
请求参数:
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | path | int | 是 | 驱动 ID |
scope | query | string | 否 | all(默认)/ noPoint / addServer / advanced / addPoint |
响应(实测 count: 16):data 是配置项数组,字段:id / driver / model / exScope / name / key / value / ed / flag / textType / textData / data1 / data2。
json
{"code":0,"count":16,"data":[
{"driver":"GB_Demo_Jenkins","name":"测点添加模式","key":"isLink","value":"true",
"exScope":"advanced","textType":"select","textData":"true|false"},
{"driver":"GB_Demo_Jenkins","name":"接口模式","key":"comm_mode","value":"...","textType":"select"}
],"msg":"ok"}【提示】这个数组就是"建服务请求体"的字段清单——每项的
key就是POST /v1/das的参数名,value是默认值。
建服务必须取两段拼起来:?scope=addServer+?scope=advanced。缺一段会漏字段。
【注意】textType为ispassword/password的项,value是base64(AES(明文))密文(见 7.4)。
4.3.5 DELETE /v1/driver/{ids} — 删除驱动 ⚠️破坏性
| 项 | 值 |
|---|---|
| 实现 | DriverController.Delete(controllers/data/driver.go:147) |
| 鉴权 | 需认证 |
路径参数:id = 一个或多个逗号分隔的驱动 ID(如 /v1/driver/97,96)。
响应:成功 {"code":0,"count":1,"data":"删除成功","msg":"ok"}
【警告】该接口会连带删除
example_conf表里该驱动的全部配置行——删掉后即使重新放回文件,也无法凭原模板重建,必须重新上传驱动包。
【警告】不检查驱动是否正在被服务使用:删掉后服务进程仍在跑,但下次重启会因找不到可执行文件而启不来。
【注意】ID 不存在时静默跳过,全部不存在也返回「删除成功」。
4.3.6 GET /v1/driver/appMarketURL — 应用市场地址
响应:{"code":0,"count":1,"data":"http://www.magusiot.cn:8586","msg":"ok"}
data 是裸字符串。取值来自 conf/.env 的 appMarketURL,读不到则回退到硬编码默认值。无失败分支,恒 code:0。
4.4 采集测点(/v1/point/*)
【警告】这一组的路径参数
{id}含义随接口而变,是本手册最重要的注意点。速查:
接口 {id}/{name}的含义GET /v1/point/{id}测点 UID(实时库点号) POST /v1/point无路径参数 PUT /v1/point/{id}测点 UID DELETE /v1/point/{id}逗号分隔的测点 UID 列表 import/import/local/multimport/export/empty采集服务 ID(dasId) empty/local/{name}采集服务名 clean/forceDelete/template完全被忽略
4.4.1 GET /v1/point — 查询采集测点
| 项 | 值 |
|---|---|
| 实现 | PointController.Get(controllers/data/point.go:49) |
| 鉴权 | 需认证 |
请求参数:
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | path | int | 否 | 测点 UID(优先于 query 的 ID) |
ID | query | int | 否 | 测点 UID |
SN | query | string | 否 | 采集服务名,精确匹配 ← 按服务查测点就用这个 |
PN | query | string | 否 | 点名模糊匹配(_ % 会被转义) |
ED | query | string | 否 | 描述模糊匹配(未转义) |
AS | query | string | 否 | 状态过滤:Good → DS=0;其它非空值 → DS<0。该分支走实时库 |
DS | query | int | 否 | 读出但未使用(死参数) |
HOST | query | string | 否 | 本接口实际未使用(死参数) |
limit | query | int | 否 | 实为 SQL 起始行偏移(跳过几条) |
offset | query | int | 否 | 实为 SQL 每页条数(取几条);传 0/缺省被强制为 20 |
实测对照(同一台设备共 4 个测点):
| 请求 | 实测结果 |
|---|---|
?SN=jen | count:4,返回 4 条 |
?SN=mqtt | count:0 |
?limit=2(→ LIMIT 2,20) | count:4,返回 2 条(UID 1026、1025,即跳过前 2 条) |
?limit=0&offset=2(→ LIMIT 0,2) | count:4,返回 2 条(UID 1030、1029) |
响应(实测,单条测点约 80 个字段):
json
{"code":0,"count":4,"data":[
{"ID":226,"UID":1026,"PID":0,"PN":"AX002","GN":"W3.JEN.AX002","SN":"jen","RT":0,
"AD":"","EU":"","TV":100,"BV":0,"DT":1,"DB":0.2,"KZ":1,"DS":-32768,"PH":100,"PL":0,
"ED":"这地方哈哈","FQ":1,"FM":2,"FLAG":"adding"}
],"msg":"ok"}【警告】列表数据全部来自关系库(SQLite),不是实时库:
DS恒为-32768、AV恒为null、TM恒为0。要实时值必须用/v1/point/app或AS=分支。
【警告】SN/ED/AS直接拼进 SQL(只有PN走了转义),存在注入面。
【注意】SQL 出错时返回code:0+msg:"ok"+ 空列表(静默失败),见 7.8。
4.4.2 GET /v1/point/third?name={服务名} — 按服务名取全部测点
| 项 | 值 |
|---|---|
| 实现 | PointController.GetThirdPoint(controllers/data/point.go:95) |
| 参数 | name(query)= 采集服务名 |
| 上限 | data 最多 100000 条 |
等价于 GET /v1/point?SN={服务名} 的"一次拉全"版本。name 为空时会返回全库前 10 万条。
4.4.3 GET /v1/point/app — APP 关键字查询(带实时值)
| 项 | 值 |
|---|---|
| 实现 | PointController.AppGet(controllers/data/point.go:949) |
请求参数:ED(同时当 PN 和 ED 用)、SN、ID、AS、limit / offset(语义同 4.4.1)、HOST(本接口真正使用)。
与 4.4.1 的关键差异:DS / AV / TM 是实时库真值(实时库取不到时逐点写 DS=-32768, TM=0, AV=0)。
【警告】
ED条件在 SQL 里是用or拼接的(sn='x' and uid=1 or ed like '%y%'),因此传了ED可能返回不属于该SN/ID的测点。用这个接口时要么别传SN/ID,要么别传ED。
4.4.4 POST /v1/point — 新建单个测点
| 项 | 值 |
|---|---|
| 实现 | PointController.Post(controllers/data/point.go:136) |
| Content-Type | application/x-www-form-urlencoded |
请求参数:SN(服务名,必填)、PN(点名,必填)、ID(实时库 UID)、DN(驱动名,用于 SR 白名单校验)、RT、SR、AN、ED、KR、EU、AD、CP、EX、DB、DT、KZ、FQ、FK、FB、TV、BV、PH、PL、EVENT、FM、PT、KT、AP、LC、H4`L4`、`C1`C8。完整含义见 5-数据字典。
响应:成功 {"code":0,"count":1,"data":"添加成功","msg":"ok"};失败 {"code":-1,"count":1,"data":"<服务名> 添加失败 GN:... error:...","msg":"error"}
校验规则:PN 非空、字符集合法、长度 ≤ 32;TV ≥ BV;PH ≥ PL;FK 传 0 会被强制改成 1;SR 必须在驱动白名单内;受 License 点数容量约束。
【注意】先写实时库、再写关系库(
isLink="true"时),实时库失败会回滚已写入的点。
【注意】SN取自内存服务表而非数据库;dasserver 刚启动时可能短暂报「服务不存在」。
4.4.5 POST /v1/point/import/{dasId} — 点表导入(本组核心接口)
| 项 | 值 |
|---|---|
| 实现 | PointController.Import(controllers/data/point.go:1035) |
| 鉴权 | 需认证 |
| Content-Type | multipart/form-data |
| 路径参数 | dasId = 采集服务 ID |
请求参数:
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
dasId | path | int | 是 | 采集服务 ID(das_service.id) |
pointcsv | form(file) | file | 是 | 文件字段名固定为 pointcsv |
HOST | query/form | string | 否 | 实时库地址,空则用配置默认 |
上传文件要求(逐条来自源码,全部是硬约束):
| 项 | 要求 | 不满足时 |
|---|---|---|
| 扩展名 | 必须是 .xlsx,大小写敏感(.XLSX 被拒),不支持 csv | 文件格式不是CSV(文案是遗留错误) |
| 工作表名 | 必须逐字是 Sheet1 | 获取数据失败 |
| 表头必需列 | PN 与 RT(这两列大小写不敏感) | 不能没有PN列 / 不能没有RT列 |
| 表头列名 | 其余列名必须全大写、在 5.2.1 的白名单内 | 非法的字段:<列名> |
| 行长度 | 必须与表头长度严格相等(Excel 会丢掉行尾空单元格,所以每行都要填到最后一列) | 长度不匹配 |
| 空表 | 没有任何行会 panic → HTTP 500 | 500 |
导入语义:增量 + 更新。按 GN(节点名.点名)与该服务已有测点比对——已存在的走更新,不存在的走新增。不会清空原有测点,也不会删除文件里没提到的点。同一文件重复导入是幂等的。
响应:
json
// 成功(注意 count 恒为 0)
{"code":0,"count":0,"data":[],"msg":"ok"}
// 部分行入库失败(count = 文件解析出的数据总行数,不是失败行数)
{"code":-1,"count":500,"data":[{"ID":1046,"PN":"G02","Number":0,
"Flag":"GN:W3.DEMO1.G02 ID:1046 error:UNIQUE constraint failed: point.gn"}],"msg":"error"}
// 早退错误(count = 1)
{"code":-1,"count":1,"data":[{"ID":0,"PN":"不能没有PN列","Number":0,"Flag":"不能没有PN列"}],"msg":"error"}【警告】成功时
count恒为0,不是导入条数。要拿实际条数请导入前后各查一次GET /v1/point?SN=<服务名>的count做差(见 7.9)。
【警告】逐行失败原因在data[].Flag里(键名是ID/PN/Number/Flag,大写)。部分行成功、部分行失败时已成功的行不会回滚。
【警告】同步阻塞、无异步任务:读 xlsx → 逐行校验 → 写实时库 → 写 SQLite → 通知采集服务,全在一个请求内完成。上万行会长时间不返回,且客户端超时断开不会中断后端处理。客户端超时请设 ≥300s,且不要自动重试(重试会再导入一次)。
常见逐行错误:见 6.5.3。
4.4.6 POST /v1/point/import/local/{dasId} — 仅导入关系库
与 4.4.5 参数、格式、响应完全相同,唯一差异:只写关系库,完全不写实时库(也不推双机对端)。这是双机热备备机专用入口——让备机的关系库追上主机,实时库由实时库自身的复制机制同步。
【注意】误用后果:关系库有点、实时库没有点,两边不一致。常规导入请用 4.4.5。
4.4.7 POST /v1/point/multimport/{dasId} — CSV 批量强插
| 项 | 说明 |
|---|---|
| 文件字段名 | 同样是 pointcsv |
| 文件格式 | .csv,编码必须是 GBK(UTF-8 中文会乱码) |
| 语义 | 只插入、不比对、不更新(与 Import 完全不同) |
| 容量校验 | 无(可能超出 License) |
| 写入顺序 | 先写实时库 → sleep 1s → 再写 SQLite |
【警告】
IsExistDatabase出错时该接口不写任何响应体,客户端会拿到空 body 的 200。
【注意】CSV 表头会被原地转大写,所以表头大小写不敏感(与 xlsx 路径不同)。
4.4.8 PUT /v1/point/{uid} / PUT /v1/point/update/{uid} — 更新测点(两者语义不同)
PUT /v1/point/{uid} | PUT /v1/point/update/{uid} | |
|---|---|---|
| 实现 | PointController.Put(point.go:487) | UpdateLocalData(point.go:676) |
| 实时库 | 写(isLink=true 时) | 不写(只改关系库) |
| 双机对端 | 同步 | 不同步 |
| 定位 | uid | uid |
| 语义 | 常规更新 | 双机热备备机专用 |
【警告】
PUT /v1/point/update/{uid}未传的数值字段会被写成0(不是"只改传了的字段")。回写前请先读取完整记录再整体提交。
【注意】PUT /v1/point/update/{uid}的PN未做大写归一,与Post不一致,容易写出大小写不一的GN。
4.4.9 DELETE /v1/point/{uids} — 删除测点 ⚠️破坏性
路径参数:id = 逗号分隔的测点 UID 列表(如 /v1/point/1026,1025),不是 dasId、不是单个 id。
响应:{"code":0,"count":1,"data":"删除成功","msg":"ok"}
【警告】静默成功:只要列表里第一个 UID 查不到对应测点,整个删除会被跳过,但接口仍返回「删除成功」。排障时务必核对
point表的实际行数。
【注意】它只根据第一个 UID 定位所属服务,因此跨服务批量删除时,只有第一个服务会收到刷新通知。
【注意】isLink="true"时同时删除实时库的点。
4.4.10 GET /v1/point/empty/local/{name} — 仅清空关系库
路径参数:name = 采集服务名(字符串,不是 ID)。响应 {"code":0,"count":1,"data":"清空成功","msg":"ok"}。
只清关系库,不碰实时库(对比 4.4.11)。双机热备备机专用。
4.4.11 其它接口速查
| 方法 | 路径 | 实现 | {id} 含义 | 说明 |
|---|---|---|---|---|
GET | /v1/point/sr?DN={驱动名} | GetPointSr(point.go:118) | — | 返回该驱动支持的 SR 列表。data 是字符串数组 |
POST | /v1/point/server/add | ServerAddPoints(point.go:987) | — | 参数 pointIds(逗号分隔 UID)+ collectName(服务名)。把实时库已有点登记到关系库,不写实时库、不校验容量 |
POST | /v1/point/export/{dasId} | Export(point.go:1794) | dasId | 导出该服务测点为 xlsx(文件流) |
POST | /v1/point/empty/{dasId} | Empty(point.go:1916) | dasId | ⚠️清空该服务全部测点(isLink=true 时连实时库一起删) |
POST | /v1/point/clean/{任意} | ClearJunkData(point.go:1987) | 被忽略 | ⚠️全局清理游离数据(不分服务),且恒返回成功 |
POST | /v1/point/forceDelete/{任意} | ForceDelete(point.go:2002) | 被忽略 | ⚠️空实现,什么都不删(见 7.26) |
POST | /v1/point/template/{任意} | DownTemplate(point.go:2016) | 被忽略 | 下载通用导入模板(xlsx,实测)。任意 id 都得到同一份 |
POST | /v1/point/insert | InsertLocalData(point.go:323) | — | 仅写关系库(备机专用) |
DELETE | /v1/point/delete/{uids} | DeleteLocalData(point.go:898) | UID 列表 | 仅删关系库(备机专用) |
GET/PUT/DELETE | /v1/point/pn | NPointController(npoint.go) | — | 按点名操作;PUT/DELETE 用 JSON body;GET 的 sn 是模糊匹配 |
【警告】
/v1/point/export/{dasId}导出的 xlsx 里,P 列与 Q 列的标题与数据错位(H4/LC互换)。把导出文件再导入或人眼比对时会错位,请以导入模板的列序为准。
【警告】/v1/point/export/{dasId}与/v1/point/template都先写到进程工作目录再下载删除,并发调用会互删/互相覆盖。
【注意】/v1/point/insert、/v1/point/delete/{uids}、/v1/point/update/{uid}、/v1/point/import/local/{dasId}、GET /v1/point/empty/local/{name}都是双机热备专用:只动关系库。常规用途请用对应的非local/insert/delete版本。
4.5 上传点(/v1/upoint/*)
4.5.1 上传点与采集点的关系
| 维度 | 采集点 point | 上传点 upoint |
|---|---|---|
| 方向 | 设备/驱动 → 采进来 | 实时库 → 传出去 |
SN 语义 | 采集服务名 | 上传服务名 |
UID 约束 | 唯一(一个实时库点只属于一个采集服务) | 不唯一(同一点可被多个上传服务引用) |
| 表的选用 | driverType 含 das 的服务读 point 表 | driverType = upload 的服务读 upoint 表 |
| 关联键 | UID(实时库点号)+ GN(全局名) | 同上 |
为什么需要上传点:本地实时库是共享的,同一份数据可能要同时上传给多个通道;而 point.uid 是唯一的,无法表达"一个点被多个服务引用",所以必须有第二张表放宽这个约束。上传点不是"新点",而是对实时库既有测点的订阅/投影清单——所以上传点的 PN/GN/RT 等字段都是从实时库回读得到的,不是文件里说了算。
字段结构两者同构,含义见 5-数据字典。
4.5.2 GET /v1/upoint — 查询上传点
参数与 4.4.1 基本一致(id/ID = 测点 UID、SN = 上传服务名、PN、ED、AS、limit/offset 同样是反的)。
【注意】
DS与host在本接口是死参数;DS恒为-32768、AV恒为0(本接口不取实时值)。
【注意】DB 出错时该接口返回code:0+msg:"ok",而data是错误字符串(伪成功),见 7.8。
4.5.3 ANY /v1/upoint/import/{dasId} — 上传点导入
| 项 | 值 |
|---|---|
| 实现 | UPointController.Import(controllers/data/upoint.go:340) |
| 路径参数 | dasId = 上传服务 ID |
| 文件字段名 | pointcsv |
| 文件格式 | 仅 .xlsx(大小写敏感),工作表名必须 Sheet1 |
| 必需列 | ID(实时库测点 UID,≥1024、文件内不重复) |
响应:
json
// 成功(count 恒为 0)
{"code":0,"count":0,"data":[],"msg":"ok"}
// 行级失败(count = 解析出的数据行数;Flag 是错误码或 ORM 原文)
{"code":-1,"count":3,"data":[{"ID":1046,"PN":"G02","Number":0,"Flag":"-104"}],"msg":"error"}
// 表单级错误(count = 1,PN 与 Flag 都是错误文案)
{"code":-1,"count":1,"data":[{"ID":0,"PN":"文件格式不是xlsx","Number":0,"Flag":"文件格式不是xlsx"}],"msg":"error"}【警告】官方上传点模板是 CSV,而导入只吃 xlsx —— 拿模板直接导入必然失败(见 7.28)。
【注意】上传点导入的列白名单与采集点不同:GN与全大写REDATA2会被判为「非法的字段」;表头大小写敏感(ID除外)。
【注意】语义是按GN增量 upsert,不预先清空;文件里的PN/GN会被实时库的值覆盖,所以写什么基本不影响结果——真正决定导入内容的是ID列。
4.5.4 ANY /v1/upoint/export/{dasId} — 导出上传点
返回文件流(application/octet-stream,文件名 <上传服务名>.xlsx),工作表 Sheet1,表头固定 13 列:
ID, AN, AD, SR, ED, UM, FK, FB, TV, BV, PH, PL, REDATA1【警告】导出的 13 列 ≠ 导入所需的列集(没有
PN/GN/SN/CP/EU/EVENT),回灌要靠实时库补PN/GN才成立。
【注意】该服务下一条上传点都没有时,返回的是{"code":-1,"data":"服务不存在"}——文案误导,实际是"没有数据"。
4.5.5 其它上传点接口速查
| 方法 | 路径 | {id} 含义 | 说明 |
|---|---|---|---|
POST | /v1/upoint | — | 新增:pointIds(逗号分隔 UID)+ collectName(上传服务名)。按 同服务下 GN 不重复判重 |
PUT | /v1/upoint/{uid} | 测点 UID | 更新。⚠️全量覆盖:未传字段会被清 0/清空。PN 无法通过本接口修改 |
DELETE | /v1/upoint/{uids} | UID 列表 | 删除。⚠️只按第一个 UID 的 SN 限定范围 |
ANY | /v1/upoint/empty/{dasId} | dasId | ⚠️清空该上传服务全部上传点。isLink 无关,不动实时库 |
ANY | /v1/upoint/clean/{任意} | 被忽略 | ⚠️全局垃圾清理,会同时动 upoint、point 与实时库,且恒返回成功 |
ANY | /v1/upoint/template/{任意} | 被忽略 | 下载模板(实测为 CSV,见 7.28) |
GET/PUT/DELETE | /v1/upoint/pn | — | ⚠️sn/pn 是小写;pn/pns 实际是全局名 GN(见 7.29);PUT/DELETE 用 JSON body;查不到会 HTTP 500 |
【警告】
ANY表示这些路由注册成了*:方法——用 GET 就能触发导入/导出/清空(见 7.5)。生产环境建议在网关层限制方法。
4.6 系统信息与资源
4.6.1 命名风格警告
这一组的字段名大小写风格不统一,且大多没有 JSON tag(键名就是 Go 字段名):
| 接口 | 风格 | 示例 |
|---|---|---|
/v1/baseInfo/、/v1/resource/、/v1/system/license/、/v1/system/conf | 大驼峰(PascalCase) | Model、DevCode、MEMTOTAL、Size |
/v1/mqtt/baseInfo、/v1/mqtt/resource、/v1/mqtt/netInfo | 小驼峰(camelCase) | boxName、licensePoint、systemTime |
【警告】不要按同一套规则解析整组接口,逐接口对照。
4.6.2 GET /v1/baseInfo/ — 设备基础信息
| 项 | 值 |
|---|---|
| 实现 | device.BaseInfo.Get(controllers/device/running.go:28) |
| 鉴权 | 需认证 |
响应(实测,已截断 NetInfos):data 是对象(不是数组),count 为 1。
json
{"code":0,"count":1,"data":{
"Model":"IA-2230","Version":"2.5.9.20241216","DevCode":"9TFM7-FE92M-Z1GZE-PD47H",
"Sn":"IA22301000970001","BoxName":"","Desc":"","SysTime":1504116085,
"NetInfos":[{"id":0,"netName":"eth0","ipv4Addr":"192.168.100.169"},
{"id":0,"netName":"eth1","ipv4Addr":"192.168.50.121"}],
"ActiveStandbyStatus":"","PwrStatus":"","CurrRunningTime":0,
"TotalRunningTime":0,"Temperature":0,"FourGInfo":null,"GPSInfo":null,
"ImageVersion":"","BoxCode":""
},"msg":"ok"}关键字段:
| 字段 | 说明 |
|---|---|
Model | 设备型号(实测 IA-2230) |
Version | 软件版本(实测 2.5.9.20241216) |
DevCode | 设备码 / 机器码,由外部程序 openplant/licrep 产生。授权就是绑这个值的 |
Sn | 序列号 |
BoxName / Desc | 盒子名称 / 描述,可写(见下) |
SysTime | 设备当前时间(Unix 秒) |
NetInfos | 网口数组。元素含 id/netName/ipv4Addr/status/netGroup/mask/gateway/isDHCP 等,但本接口实际只填 netName 与 ipv4Addr,其余恒为零值 |
CurrRunningTime | 实时库运行时长(秒,可能带小数) |
TotalRunningTime | 累计运行时长(秒) |
Temperature | 恒为 0(后端未实现采集) |
ActiveStandbyStatus / PwrStatus | 恒为空串(未实现) |
FourGInfo / GPSInfo | 恒为 null(要 4G 信息用 4.6.6) |
【注意】多个字段"有字段没数据":温度、电源状态、主备状态、GPS、4G 都不要当真实值用。
【注意】DevCode依赖外部可执行文件openplant/licrep。该文件缺失时DevCode为空并且授权匹配会一起失效(License 的Host用的是同一个值)。
PUT /v1/baseInfo/ — 修改盒子名称与描述:参数 boxName、desc(form/query)。
4.6.3 GET /v1/resource/ — 设备资源占用
| 项 | 值 |
|---|---|
| 实现 | device.SourceInfo.Get(controllers/device/running.go:108) |
| 鉴权 | 需认证 |
实测响应:
json
{"code":0,"count":1,"data":{
"CPU":0,"CPUTOTAL":1000,"CPUUSED":0,
"MEM":12100,"MEMTOTAL":1,"MEMUSED":121,
"DISK":100,"DISKTOTAL":1,"DISKUSED":1,"DISKFREE":0
},"msg":"ok"}字段完整清单与单位:
| 字段 | 单位 | 说明 |
|---|---|---|
CPU | % | CPU 使用率 |
CPUTOTAL | MHz | CPU 主频总量(实测 1000) |
CPUUSED | MHz | 已用频率 = CPUTOTAL × CPU% ÷ 100。不是百分比 |
MEM | % | 内存使用率 = 100 × MEMUSED ÷ MEMTOTAL |
MEMTOTAL | MB | 内存总量。不是字节 |
MEMUSED | MB | 已用内存 |
DISK | % | 磁盘使用率 |
DISKTOTAL | MB | 磁盘总量 |
DISKUSED | MB | 已用磁盘 |
DISKFREE | MB | 空闲磁盘 |
【警告】单位是 MB,不是字节。 源码里有处注释写「单位:B」是错的,权威依据是 openplant 点表里
MEMTOTAL/VOLTOTAL等点的工程单位EU都是MB。按字节换算会差约 10⁶ 倍。
【警告】实测这台设备的返回值本身是失真的:MEMTOTAL=1、MEMUSED=121,导致MEM=12100(即 12100%)。原因是内存总量取不到时被强制置为 1 以避免除零,于是比率爆掉。做监控告警前务必先判断MEMTOTAL是否为 1/0 这种哨兵值。
【注意】数据来自进程内缓存,最长约 3 分钟陈旧(后台每 180 秒刷新一次)。启动初期各字段可能全为 0。
【注意】实时库不可达时后台会尝试执行sudo ./sh/op-repair(外部命令),失败只写日志。
4.6.4 GET /v1/system/license/ — 授权信息
| 项 | 值 |
|---|---|
| 实现 | system.LicenseController.Get(controllers/system/license.go:31) |
| 鉴权 | 需认证 |
实测响应:data 是数组(count 仍为 1,UI 取 data[0])。
json
{"code":0,"count":1,"data":[
{"Project":"","Product":"IA-2230-Pro","Host":"9TFM7-FE92M-Z1GZE-PD47H",
"Desc":"","Version":"","Size":1900,"Expired":"2027-03-24",
"Atrributes":"","Valid":false}
],"msg":"ok"}| 字段 | 说明 |
|---|---|
Product | 授权产品名 |
Host | 设备码 / 机器码(与 /v1/baseInfo/ 的 DevCode 同源) |
Size | 授权点数总量 |
Expired | 到期日 yyyy-MM-dd;永久授权为空串(或 "永久",视路径而定) |
Atrributes | 授权属性(源码拼写就是 Atrributes) |
Valid | 恒为 false(后端未赋值)→ 不要用它判断授权有效性 |
Project / Desc / Version | 恒为空串 |
【警告】
Size不是授权文件里的原始点数,而是原始点数 − 100(硬编码)。实测Size=1900对应/v1/mqtt/baseInfo的licensePoint=2000——两个接口的总量恒差 100。
【警告】Valid恒为false,别拿它当判据。
授权余量怎么算:
| 量 | 从哪来 |
|---|---|
| 总量 | /v1/system/license/ 的 Size,或 /v1/mqtt/baseInfo 的 licensePoint(两者差 100,选定一边就别混用) |
| 已用 | /v1/mqtt/baseInfo 的 userdPoint(拼写就少一个 e);等价于实时库里的 select count(*) from Point |
| 余量 | 总量 − 已用 |
实测对照:licensePoint=2000、userdPoint=5、Size=1900 → 余量约 1995。
【注意】POST 同一路径 = 上传授权(multipart 字段名
license,必须.xml)。该操作会 kill 实时库进程、覆盖授权文件并写数据库,属高危运维动作,二次开发不要随手调。
4.6.5 GET /v1/system/conf — 读取全局配置
响应:data 是一个大对象,含 Base / HostOP / Log / Grpc / Broker / Service / Point / License 八组。
实测关键值(真机):
| 键 | 实测值 | 说明 |
|---|---|---|
Base.MaxPnLength | 32 | 点名长度上限(见 5.4) |
Base.MaxLengthServiceName | 11 | 服务名长度上限 |
Base.RequireLoginLogin | true | 本机免鉴权开关(见 2.3.4 与 7.12) |
Base.BoxCode | default_0011 | 盒子编码 |
Service.MaxNumber | 10 | 采集服务数上限 |
Point.MaxNumber | 2000 | 测点数上限 |
License.Device | IA-22 | 授权绑定的型号前缀 |
Grpc.RpcClientSend | 127.0.0.1:7633 | MQTT 驱动 gRPC 目标 |
HostOP.IP / Port | 127.0.0.1 / 8200 | 实时库地址 |
【警告】这是本产品最敏感的一个接口。
HostOP.Password返回的是解密后的实时库明文口令,Broker.Password是云平台 MQTT 口令,Base.RequireLoginLogin顺带暴露"本机是否免鉴权"。任何已登录用户(包括低权限角色)都能读——权限模型只有菜单可见性,没有接口级 RBAC(见 7.11 与 4.8.7)。
【注意】RequireLoginLogin这个字段名有误导性:注释写「本地访问是否鉴权」,但代码行为是为true时本机回环请求直接放行(即免鉴权),为false时回环也要登录。以代码行为为准。
4.6.6 /v1/mqtt/* — 面向云平台的上报接口
这四条是给云平台 / 物联网网关(edge_mqtt_hub 等)周期上报用的契约,不是给浏览器 UI 用的(UI 用 4.6.2 / 4.6.3 / 4.6.4)。
| 接口 | 用途 | data 形态 |
|---|---|---|
GET /v1/mqtt/info | MQTT 客户端自身状态(断连/发送/心跳/下载进度) | 对象或 null |
GET /v1/mqtt/baseInfo | 扁平版设备基础信息 + 授权 | 对象 |
GET /v1/mqtt/resource | 扁平版资源占用 + 运行时长 | 对象 |
GET /v1/mqtt/netInfo | 网络信息(4G / IP 列表 / 流量) | 对象 |
【警告】这四条
mqtt接口全部需要登录,没有免登录白名单。已核实:edge_iothub自身就是先POST /v1/login/拿 Cookie、再把 Cookie 附到每个/v1/mqtt/*请求上。不要指望它们像"上报口"那样开放。
GET /v1/mqtt/baseInfo(实测)
json
{"code":0,"count":1,"data":{
"boxName":"","version":"2.5.9.20241216","hardVersion":"IA-2230",
"mirrorVersion":"IA22xx_2.5.8_20240321320","devcode":"default_0011",
"sn":"IA22301000970001","expire":"2027-03-24",
"licensePoint":2000,"userdPoint":5
},"msg":"ok"}| 字段 | 说明 |
|---|---|
version | 软件版本 |
hardVersion | 型号(名字有歧义,不是"硬件版本") |
mirrorVersion | 系统镜像版本 |
devcode | 盒子编码(.env 的 box.code)。⚠️ 与 /v1/baseInfo/ 的 DevCode(licrep 机器码)不是同一个值 |
expire | 授权到期日 |
licensePoint | 授权点数总量(未减 100,与 /v1/system/license/ 的 Size 差 100) |
userdPoint | 已用测点数(拼写少一个 e) |
【警告】若设备没有任何有效授权(关系库无匹配且
license.xml打不开/为空/机器码不匹配),该接口会因 nil 解引用 panic → HTTP 500。
GET /v1/mqtt/resource
字段:systemTime(秒)、currentRunningTime(秒,float,可能带小数)、totalRunningTIme(注意 TIme 的大小写)、memTotal/memUsed/diskTotal/diskUsed(MB)、mhz(MHz)、usedPercent。
【警告】
usedPercent名不副实:它实际是已用频率(MHz),不是百分比。要真百分比请用/v1/resource/的CPU。
【警告】currentRunningTime是 float32,会出现500036.78这样的值。消费方若声明成int64会反序列化失败导致整块数据取不到。
GET /v1/mqtt/netInfo
字段:fourGConnectStatusCode、fourGCSQ、fourGFlow(MB)、Ips、以及 WiFi / 热点相关字段。
【注意】Linux 实现下 WiFi 与热点的字段是写死的常量 0/空串,没有采集逻辑——不要把"WiFi 未连接"当真实状态。只有 4G 的三项有真值。
【注意】Ips的键是大写I,且值是[{"ip":"192.168.1.10"}]这样的对象数组,不是字符串数组。按[]string解析会失败。
4.6.7 GET /v1/flow/ — 网口流量(空壳)
实测响应:{"code":0,"count":1,"data":"","msg":"ok"}
data 恒为空字符串。后端虽有 FlowResponse 结构定义,但全仓没有任何写入方——这个接口拿不到流量数据。要网口信息请用 /v1/baseInfo/ 或 /v1/mqtt/netInfo。
4.6.8 其它
| 方法 | 路径 | 说明 |
|---|---|---|
PUT | /v1/baseInfo/ | 修改 boxName / desc |
ANY | /v1/baseInfo/conf | ⚠️名字极具误导性:它不改型号/序列号/平台,只有 menuAuth 参数会写 conf/auth.conf;执行后 3 秒 os.Exit(0) 杀掉整个 dasserver 进程(由守护拉起) |
GET | /v1/system/first/ | 首次启动时间。⚠️当前代码下必然 HTTP 500(会话键 userId 从未写入 → 类型断言 panic)。需要该值请直接读设备上的 /usr/lib/system32box.so |
【警告】
/v1/baseInfo/conf会直接杀掉 dasserver 进程(不是热重载)。虽然守护会把它拉起来,但这属于中断性操作。
4.7 实时与历史数据(/v1/calcModel/*、/v1/opconsole/*)
【警告】这一组里有一个致命陷阱,请先读 4.7.2:
/v1/calcModel/gethistorybyid返回的是伪造的演示数据,不是真实历史值。只有/v1/opconsole/gethistorybyid(s)能取到真实归档数据。
4.7.1 GET /v1/calcModel/list / detail/{modelid} — 计算模型
| 接口 | 实现 | 说明 |
|---|---|---|
GET /v1/calcModel/list | CalcModelController.Get(controllers/data/calcModel.go:78) | 计算模型列表 |
GET /v1/calcModel/detail/{modelid} | ModelDetail(calcModel.go:132) | 模型详情与关联点 ID |
实测 /v1/calcModel/list:
json
{"code":-1,"count":0,"data":"Get TimeStamp Error!","msg":"error"}原因(源码确认):该组接口会先去请求一个外部 HTTP 服务获取时间戳与签名:
go
func getTimeStamp() { http.Get(GetTimeStamp) ... }
func getSign(timestamp, uri string) { http.Get(GetSign + "?param=appId=OFM...&secretKey=...&uri=" + uri) ... }这个地址指向第三方(西门子侧)服务,在设备本地网络里通常不可达,于是报 Get TimeStamp Error!。
【警告】该接口不是纯本地接口,依赖外部网络。返回值不可用时无法通过本地配置修复。
【注意】getSign里硬编码了secretKey。这是源码中的凭据硬编码问题,不要外传。
4.7.2 GET /v1/calcModel/gethistorybyid — 历史数据(返回伪造数据)
| 项 | 值 |
|---|---|
| 实现 | CalcModelController.GetArchiveByIDWithTime(controllers/data/calcModel.go:226) |
| 请求参数 | HOST、begin、end、interval、ID |
【警告】这个接口返回的是随机生成的假数据,不是真实历史值。
源码里
opconsole.GetArchive()的第一行就是return Temp(begin, end, idStr, interval),它下面所有真实的归档查询逻辑全是不可达的死代码。而Temp()的实现是这样的:gorealTimeValue = []float64{40.0267, 50, 60, 70, 80, 90} avAndtms = append(avAndtms, AVAndTM{ AV: realTimeValue[num] + float64(rand.Float64()*10-5), // 加随机抖动 TM: int64(beginInt), }) ... archiveData.PN = "TEST_POINT_0005" archiveData.GN = "W3.DATAPOINT.TEST_POINT_0005"也就是:曲线值来自一个硬编码的常量数组 + 随机数,点名恒为
TEST_POINT_0005。
实测两次不同请求的对比(ID 分别是 1026 与 999999):
json
{"code":0,"count":1,"data":[{"PN":"TEST_POINT_0005","GN":"W3.DATAPOINT.TEST_POINT_0005",
"EstimatedCurve":[{"AV":90,"TM":1504116600},{"AV":80,"TM":1504116540}, ...],
"ResidualCurve":[{"AV":0.033713963604995456,...}, ...]}]}两次响应的 PN/GN 完全相同,曲线值也是同一组常量,只有 ResidualCurve 的抖动值不同。
【警告】任何基于此接口做历史分析、报表或趋势判断的实现都会得到无意义的结果。 需要真实历史数据请用 4.7.4 的
/v1/opconsole/gethistorybyid。
4.7.3 GET /v1/opconsole/getrealtime/ — 实时数据查询(真实数据)
| 项 | 值 |
|---|---|
| 实现 | OPConsoleController.GetRealTime(controllers/opconsole/opdata.go:202) |
| 鉴权 | 需认证 |
| 数据源 | 实时库 Realtime 表(SQL 直查) |
请求参数:
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
collectName | query | string | 否 | 采集/上传服务名。传了会把该服务全部点的 UID 追加进 idsFilter |
idsFilter | query | string | 否 | 逗号分隔的测点 UID 列表 |
Node | query | string | 否 | 节点名,过滤 GN like '<Node>.%' |
PN | query | string | 否 | 点名模糊匹配 |
ED / AN | query | string | 否 | 描述 / 别名模糊匹配 |
RT | query | string | 否 | 类型过滤,拼进 RT in (...) |
ID | query | string | 否 | 精确 ID |
field | query | string | 否 | 返回字段列表。缺省为 ID,GN,PN,AN,RT,ED,EU,KR,DS,AP,TM |
order | query | string | 否 | 排序 |
offset | query | int | 否 | 实为 SQL 起始行偏移;缺省被置为 20 |
limit | query | int | 否 | 实为 SQL 每页条数 |
HOST | query | string | 否 | 实时库地址 |
响应:data 为行对象数组,count 为命中总数。
【警告】
offset/limit语义与直觉相反(同 4.4.1 与 4.3.2,后端拼limit <offset>,<limit>风格)。offset缺省为 20。
【警告】Node/PN/RT/ID/field等参数直接拼接进 SQL,存在注入面。field尤其危险——它整段进select子句。
【注意】field里若不含ID,后端会自动补在最前面。
4.7.4 GET /v1/opconsole/gethistorybyid/ 与 /gethistorybyids/ — 历史数据(真实数据)
| 项 | gethistorybyid | gethistorybyids |
|---|---|---|
| 实现 | GetArchiveByIDWithTime(opdata.go:821) | GetArchiveByIDsBetweenTime(opdata.go:851) |
| 点参数 | ID = 单个测点 ID(实时库 ID) | IDs = 逗号分隔的测点 ID 列表 |
| 时间参数 | begin / end | begin / end |
HOST | 可选(实际被忽略) | 可选(实际被忽略) |
| 底层 SQL | select ID,GN,TM,DS,AV from W3.Archive where ID =<ID> and TM between '<begin>' and '<end>' and mode='span' and interval=1 | 同左,ID in (<IDs>) |
data 结构 | 完整测点对象数组(80+ 字段,TM 为毫秒) | 原始行数组,只有 5 个键:AV / DS / GN / ID / TM(TM 为秒) |
count | 该点的行数 | 所有点的行数合计 |
时间参数格式(实测两种都可用,推荐日期时间字符串):
| 格式 | 示例 | 实测结果 |
|---|---|---|
| 日期时间字符串(推荐) | begin=2017-08-30 17:00:00&end=2017-08-30 21:00:00 | count: 14401(4 小时 = 14400 秒,正好每秒 1 条) |
| 数字 Unix 秒 | begin=1504110000&end=1504120000 | 同样返回数据(该窗口 count: 6593) |
【警告】查询精度被写死为「1 秒 1 个点」:SQL 里
mode='span' and interval=1是硬编码的,调用方无法指定原始值、最大/最小/平均值,也无法放大采样间隔。所以时间窗口必须开得很小——实测 4 小时单点就有 14401 条,跨天查询会直接把设备拖垮。
【警告】没有任何行数上限、也没有分页参数。实测 4 小时区间响应体约 1MB 量级;多点(byids)行数 = 点数 × 时间点数,极易打爆内存。请自行把窗口切成 ≤1 小时并串行请求。
【警告】两个接口的data结构与TM单位都不同(byid毫秒 /byids秒),不能共用同一套解析器。
【警告】ID/IDs/begin/end都直接拼接进 SQL,存在注入面。
【警告】只有本接口能取到真实历史数据;/v1/calcModel/gethistorybyid返回的是假数据(见 4.7.2)。
实测样本:
json
// gethistorybyid,ID=1026
{"code":0,"count":6593,"data":[{"ID":0,"UID":1026,"PN":"AX002","GN":"W3.JEN.AX002",
"AV":15902161,"DS":0,"TM":1504116592000, ...}]}
// gethistorybyids,IDs=1026,1025
{"code":0,"count":22,"data":[
{"ID":1025,"GN":"W3.JEN.AX001","TM":1504098000,"DS":0,"AV":15883569}]}【注意】
gethistorybyid返回的对象里ID恒为 0,真正可用的测点标识在UID字段。这是映射实现导致的(SQL 里的ID被写进了UID)。
4.7.5 其它 OPConsole 接口速查
/v1/opconsole/* 是给内置 OPConsole 前端用的数据面接口,直接读写实时库。二次开发如非必要不建议依赖(参数即 SQL 片段、无分页保护、无参数化)。
只读:
| 方法 | 路径 | 关键参数 | 说明 |
|---|---|---|---|
| 任意 | /v1/opconsole/getdatabase/ | HOST | 库列表(实测返回 ID/ED/PN/GN/CT/UD) |
| 任意 | /v1/opconsole/getnodelist/ | HOST、db_name、PN、filter、children | 节点列表 |
| 任意 | /v1/opconsole/getnode/ | HOST | 节点 |
| 任意 | /v1/opconsole/getnodedetail/ | HOST、DBName | 节点详情 |
| 任意 | /v1/opconsole/getpointfield/ | HOST | 可用字段列表(配合 getrealtime 的 field 用) |
| 任意 | /v1/opconsole/getpointinfo/ | HOST | 点信息 |
| 任意 | /v1/opconsole/exportpoint/ | HOST、Node、PN、ED、AN、RT、field | 导出点(文件流) |
| 任意 | /v1/opconsole/getProxyConn/ | HOST | 当前实时库连接信息 |
| 任意 | /v1/opconsole/TestConn/ | HOST、PORT、User、Pwd | 测试连接 |
写操作(⚠️ 直改实时库):
| 方法 | 路径 | 关键参数 | 说明 |
|---|---|---|---|
| 任意 | /v1/opconsole/addpoint/ | HOST、Node、PN、RT、ID 及大量点属性 | ⚠️ 向实时库新增点 |
| 任意 | /v1/opconsole/updatepoint/ | 同上 | ⚠️ 修改实时库点 |
| 任意 | /v1/opconsole/removepoints/ | HOST、ids | ⚠️ 删除实时库点 |
| 任意 | /v1/opconsole/importpoint/ | HOST | ⚠️ 导入点(文件) |
| 任意 | /v1/opconsole/setNodeLc/ | HOST、GN、LC | 设置节点 LC |
| 任意 | /v1/opconsole/UpdateConn/ | HOST、PORT、User、Pwd | 改实时库连接 |
| 任意 | /v1/opconsole/Reconnect/ | HOST、PORT、User、Pwd | 重连实时库 |
POST | /v1/opconsole/calc/addpoint | pn、rt、pt、kt、ex、ed、an、eu、unit | 新增计算点 |
POST | /v1/opconsole/calc/edit | pn、kt、ex、ed、an、eu、node | 编辑计算点 |
POST | /v1/opconsole/calc/removepoints | sn、pns | 删除计算点 |
POST | /v1/opconsole/calc/getpointinfo | sn、pn | 计算点信息 |
【警告】上表"写操作"全部直接改动实时库,绕过 DASS2 的关系库与
isLink联动逻辑。误用会造成关系库与实时库不一致(表现为/v1/point查不到但实时库有点,或反之)。常规点表维护请用 4.4 的/v1/point/*。
【警告】这些路由注册成了*:方法——GET 也会真的执行写操作。
4.8 系统运维(/v1/system/*)
4.8.1 系统服务管理(/v1/system/service/*)
【警告】先分清两套"服务"——这是本组最容易搞错的地方:
/v1/system/service/*/v1/das/*管什么 设备端系统服务 / 进程: dasserver、magusdog、openplant(实时库)、auth-center、edge_mqtt_hub等DAS 采集服务实例 主键 name(服务名)数字 id(dasId)数据源 magusdog 的管理面( 127.0.0.1:8089)dasserver 自己的 db/data.db启停执行者 magusdog(守护程序) dasserver 自己 有守护/自启概念 有( Valid= 守护开关)无 一句话:
/v1/system/service/*是盒子级进程编排(改它 = 改开机自启与存活),/v1/das/*是采集业务编排。不要拿service/status去启停采集服务。
| 方法 | 路径 | 关键参数 | 说明 |
|---|---|---|---|
GET | /v1/system/service/ | id(被忽略) | 服务列表。实质只返回前 50 个,无分页 |
POST | /v1/system/service/ | multipart 文件字段 systemService | ⚠️ 上传系统服务包(解包+落盘+装库+写配置) |
PUT | /v1/system/service/ | 无 | 死代码:写死了 proxy 服务,不要用 |
DELETE | /v1/system/service/{服务名} | id = 服务名(支持逗号) | ⚠️ 删除守护记录。多选删除静默失效(把 a,b,c 当成一个名字) |
GET | /v1/system/service/status | name(服务名)、status(start/stop) | ⚠️ 启停系统服务 |
ANY | /v1/system/service/protect/ | Name、Valid、Path 等(整行回传) | 守护开关(Valid=true 开守护)。⚠️ 是 upsert,名字不存在会新建 |
GET/PUT | /v1/system/service/conf/{服务名} | GET 用 path;PUT 必须在表单里再传一次 name | 读写系统服务的配置项(example_conf 表) |
POST | /v1/system/service/add/ | name、path、version、description | 新增服务记录(默认 守护开 + 标为运行) |
GET | /v1/system/service/displayLog/{服务名} | name | 日志文件列表 |
GET | /v1/system/service/log/{服务名} | name(正则 [\w]+,不能含 -)、fileName | ⚠️ 下载日志,下载后文件被删除 |
GET | /v1/system/service/log/exist/{服务名} | name | 判断日志是否存在 |
服务列表的字段(大驼峰,来自 magusdog):Name / Path / PID / Valid(守护开关) / Running / Version / StartDelay / LastTime / Desc / Error。
【警告】
Valid才是守护开关(不是它字面的"有效")。Valid=true表示该服务会被 magusdog 守护拉起。
【警告】GET /v1/system/service/status?name=<服务名>&status=stop停服务时,magusdog 会同时关闭守护(否则会被立刻拉起)。停掉dasserver就是停掉本接口自身。
【警告】GET /v1/system/service/log/{服务名}?fileName=...有两个高危点:① 下载后os.Remove删除文件,不可重复下载;②fileName未做路径约束,可路径穿越读取并删除任意文件。二次开发不要暴露这个接口。
【注意】DELETE /v1/system/service/{服务名}服务端不保护dasserver/magusdog/openplant(只有前端拦),删掉magusdog等于自毁守护。
【注意】GET /v1/system/service/的count与实际条数可能差 1:代码会硬塞一行 magusdog(PID恒 1122、Version恒 7.0.9),不是真实进程状态。
4.8.2 操作审计日志(/v1/system/log/*)
| 方法 | 路径 | 关键参数 | 说明 |
|---|---|---|---|
GET | /v1/system/log/ | ID、Type、Level、Module、Desc、beginDate、endDate、limit、offset | 查询审计日志 |
DELETE | /v1/system/log/{id} | id(支持逗号批量) | ⚠️ 物理删除审计日志 |
GET | /v1/system/log/download/{id} | id(不传=全部) | 导出日志(TSV 文件流) |
GET | /v1/system/log/system | 无 | 下载设备 /var/log/syslog 打包 |
GET | /v1/system/log/empty/ | 无 | ⚠️ 清空全部审计日志 |
GET | /v1/system/log/realtime/ | 无 | ⚠️ 不可用:路由挂到了没有 Get 方法的控制器上,请求会 HTTP 500 |
【警告】
limit/offset又是反的:SQL 为order by id desc limit <limit>,<offset>。而且limit默认为 0,会导致LIMIT 0返回 0 行——必须显式传limit。
【注意】/v1/system/log/download/的响应头写charset=gbk但内容其实是 UTF-8,用 Excel 直接打开可能乱码。
【注意】实时日志功能(内存环形缓冲)虽有实现,但路由未注册——该功能当前不可用。
4.8.3 用户与授权(/v1/system/user/*)
| 方法 | 路径 | 关键参数 | 说明 |
|---|---|---|---|
GET | /v1/system/user/ | id、name、limit、offset | 用户列表(loginName 为 ceshi 的行被硬编码跳过) |
POST | /v1/system/user/ | loginName、realName、email、phone | 新增用户。初始密码固定为 000000;不能指定角色 |
PUT | /v1/system/user/{id} | loginName、email、phone | ⚠️ 实现有 bug:id 未赋给实体 → 更新永远命中不了目标行(但返回「修改成功」) |
DELETE | /v1/system/user/{id} | id(支持逗号) | ⚠️ 删除用户。无"不能删自己/不能删最后一个管理员"的保护 |
ANY | /v1/system/user/changPwd/ | pldPwd(旧密码 MD5)、NewPwd(新密码 MD5) | 改自己的密码(:id 被忽略) |
ANY | /v1/system/user/resetPwd/{id} | id = 目标用户 | ⚠️ 弱口令重置:需 Role=="1" |
GET | /v1/system/auth | 无 | 当前用户菜单树 |
口令算法(关键):数据库里存的是 md5(md5(明文));而接口收的是 md5(明文)。所以客户端要先自己算一次 md5(明文) 再传。传明文会得到「原密码错误」。
【警告】
resetPwd是弱口令重置:目标admin→ 密码重置为sis;目标magus→ 重置为openplant(与出厂默认一致);其它用户仅被status=0。接口不要求操作者输入自己的密码,只要Role=="1"。这是一个高危后门,拿到管理员会话即可一键弱口令化。
【警告】DELETE /v1/system/user/{id}把用户全删光后,下次登录会重建出厂默认账号(admin/sis、magus/openplant、ceshi),等于把口令重置回默认值。
【注意】参数名pldPwd(拼写就是pld,不是old)、NewPwd(大写N)——传错不报错,只会「原密码错误」。
【注意】改密不会踢掉已有会话(Cookie 校验不验签名),旧会话在有效期内继续可用。
4.8.4 备份与恢复(/v1/system/backup*)
备份/恢复由外部可执行文件
dass-backup完成(须位于 dasserver 工作目录),后端只是exec它并转发结果。
| 方法 | 路径 | 关键参数 | 说明 |
|---|---|---|---|
GET | /v1/system/backup | 无 | 备份记录列表。字段:FileName / FilePath / Status / Size / TimeStamp |
POST | /v1/system/backup | 无 | 立即备份并下载(文件流) |
GET | /v1/system/backup/recover | filePath(来自上一条的 FilePath) | ⚠️ 整库覆盖恢复 |
POST | /v1/system/backup/recover/import | multipart 文件字段 fileName | ⚠️ 上传备份文件恢复 |
备份内容 = db/data.db(关系库)——即服务、测点、用户、配置、日志。不包含:openplant/ 实时库数据、各服务 logs/、conf/。
【警告】
recover与recover/import都会整库覆盖:当前所有服务/测点/用户/配置被回滚到备份时刻,恢复后的新增数据全部丢失,不可撤销。恢复过程会中断服务(后端超时 5 分钟),恢复后必须重启服务或整机,否则内存里的旧状态与新库不一致。
【警告】recover/import上传的文件不校验类型/魔数,直接落盘chmod 0777后交给外部程序执行。
【建议】任何恢复操作前,先自己POST /v1/system/backup存一份当前状态。
4.8.5 缓存镜像(/v1/system/mirror/*)
镜像 = 本机实时库向另一台实时库做数据点复制。共 17 条路由,全部注册为 *:方法。
| 路径 | 说明 | 关键参数 |
|---|---|---|
/v1/system/mirror/readMirrorFile | 读镜像配置(树形) | 无 |
/v1/system/mirror/addRep | 新增镜像 | US、PW(base64+AES)、PN、IP、PO、SP、SY、LN、Name |
/v1/system/mirror/updateRep | 编辑镜像 | 同上 + id |
/v1/system/mirror/delRep/{id} | 删除镜像(连带其数据点) | id |
/v1/system/mirror/delAllReps | 删除全部镜像 | 无 |
/v1/system/mirror/addItem | 新增镜像数据点 | PN、TN、XF、pid |
/v1/system/mirror/updateItem | 更新数据点 | id(= 真实 id + 10000)、PN、TN、XF、pid |
/v1/system/mirror/delItem/{id} | 删除数据点 | id(= 真实 id + 10000) |
/v1/system/mirror/delAllItems/{id} | 删除某镜像全部数据点 | id = 镜像 id(无偏移) |
/v1/system/mirror/geneRepFile | ⚠️ 生成镜像配置并应用 | 无 |
/v1/system/mirror/filePreview / fileDownload | 预览 / 下载 replicator.xml | 无 |
/v1/system/mirror/checkMirror | 查询是否有未应用的改动 | 无 |
/v1/system/mirror/checkInfo | 连通性 / 配置自检 | sign、US、PW、PN、IP、PO 等 |
/v1/system/mirror/clearRtdbBuffer | 「清理实时库缓存」 | 无 —— ⚠️ 空操作,函数体全被注释 |
/v1/system/mirror/getObjNode | 连目的实时库取库名/节点名 | ip、po、usr、pwd(base64+AES) |
/v1/system/mirror/checkPointExist | 查目的库测点是否存在 | ip、po、usr、pwd(明文!与上一条口径不同)、gn |
【警告】
geneRepFile在检测到配置变化时会主动 kill 实时库进程(rtnn),依赖 magusdog 守护把它拉回来。若该服务的守护被关闭,实时库会一直挂着。 调用前务必确认「openplant 的Valid=true」。
【警告】getObjNode与checkPointExist的pwd加密口径不一致(一个要密文、一个要明文),是明显的实现不一致。
【注意】镜像数据点的id有 +10000 偏移,而镜像本身没有——增删改时容易错位。
【注意】AES 密钥与 IV 硬编码在源码里(0f90023fc9ae101e),且镜像口令最终会以明文写进replicator.xml。
4.8.6 双机热备(/v1/system/dualActive/*)
【注意】ARM 机型或
IA-22型号上热备模块根本不启动,相关接口不可用。
| 方法 | 路径 | 关键参数 | 说明 |
|---|---|---|---|
ANY | /v1/system/dualActive/baseInfo | 无 | 基本信息:role、foreignIP、nativeIP、status、errCode、serviceStatuses[] |
POST | /v1/system/dualActive/setParameter | JSON body:role、foreignIP | 设置对端(nativeIP 被服务端覆盖) |
ANY | /v1/system/dualActive/start / stop | 无 | ⚠️ 双向操作(会同时改变对端的热备开关)。恒返回成功,实际是否生效要看 baseInfo.status |
POST | /v1/system/dualActive/records | JSON body:limit、offset(页码,从 1 起) | 切换记录 |
baseInfo 字段:role(master/slave/空)、foreignIP、nativeIP、status(总开关)、errCode(0 正常 / -1 配置不完整 / -2 两侧服务不一致)、errCodeString、serviceStatuses[](name/mStatus/sStatus/mExist/sExist/msg)。
【警告】
start/stop几乎没有失败路径——底层 gRPC 调用失败也只是return,接口仍报成功。判断是否真的生效必须查baseInfo.status。
【警告】start/stop会同时通知对端切换开关,单机测试时不要随意调。
【注意】baseInfo返回code:0不代表配置正常,要看errCode。
4.8.7 云平台接入
| 方法 | 路径 | 关键参数 | 说明 |
|---|---|---|---|
ANY | /v1/system/access | access_token(base64 + AES,密钥硬编码) | 保存绑定,返回 boxCode 与 cloudCenterUrl;会写 conf/.env |
ANY | /v1/system/setCloudKey | cloud_key | 写 conf/.env(源码注释标注「暂不使用」) |
GET | /v1/system/getCloudKey | cloud_key | ⚠️ 不回显已保存的 key,只是把你传的解一下再返回 |
ANY | /v1/system/boxCode | 无 | 取本机盒子编码(来自内存,改 .env 后需重启进程才变) |
4.8.8 数据同步与重启
| 方法 | 路径 | 说明 |
|---|---|---|
ANY | /v1/system/sync | 「系统缓存落盘」—— ⚠️ 空操作:只构造了 sync 命令对象,从未执行 |
ANY | /v1/system/reboot/ | ⚠️ 重启整机(3 秒后 reboot) |
ANY | /v1/system/serviceBoot/ | ⚠️ 仅退出 dasserver 进程(os.Exit(0)) |
【警告】这两个重启接口的响应体是两段 JSON 串接(不是合法 JSON),不能靠解析响应判断成功,应轮询设备可达性。详见 7.27。
【警告】serviceBoot的「能否自动回来」取决于 magusdog 是否在守护 dasserver。若未受守护,进程退出后永远不会回来——等于远程关机。
4.8.9 其它
| 方法 | 路径 | 说明 |
|---|---|---|
ANY | /v1/system/reset/ | ⚠️ 恢复出厂设置(会删除首次启动时间文件)。需 admin 角色 + base64/AES 口令 |
ANY | /v1/system/serviceBoot/ | 见 4.8.8 |
GET | /v1/system/first/ | 首次启动时间。⚠️ 当前必然 HTTP 500(见 4.6.8) |
GET | /v1/system/conf | ⚠️ 泄露明文口令,见 4.6.5 |
【注意】关于本产品的权限模型:
auth表只决定前端菜单可见性,没有任何接口级 RBAC 拦截。也就是说任何登录用户都能调用全部/v1/system/*接口——包括重置密码、清空日志、上传服务包、重启设备。做集成时不要依赖"角色"来限制能力。
帮助中心