Samsung TV / 에어컨 / SmartThings 전용 기기 Home Assistant 로컬 제어 가이드
배경: Samsung SmartThings API가 2026년 10월부터 유료화(개인 개발자 Personal Plan 예고 $4.99/월, 상업용 파트너는 별도 요금제) 됨에 따라, SmartThings 클라우드 REST API를 거치지 않고 Home Assistant에서 삼성 가전을 제어/조회하기 위한 설정을 정리한 문서. 기기를 두 부류로 나눠서 다룬다.
- 로컬 프로토콜이 애초에 존재하는 기기 (TV, 2018년형 에어컨 등) — 해당 기기용 로컬 통합을 바로 붙이면 된다. → 2, 3장.
- 와이파이로만 동작하고 SmartThings 클라우드와만 통신하도록 설계되어 로컬로 붙일 방법 자체가 없는 기기 (공기청정기, 공기질 모니터, 냉장고/세탁기 일부 상태값 등) — Matter와 SmartThings 루틴을 조합한 우회 브릿지가 필요하다. → 4장.
목차
- 공통 배경 – SmartThings API 유료화
- Samsung TV 설정
- Samsung 에어컨 설정
- SmartThings 전용 기기 – Matter 브릿지 우회
- Template Switch 최신 문법
- 참고 자료 / 링크
- 전체 요약
1. 공통 배경 – SmartThings API 유료화
- Samsung은 2026년 10월부터 SmartThings API 무료 접근을 중단합니다. 상업용 파트너는 별도 요금제가 적용되고, 개인 개발자에게는 월 $4.99 Personal Plan이 예고되어 있는데, 정확한 쿼터나 세부 요금 체계는 이 문서 작성 시점 기준으로 아직 공개되지 않았습니다.
- Home Assistant의 SmartThings 통합 역시 내부적으로 이 REST API를 호출하는 구조이기 때문에, 유료화 정책이 그대로 적용되면 HA ↔ SmartThings 클라우드 연동이 끊기거나 유료 전환이 강제될 가능성이 높습니다.
- 이 문서는 클라우드 API(SmartThings) 없이, 같은 네트워크(LAN) 안에서 로컬로만 통신하는 방식을 정리한 것입니다.
- 단, 모든 기기가 로컬 대체 경로를 갖는 것은 아닙니다. 지그비(Zigbee)로 붙는 센서/스위치류는 SmartThings 허브를 거치지 않고 HA의 지그비 코디네이터로 직접 재페어링하면 되므로 애초에 이 문제와 무관합니다. 반면 와이파이 기반이면서 로컬 프로토콜 자체가 없는 기기(공기청정기, 공기질 모니터 등)는 2·3장의 방식이 통하지 않으며, 4장의 Matter 브릿지 우회가 필요합니다.
- 로컬 방식의 공통 장점:
- 인터넷 연결 끊겨도 동작
- Samsung 계정/구독 불필요
- 응답 속도가 빠름 (클라우드 왕복 없음)
- 공통 단점:
- 공식 지원이 아닌 커뮤니티/리버스 엔지니어링 기반 통합이 많음
- HA와 기기가 반드시 같은 네트워크(VLAN)에 있어야 함
- 일부 기능(앱 목록, 채널명 등)은 SmartThings 클라우드 전용이라 로컬 방식에서는 제한될 수 있음
2. Samsung TV 설정
2.1 기기 정보 (예시)
| 항목 | 값 |
|---|---|
| MAC 주소 | 80:8A:BD:80:E1:6A |
| IP 주소 | 192.168.219.5 |
| WOL(Wake on LAN) 지원 | O |
2.2 사용하는 통합: Samsung Smart TV (내장 통합, samsungtv)
- Home Assistant 공식 내장 통합이며 SmartThings 클라우드가 아니라 로컬 REST API + 웹소켓으로 직접 통신합니다.
- 지원 기능:
- 전원 켜기 (내부적으로 WOL 매직 패킷 사용)
- 전원 끄기 (로컬 웹소켓 명령)
- 리모컨 기능 (볼륨, 채널, 앱 실행 등)
- 미디어 재생 정보, 상태 업데이트
2.3 설정 방법
- HA → 설정 → 기기 및 서비스 → 통합 추가 → “Samsung Smart TV” 검색
- 같은 네트워크에 있으면 자동으로 발견(Discovered)되는 경우가 많음
- IP 주소 입력:
192.168.219.5 - TV 화면에 뜨는 연결 허용 팝업을 리모컨으로 즉시 승인
- ⚠️ 이 팝업을 놓치면 페어링이 실패함 → TV 전원 껐다 켜고 재시도
- 완료되면
media_player.xxx엔티티가 생성됨
2.4 참고: 순수 wake_on_lan 통합 (대안, 켜기 전용)
TV 자체 통합 없이 WOL만 쓰고 싶다면 아래처럼도 가능하지만, 끄기는 별도 구현이 필요합니다.
switch:
- platform: wake_on_lan
mac: "80:8A:BD:80:E1:6A"
host: 192.168.219.5
name: "거실 TV"
turn_off에 스크립트/shell_command를 연결하지 않으면 HA 화면상 스위치만 꺼지고 실제 TV는 켜진 채로 남음.- 삼성 TV의 경우
samsungtv통합이 켜기/끄기를 모두 로컬로 지원하므로, 이 방식보다samsungtv통합 사용을 우선 권장.
2.5 switch 엔티티로 감싸기 (Template Switch)
samsungtv는 기본적으로 media_player 엔티티지만, 아래처럼 template switch로 감싸면 switch 카드로 표시 가능. (문법은 5장 참고)
template:
- switch:
- name: "거실 TV"
unique_id: tv_power
state: "{{ is_state('media_player.tv이름', 'on') }}"
turn_on:
action: media_player.turn_on
target:
entity_id: media_player.tv이름
turn_off:
action: media_player.turn_off
target:
entity_id: media_player.tv이름
2.6 알려진 이슈 / 주의사항
| 이슈 | 원인 / 해결 |
|---|---|
| VLAN/서브넷 분리 시 연결 안 됨 | 웹소켓 연결은 다른 VLAN을 지원하지 않는 경우가 많음. HA와 TV를 같은 대역에 두어야 함 |
| TV 완전히 꺼진 상태에서 WOL 안 됨 | TV 자체 네트워크 설정에서 “빠른 시작 모드” / “네트워크 대기모드”를 켜둬야 대기 전력 상태에서도 네트워크 카드가 살아있어 매직 패킷 수신 가능 |
| 구형 모델(H, J 시리즈) 반응 느림 | 웹소켓이 아닌 레거시 폴링(10초 간격) 방식 사용 → 정상 동작이나 지연 있음 |
| 웹소켓 끄기 명령이 가끔 씹힘 (최신 Tizen) | HACS의 서드파티 통합 ha-samsungtv-smart (SmartThings 토큰 없이 로컬 전용 모드 지원)로 대체 검토 |
| MAC 주소 표기 | 하이픈(-)이 아닌 콜론(:)으로 입력해야 함 (80:8A:BD:80:E1:6A) |
| IP 변동 | 라우터에서 TV에 고정 IP(DHCP reservation) 할당 권장 |
3. Samsung 에어컨 설정
3.1 기기 정보 (예시)
| 항목 | 값 |
|---|---|
| 모델 연식 | 2018년형 |
| IP 주소 | 192.168.219.8 |
| 개방 가능 포트 | 8888번만 오픈 가능 |
| 프로토콜 세대 | 신세대 REST API (토큰 기반 HTTPS) |
| 확보한 토큰 | B5F6rz6771 |
8888 포트 = 2018
2022년형 삼성 에어컨에서 쓰이는 토큰 기반 로컬 HTTPS REST API. 참고로 더 구형(20132015년형,AR**HSFS계열)은 2878 포트(DPLUG/AC14K 프로토콜)를 사용하며 이 문서의 대상과 다름.
3.2 사용하는 통합: Climate_IP (samsungrac, HACS 커스텀 통합)
- 원저작자
SebuZet가 활동 중단(MIA) → 여러 포크가 존재하며, 이 문서에서는clipman/samsungrac(atxbyea/samsungrac의 포크)을 사용. - 저장소:
https://github.com/clipman/samsungrac - 지원 범위:
- 포트 8888 (신세대 REST API) ← 2018년형 대상 기종은 이쪽
- 포트 2878 (구세대 소켓 통신)
- MIM-H03 컨트롤러 (REST API, 포트 8888)
- MIM-H04 컨트롤러 (SmartThings 클라우드 경유, 참고용 – 본 목적과는 다름)
3.3 설치 (HACS Custom Repository)
- HACS → 우측 상단
⋮(점 3개) 메뉴 → Custom repositories 클릭 - 입력창에 아래 정보 입력 후 추가:
- Repository:
https://github.com/clipman/samsungrac - Type:
Integration
- Repository:
- 추가된
samsungrac(Climate_IP) 저장소를 HACS 목록에서 찾아 Download 클릭 - Home Assistant 재시작
재시작 후
config/custom_components/climate_ip폴더가 자동으로 생성되어 있으면 설치 완료입니다. 이후 3.4절의configuration.yaml설정만 추가하면 됩니다.
3.4 설정 (configuration.yaml) – 8888 포트 / 신세대 기준
climate:
- platform: climate_ip
config_file: '/config/custom_components/climate_ip/samsungrac.yaml'
ip_address: 192.168.219.xx # 에어컨 실제 IP (고정 IP 권장)
token: 'AC에서_추출한_토큰'
cert: 'ac14k_m.pem'
name: '거실 에어컨'
| 파라미터 | 설명 | 필수 여부 |
|---|---|---|
config_file | YAML 설정 파일 경로 | 필수 |
ip_address | 에어컨 IP 주소 | 필수 |
token | 기기에서 추출한 액세스 토큰 | 필수 |
cert / cert_file | 인증서 파일명 (기본값: ac14k_m.pem, 검증 생략 시 None) | 대부분 필수 |
mac | MAC 주소 | 2878 포트 기기만 필수 |
name | 표시 이름 | 선택 |
poll | 상태 폴링 여부 | 선택 (구세대는 기본 활성) |
debug | 디버그 로그 | 선택 |
3.5 토큰(Token) 추출 – 실제 성공한 절차 (2026년형 Python 환경 기준)
8888 포트 방식은 기기 내부에 저장된 액세스 토큰이 있어야 통신이 가능합니다. 이 토큰은 SmartThings 앱으로 최초 등록할 때 에어컨 내부에 발급/저장되므로, 이미 SmartThings에 1회 이상 등록된 적이 있는 기기라면 클라우드 API 없이도 로컬 네트워크에서 토큰을 “가로채서” 추출할 수 있습니다.
원문 출처: creatingsmarthome.com “Guide: Samsung A/C to Home Assistant” (2021, 8888 포트 기준) 작성자가 Google Drive에 배포한
server.py/actest.py/cert.pem3개 파일 사용.⚠️ 중요: 원본 스크립트는 2021년에 작성되어 Python 3.14 + 최신 OpenSSL 3.x 환경에서는 그대로 동작하지 않습니다. 아래는 실제로 막혔던 지점과, 최종적으로 동작을 확인한 수정 코드입니다.
실제 사용 환경
| 항목 | 값 |
|---|---|
| 에어컨 IP | 192.168.219.8 |
| 토큰 수신 서버(작업 머신) IP | 192.168.219.137 |
| Python 버전 | 3.14 (HA venv, /root/homeassistant/bin/activate) |
| 작업 디렉토리 | ~/samsung-token |
사전 준비물
- 에어컨의 고정 IP (DHCP 예약 권장)
- SSH 접속 가능한 환경 (HA Supervisor의
SSH & Web TerminalAdd-on, 또는 같은 네트워크의 리눅스 머신) - 원본 3개 파일:
server.py,actest.py,cert.pem(2021년 creatingsmarthome.com 가이드에서 배포된 Google Drive 파일) - 에어컨 리모컨 (전원 끄기/켜기용)
1단계. 포트 확인 (성공)
telnet 192.168.219.8 8888
실제 결과:
Trying 192.168.219.8...
Connected to 192.168.219.8.
Escape character is '^]'.
→ 8888 포트 정상 확인. Ctrl+] → quit으로 텔넷 세션 종료.
2단계. SSH 환경 준비
HA Supervisor → Add-on Store → SSH & Web Terminal 설치 후 접속. 작업은 ~/samsung-token 디렉토리에서 진행.
mkdir -p ~/samsung-token && cd ~/samsung-token
# server.py, actest.py, cert.pem 3개 파일을 이 디렉토리로 scp 등으로 복사
3단계. actest.py의 AC IP 확인
원본 파일에는 이미 IP가 하드코딩되어 있었음 (수정 불필요, 그대로 사용):
import requests
s = requests.Session()
headers = {'content-type': 'text/xml'}
resp = s.post("https://192.168.219.8:8888/devicetoken/request", data={"DeviceToken":"xxxxxxxxxxx"}, headers=headers, stream=True, verify=False, cert='cert.pem')
4단계. 에어컨 전원 끄기
리모컨으로 전원 OFF (플러그를 뽑지 않고 리모컨 전원만 끔).
5단계. server.py 실행 → 오류 1: AttributeError: module 'ssl' has no attribute 'wrap_socket'
원본 코드의 ssl.wrap_socket()은 Python 3.12부터 제거되어 최신 환경에서 바로 에러가 남.
해결: SSLContext 객체 방식으로 교체.
6단계. 재실행 → 오류 2: ssl.SSLError: [SSL: CA_MD_TOO_WEAK] ca md too weak
cert.pem이 오래된 약한 해시(MD5 등) 서명 인증서라서 OpenSSL 3.x의 기본 보안 레벨에서 거부됨.
해결: context.set_ciphers('DEFAULT:@SECLEVEL=0')을 load_cert_chain() 호출 전에 추가.
7단계. server.py 최종 성공 버전
from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl
class RequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
request_path = self.path
print("\n----- Request Start ----->\n")
print("Request path:", request_path)
print("Request headers:", self.headers)
print("<----- Request End -----\n")
self.send_response(200)
self.send_header("Set-Cookie", "foo=bar")
self.end_headers()
def do_POST(self):
request_path = self.path
print("\n----- Request Start ----->\n")
print("Request path:", request_path)
request_headers = self.headers
content_length = request_headers.get('Content-Length')
length = int(content_length) if content_length else 0
print("Content Length:", length)
print("Request headers:", request_headers)
print("Request payload:", self.rfile.read(length if length else 28))
print("Body:", self)
print("<----- Request End -----\n")
self.send_response(200)
self.end_headers()
do_PUT = do_POST
do_DELETE = do_GET
def main():
port = 8889
print('Listening on localhost:%s' % port)
server = HTTPServer(('', port), RequestHandler)
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.minimum_version = ssl.TLSVersion.TLSv1 # 구형 TLS 1.0 허용 (AC가 구형 프로토콜만 지원)
context.maximum_version = ssl.TLSVersion.TLSv1_2
context.set_ciphers('DEFAULT:@SECLEVEL=0') # 약한 해시(MD5 등) 인증서 허용
context.load_cert_chain(certfile='cert.pem')
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
server.socket = context.wrap_socket(server.socket, server_side=True)
server.serve_forever()
if __name__ == "__main__":
main()
python3 server.py 실행 → Listening on localhost:8889만 뜨고 에러 없이 대기 상태 확인.
8단계. actest.py 실행 → 오류 3: ssl.SSLError: [SSL: CA_MD_TOO_WEAK]
requests 라이브러리는 기본 SSL 컨텍스트를 내부적으로 생성하므로, cert= 파라미터만으로는 SECLEVEL을 조정할 수 없음.
해결: HTTPAdapter를 커스텀 SSLContext로 오버라이드하는 어댑터 작성.
9단계. 재실행 → 오류 4: ssl.SSLError: [SSL: UNSUPPORTED_PROTOCOL] unsupported protocol
SECLEVEL 문제는 해결됐지만, Python 3.14 기본 SSLContext가 TLS 1.2 이상만 허용하도록 강제되어 있어, AC의 구형 TLS 핸드셰이크가 거부됨.
해결: 어댑터에 minimum_version = ssl.TLSVersion.TLSv1 추가.
10단계. actest.py 최종 성공 버전
import requests
import ssl
from requests.adapters import HTTPAdapter
class LegacySSLAdapter(HTTPAdapter):
def init_poolmanager(self, *args, **kwargs):
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.minimum_version = ssl.TLSVersion.TLSv1 # 오래된 TLS 1.0 허용
context.maximum_version = ssl.TLSVersion.TLSv1_2
context.set_ciphers('DEFAULT:@SECLEVEL=0')
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
context.load_cert_chain(certfile='cert.pem')
kwargs['ssl_context'] = context
return super().init_poolmanager(*args, **kwargs)
s = requests.Session()
s.mount('https://', LegacySSLAdapter())
headers = {'content-type': 'text/xml'}
resp = s.post(
"https://192.168.219.8:8888/devicetoken/request",
data={"DeviceToken": "xxxxxxxxxxx"},
headers=headers,
stream=True,
verify=False
)
print(resp.status_code)
실행 결과 (성공):
/root/samsung-token/actest.py:8: DeprecationWarning: ssl.TLSVersion.TLSv1 is deprecated
.../urllib3/.../connectionpool.py:1110: InsecureRequestWarning: Unverified HTTPS request is being made...
200
DeprecationWarning, InsecureRequestWarning은 무시 가능. 200이 반환되면 AC가 요청을 정상 수신한 것.
11단계. 에어컨 전원 켜기 → 토큰 캡처 (성공)
server.py가 대기 중인 터미널에서, 리모컨으로 에어컨을 켜자 아래 로그가 출력됨:
----- Request Start ----->
Request path: /devicetoken/response
Content Length: 0
Request headers: Host: 192.168.219.137:8889
Accept: */*
X-API-Version : v1.0.0
Content-Type: application/json
Content-Length: 28
Request payload: b'{"DeviceToken":"B5F6rz6771"}'
Body: <__main__.RequestHandler object at 0x735f57c590>
<----- Request End -----
192.168.219.8 - - [23/Jul/2026 18:14:54] "POST /devicetoken/response HTTP/1.1" 200 -
추출된 토큰: B5F6rz6771
🔑 이 토큰은 이번 실제 작업에서 확보한 값입니다. 다른 사람과 이 문서를 공유할 경우, 이 값은 반드시 가리거나 삭제하고 공유하세요 (기기 접근 권한에 해당하는 자격 증명입니다).
12단계. 마무리
server.py터미널에서Ctrl + C로 종료- SSH 세션 종료,
SSH & Web TerminalAdd-on 비활성화(또는 삭제) 권장 - 확보한 토큰을 3.4 설정에 반영:
climate:
- platform: climate_ip
config_file: '/config/custom_components/climate_ip/samsungrac.yaml'
ip_address: 192.168.219.8
token: 'B5F6rz6771'
cert: 'ac14k_m.pem'
name: '거실 에어컨'
참고:
climate_ip통합이 요구하는ac14k_m.pem은 이번 토큰 추출에 쓴cert.pem과 이름만 다를 뿐 동일 계열 인증서인 경우가 많음. 저장소에 파일이 없다면cert.pem을ac14k_m.pem으로 복사해 시도.
트러블슈팅 종합표 (실제로 겪은 순서대로)
| 단계 | 오류 메시지 | 원인 | 해결 |
|---|---|---|---|
| server.py 1차 실행 | AttributeError: module 'ssl' has no attribute 'wrap_socket' | Python 3.12부터 ssl.wrap_socket() 제거됨 | SSLContext + load_cert_chain() 방식으로 교체 |
| server.py 2차 실행 | ssl.SSLError: [SSL: CA_MD_TOO_WEAK] ca md too weak | 인증서가 약한 해시(MD5)로 서명되어 OpenSSL 3.x 기본 보안 레벨에서 거부 | context.set_ciphers('DEFAULT:@SECLEVEL=0')을 load_cert_chain() 전에 추가 |
| server.py 3차 실행 | 정상 (Listening on localhost:8889) | – | – |
| actest.py 1차 실행 | ssl.SSLError: [SSL: CA_MD_TOO_WEAK] ca md too weak | requests가 기본 SSLContext 사용, cert= 파라미터로는 SECLEVEL 조정 불가 | HTTPAdapter 상속한 LegacySSLAdapter 작성, 커스텀 SSLContext를 mount() |
| actest.py 2차 실행 | ssl.SSLError: [SSL: UNSUPPORTED_PROTOCOL] unsupported protocol | AC가 TLS 1.0급 구형 프로토콜만 지원, Python 3.14 기본값은 TLS 1.2 이상만 허용 | context.minimum_version = ssl.TLSVersion.TLSv1 추가 |
| actest.py 3차 실행 | 성공 (200, 경고만 출력) | – | – |
| server.py (initial, TLS 미조정 상태) | 에러 없이 대기만 하고 로그 무응답 | AC 콜백 접속 시 SSL 핸드셰이크가 프로토콜 불일치로 조용히 실패 (애플리케이션 레벨까지 도달 못 함) | server.py에도 minimum_version = TLSv1 동일하게 추가 후 재시도 → 토큰 로그 정상 수신 |
InsecureRequestWarning, DeprecationWarning (양쪽 스크립트 공통) | 자체서명 인증서 미검증 경고, TLSv1 deprecated 경고 | 로컬 LAN 통신 및 레거시 기기 호환 목적상 의도된 설정 | 무시 가능 (동작에 영향 없음) |
핵심 교훈: 2021년 작성된 스크립트를 최신 Python(3.12+)/OpenSSL(3.x) 환경에서 쓰려면 ① ssl.wrap_socket() → SSLContext 전환, ② SECLEVEL=0으로 약한 인증서 허용, ③ minimum_version=TLSv1로 구형 프로토콜 허용 — 이 세 가지를 클라이언트(actest.py)와 서버(server.py) 양쪽 모두에 적용해야 함.
토큰 재추출이 필요한 경우: 에어컨을 공장 초기화하거나 SmartThings 앱에서 기기를 삭제/재등록하면 토큰이 갱신되므로, 이 경우 위 과정을 처음부터 다시 진행해야 합니다.
3.6 기능별 스위치 만들기 (Template Switch)
climate_ip 통합은 climate.climate_ip_set_property 서비스를 제공하여 정화(purify), 특수 모드(comfort/quiet 등) 같은 기기별 속성을 조작할 수 있습니다. 이를 개별 switch 엔티티로 노출하려면 Template Switch로 감쌉니다.
template:
- switch:
- name: "에어컨 공기청정"
unique_id: ac_purify
state: "{{ is_state_attr('climate.거실_에어컨', 'purify', 'on') }}"
turn_on:
action: climate.climate_ip_set_property
data:
entity_id: climate.거실_에어컨
purify: 'on'
turn_off:
action: climate.climate_ip_set_property
data:
entity_id: climate.거실_에어컨
purify: 'off'
동일한 패턴으로 auto_clean, beep, special_mode 등도 스위치/셀렉트로 확장 가능 (자세한 속성 목록은 samsungrac.yaml 설정 파일 참고).
3.7 신세대(8888) 지원 기능 목록
- 전원 켜기/끄기
- 목표/최소/최대 온도 설정 및 조회
- 풍향(swing) 설정 및 조회
- 팬 속도 설정 및 조회 / 최대 팬 레벨 설정
- 특수 모드 설정 (2Step, Comfort, Quiet 등)
- Good Sleep 모드 설정
- 공기청정(purify) 켜기/끄기
- 자동 청소(auto clean) 켜기/끄기
- 비프음(beep) 켜기/끄기
- 실내 온도 조회
- 기기 설정 정보 조회
3.8 알려진 이슈
| 이슈 | 비고 |
|---|---|
pip install 시 SSL 오류 | GitHub 이슈 #25에서 해결 방법 논의 중 |
| 토큰 미존재 (SmartThings 미등록 기기) | 스마트폰 앱으로 1회 등록 후 토큰 추출 필요 |
| MIM-H03/H04 등 중앙 컨트롤러 사용 시 | device_id 파라미터 별도 설정 필요 (기본값 032000000) |
3.9 실제 설정 가능한 값 총정리 (실기기 로그로 검증)
samsungrac.yaml(8888 포트, 신세대) 기준으로 climate.* 엔티티에서 조작 가능한 값들을 실제 기기 응답 로그로 검증한 결과입니다. 대상 기기는 두 대(FAC_BORA_RAC_17K 안방, FAC_BORA_17K 거실)이며, 두 모델의 내부 응답 구조가 달라 설정값 이름은 같아도 원문 로그로 재검증이 필요했습니다 (자세한 내용은 3.11).
climate 엔티티 표준 속성 (UI에서 바로 조작 가능)
| 속성 | HA 값 | 기기 값 | 비고 |
|---|---|---|---|
hvac_mode | cool | Cool | |
heat | Heat | ||
dry | Dry | ||
fan_only | Wind | ||
auto | Auto | 원래 heat_cool로 정의돼 있었으나, 실제 기기 동작이 완전자동 선택(HVACMode.AUTO)에 더 가까워 auto로 변경 | |
off | Operation.power: Off | ||
fan_mode | auto / low / medium / high / Turbo | speedLevel: 0~4 | |
swing_mode | off | Fix (안방) 또는 Off (거실) | 두 모델이 서로 다른 문자열로 “스윙 없음”을 보고함. Off도 off로 정규화 처리함 |
vertical | Up_And_Low | 실기기로 미검증 (문서/코드 추정값) | |
horizontal | Left_And_Right | 실기기로 미검증 | |
both | All | 실기기로 미검증 | |
preset_mode | None | Comode_Off | ✅ 실기기 로그로 검증됨 (두 기기 모두 기본값) |
Good Sleep | Comode_Sleep | 미검증 (로그상 관측된 적 없음) | |
Fast Turbo | Comode_Speed | 미검증 | |
2 Step | Comode_2Step | 미검증 | |
Comfort | Comode_Comfort | 미검증 | |
Quiet | Comode_Quiet | 미검증 | |
Single User | Comode_Smart | 미검증 | |
Wind Free | Comode_Nano | 미검증 |
표준 속성이 아닌, 서비스로만 제어 가능한 값 (3.10 참고)
| 속성명(서비스 파라미터) | 값 | 기기 값 | 비고 |
|---|---|---|---|
auto_clean | on / off | Autoclean_On / Autoclean_Off | ✅ 실기기 로그로 검증됨, 두 기기 모두 정상 |
special | preset_mode와 동일 값 세트 | Comode_* | preset과 소스가 같은 항목 (중복) |
good_sleep | 정수 0~24 (시간) | Sleep_{N} | ✅ 검증됨 (현재값 0) |
beep | on / off | Volume_100 / Volume_Mute | 안방은 정상 매핑되나, 거실 유닛은 Volume_33처럼 on/off 외 중간값을 보고해 이 경우 원문 그대로 노출됨 (알려진 한계) |
purify | on / off | Spi_On / Spi_Off | ⚠️ 두 기기 응답 어디에도 Spi_ 값이 관측되지 않음. 이 기종/펌웨어에서 실제 지원 여부 미확인 |
fan_max | auto/low/medium/high/Turbo | maxSpeedLevel: 0~4 | 실기기로 미검증 |
3.10 커스텀 속성 서비스로 제어하기 (climate_ip_set_property)
auto_clean, purify, beep, special, good_sleep, fan_max는 표준 climate 속성이 아니라서 카드 UI에 바로 안 뜨고, 아래 서비스로만 조작할 수 있습니다.
service: climate_ip.climate_ip_set_property
target:
entity_id: climate.livingroom_aircon # 대상 climate 엔티티 (개발자 도구 > 상태 에서 실제 값 확인)
data:
auto_clean: "on" # 또는 "off"
services.yaml이 비어 있어 개발자 도구 UI에 파라미터 폼이 뜨지 않음 → YAML 모드로 직접 입력해야 함.- 값은 대상 속성의 HA 쪽 키(
on/off등) 문자열 그대로 입력. - 여러 속성을 한 번에 바꿀 수도 있음(예:
auto_clean과beep을 같은 서비스 콜에 함께 지정). - 3.6처럼 Template Switch로 감싸면 대시보드에 토글 버튼으로 노출 가능.
auto_clean도 동일한 패턴 적용:
template:
- switch:
- name: "거실 에어컨 자동청소"
unique_id: ac_livingroom_autoclean
state: "{{ is_state_attr('climate.livingroom_aircon', 'auto_clean', 'on') }}"
turn_on:
action: climate_ip.climate_ip_set_property
data:
entity_id: climate.livingroom_aircon
auto_clean: "on"
turn_off:
action: climate_ip.climate_ip_set_property
data:
entity_id: climate.livingroom_aircon
auto_clean: "off"
3.11 기기별 실측 차이 & yaml 버그 수정 이력
두 대(안방 FAC_BORA_RAC_17K, 거실 FAC_BORA_17K)를 같은 samsungrac.yaml로 물렸는데, 실제 기기 응답의 Mode.options 배열 구조가 모델마다 달라서 원본 yaml(고정 인덱스 참조 방식)이 한쪽 기기에서만 정상 동작하는 문제가 있었습니다.
| 항목 | 원인 | 증상 | 수정 방법 |
|---|---|---|---|
preset_mode / special | 거실 유닛의 Mode.options 배열 맨 앞에 Operation_Family 항목이 하나 더 있어, 이후 모든 인덱스가 1칸씩 밀림 | 거실 유닛의 프리셋이 Operation_Family라는 값(없는 프리셋)으로 표시되며 매핑 실패 | 고정 인덱스(options.0) 대신, 배열 전체를 순회해 Comode_ 접두어를 가진 항목을 찾도록 status_template 변경 |
good_sleep | 위와 동일한 인덱스 밀림 | 거실 유닛에서 Comode_Off의 뒷부분(_Off)이 숫자처럼 파싱되어 잘못된 값 노출 | Sleep_ 접두어 검색 방식으로 변경 |
auto_clean | 위와 동일 | 거실 유닛에서 Sleep_0이 on/off 값으로 잘못 읽힘 | Autoclean_ 접두어 검색 방식으로 변경 |
beep | 원본이 options.14처럼 배열 끝 쪽 고정 인덱스를 참조 | 안방(배열 길이 10)은 인덱스 자체가 범위를 벗어나 값이 안 뜨고, 거실은 엉뚱한 값(ModelInfo_...)이 뜸 | Volume_ 접두어 검색으로 변경 (단, 거실은 Volume_33처럼 중간값이 있어 on/off로 완전히 표현은 안 됨 — 알려진 한계로 남김) |
swing_mode | “스윙 없음” 상태를 안방은 Fix, 거실은 Off로 서로 다르게 보고 | 거실 유닛의 스윙 상태가 매핑 테이블(Fix/Up_And_Low/Left_And_Right/All)에 없는 값이라 인식 실패 | status_template에서 Off를 Fix로 정규화 후 매핑 |
hvac_mode | 원본 키가 heat_cool로 정의됨 | 기능상 문제는 아니었으나, HA의 HVACMode.AUTO(“완전 자동”)와 의미가 더 맞아 사용자 요청으로 변경 | yaml 키를 heat_cool → auto로 rename (기기 값 Auto는 그대로) |
위 수정 내역은 실제 두 기기의 로그(
Mode.options,Wind.direction원문)를 놓고 템플릿을 직접 렌더링해 검증했습니다.purify(Spi_)는 두 기기 로그 어디에도 값이 관측되지 않아 여전히 지원 여부 미확인 상태입니다.
4. SmartThings 전용 기기 – Matter 브릿지 우회
2·3장에서 다룬 TV와 2018년형 에어컨은 각각 로컬 웹소켓/REST와 토큰 기반 로컬 REST API라는, 애초에 로컬 네트워크로 직접 붙을 수 있는 경로를 가진 기기였습니다. 이번 장에서 다루는 대상은 그 경로 자체가 없는 기기, 즉 SmartThings 앱에만 등록되어야 존재를 확인하고 제어할 수 있는 삼성 가전입니다.
4.1 대상 기기와 범위
- 공기청정기, 공기질 모니터, 냉장고나 세탁기의 일부 상태값처럼 와이파이 기반이라 로컬 프로토콜로 직접 붙일 방법이 없고, 삼성 클라우드와만 통신하도록 설계된 기기가 대상입니다.
- 지그비로 연결되는 센서/스위치류는 이 장에서 다루지 않습니다. SmartThings 허브를 거치지 않고 HA의 지그비 코디네이터로 바로 재페어링하면 되므로, 애초에 API 유료화와 무관한 문제입니다.
- 대상 기기는 지그비처럼 우회할 수 있는 대체 경로 자체가 없다는 게 공통적인 문제입니다.
4.2 지금 문제가 되는 구조
현재는 HA가 SmartThings 클라우드의 REST API를 거쳐서 이 기기들과 통신합니다.
- 상태 조회: HA가 API를 폴링하거나 웹훅을 구독
- 제어: HA가 API로 커맨드를 호출
즉 상태 조회든 제어든 전부 과금 대상이 될 REST API를 경유하는 구조이며, 이 경로 자체를 없애는 것이 이 장의 목표입니다.
4.3 핵심 아이디어
두 가지 사실을 조합합니다.
- SmartThings 루틴(자동화)은 API 과금과 무관하게 ST 앱과 허브 내부에서 로컬로 동작합니다.
- Matter는 클라우드 API가 아니라 로컬 네트워크 기반 프로토콜이므로 이번 유료화 정책과 무관합니다.
이 둘을 조합하면, HA와 SmartThings 사이에 REST API를 단 한 번도 호출하지 않고도 상태 동기화와 제어가 모두 가능한 우회로를 만들 수 있습니다.
동작 원리를 순서대로 정리하면:
- HA 안에 실제 SmartThings 기기를 대리하는 가상 기기를 하나 만든다.
- 이 가상 기기를 Matterbridge(애드온/앱)를 통해 Matter 액세서리로 바깥에 노출시킨다.
- SmartThings 허브 혹은 앱의 Matter 지원 기능이 이 가상 기기를 **로컬 네트워크 상에서 커미셔닝(페어링)**해서 ST 앱의 기기 목록에 추가한다. 여기까지는 전부 로컬 통신이라 API 호출이 발생하지 않는다.
- SmartThings 앱 안에서 실제 기기의 상태가 바뀔 때마다 가상 기기의 상태도 똑같이 맞춰주는 루틴을 만든다. → 가상 기기 상태가 바뀌는 순간 Matter의 상태 구독 리포트를 통해 HA 쪽 가상 기기 상태도 즉시 갱신되고, 결과적으로 HA에서 보는 값이 실제 ST 기기 상태와 항상 일치한다.
- 반대 방향(제어)도 같은 원리다. HA에서 가상 기기를 조작하면 Matter 커맨드로 SmartThings 쪽 가상 기기에 전달되고, 가상 기기 상태가 바뀌면 실제 기기를 그 상태로 제어하라는 루틴을 하나 더 만들면 된다.
정리하면 HA는 오직 Matter로만 이야기하고, 실제 기기와 가상 기기 사이의 상태 미러링은 전부 SmartThings 루틴이 전담하는 구조입니다. HA 입장에서는 SmartThings라는 존재 자체를 몰라도 됩니다.
4.4 필요한 구성 요소
| 구성 요소 | 위치 | 역할 |
|---|---|---|
가상 엔티티 (input_boolean / template switch / Template Climate) | HA | 실제 기기를 대리하는 그릇 |
| Matterbridge | HA 애드온 또는 별도 컨테이너 | 위 엔티티를 Matter 액세서리로 노출 |
| 허브/앱의 Matter 지원 기능 | SmartThings | Matter 컨트롤러 겸 커미셔너로 가상 기기를 로컬 페어링 |
| SmartThings 루틴 2개 | SmartThings | 실제 기기 ↔ 가상 기기 상태를 양방향으로 미러링 |
4.5 설정 절차 – 온오프형 기기 기준
전원 켜기/끄기 정도의 캐패빌리티만 있는 기기부터 봅니다.
- HA에 가상 스위치 정의:
configuration.yaml에input_boolean을 하나 정의해 실제 기기를 대리하는 가상 스위치를 만듭니다. 상태 변경 시 알림/로그 같은 부가 기능이 필요하면 5장 문법의 template 스위치로 확장할 수도 있습니다. - Matterbridge 설치: HA 애드온 스토어(공식
Matterbridge Home Assistant Application,https://github.com/Luligu/matterbridge-home-assistant-addon) 또는 도커로 설치합니다. - 엔티티 브릿징: Matterbridge에서 1번의 가상 스위치 엔티티(HA 통합 대상이므로
matterbridge-hass플러그인 사용)를 Matter 액세서리로 브릿징합니다. 이 과정에서 페어링 코드(QR/숫자 코드)가 발급됩니다. - SmartThings에서 커미셔닝: SmartThings 앱 → 기기 추가 → Matter 기기 추가 플로우를 선택하고, 3번에서 발급된 코드로 로컬 커미셔닝을 진행합니다. 정상 완료되면 ST 앱 안에 “가상 기기”라는 새 기기가 생기며, 이 통신은 로컬 스레드/와이파이 기반이라 REST API를 전혀 타지 않습니다.
- SmartThings 루틴 2개 생성
- 루틴 A: 실제 기기 상태(켜짐/꺼짐)가 바뀌면 → 가상 기기 상태를 동일하게 설정
- 루틴 B: 가상 기기 상태가 바뀌면 → 실제 기기를 그 상태로 제어
루틴 A 덕분에 가상 기기 상태가 바뀌면 Matter 상태 리포트를 통해 HA의 input_boolean 상태도 즉시 갱신되고, 루틴 B 덕분에 HA에서 가상 기기를 조작하면 그게 실제 기기 제어로 이어집니다. Matter의 온오프(On/Off) 클러스터는 원래 외부에서 값을 써넣을 수 있도록 설계되어 있으므로, 전원 제어가 전부인 기기라면 이 방식이 무리 없이 통할 가능성이 높습니다.
4.6 한계 – 읽기 전용 센서형 기기는 통하지 않을 수 있음
공기질 모니터처럼 제어할 것 없이 값을 읽기만 하는 순수 센서형 기기는 사정이 다릅니다.
- 4.3~4.5의 구조는 근본적으로 SmartThings 루틴이 가상 기기의 상태값을 특정 값으로 강제로 세팅하는 액션이 존재한다는 것을 전제로 합니다.
- 스위치나 에어컨 전원처럼 On/Off 클러스터는 외부에서 값을 써넣을 수 있도록 설계되어 있어 이 전제가 성립합니다.
- 반면 온도·습도·미세먼지 농도 같은 측정값 클러스터는 Matter 표준상 대체로 읽기 전용이라, 외부에서 임의의 값을 써넣도록 만들어져 있지 않습니다.
- 즉 SmartThings 루틴의 액션 목록에 “가상 공기질 센서의 미세먼지 수치를 특정 값으로 설정하라”는 항목 자체가 아예 없을 가능성이 있습니다. 이 경우 스위치/에어컨 전원에 통했던 트릭이 센서형 기기에는 구조적으로 통하지 않습니다.
4.7 적용 가능 여부 판단 기준
정리하면, SmartThings 전용 기기를 이 방식으로 우회할 수 있는지는 결국 그 기기의 캐패빌리티가 쓰기 가능한지, 읽기 전용인지에 달려 있습니다.
| 캐패빌리티 성격 | 예시 | 이 방식 적용 가능성 |
|---|---|---|
| 쓰기 가능 (외부에서 값을 써넣을 수 있음) | 전원 On/Off, 모드 설정 | 높음 |
| 읽기 전용 (측정값만 내보냄) | 공기질 모니터의 미세먼지 농도, 순수 온습도 센서값 | 낮음/구조적으로 불가능할 가능성 큼 |
4.8 기대 효과
- HA와 SmartThings 사이에 REST API 호출이 전혀 발생하지 않아 유료화 정책과 무관해집니다.
- 기존 SmartThings 통합과 사용자 체감상 거의 동일한 양방향 동기화 경험을 유지할 수 있습니다.
- Matter가 로컬 프로토콜이다 보니 기존 클라우드 폴링 방식보다 응답 속도가 더 빠를 가능성이 있습니다.
5. Template Switch 최신 문법
Home Assistant는 switch: - platform: template 방식을 2025.12부터 deprecated, 2026.6부터 완전 제거했습니다. 최상위 template: 키를 사용하는 새 문법으로 전환해야 합니다.
변경 비교
| 항목 | 예전 (제거됨) | 최신 |
|---|---|---|
| 최상위 키 | switch: + platform: template | template: |
| 여러 스위치 묶기 | switches: 딕셔너리 | switch: 리스트 (항목별 딕셔너리) |
| 이름 지정 | friendly_name: | name: |
| 상태 판별 | value_template: | state: |
| 서비스 호출 키 | service: | action: (service:도 동작은 하나 action:이 표준) |
| 고유 ID | 선택 | unique_id 부여 시 UI에서 이름/아이콘 편집 가능 (권장) |
최신 문법 기본 골격
template:
- switch:
- name: "스위치 이름"
unique_id: 고유_id
state: "{{ 상태_판별_템플릿 }}"
turn_on:
action: 도메인.서비스명
target:
entity_id: 대상_엔티티
turn_off:
action: 도메인.서비스명
target:
entity_id: 대상_엔티티
template:키는 파일 내에서 하나만 존재해야 하므로, 기존에sensor:,binary_sensor:등 다른 template 항목이 있다면 그 아래에switch:항목만 추가.- 설정 반영: 개발자 도구 → YAML → 설정 다시 로드 → Template Entities 리로드로 재시작 없이 적용 가능.
- ⚠️ ESPHome 기기 YAML 안의
platform: template은 이 deprecation과 무관 (ESPHome 자체 문법이므로 그대로 유지).
6. 참고 자료 / 링크
TV
- Home Assistant 공식 문서:
https://www.home-assistant.io/integrations/samsungtv/ - SmartThings 통합(참고, 유료화 공지 포함):
https://www.home-assistant.io/integrations/smartthings/ - 서드파티 통합 (SmartThings 토큰 활용, 로컬 옵션 포함):
https://github.com/ollo69/ha-samsungtv-smart
에어컨
- 사용 통합 저장소 (HACS Custom repository로 등록):
https://github.com/clipman/samsungrac - 상위 저장소 (fork 대상):
https://github.com/atxbyea/samsungrac - 원본 저장소 (활동 중단):
https://github.com/SebuZet/samsungrac - 토큰 추출 참고 가이드:
https://www.creatingsmarthome.com/index.php/2021/06/09/guide-samsung-a-c-to-home-assistant/ - 삼성 AC 프로토콜 설명 (openHAB 커뮤니티):
https://community.openhab.org/t/newgen-samsung-ac-protocol/33805 - 구세대(2878 포트, 2013~2015년형) 전용 대안 통합:
https://github.com/porech/samsung_ac_dplug
SmartThings 전용 기기 (Matter 브릿지 우회)
- Matterbridge 공식 Home Assistant 애플리케이션(애드온):
https://github.com/Luligu/matterbridge-home-assistant-addon - Matterbridge용 Home Assistant 플러그인 (
matterbridge-hass, HA 엔티티를 Matter로 노출):https://github.com/Luligu/matterbridge-hass - Home Assistant Matter 통합(로컬 Matter 컨트롤러) 공식 문서:
https://www.home-assistant.io/integrations/matter/
Template
- Home Assistant Template 통합 공식 문서:
https://www.home-assistant.io/integrations/template/
7. 전체 요약
| 기기 | 방식 | 통합 | 포트/프로토콜 | 상태 |
|---|---|---|---|---|
| Samsung TV | 로컬 REST API + 웹소켓 | samsungtv (HA 내장) | 로컬 네트워크 | ✅ 설정 완료 |
| Samsung 에어컨 (2018년형) | 로컬 토큰 기반 REST API | climate_ip (clipman/samsungrac, HACS Custom repository) | 8888 (TCP/HTTPS) | ✅ 토큰 추출 완료 (B5F6rz6771) / HA 설정 반영 단계 |
| SmartThings 전용 기기 (공기청정기, 공기질 모니터 등, 쓰기 가능한 캐패빌리티) | 가상 기기 + Matterbridge + SmartThings 루틴 미러링 | Matterbridge(matterbridge-hass) + SmartThings 앱 Matter 지원 | 로컬 Matter (Thread/Wi-Fi) | 구조 설계 완료 / 구축 단계 |
| SmartThings 전용 기기 (읽기 전용 측정값, 예: 공기질 미세먼지 농도) | 해당 없음 – 구조적 한계 | – | – | ❌ 이 방식으로는 적용 불가 가능성 큼 (대안 검토 필요) |
세 부류 모두 SmartThings 클라우드 API 없이, 같은 LAN 안에서 로컬 통신만으로 제어/동기화하는 것이 핵심 목표이며, 이를 통해 향후 SmartThings API 유료화 정책과 무관하게 안정적으로 자동화를 유지할 수 있습니다. 다만 읽기 전용 센서형 기기는 Matter 클러스터 구조상 이번 우회 방식이 통하지 않을 가능성이 크므로, 필요 시 별도의 대안(예: 유료 Personal Plan 구독, 또는 삼성 기기의 로컬 프로토콜이 추후 공개될 경우 재검토)을 고려해야 합니다.