mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Add MQTT cover as entity platform on MQTT subentries (#144381)
* Add MQTT cover as entity platform on MQTT subentries * Revert change vol.Coerce wrappers on cover schema * Fix template validator and cleanup redundant validators * Cleanup more redundant validators
This commit is contained in:
parent
17297ab929
commit
e8ea5c9d62
@ -27,6 +27,7 @@ import voluptuous as vol
|
||||
|
||||
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
|
||||
from homeassistant.components.button import ButtonDeviceClass
|
||||
from homeassistant.components.cover import CoverDeviceClass
|
||||
from homeassistant.components.file_upload import process_uploaded_file
|
||||
from homeassistant.components.hassio import AddonError, AddonManager, AddonState
|
||||
from homeassistant.components.light import (
|
||||
@ -78,6 +79,10 @@ from homeassistant.const import (
|
||||
CONF_UNIT_OF_MEASUREMENT,
|
||||
CONF_USERNAME,
|
||||
CONF_VALUE_TEMPLATE,
|
||||
STATE_CLOSED,
|
||||
STATE_CLOSING,
|
||||
STATE_OPEN,
|
||||
STATE_OPENING,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.data_entry_flow import AbortFlow, SectionConfig, section
|
||||
@ -150,6 +155,8 @@ from .const import (
|
||||
CONF_FLASH,
|
||||
CONF_FLASH_TIME_LONG,
|
||||
CONF_FLASH_TIME_SHORT,
|
||||
CONF_GET_POSITION_TEMPLATE,
|
||||
CONF_GET_POSITION_TOPIC,
|
||||
CONF_GREEN_TEMPLATE,
|
||||
CONF_HS_COMMAND_TEMPLATE,
|
||||
CONF_HS_COMMAND_TOPIC,
|
||||
@ -163,8 +170,14 @@ from .const import (
|
||||
CONF_ON_COMMAND_TYPE,
|
||||
CONF_OPTIONS,
|
||||
CONF_PAYLOAD_AVAILABLE,
|
||||
CONF_PAYLOAD_CLOSE,
|
||||
CONF_PAYLOAD_NOT_AVAILABLE,
|
||||
CONF_PAYLOAD_OPEN,
|
||||
CONF_PAYLOAD_PRESS,
|
||||
CONF_PAYLOAD_STOP,
|
||||
CONF_PAYLOAD_STOP_TILT,
|
||||
CONF_POSITION_CLOSED,
|
||||
CONF_POSITION_OPEN,
|
||||
CONF_QOS,
|
||||
CONF_RED_TEMPLATE,
|
||||
CONF_RETAIN,
|
||||
@ -181,10 +194,26 @@ from .const import (
|
||||
CONF_RGBWW_STATE_TOPIC,
|
||||
CONF_RGBWW_VALUE_TEMPLATE,
|
||||
CONF_SCHEMA,
|
||||
CONF_SET_POSITION_TEMPLATE,
|
||||
CONF_SET_POSITION_TOPIC,
|
||||
CONF_STATE_CLOSED,
|
||||
CONF_STATE_CLOSING,
|
||||
CONF_STATE_OPEN,
|
||||
CONF_STATE_OPENING,
|
||||
CONF_STATE_STOPPED,
|
||||
CONF_STATE_TOPIC,
|
||||
CONF_STATE_VALUE_TEMPLATE,
|
||||
CONF_SUGGESTED_DISPLAY_PRECISION,
|
||||
CONF_SUPPORTED_COLOR_MODES,
|
||||
CONF_TILT_CLOSED_POSITION,
|
||||
CONF_TILT_COMMAND_TEMPLATE,
|
||||
CONF_TILT_COMMAND_TOPIC,
|
||||
CONF_TILT_MAX,
|
||||
CONF_TILT_MIN,
|
||||
CONF_TILT_OPEN_POSITION,
|
||||
CONF_TILT_STATE_OPTIMISTIC,
|
||||
CONF_TILT_STATUS_TEMPLATE,
|
||||
CONF_TILT_STATUS_TOPIC,
|
||||
CONF_TLS_INSECURE,
|
||||
CONF_TRANSITION,
|
||||
CONF_TRANSPORT,
|
||||
@ -205,14 +234,24 @@ from .const import (
|
||||
DEFAULT_KEEPALIVE,
|
||||
DEFAULT_ON_COMMAND_TYPE,
|
||||
DEFAULT_PAYLOAD_AVAILABLE,
|
||||
DEFAULT_PAYLOAD_CLOSE,
|
||||
DEFAULT_PAYLOAD_NOT_AVAILABLE,
|
||||
DEFAULT_PAYLOAD_OFF,
|
||||
DEFAULT_PAYLOAD_ON,
|
||||
DEFAULT_PAYLOAD_OPEN,
|
||||
DEFAULT_PAYLOAD_PRESS,
|
||||
DEFAULT_PAYLOAD_STOP,
|
||||
DEFAULT_PORT,
|
||||
DEFAULT_POSITION_CLOSED,
|
||||
DEFAULT_POSITION_OPEN,
|
||||
DEFAULT_PREFIX,
|
||||
DEFAULT_PROTOCOL,
|
||||
DEFAULT_QOS,
|
||||
DEFAULT_STATE_STOPPED,
|
||||
DEFAULT_TILT_CLOSED_POSITION,
|
||||
DEFAULT_TILT_MAX,
|
||||
DEFAULT_TILT_MIN,
|
||||
DEFAULT_TILT_OPEN_POSITION,
|
||||
DEFAULT_TRANSPORT,
|
||||
DEFAULT_WILL,
|
||||
DEFAULT_WS_PATH,
|
||||
@ -313,6 +352,7 @@ KEY_UPLOAD_SELECTOR = FileSelector(
|
||||
SUBENTRY_PLATFORMS = [
|
||||
Platform.BINARY_SENSOR,
|
||||
Platform.BUTTON,
|
||||
Platform.COVER,
|
||||
Platform.LIGHT,
|
||||
Platform.NOTIFY,
|
||||
Platform.SENSOR,
|
||||
@ -365,6 +405,14 @@ BUTTON_DEVICE_CLASS_SELECTOR = SelectSelector(
|
||||
sort=True,
|
||||
)
|
||||
)
|
||||
COVER_DEVICE_CLASS_SELECTOR = SelectSelector(
|
||||
SelectSelectorConfig(
|
||||
options=[device_class.value for device_class in CoverDeviceClass],
|
||||
mode=SelectSelectorMode.DROPDOWN,
|
||||
translation_key="device_class_cover",
|
||||
sort=True,
|
||||
)
|
||||
)
|
||||
SENSOR_STATE_CLASS_SELECTOR = SelectSelector(
|
||||
SelectSelectorConfig(
|
||||
options=[device_class.value for device_class in SensorStateClass],
|
||||
@ -386,6 +434,9 @@ TIMEOUT_SELECTOR = NumberSelector(
|
||||
NumberSelectorConfig(mode=NumberSelectorMode.BOX, min=0)
|
||||
)
|
||||
|
||||
# Cover specific selectors
|
||||
POSITION_SELECTOR = NumberSelector(NumberSelectorConfig(mode=NumberSelectorMode.BOX))
|
||||
|
||||
# Switch specific selectors
|
||||
SWITCH_DEVICE_CLASS_SELECTOR = SelectSelector(
|
||||
SelectSelectorConfig(
|
||||
@ -444,6 +495,48 @@ SUPPORTED_COLOR_MODES_SELECTOR = SelectSelector(
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def validate_cover_platform_config(
|
||||
config: dict[str, Any],
|
||||
) -> dict[str, str]:
|
||||
"""Validate the cover platform options."""
|
||||
errors: dict[str, str] = {}
|
||||
|
||||
# If set position topic is set then get position topic is set as well.
|
||||
if CONF_SET_POSITION_TOPIC in config and CONF_GET_POSITION_TOPIC not in config:
|
||||
errors["cover_position_settings"] = (
|
||||
"cover_get_and_set_position_must_be_set_together"
|
||||
)
|
||||
|
||||
# if templates are set make sure the topic for the template is also set
|
||||
if CONF_VALUE_TEMPLATE in config and CONF_STATE_TOPIC not in config:
|
||||
errors[CONF_VALUE_TEMPLATE] = (
|
||||
"cover_value_template_must_be_used_with_state_topic"
|
||||
)
|
||||
|
||||
if CONF_GET_POSITION_TEMPLATE in config and CONF_GET_POSITION_TOPIC not in config:
|
||||
errors["cover_position_settings"] = (
|
||||
"cover_get_position_template_must_be_used_with_get_position_topic"
|
||||
)
|
||||
|
||||
if CONF_SET_POSITION_TEMPLATE in config and CONF_SET_POSITION_TOPIC not in config:
|
||||
errors["cover_position_settings"] = (
|
||||
"cover_set_position_template_must_be_used_with_set_position_topic"
|
||||
)
|
||||
|
||||
if CONF_TILT_COMMAND_TEMPLATE in config and CONF_TILT_COMMAND_TOPIC not in config:
|
||||
errors["cover_tilt_settings"] = (
|
||||
"cover_tilt_command_template_must_be_used_with_tilt_command_topic"
|
||||
)
|
||||
|
||||
if CONF_TILT_STATUS_TEMPLATE in config and CONF_TILT_STATUS_TOPIC not in config:
|
||||
errors["cover_tilt_settings"] = (
|
||||
"cover_tilt_status_template_must_be_used_with_tilt_status_topic"
|
||||
)
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
@callback
|
||||
def validate_sensor_platform_config(
|
||||
config: dict[str, Any],
|
||||
@ -571,6 +664,12 @@ PLATFORM_ENTITY_FIELDS = {
|
||||
required=False,
|
||||
),
|
||||
},
|
||||
Platform.COVER.value: {
|
||||
CONF_DEVICE_CLASS: PlatformField(
|
||||
selector=COVER_DEVICE_CLASS_SELECTOR,
|
||||
required=False,
|
||||
),
|
||||
},
|
||||
Platform.NOTIFY.value: {},
|
||||
Platform.SENSOR.value: {
|
||||
CONF_DEVICE_CLASS: PlatformField(
|
||||
@ -673,6 +772,185 @@ PLATFORM_MQTT_FIELDS = {
|
||||
),
|
||||
CONF_RETAIN: PlatformField(selector=BOOLEAN_SELECTOR, required=False),
|
||||
},
|
||||
Platform.COVER.value: {
|
||||
CONF_COMMAND_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_publish_topic,
|
||||
error="invalid_publish_topic",
|
||||
),
|
||||
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_RETAIN: PlatformField(selector=BOOLEAN_SELECTOR, required=False),
|
||||
CONF_OPTIMISTIC: PlatformField(selector=BOOLEAN_SELECTOR, required=False),
|
||||
CONF_PAYLOAD_CLOSE: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
default=DEFAULT_PAYLOAD_CLOSE,
|
||||
section="cover_payload_settings",
|
||||
),
|
||||
CONF_PAYLOAD_OPEN: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
default=DEFAULT_PAYLOAD_OPEN,
|
||||
section="cover_payload_settings",
|
||||
),
|
||||
CONF_PAYLOAD_STOP: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
default=None,
|
||||
section="cover_payload_settings",
|
||||
),
|
||||
CONF_PAYLOAD_STOP_TILT: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
default=DEFAULT_PAYLOAD_STOP,
|
||||
section="cover_payload_settings",
|
||||
),
|
||||
CONF_STATE_CLOSED: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
default=STATE_CLOSED,
|
||||
section="cover_payload_settings",
|
||||
),
|
||||
CONF_STATE_CLOSING: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
default=STATE_CLOSING,
|
||||
section="cover_payload_settings",
|
||||
),
|
||||
CONF_STATE_OPEN: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
default=STATE_OPEN,
|
||||
section="cover_payload_settings",
|
||||
),
|
||||
CONF_STATE_OPENING: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
default=STATE_OPENING,
|
||||
section="cover_payload_settings",
|
||||
),
|
||||
CONF_STATE_STOPPED: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
default=DEFAULT_STATE_STOPPED,
|
||||
section="cover_payload_settings",
|
||||
),
|
||||
CONF_SET_POSITION_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_publish_topic,
|
||||
error="invalid_publish_topic",
|
||||
section="cover_position_settings",
|
||||
),
|
||||
CONF_SET_POSITION_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="cover_position_settings",
|
||||
),
|
||||
CONF_GET_POSITION_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_subscribe_topic,
|
||||
error="invalid_subscribe_topic",
|
||||
section="cover_position_settings",
|
||||
),
|
||||
CONF_GET_POSITION_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="cover_position_settings",
|
||||
),
|
||||
CONF_POSITION_CLOSED: PlatformField(
|
||||
selector=POSITION_SELECTOR,
|
||||
required=False,
|
||||
validator=int,
|
||||
default=DEFAULT_POSITION_CLOSED,
|
||||
section="cover_position_settings",
|
||||
),
|
||||
CONF_POSITION_OPEN: PlatformField(
|
||||
selector=POSITION_SELECTOR,
|
||||
required=False,
|
||||
validator=int,
|
||||
default=DEFAULT_POSITION_OPEN,
|
||||
section="cover_position_settings",
|
||||
),
|
||||
CONF_TILT_COMMAND_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_publish_topic,
|
||||
error="invalid_publish_topic",
|
||||
section="cover_tilt_settings",
|
||||
),
|
||||
CONF_TILT_COMMAND_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="cover_tilt_settings",
|
||||
),
|
||||
CONF_TILT_CLOSED_POSITION: PlatformField(
|
||||
selector=POSITION_SELECTOR,
|
||||
required=False,
|
||||
validator=int,
|
||||
default=DEFAULT_TILT_CLOSED_POSITION,
|
||||
section="cover_tilt_settings",
|
||||
),
|
||||
CONF_TILT_OPEN_POSITION: PlatformField(
|
||||
selector=POSITION_SELECTOR,
|
||||
required=False,
|
||||
validator=int,
|
||||
default=DEFAULT_TILT_OPEN_POSITION,
|
||||
section="cover_tilt_settings",
|
||||
),
|
||||
CONF_TILT_STATUS_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_subscribe_topic,
|
||||
error="invalid_subscribe_topic",
|
||||
section="cover_tilt_settings",
|
||||
),
|
||||
CONF_TILT_STATUS_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="cover_tilt_settings",
|
||||
),
|
||||
CONF_TILT_MIN: PlatformField(
|
||||
selector=POSITION_SELECTOR,
|
||||
required=False,
|
||||
validator=int,
|
||||
default=DEFAULT_TILT_MIN,
|
||||
section="cover_tilt_settings",
|
||||
),
|
||||
CONF_TILT_MAX: PlatformField(
|
||||
selector=POSITION_SELECTOR,
|
||||
required=False,
|
||||
validator=int,
|
||||
default=DEFAULT_TILT_MAX,
|
||||
section="cover_tilt_settings",
|
||||
),
|
||||
CONF_TILT_STATE_OPTIMISTIC: PlatformField(
|
||||
selector=BOOLEAN_SELECTOR,
|
||||
required=False,
|
||||
section="cover_tilt_settings",
|
||||
),
|
||||
},
|
||||
Platform.NOTIFY.value: {
|
||||
CONF_COMMAND_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
@ -1231,6 +1509,7 @@ ENTITY_CONFIG_VALIDATOR: dict[
|
||||
] = {
|
||||
Platform.BINARY_SENSOR.value: None,
|
||||
Platform.BUTTON.value: None,
|
||||
Platform.COVER.value: validate_cover_platform_config,
|
||||
Platform.LIGHT.value: validate_light_platform_config,
|
||||
Platform.NOTIFY.value: None,
|
||||
Platform.SENSOR.value: validate_sensor_platform_config,
|
||||
|
@ -90,6 +90,8 @@ CONF_EXPIRE_AFTER = "expire_after"
|
||||
CONF_FLASH = "flash"
|
||||
CONF_FLASH_TIME_LONG = "flash_time_long"
|
||||
CONF_FLASH_TIME_SHORT = "flash_time_short"
|
||||
CONF_GET_POSITION_TEMPLATE = "position_template"
|
||||
CONF_GET_POSITION_TOPIC = "position_topic"
|
||||
CONF_GREEN_TEMPLATE = "green_template"
|
||||
CONF_HS_COMMAND_TEMPLATE = "hs_command_template"
|
||||
CONF_HS_COMMAND_TOPIC = "hs_command_topic"
|
||||
@ -111,6 +113,7 @@ CONF_PAYLOAD_CLOSE = "payload_close"
|
||||
CONF_PAYLOAD_OPEN = "payload_open"
|
||||
CONF_PAYLOAD_PRESS = "payload_press"
|
||||
CONF_PAYLOAD_STOP = "payload_stop"
|
||||
CONF_PAYLOAD_STOP_TILT = "payload_stop_tilt"
|
||||
CONF_POSITION_CLOSED = "position_closed"
|
||||
CONF_POSITION_OPEN = "position_open"
|
||||
CONF_POWER_COMMAND_TOPIC = "power_command_topic"
|
||||
@ -129,10 +132,13 @@ CONF_RGBWW_COMMAND_TEMPLATE = "rgbww_command_template"
|
||||
CONF_RGBWW_COMMAND_TOPIC = "rgbww_command_topic"
|
||||
CONF_RGBWW_STATE_TOPIC = "rgbww_state_topic"
|
||||
CONF_RGBWW_VALUE_TEMPLATE = "rgbww_value_template"
|
||||
CONF_SET_POSITION_TEMPLATE = "set_position_template"
|
||||
CONF_SET_POSITION_TOPIC = "set_position_topic"
|
||||
CONF_STATE_CLOSED = "state_closed"
|
||||
CONF_STATE_CLOSING = "state_closing"
|
||||
CONF_STATE_OPEN = "state_open"
|
||||
CONF_STATE_OPENING = "state_opening"
|
||||
CONF_STATE_STOPPED = "state_stopped"
|
||||
CONF_SUGGESTED_DISPLAY_PRECISION = "suggested_display_precision"
|
||||
CONF_SUPPORTED_COLOR_MODES = "supported_color_modes"
|
||||
CONF_TEMP_COMMAND_TEMPLATE = "temperature_command_template"
|
||||
@ -142,6 +148,15 @@ CONF_TEMP_STATE_TOPIC = "temperature_state_topic"
|
||||
CONF_TEMP_INITIAL = "initial"
|
||||
CONF_TEMP_MAX = "max_temp"
|
||||
CONF_TEMP_MIN = "min_temp"
|
||||
CONF_TILT_COMMAND_TEMPLATE = "tilt_command_template"
|
||||
CONF_TILT_COMMAND_TOPIC = "tilt_command_topic"
|
||||
CONF_TILT_STATUS_TOPIC = "tilt_status_topic"
|
||||
CONF_TILT_STATUS_TEMPLATE = "tilt_status_template"
|
||||
CONF_TILT_CLOSED_POSITION = "tilt_closed_value"
|
||||
CONF_TILT_MAX = "tilt_max"
|
||||
CONF_TILT_MIN = "tilt_min"
|
||||
CONF_TILT_OPEN_POSITION = "tilt_opened_value"
|
||||
CONF_TILT_STATE_OPTIMISTIC = "tilt_optimistic"
|
||||
CONF_TRANSITION = "transition"
|
||||
CONF_XY_COMMAND_TEMPLATE = "xy_command_template"
|
||||
CONF_XY_COMMAND_TOPIC = "xy_command_topic"
|
||||
@ -190,15 +205,25 @@ DEFAULT_PAYLOAD_OFF = "OFF"
|
||||
DEFAULT_PAYLOAD_ON = "ON"
|
||||
DEFAULT_PAYLOAD_OPEN = "OPEN"
|
||||
DEFAULT_PAYLOAD_PRESS = "PRESS"
|
||||
DEFAULT_PAYLOAD_STOP = "STOP"
|
||||
DEFAULT_PORT = 1883
|
||||
DEFAULT_RETAIN = False
|
||||
DEFAULT_TILT_CLOSED_POSITION = 0
|
||||
DEFAULT_TILT_MAX = 100
|
||||
DEFAULT_TILT_MIN = 0
|
||||
DEFAULT_TILT_OPEN_POSITION = 100
|
||||
DEFAULT_TILT_OPTIMISTIC = False
|
||||
DEFAULT_WS_HEADERS: dict[str, str] = {}
|
||||
DEFAULT_WS_PATH = "/"
|
||||
DEFAULT_POSITION_CLOSED = 0
|
||||
DEFAULT_POSITION_OPEN = 100
|
||||
DEFAULT_RETAIN = False
|
||||
DEFAULT_STATE_STOPPED = "stopped"
|
||||
DEFAULT_WHITE_SCALE = 255
|
||||
|
||||
COVER_PAYLOAD = "cover"
|
||||
TILT_PAYLOAD = "tilt"
|
||||
|
||||
VALUES_ON_COMMAND_TYPE = ["first", "last", "brightness"]
|
||||
|
||||
PROTOCOL_31 = "3.1"
|
||||
|
@ -43,23 +43,45 @@ from . import subscription
|
||||
from .config import MQTT_BASE_SCHEMA
|
||||
from .const import (
|
||||
CONF_COMMAND_TOPIC,
|
||||
CONF_GET_POSITION_TEMPLATE,
|
||||
CONF_GET_POSITION_TOPIC,
|
||||
CONF_PAYLOAD_CLOSE,
|
||||
CONF_PAYLOAD_OPEN,
|
||||
CONF_PAYLOAD_STOP,
|
||||
CONF_PAYLOAD_STOP_TILT,
|
||||
CONF_POSITION_CLOSED,
|
||||
CONF_POSITION_OPEN,
|
||||
CONF_RETAIN,
|
||||
CONF_SET_POSITION_TEMPLATE,
|
||||
CONF_SET_POSITION_TOPIC,
|
||||
CONF_STATE_CLOSED,
|
||||
CONF_STATE_CLOSING,
|
||||
CONF_STATE_OPEN,
|
||||
CONF_STATE_OPENING,
|
||||
CONF_STATE_STOPPED,
|
||||
CONF_STATE_TOPIC,
|
||||
CONF_TILT_CLOSED_POSITION,
|
||||
CONF_TILT_COMMAND_TEMPLATE,
|
||||
CONF_TILT_COMMAND_TOPIC,
|
||||
CONF_TILT_MAX,
|
||||
CONF_TILT_MIN,
|
||||
CONF_TILT_OPEN_POSITION,
|
||||
CONF_TILT_STATE_OPTIMISTIC,
|
||||
CONF_TILT_STATUS_TEMPLATE,
|
||||
CONF_TILT_STATUS_TOPIC,
|
||||
DEFAULT_OPTIMISTIC,
|
||||
DEFAULT_PAYLOAD_CLOSE,
|
||||
DEFAULT_PAYLOAD_OPEN,
|
||||
DEFAULT_PAYLOAD_STOP,
|
||||
DEFAULT_POSITION_CLOSED,
|
||||
DEFAULT_POSITION_OPEN,
|
||||
DEFAULT_RETAIN,
|
||||
DEFAULT_STATE_STOPPED,
|
||||
DEFAULT_TILT_CLOSED_POSITION,
|
||||
DEFAULT_TILT_MAX,
|
||||
DEFAULT_TILT_MIN,
|
||||
DEFAULT_TILT_OPEN_POSITION,
|
||||
DEFAULT_TILT_OPTIMISTIC,
|
||||
PAYLOAD_NONE,
|
||||
)
|
||||
from .entity import MqttEntity, async_setup_entity_entry_helper
|
||||
@ -71,37 +93,8 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
CONF_GET_POSITION_TOPIC = "position_topic"
|
||||
CONF_GET_POSITION_TEMPLATE = "position_template"
|
||||
CONF_SET_POSITION_TOPIC = "set_position_topic"
|
||||
CONF_SET_POSITION_TEMPLATE = "set_position_template"
|
||||
CONF_TILT_COMMAND_TOPIC = "tilt_command_topic"
|
||||
CONF_TILT_COMMAND_TEMPLATE = "tilt_command_template"
|
||||
CONF_TILT_STATUS_TOPIC = "tilt_status_topic"
|
||||
CONF_TILT_STATUS_TEMPLATE = "tilt_status_template"
|
||||
|
||||
CONF_STATE_STOPPED = "state_stopped"
|
||||
CONF_PAYLOAD_STOP_TILT = "payload_stop_tilt"
|
||||
CONF_TILT_CLOSED_POSITION = "tilt_closed_value"
|
||||
CONF_TILT_MAX = "tilt_max"
|
||||
CONF_TILT_MIN = "tilt_min"
|
||||
CONF_TILT_OPEN_POSITION = "tilt_opened_value"
|
||||
CONF_TILT_STATE_OPTIMISTIC = "tilt_optimistic"
|
||||
|
||||
TILT_PAYLOAD = "tilt"
|
||||
COVER_PAYLOAD = "cover"
|
||||
|
||||
DEFAULT_NAME = "MQTT Cover"
|
||||
|
||||
DEFAULT_STATE_STOPPED = "stopped"
|
||||
DEFAULT_PAYLOAD_STOP = "STOP"
|
||||
|
||||
DEFAULT_TILT_CLOSED_POSITION = 0
|
||||
DEFAULT_TILT_MAX = 100
|
||||
DEFAULT_TILT_MIN = 0
|
||||
DEFAULT_TILT_OPEN_POSITION = 100
|
||||
DEFAULT_TILT_OPTIMISTIC = False
|
||||
|
||||
TILT_FEATURES = (
|
||||
CoverEntityFeature.OPEN_TILT
|
||||
| CoverEntityFeature.CLOSE_TILT
|
||||
|
@ -316,6 +316,75 @@
|
||||
"transition": "Enable the transition feature for this light"
|
||||
}
|
||||
},
|
||||
"cover_payload_settings": {
|
||||
"name": "Payload settings",
|
||||
"data": {
|
||||
"payload_close": "Payload \"close\"",
|
||||
"payload_open": "Payload \"open\"",
|
||||
"payload_stop": "Payload \"stop\"",
|
||||
"payload_stop_tilt": "Payload \"stop tilt\"",
|
||||
"state_closed": "State \"closed\"",
|
||||
"state_closing": "State \"closing\"",
|
||||
"state_open": "State \"open\"",
|
||||
"state_opening": "State \"opening\"",
|
||||
"state_stopped": "State \"stopped\""
|
||||
},
|
||||
"data_description": {
|
||||
"payload_close": "The payload sent when a \"close\" command is issued.",
|
||||
"payload_open": "The payload sent when an \"open\" command is issued.",
|
||||
"payload_stop": "The payload sent when a \"stop\" command is issued. Leave empty to disable the \"stop\" feature.",
|
||||
"payload_stop_tilt": "The payload sent when a \"stop tilt\" command is issued.",
|
||||
"state_closed": "The payload received at the state topic that represents the \"closed\" state.",
|
||||
"state_closing": "The payload received at the state topic that represents the \"closing\" state.",
|
||||
"state_open": "The payload received at the state topic that represents the \"open\" state.",
|
||||
"state_opening": "The payload received at the state topic that represents the \"opening\" state.",
|
||||
"state_stopped": "The payload received at the state topic that represents the \"stopped\" state (for covers that do not report \"open\"/\"closed\" state)."
|
||||
}
|
||||
},
|
||||
"cover_position_settings": {
|
||||
"name": "Position settings",
|
||||
"data": {
|
||||
"position_closed": "Position \"closed\" value",
|
||||
"position_open": "Position \"open\" value",
|
||||
"position_template": "Position value template",
|
||||
"position_topic": "Position state topic",
|
||||
"set_position_template": "Set position template",
|
||||
"set_position_topic": "Set position topic"
|
||||
},
|
||||
"data_description": {
|
||||
"position_closed": "Number which represents \"closed\" position.",
|
||||
"position_open": "Number which represents \"open\" position.",
|
||||
"position_template": "Defines a [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to extract the payload for the position topic. Within the template the following variables are also available: `entity_id`, `position_open`, `position_closed`, `tilt_min` and `tilt_max`. [Learn more.]({url}#position_template)",
|
||||
"position_topic": "The MQTT topic subscribed to receive cover position state messages. [Learn more.]({url}#position_topic)",
|
||||
"set_position_template": "[Template](https://www.home-assistant.io/docs/configuration/templating/#using-command-templates-with-mqtt) to define the position to be sent to the set position topic. Within the template the following variables are available: `value` (the scaled target position), `entity_id`, `position` (the target position percentage), `position_open`, `position_closed`, `tilt_min` and `tilt_max`. [Learn more.]({url}#set_position_template)",
|
||||
"set_position_topic": "The MQTT topic to publish position commands to. You need to use the set position topic as well if you want to use the position topic. Use template if position topic wants different values than within range \"position closed\" - \"position_open\". If template is not defined and position \"closed\" != 100 and position \"open\" != 0 then proper position value is calculated from percentage position. [Learn more.]({url}#set_position_topic)"
|
||||
}
|
||||
},
|
||||
"cover_tilt_settings": {
|
||||
"name": "Tilt settings",
|
||||
"data": {
|
||||
"tilt_closed_value": "Tilt \"closed\" value",
|
||||
"tilt_command_template": "Set tilt template",
|
||||
"tilt_command_topic": "Set tilt topic",
|
||||
"tilt_max": "Tilt max",
|
||||
"tilt_min": "Tilt min",
|
||||
"tilt_opened_value": "Tilt \"opened\" value",
|
||||
"tilt_status_template": "Tilt value template",
|
||||
"tilt_status_topic": "Tilt status topic",
|
||||
"tilt_optimistic": "Tilt optimistic"
|
||||
},
|
||||
"data_description": {
|
||||
"tilt_closed_value": "The value that will be sent to the \"set tilt topic\" when the cover tilt is closed.",
|
||||
"tilt_command_template": "[Template](https://www.home-assistant.io/docs/configuration/templating/#using-command-templates-with-mqtt) to define the position to be sent to the set tilt topic. Within the template the following variables are available: `entity_id`, `tilt_position` (the target tilt position percentage), `position_open`, `position_closed`, `tilt_min` and `tilt_max`. [Learn more.]({url}#tilt_command_template)",
|
||||
"tilt_command_topic": "The MQTT topic to publish commands to control the cover tilt. [Learn more.]({url}#tilt_command_topic)",
|
||||
"tilt_max": "The maximum tilt value.",
|
||||
"tilt_min": "The minimum tilt value.",
|
||||
"tilt_opened_value": "The value that will be sent to the \"set tilt topic\" when the cover tilt is opened.",
|
||||
"tilt_status_template": "Defines a [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to extract the payload for the tilt status topic. Within the template the following variables are available: `entity_id`, `position_open`, `position_closed`, `tilt_min` and `tilt_max`. [Learn more.]({url}#tilt_status_template)",
|
||||
"tilt_status_topic": "The MQTT topic subscribed to receive tilt status update values. [Learn more.]({url}#tilt_status_topic)",
|
||||
"tilt_optimistic": "Flag that defines if tilt works in optimistic mode. If tilt status topic is not defined, tilt works in optimisic mode by default. [Learn more.]({url}#tilt_optimistic)"
|
||||
}
|
||||
},
|
||||
"light_brightness_settings": {
|
||||
"name": "Brightness settings",
|
||||
"data": {
|
||||
@ -476,6 +545,12 @@
|
||||
"default": "MQTT device with {platform} entity \"{entity}\" was set up successfully.\n\nNote that you can reconfigure the MQTT device at any time, e.g. to add more entities."
|
||||
},
|
||||
"error": {
|
||||
"cover_get_and_set_position_must_be_set_together": "The get position and set position topic options must be set together",
|
||||
"cover_get_position_template_must_be_used_with_get_position_topic": "The position value template must be used together with the position state topic setting",
|
||||
"cover_set_position_template_must_be_used_with_set_position_topic": "The set position template must be used with the set position topic",
|
||||
"cover_tilt_command_template_must_be_used_with_tilt_command_topic": "The tilt command template must be used with the tilt command topic",
|
||||
"cover_tilt_status_template_must_be_used_with_tilt_status_topic": "The tilt value template must be used with the tilt status topic",
|
||||
"cover_value_template_must_be_used_with_state_topic": "The value template must be used with the state topic option",
|
||||
"invalid_input": "Invalid value",
|
||||
"invalid_subscribe_topic": "Invalid subscribe topic",
|
||||
"invalid_template": "Invalid template",
|
||||
@ -643,6 +718,20 @@
|
||||
"update": "[%key:component::button::entity_component::update::name%]"
|
||||
}
|
||||
},
|
||||
"device_class_cover": {
|
||||
"options": {
|
||||
"awning": "[%key:component::cover::entity_component::awning::name%]",
|
||||
"blind": "[%key:component::cover::entity_component::blind::name%]",
|
||||
"curtain": "[%key:component::cover::entity_component::curtain::name%]",
|
||||
"damper": "[%key:component::cover::entity_component::damper::name%]",
|
||||
"door": "[%key:component::cover::entity_component::door::name%]",
|
||||
"garage": "[%key:component::cover::entity_component::garage::name%]",
|
||||
"gate": "[%key:component::cover::entity_component::gate::name%]",
|
||||
"shade": "[%key:component::cover::entity_component::shade::name%]",
|
||||
"shutter": "[%key:component::cover::entity_component::shutter::name%]",
|
||||
"window": "[%key:component::cover::entity_component::window::name%]"
|
||||
}
|
||||
},
|
||||
"device_class_sensor": {
|
||||
"options": {
|
||||
"apparent_power": "[%key:component::sensor::entity_component::apparent_power::name%]",
|
||||
@ -727,6 +816,7 @@
|
||||
"options": {
|
||||
"binary_sensor": "[%key:component::binary_sensor::title%]",
|
||||
"button": "[%key:component::button::title%]",
|
||||
"cover": "[%key:component::cover::title%]",
|
||||
"light": "[%key:component::light::title%]",
|
||||
"notify": "[%key:component::notify::title%]",
|
||||
"sensor": "[%key:component::sensor::title%]",
|
||||
|
@ -92,6 +92,41 @@ MOCK_SUBENTRY_BUTTON_COMPONENT = {
|
||||
"entity_picture": "https://example.com/365d05e6607c4dfb8ae915cff71a954b",
|
||||
},
|
||||
}
|
||||
MOCK_SUBENTRY_COVER_COMPONENT = {
|
||||
"b37acf667fa04c688ad7dfb27de2178b": {
|
||||
"platform": "cover",
|
||||
"name": "Blind",
|
||||
"device_class": "blind",
|
||||
"command_topic": "test-topic",
|
||||
"payload_stop": None,
|
||||
"payload_stop_tilt": "STOP",
|
||||
"payload_open": "OPEN",
|
||||
"payload_close": "CLOSE",
|
||||
"position_closed": 0,
|
||||
"position_open": 100,
|
||||
"position_template": "{{ value_json.position }}",
|
||||
"position_topic": "test-topic/position",
|
||||
"set_position_template": "{{ value }}",
|
||||
"set_position_topic": "test-topic/position-set",
|
||||
"state_closed": "closed",
|
||||
"state_closing": "closing",
|
||||
"state_open": "open",
|
||||
"state_opening": "opening",
|
||||
"state_stopped": "stopped",
|
||||
"state_topic": "test-topic",
|
||||
"tilt_closed_value": 0,
|
||||
"tilt_max": 100,
|
||||
"tilt_min": 0,
|
||||
"tilt_opened_value": 100,
|
||||
"tilt_optimistic": False,
|
||||
"tilt_command_topic": "test-topic/tilt-set",
|
||||
"tilt_command_template": "{{ value }}",
|
||||
"tilt_status_topic": "test-topic/tilt",
|
||||
"tilt_status_template": "{{ value_json.position }}",
|
||||
"retain": False,
|
||||
"entity_picture": "https://example.com/b37acf667fa04c688ad7dfb27de2178b",
|
||||
},
|
||||
}
|
||||
MOCK_SUBENTRY_NOTIFY_COMPONENT1 = {
|
||||
"363a7ecad6be4a19b939a016ea93e994": {
|
||||
"platform": "notify",
|
||||
@ -225,6 +260,10 @@ MOCK_BUTTON_SUBENTRY_DATA_SINGLE = {
|
||||
"device": MOCK_SUBENTRY_DEVICE_DATA | {"mqtt_settings": {"qos": 2}},
|
||||
"components": MOCK_SUBENTRY_BUTTON_COMPONENT,
|
||||
}
|
||||
MOCK_COVER_SUBENTRY_DATA_SINGLE = {
|
||||
"device": MOCK_SUBENTRY_DEVICE_DATA | {"mqtt_settings": {"qos": 0}},
|
||||
"components": MOCK_SUBENTRY_COVER_COMPONENT,
|
||||
}
|
||||
MOCK_NOTIFY_SUBENTRY_DATA_SINGLE = {
|
||||
"device": MOCK_SUBENTRY_DEVICE_DATA | {"mqtt_settings": {"qos": 1}},
|
||||
"components": MOCK_SUBENTRY_NOTIFY_COMPONENT1,
|
||||
|
@ -35,6 +35,7 @@ from homeassistant.helpers.service_info.hassio import HassioServiceInfo
|
||||
from .common import (
|
||||
MOCK_BINARY_SENSOR_SUBENTRY_DATA_SINGLE,
|
||||
MOCK_BUTTON_SUBENTRY_DATA_SINGLE,
|
||||
MOCK_COVER_SUBENTRY_DATA_SINGLE,
|
||||
MOCK_LIGHT_BASIC_KELVIN_SUBENTRY_DATA_SINGLE,
|
||||
MOCK_NOTIFY_SUBENTRY_DATA_MULTI,
|
||||
MOCK_NOTIFY_SUBENTRY_DATA_NO_NAME,
|
||||
@ -2698,6 +2699,92 @@ async def test_migrate_of_incompatible_config_entry(
|
||||
),
|
||||
"Milk notifier Restart",
|
||||
),
|
||||
(
|
||||
MOCK_COVER_SUBENTRY_DATA_SINGLE,
|
||||
{"name": "Milk notifier", "mqtt_settings": {"qos": 0}},
|
||||
{"name": "Blind"},
|
||||
{"device_class": "blind"},
|
||||
(),
|
||||
{
|
||||
"command_topic": "test-topic",
|
||||
"cover_position_settings": {
|
||||
"position_template": "{{ value_json.position }}",
|
||||
"position_topic": "test-topic/position",
|
||||
"set_position_template": "{{ value }}",
|
||||
"set_position_topic": "test-topic/position-set",
|
||||
},
|
||||
"state_topic": "test-topic",
|
||||
"retain": False,
|
||||
"cover_tilt_settings": {
|
||||
"tilt_command_topic": "test-topic/tilt-set",
|
||||
"tilt_command_template": "{{ value }}",
|
||||
"tilt_status_topic": "test-topic/tilt",
|
||||
"tilt_status_template": "{{ value_json.position }}",
|
||||
"tilt_closed_value": 0,
|
||||
"tilt_opened_value": 100,
|
||||
"tilt_max": 100,
|
||||
"tilt_min": 0,
|
||||
"tilt_optimistic": False,
|
||||
},
|
||||
},
|
||||
(
|
||||
(
|
||||
{"value_template": "{{ json_value.state }}"},
|
||||
{
|
||||
"value_template": "cover_value_template_must_be_used_with_state_topic"
|
||||
},
|
||||
),
|
||||
(
|
||||
{"cover_position_settings": {"set_position_topic": "test-topic"}},
|
||||
{
|
||||
"cover_position_settings": "cover_get_and_set_position_must_be_set_together"
|
||||
},
|
||||
),
|
||||
(
|
||||
{
|
||||
"cover_position_settings": {
|
||||
"set_position_template": "{{ value }}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cover_position_settings": "cover_set_position_template_must_be_used_with_set_position_topic"
|
||||
},
|
||||
),
|
||||
(
|
||||
{
|
||||
"cover_position_settings": {
|
||||
"position_template": "{{ json_value.position }}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cover_position_settings": "cover_get_position_template_must_be_used_with_get_position_topic"
|
||||
},
|
||||
),
|
||||
(
|
||||
{"cover_position_settings": {"set_position_topic": "{{ value }}"}},
|
||||
{
|
||||
"cover_position_settings": "cover_get_and_set_position_must_be_set_together"
|
||||
},
|
||||
),
|
||||
(
|
||||
{"cover_tilt_settings": {"tilt_command_template": "{{ value }}"}},
|
||||
{
|
||||
"cover_tilt_settings": "cover_tilt_command_template_must_be_used_with_tilt_command_topic"
|
||||
},
|
||||
),
|
||||
(
|
||||
{
|
||||
"cover_tilt_settings": {
|
||||
"tilt_status_template": "{{ json_value.position }}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cover_tilt_settings": "cover_tilt_status_template_must_be_used_with_tilt_status_topic"
|
||||
},
|
||||
),
|
||||
),
|
||||
"Milk notifier Blind",
|
||||
),
|
||||
(
|
||||
MOCK_NOTIFY_SUBENTRY_DATA_SINGLE,
|
||||
{"name": "Milk notifier", "mqtt_settings": {"qos": 1}},
|
||||
@ -2883,6 +2970,7 @@ async def test_migrate_of_incompatible_config_entry(
|
||||
ids=[
|
||||
"binary_sensor",
|
||||
"button",
|
||||
"cover",
|
||||
"notify_with_entity_name",
|
||||
"notify_no_entity_name",
|
||||
"sensor_options",
|
||||
|
Loading…
x
Reference in New Issue
Block a user