← 개발자 참고로 ← Back to Developer notes
범용 MQTT→Edge 브리지의 역할과 프로토콜. 드라이버를 붙이기 전에 읽어 보세요.
AEB의 MQTT 브리지는 범용·수신 전용(SUBSCRIBER-only) 브리지입니다. 외부 MQTT 브로커에 mTLS로 접속해 토픽을 구독하고, 받은 메시지를 같은 LAN의 SmartThings Hub Edge 드라이버로 HTTP POST 포워딩합니다. 특정 벤더(LG·AWS 등)를 전혀 알지 못하는 범용 파이프입니다 — 인증서·토픽·clientId만 주면 됩니다.
AEB's MQTT bridge is a general-purpose, receive-only (SUBSCRIBER) bridge. It connects to an external MQTT broker over mTLS, subscribes to topics, and HTTP-POST forwards received messages to a SmartThings Hub Edge driver on the same LAN. It is a generic pipe that knows nothing about any vendor (LG, AWS, …) — you just hand it a certificate, topics, and a clientId.
메시지는 한 방향으로만 흐릅니다: 브로커 → AEB → 허브 드라이버.
Messages flow one way only: broker → AEB → hub driver.
제어 평면(세션 생성·connect·forward 등록)도 같은 방향입니다: 드라이버가 LAN HTTP로 AEB의 /mqtt/* API를 호출합니다. 데이터 평면(메시지)만 AEB→허브로 흐릅니다.
The control plane (create session, connect, register forward) runs the same way: the driver calls AEB's /mqtt/* API over LAN HTTP. Only the data plane (messages) flows AEB→hub.
AEB는 LAN에 로컬 HTTP API를 노출합니다(기본 포트 8088). 모든 요청에 헤더 X-AEB-Api-Version: 1이 필요합니다. 아래는 Interface-Spec v0.3 §4 와 일치합니다.
AEB exposes a local HTTP API on the LAN (default port 8088). Every request requires the header X-AEB-Api-Version: 1. The below matches Interface-Spec v0.3 §4.
| Method | 경로 | Path | 역할 | Role |
|---|---|---|---|---|
| POST | /mqtt/sessions |
세션 생성 + RSA2048 키쌍 + PKCS#10 CSR(PEM) 발급 | Create session + RSA2048 keypair + PKCS#10 CSR (PEM) | |
| POST | /mqtt/sessions/{id}/connect |
브로커 mTLS 접속 + 토픽 구독 | mTLS connect to broker + subscribe to topics | |
| PUT | /mqtt/sessions/{id}/forward |
포워드 타깃 등록(멱등) → http://<hub>:port/path |
Register forward target (idempotent) → http://<hub>:port/path | |
| GET | /mqtt/sessions/{id}/status |
상태 + 진단 조회 | Read state + diagnostics | |
| DELETE | /mqtt/sessions/{id} |
세션 종료 + 키·인증서 삭제 | Terminate session + erase keys/certs | |
| GET | /mqtt/sessions/{id}/messages?since= |
(선택) 캐치업 폴링 — 버퍼된 메시지 페이지 조회 | (optional) Catch-up polling — page through buffered messages |
요청 본문은 선택. 응답에서 받은 csrPem을 외부 CA로 서명해 connect의 certPem으로 씁니다. 개인키는 AEB 안에만 남고 절대 응답에 포함되지 않습니다.
Request body optional. Sign the returned csrPem with an external CA and use it as certPem in connect. The private key stays inside AEB and is never returned.
// request (optional) { "keyType": "RSA2048", "subjectCN": "AWS IoT Certificate" } // 201 response { "sessionId": "sess_ab12cd34ef56", "csrPem": "-----BEGIN CERTIFICATE REQUEST-----\n...", "state": "CREATED" }
qos는 0 또는 1만 허용(2 미지원). topics는 최소 1개, 와일드카드 +·# 가능. caPem 생략 시 시스템 신뢰 저장소 사용. clientId 생략 시 aeb-<sessionId> 사용 — AWS IoT/ThinQ는 정책에 맞는 clientId가 필요합니다.
qos is 0 or 1 only (2 unsupported). topics needs ≥1 entry; wildcards +/# allowed. If caPem is omitted the system trust store is used. If clientId is omitted, aeb-<sessionId> is used — AWS IoT/ThinQ require a policy-matching clientId.
// request { "certPem": "-----BEGIN CERTIFICATE-----\n...", "caPem": "-----BEGIN CERTIFICATE-----\n...", // optional "endpoint": "xxxx-ats.iot.ap-northeast-2.amazonaws.com", "port": 8883, "topics": ["device/+/state", "device/status"], "qos": 1, "keepAliveSec": 60, "clientId": "my-device-id" // optional } // 200 response { "sessionId": "sess_ab12cd34ef56", "state": "CONNECTING", "subscribedTopics": ["device/+/state","device/status"] }
멱등. hubAddress를 생략하면 AEB가 요청 소스 IP(=허브)를 사용합니다. path 기본값 /aeb/ingest.
Idempotent. If hubAddress is omitted, AEB uses the request source IP (= the hub). path defaults to /aeb/ingest.
// request { "hubPort": 12345, "path": "/aeb/ingest", "hubAddress": null } // 200 response { "sessionId": "sess_ab12cd34ef56", "forwardTarget": "http://192.168.0.20:12345/aeb/ingest" }
{
"sessionId": "sess_ab12cd34ef56",
"state": "CONNECTED",
"subscribedTopics": ["device/+/state", "device/status"],
"forwardTarget": "http://192.168.0.20:12345/aeb/ingest",
"pendingForwardCount": 0,
"lastConnectedTs": 1717689874000,
"lastForwardOkTs": 1717689900000,
"lastError": null,
"effectiveClientId": "my-device-id", // actual clientId of the CONNECT (aeb-<id> if fallback)
"liveClientIdConnections": 1, // concurrent connections using the same clientId (1=normal, ≥2=duplicate)
"forwardFailureCount": 3, // consecutive forward-delivery failures since last success (0 = omitted)
"lastForwardErrorTs": 1717690000000, // last delivery failure time (absent if none)
"forwardTargetHealthy": false // false = deliveries are failing now, re-register /forward (true = omitted)
}
{ "error": { "code": "SESSION_NOT_FOUND", "message": "..." } }
세션은 다음 상태를 거칩니다. status의 state 필드로 노출됩니다.
A session moves through these states, exposed as the state field of status.
CREATED → CONNECTING → CONNECTED → DISCONNECTED | ERROR
connect 수락, mTLS 핸드셰이크 + CONNACK 대기 중.connect accepted, mTLS handshake + awaiting CONNACK.connect.connect.lastError에 원인.lastError.CONNECTED 상태에서 받은 각 MQTT 메시지는 아래 JSON으로 포워드 타깃에 POST됩니다(Interface-Spec v0.3 §5).
While CONNECTED, each received MQTT message is POSTed to the forward target as the JSON below (Interface-Spec v0.3 §5).
// POST <forwardTarget> body: { "sessionId": "sess_ab12cd34ef56", "seq": 1, "topic": "device/abc/state", "payload": "{\"power\":\"on\"}", "payloadEncoding": "utf8", // "utf8" | "base64" "ts": 1717689900000 }
utf8), 아니면 base64.utf8); otherwise base64.lastError 기록.lastError.PUT /forward는 성공해도 실제 배달(POST)이 계속 실패할 수 있습니다(예: 등록된 포트가 살아있지 않음). status의 forwardTargetHealthy(false=실패 중), forwardFailureCount(마지막 성공 이후 누적), lastForwardErrorTs로 감지하세요. 배달 시도가 없었으면 healthy입니다(트래픽 없음 ≠ 실패). 리셋 조건: 배달 성공 또는 PUT /forward 수신 시. 드라이버는 폴링 중 forwardTargetHealthy===false를 보면 즉시 PUT /forward로 재등록할 것을 권장합니다.PUT /forward can succeed while actual delivery (POST) keeps failing (e.g. the registered port is no longer alive). Detect this via status's forwardTargetHealthy (false = currently failing), forwardFailureCount (cumulative since last success), and lastForwardErrorTs. No delivery attempts yet = healthy (no traffic ≠ failure). Reset condition: on delivery success or on receiving PUT /forward. Drivers are encouraged to re-issue PUT /forward immediately when polling observes forwardTargetHealthy===false./messages 폴링으로 복구 가능)./messages polling).caPem을 주면 그 CA만 신뢰. 생략하면 시스템 신뢰 저장소 사용.endpoint)을 TLS SNI로 전송합니다. AWS IoT 등 일부 브로커는 SNI를 요구합니다.clientId를 넣어 주세요.caPem to trust only that CA; omit it to use the system trust store.endpoint) as the TLS SNI. Some brokers (e.g. AWS IoT) require it.clientId on connect.이 브리지로 드라이버를 만드는 5단계 + LG ThinQ 사례 + 활용 케이스.
The 5-step driver flow + LG ThinQ case + use cases.
Edge Bridge HTTP API 레퍼런스와 EdgeBridgeBase 참고 저장소.
The EdgeBridge HTTP API reference and the EdgeBridgeBase sample repo.