1 """Support for MQTT sirens."""
3 from __future__
import annotations
5 from collections.abc
import Callable
7 from typing
import Any, cast
9 import voluptuous
as vol
20 SirenTurnOnServiceParameters,
21 process_turn_on_params,
39 from .
import subscription
40 from .config
import MQTT_RW_SCHEMA
42 CONF_COMMAND_TEMPLATE,
45 CONF_STATE_VALUE_TEMPLATE,
49 from .entity
import MqttEntity, async_setup_entity_entry_helper
56 from .schemas
import MQTT_ENTITY_COMMON_SCHEMA
60 DEFAULT_NAME =
"MQTT Siren"
61 DEFAULT_PAYLOAD_ON =
"ON"
62 DEFAULT_PAYLOAD_OFF =
"OFF"
64 ENTITY_ID_FORMAT = siren.DOMAIN +
".{}"
66 CONF_AVAILABLE_TONES =
"available_tones"
67 CONF_COMMAND_OFF_TEMPLATE =
"command_off_template"
68 CONF_STATE_ON =
"state_on"
69 CONF_STATE_OFF =
"state_off"
70 CONF_SUPPORT_DURATION =
"support_duration"
71 CONF_SUPPORT_VOLUME_SET =
"support_volume_set"
75 PLATFORM_SCHEMA_MODERN = MQTT_RW_SCHEMA.extend(
77 vol.Optional(CONF_AVAILABLE_TONES): cv.ensure_list,
78 vol.Optional(CONF_COMMAND_TEMPLATE): cv.template,
79 vol.Optional(CONF_COMMAND_OFF_TEMPLATE): cv.template,
80 vol.Optional(CONF_NAME): vol.Any(cv.string,
None),
81 vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string,
82 vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string,
83 vol.Optional(CONF_STATE_OFF): cv.string,
84 vol.Optional(CONF_STATE_ON): cv.string,
85 vol.Optional(CONF_STATE_VALUE_TEMPLATE): cv.template,
86 vol.Optional(CONF_SUPPORT_DURATION, default=
True): cv.boolean,
87 vol.Optional(CONF_SUPPORT_VOLUME_SET, default=
True): cv.boolean,
89 ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
91 DISCOVERY_SCHEMA = vol.All(PLATFORM_SCHEMA_MODERN.extend({}, extra=vol.REMOVE_EXTRA))
93 MQTT_SIREN_ATTRIBUTES_BLOCKED = frozenset(
102 SUPPORTED_BASE = SirenEntityFeature.TURN_OFF | SirenEntityFeature.TURN_ON
104 SUPPORTED_ATTRIBUTES = {
105 ATTR_DURATION: SirenEntityFeature.DURATION,
106 ATTR_TONE: SirenEntityFeature.TONES,
107 ATTR_VOLUME_LEVEL: SirenEntityFeature.VOLUME_SET,
110 _LOGGER = logging.getLogger(__name__)
115 config_entry: ConfigEntry,
116 async_add_entities: AddEntitiesCallback,
118 """Set up MQTT siren through YAML and through MQTT discovery."""
126 PLATFORM_SCHEMA_MODERN,
131 """Representation of a siren that can be controlled using MQTT."""
133 _default_name = DEFAULT_NAME
134 _entity_id_format = ENTITY_ID_FORMAT
135 _attributes_extra_blocked = MQTT_SIREN_ATTRIBUTES_BLOCKED
136 _extra_attributes: dict[str, Any]
138 _command_templates: dict[
139 str, Callable[[PublishPayloadType, TemplateVarsType], PublishPayloadType] |
None
141 _value_template: Callable[[ReceivePayloadType], ReceivePayloadType]
148 """Return the config schema."""
149 return DISCOVERY_SCHEMA
152 """(Re)Setup the entity."""
154 state_on: str |
None = config.get(CONF_STATE_ON)
155 self.
_state_on_state_on = state_on
if state_on
else config[CONF_PAYLOAD_ON]
157 state_off: str |
None = config.get(CONF_STATE_OFF)
158 self.
_state_off_state_off = state_off
if state_off
else config[CONF_PAYLOAD_OFF]
162 _supported_features = SUPPORTED_BASE
163 if config[CONF_SUPPORT_DURATION]:
164 _supported_features |= SirenEntityFeature.DURATION
167 if config.get(CONF_AVAILABLE_TONES):
168 _supported_features |= SirenEntityFeature.TONES
172 if config[CONF_SUPPORT_VOLUME_SET]:
173 _supported_features |= SirenEntityFeature.VOLUME_SET
177 self.
_optimistic_optimistic = config[CONF_OPTIMISTIC]
or CONF_STATE_TOPIC
not in config
181 command_template: Template |
None = config.get(CONF_COMMAND_TEMPLATE)
182 command_off_template: Template |
None = (
183 config.get(CONF_COMMAND_OFF_TEMPLATE)
or command_template
187 command_template, entity=self
192 command_off_template, entity=self
194 if command_off_template
198 config.get(CONF_STATE_VALUE_TEMPLATE),
200 ).async_render_with_possible_json_value
204 """Handle new MQTT state messages."""
206 if not payload
or payload == PAYLOAD_EMPTY_JSON:
208 "Ignoring empty payload '%s' after rendering for topic %s",
213 json_payload: dict[str, Any] = {}
215 json_payload = {STATE: payload}
221 "JSON payload detected after processing payload '%s' on"
227 except JSON_DECODE_EXCEPTIONS:
230 "No valid (JSON) payload detected after processing payload"
237 if STATE
in json_payload:
238 if json_payload[STATE] == self.
_state_on_state_on:
240 if json_payload[STATE] == self.
_state_off_state_off:
242 if json_payload[STATE] == PAYLOAD_NONE:
244 del json_payload[STATE]
249 params: SirenTurnOnServiceParameters
250 params = vol.All(TURN_ON_SCHEMA)(json_payload)
251 except vol.MultipleInvalid
as invalid_siren_parameters:
253 "Unable to update siren state attributes from payload '%s': %s",
255 invalid_siren_parameters,
265 """(Re)Subscribe to topics."""
269 {
"_attr_is_on",
"_extra_attributes"},
276 """(Re)Subscribe to topics."""
277 subscription.async_subscribe_topics_internal(self.
hasshasshass, self.
_sub_state_sub_state)
281 """Return the state attributes."""
284 if hasattr(self,
"_attr_extra_state_attributes")
296 variables: dict[str, Any] |
None =
None,
298 """Publish MQTT payload with optional command template."""
299 template_variables: dict[str, Any] = {STATE: value}
300 if variables
is not None:
301 template_variables.update(variables)
303 payload = command_template(value, template_variables)
306 if payload
and str(payload) != PAYLOAD_NONE:
310 """Turn the siren on.
312 This method is a coroutine.
316 CONF_COMMAND_TEMPLATE,
317 self.
_config_config[CONF_PAYLOAD_ON],
322 _LOGGER.debug(
"Writing state attributes %s", kwargs)
324 self.
_update_update(cast(SirenTurnOnServiceParameters, kwargs))
328 """Turn the siren off.
330 This method is a coroutine.
334 CONF_COMMAND_OFF_TEMPLATE,
335 self.
_config_config[CONF_PAYLOAD_OFF],
343 def _update(self, data: SirenTurnOnServiceParameters) ->
None:
344 """Update the extra siren state attributes."""
348 for attribute, support
in SUPPORTED_ATTRIBUTES.items()
350 and attribute
in data
351 and (data_attr := data[attribute])
_attr_extra_state_attributes
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)
VolSchemaType config_schema()
None _subscribe_topics(self)
dict[str, Any]|None extra_state_attributes(self)
None _setup_from_config(self, ConfigType config)
None _update(self, SirenTurnOnServiceParameters data)
None _prepare_subscribe_topics(self)
None async_turn_off(self, **Any kwargs)
None _state_message_received(self, ReceiveMessage msg)
None _async_publish(self, str topic, str template, Any value, dict[str, Any]|None variables=None)
None async_turn_on(self, **Any kwargs)
None async_write_ha_state(self)
web.Response get(self, web.Request request, str config_key)
IssData update(pyiss.ISS iss)
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)
SirenTurnOnServiceParameters process_turn_on_params(SirenEntity siren, SirenTurnOnServiceParameters params)
JsonObjectType json_loads_object(bytes|bytearray|memoryview|str obj)