Refactor mqtt callbacks for light basic, json and template schema (#118113)
This commit is contained in:
parent
f21c0679b4
commit
d4a95b3735
3 changed files with 429 additions and 441 deletions
|
@ -3,6 +3,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from functools import partial
|
||||
import logging
|
||||
from typing import Any, cast
|
||||
|
||||
|
@ -53,8 +54,7 @@ from ..const import (
|
|||
CONF_STATE_VALUE_TEMPLATE,
|
||||
PAYLOAD_NONE,
|
||||
)
|
||||
from ..debug_info import log_messages
|
||||
from ..mixins import MqttEntity, write_state_on_attr_change
|
||||
from ..mixins import MqttEntity
|
||||
from ..models import (
|
||||
MessageCallbackType,
|
||||
MqttCommandTemplate,
|
||||
|
@ -378,24 +378,8 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
attr: bool = getattr(self, f"_optimistic_{attribute}")
|
||||
return attr
|
||||
|
||||
def _prepare_subscribe_topics(self) -> None: # noqa: C901
|
||||
"""(Re)Subscribe to topics."""
|
||||
topics: dict[str, dict[str, Any]] = {}
|
||||
|
||||
def add_topic(topic: str, msg_callback: MessageCallbackType) -> None:
|
||||
"""Add a topic."""
|
||||
if self._topic[topic] is not None:
|
||||
topics[topic] = {
|
||||
"topic": self._topic[topic],
|
||||
"msg_callback": msg_callback,
|
||||
"qos": self._config[CONF_QOS],
|
||||
"encoding": self._config[CONF_ENCODING] or None,
|
||||
}
|
||||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
@write_state_on_attr_change(self, {"_attr_is_on"})
|
||||
def state_received(msg: ReceiveMessage) -> None:
|
||||
def _state_received(self, msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages."""
|
||||
payload = self._value_templates[CONF_STATE_VALUE_TEMPLATE](
|
||||
msg.payload, PayloadSentinel.NONE
|
||||
|
@ -411,18 +395,8 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
elif payload == PAYLOAD_NONE:
|
||||
self._attr_is_on = None
|
||||
|
||||
if self._topic[CONF_STATE_TOPIC] is not None:
|
||||
topics[CONF_STATE_TOPIC] = {
|
||||
"topic": self._topic[CONF_STATE_TOPIC],
|
||||
"msg_callback": state_received,
|
||||
"qos": self._config[CONF_QOS],
|
||||
"encoding": self._config[CONF_ENCODING] or None,
|
||||
}
|
||||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
@write_state_on_attr_change(self, {"_attr_brightness"})
|
||||
def brightness_received(msg: ReceiveMessage) -> None:
|
||||
def _brightness_received(self, msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages for the brightness."""
|
||||
payload = self._value_templates[CONF_BRIGHTNESS_VALUE_TEMPLATE](
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
|
@ -439,23 +413,18 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
percent_bright = device_value / self._config[CONF_BRIGHTNESS_SCALE]
|
||||
self._attr_brightness = min(round(percent_bright * 255), 255)
|
||||
|
||||
add_topic(CONF_BRIGHTNESS_STATE_TOPIC, brightness_received)
|
||||
|
||||
@callback
|
||||
def _rgbx_received(
|
||||
self,
|
||||
msg: ReceiveMessage,
|
||||
template: str,
|
||||
color_mode: ColorMode,
|
||||
convert_color: Callable[..., tuple[int, ...]],
|
||||
) -> tuple[int, ...] | None:
|
||||
"""Handle new MQTT messages for RGBW and RGBWW."""
|
||||
payload = self._value_templates[template](
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
)
|
||||
"""Process MQTT messages for RGBW and RGBWW."""
|
||||
payload = self._value_templates[template](msg.payload, PayloadSentinel.DEFAULT)
|
||||
if payload is PayloadSentinel.DEFAULT or not payload:
|
||||
_LOGGER.debug(
|
||||
"Ignoring empty %s message from '%s'", color_mode, msg.topic
|
||||
)
|
||||
_LOGGER.debug("Ignoring empty %s message from '%s'", color_mode, msg.topic)
|
||||
return None
|
||||
color = tuple(int(val) for val in str(payload).split(","))
|
||||
if self._optimistic_color_mode:
|
||||
|
@ -478,29 +447,19 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
return color
|
||||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
@write_state_on_attr_change(
|
||||
self, {"_attr_brightness", "_attr_color_mode", "_attr_rgb_color"}
|
||||
)
|
||||
def rgb_received(msg: ReceiveMessage) -> None:
|
||||
def _rgb_received(self, msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages for RGB."""
|
||||
rgb = _rgbx_received(
|
||||
rgb = self._rgbx_received(
|
||||
msg, CONF_RGB_VALUE_TEMPLATE, ColorMode.RGB, lambda *x: x
|
||||
)
|
||||
if rgb is None:
|
||||
return
|
||||
self._attr_rgb_color = cast(tuple[int, int, int], rgb)
|
||||
|
||||
add_topic(CONF_RGB_STATE_TOPIC, rgb_received)
|
||||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
@write_state_on_attr_change(
|
||||
self, {"_attr_brightness", "_attr_color_mode", "_attr_rgbw_color"}
|
||||
)
|
||||
def rgbw_received(msg: ReceiveMessage) -> None:
|
||||
def _rgbw_received(self, msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages for RGBW."""
|
||||
rgbw = _rgbx_received(
|
||||
rgbw = self._rgbx_received(
|
||||
msg,
|
||||
CONF_RGBW_VALUE_TEMPLATE,
|
||||
ColorMode.RGBW,
|
||||
|
@ -510,31 +469,21 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
return
|
||||
self._attr_rgbw_color = cast(tuple[int, int, int, int], rgbw)
|
||||
|
||||
add_topic(CONF_RGBW_STATE_TOPIC, rgbw_received)
|
||||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
@write_state_on_attr_change(
|
||||
self, {"_attr_brightness", "_attr_color_mode", "_attr_rgbww_color"}
|
||||
)
|
||||
def rgbww_received(msg: ReceiveMessage) -> None:
|
||||
def _rgbww_received(self, msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages for RGBWW."""
|
||||
|
||||
@callback
|
||||
def _converter(
|
||||
r: int, g: int, b: int, cw: int, ww: int
|
||||
) -> tuple[int, int, int]:
|
||||
min_kelvin = color_util.color_temperature_mired_to_kelvin(
|
||||
self.max_mireds
|
||||
)
|
||||
max_kelvin = color_util.color_temperature_mired_to_kelvin(
|
||||
self.min_mireds
|
||||
)
|
||||
min_kelvin = color_util.color_temperature_mired_to_kelvin(self.max_mireds)
|
||||
max_kelvin = color_util.color_temperature_mired_to_kelvin(self.min_mireds)
|
||||
return color_util.color_rgbww_to_rgb(
|
||||
r, g, b, cw, ww, min_kelvin, max_kelvin
|
||||
)
|
||||
|
||||
rgbww = _rgbx_received(
|
||||
rgbww = self._rgbx_received(
|
||||
msg,
|
||||
CONF_RGBWW_VALUE_TEMPLATE,
|
||||
ColorMode.RGBWW,
|
||||
|
@ -544,12 +493,8 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
return
|
||||
self._attr_rgbww_color = cast(tuple[int, int, int, int, int], rgbww)
|
||||
|
||||
add_topic(CONF_RGBWW_STATE_TOPIC, rgbww_received)
|
||||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
@write_state_on_attr_change(self, {"_attr_color_mode"})
|
||||
def color_mode_received(msg: ReceiveMessage) -> None:
|
||||
def _color_mode_received(self, msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages for color mode."""
|
||||
payload = self._value_templates[CONF_COLOR_MODE_VALUE_TEMPLATE](
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
|
@ -560,12 +505,8 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
|
||||
self._attr_color_mode = ColorMode(str(payload))
|
||||
|
||||
add_topic(CONF_COLOR_MODE_STATE_TOPIC, color_mode_received)
|
||||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
@write_state_on_attr_change(self, {"_attr_color_mode", "_attr_color_temp"})
|
||||
def color_temp_received(msg: ReceiveMessage) -> None:
|
||||
def _color_temp_received(self, msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages for color temperature."""
|
||||
payload = self._value_templates[CONF_COLOR_TEMP_VALUE_TEMPLATE](
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
|
@ -578,12 +519,8 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
self._attr_color_mode = ColorMode.COLOR_TEMP
|
||||
self._attr_color_temp = int(payload)
|
||||
|
||||
add_topic(CONF_COLOR_TEMP_STATE_TOPIC, color_temp_received)
|
||||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
@write_state_on_attr_change(self, {"_attr_effect"})
|
||||
def effect_received(msg: ReceiveMessage) -> None:
|
||||
def _effect_received(self, msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages for effect."""
|
||||
payload = self._value_templates[CONF_EFFECT_VALUE_TEMPLATE](
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
|
@ -594,12 +531,8 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
|
||||
self._attr_effect = str(payload)
|
||||
|
||||
add_topic(CONF_EFFECT_STATE_TOPIC, effect_received)
|
||||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
@write_state_on_attr_change(self, {"_attr_color_mode", "_attr_hs_color"})
|
||||
def hs_received(msg: ReceiveMessage) -> None:
|
||||
def _hs_received(self, msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages for hs color."""
|
||||
payload = self._value_templates[CONF_HS_VALUE_TEMPLATE](
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
|
@ -615,12 +548,8 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
except ValueError:
|
||||
_LOGGER.warning("Failed to parse hs state update: '%s'", payload)
|
||||
|
||||
add_topic(CONF_HS_STATE_TOPIC, hs_received)
|
||||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
@write_state_on_attr_change(self, {"_attr_color_mode", "_attr_xy_color"})
|
||||
def xy_received(msg: ReceiveMessage) -> None:
|
||||
def _xy_received(self, msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages for xy color."""
|
||||
payload = self._value_templates[CONF_XY_VALUE_TEMPLATE](
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
|
@ -634,7 +563,63 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
self._attr_color_mode = ColorMode.XY
|
||||
self._attr_xy_color = cast(tuple[float, float], xy_color)
|
||||
|
||||
add_topic(CONF_XY_STATE_TOPIC, xy_received)
|
||||
def _prepare_subscribe_topics(self) -> None: # noqa: C901
|
||||
"""(Re)Subscribe to topics."""
|
||||
topics: dict[str, dict[str, Any]] = {}
|
||||
|
||||
def add_topic(
|
||||
topic: str, msg_callback: MessageCallbackType, tracked_attributes: set[str]
|
||||
) -> None:
|
||||
"""Add a topic."""
|
||||
if self._topic[topic] is not None:
|
||||
topics[topic] = {
|
||||
"topic": self._topic[topic],
|
||||
"msg_callback": partial(
|
||||
self._message_callback, msg_callback, tracked_attributes
|
||||
),
|
||||
"entity_id": self.entity_id,
|
||||
"qos": self._config[CONF_QOS],
|
||||
"encoding": self._config[CONF_ENCODING] or None,
|
||||
}
|
||||
|
||||
add_topic(CONF_STATE_TOPIC, self._state_received, {"_attr_is_on"})
|
||||
add_topic(
|
||||
CONF_BRIGHTNESS_STATE_TOPIC, self._brightness_received, {"_attr_brightness"}
|
||||
)
|
||||
add_topic(
|
||||
CONF_RGB_STATE_TOPIC,
|
||||
self._rgb_received,
|
||||
{"_attr_brightness", "_attr_color_mode", "_attr_rgb_color"},
|
||||
)
|
||||
add_topic(
|
||||
CONF_RGBW_STATE_TOPIC,
|
||||
self._rgbw_received,
|
||||
{"_attr_brightness", "_attr_color_mode", "_attr_rgbw_color"},
|
||||
)
|
||||
add_topic(
|
||||
CONF_RGBWW_STATE_TOPIC,
|
||||
self._rgbww_received,
|
||||
{"_attr_brightness", "_attr_color_mode", "_attr_rgbww_color"},
|
||||
)
|
||||
add_topic(
|
||||
CONF_COLOR_MODE_STATE_TOPIC, self._color_mode_received, {"_attr_color_mode"}
|
||||
)
|
||||
add_topic(
|
||||
CONF_COLOR_TEMP_STATE_TOPIC,
|
||||
self._color_temp_received,
|
||||
{"_attr_color_mode", "_attr_color_temp"},
|
||||
)
|
||||
add_topic(CONF_EFFECT_STATE_TOPIC, self._effect_received, {"_attr_effect"})
|
||||
add_topic(
|
||||
CONF_HS_STATE_TOPIC,
|
||||
self._hs_received,
|
||||
{"_attr_color_mode", "_attr_hs_color"},
|
||||
)
|
||||
add_topic(
|
||||
CONF_XY_STATE_TOPIC,
|
||||
self._xy_received,
|
||||
{"_attr_color_mode", "_attr_xy_color"},
|
||||
)
|
||||
|
||||
self._sub_state = subscription.async_prepare_subscribe_topics(
|
||||
self.hass, self._sub_state, topics
|
||||
|
|
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||
|
||||
from collections.abc import Callable
|
||||
from contextlib import suppress
|
||||
from functools import partial
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any, cast
|
||||
|
||||
|
@ -66,8 +67,7 @@ from ..const import (
|
|||
CONF_STATE_TOPIC,
|
||||
DOMAIN as MQTT_DOMAIN,
|
||||
)
|
||||
from ..debug_info import log_messages
|
||||
from ..mixins import MqttEntity, write_state_on_attr_change
|
||||
from ..mixins import MqttEntity
|
||||
from ..models import ReceiveMessage
|
||||
from ..schemas import MQTT_ENTITY_COMMON_SCHEMA
|
||||
from ..util import valid_subscribe_topic
|
||||
|
@ -414,27 +414,8 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||
self.entity_id,
|
||||
)
|
||||
|
||||
def _prepare_subscribe_topics(self) -> None:
|
||||
"""(Re)Subscribe to topics."""
|
||||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
@write_state_on_attr_change(
|
||||
self,
|
||||
{
|
||||
"_attr_brightness",
|
||||
"_attr_color_temp",
|
||||
"_attr_effect",
|
||||
"_attr_hs_color",
|
||||
"_attr_is_on",
|
||||
"_attr_rgb_color",
|
||||
"_attr_rgbw_color",
|
||||
"_attr_rgbww_color",
|
||||
"_attr_xy_color",
|
||||
"color_mode",
|
||||
},
|
||||
)
|
||||
def state_received(msg: ReceiveMessage) -> None:
|
||||
def _state_received(self, msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages."""
|
||||
values = json_loads_object(msg.payload)
|
||||
|
||||
|
@ -509,14 +490,36 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||
with suppress(KeyError):
|
||||
self._attr_effect = cast(str, values["effect"])
|
||||
|
||||
if self._topic[CONF_STATE_TOPIC] is not None:
|
||||
def _prepare_subscribe_topics(self) -> None:
|
||||
"""(Re)Subscribe to topics."""
|
||||
|
||||
#
|
||||
if self._topic[CONF_STATE_TOPIC] is None:
|
||||
return
|
||||
|
||||
self._sub_state = subscription.async_prepare_subscribe_topics(
|
||||
self.hass,
|
||||
self._sub_state,
|
||||
{
|
||||
"state_topic": {
|
||||
CONF_STATE_TOPIC: {
|
||||
"topic": self._topic[CONF_STATE_TOPIC],
|
||||
"msg_callback": state_received,
|
||||
"msg_callback": partial(
|
||||
self._message_callback,
|
||||
self._state_received,
|
||||
{
|
||||
"_attr_brightness",
|
||||
"_attr_color_temp",
|
||||
"_attr_effect",
|
||||
"_attr_hs_color",
|
||||
"_attr_is_on",
|
||||
"_attr_rgb_color",
|
||||
"_attr_rgbw_color",
|
||||
"_attr_rgbww_color",
|
||||
"_attr_xy_color",
|
||||
"color_mode",
|
||||
},
|
||||
),
|
||||
"entity_id": self.entity_id,
|
||||
"qos": self._config[CONF_QOS],
|
||||
"encoding": self._config[CONF_ENCODING] or None,
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from functools import partial
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
|
@ -44,8 +45,7 @@ from ..const import (
|
|||
CONF_STATE_TOPIC,
|
||||
PAYLOAD_NONE,
|
||||
)
|
||||
from ..debug_info import log_messages
|
||||
from ..mixins import MqttEntity, write_state_on_attr_change
|
||||
from ..mixins import MqttEntity
|
||||
from ..models import (
|
||||
MqttCommandTemplate,
|
||||
MqttValueTemplate,
|
||||
|
@ -188,23 +188,8 @@ class MqttLightTemplate(MqttEntity, LightEntity, RestoreEntity):
|
|||
# Support for ct + hs, prioritize hs
|
||||
self._attr_color_mode = ColorMode.HS if self.hs_color else ColorMode.COLOR_TEMP
|
||||
|
||||
def _prepare_subscribe_topics(self) -> None:
|
||||
"""(Re)Subscribe to topics."""
|
||||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
@write_state_on_attr_change(
|
||||
self,
|
||||
{
|
||||
"_attr_brightness",
|
||||
"_attr_color_mode",
|
||||
"_attr_color_temp",
|
||||
"_attr_effect",
|
||||
"_attr_hs_color",
|
||||
"_attr_is_on",
|
||||
},
|
||||
)
|
||||
def state_received(msg: ReceiveMessage) -> None:
|
||||
def _state_received(self, msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages."""
|
||||
state = self._value_templates[CONF_STATE_TEMPLATE](msg.payload)
|
||||
if state == STATE_ON:
|
||||
|
@ -229,9 +214,7 @@ class MqttLightTemplate(MqttEntity, LightEntity, RestoreEntity):
|
|||
)
|
||||
|
||||
except ValueError:
|
||||
_LOGGER.warning(
|
||||
"Invalid brightness value received from %s", msg.topic
|
||||
)
|
||||
_LOGGER.warning("Invalid brightness value received from %s", msg.topic)
|
||||
|
||||
if CONF_COLOR_TEMP_TEMPLATE in self._config:
|
||||
try:
|
||||
|
@ -272,14 +255,31 @@ class MqttLightTemplate(MqttEntity, LightEntity, RestoreEntity):
|
|||
else:
|
||||
_LOGGER.warning("Unsupported effect value received")
|
||||
|
||||
if self._topics[CONF_STATE_TOPIC] is not None:
|
||||
def _prepare_subscribe_topics(self) -> None:
|
||||
"""(Re)Subscribe to topics."""
|
||||
|
||||
if self._topics[CONF_STATE_TOPIC] is None:
|
||||
return
|
||||
|
||||
self._sub_state = subscription.async_prepare_subscribe_topics(
|
||||
self.hass,
|
||||
self._sub_state,
|
||||
{
|
||||
"state_topic": {
|
||||
"topic": self._topics[CONF_STATE_TOPIC],
|
||||
"msg_callback": state_received,
|
||||
"msg_callback": partial(
|
||||
self._message_callback,
|
||||
self._state_received,
|
||||
{
|
||||
"_attr_brightness",
|
||||
"_attr_color_mode",
|
||||
"_attr_color_temp",
|
||||
"_attr_effect",
|
||||
"_attr_hs_color",
|
||||
"_attr_is_on",
|
||||
},
|
||||
),
|
||||
"entity_id": self.entity_id,
|
||||
"qos": self._config[CONF_QOS],
|
||||
"encoding": self._config[CONF_ENCODING] or None,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue