1 """Support for MQTT locks."""
3 from __future__
import annotations
5 from collections.abc
import Callable
10 import voluptuous
as vol
27 from .
import subscription
28 from .config
import MQTT_RW_SCHEMA
30 CONF_COMMAND_TEMPLATE,
37 from .entity
import MqttEntity, async_setup_entity_entry_helper
44 from .schemas
import MQTT_ENTITY_COMMON_SCHEMA
46 _LOGGER = logging.getLogger(__name__)
50 CONF_CODE_FORMAT =
"code_format"
52 CONF_PAYLOAD_LOCK =
"payload_lock"
53 CONF_PAYLOAD_UNLOCK =
"payload_unlock"
54 CONF_PAYLOAD_OPEN =
"payload_open"
56 CONF_STATE_LOCKED =
"state_locked"
57 CONF_STATE_LOCKING =
"state_locking"
59 CONF_STATE_UNLOCKED =
"state_unlocked"
60 CONF_STATE_UNLOCKING =
"state_unlocking"
61 CONF_STATE_JAMMED =
"state_jammed"
63 DEFAULT_NAME =
"MQTT Lock"
64 DEFAULT_PAYLOAD_LOCK =
"LOCK"
65 DEFAULT_PAYLOAD_UNLOCK =
"UNLOCK"
66 DEFAULT_PAYLOAD_OPEN =
"OPEN"
67 DEFAULT_PAYLOAD_RESET =
"None"
68 DEFAULT_STATE_LOCKED =
"LOCKED"
69 DEFAULT_STATE_LOCKING =
"LOCKING"
70 DEFAULT_STATE_OPEN =
"OPEN"
71 DEFAULT_STATE_OPENING =
"OPENING"
72 DEFAULT_STATE_UNLOCKED =
"UNLOCKED"
73 DEFAULT_STATE_UNLOCKING =
"UNLOCKING"
74 DEFAULT_STATE_JAMMED =
"JAMMED"
76 MQTT_LOCK_ATTRIBUTES_BLOCKED = frozenset(
79 lock.ATTR_CODE_FORMAT,
83 PLATFORM_SCHEMA_MODERN = MQTT_RW_SCHEMA.extend(
85 vol.Optional(CONF_CODE_FORMAT): cv.is_regex,
86 vol.Optional(CONF_COMMAND_TEMPLATE): cv.template,
87 vol.Optional(CONF_NAME): vol.Any(cv.string,
None),
88 vol.Optional(CONF_PAYLOAD_LOCK, default=DEFAULT_PAYLOAD_LOCK): cv.string,
89 vol.Optional(CONF_PAYLOAD_UNLOCK, default=DEFAULT_PAYLOAD_UNLOCK): cv.string,
90 vol.Optional(CONF_PAYLOAD_OPEN): cv.string,
91 vol.Optional(CONF_PAYLOAD_RESET, default=DEFAULT_PAYLOAD_RESET): cv.string,
92 vol.Optional(CONF_STATE_JAMMED, default=DEFAULT_STATE_JAMMED): cv.string,
93 vol.Optional(CONF_STATE_LOCKED, default=DEFAULT_STATE_LOCKED): cv.string,
94 vol.Optional(CONF_STATE_LOCKING, default=DEFAULT_STATE_LOCKING): cv.string,
95 vol.Optional(CONF_STATE_OPEN, default=DEFAULT_STATE_OPEN): cv.string,
96 vol.Optional(CONF_STATE_OPENING, default=DEFAULT_STATE_OPENING): cv.string,
97 vol.Optional(CONF_STATE_UNLOCKED, default=DEFAULT_STATE_UNLOCKED): cv.string,
98 vol.Optional(CONF_STATE_UNLOCKING, default=DEFAULT_STATE_UNLOCKING): cv.string,
99 vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
101 ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
103 DISCOVERY_SCHEMA = PLATFORM_SCHEMA_MODERN.extend({}, extra=vol.REMOVE_EXTRA)
105 STATE_CONFIG_KEYS = [
112 CONF_STATE_UNLOCKING,
118 config_entry: ConfigEntry,
119 async_add_entities: AddEntitiesCallback,
121 """Set up MQTT lock through YAML and through MQTT discovery."""
129 PLATFORM_SCHEMA_MODERN,
134 """Representation of a lock that can be toggled using MQTT."""
136 _default_name = DEFAULT_NAME
137 _entity_id_format = lock.ENTITY_ID_FORMAT
138 _attributes_extra_blocked = MQTT_LOCK_ATTRIBUTES_BLOCKED
140 _compiled_pattern: re.Pattern[Any] |
None
142 _valid_states: list[str]
143 _command_template: Callable[
144 [PublishPayloadType, TemplateVarsType], PublishPayloadType
146 _value_template: Callable[[ReceivePayloadType], ReceivePayloadType]
150 """Return the config schema."""
151 return DISCOVERY_SCHEMA
154 """(Re)Setup the entity."""
156 optimistic := config[CONF_OPTIMISTIC]
157 or config.get(CONF_STATE_TOPIC)
is None
169 config.get(CONF_COMMAND_TEMPLATE), entity=self
173 config.get(CONF_VALUE_TEMPLATE),
175 ).async_render_with_possible_json_value
178 if CONF_PAYLOAD_OPEN
in config:
181 self.
_valid_states_valid_states = [config[state]
for state
in STATE_CONFIG_KEYS]
185 """Handle new lock state messages."""
187 if not payload.strip():
189 "Ignoring empty payload '%s' after rendering for topic %s",
194 if payload == self.
_config_config[CONF_PAYLOAD_RESET]:
207 """(Re)Subscribe to topics."""
217 "_attr_is_unlocking",
222 """(Re)Subscribe to topics."""
223 subscription.async_subscribe_topics_internal(self.
hasshasshass, self.
_sub_state_sub_state)
228 This method is a coroutine.
230 tpl_vars: TemplateVarsType = {
231 ATTR_CODE: kwargs.get(ATTR_CODE)
if kwargs
else None
241 """Unlock the device.
243 This method is a coroutine.
245 tpl_vars: TemplateVarsType = {
246 ATTR_CODE: kwargs.get(ATTR_CODE)
if kwargs
else None
256 """Open the door latch.
258 This method is a coroutine.
260 tpl_vars: TemplateVarsType = {
261 ATTR_CODE: kwargs.get(ATTR_CODE)
if kwargs
else None
None async_publish_with_config(self, str topic, PublishPayloadType payload)
bool add_subscription(self, str state_topic_config_key, Callable[[ReceiveMessage], None] msg_callback, set[str]|None tracked_attributes, bool disable_encoding=False)
None _message_received(self, ReceiveMessage msg)
None async_open(self, **Any kwargs)
None async_unlock(self, **Any kwargs)
vol.Schema config_schema()
None async_lock(self, **Any kwargs)
None _subscribe_topics(self)
None _setup_from_config(self, ConfigType config)
None _prepare_subscribe_topics(self)
None async_write_ha_state(self)
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)
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)