Skip to main content

HTTP / MOTORSENSE Driver

Overview

Two modes based on the HTTP protocol:

  1. HTTP — when an external system pushes a value via /api/v1/tag/{tagId}/value or /api/http, it is bound to the edge internal cache (current_value_map). The cache is read on every collection cycle.
  2. MOTOR_SENSE — polls the KOPENS Motor Sense API to collect signal/status data. A separate plantpulse-edge-driver-motorsensor.jar is loaded via reflection.
ItemHTTPMOTOR_SENSE
opc_typeHTTPMOTOR_SENSE
Implementation classplantpulse.driver.protocol.http.HTTPDriverplantpulse.driver.protocol.motor_sense.MotorSenseDriver (separate jar)
read✅ (cache)✅ (HTTP polling)
write✅ (bind())
SecurityNone (use a proxy if authentication is required at the REST layer)API Key + customer-id

HTTP Mode

OPC Registration Form

FieldMeaningExample
opc_agent_ip(not actually used, for identification)127.0.0.1
opc_agent_port(not actually used)0
timecycleCache read cycle (ms)1000

Tag plc_address Format

A free-form key string. Maps 1:1 to the io_address of bind(io_address, value).

NotationMeaning
temperatureValue that arrived externally via bind("temperature", "25.7")
line/A/rpmFree-form string, slashes allowed

Writing Values (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" }'

Internally this calls HTTPDriver.bind(plc_address, "42.5") → the value is read on the next polling cycle.

curl Registration Example (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 Mode

Characteristics

  • No IP / Port entry required (uses the HTTP protocol, though the registration form auto-fills the OPC agent IP/port)
  • No manual tag entry required — tags are generated automatically (signals, health_index, 2 tags)
  • Collects data in JSON format
  • Displays data grouped by ASSET

OPC Registration Form

FieldMeaningStorage Location
API KEYMotor Sense API authentication keyoptions.api-key
Customer IDCustomer identifieroptions.customer-id
Asset List URLURL for retrieving the asset listoptions.asset-list-url
Asset Signal URLURL for asset signal dataoptions.asset-signal-url
Asset Health Index URLURL for the asset health indexoptions.asset-status-url
Load waveform/spectrumWhether to load waveform/spectrum dataoptions.load-waveform-spectrum (optional)

URLs must start with http:// or https:// (validated on the JS side).

Auto-generated Tags

tag_idtag_nameplc_addressdata_type
<OPC_ID>_TAG_00001signalssignalsString
<OPC_ID>_TAG_00002health_indexhealth_indexString

VALUE is stored as a JSON array string (multiple ASSET entries within a single tag).

signals VALUE Example

[
{
"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 Example

[
{
"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 Registration Example (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": "에셋의 상태 지수"
}
]
}'

Behavioral Differences Unique to MOTOR_SENSE

Standard PLCMOTOR_SENSE
read is skipped if isConnected() is falseread is attempted even when isConnected()=false (HTTP-based, so brief disconnections are common)
Standard TAG table shown on screenCards per ASSET (HEALTH INDEX / SIGNAL) shown
Refresh = screen reloadBackground refresh every 1 second (no loading indicator)

Common Errors and Resolutions

Message / SymptomCauseResolution
MOTOR_SENSE 드라이버를 사용하려면 plantpulse-edge-driver-motorsensor.jar를 classpath에 추가Separate jar not installedPlace the jar in WebContent/WEB-INF/lib/ and redeploy
401 Unauthorized (Motor Sense)API KEY / customer-id errorUse the exact key issued by KOPENS. Also verify the URL endpoint
value is always empty in HTTP modebind() is never called, or plc_address and io_address do not matchPush via POST /api/v1/tag/{tagId}/value and wait for the next cycle
tag write not supported for opc_type=...write called on a non-HTTP protocolwrite is only possible on HTTP protocol tags. See the follow-up Phase 3

Example Collection (by Data Type, HTTP Mode)

HTTP mode accepts the free-form string values pushed by external systems as-is. raw is a String, and data_type / fomula are used for post-processing.

Boolean

data_typeplc_addressPush example (POST /api/v1/tag/.../value)Notes
Booleanpump1.run{"value":"true"}true/false string
Booleandoor.open{"value":"1"}1/0 also possible (cast in post-processing)

Integer

data_typeplc_addressPush exampleNotes
Integercounter.production{"value":"12345"}
Longcounter.total{"value":"9876543210"}Exceeds 32-bit

Floating Point

data_typeplc_addressPush exampleNotes
Floattemperature{"value":"25.7"}
Doublepower.kw{"value":"1234.56789"}High precision

String

data_typeplc_addressPush exampleNotes
Stringrecipe.name{"value":"R-2025-A"}Free-form string
Stringbarcode.last{"value":"880699112"}Barcode capture push

Using Formulas (HTTP)

Purposedata_typefomulaNotes
Scale an externally pushed valueFloat${VALUE}*1.8+32C → F
Sum two external valuesFloat${VALUE}+${EXT_OFFSET}References another HTTP tag

Comprehensive curl Example (HTTP Push Flow)

# 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 적용된 화씨값