Skip to content

Commit

Permalink
fix(capabilities): make capabilities optional (#217)
Browse files Browse the repository at this point in the history
With this change, if capabilities fail, no exception is thrown. So AC
devices that doesn't support capabilities will remain working.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Improved device connection process to streamline capability querying.

- **Refactor**
- Simplified the `get_capabilities` method to focus on sending commands.

- **Tests**
- Updated tests for capability querying to enhance clarity and remove
redundant checks.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
rokam authored Jul 11, 2024
1 parent 31bc7ac commit c269e71
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 83 deletions.
42 changes: 3 additions & 39 deletions midealocal/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,6 @@ class AuthException(Exception):
"""Authentication exception."""


class CapabilitiesFailed(Exception):
"""Capabilities failed exception."""


class ResponseException(Exception):
"""Response exception."""

Expand Down Expand Up @@ -218,7 +214,7 @@ def connect(
if refresh_status:
self.refresh_status(wait_response=True)
if get_capabilities:
self.get_capabilities(wait_response=True)
self.get_capabilities()
connected = True
except TimeoutError:
_LOGGER.debug("[%s] Connection timed out", self._device_id)
Expand All @@ -228,8 +224,6 @@ def connect(
_LOGGER.debug("[%s] Authentication failed", self._device_id)
except RefreshFailed:
_LOGGER.debug("[%s] Refresh status is timed out", self._device_id)
except CapabilitiesFailed:
_LOGGER.debug("[%s] Refresh capabilities is timed out", self._device_id)
except Exception as e:
file = None
lineno = None
Expand Down Expand Up @@ -292,41 +286,11 @@ def build_send(self, cmd: MessageRequest) -> None:
msg = PacketBuilder(self._device_id, data).finalize()
self.send_message(msg)

def get_capabilities(self, wait_response: bool = False) -> None:
def get_capabilities(self) -> None:
"""Get device capabilities."""
cmds: list = self.capabilities_query()
if self._appliance_query:
cmds = [MessageQueryAppliance(self.device_type), *cmds]
error_count = 0
for cmd in cmds:
if cmd.__class__.__name__ not in self._unsupported_protocol:
self.build_send(cmd)
if wait_response:
try:
while True:
if not self._socket:
raise SocketException
msg = self._socket.recv(512)
if len(msg) == 0:
raise OSError("Empty message received.")
result = self.parse_message(msg)
if result == ParseMessageResult.SUCCESS:
break
if result == ParseMessageResult.PADDING:
continue
error_count += 1
except TimeoutError:
error_count += 1
self._unsupported_protocol.append(cmd.__class__.__name__)
_LOGGER.debug(
"[%s] Does not supports the protocol %s, ignored",
self._device_id,
cmd.__class__.__name__,
)
else:
error_count += 1
if len(cmds) > 0 and error_count == len(cmds):
raise CapabilitiesFailed
self.build_send(cmd)

def refresh_status(self, wait_response: bool = False) -> None:
"""Refresh device status."""
Expand Down
51 changes: 7 additions & 44 deletions tests/device_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
from midealocal.cloud import default_keys
from midealocal.device import (
AuthException,
CapabilitiesFailed,
MideaDevice,
ParseMessageResult,
ProtocolVersion,
RefreshFailed,
)
from midealocal.devices.ac.message import MessageCapabilitiesQuery
from midealocal.exceptions import SocketException
from midealocal.message import MessageType

Expand Down Expand Up @@ -66,17 +66,17 @@ def test_connect(self) -> None:
patch.object(
self.device,
"authenticate",
side_effect=[AuthException(), None, None, None],
side_effect=[AuthException(), None, None],
),
patch.object(
self.device,
"refresh_status",
side_effect=[RefreshFailed(), None, None],
side_effect=[RefreshFailed(), None],
),
patch.object(
self.device,
"get_capabilities",
side_effect=[CapabilitiesFailed(), None],
side_effect=[None],
),
):
connect_mock.side_effect = [
Expand All @@ -99,9 +99,6 @@ def test_connect(self) -> None:
assert self.device.connect(True, True) is False
assert self.device.available is False

assert self.device.connect(True, True) is False
assert self.device.available is False

assert self.device.connect(True, True) is True
assert self.device.available is True

Expand Down Expand Up @@ -225,50 +222,16 @@ def test_send_message(self) -> None:

def test_get_capabilities(self) -> None:
"""Test get capabilities."""
self.device._appliance_query = False
self.device.get_capabilities() # Empty capabilities
self.device._appliance_query = True
socket_mock = MagicMock()
with (
patch.object(
socket_mock,
"recv",
side_effect=[
bytearray([]),
bytearray([0x0]),
bytearray([0x0]),
bytearray([0x0]),
TimeoutError(),
],
),
patch.object(self.device, "build_send", return_value=None),
patch.object(
self.device,
"parse_message",
side_effect=[
ParseMessageResult.SUCCESS,
ParseMessageResult.PADDING,
ParseMessageResult.ERROR,
],
"capabilities_query",
return_value=[MessageCapabilitiesQuery(ProtocolVersion.V2, False)],
),
):
self.device._socket = None
with pytest.raises(SocketException):
self.device.get_capabilities(True)

self.device._socket = socket_mock
with pytest.raises(OSError, match="Empty message received."):
self.device.get_capabilities(True)

self.device.get_capabilities(True) # SUCCESS
self.device.get_capabilities(True) # PADDING

with pytest.raises(CapabilitiesFailed):
self.device.get_capabilities(True) # ERROR
with pytest.raises(CapabilitiesFailed):
self.device.get_capabilities(True) # Timeout
with pytest.raises(CapabilitiesFailed):
self.device.get_capabilities(True) # Unsupported protocol
self.device.get_capabilities()

def test_refresh_status(self) -> None:
"""Test refresh status."""
Expand Down

0 comments on commit c269e71

Please sign in to comment.