Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve reported temperature precision #93

Merged
merged 1 commit into from
Oct 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions msmart/device/AC/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,13 @@ def decode_temp(d: int) -> Optional[float]:

self.display_on = (payload[14] != 0x70)

# Decode additional temperature resolution
if self.indoor_temperature:
self.indoor_temperature += (payload[15] & 0xF) / 10

if self.outdoor_temperature:
self.outdoor_temperature += (payload[15] >> 4) / 10

# TODO dudanov/MideaUART humidity set point in byte 19, mask 0x7F

# TODO Some payloads are shorter than expected. Unsure what, when or why
Expand Down
65 changes: 65 additions & 0 deletions msmart/device/AC/test_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def _test_response(self, msg) -> StateResponse:
return cast(StateResponse, resp)

def test_message_checksum(self) -> None:
# https://github.com/mill1000/midea-ac-py/issues/11#issuecomment-1650647625
# V3 state response with checksum as CRC, and shorter than expected
TEST_MESSAGE_CHECKSUM_AS_CRC = bytes.fromhex(
"aa1eac00000000000003c0004b1e7f7f000000000069630000000000000d33")
Expand Down Expand Up @@ -89,6 +90,70 @@ def test_message_v3(self) -> None:
self.assertEqual(resp.indoor_temperature, 21.0)
self.assertEqual(resp.outdoor_temperature, 28.5)

def test_message_additional_precision(self) -> None:
"""Test decoding of temperatures with higher precision."""
# Messages with additional temperature precision bits
TEST_MESSAGES = {
# https://github.com/mill1000/midea-msmart/issues/89#issuecomment-1783316836
(24.0, 25.1, 10.0): bytes.fromhex(
"aa23ac00000000000203c00188647f7f000000000063450c0056190000000000000497c3"),
# https://github.com/mill1000/midea-msmart/issues/89#issuecomment-1782352164
(24.0, 27.0, 10.2): bytes.fromhex(
"aa23ac00000000000203c00188647f7f000000000067450c00750000000000000001a3b0"),
(24.0, 25.0, 10.0): bytes.fromhex(
"aa23ac00000000000203c00188647f7f000080000064450c00501d00000000000001508e"),
}

for targets, message in TEST_MESSAGES.items():
# Create response from the message
resp = self._test_response(message)

# Assert response is a state response
self.assertEqual(type(resp), StateResponse)

# Suppress type errors
resp = cast(StateResponse, resp)

target, indoor, outdoor = targets

self.assertEqual(resp.target_temperature, target)
self.assertEqual(resp.indoor_temperature, indoor)
self.assertEqual(resp.outdoor_temperature, outdoor)

# Raw responses with additional temperature precision bits
TEST_RESPONSES = {
# https://github.com/mill1000/midea-ac-py/issues/39#issuecomment-1729884851
# Corrected target values from user reported values
(16.0, 23.2, 18.4): bytes.fromhex("c00181667f7f003c00000060560400420000000000000048"),
(16.5, 23.4, 18.4): bytes.fromhex("c00191667f7f003c00000060560400440000000000000049"),
(17.0, 24.1, 18.3): bytes.fromhex("c00181667f7f003c0000006156050036000000000000004a"),
(17.5, 24.3, 18.2): bytes.fromhex("c00191667f7f003c0000006156050028000000000000004b"),
(18.0, 24.3, 18.2): bytes.fromhex("c00182667f7f003c0000006156060028000000000000004c"),
(18.5, 24.3, 18.2): bytes.fromhex("c00192667f7f003c0000006156060028000000000000004d"),
(19.0, 24.3, 18.2): bytes.fromhex("c00183667f7f003c0000006156070028000000000000004e"),
(19.5, 24.0, 19.0): bytes.fromhex("c00193667f7f003c00000061570700550000000000000050"),
}

for targets, payload in TEST_RESPONSES.items():
# Create response
with memoryview(payload) as mv_payload:
resp = StateResponse(mv_payload)

# Assert that it exists
self.assertIsNotNone(resp)

# Assert response is a state response
self.assertEqual(type(resp), StateResponse)

# Suppress type errors
resp = cast(StateResponse, resp)

target, indoor, outdoor = targets

self.assertEqual(resp.target_temperature, target)
self.assertEqual(resp.indoor_temperature, indoor)
self.assertEqual(resp.outdoor_temperature, outdoor)

def test_target_temperature(self) -> None:
"""Test decoding of target temperature from a variety of state responses."""
TEST_PAYLOADS = {
Expand Down