YOGYUI

힐스테이트 광교산::도시가스차단기(밸브) - 애플 홈킷 + 구글 어시스턴트 연동 본문

홈네트워크(IoT)/힐스테이트 광교산

힐스테이트 광교산::도시가스차단기(밸브) - 애플 홈킷 + 구글 어시스턴트 연동

요겨 2022. 6. 15. 23:54
반응형

 

지난 포스트에서 가스밸브 잠금 기능 관련 RS-485 패킷 후킹 및 분석을 완료했다 (링크)

이제 바로 코드를 작성하고 홈네트워크 플랫폼 액세서리를 추가하자


깃헙 저장소에 hillstate-gasvalve 브랜치로 소스코드를 커밋했다

https://github.com/YOGYUI/HomeNetwork/tree/hillstate-gasvalve

 

GitHub - YOGYUI/HomeNetwork: HomeNetwork(Homebridge) Repo

HomeNetwork(Homebridge) Repo. Contribute to YOGYUI/HomeNetwork development by creating an account on GitHub.

github.com

 

핵심은 쿼리 및 명령 패킷 생성, 시리얼 패킷 해석 구문

class GasValve(Device):
    def __init__(self, name: str = 'GasValve', **kwargs):
        super().__init__(name, **kwargs)
    
    def publish_mqtt(self):
        obj = {"state": self.state}
        if self.mqtt_client is not None:
            self.mqtt_client.publish(self.mqtt_publish_topic, json.dumps(obj), 1)
        
    def makePacketQueryState(self) -> bytearray:
        # F7 0B 01 1B 01 43 11 00 00 B5 EE
        return bytearray([0xF7, 0x0B, 0x01, 0x1B, 0x01, 0x43, 0x11, 0x00, 0x00, 0xB5, 0xEE])

    def makePacketSetState(self, state: bool):
        # F7 0B 01 1B 02 43 11 XX 00 YY EE
        # XX: 03 = OFF, 04 = ON (지원되지 않음)
        # YY: Checksum (XOR SUM)
        packet = bytearray([0xF7, 0x0B, 0x01, 0x1B, 0x02, 0x43, 0x11])
        if state:
            packet.extend([0x04, 0x00])
        else:
            packet.extend([0x03, 0x00])
        packet.append(self.calcXORChecksum(packet))
        packet.append(0xEE)
        return packet

패킷 생성 구문은 가스밸브가 하나이기 때문에 복잡하게 생각하지 않고 단순하게 RS-485 후킹 시 캡쳐해둔 패킷을 그대로 활용하게 만들었다

혹시나 싶어 밸브를 여는 패킷 (8번째 바이트를 0x04값으로) 을 만들어봤지만, 당연하게도 동작은 하지 않았다

 

class ParserGas(SerialParser):    
    def interpretPacket(self, packet: bytearray):
        try:
            if packet[2:4] == bytearray([0x01, 0x1B]):  # 가스차단기
                if packet[4] == 0x01:  # 상태 쿼리
                    pass
                elif packet[4] == 0x02:  # 상태 변경 명령
                    pass
                elif packet[4] == 0x04:  # 상태 응답
                    state = 0 if packet[8] == 0x03 else 1
                    result = {
                        'device': 'gasvalve',
                        'state': state
                    }
                    self.sig_parse_result.emit(result)
        except Exception as e:
            writeLog('interpretPacket::Exception::{} ({})'.format(e, packet), self)

패킷 파서는 단순하게 응답 패킷의 8번째 바이트값이 0x03인지, 0x04인지만 판단하도록 구현했다 

나중에 다른 기기들도 이 시리얼 파서를 활용해야 하기에 파서 클래스 이름은 나중에 변경할 예정


Homebridge와 Home Assistant 액세서리도 추가했다

홈브릿지 액세서리 추가
Home Assistant 액세서리 추가


가스관에 설치된 전자식 밸브 차단기는 (주)한국소방기구제작소 (Kfire)라는 회사의 제품이 장착되어 있다

아래쪽에 보이는 '전자식차단기'를 손으로 누르면 열리는데, 열린 상태에서 손으로 잡아당겨도 닫히진 않는 구조이다 (닫을려면 제어기의 '열림(가스차단) 닫힘' 스위치를 눌러줘야 한다)

 

모바일 기기로 제어가 잘되는지 확인해보자

가스 라벨이 붙은 시리얼 통신 포트로 다른 기기들도 모두 조회-응답이 이뤄지다보니 실제 기기의 상태가 변경 후 홈네트워크 플랫폼에 상태 변경이 적용될 때까지 3초 이상의 딜레이가 발생하는 것을 알 수 있다 (약간 아쉽긴 아지만 월패드 내부에서 이뤄지는 작업이라 내가 손댈수 있는 부분이 없다 ㅠ)

 

월패드로 제어하는 것과도 비교해보자

확실히 월패드가 통신을 통해 얻어오는 구문이 느리긴 하다

 

패킷을 로깅할 때 타임스탬프를 추가해서 확인해보자



<23:46:22.925167> F7 0B 01 1C 01 40 11 00 00 B1 EE
<23:46:23.004638> F7 0F 01 1C 04 40 11 00 02 19 17 01 03 BE EE
<23:46:23.036424> F7 0B 01 1C 01 40 21 00 00 81 EE
<23:46:23.100928> F7 0F 01 1C 04 40 21 00 02 19 17 01 01 8C EE
<23:46:23.132284> F7 0B 01 1C 01 40 31 00 00 91 EE
<23:46:23.196655> F7 0F 01 1C 04 40 31 00 02 19 17 01 02 9F EE
<23:46:23.227847> F7 0B 01 1C 01 40 41 00 00 E1 EE
<23:46:23.307782> F7 0F 01 1C 04 40 41 00 02 1A 12 01 04 EF EE
<23:46:23.388621> F7 0B 01 1B 01 43 11 00 00 B5 EE
<23:46:23.452944> F7 0D 01 1B 04 43 11 00 03 00 00 B5 EE
<23:46:23.483864> F7 0B 01 18 01 46 10 00 00 B2 EE
<23:46:23.564181> F7 22 01 18 04 46 10 00 04 19 15 04 19 17 04 19 16 04 1A 16 00 00 00 00 00 00 00 00 00 00 00 00 9F EE
<23:46:25.580748> F7 0D 01 34 01 41 10 00 00 00 00 9F EE
<23:46:25.628633> F7 0B 01 34 04 41 10 00 00 9C EE
<23:46:25.662155> F7 0D 01 48 01 40 10 00 71 11 02 80 EE
<23:46:25.724846> F7 0D 01 48 04 40 10 00 71 11 02 85 EE
<23:46:25.772030> F7 0E 01 2A 01 40 10 00 19 00 1B 03 82 EE
<23:46:25.835951> F7 0E 01 2A 04 40 10 00 19 02 1B 03 85 EE
<23:46:26.204378> F7 0B 01 2B 01 40 11 00 00 86 EE
<23:46:26.267457> F7 0C 01 2B 04 40 11 00 01 01 84 EE
<23:46:26.396160> F7 0B 01 18 01 46 10 00 00 B2 EE
<23:46:26.476696> F7 22 01 18 04 46 10 00 04 19 15 04 19 17 04 19 16 04 1A 16 00 00 00 00 00 00 00 00 00 00 00 00 9F EE
<23:46:28.747574> F7 0B 01 1C 01 40 11 00 00 B1 EE
<23:46:28.811417> F7 0F 01 1C 04 40 11 00 02 19 17 01 03 BE EE
<23:46:28.844024> F7 0B 01 1C 01 40 21 00 00 81 EE
<23:46:28.923292> F7 0F 01 1C 04 40 21 00 02 19 17 01 01 8C EE
<23:46:28.956082> F7 0B 01 1C 01 40 31 00 00 91 EE
<23:46:29.019378> F7 0F 01 1C 04 40 31 00 02 19 17 01 02 9F EE
<23:46:29.050575> F7 0B 01 1C 01 40 41 00 00 E1 EE
<23:46:29.115941> F7 0F 01 1C 04 40 41 00 02 1A 12 01 04 EF EE
<23:46:29.194653> F7 0B 01 1B 01 43 11 00 00 B5 EE
<23:46:29.260067> F7 0D 01 1B 04 43 11 00 03 00 00 B5 EE
<23:46:29.291606> F7 0B 01 18 01 46 10 00 00 B2 EE
<23:46:29.387046> F7 22 01 18 04 46 10 00 04 19 15 04 19 17 04 19 16 04 1A 16 00 00 00 00 00 00 00 00 00 00 00 00 9F EE


4번째 바이트가 0x1B인 가스밸스 조회-응답 패킷군 간의 시간간격이 약 5.8초로, 상당히 길다

생각해보면 가스밸브라는게 어차피 소방안전을 위해 닫는 기능만 있으면 되고, 닫혔는지 여부를 실시간으로 확인해야할 필요는 없다보니 조회를 자주할 필요가 전혀 없긴 하다 ㅎㅎ

 

어찌되었든 이제 집 바깥에서 애플 홈 앱이나 구글 홈 앱으로 가스밸브도 잠글 수 있게 되었다 ^^

(아이파크에 거주할 때도 느꼈지만, 생각보다 자주 사용하게 된다)

 

[TODO]

  • 조명 On/Off
  • 아울렛(전원 콘센트) On/Off - 실시간 전력량 조회는 불가능
  • 도시가스 차단
  • 난방 제어, 현재 방 온도 가져오기
  • 시스템 에어컨 (냉방 및 공기청정)
  • 환기 (전열교환기)
  • 엘리베이터 호출
  • 도어락 해제
  • Optional: 현관 비디오폰 영상, 거실 천장 모션 센서
반응형
Comments