Skip to content

Commit

Permalink
Update temperature, zone_status decoding to match spec changes
Browse files Browse the repository at this point in the history
  • Loading branch information
danzel committed Jun 27, 2024
1 parent 2740841 commit ca4a0a2
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 23 deletions.
42 changes: 19 additions & 23 deletions airtouch5py/packet_decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,36 +131,30 @@ def decode_control_status(self, bytes: bytes) -> Data:
raise ValueError(
"Zone control message should have 4 byte repeat data"
)
return self.decode_zone_control(bytes[8:], repeat_data_count)
return self.decode_zone_control(bytes[8 + normal_data_length:], repeat_data_count)
case ControlStatusSubType.ZONE_STATUS.value:
if normal_data_length != 0:
raise ValueError("Zone status message should not have normal data")
if repeat_data_count != 0 and repeat_data_length != 8:
#This packet doesn't currently have normal data (1.2.0), but the docs say it might in the future
if repeat_data_count != 0 and repeat_data_length < 8:
raise ValueError(
"Zone status message should have 8 byte repeat data"
"Zone status message should have at least 8 byte repeat data"
)
return self.decode_zone_status(bytes[8:], repeat_data_count)
return self.decode_zone_status(bytes[8 + normal_data_length:], repeat_data_count, repeat_data_length)
case ControlStatusSubType.AC_CONTROL.value:
if normal_data_length != 0:
raise ValueError("AC control message should not have normal data")
if repeat_data_length != 4:
raise ValueError(
"AC control message should have 4 byte repeat data"
)
return self.decode_ac_control(bytes[8:], repeat_data_count)
return self.decode_ac_control(bytes[8 + normal_data_length:], repeat_data_count)
case ControlStatusSubType.AC_STATUS.value:
if normal_data_length != 0:
raise ValueError("AC status message should not have normal data")
if (
repeat_data_count != 0
and repeat_data_length != 10
and repeat_data_length != 14
):
#This packet doesn't currently have normal data (1.2.0), but the docs say it might in the future
if repeat_data_count != 0 and repeat_data_length < 10:
raise ValueError(
f"AC status message should have 10 or 14 byte repeat data, but it was {repeat_data_length}"
f"AC status message should have at least 10 or 14 byte repeat data, but it was {repeat_data_length}"
)
return self.decode_ac_status(
bytes[8:], repeat_data_count, repeat_data_length
bytes[8 + normal_data_length:], repeat_data_count, repeat_data_length
)
case _:
raise ValueError(f"Unknown sub message type: {hex(sub_message_type)}")
Expand Down Expand Up @@ -202,7 +196,7 @@ def decode_zone_control(
return ZoneControlData(zones)

def decode_zone_status(
self, bytes: bytes, repeat_data_count: int
self, bytes: bytes, repeat_data_count: int, repeat_data_length: int
) -> ZoneStatusData:
if repeat_data_count == 0:
return ZoneStatusData([])
Expand All @@ -212,7 +206,7 @@ def decode_zone_status(

for i in range(0, repeat_data_count):
bits.clear()
bits.frombytes(bytes[i * 8 : i * 8 + 8])
bits.frombytes(bytes[i * repeat_data_length : i * repeat_data_length + repeat_data_length])
# Byte 1 Bit 8-7 Zone power state
zone_power_state = ZonePowerState(ba2int(bits[0:2]))
# Byte 1 Bit 6-1 Zone number
Expand All @@ -229,9 +223,11 @@ def decode_zone_status(
set_point = (set_point + 100) / 10
# Byte 4 Bit 8 Has sensor
has_sensor = bool(bits[24 + 0])
# Byte 5-6 Temperature
temperature = (ba2int(bits[32 : 32 + 16]) - 500) / 10
if temperature > 150: # temp > 150 invalid
# Byte 5 Bit 3-1, Byte 6 Temperature
temperature = ba2int(bits[32 + 5 : 32 + 5 + 3 + 8])
if temperature <= 2000:
temperature = (temperature - 500) / 10
else: # Other: Not available
temperature = None
# Byte 7 Bit 2 Spill active
spill_active = bool(bits[48 + 6])
Expand Down Expand Up @@ -347,8 +343,8 @@ def decode_ac_status(
spill_active = bool(bits[24 + 6])
# Byte 4 Bit 1 Timer set
timer_set = bool(bits[24 + 7])
# Byte 5-6 Temperature
temperature = ba2int(bits[32 : 32 + 16])
# Byte 5 Bit 3-1, Byte 6 Temperature
temperature = ba2int(bits[32 + 5 : 32 + 5 + 3 + 8])
if temperature <= 2000:
temperature = (temperature - 500) / 10
else: # Other: Not available
Expand Down
35 changes: 35 additions & 0 deletions tests/test_packet_decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,41 @@ def test_decode_ac_status_response_2_acs_example():
assert ac.temperature == 24.0
assert ac.error_code == 0 # No error

def test_decode_ac_status_response_console_120():
"""
Decode the AC status (response) message as received with console version 1.2.0 (2024-06-27 release).
The repeated section is 14 bytes instead of 10 as it used to be
"""
decoder = PacketDecoder()
data = b"\x55\x55\x55\xaa\xb0\x80\x07\xc0\x00\x16\x23\x00\x00\x00\x00\x0e\x00\x01\x10\x12\x82\xc5\x0a\xbf\x00\x00\xe5\x00\xe2\xe4\x00\x00\xa7\xd5"
packet: DataPacket = decoder.decode(data)

# Packet

assert packet.address == 0xB080
assert packet.message_id == 0x07
assert type(packet.data) is AcStatusData

# AC status

assert len(packet.data.ac_status) == 1

# AC 0

ac = packet.data.ac_status[0]
assert ac.ac_power_state == AcPowerState.ON
assert ac.ac_number == 0
assert ac.ac_mode == AcMode.HEAT
assert ac.ac_fan_speed == AcFanSpeed.LOW
assert ac.ac_setpoint == 23.0
assert ac.turbo_active == False
assert ac.bypass_active == True
assert ac.spill_active == False
assert ac.timer_set == True
assert ac.temperature == 20.3
assert ac.error_code == 0 # No error


def test_decode_extended_ac_ability_request_example():
"""
Expand Down

0 comments on commit ca4a0a2

Please sign in to comment.