mirror of
https://github.com/python-kasa/python-kasa.git
synced 2024-12-23 03:33:35 +00:00
Add device_id property, rename context to child_id (#15)
For regular devices, device_id is the mac address and for child devices it is a combination of the mac address and the child_id.
This commit is contained in:
parent
524d28abbc
commit
0f0df481a0
@ -76,7 +76,7 @@ class SmartBulb(SmartDevice):
|
|||||||
self,
|
self,
|
||||||
host: str,
|
host: str,
|
||||||
protocol: TPLinkSmartHomeProtocol = None,
|
protocol: TPLinkSmartHomeProtocol = None,
|
||||||
context: str = None,
|
child_id: str = None,
|
||||||
cache_ttl: int = 3,
|
cache_ttl: int = 3,
|
||||||
*,
|
*,
|
||||||
ioloop=None,
|
ioloop=None,
|
||||||
@ -85,7 +85,7 @@ class SmartBulb(SmartDevice):
|
|||||||
self,
|
self,
|
||||||
host=host,
|
host=host,
|
||||||
protocol=protocol,
|
protocol=protocol,
|
||||||
context=context,
|
child_id=child_id,
|
||||||
cache_ttl=cache_ttl,
|
cache_ttl=cache_ttl,
|
||||||
ioloop=ioloop,
|
ioloop=ioloop,
|
||||||
)
|
)
|
||||||
|
@ -111,7 +111,7 @@ class SmartDevice:
|
|||||||
self,
|
self,
|
||||||
host: str,
|
host: str,
|
||||||
protocol: Optional[TPLinkSmartHomeProtocol] = None,
|
protocol: Optional[TPLinkSmartHomeProtocol] = None,
|
||||||
context: str = None,
|
child_id: str = None,
|
||||||
cache_ttl: int = 3,
|
cache_ttl: int = 3,
|
||||||
*,
|
*,
|
||||||
ioloop=None,
|
ioloop=None,
|
||||||
@ -119,20 +119,19 @@ class SmartDevice:
|
|||||||
"""Create a new SmartDevice instance.
|
"""Create a new SmartDevice instance.
|
||||||
|
|
||||||
:param str host: host name or ip address on which the device listens
|
:param str host: host name or ip address on which the device listens
|
||||||
:param context: optional child ID for context in a parent device
|
:param child_id: optional child ID for context in a parent device
|
||||||
"""
|
"""
|
||||||
self.host = host
|
self.host = host
|
||||||
if protocol is None: # pragma: no cover
|
if protocol is None: # pragma: no cover
|
||||||
protocol = TPLinkSmartHomeProtocol()
|
protocol = TPLinkSmartHomeProtocol()
|
||||||
self.protocol = protocol
|
self.protocol = protocol
|
||||||
self.emeter_type = "emeter"
|
self.emeter_type = "emeter"
|
||||||
self.context = context
|
self.child_id = child_id
|
||||||
self.num_children = 0
|
|
||||||
self.cache_ttl = timedelta(seconds=cache_ttl)
|
self.cache_ttl = timedelta(seconds=cache_ttl)
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Initializing %s using context %s and cache ttl %s",
|
"Initializing %s using child_id %s and cache ttl %s",
|
||||||
self.host,
|
self.host,
|
||||||
self.context,
|
self.child_id,
|
||||||
self.cache_ttl,
|
self.cache_ttl,
|
||||||
)
|
)
|
||||||
self.cache = defaultdict(lambda: defaultdict(lambda: None)) # type: ignore
|
self.cache = defaultdict(lambda: defaultdict(lambda: None)) # type: ignore
|
||||||
@ -189,8 +188,8 @@ class SmartDevice:
|
|||||||
:raises SmartDeviceException: if command was not executed correctly
|
:raises SmartDeviceException: if command was not executed correctly
|
||||||
"""
|
"""
|
||||||
request: Dict[str, Any] = {target: {cmd: arg}}
|
request: Dict[str, Any] = {target: {cmd: arg}}
|
||||||
if self.context is not None:
|
if self.child_id is not None:
|
||||||
request = {"context": {"child_ids": [self.context]}, target: {cmd: arg}}
|
request = {"context": {"child_ids": [self.child_id]}, target: {cmd: arg}}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = self._result_from_cache(target, cmd)
|
response = self._result_from_cache(target, cmd)
|
||||||
@ -219,6 +218,16 @@ class SmartDevice:
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def _get_child_info(self) -> Dict:
|
||||||
|
"""Return the child information dict, if available.
|
||||||
|
|
||||||
|
:raises SmartDeviceException: if there is no child or it cannot be found.
|
||||||
|
"""
|
||||||
|
for plug in self.sys_info["children"]:
|
||||||
|
if plug["id"] == self.child_id:
|
||||||
|
return plug
|
||||||
|
raise SmartDeviceException("Unable to find children %s")
|
||||||
|
|
||||||
def has_emeter(self) -> bool:
|
def has_emeter(self) -> bool:
|
||||||
"""Return if device has an energy meter.
|
"""Return if device has an energy meter.
|
||||||
|
|
||||||
@ -614,6 +623,18 @@ class SmartDevice:
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError("Device subclass needs to implement this.")
|
raise NotImplementedError("Device subclass needs to implement this.")
|
||||||
|
|
||||||
|
@property # type: ignore
|
||||||
|
@requires_update
|
||||||
|
def device_id(self) -> str:
|
||||||
|
"""Return unique ID for the device.
|
||||||
|
|
||||||
|
For regular devices this is the MAC address of the device,
|
||||||
|
for child devices a combination of MAC and child's ID.
|
||||||
|
"""
|
||||||
|
if self.is_child_device:
|
||||||
|
return f"{self.mac}_{self.child_id}"
|
||||||
|
return self.mac
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_type(self) -> DeviceType:
|
def device_type(self) -> DeviceType:
|
||||||
"""Return the device type."""
|
"""Return the device type."""
|
||||||
@ -635,7 +656,7 @@ class SmartDevice:
|
|||||||
return self._device_type == DeviceType.Strip
|
return self._device_type == DeviceType.Strip
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_dimmable(self):
|
def is_dimmable(self) -> bool:
|
||||||
"""Return True if the device is dimmable."""
|
"""Return True if the device is dimmable."""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -644,6 +665,11 @@ class SmartDevice:
|
|||||||
"""Return True if the device supports color temperature."""
|
"""Return True if the device supports color temperature."""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_child_device(self) -> bool:
|
||||||
|
"""Return True if the device is a child device of another device."""
|
||||||
|
return self.child_id is not None
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<{} model {} at {} ({}), is_on: {} - dev specific: {}>".format(
|
return "<{} model {} at {} ({}), is_on: {} - dev specific: {}>".format(
|
||||||
self.__class__.__name__,
|
self.__class__.__name__,
|
||||||
@ -653,31 +679,3 @@ class SmartDevice:
|
|||||||
self.is_on,
|
self.is_on,
|
||||||
self.state_information,
|
self.state_information,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SyncSmartDevice:
|
|
||||||
"""A synchronous SmartDevice speaker class.
|
|
||||||
|
|
||||||
This has the same methods as `SyncSmartDevice`, however, it wraps all async
|
|
||||||
methods and call them in a blocking way.
|
|
||||||
|
|
||||||
Taken from https://github.com/basnijholt/media_player.kef/
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, async_device, ioloop):
|
|
||||||
self.async_device = async_device
|
|
||||||
self.ioloop = ioloop
|
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
|
||||||
method = getattr(self.async_device, attr)
|
|
||||||
if method is None:
|
|
||||||
raise AttributeError(f"'SyncSmartDevice' object has no attribute '{attr}.'")
|
|
||||||
if inspect.iscoroutinefunction(method):
|
|
||||||
|
|
||||||
@functools.wraps(method)
|
|
||||||
def wrapped(*args, **kwargs):
|
|
||||||
return self.ioloop.run_until_complete(method(*args, **kwargs))
|
|
||||||
|
|
||||||
return wrapped
|
|
||||||
else:
|
|
||||||
return method
|
|
||||||
|
@ -40,12 +40,12 @@ class SmartPlug(SmartDevice):
|
|||||||
self,
|
self,
|
||||||
host: str,
|
host: str,
|
||||||
protocol: "TPLinkSmartHomeProtocol" = None,
|
protocol: "TPLinkSmartHomeProtocol" = None,
|
||||||
context: str = None,
|
child_id: str = None,
|
||||||
cache_ttl: int = 3,
|
cache_ttl: int = 3,
|
||||||
*,
|
*,
|
||||||
ioloop=None,
|
ioloop=None,
|
||||||
) -> None:
|
) -> None:
|
||||||
SmartDevice.__init__(self, host, protocol, context, cache_ttl, ioloop=ioloop)
|
SmartDevice.__init__(self, host, protocol, child_id, cache_ttl, ioloop=ioloop)
|
||||||
self.emeter_type = "emeter"
|
self.emeter_type = "emeter"
|
||||||
self._device_type = DeviceType.Plug
|
self._device_type = DeviceType.Plug
|
||||||
|
|
||||||
@ -90,12 +90,6 @@ class SmartPlug(SmartDevice):
|
|||||||
else:
|
else:
|
||||||
raise ValueError("Brightness value %s is not valid." % value)
|
raise ValueError("Brightness value %s is not valid." % value)
|
||||||
|
|
||||||
def _get_child_info(self):
|
|
||||||
for plug in self.sys_info["children"]:
|
|
||||||
if plug["id"] == self.context:
|
|
||||||
return plug
|
|
||||||
raise SmartDeviceException("Unable to find children %s")
|
|
||||||
|
|
||||||
@property # type: ignore
|
@property # type: ignore
|
||||||
@requires_update
|
@requires_update
|
||||||
def alias(self) -> str:
|
def alias(self) -> str:
|
||||||
@ -104,7 +98,7 @@ class SmartPlug(SmartDevice):
|
|||||||
:return: Device name aka alias.
|
:return: Device name aka alias.
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
if self.context:
|
if self.is_child_device:
|
||||||
info = self._get_child_info()
|
info = self._get_child_info()
|
||||||
return info["alias"]
|
return info["alias"]
|
||||||
else:
|
else:
|
||||||
@ -140,7 +134,7 @@ class SmartPlug(SmartDevice):
|
|||||||
|
|
||||||
:return: True if device is on, False otherwise
|
:return: True if device is on, False otherwise
|
||||||
"""
|
"""
|
||||||
if self.context:
|
if self.is_child_device:
|
||||||
info = self._get_child_info()
|
info = self._get_child_info()
|
||||||
return info["state"]
|
return info["state"]
|
||||||
|
|
||||||
@ -192,7 +186,7 @@ class SmartPlug(SmartDevice):
|
|||||||
:rtype: datetime
|
:rtype: datetime
|
||||||
"""
|
"""
|
||||||
sys_info = self.sys_info
|
sys_info = self.sys_info
|
||||||
if self.context:
|
if self.is_child_device:
|
||||||
info = self._get_child_info()
|
info = self._get_child_info()
|
||||||
on_time = info["on_time"]
|
on_time = info["on_time"]
|
||||||
else:
|
else:
|
||||||
|
@ -79,7 +79,7 @@ class SmartStrip(SmartPlug):
|
|||||||
SmartPlug(
|
SmartPlug(
|
||||||
self.host,
|
self.host,
|
||||||
self.protocol,
|
self.protocol,
|
||||||
context=child["id"],
|
child_id=child["id"],
|
||||||
cache_ttl=self.cache_ttl.total_seconds(),
|
cache_ttl=self.cache_ttl.total_seconds(),
|
||||||
ioloop=self.ioloop,
|
ioloop=self.ioloop,
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user