Initial implementation for modularized smartdevice (#757)

The initial steps to modularize the smartdevice. Modules are initialized based on the component negotiation, and each module can indicate which features it supports and which queries should be run during the update cycle.
This commit is contained in:
Teemu R
2024-02-19 18:01:31 +01:00
committed by GitHub
parent e86dcb6bf5
commit 11719991c0
21 changed files with 408 additions and 156 deletions

View File

@@ -24,7 +24,8 @@ from ..emeterstatus import EmeterStatus
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__)

View File

@@ -1,20 +1,14 @@
"""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 ..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():
@@ -25,32 +19,16 @@ def merge(d, u):
return d
class IotModule(ABC):
"""Base class implemention for all modules.
class IotModule(Module):
"""Base class implemention for all IOT modules."""
The base classes should implement `query` to return the query they want to be
executed during the regular update cycle.
"""
def call(self, method, params=None):
"""Call the given method with the given parameters."""
return self._device._query_helper(self._module, method, params)
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):
"""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.
"""
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 estimated_query_response_size(self):
@@ -80,17 +58,3 @@ class IotModule(ABC):
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}>"
)

View File

@@ -4,7 +4,6 @@ from .antitheft import Antitheft
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
@@ -17,7 +16,6 @@ __all__ = [
"Cloud",
"Countdown",
"Emeter",
"IotModule",
"Motion",
"Rule",
"RuleModule",

View File

@@ -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,

View File

@@ -5,7 +5,7 @@ except ImportError:
from pydantic import BaseModel
from ...feature import Feature, FeatureType
from .module import IotModule
from ..iotmodule import IotModule
class CloudInfo(BaseModel):

View File

@@ -3,7 +3,7 @@ from enum import Enum
from typing import Optional
from ...exceptions import SmartDeviceException
from .module import IotModule
from ..iotmodule import IotModule
class Range(Enum):

View File

@@ -9,7 +9,7 @@ except ImportError:
from pydantic import BaseModel
from .module import IotModule, merge
from ..iotmodule import IotModule, merge
class Action(Enum):

View File

@@ -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):

View File

@@ -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):