diff --git a/homeassistant/components/mqtt/alarm_control_panel.py b/homeassistant/components/mqtt/alarm_control_panel.py index 825ad345272..72b01f3087b 100644 --- a/homeassistant/components/mqtt/alarm_control_panel.py +++ b/homeassistant/components/mqtt/alarm_control_panel.py @@ -97,6 +97,8 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend( } ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema) +DISCOVERY_SCHEMA = PLATFORM_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA) + async def async_setup_platform( hass: HomeAssistant, config: ConfigType, async_add_entities, discovery_info=None @@ -111,7 +113,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): setup = functools.partial( _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper(hass, alarm.DOMAIN, setup, PLATFORM_SCHEMA) + await async_setup_entry_helper(hass, alarm.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( @@ -135,7 +137,7 @@ class MqttAlarm(MqttEntity, alarm.AlarmControlPanelEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA + return DISCOVERY_SCHEMA def _setup_from_config(self, config): value_template = self._config.get(CONF_VALUE_TEMPLATE) diff --git a/homeassistant/components/mqtt/binary_sensor.py b/homeassistant/components/mqtt/binary_sensor.py index 70638f5cc76..213aabdb006 100644 --- a/homeassistant/components/mqtt/binary_sensor.py +++ b/homeassistant/components/mqtt/binary_sensor.py @@ -58,6 +58,8 @@ PLATFORM_SCHEMA = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend( } ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema) +DISCOVERY_SCHEMA = PLATFORM_SCHEMA.extend({}, extra=vol.REMOVE_EXTRA) + async def async_setup_platform( hass: HomeAssistant, config: ConfigType, async_add_entities, discovery_info=None @@ -72,7 +74,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): setup = functools.partial( _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper(hass, binary_sensor.DOMAIN, setup, PLATFORM_SCHEMA) + await async_setup_entry_helper(hass, binary_sensor.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( @@ -101,7 +103,7 @@ class MqttBinarySensor(MqttEntity, BinarySensorEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA + return DISCOVERY_SCHEMA def _setup_from_config(self, config): value_template = self._config.get(CONF_VALUE_TEMPLATE) diff --git a/homeassistant/components/mqtt/camera.py b/homeassistant/components/mqtt/camera.py index cc331c0008c..39457dbd629 100644 --- a/homeassistant/components/mqtt/camera.py +++ b/homeassistant/components/mqtt/camera.py @@ -37,6 +37,8 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend( } ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema) +DISCOVERY_SCHEMA = PLATFORM_SCHEMA.extend({}, extra=vol.REMOVE_EXTRA) + async def async_setup_platform( hass: HomeAssistant, config: ConfigType, async_add_entities, discovery_info=None @@ -51,7 +53,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): setup = functools.partial( _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper(hass, camera.DOMAIN, setup, PLATFORM_SCHEMA) + await async_setup_entry_helper(hass, camera.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( @@ -76,7 +78,7 @@ class MqttCamera(MqttEntity, Camera): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA + return DISCOVERY_SCHEMA async def _subscribe_topics(self): """(Re)Subscribe to topics.""" diff --git a/homeassistant/components/mqtt/climate.py b/homeassistant/components/mqtt/climate.py index fb19c5e7038..16d4ae695c1 100644 --- a/homeassistant/components/mqtt/climate.py +++ b/homeassistant/components/mqtt/climate.py @@ -268,6 +268,8 @@ PLATFORM_SCHEMA = SCHEMA_BASE.extend( } ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema) +DISCOVERY_SCHEMA = PLATFORM_SCHEMA.extend({}, extra=vol.REMOVE_EXTRA) + async def async_setup_platform( hass: HomeAssistant, async_add_entities, config: ConfigType, discovery_info=None @@ -282,7 +284,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): setup = functools.partial( _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper(hass, climate.DOMAIN, setup, PLATFORM_SCHEMA) + await async_setup_entry_helper(hass, climate.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( @@ -319,7 +321,7 @@ class MqttClimate(MqttEntity, ClimateEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA + return DISCOVERY_SCHEMA async def async_added_to_hass(self): """Handle being added to Home Assistant.""" diff --git a/homeassistant/components/mqtt/cover.py b/homeassistant/components/mqtt/cover.py index b48f39908fa..0af9d7d3739 100644 --- a/homeassistant/components/mqtt/cover.py +++ b/homeassistant/components/mqtt/cover.py @@ -142,53 +142,58 @@ def validate_options(value): return value +_PLATFORM_SCHEMA_BASE = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend( + { + vol.Optional(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, + vol.Optional(CONF_GET_POSITION_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, + vol.Optional(CONF_PAYLOAD_CLOSE, default=DEFAULT_PAYLOAD_CLOSE): vol.Any( + cv.string, None + ), + vol.Optional(CONF_PAYLOAD_OPEN, default=DEFAULT_PAYLOAD_OPEN): vol.Any( + cv.string, None + ), + vol.Optional(CONF_PAYLOAD_STOP, default=DEFAULT_PAYLOAD_STOP): vol.Any( + cv.string, None + ), + vol.Optional(CONF_POSITION_CLOSED, default=DEFAULT_POSITION_CLOSED): int, + vol.Optional(CONF_POSITION_OPEN, default=DEFAULT_POSITION_OPEN): int, + vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean, + vol.Optional(CONF_SET_POSITION_TEMPLATE): cv.template, + vol.Optional(CONF_SET_POSITION_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_STATE_CLOSED, default=STATE_CLOSED): cv.string, + vol.Optional(CONF_STATE_CLOSING, default=STATE_CLOSING): cv.string, + vol.Optional(CONF_STATE_OPEN, default=STATE_OPEN): cv.string, + vol.Optional(CONF_STATE_OPENING, default=STATE_OPENING): cv.string, + vol.Optional(CONF_STATE_STOPPED, default=DEFAULT_STATE_STOPPED): cv.string, + vol.Optional(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional( + CONF_TILT_CLOSED_POSITION, default=DEFAULT_TILT_CLOSED_POSITION + ): int, + vol.Optional(CONF_TILT_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_TILT_MAX, default=DEFAULT_TILT_MAX): int, + vol.Optional(CONF_TILT_MIN, default=DEFAULT_TILT_MIN): int, + vol.Optional(CONF_TILT_OPEN_POSITION, default=DEFAULT_TILT_OPEN_POSITION): int, + vol.Optional( + CONF_TILT_STATE_OPTIMISTIC, default=DEFAULT_TILT_OPTIMISTIC + ): cv.boolean, + vol.Optional(CONF_TILT_STATUS_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_TILT_STATUS_TEMPLATE): cv.template, + vol.Optional(CONF_VALUE_TEMPLATE): cv.template, + vol.Optional(CONF_GET_POSITION_TEMPLATE): cv.template, + vol.Optional(CONF_TILT_COMMAND_TEMPLATE): cv.template, + } +).extend(MQTT_ENTITY_COMMON_SCHEMA.schema) + PLATFORM_SCHEMA = vol.All( - mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend( - { - vol.Optional(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, - vol.Optional(CONF_GET_POSITION_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, - vol.Optional(CONF_PAYLOAD_CLOSE, default=DEFAULT_PAYLOAD_CLOSE): vol.Any( - cv.string, None - ), - vol.Optional(CONF_PAYLOAD_OPEN, default=DEFAULT_PAYLOAD_OPEN): vol.Any( - cv.string, None - ), - vol.Optional(CONF_PAYLOAD_STOP, default=DEFAULT_PAYLOAD_STOP): vol.Any( - cv.string, None - ), - vol.Optional(CONF_POSITION_CLOSED, default=DEFAULT_POSITION_CLOSED): int, - vol.Optional(CONF_POSITION_OPEN, default=DEFAULT_POSITION_OPEN): int, - vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean, - vol.Optional(CONF_SET_POSITION_TEMPLATE): cv.template, - vol.Optional(CONF_SET_POSITION_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_STATE_CLOSED, default=STATE_CLOSED): cv.string, - vol.Optional(CONF_STATE_CLOSING, default=STATE_CLOSING): cv.string, - vol.Optional(CONF_STATE_OPEN, default=STATE_OPEN): cv.string, - vol.Optional(CONF_STATE_OPENING, default=STATE_OPENING): cv.string, - vol.Optional(CONF_STATE_STOPPED, default=DEFAULT_STATE_STOPPED): cv.string, - vol.Optional(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional( - CONF_TILT_CLOSED_POSITION, default=DEFAULT_TILT_CLOSED_POSITION - ): int, - vol.Optional(CONF_TILT_COMMAND_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_TILT_MAX, default=DEFAULT_TILT_MAX): int, - vol.Optional(CONF_TILT_MIN, default=DEFAULT_TILT_MIN): int, - vol.Optional( - CONF_TILT_OPEN_POSITION, default=DEFAULT_TILT_OPEN_POSITION - ): int, - vol.Optional( - CONF_TILT_STATE_OPTIMISTIC, default=DEFAULT_TILT_OPTIMISTIC - ): cv.boolean, - vol.Optional(CONF_TILT_STATUS_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional(CONF_TILT_STATUS_TEMPLATE): cv.template, - vol.Optional(CONF_VALUE_TEMPLATE): cv.template, - vol.Optional(CONF_GET_POSITION_TEMPLATE): cv.template, - vol.Optional(CONF_TILT_COMMAND_TEMPLATE): cv.template, - } - ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema), + _PLATFORM_SCHEMA_BASE, + validate_options, +) + +DISCOVERY_SCHEMA = vol.All( + _PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA), validate_options, ) @@ -206,7 +211,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): setup = functools.partial( _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper(hass, cover.DOMAIN, setup, PLATFORM_SCHEMA) + await async_setup_entry_helper(hass, cover.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( @@ -235,7 +240,7 @@ class MqttCover(MqttEntity, CoverEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA + return DISCOVERY_SCHEMA def _setup_from_config(self, config): no_position = ( diff --git a/homeassistant/components/mqtt/device_tracker/schema_discovery.py b/homeassistant/components/mqtt/device_tracker/schema_discovery.py index d6688636bb2..f962d9208a4 100644 --- a/homeassistant/components/mqtt/device_tracker/schema_discovery.py +++ b/homeassistant/components/mqtt/device_tracker/schema_discovery.py @@ -37,15 +37,15 @@ PLATFORM_SCHEMA_DISCOVERY = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend( } ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema) +DISCOVERY_SCHEMA = PLATFORM_SCHEMA_DISCOVERY.extend({}, extra=vol.REMOVE_EXTRA) + async def async_setup_entry_from_discovery(hass, config_entry, async_add_entities): """Set up MQTT device tracker dynamically through MQTT discovery.""" setup = functools.partial( _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper( - hass, device_tracker.DOMAIN, setup, PLATFORM_SCHEMA_DISCOVERY - ) + await async_setup_entry_helper(hass, device_tracker.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( @@ -67,7 +67,7 @@ class MqttDeviceTracker(MqttEntity, TrackerEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA_DISCOVERY + return DISCOVERY_SCHEMA def _setup_from_config(self, config): """(Re)Setup the entity.""" diff --git a/homeassistant/components/mqtt/device_trigger.py b/homeassistant/components/mqtt/device_trigger.py index 42bd4d19132..78f52e58726 100644 --- a/homeassistant/components/mqtt/device_trigger.py +++ b/homeassistant/components/mqtt/device_trigger.py @@ -47,7 +47,6 @@ from .mixins import ( MQTT_ENTITY_DEVICE_INFO_SCHEMA, cleanup_device_registry, device_info_from_config, - validate_device_has_at_least_one_identifier, ) _LOGGER = logging.getLogger(__name__) @@ -85,7 +84,7 @@ TRIGGER_DISCOVERY_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend( vol.Required(CONF_TYPE): cv.string, vol.Optional(CONF_VALUE_TEMPLATE, default=None): vol.Any(None, cv.string), }, - validate_device_has_at_least_one_identifier, + extra=vol.REMOVE_EXTRA, ) DEVICE_TRIGGERS = "mqtt_device_triggers" diff --git a/homeassistant/components/mqtt/fan.py b/homeassistant/components/mqtt/fan.py index 28a187941bc..f950a4d2c60 100644 --- a/homeassistant/components/mqtt/fan.py +++ b/homeassistant/components/mqtt/fan.py @@ -113,6 +113,64 @@ def valid_preset_mode_configuration(config): return config +_PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend( + { + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, + vol.Optional(CONF_COMMAND_TEMPLATE): cv.template, + vol.Optional(CONF_OSCILLATION_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_OSCILLATION_COMMAND_TEMPLATE): cv.template, + vol.Optional(CONF_OSCILLATION_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_OSCILLATION_VALUE_TEMPLATE): cv.template, + vol.Optional(CONF_PERCENTAGE_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_PERCENTAGE_COMMAND_TEMPLATE): cv.template, + vol.Optional(CONF_PERCENTAGE_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_PERCENTAGE_VALUE_TEMPLATE): cv.template, + # CONF_PRESET_MODE_COMMAND_TOPIC and CONF_PRESET_MODES_LIST must be used together + vol.Inclusive( + CONF_PRESET_MODE_COMMAND_TOPIC, "preset_modes" + ): mqtt.valid_publish_topic, + vol.Inclusive( + CONF_PRESET_MODES_LIST, "preset_modes", default=[] + ): cv.ensure_list, + vol.Optional(CONF_PRESET_MODE_COMMAND_TEMPLATE): cv.template, + vol.Optional(CONF_PRESET_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_PRESET_MODE_VALUE_TEMPLATE): cv.template, + vol.Optional( + CONF_SPEED_RANGE_MIN, default=DEFAULT_SPEED_RANGE_MIN + ): cv.positive_int, + vol.Optional( + CONF_SPEED_RANGE_MAX, default=DEFAULT_SPEED_RANGE_MAX + ): cv.positive_int, + vol.Optional( + CONF_PAYLOAD_RESET_PERCENTAGE, default=DEFAULT_PAYLOAD_RESET + ): cv.string, + vol.Optional( + CONF_PAYLOAD_RESET_PRESET_MODE, default=DEFAULT_PAYLOAD_RESET + ): cv.string, + vol.Optional(CONF_PAYLOAD_HIGH_SPEED, default=SPEED_HIGH): cv.string, + vol.Optional(CONF_PAYLOAD_LOW_SPEED, default=SPEED_LOW): cv.string, + vol.Optional(CONF_PAYLOAD_MEDIUM_SPEED, default=SPEED_MEDIUM): cv.string, + vol.Optional(CONF_PAYLOAD_OFF_SPEED, default=SPEED_OFF): cv.string, + vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string, + vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string, + vol.Optional( + CONF_PAYLOAD_OSCILLATION_OFF, default=OSCILLATE_OFF_PAYLOAD + ): cv.string, + vol.Optional( + CONF_PAYLOAD_OSCILLATION_ON, default=OSCILLATE_ON_PAYLOAD + ): cv.string, + vol.Optional(CONF_SPEED_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional( + CONF_SPEED_LIST, + default=[SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH], + ): cv.ensure_list, + vol.Optional(CONF_SPEED_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_SPEED_VALUE_TEMPLATE): cv.template, + vol.Optional(CONF_STATE_VALUE_TEMPLATE): cv.template, + } +).extend(MQTT_ENTITY_COMMON_SCHEMA.schema) + PLATFORM_SCHEMA = vol.All( # CONF_SPEED_COMMAND_TOPIC, CONF_SPEED_LIST, CONF_SPEED_STATE_TOPIC, CONF_SPEED_VALUE_TEMPLATE and # Speeds SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH SPEED_OFF, @@ -124,63 +182,23 @@ PLATFORM_SCHEMA = vol.All( cv.deprecated(CONF_SPEED_LIST), cv.deprecated(CONF_SPEED_STATE_TOPIC), cv.deprecated(CONF_SPEED_VALUE_TEMPLATE), - mqtt.MQTT_RW_PLATFORM_SCHEMA.extend( - { - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, - vol.Optional(CONF_COMMAND_TEMPLATE): cv.template, - vol.Optional(CONF_OSCILLATION_COMMAND_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_OSCILLATION_COMMAND_TEMPLATE): cv.template, - vol.Optional(CONF_OSCILLATION_STATE_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional(CONF_OSCILLATION_VALUE_TEMPLATE): cv.template, - vol.Optional(CONF_PERCENTAGE_COMMAND_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_PERCENTAGE_COMMAND_TEMPLATE): cv.template, - vol.Optional(CONF_PERCENTAGE_STATE_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional(CONF_PERCENTAGE_VALUE_TEMPLATE): cv.template, - # CONF_PRESET_MODE_COMMAND_TOPIC and CONF_PRESET_MODES_LIST must be used together - vol.Inclusive( - CONF_PRESET_MODE_COMMAND_TOPIC, "preset_modes" - ): mqtt.valid_publish_topic, - vol.Inclusive( - CONF_PRESET_MODES_LIST, "preset_modes", default=[] - ): cv.ensure_list, - vol.Optional(CONF_PRESET_MODE_COMMAND_TEMPLATE): cv.template, - vol.Optional(CONF_PRESET_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional(CONF_PRESET_MODE_VALUE_TEMPLATE): cv.template, - vol.Optional( - CONF_SPEED_RANGE_MIN, default=DEFAULT_SPEED_RANGE_MIN - ): cv.positive_int, - vol.Optional( - CONF_SPEED_RANGE_MAX, default=DEFAULT_SPEED_RANGE_MAX - ): cv.positive_int, - vol.Optional( - CONF_PAYLOAD_RESET_PERCENTAGE, default=DEFAULT_PAYLOAD_RESET - ): cv.string, - vol.Optional( - CONF_PAYLOAD_RESET_PRESET_MODE, default=DEFAULT_PAYLOAD_RESET - ): cv.string, - vol.Optional(CONF_PAYLOAD_HIGH_SPEED, default=SPEED_HIGH): cv.string, - vol.Optional(CONF_PAYLOAD_LOW_SPEED, default=SPEED_LOW): cv.string, - vol.Optional(CONF_PAYLOAD_MEDIUM_SPEED, default=SPEED_MEDIUM): cv.string, - vol.Optional(CONF_PAYLOAD_OFF_SPEED, default=SPEED_OFF): cv.string, - vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string, - vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string, - vol.Optional( - CONF_PAYLOAD_OSCILLATION_OFF, default=OSCILLATE_OFF_PAYLOAD - ): cv.string, - vol.Optional( - CONF_PAYLOAD_OSCILLATION_ON, default=OSCILLATE_ON_PAYLOAD - ): cv.string, - vol.Optional(CONF_SPEED_COMMAND_TOPIC): mqtt.valid_publish_topic, - vol.Optional( - CONF_SPEED_LIST, - default=[SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH], - ): cv.ensure_list, - vol.Optional(CONF_SPEED_STATE_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional(CONF_SPEED_VALUE_TEMPLATE): cv.template, - vol.Optional(CONF_STATE_VALUE_TEMPLATE): cv.template, - } - ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema), + _PLATFORM_SCHEMA_BASE, + valid_speed_range_configuration, + valid_preset_mode_configuration, +) + +DISCOVERY_SCHEMA = vol.All( + # CONF_SPEED_COMMAND_TOPIC, CONF_SPEED_LIST, CONF_SPEED_STATE_TOPIC, CONF_SPEED_VALUE_TEMPLATE and + # Speeds SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH SPEED_OFF, + # are deprecated, support will be removed with release 2021.9 + cv.deprecated(CONF_PAYLOAD_HIGH_SPEED), + cv.deprecated(CONF_PAYLOAD_LOW_SPEED), + cv.deprecated(CONF_PAYLOAD_MEDIUM_SPEED), + cv.deprecated(CONF_SPEED_COMMAND_TOPIC), + cv.deprecated(CONF_SPEED_LIST), + cv.deprecated(CONF_SPEED_STATE_TOPIC), + cv.deprecated(CONF_SPEED_VALUE_TEMPLATE), + _PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA), valid_speed_range_configuration, valid_preset_mode_configuration, ) @@ -199,7 +217,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): setup = functools.partial( _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper(hass, fan.DOMAIN, setup, PLATFORM_SCHEMA) + await async_setup_entry_helper(hass, fan.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( @@ -236,7 +254,7 @@ class MqttFan(MqttEntity, FanEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA + return DISCOVERY_SCHEMA def _setup_from_config(self, config): """(Re)Setup the entity.""" diff --git a/homeassistant/components/mqtt/humidifier.py b/homeassistant/components/mqtt/humidifier.py index c1db0a6d4ee..e8bbbc7fd4b 100644 --- a/homeassistant/components/mqtt/humidifier.py +++ b/homeassistant/components/mqtt/humidifier.py @@ -86,46 +86,52 @@ def valid_humidity_range_configuration(config): return config +_PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend( + { + # CONF_AVAIALABLE_MODES_LIST and CONF_MODE_COMMAND_TOPIC must be used together + vol.Inclusive( + CONF_AVAILABLE_MODES_LIST, "available_modes", default=[] + ): cv.ensure_list, + vol.Inclusive( + CONF_MODE_COMMAND_TOPIC, "available_modes" + ): mqtt.valid_publish_topic, + vol.Optional(CONF_COMMAND_TEMPLATE): cv.template, + vol.Optional(CONF_DEVICE_CLASS, default=DEVICE_CLASS_HUMIDIFIER): vol.In( + [DEVICE_CLASS_HUMIDIFIER, DEVICE_CLASS_DEHUMIDIFIER] + ), + vol.Optional(CONF_MODE_COMMAND_TEMPLATE): cv.template, + vol.Optional(CONF_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_MODE_STATE_TEMPLATE): cv.template, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, + vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string, + vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string, + vol.Optional(CONF_STATE_VALUE_TEMPLATE): cv.template, + vol.Required(CONF_TARGET_HUMIDITY_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_TARGET_HUMIDITY_COMMAND_TEMPLATE): cv.template, + vol.Optional( + CONF_TARGET_HUMIDITY_MAX, default=DEFAULT_MAX_HUMIDITY + ): cv.positive_int, + vol.Optional( + CONF_TARGET_HUMIDITY_MIN, default=DEFAULT_MIN_HUMIDITY + ): cv.positive_int, + vol.Optional(CONF_TARGET_HUMIDITY_STATE_TEMPLATE): cv.template, + vol.Optional(CONF_TARGET_HUMIDITY_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional( + CONF_PAYLOAD_RESET_HUMIDITY, default=DEFAULT_PAYLOAD_RESET + ): cv.string, + vol.Optional(CONF_PAYLOAD_RESET_MODE, default=DEFAULT_PAYLOAD_RESET): cv.string, + } +).extend(MQTT_ENTITY_COMMON_SCHEMA.schema) + PLATFORM_SCHEMA = vol.All( - mqtt.MQTT_RW_PLATFORM_SCHEMA.extend( - { - # CONF_AVAIALABLE_MODES_LIST and CONF_MODE_COMMAND_TOPIC must be used together - vol.Inclusive( - CONF_AVAILABLE_MODES_LIST, "available_modes", default=[] - ): cv.ensure_list, - vol.Inclusive( - CONF_MODE_COMMAND_TOPIC, "available_modes" - ): mqtt.valid_publish_topic, - vol.Optional(CONF_COMMAND_TEMPLATE): cv.template, - vol.Optional(CONF_DEVICE_CLASS, default=DEVICE_CLASS_HUMIDIFIER): vol.In( - [DEVICE_CLASS_HUMIDIFIER, DEVICE_CLASS_DEHUMIDIFIER] - ), - vol.Optional(CONF_MODE_COMMAND_TEMPLATE): cv.template, - vol.Optional(CONF_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional(CONF_MODE_STATE_TEMPLATE): cv.template, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, - vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string, - vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string, - vol.Optional(CONF_STATE_VALUE_TEMPLATE): cv.template, - vol.Required(CONF_TARGET_HUMIDITY_COMMAND_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_TARGET_HUMIDITY_COMMAND_TEMPLATE): cv.template, - vol.Optional( - CONF_TARGET_HUMIDITY_MAX, default=DEFAULT_MAX_HUMIDITY - ): cv.positive_int, - vol.Optional( - CONF_TARGET_HUMIDITY_MIN, default=DEFAULT_MIN_HUMIDITY - ): cv.positive_int, - vol.Optional(CONF_TARGET_HUMIDITY_STATE_TEMPLATE): cv.template, - vol.Optional(CONF_TARGET_HUMIDITY_STATE_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional( - CONF_PAYLOAD_RESET_HUMIDITY, default=DEFAULT_PAYLOAD_RESET - ): cv.string, - vol.Optional( - CONF_PAYLOAD_RESET_MODE, default=DEFAULT_PAYLOAD_RESET - ): cv.string, - } - ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema), + _PLATFORM_SCHEMA_BASE, + valid_humidity_range_configuration, + valid_mode_configuration, +) + +DISCOVERY_SCHEMA = vol.All( + _PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA), valid_humidity_range_configuration, valid_mode_configuration, ) @@ -144,7 +150,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): setup = functools.partial( _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper(hass, humidifier.DOMAIN, setup, PLATFORM_SCHEMA) + await async_setup_entry_helper(hass, humidifier.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( @@ -179,7 +185,7 @@ class MqttHumidifier(MqttEntity, HumidifierEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA + return DISCOVERY_SCHEMA def _setup_from_config(self, config): """(Re)Setup the entity.""" diff --git a/homeassistant/components/mqtt/light/__init__.py b/homeassistant/components/mqtt/light/__init__.py index 95a0cde52f4..28cf6ebb480 100644 --- a/homeassistant/components/mqtt/light/__init__.py +++ b/homeassistant/components/mqtt/light/__init__.py @@ -11,9 +11,31 @@ from homeassistant.helpers.typing import ConfigType from .. import DOMAIN, PLATFORMS from ..mixins import async_setup_entry_helper from .schema import CONF_SCHEMA, MQTT_LIGHT_SCHEMA_SCHEMA -from .schema_basic import PLATFORM_SCHEMA_BASIC, async_setup_entity_basic -from .schema_json import PLATFORM_SCHEMA_JSON, async_setup_entity_json -from .schema_template import PLATFORM_SCHEMA_TEMPLATE, async_setup_entity_template +from .schema_basic import ( + DISCOVERY_SCHEMA_BASIC, + PLATFORM_SCHEMA_BASIC, + async_setup_entity_basic, +) +from .schema_json import ( + DISCOVERY_SCHEMA_JSON, + PLATFORM_SCHEMA_JSON, + async_setup_entity_json, +) +from .schema_template import ( + DISCOVERY_SCHEMA_TEMPLATE, + PLATFORM_SCHEMA_TEMPLATE, + async_setup_entity_template, +) + + +def validate_mqtt_light_discovery(value): + """Validate MQTT light schema.""" + schemas = { + "basic": DISCOVERY_SCHEMA_BASIC, + "json": DISCOVERY_SCHEMA_JSON, + "template": DISCOVERY_SCHEMA_TEMPLATE, + } + return schemas[value[CONF_SCHEMA]](value) def validate_mqtt_light(value): @@ -26,6 +48,12 @@ def validate_mqtt_light(value): return schemas[value[CONF_SCHEMA]](value) +DISCOVERY_SCHEMA = vol.All( + MQTT_LIGHT_SCHEMA_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA), + validate_mqtt_light_discovery, +) + + PLATFORM_SCHEMA = vol.All( MQTT_LIGHT_SCHEMA_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA), validate_mqtt_light ) @@ -44,7 +72,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): setup = functools.partial( _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper(hass, light.DOMAIN, setup, PLATFORM_SCHEMA) + await async_setup_entry_helper(hass, light.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( diff --git a/homeassistant/components/mqtt/light/schema_basic.py b/homeassistant/components/mqtt/light/schema_basic.py index cb350ae4c9c..5dd3f13af25 100644 --- a/homeassistant/components/mqtt/light/schema_basic.py +++ b/homeassistant/components/mqtt/light/schema_basic.py @@ -152,9 +152,7 @@ VALUE_TEMPLATE_KEYS = [ CONF_XY_VALUE_TEMPLATE, ] -PLATFORM_SCHEMA_BASIC = vol.All( - # CONF_VALUE_TEMPLATE is deprecated, support will be removed in 2021.10 - cv.deprecated(CONF_VALUE_TEMPLATE, CONF_STATE_VALUE_TEMPLATE), +_PLATFORM_SCHEMA_BASE = ( mqtt.MQTT_RW_PLATFORM_SCHEMA.extend( { vol.Optional(CONF_BRIGHTNESS_COMMAND_TOPIC): mqtt.valid_publish_topic, @@ -212,10 +210,22 @@ PLATFORM_SCHEMA_BASIC = vol.All( vol.Optional(CONF_XY_COMMAND_TOPIC): mqtt.valid_publish_topic, vol.Optional(CONF_XY_STATE_TOPIC): mqtt.valid_subscribe_topic, vol.Optional(CONF_XY_VALUE_TEMPLATE): cv.template, - } + }, ) .extend(MQTT_ENTITY_COMMON_SCHEMA.schema) - .extend(MQTT_LIGHT_SCHEMA_SCHEMA.schema), + .extend(MQTT_LIGHT_SCHEMA_SCHEMA.schema) +) + +PLATFORM_SCHEMA_BASIC = vol.All( + # CONF_VALUE_TEMPLATE is deprecated, support will be removed in 2021.10 + cv.deprecated(CONF_VALUE_TEMPLATE, CONF_STATE_VALUE_TEMPLATE), + _PLATFORM_SCHEMA_BASE, +) + +DISCOVERY_SCHEMA_BASIC = vol.All( + # CONF_VALUE_TEMPLATE is deprecated, support will be removed in 2021.10 + cv.deprecated(CONF_VALUE_TEMPLATE, CONF_STATE_VALUE_TEMPLATE), + _PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA), ) @@ -268,7 +278,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA_BASIC + return DISCOVERY_SCHEMA_BASIC def _setup_from_config(self, config): """(Re)Setup the entity.""" diff --git a/homeassistant/components/mqtt/light/schema_json.py b/homeassistant/components/mqtt/light/schema_json.py index 8538b1169cc..9915c2455df 100644 --- a/homeassistant/components/mqtt/light/schema_json.py +++ b/homeassistant/components/mqtt/light/schema_json.py @@ -102,7 +102,7 @@ def valid_color_configuration(config): return config -PLATFORM_SCHEMA_JSON = vol.All( +_PLATFORM_SCHEMA_BASE = ( mqtt.MQTT_RW_PLATFORM_SCHEMA.extend( { vol.Optional(CONF_BRIGHTNESS, default=DEFAULT_BRIGHTNESS): cv.boolean, @@ -143,7 +143,16 @@ PLATFORM_SCHEMA_JSON = vol.All( }, ) .extend(MQTT_ENTITY_COMMON_SCHEMA.schema) - .extend(MQTT_LIGHT_SCHEMA_SCHEMA.schema), + .extend(MQTT_LIGHT_SCHEMA_SCHEMA.schema) +) + +PLATFORM_SCHEMA_JSON = vol.All( + _PLATFORM_SCHEMA_BASE, + valid_color_configuration, +) + +DISCOVERY_SCHEMA_JSON = vol.All( + _PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA), valid_color_configuration, ) @@ -184,7 +193,7 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA_JSON + return DISCOVERY_SCHEMA_JSON def _setup_from_config(self, config): """(Re)Setup the entity.""" diff --git a/homeassistant/components/mqtt/light/schema_template.py b/homeassistant/components/mqtt/light/schema_template.py index 0c6522efc4f..6b7396846e1 100644 --- a/homeassistant/components/mqtt/light/schema_template.py +++ b/homeassistant/components/mqtt/light/schema_template.py @@ -84,6 +84,8 @@ PLATFORM_SCHEMA_TEMPLATE = ( .extend(MQTT_LIGHT_SCHEMA_SCHEMA.schema) ) +DISCOVERY_SCHEMA_TEMPLATE = PLATFORM_SCHEMA_TEMPLATE.extend({}, extra=vol.REMOVE_EXTRA) + async def async_setup_entity_template( hass, config, async_add_entities, config_entry, discovery_data @@ -117,7 +119,7 @@ class MqttLightTemplate(MqttEntity, LightEntity, RestoreEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA_TEMPLATE + return DISCOVERY_SCHEMA_TEMPLATE def _setup_from_config(self, config): """(Re)Setup the entity.""" diff --git a/homeassistant/components/mqtt/lock.py b/homeassistant/components/mqtt/lock.py index 158e3547737..fdcd4294b8c 100644 --- a/homeassistant/components/mqtt/lock.py +++ b/homeassistant/components/mqtt/lock.py @@ -49,6 +49,8 @@ PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend( } ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema) +DISCOVERY_SCHEMA = PLATFORM_SCHEMA.extend({}, extra=vol.REMOVE_EXTRA) + async def async_setup_platform( hass: HomeAssistant, config: ConfigType, async_add_entities, discovery_info=None @@ -63,7 +65,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): setup = functools.partial( _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper(hass, lock.DOMAIN, setup, PLATFORM_SCHEMA) + await async_setup_entry_helper(hass, lock.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( @@ -88,7 +90,7 @@ class MqttLock(MqttEntity, LockEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA + return DISCOVERY_SCHEMA def _setup_from_config(self, config): """(Re)Setup the entity.""" diff --git a/homeassistant/components/mqtt/number.py b/homeassistant/components/mqtt/number.py index f2a472709b3..902d828d911 100644 --- a/homeassistant/components/mqtt/number.py +++ b/homeassistant/components/mqtt/number.py @@ -59,21 +59,28 @@ def validate_config(config): return config +_PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend( + { + vol.Optional(CONF_MAX, default=DEFAULT_MAX_VALUE): vol.Coerce(float), + vol.Optional(CONF_MIN, default=DEFAULT_MIN_VALUE): vol.Coerce(float), + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, + vol.Optional(CONF_PAYLOAD_RESET, default=DEFAULT_PAYLOAD_RESET): cv.string, + vol.Optional(CONF_STEP, default=DEFAULT_STEP): vol.All( + vol.Coerce(float), vol.Range(min=1e-3) + ), + vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string, + vol.Optional(CONF_VALUE_TEMPLATE): cv.template, + }, +).extend(MQTT_ENTITY_COMMON_SCHEMA.schema) + PLATFORM_SCHEMA = vol.All( - mqtt.MQTT_RW_PLATFORM_SCHEMA.extend( - { - vol.Optional(CONF_MAX, default=DEFAULT_MAX_VALUE): vol.Coerce(float), - vol.Optional(CONF_MIN, default=DEFAULT_MIN_VALUE): vol.Coerce(float), - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, - vol.Optional(CONF_PAYLOAD_RESET, default=DEFAULT_PAYLOAD_RESET): cv.string, - vol.Optional(CONF_STEP, default=DEFAULT_STEP): vol.All( - vol.Coerce(float), vol.Range(min=1e-3) - ), - vol.Optional(CONF_VALUE_TEMPLATE): cv.template, - vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string, - }, - ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema), + _PLATFORM_SCHEMA_BASE, + validate_config, +) + +DISCOVERY_SCHEMA = vol.All( + _PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA), validate_config, ) @@ -91,7 +98,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): setup = functools.partial( _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper(hass, number.DOMAIN, setup, PLATFORM_SCHEMA) + await async_setup_entry_helper(hass, number.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( @@ -120,7 +127,7 @@ class MqttNumber(MqttEntity, NumberEntity, RestoreEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA + return DISCOVERY_SCHEMA def _setup_from_config(self, config): """(Re)Setup the entity.""" diff --git a/homeassistant/components/mqtt/scene.py b/homeassistant/components/mqtt/scene.py index 5d9f7ba376e..6cf953ccf44 100644 --- a/homeassistant/components/mqtt/scene.py +++ b/homeassistant/components/mqtt/scene.py @@ -35,6 +35,8 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend( } ).extend(MQTT_AVAILABILITY_SCHEMA.schema) +DISCOVERY_SCHEMA = PLATFORM_SCHEMA.extend({}, extra=vol.REMOVE_EXTRA) + async def async_setup_platform( hass: HomeAssistant, config: ConfigType, async_add_entities, discovery_info=None @@ -49,7 +51,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): setup = functools.partial( _async_setup_entity, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper(hass, scene.DOMAIN, setup, PLATFORM_SCHEMA) + await async_setup_entry_helper(hass, scene.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( @@ -85,7 +87,7 @@ class MqttScene( async def discovery_update(self, discovery_payload): """Handle updated discovery message.""" - config = PLATFORM_SCHEMA(discovery_payload) + config = DISCOVERY_SCHEMA(discovery_payload) self._setup_from_config(config) await self.availability_discovery_update(config) self.async_write_ha_state() diff --git a/homeassistant/components/mqtt/select.py b/homeassistant/components/mqtt/select.py index 439aaccdc3b..b289bd53f0d 100644 --- a/homeassistant/components/mqtt/select.py +++ b/homeassistant/components/mqtt/select.py @@ -41,15 +41,22 @@ def validate_config(config): return config +_PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend( + { + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, + vol.Required(CONF_OPTIONS): cv.ensure_list, + vol.Optional(CONF_VALUE_TEMPLATE): cv.template, + }, +).extend(MQTT_ENTITY_COMMON_SCHEMA.schema) + PLATFORM_SCHEMA = vol.All( - mqtt.MQTT_RW_PLATFORM_SCHEMA.extend( - { - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, - vol.Required(CONF_OPTIONS): cv.ensure_list, - vol.Optional(CONF_VALUE_TEMPLATE): cv.template, - }, - ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema), + _PLATFORM_SCHEMA_BASE, + validate_config, +) + +DISCOVERY_SCHEMA = vol.All( + _PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA), validate_config, ) @@ -67,7 +74,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): setup = functools.partial( _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper(hass, select.DOMAIN, setup, PLATFORM_SCHEMA) + await async_setup_entry_helper(hass, select.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( @@ -96,7 +103,7 @@ class MqttSelect(MqttEntity, SelectEntity, RestoreEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA + return DISCOVERY_SCHEMA def _setup_from_config(self, config): """(Re)Setup the entity.""" diff --git a/homeassistant/components/mqtt/sensor.py b/homeassistant/components/mqtt/sensor.py index 0c0e1e700b7..3881dfee0e8 100644 --- a/homeassistant/components/mqtt/sensor.py +++ b/homeassistant/components/mqtt/sensor.py @@ -80,20 +80,28 @@ def validate_options(conf): return conf +_PLATFORM_SCHEMA_BASE = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend( + { + vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, + vol.Optional(CONF_EXPIRE_AFTER): cv.positive_int, + vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean, + vol.Optional(CONF_LAST_RESET_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_LAST_RESET_VALUE_TEMPLATE): cv.template, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_STATE_CLASS): STATE_CLASSES_SCHEMA, + vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string, + } +).extend(MQTT_ENTITY_COMMON_SCHEMA.schema) + PLATFORM_SCHEMA = vol.All( cv.deprecated(CONF_LAST_RESET_TOPIC), - mqtt.MQTT_RO_PLATFORM_SCHEMA.extend( - { - vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, - vol.Optional(CONF_EXPIRE_AFTER): cv.positive_int, - vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean, - vol.Optional(CONF_LAST_RESET_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional(CONF_LAST_RESET_VALUE_TEMPLATE): cv.template, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_STATE_CLASS): STATE_CLASSES_SCHEMA, - vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string, - } - ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema), + _PLATFORM_SCHEMA_BASE, + validate_options, +) + +DISCOVERY_SCHEMA = vol.All( + cv.deprecated(CONF_LAST_RESET_TOPIC), + _PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA), validate_options, ) @@ -111,7 +119,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): setup = functools.partial( _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper(hass, sensor.DOMAIN, setup, PLATFORM_SCHEMA) + await async_setup_entry_helper(hass, sensor.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( @@ -143,7 +151,7 @@ class MqttSensor(MqttEntity, SensorEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA + return DISCOVERY_SCHEMA def _setup_from_config(self, config): """(Re)Setup the entity.""" diff --git a/homeassistant/components/mqtt/switch.py b/homeassistant/components/mqtt/switch.py index 52addc19d12..3a593adf1e3 100644 --- a/homeassistant/components/mqtt/switch.py +++ b/homeassistant/components/mqtt/switch.py @@ -51,6 +51,8 @@ PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend( } ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema) +DISCOVERY_SCHEMA = PLATFORM_SCHEMA.extend({}, extra=vol.REMOVE_EXTRA) + async def async_setup_platform( hass: HomeAssistant, config: ConfigType, async_add_entities, discovery_info=None @@ -65,7 +67,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): setup = functools.partial( _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper(hass, switch.DOMAIN, setup, PLATFORM_SCHEMA) + await async_setup_entry_helper(hass, switch.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( @@ -93,7 +95,7 @@ class MqttSwitch(MqttEntity, SwitchEntity, RestoreEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA + return DISCOVERY_SCHEMA def _setup_from_config(self, config): """(Re)Setup the entity.""" diff --git a/homeassistant/components/mqtt/tag.py b/homeassistant/components/mqtt/tag.py index 908895f180c..a228d56d5c7 100644 --- a/homeassistant/components/mqtt/tag.py +++ b/homeassistant/components/mqtt/tag.py @@ -29,7 +29,6 @@ from .mixins import ( async_setup_entry_helper, cleanup_device_registry, device_info_from_config, - validate_device_has_at_least_one_identifier, ) from .util import valid_subscribe_topic @@ -45,7 +44,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend( vol.Required(CONF_TOPIC): valid_subscribe_topic, vol.Optional(CONF_VALUE_TEMPLATE): cv.template, }, - validate_device_has_at_least_one_identifier, + extra=vol.REMOVE_EXTRA, ) diff --git a/homeassistant/components/mqtt/vacuum/__init__.py b/homeassistant/components/mqtt/vacuum/__init__.py index 12d2ff5319c..6ff03a437e5 100644 --- a/homeassistant/components/mqtt/vacuum/__init__.py +++ b/homeassistant/components/mqtt/vacuum/__init__.py @@ -9,8 +9,22 @@ from homeassistant.helpers.reload import async_setup_reload_service from .. import DOMAIN as MQTT_DOMAIN, PLATFORMS from ..mixins import async_setup_entry_helper from .schema import CONF_SCHEMA, LEGACY, MQTT_VACUUM_SCHEMA, STATE -from .schema_legacy import PLATFORM_SCHEMA_LEGACY, async_setup_entity_legacy -from .schema_state import PLATFORM_SCHEMA_STATE, async_setup_entity_state +from .schema_legacy import ( + DISCOVERY_SCHEMA_LEGACY, + PLATFORM_SCHEMA_LEGACY, + async_setup_entity_legacy, +) +from .schema_state import ( + DISCOVERY_SCHEMA_STATE, + PLATFORM_SCHEMA_STATE, + async_setup_entity_state, +) + + +def validate_mqtt_vacuum_discovery(value): + """Validate MQTT vacuum schema.""" + schemas = {LEGACY: DISCOVERY_SCHEMA_LEGACY, STATE: DISCOVERY_SCHEMA_STATE} + return schemas[value[CONF_SCHEMA]](value) def validate_mqtt_vacuum(value): @@ -19,6 +33,10 @@ def validate_mqtt_vacuum(value): return schemas[value[CONF_SCHEMA]](value) +DISCOVERY_SCHEMA = vol.All( + MQTT_VACUUM_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA), validate_mqtt_vacuum_discovery +) + PLATFORM_SCHEMA = vol.All( MQTT_VACUUM_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA), validate_mqtt_vacuum ) @@ -35,7 +53,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): setup = functools.partial( _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) - await async_setup_entry_helper(hass, DOMAIN, setup, PLATFORM_SCHEMA) + await async_setup_entry_helper(hass, DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( diff --git a/homeassistant/components/mqtt/vacuum/schema_legacy.py b/homeassistant/components/mqtt/vacuum/schema_legacy.py index 8543fa177c4..d827853d603 100644 --- a/homeassistant/components/mqtt/vacuum/schema_legacy.py +++ b/homeassistant/components/mqtt/vacuum/schema_legacy.py @@ -156,6 +156,8 @@ PLATFORM_SCHEMA_LEGACY = ( .extend(MQTT_VACUUM_SCHEMA.schema) ) +DISCOVERY_SCHEMA_LEGACY = PLATFORM_SCHEMA_LEGACY.extend({}, extra=vol.REMOVE_EXTRA) + async def async_setup_entity_legacy( hass, config, async_add_entities, config_entry, discovery_data @@ -185,7 +187,7 @@ class MqttVacuum(MqttEntity, VacuumEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA_LEGACY + return DISCOVERY_SCHEMA_LEGACY def _setup_from_config(self, config): supported_feature_strings = config[CONF_SUPPORTED_FEATURES] diff --git a/homeassistant/components/mqtt/vacuum/schema_state.py b/homeassistant/components/mqtt/vacuum/schema_state.py index 3bc30d9d5cc..80f566ff5de 100644 --- a/homeassistant/components/mqtt/vacuum/schema_state.py +++ b/homeassistant/components/mqtt/vacuum/schema_state.py @@ -136,6 +136,9 @@ PLATFORM_SCHEMA_STATE = ( ) +DISCOVERY_SCHEMA_STATE = PLATFORM_SCHEMA_STATE.extend({}, extra=vol.REMOVE_EXTRA) + + async def async_setup_entity_state( hass, config, async_add_entities, config_entry, discovery_data ): @@ -159,7 +162,7 @@ class MqttStateVacuum(MqttEntity, StateVacuumEntity): @staticmethod def config_schema(): """Return the config schema.""" - return PLATFORM_SCHEMA_STATE + return DISCOVERY_SCHEMA_STATE def _setup_from_config(self, config): supported_feature_strings = config[CONF_SUPPORTED_FEATURES] diff --git a/tests/components/mqtt/test_alarm_control_panel.py b/tests/components/mqtt/test_alarm_control_panel.py index 7b4b8d22168..1351ae59496 100644 --- a/tests/components/mqtt/test_alarm_control_panel.py +++ b/tests/components/mqtt/test_alarm_control_panel.py @@ -625,15 +625,13 @@ async def test_discovery_update_alarm_topic_and_template(hass, mqtt_mock, caplog ([("alarm/state2", '{"state2":{"state":"triggered"}}')], "triggered", None), ] - data1 = json.dumps(config1) - data2 = json.dumps(config2) await help_test_discovery_update( hass, mqtt_mock, caplog, alarm_control_panel.DOMAIN, - data1, - data2, + config1, + config2, state_data1=state_data1, state_data2=state_data2, ) @@ -658,15 +656,13 @@ async def test_discovery_update_alarm_template(hass, mqtt_mock, caplog): ([("alarm/state1", '{"state2":{"state":"triggered"}}')], "triggered", None), ] - data1 = json.dumps(config1) - data2 = json.dumps(config2) await help_test_discovery_update( hass, mqtt_mock, caplog, alarm_control_panel.DOMAIN, - data1, - data2, + config1, + config2, state_data1=state_data1, state_data2=state_data2, ) diff --git a/tests/components/mqtt/test_binary_sensor.py b/tests/components/mqtt/test_binary_sensor.py index bf88b7901e1..ba601fd094d 100644 --- a/tests/components/mqtt/test_binary_sensor.py +++ b/tests/components/mqtt/test_binary_sensor.py @@ -679,15 +679,13 @@ async def test_discovery_update_binary_sensor_topic_template(hass, mqtt_mock, ca ([("sensor/state2", '{"state2":{"state":"OFF"}}')], "off", None), ] - data1 = json.dumps(config1) - data2 = json.dumps(config2) await help_test_discovery_update( hass, mqtt_mock, caplog, binary_sensor.DOMAIN, - data1, - data2, + config1, + config2, state_data1=state_data1, state_data2=state_data2, ) @@ -714,15 +712,13 @@ async def test_discovery_update_binary_sensor_template(hass, mqtt_mock, caplog): ([("sensor/state1", '{"state2":{"state":"OFF"}}')], "off", None), ] - data1 = json.dumps(config1) - data2 = json.dumps(config2) await help_test_discovery_update( hass, mqtt_mock, caplog, binary_sensor.DOMAIN, - data1, - data2, + config1, + config2, state_data1=state_data1, state_data2=state_data2, ) diff --git a/tests/components/mqtt/test_camera.py b/tests/components/mqtt/test_camera.py index 2036b486f94..5db4362b1fb 100644 --- a/tests/components/mqtt/test_camera.py +++ b/tests/components/mqtt/test_camera.py @@ -161,11 +161,11 @@ async def test_discovery_removal_camera(hass, mqtt_mock, caplog): async def test_discovery_update_camera(hass, mqtt_mock, caplog): """Test update of discovered camera.""" - data1 = '{ "name": "Beer", "topic": "test_topic"}' - data2 = '{ "name": "Milk", "topic": "test_topic"}' + config1 = {"name": "Beer", "topic": "test_topic"} + config2 = {"name": "Milk", "topic": "test_topic"} await help_test_discovery_update( - hass, mqtt_mock, caplog, camera.DOMAIN, data1, data2 + hass, mqtt_mock, caplog, camera.DOMAIN, config1, config2 ) diff --git a/tests/components/mqtt/test_climate.py b/tests/components/mqtt/test_climate.py index 24c9e4a5b74..323d75ae091 100644 --- a/tests/components/mqtt/test_climate.py +++ b/tests/components/mqtt/test_climate.py @@ -991,10 +991,10 @@ async def test_discovery_removal_climate(hass, mqtt_mock, caplog): async def test_discovery_update_climate(hass, mqtt_mock, caplog): """Test update of discovered climate.""" - data1 = '{ "name": "Beer" }' - data2 = '{ "name": "Milk" }' + config1 = {"name": "Beer"} + config2 = {"name": "Milk"} await help_test_discovery_update( - hass, mqtt_mock, caplog, CLIMATE_DOMAIN, data1, data2 + hass, mqtt_mock, caplog, CLIMATE_DOMAIN, config1, config2 ) diff --git a/tests/components/mqtt/test_common.py b/tests/components/mqtt/test_common.py index 72f5f236d28..16af5b8e484 100644 --- a/tests/components/mqtt/test_common.py +++ b/tests/components/mqtt/test_common.py @@ -662,8 +662,8 @@ async def help_test_discovery_update( mqtt_mock, caplog, domain, - discovery_data1, - discovery_data2, + discovery_config1, + discovery_config2, state_data1=None, state_data2=None, ): @@ -671,6 +671,14 @@ async def help_test_discovery_update( This is a test helper for the MqttDiscoveryUpdate mixin. """ + # Add some future configuration to the configurations + config1 = copy.deepcopy(discovery_config1) + config1["some_future_option_1"] = "future_option_1" + config2 = copy.deepcopy(discovery_config2) + config2["some_future_option_2"] = "future_option_2" + discovery_data1 = json.dumps(config1) + discovery_data2 = json.dumps(config2) + async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", discovery_data1) await hass.async_block_till_done() diff --git a/tests/components/mqtt/test_cover.py b/tests/components/mqtt/test_cover.py index cd2966f6853..794d143ac83 100644 --- a/tests/components/mqtt/test_cover.py +++ b/tests/components/mqtt/test_cover.py @@ -2401,10 +2401,10 @@ async def test_discovery_removal_cover(hass, mqtt_mock, caplog): async def test_discovery_update_cover(hass, mqtt_mock, caplog): """Test update of discovered cover.""" - data1 = '{ "name": "Beer", "command_topic": "test_topic" }' - data2 = '{ "name": "Milk", "command_topic": "test_topic" }' + config1 = {"name": "Beer", "command_topic": "test_topic"} + config2 = {"name": "Milk", "command_topic": "test_topic"} await help_test_discovery_update( - hass, mqtt_mock, caplog, cover.DOMAIN, data1, data2 + hass, mqtt_mock, caplog, cover.DOMAIN, config1, config2 ) diff --git a/tests/components/mqtt/test_device_trigger.py b/tests/components/mqtt/test_device_trigger.py index b0db6169373..c3b16e3de43 100644 --- a/tests/components/mqtt/test_device_trigger.py +++ b/tests/components/mqtt/test_device_trigger.py @@ -130,7 +130,7 @@ async def test_discover_bad_triggers(hass, device_reg, entity_reg, mqtt_mock): '{ "automation_type":"trigger",' ' "device":{"identifiers":["0AFFD2"]},' ' "payloads": "short_press",' - ' "topic": "foobar/triggers/button1",' + ' "topics": "foobar/triggers/button1",' ' "type": "button_short_press",' ' "subtype": "button_1" }' ) @@ -167,22 +167,28 @@ async def test_discover_bad_triggers(hass, device_reg, entity_reg, mqtt_mock): async def test_update_remove_triggers(hass, device_reg, entity_reg, mqtt_mock): """Test triggers can be updated and removed.""" - data1 = ( - '{ "automation_type":"trigger",' - ' "device":{"identifiers":["0AFFD2"]},' - ' "payload": "short_press",' - ' "topic": "foobar/triggers/button1",' - ' "type": "button_short_press",' - ' "subtype": "button_1" }' - ) - data2 = ( - '{ "automation_type":"trigger",' - ' "device":{"identifiers":["0AFFD2"]},' - ' "payload": "short_press",' - ' "topic": "foobar/triggers/button1",' - ' "type": "button_short_press",' - ' "subtype": "button_2" }' - ) + config1 = { + "automation_type": "trigger", + "device": {"identifiers": ["0AFFD2"]}, + "payload": "short_press", + "topic": "foobar/triggers/button1", + "type": "button_short_press", + "subtype": "button_1", + } + config1["some_future_option_1"] = "future_option_1" + data1 = json.dumps(config1) + + config2 = { + "automation_type": "trigger", + "device": {"identifiers": ["0AFFD2"]}, + "payload": "short_press", + "topic": "foobar/triggers/button1", + "type": "button_short_press", + "subtype": "button_2", + } + config2["topic"] = "foobar/tag_scanned2" + data2 = json.dumps(config2) + async_fire_mqtt_message(hass, "homeassistant/device_automation/bla/config", data1) await hass.async_block_till_done() diff --git a/tests/components/mqtt/test_fan.py b/tests/components/mqtt/test_fan.py index 0501927d003..c310db335ad 100644 --- a/tests/components/mqtt/test_fan.py +++ b/tests/components/mqtt/test_fan.py @@ -1590,9 +1590,11 @@ async def test_discovery_removal_fan(hass, mqtt_mock, caplog): async def test_discovery_update_fan(hass, mqtt_mock, caplog): """Test update of discovered fan.""" - data1 = '{ "name": "Beer", "command_topic": "test_topic" }' - data2 = '{ "name": "Milk", "command_topic": "test_topic" }' - await help_test_discovery_update(hass, mqtt_mock, caplog, fan.DOMAIN, data1, data2) + config1 = {"name": "Beer", "command_topic": "test_topic"} + config2 = {"name": "Milk", "command_topic": "test_topic"} + await help_test_discovery_update( + hass, mqtt_mock, caplog, fan.DOMAIN, config1, config2 + ) async def test_discovery_update_unchanged_fan(hass, mqtt_mock, caplog): diff --git a/tests/components/mqtt/test_humidifier.py b/tests/components/mqtt/test_humidifier.py index 4ae834be5da..76c0b6e9f8e 100644 --- a/tests/components/mqtt/test_humidifier.py +++ b/tests/components/mqtt/test_humidifier.py @@ -975,10 +975,18 @@ async def test_discovery_removal_humidifier(hass, mqtt_mock, caplog): async def test_discovery_update_humidifier(hass, mqtt_mock, caplog): """Test update of discovered humidifier.""" - data1 = '{ "name": "Beer", "command_topic": "test_topic", "target_humidity_command_topic": "test-topic2" }' - data2 = '{ "name": "Milk", "command_topic": "test_topic", "target_humidity_command_topic": "test-topic2" }' + config1 = { + "name": "Beer", + "command_topic": "test_topic", + "target_humidity_command_topic": "test-topic2", + } + config2 = { + "name": "Milk", + "command_topic": "test_topic", + "target_humidity_command_topic": "test-topic2", + } await help_test_discovery_update( - hass, mqtt_mock, caplog, humidifier.DOMAIN, data1, data2 + hass, mqtt_mock, caplog, humidifier.DOMAIN, config1, config2 ) diff --git a/tests/components/mqtt/test_legacy_vacuum.py b/tests/components/mqtt/test_legacy_vacuum.py index 2dc8993a565..5d9b50252a4 100644 --- a/tests/components/mqtt/test_legacy_vacuum.py +++ b/tests/components/mqtt/test_legacy_vacuum.py @@ -651,10 +651,10 @@ async def test_discovery_removal_vacuum(hass, mqtt_mock, caplog): async def test_discovery_update_vacuum(hass, mqtt_mock, caplog): """Test update of discovered vacuum.""" - data1 = '{ "name": "Beer",' ' "command_topic": "test_topic" }' - data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }' + config1 = {"name": "Beer", " " "command_topic": "test_topic"} + config2 = {"name": "Milk", " " "command_topic": "test_topic"} await help_test_discovery_update( - hass, mqtt_mock, caplog, vacuum.DOMAIN, data1, data2 + hass, mqtt_mock, caplog, vacuum.DOMAIN, config1, config2 ) diff --git a/tests/components/mqtt/test_light.py b/tests/components/mqtt/test_light.py index 109d6961a0d..bf327796f57 100644 --- a/tests/components/mqtt/test_light.py +++ b/tests/components/mqtt/test_light.py @@ -153,7 +153,6 @@ light: payload_off: "off" """ -import json from os import path from unittest.mock import call, patch @@ -2798,65 +2797,61 @@ async def test_discovery_deprecated(hass, mqtt_mock, caplog): async def test_discovery_update_light_topic_and_template(hass, mqtt_mock, caplog): """Test update of discovered light.""" - data1 = json.dumps( - { - "name": "Beer", - "state_topic": "test_light_rgb/state1", - "command_topic": "test_light_rgb/set", - "brightness_command_topic": "test_light_rgb/state1", - "rgb_command_topic": "test_light_rgb/rgb/set", - "color_temp_command_topic": "test_light_rgb/state1", - "effect_command_topic": "test_light_rgb/effect/set", - "hs_command_topic": "test_light_rgb/hs/set", - "white_value_command_topic": "test_light_rgb/white_value/set", - "xy_command_topic": "test_light_rgb/xy/set", - "brightness_state_topic": "test_light_rgb/state1", - "color_temp_state_topic": "test_light_rgb/state1", - "effect_state_topic": "test_light_rgb/state1", - "hs_state_topic": "test_light_rgb/state1", - "rgb_state_topic": "test_light_rgb/state1", - "white_value_state_topic": "test_light_rgb/state1", - "xy_state_topic": "test_light_rgb/state1", - "state_value_template": "{{ value_json.state1.state }}", - "brightness_value_template": "{{ value_json.state1.brightness }}", - "color_temp_value_template": "{{ value_json.state1.ct }}", - "effect_value_template": "{{ value_json.state1.fx }}", - "hs_value_template": "{{ value_json.state1.hs }}", - "rgb_value_template": "{{ value_json.state1.rgb }}", - "white_value_template": "{{ value_json.state1.white }}", - "xy_value_template": "{{ value_json.state1.xy }}", - } - ) + config1 = { + "name": "Beer", + "state_topic": "test_light_rgb/state1", + "command_topic": "test_light_rgb/set", + "brightness_command_topic": "test_light_rgb/state1", + "rgb_command_topic": "test_light_rgb/rgb/set", + "color_temp_command_topic": "test_light_rgb/state1", + "effect_command_topic": "test_light_rgb/effect/set", + "hs_command_topic": "test_light_rgb/hs/set", + "white_value_command_topic": "test_light_rgb/white_value/set", + "xy_command_topic": "test_light_rgb/xy/set", + "brightness_state_topic": "test_light_rgb/state1", + "color_temp_state_topic": "test_light_rgb/state1", + "effect_state_topic": "test_light_rgb/state1", + "hs_state_topic": "test_light_rgb/state1", + "rgb_state_topic": "test_light_rgb/state1", + "white_value_state_topic": "test_light_rgb/state1", + "xy_state_topic": "test_light_rgb/state1", + "state_value_template": "{{ value_json.state1.state }}", + "brightness_value_template": "{{ value_json.state1.brightness }}", + "color_temp_value_template": "{{ value_json.state1.ct }}", + "effect_value_template": "{{ value_json.state1.fx }}", + "hs_value_template": "{{ value_json.state1.hs }}", + "rgb_value_template": "{{ value_json.state1.rgb }}", + "white_value_template": "{{ value_json.state1.white }}", + "xy_value_template": "{{ value_json.state1.xy }}", + } - data2 = json.dumps( - { - "name": "Milk", - "state_topic": "test_light_rgb/state2", - "command_topic": "test_light_rgb/set", - "brightness_command_topic": "test_light_rgb/state2", - "rgb_command_topic": "test_light_rgb/rgb/set", - "color_temp_command_topic": "test_light_rgb/state2", - "effect_command_topic": "test_light_rgb/effect/set", - "hs_command_topic": "test_light_rgb/hs/set", - "white_value_command_topic": "test_light_rgb/white_value/set", - "xy_command_topic": "test_light_rgb/xy/set", - "brightness_state_topic": "test_light_rgb/state2", - "color_temp_state_topic": "test_light_rgb/state2", - "effect_state_topic": "test_light_rgb/state2", - "hs_state_topic": "test_light_rgb/state2", - "rgb_state_topic": "test_light_rgb/state2", - "white_value_state_topic": "test_light_rgb/state2", - "xy_state_topic": "test_light_rgb/state2", - "state_value_template": "{{ value_json.state2.state }}", - "brightness_value_template": "{{ value_json.state2.brightness }}", - "color_temp_value_template": "{{ value_json.state2.ct }}", - "effect_value_template": "{{ value_json.state2.fx }}", - "hs_value_template": "{{ value_json.state2.hs }}", - "rgb_value_template": "{{ value_json.state2.rgb }}", - "white_value_template": "{{ value_json.state2.white }}", - "xy_value_template": "{{ value_json.state2.xy }}", - } - ) + config2 = { + "name": "Milk", + "state_topic": "test_light_rgb/state2", + "command_topic": "test_light_rgb/set", + "brightness_command_topic": "test_light_rgb/state2", + "rgb_command_topic": "test_light_rgb/rgb/set", + "color_temp_command_topic": "test_light_rgb/state2", + "effect_command_topic": "test_light_rgb/effect/set", + "hs_command_topic": "test_light_rgb/hs/set", + "white_value_command_topic": "test_light_rgb/white_value/set", + "xy_command_topic": "test_light_rgb/xy/set", + "brightness_state_topic": "test_light_rgb/state2", + "color_temp_state_topic": "test_light_rgb/state2", + "effect_state_topic": "test_light_rgb/state2", + "hs_state_topic": "test_light_rgb/state2", + "rgb_state_topic": "test_light_rgb/state2", + "white_value_state_topic": "test_light_rgb/state2", + "xy_state_topic": "test_light_rgb/state2", + "state_value_template": "{{ value_json.state2.state }}", + "brightness_value_template": "{{ value_json.state2.brightness }}", + "color_temp_value_template": "{{ value_json.state2.ct }}", + "effect_value_template": "{{ value_json.state2.fx }}", + "hs_value_template": "{{ value_json.state2.hs }}", + "rgb_value_template": "{{ value_json.state2.rgb }}", + "white_value_template": "{{ value_json.state2.white }}", + "xy_value_template": "{{ value_json.state2.xy }}", + } state_data1 = [ ( [ @@ -3054,8 +3049,8 @@ async def test_discovery_update_light_topic_and_template(hass, mqtt_mock, caplog mqtt_mock, caplog, light.DOMAIN, - data1, - data2, + config1, + config2, state_data1=state_data1, state_data2=state_data2, ) @@ -3063,65 +3058,61 @@ async def test_discovery_update_light_topic_and_template(hass, mqtt_mock, caplog async def test_discovery_update_light_template(hass, mqtt_mock, caplog): """Test update of discovered light.""" - data1 = json.dumps( - { - "name": "Beer", - "state_topic": "test_light_rgb/state1", - "command_topic": "test_light_rgb/set", - "brightness_command_topic": "test_light_rgb/state1", - "rgb_command_topic": "test_light_rgb/rgb/set", - "color_temp_command_topic": "test_light_rgb/state1", - "effect_command_topic": "test_light_rgb/effect/set", - "hs_command_topic": "test_light_rgb/hs/set", - "white_value_command_topic": "test_light_rgb/white_value/set", - "xy_command_topic": "test_light_rgb/xy/set", - "brightness_state_topic": "test_light_rgb/state1", - "color_temp_state_topic": "test_light_rgb/state1", - "effect_state_topic": "test_light_rgb/state1", - "hs_state_topic": "test_light_rgb/state1", - "rgb_state_topic": "test_light_rgb/state1", - "white_value_state_topic": "test_light_rgb/state1", - "xy_state_topic": "test_light_rgb/state1", - "state_value_template": "{{ value_json.state1.state }}", - "brightness_value_template": "{{ value_json.state1.brightness }}", - "color_temp_value_template": "{{ value_json.state1.ct }}", - "effect_value_template": "{{ value_json.state1.fx }}", - "hs_value_template": "{{ value_json.state1.hs }}", - "rgb_value_template": "{{ value_json.state1.rgb }}", - "white_value_template": "{{ value_json.state1.white }}", - "xy_value_template": "{{ value_json.state1.xy }}", - } - ) + config1 = { + "name": "Beer", + "state_topic": "test_light_rgb/state1", + "command_topic": "test_light_rgb/set", + "brightness_command_topic": "test_light_rgb/state1", + "rgb_command_topic": "test_light_rgb/rgb/set", + "color_temp_command_topic": "test_light_rgb/state1", + "effect_command_topic": "test_light_rgb/effect/set", + "hs_command_topic": "test_light_rgb/hs/set", + "white_value_command_topic": "test_light_rgb/white_value/set", + "xy_command_topic": "test_light_rgb/xy/set", + "brightness_state_topic": "test_light_rgb/state1", + "color_temp_state_topic": "test_light_rgb/state1", + "effect_state_topic": "test_light_rgb/state1", + "hs_state_topic": "test_light_rgb/state1", + "rgb_state_topic": "test_light_rgb/state1", + "white_value_state_topic": "test_light_rgb/state1", + "xy_state_topic": "test_light_rgb/state1", + "state_value_template": "{{ value_json.state1.state }}", + "brightness_value_template": "{{ value_json.state1.brightness }}", + "color_temp_value_template": "{{ value_json.state1.ct }}", + "effect_value_template": "{{ value_json.state1.fx }}", + "hs_value_template": "{{ value_json.state1.hs }}", + "rgb_value_template": "{{ value_json.state1.rgb }}", + "white_value_template": "{{ value_json.state1.white }}", + "xy_value_template": "{{ value_json.state1.xy }}", + } - data2 = json.dumps( - { - "name": "Milk", - "state_topic": "test_light_rgb/state1", - "command_topic": "test_light_rgb/set", - "brightness_command_topic": "test_light_rgb/state1", - "rgb_command_topic": "test_light_rgb/rgb/set", - "color_temp_command_topic": "test_light_rgb/state1", - "effect_command_topic": "test_light_rgb/effect/set", - "hs_command_topic": "test_light_rgb/hs/set", - "white_value_command_topic": "test_light_rgb/white_value/set", - "xy_command_topic": "test_light_rgb/xy/set", - "brightness_state_topic": "test_light_rgb/state1", - "color_temp_state_topic": "test_light_rgb/state1", - "effect_state_topic": "test_light_rgb/state1", - "hs_state_topic": "test_light_rgb/state1", - "rgb_state_topic": "test_light_rgb/state1", - "white_value_state_topic": "test_light_rgb/state1", - "xy_state_topic": "test_light_rgb/state1", - "state_value_template": "{{ value_json.state2.state }}", - "brightness_value_template": "{{ value_json.state2.brightness }}", - "color_temp_value_template": "{{ value_json.state2.ct }}", - "effect_value_template": "{{ value_json.state2.fx }}", - "hs_value_template": "{{ value_json.state2.hs }}", - "rgb_value_template": "{{ value_json.state2.rgb }}", - "white_value_template": "{{ value_json.state2.white }}", - "xy_value_template": "{{ value_json.state2.xy }}", - } - ) + config2 = { + "name": "Milk", + "state_topic": "test_light_rgb/state1", + "command_topic": "test_light_rgb/set", + "brightness_command_topic": "test_light_rgb/state1", + "rgb_command_topic": "test_light_rgb/rgb/set", + "color_temp_command_topic": "test_light_rgb/state1", + "effect_command_topic": "test_light_rgb/effect/set", + "hs_command_topic": "test_light_rgb/hs/set", + "white_value_command_topic": "test_light_rgb/white_value/set", + "xy_command_topic": "test_light_rgb/xy/set", + "brightness_state_topic": "test_light_rgb/state1", + "color_temp_state_topic": "test_light_rgb/state1", + "effect_state_topic": "test_light_rgb/state1", + "hs_state_topic": "test_light_rgb/state1", + "rgb_state_topic": "test_light_rgb/state1", + "white_value_state_topic": "test_light_rgb/state1", + "xy_state_topic": "test_light_rgb/state1", + "state_value_template": "{{ value_json.state2.state }}", + "brightness_value_template": "{{ value_json.state2.brightness }}", + "color_temp_value_template": "{{ value_json.state2.ct }}", + "effect_value_template": "{{ value_json.state2.fx }}", + "hs_value_template": "{{ value_json.state2.hs }}", + "rgb_value_template": "{{ value_json.state2.rgb }}", + "white_value_template": "{{ value_json.state2.white }}", + "xy_value_template": "{{ value_json.state2.xy }}", + } state_data1 = [ ( [ @@ -3277,8 +3268,8 @@ async def test_discovery_update_light_template(hass, mqtt_mock, caplog): mqtt_mock, caplog, light.DOMAIN, - data1, - data2, + config1, + config2, state_data1=state_data1, state_data2=state_data2, ) diff --git a/tests/components/mqtt/test_light_json.py b/tests/components/mqtt/test_light_json.py index bf0dd1880a4..677509277c7 100644 --- a/tests/components/mqtt/test_light_json.py +++ b/tests/components/mqtt/test_light_json.py @@ -1786,20 +1786,20 @@ async def test_discovery_removal(hass, mqtt_mock, caplog): async def test_discovery_update_light(hass, mqtt_mock, caplog): """Test update of discovered light.""" - data1 = ( - '{ "name": "Beer",' - ' "schema": "json",' - ' "state_topic": "test_topic",' - ' "command_topic": "test_topic" }' - ) - data2 = ( - '{ "name": "Milk",' - ' "schema": "json",' - ' "state_topic": "test_topic",' - ' "command_topic": "test_topic" }' - ) + config1 = { + "name": "Beer", + "schema": "json", + "state_topic": "test_topic", + "command_topic": "test_topic", + } + config2 = { + "name": "Milk", + "schema": "json", + "state_topic": "test_topic", + "command_topic": "test_topic", + } await help_test_discovery_update( - hass, mqtt_mock, caplog, light.DOMAIN, data1, data2 + hass, mqtt_mock, caplog, light.DOMAIN, config1, config2 ) diff --git a/tests/components/mqtt/test_light_template.py b/tests/components/mqtt/test_light_template.py index 2dabf0b7e46..fe2d9badf7d 100644 --- a/tests/components/mqtt/test_light_template.py +++ b/tests/components/mqtt/test_light_template.py @@ -950,24 +950,24 @@ async def test_discovery_removal(hass, mqtt_mock, caplog): async def test_discovery_update_light(hass, mqtt_mock, caplog): """Test update of discovered light.""" - data1 = ( - '{ "name": "Beer",' - ' "schema": "template",' - ' "state_topic": "test_topic",' - ' "command_topic": "test_topic",' - ' "command_on_template": "on",' - ' "command_off_template": "off"}' - ) - data2 = ( - '{ "name": "Milk",' - ' "schema": "template",' - ' "state_topic": "test_topic",' - ' "command_topic": "test_topic",' - ' "command_on_template": "on",' - ' "command_off_template": "off"}' - ) + config1 = { + "name": "Beer", + "schema": "template", + "state_topic": "test_topic", + "command_topic": "test_topic", + "command_on_template": "on", + "command_off_template": "off", + } + config2 = { + "name": "Milk", + "schema": "template", + "state_topic": "test_topic", + "command_topic": "test_topic", + "command_on_template": "on", + "command_off_template": "off", + } await help_test_discovery_update( - hass, mqtt_mock, caplog, light.DOMAIN, data1, data2 + hass, mqtt_mock, caplog, light.DOMAIN, config1, config2 ) diff --git a/tests/components/mqtt/test_lock.py b/tests/components/mqtt/test_lock.py index 39250b0a2fa..97f524d5d82 100644 --- a/tests/components/mqtt/test_lock.py +++ b/tests/components/mqtt/test_lock.py @@ -379,19 +379,21 @@ async def test_discovery_removal_lock(hass, mqtt_mock, caplog): async def test_discovery_update_lock(hass, mqtt_mock, caplog): """Test update of discovered lock.""" - data1 = ( - '{ "name": "Beer",' - ' "state_topic": "test_topic",' - ' "command_topic": "command_topic",' - ' "availability_topic": "availability_topic1" }' + config1 = { + "name": "Beer", + "state_topic": "test_topic", + "command_topic": "command_topic", + "availability_topic": "availability_topic1", + } + config2 = { + "name": "Milk", + "state_topic": "test_topic2", + "command_topic": "command_topic", + "availability_topic": "availability_topic2", + } + await help_test_discovery_update( + hass, mqtt_mock, caplog, LOCK_DOMAIN, config1, config2 ) - data2 = ( - '{ "name": "Milk",' - ' "state_topic": "test_topic2",' - ' "command_topic": "command_topic",' - ' "availability_topic": "availability_topic2" }' - ) - await help_test_discovery_update(hass, mqtt_mock, caplog, LOCK_DOMAIN, data1, data2) async def test_discovery_update_unchanged_lock(hass, mqtt_mock, caplog): diff --git a/tests/components/mqtt/test_number.py b/tests/components/mqtt/test_number.py index e1e961aa84a..3b8b370eff8 100644 --- a/tests/components/mqtt/test_number.py +++ b/tests/components/mqtt/test_number.py @@ -344,15 +344,19 @@ async def test_discovery_removal_number(hass, mqtt_mock, caplog): async def test_discovery_update_number(hass, mqtt_mock, caplog): """Test update of discovered number.""" - data1 = ( - '{ "name": "Beer", "state_topic": "test-topic", "command_topic": "test-topic"}' - ) - data2 = ( - '{ "name": "Milk", "state_topic": "test-topic", "command_topic": "test-topic"}' - ) + config1 = { + "name": "Beer", + "state_topic": "test-topic", + "command_topic": "test-topic", + } + config2 = { + "name": "Milk", + "state_topic": "test-topic", + "command_topic": "test-topic", + } await help_test_discovery_update( - hass, mqtt_mock, caplog, number.DOMAIN, data1, data2 + hass, mqtt_mock, caplog, number.DOMAIN, config1, config2 ) diff --git a/tests/components/mqtt/test_scene.py b/tests/components/mqtt/test_scene.py index 9a233e19fd8..3d4cd0f5c25 100644 --- a/tests/components/mqtt/test_scene.py +++ b/tests/components/mqtt/test_scene.py @@ -1,6 +1,5 @@ """The tests for the MQTT scene platform.""" import copy -import json from unittest.mock import patch import pytest @@ -147,15 +146,13 @@ async def test_discovery_update_payload(hass, mqtt_mock, caplog): config1["payload_on"] = "ON" config2["payload_on"] = "ACTIVATE" - data1 = json.dumps(config1) - data2 = json.dumps(config2) await help_test_discovery_update( hass, mqtt_mock, caplog, scene.DOMAIN, - data1, - data2, + config1, + config2, ) diff --git a/tests/components/mqtt/test_select.py b/tests/components/mqtt/test_select.py index f2e48e10dc5..4843631f98b 100644 --- a/tests/components/mqtt/test_select.py +++ b/tests/components/mqtt/test_select.py @@ -309,11 +309,21 @@ async def test_discovery_removal_select(hass, mqtt_mock, caplog): async def test_discovery_update_select(hass, mqtt_mock, caplog): """Test update of discovered select.""" - data1 = '{ "name": "Beer", "state_topic": "test-topic", "command_topic": "test-topic", "options": ["milk", "beer"]}' - data2 = '{ "name": "Milk", "state_topic": "test-topic", "command_topic": "test-topic", "options": ["milk", "beer"]}' + config1 = { + "name": "Beer", + "state_topic": "test-topic", + "command_topic": "test-topic", + "options": ["milk", "beer"], + } + config2 = { + "name": "Milk", + "state_topic": "test-topic", + "command_topic": "test-topic", + "options": ["milk", "beer"], + } await help_test_discovery_update( - hass, mqtt_mock, caplog, select.DOMAIN, data1, data2 + hass, mqtt_mock, caplog, select.DOMAIN, config1, config2 ) diff --git a/tests/components/mqtt/test_sensor.py b/tests/components/mqtt/test_sensor.py index b7120b99f6e..752b1cfa48a 100644 --- a/tests/components/mqtt/test_sensor.py +++ b/tests/components/mqtt/test_sensor.py @@ -661,15 +661,13 @@ async def test_discovery_update_sensor_topic_template(hass, mqtt_mock, caplog): ([("sensor/state2", '{"state":100}')], "200", None), ] - data1 = json.dumps(config1) - data2 = json.dumps(config2) await help_test_discovery_update( hass, mqtt_mock, caplog, sensor.DOMAIN, - data1, - data2, + config1, + config2, state_data1=state_data1, state_data2=state_data2, ) @@ -694,15 +692,13 @@ async def test_discovery_update_sensor_template(hass, mqtt_mock, caplog): ([("sensor/state1", '{"state":100}')], "200", None), ] - data1 = json.dumps(config1) - data2 = json.dumps(config2) await help_test_discovery_update( hass, mqtt_mock, caplog, sensor.DOMAIN, - data1, - data2, + config1, + config2, state_data1=state_data1, state_data2=state_data2, ) diff --git a/tests/components/mqtt/test_state_vacuum.py b/tests/components/mqtt/test_state_vacuum.py index 46cc5552b6a..f53f8ebdab3 100644 --- a/tests/components/mqtt/test_state_vacuum.py +++ b/tests/components/mqtt/test_state_vacuum.py @@ -427,10 +427,10 @@ async def test_discovery_removal_vacuum(hass, mqtt_mock, caplog): async def test_discovery_update_vacuum(hass, mqtt_mock, caplog): """Test update of discovered vacuum.""" - data1 = '{ "schema": "state", "name": "Beer", "command_topic": "test_topic"}' - data2 = '{ "schema": "state", "name": "Milk", "command_topic": "test_topic"}' + config1 = {"schema": "state", "name": "Beer", "command_topic": "test_topic"} + config2 = {"schema": "state", "name": "Milk", "command_topic": "test_topic"} await help_test_discovery_update( - hass, mqtt_mock, caplog, vacuum.DOMAIN, data1, data2 + hass, mqtt_mock, caplog, vacuum.DOMAIN, config1, config2 ) diff --git a/tests/components/mqtt/test_switch.py b/tests/components/mqtt/test_switch.py index d5dcfbd4fa7..263ec0a2825 100644 --- a/tests/components/mqtt/test_switch.py +++ b/tests/components/mqtt/test_switch.py @@ -1,6 +1,5 @@ """The tests for the MQTT switch platform.""" import copy -import json from unittest.mock import patch import pytest @@ -339,15 +338,13 @@ async def test_discovery_update_switch_topic_template(hass, mqtt_mock, caplog): ([("switch/state2", '{"state2":{"state":"OFF"}}')], "off", None), ] - data1 = json.dumps(config1) - data2 = json.dumps(config2) await help_test_discovery_update( hass, mqtt_mock, caplog, switch.DOMAIN, - data1, - data2, + config1, + config2, state_data1=state_data1, state_data2=state_data2, ) @@ -374,15 +371,13 @@ async def test_discovery_update_switch_template(hass, mqtt_mock, caplog): ([("switch/state1", '{"state2":{"state":"OFF"}}')], "off", None), ] - data1 = json.dumps(config1) - data2 = json.dumps(config2) await help_test_discovery_update( hass, mqtt_mock, caplog, switch.DOMAIN, - data1, - data2, + config1, + config2, state_data1=state_data1, state_data2=state_data2, ) diff --git a/tests/components/mqtt/test_tag.py b/tests/components/mqtt/test_tag.py index 5e518c561b3..dfc0bddeec4 100644 --- a/tests/components/mqtt/test_tag.py +++ b/tests/components/mqtt/test_tag.py @@ -144,7 +144,9 @@ async def test_if_fires_on_mqtt_message_after_update_with_device( ): """Test tag scanning after update.""" config1 = copy.deepcopy(DEFAULT_CONFIG_DEVICE) + config1["some_future_option_1"] = "future_option_1" config2 = copy.deepcopy(DEFAULT_CONFIG_DEVICE) + config2["some_future_option_2"] = "future_option_2" config2["topic"] = "foobar/tag_scanned2" async_fire_mqtt_message(hass, "homeassistant/tag/bla1/config", json.dumps(config1))