YOGYUI

현대통신 월패드 시스템에어컨 '운전모드' 제어 기능 추가 (깃허브) 본문

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

현대통신 월패드 시스템에어컨 '운전모드' 제어 기능 추가 (깃허브)

요겨 2024. 8. 2. 19:29
반응형

Add Control Function for Hyundai HT Wallpad Airconditioner 'Operation Mode'

지난 글에서 현대통신 월패드의 '디밍조명' 제어 기능 추가에 대한 깃허브 PR(Pull Request)건과 디밍조명 패킷 상세, 소스코드 변경 사항에 대해 다룬 바 있다

현대통신 월패드 '디밍조명' 제어 기능 추가 (깃허브, HA 애드온)

 

현대통신 월패드 '디밍조명' 제어 기능 추가 (깃허브, HA 애드온)

Add Hyundai HT Wallpad 'dimming light' device type1. 개요3주 전인 2024년 7월 11일, 현대통신 월패드 RS-485 연동 깃허브 소스코드에 처음으로 Pull-Request가 등록됐다https://github.com/YOGYUI/HomeNetwork/pull/12 Add support fo

yogyui.tistory.com

PR 올려주신 개발자분께서 깃허브를 통해 '시스템에어컨의 운전모드(냉방/자동/송풍/제습) 제어'에 대한 요구사항을 주셔서 즐거운 마음으로(?) 코딩 작업을 했다

구조화하지 않고 내멋대로 짠 코드인지라 다른 고급 개발자에게 선보이기 부끄럽기에 PR 받기 전에 후다다닥 작업해버렸다 ^^;;

1. Home Assistant Integration 문서 확인

애초에 Home Assistant(HA)는 내가 사용하는 메이저 IoT 플랫폼은 아니었기에 (homebridge를 사용중) 에어컨은 냉방 운전모드에 대해서만 구현했었는데, HA MQTT integration 공식 문서를 보니 냉방 외에도 월패드의 운전모드 제어 기능을 모두 지원하는 것을 알 수 있었다

https://www.home-assistant.io/integrations/climate.mqtt/

 

MQTT HVAC

Instructions on how to integrate MQTT HVAC into Home Assistant.

www.home-assistant.io

직관적으로 'auto'는 자동, 'off'는 전원 종료, 'cool'은 냉방, 'heat'은 난방, 'dry'는 제습, 'fan_only'는 송풍으로 해석해 사용하면 될 것 같다 ㅎㅎ

2. 패킷 상세

현대통신 월패드의 시스템에어컨 관련 RS-485 패킷은 이미 힐스테이트 광교산 입주 초기 분석을 완료했다

힐스테이트 광교산::시스템에어컨 제어 RS-485 패킷 분석

 

힐스테이트 광교산::시스템에어컨 제어 RS-485 패킷 분석

분양받을 때 옵션으로 거실이랑 방3개 모두 천장형 시스템에어컨 (공기청정 미적용) 설치하기로 계약했다 원래 가지고 있던 에어컨이 없었을 뿐더러 이제껏 천장에 달린 시스템에어컨이 있는

yogyui.tistory.com

  • 4번째 바이트가 0x1C이면 시스템 에어컨과 관련된 쿼리/명령/상태 패킷
  • 6번째 바이트가 0x5C이면 시스템 에어컨의 운전 모드 (자동/냉방/제습/공기청정 혹은 송풍)
  • 운전모드 관련값: 0x00 = 자동, 0x01 = 냉방, 0x02 = 제습, 0x03 = 공기청정(송풍)

쿼리, 명령, 상태 패킷에 대한 상세는 위 글을 참고하면 된다

3. 코드 수정

Homebridge는 어차피 아직까지도 냉방/난방 외 다른 모드에 대해서는 지원하지 않는 것으로 확인되었기에, 기존에 사용하던 홈브릿지용 MQTT json 템플릿은 유지한 채 HA용 json 템플릿을 추가하는 방향으로 구현했다

3.1. HA Device Discovery 템플릿 변경

AirConditioner 클래스 생성시 HA에 발행(publish)하는 MQTT Discovery json 템플릿을 HA 공식 문서에 맞춰 변경했다

class AirConditioner(Device):
    def configMQTT(self, retain: bool = False):
        topic = f'{self.ha_discovery_prefix}/climate/{self.unique_id}/config'
        obj = {
            "name": self.name,
            "object_id": self.unique_id,
            "unique_id": self.unique_id,
            "modes": ["off", "cool", "auto", "dry", "fan_only"],
            "fan_modes": ["Max", "Medium", "Min", "Auto"],  # TODO: [“auto”, “low”, “medium”, “high”]로 대체해야하나?
            "mode_state_topic": self.mqtt_publish_topic,
            "mode_state_template": "{{ value_json.mode }}",
            "mode_command_topic": self.mqtt_subscribe_topic,
            "mode_command_template": '{% set values = {"off": 0, "cool": 1, "auto": 2, "dry": 3, "fan_only": 4} %} \
                                      { "mode": {{ values[value] if value in values.keys() else 0 }} }',
            "temperature_state_topic": self.mqtt_publish_topic,
            "temperature_state_template": "{{ value_json.targetTemperature }}",
            "temperature_command_topic": self.mqtt_subscribe_topic,
            "temperature_command_template": '{ "targetTemperature": {{ value }} }',
            "current_temperature_topic": self.mqtt_publish_topic,
            "current_temperature_template": "{{ value_json.currentTemperature }}",
            "fan_mode_command_topic": self.mqtt_subscribe_topic,
            "fan_mode_command_template": '{ "rotationspeed_name": "{{ value }}" }',
            "fan_mode_state_topic": self.mqtt_publish_topic,
            "fan_mode_state_template": "{{ value_json.rotationspeed_name }}",
            "min_temp": self.temp_range[0],
            "max_temp": self.temp_range[1],
            "precision": 1,
        }
        self.mqtt_client.publish(topic, json.dumps(obj), 1, retain)

바뀐 거라곤 "modes"와 "mode_state_topic", "mode_command_topic"이 전부~

3.2. Device 현재 상태 업데이트 (MQTT)

AirConditioner 클래스의 현재 상태 MQTT publish 구문에 4종류의 운전모드를 문자열로 보낼 수 있게 수정

class AirConditioner(Device):    
    def publishMQTT(self):
        mode_str = 'off'
        if self.state:
            if self.mode == 0:
                mode_str = 'auto'
            elif self.mode == 1:
                mode_str = 'cool'
            elif self.mode == 2:
                mode_str = 'dry'
            elif self.mode == 3:
                mode_str = 'fan_only'

        obj = {
            "mode": mode_str,
            "currentTemperature": self.temp_current,
            "targetTemperature": self.temp_config,
            "timer": int(self.isTimerOnOffRunning())
        }
        if self.rotation_speed == 0x02:  # 미풍
            obj['rotationspeed'] = 50
            obj['rotationspeed_name'] = 'Min'
        elif self.rotation_speed == 0x03:  # 약풍
            obj['rotationspeed'] = 75
            obj['rotationspeed_name'] = 'Medium'
        elif self.rotation_speed == 0x04:  # 강풍
            obj['rotationspeed'] = 100
            obj['rotationspeed_name'] = 'Max'
        else:
            obj['rotationspeed'] = 25
            obj['rotationspeed_name'] = 'Auto'
        if self.mqtt_client is not None:
            self.mqtt_client.publish(self.mqtt_publish_topic, json.dumps(obj), 1)

3.3 운전모드에 대한 별도 핸들링 구문 추가

기존 homebridge/HA 통일해서 사용하던 'active' 키를 유지하며 'mode' 키에 대한 핸들링 구문을 추가해 기존 환경에서도 동일하게 사용할 수 있게 코드를 수정해줬다 (HA에서 MQTT 메시지 구독 시 들어오는 메시지에 대한 처리)

class Home:
    def onMqttCommandAirconditioner(self, topic: str, message: dict):
        # ...
        if 'mode' in message.keys():
            self.send_command(
                device=device,
                category='mode',
                target=message['mode']
            )
        # ...

class ThreadCommandQueue(threading.Thread):
    def run(self):
        while self._keepAlive:
            elem = self._queue.get()
            dev = elem.get('device')
            category = elem.get('category')
            target = elem.get('target')
            parser = elem.get('parser')
            # ...
            if isinstance(dev, AirConditioner):
                if category == 'mode':
                    if not target:  
                        self.set_state_common(dev, 0, parser)
                    else:
                        self.set_state_common(dev, 1, parser)
                        mode_value = 1
                        if target == 2:
                            mode_value = 0
                        elif target == 3:
                            mode_value = 2
                        elif target == 4:
                            mode_value = 3
                        self.set_airconditioner_mode(dev, mode_value, parser)
            # ...

3.4. HA Configuration(yaml) 템플릿

만약 HA의 MQTT Discovery를 사용하지 않고 configuration을 직접 구성해 사용하는 유저라면 아래와 같이 템플릿을 약간 수정해줘야 한다 (기존 템플릿으로는 정상 동작하지 않음..)

climate:
  - platform: mqtt
    name: "거실 에어컨"
    unique_id: "livingroom_airconditioner"
    modes:
      - "off"
      - "cool"
      - "auto"
      - "dry"
      - "fan_only"
    fan_modes:
      - "Max"
      - "Medium"
      - "Min"
      - "Auto"
    mode_state_topic: "home/state/airconditioner/1/0"
    mode_state_template: "{{ value_json.mode }}"
    mode_command_topic: "home/command/airconditioner/1/0"
    mode_command_template: >-
      {% set values = {"off": 0, "cool": 1, "auto": 2, "dry": 3, "fan_only": 4} %}
      { "mode": {{ values[value] if value in values.keys() else 0 }} }
    temperature_state_topic: "home/state/airconditioner/1/0"
    temperature_state_template: "{{ value_json.targetTemperature }}"
    temperature_command_topic: "home/command/airconditioner/1/0"
    temperature_command_template: '{ "targetTemperature": {{ value }} }'
    current_temperature_topic: "home/state/airconditioner/1/0"
    current_temperature_template: "{{ value_json.currentTemperature }}"
    fan_mode_command_topic: "home/command/airconditioner/1/0"
    fan_mode_command_template: '{ "rotationspeed_name": "{{ value }}" }'
    fan_mode_state_topic: "home/state/airconditioner/1/0"
    fan_mode_state_template: "{{ value_json.rotationspeed_name }}"
    min_temp: 18
    max_temp: 30
    precision: 1

※ modes, mode_state_template, mode_command_template만 위와 같이 바꿔주면 된다

3.5. GitHub Commit

전체 코드 변경 내용은 아래 커밋에서 확인할 수 있다

https://github.com/YOGYUI/HomeNetwork/commit/d3eaa52466d4abbcb7d887006674c7f1580adc45

 

에어컨: 운전모드 제어 연동 (냉방/자동/제습/송풍) · YOGYUI/HomeNetwork@d3eaa52

YOGYUI committed Aug 2, 2024

github.com

4. 동작 확인

코드를 업데이트 및 재실행하고 HA도 설정파일을 다시 부르거나 MQTT Discovery가 재수행된 뒤 다음과 같이 에어컨 엔티티에 운전모드가 추가된 것을 확인할 수 있다

운전모드마다 HA에 표시되는 색상이 다른 것을 확인할 수 있다

  • 냉방: 파란색
  • 제습: 주황색
  • 송풍: 청록색
  • 자동: 초록색

집에 설치된 시스템에어컨은 LG전자 제품이라 ThinQ와 모두 연동해뒀는데, HA에서 바꾸는 운전모드와 ThinQ의 운전모드가 연동되는 것 또한 확인 완료!

ThinQ 모바일 앱 인터페이스

5. 기타

소스코드만 바뀐 것이기 때문에, HA용 현대통신 애드온 사용자라면 애드온을 재시작하기만 하면 최신 코드로 업데이트되므로 별도의 애드온 업데이트는 필요하지 않다

(MQTT Discovery 기능을 사용하고 있다면 HA 엔티티도 자동으로 변경되므로 별도의 번거로운 수정 작업이 필요없다!)


[24.08.06 추가]

운전모드 관련 추가 기능은 다행히도 모두 정상적으로 동작한다는 피드백을 받았다 ^^

또한, 시스템에어컨 관련 6번째 바이트가 0x5E인 상태응답 패킷에 대한 예외처리가 필요하다는 피드백도 있었기에 간단하게 수정해서 커밋 완료!

반응형