homebridge-smartthings-km81
v1.5.8
Published
Unified Homebridge plugin for Samsung devices via SmartThings (legacy AC over TLSv1, modern AC, washer/dryer with notification sensors).
Maintainers
Readme
homebridge-smartthings-km81
Samsung 가전 3종(구형 에어컨 / 신형 에어컨 / 세탁기·건조기)을 하나의 Homebridge 플러그인으로 통합한 플랫폼입니다.
기존에 분리되어 있던 다음 3개 플러그인을 통합·대체합니다.
homebridge-samsung-ac(구형 에어컨, TLSv1 직접 통신)homebridge-smartthings-ac-km81(신형 에어컨, SmartThings API)homebridge-smartthings-washer(세탁기/건조기, SmartThings API)
주요 기능
- 한 플러그인, 하나의 SmartThings OAuth 토큰(
smartthings_km81_token.json)으로 신형 AC + 세탁기 + 건조기를 모두 관리 - 구형 에어컨은 TLSv1 /
SECLEVEL=0직접 통신을 그대로 유지 (Homebridge 2.0 호환) - 신형 에어컨 무풍/자동건조 매핑, 별도 스위치 노출 등 기존 기능 보존
- 세탁기/건조기 Valve 서비스(Active/InUse/RemainingDuration)는 그대로
- NEW (v1.2.0): 구형 에어컨 HomeKit↔모드 매핑을 드롭다운 UI로 단순화 (Cool/CoolClean/Dry/DryClean/Wind/Auto + 무풍 옵션), 전원 ON 시 자동 적용
- NEW (v1.5.0): 세탁기/건조기 종료 알림 센서를 모션 센서로 단순화 — iOS 푸시 1회 + 사용자 지정 이름 지원
설치
npm install -g homebridge-smartthings-km81Homebridge UI 플러그인 탭에서 검색해 설치할 수도 있습니다.
장치 종류 (deviceType)
devices 배열의 각 항목에 deviceType을 지정합니다. UI에서 선택한 타입에 따라 해당 필드만 표시됩니다.
| deviceType | 설명 | 통신 방식 |
| --- | --- | --- |
| legacyAc | 구형 Samsung 에어컨 | 로컬 TLSv1 (8888 포트) |
| smartAc | 신형 Samsung 에어컨 | SmartThings Cloud |
| washer | 세탁기 | SmartThings Cloud |
| dryer | 건조기 | SmartThings Cloud |
SmartThings 기반 장치(
smartAc/washer/dryer)가 하나라도 있으면clientId,clientSecret,redirectUri가 필요합니다.
SmartThings OAuth 인증 절차
SmartThings의 보안 정책상 Redirect URI는 https 프로토콜이어야 하며, 별도 포트를 적을 수 없습니다 (즉 기본 443 포트만 허용). 따라서 외부에서 https://<나의도메인> 으로 접속할 수 있는 환경을 만들고, 이를 내부 Homebridge의 http://<homebridge_ip>:8999 로 전달해주는 리버스 프록시(Reverse Proxy) 설정이 필수입니다.
1단계: 리버스 프록시 설정 (HTTPS → 내부 8999)
가장 먼저 외부에서 접속 가능한 https 주소를 준비해야 합니다. Synology NAS의 리버스 프록시, UGreen NAS, Nginx Proxy Manager(NPM), Caddy 등 어떤 도구든 사용 가능합니다.
리버스 프록시 개념
| 구분 | 주소 | 비고 |
|---|---|---|
| 외부 주소 (SmartThings 등록용) | https://<나의도메인> | 포트 없음 (443 고정) |
| 내부 주소 (플러그인이 듣는 곳) | http://<homebridge_ip>:8999 | 포트 8999 고정 |
⚠️ Redirect URI에
https://myhome.com:9001처럼 포트를 붙이면 SmartThings가 거부합니다. 반드시https://myhome.com형태로, 외부에서 443 포트로 접속 가능해야 합니다.
설정 예시 (Nginx Proxy Manager 기준)
- NPM 관리 UI → Proxy Hosts → Add Proxy Host
- Details 탭:
- Domain Names:
myhome.example.com(본인 도메인) - Scheme:
http - Forward Hostname / IP: Homebridge 머신의 내부 IP (예:
192.168.1.10) - Forward Port:
8999 - Block Common Exploits: ✅
- Websockets Support: ✅ (선택)
- Domain Names:
- SSL 탭:
- SSL Certificate:
Request a new SSL Certificate (Let's Encrypt)선택 - Force SSL: ✅
- HTTP/2 Support: ✅
- 본인 이메일 입력 후 약관 동의 → Save
- SSL Certificate:
설정 예시 (Synology NAS 기준)
- 제어판 → 로그인 포털 → 고급 → 리버스 프록시 → 생성
- 소스: 프로토콜
HTTPS, 호스트myhome.example.com, 포트443 - 대상: 프로토콜
HTTP, 호스트<homebridge_ip>, 포트8999
사전 체크
- 라우터에서 외부 443 포트가 NAS의 443 포트로 포워딩되어 있어야 함
- DDNS가 현재 공인 IP를 가리키고 있어야 함
- SSL 인증서가 만료되지 않았어야 함 (Let's Encrypt 자동 갱신 권장)
2단계: SmartThings OAuth 앱 생성 (CLI 방식)
2-1. SmartThings CLI 설치
npm install -g @smartthings/cli2-2. 개인용 액세스 토큰(PAT) 발급
- https://account.smartthings.com/tokens 접속
- Generate new token 클릭
- 모든 권한(scope) 체크 → 생성
- 표시되는 토큰 값을 복사 (페이지를 떠나면 다시 못 봅니다)
2-3. CLI 인증
# "YOUR_PAT_TOKEN" 부분을 위에서 복사한 토큰으로 교체
export SMARTTHINGS_TOKEN="YOUR_PAT_TOKEN"2-4. OAuth-In SmartApp 생성
smartthings apps:create대화형 프롬프트에 다음과 같이 입력:
| 항목 | 입력값 |
|---|---|
| What kind of app | OAuth-In App |
| Display Name | Homebridge SmartThings KM81 (자유) |
| Description | Homebridge SmartThings KM81 (자유) |
| Icon Image URL | (엔터로 넘김) |
| Target URL | (엔터로 넘김) |
| Select Scopes | 스페이스바로 다음 3개 모두 선택 후 엔터:r:devices:*w:devices:*x:devices:* |
| Add or edit Redirect URIs | Add Redirect URI 선택 |
| Redirect URI | https://myhome.example.com (1단계의 외부 주소, 포트 없이) |
| Add or edit Redirect URIs | Finish editing Redirect URIs 선택 |
| Choose an action | Finish and create OAuth-In SmartApp 선택 |
생성 완료 후 출력되는 OAuth Client Id 와 OAuth Client Secret 을 반드시 즉시 복사해 저장하세요. 다시 볼 수 없습니다.
3단계: Homebridge 설정에 입력
Homebridge UI 또는 config.json의 플러그인 블록에 다음을 입력:
clientId: 위에서 발급받은 OAuth Client IdclientSecret: 위에서 발급받은 OAuth Client SecretredirectUri: 2-4에서 입력한 것과 정확히 동일한 값 (예:https://myhome.example.com)
Homebridge 재시작.
4단계: 권한 허용
- Homebridge 로그에 인증 URL이 표시됩니다 (예시):
인증 URL: https://api.smartthings.com/oauth/authorize?client_id=...&scope=...&redirect_uri=https%3A%2F%2Fmyhome.example.com - 해당 URL을 브라우저로 열어 SmartThings 로그인 → 위치 선택 → 인증 클릭
- 자동으로
https://myhome.example.com/?code=...로 리다이렉트 → 리버스 프록시 통해 내부 8999 포트로 전달 → 플러그인이 토큰을 발급받아smartthings_km81_token.json에 저장 - 로그에
최초 토큰 발급 완료!메시지 확인 - Homebridge를 한 번 더 재시작하면 장치가 추가됩니다.
Webhook lifecycle CONFIRMATION 요청(SmartThings가 처음 앱 등록할 때 보내는 핸드셰이크)도 같은 8999 포트의 서버가 자동 처리합니다.
설정 예시 (config.json)
{
"platform": "SmartThingsKM81",
"name": "SmartThings KM81",
"clientId": "YOUR_CLIENT_ID",
"clientSecret": "YOUR_CLIENT_SECRET",
"redirectUri": "https://myhome.example.com",
"temperatureMin": 18,
"temperatureMax": 30,
"temperatureStep": 1,
"devices": [
{
"deviceType": "legacyAc",
"name": "거실 에어컨",
"ip": "192.168.1.50",
"token": "LEGACY_TOKEN",
"swingModeType": "comfort",
"pollingInterval": 60,
"hkCoolMode": "DryClean",
"hkCoolWithWindFree": true,
"hkHeatMode": "none",
"hkAutoMode": "none",
"powerOnMode": "DryClean",
"powerOnWithWindFree": true
},
{
"deviceType": "smartAc",
"deviceLabel": "안방 에어컨",
"coolModeCommand": "dry",
"swingBinding": "windFree",
"lockBinding": "autoClean",
"exposeWindFreeSwitch": true,
"exposeAutoCleanSwitch": true
},
{
"deviceType": "washer",
"deviceLabel": "세탁기",
"model": "WF24B9600",
"enableNotificationSensor": true,
"sensorName": "세탁기 종료알림",
"sensorPollInterval": 30
},
{
"deviceType": "dryer",
"deviceLabel": "건조기",
"model": "DV90B6800",
"enableNotificationSensor": true,
"sensorName": "건조기 종료알림"
}
]
}세탁기/건조기 종료 알림 센서
세탁/건조가 끝나는 순간 iOS 푸시 알림 1회를 받기 위한 가상 모션 센서를 별도 액세서리로 노출합니다. HomeKit 자동화 트리거로도 사용 가능합니다.
옵션
| 필드 | 타입 | 기본값 | 설명 |
| --- | --- | --- | --- |
| enableNotificationSensor | boolean | false | 종료 알림 모션 센서 활성화 |
| sensorName | string | "{장치명} 종료알림" | HomeKit에 표시될 모션 센서 이름 |
| sensorPollInterval | integer | 30 (최소 5) | 운전 종료 감지용 SmartThings 상태 폴링 주기(초) |
동작
- 직전 상태가
active였다가inactive로 바뀌는 순간 모션 센서를detected로 트리거 → 약 10초 후 자동으로 해제 - 모션 센서를 선택한 이유: iOS HomeKit의 푸시 알림이
motion=false → true전환에서만 발생하므로 운전 종료 시 정확히 1회만 알림이 옴 (Contact/Occupancy는 양방향이라 2회 발송됨) - 10초 후 자동 해제는 다음 종료 사이클에서 또 알림을 받기 위해 필수
- 폴링은
enableNotificationSensor: true인 장치에만 시작됨
사용 방법
- Homebridge 설정에서 세탁기/건조기 각각
enableNotificationSensor체크 + (선택)sensorName입력 - Homebridge 재시작 → 모션 센서 액세서리가 자동 생성됨
- iOS 홈 앱 → 해당 모션 센서 액세서리 → "센서 활동 알림" 켜기
- 운전이 끝나면 폰에 푸시 알림이 1회 도착
HomeKit 자동화 예시
| 시나리오 | 트리거 | 동작 | | --- | --- | --- | | 세탁 완료 시 거실 조명 깜빡임 | "세탁기 종료알림"에서 동작 감지되면 | 거실 조명 On → 1분 후 Off | | 건조 완료 시 가족에게 알림 | "건조기 종료알림"에서 동작 감지되면 | "건조 끝났어요" 메시지 전송 |
v1.5.0 마이그레이션: 이전 버전의
sensorTypes/triggerMode배열 옵션은 제거되었습니다. config.json에 남아 있어도 무시되며 다음 시작 시 기존 접촉/점유 센서 액세서리는 자동으로 정리됩니다. iOS 홈 앱에서 새로 나타나는 모션 센서에 "활동 알림"을 다시 켜주세요.
구형 에어컨 (legacyAc) 토큰 추출 가이드
legacyAc 장치를 사용하려면 에어컨의 고유 인증 토큰이 필요합니다. 토큰은 DNS 스푸핑(Spoofing) 기법으로, 에어컨이 삼성 클라우드(api.smartthings.com)와 통신하는 내용을 중간에서 가로채어 추출합니다.
⚠️ 사전 준비물
- Homebridge가 설치된 컴퓨터(NAS / 라즈베리파이 / Mac 등) — Python 3 + OpenSSL 필요
- 공유기 관리자 페이지 접근 권한 (정적 DNS 설정 변경용)
- 에어컨을 Wi-Fi 설정 모드로 다시 연결할 준비
1단계: 가짜 서버 스크립트 준비
아래 Python 코드를 fake_server.py 라는 이름으로 컴퓨터에 저장합니다.
#!/usr/bin/env python3
import ssl
import socket
import os
import threading
LISTEN_IP = '0.0.0.0'
HTTPS_PORT = 443
CERT_FILE = 'temp_server_cert.pem'
KEY_FILE = 'temp_server_key.pem'
def generate_self_signed_cert(cert_file, key_file):
if not (os.path.exists(cert_file) and os.path.exists(key_file)):
print(f"임시 서버 인증서 '{cert_file}' 및 '{key_file}' 생성 중...")
subj = "/CN=api.smartthings.com"
os.system(f'openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout {key_file} -out {cert_file} -subj "{subj}"')
print("임시 서버 인증서 준비 완료.")
def handle_client(conn, addr):
print(f"\n>>> [연결 수립] From: {addr}")
try:
while True:
data = conn.recv(8192)
if not data:
break
decoded_data = data.decode('utf-8', errors='ignore')
print("\n" + "="*20 + " 데이터 수신 " + "="*20)
print(decoded_data)
for line in decoded_data.splitlines():
if 'authorization' in line.lower():
print("\n" + "*"*20 + " 토큰 발견 " + "*"*20)
token = line.split(' ')[-1]
print(f"추출된 토큰: {token}")
print("*"*56)
print("이 토큰을 복사하여 Homebridge 설정에 사용하세요.")
conn.sendall(b'HTTP/1.1 200 OK\r\n\r\n')
except Exception as e:
print(f"[오류] 클라이언트 처리 중 오류: {e}")
finally:
print(f"<<< [연결 종료] From: {addr}")
conn.close()
def main():
generate_self_signed_cert(CERT_FILE, KEY_FILE)
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile=CERT_FILE, keyfile=KEY_FILE)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((LISTEN_IP, HTTPS_PORT))
sock.listen(5)
print("\n" + "="*50)
print(f"가짜 삼성 클라우드 서버가 시작되었습니다. (포트: {HTTPS_PORT})")
print("이제 에어컨을 Wi-Fi 설정 모드로 변경하고, SmartThings 앱으로 연결을 시도하세요.")
print("="*50)
while True:
conn, addr = sock.accept()
threading.Thread(target=handle_client, args=(conn, addr)).start()
if __name__ == '__main__':
try:
main()
except PermissionError:
print("\n[오류] 443 포트를 사용하려면 root 권한이 필요합니다. 'sudo python3 fake_server.py'로 실행해주세요.")
except KeyboardInterrupt:
print("\n서버를 종료합니다.")
finally:
if os.path.exists(CERT_FILE): os.remove(CERT_FILE)
if os.path.exists(KEY_FILE): os.remove(KEY_FILE)2단계: DNS 스푸핑 설정 (가장 중요)
fake_server.py를 실행할 컴퓨터의 내부 IP 주소를 확인합니다 (예:192.168.1.10).- 공유기 관리자 페이지(보통
192.168.0.1또는192.168.1.1)에 접속. - '정적 DNS', 'DNS 호스트 이름' 같은 메뉴 찾기 (공유기마다 명칭이 다름).
- 아래 항목으로 정적 DNS 규칙 추가:
- 호스트 이름:
api.smartthings.com - IP 주소: 위 1번에서 확인한 컴퓨터 IP (예:
192.168.1.10)
- 호스트 이름:
이렇게 하면 에어컨이 api.smartthings.com을 우리 컴퓨터로 인식합니다.
3단계: 토큰 추출 실행
- 터미널에서 root 권한으로 가짜 서버 실행 (443 포트 필요):
sudo python3 fake_server.py - 에어컨을 Wi-Fi 설정 모드로 변경 → SmartThings 앱에서 네트워크 연결 절차 진행.
- 에어컨이 Wi-Fi에 연결되면 우리 PC의 가짜 서버로 접속을 시도. 터미널에 다음과 같이 출력됩니다:
******************** 토큰 발견 ******************** 추출된 토큰: 8G7s7VTGGG ******************************************************** - 이 토큰을 Homebridge UI에서
legacyAc장치의 인증 토큰 필드에 입력합니다.
4단계: DNS 설정 원복 (필수)
토큰을 얻었으면 반드시 2단계에서 추가한 정적 DNS 규칙을 삭제해야 합니다. 그렇지 않으면 인터넷 사용에 문제가 생기거나 에어컨이 계속 가짜 서버로 접속하게 됩니다.
🔒 보안 경고: 이 통신은 오래된 TLSv1을 사용하므로 신뢰할 수 있는 로컬 네트워크에서만 사용하세요.
HomeKit ↔ 구형 AC 모드 매핑 (legacyAc, v1.2.0+)
구형 삼성 에어컨은 단순 Cool/Dry/Auto/Wind 외에도 CoolClean(냉방청정), DryClean(제습청정) 같은 복합 모드를 지원합니다. HomeKit의 냉방(Cool) / 난방(Heat) / 자동(Auto) 각 버튼을 어떤 실제 AC 모드에 매핑할지 드롭다운으로 선택할 수 있습니다.
설정 필드 (legacyAc 장치 단위)
| 필드 | 설명 | 기본값 |
|---|---|---|
| hkCoolMode | HomeKit '냉방' 버튼이 보낼 AC 모드 (enum) | "Cool" |
| hkCoolWithWindFree | HomeKit 냉방 시 무풍(Comode_Nano) 같이 켜기 | false |
| hkHeatMode | HomeKit '난방' 버튼이 보낼 AC 모드 (enum) | "none" (숨김) |
| hkHeatWithWindFree | HomeKit 난방 시 무풍 같이 켜기 | false |
| hkAutoMode | HomeKit '자동' 버튼이 보낼 AC 모드 (enum) | "none" (숨김) |
| hkAutoWithWindFree | HomeKit 자동 시 무풍 같이 켜기 | false |
| powerOnMode | 전원 ON 시 자동 적용할 AC 모드 (enum) | "none" (직전 모드 유지) |
| powerOnWithWindFree | 전원 ON 시 무풍 같이 켜기 | false |
선택 가능한 모드 (enum 값)
| 값 | 의미 |
|---|---|
| none | 사용 안 함 (HomeKit 버튼 숨김 / 전원 ON 시 모드 변경 안 함) |
| Cool | 냉방 |
| CoolClean | 냉방청정 |
| Dry | 제습 |
| DryClean | 제습청정 |
| Wind | 공기청정 (송풍) |
| Auto | 스마트 쾌적 |
동작 방식
- HomeKit에서 모드 버튼을 누르면
PUT /devices/{N}/mode로{"modes":["<선택한값>"]}전송 WithWindFree체크가 켜져 있으면 이어서{"options":["Comode_Nano"]}도 전송none선택 시 해당 HomeKit 버튼이validValues에서 제외되어 HomeKit에 아예 안 보임- 전원 ON 시
powerOnMode가none이 아니면, 전원 명령 직후 자동으로 해당 모드 적용
설정 예시
예시 A — 전원 ON 시 항상 "제습청정 + 무풍"으로 시작, HomeKit은 냉방만 노출
{
"deviceType": "legacyAc",
"name": "거실 에어컨",
"ip": "192.168.1.50",
"token": "YOUR_TOKEN",
"hkCoolMode": "DryClean",
"hkCoolWithWindFree": true,
"hkHeatMode": "none",
"hkAutoMode": "none",
"powerOnMode": "DryClean",
"powerOnWithWindFree": true
}예시 B — HomeKit 3개 버튼을 각각 다른 청정 모드로
{
"deviceType": "legacyAc",
"name": "안방 에어컨",
"ip": "192.168.1.51",
"token": "YOUR_TOKEN",
"hkCoolMode": "CoolClean",
"hkHeatMode": "DryClean",
"hkAutoMode": "Auto",
"powerOnMode": "CoolClean"
}💡 HomeKit이 'Heat'를 난방으로 표시하지만, 실제로는 사용자가 원하는 어떤 모드든 매핑할 수 있습니다 (이름표일 뿐).
v1.1.x 에서 v1.2.0 마이그레이션
기존 hkCoolEnabled/hkCoolModes[]/hkCoolOptions[] 같은 배열 기반 필드도 자동으로 인식됩니다 (config.json을 안 고쳐도 v1.2.0 에서 그대로 작동). UI에서 다시 저장하면 새 필드(hkCoolMode, hkCoolWithWindFree)로 정리됩니다.
구형 에어컨 (legacyAc) 참고
- 인증서 경로(
certPath/keyPath)를 비워두면 패키지에 포함된cert/cert.pem을 사용합니다. swingModeType은 모델에 따라comfort(무풍) 또는wind(상하 바람) 중 선택.- TLSv1 /
DEFAULT@SECLEVEL=0은 구형 펌웨어 호환을 위해 의도적으로 사용합니다. deviceIndex/setDeviceIndex: 하나의 에어컨 본체에 여러Devices[N]엔트리가 있는 모델(예: 스탠드+벽걸이 결합)에서 어떤 인덱스를 읽고/쓸지 지정합니다. 기본값0.
마이그레이션 가이드
기존 3개 플러그인을 사용 중이라면, 본 플러그인 설치 후:
- 기존 플러그인의 platform 블록을
config.json에서 제거합니다. - 본 플러그인(
SmartThingsKM81) 블록을 추가하고devices배열에 항목별deviceType을 명시합니다. - 기존 토큰 파일(
smartthings_ac_token.json,smartthings_washer_token.json)이 있더라도 사용하지 않습니다. 본 플러그인은 새 OAuth 흐름으로smartthings_km81_token.json을 새로 발급합니다. - Homebridge 재시작 → 인증 URL 접속 → 권한 허용 → 재시작.
라이선스
MIT © Km81
