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

Add WhiteLamp SmartCam module for outdoor cameras (e.g. C325WB) by ijardillier · Pull Request #1713 · python-kasa/python-kasa · GitHub

Repository navigation

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

Filter by extension

Filter by extension .json  (1) .md  (1) .py  (6) All 3 file types 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
1 change: 1 addition & 0 deletions SUPPORTED.md
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 @@ -333,6 +333,7 @@ All Tapo devices require authentication.<br>Hub-Connected Devices may work acros
- Hardware: 2.0 (US) / Firmware: 1.0.11
- **C325WB**
- Hardware: 1.0 (EU) / Firmware: 1.1.17
- Hardware: 1.0 (EU) / Firmware: 1.4.4
- **C460**
- Hardware: 1.0 (CA) / Firmware: 1.2.0
- **C520WS**
Expand Down
1 change: 1 addition & 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
Expand Up @@ -174,6 +174,7 @@ class Module(ABC):
Camera: Final[ModuleName[smartcam.Camera]] = ModuleName("Camera")
LensMask: Final[ModuleName[smartcam.LensMask]] = ModuleName("LensMask")
PanTilt: Final[ModuleName[smartcam.PanTilt]] = ModuleName("PanTilt")
FloodLight: Final[ModuleName[smartcam.FloodLight]] = ModuleName("FloodLight")

# Vacuum modules
Clean: Final[ModuleName[smart.Clean]] = ModuleName("Clean")
Expand Down
2 changes: 2 additions & 0 deletions kasa/smartcam/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 @@ -8,6 +8,7 @@
from .childdevice import ChildDevice
from .childsetup import ChildSetup
from .device import DeviceModule
from .floodlight import FloodLight
from .glassdetection import GlassDetection
from .homekit import HomeKit
from .lastalertdetection import LastAlertDetection
Expand All @@ -33,6 +34,7 @@
"ChildDevice",
"ChildSetup",
"DeviceModule",
"FloodLight",
"GlassDetection",
"LastAlertDetection",
"Led",
Expand Down
160 changes: 160 additions & 0 deletions kasa/smartcam/modules/floodlight.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,160 @@
"""Module for floodlight controls ("whitelamp" module) on Tapo outdoor cameras."""

from __future__ import annotations

from typing import Annotated

from ...exceptions import KasaException
from ...feature import Feature
from ...interfaces.light import HSV, LightState
from ...interfaces.light import Light as LightInterface
from ...module import FeatureAttribute
from ...smart.smartmodule import allow_update_after
from ..smartcammodule import SmartCamModule


class FloodLight(SmartCamModule, LightInterface):
"""Implementation of floodlight controls for outdoor cameras."""

REQUIRED_COMPONENT = "whiteLamp"

QUERY_GETTER_NAME = "getWhitelampStatus"
QUERY_MODULE_NAME = "image"

def query(self) -> dict:
"""Query to execute during the update cycle."""
q = super().query()
q["getWhitelampStatus"] = {self.QUERY_MODULE_NAME: {"get_wtl_status": ["null"]}}
q["getWhitelampConfig"] = {self.QUERY_MODULE_NAME: {"name": "switch"}}
return q

def _initialize_features(self) -> None:
"""Initialize features after the initial update."""
self._add_feature(
Feature(
self._device,
id="floodlight",
name="Floodlight",
container=self,
attribute_getter="is_on",
attribute_setter="set_on",
type=Feature.Type.Switch,
category=Feature.Category.Primary,
)
)
if self._is_dimmable:
self._add_feature(
Feature(
self._device,
id="floodlight_brightness",
name="Floodlight brightness",
container=self,
attribute_getter="brightness",
attribute_setter="set_brightness",
range_getter=lambda: (1, 100),
type=Feature.Type.Number,
category=Feature.Category.Config,
)
)

@property
def _config(self) -> dict:
return self.data["getWhitelampConfig"]["image"]["switch"]

@property
def _is_dimmable(self) -> bool:
return "wtl_intensity_level" in self._config

@property
def is_on(self) -> bool:
"""Return whether the floodlight is on."""
return int(self.data["getWhitelampStatus"]["status"]) == 1

@allow_update_after
async def set_on(self, on: bool) -> dict:
"""Turn the floodlight on or off."""
if self.is_on != on:
return await self.call(
"reverseWhitelampStatus", {"image": {"reverse_wtl_status": ["null"]}}
)
return {}

@property
def brightness(self) -> Annotated[int, FeatureAttribute()]:
"""Return the current brightness in percentage."""
if not self._is_dimmable:
raise KasaException("Floodlight is not dimmable.")

return int(self._config["wtl_intensity_level"])

@allow_update_after
async def set_brightness(
self, brightness: int, *, transition: int | None = None
) -> Annotated[dict, FeatureAttribute()]:
"""Set the brightness in percentage.

Note, transition is not supported and will be ignored.

:param int brightness: brightness in percent
:param int transition: transition in milliseconds.
"""
if not self._is_dimmable:
raise KasaException("Floodlight is not dimmable.")

return await self._device._query_setter_helper(
"setWhitelampConfig",
self.QUERY_MODULE_NAME,
"switch",
{"wtl_intensity_level": str(brightness)},
)

@property
def hsv(self) -> Annotated[HSV, FeatureAttribute()]:
"""Return the current HSV state of the light."""
raise KasaException("Floodlight does not support color.")

@property
def color_temp(self) -> Annotated[int, FeatureAttribute()]:
"""Return the current color temperature."""
raise KasaException("Floodlight does not support colortemp.")

async def set_hsv(
self,
hue: int,
saturation: int,
value: int | None = None,
*,
transition: int | None = None,
) -> Annotated[dict, FeatureAttribute()]:
"""Set new HSV."""
raise KasaException("Floodlight does not support color.")

async def set_color_temp(
self, temp: int, *, brightness: int | None = None, transition: int | None = None
) -> Annotated[dict, FeatureAttribute()]:
"""Set the color temperature."""
raise KasaException("Floodlight does not support colortemp.")

@property
def state(self) -> LightState:
"""Return the current light state."""
state = LightState(light_on=self.is_on)
if self._is_dimmable:
state.brightness = self.brightness
return state

async def set_state(self, state: LightState) -> dict:
"""Set the light state."""
# brightness of 0 turns off the light, it's not a valid brightness
if state.brightness == 0:
return await self.set_on(False)

res: dict = {}
if state.brightness is not None:
res.update(await self.set_brightness(state.brightness))
light_on = state.light_on
if light_on is None and state.brightness is not None:
light_on = True
if light_on is not None:
res.update(await self.set_on(light_on))
return res
2 changes: 2 additions & 0 deletions kasa/smartcam/smartcammodule.py

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I am not sure what is going on here, newline separator changes?

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 @@ -62,6 +62,8 @@ class SmartCamModule(SmartModule):
"devicemodule"
)

SmartCamFloodLight: Final[ModuleName[modules.FloodLight]] = ModuleName("FloodLight")

#: Module name to be queried
QUERY_MODULE_NAME: str
#: Section name or names to be queried
Expand Down
6 changes: 6 additions & 0 deletions tests/fakeprotocol_smartcam.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 @@ -363,6 +363,12 @@ async def _send_request(self, request_dict: dict):
return {"error_code": -1}
elif method == "removeChildDeviceList":
return self._hub_remove_device(info, request_dict["params"]["childControl"])
elif method == "reverseWhitelampStatus":
if "getWhitelampStatus" in info:
info["getWhitelampStatus"]["status"] = (
0 if info["getWhitelampStatus"]["status"] == 1 else 1
)
return {"result": {}, "error_code": 0}
# actions
elif method in [
"addScanChildDeviceList",
Expand Down
Loading
Loading

Back | FazBrowse Home | New Git URL