개요
연동 방식은 목적에 따라 두 가지입니다.
| 방식 | 용도 | 전송·형식 | 인증 | 접근 범위 |
|---|---|---|---|---|
| HTTP/JSON API | 채널·이벤트·검색·재생 조회 | HTTP POST · JSON | Bearer(JWT) | HTTPS 권장 |
| 실시간 이벤트 | 이벤트 발생 즉시 수신 | Connect 서버 스트림 | Bearer(JWT) | HTTPS 권장 |
EdgeFlow AI 서버는 Connect RPC 규격으로 API를 제공합니다. 모든 호출은 POST /edgeflowai.v4.<서비스>/<메서드> 형태이며, 본문은 JSON입니다. 같은 경로로 gRPC·gRPC-Web 클라이언트도 사용할 수 있습니다.
인증
Login으로 받은 JWT를 Authorization: Bearer 헤더에 넣습니다. 인증 없이 부를 수 있는 API는 Login·Me뿐입니다.
권한
관리자는 전체, 운영자 등 일반 역할은 조회 API만 호출할 수 있습니다. 허용되지 않은 호출은 permission_denied를 반환합니다.
데이터 형식
필드는 lowerCamelCase JSON(예: channelUids), 시각은 RFC3339 UTC입니다. 화면 표시는 KST 기준입니다.
빠른 시작
1. 로그인
# YOUR_SERVER·계정은 관리자가 안내한 값으로 바꿉니다.
curl -X POST "https://YOUR_SERVER/edgeflowai.v4.AuthService/Login" \
-H "Content-Type: application/json" \
-H "Connect-Protocol-Version: 1" \
--data '{"username":"YOUR_USERNAME","password":"YOUR_PASSWORD"}'
HTTP 200이어도 로그인 실패일 수 있습니다. 응답의 ok가 true이고 token이 있을 때만 다음 단계로 진행하세요. 10회 연속 실패하면 5분간 잠기며 lockedUntil로 해제 시각을 알려 줍니다.
2. 채널 목록
curl -X POST "https://YOUR_SERVER/edgeflowai.v4.ChannelService/ListChannels" \
-H "Content-Type: application/json" \
-H "Connect-Protocol-Version: 1" \
-H "Authorization: Bearer YOUR_TOKEN" \
--data '{}'
버전별 공개 API
설치된 제품 버전을 선택하면 해당 버전에서 사용할 수 있는 API를 보여 줍니다.
| API | 설명 | 인증 | 도입 |
|---|
경로는 모두 POST /edgeflowai.v4.<서비스>/<메서드>입니다. API 이름을 누르면 상세 설명과 코드 예제로 이동합니다. 이 밖의 관리 API(사용자·장비 제어·설정·업데이트 등)는 보안상 공개하지 않습니다.
공통 규칙
- 필드명은 JSON lowerCamelCase입니다(예:
channelUids). int64·uint64값은 JSON에서 문자열로 옵니다(예:"expiresAt":"1792432800"). 요청에는 숫자도 받습니다.- 시각(
Timestamp)은 RFC3339 UTC 문자열입니다(예:"2026-10-19T01:00:00Z"). - enum은 이름 문자열로 옵니다(예:
"CHANNEL_STATE_NORMAL"). - 기본값(0, 빈 문자열, false, 빈 배열)인 필드는 응답에서 생략됩니다. 필드가 없으면 기본값으로 처리하세요.
- 일부 노드만 실패한 경우 오류 대신 성공한 결과와
warnings를 함께 반환합니다.
오류 응답
HTTP 4xx·5xx와 함께 {"code":"unauthenticated","message":"..."} 형태로 반환합니다.
| code | HTTP | 원인 |
|---|
API 상세
v1.4.16 기준입니다(공개 API 정의는 v1.4.15와 동일). 예시의 값은 모두 가상의 값입니다.
실시간 이벤트
EventStreamService/StreamEvents는 서버 스트리밍 API입니다. 연결을 유지한 채 이벤트가 발생할 때마다 메시지를 받습니다.
- 요청:
kinds(예:va_event,alarm,node_status),channelUids로 필터 - 연결 유지:
kind가ping인 메시지가 구독 직후와 15초마다 옵니다. 무시하고, 45초 이상 아무 메시지도 없으면 재연결하세요. - 메시지:
kind,channelUid,time,json(이벤트 본문 JSON 문자열) - 인증된 사용자는 역할과 무관하게 구독할 수 있습니다.
스트리밍은 길이 접두 바이너리 프레임을 사용하므로 curl보다 connect-web(TypeScript), connect-go, grpcurl 같은 Connect·gRPC 클라이언트 사용을 권장합니다. 연결이 끊기면 재연결하고, 누락 구간은
StatsService/ListEvents로 보완하세요.이벤트 데이터
이벤트는 실시간 이벤트(StreamEvents의 va_event 메시지 json)와 이벤트 이력(ListEvents의 items)으로 받습니다. 모든 이벤트가 같은 공통 필드를 갖고, 종류에 따라 일부 필드가 추가됩니다.
이벤트 흐름
하나의 이벤트는 같은 eventId로 BEGIN → CONTINUE → END 순서의 메시지로 전달됩니다.
| 상태 | 언제 오는가 | 함께 바뀌는 값 |
|---|---|---|
| BEGIN | 이벤트가 확정된 순간 1회 | transitionSeq 1, stayTime은 확정까지 걸린 시간(0일 수 있음) |
| CONTINUE | 이벤트가 이어지는 동안 진행 상태가 바뀔 때. 주기적이지 않으며 오지 않을 수도 있음 | transitionSeq 증가, stayTime·abnormalScore·box 갱신 |
| END | 대상이 사라지거나 조건이 해제된 순간 1회 | 최종 stayTime(이벤트 지속 시간) |
- 라인 통과처럼 순간적인 이벤트는
BEGIN과END가 거의 동시에 옵니다. - 이벤트 이력(
ListEvents)에는 BEGIN 시점에 한 건이 생기고, END가 오면endTs가 채워집니다.endTs가 없으면 진행 중입니다. - 메시지가 순서대로 오지 않거나 일부가 빠질 수 있으니
transitionSeq로 순서를 맞추고, END를 받지 못한 이벤트는ListEvents로 상태를 확인하세요. - 알림은 BEGIN에서 한 번만 보내고, CONTINUE·END는 같은 이벤트의 갱신으로 처리하는 것을 권장합니다.
이벤트 종류
eventType에 아래 문자열이 옵니다. ListEvents의 eventTypes 필터에도 같은 값을 씁니다.
| eventType | 이름 | 설명 |
|---|---|---|
| 영역·행동 | ||
| Intrusion | 침입 | 지정 영역에 대상이 들어와 머묾 |
| MachineActiveIntrusion | 위험 설비 접근 | 설비 가동 중 영역 진입 |
| Loitering | 배회 | 영역 안에서 일정 시간 이상 서성임 |
| LongstayLevel | 장기 체류 | 체류 시간 단계(1·2·3) 도달 |
| LineCrossing LineEnter / LineExit | 라인 통과 | 지정한 선을 넘음(진입·진출 방향) |
| AbnormalObjectCount | 객체 밀집 | 영역 안 객체 수가 기준을 넘음 |
| 사람 안전 | ||
| Falldown | 쓰러짐 | 사람이 넘어진 자세 |
| FallMotionless | 쓰러짐(무동작) | 쓰러진 채 움직임 없음(단계 1 경고 · 2 긴급) |
| Fight | 싸움 | 사람 간 싸움 행동 |
| Violence | 폭력 | 폭력 행동(이전 판정 방식) |
| DangerousWork | 끼임 | 작업자 신체가 설비에 근접 |
| PPE | 안전장구 미착용 | 안전모 등 보호구 미착용 |
| 화재·사물·계기 | ||
| Smoke / Flame | 연기 / 불꽃 | 연기 또는 불꽃 감지 |
| AbandonedObject | 유기(방치물) | 소유자가 떠난 뒤 물체가 남음 |
| ValueChange | 값 변화 | 계기·표시창 숫자 판독값 변화 |
| 교통 | ||
| JayWalking | 무단횡단 | 보행 신호가 아닐 때 횡단 |
| CrosswalkRiding | 불법 횡단(이동체) | 이륜차 등이 횡단보도 위를 주행 |
| IllegalParking | 불법 주정차 | 금지 구역 정차 |
| WrongWayDriving | 역주행 | 진행 방향과 반대로 주행 |
교통량·차로 방향(좌회전·우회전·유턴)·대기 차량 등 교통 분석 이벤트는 교통 분석 옵션 도입 시 별도로 안내합니다.
공통 필드
실시간 이벤트(va_event)의 json 본문 기준입니다.
| 필드 | 타입 | 설명 |
|---|---|---|
| eventType | string | 이벤트 종류(위 표) |
| eventStatus | string | BEGIN 시작 · CONTINUE 진행 중 상태 변화 · END 종료(위 이벤트 흐름 참고) |
| eventId | int | 채널 안 이벤트 번호. 같은 eventId의 BEGIN과 END가 한 이벤트 |
| transitionSeq | int | 같은 이벤트 안의 메시지 순번(1부터 증가) |
| eventUid | string | 이벤트 전역 고유 ID(있을 때). 이벤트 묶기에 권장 |
| cameraUid | string | 채널 키(= channelUid) |
| cameraName | string | 채널 이름 |
| objectId | int | 객체 추적 ID(사람 신원이 아님) |
| classId | int | 객체 종류 — 아래 표준 클래스 번호 |
| prob | double | 검출 신뢰도(0~1) |
| box | object | {x, y, width, height} 0~1 정규화. bbox 배열은 같은 값의 호환용 표기 |
| roiId / roiName | string | 이벤트가 발생한 관심 영역 |
| roi | number[][] | 관심 영역 다각형(0~1 정규화, 있을 때) |
| ruleId / ruleName | string | 이벤트를 발생시킨 분석 규칙 |
| riskLevel | int | 위험도 1 관심 · 2 주의 · 3 경계 · 4 심각(0 미지정) |
| stayTime | double | 대상이 머문 시간(초) |
| abnormalScore | double | 판정 점수. 의미는 이벤트 종류마다 다르며, 단계형 이벤트에서는 단계값 |
| timestamp | string | 분석 장비의 로컬 시각 문자열(시간대 없음). 절대 시각은 메시지의 time(UTC)을 사용 |
종류별 추가 필드
| 이벤트 | 필드 | 설명 |
|---|---|---|
| ValueChange | valueText valuePrevious valueTrigger valueConfidence | 새 값 · 이전 값 · 판정 방식(change, digits, threshold, equals, direction, delta, stall) · 판독 신뢰도 |
| JayWalking CrosswalkRiding | signalStateAtBegin beginReason objectSpeed | 시작 시점 보행 신호(RED·GREEN) · 시작 사유(예: red_entry, outside_crosswalk) · 이동 속도(CrosswalkRiding) |
| FallMotionless LongstayLevel | abnormalScore reason | 단계값(FallMotionless 1·2, LongstayLevel 1·2·3) · 단계 변화 사유 |
| LineCrossing LineEnter / LineExit | crossing | 통과 방향 enter · exit. 순간 사건이라 BEGIN과 END가 거의 동시에 옴 |
| Loitering Intrusion 등 | stayTime | 영역 안에 머문 시간(초) |
표준 클래스 번호
실시간 이벤트·이벤트 이력의 classId와 ListEvents의 objectTypes 필터가 쓰는 번호입니다.
| 번호 | 객체 | 번호 | 객체 |
|---|---|---|---|
| 0 | 사람 | 100 | 차량(일반) |
| 2 | 쓰러진 사람 | 102 | 자전거 |
| 3 | 폭력 자세 | 103 | 이륜차(오토바이) |
| 4 | 머리(인원수 산출 기준) | 125 | 트럭 |
| 5 | 안전모 착용 머리 | 134 | 버스 |
| 200 | 연기 | 500 | 가방·물체(유기 대상) |
| 201 | 불꽃 | 1001~1004 | 장갑 · 보안면 · 안전화 · 용접 토시 |
- 차량은 배포된 모델에 따라 101~133의 세부 차종 번호(세단, SUV, 지게차 등)로 올 수 있습니다.
- 3000 이상은 표준에 없는 모델 고유 클래스, 1000000 이상은 현장에서 정의한 사용자 클래스입니다.
- 값 변화(ValueChange)처럼 영역을 직접 판독하는 이벤트는 classId가 대상 객체를 뜻하지 않습니다.
- SearchMetadata는 다른 번호 체계를 씁니다(사람 0, 승용차 2, 이륜차 3, 버스 4, 트럭 5, 불꽃 50, 연기 51). 같은 숫자라도 뜻이 다르니 API별로 구분하세요.
이벤트별 샘플 데이터
그룹과 이벤트를 고르면 실시간 메시지 본문(va_event의 json, BEGIN 시점)과 이력 항목(ListEvents의 items[])을 보여 줍니다. 값은 모두 예시입니다.
실시간 이벤트와 이벤트 이력의 필드 이름
같은 이벤트라도 두 API에서 일부 이름과 형식이 다릅니다.
| 실시간 이벤트(va_event) | 이벤트 이력(ListEvents) | 비고 |
|---|---|---|
| cameraUid | channelUid | 같은 채널 키 |
| eventStatus BEGIN / CONTINUE / END | beginTs / endTs | 이력은 한 건으로 합쳐짐. endTs가 없으면 진행 중 |
| timestamp | beginTs | 로컬 문자열 ↔ UTC Timestamp |
| stayTime | staySec | |
| box / bbox | boxX · boxY · boxW · boxH | 이력은 시작 시점 위치 |
| riskLevel (1~4) | riskLevel (RISK_*) | 숫자 ↔ 이름(1 ATTENTION · 2 CAUTION · 3 ALERT · 4 SEVERE) |
| prob | — | 이력에는 신뢰도 없음 |
| — | ruleEventType | 규칙 유형. eventType과 다를 수 있음(예: Fight ↔ violence) |
| — | reviewStatus · sceneCaption | 이력에만 있는 사후 확인 상태 · AI 장면 설명 |
eventType이AllDetect인 메시지는 검출 확인용이며 이벤트가 아닙니다. 무시하세요.- 이벤트는
eventUid로 묶고, 없으면channelUid + eventId + 시각을 씁니다. 장비 재시작 후 eventId가 다시 쓰일 수 있습니다. - 이 표에 없는 필드는 내부용이거나 이후 추가될 수 있으니 무시하도록 구현하세요.
ruleId·riskLevel은 발생 시점 값이며, 이후 규칙을 바꿔도 지난 이벤트에는 반영되지 않습니다.
버전 이력
v1.3.0 이후 공개·관리 API는 추가만 있었고 제거되거나 이름이 바뀐 API는 없습니다.
| 버전 | 배포일 | API 수 | 변경 내용 |
|---|
유의사항
- v1.3.5부터 역할 기반 권한이 적용되어, 일반 역할 토큰으로 쓰기 API를 호출하면 거부됩니다.
ResolveSearchQuery는 서버에 로컬 AI 런타임이 설치되어 있어야 동작합니다.- 토큰·비밀번호를 URL, 공개 저장소, 로그에 남기지 마세요. 운영 서버는 HTTPS로 접속하세요.
- 연동 전 설치된 제품 버전(
VersionService/GetVersions)을 확인하고, 해당 버전에서 먼저 시험하세요. - 관리 화면 전용 기능(사용자·권한 관리, 장비 제어, 설정, 업데이트, AI 장면 설명 관리 등)의 API는 공개하지 않습니다.