Home Assistant로 묶은 우리 집, 자동화마다 적어 둔 설정 노트

“거실 불 꺼 줘.” 이 한마디에 우리 집 조명 17개가 한꺼번에 반응한 적이 있다. 원인은 둘이었다. 음성 비서에게 벽스위치를 하나도 빼지 않고 다 보여 줬고 구글 홈에서는 그 스위치들이 전부 거실로 잡혀 있었다. 7월 6일에 방마다 조명 묶음을 만들고 음성 비서에게는 그 묶음과 전체 조명만 보이게 바꿨다.
우리 집 Home Assistant(HA)는 이런 설정이 하나씩 쌓여서 지금 모양이 됐다. HA는 회사가 다른 스마트홈 기기를 한곳에 모아 자동화를 만드는 오픈소스 프로그램이다. 이 글에는 우리 집 HA가 맡은 일마다 무엇을 하는지, 왜 그렇게 정했는지, 설정은 어떻게 생겼는지를 적는다. 템플릿과 자동화 예시는 그대로 복사해 쓸 수 있게 코드 칸에 넣었다.

허브 셋은 그대로 두고 HA를 올렸다
인테리어 공사 때 들어온 기기들은 만든 회사가 셋으로 나뉜다. 회사마다 허브와 앱이 따로라서 한 회사 센서가 본 걸 다른 회사 스위치가 알 길이 없었다.
| 허브 | 주로 연결된 기기 | 대수(8월 22일) |
|---|---|---|
| 아카라 허브 | 벽스위치, 도어락, 커튼 | 14대 |
| 투야 게이트웨이 | 난방 조절기, 온습도 센서, 화장실 움직임 센서 | 16대 |
| 삼성 SmartThings | 에어컨과 가전(허브 내장) | 11대 |
세 허브를 합치면 41대이고 나머지 2대는 허브 없이 HA에 바로 연결된 로봇청소기 쪽 기기다.
HA는 이 허브들을 없애지 않는다. 허브마다 HA의 통합으로 연결하고 HA가 그 위에서 기기 상태를 모아 자동화를 실행한다. 손으로 연 커튼처럼 HA가 모르는 상태도 있다. 우리 집 HA는 윈도우 홈서버의 도커 컨테이너에서 실행된다. 말로 부르고 말로 듣는 쪽은 거실의 구글 네스트 허브가 맡고 아카라 기기의 상태 신호는 n8n이 받아서 HA로 넘긴다.

이 구조도는 SVG 원본으로 내려받을 수 있다.
기기는 43대(8월 22일 기준)다. HA가 다루는 가장 작은 단위를 엔티티라고 부르는데, 조명 하나, 온도 센서 값 하나가 각각 엔티티 하나다. 우리 집 엔티티는 405개(8월 23일)이고 자동화는 41개(9월 6일)다. 2화에 적은 자동화 29개는 6월 8일 기준이었으니, 석 달 사이 41개로 늘었다.
첫 화면은 방 단위로 나눴다
기기가 마흔 대를 넘으면 이름보다 위치로 찾는 게 빠르다. 캡처한 9월 14일 화면에서는 위쪽 즐겨찾기에 자주 쓰는 조명과 커튼을 올려 뒀다. 아래쪽은 거실, 주방, 화장실처럼 방 이름으로 칸을 만들었고 오른쪽 칸에는 유지보수 상태가 뜬다.

거실 칸을 열면 거실에 있는 기기가 한 화면에 모인다. 에어컨과 난방, 공기청정기, 전동 커튼, 벽스위치마다의 조명과 전력, 로봇청소기, 따로 둔 공기질 측정기까지 있다. 스크롤이 길어서 아래 그림은 캡처 두 장을 붙인 것이다.

맨 앞의 조명 17개 사건도 같은 원리로 풀었다.
커튼은 28도와 25도 사이에서 움직이지 않는다
여름 낮에 거실 커튼을 여닫는 기준은 발코니 온도 28도와 25도, 두 값이다. 28도를 넘으면 닫기, 25도 밑으로 내려가면 열기. 25도와 28도 사이에서는 아무것도 하지 않는다.
기준을 하나만 쓰면 탈이 난다. 예를 들어 28도 하나만 기준으로 쓰면, 발코니 온도가 28도 언저리에서 0.1도씩 오르내리는 날엔 커튼이 쉬지 않고 열리고 닫힌다. 그래서 닫는 값과 여는 값을 3도 떨어뜨렸다. 이렇게 켜는 값과 끄는 값을 일부러 다르게 두는 방식을 히스테리시스(hysteresis)라고 부른다.
봄, 가을, 겨울에는 바깥 밝기를 기준으로 쓴다. 열 때는 해가 뜬 다음 밖이 충분히 밝아졌는지를 보고 닫을 때는 해가 진 다음 어두워졌는지를 본다. 낮에는 볕을 들이고 밤에는 집 안 온기가 빠져나가지 않게 하려는 설정이다.
여름 기준을 HA 자동화로 적으면 아래 모양이 된다. 우리 집 설정 파일을 그대로 옮긴 게 아니라 같은 기준을 적은 예시라서 엔티티 이름은 자기 집 것으로 바꿔야 한다. 우리 집 거실 커튼은 ‘열기’, ‘닫기’ 명령을 무시해서 위치값(열림 100, 닫힘 0)으로 보낸다. 여닫기 명령이 잘 듣는 커튼이면 위치값 대신 cover.close_cover 와 cover.open_cover 를 써도 된다.
# 예시: 엔티티 이름은 자기 집 것으로 바꾼다
- alias: 여름 거실 커튼 닫기 (발코니 28도 넘음)
trigger:
- platform: numeric_state
entity_id: sensor.balcony_temperature
above: 28
action:
- service: cover.set_cover_position
target:
entity_id: cover.living_room_curtain
data:
position: 0
- alias: 여름 거실 커튼 열기 (발코니 25도 밑)
trigger:
- platform: numeric_state
entity_id: sensor.balcony_temperature
below: 25
action:
- service: cover.set_cover_position
target:
entity_id: cover.living_room_curtain
data:
position: 100
우리 집 기록에서 여름은 6월부터 8월까지다. 두 자동화에 아래 조건을 똑같이 넣으면 여름 낮에만 실행된다(trigger, action 과 같은 들여쓰기).
condition:
- condition: template
value_template: "{{ now().month in [6, 7, 8] }}"
- condition: state
entity_id: sun.sun
state: above_horizon
numeric_state 트리거는 값이 기준선을 넘어가는 순간에만 실행되니, 온도가 28도 위에 계속 머물러도 닫기가 되풀이되지는 않는다. 센서가 잠깐 끊겼다 돌아오면 한 번 더 실행될 수 있지만 위치값 명령이라 이미 닫힌 커튼은 그대로다.
위 예시는 automations.yaml 에 넣는 목록 모양이다. HA 화면의 자동화 편집기에서 ‘YAML로 편집’에 붙일 때는 하나씩, 맨 앞의 ‘- ‘를 빼고 붙인다. automations.yaml 에 직접 넣을 때는 자동화마다 id: 를 하나씩 달아 둬야 화면에서도 고칠 수 있다.
공기청정기와 ‘우리집 현황’ 화면
외출 모드가 켜지면 공기청정기도 같이 꺼진다. 집에 사람이 있을 때는 공기 질 수치에 따라 세기가 달라진다.
‘우리집 현황’ 화면에는 방마다 온도와 습도, 에어컨과 난방 상태, 공기질을 한데 모았다. 오른쪽 그래프는 공기청정기에 달린 센서와 따로 사 둔 측정기의 초미세먼지(PM2.5) 값을 같이 그린다. 캡처한 날에도 한쪽은 27, 다른 쪽은 7을 가리켰다. 어느 쪽 말이 맞는지 몰라서 두 값을 다 띄워 둔다.

스피커는 아침 브리핑, 학원 알람, 현관 인사를 맡는다
아침에 스피커가 맡은 일은 8시 브리핑이다. 두 캘린더(가족, 내 업무)를 합친 다음 이미 지난 일정은 빼고 남은 것만 스피커로 읽는다. 놓쳤을 땐 “오늘 브리핑 켜 줘” 한마디면 처음부터 다시 나온다.
학원 알람은 아이들 학원 시간표를 넣어 두고 거실 스피커가 때맞춰 이름을 부르게 한 자동화다. 언제 누구를 부르는지는 이렇다.
| 언제 | 누구를 부르나 |
|---|---|
| 학원 가기 20분 전 | 그 학원에 갈 아이 |
| 학원 차를 타는 날, 탑승 10분 전 | 차를 탈 아이(한 번 더) |
| 학원 차에서 내리기 5분 전 | 마중 나갈 어른 |
| 두 아이 시각이 겹칠 때 | 두 아이 모두 |
받침 계산 템플릿
이름을 부르는 문장에는 받침 문제가 따라온다. 받침이 있는 이름 뒤에는 ‘아’, 없는 이름 뒤에는 ‘야’가 붙어야 자연스럽다. 이름마다 문장을 따로 만들 수도 있지만 HA 템플릿을 쓰면 끝 글자를 보고 알아서 고른다. 템플릿 속 이름은 지어낸 것이다.
{%- set who = "지안" -%}
{%- set has_final = ((who[-1] | ord) - 44032) % 28 != 0 -%}
{{ who }}{{ "아" if has_final else "야" }}, 학원 갈 시간이야
이름이 “지안”이면 “지안아, 학원 갈 시간이야”, “서우”면 “서우야, 학원 갈 시간이야”가 된다.
원리는 유니코드에 있다. 한글 음절 11,172자는 첫소리, 가운뎃소리, 받침의 조합 순서대로 번호가 붙어 있고 맨 앞 ‘가’가 44032번이다. 받침 자리는 받침 없음까지 28가지라서 끝 글자의 번호에서 44032를 뺀 값을 28로 나눠 보면 된다. 나머지가 0이면 받침이 없고 0이 아니면 받침이 있다. ord는 글자를 유니코드 번호로 바꿔 주는 HA 템플릿 필터다. 이름이 한글로 끝날 때만 맞으니, 영어 이름이나 숫자로 끝나는 이름에는 쓰지 않는다.
현관 인사
도어락에 지문이 찍히면 스피커가 들어온 사람에게 인사한다. 인사 문장은 매번 AI가 새로 만든다. 누가 들어왔는지, 집을 얼마나 오래 비웠는지, 구글 캘린더에 적힌 가족 일정이 무엇인지에 따라 말이 달라진다. AI 답이 7초 안에 오지 않으면 미리 준비해 둔 인사로 넘어간다. 신발도 못 벗고 서 있게 할 수는 없으니까.
식구들이 다 잠든 늦은 밤에도 반겨 주는 목소리가 있어서 귀갓길이 은근히 기다려질 때가 있다.
집안일 칸
‘우리집 현황’ 화면을 아래로 내리면 집안일 칸이 나온다. 습도와 소모품 위주다. 화장실 두 곳의 습도와 환풍기, 로봇청소기 소모품을 갈 때까지 남은 시간과 물통이 얼마나 남았는지 추정한 값, 벙커침대 아래 수납칸의 습도를 한 화면에 모았다. 수납칸 습도는 방 습도와 나란히 재서 비교하고 그날 할 일도 띄운다. 캡처할 때 떠 있던 건 수납칸을 열어서 말리라는 안내였다.

밤에는 스스로 점검한다
HA를 쓰다 보면 이유를 다 알 수 없는 자잘한 고장이 생긴다. 연결이 끊기기도 하고 센서 값이 어느 순간부터 갱신되지 않기도 한다. 그래서 밤사이에 점검이 실행된다.
가장 중요한 건 아카라 인증 토큰이다. 토큰 유효 기간은 30일이고 남은 기간이 5일 안으로 들어오면 자가수리 스크립트가 새 토큰을 받아 넣은 뒤 텔레그램으로 결과를 알린다. 우리 집에서는 이 스크립트가 매일 새벽 4시에 실행된다. 센서가 몇 시간째 아무 값도 보내지 않을 때도 알림이 온다.
이 스크립트에서 우리 집 정보를 뺀 키트를 홈 블로그에 올려 뒀다: 아카라 토큰 자동 갱신 키트
아이들 기기 사이트 차단은 HA 밖에 뒀다
공유기에는 원래 기기마다 사이트 접속을 제한하는 기능이 있다. 이걸로 아이들이 쓰는 기기에서 유튜브와 게임 사이트를 막았다. HA는 여기 관여하지 않는다.
막을 기기를 고르지 않고 허락할 기기를 고르는 쪽으로 정했다. 처음 보는 기기는 기본으로 그 사이트들이 막히고 허락 목록에 올린 기기만 막힌 사이트에 들어갈 수 있다. 기기가 새로 생겨도 저절로 막히는 쪽이라 놓칠 일이 없다. 덕분에 새로 산 내 폰도 첫날 넷플릭스가 안 열렸다.
DNS로 막는 방법도 있었다. 다만 그 DNS를 홈서버에 두면, 홈서버가 멈추는 날 집 안 모든 기기의 인터넷이 같이 끊긴다. 그래서 공유기 기능을 골랐다. 아이들에게는 집 인터넷이 고장 났다고 말해 뒀는데, 큰아이는 믿지 않는 눈치다.
반년 뒤 제일 크게 달라진 것
HA로 묶고 나서 나는 누워서 말로 불을 끄는 게으른 날을 꿈꿨다. 반년이 지나고 보니 제일 쓸모 있었던 건 따로 있었다. 지난여름 방학 동안 아이들이 학원에 한 번도 늦지 않았다. 마지막 학원 알람 뒤에는 와이파이를 잠시 끊어 두기도 한다. 이것도 제법 도움이 됐다.
따라 하려면
- 쓰던 허브와 앱은 그대로 둔다. HA에서 허브를 하나씩 통합으로 연결하면 된다.
- 처음 만들 자동화는 하나면 충분하다. 고르는 기준은 서로 다른 회사 기기를 잇는 것이다. 우리 집에서 처음으로 회사가 다른 기기를 이은 자동화도 투야 움직임 센서와 아카라 스위치로 켜는 화장실 조명이었다.
- 첫 화면과 음성 비서는 방 단위로 나눈다.
- 켜고 끄는 기준이 한 값 근처에서 오락가락하면, 켜는 값과 끄는 값을 따로 둔다.
- 안내 문장에 이름이 들어가면 받침 템플릿을 쓴다.
- 토큰처럼 기한이 있는 연결은 만료 전에 알아서 갱신하게 만든다.
다음 글에선
다음 글은 우리 집이 여기까지 온 과정이다. 앱 세 개를 오가던 시절, 윈도우 홈서버에 HA를 처음 켠 3월 마지막 주말, 그리고 연결이 끊길 때마다 씨름한 반년을 적는다.