외부 프로그램 연동
엣지가 지원하지 않는 장비도 엣지의 데이터 모델로 들어올 수 있습니다.

외부에서 만든 프로그램이 값을 읽어 HTTP 로 밀어 넣으면, 그 값은 엣지가 직접 수집한 태그와 똑같이 취급됩니다. 플랫폼 전송·이력·알람·플로우가 전부 그대로 걸립니다. 드라이버를 새로 만들 필요가 없습니다.
- 엣지에 드라이버가 없는 프로토콜의 장비
- 이미 값을 읽고 있는 기존 시스템(MES · SCADA · 자체 수집기)
- 계산·가공을 거친 값을 올리고 싶을 때
어떻게 동작하나
HTTP 연결은 수집하지 않습니다. 값을 받아 두는 캐시입니다.
외부 프로그램 ──HTTP──▶ 엣지의 값 캐시 ──timecycle 주기로 샘플링──▶ 태그 이력 · 플랫폼
밀어 넣는데 왜 값이 사라지나
바깥은 푸시인데 엣지 안쪽은 여전히 폴링이기 때문입니다.
다른 드라이버는 엣지가 장비를 직접 폴링합니다. HTTP 는 그 «장비» 자리에 캐시가 앉은 것뿐이고, 캐시를 읽는 쪽은 똑같이 폴링입니다. 그래서 밀어 넣는 쪽과 읽는 쪽의 박자가 다르면 값이 어긋납니다.
| 바깥 → 엣지 | 엣지 → 이력 | |
|---|---|---|
| 방식 | 푸시 (외부가 원할 때) | 폴링 (timecycle 주기) |
| 놓치면 | — | 주기 사이의 값은 마지막 하나만 남습니다 |
메시지를 받는 드라이버는 전부 같은 구조입니다. 브로커에서 온 메시지를 «마지막 값» 하나로 덮어쓰고, 수집 스케줄러가 그것을 주기로 읽어 갑니다.
| 드라이버 | 값이 들어오는 곳 |
|---|---|
| HTTP | 외부 프로그램의 요청 |
| MQTT Client | 구독한 토픽 |
| Kafka | 컨슈머가 받은 레코드 |
| WebSocket | 수신 프레임 |
그래서 「브로커에 발행한 건수보다 수집된 건수가 훨씬 적다」는 것이 정상입니다. 브로커의 LAG 이 0 이면 엣지는 다 받고 있습니다 — 다만 이력에 남는 것은 주기마다 하나입니다. 이걸 유실로 오해해 오래 파고든 사례가 있습니다 (현장 사례집).
이 구조 때문에 따라오는 성질이 있습니다. 먼저 이해하고 시작하세요.
| 성질 | 뜻 |
|---|---|
| 밀어 넣은 값이 즉시 저장되지 않습니다 | 연결의 timecycle 주기로 샘플링됩니다 |
| 주기보다 빨리 밀면 중간값이 사라집니다 | 마지막 값만 남습니다 |
| 주기보다 느리게 밀면 같은 값이 반복 저장됩니다 | 캐시에 남은 값을 계속 읽습니다 |
빨리 반영되게 하려면 timecycle 을 줄이세요. 이 값이 곧 반영 지연입니다.
1000(1초)이면 최대 1초 뒤에 남고, 200 으로 줄이면 최대 0.2초 뒤에 남습니다. 최소값은
100(0.1초)입니다.
| 원하는 것 | timecycle |
|---|---|
| 거의 즉시 반영 | 100 ~ 200 |
| 일반적인 실시간 감시 | 1000 |
| 느리게 변하는 값(온도·수위) | 5000 이상 |
주기를 줄이면 지연은 줄지만 마지막 값 하나만 읽는다는 성질은 그대로입니다. 주기 사이에 값이 세 번 바뀌면 마지막 하나만 남습니다.
모든 이벤트를 하나도 빠뜨리지 않고 남겨야 한다면 이 방식이 맞지 않습니다. 주기를 아무리 촘촘히 잡아도 그렇습니다.
그 연결에 달린 모든 태그를 그 주기로 읽습니다. 태그가 많은 연결의 주기를 100 으로 내리면 부하가 그만큼 커집니다. 빨라야 하는 태그만 따로 HTTP 연결을 만들어 그 연결만 주기를 낮추는 편이 낫습니다.
1단계 — HTTP 연결을 만듭니다
화면에서 연결 → 추가 → HTTP 로 들어갑니다.
https://<엣지 주소>/ui/connect/http
HTTP 연결에는 드라이버 옵션이 하나도 없습니다. IP 와 포트 칸이 있지만 드라이버가 읽지 않습니다 — 형식상 입력이므로 아무 값이나 넣어도 동작에 영향이 없습니다.
REST 로 만들 수도 있습니다. 여덟 필드가 전부 필수입니다.
curl -X POST https://<엣지 주소>/api/v1/opc \
-H 'X-API-Key: <API 키>' \
-H 'Content-Type: application/json' \
-d '{
"opc_id": "OPC_EXTERNAL_01",
"opc_name": "외부 수집기",
"opc_type": "HTTP",
"site_id": "SITE_00001",
"opc_agent_ip": "127.0.0.1",
"opc_agent_port": 80,
"timecycle": 1000,
"async": false
}'
| 필드 | 규칙 |
|---|---|
opc_id | OPC_ 로 시작, 대문자·숫자·밑줄 1~60자 |
site_id | SITE_ 로 시작 |
opc_type | 정확히 HTTP 여야 합니다. 다르면 값 밀어넣기가 거부됩니다 |
opc_agent_port | 1~65535 |
timecycle | 100 이상(밀리초). 이 값이 곧 샘플링 주기입니다 |
화면으로 만들면 빠진 값을 화면이 채워 줍니다. 그래서 REST 로 만들 때만 필드 누락으로 연결이 만들어지고도 동작하지 않는 일이 생깁니다.
2단계 — 태그를 등록하고 tag_id 를 받습니다
그 연결 아래에 태그를 만듭니다. 값 하나가 태그 하나입니다.
데이터 타입을 값 성격에 맞게 고르세요. 값이 문자열로 와도 선언한 타입만 맞으면 정확히 파싱됩니다. 반대로 타입이 틀리면 적재 단계에서 예외가 납니다.
| 값 | 타입 |
|---|---|
| 전류 · 온도 · 전압 · 중량 · 속도 · 좌표 | Double |
| 배터리 · 에러코드 · 카운터 | Integer |
| 알람 · 상태 · 구역 · 방향 · 색 | String |
밀어넣을 때 쓸 tag_id 는 태그 목록 화면이나 태그 조회 API 로 확인합니다.
3단계 — 값을 밀어 넣습니다
curl -X POST https://<엣지 주소>/api/v1/tag/<tag_id>/value \
-H 'X-API-Key: <API 키>' \
-H 'Content-Type: application/json' \
-d '{"value":"1500"}'
값은 문자열로 보내도 됩니다. 태그에 선언한 타입으로 파싱됩니다.
인증
/api/ 아래는 전부 인증이 걸립니다. 키가 없으면 막힙니다 — 설정이 빠져 있어도
열리지 않습니다.
| 방법 | 형태 |
|---|---|
| 헤더 (권장) | X-API-Key: <키> |
| 헤더 | Authorization: Bearer <키> |
| 브라우저 세션 | 로그인 상태면 키 없이 통과 |
?api_key=… 는 v1 에서 제거됐습니다. 쓰면 401 입니다. 옛 예제를 그대로 옮기지 마세요.
HTTPS 로 부르세요
기본값이 HTTPS 전용입니다. http:// 로 부르면 403 이 돌아옵니다.
값이 안 들어올 때
순서대로 좁힙니다.
- 연결이 기동 중인가 — 정지 상태면 값을 받지 않고 거부합니다. 화면에서 그 연결을 시작하세요.
opc_type이HTTP인가 — 다른 타입의 연결에는 밀어넣을 수 없습니다.- HTTPS 로 불렀는가 —
http://는 403 입니다. - 키를 헤더로 보냈는가 — 쿼리 파라미터는 401 입니다.
tag_id가 맞는가 — 태그 목록에서 다시 확인합니다.- 주기를 기다렸는가 — 밀어 넣은 즉시 저장되지 않습니다.
timecycle만큼 기다린 뒤 이력을 봅니다.
알아 둘 것
한 번에 하나씩입니다. 여러 태그를 한 요청으로 밀어 넣는 엔드포인트는 없습니다. 태그마다 따로 호출합니다.
이중화 구성에서도 받습니다. 쓰기 권한이 없는 엣지라도 HTTP 로 밀어 넣는 값은 계속 받습니다. 외부 연동이 이중화 전환에 끊기지 않도록 일부러 그렇게 되어 있습니다.
옛 엔드포인트가 있습니다. POST /api/http 는 opc_id 와 plc_address 로 대상을 지정하는
예전 방식입니다. 2026년 12월 31일에 없어집니다. 요율 제한과 중복 방지도 걸리지 않으므로
새로 만드는 연동은 위의 /api/v1/tag/{tag_id}/value 를 쓰세요.
관련 문서
- 태그 추가 — 태그와 데이터 타입
- 연결 목록 — 연결 시작·정지
- PLC 주소 레퍼런스 — 다른 프로토콜의 주소 표기
- 현장 사례집 — 타입 예외·빈 값이 났을 때