mirror of
https://github.com/home-assistant/core
synced 2024-07-27 18:58:57 +02:00
Improve type hints MQTT light schema json (#82208)
* Improve type hints schema json * Add hint for brightness * Follow up comments * Follow up missed comments * Correct hint on flash arg * hints on one line
This commit is contained in:
parent
5453b346dd
commit
fb909d694f
@ -3,6 +3,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any, cast
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
@ -62,6 +63,7 @@ from ..const import (
|
|||||||
)
|
)
|
||||||
from ..debug_info import log_messages
|
from ..debug_info import log_messages
|
||||||
from ..mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity
|
from ..mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity
|
||||||
|
from ..models import ReceiveMessage
|
||||||
from ..util import get_mqtt_data, valid_subscribe_topic
|
from ..util import get_mqtt_data, valid_subscribe_topic
|
||||||
from .schema import MQTT_LIGHT_SCHEMA_SCHEMA
|
from .schema import MQTT_LIGHT_SCHEMA_SCHEMA
|
||||||
from .schema_basic import (
|
from .schema_basic import (
|
||||||
@ -102,7 +104,7 @@ CONF_MIN_MIREDS = "min_mireds"
|
|||||||
CONF_WHITE_VALUE = "white_value"
|
CONF_WHITE_VALUE = "white_value"
|
||||||
|
|
||||||
|
|
||||||
def valid_color_configuration(config):
|
def valid_color_configuration(config: ConfigType) -> ConfigType:
|
||||||
"""Test color_mode is not combined with deprecated config."""
|
"""Test color_mode is not combined with deprecated config."""
|
||||||
deprecated = {CONF_COLOR_TEMP, CONF_HS, CONF_RGB, CONF_XY}
|
deprecated = {CONF_COLOR_TEMP, CONF_HS, CONF_RGB, CONF_XY}
|
||||||
if config[CONF_COLOR_MODE] and any(config.get(key) for key in deprecated):
|
if config[CONF_COLOR_MODE] and any(config.get(key) for key in deprecated):
|
||||||
@ -194,21 +196,27 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
_entity_id_format = ENTITY_ID_FORMAT
|
_entity_id_format = ENTITY_ID_FORMAT
|
||||||
_attributes_extra_blocked = MQTT_LIGHT_ATTRIBUTES_BLOCKED
|
_attributes_extra_blocked = MQTT_LIGHT_ATTRIBUTES_BLOCKED
|
||||||
|
|
||||||
def __init__(self, hass, config, config_entry, discovery_data):
|
_flash_times: dict[str, int | None]
|
||||||
"""Initialize MQTT JSON light."""
|
_topic: dict[str, str | None]
|
||||||
self._topic = None
|
_optimistic: bool
|
||||||
self._optimistic = False
|
|
||||||
self._fixed_color_mode = None
|
|
||||||
self._flash_times = None
|
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config: ConfigType,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
discovery_data: DiscoveryInfoType | None,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize MQTT JSON light."""
|
||||||
|
self._fixed_color_mode: ColorMode | str | None = None
|
||||||
MqttEntity.__init__(self, hass, config, config_entry, discovery_data)
|
MqttEntity.__init__(self, hass, config, config_entry, discovery_data)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def config_schema():
|
def config_schema() -> vol.Schema:
|
||||||
"""Return the config schema."""
|
"""Return the config schema."""
|
||||||
return DISCOVERY_SCHEMA_JSON
|
return DISCOVERY_SCHEMA_JSON
|
||||||
|
|
||||||
def _setup_from_config(self, config):
|
def _setup_from_config(self, config: ConfigType) -> None:
|
||||||
"""(Re)Setup the entity."""
|
"""(Re)Setup the entity."""
|
||||||
self._attr_max_mireds = config.get(CONF_MAX_MIREDS, super().max_mireds)
|
self._attr_max_mireds = config.get(CONF_MAX_MIREDS, super().max_mireds)
|
||||||
self._attr_min_mireds = config.get(CONF_MIN_MIREDS, super().min_mireds)
|
self._attr_min_mireds = config.get(CONF_MIN_MIREDS, super().min_mireds)
|
||||||
@ -217,7 +225,7 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
self._topic = {
|
self._topic = {
|
||||||
key: config.get(key) for key in (CONF_STATE_TOPIC, CONF_COMMAND_TOPIC)
|
key: config.get(key) for key in (CONF_STATE_TOPIC, CONF_COMMAND_TOPIC)
|
||||||
}
|
}
|
||||||
optimistic = config[CONF_OPTIMISTIC]
|
optimistic: bool = config[CONF_OPTIMISTIC]
|
||||||
self._optimistic = optimistic or self._topic[CONF_STATE_TOPIC] is None
|
self._optimistic = optimistic or self._topic[CONF_STATE_TOPIC] is None
|
||||||
|
|
||||||
self._flash_times = {
|
self._flash_times = {
|
||||||
@ -240,14 +248,14 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
if config[CONF_HS] or config[CONF_RGB] or config[CONF_XY]:
|
if config[CONF_HS] or config[CONF_RGB] or config[CONF_XY]:
|
||||||
color_modes.add(ColorMode.HS)
|
color_modes.add(ColorMode.HS)
|
||||||
self._attr_supported_color_modes = filter_supported_color_modes(color_modes)
|
self._attr_supported_color_modes = filter_supported_color_modes(color_modes)
|
||||||
if len(self.supported_color_modes) == 1:
|
if self.supported_color_modes and len(self.supported_color_modes) == 1:
|
||||||
self._fixed_color_mode = next(iter(self.supported_color_modes))
|
self._fixed_color_mode = next(iter(self.supported_color_modes))
|
||||||
else:
|
else:
|
||||||
self._attr_supported_color_modes = self._config[CONF_SUPPORTED_COLOR_MODES]
|
self._attr_supported_color_modes = self._config[CONF_SUPPORTED_COLOR_MODES]
|
||||||
if len(self.supported_color_modes) == 1:
|
if self.supported_color_modes and len(self.supported_color_modes) == 1:
|
||||||
self._attr_color_mode = next(iter(self.supported_color_modes))
|
self._attr_color_mode = next(iter(self.supported_color_modes))
|
||||||
|
|
||||||
def _update_color(self, values):
|
def _update_color(self, values: dict[str, Any]) -> None:
|
||||||
if not self._config[CONF_COLOR_MODE]:
|
if not self._config[CONF_COLOR_MODE]:
|
||||||
# Deprecated color handling
|
# Deprecated color handling
|
||||||
try:
|
try:
|
||||||
@ -287,7 +295,7 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
color_mode = values["color_mode"]
|
color_mode: str = values["color_mode"]
|
||||||
if not self._supports_color_mode(color_mode):
|
if not self._supports_color_mode(color_mode):
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Invalid color mode received for entity %s", self.entity_id
|
"Invalid color mode received for entity %s", self.entity_id
|
||||||
@ -336,14 +344,14 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
self.entity_id,
|
self.entity_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _prepare_subscribe_topics(self):
|
def _prepare_subscribe_topics(self) -> None:
|
||||||
"""(Re)Subscribe to topics."""
|
"""(Re)Subscribe to topics."""
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@log_messages(self.hass, self.entity_id)
|
@log_messages(self.hass, self.entity_id)
|
||||||
def state_received(msg):
|
def state_received(msg: ReceiveMessage) -> None:
|
||||||
"""Handle new MQTT messages."""
|
"""Handle new MQTT messages."""
|
||||||
values = json_loads(msg.payload)
|
values: dict[str, Any] = json_loads(msg.payload)
|
||||||
|
|
||||||
if values["state"] == "ON":
|
if values["state"] == "ON":
|
||||||
self._attr_is_on = True
|
self._attr_is_on = True
|
||||||
@ -382,7 +390,8 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
ColorMode.COLOR_TEMP in self.supported_color_modes
|
self.supported_color_modes
|
||||||
|
and ColorMode.COLOR_TEMP in self.supported_color_modes
|
||||||
and not self._config[CONF_COLOR_MODE]
|
and not self._config[CONF_COLOR_MODE]
|
||||||
):
|
):
|
||||||
# Deprecated color handling
|
# Deprecated color handling
|
||||||
@ -419,7 +428,7 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _subscribe_topics(self):
|
async def _subscribe_topics(self) -> None:
|
||||||
"""(Re)Subscribe to topics."""
|
"""(Re)Subscribe to topics."""
|
||||||
await subscription.async_subscribe_topics(self.hass, self._sub_state)
|
await subscription.async_subscribe_topics(self.hass, self._sub_state)
|
||||||
|
|
||||||
@ -448,12 +457,12 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
self._attr_xy_color = last_attributes.get(ATTR_XY_COLOR, self.xy_color)
|
self._attr_xy_color = last_attributes.get(ATTR_XY_COLOR, self.xy_color)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def assumed_state(self):
|
def assumed_state(self) -> bool:
|
||||||
"""Return true if we do optimistic updates."""
|
"""Return true if we do optimistic updates."""
|
||||||
return self._optimistic
|
return self._optimistic
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def color_mode(self):
|
def color_mode(self) -> ColorMode | str | None:
|
||||||
"""Return current color mode."""
|
"""Return current color mode."""
|
||||||
if self._config[CONF_COLOR_MODE]:
|
if self._config[CONF_COLOR_MODE]:
|
||||||
return self._attr_color_mode
|
return self._attr_color_mode
|
||||||
@ -465,41 +474,49 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
return ColorMode.HS
|
return ColorMode.HS
|
||||||
return ColorMode.COLOR_TEMP
|
return ColorMode.COLOR_TEMP
|
||||||
|
|
||||||
def _set_flash_and_transition(self, message, **kwargs):
|
def _set_flash_and_transition(self, message: dict[str, Any], **kwargs: Any) -> None:
|
||||||
if ATTR_TRANSITION in kwargs:
|
if ATTR_TRANSITION in kwargs:
|
||||||
message["transition"] = kwargs[ATTR_TRANSITION]
|
message["transition"] = kwargs[ATTR_TRANSITION]
|
||||||
|
|
||||||
if ATTR_FLASH in kwargs:
|
if ATTR_FLASH in kwargs:
|
||||||
flash = kwargs.get(ATTR_FLASH)
|
flash: str = kwargs[ATTR_FLASH]
|
||||||
|
|
||||||
if flash == FLASH_LONG:
|
if flash == FLASH_LONG:
|
||||||
message["flash"] = self._flash_times[CONF_FLASH_TIME_LONG]
|
message["flash"] = self._flash_times[CONF_FLASH_TIME_LONG]
|
||||||
elif flash == FLASH_SHORT:
|
elif flash == FLASH_SHORT:
|
||||||
message["flash"] = self._flash_times[CONF_FLASH_TIME_SHORT]
|
message["flash"] = self._flash_times[CONF_FLASH_TIME_SHORT]
|
||||||
|
|
||||||
def _scale_rgbxx(self, rgbxx, kwargs):
|
def _scale_rgbxx(self, rgbxx: tuple[int, ...], kwargs: Any) -> tuple[int, ...]:
|
||||||
# If there's a brightness topic set, we don't want to scale the
|
# If there's a brightness topic set, we don't want to scale the
|
||||||
# RGBxx values given using the brightness.
|
# RGBxx values given using the brightness.
|
||||||
|
brightness: int
|
||||||
if self._config[CONF_BRIGHTNESS]:
|
if self._config[CONF_BRIGHTNESS]:
|
||||||
brightness = 255
|
brightness = 255
|
||||||
else:
|
else:
|
||||||
brightness = kwargs.get(ATTR_BRIGHTNESS, 255)
|
brightness = kwargs.get(ATTR_BRIGHTNESS, 255)
|
||||||
return tuple(round(i / 255 * brightness) for i in rgbxx)
|
return tuple(round(i / 255 * brightness) for i in rgbxx)
|
||||||
|
|
||||||
def _supports_color_mode(self, color_mode):
|
def _supports_color_mode(self, color_mode: ColorMode | str) -> bool:
|
||||||
"""Return True if the light natively supports a color mode."""
|
"""Return True if the light natively supports a color mode."""
|
||||||
return (
|
return (
|
||||||
self._config[CONF_COLOR_MODE] and color_mode in self.supported_color_modes
|
self._config[CONF_COLOR_MODE]
|
||||||
|
and self.supported_color_modes is not None
|
||||||
|
and color_mode in self.supported_color_modes
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs): # noqa: C901
|
async def async_turn_on(self, **kwargs: Any) -> None: # noqa: C901
|
||||||
"""Turn the device on.
|
"""Turn the device on.
|
||||||
|
|
||||||
This method is a coroutine.
|
This method is a coroutine.
|
||||||
"""
|
"""
|
||||||
|
brightness: int
|
||||||
should_update = False
|
should_update = False
|
||||||
|
hs_color: tuple[float, float]
|
||||||
message = {"state": "ON"}
|
message: dict[str, Any] = {"state": "ON"}
|
||||||
|
rgb: tuple[int, ...]
|
||||||
|
rgbw: tuple[int, ...]
|
||||||
|
rgbcw: tuple[int, ...]
|
||||||
|
xy_color: tuple[float, float]
|
||||||
|
|
||||||
if ATTR_HS_COLOR in kwargs and (
|
if ATTR_HS_COLOR in kwargs and (
|
||||||
self._config[CONF_HS] or self._config[CONF_RGB] or self._config[CONF_XY]
|
self._config[CONF_HS] or self._config[CONF_RGB] or self._config[CONF_XY]
|
||||||
@ -546,37 +563,37 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
message["color"] = {"r": rgb[0], "g": rgb[1], "b": rgb[2]}
|
message["color"] = {"r": rgb[0], "g": rgb[1], "b": rgb[2]}
|
||||||
if self._optimistic:
|
if self._optimistic:
|
||||||
self._attr_color_mode = ColorMode.RGB
|
self._attr_color_mode = ColorMode.RGB
|
||||||
self._attr_rgb_color = rgb
|
self._attr_rgb_color = cast(tuple[int, int, int], rgb)
|
||||||
should_update = True
|
should_update = True
|
||||||
|
|
||||||
if ATTR_RGBW_COLOR in kwargs and self._supports_color_mode(ColorMode.RGBW):
|
if ATTR_RGBW_COLOR in kwargs and self._supports_color_mode(ColorMode.RGBW):
|
||||||
rgb = self._scale_rgbxx(kwargs[ATTR_RGBW_COLOR], kwargs)
|
rgbw = self._scale_rgbxx(kwargs[ATTR_RGBW_COLOR], kwargs)
|
||||||
message["color"] = {"r": rgb[0], "g": rgb[1], "b": rgb[2], "w": rgb[3]}
|
message["color"] = {"r": rgbw[0], "g": rgbw[1], "b": rgbw[2], "w": rgbw[3]}
|
||||||
if self._optimistic:
|
if self._optimistic:
|
||||||
self._attr_color_mode = ColorMode.RGBW
|
self._attr_color_mode = ColorMode.RGBW
|
||||||
self._attr_rgbw_color = rgb
|
self._attr_rgbw_color = cast(tuple[int, int, int, int], rgbw)
|
||||||
should_update = True
|
should_update = True
|
||||||
|
|
||||||
if ATTR_RGBWW_COLOR in kwargs and self._supports_color_mode(ColorMode.RGBWW):
|
if ATTR_RGBWW_COLOR in kwargs and self._supports_color_mode(ColorMode.RGBWW):
|
||||||
rgb = self._scale_rgbxx(kwargs[ATTR_RGBWW_COLOR], kwargs)
|
rgbcw = self._scale_rgbxx(kwargs[ATTR_RGBWW_COLOR], kwargs)
|
||||||
message["color"] = {
|
message["color"] = {
|
||||||
"r": rgb[0],
|
"r": rgbcw[0],
|
||||||
"g": rgb[1],
|
"g": rgbcw[1],
|
||||||
"b": rgb[2],
|
"b": rgbcw[2],
|
||||||
"c": rgb[3],
|
"c": rgbcw[3],
|
||||||
"w": rgb[4],
|
"w": rgbcw[4],
|
||||||
}
|
}
|
||||||
if self._optimistic:
|
if self._optimistic:
|
||||||
self._attr_color_mode = ColorMode.RGBWW
|
self._attr_color_mode = ColorMode.RGBWW
|
||||||
self._attr_rgbww_color = rgb
|
self._attr_rgbww_color = cast(tuple[int, int, int, int, int], rgbcw)
|
||||||
should_update = True
|
should_update = True
|
||||||
|
|
||||||
if ATTR_XY_COLOR in kwargs and self._supports_color_mode(ColorMode.XY):
|
if ATTR_XY_COLOR in kwargs and self._supports_color_mode(ColorMode.XY):
|
||||||
xy = kwargs[ATTR_XY_COLOR] # pylint: disable=invalid-name
|
xy_color = kwargs[ATTR_XY_COLOR]
|
||||||
message["color"] = {"x": xy[0], "y": xy[1]}
|
message["color"] = {"x": xy_color[0], "y": xy_color[1]}
|
||||||
if self._optimistic:
|
if self._optimistic:
|
||||||
self._attr_color_mode = ColorMode.XY
|
self._attr_color_mode = ColorMode.XY
|
||||||
self._attr_xy_color = xy
|
self._attr_xy_color = xy_color
|
||||||
should_update = True
|
should_update = True
|
||||||
|
|
||||||
self._set_flash_and_transition(message, **kwargs)
|
self._set_flash_and_transition(message, **kwargs)
|
||||||
@ -625,7 +642,7 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
should_update = True
|
should_update = True
|
||||||
|
|
||||||
await self.async_publish(
|
await self.async_publish(
|
||||||
self._topic[CONF_COMMAND_TOPIC],
|
str(self._topic[CONF_COMMAND_TOPIC]),
|
||||||
json_dumps(message),
|
json_dumps(message),
|
||||||
self._config[CONF_QOS],
|
self._config[CONF_QOS],
|
||||||
self._config[CONF_RETAIN],
|
self._config[CONF_RETAIN],
|
||||||
@ -640,17 +657,17 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
if should_update:
|
if should_update:
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs):
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn the device off.
|
"""Turn the device off.
|
||||||
|
|
||||||
This method is a coroutine.
|
This method is a coroutine.
|
||||||
"""
|
"""
|
||||||
message = {"state": "OFF"}
|
message: dict[str, Any] = {"state": "OFF"}
|
||||||
|
|
||||||
self._set_flash_and_transition(message, **kwargs)
|
self._set_flash_and_transition(message, **kwargs)
|
||||||
|
|
||||||
await self.async_publish(
|
await self.async_publish(
|
||||||
self._topic[CONF_COMMAND_TOPIC],
|
str(self._topic[CONF_COMMAND_TOPIC]),
|
||||||
json_dumps(message),
|
json_dumps(message),
|
||||||
self._config[CONF_QOS],
|
self._config[CONF_QOS],
|
||||||
self._config[CONF_RETAIN],
|
self._config[CONF_RETAIN],
|
||||||
|
Loading…
Reference in New Issue
Block a user