FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Modularize smartdevice by rytilahti · Pull Request #713 · python-kasa/python-kasa · GitHub

Repository navigation

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .py  (21) All 1 file type selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
5 changes: 5 additions & 0 deletions kasa/cli.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,11 @@ async def state(ctx, dev: Device):
for module in dev.modules.values():
if module.is_supported:
echo(f"\t[green]+ {module}[/green]")
# TODO: fix this hack, probably with descriptors?
if pretty_print := getattr(module, "__cli_output__", None):
echo(f"\t\t{pretty_print()}")
else:
echo(f"\t\t{pf(module.data)}")
else:
echo(f"\t[red]- {module}[/red]")

Expand Down
3 changes: 2 additions & 1 deletion kasa/iot/iotdevice.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
from ..exceptions import SmartDeviceException
from ..feature import Feature
from ..protocol import BaseProtocol
from .modules import Emeter, IotModule
from .iotmodule import IotModule
from .modules import Emeter

_LOGGER = logging.getLogger(__name__)

Expand Down
60 changes: 16 additions & 44 deletions kasa/iot/modules/module.py → kasa/iot/iotmodule.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
"""Base class for all module implementations."""
"""Base class for IOT module implementations."""
import collections
import logging
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Dict

from ...exceptions import SmartDeviceException
from ...feature import Feature

if TYPE_CHECKING:
from kasa.iot import IotDevice

from ..exceptions import SmartDeviceException
from ..feature import Feature
from ..module import Module

_LOGGER = logging.getLogger(__name__)


# TODO: This is used for query construcing
# TODO: This is used for query constructing, check for a better place
def merge(d, u):
"""Update dict recursively."""
for k, v in u.items():
Expand All @@ -25,33 +20,16 @@ def merge(d, u):
return d


class IotModule(ABC):
"""Base class implemention for all modules.

The base classes should implement `query` to return the query they want to be
executed during the regular update cycle.
"""
class IotModule(Module):
"""Base class implemention for all IOT modules."""

def __init__(self, device: "IotDevice", module: str):
self._device = device
self._module = module
self._module_features: Dict[str, Feature] = {}

def _add_feature(self, feature: Feature):
def add_feature(self, feature: Feature):
"""Add module feature."""
feature_name = f"{self._module}_{feature.name}"
if feature_name in self._module_features:
raise SmartDeviceException("Duplicate name detected %s" % feature_name)
self._module_features[feature_name] = feature

@abstractmethod
def query(self):
"""Query to execute during the update cycle.

The inheriting modules implement this to include their wanted
queries to the query that gets executed when Device.update() gets called.
"""

@property
def estimated_query_response_size(self):
"""Estimated maximum size of query response.
Expand All @@ -61,6 +39,14 @@ def estimated_query_response_size(self):
"""
return 256 # Estimate for modules that don't specify

def call(self, method, params=None):
"""Call the given method with the given parameters."""
return self._device._query_helper(self._module, method, params)

def query_for_command(self, query, params=None):
"""Create a request object for the given parameters."""
return self._device._create_request(self._module, query, params)

@property
def data(self):
"""Return the module specific raw data from the last update."""
Expand All @@ -80,17 +66,3 @@ def is_supported(self) -> bool:
return True

return "err_code" not in self.data

def call(self, method, params=None):
"""Call the given method with the given parameters."""
return self._device._query_helper(self._module, method, params)

def query_for_command(self, query, params=None):
"""Create a request object for the given parameters."""
return self._device._create_request(self._module, query, params)

def __repr__(self) -> str:
return (
f"<Module {self.__class__.__name__} ({self._module})"
f" for {self._device.host}>"
)
2 changes: 0 additions & 2 deletions kasa/iot/modules/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from .cloud import Cloud
from .countdown import Countdown
from .emeter import Emeter
from .module import IotModule
from .motion import Motion
from .rulemodule import Rule, RuleModule
from .schedule import Schedule
Expand All @@ -17,7 +16,6 @@
"Cloud",
"Countdown",
"Emeter",
"IotModule",
"Motion",
"Rule",
"RuleModule",
Expand Down
2 changes: 1 addition & 1 deletion kasa/iot/modules/ambientlight.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Implementation of the ambient light (LAS) module found in some dimmers."""
from .module import IotModule
from ..iotmodule import IotModule

# TODO create tests and use the config reply there
# [{"hw_id":0,"enable":0,"dark_index":1,"min_adc":0,"max_adc":2450,
Expand Down
2 changes: 1 addition & 1 deletion kasa/iot/modules/cloud.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from pydantic import BaseModel

from ...feature import Feature, FeatureType
from .module import IotModule
from ..iotmodule import IotModule


class CloudInfo(BaseModel):
Expand Down
2 changes: 1 addition & 1 deletion kasa/iot/modules/motion.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from typing import Optional

from ...exceptions import SmartDeviceException
from .module import IotModule
from ..iotmodule import IotModule


class Range(Enum):
Expand Down
2 changes: 1 addition & 1 deletion kasa/iot/modules/rulemodule.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pydantic import BaseModel


from .module import IotModule, merge
from ..iotmodule import IotModule, merge


class Action(Enum):
Expand Down
2 changes: 1 addition & 1 deletion kasa/iot/modules/time.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from datetime import datetime

from ...exceptions import SmartDeviceException
from .module import IotModule, merge
from ..iotmodule import IotModule, merge


class Time(IotModule):
Expand Down
2 changes: 1 addition & 1 deletion kasa/iot/modules/usage.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from datetime import datetime
from typing import Dict

from .module import IotModule, merge
from ..iotmodule import IotModule, merge


class Usage(IotModule):
Expand Down
53 changes: 53 additions & 0 deletions kasa/module.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""Base class for all module implementations."""
import logging
from abc import ABC, abstractmethod
from typing import Dict

from .device import Device
from .feature import Feature

_LOGGER = logging.getLogger(__name__)


class Module(ABC):
"""Base class implemention for all modules.

The base classes should implement `query` to return the query they want to be
executed during the regular update cycle.
"""

def __init__(self, device: "Device", module: str):
self._device = device
self._module = module
self._module_features: Dict[str, Feature] = {}

def _add_feature(self, feature: Feature):
"""Add module descriptor."""
feat_name = f"{self._module}_{feature.name}"
if feat_name in self._module_features:
raise Exception("Duplicate name detected %s" % feat_name)
self._module_features[feat_name] = feature

@abstractmethod
def query(self):
"""Query to execute during the update cycle.

The inheriting modules implement this to include their wanted
queries to the query that gets executed when Device.update() gets called.
"""

@property
@abstractmethod
def data(self):
"""Return the module specific raw data from the last update."""

@property
@abstractmethod
def is_supported(self) -> bool:
"""Return whether the module is supported by the device."""

def __repr__(self) -> str:
return (
f"<Module {self.__class__.__name__} ({self._module})"
f" for {self._device.host}>"
)
8 changes: 8 additions & 0 deletions kasa/smart/modules/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""SMART modules package."""
from .auto_off import AutoOff
from .device_time import DeviceTime
from .energy_monitoring import EnergyMonitoring
from .led import Led
from .on_off_gradually import OnOffGradually

__all__ = ["DeviceTime", "EnergyMonitoring", "OnOffGradually", "AutoOff", "Led"]
36 changes: 36 additions & 0 deletions kasa/smart/modules/auto_off.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Implementation of auto off module."""
from typing import Dict

from ..smartmodule import SmartModule


class AutoOff(SmartModule):
"""Implementation of auto off module."""

REQUIRED_COMPONENT = "auto_off"
QUERY_GETTER_NAME = "get_auto_off_config"

def query(self) -> Dict:
"""Query to execute during the update cycle."""
return {self.QUERY_GETTER_NAME: {"start_index": 0}}

@property
def enabled(self) -> bool:
"""Return True if enabled."""
return self.data["enable"]

def set_enabled(self, enable: bool):
"""Enable/disable auto off."""
return self.call("set_auto_off_config", {"enable": enable})

@property
def delay(self) -> int:
"""Return time until auto off."""
return self.data["delay_min"]

def set_delay(self, delay: int):
"""Set time until auto off."""
return self.call("set_auto_off_config", {"delay_min": delay})

def __cli_output__(self):
return f"Auto off enabled: {self.enabled} (delay: {self.delay}min)"
41 changes: 41 additions & 0 deletions kasa/smart/modules/default_states.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from enum import Enum

from pydantic import BaseModel, Field

from ..smartmodule import SmartModule


class Type(Enum):
Last = "last_states"
Custom = "custom"


class DefaultStatesModel(BaseModel):
type = Field()
state = Field() # if type is custom, something like {"state": {"on": False}}
"""l530:
{"state": {
"brightness": 100,
"color_temp": 9000,
"hue": 0,
"saturation": 100
}
}
"""

"""L510, type stored inside brightness:
{"brightness": {
"type": "last_states",
"value": 100
}
}
"""
re_power_type = (
Field()
) # seen on L530, "re_power_type": "always_on", KS225 "always_off"
re_power_type_capability: list | None # KS225: ["last_states", "always_on", "always_off"]


class DefaultStates(SmartModule):
QUERY_GETTER_NAME = None
REQUIRED_COMPONENT = "default_states"
42 changes: 42 additions & 0 deletions kasa/smart/modules/device_time.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Implementation of device time module."""
from datetime import datetime, timedelta, timezone
from time import mktime
from typing import TYPE_CHECKING, cast

from ..smartmodule import SmartModule

if TYPE_CHECKING:
pass


class DeviceTime(SmartModule):
"""Implementation of device_local_time."""

REQUIRED_COMPONENT = "device_local_time"
QUERY_GETTER_NAME = "get_device_time"

@property
def time(self) -> datetime:
"""Return device's current datetime."""
td = timedelta(minutes=cast(float, self.data.get("time_diff")))
if self.data.get("region"):
tz = timezone(td, str(self.data.get("region")))
else:
# in case the device returns a blank region this will result in the
# tzname being a UTC offset
tz = timezone(td)
return datetime.fromtimestamp(
cast(float, self.data.get("timestamp")),
tz=tz,
)

async def set_time(self, dt: datetime):
"""Set device time."""
unixtime = mktime(dt.timetuple())
return await self.call(
"set_device_time",
{"timestamp": unixtime, "time_diff": dt.utcoffset(), "region": dt.tzname()},
)

def __cli_output__(self):
return f"Time: {self.time}"
6 changes: 6 additions & 0 deletions kasa/smart/modules/device_usage.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from ..smartmodule import SmartModule


class DeviceUsage(SmartModule):
REQUIRED_COMPONENT = "device"
QUERY_GETTER_NAME = "get_device_usage"
13 changes: 13 additions & 0 deletions kasa/smart/modules/energy_monitoring.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from typing import Dict

from ..smartmodule import SmartModule


class EnergyMonitoring(SmartModule):
REQUIRED_COMPONENT = "energy_monitoring"

def query(self) -> Dict:
return {
"get_energy_usage": None,
"get_current_power": None,
}
Loading

Back | FazBrowse Home | New Git URL