역할
SCI는 삼성 SmartThings와 LH 스마트홈을 잇는 C2C(Cloud-to-Cloud) 커넥터임. 삼성 배포 @homeiot/partnersdk 기반 SmartApp 샘플을 LH용으로 고친 Node.js 서버임. 전체 그림은 공개노트/개발/시스템 구성.
- SmartThings → LH: 입주민이 SmartThings 앱에서 제어하면 SCI가 공개노트/개발/모듈/PIW 연계 서버의
/api/eum/devices/*를 호출함 - LH → SmartThings: 기기 상태가 바뀌면 PIW가 SCI의
/api/sci/partner로 이벤트를 보내고 SCI가 SmartThings API로 전달함 - SmartApp 라이프사이클: SmartThings 클라우드가 SCI의
/api/sci로 INSTALL/UPDATE/UNINSTALL/이벤트 등을 보냄 - SmartThings 앱 홈의 대시보드 카드(공지·주차·택배 등), 알림 항목 관리도 담당함(현재 대부분 미사용, 아래 참고)
기술 스택
| 항목 | 값 |
|---|---|
| 런타임 | Node.js, TypeScript(tsc -b → lib/) |
| 프로세스 매니저 | pm2, pm2-logrotate(300MB, 60개 보관) |
| 웹 프레임워크 | express |
| 핵심 SDK | @homeiot/partnersdk(삼성 비공개 npm), @smartthings/core-sdk, @smartthings/smartapp |
| 저장소 | Redis(관계형 DB 없음) |
| 포트 | dev/prod 8088, local 8080. API base path /api/sci |
| 로그 | /app/logs/was/nodejs-sci/sci.log, sci-error.log |
기동은 PROXY_HOST=[내부프록시] PROXY_PORT=13128을 앞에 붙여 squid 프록시를 태움(내부망 → 외부 SmartThings 호출용). npm install 후 npm run patch 필수(SDK 파일을 node_modules에 덮어씀).
PARTNER_CLIENTID=sse가 OAW의 tb_ptnr_m.ptnr_id와 같은 값이고, PARTNER_AUTHURL/PARTNER_REFRESHURL이 OAW의 /api/uma/authorize, /api/uma/token을 가리킴.
HTTP 엔드포인트 (전부 POST)
| 경로 | 호출자 | 하는 일 |
|---|---|---|
/api/sci | SmartThings 클라우드 | SmartApp 라이프사이클 전부 |
/api/sci/partner | PIW, MAW(입주민 앱) | 본문에 events/commands/subscriptions로 분기. 셋 다 아니면 401 |
/api/sci/misc-command | 운영자 | 운영 명령(로그레벨 변경, 토큰 강제 갱신, Redis/DB 점검 등). 고정 헤더 키로 인증 |
/api/sci/partner가 PIW의 sqi.partner.sse.api-event.uri(http://localhost:8088/api/sci/partner)가 가리키는 그 엔드포인트임.
입주민 앱(MAW)이 부를 때
- 엔드포인트가 언제나
/api/sci/partner하나임. 기기 목록 조회인지 제어인지는 본문의commands[]로만 갈림. 로그에서 경로만 보면 무슨 요청인지 알 수 없으니 본문을 같이 볼 것 - 인증 토큰은 MAW가 발급하지 않고 Redis에 삼성 커넥터가 심어 준 값을 읽어 씀. 값이 없으면 MAW 쪽에서 데이터 없음으로 끝남
- 삼성 연동 해제 시 MAW가 알림 발송 성공 뒤 10초를 고정으로 기다린 다음 스마트앱 제거를 호출함(삼성 가이드 요구). 앱에서는 10초 이상 로딩으로 보이며 정상 동작임. 공개노트/개발/모듈/MAW 앱 API 서버
SmartApp 라이프사이클 핵심 흐름
- INSTALL: 개인정보 동의 저장(실패 시 설치 전체 중단) → LH 기기 목록 조회해 SmartThings에 디바이스 생성 → SmartThings 토큰 갱신 스케줄 등록(월 2회). 콜백 등록(
registerCallbackToPartnerWithIds)은return true만 하고 실제 호출은 미구현임(“OAW가 액세스토큰을 저장하지 않아 구현 불가”라는 주석 있음) - 기기 제어(SmartThings → LH): LH 현재 상태 먼저 조회 → 이미 그 상태면 LH 호출 생략(중복 제어 방지) → 다르면 PIW에 명령 전송. 승강기는 2초 뒤
standby이벤트를 따로 쏨(PARTNER_ELEVATOR_LAGGING_EVENT) - 기기 상태 이벤트 수신(LH → SmartThings): Redis
PartnerDevice:{기기ID}로 이 기기가 속한 설치 건을 찾아 각각 전달. SmartThings 토큰이INVALID면 조용히 버림 — 입주민이 커넥터를 다시 연결해야 함 - 대시보드 카드: 공지·주차·택배 등 10개 항목. 현재 저장소 설정은 전부
off. 카드용 API 경로(/notice/title등)가 PIW에는 없어 LH에서 미사용으로 추정됨
기기 타입 ↔ SmartThings capability 매핑
| SCI 타입 | LH type | SmartThings 명령 | LH 속성 |
|---|---|---|---|
| HNLIGHT | light | on/off | power |
| HNDIMLIGHT | light(dimming) | on/off, setLevel | power, dimming |
| HNHEAT | thermostat | on/off, setHeatingSetpoint | power, setTemperature |
| HNGAS | gas | open/close | lock(on=열림, off=잠김) |
| HNVENT | ventilator | on/off, setFanSpeed | power, auto, speed |
| HNELEVATOR | elevator | call | (PIW /eum/devices/elevator/sse) |
| HNAWAY | outing | on/off | set |
| HNSECURITY | prevention | on/off | set |
값 변환
- 디밍: LH 1
5단계 ↔ SmartThings 0100%(1→20, 2→40, 3→60, 4→80, 5→100) - 환기:
auto=on→fan_speed=0,auto=off+speed=1~3→그 값. SmartThings에서 켜기 명령은power=on+auto=off+speed=1세 개를 함께 보냄 - 가스: LH
lock=off가 잠김(close), SmartThingsvalve=closed
단지별 구성
하나의 SCI 프로세스가 여러 단지를 각각 다른 SmartApp으로 서비스함. 단지마다 삼성에 별도 SmartApp을 만들고 id-list.json(운영)/id-list-dev.json(개발)에 appId/clientId/clientSecret/단지명을 등록함. 신규 단지 삼성 연동 절차: (1) 삼성에서 SmartApp 생성 → (2) id-list.json에 등록 → (3) 재배포.
운영 등록 현황(코드 시점): LH과천포레드림, LH인천검단37단지 2곳. prod의 ST_APP_LIST가 플레이스홀더라 다중 앱 모드가 꺼져 있고 단일 앱만 씀 — 실제 운영 상태 확인 필요(아래 참조).
온보딩 (PARTNER_ONBOARD_TYPE)
LH는 타입 1을 씀: “아파트 앱을 먼저 설치하고 계정을 만든 뒤 진행”임. 즉 입주민은 홈즈 앱 계정이 있어야 SmartThings 연동 가능. “SmartThings에서 LH 로그인이 안 된다” 문의는 대부분 홈즈 앱 계정이 승인 대기(RDY)이거나 없는 경우임.
스케줄
| 이름 | 주기 | 하는 일 |
|---|---|---|
| SmartThingsRefreshToken | 월 2회 새벽 3시(설치 시각 기반) | SmartThings access 토큰 갱신 |
| SmartThingsDailyMonitorScheduler | 5분마다(이름은 Daily) | 전력계량기 관련, LH는 미사용 프로필이라 실질 동작 없음 |
| PartnerRefreshToken | 등록된 스케줄 없음 | 아래 확인 필요 참조 |
데이터
관계형 DB 없음. 모든 상태는 Redis.
| 키 | 내용 |
|---|---|
SmartThings:{installedAppId} | SmartThings 쪽 authToken/refreshToken |
Partner:{installedAppId} | LH 쪽 accessToken/refreshToken + PartnerDeviceId:{LH기기ID} 매핑 |
PartnerDevice:{LH기기ID} | 이 기기를 쓰는 installedAppId 목록(역방향) |
Partner:{installedAppId}의 accessToken이 PIW가 삼성 이벤트 발송 시 읽는 그 값임(공개노트/개발/모듈/PIW 연계 서버 참고).
알려진 이슈
- 콜백 등록 미구현으로 입주민 퇴거 시 SmartThings 연동 자동 해제가 동작하지 않을 가능성 있음.
PartnerRefreshToken갱신 스케줄이 등록되지 않음. LH refresh 토큰(2주 만료) 대응이 401 시 자동 갱신 경로에만 의존하는 것으로 추정됨./api/sci/partner에 인증이 없음(본문 형태로만 분기). PIW가localhost:8088로만 호출하는 구조라 외부 노출이 없어야 함.- 환경 파일에 SmartThings·LH clientSecret이 평문으로 커밋되어 있음.
- PIW의 Redis는 Sentinel(3노드)인데 SCI는 단독 노드 설정으로 되어 있어 같은 Redis인지 확인 필요(다르면 삼성 이벤트에 토큰이 안 붙음).
확인 필요
확인 필요
- PIW가 읽는 Redis와 SCI가 쓰는 Redis가 같은 인스턴스인지.
PartnerRefreshToken스케줄 미등록이 의도인지.- 입주민 퇴거 시 SmartThings 연동 해제 절차(콜백 미구현 관련).
- 대시보드 카드용 API(
/notice/title등)를 제공하는 서버(MAW로 추정) 및 카드 전체off가 의도인지.- 운영에 등록된 단지가 2곳뿐인지, 이후 추가된 단지가 실제 반영되었는지.
- 승강기 lagging 이벤트(SCI, 2초 뒤
standby)와 PIW의 승강기 이벤트 2회 발송(1초called, 20초standby)이 중복되는지.
관련
공개노트/개발/시스템 구성 공개노트/개발/모듈/PIW 연계 서버 공개노트/개발/모듈/APW 연계 서버 공개노트/기능/승강기 호출 공개노트/기능/홈넷 서버 연동