일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 해외주식
- 나스닥
- SK텔레콤
- esp32
- 배당
- 파이썬
- Home Assistant
- 미국주식
- Python
- 월패드
- 현대통신
- raspberry pi
- 홈네트워크
- 애플
- 국내주식
- 오블완
- Apple
- cluster
- MQTT
- homebridge
- ConnectedHomeIP
- matter
- RS-485
- 티스토리챌린지
- 힐스테이트 광교산
- 공모주
- Bestin
- 코스피
- 매터
- Espressif
- Today
- Total
YOGYUI
힐스테이트 광교산::현관 도어락 - 애플 홈킷 + 구글 어시스턴트 연동 본문
거실 월패드에서는 비디오폰을 통화를 하거나, 현관 출입문 도어락을 해제할 수 있다 (문열기)
문열기 버튼을 클릭했을 때, 조명과 아울렛이 연결된 RS-485 포트에서 처음보는 패킷을 캡쳐할 수 있다
class ParserLight(SerialParser):
def interpretPacket(self, packet: bytearray):
try:
if packet[3] == 0x19: # 조명
self.handleLight(packet)
elif packet[3] == 0x1F: # 아울렛 (콘센트)
self.handleOutlet(packet)
else:
writeLog(f'Unknown packet: {self.prettifyPacket(packet)}', self)
except Exception as e:
writeLog('interpretPacket::Exception::{} ({})'.format(e, packet), self)
<14:19:08.704579> [ParserLight] Unknown packet: F7 0E 01 1E 02 43 11 04 00 04 FF FF B6 EE
<14:19:08.991658> [ParserLight] Unknown packet: F7 0E 01 1E 02 43 11 04 00 04 FF FF B6 EE
패킷의 4번째 바이트가 0x1E인 명령 패킷이 약 300ms 간격을 두고 두번 반복해서 캡쳐되었다
그런데...
아무리 캡쳐된 패킷을 전송해봐도 현관 도어락이 해제되지 않았다 ㅠ_ㅠ
패킷간 인터벌까지 100ms~500ms까지 1ms 단위로 바꿔가면서 이리저리 삽질을 해봤는데도 아무런 반응이 없었다
결국 RS-485 방식으로는 제어가 되지 않는 것 같아 월패드를 다시 뜯어봤다
1. 도어락 무선 송수신 모듈 신호 확인
월패드에 너무나 익숙한 게이트맨社의 도어락 연동기가 연결되어 있는 것을 알 수 있었다!
부리나케 현관으로 달려가 도어락을 확인해보니
아니나다를까 게이트맨의 ASSA ABLOY(?) 제품이 설치되어 있다 (이제서야 확인하다니 ㅋㅋ)
회사 홈페이지를 가보니 G-SUIT scan이라는 제품명으로 판매가 되고 있다
(57만원이라니... 더럽게도 비싼거 달아놨네 ㅋㅋㅋ)
나름 지문인식 제품이라 편하게 사용하고 있다
블루투스 지원도 된다고 하는데, 기능을 활용하려면 브릿지를 따로 사야한다고 한다... 굳이 살 필요는 없겠지? ㅎㅎ
도어락 건전지 삽입부 아래를 보면 무선 통신 모듈(스마트리빙팩)이 장착되어 있는 것을 볼 수 있다
이녀석이 월패드에 장착된 연동기랑 무선으로 통신을 하면서 도어락을 해제하는 구조로 보인다
연동기와 연결된 4pin 신호선은 다행히도 터미널블록을 통해 월패드와 연결되어 있어, 멀티미터나 오실로스코프 측정이 용이하다 (연결된 선 색은 위에서부터 빨간색, 검은색, 흰색, 노란색)
빨간색과 검은색 선은 전원과 접지(ground)로 사용되는 것이 일반적이라 멀티미터로 전원을 측정해보니 DC +12V로 값이 나왔다 ※ 나중에 외부 전원 필요한 모듈 사용할 때 이 12V를 사용하는 걸 고려해봐야겠다
그리고 흰색선과 노란색 선은 정체를 알 수 없어 오실로스코프로 연결 후 파형을 측정해봤다
아무런 조작을 하지 않았을 때, 노란색 선은 약 +3V 레벨로 측정되었으며, 흰색 선은 0V 레벨로 측정되었다
(이사하면서 USB 플래시 메모리를 잃어버렸는지, 아무리 찾아봐도 없어서 파형은 사진으로 대체 ㅠㅠ)
그리고 월패드에서 문열기 버튼을 눌렀을 때 트리거를 잡아보면
노란색 선의 전압 레벨이 0V로 내려갔다가 약 1초 후 다시 +3V로 복귀하는 것을 알 수 있었다
시간축을 좀 더 확대해보면
노란색 선의 신호가 0으로 떨어진 뒤, 약 27us 뒤 다시 살짝 올라갔다가 약 30us 뒤 다시 0으로 떨어지는 아주 기묘한 파형을 볼 수 있다 (뭔가 시리얼 통신이 이루어지는 느낌이 아니긴 한데...)
2. 도어락 해제 GPIO 제어 코드 작성
측정한 파형을 토대로, 광교 아이파크때와 마찬가지로 라즈베리파이의 GPIO를 노란색 선에 연결해 이리저리 제어해봤다
그 결과, 두번 정도만 Positive Edge 트리거를 잡을 수 있게 해주면 문이 열리는 것을 알 수 있었다
import json
from Device import *
import threading
import RPi.GPIO as GPIO
from Common import Callback, writeLog
class ThreadDoorLockOpen(threading.Thread):
def __init__(self, gpio_port: int):
threading.Thread.__init__(self)
self.gpio_port = gpio_port
self.sig_terminated = Callback()
def run(self):
writeLog('Started', self)
GPIO.output(self.gpio_port, GPIO.LOW)
for _ in range(2):
writeLog(f"Set GPIO PIN{self.gpio_port} as LOW", self)
time.sleep(0.1)
GPIO.output(self.gpio_port, GPIO.HIGH)
writeLog(f"Set GPIO PIN{self.gpio_port} as HIGH", self)
time.sleep(0.1)
time.sleep(5) # 5초간 Unsecured state를 유지해준다
writeLog('Terminated', self)
self.sig_terminated.emit()
class DoorLock(Device):
enable: bool = False
gpio_port: int = 0
thread_open: Union[ThreadDoorLockOpen, None] = None
def __init__(self, name: str = 'Doorlock', **kwargs):
super().__init__(name, **kwargs)
self.state = 1
self.setParams(True, 23)
def __repr__(self):
repr_txt = f'<{self.name}({self.__class__.__name__} at {hex(id(self))})'
repr_txt += '>'
return repr_txt
def publish_mqtt(self):
# 'Unsecured', 'Secured', 'Jammed', 'Unknown'
state_str = 'Unknown'
if self.state == 0:
state_str = 'Unsecured'
elif self.state == 1:
state_str = 'Secured'
obj = {"state": state_str}
if self.mqtt_client is not None:
self.mqtt_client.publish(self.mqtt_publish_topic, json.dumps(obj), 1)
def setParams(self, enable: bool, gpio_port: int):
self.enable = enable
self.gpio_port = gpio_port
GPIO.setmode(GPIO.BCM)
GPIO.setup(self.gpio_port, GPIO.IN, GPIO.PUD_UP) # GPIO IN, Pull Down 설정
def updateState(self, state: int, **kwargs):
self.state = state
if not self.init:
self.publish_mqtt()
self.init = True
if self.state != self.state_prev:
self.publish_mqtt()
self.state_prev = self.state
def startThreadOpen(self):
if self.thread_open is None:
self.state = 0
GPIO.setup(self.gpio_port, GPIO.OUT)
GPIO.output(self.gpio_port, GPIO.HIGH)
self.thread_open = ThreadDoorLockOpen(self.gpio_port)
self.thread_open.sig_terminated.connect(self.onThreadOpenTerminated)
self.thread_open.start()
else:
writeLog('Thread is still working', self)
def onThreadOpenTerminated(self):
del self.thread_open
self.thread_open = None
self.state = 1
self.publish_mqtt()
GPIO.setup(self.gpio_port, GPIO.IN, GPIO.PUD_UP) # GPIO IN, Pull Down 설정
def open(self):
if self.enable:
self.startThreadOpen()
else:
writeLog('Disabled!', self)
광교 아이파크때와 마찬가지로 평소에는 GPIO 핀을 INPUT, Pull-up 모드로 설정한 뒤 (평소에는 3V니깐~), 제어하고자 할 때는 OUTPUT 모드로 변경하도록 구현했다
또한, open 명령이 왔을 때 메인 이벤트 루프가 아닌 별도의 쓰레드에서 LOW-HIGH 설정 동작을 2회 반복하도록 구현했다
(그냥 0.1초 간격으로 충분히 긴 간격으로 두번 LOW-HIGH해도 정상적으로 동작하는걸 실험을 통해 확인했다)
3. Homebridge 액세서리 설정
광교 아이파크때는 단순한 switch로 설정했었는데, 여기서는 좀 다른 시도를 해보고 싶어 Lock Mechanism 항목을 사용해보기로 했다
매뉴얼을 따라서 간단하게 다음과 같이 액세서리를 구성해줬다
{
"accessory": "mqttthing",
"type": "lockMechanism",
"name": "Doorlock (MQTT)",
"url": "mosquitto broker url",
"username": "mosquitto auth id",
"password": "mosquitto auth password",
"topics": {
"getLockCurrentState": {
"topic": "home/hillstate/doorlock/state",
"apply": "return JSON.parse(message).state;"
},
"getLockTargetState": {
"topic": "home/hillstate/doorlock/state",
"apply": "return JSON.parse(message).state;"
},
"setLockTargetState": {
"topic": "home/hillstate/doorlock/command",
"apply": "return JSON.stringify({state: message});"
}
},
"lockValues": [
"Unsecured",
"Secured",
"Jammed",
"Unknown"
],
"logMqtt": true
}
안타깝게도 연동기를 통해서는 현재 도어락의 잠김/열림/걸림 상태를 확인할 수 있는 방법이 없어서 명령을 통해 제어 가능한 상태는 Unsecured가 전부이다 ㅠㅠ (열기만 하면 되니 기능상 큰 불편함을 없을 것 같긴 한데... 문이 제대로 안닫힌 상태인 것을 확인할 수 있으면 참 좋을텐데 아쉽다)
이에 맞춰서 소스코드(MQTT 메시지 핸들러, 명령 큐 쓰레드)도 수정해줬다
소스코드는 hillstate-doorlock 브랜치로 커밋했다
https://github.com/YOGYUI/HomeNetwork/tree/hillstate-doorlock
4. 동작 테스트
연동기 하드웨어의 신호선을 다이렉트로 건드린 거라 월패드를 통해서는 안내 메시지가 송출되지 않고, 도어락에서만 열림에 대한 안내 메시지를 들을 수 있다 (동영상 소리에서 도어락 안내 음성 확인 가능)
비록 도어락의 현재 상태값에 대해서는 알 수 없지만, 열림 명령 이후 5초간은 열림 상태를 유지할 수 있도록 Doorlock 클래스의 쓰레드를 구현했기 때문에 단순히 열고 닫는 동작에 있어서는 나름 현실과 괴리감이 크지 않게 사용할 수 있다
(지문인식이라는 편한 기능이 있기 때문에 굳이 아이폰이나 애플워치로 문을 여는 상황은 많이 발생하진 않을듯 ㅎㅎ)
5. Home Assistant 액세서리 추가
Home Assistant에서는 'lock' 아이템으로 하나 추가해줬다
lock:
- platform: mqtt
name: "현관 도어락"
unique_id: "doorlock_frontdoor"
state_topic: "home/hillstate/doorlock/state"
command_topic: "home/hillstate/doorlock/command"
value_template: '{{ value_json.state }}'
payload_lock: '{ "state": "Secured" }'
payload_unlock: '{ "state": "Unsecured" }'
state_locked: "Secured"
state_unlocked: "Unsecured"
optimistic: false
retain: false
icon: mdi:door-closed-lock
lock 아이템의 문제인지, 구글 어시스턴트에는 아이템이 연동되질 않아서 구글 홈 미니 음성 명령이 먹히질 않는다.. 다른 아이템으로 교체하는걸 고려해봐야겠다 ㅠ (HA는 어려워;;)
열심히 달려왔다..
이제 현관 비디오폰 영상 연동만 하면 대충 하고자 했던 건 다 끝난다.. (물론 자동화를 통한 스마트라이프 구축은 이제부터 시작이지만 ㅠ)
[TODO]
조명 On/Off아울렛(전원 콘센트) On/Off - 실시간 전력량 조회는 불가능도시가스 차단난방 제어 (On/Off, 희망 온도 설정, 현재 방 온도 가져오기)환기 (전열교환기)시스템 에어컨 (냉방 및 공기청정)엘리베이터 호출도어락 해제- Optional: 현관 비디오폰 영상, 거실 천장 모션 센서
'홈네트워크(IoT) > 힐스테이트 광교산' 카테고리의 다른 글
힐스테이트 광교산::Elfin EW11 RS485-WiFi 모듈 Migration (0) | 2022.07.03 |
---|---|
힐스테이트 광교산::다용도실 전등 스위치 - Aqara 스마트 조명 스위치 (1구)로 교체 (0) | 2022.06.28 |
힐스테이트 광교산::엘리베이터 - 애플 홈킷 + 구글 어시스턴트 연동 (0) | 2022.06.24 |
힐스테이트 광교산::엘리베이터 호출 제어 RS-485 패킷 분석 (9) | 2022.06.23 |
힐스테이트 광교산::시스템에어컨 - 애플 홈킷 + 구글 어시스턴트 연동 (0) | 2022.06.20 |