HTTP / MOTORSENSE 드라이버
개요
HTTP 프로토콜 기반의 두 가지 모드:
HTTP— 외부 시스템이/api/v1/tag/{tagId}/value또는/api/http로 값을 push 하면 edge 내부 캐시 (current_value_map) 에 bind. 수집 주기마다 캐시에서 read.MOTOR_SENSE— KOPENS Motor Sense API 를 polling 해 시그널/상태 데이터를 수집. 별도plantpulse-edge-driver-motorsensor.jar가 reflection 으로 로드됩니다.
| 항목 | 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 와 1:1 대응.
| 표기 | 의미 |
|---|---|
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_index2개) - 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 skip | isConnected()=false 여도 read 시도 (HTTP 기반이라 일시 단절 흔함) |
| 화면에서 일반 TAG 테이블 표시 | ASSET 별 카드 (HEALTH INDEX / SIGNAL) 표시 |
| 갱신 = 화면 reload | 1 초 주기 백그라운드 갱신 (로딩 표시 없음) |
흔한 에러 + 해결
| 메시지 / 증상 | 원인 | 해결 |
|---|---|---|
MOTOR_SENSE 드라이버를 사용하려면 plantpulse-edge-driver-motorsensor.jar를 classpath에 추가 | 별도 jar 미설치 | WebContent/WEB-INF/lib/ 에 jar 배치 후 재배포 |
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 프로토콜 태그에만 write 가능. 후속 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 적용된 화씨값