Add subentry support for MQTT siren device (#154220)

This commit is contained in:
Jan Bouwhuis
2025-10-14 16:45:48 +02:00
committed by GitHub
parent 28405e2b04
commit 8b6fb05ee4
6 changed files with 157 additions and 9 deletions

View File

@@ -150,6 +150,7 @@ from .const import (
CONF_ACTION_TOPIC,
CONF_AVAILABILITY_TEMPLATE,
CONF_AVAILABILITY_TOPIC,
CONF_AVAILABLE_TONES,
CONF_BIRTH_MESSAGE,
CONF_BLUE_TEMPLATE,
CONF_BRIGHTNESS_COMMAND_TEMPLATE,
@@ -307,6 +308,8 @@ from .const import (
CONF_STATE_VALUE_TEMPLATE,
CONF_STEP,
CONF_SUGGESTED_DISPLAY_PRECISION,
CONF_SUPPORT_DURATION,
CONF_SUPPORT_VOLUME_SET,
CONF_SUPPORTED_COLOR_MODES,
CONF_SUPPORTED_FEATURES,
CONF_SWING_HORIZONTAL_MODE_COMMAND_TEMPLATE,
@@ -460,6 +463,7 @@ SUBENTRY_PLATFORMS = [
Platform.NUMBER,
Platform.SELECT,
Platform.SENSOR,
Platform.SIREN,
Platform.SWITCH,
]
@@ -1163,6 +1167,7 @@ ENTITY_CONFIG_VALIDATOR: dict[
Platform.NOTIFY.value: None,
Platform.NUMBER.value: validate_number_platform_config,
Platform.SELECT: None,
Platform.SIREN: None,
Platform.SENSOR.value: validate_sensor_platform_config,
Platform.SWITCH.value: None,
}
@@ -1419,6 +1424,7 @@ PLATFORM_ENTITY_FIELDS: dict[str, dict[str, PlatformField]] = {
default=None,
),
},
Platform.SIREN: {},
Platform.SWITCH.value: {
CONF_DEVICE_CLASS: PlatformField(
selector=SWITCH_DEVICE_CLASS_SELECTOR, required=False
@@ -3181,6 +3187,71 @@ PLATFORM_MQTT_FIELDS: dict[str, dict[str, PlatformField]] = {
section="advanced_settings",
),
},
Platform.SIREN: {
CONF_COMMAND_TOPIC: PlatformField(
selector=TEXT_SELECTOR,
required=True,
validator=valid_publish_topic,
error="invalid_publish_topic",
),
CONF_COMMAND_TEMPLATE: PlatformField(
selector=TEMPLATE_SELECTOR,
required=False,
validator=validate(cv.template),
error="invalid_template",
),
CONF_STATE_TOPIC: PlatformField(
selector=TEXT_SELECTOR,
required=False,
validator=valid_subscribe_topic,
error="invalid_subscribe_topic",
),
CONF_VALUE_TEMPLATE: PlatformField(
selector=TEMPLATE_SELECTOR,
required=False,
validator=validate(cv.template),
error="invalid_template",
),
CONF_PAYLOAD_OFF: PlatformField(
selector=TEXT_SELECTOR,
required=False,
default=DEFAULT_PAYLOAD_OFF,
),
CONF_PAYLOAD_ON: PlatformField(
selector=TEXT_SELECTOR,
required=False,
default=DEFAULT_PAYLOAD_ON,
),
CONF_STATE_OFF: PlatformField(
selector=TEXT_SELECTOR,
required=False,
),
CONF_STATE_ON: PlatformField(
selector=TEXT_SELECTOR,
required=False,
),
CONF_AVAILABLE_TONES: PlatformField(
selector=OPTIONS_SELECTOR,
required=False,
),
CONF_SUPPORT_DURATION: PlatformField(
selector=BOOLEAN_SELECTOR,
required=False,
),
CONF_SUPPORT_VOLUME_SET: PlatformField(
selector=BOOLEAN_SELECTOR,
required=False,
),
CONF_RETAIN: PlatformField(selector=BOOLEAN_SELECTOR, required=False),
CONF_OPTIMISTIC: PlatformField(selector=BOOLEAN_SELECTOR, required=False),
CONF_COMMAND_OFF_TEMPLATE: PlatformField(
selector=TEMPLATE_SELECTOR,
required=False,
validator=validate(cv.template),
error="invalid_template",
section="siren_advanced_settings",
),
},
Platform.SWITCH.value: {
CONF_COMMAND_TOPIC: PlatformField(
selector=TEXT_SELECTOR,

View File

@@ -30,6 +30,7 @@ CONF_AVAILABILITY = "availability"
CONF_AVAILABILITY_MODE = "availability_mode"
CONF_AVAILABILITY_TEMPLATE = "availability_template"
CONF_AVAILABILITY_TOPIC = "availability_topic"
CONF_AVAILABLE_TONES = "available_tones"
CONF_BROKER = "broker"
CONF_BIRTH_MESSAGE = "birth_message"
CONF_CODE_ARM_REQUIRED = "code_arm_required"
@@ -200,6 +201,8 @@ CONF_STATE_UNLOCKED = "state_unlocked"
CONF_STATE_UNLOCKING = "state_unlocking"
CONF_STEP = "step"
CONF_SUGGESTED_DISPLAY_PRECISION = "suggested_display_precision"
CONF_SUPPORT_DURATION = "support_duration"
CONF_SUPPORT_VOLUME_SET = "support_volume_set"
CONF_SUPPORTED_COLOR_MODES = "supported_color_modes"
CONF_SWING_HORIZONTAL_MODE_COMMAND_TEMPLATE = "swing_horizontal_mode_command_template"
CONF_SWING_HORIZONTAL_MODE_COMMAND_TOPIC = "swing_horizontal_mode_command_topic"

View File

@@ -39,10 +39,18 @@ from homeassistant.util.json import JSON_DECODE_EXCEPTIONS, json_loads_object
from . import subscription
from .config import MQTT_RW_SCHEMA
from .const import (
CONF_AVAILABLE_TONES,
CONF_COMMAND_OFF_TEMPLATE,
CONF_COMMAND_TEMPLATE,
CONF_COMMAND_TOPIC,
CONF_STATE_OFF,
CONF_STATE_ON,
CONF_STATE_TOPIC,
CONF_STATE_VALUE_TEMPLATE,
CONF_SUPPORT_DURATION,
CONF_SUPPORT_VOLUME_SET,
DEFAULT_PAYLOAD_OFF,
DEFAULT_PAYLOAD_ON,
PAYLOAD_EMPTY_JSON,
PAYLOAD_NONE,
)
@@ -58,18 +66,9 @@ from .schemas import MQTT_ENTITY_COMMON_SCHEMA
PARALLEL_UPDATES = 0
DEFAULT_NAME = "MQTT Siren"
DEFAULT_PAYLOAD_ON = "ON"
DEFAULT_PAYLOAD_OFF = "OFF"
ENTITY_ID_FORMAT = siren.DOMAIN + ".{}"
CONF_AVAILABLE_TONES = "available_tones"
CONF_COMMAND_OFF_TEMPLATE = "command_off_template"
CONF_STATE_ON = "state_on"
CONF_STATE_OFF = "state_off"
CONF_SUPPORT_DURATION = "support_duration"
CONF_SUPPORT_VOLUME_SET = "support_volume_set"
STATE = "state"
PLATFORM_SCHEMA_MODERN = MQTT_RW_SCHEMA.extend(

View File

@@ -318,6 +318,7 @@
"title": "Configure MQTT device \"{mqtt_device}\"",
"description": "Please configure MQTT specific details for {platform} entity \"{entity}\":",
"data": {
"available_tones": "Available Tones",
"blue_template": "Blue template",
"brightness_template": "Brightness template",
"code": "Alarm code",
@@ -360,12 +361,15 @@
"state_topic": "State topic",
"state_value_template": "State value template",
"step": "Step",
"support_duration": "Duration support",
"support_volume_set": "Set volume support",
"supported_color_modes": "Supported color modes",
"url_template": "URL template",
"url_topic": "URL topic",
"value_template": "Value template"
},
"data_description": {
"available_tones": "The siren supports tones. The `tone` variable will become available for use in the \"Command template\" setting. [Learn more.]({url}#available_tones)",
"blue_template": "[Template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to extract blue color from the state payload value. Expected result of the template is an integer from 0-255 range.",
"brightness_template": "[Template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to extract brightness from the state payload value. Expected result of the template is an integer from 0-255 range.",
"code": "Specifies a code to enable or disable the alarm in the frontend. Note that this blocks sending MQTT message commands to the remote device if the code validation fails. [Learn more.]({url}#code)",
@@ -407,6 +411,8 @@
"state_template": "[Template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to extract state from the state payload value.",
"state_topic": "The MQTT topic subscribed to receive {platform} state values. [Learn more.]({url}#state_topic)",
"step": "Step value. Smallest value 0.001.",
"support_duration": "The siren supports setting a duration in second. The `duration` variable will become available for use in the \"Command template\" setting. [Learn more.]({url}#support_duration)",
"support_volume_set": "The siren supports setting a volume. The `tone` variable will become available for use in the \"Command template\" setting. [Learn more.]({url}#support_volume_set)",
"supported_color_modes": "A list of color modes supported by the light. Possible color modes are On/Off, Brightness, Color temperature, HS, XY, RGB, RGBW, RGBWW, White. Note that if On/Off or Brightness are used, that must be the only value in the list. [Learn more.]({url}#supported_color_modes)",
"url_template": "[Template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to extract an URL from the received URL topic payload value. [Learn more.]({url}#url_template)",
"url_topic": "The MQTT topic subscribed to receive messages containing the image URL. [Learn more.]({url}#url_topic)",
@@ -910,6 +916,15 @@
"target_humidity_state_topic": "The MQTT topic to subscribe for changes of the target humidity. [Learn more.]({url}#humidity_state_topic)"
}
},
"siren_advanced_settings": {
"name": "Advanced siren settings",
"data": {
"command_off_template": "Command \"off\" template"
},
"data_description": {
"command_off_template": "The [template]({templating_url}#using-command-templates-with-mqtt) for \"off\" state changes. By default the \"[Command template]({url}#command_template)\" will be used. [Learn more.]({url}#command_off_template)"
}
},
"target_temperature_settings": {
"name": "Target temperature settings",
"data": {
@@ -1338,6 +1353,7 @@
"number": "[%key:component::number::title%]",
"select": "[%key:component::select::title%]",
"sensor": "[%key:component::sensor::title%]",
"siren": "[%key:component::siren::title%]",
"switch": "[%key:component::switch::title%]"
}
},

View File

@@ -565,6 +565,25 @@ MOCK_SUBENTRY_SENSOR_COMPONENT_LAST_RESET = {
"entity_picture": "https://example.com/e9261f6feed443e7b7d5f3fbe2a47412",
},
}
MOCK_SUBENTRY_SIREN_COMPONENT = {
"3faf1318023c46c5aea26707eeb6f12e": {
"platform": "siren",
"name": "Siren",
"entity_category": None,
"command_topic": "test-topic",
"state_topic": "test-topic",
"command_template": "{{ value }}",
"command_off_template": "{{ value }}",
"value_template": "{{ value_json.value }}",
"payload_off": "OFF",
"payload_on": "ON",
"available_tones": ["Happy hour", "Cooling alarm"],
"support_volume_set": True,
"support_duration": True,
"entity_picture": "https://example.com/3faf1318023c46c5aea26707eeb6f12e",
"optimistic": True,
},
}
MOCK_SUBENTRY_SWITCH_COMPONENT = {
"3faf1318016c46c5aea26707eeb6f12e": {
"platform": "switch",
@@ -698,6 +717,10 @@ MOCK_SENSOR_SUBENTRY_DATA_LAST_RESET_TEMPLATE = {
"device": MOCK_SUBENTRY_DEVICE_DATA | {"mqtt_settings": {"qos": 0}},
"components": MOCK_SUBENTRY_SENSOR_COMPONENT_LAST_RESET,
}
MOCK_SIREN_SUBENTRY_DATA = {
"device": MOCK_SUBENTRY_DEVICE_DATA | {"mqtt_settings": {"qos": 0}},
"components": MOCK_SUBENTRY_SIREN_COMPONENT,
}
MOCK_SWITCH_SUBENTRY_DATA = {
"device": MOCK_SUBENTRY_DEVICE_DATA | {"mqtt_settings": {"qos": 0}},
"components": MOCK_SUBENTRY_SWITCH_COMPONENT,

View File

@@ -60,6 +60,7 @@ from .common import (
MOCK_SENSOR_SUBENTRY_DATA,
MOCK_SENSOR_SUBENTRY_DATA_LAST_RESET_TEMPLATE,
MOCK_SENSOR_SUBENTRY_DATA_STATE_CLASS,
MOCK_SIREN_SUBENTRY_DATA,
MOCK_SWITCH_SUBENTRY_DATA,
)
@@ -3655,6 +3656,41 @@ async def test_migrate_of_incompatible_config_entry(
"Milk notifier Energy",
id="sensor_total",
),
pytest.param(
MOCK_SIREN_SUBENTRY_DATA,
{"name": "Milk notifier", "mqtt_settings": {"qos": 0}},
{"name": "Siren"},
{},
(),
{
"command_topic": "test-topic",
"command_template": "{{ value }}",
"state_topic": "test-topic",
"value_template": "{{ value_json.value }}",
"optimistic": True,
"available_tones": ["Happy hour", "Cooling alarm"],
"support_duration": True,
"support_volume_set": True,
"siren_advanced_settings": {
"command_off_template": "{{ value }}",
},
},
(
(
{"command_topic": "test-topic#invalid"},
{"command_topic": "invalid_publish_topic"},
),
(
{
"command_topic": "test-topic",
"state_topic": "test-topic#invalid",
},
{"state_topic": "invalid_subscribe_topic"},
),
),
"Milk notifier Siren",
id="siren",
),
pytest.param(
MOCK_SWITCH_SUBENTRY_DATA,
{"name": "Milk notifier", "mqtt_settings": {"qos": 0}},