Make timeout adjustable (#494)

This commit is contained in:
J. Nick Koston 2023-10-07 08:58:00 -10:00 committed by GitHub
parent 20b3f7a771
commit 0ec0826cc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 39 additions and 17 deletions

View File

@ -47,7 +47,8 @@ class _DiscoverProtocol(asyncio.DatagramProtocol):
port: Optional[int] = None, port: Optional[int] = None,
discovered_event: Optional[asyncio.Event] = None, discovered_event: Optional[asyncio.Event] = None,
credentials: Optional[Credentials] = None, credentials: Optional[Credentials] = None,
): timeout: Optional[int] = None,
) -> None:
self.transport = None self.transport = None
self.discovery_packets = discovery_packets self.discovery_packets = discovery_packets
self.interface = interface self.interface = interface
@ -61,6 +62,7 @@ class _DiscoverProtocol(asyncio.DatagramProtocol):
self.on_unsupported = on_unsupported self.on_unsupported = on_unsupported
self.discovered_event = discovered_event self.discovered_event = discovered_event
self.credentials = credentials self.credentials = credentials
self.timeout = timeout
def connection_made(self, transport) -> None: def connection_made(self, transport) -> None:
"""Set socket options for broadcasting.""" """Set socket options for broadcasting."""
@ -124,7 +126,9 @@ class _DiscoverProtocol(asyncio.DatagramProtocol):
self.discovered_event.set() self.discovered_event.set()
return return
device = device_class(ip, port=port, credentials=self.credentials) device = device_class(
ip, port=port, credentials=self.credentials, timeout=self.timeout
)
device.update_from_discover_info(info) device.update_from_discover_info(info)
self.discovered_devices[ip] = device self.discovered_devices[ip] = device
@ -226,6 +230,7 @@ class Discover:
interface=interface, interface=interface,
on_unsupported=on_unsupported, on_unsupported=on_unsupported,
credentials=credentials, credentials=credentials,
timeout=timeout,
), ),
local_addr=("0.0.0.0", 0), local_addr=("0.0.0.0", 0),
) )
@ -259,7 +264,11 @@ class Discover:
event = asyncio.Event() event = asyncio.Event()
transport, protocol = await loop.create_datagram_endpoint( transport, protocol = await loop.create_datagram_endpoint(
lambda: _DiscoverProtocol( lambda: _DiscoverProtocol(
target=host, port=port, discovered_event=event, credentials=credentials target=host,
port=port,
discovered_event=event,
credentials=credentials,
timeout=timeout,
), ),
local_addr=("0.0.0.0", 0), local_addr=("0.0.0.0", 0),
) )

View File

@ -37,7 +37,9 @@ class TPLinkSmartHomeProtocol:
DEFAULT_TIMEOUT = 5 DEFAULT_TIMEOUT = 5
BLOCK_SIZE = 4 BLOCK_SIZE = 4
def __init__(self, host: str, *, port: Optional[int] = None) -> None: def __init__(
self, host: str, *, port: Optional[int] = None, timeout: Optional[int] = None
) -> None:
"""Create a protocol object.""" """Create a protocol object."""
self.host = host self.host = host
self.port = port or TPLinkSmartHomeProtocol.DEFAULT_PORT self.port = port or TPLinkSmartHomeProtocol.DEFAULT_PORT
@ -45,6 +47,7 @@ class TPLinkSmartHomeProtocol:
self.writer: Optional[asyncio.StreamWriter] = None self.writer: Optional[asyncio.StreamWriter] = None
self.query_lock: Optional[asyncio.Lock] = None self.query_lock: Optional[asyncio.Lock] = None
self.loop: Optional[asyncio.AbstractEventLoop] = None self.loop: Optional[asyncio.AbstractEventLoop] = None
self.timeout = timeout or TPLinkSmartHomeProtocol.DEFAULT_TIMEOUT
def _detect_event_loop_change(self) -> None: def _detect_event_loop_change(self) -> None:
"""Check if this object has been reused betwen event loops.""" """Check if this object has been reused betwen event loops."""
@ -73,10 +76,8 @@ class TPLinkSmartHomeProtocol:
request = json_dumps(request) request = json_dumps(request)
assert isinstance(request, str) assert isinstance(request, str)
timeout = TPLinkSmartHomeProtocol.DEFAULT_TIMEOUT
async with self.query_lock: async with self.query_lock:
return await self._query(request, retry_count, timeout) return await self._query(request, retry_count, self.timeout)
async def _connect(self, timeout: int) -> None: async def _connect(self, timeout: int) -> None:
"""Try to connect or reconnect to the device.""" """Try to connect or reconnect to the device."""

View File

@ -208,9 +208,10 @@ class SmartBulb(SmartDevice):
host: str, host: str,
*, *,
port: Optional[int] = None, port: Optional[int] = None,
credentials: Optional[Credentials] = None credentials: Optional[Credentials] = None,
timeout: Optional[int] = None,
) -> None: ) -> None:
super().__init__(host=host, port=port, credentials=credentials) super().__init__(host=host, port=port, credentials=credentials, timeout=timeout)
self._device_type = DeviceType.Bulb self._device_type = DeviceType.Bulb
self.add_module("schedule", Schedule(self, "smartlife.iot.common.schedule")) self.add_module("schedule", Schedule(self, "smartlife.iot.common.schedule"))
self.add_module("usage", Usage(self, "smartlife.iot.common.schedule")) self.add_module("usage", Usage(self, "smartlife.iot.common.schedule"))
@ -372,7 +373,7 @@ class SmartBulb(SmartDevice):
saturation: int, saturation: int,
value: Optional[int] = None, value: Optional[int] = None,
*, *,
transition: Optional[int] = None transition: Optional[int] = None,
) -> Dict: ) -> Dict:
"""Set new HSV. """Set new HSV.

View File

@ -195,6 +195,7 @@ class SmartDevice:
*, *,
port: Optional[int] = None, port: Optional[int] = None,
credentials: Optional[Credentials] = None, credentials: Optional[Credentials] = None,
timeout: Optional[int] = None,
) -> None: ) -> None:
"""Create a new SmartDevice instance. """Create a new SmartDevice instance.
@ -203,7 +204,7 @@ class SmartDevice:
self.host = host self.host = host
self.port = port self.port = port
self.protocol = TPLinkSmartHomeProtocol(host, port=port) self.protocol = TPLinkSmartHomeProtocol(host, port=port, timeout=timeout)
self.credentials = credentials self.credentials = credentials
_LOGGER.debug("Initializing %s of type %s", self.host, type(self)) _LOGGER.debug("Initializing %s of type %s", self.host, type(self))
self._device_type = DeviceType.Unknown self._device_type = DeviceType.Unknown

View File

@ -69,8 +69,9 @@ class SmartDimmer(SmartPlug):
*, *,
port: Optional[int] = None, port: Optional[int] = None,
credentials: Optional[Credentials] = None, credentials: Optional[Credentials] = None,
timeout: Optional[int] = None,
) -> None: ) -> None:
super().__init__(host, port=port, credentials=credentials) super().__init__(host, port=port, credentials=credentials, timeout=timeout)
self._device_type = DeviceType.Dimmer self._device_type = DeviceType.Dimmer
# TODO: need to be verified if it's okay to call these on HS220 w/o these # TODO: need to be verified if it's okay to call these on HS220 w/o these
# TODO: need to be figured out what's the best approach to detect support for these # TODO: need to be figured out what's the best approach to detect support for these

View File

@ -48,8 +48,9 @@ class SmartLightStrip(SmartBulb):
*, *,
port: Optional[int] = None, port: Optional[int] = None,
credentials: Optional[Credentials] = None, credentials: Optional[Credentials] = None,
timeout: Optional[int] = None,
) -> None: ) -> None:
super().__init__(host, port=port, credentials=credentials) super().__init__(host, port=port, credentials=credentials, timeout=timeout)
self._device_type = DeviceType.LightStrip self._device_type = DeviceType.LightStrip
@property # type: ignore @property # type: ignore

View File

@ -43,9 +43,10 @@ class SmartPlug(SmartDevice):
host: str, host: str,
*, *,
port: Optional[int] = None, port: Optional[int] = None,
credentials: Optional[Credentials] = None credentials: Optional[Credentials] = None,
timeout: Optional[int] = None,
) -> None: ) -> None:
super().__init__(host, port=port, credentials=credentials) super().__init__(host, port=port, credentials=credentials, timeout=timeout)
self._device_type = DeviceType.Plug self._device_type = DeviceType.Plug
self.add_module("schedule", Schedule(self, "schedule")) self.add_module("schedule", Schedule(self, "schedule"))
self.add_module("usage", Usage(self, "schedule")) self.add_module("usage", Usage(self, "schedule"))

View File

@ -86,8 +86,9 @@ class SmartStrip(SmartDevice):
*, *,
port: Optional[int] = None, port: Optional[int] = None,
credentials: Optional[Credentials] = None, credentials: Optional[Credentials] = None,
timeout: Optional[int] = None,
) -> None: ) -> None:
super().__init__(host=host, port=port, credentials=credentials) super().__init__(host=host, port=port, credentials=credentials, timeout=timeout)
self.emeter_type = "emeter" self.emeter_type = "emeter"
self._device_type = DeviceType.Strip self._device_type = DeviceType.Strip
self.add_module("antitheft", Antitheft(self, "anti_theft")) self.add_module("antitheft", Antitheft(self, "anti_theft"))

View File

@ -166,7 +166,7 @@ async def _update_and_close(d):
async def _discover_update_and_close(ip): async def _discover_update_and_close(ip):
d = await Discover.discover_single(ip) d = await Discover.discover_single(ip, timeout=10)
return await _update_and_close(d) return await _update_and_close(d)

View File

@ -194,3 +194,9 @@ async def test_modules_preserved(dev: SmartDevice):
dev._last_update["some_module_not_being_updated"] = "should_be_kept" dev._last_update["some_module_not_being_updated"] = "should_be_kept"
await dev.update() await dev.update()
assert dev._last_update["some_module_not_being_updated"] == "should_be_kept" assert dev._last_update["some_module_not_being_updated"] == "should_be_kept"
async def test_create_smart_device_with_timeout():
"""Make sure timeout is passed to the protocol."""
dev = SmartDevice(host="127.0.0.1", timeout=100)
assert dev.protocol.timeout == 100