Adjust payload sentinel in mqtt (#81553)
* Adjust payload sentinel in mqtt * Add type hints * Update sensor.py * Adjust vacuum * Add type hints * Adjust schema basic * Remove invalid hintpull/81307/head
parent
d1fd141e8c
commit
9b2a8901b1
|
@ -50,7 +50,12 @@ from ..const import (
|
|||
)
|
||||
from ..debug_info import log_messages
|
||||
from ..mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity
|
||||
from ..models import MqttCommandTemplate, MqttValueTemplate
|
||||
from ..models import (
|
||||
MqttCommandTemplate,
|
||||
MqttValueTemplate,
|
||||
PayloadSentinel,
|
||||
ReceiveMessage,
|
||||
)
|
||||
from ..util import get_mqtt_data, valid_publish_topic, valid_subscribe_topic
|
||||
from .schema import MQTT_LIGHT_SCHEMA_SCHEMA
|
||||
|
||||
|
@ -450,12 +455,12 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
def brightness_received(msg):
|
||||
def brightness_received(msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages for the brightness."""
|
||||
payload = self._value_templates[CONF_BRIGHTNESS_VALUE_TEMPLATE](
|
||||
msg.payload, None
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
)
|
||||
if not payload:
|
||||
if payload is PayloadSentinel.DEFAULT or not payload:
|
||||
_LOGGER.debug("Ignoring empty brightness message from '%s'", msg.topic)
|
||||
return
|
||||
|
||||
|
@ -468,8 +473,10 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
|
||||
def _rgbx_received(msg, template, color_mode, convert_color):
|
||||
"""Handle new MQTT messages for RGBW and RGBWW."""
|
||||
payload = self._value_templates[template](msg.payload, None)
|
||||
if not payload:
|
||||
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
|
||||
)
|
||||
|
@ -533,12 +540,12 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
def color_mode_received(msg):
|
||||
def color_mode_received(msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages for color mode."""
|
||||
payload = self._value_templates[CONF_COLOR_MODE_VALUE_TEMPLATE](
|
||||
msg.payload, None
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
)
|
||||
if not payload:
|
||||
if payload is PayloadSentinel.DEFAULT or not payload:
|
||||
_LOGGER.debug("Ignoring empty color mode message from '%s'", msg.topic)
|
||||
return
|
||||
|
||||
|
@ -549,12 +556,12 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
def color_temp_received(msg):
|
||||
def color_temp_received(msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages for color temperature."""
|
||||
payload = self._value_templates[CONF_COLOR_TEMP_VALUE_TEMPLATE](
|
||||
msg.payload, None
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
)
|
||||
if not payload:
|
||||
if payload is PayloadSentinel.DEFAULT or not payload:
|
||||
_LOGGER.debug("Ignoring empty color temp message from '%s'", msg.topic)
|
||||
return
|
||||
|
||||
|
@ -567,12 +574,12 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
def effect_received(msg):
|
||||
def effect_received(msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages for effect."""
|
||||
payload = self._value_templates[CONF_EFFECT_VALUE_TEMPLATE](
|
||||
msg.payload, None
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
)
|
||||
if not payload:
|
||||
if payload is PayloadSentinel.DEFAULT or not payload:
|
||||
_LOGGER.debug("Ignoring empty effect message from '%s'", msg.topic)
|
||||
return
|
||||
|
||||
|
@ -583,10 +590,12 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
def hs_received(msg):
|
||||
def hs_received(msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages for hs color."""
|
||||
payload = self._value_templates[CONF_HS_VALUE_TEMPLATE](msg.payload, None)
|
||||
if not payload:
|
||||
payload = self._value_templates[CONF_HS_VALUE_TEMPLATE](
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
)
|
||||
if payload is PayloadSentinel.DEFAULT or not payload:
|
||||
_LOGGER.debug("Ignoring empty hs message from '%s'", msg.topic)
|
||||
return
|
||||
try:
|
||||
|
@ -602,10 +611,12 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
|||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
def xy_received(msg):
|
||||
def xy_received(msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT messages for xy color."""
|
||||
payload = self._value_templates[CONF_XY_VALUE_TEMPLATE](msg.payload, None)
|
||||
if not payload:
|
||||
payload = self._value_templates[CONF_XY_VALUE_TEMPLATE](
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
)
|
||||
if payload is PayloadSentinel.DEFAULT or not payload:
|
||||
_LOGGER.debug("Ignoring empty xy-color message from '%s'", msg.topic)
|
||||
return
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ from typing import TYPE_CHECKING, Any, TypedDict, Union
|
|||
|
||||
import attr
|
||||
|
||||
from homeassistant.backports.enum import StrEnum
|
||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_NAME
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
|
||||
from homeassistant.helpers import template
|
||||
|
@ -26,7 +27,13 @@ if TYPE_CHECKING:
|
|||
from .discovery import MQTTDiscoveryPayload
|
||||
from .tag import MQTTTagScanner
|
||||
|
||||
_SENTINEL = object()
|
||||
|
||||
class PayloadSentinel(StrEnum):
|
||||
"""Sentinel for `async_render_with_possible_json_value`."""
|
||||
|
||||
NONE = "none"
|
||||
DEFAULT = "default"
|
||||
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -189,7 +196,7 @@ class MqttValueTemplate:
|
|||
def async_render_with_possible_json_value(
|
||||
self,
|
||||
payload: ReceivePayloadType,
|
||||
default: ReceivePayloadType | object = _SENTINEL,
|
||||
default: ReceivePayloadType | PayloadSentinel = PayloadSentinel.NONE,
|
||||
variables: TemplateVarsType = None,
|
||||
) -> ReceivePayloadType:
|
||||
"""Render with possible json value or pass-though a received MQTT value."""
|
||||
|
@ -213,7 +220,7 @@ class MqttValueTemplate:
|
|||
)
|
||||
values[ATTR_THIS] = self._template_state
|
||||
|
||||
if default == _SENTINEL:
|
||||
if default is PayloadSentinel.NONE:
|
||||
_LOGGER.debug(
|
||||
"Rendering incoming payload '%s' with variables %s and %s",
|
||||
payload,
|
||||
|
|
|
@ -45,7 +45,7 @@ from .mixins import (
|
|||
async_setup_platform_helper,
|
||||
warn_for_legacy_schema,
|
||||
)
|
||||
from .models import MqttValueTemplate
|
||||
from .models import MqttValueTemplate, PayloadSentinel, ReceiveMessage
|
||||
from .util import get_mqtt_data, valid_subscribe_topic
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -244,7 +244,7 @@ class MqttSensor(MqttEntity, RestoreSensor):
|
|||
"""(Re)Subscribe to topics."""
|
||||
topics = {}
|
||||
|
||||
def _update_state(msg):
|
||||
def _update_state(msg: ReceiveMessage) -> None:
|
||||
# auto-expire enabled?
|
||||
expire_after = self._config.get(CONF_EXPIRE_AFTER)
|
||||
if expire_after is not None and expire_after > 0:
|
||||
|
@ -262,20 +262,25 @@ class MqttSensor(MqttEntity, RestoreSensor):
|
|||
self.hass, self._value_is_expired, expiration_at
|
||||
)
|
||||
|
||||
payload = self._template(msg.payload, default=self.native_value)
|
||||
|
||||
if payload is not None and self.device_class in (
|
||||
payload = self._template(msg.payload, default=PayloadSentinel.DEFAULT)
|
||||
if payload is PayloadSentinel.DEFAULT:
|
||||
return
|
||||
if self.device_class not in {
|
||||
SensorDeviceClass.DATE,
|
||||
SensorDeviceClass.TIMESTAMP,
|
||||
):
|
||||
if (payload := dt_util.parse_datetime(payload)) is None:
|
||||
_LOGGER.warning(
|
||||
"Invalid state message '%s' from '%s'", msg.payload, msg.topic
|
||||
)
|
||||
elif self.device_class == SensorDeviceClass.DATE:
|
||||
payload = payload.date()
|
||||
|
||||
self._attr_native_value = payload
|
||||
}:
|
||||
self._attr_native_value = str(payload)
|
||||
return
|
||||
if (payload_datetime := dt_util.parse_datetime(str(payload))) is None:
|
||||
_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):
|
||||
payload = self._last_reset_template(msg.payload)
|
||||
|
|
|
@ -19,7 +19,7 @@ from ..config import MQTT_BASE_SCHEMA
|
|||
from ..const import CONF_COMMAND_TOPIC, CONF_ENCODING, CONF_QOS, CONF_RETAIN
|
||||
from ..debug_info import log_messages
|
||||
from ..mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, warn_for_legacy_schema
|
||||
from ..models import MqttValueTemplate
|
||||
from ..models import MqttValueTemplate, PayloadSentinel, ReceiveMessage
|
||||
from ..util import get_mqtt_data, valid_publish_topic
|
||||
from .const import MQTT_VACUUM_ATTRIBUTES_BLOCKED
|
||||
from .schema import MQTT_VACUUM_SCHEMA, services_to_strings, strings_to_services
|
||||
|
@ -246,7 +246,7 @@ class MqttVacuum(MqttEntity, VacuumEntity):
|
|||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
def message_received(msg):
|
||||
def message_received(msg: ReceiveMessage) -> None:
|
||||
"""Handle new MQTT message."""
|
||||
if (
|
||||
msg.topic == self._state_topics[CONF_BATTERY_LEVEL_TOPIC]
|
||||
|
@ -254,8 +254,10 @@ class MqttVacuum(MqttEntity, VacuumEntity):
|
|||
):
|
||||
battery_level = self._templates[
|
||||
CONF_BATTERY_LEVEL_TEMPLATE
|
||||
].async_render_with_possible_json_value(msg.payload, None)
|
||||
if battery_level:
|
||||
].async_render_with_possible_json_value(
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
)
|
||||
if battery_level and battery_level is not PayloadSentinel.DEFAULT:
|
||||
self._battery_level = int(battery_level)
|
||||
|
||||
if (
|
||||
|
@ -264,8 +266,10 @@ class MqttVacuum(MqttEntity, VacuumEntity):
|
|||
):
|
||||
charging = self._templates[
|
||||
CONF_CHARGING_TEMPLATE
|
||||
].async_render_with_possible_json_value(msg.payload, None)
|
||||
if charging:
|
||||
].async_render_with_possible_json_value(
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
)
|
||||
if charging and charging is not PayloadSentinel.DEFAULT:
|
||||
self._charging = cv.boolean(charging)
|
||||
|
||||
if (
|
||||
|
@ -274,8 +278,10 @@ class MqttVacuum(MqttEntity, VacuumEntity):
|
|||
):
|
||||
cleaning = self._templates[
|
||||
CONF_CLEANING_TEMPLATE
|
||||
].async_render_with_possible_json_value(msg.payload, None)
|
||||
if cleaning:
|
||||
].async_render_with_possible_json_value(
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
)
|
||||
if cleaning and cleaning is not PayloadSentinel.DEFAULT:
|
||||
self._cleaning = cv.boolean(cleaning)
|
||||
|
||||
if (
|
||||
|
@ -284,8 +290,10 @@ class MqttVacuum(MqttEntity, VacuumEntity):
|
|||
):
|
||||
docked = self._templates[
|
||||
CONF_DOCKED_TEMPLATE
|
||||
].async_render_with_possible_json_value(msg.payload, None)
|
||||
if docked:
|
||||
].async_render_with_possible_json_value(
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
)
|
||||
if docked and docked is not PayloadSentinel.DEFAULT:
|
||||
self._docked = cv.boolean(docked)
|
||||
|
||||
if (
|
||||
|
@ -294,8 +302,10 @@ class MqttVacuum(MqttEntity, VacuumEntity):
|
|||
):
|
||||
error = self._templates[
|
||||
CONF_ERROR_TEMPLATE
|
||||
].async_render_with_possible_json_value(msg.payload, None)
|
||||
if error is not None:
|
||||
].async_render_with_possible_json_value(
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
)
|
||||
if error is not PayloadSentinel.DEFAULT:
|
||||
self._error = cv.string(error)
|
||||
|
||||
if self._docked:
|
||||
|
@ -316,8 +326,10 @@ class MqttVacuum(MqttEntity, VacuumEntity):
|
|||
):
|
||||
fan_speed = self._templates[
|
||||
CONF_FAN_SPEED_TEMPLATE
|
||||
].async_render_with_possible_json_value(msg.payload, None)
|
||||
if fan_speed:
|
||||
].async_render_with_possible_json_value(
|
||||
msg.payload, PayloadSentinel.DEFAULT
|
||||
)
|
||||
if fan_speed and fan_speed is not PayloadSentinel.DEFAULT:
|
||||
self._fan_speed = fan_speed
|
||||
|
||||
get_mqtt_data(self.hass).state_write_requests.write_state_request(self)
|
||||
|
|
Loading…
Reference in New Issue