Home Assistant Unofficial Reference 2024.12.1
text.py
Go to the documentation of this file.
1 """Support for MQTT text platform."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable
6 import logging
7 import re
8 from typing import Any
9 
10 import voluptuous as vol
11 
12 from homeassistant.components import text
13 from homeassistant.components.text import TextEntity
14 from homeassistant.config_entries import ConfigEntry
15 from homeassistant.const import (
16  CONF_MODE,
17  CONF_NAME,
18  CONF_OPTIMISTIC,
19  CONF_VALUE_TEMPLATE,
20  MAX_LENGTH_STATE_STATE,
21 )
22 from homeassistant.core import HomeAssistant, callback
23 from homeassistant.helpers import config_validation as cv
24 from homeassistant.helpers.entity_platform import AddEntitiesCallback
25 from homeassistant.helpers.service_info.mqtt import ReceivePayloadType
26 from homeassistant.helpers.typing import ConfigType, VolSchemaType
27 
28 from . import subscription
29 from .config import MQTT_RW_SCHEMA
30 from .const import CONF_COMMAND_TEMPLATE, CONF_COMMAND_TOPIC, CONF_STATE_TOPIC
31 from .entity import MqttEntity, async_setup_entity_entry_helper
32 from .models import (
33  MqttCommandTemplate,
34  MqttValueTemplate,
35  PublishPayloadType,
36  ReceiveMessage,
37 )
38 from .schemas import MQTT_ENTITY_COMMON_SCHEMA
39 from .util import check_state_too_long
40 
41 _LOGGER = logging.getLogger(__name__)
42 
43 PARALLEL_UPDATES = 0
44 
45 CONF_MAX = "max"
46 CONF_MIN = "min"
47 CONF_PATTERN = "pattern"
48 
49 DEFAULT_NAME = "MQTT Text"
50 DEFAULT_PAYLOAD_RESET = "None"
51 
52 MQTT_TEXT_ATTRIBUTES_BLOCKED = frozenset(
53  {
54  text.ATTR_MAX,
55  text.ATTR_MIN,
56  text.ATTR_MODE,
57  text.ATTR_PATTERN,
58  }
59 )
60 
61 
62 def valid_text_size_configuration(config: ConfigType) -> ConfigType:
63  """Validate that the text length configuration is valid, throws if it isn't."""
64  if config[CONF_MIN] > config[CONF_MAX]:
65  raise vol.Invalid("text length min must be <= max")
66  if config[CONF_MAX] > MAX_LENGTH_STATE_STATE:
67  raise vol.Invalid(f"max text length must be <= {MAX_LENGTH_STATE_STATE}")
68 
69  return config
70 
71 
72 _PLATFORM_SCHEMA_BASE = MQTT_RW_SCHEMA.extend(
73  {
74  vol.Optional(CONF_COMMAND_TEMPLATE): cv.template,
75  vol.Optional(CONF_NAME): vol.Any(cv.string, None),
76  vol.Optional(CONF_MAX, default=MAX_LENGTH_STATE_STATE): cv.positive_int,
77  vol.Optional(CONF_MIN, default=0): cv.positive_int,
78  vol.Optional(CONF_MODE, default=text.TextMode.TEXT): vol.In(
79  [text.TextMode.TEXT, text.TextMode.PASSWORD]
80  ),
81  vol.Optional(CONF_PATTERN): cv.is_regex,
82  vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
83  },
84 ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
85 
86 
87 DISCOVERY_SCHEMA = vol.All(
88  _PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA),
89  valid_text_size_configuration,
90 )
91 
92 PLATFORM_SCHEMA_MODERN = vol.All(_PLATFORM_SCHEMA_BASE, valid_text_size_configuration)
93 
94 
96  hass: HomeAssistant,
97  config_entry: ConfigEntry,
98  async_add_entities: AddEntitiesCallback,
99 ) -> None:
100  """Set up MQTT text through YAML and through MQTT discovery."""
102  hass,
103  config_entry,
104  MqttTextEntity,
105  text.DOMAIN,
106  async_add_entities,
107  DISCOVERY_SCHEMA,
108  PLATFORM_SCHEMA_MODERN,
109  )
110 
111 
113  """Representation of the MQTT text entity."""
114 
115  _attr_native_value: str | None = None
116  _attributes_extra_blocked = MQTT_TEXT_ATTRIBUTES_BLOCKED
117  _default_name = DEFAULT_NAME
118  _entity_id_format = text.ENTITY_ID_FORMAT
119 
120  _compiled_pattern: re.Pattern[Any] | None
121  _optimistic: bool
122  _command_template: Callable[[PublishPayloadType], PublishPayloadType]
123  _value_template: Callable[[ReceivePayloadType], ReceivePayloadType]
124 
125  @staticmethod
126  def config_schema() -> VolSchemaType:
127  """Return the config schema."""
128  return DISCOVERY_SCHEMA
129 
130  def _setup_from_config(self, config: ConfigType) -> None:
131  """(Re)Setup the entity."""
132  self._attr_native_max_attr_native_max = config[CONF_MAX]
133  self._attr_native_min_attr_native_min = config[CONF_MIN]
134  self._attr_mode_attr_mode = config[CONF_MODE]
135  self._compiled_pattern_compiled_pattern = config.get(CONF_PATTERN)
136  self._attr_pattern_attr_pattern = (
137  self._compiled_pattern_compiled_pattern.pattern if self._compiled_pattern_compiled_pattern else None
138  )
139 
140  self._command_template_command_template = MqttCommandTemplate(
141  config.get(CONF_COMMAND_TEMPLATE),
142  entity=self,
143  ).async_render
144  self._value_template_value_template = MqttValueTemplate(
145  config.get(CONF_VALUE_TEMPLATE),
146  entity=self,
147  ).async_render_with_possible_json_value
148  optimistic: bool = config[CONF_OPTIMISTIC]
149  self._optimistic_optimistic = optimistic or config.get(CONF_STATE_TOPIC) is None
150  self._attr_assumed_state_attr_assumed_state = bool(self._optimistic_optimistic)
151 
152  @callback
153  def _handle_state_message_received(self, msg: ReceiveMessage) -> None:
154  """Handle receiving state message via MQTT."""
155  payload = str(self._value_template_value_template(msg.payload))
156  if check_state_too_long(_LOGGER, payload, self.entity_identity_id, msg):
157  return
158  self._attr_native_value_attr_native_value = payload
159 
160  @callback
161  def _prepare_subscribe_topics(self) -> None:
162  """(Re)Subscribe to topics."""
163  self.add_subscriptionadd_subscription(
164  CONF_STATE_TOPIC,
165  self._handle_state_message_received_handle_state_message_received,
166  {"_attr_native_value"},
167  )
168 
169  async def _subscribe_topics(self) -> None:
170  """(Re)Subscribe to topics."""
171  subscription.async_subscribe_topics_internal(self.hasshasshass, self._sub_state_sub_state)
172 
173  async def async_set_value(self, value: str) -> None:
174  """Change the text."""
175  payload = self._command_template_command_template(value)
176  await self.async_publish_with_configasync_publish_with_config(self._config_config[CONF_COMMAND_TOPIC], payload)
177  if self._optimistic_optimistic:
178  self._attr_native_value_attr_native_value = value
179  self.async_write_ha_stateasync_write_ha_state()
None async_publish_with_config(self, str topic, PublishPayloadType payload)
Definition: entity.py:1377
bool add_subscription(self, str state_topic_config_key, Callable[[ReceiveMessage], None] msg_callback, set[str]|None tracked_attributes, bool disable_encoding=False)
Definition: entity.py:1484
None _setup_from_config(self, ConfigType config)
Definition: text.py:130
None _handle_state_message_received(self, ReceiveMessage msg)
Definition: text.py:153
None async_setup_entity_entry_helper(HomeAssistant hass, ConfigEntry entry, type[MqttEntity]|None entity_class, str domain, AddEntitiesCallback async_add_entities, VolSchemaType discovery_schema, VolSchemaType platform_schema_modern, dict[str, type[MqttEntity]]|None schema_class_mapping=None)
Definition: entity.py:245
ConfigType valid_text_size_configuration(ConfigType config)
Definition: text.py:62
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: text.py:99
bool check_state_too_long(logging.Logger logger, str proposed_state, str entity_id, ReceiveMessage msg)
Definition: util.py:372