Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 42 additions & 49 deletions homeassistant/components/mqtt/light/schema_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
ATTR_COLOR_TEMP,
ATTR_EFFECT,
ATTR_HS_COLOR,
ATTR_RGB_COLOR,
ATTR_WHITE_VALUE,
ATTR_XY_COLOR,
SUPPORT_BRIGHTNESS,
SUPPORT_COLOR,
SUPPORT_COLOR_TEMP,
Expand Down Expand Up @@ -167,13 +169,13 @@ def __init__(self, hass, config, config_entry, discovery_data):
self._command_templates = None
self._value_templates = None
self._optimistic = False
self._optimistic_rgb = False
self._optimistic_rgb_color = False
self._optimistic_brightness = False
self._optimistic_color_temp = False
self._optimistic_effect = False
self._optimistic_hs = False
self._optimistic_hs_color = False
self._optimistic_white_value = False
self._optimistic_xy = False
self._optimistic_xy_color = False

MqttEntity.__init__(self, hass, config, config_entry, discovery_data)

Expand Down Expand Up @@ -228,7 +230,7 @@ def _setup_from_config(self, config):

optimistic = config[CONF_OPTIMISTIC]
self._optimistic = optimistic or topic[CONF_STATE_TOPIC] is None
self._optimistic_rgb = optimistic or topic[CONF_RGB_STATE_TOPIC] is None
self._optimistic_rgb_color = optimistic or topic[CONF_RGB_STATE_TOPIC] is None
self._optimistic_brightness = (
optimistic
or (
Expand All @@ -244,11 +246,15 @@ def _setup_from_config(self, config):
optimistic or topic[CONF_COLOR_TEMP_STATE_TOPIC] is None
)
self._optimistic_effect = optimistic or topic[CONF_EFFECT_STATE_TOPIC] is None
self._optimistic_hs = optimistic or topic[CONF_HS_STATE_TOPIC] is None
self._optimistic_hs_color = optimistic or topic[CONF_HS_STATE_TOPIC] is None
self._optimistic_white_value = (
optimistic or topic[CONF_WHITE_VALUE_STATE_TOPIC] is None
)
self._optimistic_xy = optimistic or topic[CONF_XY_STATE_TOPIC] is None
self._optimistic_xy_color = optimistic or topic[CONF_XY_STATE_TOPIC] is None

def _is_optimistic(self, attribute):
"""Return True if the attribute is optimistically updated."""
return getattr(self, f"_optimistic_{attribute}")

async def _subscribe_topics(self): # noqa: C901
"""(Re)Subscribe to topics."""
Expand All @@ -265,9 +271,12 @@ def add_topic(topic, msg_callback):
"qos": self._config[CONF_QOS],
}

def restore_state(attribute, condition):
def restore_state(attribute, condition_attribute=None):
"""Restore a state attribute."""
if condition and last_state and last_state.attributes.get(attribute):
if condition_attribute is None:
condition_attribute = attribute
optimistic = self._is_optimistic(condition_attribute)
if optimistic and last_state and last_state.attributes.get(attribute):
setattr(self, f"_{attribute}", last_state.attributes[attribute])

@callback
Expand Down Expand Up @@ -313,7 +322,7 @@ def brightness_received(msg):
self.async_write_ha_state()

add_topic(CONF_BRIGHTNESS_STATE_TOPIC, brightness_received)
restore_state(ATTR_BRIGHTNESS, self._optimistic_brightness)
restore_state(ATTR_BRIGHTNESS)

@callback
@log_messages(self.hass, self.entity_id)
Expand All @@ -332,7 +341,7 @@ def rgb_received(msg):
self.async_write_ha_state()

add_topic(CONF_RGB_STATE_TOPIC, rgb_received)
restore_state(ATTR_HS_COLOR, self._optimistic_rgb)
restore_state(ATTR_HS_COLOR, ATTR_RGB_COLOR)

@callback
@log_messages(self.hass, self.entity_id)
Expand All @@ -349,7 +358,7 @@ def color_temp_received(msg):
self.async_write_ha_state()

add_topic(CONF_COLOR_TEMP_STATE_TOPIC, color_temp_received)
restore_state(ATTR_COLOR_TEMP, self._optimistic_color_temp)
restore_state(ATTR_COLOR_TEMP)

@callback
@log_messages(self.hass, self.entity_id)
Expand All @@ -366,7 +375,7 @@ def effect_received(msg):
self.async_write_ha_state()

add_topic(CONF_EFFECT_STATE_TOPIC, effect_received)
restore_state(ATTR_EFFECT, self._optimistic_effect)
restore_state(ATTR_EFFECT)

@callback
@log_messages(self.hass, self.entity_id)
Expand All @@ -385,7 +394,7 @@ def hs_received(msg):
_LOGGER.debug("Failed to parse hs state update: '%s'", payload)

add_topic(CONF_HS_STATE_TOPIC, hs_received)
restore_state(ATTR_HS_COLOR, self._optimistic_hs)
restore_state(ATTR_HS_COLOR)

@callback
@log_messages(self.hass, self.entity_id)
Expand All @@ -404,7 +413,7 @@ def white_value_received(msg):
self.async_write_ha_state()

add_topic(CONF_WHITE_VALUE_STATE_TOPIC, white_value_received)
restore_state(ATTR_WHITE_VALUE, self._optimistic_white_value)
restore_state(ATTR_WHITE_VALUE)

@callback
@log_messages(self.hass, self.entity_id)
Expand All @@ -420,7 +429,7 @@ def xy_received(msg):
self.async_write_ha_state()

add_topic(CONF_XY_STATE_TOPIC, xy_received)
restore_state(ATTR_HS_COLOR, self._optimistic_xy)
restore_state(ATTR_HS_COLOR, ATTR_XY_COLOR)

self._sub_state = await subscription.async_subscribe_topics(
self.hass, self._sub_state, topics
Expand Down Expand Up @@ -523,7 +532,7 @@ def supported_features(self):

return supported_features

async def async_turn_on(self, **kwargs): # noqa: C901
async def async_turn_on(self, **kwargs):
"""Turn the device on.

This method is a coroutine.
Expand All @@ -541,6 +550,15 @@ def publish(topic, payload):
self._config[CONF_RETAIN],
)

def set_optimistic(attribute, value, condition_attribute=None):
"""Optimistically update a state attribute."""
if condition_attribute is None:
condition_attribute = attribute
if not self._is_optimistic(condition_attribute):
return False
setattr(self, f"_{attribute}", value)
return True

if on_command_type == "first":
publish(CONF_COMMAND_TOPIC, self._payload["on"])
should_update = True
Expand Down Expand Up @@ -573,28 +591,18 @@ def publish(topic, payload):
rgb_color_str = f"{rgb[0]},{rgb[1]},{rgb[2]}"

publish(CONF_RGB_COMMAND_TOPIC, rgb_color_str)

if self._optimistic_rgb:
self._hs_color = kwargs[ATTR_HS_COLOR]
should_update = True
should_update |= set_optimistic(ATTR_HS_COLOR, hs_color, ATTR_RGB_COLOR)

if ATTR_HS_COLOR in kwargs and self._topic[CONF_HS_COMMAND_TOPIC] is not None:

hs_color = kwargs[ATTR_HS_COLOR]
publish(CONF_HS_COMMAND_TOPIC, f"{hs_color[0]},{hs_color[1]}")

if self._optimistic_hs:
self._hs_color = kwargs[ATTR_HS_COLOR]
should_update = True
should_update |= set_optimistic(ATTR_HS_COLOR, hs_color)

if ATTR_HS_COLOR in kwargs and self._topic[CONF_XY_COMMAND_TOPIC] is not None:

xy_color = color_util.color_hs_to_xy(*kwargs[ATTR_HS_COLOR])
publish(CONF_XY_COMMAND_TOPIC, f"{xy_color[0]},{xy_color[1]}")

if self._optimistic_xy:
self._hs_color = kwargs[ATTR_HS_COLOR]
should_update = True
should_update |= set_optimistic(ATTR_HS_COLOR, hs_color, ATTR_XY_COLOR)

if (
ATTR_BRIGHTNESS in kwargs
Expand All @@ -608,10 +616,7 @@ def publish(topic, payload):
# Make sure the brightness is not rounded down to 0
device_brightness = max(device_brightness, 1)
publish(CONF_BRIGHTNESS_COMMAND_TOPIC, device_brightness)

if self._optimistic_brightness:
self._brightness = kwargs[ATTR_BRIGHTNESS]
should_update = True
should_update |= set_optimistic(ATTR_BRIGHTNESS, kwargs[ATTR_BRIGHTNESS])
elif (
ATTR_BRIGHTNESS in kwargs
and ATTR_HS_COLOR not in kwargs
Expand All @@ -628,10 +633,7 @@ def publish(topic, payload):
rgb_color_str = f"{rgb[0]},{rgb[1]},{rgb[2]}"

publish(CONF_RGB_COMMAND_TOPIC, rgb_color_str)

if self._optimistic_brightness:
self._brightness = kwargs[ATTR_BRIGHTNESS]
should_update = True
should_update |= set_optimistic(ATTR_BRIGHTNESS, kwargs[ATTR_BRIGHTNESS])

if (
ATTR_COLOR_TEMP in kwargs
Expand All @@ -644,19 +646,13 @@ def publish(topic, payload):
color_temp = tpl({"value": color_temp})

publish(CONF_COLOR_TEMP_COMMAND_TOPIC, color_temp)

if self._optimistic_color_temp:
self._color_temp = kwargs[ATTR_COLOR_TEMP]
should_update = True
should_update |= set_optimistic(ATTR_COLOR_TEMP, kwargs[ATTR_COLOR_TEMP])

if ATTR_EFFECT in kwargs and self._topic[CONF_EFFECT_COMMAND_TOPIC] is not None:
effect = kwargs[ATTR_EFFECT]
if effect in self._config.get(CONF_EFFECT_LIST):
publish(CONF_EFFECT_COMMAND_TOPIC, effect)

if self._optimistic_effect:
self._effect = kwargs[ATTR_EFFECT]
should_update = True
should_update |= set_optimistic(ATTR_EFFECT, effect)

if (
ATTR_WHITE_VALUE in kwargs
Expand All @@ -666,10 +662,7 @@ def publish(topic, payload):
white_scale = self._config[CONF_WHITE_VALUE_SCALE]
device_white_value = min(round(percent_white * white_scale), white_scale)
publish(CONF_WHITE_VALUE_COMMAND_TOPIC, device_white_value)

if self._optimistic_white_value:
self._white_value = kwargs[ATTR_WHITE_VALUE]
should_update = True
should_update |= set_optimistic(ATTR_WHITE_VALUE, kwargs[ATTR_WHITE_VALUE])

if on_command_type == "last":
publish(CONF_COMMAND_TOPIC, self._payload["on"])
Expand Down