async++, small powerstrip improvements (#46)

* async++, small powerstrip improvements

* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
  * new powerstrip api: turn_{on,off}_by_{name,index} methods
  * cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'

* update requirements_test.txt

* remove outdated click-datetime, replace click with asyncclick

* debug is a flag

* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties

* proper bound checking for index accesses, allow controlling the plug at index 0

* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.

* adapt cli to use that
* allow changing the alias per index

* use f-strings consistently everywhere in the cli

* add tests for get_plug_by_{index,name}
This commit is contained in:
Teemu R
2020-04-21 20:46:13 +02:00
committed by GitHub
parent 852ae494af
commit 3fe578cf26
11 changed files with 203 additions and 120 deletions

View File

@@ -93,6 +93,22 @@ class SmartStrip(SmartDevice):
await self._query_helper("system", "set_relay_state", {"state": 0})
await self.update()
def get_plug_by_name(self, name: str) -> "SmartStripPlug":
"""Return child plug for given name."""
for p in self.plugs:
if p.alias == name:
return p
raise SmartDeviceException(f"Device has no child with {name}")
def get_plug_by_index(self, index: int) -> "SmartStripPlug":
"""Return child plug for given index."""
if index + 1 > len(self.plugs) or index < 0:
raise SmartDeviceException(
f"Invalid index {index}, device has {len(self.plugs)} plugs"
)
return self.plugs[index]
@property # type: ignore
@requires_update
def on_since(self) -> datetime.datetime:
@@ -107,8 +123,6 @@ class SmartStrip(SmartDevice):
:return: True if led is on, False otherwise
:rtype: bool
"""
# TODO this is a copypaste from smartplug,
# check if led value is per socket or per device..
sys_info = self.sys_info
return bool(1 - sys_info["led_off"])
@@ -118,8 +132,6 @@ class SmartStrip(SmartDevice):
:param bool state: True to set led on, False to set led off
:raises SmartDeviceException: on error
"""
# TODO this is a copypaste from smartplug,
# check if led value is per socket or per device..
await self._query_helper("system", "set_led_off", {"off": int(not state)})
await self.update()
@@ -221,6 +233,8 @@ class SmartStripPlug(SmartPlug):
This allows you to use the sockets as they were SmartPlug objects.
Instead of calling an update on any of these, you should call an update
on the parent device before accessing the properties.
The plug inherits (most of) the system information from the parent.
"""
def __init__(self, host: str, parent: "SmartStrip", child_id: str) -> None:
@@ -228,7 +242,7 @@ class SmartStripPlug(SmartPlug):
self.parent = parent
self.child_id = child_id
self._sys_info = self._get_child_info()
self._sys_info = {**self.parent.sys_info, **self._get_child_info()}
async def update(self):
"""Override the update to no-op and inform the user."""
@@ -268,6 +282,12 @@ class SmartStripPlug(SmartPlug):
"""
return False
@property # type: ignore
@requires_update
def has_emeter(self) -> bool:
"""Children have no emeter to my knowledge."""
return False
@property # type: ignore
@requires_update
def device_id(self) -> str:
@@ -288,6 +308,13 @@ class SmartStripPlug(SmartPlug):
info = self._get_child_info()
return info["alias"]
@property # type: ignore
@requires_update
def next_action(self) -> Dict:
"""Return next scheduled(?) action."""
info = self._get_child_info()
return info["next_action"]
@property # type: ignore
@requires_update
def on_since(self) -> datetime.datetime: