Skip to content

4. 接口参考

本章按功能分组给出 DASS2 的 HTTP 接口契约。所有接口:

  • BaseURLhttp://<设备地址>: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/setLang4.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/license4.6
7实时与历史数据/v1/calcModel/* /v1/opconsole/*4.7
8系统运维/v1/system/*4.8

编排约定:核心链路接口给出完整字段表与示例;次要接口给出字段表与响应结构;纯管理界面用途的接口合并为表格列出,但保证路径完整

【警告】标注 ⚠️破坏性 的接口会删除数据或中断业务,执行前请阅读 7.6。


4.1 登录与鉴权

4.1.1 POST /v1/login — 登录

实现MainController.Logincontrollers/default.go:74
路由beego.Router("/v1/login/", &controllers.MainController{}, "*:Login")
鉴权免认证(URL 含 login
Content-Typeapplication/x-www-form-urlencoded

请求字段

参数名位置类型必填说明
usernameformstring用户名。前后空格会被 trim
passwordformstringmd5(明文) 的小写 hex,32 位

响应字段

字段类型说明
codeint0 成功;-1 失败
msgstring"ok" / "error"
countint恒为 0,不要拿来判成功
data.Userobject用户对象(Password 被清空,含 Menus 菜单树)
data.IsFirstbool是否首次启动

响应头下发 3 个 CookiebeegosessionID / 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.Logoutcontrollers/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.IsLogincontrollers/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/langBaseController.Language返回当前语言
任意/v1/setLangBaseController.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.Getcontrollers/data/das.go:57
鉴权需认证

请求参数

参数名位置类型必填说明
idpathint指定 dasId 精确查询
typequerystring驱动名模糊匹配
destTypequerystring驱动类型:das / upload
descquerystring描述模糊匹配
offsetqueryint缺省时被置为 1000(注意,不是 0)
limitqueryint限制条数

响应字段:见 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.Postcontrollers/data/das.go:112
鉴权需认证
Content-Typeapplication/x-www-form-urlencoded

请求字段平铺表单,不是 JSON):

参数名位置类型必填说明
das_nameformstring服务名。必须匹配 ^[A-Za-z0-9_]+$,长度 ≤ MaxLengthServiceName(实测 11),全局唯一
das_descformstring服务描述,不能为空
driver_nameformstring驱动名(来自 GET /v1/drivername
(驱动配置字段)formstring视驱动其余键 = GET /v1/driver/conf/{driverId} 返回项的 key,如 node_nameisLink 等。密码类字段需 base64(AES(明文))

后端自动填充(不要传):web_listen_address = :<自动分配的端口>web_path = ../wwwnode_name 会拼节点并转大写、isLink 缺省为 "true"

端口分配:采集服务从 5000~7500、上传服务从 7500~10000 自动分配(与《使用手册》一致;实测实例为 5480 / 9486)。

响应:成功返回建好的服务对象dataid / 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.Deletecontrollers/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.GetConfcontrollers/data/das.go:650
鉴权需认证

响应(实测 count: 17):data配置项数组,每项字段:

字段类型说明
keystring配置项名(改配置时的表单字段名)
valuestring当前值。密码类为 base64(AES(明文))
namestring中文名
edstring说明 / 取值提示
exScopestring作用域:advance / advanced
textTypestring控件/校验类型:select / disable / ispassword / password / 空
textDatastring枚举候选,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.PutConfcontrollers/data/das.go:784
鉴权需认证
Content-Typeapplication/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.Stopdas.go:434停止采集服务
POST /v1/das/boot/{id}BootDasController.Bootdas.go:507启动采集服务
POST /v1/das/reboot/{id}DasController.Rebootdas.go:575重启(内部 stop → 等 2 秒 → boot)

响应:成功 {"code":0,"count":1,"data":"<中文成功文案>","msg":"ok"}

幂等反馈是失败语义但属正常):

场景data
服务已在运行采集已经运行
服务已停止采集已经停止

双机热备限制(见 7.21):

角色被禁止文案
masterstop / reboot主机禁止停止服务
slaveboot备机禁止启动服务

【警告】这三个路由注册为 *:方法用 GET 访问也会真的执行(见 7.5)。
【警告】/v1/das/boot/{id}{id} 必须是数字 dasId。代码里虽有按 name 查的分支,但路由只定义了 :id,该分支不可达(见 7.17)。

实现DasController.GetDeviceStatuscontrollers/data/das.go:1146
鉴权需认证

响应(实测):{"code":0,"count":1,"data":true,"msg":"ok"}

data布尔值true 表示该采集服务与设备的链路正常。

【注意】这个接口比列表里的 status 更可信/v1/dasstatus 来自内存态,进程还在但链路断了时仍可能显示 running。做健康检查请用本接口。

4.2.9 日志相关接口

方法路径实现请求参数说明
任意/v1/das/log/exist/{id}LogIsExistdas.go:961id=dasId判断日志文件是否存在
任意/v1/das/log/{id}DownloadLogdas.go:905id=dasId下载服务日志(文件流)
任意/v1/das/displayLog/{id}LogListdas.go:985id=dasId列出日志文件
任意/v1/das/downloadFileDownloadLogsdas.go:946fileName(query)按文件名下载日志
任意/v1/das/runtime/{id}RuntimeLogdas.go:1044id=dasId服务实时运行日志(反代到采集服务自身端口/sys/logs
POST/v1/das/serviceLogServiceLogdas.go:1170JSON 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.GetConfBySNcontrollers/data/das.go:1201
请求体{"sn":"<服务名>"}
鉴权需认证

另有 /v1/das/conf/encrypt/{sn}GetConfEncryptBySNdas.go:1280)——新增版本,不过滤密码加密字段

4.2.11 其它

方法路径实现说明
GET/v1/das/appAppGetdas.go:391关键字查询(desc / offset / limitoffset 缺省 10000)
任意/v1/das/validate/{name}ValidateDasController.Validatedas.go:1010校验服务名是否合规(建服务前预校验)
POST/v1/das/history/{id}HistoryRecalldas.go:1090历史回补。参数 time,格式为 开始时间 - 结束时间- 分隔,两侧各一个空格
任意/v1/das/linkOPLinkPooldas.go:1128实时库连接信息(HOST/PORT/User/Pwd/Version
DELETE/v1/das/delete/{id}DeleteLocalServerdas.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.Getcontrollers/data/driver.go:44
鉴权需认证

请求参数

参数名位置类型必填说明
idpathint驱动 ID 精确匹配。非数字按 0 处理(等价于查全部)
typequerystring驱动类型模糊匹配(das / upload
namequerystring驱动名模糊匹配
descquerystring描述模糊匹配
limitqueryint实为 SQL 的起始行偏移
offsetqueryint实为 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"}
字段类型说明
idint驱动 ID/v1/driver/conf/{id} 要用它
namestring驱动名,建服务时的 driver_name
typestringdas=采集 / upload=上传
versionstring驱动版本
fileNamestring上传时的原始包名
descstring描述
uploadTime / publishTimestring上传时间 / 发布时间
isAuthbool恒为 false(后端 SQL 未查询该列,不是真实授权状态)
protocal_versionstring拼写少一个 o(应为 protocol_version),对应驱动包 Version.inicommStyle

【警告】分页参数与 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.Postcontrollers/data/driver.go:89
鉴权需认证
Content-Typemultipart/form-data

请求参数

参数名位置类型必填说明
driverform(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.csvlib/*.so
Version.ininame(驱动名)、type必须 dasupload)、suffixversionalias_namedescriptionpublish_timecommStyleplatform
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.inican not found Version.ini.
扩展名非 .tar.gz文件格式必须是tar.gz

【警告】同名驱动上传 = 覆盖升级,无法拒绝。而且上传成功后会把所有正在使用该驱动的采集服务停掉 → 换可执行文件 → 重启,属于有业务影响的操作。
【警告】该接口还做了部署级副作用:解压落盘、重建 example_conf 配置模板、Linux 下把 lib/*.so 拷到 /usr/lib/。这不是"传个文件"。
【注意】校验顺序是先解压落盘、后做业务校验——校验失败时文件已经留在磁盘上(只回滚数据库)。

4.3.4 GET /v1/driver/conf/{id} — 读取驱动配置字段(建服务前必做)

实现DriverConfController.Getcontrollers/data/driver.go:185
鉴权需认证

请求参数

参数名位置类型必填说明
idpathint驱动 ID
scopequerystringall(默认)/ 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。缺一段会漏字段。
【注意】textTypeispassword / password 的项,valuebase64(AES(明文)) 密文(见 7.4)。

4.3.5 DELETE /v1/driver/{ids} — 删除驱动 ⚠️破坏性

实现DriverController.Deletecontrollers/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/.envappMarketURL,读不到则回退到硬编码默认值。无失败分支,恒 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.Getcontrollers/data/point.go:49
鉴权需认证

请求参数

参数名位置类型必填说明
idpathint测点 UID(优先于 query 的 ID
IDqueryint测点 UID
SNquerystring采集服务名,精确匹配按服务查测点就用这个
PNquerystring点名模糊匹配(_ % 会被转义)
EDquerystring描述模糊匹配(未转义
ASquerystring状态过滤:GoodDS=0;其它非空值 → DS<0该分支走实时库
DSqueryint读出但未使用(死参数)
HOSTquerystring本接口实际未使用(死参数)
limitqueryint实为 SQL 起始行偏移(跳过几条)
offsetqueryint实为 SQL 每页条数(取几条);传 0/缺省被强制为 20

实测对照(同一台设备共 4 个测点):

请求实测结果
?SN=jencount:4,返回 4 条
?SN=mqttcount:0
?limit=2(→ LIMIT 2,20count:4,返回 2 条(UID 1026、1025,即跳过前 2 条)
?limit=0&offset=2(→ LIMIT 0,2count: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 恒为 -32768AV 恒为 nullTM 恒为 0要实时值必须用 /v1/point/appAS= 分支。
【警告】SN / ED / AS 直接拼进 SQL(只有 PN 走了转义),存在注入面。
【注意】SQL 出错时返回 code:0 + msg:"ok" + 空列表(静默失败),见 7.8。

4.4.2 GET /v1/point/third?name={服务名} — 按服务名取全部测点

实现PointController.GetThirdPointcontrollers/data/point.go:95
参数name(query)= 采集服务名
上限data 最多 100000

等价于 GET /v1/point?SN={服务名} 的"一次拉全"版本。name 为空时会返回全库前 10 万条。

4.4.3 GET /v1/point/app — APP 关键字查询(带实时值

实现PointController.AppGetcontrollers/data/point.go:949

请求参数ED同时当 PN 和 ED 用)、SNIDASlimit / 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.Postcontrollers/data/point.go:136
Content-Typeapplication/x-www-form-urlencoded

请求参数SN服务名,必填)、PN点名,必填)、ID(实时库 UID)、DN(驱动名,用于 SR 白名单校验)、RTSRANEDKREUADCPEXDBDTKZFQFKFBTVBVPHPLEVENTFMPTKTAPLCH4`L4`、`C1`C8。完整含义见 5-数据字典。

响应:成功 {"code":0,"count":1,"data":"添加成功","msg":"ok"};失败 {"code":-1,"count":1,"data":"<服务名> 添加失败 GN:... error:...","msg":"error"}

校验规则PN 非空、字符集合法、长度 ≤ 32;TV ≥ BVPH ≥ PLFK0 会被强制改成 1SR 必须在驱动白名单内;受 License 点数容量约束。

【注意】先写实时库、再写关系库isLink="true" 时),实时库失败会回滚已写入的点。
【注意】SN 取自内存服务表而非数据库;dasserver 刚启动时可能短暂报「服务不存在」。

4.4.5 POST /v1/point/import/{dasId} — 点表导入(本组核心接口

实现PointController.Importcontrollers/data/point.go:1035
鉴权需认证
Content-Typemultipart/form-data
路径参数dasId = 采集服务 ID

请求参数

参数名位置类型必填说明
dasIdpathint采集服务 ID(das_service.id
pointcsvform(file)file文件字段名固定为 pointcsv
HOSTquery/formstring实时库地址,空则用配置默认

上传文件要求(逐条来自源码,全部是硬约束):

要求不满足时
扩展名必须是 .xlsx大小写敏感.XLSX 被拒),不支持 csv文件格式不是CSV(文案是遗留错误)
工作表名必须逐字是 Sheet1获取数据失败
表头必需列PNRT(这两列大小写不敏感)不能没有PN列 / 不能没有RT列
表头列名其余列名必须全大写、在 5.2.1 的白名单内非法的字段:<列名>
行长度必须与表头长度严格相等(Excel 会丢掉行尾空单元格,所以每行都要填到最后一列)长度不匹配
空表没有任何行会 panic → HTTP 500500

导入语义增量 + 更新。按 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.Putpoint.go:487UpdateLocalDatapoint.go:676
实时库isLink=true 时)不写(只改关系库)
双机对端同步不同步
定位uiduid
语义常规更新双机热备备机专用

【警告】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={驱动名}GetPointSrpoint.go:118返回该驱动支持的 SR 列表。data字符串数组
POST/v1/point/server/addServerAddPointspoint.go:987参数 pointIds(逗号分隔 UID)+ collectName(服务名)。把实时库已有点登记到关系库,不写实时库、不校验容量
POST/v1/point/export/{dasId}Exportpoint.go:1794dasId导出该服务测点为 xlsx(文件流
POST/v1/point/empty/{dasId}Emptypoint.go:1916dasId⚠️清空该服务全部测点isLink=true 时连实时库一起删)
POST/v1/point/clean/{任意}ClearJunkDatapoint.go:1987被忽略⚠️全局清理游离数据(不分服务),且恒返回成功
POST/v1/point/forceDelete/{任意}ForceDeletepoint.go:2002被忽略⚠️空实现,什么都不删(见 7.26)
POST/v1/point/template/{任意}DownTemplatepoint.go:2016被忽略下载通用导入模板(xlsx,实测)。任意 id 都得到同一份
POST/v1/point/insertInsertLocalDatapoint.go:323仅写关系库(备机专用)
DELETE/v1/point/delete/{uids}DeleteLocalDatapoint.go:898UID 列表仅删关系库(备机专用)
GET/PUT/DELETE/v1/point/pnNPointControllernpoint.go点名操作;PUT/DELETEJSON bodyGETsn模糊匹配

【警告】/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 约束唯一(一个实时库点只属于一个采集服务)不唯一(同一点可被多个上传服务引用)
表的选用driverTypedas 的服务读 pointdriverType = upload 的服务读 upoint
关联键UID(实时库点号)+ GN(全局名)同上

为什么需要上传点:本地实时库是共享的,同一份数据可能要同时上传给多个通道;而 point.uid 是唯一的,无法表达"一个点被多个服务引用",所以必须有第二张表放宽这个约束。上传点不是"新点",而是对实时库既有测点的订阅/投影清单——所以上传点的 PN/GN/RT 等字段都是从实时库回读得到的,不是文件里说了算。

字段结构两者同构,含义见 5-数据字典。

4.5.2 GET /v1/upoint — 查询上传点

参数与 4.4.1 基本一致(id/ID = 测点 UIDSN = 上传服务名、PNEDASlimit/offset 同样是反的)。

【注意】DShost 在本接口是死参数DS 恒为 -32768AV 恒为 0(本接口不取实时值)。
【注意】DB 出错时该接口返回 code:0 + msg:"ok",而 data 是错误字符串(伪成功),见 7.8。

4.5.3 ANY /v1/upoint/import/{dasId} — 上传点导入

实现UPointController.Importcontrollers/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/{任意}被忽略⚠️全局垃圾清理,会同时动 upointpoint 与实时库,且恒返回成功
ANY/v1/upoint/template/{任意}被忽略下载模板(实测为 CSV,见 7.28)
GET/PUT/DELETE/v1/upoint/pn⚠️sn/pn小写pn/pns 实际是全局名 GN(见 7.29);PUT/DELETEJSON 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)ModelDevCodeMEMTOTALSize
/v1/mqtt/baseInfo/v1/mqtt/resource/v1/mqtt/netInfo小驼峰(camelCase)boxNamelicensePointsystemTime

【警告】不要按同一套规则解析整组接口,逐接口对照。

4.6.2 GET /v1/baseInfo/ — 设备基础信息

实现device.BaseInfo.Getcontrollers/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 等,但本接口实际只填 netNameipv4Addr,其余恒为零值
CurrRunningTime实时库运行时长(秒,可能带小数)
TotalRunningTime累计运行时长(秒)
Temperature恒为 0(后端未实现采集)
ActiveStandbyStatus / PwrStatus恒为空串(未实现)
FourGInfo / GPSInfo恒为 null(要 4G 信息用 4.6.6)

【注意】多个字段"有字段没数据":温度、电源状态、主备状态、GPS、4G 都不要当真实值用。
【注意】DevCode 依赖外部可执行文件 openplant/licrep。该文件缺失时 DevCode 为空并且授权匹配会一起失效(License 的 Host 用的是同一个值)。

PUT /v1/baseInfo/ — 修改盒子名称与描述:参数 boxNamedesc(form/query)。

4.6.3 GET /v1/resource/ — 设备资源占用

实现device.SourceInfo.Getcontrollers/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 使用率
CPUTOTALMHzCPU 主频总量(实测 1000
CPUUSEDMHz已用频率 = CPUTOTAL × CPU% ÷ 100不是百分比
MEM%内存使用率 = 100 × MEMUSED ÷ MEMTOTAL
MEMTOTALMB内存总量。不是字节
MEMUSEDMB已用内存
DISK%磁盘使用率
DISKTOTALMB磁盘总量
DISKUSEDMB已用磁盘
DISKFREEMB空闲磁盘

【警告】单位是 MB,不是字节。 源码里有处注释写「单位:B」是错的,权威依据是 openplant 点表里 MEMTOTAL/VOLTOTAL 等点的工程单位 EU 都是 MB。按字节换算会差约 10⁶ 倍。
【警告】实测这台设备的返回值本身是失真的MEMTOTAL=1MEMUSED=121,导致 MEM=12100(即 12100%)。原因是内存总量取不到时被强制置为 1 以避免除零,于是比率爆掉。做监控告警前务必先判断 MEMTOTAL 是否为 1/0 这种哨兵值
【注意】数据来自进程内缓存,最长约 3 分钟陈旧(后台每 180 秒刷新一次)。启动初期各字段可能全为 0。
【注意】实时库不可达时后台会尝试执行 sudo ./sh/op-repair(外部命令),失败只写日志。

4.6.4 GET /v1/system/license/ — 授权信息

实现system.LicenseController.Getcontrollers/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/baseInfolicensePoint=2000——两个接口的总量恒差 100
【警告】Valid 恒为 false别拿它当判据

授权余量怎么算

从哪来
总量/v1/system/license/Size /v1/mqtt/baseInfolicensePoint两者差 100,选定一边就别混用
已用/v1/mqtt/baseInfouserdPoint拼写就少一个 e);等价于实时库里的 select count(*) from Point
余量总量 − 已用

实测对照licensePoint=2000userdPoint=5Size=1900 → 余量约 1995。

【注意】POST 同一路径 = 上传授权(multipart 字段名 license,必须 .xml)。该操作会 kill 实时库进程、覆盖授权文件并写数据库,属高危运维动作,二次开发不要随手调。

4.6.5 GET /v1/system/conf — 读取全局配置

响应data 是一个大对象,含 Base / HostOP / Log / Grpc / Broker / Service / Point / License 八组。

实测关键值(真机):

实测值说明
Base.MaxPnLength32点名长度上限(见 5.4)
Base.MaxLengthServiceName11服务名长度上限
Base.RequireLoginLogintrue本机免鉴权开关(见 2.3.4 与 7.12)
Base.BoxCodedefault_0011盒子编码
Service.MaxNumber10采集服务数上限
Point.MaxNumber2000测点数上限
License.DeviceIA-22授权绑定的型号前缀
Grpc.RpcClientSend127.0.0.1:7633MQTT 驱动 gRPC 目标
HostOP.IP / Port127.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/infoMQTT 客户端自身状态(断连/发送/心跳/下载进度)对象或 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盒子编码(.envbox.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/diskUsedMB)、mhz(MHz)、usedPercent

【警告】usedPercent 名不副实:它实际是已用频率(MHz),不是百分比。要真百分比请用 /v1/resource/CPU
【警告】currentRunningTimefloat32,会出现 500036.78 这样的值。消费方若声明成 int64反序列化失败导致整块数据取不到。

GET /v1/mqtt/netInfo

字段fourGConnectStatusCodefourGCSQfourGFlow(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/listCalcModelController.Getcontrollers/data/calcModel.go:78计算模型列表
GET /v1/calcModel/detail/{modelid}ModelDetailcalcModel.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.GetArchiveByIDWithTimecontrollers/data/calcModel.go:226
请求参数HOSTbeginendintervalID

【警告】这个接口返回的是随机生成的假数据,不是真实历史值。

源码里 opconsole.GetArchive()第一行就是 return Temp(begin, end, idStr, interval),它下面所有真实的归档查询逻辑全是不可达的死代码。而 Temp() 的实现是这样的:

go
realTimeValue = []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 分别是 1026999999):

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.GetRealTimecontrollers/opconsole/opdata.go:202
鉴权需认证
数据源实时库 Realtime 表(SQL 直查

请求参数

参数名位置类型必填说明
collectNamequerystring采集/上传服务名。传了会把该服务全部点的 UID 追加进 idsFilter
idsFilterquerystring逗号分隔的测点 UID 列表
Nodequerystring节点名,过滤 GN like '<Node>.%'
PNquerystring点名模糊匹配
ED / ANquerystring描述 / 别名模糊匹配
RTquerystring类型过滤,拼进 RT in (...)
IDquerystring精确 ID
fieldquerystring返回字段列表。缺省为 ID,GN,PN,AN,RT,ED,EU,KR,DS,AP,TM
orderquerystring排序
offsetqueryint实为 SQL 起始行偏移;缺省被置为 20
limitqueryint实为 SQL 每页条数
HOSTquerystring实时库地址

响应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/ — 历史数据(真实数据

gethistorybyidgethistorybyids
实现GetArchiveByIDWithTimeopdata.go:821GetArchiveByIDsBetweenTimeopdata.go:851
点参数ID = 单个测点 ID(实时库 ID)IDs = 逗号分隔的测点 ID 列表
时间参数begin / endbegin / end
HOST可选(实际被忽略)可选(实际被忽略)
底层 SQLselect 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 / TMTM
count该点的行数所有点的行数合计

时间参数格式(实测两种都可用,推荐日期时间字符串):

格式示例实测结果
日期时间字符串(推荐)begin=2017-08-30 17:00:00&end=2017-08-30 21:00:00count: 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/HOSTdb_namePNfilterchildren节点列表
任意/v1/opconsole/getnode/HOST节点
任意/v1/opconsole/getnodedetail/HOSTDBName节点详情
任意/v1/opconsole/getpointfield/HOST可用字段列表(配合 getrealtimefield 用)
任意/v1/opconsole/getpointinfo/HOST点信息
任意/v1/opconsole/exportpoint/HOSTNodePNEDANRTfield导出点(文件流)
任意/v1/opconsole/getProxyConn/HOST当前实时库连接信息
任意/v1/opconsole/TestConn/HOSTPORTUserPwd测试连接

写操作(⚠️ 直改实时库)

方法路径关键参数说明
任意/v1/opconsole/addpoint/HOSTNodePNRTID 及大量点属性⚠️ 向实时库新增点
任意/v1/opconsole/updatepoint/同上⚠️ 修改实时库点
任意/v1/opconsole/removepoints/HOSTids⚠️ 删除实时库点
任意/v1/opconsole/importpoint/HOST⚠️ 导入点(文件)
任意/v1/opconsole/setNodeLc/HOSTGNLC设置节点 LC
任意/v1/opconsole/UpdateConn/HOSTPORTUserPwd改实时库连接
任意/v1/opconsole/Reconnect/HOSTPORTUserPwd重连实时库
POST/v1/opconsole/calc/addpointpnrtptktexedaneuunit新增计算点
POST/v1/opconsole/calc/editpnktexedaneunode编辑计算点
POST/v1/opconsole/calc/removepointssnpns删除计算点
POST/v1/opconsole/calc/getpointinfosnpn计算点信息

【警告】上表"写操作"全部直接改动实时库,绕过 DASS2 的关系库与 isLink 联动逻辑。误用会造成关系库与实时库不一致(表现为 /v1/point 查不到但实时库有点,或反之)。常规点表维护请用 4.4 的 /v1/point/*
【警告】这些路由注册成了 *:方法——GET 也会真的执行写操作


4.8 系统运维(/v1/system/*

4.8.1 系统服务管理(/v1/system/service/*

【警告】先分清两套"服务"——这是本组最容易搞错的地方:

/v1/system/service/*/v1/das/*
管什么设备端系统服务 / 进程dasservermagusdogopenplant(实时库)、auth-centeredge_mqtt_hubDAS 采集服务实例
主键name(服务名)数字 iddasId
数据源magusdog 的管理面(127.0.0.1:8089dasserver 自己的 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/statusname(服务名)、statusstart/stop⚠️ 启停系统服务
ANY/v1/system/service/protect/NameValidPath 等(整行回传守护开关Valid=true 开守护)。⚠️ 是 upsert,名字不存在会新建
GET/PUT/v1/system/service/conf/{服务名}GET 用 path;PUT 必须在表单里再传一次 name读写系统服务的配置项(example_conf 表)
POST/v1/system/service/add/namepathversiondescription新增服务记录(默认 守护开 + 标为运行)
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:代码会硬塞一行 magusdogPID 恒 1122、Version 恒 7.0.9),不是真实进程状态。

4.8.2 操作审计日志(/v1/system/log/*

方法路径关键参数说明
GET/v1/system/log/IDTypeLevelModuleDescbeginDateendDatelimitoffset查询审计日志
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/idnamelimitoffset用户列表(loginNameceshi 的行被硬编码跳过)
POST/v1/system/user/loginNamerealNameemailphone新增用户。初始密码固定为 000000不能指定角色
PUT/v1/system/user/{id}loginNameemailphone⚠️ 实现有 bugid 未赋给实体 → 更新永远命中不了目标行(但返回「修改成功」)
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/recoverfilePath(来自上一条的 FilePath⚠️ 整库覆盖恢复
POST/v1/system/backup/recover/importmultipart 文件字段 fileName⚠️ 上传备份文件恢复

备份内容 = db/data.db(关系库)——即服务、测点、用户、配置、日志。不包含openplant/ 实时库数据、各服务 logs/conf/

【警告】recoverrecover/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新增镜像USPW(base64+AES)、PNIPPOSPSYLNName
/v1/system/mirror/updateRep编辑镜像同上 + id
/v1/system/mirror/delRep/{id}删除镜像(连带其数据点)id
/v1/system/mirror/delAllReps删除全部镜像
/v1/system/mirror/addItem新增镜像数据点PNTNXFpid
/v1/system/mirror/updateItem更新数据点id= 真实 id + 10000)、PNTNXFpid
/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连通性 / 配置自检signUSPWPNIPPO
/v1/system/mirror/clearRtdbBuffer「清理实时库缓存」无 —— ⚠️ 空操作,函数体全被注释
/v1/system/mirror/getObjNode连目的实时库取库名/节点名ippousrpwdbase64+AES
/v1/system/mirror/checkPointExist查目的库测点是否存在ippousrpwd明文!与上一条口径不同)、gn

【警告】geneRepFile 在检测到配置变化时会主动 kill 实时库进程rtnn),依赖 magusdog 守护把它拉回来。若该服务的守护被关闭,实时库会一直挂着。 调用前务必确认「openplant 的 Valid=true」。
【警告】getObjNodecheckPointExistpwd 加密口径不一致(一个要密文、一个要明文),是明显的实现不一致。
【注意】镜像数据点的 id+10000 偏移,而镜像本身没有——增删改时容易错位。
【注意】AES 密钥与 IV 硬编码在源码里0f90023fc9ae101e),且镜像口令最终会以明文写进 replicator.xml

4.8.6 双机热备(/v1/system/dualActive/*

【注意】ARM 机型或 IA-22 型号上热备模块根本不启动,相关接口不可用。

方法路径关键参数说明
ANY/v1/system/dualActive/baseInfo基本信息:roleforeignIPnativeIPstatuserrCodeserviceStatuses[]
POST/v1/system/dualActive/setParameterJSON bodyroleforeignIP设置对端(nativeIP 被服务端覆盖)
ANY/v1/system/dualActive/start / stop⚠️ 双向操作(会同时改变对端的热备开关)。恒返回成功,实际是否生效要看 baseInfo.status
POST/v1/system/dualActive/recordsJSON bodylimitoffset页码,从 1 起切换记录

baseInfo 字段rolemaster/slave/空)、foreignIPnativeIPstatus(总开关)、errCode(0 正常 / -1 配置不完整 / -2 两侧服务不一致)、errCodeStringserviceStatuses[]name/mStatus/sStatus/mExist/sExist/msg)。

【警告】start / stop 几乎没有失败路径——底层 gRPC 调用失败也只是 return,接口仍报成功。判断是否真的生效必须查 baseInfo.status
【警告】start/stop同时通知对端切换开关,单机测试时不要随意调。
【注意】baseInfo 返回 code:0 不代表配置正常,要看 errCode

4.8.7 云平台接入

方法路径关键参数说明
ANY/v1/system/accessaccess_tokenbase64 + AES,密钥硬编码保存绑定,返回 boxCodecloudCenterUrl会写 conf/.env
ANY/v1/system/setCloudKeycloud_keyconf/.env(源码注释标注「暂不使用」)
GET/v1/system/getCloudKeycloud_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/* 接口——包括重置密码、清空日志、上传服务包、重启设备。做集成时不要依赖"角色"来限制能力。