2024-02-19 17:01:31 +00:00
|
|
|
"""Base class for all module implementations."""
|
2024-04-16 18:21:20 +00:00
|
|
|
|
2024-04-17 13:39:24 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2024-02-19 17:01:31 +00:00
|
|
|
import logging
|
|
|
|
from abc import ABC, abstractmethod
|
2024-05-03 15:01:21 +00:00
|
|
|
from typing import (
|
|
|
|
TYPE_CHECKING,
|
2024-05-10 18:29:28 +00:00
|
|
|
Final,
|
2024-05-03 15:01:21 +00:00
|
|
|
TypeVar,
|
|
|
|
)
|
2024-02-19 17:01:31 +00:00
|
|
|
|
2024-02-21 15:52:55 +00:00
|
|
|
from .exceptions import KasaException
|
2024-02-19 17:01:31 +00:00
|
|
|
from .feature import Feature
|
2024-05-10 18:29:28 +00:00
|
|
|
from .modulemapping import ModuleName
|
2024-02-19 17:01:31 +00:00
|
|
|
|
2024-04-29 16:34:20 +00:00
|
|
|
if TYPE_CHECKING:
|
2024-05-13 16:34:44 +00:00
|
|
|
from . import interfaces
|
2024-05-11 18:28:18 +00:00
|
|
|
from .device import Device
|
2024-05-10 18:29:28 +00:00
|
|
|
from .iot import modules as iot
|
|
|
|
from .smart import modules as smart
|
2024-04-29 16:34:20 +00:00
|
|
|
|
2024-02-19 17:01:31 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
2024-05-03 15:01:21 +00:00
|
|
|
ModuleT = TypeVar("ModuleT", bound="Module")
|
|
|
|
|
2024-02-19 17:01:31 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
"""
|
|
|
|
|
2024-05-10 18:29:28 +00:00
|
|
|
# Common Modules
|
2024-06-17 10:22:05 +00:00
|
|
|
Energy: Final[ModuleName[interfaces.Energy]] = ModuleName("Energy")
|
|
|
|
Fan: Final[ModuleName[interfaces.Fan]] = ModuleName("Fan")
|
2024-05-13 16:34:44 +00:00
|
|
|
LightEffect: Final[ModuleName[interfaces.LightEffect]] = ModuleName("LightEffect")
|
|
|
|
Led: Final[ModuleName[interfaces.Led]] = ModuleName("Led")
|
|
|
|
Light: Final[ModuleName[interfaces.Light]] = ModuleName("Light")
|
2024-05-19 10:20:18 +00:00
|
|
|
LightPreset: Final[ModuleName[interfaces.LightPreset]] = ModuleName("LightPreset")
|
2024-05-10 18:29:28 +00:00
|
|
|
|
|
|
|
# IOT only Modules
|
|
|
|
IotAmbientLight: Final[ModuleName[iot.AmbientLight]] = ModuleName("ambient")
|
|
|
|
IotAntitheft: Final[ModuleName[iot.Antitheft]] = ModuleName("anti_theft")
|
|
|
|
IotCountdown: Final[ModuleName[iot.Countdown]] = ModuleName("countdown")
|
|
|
|
IotMotion: Final[ModuleName[iot.Motion]] = ModuleName("motion")
|
|
|
|
IotSchedule: Final[ModuleName[iot.Schedule]] = ModuleName("schedule")
|
|
|
|
IotUsage: Final[ModuleName[iot.Usage]] = ModuleName("usage")
|
|
|
|
IotCloud: Final[ModuleName[iot.Cloud]] = ModuleName("cloud")
|
|
|
|
IotTime: Final[ModuleName[iot.Time]] = ModuleName("time")
|
|
|
|
|
|
|
|
# SMART only Modules
|
2024-05-11 18:28:18 +00:00
|
|
|
Alarm: Final[ModuleName[smart.Alarm]] = ModuleName("Alarm")
|
|
|
|
AutoOff: Final[ModuleName[smart.AutoOff]] = ModuleName("AutoOff")
|
2024-05-10 18:29:28 +00:00
|
|
|
BatterySensor: Final[ModuleName[smart.BatterySensor]] = ModuleName("BatterySensor")
|
|
|
|
Brightness: Final[ModuleName[smart.Brightness]] = ModuleName("Brightness")
|
2024-05-11 18:28:18 +00:00
|
|
|
ChildDevice: Final[ModuleName[smart.ChildDevice]] = ModuleName("ChildDevice")
|
|
|
|
Cloud: Final[ModuleName[smart.Cloud]] = ModuleName("Cloud")
|
|
|
|
Color: Final[ModuleName[smart.Color]] = ModuleName("Color")
|
|
|
|
ColorTemperature: Final[ModuleName[smart.ColorTemperature]] = ModuleName(
|
|
|
|
"ColorTemperature"
|
2024-05-10 18:29:28 +00:00
|
|
|
)
|
|
|
|
ContactSensor: Final[ModuleName[smart.ContactSensor]] = ModuleName("ContactSensor")
|
2024-05-11 18:28:18 +00:00
|
|
|
DeviceModule: Final[ModuleName[smart.DeviceModule]] = ModuleName("DeviceModule")
|
2024-05-10 18:29:28 +00:00
|
|
|
Firmware: Final[ModuleName[smart.Firmware]] = ModuleName("Firmware")
|
2024-05-11 18:28:18 +00:00
|
|
|
FrostProtection: Final[ModuleName[smart.FrostProtection]] = ModuleName(
|
|
|
|
"FrostProtection"
|
|
|
|
)
|
|
|
|
HumiditySensor: Final[ModuleName[smart.HumiditySensor]] = ModuleName(
|
|
|
|
"HumiditySensor"
|
2024-05-10 18:29:28 +00:00
|
|
|
)
|
2024-05-11 18:28:18 +00:00
|
|
|
LightTransition: Final[ModuleName[smart.LightTransition]] = ModuleName(
|
|
|
|
"LightTransition"
|
2024-05-10 18:29:28 +00:00
|
|
|
)
|
2024-05-11 18:28:18 +00:00
|
|
|
ReportMode: Final[ModuleName[smart.ReportMode]] = ModuleName("ReportMode")
|
|
|
|
TemperatureSensor: Final[ModuleName[smart.TemperatureSensor]] = ModuleName(
|
2024-05-10 18:29:28 +00:00
|
|
|
"TemperatureSensor"
|
|
|
|
)
|
2024-05-11 18:28:18 +00:00
|
|
|
TemperatureControl: Final[ModuleName[smart.TemperatureControl]] = ModuleName(
|
2024-05-10 18:29:28 +00:00
|
|
|
"TemperatureControl"
|
|
|
|
)
|
2024-05-11 18:28:18 +00:00
|
|
|
Time: Final[ModuleName[smart.Time]] = ModuleName("Time")
|
2024-05-10 18:29:28 +00:00
|
|
|
WaterleakSensor: Final[ModuleName[smart.WaterleakSensor]] = ModuleName(
|
|
|
|
"WaterleakSensor"
|
|
|
|
)
|
|
|
|
|
2024-05-11 18:28:18 +00:00
|
|
|
def __init__(self, device: Device, module: str):
|
2024-02-19 17:01:31 +00:00
|
|
|
self._device = device
|
|
|
|
self._module = module
|
2024-04-17 13:39:24 +00:00
|
|
|
self._module_features: dict[str, Feature] = {}
|
2024-02-19 17:01:31 +00:00
|
|
|
|
|
|
|
@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."""
|
|
|
|
|
2024-04-30 06:56:09 +00:00
|
|
|
def _initialize_features(self): # noqa: B027
|
|
|
|
"""Initialize features after the initial update.
|
|
|
|
|
|
|
|
This can be implemented if features depend on module query responses.
|
2024-05-19 09:18:17 +00:00
|
|
|
It will only be called once per module and will always be called
|
|
|
|
after *_post_update_hook* has been called for every device module and its
|
|
|
|
children's modules.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def _post_update_hook(self): # noqa: B027
|
|
|
|
"""Perform actions after a device update.
|
|
|
|
|
|
|
|
This can be implemented if a module needs to perform actions each time
|
|
|
|
the device has updated like generating collections for property access.
|
|
|
|
It will be called after every update and will be called prior to
|
|
|
|
*_initialize_features* on the first update.
|
2024-04-30 06:56:09 +00:00
|
|
|
"""
|
|
|
|
|
2024-02-19 17:01:31 +00:00
|
|
|
def _add_feature(self, feature: Feature):
|
|
|
|
"""Add module feature."""
|
2024-05-07 09:13:35 +00:00
|
|
|
id_ = feature.id
|
|
|
|
if id_ in self._module_features:
|
|
|
|
raise KasaException("Duplicate id detected %s" % id_)
|
|
|
|
self._module_features[id_] = feature
|
2024-02-19 17:01:31 +00:00
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
return (
|
|
|
|
f"<Module {self.__class__.__name__} ({self._module})"
|
|
|
|
f" for {self._device.host}>"
|
|
|
|
)
|