Skip to content

Add iot brightness feature #808

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions kasa/iot/iotbulb.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from ..bulb import HSV, Bulb, BulbPreset, ColorTempRange
from ..device_type import DeviceType
from ..deviceconfig import DeviceConfig
from ..feature import Feature, FeatureType
from ..protocol import BaseProtocol
from .iotdevice import IotDevice, KasaException, requires_update
from .modules import Antitheft, Cloud, Countdown, Emeter, Schedule, Time, Usage
Expand Down Expand Up @@ -204,6 +205,22 @@ def __init__(
self.add_module("countdown", Countdown(self, "countdown"))
self.add_module("cloud", Cloud(self, "smartlife.iot.common.cloud"))

async def _initialize_features(self):
await super()._initialize_features()

if bool(self.sys_info["is_dimmable"]): # pragma: no branch
Copy link
Member

@rytilahti rytilahti Mar 6, 2024

Choose a reason for hiding this comment

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

Perhaps we could check for is_dimmable and brightness already in the iotdevice's initialization, to avoid separate handling in iotbulb and iotdimmer?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The reason for keeping this on the iotbulb and iotdimmer is because brightness and set_brightness don't exist on the iotdevice so setting them as attribute_getter etc seemed flaky. It also kept the logic of which thing to check contained in each class because the dimmer and bulb check for is_dimmable and brightness elsewhere. What do you think?

Copy link
Member

@rytilahti rytilahti Mar 6, 2024

Choose a reason for hiding this comment

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

Fair enough 👍 I'm wondering if we should have a set of standard actions that we can "plug" in, with standardized getter/setter/icon/names to avoid repeating ourselves for cases like power/brightness/color_temp/color etc. that are common across all devices and families?

self._add_feature(
Feature(
device=self,
name="Brightness",
attribute_getter="brightness",
attribute_setter="set_brightness",
minimum_value=1,
maximum_value=100,
type=FeatureType.Number,
)
)

@property # type: ignore
@requires_update
def is_color(self) -> bool:
Expand Down
17 changes: 17 additions & 0 deletions kasa/iot/iotdimmer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from ..device_type import DeviceType
from ..deviceconfig import DeviceConfig
from ..feature import Feature, FeatureType
from ..protocol import BaseProtocol
from .iotdevice import KasaException, requires_update
from .iotplug import IotPlug
Expand Down Expand Up @@ -80,6 +81,22 @@ def __init__(
self.add_module("motion", Motion(self, "smartlife.iot.PIR"))
self.add_module("ambient", AmbientLight(self, "smartlife.iot.LAS"))

async def _initialize_features(self):
await super()._initialize_features()

if "brightness" in self.sys_info: # pragma: no branch
self._add_feature(
Feature(
device=self,
name="Brightness",
attribute_getter="brightness",
attribute_setter="set_brightness",
minimum_value=1,
maximum_value=100,
type=FeatureType.Number,
)
)

@property # type: ignore
@requires_update
def brightness(self) -> int:
Expand Down
3 changes: 3 additions & 0 deletions kasa/iot/iotplug.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ def __init__(
self.add_module("time", Time(self, "time"))
self.add_module("cloud", Cloud(self, "cnCloud"))

async def _initialize_features(self):
await super()._initialize_features()

self._add_feature(
Feature(
device=self,
Expand Down
25 changes: 24 additions & 1 deletion kasa/tests/test_feature_brightness.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import pytest

from kasa.iot import IotDevice
from kasa.smart import SmartDevice
from kasa.tests.conftest import parametrize
from kasa.tests.conftest import dimmable, parametrize

brightness = parametrize("brightness smart", component_filter="brightness")

Expand All @@ -26,3 +27,25 @@ async def test_brightness_component(dev: SmartDevice):

with pytest.raises(ValueError):
await feature.set_value(feature.maximum_value + 10)


@dimmable
async def test_brightness_dimmable(dev: SmartDevice):
"""Test brightness feature."""
assert isinstance(dev, IotDevice)
assert "brightness" in dev.sys_info or bool(dev.sys_info["is_dimmable"])

# Test getting the value
feature = dev.features["brightness"]
assert isinstance(feature.value, int)
assert feature.value > 0 and feature.value <= 100

# Test setting the value
await feature.set_value(10)
assert feature.value == 10

with pytest.raises(ValueError):
await feature.set_value(feature.minimum_value - 10)

with pytest.raises(ValueError):
await feature.set_value(feature.maximum_value + 10)