Rename bulb interface to light and move fan and light interface to interfaces (#910)

Also rename BulbPreset to LightPreset.
This commit is contained in:
Steven B 2024-05-11 19:40:08 +01:00 committed by GitHub
parent f259a8f162
commit d7b00336f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 59 additions and 44 deletions

View File

@ -16,7 +16,6 @@ from importlib.metadata import version
from typing import TYPE_CHECKING
from warnings import warn
from kasa.bulb import Bulb, BulbPreset
from kasa.credentials import Credentials
from kasa.device import Device
from kasa.device_type import DeviceType
@ -36,6 +35,7 @@ from kasa.exceptions import (
UnsupportedDeviceError,
)
from kasa.feature import Feature
from kasa.interfaces.light import Light, LightPreset
from kasa.iotprotocol import (
IotProtocol,
_deprecated_TPLinkSmartHomeProtocol, # noqa: F401
@ -52,14 +52,14 @@ __all__ = [
"BaseProtocol",
"IotProtocol",
"SmartProtocol",
"BulbPreset",
"LightPreset",
"TurnOnBehaviors",
"TurnOnBehavior",
"DeviceType",
"Feature",
"EmeterStatus",
"Device",
"Bulb",
"Light",
"Plug",
"Module",
"KasaException",
@ -84,7 +84,7 @@ deprecated_smart_devices = {
"SmartLightStrip": iot.IotLightStrip,
"SmartStrip": iot.IotStrip,
"SmartDimmer": iot.IotDimmer,
"SmartBulbPreset": BulbPreset,
"SmartBulbPreset": LightPreset,
}
deprecated_exceptions = {
"SmartDeviceException": KasaException,
@ -124,7 +124,7 @@ if TYPE_CHECKING:
SmartLightStrip = iot.IotLightStrip
SmartStrip = iot.IotStrip
SmartDimmer = iot.IotDimmer
SmartBulbPreset = BulbPreset
SmartBulbPreset = LightPreset
SmartDeviceException = KasaException
UnsupportedDeviceException = UnsupportedDeviceError

View File

@ -18,7 +18,6 @@ from pydantic.v1 import ValidationError
from kasa import (
AuthenticationError,
Bulb,
ConnectionType,
Credentials,
Device,
@ -28,6 +27,7 @@ from kasa import (
EncryptType,
Feature,
KasaException,
Light,
UnsupportedDeviceError,
)
from kasa.discover import DiscoveryResult
@ -859,7 +859,7 @@ async def usage(dev: Device, year, month, erase):
@click.argument("brightness", type=click.IntRange(0, 100), default=None, required=False)
@click.option("--transition", type=int, required=False)
@pass_dev
async def brightness(dev: Bulb, brightness: int, transition: int):
async def brightness(dev: Light, brightness: int, transition: int):
"""Get or set brightness."""
if not dev.is_dimmable:
echo("This device does not support brightness.")
@ -879,7 +879,7 @@ async def brightness(dev: Bulb, brightness: int, transition: int):
)
@click.option("--transition", type=int, required=False)
@pass_dev
async def temperature(dev: Bulb, temperature: int, transition: int):
async def temperature(dev: Light, temperature: int, transition: int):
"""Get or set color temperature."""
if not dev.is_variable_color_temp:
echo("Device does not support color temperature")

View File

@ -0,0 +1,14 @@
"""Package for interfaces."""
from .fan import Fan
from .led import Led
from .light import Light, LightPreset
from .lighteffect import LightEffect
__all__ = [
"Fan",
"Led",
"Light",
"LightEffect",
"LightPreset",
]

View File

@ -4,7 +4,7 @@ from __future__ import annotations
from abc import ABC, abstractmethod
from .device import Device
from ..device import Device
class Fan(Device, ABC):

View File

@ -7,7 +7,7 @@ from typing import NamedTuple, Optional
from pydantic.v1 import BaseModel
from .device import Device
from ..device import Device
class ColorTempRange(NamedTuple):
@ -25,8 +25,8 @@ class HSV(NamedTuple):
value: int
class BulbPreset(BaseModel):
"""Bulb configuration preset."""
class LightPreset(BaseModel):
"""Light configuration preset."""
index: int
brightness: int
@ -42,8 +42,8 @@ class BulbPreset(BaseModel):
mode: Optional[int] # noqa: UP007
class Bulb(Device, ABC):
"""Base class for TP-Link Bulb."""
class Light(Device, ABC):
"""Base class for TP-Link Light."""
def _raise_for_invalid_brightness(self, value):
if not isinstance(value, int) or not (0 <= value <= 100):
@ -135,5 +135,5 @@ class Bulb(Device, ABC):
@property
@abstractmethod
def presets(self) -> list[BulbPreset]:
def presets(self) -> list[LightPreset]:
"""Return a list of available bulb setting presets."""

View File

@ -9,10 +9,10 @@ from typing import Optional, cast
from pydantic.v1 import BaseModel, Field, root_validator
from ..bulb import HSV, Bulb, BulbPreset, ColorTempRange
from ..device_type import DeviceType
from ..deviceconfig import DeviceConfig
from ..feature import Feature
from ..interfaces.light import HSV, ColorTempRange, Light, LightPreset
from ..module import Module
from ..protocol import BaseProtocol
from .iotdevice import IotDevice, KasaException, requires_update
@ -88,7 +88,7 @@ NON_COLOR_MODE_FLAGS = {"transition_period", "on_off"}
_LOGGER = logging.getLogger(__name__)
class IotBulb(IotDevice, Bulb):
class IotBulb(IotDevice, Light):
r"""Representation of a TP-Link Smart Bulb.
To initialize, you have to await :func:`update()` at least once.
@ -170,9 +170,9 @@ class IotBulb(IotDevice, Bulb):
Bulb configuration presets can be accessed using the :func:`presets` property:
>>> bulb.presets
[BulbPreset(index=0, brightness=50, hue=0, saturation=0, color_temp=2700, custom=None, id=None, mode=None), BulbPreset(index=1, brightness=100, hue=0, saturation=75, color_temp=0, custom=None, id=None, mode=None), BulbPreset(index=2, brightness=100, hue=120, saturation=75, color_temp=0, custom=None, id=None, mode=None), BulbPreset(index=3, brightness=100, hue=240, saturation=75, color_temp=0, custom=None, id=None, mode=None)]
[LightPreset(index=0, brightness=50, hue=0, saturation=0, color_temp=2700, custom=None, id=None, mode=None), LightPreset(index=1, brightness=100, hue=0, saturation=75, color_temp=0, custom=None, id=None, mode=None), LightPreset(index=2, brightness=100, hue=120, saturation=75, color_temp=0, custom=None, id=None, mode=None), LightPreset(index=3, brightness=100, hue=240, saturation=75, color_temp=0, custom=None, id=None, mode=None)]
To modify an existing preset, pass :class:`~kasa.smartbulb.SmartBulbPreset`
To modify an existing preset, pass :class:`~kasa.smartbulb.LightPreset`
instance to :func:`save_preset` method:
>>> preset = bulb.presets[0]
@ -523,11 +523,11 @@ class IotBulb(IotDevice, Bulb):
@property # type: ignore
@requires_update
def presets(self) -> list[BulbPreset]:
def presets(self) -> list[LightPreset]:
"""Return a list of available bulb setting presets."""
return [BulbPreset(**vals) for vals in self.sys_info["preferred_state"]]
return [LightPreset(**vals) for vals in self.sys_info["preferred_state"]]
async def save_preset(self, preset: BulbPreset):
async def save_preset(self, preset: LightPreset):
"""Save a setting preset.
You can either construct a preset object manually, or pass an existing one

View File

@ -4,8 +4,8 @@ from __future__ import annotations
from typing import TYPE_CHECKING
from ...bulb import HSV
from ...feature import Feature
from ...interfaces.light import HSV
from ..smartmodule import SmartModule
if TYPE_CHECKING:

View File

@ -5,8 +5,8 @@ from __future__ import annotations
import logging
from typing import TYPE_CHECKING
from ...bulb import ColorTempRange
from ...feature import Feature
from ...interfaces.light import ColorTempRange
from ..smartmodule import SmartModule
if TYPE_CHECKING:

View File

@ -8,14 +8,14 @@ from datetime import datetime, timedelta
from typing import TYPE_CHECKING, Any, Mapping, Sequence, cast
from ..aestransport import AesTransport
from ..bulb import HSV, Bulb, BulbPreset, ColorTempRange
from ..device import Device, WifiNetwork
from ..device_type import DeviceType
from ..deviceconfig import DeviceConfig
from ..emeterstatus import EmeterStatus
from ..exceptions import AuthenticationError, DeviceError, KasaException, SmartErrorCode
from ..fan import Fan
from ..feature import Feature
from ..interfaces.fan import Fan
from ..interfaces.light import HSV, ColorTempRange, Light, LightPreset
from ..module import Module
from ..modulemapping import ModuleMapping, ModuleName
from ..smartprotocol import SmartProtocol
@ -39,7 +39,7 @@ WALL_SWITCH_PARENT_ONLY_MODULES = [DeviceModule, Time, Firmware, Cloud]
# Device must go last as the other interfaces also inherit Device
# and python needs a consistent method resolution order.
class SmartDevice(Bulb, Fan, Device):
class SmartDevice(Light, Fan, Device):
"""Base class to represent a SMART protocol based device."""
def __init__(
@ -766,7 +766,7 @@ class SmartDevice(Bulb, Fan, Device):
return await self.modules[Module.Brightness].set_brightness(brightness)
@property
def presets(self) -> list[BulbPreset]:
def presets(self) -> list[LightPreset]:
"""Return a list of available bulb setting presets."""
return []

View File

@ -7,7 +7,7 @@ from voluptuous import (
Schema,
)
from kasa import Bulb, BulbPreset, Device, DeviceType, KasaException
from kasa import Device, DeviceType, KasaException, Light, LightPreset
from kasa.iot import IotBulb, IotDimmer
from kasa.smart import SmartDevice
@ -65,7 +65,7 @@ async def test_get_light_state(dev: IotBulb):
@color_bulb
@turn_on
async def test_hsv(dev: Device, turn_on):
assert isinstance(dev, Bulb)
assert isinstance(dev, Light)
await handle_turn_on(dev, turn_on)
assert dev.is_color
@ -96,7 +96,7 @@ async def test_set_hsv_transition(dev: IotBulb, mocker):
@color_bulb
@turn_on
async def test_invalid_hsv(dev: Bulb, turn_on):
async def test_invalid_hsv(dev: Light, turn_on):
await handle_turn_on(dev, turn_on)
assert dev.is_color
@ -116,13 +116,13 @@ async def test_invalid_hsv(dev: Bulb, turn_on):
@color_bulb
@pytest.mark.skip("requires color feature")
async def test_color_state_information(dev: Device):
assert isinstance(dev, Bulb)
assert isinstance(dev, Light)
assert "HSV" in dev.state_information
assert dev.state_information["HSV"] == dev.hsv
@non_color_bulb
async def test_hsv_on_non_color(dev: Bulb):
async def test_hsv_on_non_color(dev: Light):
assert not dev.is_color
with pytest.raises(KasaException):
@ -134,7 +134,7 @@ async def test_hsv_on_non_color(dev: Bulb):
@variable_temp
@pytest.mark.skip("requires colortemp module")
async def test_variable_temp_state_information(dev: Device):
assert isinstance(dev, Bulb)
assert isinstance(dev, Light)
assert "Color temperature" in dev.state_information
assert dev.state_information["Color temperature"] == dev.color_temp
@ -142,7 +142,7 @@ async def test_variable_temp_state_information(dev: Device):
@variable_temp
@turn_on
async def test_try_set_colortemp(dev: Device, turn_on):
assert isinstance(dev, Bulb)
assert isinstance(dev, Light)
await handle_turn_on(dev, turn_on)
await dev.set_color_temp(2700)
await dev.update()
@ -171,7 +171,7 @@ async def test_smart_temp_range(dev: SmartDevice):
@variable_temp
async def test_out_of_range_temperature(dev: Bulb):
async def test_out_of_range_temperature(dev: Light):
with pytest.raises(ValueError):
await dev.set_color_temp(1000)
with pytest.raises(ValueError):
@ -179,7 +179,7 @@ async def test_out_of_range_temperature(dev: Bulb):
@non_variable_temp
async def test_non_variable_temp(dev: Bulb):
async def test_non_variable_temp(dev: Light):
with pytest.raises(KasaException):
await dev.set_color_temp(2700)
@ -193,7 +193,7 @@ async def test_non_variable_temp(dev: Bulb):
@dimmable
@turn_on
async def test_dimmable_brightness(dev: Device, turn_on):
assert isinstance(dev, (Bulb, IotDimmer))
assert isinstance(dev, (Light, IotDimmer))
await handle_turn_on(dev, turn_on)
assert dev.is_dimmable
@ -230,7 +230,7 @@ async def test_dimmable_brightness_transition(dev: IotBulb, mocker):
@dimmable
async def test_invalid_brightness(dev: Bulb):
async def test_invalid_brightness(dev: Light):
assert dev.is_dimmable
with pytest.raises(ValueError):
@ -241,7 +241,7 @@ async def test_invalid_brightness(dev: Bulb):
@non_dimmable
async def test_non_dimmable(dev: Bulb):
async def test_non_dimmable(dev: Light):
assert not dev.is_dimmable
with pytest.raises(KasaException):
@ -291,7 +291,7 @@ async def test_modify_preset(dev: IotBulb, mocker):
"saturation": 0,
"color_temp": 0,
}
preset = BulbPreset(**data)
preset = LightPreset(**data)
assert preset.index == 0
assert preset.brightness == 10
@ -305,7 +305,7 @@ async def test_modify_preset(dev: IotBulb, mocker):
with pytest.raises(KasaException):
await dev.save_preset(
BulbPreset(index=5, hue=0, brightness=0, saturation=0, color_temp=0)
LightPreset(index=5, hue=0, brightness=0, saturation=0, color_temp=0)
)
@ -314,11 +314,11 @@ async def test_modify_preset(dev: IotBulb, mocker):
("preset", "payload"),
[
(
BulbPreset(index=0, hue=0, brightness=1, saturation=0),
LightPreset(index=0, hue=0, brightness=1, saturation=0),
{"index": 0, "hue": 0, "brightness": 1, "saturation": 0},
),
(
BulbPreset(index=0, brightness=1, id="testid", mode=2, custom=0),
LightPreset(index=0, brightness=1, id="testid", mode=2, custom=0),
{"index": 0, "brightness": 1, "id": "testid", "mode": 2, "custom": 0},
),
],

View File

@ -25,6 +25,7 @@ def _get_subclasses(of_class):
inspect.isclass(obj)
and issubclass(obj, of_class)
and module.__package__ != "kasa"
and module.__package__ != "kasa.interfaces"
):
subclasses.add((module.__package__ + "." + name, obj))
return subclasses