YOGYUI

광교아이파크::난방 온도값 파싱 오류 본문

홈네트워크(IoT)/광교아이파크

광교아이파크::난방 온도값 파싱 오류

요겨 2021. 7. 21. 20:25
반응형

지난주부터 어마어마한 폭염이 계속되고 있다

 

오늘 문득 Apple Home 앱에서 Bestin 난방 관련 액세서리를 확인해봤는데

잉? 현재 온도가 5.5도로 표기되고 있었다... ?!?!

 

Homebridge Log를 보니 MQTT로도 이상한 값이 들어오고 있었다

 

뭐지? 싶어서 월패드를 확인해보니 월패드는 또 제대로 값을 찍고 있었다

 

뭔가 이상하다 싶어서 RS485 패킷을 로깅해봤다

class Home:
    def onParserControlResult(self, chunk: bytearray):
        try:
            if len(chunk) < 10:
                return
            header = chunk[1]  # [0x28, 0x31, 0x61]
            command = chunk[3]
            if header == 0x28 and command in [0x91, 0x92]:
                # 난방 관련 패킷 (방 인덱스)
                # chunk[3] == 0x91: 쿼리 응답
                # chunk[3] == 0x92: 명령 응답
                room_idx = chunk[5] & 0x0F
                room = self.rooms[room_idx]
                dev = room.thermostat
                dev.state = chunk[6] & 0x01
                dev.temperature_setting = (chunk[7] & 0x3F) + (chunk[7] & 0x40 > 0) * 0.5
                dev.temperature_current = chunk[9] / 10.0
                # dev.temperature_current = int.from_bytes(chunk[8:10], byteorder='big') / 10.0
                print('Room Idx: {}, Temperature Current: {}'.format(room_idx, dev.temperature_current))
                print('Raw Packet: {}'.format('|'.join(['%02X'%x for x in chunk])))
                # notification
                if dev.state != dev.state_prev or dev.temperature_setting != dev.temperature_setting_prev or not dev.init:
                    dev.publish_mqtt()
                    dev.init = True
                if dev.temperature_current != dev.temperature_current_prev:
                    # dev.publish_mqtt()
                    pass
                dev.state_prev = dev.state
                dev.temperature_setting_prev = dev.temperature_setting
                dev.temperature_current_prev = dev.temperature_current
        except Exception as e:
            writeLog('onParserControlResult Exception::{}'.format(e), self)
Room Idx: 1, Temperature Current: 5.1
Raw Packet: 02|28|10|91|A0|01|02|18|01|33|00|25|00|00|00|07
Room Idx: 2, Temperature Current: 5.0
Raw Packet: 02|28|10|91|A4|02|02|19|01|32|00|25|00|00|00|04
Room Idx: 3, Temperature Current: 3.8
Raw Packet: 02|28|10|91|A8|03|02|57|01|26|00|25|00|00|00|67

 

잘못된 부분을 찾았다!

 

처음에 분석할 때는 10번째 패킷만 10으로 나눈 실수형값이 온도값이길래 그러려니 하고 넘어갔는데, 1바이트만 사용하면 최대로 표현 가능한 온도값은 25.5도가 된다....

조금만 생각해보면 당연히 온도는 그 이상으로 표현이 되어야 하는데, 한창 구현할 때는 겨울이었다보니 미처 고려하지 못한 부분이었다

위 패킷 예시에서 9번째 패킷과 10번째 패킷을 합쳐서 보면

  • 0x133 = 307
  • 0x132 = 306
  • 0x123 = 291

이걸 10으로 나누면 30.7, 30.6, 29.1도로 월패드에 표시되고 있는 온도값과 일치하는 것을 알 수 있다


코드를 다음과 같이 수정해주면 문제는 해결된다

# dev.temperature_current = chunk[9] / 10.0
dev.temperature_current = int.from_bytes(chunk[8:10], byteorder='big') / 10.0

 

수정 후에 다시 앱을 실행해보니

액세서리들의 현재 온도값이 제대로 표시된 것을 확인할 수 있다

 

Home 앱에서도 현재 온도가 (truncation된 채로) 표기되는 것을 확인할 수 있다

끝~!

반응형
Comments