Skip to content

Commit

Permalink
Skip write-only properties for miot status requests (#1525)
Browse files Browse the repository at this point in the history
  • Loading branch information
rytilahti authored Sep 20, 2022
1 parent 0b9713b commit b056fe2
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 3 deletions.
29 changes: 27 additions & 2 deletions miio/miot_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,27 @@ def _str2bool(x):
MiotMapping = Dict[str, Dict[str, Any]]


def _filter_request_fields(req):
"""Return only the parts that belong to the request.."""
return {k: v for k, v in req.items() if k in ["did", "siid", "piid"]}


def _is_readable_property(prop):
"""Returns True if a property in the mapping can be read."""
# actions cannot be read
if "aiid" in prop:
_LOGGER.debug("Ignoring action %s for the request", prop)
return False

# if the mapping has access defined, check if the property is readable
access = getattr(prop, "access", None)
if access is not None and "read" not in access:
_LOGGER.debug("Ignoring %s as it has non-read access defined", prop)
return False

return True


class MiotDevice(Device):
"""Main class representing a MIoT device.
Expand Down Expand Up @@ -64,10 +85,14 @@ def __init__(

def get_properties_for_mapping(self, *, max_properties=15) -> list:
"""Retrieve raw properties based on mapping."""
mapping = self._get_mapping()

# We send property key in "did" because it's sent back via response and we can identify the property.
mapping = self._get_mapping()
properties = [{"did": k, **v} for k, v in mapping.items() if "aiid" not in v]
properties = [
{"did": k, **_filter_request_fields(v)}
for k, v in mapping.items()
if _is_readable_property(v)
]

return self.get_properties(
properties, property_getter="get_properties", max_properties=max_properties
Expand Down
53 changes: 52 additions & 1 deletion miio/tests/test_miotdevice.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from unittest.mock import ANY

import pytest

from miio import Huizuo, MiotDevice
from miio.miot_device import MiotValueType
from miio.miot_device import MiotValueType, _filter_request_fields

MIOT_DEVICES = MiotDevice.__subclasses__()
# TODO: huizuo needs to be refactored to use _mappings,
Expand All @@ -15,6 +17,7 @@ def dev(module_mocker):
device = MiotDevice(
"127.0.0.1", "68ffffffffffffffffffffffffffffff", mapping=DUMMY_MAPPING
)
device._model = "testmodel"
module_mocker.patch.object(device, "send")
return device

Expand Down Expand Up @@ -151,3 +154,51 @@ def test_supported_models(cls):

# make sure that that _supported_models is not defined
assert not cls._supported_models


def test_call_action(dev):
dev._mappings["testmodel"] = {"test_action": {"siid": 1, "aiid": 1}}

dev.call_action("test_action")


@pytest.mark.parametrize(
"props,included_in_request",
[
({"access": ["read"]}, True), # read only
({"access": ["read", "write"]}, True), # read-write
({}, True), # not defined
({"access": ["write"]}, False), # write-only
({"aiid": "1"}, False), # action
],
ids=["read-only", "read-write", "access-not-defined", "write-only", "action"],
)
def test_get_properties_for_mapping_readables(mocker, dev, props, included_in_request):
base_props = {"readable_property": {"siid": 1, "piid": 1}}
base_request = [{"did": k, **v} for k, v in base_props.items()]
dev._mappings["testmodel"] = mapping = {
**base_props,
"property_under_test": {"siid": 1, "piid": 2, **props},
}
expected_request = [
{"did": k, **_filter_request_fields(v)} for k, v in mapping.items()
]

req = mocker.patch.object(dev, "get_properties")
dev.get_properties_for_mapping()

try:

req.assert_called_with(
expected_request, property_getter=ANY, max_properties=ANY
)
except AssertionError:
if included_in_request:
raise AssertionError("Required property was not requested")
else:
try:
req.assert_called_with(
base_request, property_getter=ANY, max_properties=ANY
)
except AssertionError as ex:
raise AssertionError("Tried to read unreadable property") from ex

0 comments on commit b056fe2

Please sign in to comment.