HTTP / MOTORSENSE 驱动
概述
基于 HTTP 协议的两种模式:
HTTP— 外部系统通过/api/v1/tag/{tagId}/value或/api/httppush 值后,绑定到 edge 内部缓存 (current_value_map)。每个采集周期从缓存中 read。MOTOR_SENSE— 通过 polling KOPENS Motor Sense API 采集信号/状态数据。需单独通过 reflection 加载plantpulse-edge-driver-motorsensor.jar。
| 项目 | HTTP | MOTOR_SENSE |
|---|---|---|
opc_type | HTTP | MOTOR_SENSE |
| 实现类 | plantpulse.driver.protocol.http.HTTPDriver | plantpulse.driver.protocol.motor_sense.MotorSenseDriver (独立 jar) |
| read | ✅ (缓存) | ✅ (HTTP polling) |
| write | ✅ (bind()) | ❌ |
| 安全 | 无 (REST 端需认证时使用代理) | API Key + customer-id |
HTTP 模式
OPC 注册表单
| 字段 | 含义 | 示例 |
|---|---|---|
opc_agent_ip | (实际未使用,仅用于识别) | 127.0.0.1 |
opc_agent_port | (实际未使用) | 0 |
timecycle | 缓存 read 周期 (ms) | 1000 |
标签 plc_address 格式
自由键字符串。与 bind(io_address, value) 的 io_address 一一对应。
| 表示 | 含义 |
|---|---|
temperature | 由外部通过 bind("temperature", "25.7") 传入的值 |
line/A/rpm | 可使用包含斜杠的自由字符串 |
写入值 (POST /api/v1/tag/{tagId}/value)
curl -X POST http://<edge-host>/api/v1/tag/OPC_HTTP_TAG_00001/value \
-H "Content-Type: application/json" \
-d '{ "value": "42.5" }'
内部调用 HTTPDriver.bind(plc_address, "42.5") → 下一个 polling 周期即可 read 到该值。
curl 注册示例 (HTTP)
curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_HTTP_BIND",
"opc_type": "HTTP",
"opc_name": "External HTTP Bind",
"opc_agent_ip": "127.0.0.1",
"opc_agent_port": "0",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"tag_list": [
{
"tag_id": "OPC_HTTP_BIND_TAG_00001",
"tag_name": "ExtTemp",
"plc_address": "temperature",
"data_type": "Float"
}
]
}'
MOTOR_SENSE 模式
特点
- 无需输入 IP / Port (使用 HTTP 协议,但注册表单中会自动填入 OPC 代理的 IP/端口)
- 无需手动输入标签信息 — 自动生成 (
signals、health_index共 2 个) - 以 JSON 格式采集数据
- 按 ASSET 分组显示数据
OPC 注册表单
| 字段 | 含义 | 保存位置 |
|---|---|---|
| API KEY | Motor Sense API 认证密钥 | options.api-key |
| 客户 ID | 客户标识符 | options.customer-id |
| 资产列表 URL | 资产列表查询 URL | options.asset-list-url |
| 资产信号 URL | 资产信号数据 URL | options.asset-signal-url |
| 资产状态指数 URL | 资产状态指数 URL | options.asset-status-url |
| 波形/频谱加载 | 是否加载波形/频谱数据 | options.load-waveform-spectrum (可选) |
URL 必须以 http:// 或 https:// 开头 (JS 端校验)。
自动生成的标签
tag_id | tag_name | plc_address | data_type |
|---|---|---|---|
<OPC_ID>_TAG_00001 | signals | signals | String |
<OPC_ID>_TAG_00002 | health_index | health_index | String |
VALUE 以 JSON 数组字符串保存 (一个标签内包含多个 ASSET 数据)。
signals VALUE 示例
[
{
"asset_id": "4d4c097f-4449-4cf0-a7ec-b770e3950e00",
"sensor_number": "1300",
"created_at": 1768376660,
"temperature": 25.7,
"voltage": 3.31,
"rms_x": 0.1733,
"rms_y": 0.4156,
"rms_z": 0.4697,
"rms_xyz": 0.5476
}
]
health_index VALUE 示例
[
{
"asset_id": "4d4c097f-4449-4cf0-a7ec-b770e3950e2a",
"time": "2021-12-21",
"imbalance_health": 0.98,
"misalignment_health": 1.0,
"looseness_health": 1.0,
"bearing_health": 1.0,
"asset_health": 0.99
}
]
curl 注册示例 (MOTOR_SENSE)
curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_MS_PLANT_A",
"opc_type": "MOTOR_SENSE",
"opc_name": "Motor Sense Plant A",
"opc_agent_ip": "127.0.0.1",
"opc_agent_port": "0",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"options": {
"api-key": "YOUR_API_KEY",
"customer-id": "kopens-001",
"asset-list-url": "https://api.example.com/assets",
"asset-signal-url": "https://api.example.com/signals",
"asset-status-url": "https://api.example.com/health",
"load-waveform-spectrum": "false"
},
"tag_list": [
{
"tag_id": "OPC_MS_PLANT_A_TAG_00001",
"tag_name": "signals",
"plc_address": "signals",
"data_type": "String",
"description": "에셋의 시그널 데이터"
},
{
"tag_id": "OPC_MS_PLANT_A_TAG_00002",
"tag_name": "health_index",
"plc_address": "health_index",
"data_type": "String",
"description": "에셋의 상태 지수"
}
]
}'
MOTOR_SENSE 的特有行为差异
| 一般 PLC | MOTOR_SENSE |
|---|---|
isConnected() 为 false 时跳过 read | 即使为 isConnected()=false 也尝试 read (基于 HTTP,短暂断连常见) |
| 界面显示常规 TAG 表格 | 按 ASSET 显示卡片 (HEALTH INDEX / SIGNAL) |
| 刷新 = 页面 reload | 1 秒周期后台刷新 (无加载提示) |
常见错误 + 解决方法
| 消息 / 现象 | 原因 | 解决 |
|---|---|---|
MOTOR_SENSE 드라이버를 사용하려면 plantpulse-edge-driver-motorsensor.jar를 classpath에 추가 | 未安装独立 jar | 将 jar 放置到 WebContent/WEB-INF/lib/ 后重新部署 |
401 Unauthorized (Motor Sense) | API KEY / customer-id 错误 | 使用 KOPENS 签发的正确密钥。同时确认 URL endpoint |
HTTP 模式下 value 始终为空 | 未调用 bind(),或 plc_address 与 io_address 不一致 | 通过 POST /api/v1/tag/{tagId}/value push 后等待下一个周期 |
tag write not supported for opc_type=... | 对非 HTTP 协议调用了 write | 仅 HTTP 协议标签可写。参考后续 Phase 3 |
示例集 (按数据类型,HTTP 模式)
HTTP 模式直接接收外部系统 push 的自由字符串值。raw 为 String,data_type / fomula 用于后处理。
Boolean
data_type | plc_address | push 示例 (POST /api/v1/tag/.../value) | 备注 |
|---|---|---|---|
Boolean | pump1.run | {"value":"true"} | true/false 字符串 |
Boolean | door.open | {"value":"1"} | 也可使用 1/0 (后处理转换) |
整数
data_type | plc_address | push 示例 | 备注 |
|---|---|---|---|
Integer | counter.production | {"value":"12345"} | |
Long | counter.total | {"value":"9876543210"} | 超过 32-bit |
浮点数
data_type | plc_address | push 示例 | 备注 |
|---|---|---|---|
Float | temperature | {"value":"25.7"} | |
Double | power.kw | {"value":"1234.56789"} | 高精度 |
字符串
data_type | plc_address | push 示例 | 备注 |
|---|---|---|---|
String | recipe.name | {"value":"R-2025-A"} | 自由字符串 |
String | barcode.last | {"value":"880699112"} | 条码采集 push |
Formula 应用 (HTTP)
| 用途 | data_type | fomula | 备注 |
|---|---|---|---|
| 外部 push 值缩放 | Float | ${VALUE}*1.8+32 | C → F |
| 两个外部值求和 | Float | ${VALUE}+${EXT_OFFSET} | 引用其他 HTTP 标签 |
curl 综合示例 (HTTP push 流程)
# 1) OPC + 태그 등록
curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_HTTP_FULL",
"opc_type": "HTTP",
"opc_name": "External Bind Full",
"opc_agent_ip": "127.0.0.1",
"opc_agent_port": "0",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"tag_list": [
{"tag_id":"OPC_HTTP_FULL_T01", "tag_name":"PumpRun", "plc_address":"pump1.run", "data_type":"Boolean"},
{"tag_id":"OPC_HTTP_FULL_T02", "tag_name":"Counter", "plc_address":"counter.prod", "data_type":"Integer"},
{"tag_id":"OPC_HTTP_FULL_T03", "tag_name":"TempC", "plc_address":"temperature", "data_type":"Float"},
{"tag_id":"OPC_HTTP_FULL_T04", "tag_name":"TempF", "plc_address":"temperature", "data_type":"Float", "fomula":"${VALUE}*1.8+32"},
{"tag_id":"OPC_HTTP_FULL_T05", "tag_name":"BatchName", "plc_address":"recipe.name", "data_type":"String"}
]
}'
# 2) 외부에서 값 push
curl -X POST http://<edge-host>/api/v1/tag/OPC_HTTP_FULL_T01/value \
-H "Content-Type: application/json" -d '{"value":"true"}'
curl -X POST http://<edge-host>/api/v1/tag/OPC_HTTP_FULL_T03/value \
-H "Content-Type: application/json" -d '{"value":"25.7"}'
# 3) 다음 polling 주기 후 조회
curl -s http://<edge-host>/api/v1/tag/OPC_HTTP_FULL_T03/value | jq
curl -s http://<edge-host>/api/v1/tag/OPC_HTTP_FULL_T04/value | jq # fomula 적용된 화씨값