2024-10-24 16:22:45 +00:00
|
|
|
"""Base implementation for SMART modules."""
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
import logging
|
2024-11-15 10:19:40 +00:00
|
|
|
from typing import TYPE_CHECKING, Any, Final, cast
|
2024-10-24 16:22:45 +00:00
|
|
|
|
|
|
|
from ..exceptions import DeviceError, KasaException, SmartErrorCode
|
2024-11-15 10:19:40 +00:00
|
|
|
from ..modulemapping import ModuleName
|
2024-10-24 16:22:45 +00:00
|
|
|
from ..smart.smartmodule import SmartModule
|
|
|
|
|
|
|
|
if TYPE_CHECKING:
|
2024-11-15 10:19:40 +00:00
|
|
|
from . import modules
|
2024-11-23 08:07:47 +00:00
|
|
|
from .smartcamdevice import SmartCamDevice
|
2024-10-24 16:22:45 +00:00
|
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2024-11-23 08:07:47 +00:00
|
|
|
class SmartCamModule(SmartModule):
|
|
|
|
"""Base class for SMARTCAM modules."""
|
2024-10-24 16:22:45 +00:00
|
|
|
|
2024-11-23 08:07:47 +00:00
|
|
|
SmartCamAlarm: Final[ModuleName[modules.Alarm]] = ModuleName("SmartCamAlarm")
|
2024-12-19 23:22:08 +00:00
|
|
|
SmartCamMotionDetection: Final[ModuleName[modules.MotionDetection]] = ModuleName(
|
|
|
|
"MotionDetection"
|
|
|
|
)
|
|
|
|
SmartCamPersonDetection: Final[ModuleName[modules.PersonDetection]] = ModuleName(
|
|
|
|
"PersonDetection"
|
|
|
|
)
|
|
|
|
SmartCamTamperDetection: Final[ModuleName[modules.TamperDetection]] = ModuleName(
|
|
|
|
"TamperDetection"
|
|
|
|
)
|
|
|
|
SmartCamBabyCryDetection: Final[ModuleName[modules.BabyCryDetection]] = ModuleName(
|
|
|
|
"BabyCryDetection"
|
|
|
|
)
|
2024-11-15 10:19:40 +00:00
|
|
|
|
2024-12-20 06:16:18 +00:00
|
|
|
SmartCamDeviceModule: Final[ModuleName[modules.DeviceModule]] = ModuleName(
|
|
|
|
"devicemodule"
|
|
|
|
)
|
|
|
|
|
2024-10-24 16:22:45 +00:00
|
|
|
#: Module name to be queried
|
|
|
|
QUERY_MODULE_NAME: str
|
|
|
|
#: Section name or names to be queried
|
2024-11-15 10:19:40 +00:00
|
|
|
QUERY_SECTION_NAMES: str | list[str] | None = None
|
2024-10-24 16:22:45 +00:00
|
|
|
|
|
|
|
REGISTERED_MODULES = {}
|
|
|
|
|
2024-11-23 08:07:47 +00:00
|
|
|
_device: SmartCamDevice
|
2024-10-24 16:22:45 +00:00
|
|
|
|
|
|
|
def query(self) -> dict:
|
|
|
|
"""Query to execute during the update cycle.
|
|
|
|
|
|
|
|
Default implementation uses the raw query getter w/o parameters.
|
|
|
|
"""
|
2024-12-13 19:45:38 +00:00
|
|
|
if not self.QUERY_GETTER_NAME:
|
|
|
|
return {}
|
2024-11-15 10:19:40 +00:00
|
|
|
section_names = (
|
|
|
|
{"name": self.QUERY_SECTION_NAMES} if self.QUERY_SECTION_NAMES else {}
|
|
|
|
)
|
|
|
|
return {self.QUERY_GETTER_NAME: {self.QUERY_MODULE_NAME: section_names}}
|
2024-10-24 16:22:45 +00:00
|
|
|
|
|
|
|
async def call(self, method: str, params: dict | None = None) -> dict:
|
|
|
|
"""Call a method.
|
|
|
|
|
|
|
|
Just a helper method.
|
|
|
|
"""
|
|
|
|
if params:
|
|
|
|
module = next(iter(params))
|
|
|
|
section = next(iter(params[module]))
|
|
|
|
else:
|
|
|
|
module = "system"
|
|
|
|
section = "null"
|
|
|
|
|
|
|
|
if method[:3] == "get":
|
|
|
|
return await self._device._query_getter_helper(method, module, section)
|
|
|
|
|
2024-10-24 18:11:21 +00:00
|
|
|
if TYPE_CHECKING:
|
|
|
|
params = cast(dict[str, dict[str, Any]], params)
|
|
|
|
return await self._device._query_setter_helper(
|
|
|
|
method, module, section, params[module][section]
|
|
|
|
)
|
2024-10-24 16:22:45 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def data(self) -> dict:
|
|
|
|
"""Return response data for the module."""
|
|
|
|
dev = self._device
|
|
|
|
q = self.query()
|
|
|
|
|
|
|
|
if not q:
|
|
|
|
return dev.sys_info
|
|
|
|
|
|
|
|
if len(q) == 1:
|
|
|
|
query_resp = dev._last_update.get(self.QUERY_GETTER_NAME, {})
|
|
|
|
if isinstance(query_resp, SmartErrorCode):
|
|
|
|
raise DeviceError(
|
|
|
|
f"Error accessing module data in {self._module}",
|
2024-11-13 10:21:12 +00:00
|
|
|
error_code=query_resp,
|
2024-10-24 16:22:45 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
if not query_resp:
|
|
|
|
raise KasaException(
|
|
|
|
f"You need to call update() prior accessing module data"
|
|
|
|
f" for '{self._module}'"
|
|
|
|
)
|
|
|
|
|
2024-12-13 19:45:38 +00:00
|
|
|
# Some calls return the data under the module, others not
|
|
|
|
return query_resp.get(self.QUERY_MODULE_NAME, query_resp)
|
2024-10-24 16:22:45 +00:00
|
|
|
else:
|
|
|
|
found = {key: val for key, val in dev._last_update.items() if key in q}
|
|
|
|
for key in q:
|
|
|
|
if key not in found:
|
|
|
|
raise KasaException(
|
|
|
|
f"{key} not found, you need to call update() prior accessing"
|
|
|
|
f" module data for '{self._module}'"
|
|
|
|
)
|
|
|
|
if isinstance(found[key], SmartErrorCode):
|
|
|
|
raise DeviceError(
|
|
|
|
f"Error accessing module data {key} in {self._module}",
|
2024-11-13 10:21:12 +00:00
|
|
|
error_code=found[key],
|
2024-10-24 16:22:45 +00:00
|
|
|
)
|
|
|
|
return found
|