diff --git a/homeassistant/components/mqtt/sensor.py b/homeassistant/components/mqtt/sensor.py index 578c912e7b2..570db9e2a36 100644 --- a/homeassistant/components/mqtt/sensor.py +++ b/homeassistant/components/mqtt/sensor.py @@ -209,77 +209,78 @@ class MqttSensor(MqttEntity, RestoreSensor): self._config.get(CONF_LAST_RESET_VALUE_TEMPLATE), entity=self ).async_render_with_possible_json_value + @callback + def _update_state(self, msg: ReceiveMessage) -> None: + # auto-expire enabled? + if self._expire_after is not None and self._expire_after > 0: + # When self._expire_after is set, and we receive a message, assume + # device is not expired since it has to be to receive the message + self._expired = False + + # Reset old trigger + if self._expiration_trigger: + self._expiration_trigger() + + # Set new trigger + self._expiration_trigger = async_call_later( + self.hass, self._expire_after, self._value_is_expired + ) + + payload = self._template(msg.payload, PayloadSentinel.DEFAULT) + if payload is PayloadSentinel.DEFAULT: + return + new_value = str(payload) + if self._numeric_state_expected: + if new_value == "": + _LOGGER.debug("Ignore empty state from '%s'", msg.topic) + elif new_value == PAYLOAD_NONE: + self._attr_native_value = None + else: + self._attr_native_value = new_value + return + if self.device_class in { + None, + SensorDeviceClass.ENUM, + } and not check_state_too_long(_LOGGER, new_value, self.entity_id, msg): + self._attr_native_value = new_value + return + try: + if (payload_datetime := dt_util.parse_datetime(new_value)) is None: + raise ValueError + except ValueError: + _LOGGER.warning( + "Invalid state message '%s' from '%s'", msg.payload, msg.topic + ) + self._attr_native_value = None + return + if self.device_class == SensorDeviceClass.DATE: + self._attr_native_value = payload_datetime.date() + return + self._attr_native_value = payload_datetime + + @callback + def _update_last_reset(self, msg: ReceiveMessage) -> None: + payload = self._last_reset_template(msg.payload) + + if not payload: + _LOGGER.debug("Ignoring empty last_reset message from '%s'", msg.topic) + return + try: + last_reset = dt_util.parse_datetime(str(payload)) + if last_reset is None: + raise ValueError + self._attr_last_reset = last_reset + except ValueError: + _LOGGER.warning( + "Invalid last_reset message '%s' from '%s'", msg.payload, msg.topic + ) + @callback def _state_message_received(self, msg: ReceiveMessage) -> None: """Handle new MQTT state messages.""" - - def _update_state(msg: ReceiveMessage) -> None: - # auto-expire enabled? - if self._expire_after is not None and self._expire_after > 0: - # When self._expire_after is set, and we receive a message, assume - # device is not expired since it has to be to receive the message - self._expired = False - - # Reset old trigger - if self._expiration_trigger: - self._expiration_trigger() - - # Set new trigger - self._expiration_trigger = async_call_later( - self.hass, self._expire_after, self._value_is_expired - ) - - payload = self._template(msg.payload, PayloadSentinel.DEFAULT) - if payload is PayloadSentinel.DEFAULT: - return - new_value = str(payload) - if self._numeric_state_expected: - if new_value == "": - _LOGGER.debug("Ignore empty state from '%s'", msg.topic) - elif new_value == PAYLOAD_NONE: - self._attr_native_value = None - else: - self._attr_native_value = new_value - return - if self.device_class in { - None, - SensorDeviceClass.ENUM, - } and not check_state_too_long(_LOGGER, new_value, self.entity_id, msg): - self._attr_native_value = new_value - return - try: - if (payload_datetime := dt_util.parse_datetime(new_value)) is None: - raise ValueError - except ValueError: - _LOGGER.warning( - "Invalid state message '%s' from '%s'", msg.payload, msg.topic - ) - self._attr_native_value = None - return - if self.device_class == SensorDeviceClass.DATE: - self._attr_native_value = payload_datetime.date() - return - self._attr_native_value = payload_datetime - - def _update_last_reset(msg: ReceiveMessage) -> None: - payload = self._last_reset_template(msg.payload) - - if not payload: - _LOGGER.debug("Ignoring empty last_reset message from '%s'", msg.topic) - return - try: - last_reset = dt_util.parse_datetime(str(payload)) - if last_reset is None: - raise ValueError - self._attr_last_reset = last_reset - except ValueError: - _LOGGER.warning( - "Invalid last_reset message '%s' from '%s'", msg.payload, msg.topic - ) - - _update_state(msg) + self._update_state(msg) if CONF_LAST_RESET_VALUE_TEMPLATE in self._config: - _update_last_reset(msg) + self._update_last_reset(msg) @callback def _prepare_subscribe_topics(self) -> None: diff --git a/homeassistant/components/mqtt/switch.py b/homeassistant/components/mqtt/switch.py index fb33c16fd74..c11e843fc9b 100644 --- a/homeassistant/components/mqtt/switch.py +++ b/homeassistant/components/mqtt/switch.py @@ -90,18 +90,17 @@ class MqttSwitch(MqttEntity, SwitchEntity, RestoreEntity): def _setup_from_config(self, config: ConfigType) -> None: """(Re)Setup the entity.""" self._attr_device_class = config.get(CONF_DEVICE_CLASS) - state_on: str | None = config.get(CONF_STATE_ON) - self._state_on = state_on if state_on else config[CONF_PAYLOAD_ON] - state_off: str | None = config.get(CONF_STATE_OFF) - self._state_off = state_off if state_off else config[CONF_PAYLOAD_OFF] - + self._is_on_map = { + state_on if state_on else config[CONF_PAYLOAD_ON]: True, + state_off if state_off else config[CONF_PAYLOAD_OFF]: False, + PAYLOAD_NONE: None, + } self._optimistic = ( config[CONF_OPTIMISTIC] or config.get(CONF_STATE_TOPIC) is None ) self._attr_assumed_state = bool(self._optimistic) - self._value_template = MqttValueTemplate( self._config.get(CONF_VALUE_TEMPLATE), entity=self ).async_render_with_possible_json_value @@ -109,13 +108,8 @@ class MqttSwitch(MqttEntity, SwitchEntity, RestoreEntity): @callback def _state_message_received(self, msg: ReceiveMessage) -> None: """Handle new MQTT state messages.""" - payload = self._value_template(msg.payload) - if payload == self._state_on: - self._attr_is_on = True - elif payload == self._state_off: - self._attr_is_on = False - elif payload == PAYLOAD_NONE: - self._attr_is_on = None + if (payload := self._value_template(msg.payload)) in self._is_on_map: + self._attr_is_on = self._is_on_map[payload] @callback def _prepare_subscribe_topics(self) -> None: