Improve typing of deCONZ light platform (#69886)
homeassistant/components/deconz/light.py:66: error: Incompatible types in assignment (expression has type "List[Union[ConfigurationTool, Cover, Fan, Light, Lock, Siren]]", variable has type "Optional[List[Light]]") [assignment] homeassistant/components/deconz/light.py:68: error: Item "None" of "Optional[List[Light]]" has no attribute "__iter__" (not iterable) [union-attr] homeassistant/components/deconz/light.py:159: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_mode" [union-attr] homeassistant/components/deconz/light.py:159: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_mode" [union-attr] homeassistant/components/deconz/light.py:161: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_mode" [union-attr] homeassistant/components/deconz/light.py:161: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_mode" [union-attr] homeassistant/components/deconz/light.py:163: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_mode" [union-attr] homeassistant/components/deconz/light.py:163: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_mode" [union-attr] homeassistant/components/deconz/light.py:165: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "brightness" [union-attr] homeassistant/components/deconz/light.py:165: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "brightness" [union-attr] homeassistant/components/deconz/light.py:174: error: Unused "type: ignore" comment homeassistant/components/deconz/light.py:174: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "brightness" [union-attr] homeassistant/components/deconz/light.py:174: note: Error code "union-attr" not covered by "type: ignore" comment homeassistant/components/deconz/light.py:174: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "brightness" [union-attr] homeassistant/components/deconz/light.py:179: error: Unused "type: ignore" comment homeassistant/components/deconz/light.py:179: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_temp" [union-attr] homeassistant/components/deconz/light.py:179: note: Error code "union-attr" not covered by "type: ignore" comment homeassistant/components/deconz/light.py:179: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_temp" [union-attr] homeassistant/components/deconz/light.py:179: error: Incompatible return value type (got "Union[int, None, Any]", expected "int") [return-value] homeassistant/components/deconz/light.py:179: note: Error code "return-value" not covered by "type: ignore" comment homeassistant/components/deconz/light.py:184: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "hue" [union-attr] homeassistant/components/deconz/light.py:184: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "hue" [union-attr] homeassistant/components/deconz/light.py:184: error: Unsupported operand types for / ("None" and "int") [operator] homeassistant/components/deconz/light.py:184: note: Left operand is of type "Union[int, None, Any]" homeassistant/components/deconz/light.py:184: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "saturation" [union-attr] homeassistant/components/deconz/light.py:184: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "saturation" [union-attr] homeassistant/components/deconz/light.py:189: error: Unused "type: ignore" comment homeassistant/components/deconz/light.py:189: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "xy" [union-attr] homeassistant/components/deconz/light.py:189: note: Error code "union-attr" not covered by "type: ignore" comment homeassistant/components/deconz/light.py:189: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "xy" [union-attr] homeassistant/components/deconz/light.py:194: error: Unused "type: ignore" comment homeassistant/components/deconz/light.py:194: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "state" [union-attr] homeassistant/components/deconz/light.py:194: note: Error code "union-attr" not covered by "type: ignore" comment homeassistant/components/deconz/light.py:194: error: Incompatible return value type (got "Union[bool, None, Any]", expected "bool") [return-value] homeassistant/components/deconz/light.py:194: note: Error code "return-value" not covered by "type: ignore" comment homeassistant/components/deconz/light.py:228: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "set_state" [union-attr] homeassistant/components/deconz/light.py:228: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "set_state" [union-attr] homeassistant/components/deconz/light.py:228: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, float, int, str, Tuple[float, float]]]"; expected "Union[str, None, Literal['none', 'select', 'lselect']]" [arg-type] homeassistant/components/deconz/light.py:228: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, float, int, str, Tuple[float, float]]]"; expected "Optional[int]" [arg-type] homeassistant/components/deconz/light.py:228: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, float, int, str, Tuple[float, float]]]"; expected "Union[str, None, Literal['colorloop', 'none']]" [arg-type] homeassistant/components/deconz/light.py:228: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, float, int, str, Tuple[float, float]]]"; expected "Optional[bool]" [arg-type] homeassistant/components/deconz/light.py:228: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, float, int, str, Tuple[float, float]]]"; expected "Optional[Tuple[float, float]]" [arg-type] homeassistant/components/deconz/light.py:232: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "state" [union-attr] homeassistant/components/deconz/light.py:245: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "set_state" [union-attr] homeassistant/components/deconz/light.py:245: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "set_state" [union-attr] homeassistant/components/deconz/light.py:245: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, int, str]]"; expected "Union[str, None, Literal['none', 'select', 'lselect']]" [arg-type] homeassistant/components/deconz/light.py:245: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, int, str]]"; expected "Optional[int]" [arg-type] homeassistant/components/deconz/light.py:245: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, int, str]]"; expected "Union[str, None, Literal['colorloop', 'none']]" [arg-type] homeassistant/components/deconz/light.py:245: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, int, str]]"; expected "Optional[bool]" [arg-type] homeassistant/components/deconz/light.py:245: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, int, str]]"; expected "Optional[Tuple[float, float]]" [arg-type]
This commit is contained in:
parent
87551b7880
commit
66265b6e9a
4 changed files with 64 additions and 35 deletions
|
@ -68,6 +68,7 @@ homeassistant.components.deconz.climate
|
|||
homeassistant.components.deconz.config_flow
|
||||
homeassistant.components.deconz.diagnostics
|
||||
homeassistant.components.deconz.gateway
|
||||
homeassistant.components.deconz.light
|
||||
homeassistant.components.deconz.services
|
||||
homeassistant.components.device_automation.*
|
||||
homeassistant.components.device_tracker.*
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Support for deCONZ lights."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from typing import Any, Generic, TypedDict, TypeVar
|
||||
|
||||
from pydeconz.group import Group
|
||||
from pydeconz.light import (
|
||||
|
@ -10,6 +10,7 @@ from pydeconz.light import (
|
|||
EFFECT_COLOR_LOOP,
|
||||
EFFECT_NONE,
|
||||
Light,
|
||||
LightResources,
|
||||
)
|
||||
|
||||
from homeassistant.components.light import (
|
||||
|
@ -47,6 +48,22 @@ DECONZ_GROUP = "is_deconz_group"
|
|||
EFFECT_TO_DECONZ = {EFFECT_COLORLOOP: EFFECT_COLOR_LOOP, "None": EFFECT_NONE}
|
||||
FLASH_TO_DECONZ = {FLASH_SHORT: ALERT_SHORT, FLASH_LONG: ALERT_LONG}
|
||||
|
||||
_L = TypeVar("_L", Group, Light)
|
||||
|
||||
|
||||
class SetStateAttributes(TypedDict, total=False):
|
||||
"""Attributes available with set state call."""
|
||||
|
||||
alert: str
|
||||
brightness: int
|
||||
color_temperature: int
|
||||
effect: str
|
||||
hue: int
|
||||
on: bool
|
||||
saturation: int
|
||||
transition_time: int
|
||||
xy: tuple[float, float]
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
|
@ -58,7 +75,7 @@ async def async_setup_entry(
|
|||
gateway.entities[DOMAIN] = set()
|
||||
|
||||
@callback
|
||||
def async_add_light(lights: list[Light] | None = None) -> None:
|
||||
def async_add_light(lights: list[LightResources] | None = None) -> None:
|
||||
"""Add light from deCONZ."""
|
||||
entities = []
|
||||
|
||||
|
@ -119,12 +136,14 @@ async def async_setup_entry(
|
|||
async_add_group()
|
||||
|
||||
|
||||
class DeconzBaseLight(DeconzDevice, LightEntity):
|
||||
class DeconzBaseLight(Generic[_L], DeconzDevice, LightEntity):
|
||||
"""Representation of a deCONZ light."""
|
||||
|
||||
TYPE = DOMAIN
|
||||
|
||||
def __init__(self, device: Group | Light, gateway: DeconzGateway) -> None:
|
||||
_device: _L
|
||||
|
||||
def __init__(self, device: _L, gateway: DeconzGateway) -> None:
|
||||
"""Set up light."""
|
||||
super().__init__(device, gateway)
|
||||
|
||||
|
@ -154,7 +173,7 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
|
|||
self._attr_effect_list = [EFFECT_COLORLOOP]
|
||||
|
||||
@property
|
||||
def color_mode(self) -> str:
|
||||
def color_mode(self) -> str | None:
|
||||
"""Return the color mode of the light."""
|
||||
if self._device.color_mode == "ct":
|
||||
color_mode = COLOR_MODE_COLOR_TEMP
|
||||
|
@ -174,14 +193,16 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
|
|||
return self._device.brightness # type: ignore[no-any-return]
|
||||
|
||||
@property
|
||||
def color_temp(self) -> int:
|
||||
def color_temp(self) -> int | None:
|
||||
"""Return the CT color value."""
|
||||
return self._device.color_temp # type: ignore[no-any-return]
|
||||
|
||||
@property
|
||||
def hs_color(self) -> tuple[float, float]:
|
||||
def hs_color(self) -> tuple[float, float] | None:
|
||||
"""Return the hs color value."""
|
||||
return (self._device.hue / 65535 * 360, self._device.saturation / 255 * 100)
|
||||
if (hue := self._device.hue) and (sat := self._device.saturation):
|
||||
return (hue / 65535 * 360, sat / 255 * 100)
|
||||
return None
|
||||
|
||||
@property
|
||||
def xy_color(self) -> tuple[float, float] | None:
|
||||
|
@ -189,41 +210,41 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
|
|||
return self._device.xy # type: ignore[no-any-return]
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
def is_on(self) -> bool | None:
|
||||
"""Return true if light is on."""
|
||||
return self._device.state # type: ignore[no-any-return]
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn on light."""
|
||||
data: dict[str, bool | float | int | str | tuple[float, float]] = {"on": True}
|
||||
data: SetStateAttributes = {"on": True}
|
||||
|
||||
if (attr_brightness := kwargs.get(ATTR_BRIGHTNESS)) is not None:
|
||||
data["brightness"] = attr_brightness
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
data["brightness"] = kwargs[ATTR_BRIGHTNESS]
|
||||
|
||||
if attr_color_temp := kwargs.get(ATTR_COLOR_TEMP):
|
||||
data["color_temperature"] = attr_color_temp
|
||||
if ATTR_COLOR_TEMP in kwargs:
|
||||
data["color_temperature"] = kwargs[ATTR_COLOR_TEMP]
|
||||
|
||||
if attr_hs_color := kwargs.get(ATTR_HS_COLOR):
|
||||
if ATTR_HS_COLOR in kwargs:
|
||||
if COLOR_MODE_XY in self._attr_supported_color_modes:
|
||||
data["xy"] = color_hs_to_xy(*attr_hs_color)
|
||||
data["xy"] = color_hs_to_xy(*kwargs[ATTR_HS_COLOR])
|
||||
else:
|
||||
data["hue"] = int(attr_hs_color[0] / 360 * 65535)
|
||||
data["saturation"] = int(attr_hs_color[1] / 100 * 255)
|
||||
data["hue"] = int(kwargs[ATTR_HS_COLOR][0] / 360 * 65535)
|
||||
data["saturation"] = int(kwargs[ATTR_HS_COLOR][1] / 100 * 255)
|
||||
|
||||
if ATTR_XY_COLOR in kwargs:
|
||||
data["xy"] = kwargs[ATTR_XY_COLOR]
|
||||
|
||||
if (attr_transition := kwargs.get(ATTR_TRANSITION)) is not None:
|
||||
data["transition_time"] = int(attr_transition * 10)
|
||||
if ATTR_TRANSITION in kwargs:
|
||||
data["transition_time"] = int(kwargs[ATTR_TRANSITION] * 10)
|
||||
elif "IKEA" in self._device.manufacturer:
|
||||
data["transition_time"] = 0
|
||||
|
||||
if (alert := FLASH_TO_DECONZ.get(kwargs.get(ATTR_FLASH, ""))) is not None:
|
||||
data["alert"] = alert
|
||||
if ATTR_FLASH in kwargs and kwargs[ATTR_FLASH] in FLASH_TO_DECONZ:
|
||||
data["alert"] = FLASH_TO_DECONZ[kwargs[ATTR_FLASH]]
|
||||
del data["on"]
|
||||
|
||||
if (effect := EFFECT_TO_DECONZ.get(kwargs.get(ATTR_EFFECT, ""))) is not None:
|
||||
data["effect"] = effect
|
||||
if ATTR_EFFECT in kwargs and kwargs[ATTR_EFFECT] in EFFECT_TO_DECONZ:
|
||||
data["effect"] = EFFECT_TO_DECONZ[kwargs[ATTR_EFFECT]]
|
||||
|
||||
await self._device.set_state(**data)
|
||||
|
||||
|
@ -232,14 +253,14 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
|
|||
if not self._device.state:
|
||||
return
|
||||
|
||||
data: dict[str, bool | int | str] = {"on": False}
|
||||
data: SetStateAttributes = {"on": False}
|
||||
|
||||
if (attr_transition := kwargs.get(ATTR_TRANSITION)) is not None:
|
||||
if ATTR_TRANSITION in kwargs:
|
||||
data["brightness"] = 0
|
||||
data["transition_time"] = int(attr_transition * 10)
|
||||
data["transition_time"] = int(kwargs[ATTR_TRANSITION] * 10)
|
||||
|
||||
if (alert := FLASH_TO_DECONZ.get(kwargs.get(ATTR_FLASH, ""))) is not None:
|
||||
data["alert"] = alert
|
||||
if ATTR_FLASH in kwargs and kwargs[ATTR_FLASH] in FLASH_TO_DECONZ:
|
||||
data["alert"] = FLASH_TO_DECONZ[kwargs[ATTR_FLASH]]
|
||||
del data["on"]
|
||||
|
||||
await self._device.set_state(**data)
|
||||
|
@ -250,7 +271,7 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
|
|||
return {DECONZ_GROUP: isinstance(self._device, Group)}
|
||||
|
||||
|
||||
class DeconzLight(DeconzBaseLight):
|
||||
class DeconzLight(DeconzBaseLight[Light]):
|
||||
"""Representation of a deCONZ light."""
|
||||
|
||||
_device: Light
|
||||
|
@ -266,7 +287,7 @@ class DeconzLight(DeconzBaseLight):
|
|||
return self._device.min_color_temp or super().min_mireds
|
||||
|
||||
|
||||
class DeconzGroup(DeconzBaseLight):
|
||||
class DeconzGroup(DeconzBaseLight[Group]):
|
||||
"""Representation of a deCONZ group."""
|
||||
|
||||
_device: Group
|
||||
|
|
14
mypy.ini
14
mypy.ini
|
@ -550,6 +550,17 @@ no_implicit_optional = true
|
|||
warn_return_any = true
|
||||
warn_unreachable = true
|
||||
|
||||
[mypy-homeassistant.components.deconz.light]
|
||||
check_untyped_defs = true
|
||||
disallow_incomplete_defs = true
|
||||
disallow_subclassing_any = true
|
||||
disallow_untyped_calls = true
|
||||
disallow_untyped_decorators = true
|
||||
disallow_untyped_defs = true
|
||||
no_implicit_optional = true
|
||||
warn_return_any = true
|
||||
warn_unreachable = true
|
||||
|
||||
[mypy-homeassistant.components.deconz.services]
|
||||
check_untyped_defs = true
|
||||
disallow_incomplete_defs = true
|
||||
|
@ -2618,9 +2629,6 @@ ignore_errors = true
|
|||
[mypy-homeassistant.components.deconz.fan]
|
||||
ignore_errors = true
|
||||
|
||||
[mypy-homeassistant.components.deconz.light]
|
||||
ignore_errors = true
|
||||
|
||||
[mypy-homeassistant.components.deconz.lock]
|
||||
ignore_errors = true
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ IGNORED_MODULES: Final[list[str]] = [
|
|||
"homeassistant.components.deconz.binary_sensor",
|
||||
"homeassistant.components.deconz.cover",
|
||||
"homeassistant.components.deconz.fan",
|
||||
"homeassistant.components.deconz.light",
|
||||
"homeassistant.components.deconz.lock",
|
||||
"homeassistant.components.deconz.logbook",
|
||||
"homeassistant.components.deconz.number",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue