mirror of
				https://github.com/python-kasa/python-kasa.git
				synced 2025-11-04 06:32:07 +00:00 
			
		
		
		
	Perform initial update only using the sysinfo query (#199)
Some devices are known to fail when trying to query non-supported modules like emeter information. This commit makes the initial update() only request the sysinfo, followed up by a second query if emeter is supported by the device.
This commit is contained in:
		@@ -291,18 +291,33 @@ class SmartDevice:
 | 
			
		||||
        return await self._query_helper("system", "get_sysinfo")
 | 
			
		||||
 | 
			
		||||
    async def update(self):
 | 
			
		||||
        """Update some of the attributes.
 | 
			
		||||
        """Query the device to update the data.
 | 
			
		||||
 | 
			
		||||
        Needed for methods that are decorated with `requires_update`.
 | 
			
		||||
        Needed for properties that are decorated with `requires_update`.
 | 
			
		||||
        """
 | 
			
		||||
        req = {}
 | 
			
		||||
        req.update(self._create_request("system", "get_sysinfo"))
 | 
			
		||||
 | 
			
		||||
        # Check for emeter if we were never updated, or if the device has emeter
 | 
			
		||||
        if self._last_update is None or self.has_emeter:
 | 
			
		||||
        # If this is the initial update, check only for the sysinfo
 | 
			
		||||
        # This is necessary as some devices crash on unexpected modules
 | 
			
		||||
        # See #105, #120, #161
 | 
			
		||||
        if self._last_update is None:
 | 
			
		||||
            _LOGGER.debug("Performing the initial update to obtain sysinfo")
 | 
			
		||||
            self._last_update = await self.protocol.query(self.host, req)
 | 
			
		||||
            self._sys_info = self._last_update["system"]["get_sysinfo"]
 | 
			
		||||
            # If the device has no emeter, we are done for the initial update
 | 
			
		||||
            # Otherwise we will follow the regular code path to also query
 | 
			
		||||
            # the emeter data also during the initial update
 | 
			
		||||
            if not self.has_emeter:
 | 
			
		||||
                return
 | 
			
		||||
 | 
			
		||||
        if self.has_emeter:
 | 
			
		||||
            _LOGGER.debug(
 | 
			
		||||
                "The device has emeter, querying its information along sysinfo"
 | 
			
		||||
            )
 | 
			
		||||
            req.update(self._create_emeter_request())
 | 
			
		||||
 | 
			
		||||
        self._last_update = await self.protocol.query(self.host, req)
 | 
			
		||||
        # TODO: keep accessible for tests
 | 
			
		||||
        self._sys_info = self._last_update["system"]["get_sysinfo"]
 | 
			
		||||
 | 
			
		||||
    def update_from_discover_info(self, info):
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ STRIPS = {"HS107", "HS300", "KP303", "KP400"}
 | 
			
		||||
DIMMERS = {"HS220"}
 | 
			
		||||
 | 
			
		||||
DIMMABLE = {*BULBS, *DIMMERS}
 | 
			
		||||
WITH_EMETER = {"HS110", "HS300", *BULBS, *STRIPS}
 | 
			
		||||
WITH_EMETER = {"HS110", "HS300", *BULBS}
 | 
			
		||||
 | 
			
		||||
ALL_DEVICES = BULBS.union(PLUGS).union(STRIPS).union(DIMMERS)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ import pytest  # type: ignore # https://github.com/pytest-dev/pytest/issues/3342
 | 
			
		||||
 | 
			
		||||
from kasa import SmartDeviceException
 | 
			
		||||
 | 
			
		||||
from .conftest import handle_turn_on, pytestmark, turn_on
 | 
			
		||||
from .conftest import handle_turn_on, has_emeter, no_emeter, pytestmark, turn_on
 | 
			
		||||
from .newfakes import PLUG_SCHEMA, TZ_SCHEMA, FakeTransportProtocol
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -17,7 +17,24 @@ async def test_invalid_connection(dev):
 | 
			
		||||
    with patch.object(FakeTransportProtocol, "query", side_effect=SmartDeviceException):
 | 
			
		||||
        with pytest.raises(SmartDeviceException):
 | 
			
		||||
            await dev.update()
 | 
			
		||||
            dev.is_on
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@has_emeter
 | 
			
		||||
async def test_initial_update_emeter(dev, mocker):
 | 
			
		||||
    """Test that the initial update performs second query if emeter is available."""
 | 
			
		||||
    dev._last_update = None
 | 
			
		||||
    spy = mocker.spy(dev.protocol, "query")
 | 
			
		||||
    await dev.update()
 | 
			
		||||
    assert spy.call_count == 2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@no_emeter
 | 
			
		||||
async def test_initial_update_no_emeter(dev, mocker):
 | 
			
		||||
    """Test that the initial update performs second query if emeter is available."""
 | 
			
		||||
    dev._last_update = None
 | 
			
		||||
    spy = mocker.spy(dev.protocol, "query")
 | 
			
		||||
    await dev.update()
 | 
			
		||||
    assert spy.call_count == 1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def test_query_helper(dev):
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user