스마트홈을 향하여

지금 집으로 이사를 오고 나서 보일러와 환풍기를 KOCOM 월패드로 컨트롤하고 있는데, 이걸 월패드가 아닌 애플 홈 안에서 간편하게 컨트롤 하고 싶어 시도해 보았다.

RS-485

RS-485는 2선 또는 4선으로 구성된 시리얼 통신 규격이다. 굳이 스마트홈이 아니더라도 예전부터 집안의 전등/보일러, 환풍기 등의 기구를 조작하기 위해 사용하는 규격이다.

집 내의 월패드에서도 마찬가지로 RS-485 규격으로 신호를 전송하고 있다. 당연하게도 이미 어플리케이션 레이어로 올라온 월패드를 직접적으로는 사용할 수 없지만, RS-485 신호를 송수신하는 부분에 같이 전선을 결선하는 것만으로 신호를 송수신할 수 있다. 그러므로 스마트홈을 구축하기 위해서는 이 신호를 가져와 어플리케이션을 따로 구성하고 나서 동일한 RS-485신호를 듣고 뿌려주면 된다.

시리얼 신호를 익숙한 바이트 데이터로 바꾸기 위해 가장 범용적으로 사용되는 Elfin-EW11이라는 장치가 있어 구매했다. 이를 활용하면 RS-485 시리얼 통신을 그대로 바이트 프레임으로 받아낼 수 있다. Wifi를 사용할 수 있는 제품으로 구매했는데, 별도의 다른 연결 없이 그대로 매립할 수 있어 매우 간편했다.

월패드를 뜯고 RS-485 신호와 전원을 결선한다(12V가 걸려있으니 조심해야 한다!). 위에서부터 RS-485 2선이고 VCC, GND이다. 연결되고 나면 으레 대부분의 네트워크 장비가 그렇듯이 EW11 이름의 AP를 잡고 설정을 해 주면 된다.

설정 페이지(10.10.100.254, 초기계정: admin/admin)를 열고 나면 네트워크 영역에서는 특별한 설정 없이 TCP Server로 설정해 주면 되고, 관리 용이상 내부 고정 IP를 사용하도록 해 두었다. 시리얼 통신 영역에서는 보레이트를 맞춰주면 되는데(아두이노 경험이 있다면 익숙할 것이다.), 나는 기본값인 9600으로 신호를 받을 수 있었다. 값을 확인하기 위해 SerialPortMon 프로그램을 많이 사용하는 것 같은데, 윈도우용만 있고 맥용은 없기 때문에 그냥 바로 웹소켓 레이어를 붙여서 확인했다.

어플리케이션

이제 어플리케이션 작업을 하면 된다. EW11을 소켓통신으로 연결하고 월패드에서 온도를 내리거나 환풍기를 조작하면 바이트 프레임이 쏟아지는 걸 볼 수 있는데, 기본적으로 월패드에서 명령을 내려 조작한 뒤 나오는 신호를 보고 분석한 다음, 필요한 상황에 동일한 명령 신호를 복제하여 다시 명령을 내리면 된다.

어차피 조작할 명령이 그닥 많지않아서 사용할 모든 커맨드를 덤프했는데, 나중에 알고보니 KOCOM 월패드에서 나오는 신호의 각 장치들에 대해 일정한 프로토콜이 있었고 분석하신 분이 계셨다… https://mscg.kr/65

그리고 처음 구현시에는 맥에서 작업을 했기 때문에 아무 생각없이 CocoaAsyncSocket, CocoaMQTT를 사용했는데 중간에 Synology NAS에서 돌리기 위해서 swift-nio, mqtt-nio로 변경했다. 구현체만 바꾸면 돼서 작업량이 크게 많지는 않았지만 Cocoa 이름에서 먼저 눈치를 챘어야 하는 아쉬운 부분이 있었다.

홈어시스턴트

집 Synolgy NAS에 가상화로 홈어시스턴트를 올려서 사용하고 있는데, 이제 여기로 현재 장치들을 연결한다. EW11에서 가져온 데이터를 홈어시스턴트로 가져오고 홈어시스턴트에서의 명령을 어플리케이션이 매개하는데, 이 과정에서 MQTT 프로토콜을 사용한다.

MQTT는 pub/sub 기반의 간단한 프로토콜이다. 상태/명령을 메시지 기반으로 주고받는데, 집을 하나의 상태로 간주함으로써 스마트홈에서 많이 사용된다. 그리고 사내 업무를 보다가 안 건데, 전기차 충전기에서도 사용되고 있는 듯 하다.

홈어시스턴트와는 별개로 MQTT 스펙을 매개할 메시지 브로커가 항상 돌아가고 있어야 한다. mosquitto라는 브로커를 사용해 가상화로 띄우고 홈어시스턴트에 붙여주었다. 이름이 꽤 인상적이다.

이제 홈어시스턴트 MQTT 스펙에 맞춰서 어플리케이션과 mosquitto와 연결하고 Discovery를 보내 장치를 등록하면 된다. 보내줘야 하는 메타데이터가 꽤 많은데 결국 익숙한 JSON 이라 Codable로 직렬화할 수 있다. 프로토콜은 문서에 자세하게 되어 있는 편이다. https://www.home-assistant.io/integrations/mqtt

상태를 보내면 홈어시스턴트에 러브레이스가 올라올 것이다. 명령 커맨드도 작성하고 나면 러브레이스를 직접 눌러가면서 보일러와 환풍기의 변하는 상태를 볼 수 있다.

완성!

애플 HomeKit Bridge를 설정하고 나면 그대로 애플 홈으로 연결할 수 있다. 이전부터 여러 기기를 붙여서 쓰고 있긴 하지만 점점 추가되고 있다…

flowchart

A["Kocom 월패드"]

B["EW11"]

C["Application"]

D["MQTT Broker"]

E["Home Assistant"]

F["Apple Home"]

  

A -- "RS-485 신호" --> B

B -- "TCP RS-485 프레임 패킷" --> C

C -- "상태 Publish / 명령 Subscribe" --> D

D -- "MQTT Integration" --> E

E -- "HomeKit Bridge" --> F

  

F -- "HomeKit 제어" --> E

E -- "MQTT Command" --> D

D -- "명령 전달 (JSON)" --> C

C -- "RS-485 프레임" --> B

B -- "RS-485 신호" --> A

전체적인 흐름이다. 이렇게 보니까 꽤 여러 레이어를 거치는데, failable 요소가 많음에도 불구하고(특히 RS-485의 반이중 통신 하드웨어 제약을 극복할 수 없다) 실제 생활에서는 거의 오류가 없어 잘 사용하고 있다. 무엇보다도 직접 만들어서 띄워보니 뿌듯하기도 하고 꽤 재미있었다. Synology NAS용 컨테이너 이미지와 소스코드를 오픈해 놓았다. https://github.com/nrurnru/swift-kocom-wallpad