Skip to content

Commit 95ba499

Browse files
authored
fix(ac): allow half-degree integer temperatures (#412)
This is deduplicating the temperature functions, and then finally dropping the int(...) cast on the "integer" temperature value. This is used on e.g. the Midea PortaSplit, which reports half-degree values via this field (decimal value = 0). I'd think if a device reports a decimal value as int + decimal, then it won't report half-degree steps for the integer, and the casting of the integer would be redundant. To be on the safe side though, and avoid potential regressions, I've implemented it to only return the integer as float, if the decimal really is 0. So even if the integer is reported with half-degree steps *and* a seperate decimal simultaneously, it'd be fine, since in that case the integer should be a whole number anyway. PS: Let me know if and what you'd want as "proof", e.g. HA or Midea-App screenshots, debug logs (before or after fix), etc., and I'll provide it (just don't want to waste time on unnecessary stuff)
1 parent e8f127c commit 95ba499

File tree

1 file changed

+24
-47
lines changed

1 file changed

+24
-47
lines changed

midealocal/devices/ac/message.py

Lines changed: 24 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
SCREEN_DISPLAY_BYTE_CHECK = 0x07
3232
SUB_PROTOCOL_BODY_TEMP_CHECK = 0x80
3333
TEMP_DECIMAL_MIN_BODY_LENGTH = 20
34-
TEMP_NEG_VALUE = 49
3534
TIMER_MIN_SUBPROTOCOL_LENGTH = 27
3635
XBB_SN8_BYTE_FLAG = 0x31
3736
XC1_SUBBODY_TYPE_44 = 0x44
@@ -806,7 +805,23 @@ def __init__(self, body: bytearray) -> None:
806805
self.fresh_filter_timeout = (body[13] & 0x40) >> 6
807806

808807

809-
class XA1MessageBody(MessageBody):
808+
class XMessageBody(MessageBody):
809+
"""AC A1/C0 message body - common functions."""
810+
811+
@staticmethod
812+
def parse_temperature(integer: int, decimal: int) -> float | None:
813+
"""Decode special signed integer with BCD decimal temperature format."""
814+
if integer == MAX_BYTE_VALUE:
815+
return None
816+
temp_integer = (integer - 50) / 2
817+
if decimal == 0:
818+
return temp_integer
819+
if temp_integer < 0:
820+
return int(temp_integer) - decimal * 0.1
821+
return int(temp_integer) + decimal * 0.1
822+
823+
824+
class XA1MessageBody(XMessageBody):
810825
"""AC A1 message body."""
811826

812827
def __init__(self, body: bytearray) -> None:
@@ -818,32 +833,9 @@ def __init__(self, body: bytearray) -> None:
818833
+ body[11] * 60
819834
+ body[12]
820835
)
821-
# indoorTemperatureValue
822-
if body[13] != MAX_BYTE_VALUE:
823-
temp_integer = int((body[13] - 50) / 2)
824-
temp_decimal = (
825-
((body[18] & 0xF) * 0.1)
826-
if len(body) > TEMP_DECIMAL_MIN_BODY_LENGTH
827-
else 0
828-
)
829-
if body[13] > TEMP_NEG_VALUE:
830-
self.indoor_temperature = temp_integer + temp_decimal
831-
else:
832-
self.indoor_temperature = temp_integer - temp_decimal
833-
# outdoorTemperatureValue
834-
if body[14] == MAX_BYTE_VALUE:
835-
self.outdoor_temperature = None
836-
else:
837-
temp_integer = int((body[14] - 50) / 2)
838-
temp_decimal = (
839-
(((body[18] & 0xF0) >> 4) * 0.1)
840-
if len(body) > TEMP_DECIMAL_MIN_BODY_LENGTH
841-
else 0
842-
)
843-
if body[14] > TEMP_NEG_VALUE:
844-
self.outdoor_temperature = temp_integer + temp_decimal
845-
else:
846-
self.outdoor_temperature = temp_integer - temp_decimal
836+
decimal = body[18] if len(body) > TEMP_DECIMAL_MIN_BODY_LENGTH else 0
837+
self.indoor_temperature = self.parse_temperature(body[13], decimal & 0x0F)
838+
self.outdoor_temperature = self.parse_temperature(body[14], decimal >> 4)
847839
self.indoor_humidity = body[17] if body[17] != 0 else None
848840

849841

@@ -920,7 +912,7 @@ def __init__(self, body: bytearray, bt: int) -> None:
920912
self.b5_humidity = params[NewProtocolTags.b5_humidity][0]
921913

922914

923-
class XC0MessageBody(MessageBody):
915+
class XC0MessageBody(XMessageBody):
924916
"""AC C0 message body."""
925917

926918
def __init__(self, body: bytearray) -> None:
@@ -948,24 +940,9 @@ def __init__(self, body: bytearray) -> None:
948940
self.purifier = body[9] & 0x20 # purifierValue
949941
self.temp_fahrenheit = (body[10] & 0x04) > 0
950942
self.sleep_mode = (body[10] & 0x01) > 0
951-
if body[11] != MAX_BYTE_VALUE:
952-
temp_integer = int((body[11] - 50) / 2) # indoorTemperatureValue
953-
temp_decimal = (body[15] & 0x0F) * 0.1 # smallIndoorTemperatureValue
954-
if body[11] > TEMP_NEG_VALUE:
955-
self.indoor_temperature = temp_integer + temp_decimal
956-
else:
957-
self.indoor_temperature = temp_integer - temp_decimal
958-
if body[12] == MAX_BYTE_VALUE:
959-
self.outdoor_temperature = None
960-
else:
961-
# outdoorTemperatureValue
962-
temp_integer = int((body[12] - 50) / 2)
963-
# smallOutdoorTemperatureValue
964-
temp_decimal = ((body[15] & 0xF0) >> 4) * 0.1
965-
if body[12] > TEMP_NEG_VALUE:
966-
self.outdoor_temperature = temp_integer + temp_decimal
967-
else:
968-
self.outdoor_temperature = temp_integer - temp_decimal
943+
decimal = body[15] if len(body) > TEMP_DECIMAL_MIN_BODY_LENGTH else 0
944+
self.indoor_temperature = self.parse_temperature(body[11], decimal & 0x0F)
945+
self.outdoor_temperature = self.parse_temperature(body[12], decimal >> 4)
969946
self.kick_quilt = (body[10] & 0x04) >> 2 # kickQuilt
970947
self.prevent_cold = (body[10] & 0x20) >> 5 # preventCold
971948
self.full_dust = ((body[13] & 0x20) >> 5) > 0 # dust_full_time

0 commit comments

Comments
 (0)