일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 공모주
- raspberry pi
- MQTT
- 티스토리챌린지
- 배당
- homebridge
- Bestin
- RS-485
- 월패드
- 매터
- 현대통신
- 파이썬
- 코스피
- Home Assistant
- cluster
- Python
- 애플
- Apple
- 오블완
- 국내주식
- 해외주식
- SK텔레콤
- 힐스테이트 광교산
- matter
- ConnectedHomeIP
- Espressif
- 나스닥
- 홈네트워크
- 미국주식
- esp32
- Today
- Total
YOGYUI
현대통신 월패드 주방 비디오폰 세대현관문/공동현관문 자동 열림 기능 추가 본문
Hyundai HT Wallpad: Automatic Open Front/Communal Door Function (Kitchen Subphone)
요근래 1주일간 블로그에 달린 댓글들이 나를 아주 기분좋게 만들었다 ^^
특히 '현대통신 월패드 RS-485 통신 연동 홈어시스턴트 애드온'은 큰 문제없이 잘 작동하고 있다고 하니 꽤나 뿌듯하다
기분이 좋아진 김에, "언젠가는 해야지..." 하고 미뤄뒀던 추가 기능 개발을 하루만에 해치워버렸다 ㅋㅋ
힐스테이트 광교산::주방 비디오폰 세대현관문/공동현관문 기능 분리 (HomeAssistant)
주방 비디오폰 연동 관련 글이 반응이 나름 좋았는데, "세대/공동현관문 자동 열림" 기능은 홈어시스턴트(HA)나 애플 홈킷, 구글 홈 등 IoT 플랫폼의 자동화나 씬(scene)을 통해 구현을 해야만 했다
구글 홈이나 애플 홈킷 등 홈 IoT 플랫폼에서 별도로 사용자가 자동화를 구성할 필요없이 간단하게 현관문이 호출된 후 일정 시간이 지나면 자동으로 열어주는 기능을 활성화/비활성화할 수 있게 엔티티(혹은 액세서리)를 추가해봤다
※ 개인적으로 자동 열림 기능은 배달 음식 시켜먹을 때 아주 유용하게 써먹고 있다
1. 요구사항
- 구글 홈, 애플 홈킷 등 홈 IoT 플랫폼에서 손쉽게 자동열림 기능을 켜고 끌 수 있어야 한다
- 세대현관문과 공동현관문의 자동 열림 기능은 서로 분리되어야 한다
- 현관문이 호출된 후 일정 시간이 지나면 자동으로 열어줘야 한다
2. 코드 구현
위에서 정리한 요구사항들을 바탕으로 간단하게 코드 몇줄을 추가해줬다
2.1. 소스코드 변경 사항
현관문이 호출된 후 일정 시간이 지나면 종료되면서 콜백을 호출하는 쓰레드를 다음과 같이 구현했다
## Subphone.py
import threading
class ThreadAutoOpenDoor(threading.Thread):
_keepAlive: bool = True
def __init__(self, interval_sec: float):
threading.Thread.__init__(self)
self.interval_sec = interval_sec
self.sig_terminated = Callback(bool)
def run(self):
tm_start = time.perf_counter()
while self._keepAlive:
elapsed = time.perf_counter() - tm_start
if elapsed >= self.interval_sec:
break
time.sleep(100e-3)
self.sig_terminated.emit(self._keepAlive)
def stop(self):
self._keepAlive = False
세대현관문, 공동현관문 각각 자동열림 기능을 활성화할 지 여부 및 몇 초가 지난 뒤 열지(인터벌 시간)를 결정하는 파라미터는 Subphone 객체 내부 멤버변수로 지정했다 (인터벌 default값은 3초로 설정.. 너무 바로 여는 것보다는 어느 정도 여유를 두고 여는게 약간 자연스러워보인다고나 할까? ㅋㅋ)
class SubPhone(Device):
# 세대/공동현관문 자동 열림 기능
enable_auto_open_front_door: bool = False
auto_open_front_door_interval_sec: float = 3
enable_auto_open_communal_door: bool = False
auto_open_communal_door_interval_sec: float = 3
def __init__(self, name: str = 'SubPhone', index: int = 0, room_index: int = 0):
self._thread_auto_open_front_door: Union[ThreadAutoOpenDoor, None] = None
self._thread_auto_open_communal_door: Union[ThreadAutoOpenDoor, None] = None
self.sig_open_front_door = Callback(int, int)
self.sig_open_communal_door = Callback(int, int)
현관문 각각 쓰레드 시작/종료 및 콜백 처리 메서드도 적절하게 구현
class SubPhone(Device):
def _startThreadAutoOpenFrontDoor(self):
if self._thread_auto_open_front_door is None:
self._thread_auto_open_front_door = ThreadAutoOpenDoor(self.auto_open_front_door_interval_sec)
self._thread_auto_open_front_door.sig_terminated.connect(self._onThreadAutoOpenFrontDoorTerminated)
self._thread_auto_open_front_door.daemon = True
self._thread_auto_open_front_door.start()
writeLog('Auto open front door thread started', self)
def _stopThreadAutoOpenFrontDoor(self):
if self._thread_auto_open_front_door is not None:
self._thread_auto_open_front_door.stop()
def _onThreadAutoOpenFrontDoorTerminated(self, command: bool):
del self._thread_auto_open_front_door
self._thread_auto_open_front_door = None
writeLog('Auto open front door thread terminated', self)
if command:
self.sig_open_front_door.emit(self.index, self.room_index)
def _startThreadAutoOpenCommunalDoor(self):
if self._thread_auto_open_communal_door is None:
self._thread_auto_open_communal_door = ThreadAutoOpenDoor(self.auto_open_communal_door_interval_sec)
self._thread_auto_open_communal_door.sig_terminated.connect(self._onThreadAutoOpenCommunalDoorTerminated)
self._thread_auto_open_communal_door.daemon = True
self._thread_auto_open_communal_door.start()
writeLog('Auto open communal door thread started', self)
def _stopThreadAutoOpenCommunalDoor(self):
if self._thread_auto_open_communal_door is not None:
self._thread_auto_open_communal_door.stop()
def _onThreadAutoOpenCommunalDoorTerminated(self, command: bool):
del self._thread_auto_open_communal_door
self._thread_auto_open_communal_door = None
writeLog('Auto open communal door thread terminated', self)
if command:
self.sig_open_communal_door.emit(self.index, self.room_index)
현관문의 호출 상태가 변했을 때, 자동열림 기능이 활성화되어 있는 경우 인터벌 체크 쓰레드를 구동하도록 다음과 같이 코드를 추가해줬다
class Subphone(Device):
def updateState(self, _: int, **kwargs):
ringing_front = kwargs.get('ringing_front')
if ringing_front is not None:
if ringing_front:
self.state_ringing = StateRinging.FRONT
self.state_ringing_front = 1
if self.enable_auto_open_front_door:
self._startThreadAutoOpenFrontDoor()
else:
self.state_ringing = StateRinging.IDLE
self.state_ringing_front = 0
self._stopThreadAutoOpenFrontDoor()
ringing_communal = kwargs.get('ringing_communal')
if ringing_communal is not None:
if ringing_communal:
self.state_ringing = StateRinging.COMMUNAL
self.state_ringring_communal = 1
if self.enable_auto_open_communal_door:
self._startThreadAutoOpenCommunalDoor()
else:
self.state_ringing = StateRinging.IDLE
self.state_ringring_communal = 0
self._stopThreadAutoOpenCommunalDoor()
이 외에 콜백 처리 구문이나 활성화 여부 등의 코드는 Home 객체에 구현해뒀는데, 아래 깃허브 커밋을 보면 구현 방법을 상세히 알 수 있다
2.2. MQTT 사양
(1) 현재 상태를 외부로 publish
Topic: home/state/subphone/0/0/autoopen
Payload: {
"enable_auto_open_front": int,
"auto_open_front_interval": float,
"enable_auto_open_communal": int,
"auto_open_communal_interval": float
}
(2) 상태 변경 명령 subscribe
Topic: home/command/subphone/0/0
Payload:
- {"enable_auto_open_front": int}
- {"auto_open_front_interval": float}
- {"enable_auto_open_communal": int}
- {"auto_open_communal_interval": float}
(4종의 페이로드를 한꺼번에 보내도 동작함)
2.3. GitHub Commit
commit id: fc6e14e8f7c83e5108b9efef84ee9097d3348de4
https://github.com/YOGYUI/HomeNetwork/commit/fc6e14e8f7c83e5108b9efef84ee9097d3348de4
3. 홈IoT 플랫폼 연동
구글홈, 애플홈, HomeAssistant 모두 자동열림 기능을 간단하게 활성화/비활성화하기 위해 스위치 형태로 액세서리 혹은 엔티티를 추가해주기로 결정!
3.1. Homeassistant 엔티티 추가 (auto discovery)
HA 사용자의 경우 별도로 configuration.yaml 파일을 수정할 필요없이 자동으로 엔티티가 추가될 수 있는 MQTT discovery 기능을 사용하면 된다
Subphone.py 내부에 discovery용 토픽 및 페이로드 발행 코드를 아래와 같이 구현했다
class Subphone(Device):
def configMQTT(self, retain: bool = False):
topic = f'{self.ha_discovery_prefix}/switch/{self.unique_id}_auto_open_front/config'
obj = {
"name": self.name + " Auto Open (Front)",
"object_id": self.unique_id + "_auto_open_front",
"unique_id": self.unique_id + "_auto_open_front",
"state_topic": self.mqtt_publish_topic + '/autoopen',
"command_topic": self.mqtt_subscribe_topic,
"value_template": '{ "enable_auto_open_front": {{ value_json.enable_auto_open_front }} }',
"payload_on": '{ "enable_auto_open_front": 1 }',
"payload_off": '{ "enable_auto_open_front": 0 }',
"icon": "mdi:door-open"
}
self.mqtt_client.publish(topic, json.dumps(obj), 1)
topic = f'{self.ha_discovery_prefix}/switch/{self.unique_id}_auto_open_communal/config'
obj = {
"name": self.name + " Auto Open (Communal)",
"object_id": self.unique_id + "_auto_open_communal",
"unique_id": self.unique_id + "_auto_open_communal",
"state_topic": self.mqtt_publish_topic + '/autoopen',
"command_topic": self.mqtt_subscribe_topic,
"value_template": '{ "enable_auto_open_communal": {{ value_json.enable_auto_open_communal }} }',
"payload_on": '{ "enable_auto_open_communal": 1 }',
"payload_off": '{ "enable_auto_open_communal": 0 }',
"icon": "mdi:door-open"
}
self.mqtt_client.publish(topic, json.dumps(obj), 1)
자동으로 추가되는 엔티티는 아래와 같이 각각
- subphone_0_0_auto_open_front
- subphone_0_0_auto_open_communal
고유 아이디를 가진 엔티티가 추가된다 (디스플레이 이름은 적절하게 바꿔주면 된다)
대시보드에 현관문 관련 구성요소만 모아놓으면 나름 그럴듯해보인다
3.2. Homebridge 액세서리 추가
안타깝게도 Homebridge 액세서리를 자동으로 추가하는 기능은 찾아보지도 않았다 ㅋㅋ
아직까지도 우직하게 json 파일에 무식하게 추가해주고있다 ^^;;
{
"accessories": [
{
"accessory": "mqttthing",
"type": "switch",
"name": "Auto Open Front Door(MQTT)",
"topics": {
"getOn": {
"topic": "home/state/subphone/0/0/autoopen",
"apply": "return (JSON.parse(message).enable_auto_open_front == 1);"
},
"setOn": {
"topic": "home/command/subphone/0/0",
"apply": "return JSON.stringify({enable_auto_open_front: message});"
}
},
"integerValue": true,
"onValue": 1,
"offValue": 0,
"logMqtt": false
},
{
"accessory": "mqttthing",
"type": "switch",
"name": "Auto Open Communal Door(MQTT)",
"topics": {
"getOn": {
"topic": "home/state/subphone/0/0/autoopen",
"apply": "return (JSON.parse(message).enable_auto_open_communal == 1);"
},
"setOn": {
"topic": "home/command/subphone/0/0",
"apply": "return JSON.stringify({enable_auto_open_communal: message});"
}
},
"integerValue": true,
"onValue": 1,
"offValue": 0,
"logMqtt": false
}
]
}
추가 후 애플 홈에 추가된 2개의 스위치를 적절히 이름을 바꾸고 '현관'방에 배치해줬다
Siri를 통해 자동열림 스위치를 손쉽게 음성으로 켜고 끌 수 있다
3.3. Homeassistant 애드온 버전 업데이트
자동 열림 인터벌은 HA 애드온 설정을 통해 변경 가능하도록 애드온 파라미터를 추가해줬다 (따라서 애드온 버전 업데이트가 필요!)
※ 업데이트된 버전은 1.1.4
※ 물론 MQTT를 통해서도 변경 가능하게 구현은 해뒀다 ㅎㅎ 관련 토픽/페이로드는 소스코드를 참고하면 된다
1.1.3 버전 업데이트 시기가 8월 22일이었으니 거의 2달만에 이뤄진 업데이트!
파라미터 설명도 나름 상세히 추가해뒀다
4. 테스트
## 공동현관문 자동 열림 기능 활성화
<18:11:19.785> [SubPhone (0xB2791510)] Set enable auto open communal door: True
<18:11:47.112> [PacketParser (0xB2788A50)] <SUBPHONE> 7F 5A 00 00 EE >> Communal door ringing started
## 공동현관문 호출 시, 자동 열림 기능 활성화에 따른 인터벌 체크 쓰레드 시작
<18:11:47.113> [SubPhone (0xB2791510)] Auto open communal door thread started
<18:11:47.113> [SubPhone (0xB2791510)] Ringing: COMMUNAL
## 설정된 인터벌(3초) 후 쓰레드 종료
<18:11:50.123> [SubPhone (0xB2791510)] Auto open communal door thread terminated
## 쓰레드 종료 후 주방 비디오폰 '공동현관문 열기' 패킷 전송
<18:11:50.123> [ThreadCommandQueue (0xB1CFF400)] Get Command Queue: {
device: <Kitchen Subphone, Dev Idx: 0, Room Idx: 0>
category: lock_communal target: Unsecured
parser: <SUBPHONE(PacketParser at 0xb2788a50)>
}
<18:11:50.124> [SubPhone (0xB2791510)] Lock Communal: Unsecured
<18:11:50.137> [PacketParser (0xB2788A50)] <SUBPHONE> Send >> 7F 5F 00 00 EE
<18:11:50.334> [PacketParser (0xB2788A50)] <SUBPHONE> Send >> 7F 61 00 00 EE
<18:11:50.535> [PacketParser (0xB2788A50)] <SUBPHONE> Send >> 7F 60 00 00 EE
<18:11:54.060> [PacketParser (0xB2788A50)] <SUBPHONE> 7F 5E 00 00 EE >> Streaming finished
<18:11:54.061> [SubPhone (0xB2791510)] Streaming: False
<18:11:54.061> [SubPhone (0xB2791510)] Ringing: IDLE
<18:11:54.061> [SubPhone (0xB2791510)] Lock Communal: Secured
설정한 시간 후 자동으로 열리는 것을 확인!
동영상도 찍어서 같이 올리고 싶었는데, 호출기에 아파트 동-호수가 고스란히 찍히기 때문에 패스~~ ㅎㅎ
이번 구현 결과물의 장점을 하나 꼽아본다면, 홈IoT 플랫폼의 네트워크 기반 자동화에 의한 자동 열림보다는 좀 더 반응이 빠르다는 점? ^^ (로컬 월패드-주방 비디오폰 간 RS-485 통신 라인을 그대로 이용하기 때문!)
이렇게 또 하나의 기능이 아주 스무스하게 추가되었다
역시 칭찬은 고래도 춤추게 한다 ㅎㅎ
'홈네트워크(IoT) > 힐스테이트 광교산' 카테고리의 다른 글
현대통신 월패드 RS-485 통신 프로토콜 명세 - 일반 조명 (1) | 2024.11.08 |
---|---|
현대통신 월패드 RS-485 통신 프로토콜 명세 - 공통 사양 (1) | 2024.11.07 |
현대통신 월패드 '디밍조명' RS-485 응답 패킷 유형 추가 (깃허브) (0) | 2024.09.03 |
현대통신 월패드 HA 애드온 RS-485 명령 반복 전송 파라미터 추가 (0) | 2024.08.22 |
현대통신 월패드 시스템에어컨 '운전모드' 제어 기능 추가 (깃허브) (0) | 2024.08.02 |