WebAPI 参考
Darra PnSlave 服务内置 HTTP API。实时过程数据走 SDK 共享内存(SHM);本页是 SDK 的备用面:给 GUI 观测、诊断工具、以及无法走 SHM 时的控制/排障。不要把 WebAPI 当成周期 IO 主路径。
| 项 | 值 |
|---|---|
| 品牌 | Darra PnSlave |
| 基址 | http://127.0.0.1:18840 |
| 端口 | 18840 固定(编译期常量,不可改、不可配) |
| 监听 | 仅 127.0.0.1。局域网不可达 |
| JSON | camelCase;枚举为字符串 |
| 鉴权 | 回环默认放行。配置了 Api:ApiKey 后,所有请求必须带 X-Darra-Pnet-Api-Key |
| 请求体上限 | 64 KB(超限 HTTP 413) |
| 授权 | 无授权端点。授权只在 GUI 注册 + 服务内部复查;未授权时 POST /api/start 失败 |
成功响应按各端点结构(启停带 ok),不叠加 success。失败统一:
{ "success": false, "message": "…", "code": 400, "errorCode": 0, "timestamp": "…" }
code = HTTP 状态码。errorCode:原生栈 rc 可用时透出;运行态失败透出服务当前错误码;纯客户端错误(400 / 401 / 404 / 413)为 0。内部异常不进响应,查 %ProgramData%\Darra\Pnet 日志。
GET / 返回基础 Web 页(只看状态 / IO,禁止配置)。JSON 服务信息在 GET /api/info。
定位
| 通道 | 用途 |
|---|---|
| SDK SHM | 周期实时 IO。设备 ↔ 控制器的过程数据主路径 |
| WebAPI | GUI 状态/报警/诊断;备用启停与写 I;现场排障 |
语言 SDK 的服务模式可以转发到本 API,但周期读写仍应以 SHM 为准。用 HTTP 轮询 IO 只能作观测或一次性写入,不能当 1 ms 周期面。
端点总表
| 方法 | 路径 | 方向 | 用途 |
|---|---|---|---|
| GET | /api/info | 读 | 服务信息 + 端点清单 |
| GET | /api/status | 读 | 运行态快照(含 connected) |
| GET | /api/io | 读 | 过程映像。inputHex=Q 只读;outputHex=I |
| GET | /api/alarms | 读 | 活动报警 |
| GET | /api/alarms/history | 读 | 报警历史(最近 500 条,时间升序) |
| GET | /api/diag | 读 | 驱动 / 栈诊断计数器 |
| GET | /api/im | 读 | I&M 设备标识 |
| GET | /api/records | 读 | 用户区记录(Index 0x0000–0x7FFF) |
| POST | /api/start | 写 | 启动从站 |
| POST | /api/stop | 写 | 停止从站(软停)。connected=true 禁止 |
| POST | /api/io | 写 | 只写 I(设备→控制器),部分覆盖 |
| POST | /api/diag | 写 | 标准诊断 add / update / remove |
| POST | /api/alarm | 写 | 发送过程报警(设备→控制器) |
| POST | /api/alarms/ack | 写 | 确认单条活动报警 |
| POST | /api/alarms/ack-all | 写 | 确认全部活动报警 |
| POST | /api/reset | 写 | 复位。connected=true 禁止 |
| POST | /api/config/reload | 写 | 重载运行配置 XML。connected=true 禁止 |
I / Q 与 GET|POST /api/io
过程映像在 WebAPI 上的方向是固定的,不要按字段名字面猜:
| 字段 / 操作 | PLC 区 | 方向 | 可写 |
|---|---|---|---|
GET inputHex | Q | 控制器 → 设备 | 否(只读) |
GET outputHex | I | 设备 → 控制器 | 否(影子;写走 POST) |
POST /api/io | I | 设备 → 控制器 | 是(部分覆盖) |
POST /api/io 只写 I。不能经 WebAPI 写 Q。Q 只来自主站周期帧。
请求体:
{ "offset": 0, "data": "A1B2C3D4" }
| 字段 | 类型 | 说明 |
|---|---|---|
offset | 非负整数 | I 区字节偏移 |
data | 偶数长度 hex | 覆盖内容(大小写均可) |
成功:
{ "ok": true, "offset": 0, "length": 4, "timestamp": "…" }
越界(offset + 长度 超出 I 区)返回 400,不截断。未连主站时写入暂存在本地,主站连上后随周期帧发出。
GET /api/io 主要字段:
| 字段 | 说明 |
|---|---|
inputHex | Q 当前值(hex) |
outputHex | I 当前值(hex,含刚写入的本地影子) |
inputLength / outputLength | Q / I 区长度(字节) |
inputIopsHex / inputIocsHex | Q 侧 IOPS / IOCS |
outputIopsHex / outputIocsHex | I 侧 IOPS / IOCS |
inputValid / outputValid | 数据是否有效。掉线时为 BAD,不虚构 GOOD |
formatVersion | JSON 契约版本(当前 1) |
epoch | 过程映像世代 |
测法:写 I 看 Q,不要看影子
要验证主站是否把从站 I 同步回来,只认 Q(inputHex),不认 I 影子(outputHex)。
- 记一次
GET /api/io的inputHex前 8 个 hex 字符(Q 前 4 字节)作为基线。 POST /api/io写 I 前 4 字节,例如{ "offset": 0, "data": "11223344" }。- 立刻再
GET /api/io:outputHex前 8 字符通常已经是11223344。这只说明本地 I 影子已改,不算通过。 - 轮询
GET /api/io的inputHex,记录它相对基线发生变化的时刻。 inputHex(Q)变了,才算主站把 I 同步到了 Q。inputHex一直不变也可以发生:主站没有把 I 抄回 Q。这不是从站 WebAPI 写失败——POST 成功只保证 I 已进本地过程区。如实记录「Q 未变 / 主站未拷」,不要把outputHex当通过门。
从站不会周期把 Q 抄回 I。前 4 字节回写(若出现)是主站行为。
connected=true 禁令
先 GET /api/status 读 connected。已与 IO 控制器建立周期数据交换时:
| 端点 | connected=true |
|---|---|
POST /api/stop | 禁止 |
POST /api/reset | 禁止 |
POST /api/config/reload | 禁止 |
在线拆 AR / 重载配置会打断正在交换的周期数据。先等主站断开(connected=false),再停、复位或重载。POST /api/start、写 I、诊断、报警不受此条限制。
GET 端点
GET /api/info
服务存活探测 + 端点清单。
{
"serviceName": "DarraPnet",
"version": "1.0.0",
"port": 18840,
"endpoints": ["GET /api/info", "GET /api/status"]
}
port 恒为 18840。
GET /api/status
运行态单一权威快照。
| 字段 | 说明 |
|---|---|
state | Idle / Connecting / DataExchange / ConfigError 等 |
connected | 是否已与 IO 控制器建立周期数据交换 |
everConnected | 曾连接过。待机 = false;掉线后仍为 true |
errorCode | 最近错误码原值(0 = 无) |
statusMessage | 状态详情(ConfigError 时带原因) |
alarmCount / criticalAlarmCount | 活动报警数 |
ioEpoch | 过程映像世代 |
masterAssignedIp / Mask / Gateway / masterStationName | 主站 DCP Set 分配值(空 = 未分配) |
dcpIpApplied / dcpIpApplyMessage | DCP IP 是否已应用到本机 |
GET /api/io
见上文「I / Q」。掉线时 IOPS/IOCS 为 BAD,不虚构 GOOD。
GET /api/alarms
活动报警数组(时间与汇聚由服务单源维护)。
[
{
"id": "Pnet.LinkDown",
"severity": "Critical",
"message": "链路断开",
"occurredAt": "…",
"count": 1,
"source": "driver"
}
]
GET /api/alarms/history
最近 500 条,时间升序。元素契约与活动列表相同。
GET /api/diag
驱动共享内存头 + 栈统计。从站未启动时 ok=false、sharedMemoryMapped=false,计数器不虚构。
主要观测字段:linkUp / connected / rxFrames / txFrames / rxRtFrames / txRtFrames / droppedFrames / watchdogTrips / cycleCounter / stackCycles / arEpoch / arFrameIdCpm / arFrameIdPpm / arControllerMac。degraded=true 表示驱动未就绪、服务在退避重试。
GET /api/im
I&M0 真读原生栈(与控制器 IODRead 同源)。栈未运行时回退固定镜像,imSource 标明 "native" 或 "fixed-image",不假装读成功。
| 字段 | 说明 |
|---|---|
vendorId / deviceId | 厂商 / 设备标识 |
orderId / serialNumber | 订货号 / 序列号 |
hardwareRevision / softwareRevision | 硬件 / 软件版本 |
stationName / productName | 站点名 / 产品名(服务配置) |
im1TagFunction / im1TagLocation / im2Date / im3Descriptor / im4SignatureHex | I&M1–4(主站未写则空) |
projectOrderNumber 等 | 工程 XML 标识(文件缺失则空) |
GET /api/records
用户区记录,只含已占用槽。栈未运行:records=[]、count=0,不返 500。
{
"records": [
{ "slot": 1, "subslot": 1, "index": 1, "length": 4, "dataHex": "01020304" }
],
"count": 1,
"timestamp": "…"
}
POST 端点
POST /api/start
启动从站。无请求体。已在运行则幂等成功。授权失败文案带 (AUTH)。网卡/驱动不可用时进入 ConfigError,ok=false。
{ "ok": true, "message": "从站已启动", "errorCode": 0, "timestamp": "…" }
curl -s -X POST http://127.0.0.1:18840/api/start
POST /api/stop
软停止:停数据面,保留实例 / 驱动句柄 / 绑卡。再次 start 复用,不重建。未运行也返回 ok=true。
connected=true 时禁止调用。
{ "ok": true, "message": "从站已停止", "errorCode": 0, "timestamp": "…" }
curl -s -X POST http://127.0.0.1:18840/api/stop
POST /api/diag
标准通道诊断(上控制器)。action:add / update / remove。
{
"action": "add",
"slot": 1,
"subslot": 1,
"ch": 32768,
"chBits": 0,
"severity": 0,
"chErrorType": 2832,
"extChErrorType": 0,
"extChAddValue": 0
}
| 字段 | 说明 |
|---|---|
slot / subslot | 0–65534(65535 规范保留) |
ch | 0–0x8000(0x8000 = 整子模块) |
chBits | 仅 add:0 / 1 / 2 / 4 / 8 / 16 / 32 / 64 |
severity | 仅 add:0 故障 / 1 需要维护 / 2 要求维护 / 3 合格化 |
chErrorType | 通道错误类型(例 0x0B10 = 2832) |
{ "ok": true, "action": "add", "slot": 1, "subslot": 1, "timestamp": "…" }
插拔类诊断由栈在模块插拔时自动发,不要用本端点冒充。
POST /api/alarm
过程报警(设备→控制器)。一次一条在途;上一条未获控制器确认则拒发下一条。
{ "slot": 1, "subslot": 1, "usi": 1, "data": "A1B2" }
| 字段 | 说明 |
|---|---|
slot / subslot | 0–65534 |
usi | 0 = 无负载(此时 data 必须空);1–0x7FFF = 厂商 USI |
data | 可选 hex,负载 ≤ 1408 字节 |
{ "ok": true, "slot": 1, "subslot": 1, "usi": 1, "length": 2, "timestamp": "…" }
诊断报警走 POST /api/diag,不要混用。
POST /api/alarms/ack
确认单条活动报警。id 取自 GET /api/alarms。无此活动记录返回 404。
{ "id": "Pnet.LinkDown" }
{ "ok": true, "message": "报警已确认: Pnet.LinkDown", "timestamp": "…" }
POST /api/alarms/ack-all
确认全部活动报警。无请求体。无活动报警时仍 ok=true,acknowledgedCount=0。
{ "ok": true, "message": "已确认全部报警: 2 条", "acknowledgedCount": 2, "timestamp": "…" }
POST /api/reset
connected=true 时禁止。
{ "mode": "communication" }
mode | 行为 |
|---|---|
communication | 软停 + 重启。应用参数记录保留 |
factory | 销毁实例 + 全新启动。用户区记录清空。通讯参数 / IP 仍由控制器 DCP ResetToFactory 处理 |
未知 mode 返回 400。
POST /api/config/reload
重读 appsettings.json + DARRA_PNET_* + 运行配置 XML,写回服务运行配置。下次启动从站才对栈生效,不热切运行中的 AR。
connected=true 时禁止。
{
"ok": true,
"message": "配置已重载并写入服务运行配置 (下次启动从站生效); 对运行中栈生效需重启服务",
"reloadedAt": "…"
}