Deduplicate code in MQTT basic light pt4: Add set_optimistic helper (#50774)

This commit is contained in:
Erik Montnemery 2021-05-17 16:28:30 +02:00 committed by GitHub
parent 2f10f59717
commit 848ab5c2bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -8,7 +8,9 @@ from homeassistant.components.light import (
ATTR_COLOR_TEMP, ATTR_COLOR_TEMP,
ATTR_EFFECT, ATTR_EFFECT,
ATTR_HS_COLOR, ATTR_HS_COLOR,
ATTR_RGB_COLOR,
ATTR_WHITE_VALUE, ATTR_WHITE_VALUE,
ATTR_XY_COLOR,
SUPPORT_BRIGHTNESS, SUPPORT_BRIGHTNESS,
SUPPORT_COLOR, SUPPORT_COLOR,
SUPPORT_COLOR_TEMP, SUPPORT_COLOR_TEMP,
@ -167,13 +169,13 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
self._command_templates = None self._command_templates = None
self._value_templates = None self._value_templates = None
self._optimistic = False self._optimistic = False
self._optimistic_rgb = False self._optimistic_rgb_color = False
self._optimistic_brightness = False self._optimistic_brightness = False
self._optimistic_color_temp = False self._optimistic_color_temp = False
self._optimistic_effect = False self._optimistic_effect = False
self._optimistic_hs = False self._optimistic_hs_color = False
self._optimistic_white_value = False self._optimistic_white_value = False
self._optimistic_xy = False self._optimistic_xy_color = False
MqttEntity.__init__(self, hass, config, config_entry, discovery_data) MqttEntity.__init__(self, hass, config, config_entry, discovery_data)
@ -228,7 +230,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
optimistic = config[CONF_OPTIMISTIC] optimistic = config[CONF_OPTIMISTIC]
self._optimistic = optimistic or topic[CONF_STATE_TOPIC] is None 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 = ( self._optimistic_brightness = (
optimistic optimistic
or ( or (
@ -244,11 +246,15 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
optimistic or topic[CONF_COLOR_TEMP_STATE_TOPIC] is None optimistic or topic[CONF_COLOR_TEMP_STATE_TOPIC] is None
) )
self._optimistic_effect = optimistic or topic[CONF_EFFECT_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 = ( self._optimistic_white_value = (
optimistic or topic[CONF_WHITE_VALUE_STATE_TOPIC] is None 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 async def _subscribe_topics(self): # noqa: C901
"""(Re)Subscribe to topics.""" """(Re)Subscribe to topics."""
@ -265,9 +271,12 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
"qos": self._config[CONF_QOS], "qos": self._config[CONF_QOS],
} }
def restore_state(attribute, condition): def restore_state(attribute, condition_attribute=None):
"""Restore a state attribute.""" """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]) setattr(self, f"_{attribute}", last_state.attributes[attribute])
@callback @callback
@ -313,7 +322,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
self.async_write_ha_state() self.async_write_ha_state()
add_topic(CONF_BRIGHTNESS_STATE_TOPIC, brightness_received) add_topic(CONF_BRIGHTNESS_STATE_TOPIC, brightness_received)
restore_state(ATTR_BRIGHTNESS, self._optimistic_brightness) restore_state(ATTR_BRIGHTNESS)
@callback @callback
@log_messages(self.hass, self.entity_id) @log_messages(self.hass, self.entity_id)
@ -332,7 +341,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
self.async_write_ha_state() self.async_write_ha_state()
add_topic(CONF_RGB_STATE_TOPIC, rgb_received) 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 @callback
@log_messages(self.hass, self.entity_id) @log_messages(self.hass, self.entity_id)
@ -349,7 +358,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
self.async_write_ha_state() self.async_write_ha_state()
add_topic(CONF_COLOR_TEMP_STATE_TOPIC, color_temp_received) 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 @callback
@log_messages(self.hass, self.entity_id) @log_messages(self.hass, self.entity_id)
@ -366,7 +375,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
self.async_write_ha_state() self.async_write_ha_state()
add_topic(CONF_EFFECT_STATE_TOPIC, effect_received) add_topic(CONF_EFFECT_STATE_TOPIC, effect_received)
restore_state(ATTR_EFFECT, self._optimistic_effect) restore_state(ATTR_EFFECT)
@callback @callback
@log_messages(self.hass, self.entity_id) @log_messages(self.hass, self.entity_id)
@ -385,7 +394,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
_LOGGER.debug("Failed to parse hs state update: '%s'", payload) _LOGGER.debug("Failed to parse hs state update: '%s'", payload)
add_topic(CONF_HS_STATE_TOPIC, hs_received) add_topic(CONF_HS_STATE_TOPIC, hs_received)
restore_state(ATTR_HS_COLOR, self._optimistic_hs) restore_state(ATTR_HS_COLOR)
@callback @callback
@log_messages(self.hass, self.entity_id) @log_messages(self.hass, self.entity_id)
@ -404,7 +413,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
self.async_write_ha_state() self.async_write_ha_state()
add_topic(CONF_WHITE_VALUE_STATE_TOPIC, white_value_received) 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 @callback
@log_messages(self.hass, self.entity_id) @log_messages(self.hass, self.entity_id)
@ -420,7 +429,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
self.async_write_ha_state() self.async_write_ha_state()
add_topic(CONF_XY_STATE_TOPIC, xy_received) 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._sub_state = await subscription.async_subscribe_topics(
self.hass, self._sub_state, topics self.hass, self._sub_state, topics
@ -523,7 +532,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
return supported_features return supported_features
async def async_turn_on(self, **kwargs): # noqa: C901 async def async_turn_on(self, **kwargs):
"""Turn the device on. """Turn the device on.
This method is a coroutine. This method is a coroutine.
@ -541,6 +550,15 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
self._config[CONF_RETAIN], 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": if on_command_type == "first":
publish(CONF_COMMAND_TOPIC, self._payload["on"]) publish(CONF_COMMAND_TOPIC, self._payload["on"])
should_update = True should_update = True
@ -573,28 +591,18 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
rgb_color_str = f"{rgb[0]},{rgb[1]},{rgb[2]}" rgb_color_str = f"{rgb[0]},{rgb[1]},{rgb[2]}"
publish(CONF_RGB_COMMAND_TOPIC, rgb_color_str) publish(CONF_RGB_COMMAND_TOPIC, rgb_color_str)
should_update |= set_optimistic(ATTR_HS_COLOR, hs_color, ATTR_RGB_COLOR)
if self._optimistic_rgb:
self._hs_color = kwargs[ATTR_HS_COLOR]
should_update = True
if ATTR_HS_COLOR in kwargs and self._topic[CONF_HS_COMMAND_TOPIC] is not None: if ATTR_HS_COLOR in kwargs and self._topic[CONF_HS_COMMAND_TOPIC] is not None:
hs_color = kwargs[ATTR_HS_COLOR] hs_color = kwargs[ATTR_HS_COLOR]
publish(CONF_HS_COMMAND_TOPIC, f"{hs_color[0]},{hs_color[1]}") publish(CONF_HS_COMMAND_TOPIC, f"{hs_color[0]},{hs_color[1]}")
should_update |= set_optimistic(ATTR_HS_COLOR, hs_color)
if self._optimistic_hs:
self._hs_color = kwargs[ATTR_HS_COLOR]
should_update = True
if ATTR_HS_COLOR in kwargs and self._topic[CONF_XY_COMMAND_TOPIC] is not None: 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]) xy_color = color_util.color_hs_to_xy(*kwargs[ATTR_HS_COLOR])
publish(CONF_XY_COMMAND_TOPIC, f"{xy_color[0]},{xy_color[1]}") publish(CONF_XY_COMMAND_TOPIC, f"{xy_color[0]},{xy_color[1]}")
should_update |= set_optimistic(ATTR_HS_COLOR, hs_color, ATTR_XY_COLOR)
if self._optimistic_xy:
self._hs_color = kwargs[ATTR_HS_COLOR]
should_update = True
if ( if (
ATTR_BRIGHTNESS in kwargs ATTR_BRIGHTNESS in kwargs
@ -608,10 +616,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
# Make sure the brightness is not rounded down to 0 # Make sure the brightness is not rounded down to 0
device_brightness = max(device_brightness, 1) device_brightness = max(device_brightness, 1)
publish(CONF_BRIGHTNESS_COMMAND_TOPIC, device_brightness) publish(CONF_BRIGHTNESS_COMMAND_TOPIC, device_brightness)
should_update |= set_optimistic(ATTR_BRIGHTNESS, kwargs[ATTR_BRIGHTNESS])
if self._optimistic_brightness:
self._brightness = kwargs[ATTR_BRIGHTNESS]
should_update = True
elif ( elif (
ATTR_BRIGHTNESS in kwargs ATTR_BRIGHTNESS in kwargs
and ATTR_HS_COLOR not in kwargs and ATTR_HS_COLOR not in kwargs
@ -628,10 +633,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
rgb_color_str = f"{rgb[0]},{rgb[1]},{rgb[2]}" rgb_color_str = f"{rgb[0]},{rgb[1]},{rgb[2]}"
publish(CONF_RGB_COMMAND_TOPIC, rgb_color_str) publish(CONF_RGB_COMMAND_TOPIC, rgb_color_str)
should_update |= set_optimistic(ATTR_BRIGHTNESS, kwargs[ATTR_BRIGHTNESS])
if self._optimistic_brightness:
self._brightness = kwargs[ATTR_BRIGHTNESS]
should_update = True
if ( if (
ATTR_COLOR_TEMP in kwargs ATTR_COLOR_TEMP in kwargs
@ -644,19 +646,13 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
color_temp = tpl({"value": color_temp}) color_temp = tpl({"value": color_temp})
publish(CONF_COLOR_TEMP_COMMAND_TOPIC, color_temp) publish(CONF_COLOR_TEMP_COMMAND_TOPIC, color_temp)
should_update |= set_optimistic(ATTR_COLOR_TEMP, kwargs[ATTR_COLOR_TEMP])
if self._optimistic_color_temp:
self._color_temp = kwargs[ATTR_COLOR_TEMP]
should_update = True
if ATTR_EFFECT in kwargs and self._topic[CONF_EFFECT_COMMAND_TOPIC] is not None: if ATTR_EFFECT in kwargs and self._topic[CONF_EFFECT_COMMAND_TOPIC] is not None:
effect = kwargs[ATTR_EFFECT] effect = kwargs[ATTR_EFFECT]
if effect in self._config.get(CONF_EFFECT_LIST): if effect in self._config.get(CONF_EFFECT_LIST):
publish(CONF_EFFECT_COMMAND_TOPIC, effect) publish(CONF_EFFECT_COMMAND_TOPIC, effect)
should_update |= set_optimistic(ATTR_EFFECT, effect)
if self._optimistic_effect:
self._effect = kwargs[ATTR_EFFECT]
should_update = True
if ( if (
ATTR_WHITE_VALUE in kwargs ATTR_WHITE_VALUE in kwargs
@ -666,10 +662,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
white_scale = self._config[CONF_WHITE_VALUE_SCALE] white_scale = self._config[CONF_WHITE_VALUE_SCALE]
device_white_value = min(round(percent_white * white_scale), white_scale) device_white_value = min(round(percent_white * white_scale), white_scale)
publish(CONF_WHITE_VALUE_COMMAND_TOPIC, device_white_value) publish(CONF_WHITE_VALUE_COMMAND_TOPIC, device_white_value)
should_update |= set_optimistic(ATTR_WHITE_VALUE, kwargs[ATTR_WHITE_VALUE])
if self._optimistic_white_value:
self._white_value = kwargs[ATTR_WHITE_VALUE]
should_update = True
if on_command_type == "last": if on_command_type == "last":
publish(CONF_COMMAND_TOPIC, self._payload["on"]) publish(CONF_COMMAND_TOPIC, self._payload["on"])