-
-
Notifications
You must be signed in to change notification settings - Fork 187
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor devices into subpackages and deprecate old names (#716)
* Refactor devices into subpackages and deprecate old names * Tweak and add tests * Fix linting * Remove duplicate implementations affecting project coverage * Update post review * Add device base class attributes and rename subclasses * Rename Module to BaseModule * Remove has_emeter_history * Fix missing _time in init * Update post review * Fix test_readmeexamples * Fix erroneously duped files * Clean up iot and smart imports * Update post latest review * Tweak Device docstring
- Loading branch information
Showing
49 changed files
with
1,047 additions
and
607 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
This file contains 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,144 @@ | ||
"""Module for Device base class.""" | ||
from abc import ABC, abstractmethod | ||
from typing import Dict, List, NamedTuple, Optional | ||
|
||
from .device import Device | ||
|
||
try: | ||
from pydantic.v1 import BaseModel | ||
except ImportError: | ||
from pydantic import BaseModel | ||
|
||
|
||
class ColorTempRange(NamedTuple): | ||
"""Color temperature range.""" | ||
|
||
min: int | ||
max: int | ||
|
||
|
||
class HSV(NamedTuple): | ||
"""Hue-saturation-value.""" | ||
|
||
hue: int | ||
saturation: int | ||
value: int | ||
|
||
|
||
class BulbPreset(BaseModel): | ||
"""Bulb configuration preset.""" | ||
|
||
index: int | ||
brightness: int | ||
|
||
# These are not available for effect mode presets on light strips | ||
hue: Optional[int] | ||
saturation: Optional[int] | ||
color_temp: Optional[int] | ||
|
||
# Variables for effect mode presets | ||
custom: Optional[int] | ||
id: Optional[str] | ||
mode: Optional[int] | ||
|
||
|
||
class Bulb(Device, ABC): | ||
"""Base class for TP-Link Bulb.""" | ||
|
||
def _raise_for_invalid_brightness(self, value): | ||
if not isinstance(value, int) or not (0 <= value <= 100): | ||
raise ValueError(f"Invalid brightness value: {value} (valid range: 0-100%)") | ||
|
||
@property | ||
@abstractmethod | ||
def is_color(self) -> bool: | ||
"""Whether the bulb supports color changes.""" | ||
|
||
@property | ||
@abstractmethod | ||
def is_dimmable(self) -> bool: | ||
"""Whether the bulb supports brightness changes.""" | ||
|
||
@property | ||
@abstractmethod | ||
def is_variable_color_temp(self) -> bool: | ||
"""Whether the bulb supports color temperature changes.""" | ||
|
||
@property | ||
@abstractmethod | ||
def valid_temperature_range(self) -> ColorTempRange: | ||
"""Return the device-specific white temperature range (in Kelvin). | ||
:return: White temperature range in Kelvin (minimum, maximum) | ||
""" | ||
|
||
@property | ||
@abstractmethod | ||
def has_effects(self) -> bool: | ||
"""Return True if the device supports effects.""" | ||
|
||
@property | ||
@abstractmethod | ||
def hsv(self) -> HSV: | ||
"""Return the current HSV state of the bulb. | ||
:return: hue, saturation and value (degrees, %, %) | ||
""" | ||
|
||
@property | ||
@abstractmethod | ||
def color_temp(self) -> int: | ||
"""Whether the bulb supports color temperature changes.""" | ||
|
||
@property | ||
@abstractmethod | ||
def brightness(self) -> int: | ||
"""Return the current brightness in percentage.""" | ||
|
||
@abstractmethod | ||
async def set_hsv( | ||
self, | ||
hue: int, | ||
saturation: int, | ||
value: Optional[int] = None, | ||
*, | ||
transition: Optional[int] = None, | ||
) -> Dict: | ||
"""Set new HSV. | ||
Note, transition is not supported and will be ignored. | ||
:param int hue: hue in degrees | ||
:param int saturation: saturation in percentage [0,100] | ||
:param int value: value in percentage [0, 100] | ||
:param int transition: transition in milliseconds. | ||
""" | ||
|
||
@abstractmethod | ||
async def set_color_temp( | ||
self, temp: int, *, brightness=None, transition: Optional[int] = None | ||
) -> Dict: | ||
"""Set the color temperature of the device in kelvin. | ||
Note, transition is not supported and will be ignored. | ||
:param int temp: The new color temperature, in Kelvin | ||
:param int transition: transition in milliseconds. | ||
""" | ||
|
||
@abstractmethod | ||
async def set_brightness( | ||
self, brightness: int, *, transition: Optional[int] = None | ||
) -> Dict: | ||
"""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. | ||
""" | ||
|
||
@property | ||
@abstractmethod | ||
def presets(self) -> List[BulbPreset]: | ||
"""Return a list of available bulb setting presets.""" |
Oops, something went wrong.