mirror of
https://github.com/home-assistant/core.git
synced 2025-07-31 17:18:23 +00:00
Add climate support for MQTT subentries (#149451)
Co-authored-by: Norbert Rittel <norbert@rittel.de>
This commit is contained in:
parent
c4d4ef884e
commit
a5b075af68
@ -60,6 +60,17 @@ from .const import (
|
||||
CONF_CURRENT_HUMIDITY_TOPIC,
|
||||
CONF_CURRENT_TEMP_TEMPLATE,
|
||||
CONF_CURRENT_TEMP_TOPIC,
|
||||
CONF_FAN_MODE_COMMAND_TEMPLATE,
|
||||
CONF_FAN_MODE_COMMAND_TOPIC,
|
||||
CONF_FAN_MODE_LIST,
|
||||
CONF_FAN_MODE_STATE_TEMPLATE,
|
||||
CONF_FAN_MODE_STATE_TOPIC,
|
||||
CONF_HUMIDITY_COMMAND_TEMPLATE,
|
||||
CONF_HUMIDITY_COMMAND_TOPIC,
|
||||
CONF_HUMIDITY_MAX,
|
||||
CONF_HUMIDITY_MIN,
|
||||
CONF_HUMIDITY_STATE_TEMPLATE,
|
||||
CONF_HUMIDITY_STATE_TOPIC,
|
||||
CONF_MODE_COMMAND_TEMPLATE,
|
||||
CONF_MODE_COMMAND_TOPIC,
|
||||
CONF_MODE_LIST,
|
||||
@ -68,14 +79,39 @@ from .const import (
|
||||
CONF_POWER_COMMAND_TEMPLATE,
|
||||
CONF_POWER_COMMAND_TOPIC,
|
||||
CONF_PRECISION,
|
||||
CONF_PRESET_MODE_COMMAND_TEMPLATE,
|
||||
CONF_PRESET_MODE_COMMAND_TOPIC,
|
||||
CONF_PRESET_MODE_STATE_TOPIC,
|
||||
CONF_PRESET_MODE_VALUE_TEMPLATE,
|
||||
CONF_PRESET_MODES_LIST,
|
||||
CONF_RETAIN,
|
||||
CONF_SWING_HORIZONTAL_MODE_COMMAND_TEMPLATE,
|
||||
CONF_SWING_HORIZONTAL_MODE_COMMAND_TOPIC,
|
||||
CONF_SWING_HORIZONTAL_MODE_LIST,
|
||||
CONF_SWING_HORIZONTAL_MODE_STATE_TEMPLATE,
|
||||
CONF_SWING_HORIZONTAL_MODE_STATE_TOPIC,
|
||||
CONF_SWING_MODE_COMMAND_TEMPLATE,
|
||||
CONF_SWING_MODE_COMMAND_TOPIC,
|
||||
CONF_SWING_MODE_LIST,
|
||||
CONF_SWING_MODE_STATE_TEMPLATE,
|
||||
CONF_SWING_MODE_STATE_TOPIC,
|
||||
CONF_TEMP_COMMAND_TEMPLATE,
|
||||
CONF_TEMP_COMMAND_TOPIC,
|
||||
CONF_TEMP_HIGH_COMMAND_TEMPLATE,
|
||||
CONF_TEMP_HIGH_COMMAND_TOPIC,
|
||||
CONF_TEMP_HIGH_STATE_TEMPLATE,
|
||||
CONF_TEMP_HIGH_STATE_TOPIC,
|
||||
CONF_TEMP_INITIAL,
|
||||
CONF_TEMP_LOW_COMMAND_TEMPLATE,
|
||||
CONF_TEMP_LOW_COMMAND_TOPIC,
|
||||
CONF_TEMP_LOW_STATE_TEMPLATE,
|
||||
CONF_TEMP_LOW_STATE_TOPIC,
|
||||
CONF_TEMP_MAX,
|
||||
CONF_TEMP_MIN,
|
||||
CONF_TEMP_STATE_TEMPLATE,
|
||||
CONF_TEMP_STATE_TOPIC,
|
||||
CONF_TEMP_STEP,
|
||||
DEFAULT_CLIMATE_INITIAL_TEMPERATURE,
|
||||
DEFAULT_OPTIMISTIC,
|
||||
PAYLOAD_NONE,
|
||||
)
|
||||
@ -95,49 +131,6 @@ PARALLEL_UPDATES = 0
|
||||
|
||||
DEFAULT_NAME = "MQTT HVAC"
|
||||
|
||||
CONF_FAN_MODE_COMMAND_TEMPLATE = "fan_mode_command_template"
|
||||
CONF_FAN_MODE_COMMAND_TOPIC = "fan_mode_command_topic"
|
||||
CONF_FAN_MODE_LIST = "fan_modes"
|
||||
CONF_FAN_MODE_STATE_TEMPLATE = "fan_mode_state_template"
|
||||
CONF_FAN_MODE_STATE_TOPIC = "fan_mode_state_topic"
|
||||
|
||||
CONF_HUMIDITY_COMMAND_TEMPLATE = "target_humidity_command_template"
|
||||
CONF_HUMIDITY_COMMAND_TOPIC = "target_humidity_command_topic"
|
||||
CONF_HUMIDITY_STATE_TEMPLATE = "target_humidity_state_template"
|
||||
CONF_HUMIDITY_STATE_TOPIC = "target_humidity_state_topic"
|
||||
CONF_HUMIDITY_MAX = "max_humidity"
|
||||
CONF_HUMIDITY_MIN = "min_humidity"
|
||||
|
||||
CONF_PRESET_MODE_STATE_TOPIC = "preset_mode_state_topic"
|
||||
CONF_PRESET_MODE_COMMAND_TOPIC = "preset_mode_command_topic"
|
||||
CONF_PRESET_MODE_VALUE_TEMPLATE = "preset_mode_value_template"
|
||||
CONF_PRESET_MODE_COMMAND_TEMPLATE = "preset_mode_command_template"
|
||||
CONF_PRESET_MODES_LIST = "preset_modes"
|
||||
|
||||
CONF_SWING_HORIZONTAL_MODE_COMMAND_TEMPLATE = "swing_horizontal_mode_command_template"
|
||||
CONF_SWING_HORIZONTAL_MODE_COMMAND_TOPIC = "swing_horizontal_mode_command_topic"
|
||||
CONF_SWING_HORIZONTAL_MODE_LIST = "swing_horizontal_modes"
|
||||
CONF_SWING_HORIZONTAL_MODE_STATE_TEMPLATE = "swing_horizontal_mode_state_template"
|
||||
CONF_SWING_HORIZONTAL_MODE_STATE_TOPIC = "swing_horizontal_mode_state_topic"
|
||||
|
||||
CONF_SWING_MODE_COMMAND_TEMPLATE = "swing_mode_command_template"
|
||||
CONF_SWING_MODE_COMMAND_TOPIC = "swing_mode_command_topic"
|
||||
CONF_SWING_MODE_LIST = "swing_modes"
|
||||
CONF_SWING_MODE_STATE_TEMPLATE = "swing_mode_state_template"
|
||||
CONF_SWING_MODE_STATE_TOPIC = "swing_mode_state_topic"
|
||||
|
||||
CONF_TEMP_HIGH_COMMAND_TEMPLATE = "temperature_high_command_template"
|
||||
CONF_TEMP_HIGH_COMMAND_TOPIC = "temperature_high_command_topic"
|
||||
CONF_TEMP_HIGH_STATE_TEMPLATE = "temperature_high_state_template"
|
||||
CONF_TEMP_HIGH_STATE_TOPIC = "temperature_high_state_topic"
|
||||
CONF_TEMP_LOW_COMMAND_TEMPLATE = "temperature_low_command_template"
|
||||
CONF_TEMP_LOW_COMMAND_TOPIC = "temperature_low_command_topic"
|
||||
CONF_TEMP_LOW_STATE_TEMPLATE = "temperature_low_state_template"
|
||||
CONF_TEMP_LOW_STATE_TOPIC = "temperature_low_state_topic"
|
||||
CONF_TEMP_STEP = "temp_step"
|
||||
|
||||
DEFAULT_INITIAL_TEMPERATURE = 21.0
|
||||
|
||||
MQTT_CLIMATE_ATTRIBUTES_BLOCKED = frozenset(
|
||||
{
|
||||
climate.ATTR_CURRENT_HUMIDITY,
|
||||
@ -299,8 +292,9 @@ _PLATFORM_SCHEMA_BASE = MQTT_BASE_SCHEMA.extend(
|
||||
vol.Optional(CONF_PAYLOAD_OFF, default="OFF"): cv.string,
|
||||
vol.Optional(CONF_POWER_COMMAND_TOPIC): valid_publish_topic,
|
||||
vol.Optional(CONF_POWER_COMMAND_TEMPLATE): cv.template,
|
||||
vol.Optional(CONF_PRECISION): vol.In(
|
||||
[PRECISION_TENTHS, PRECISION_HALVES, PRECISION_WHOLE]
|
||||
vol.Optional(CONF_PRECISION): vol.All(
|
||||
vol.Coerce(float),
|
||||
vol.In([PRECISION_TENTHS, PRECISION_HALVES, PRECISION_WHOLE]),
|
||||
),
|
||||
vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
|
||||
vol.Optional(CONF_ACTION_TEMPLATE): cv.template,
|
||||
@ -577,7 +571,7 @@ class MqttClimate(MqttTemperatureControlEntity, ClimateEntity):
|
||||
init_temp: float = config.get(
|
||||
CONF_TEMP_INITIAL,
|
||||
TemperatureConverter.convert(
|
||||
DEFAULT_INITIAL_TEMPERATURE,
|
||||
DEFAULT_CLIMATE_INITIAL_TEMPERATURE,
|
||||
UnitOfTemperature.CELSIUS,
|
||||
self.temperature_unit,
|
||||
),
|
||||
|
@ -29,6 +29,13 @@ import yaml
|
||||
|
||||
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
|
||||
from homeassistant.components.button import ButtonDeviceClass
|
||||
from homeassistant.components.climate import (
|
||||
DEFAULT_MAX_HUMIDITY,
|
||||
DEFAULT_MAX_TEMP,
|
||||
DEFAULT_MIN_HUMIDITY,
|
||||
DEFAULT_MIN_TEMP,
|
||||
PRESET_NONE,
|
||||
)
|
||||
from homeassistant.components.cover import CoverDeviceClass
|
||||
from homeassistant.components.file_upload import process_uploaded_file
|
||||
from homeassistant.components.hassio import AddonError, AddonManager, AddonState
|
||||
@ -80,6 +87,7 @@ from homeassistant.const import (
|
||||
CONF_PORT,
|
||||
CONF_PROTOCOL,
|
||||
CONF_STATE_TEMPLATE,
|
||||
CONF_TEMPERATURE_UNIT,
|
||||
CONF_UNIQUE_ID,
|
||||
CONF_UNIT_OF_MEASUREMENT,
|
||||
CONF_USERNAME,
|
||||
@ -89,8 +97,9 @@ from homeassistant.const import (
|
||||
STATE_OPEN,
|
||||
STATE_OPENING,
|
||||
EntityCategory,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.core import HomeAssistant, async_get_hass, callback
|
||||
from homeassistant.data_entry_flow import AbortFlow, SectionConfig, section
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.helpers.hassio import is_hassio
|
||||
@ -115,6 +124,7 @@ from homeassistant.helpers.selector import (
|
||||
)
|
||||
from homeassistant.helpers.service_info.hassio import HassioServiceInfo
|
||||
from homeassistant.util.json import JSON_DECODE_EXCEPTIONS, json_loads
|
||||
from homeassistant.util.unit_conversion import TemperatureConverter
|
||||
|
||||
from .addon import get_addon_manager
|
||||
from .client import MqttClientSetup
|
||||
@ -123,6 +133,8 @@ from .const import (
|
||||
ATTR_QOS,
|
||||
ATTR_RETAIN,
|
||||
ATTR_TOPIC,
|
||||
CONF_ACTION_TEMPLATE,
|
||||
CONF_ACTION_TOPIC,
|
||||
CONF_AVAILABILITY_TEMPLATE,
|
||||
CONF_AVAILABILITY_TOPIC,
|
||||
CONF_BIRTH_MESSAGE,
|
||||
@ -149,6 +161,10 @@ from .const import (
|
||||
CONF_COMMAND_ON_TEMPLATE,
|
||||
CONF_COMMAND_TEMPLATE,
|
||||
CONF_COMMAND_TOPIC,
|
||||
CONF_CURRENT_HUMIDITY_TEMPLATE,
|
||||
CONF_CURRENT_HUMIDITY_TOPIC,
|
||||
CONF_CURRENT_TEMP_TEMPLATE,
|
||||
CONF_CURRENT_TEMP_TOPIC,
|
||||
CONF_DIRECTION_COMMAND_TEMPLATE,
|
||||
CONF_DIRECTION_COMMAND_TOPIC,
|
||||
CONF_DIRECTION_STATE_TOPIC,
|
||||
@ -162,6 +178,11 @@ from .const import (
|
||||
CONF_EFFECT_VALUE_TEMPLATE,
|
||||
CONF_ENTITY_PICTURE,
|
||||
CONF_EXPIRE_AFTER,
|
||||
CONF_FAN_MODE_COMMAND_TEMPLATE,
|
||||
CONF_FAN_MODE_COMMAND_TOPIC,
|
||||
CONF_FAN_MODE_LIST,
|
||||
CONF_FAN_MODE_STATE_TEMPLATE,
|
||||
CONF_FAN_MODE_STATE_TOPIC,
|
||||
CONF_FLASH,
|
||||
CONF_FLASH_TIME_LONG,
|
||||
CONF_FLASH_TIME_SHORT,
|
||||
@ -172,10 +193,21 @@ from .const import (
|
||||
CONF_HS_COMMAND_TOPIC,
|
||||
CONF_HS_STATE_TOPIC,
|
||||
CONF_HS_VALUE_TEMPLATE,
|
||||
CONF_HUMIDITY_COMMAND_TEMPLATE,
|
||||
CONF_HUMIDITY_COMMAND_TOPIC,
|
||||
CONF_HUMIDITY_MAX,
|
||||
CONF_HUMIDITY_MIN,
|
||||
CONF_HUMIDITY_STATE_TEMPLATE,
|
||||
CONF_HUMIDITY_STATE_TOPIC,
|
||||
CONF_KEEPALIVE,
|
||||
CONF_LAST_RESET_VALUE_TEMPLATE,
|
||||
CONF_MAX_KELVIN,
|
||||
CONF_MIN_KELVIN,
|
||||
CONF_MODE_COMMAND_TEMPLATE,
|
||||
CONF_MODE_COMMAND_TOPIC,
|
||||
CONF_MODE_LIST,
|
||||
CONF_MODE_STATE_TEMPLATE,
|
||||
CONF_MODE_STATE_TOPIC,
|
||||
CONF_OFF_DELAY,
|
||||
CONF_ON_COMMAND_TYPE,
|
||||
CONF_OPTIONS,
|
||||
@ -200,6 +232,9 @@ from .const import (
|
||||
CONF_PERCENTAGE_VALUE_TEMPLATE,
|
||||
CONF_POSITION_CLOSED,
|
||||
CONF_POSITION_OPEN,
|
||||
CONF_POWER_COMMAND_TEMPLATE,
|
||||
CONF_POWER_COMMAND_TOPIC,
|
||||
CONF_PRECISION,
|
||||
CONF_PRESET_MODE_COMMAND_TEMPLATE,
|
||||
CONF_PRESET_MODE_COMMAND_TOPIC,
|
||||
CONF_PRESET_MODE_STATE_TOPIC,
|
||||
@ -236,6 +271,32 @@ from .const import (
|
||||
CONF_STATE_VALUE_TEMPLATE,
|
||||
CONF_SUGGESTED_DISPLAY_PRECISION,
|
||||
CONF_SUPPORTED_COLOR_MODES,
|
||||
CONF_SWING_HORIZONTAL_MODE_COMMAND_TEMPLATE,
|
||||
CONF_SWING_HORIZONTAL_MODE_COMMAND_TOPIC,
|
||||
CONF_SWING_HORIZONTAL_MODE_LIST,
|
||||
CONF_SWING_HORIZONTAL_MODE_STATE_TEMPLATE,
|
||||
CONF_SWING_HORIZONTAL_MODE_STATE_TOPIC,
|
||||
CONF_SWING_MODE_COMMAND_TEMPLATE,
|
||||
CONF_SWING_MODE_COMMAND_TOPIC,
|
||||
CONF_SWING_MODE_LIST,
|
||||
CONF_SWING_MODE_STATE_TEMPLATE,
|
||||
CONF_SWING_MODE_STATE_TOPIC,
|
||||
CONF_TEMP_COMMAND_TEMPLATE,
|
||||
CONF_TEMP_COMMAND_TOPIC,
|
||||
CONF_TEMP_HIGH_COMMAND_TEMPLATE,
|
||||
CONF_TEMP_HIGH_COMMAND_TOPIC,
|
||||
CONF_TEMP_HIGH_STATE_TEMPLATE,
|
||||
CONF_TEMP_HIGH_STATE_TOPIC,
|
||||
CONF_TEMP_INITIAL,
|
||||
CONF_TEMP_LOW_COMMAND_TEMPLATE,
|
||||
CONF_TEMP_LOW_COMMAND_TOPIC,
|
||||
CONF_TEMP_LOW_STATE_TEMPLATE,
|
||||
CONF_TEMP_LOW_STATE_TOPIC,
|
||||
CONF_TEMP_MAX,
|
||||
CONF_TEMP_MIN,
|
||||
CONF_TEMP_STATE_TEMPLATE,
|
||||
CONF_TEMP_STATE_TOPIC,
|
||||
CONF_TEMP_STEP,
|
||||
CONF_TILT_CLOSED_POSITION,
|
||||
CONF_TILT_COMMAND_TEMPLATE,
|
||||
CONF_TILT_COMMAND_TOPIC,
|
||||
@ -260,6 +321,7 @@ from .const import (
|
||||
CONFIG_ENTRY_MINOR_VERSION,
|
||||
CONFIG_ENTRY_VERSION,
|
||||
DEFAULT_BIRTH,
|
||||
DEFAULT_CLIMATE_INITIAL_TEMPERATURE,
|
||||
DEFAULT_DISCOVERY,
|
||||
DEFAULT_ENCODING,
|
||||
DEFAULT_KEEPALIVE,
|
||||
@ -392,6 +454,7 @@ KEY_UPLOAD_SELECTOR = FileSelector(
|
||||
SUBENTRY_PLATFORMS = [
|
||||
Platform.BINARY_SENSOR,
|
||||
Platform.BUTTON,
|
||||
Platform.CLIMATE,
|
||||
Platform.COVER,
|
||||
Platform.FAN,
|
||||
Platform.LIGHT,
|
||||
@ -493,6 +556,59 @@ TIMEOUT_SELECTOR = NumberSelector(
|
||||
NumberSelectorConfig(mode=NumberSelectorMode.BOX, min=0)
|
||||
)
|
||||
|
||||
# Climate specific selectors
|
||||
CLIMATE_MODE_SELECTOR = SelectSelector(
|
||||
SelectSelectorConfig(
|
||||
options=["auto", "off", "cool", "heat", "dry", "fan_only"],
|
||||
multiple=True,
|
||||
translation_key="climate_modes",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def temperature_selector(config: dict[str, Any]) -> Selector:
|
||||
"""Return a temperature selector with configured or system unit."""
|
||||
|
||||
return NumberSelector(
|
||||
NumberSelectorConfig(
|
||||
mode=NumberSelectorMode.BOX,
|
||||
unit_of_measurement=cv.temperature_unit(config[CONF_TEMPERATURE_UNIT]),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def temperature_step_selector(config: dict[str, Any]) -> Selector:
|
||||
"""Return a temperature step selector."""
|
||||
|
||||
return NumberSelector(
|
||||
NumberSelectorConfig(
|
||||
mode=NumberSelectorMode.BOX,
|
||||
min=0.1,
|
||||
max=10.0,
|
||||
step=0.1,
|
||||
unit_of_measurement=cv.temperature_unit(config[CONF_TEMPERATURE_UNIT]),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
TEMPERATURE_UNIT_SELECTOR = SelectSelector(
|
||||
SelectSelectorConfig(
|
||||
options=[
|
||||
SelectOptionDict(value="C", label="°C"),
|
||||
SelectOptionDict(value="F", label="°F"),
|
||||
],
|
||||
mode=SelectSelectorMode.DROPDOWN,
|
||||
)
|
||||
)
|
||||
PRECISION_SELECTOR = SelectSelector(
|
||||
SelectSelectorConfig(
|
||||
options=["1.0", "0.5", "0.1"],
|
||||
mode=SelectSelectorMode.DROPDOWN,
|
||||
)
|
||||
)
|
||||
|
||||
# Cover specific selectors
|
||||
POSITION_SELECTOR = NumberSelector(NumberSelectorConfig(mode=NumberSelectorMode.BOX))
|
||||
|
||||
@ -567,10 +683,91 @@ SUPPORTED_COLOR_MODES_SELECTOR = SelectSelector(
|
||||
EXCLUDE_FROM_CONFIG_IF_NONE = {CONF_ENTITY_CATEGORY}
|
||||
|
||||
|
||||
# Target temperature feature selector
|
||||
@callback
|
||||
def validate_cover_platform_config(
|
||||
config: dict[str, Any],
|
||||
) -> dict[str, str]:
|
||||
def configured_target_temperature_feature(config: dict[str, Any]) -> str:
|
||||
"""Calculate current target temperature feature from config."""
|
||||
if (
|
||||
config == {CONF_PLATFORM: Platform.CLIMATE.value}
|
||||
or CONF_TEMP_COMMAND_TOPIC in config
|
||||
):
|
||||
# default to single on initial set
|
||||
return "single"
|
||||
if CONF_TEMP_HIGH_COMMAND_TOPIC in config:
|
||||
return "high_low"
|
||||
return "none"
|
||||
|
||||
|
||||
TARGET_TEMPERATURE_FEATURE_SELECTOR = SelectSelector(
|
||||
SelectSelectorConfig(
|
||||
options=["single", "high_low", "none"],
|
||||
mode=SelectSelectorMode.DROPDOWN,
|
||||
translation_key="target_temperature_feature",
|
||||
)
|
||||
)
|
||||
HUMIDITY_SELECTOR = vol.All(
|
||||
NumberSelector(
|
||||
NumberSelectorConfig(mode=NumberSelectorMode.BOX, min=0, max=100, step=1)
|
||||
),
|
||||
vol.Coerce(int),
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def temperature_default_from_celsius_to_system_default(
|
||||
value: float,
|
||||
) -> Callable[[dict[str, Any]], int]:
|
||||
"""Return temperature in Celsius in system default unit."""
|
||||
|
||||
def _default(config: dict[str, Any]) -> int:
|
||||
return round(
|
||||
TemperatureConverter.convert(
|
||||
value,
|
||||
UnitOfTemperature.CELSIUS,
|
||||
cv.temperature_unit(config[CONF_TEMPERATURE_UNIT]),
|
||||
)
|
||||
)
|
||||
|
||||
return _default
|
||||
|
||||
|
||||
@callback
|
||||
def default_precision(config: dict[str, Any]) -> str:
|
||||
"""Return the thermostat precision for system default unit."""
|
||||
|
||||
return str(
|
||||
config.get(
|
||||
CONF_PRECISION,
|
||||
0.1
|
||||
if cv.temperature_unit(config[CONF_TEMPERATURE_UNIT])
|
||||
is UnitOfTemperature.CELSIUS
|
||||
else 1.0,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def validate_climate_platform_config(config: dict[str, Any]) -> dict[str, str]:
|
||||
"""Validate the climate platform options."""
|
||||
errors: dict[str, str] = {}
|
||||
if (
|
||||
CONF_PRESET_MODES_LIST in config
|
||||
and PRESET_NONE in config[CONF_PRESET_MODES_LIST]
|
||||
):
|
||||
errors["climate_preset_mode_settings"] = "preset_mode_none_not_allowed"
|
||||
if (
|
||||
CONF_HUMIDITY_MIN in config
|
||||
and config[CONF_HUMIDITY_MIN] >= config[CONF_HUMIDITY_MAX]
|
||||
):
|
||||
errors["target_humidity_settings"] = "max_below_min_humidity"
|
||||
if CONF_TEMP_MIN in config and config[CONF_TEMP_MIN] >= config[CONF_TEMP_MAX]:
|
||||
errors["target_temperature_settings"] = "max_below_min_temperature"
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
@callback
|
||||
def validate_cover_platform_config(config: dict[str, Any]) -> dict[str, str]:
|
||||
"""Validate the cover platform options."""
|
||||
errors: dict[str, str] = {}
|
||||
|
||||
@ -680,6 +877,14 @@ def validate_sensor_platform_config(
|
||||
return errors
|
||||
|
||||
|
||||
@callback
|
||||
def no_empty_list(value: list[Any]) -> list[Any]:
|
||||
"""Validate a selector returns at least one item."""
|
||||
if not value:
|
||||
raise vol.Invalid("empty_list_not_allowed")
|
||||
return value
|
||||
|
||||
|
||||
@callback
|
||||
def validate(validator: Callable[[Any], Any]) -> Callable[[Any], Any]:
|
||||
"""Run validator, then return the unmodified input."""
|
||||
@ -695,13 +900,13 @@ def validate(validator: Callable[[Any], Any]) -> Callable[[Any], Any]:
|
||||
class PlatformField:
|
||||
"""Stores a platform config field schema, required flag and validator."""
|
||||
|
||||
selector: Selector[Any] | Callable[..., Selector[Any]]
|
||||
selector: Selector[Any] | Callable[[dict[str, Any]], Selector[Any]]
|
||||
required: bool
|
||||
validator: Callable[..., Any] | None = None
|
||||
validator: Callable[[Any], Any] | None = None
|
||||
error: str | None = None
|
||||
default: (
|
||||
str | int | bool | None | Callable[[dict[str, Any]], Any] | vol.Undefined
|
||||
) = vol.UNDEFINED
|
||||
default: Any | None | Callable[[dict[str, Any]], Any] | vol.Undefined = (
|
||||
vol.UNDEFINED
|
||||
)
|
||||
is_schema_default: bool = False
|
||||
exclude_from_reconfig: bool = False
|
||||
exclude_from_config: bool = False
|
||||
@ -790,6 +995,78 @@ PLATFORM_ENTITY_FIELDS: dict[str, dict[str, PlatformField]] = {
|
||||
required=False,
|
||||
),
|
||||
},
|
||||
Platform.CLIMATE.value: {
|
||||
CONF_TEMPERATURE_UNIT: PlatformField(
|
||||
selector=TEMPERATURE_UNIT_SELECTOR,
|
||||
validator=validate(cv.temperature_unit),
|
||||
required=True,
|
||||
exclude_from_reconfig=True,
|
||||
default=lambda _: "C"
|
||||
if async_get_hass().config.units.temperature_unit
|
||||
is UnitOfTemperature.CELSIUS
|
||||
else "F",
|
||||
),
|
||||
"climate_feature_action": PlatformField(
|
||||
selector=BOOLEAN_SELECTOR,
|
||||
required=False,
|
||||
exclude_from_config=True,
|
||||
default=lambda config: bool(config.get(CONF_ACTION_TOPIC)),
|
||||
),
|
||||
"climate_feature_target_temperature": PlatformField(
|
||||
selector=TARGET_TEMPERATURE_FEATURE_SELECTOR,
|
||||
required=False,
|
||||
exclude_from_config=True,
|
||||
default=configured_target_temperature_feature,
|
||||
),
|
||||
"climate_feature_current_temperature": PlatformField(
|
||||
selector=BOOLEAN_SELECTOR,
|
||||
required=False,
|
||||
exclude_from_config=True,
|
||||
default=lambda config: bool(config.get(CONF_CURRENT_TEMP_TOPIC)),
|
||||
),
|
||||
"climate_feature_target_humidity": PlatformField(
|
||||
selector=BOOLEAN_SELECTOR,
|
||||
required=False,
|
||||
exclude_from_config=True,
|
||||
default=lambda config: bool(config.get(CONF_HUMIDITY_COMMAND_TOPIC)),
|
||||
),
|
||||
"climate_feature_current_humidity": PlatformField(
|
||||
selector=BOOLEAN_SELECTOR,
|
||||
required=False,
|
||||
exclude_from_config=True,
|
||||
default=lambda config: bool(config.get(CONF_HUMIDITY_STATE_TOPIC)),
|
||||
),
|
||||
"climate_feature_preset_modes": PlatformField(
|
||||
selector=BOOLEAN_SELECTOR,
|
||||
required=False,
|
||||
exclude_from_config=True,
|
||||
default=lambda config: bool(config.get(CONF_PRESET_MODES_LIST)),
|
||||
),
|
||||
"climate_feature_fan_modes": PlatformField(
|
||||
selector=BOOLEAN_SELECTOR,
|
||||
required=False,
|
||||
exclude_from_config=True,
|
||||
default=lambda config: bool(config.get(CONF_FAN_MODE_LIST)),
|
||||
),
|
||||
"climate_feature_swing_modes": PlatformField(
|
||||
selector=BOOLEAN_SELECTOR,
|
||||
required=False,
|
||||
exclude_from_config=True,
|
||||
default=lambda config: bool(config.get(CONF_SWING_MODE_LIST)),
|
||||
),
|
||||
"climate_feature_swing_horizontal_modes": PlatformField(
|
||||
selector=BOOLEAN_SELECTOR,
|
||||
required=False,
|
||||
exclude_from_config=True,
|
||||
default=lambda config: bool(config.get(CONF_SWING_HORIZONTAL_MODE_LIST)),
|
||||
),
|
||||
"climate_feature_power": PlatformField(
|
||||
selector=BOOLEAN_SELECTOR,
|
||||
required=False,
|
||||
exclude_from_config=True,
|
||||
default=lambda config: bool(config.get(CONF_POWER_COMMAND_TOPIC)),
|
||||
),
|
||||
},
|
||||
Platform.COVER.value: {
|
||||
CONF_DEVICE_CLASS: PlatformField(
|
||||
selector=COVER_DEVICE_CLASS_SELECTOR,
|
||||
@ -929,6 +1206,496 @@ PLATFORM_MQTT_FIELDS: dict[str, dict[str, PlatformField]] = {
|
||||
),
|
||||
CONF_RETAIN: PlatformField(selector=BOOLEAN_SELECTOR, required=False),
|
||||
},
|
||||
Platform.CLIMATE.value: {
|
||||
# operation mode settings
|
||||
CONF_MODE_COMMAND_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_publish_topic,
|
||||
error="invalid_publish_topic",
|
||||
),
|
||||
CONF_MODE_COMMAND_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
),
|
||||
CONF_MODE_STATE_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_subscribe_topic,
|
||||
error="invalid_subscribe_topic",
|
||||
),
|
||||
CONF_MODE_STATE_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
),
|
||||
CONF_MODE_LIST: PlatformField(
|
||||
selector=CLIMATE_MODE_SELECTOR,
|
||||
required=True,
|
||||
default=[],
|
||||
validator=validate(no_empty_list),
|
||||
error="empty_list_not_allowed",
|
||||
),
|
||||
CONF_RETAIN: PlatformField(
|
||||
selector=BOOLEAN_SELECTOR, required=False, validator=validate(bool)
|
||||
),
|
||||
CONF_OPTIMISTIC: PlatformField(
|
||||
selector=BOOLEAN_SELECTOR, required=False, validator=validate(bool)
|
||||
),
|
||||
# current action settings
|
||||
CONF_ACTION_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=True,
|
||||
validator=valid_subscribe_topic,
|
||||
error="invalid_subscribe_topic",
|
||||
section="climate_action_settings",
|
||||
conditions=({"climate_feature_action": True},),
|
||||
),
|
||||
CONF_ACTION_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="climate_action_settings",
|
||||
conditions=({"climate_feature_action": True},),
|
||||
),
|
||||
# target temperature settings
|
||||
CONF_TEMP_COMMAND_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=True,
|
||||
validator=valid_publish_topic,
|
||||
error="invalid_publish_topic",
|
||||
section="target_temperature_settings",
|
||||
conditions=({"climate_feature_target_temperature": "single"},),
|
||||
),
|
||||
CONF_TEMP_COMMAND_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="target_temperature_settings",
|
||||
conditions=({"climate_feature_target_temperature": "single"},),
|
||||
),
|
||||
CONF_TEMP_STATE_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_subscribe_topic,
|
||||
error="invalid_subscribe_topic",
|
||||
section="target_temperature_settings",
|
||||
conditions=({"climate_feature_target_temperature": "single"},),
|
||||
),
|
||||
CONF_TEMP_STATE_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="target_temperature_settings",
|
||||
conditions=({"climate_feature_target_temperature": "single"},),
|
||||
),
|
||||
CONF_TEMP_LOW_COMMAND_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=True,
|
||||
validator=valid_publish_topic,
|
||||
error="invalid_publish_topic",
|
||||
section="target_temperature_settings",
|
||||
conditions=({"climate_feature_target_temperature": "high_low"},),
|
||||
),
|
||||
CONF_TEMP_LOW_COMMAND_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="target_temperature_settings",
|
||||
conditions=({"climate_feature_target_temperature": "high_low"},),
|
||||
),
|
||||
CONF_TEMP_LOW_STATE_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_subscribe_topic,
|
||||
error="invalid_subscribe_topic",
|
||||
section="target_temperature_settings",
|
||||
conditions=({"climate_feature_target_temperature": "high_low"},),
|
||||
),
|
||||
CONF_TEMP_LOW_STATE_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="target_temperature_settings",
|
||||
conditions=({"climate_feature_target_temperature": "high_low"},),
|
||||
),
|
||||
CONF_TEMP_HIGH_COMMAND_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=True,
|
||||
validator=valid_publish_topic,
|
||||
error="invalid_publish_topic",
|
||||
section="target_temperature_settings",
|
||||
conditions=({"climate_feature_target_temperature": "high_low"},),
|
||||
),
|
||||
CONF_TEMP_HIGH_COMMAND_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="target_temperature_settings",
|
||||
conditions=({"climate_feature_target_temperature": "high_low"},),
|
||||
),
|
||||
CONF_TEMP_HIGH_STATE_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_subscribe_topic,
|
||||
error="invalid_subscribe_topic",
|
||||
section="target_temperature_settings",
|
||||
conditions=({"climate_feature_target_temperature": "high_low"},),
|
||||
),
|
||||
CONF_TEMP_HIGH_STATE_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="target_temperature_settings",
|
||||
conditions=({"climate_feature_target_temperature": "high_low"},),
|
||||
),
|
||||
CONF_TEMP_MIN: PlatformField(
|
||||
selector=temperature_selector,
|
||||
custom_filtering=True,
|
||||
required=True,
|
||||
default=temperature_default_from_celsius_to_system_default(
|
||||
DEFAULT_MIN_TEMP
|
||||
),
|
||||
section="target_temperature_settings",
|
||||
conditions=(
|
||||
{"climate_feature_target_temperature": "high_low"},
|
||||
{"climate_feature_target_temperature": "single"},
|
||||
),
|
||||
),
|
||||
CONF_TEMP_MAX: PlatformField(
|
||||
selector=temperature_selector,
|
||||
custom_filtering=True,
|
||||
required=True,
|
||||
default=temperature_default_from_celsius_to_system_default(
|
||||
DEFAULT_MAX_TEMP
|
||||
),
|
||||
section="target_temperature_settings",
|
||||
conditions=(
|
||||
{"climate_feature_target_temperature": "high_low"},
|
||||
{"climate_feature_target_temperature": "single"},
|
||||
),
|
||||
),
|
||||
CONF_PRECISION: PlatformField(
|
||||
selector=PRECISION_SELECTOR,
|
||||
required=False,
|
||||
default=default_precision,
|
||||
section="target_temperature_settings",
|
||||
conditions=(
|
||||
{"climate_feature_target_temperature": "high_low"},
|
||||
{"climate_feature_target_temperature": "single"},
|
||||
),
|
||||
),
|
||||
CONF_TEMP_STEP: PlatformField(
|
||||
selector=temperature_step_selector,
|
||||
custom_filtering=True,
|
||||
required=False,
|
||||
default=1.0,
|
||||
section="target_temperature_settings",
|
||||
conditions=(
|
||||
{"climate_feature_target_temperature": "high_low"},
|
||||
{"climate_feature_target_temperature": "single"},
|
||||
),
|
||||
),
|
||||
CONF_TEMP_INITIAL: PlatformField(
|
||||
selector=temperature_selector,
|
||||
custom_filtering=True,
|
||||
required=False,
|
||||
default=temperature_default_from_celsius_to_system_default(
|
||||
DEFAULT_CLIMATE_INITIAL_TEMPERATURE
|
||||
),
|
||||
section="target_temperature_settings",
|
||||
conditions=(
|
||||
{"climate_feature_target_temperature": "high_low"},
|
||||
{"climate_feature_target_temperature": "single"},
|
||||
),
|
||||
),
|
||||
# current temperature settings
|
||||
CONF_CURRENT_TEMP_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_subscribe_topic,
|
||||
error="invalid_subscribe_topic",
|
||||
section="current_temperature_settings",
|
||||
conditions=({"climate_feature_current_temperature": True},),
|
||||
),
|
||||
CONF_CURRENT_TEMP_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="current_temperature_settings",
|
||||
conditions=({"climate_feature_current_temperature": True},),
|
||||
),
|
||||
# target humidity settings
|
||||
CONF_HUMIDITY_COMMAND_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=True,
|
||||
validator=valid_publish_topic,
|
||||
error="invalid_publish_topic",
|
||||
section="target_humidity_settings",
|
||||
conditions=({"climate_feature_target_humidity": True},),
|
||||
),
|
||||
CONF_HUMIDITY_COMMAND_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="target_humidity_settings",
|
||||
conditions=({"climate_feature_target_humidity": True},),
|
||||
),
|
||||
CONF_HUMIDITY_STATE_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_subscribe_topic,
|
||||
error="invalid_subscribe_topic",
|
||||
section="target_humidity_settings",
|
||||
conditions=({"climate_feature_target_humidity": True},),
|
||||
),
|
||||
CONF_HUMIDITY_STATE_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="target_humidity_settings",
|
||||
conditions=({"climate_feature_target_humidity": True},),
|
||||
),
|
||||
CONF_HUMIDITY_MIN: PlatformField(
|
||||
selector=HUMIDITY_SELECTOR,
|
||||
required=True,
|
||||
default=DEFAULT_MIN_HUMIDITY,
|
||||
section="target_humidity_settings",
|
||||
conditions=({"climate_feature_target_humidity": True},),
|
||||
),
|
||||
CONF_HUMIDITY_MAX: PlatformField(
|
||||
selector=HUMIDITY_SELECTOR,
|
||||
required=True,
|
||||
default=DEFAULT_MAX_HUMIDITY,
|
||||
section="target_humidity_settings",
|
||||
conditions=({"climate_feature_target_humidity": True},),
|
||||
),
|
||||
# current humidity settings
|
||||
CONF_CURRENT_HUMIDITY_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=True,
|
||||
validator=valid_subscribe_topic,
|
||||
error="invalid_subscribe_topic",
|
||||
section="current_humidity_settings",
|
||||
conditions=({"climate_feature_current_humidity": True},),
|
||||
),
|
||||
CONF_CURRENT_HUMIDITY_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="current_humidity_settings",
|
||||
conditions=({"climate_feature_current_humidity": True},),
|
||||
),
|
||||
# power on/off support
|
||||
CONF_POWER_COMMAND_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_publish_topic,
|
||||
error="invalid_publish_topic",
|
||||
section="climate_power_settings",
|
||||
conditions=({"climate_feature_power": True},),
|
||||
),
|
||||
CONF_POWER_COMMAND_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="climate_power_settings",
|
||||
conditions=({"climate_feature_power": True},),
|
||||
),
|
||||
CONF_PAYLOAD_OFF: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
default=DEFAULT_PAYLOAD_OFF,
|
||||
section="climate_power_settings",
|
||||
conditions=({"climate_feature_power": True},),
|
||||
),
|
||||
CONF_PAYLOAD_ON: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
default=DEFAULT_PAYLOAD_ON,
|
||||
section="climate_power_settings",
|
||||
conditions=({"climate_feature_power": True},),
|
||||
),
|
||||
# preset mode settings
|
||||
CONF_PRESET_MODE_COMMAND_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=True,
|
||||
validator=valid_publish_topic,
|
||||
error="invalid_publish_topic",
|
||||
section="climate_preset_mode_settings",
|
||||
conditions=({"climate_feature_preset_modes": True},),
|
||||
),
|
||||
CONF_PRESET_MODE_COMMAND_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="climate_preset_mode_settings",
|
||||
conditions=({"climate_feature_preset_modes": True},),
|
||||
),
|
||||
CONF_PRESET_MODE_STATE_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_subscribe_topic,
|
||||
error="invalid_subscribe_topic",
|
||||
section="climate_preset_mode_settings",
|
||||
conditions=({"climate_feature_preset_modes": True},),
|
||||
),
|
||||
CONF_PRESET_MODE_VALUE_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="climate_preset_mode_settings",
|
||||
conditions=({"climate_feature_preset_modes": True},),
|
||||
),
|
||||
CONF_PRESET_MODES_LIST: PlatformField(
|
||||
selector=PRESET_MODES_SELECTOR,
|
||||
required=True,
|
||||
validator=validate(no_empty_list),
|
||||
error="empty_list_not_allowed",
|
||||
section="climate_preset_mode_settings",
|
||||
conditions=({"climate_feature_preset_modes": True},),
|
||||
),
|
||||
# fan mode settings
|
||||
CONF_FAN_MODE_COMMAND_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=True,
|
||||
validator=valid_publish_topic,
|
||||
error="invalid_publish_topic",
|
||||
section="climate_fan_mode_settings",
|
||||
conditions=({"climate_feature_fan_modes": True},),
|
||||
),
|
||||
CONF_FAN_MODE_COMMAND_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="climate_fan_mode_settings",
|
||||
conditions=({"climate_feature_fan_modes": True},),
|
||||
),
|
||||
CONF_FAN_MODE_STATE_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_subscribe_topic,
|
||||
error="invalid_subscribe_topic",
|
||||
section="climate_fan_mode_settings",
|
||||
conditions=({"climate_feature_fan_modes": True},),
|
||||
),
|
||||
CONF_FAN_MODE_STATE_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="climate_fan_mode_settings",
|
||||
conditions=({"climate_feature_fan_modes": True},),
|
||||
),
|
||||
CONF_FAN_MODE_LIST: PlatformField(
|
||||
selector=PRESET_MODES_SELECTOR,
|
||||
required=True,
|
||||
validator=validate(no_empty_list),
|
||||
error="empty_list_not_allowed",
|
||||
section="climate_fan_mode_settings",
|
||||
conditions=({"climate_feature_fan_modes": True},),
|
||||
),
|
||||
# swing mode settings
|
||||
CONF_SWING_MODE_COMMAND_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=True,
|
||||
validator=valid_publish_topic,
|
||||
error="invalid_publish_topic",
|
||||
section="climate_swing_mode_settings",
|
||||
conditions=({"climate_feature_swing_modes": True},),
|
||||
),
|
||||
CONF_SWING_MODE_COMMAND_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="climate_swing_mode_settings",
|
||||
conditions=({"climate_feature_swing_modes": True},),
|
||||
),
|
||||
CONF_SWING_MODE_STATE_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_subscribe_topic,
|
||||
error="invalid_subscribe_topic",
|
||||
section="climate_swing_mode_settings",
|
||||
conditions=({"climate_feature_swing_modes": True},),
|
||||
),
|
||||
CONF_SWING_MODE_STATE_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="climate_swing_mode_settings",
|
||||
conditions=({"climate_feature_swing_modes": True},),
|
||||
),
|
||||
CONF_SWING_MODE_LIST: PlatformField(
|
||||
selector=PRESET_MODES_SELECTOR,
|
||||
required=True,
|
||||
validator=validate(no_empty_list),
|
||||
error="empty_list_not_allowed",
|
||||
section="climate_swing_mode_settings",
|
||||
conditions=({"climate_feature_swing_modes": True},),
|
||||
),
|
||||
# swing horizontal mode settings
|
||||
CONF_SWING_HORIZONTAL_MODE_COMMAND_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=True,
|
||||
validator=valid_publish_topic,
|
||||
error="invalid_publish_topic",
|
||||
section="climate_swing_horizontal_mode_settings",
|
||||
conditions=({"climate_feature_swing_horizontal_modes": True},),
|
||||
),
|
||||
CONF_SWING_HORIZONTAL_MODE_COMMAND_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="climate_swing_horizontal_mode_settings",
|
||||
conditions=({"climate_feature_swing_horizontal_modes": True},),
|
||||
),
|
||||
CONF_SWING_HORIZONTAL_MODE_STATE_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
required=False,
|
||||
validator=valid_subscribe_topic,
|
||||
error="invalid_subscribe_topic",
|
||||
section="climate_swing_horizontal_mode_settings",
|
||||
conditions=({"climate_feature_swing_horizontal_modes": True},),
|
||||
),
|
||||
CONF_SWING_HORIZONTAL_MODE_STATE_TEMPLATE: PlatformField(
|
||||
selector=TEMPLATE_SELECTOR,
|
||||
required=False,
|
||||
validator=validate(cv.template),
|
||||
error="invalid_template",
|
||||
section="climate_swing_horizontal_mode_settings",
|
||||
conditions=({"climate_feature_swing_horizontal_modes": True},),
|
||||
),
|
||||
CONF_SWING_HORIZONTAL_MODE_LIST: PlatformField(
|
||||
selector=PRESET_MODES_SELECTOR,
|
||||
required=True,
|
||||
validator=validate(no_empty_list),
|
||||
error="empty_list_not_allowed",
|
||||
section="climate_swing_horizontal_mode_settings",
|
||||
conditions=({"climate_feature_swing_horizontal_modes": True},),
|
||||
),
|
||||
},
|
||||
Platform.COVER.value: {
|
||||
CONF_COMMAND_TOPIC: PlatformField(
|
||||
selector=TEXT_SELECTOR,
|
||||
@ -1904,6 +2671,7 @@ ENTITY_CONFIG_VALIDATOR: dict[
|
||||
] = {
|
||||
Platform.BINARY_SENSOR.value: None,
|
||||
Platform.BUTTON.value: None,
|
||||
Platform.CLIMATE.value: validate_climate_platform_config,
|
||||
Platform.COVER.value: validate_cover_platform_config,
|
||||
Platform.FAN.value: validate_fan_platform_config,
|
||||
Platform.LIGHT.value: validate_light_platform_config,
|
||||
@ -2097,15 +2865,15 @@ def data_schema_from_fields(
|
||||
no_reconfig_options: set[Any] = set()
|
||||
for schema_section in sections:
|
||||
data_schema_element = {
|
||||
vol.Required(field_name, default=field_details.default)
|
||||
vol.Required(field_name, default=get_default(field_details))
|
||||
if field_details.required
|
||||
else vol.Optional(
|
||||
field_name,
|
||||
default=get_default(field_details)
|
||||
if field_details.default is not None
|
||||
else vol.UNDEFINED,
|
||||
): field_details.selector(component_data_with_user_input) # type: ignore[operator]
|
||||
if field_details.custom_filtering
|
||||
): field_details.selector(component_data_with_user_input or {})
|
||||
if callable(field_details.selector) and field_details.custom_filtering
|
||||
else field_details.selector
|
||||
for field_name, field_details in data_schema_fields.items()
|
||||
if not field_details.is_schema_default
|
||||
@ -2127,12 +2895,20 @@ def data_schema_from_fields(
|
||||
if not data_schema_element:
|
||||
# Do not show empty sections
|
||||
continue
|
||||
# Collapse if values are changed or required fields need to be set
|
||||
collapsed = (
|
||||
not any(
|
||||
(default := data_schema_fields[str(option)].default) is vol.UNDEFINED
|
||||
or component_data_with_user_input[str(option)] != default
|
||||
or (
|
||||
str(option) in component_data_with_user_input
|
||||
and component_data_with_user_input[str(option)] != default
|
||||
)
|
||||
for option in data_element_options
|
||||
if option in component_data_with_user_input
|
||||
or (
|
||||
str(option) in data_schema_fields
|
||||
and data_schema_fields[str(option)].required
|
||||
)
|
||||
)
|
||||
if component_data_with_user_input is not None
|
||||
else True
|
||||
|
@ -26,7 +26,6 @@ CONF_PAYLOAD_AVAILABLE = "payload_available"
|
||||
CONF_PAYLOAD_NOT_AVAILABLE = "payload_not_available"
|
||||
|
||||
CONF_AVAILABILITY = "availability"
|
||||
|
||||
CONF_AVAILABILITY_MODE = "availability_mode"
|
||||
CONF_AVAILABILITY_TEMPLATE = "availability_template"
|
||||
CONF_AVAILABILITY_TOPIC = "availability_topic"
|
||||
@ -53,7 +52,6 @@ CONF_WS_HEADERS = "ws_headers"
|
||||
CONF_WILL_MESSAGE = "will_message"
|
||||
CONF_PAYLOAD_RESET = "payload_reset"
|
||||
CONF_SUPPORTED_FEATURES = "supported_features"
|
||||
|
||||
CONF_ACTION_TEMPLATE = "action_template"
|
||||
CONF_ACTION_TOPIC = "action_topic"
|
||||
CONF_BLUE_TEMPLATE = "blue_template"
|
||||
@ -91,6 +89,11 @@ CONF_EFFECT_TEMPLATE = "effect_template"
|
||||
CONF_EFFECT_VALUE_TEMPLATE = "effect_value_template"
|
||||
CONF_ENTITY_PICTURE = "entity_picture"
|
||||
CONF_EXPIRE_AFTER = "expire_after"
|
||||
CONF_FAN_MODE_COMMAND_TEMPLATE = "fan_mode_command_template"
|
||||
CONF_FAN_MODE_COMMAND_TOPIC = "fan_mode_command_topic"
|
||||
CONF_FAN_MODE_LIST = "fan_modes"
|
||||
CONF_FAN_MODE_STATE_TEMPLATE = "fan_mode_state_template"
|
||||
CONF_FAN_MODE_STATE_TOPIC = "fan_mode_state_topic"
|
||||
CONF_FLASH = "flash"
|
||||
CONF_FLASH_TIME_LONG = "flash_time_long"
|
||||
CONF_FLASH_TIME_SHORT = "flash_time_short"
|
||||
@ -101,6 +104,12 @@ CONF_HS_COMMAND_TEMPLATE = "hs_command_template"
|
||||
CONF_HS_COMMAND_TOPIC = "hs_command_topic"
|
||||
CONF_HS_STATE_TOPIC = "hs_state_topic"
|
||||
CONF_HS_VALUE_TEMPLATE = "hs_value_template"
|
||||
CONF_HUMIDITY_COMMAND_TEMPLATE = "target_humidity_command_template"
|
||||
CONF_HUMIDITY_COMMAND_TOPIC = "target_humidity_command_topic"
|
||||
CONF_HUMIDITY_STATE_TEMPLATE = "target_humidity_state_template"
|
||||
CONF_HUMIDITY_STATE_TOPIC = "target_humidity_state_topic"
|
||||
CONF_HUMIDITY_MAX = "max_humidity"
|
||||
CONF_HUMIDITY_MIN = "min_humidity"
|
||||
CONF_LAST_RESET_VALUE_TEMPLATE = "last_reset_value_template"
|
||||
CONF_MAX_KELVIN = "max_kelvin"
|
||||
CONF_MAX_MIREDS = "max_mireds"
|
||||
@ -166,13 +175,32 @@ 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_SWING_HORIZONTAL_MODE_COMMAND_TEMPLATE = "swing_horizontal_mode_command_template"
|
||||
CONF_SWING_HORIZONTAL_MODE_COMMAND_TOPIC = "swing_horizontal_mode_command_topic"
|
||||
CONF_SWING_HORIZONTAL_MODE_LIST = "swing_horizontal_modes"
|
||||
CONF_SWING_HORIZONTAL_MODE_STATE_TEMPLATE = "swing_horizontal_mode_state_template"
|
||||
CONF_SWING_HORIZONTAL_MODE_STATE_TOPIC = "swing_horizontal_mode_state_topic"
|
||||
CONF_SWING_MODE_COMMAND_TEMPLATE = "swing_mode_command_template"
|
||||
CONF_SWING_MODE_COMMAND_TOPIC = "swing_mode_command_topic"
|
||||
CONF_SWING_MODE_LIST = "swing_modes"
|
||||
CONF_SWING_MODE_STATE_TEMPLATE = "swing_mode_state_template"
|
||||
CONF_SWING_MODE_STATE_TOPIC = "swing_mode_state_topic"
|
||||
CONF_TEMP_COMMAND_TEMPLATE = "temperature_command_template"
|
||||
CONF_TEMP_COMMAND_TOPIC = "temperature_command_topic"
|
||||
CONF_TEMP_STATE_TEMPLATE = "temperature_state_template"
|
||||
CONF_TEMP_STATE_TOPIC = "temperature_state_topic"
|
||||
CONF_TEMP_HIGH_COMMAND_TEMPLATE = "temperature_high_command_template"
|
||||
CONF_TEMP_HIGH_COMMAND_TOPIC = "temperature_high_command_topic"
|
||||
CONF_TEMP_HIGH_STATE_TEMPLATE = "temperature_high_state_template"
|
||||
CONF_TEMP_HIGH_STATE_TOPIC = "temperature_high_state_topic"
|
||||
CONF_TEMP_INITIAL = "initial"
|
||||
CONF_TEMP_LOW_COMMAND_TEMPLATE = "temperature_low_command_template"
|
||||
CONF_TEMP_LOW_COMMAND_TOPIC = "temperature_low_command_topic"
|
||||
CONF_TEMP_LOW_STATE_TEMPLATE = "temperature_low_state_template"
|
||||
CONF_TEMP_LOW_STATE_TOPIC = "temperature_low_state_topic"
|
||||
CONF_TEMP_MAX = "max_temp"
|
||||
CONF_TEMP_MIN = "min_temp"
|
||||
CONF_TEMP_STATE_TEMPLATE = "temperature_state_template"
|
||||
CONF_TEMP_STATE_TOPIC = "temperature_state_topic"
|
||||
CONF_TEMP_STEP = "temp_step"
|
||||
CONF_TILT_COMMAND_TEMPLATE = "tilt_command_template"
|
||||
CONF_TILT_COMMAND_TOPIC = "tilt_command_topic"
|
||||
CONF_TILT_STATUS_TOPIC = "tilt_status_topic"
|
||||
@ -213,6 +241,7 @@ CONF_SUPPORT_URL = "support_url"
|
||||
|
||||
DEFAULT_BRIGHTNESS = False
|
||||
DEFAULT_BRIGHTNESS_SCALE = 255
|
||||
DEFAULT_CLIMATE_INITIAL_TEMPERATURE = 21.0
|
||||
DEFAULT_PREFIX = "homeassistant"
|
||||
DEFAULT_BIRTH_WILL_TOPIC = DEFAULT_PREFIX + "/status"
|
||||
DEFAULT_DISCOVERY = True
|
||||
|
@ -239,6 +239,16 @@
|
||||
"title": "Configure MQTT device \"{mqtt_device}\"",
|
||||
"description": "Please configure specific details for {platform} entity \"{entity}\":",
|
||||
"data": {
|
||||
"climate_feature_action": "Current action support",
|
||||
"climate_feature_current_humidity": "Current humidity support",
|
||||
"climate_feature_current_temperature": "Current temperature support",
|
||||
"climate_feature_fan_modes": "Fan mode support",
|
||||
"climate_feature_power": "Power on/off support",
|
||||
"climate_feature_preset_modes": "[%key:component::mqtt::config_subentries::device::step::entity_platform_config::data::fan_feature_preset_modes%]",
|
||||
"climate_feature_swing_horizontal_modes": "Horizontal swing mode support",
|
||||
"climate_feature_swing_modes": "Swing mode support",
|
||||
"climate_feature_target_temperature": "Target temperature support",
|
||||
"climate_feature_target_humidity": "Target humidity support",
|
||||
"device_class": "Device class",
|
||||
"entity_category": "Entity category",
|
||||
"fan_feature_speed": "Speed support",
|
||||
@ -249,9 +259,20 @@
|
||||
"schema": "Schema",
|
||||
"state_class": "State class",
|
||||
"suggested_display_precision": "Suggested display precision",
|
||||
"temperature_unit": "Temperature unit",
|
||||
"unit_of_measurement": "Unit of measurement"
|
||||
},
|
||||
"data_description": {
|
||||
"climate_feature_action": "The climate supports reporting the current action.",
|
||||
"climate_feature_current_humidity": "The climate supports reporting the current humidity.",
|
||||
"climate_feature_current_temperature": "The climate supports reporting the current temperature.",
|
||||
"climate_feature_fan_modes": "The climate supports fan modes.",
|
||||
"climate_feature_power": "The climate supports the power \"on\" and \"off\" commands.",
|
||||
"climate_feature_preset_modes": "The climate supports preset modes.",
|
||||
"climate_feature_swing_horizontal_modes": "The climate supports horizontal swing modes.",
|
||||
"climate_feature_swing_modes": "The climate supports swing modes.",
|
||||
"climate_feature_target_temperature": "The climate supports setting the target temperature.",
|
||||
"climate_feature_target_humidity": "The climate supports setting the target humidity.",
|
||||
"device_class": "The device class of the {platform} entity. [Learn more.]({url}#device_class)",
|
||||
"entity_category": "Allows marking an entity as device configuration or diagnostics. An entity with a category will not be exposed to cloud, Alexa, or Google Assistant components, nor included in indirect action calls to devices or areas. Sensor entities cannot be assigned a device configuration class. [Learn more.](https://developers.home-assistant.io/docs/core/entity/#registry-properties)",
|
||||
"fan_feature_speed": "The fan supports multiple speeds.",
|
||||
@ -262,6 +283,7 @@
|
||||
"schema": "The schema to use. [Learn more.]({url}#comparison-of-light-mqtt-schemas)",
|
||||
"state_class": "The [State class](https://developers.home-assistant.io/docs/core/entity/sensor/#available-state-classes) of the sensor. [Learn more.]({url}#state_class)",
|
||||
"suggested_display_precision": "The number of decimals which should be used in the {platform} entity state after rounding. [Learn more.]({url}#suggested_display_precision)",
|
||||
"temperature_unit": "This determines the native unit of measurement the MQTT climate device works with.",
|
||||
"unit_of_measurement": "Defines the unit of measurement of the sensor, if any."
|
||||
},
|
||||
"sections": {
|
||||
@ -290,6 +312,11 @@
|
||||
"force_update": "Force update",
|
||||
"green_template": "Green template",
|
||||
"last_reset_value_template": "Last reset value template",
|
||||
"modes": "Supported operation modes",
|
||||
"mode_command_topic": "Operation mode command topic",
|
||||
"mode_command_template": "Operation mode command template",
|
||||
"mode_state_topic": "Operation mode state topic",
|
||||
"mode_state_template": "Operation mode value template",
|
||||
"on_command_type": "ON command type",
|
||||
"optimistic": "Optimistic",
|
||||
"payload_off": "Payload \"off\"",
|
||||
@ -317,6 +344,11 @@
|
||||
"force_update": "Sends update events even if the value hasn’t changed. Useful if you want to have meaningful value graphs in history. [Learn more.]({url}#force_update)",
|
||||
"green_template": "[Template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to extract green color from the state payload value. Expected result of the template is an integer from 0-255 range.",
|
||||
"last_reset_value_template": "Defines a [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to extract the last reset. When Last reset template is set, the State class option must be Total. [Learn more.]({url}#last_reset_value_template)",
|
||||
"modes": "A list of supported operation modes. [Learn more.]({url}#modes)",
|
||||
"mode_command_topic": "The MQTT topic to publish commands to change the climate operation mode. [Learn more.]({url}#mode_command_topic)",
|
||||
"mode_command_template": "[Template](https://www.home-assistant.io/docs/configuration/templating/#using-command-templates-with-mqtt) to define the operation mode to be sent to the operation mode command topic. [Learn more.]({url}#mode_command_template)",
|
||||
"mode_state_topic": "The MQTT topic subscribed to receive operation mode state messages. [Learn more.]({url}#mode_state_topic)",
|
||||
"mode_state_template": "Defines a [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to extract the operation mode state. [Learn more.]({url}#mode_state_template)",
|
||||
"on_command_type": "Defines when the payload \"on\" is sent. Using \"Last\" (the default) will send any style (brightness, color, etc) topics first and then a payload \"on\" to the command topic. Using \"First\" will send the payload \"on\" and then any style topics. Using \"Brightness\" will only send brightness commands instead of the payload \"on\" to turn the light on.",
|
||||
"optimistic": "Flag that defines if the {platform} entity works in optimistic mode. [Learn more.]({url}#optimistic)",
|
||||
"payload_off": "The payload that represents the \"off\" state.",
|
||||
@ -356,6 +388,100 @@
|
||||
"transition": "Enable the transition feature for this light"
|
||||
}
|
||||
},
|
||||
"climate_action_settings": {
|
||||
"name": "Current action settings",
|
||||
"data": {
|
||||
"action_template": "Action template",
|
||||
"action_topic": "Action topic"
|
||||
},
|
||||
"data_description": {
|
||||
"action_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to render the value received on the action topic with.",
|
||||
"action_topic": "The MQTT topic to subscribe for changes of the current action. If this is set, the climate graph uses the value received as data source. A \"None\" payload resets the current action state. An empty payload is ignored. Valid action values are: \"off\", \"heating\", \"cooling\", \"drying\", \"idle\" and \"fan\". [Learn more.]({url}#action_topic)"
|
||||
}
|
||||
},
|
||||
"climate_fan_mode_settings": {
|
||||
"name": "Fan mode settings",
|
||||
"data": {
|
||||
"fan_modes": "Fan modes",
|
||||
"fan_mode_command_topic": "Fan mode command topic",
|
||||
"fan_mode_command_template": "Fan mode command template",
|
||||
"fan_mode_state_topic": "Fan mode state topic",
|
||||
"fan_mode_state_template": "Fan mode state template"
|
||||
},
|
||||
"data_description": {
|
||||
"fan_modes": "List of fan modes this climate is capable of running at. Common fan modes that offer translations are `off`, `on`, `auto`, `low`, `medium`, `high`, `middle`, `focus` and `diffuse`.",
|
||||
"fan_mode_command_topic": "The MQTT topic to publish commands to change the climate fan mode. [Learn more.]({url}#fan_mode_command_topic)",
|
||||
"fan_mode_command_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-command-templates-with-mqtt) to compose the payload to be published at the fan mode command topic.",
|
||||
"fan_mode_state_topic": "The MQTT topic subscribed to receive the climate fan mode. [Learn more.]({url}#fan_mode_state_topic)",
|
||||
"fan_mode_state_template": "Defines a [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to extract the climate fan mode value."
|
||||
}
|
||||
},
|
||||
"climate_power_settings": {
|
||||
"name": "Power settings",
|
||||
"data": {
|
||||
"payload_off": "[%key:component::mqtt::config_subentries::device::step::mqtt_platform_config::data::payload_off%]",
|
||||
"payload_on": "[%key:component::mqtt::config_subentries::device::step::mqtt_platform_config::data::payload_on%]",
|
||||
"power_command_template": "Power command template",
|
||||
"power_command_topic": "Power command topic"
|
||||
},
|
||||
"data_description": {
|
||||
"payload_off": "[%key:component::mqtt::config_subentries::device::step::mqtt_platform_config::data_description::payload_off%]",
|
||||
"payload_on": "[%key:component::mqtt::config_subentries::device::step::mqtt_platform_config::data_description::payload_off%]",
|
||||
"power_command_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-command-templates-with-mqtt) to compose the payload to be published at the power command topic. The `value` parameter is the payload set for payload \"on\" or payload \"off\".",
|
||||
"power_command_topic": "The MQTT topic to publish commands to change the climate power state. Sends the payload configured with payload \"on\" or payload \"off\". [Learn more.]({url}#power_command_topic)"
|
||||
}
|
||||
},
|
||||
"climate_preset_mode_settings": {
|
||||
"name": "[%key:component::mqtt::config_subentries::device::step::mqtt_platform_config::sections::fan_preset_mode_settings::name%]",
|
||||
"data": {
|
||||
"preset_mode_command_template": "[%key:component::mqtt::config_subentries::device::step::mqtt_platform_config::sections::fan_preset_mode_settings::data::preset_mode_command_template%]",
|
||||
"preset_mode_command_topic": "[%key:component::mqtt::config_subentries::device::step::mqtt_platform_config::sections::fan_preset_mode_settings::data::preset_mode_command_topic%]",
|
||||
"preset_mode_value_template": "[%key:component::mqtt::config_subentries::device::step::mqtt_platform_config::sections::fan_preset_mode_settings::data::preset_mode_value_template%]",
|
||||
"preset_mode_state_topic": "[%key:component::mqtt::config_subentries::device::step::mqtt_platform_config::sections::fan_preset_mode_settings::data::preset_mode_state_topic%]",
|
||||
"preset_modes": "[%key:component::mqtt::config_subentries::device::step::mqtt_platform_config::sections::fan_preset_mode_settings::data::preset_modes%]"
|
||||
},
|
||||
"data_description": {
|
||||
"preset_mode_command_template": "[%key:component::mqtt::config_subentries::device::step::mqtt_platform_config::sections::fan_preset_mode_settings::data_description::preset_mode_command_template%]",
|
||||
"preset_mode_command_topic": "The MQTT topic to publish commands to change the climate preset mode. [Learn more.]({url}#preset_mode_command_topic)",
|
||||
"preset_mode_value_template": "[%key:component::mqtt::config_subentries::device::step::mqtt_platform_config::sections::fan_preset_mode_settings::data_description::preset_mode_value_template%]",
|
||||
"preset_mode_state_topic": "[%key:component::mqtt::config_subentries::device::step::mqtt_platform_config::sections::fan_preset_mode_settings::data_description::preset_mode_state_topic%]",
|
||||
"preset_modes": "List of preset modes this climate is capable of running at. Common preset modes that offer translations are `none`, `away`, `eco`, `boost`, `comfort`, `home`, `sleep` and `activity`."
|
||||
}
|
||||
},
|
||||
"climate_swing_horizontal_mode_settings": {
|
||||
"name": "Horizontal swing mode settings",
|
||||
"data": {
|
||||
"swing_horizontal_modes": "Horizontal swing modes",
|
||||
"swing_horizontal_mode_command_topic": "Horizontal swing mode command topic",
|
||||
"swing_horizontal_mode_command_template": "Horizontal swing mode command template",
|
||||
"swing_horizontal_mode_state_topic": "Horizontal swing mode state topic",
|
||||
"swing_horizontal_mode_state_template": "Horizontal swing mode state template"
|
||||
},
|
||||
"data_description": {
|
||||
"swing_horizontal_modes": "List of horizontal swing modes this climate is capable of running at. Common horizontal swing modes that offer translations are `off` and `on`.",
|
||||
"swing_horizontal_mode_command_topic": "The MQTT topic to publish commands to change the climate horizontal swing mode. [Learn more.]({url}#swing_horizontal_mode_command_topic)",
|
||||
"swing_horizontal_mode_command_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-command-templates-with-mqtt) to compose the payload to be published at the horizontal swing mode command topic.",
|
||||
"swing_horizontal_mode_state_topic": "The MQTT topic subscribed to receive the climate horizontal swing mode. [Learn more.]({url}#swing_horizontal_mode_state_topic)",
|
||||
"swing_horizontal_mode_state_template": "Defines a [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to extract the climate horizontal swing mode value."
|
||||
}
|
||||
},
|
||||
"climate_swing_mode_settings": {
|
||||
"name": "Swing mode settings",
|
||||
"data": {
|
||||
"swing_modes": "Swing modes",
|
||||
"swing_mode_command_topic": "Swing mode command topic",
|
||||
"swing_mode_command_template": "Swing mode command template",
|
||||
"swing_mode_state_topic": "Swing mode state topic",
|
||||
"swing_mode_state_template": "Swing mode state template"
|
||||
},
|
||||
"data_description": {
|
||||
"swing_modes": "List of swing modes this climate is capable of running at. Common swing modes that offer translations are `off`, `on`, `vertical`, `horizontal` and `both`.",
|
||||
"swing_mode_command_topic": "The MQTT topic to publish commands to change the climate swing mode. [Learn more.]({url}#swing_mode_command_topic)",
|
||||
"swing_mode_command_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-command-templates-with-mqtt) to compose the payload to be published at the swing mode command topic.",
|
||||
"swing_mode_state_topic": "The MQTT topic subscribed to receive the climate swing mode. [Learn more.]({url}#swing_mode_state_topic)",
|
||||
"swing_mode_state_template": "Defines a [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to extract the climate swing mode value."
|
||||
}
|
||||
},
|
||||
"cover_payload_settings": {
|
||||
"name": "Payload settings",
|
||||
"data": {
|
||||
@ -425,6 +551,28 @@
|
||||
"tilt_optimistic": "Flag that defines if tilt works in optimistic mode. If tilt status topic is not defined, tilt works in optimistic mode by default. [Learn more.]({url}#tilt_optimistic)"
|
||||
}
|
||||
},
|
||||
"current_humidity_settings": {
|
||||
"name": "Current humidity settings",
|
||||
"data": {
|
||||
"current_humidity_template": "Current humidity template",
|
||||
"current_humidity_topic": "Current humidity topic"
|
||||
},
|
||||
"data_description": {
|
||||
"current_humidity_template": "Defines a [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to extract the current humidity value. [Learn more.]({url}#current_humidity_template)",
|
||||
"current_humidity_topic": "The MQTT topic subscribed to receive current humidity update values. [Learn more.]({url}#current_humidity_topic)"
|
||||
}
|
||||
},
|
||||
"current_temperature_settings": {
|
||||
"name": "Current temperature settings",
|
||||
"data": {
|
||||
"current_temperature_template": "Current temperature template",
|
||||
"current_temperature_topic": "Current temperature topic"
|
||||
},
|
||||
"data_description": {
|
||||
"current_temperature_template": "Defines a [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to extract the current temperature value. [Learn more.]({url}#current_temperature_template)",
|
||||
"current_temperature_topic": "The MQTT topic subscribed to receive current temperature update values. [Learn more.]({url}#current_temperature_topic)"
|
||||
}
|
||||
},
|
||||
"light_brightness_settings": {
|
||||
"name": "Brightness settings",
|
||||
"data": {
|
||||
@ -648,6 +796,66 @@
|
||||
"xy_state_topic": "The MQTT topic subscribed to receive XY state updates. The expected payload is the X and Y color values separated by commas, for example, `0.675,0.322`. [Learn more.]({url}#xy_state_topic)",
|
||||
"xy_value_template": "Defines a [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to extract the XY value."
|
||||
}
|
||||
},
|
||||
"target_humidity_settings": {
|
||||
"name": "Target humidity settings",
|
||||
"data": {
|
||||
"max_humidity": "Maximum humidity",
|
||||
"min_humidity": "Minimum humidity",
|
||||
"target_humidity_command_template": "Humidity command template",
|
||||
"target_humidity_command_topic": "Humidity command topic",
|
||||
"target_humidity_state_template": "Humidity state template",
|
||||
"target_humidity_state_topic": "Humidity state topic"
|
||||
},
|
||||
"data_description": {
|
||||
"max_humidity": "The maximum target humidity that can be set.",
|
||||
"min_humidity": "The minimum target humidity that can be set.",
|
||||
"target_humidity_command_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-command-templates-with-mqtt) to compose the payload to be published at the humidity command topic.",
|
||||
"target_humidity_command_topic": "The MQTT topic to publish commands to change the climate target humidity. [Learn more.]({url}#humidity_command_topic)",
|
||||
"target_humidity_state_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to render the value received on the humidity state topic with.",
|
||||
"target_humidity_state_topic": "The MQTT topic to subscribe for changes of the target humidity. [Learn more.]({url}#humidity_state_topic)"
|
||||
}
|
||||
},
|
||||
"target_temperature_settings": {
|
||||
"name": "Target temperature settings",
|
||||
"data": {
|
||||
"initial": "Initial temperature",
|
||||
"max_temp": "Maximum temperature",
|
||||
"min_temp": "Minimum temperature",
|
||||
"precision": "Precision",
|
||||
"temp_step": "Temperature step",
|
||||
"temperature_command_template": "Temperature command template",
|
||||
"temperature_command_topic": "Temperature command topic",
|
||||
"temperature_high_command_template": "Upper temperature command template",
|
||||
"temperature_high_command_topic": "Upper temperature command topic",
|
||||
"temperature_low_command_template": "Lower temperature command template",
|
||||
"temperature_low_command_topic": "Lower temperature command topic",
|
||||
"temperature_state_template": "Temperature state template",
|
||||
"temperature_state_topic": "Temperature state topic",
|
||||
"temperature_high_state_template": "Upper temperature state template",
|
||||
"temperature_high_state_topic": "Upper temperature state topic",
|
||||
"temperature_low_state_template": "Lower temperature state template",
|
||||
"temperature_low_state_topic": "Lower temperature state topic"
|
||||
},
|
||||
"data_description": {
|
||||
"initial": "The climate initalizes with this target temperature.",
|
||||
"max_temp": "The maximum target temperature that can be set.",
|
||||
"min_temp": "The minimum target temperature that can be set.",
|
||||
"precision": "The precision in degrees the thermostat is working at.",
|
||||
"temp_step": "The target temperature step in degrees Celsius or Fahrenheit.",
|
||||
"temperature_command_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-command-templates-with-mqtt) to compose the payload to be published at the temperature command topic.",
|
||||
"temperature_command_topic": "The MQTT topic to publish commands to change the climate target temperature. [Learn more.]({url}#temperature_command_topic)",
|
||||
"temperature_high_command_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-command-templates-with-mqtt) to compose the payload to be published at the upper temperature command topic.",
|
||||
"temperature_high_command_topic": "The MQTT topic to publish commands to change the climate upper target temperature. [Learn more.]({url}#temperature_high_command_topic)",
|
||||
"temperature_low_command_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-command-templates-with-mqtt) to compose the payload to be published at the lower temperature command topic.",
|
||||
"temperature_low_command_topic": "The MQTT topic to publish commands to change the climate lower target temperature. [Learn more.]({url}#temperature_low_command_topic)",
|
||||
"temperature_state_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to render the value received on the temperature state topic with.",
|
||||
"temperature_state_topic": "The MQTT topic to subscribe for changes of the target temperature. [Learn more.]({url}#temperature_state_topic)",
|
||||
"temperature_high_state_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to render the value received on the upper temperature state topic with.",
|
||||
"temperature_high_state_topic": "The MQTT topic to subscribe for changes of the upper target temperature. [Learn more.]({url}#temperature_high_state_topic)",
|
||||
"temperature_low_state_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to render the value received on the lower temperature state topic with.",
|
||||
"temperature_low_state_topic": "The MQTT topic to subscribe for changes of the lower target temperature. [Learn more.]({url}#temperature_low_state_topic)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -695,6 +903,7 @@
|
||||
"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",
|
||||
"empty_list_not_allowed": "Empty list is not allowed. Add at least one item",
|
||||
"fan_speed_range_max_must_be_greater_than_speed_range_min": "Speed range max must be greater than speed range min",
|
||||
"fan_preset_mode_reset_in_preset_modes_list": "Payload \"reset preset mode\" is not a valid as a preset mode",
|
||||
"invalid_input": "Invalid value",
|
||||
@ -705,10 +914,13 @@
|
||||
"invalid_uom_for_state_class": "The unit of measurement \"{unit_of_measurement}\" is not supported by the selected state class, please either remove the state class, select a state class which supports \"{unit_of_measurement}\", or pick a supported unit of measurement from the list",
|
||||
"invalid_url": "Invalid URL",
|
||||
"last_reset_not_with_state_class_total": "The last reset value template option should be used with state class 'Total' only",
|
||||
"max_below_min_humidity": "Max humidity value should be greater than min humidity value",
|
||||
"max_below_min_kelvin": "Max Kelvin value should be greater than min Kelvin value",
|
||||
"max_below_min_temperature": "Max temperature value should be greater than min temperature value",
|
||||
"options_not_allowed_with_state_class_or_uom": "The 'Options' setting is not allowed when state class or unit of measurement are used",
|
||||
"options_device_class_enum": "The 'Options' setting must be used with the Enumeration device class. If you continue, the existing options will be reset",
|
||||
"options_with_enum_device_class": "Configure options for the enumeration sensor",
|
||||
"preset_mode_none_not_allowed": "Preset \"none\" is not a valid preset mode",
|
||||
"uom_required_for_device_class": "The selected device class requires a unit"
|
||||
}
|
||||
}
|
||||
@ -826,6 +1038,17 @@
|
||||
}
|
||||
},
|
||||
"selector": {
|
||||
"climate_modes": {
|
||||
"options": {
|
||||
"off": "[%key:common::state::off%]",
|
||||
"auto": "[%key:common::state::auto%]",
|
||||
"heat": "[%key:component::climate::entity_component::_::state::heat%]",
|
||||
"cool": "[%key:component::climate::entity_component::_::state::cool%]",
|
||||
"heat_cool": "[%key:component::climate::entity_component::_::state::heat_cool%]",
|
||||
"dry": "[%key:component::climate::entity_component::_::state::dry%]",
|
||||
"fan_only": "[%key:component::climate::entity_component::_::state::fan_only%]"
|
||||
}
|
||||
},
|
||||
"device_class_binary_sensor": {
|
||||
"options": {
|
||||
"battery": "[%key:component::binary_sensor::entity_component::battery::name%]",
|
||||
@ -969,6 +1192,7 @@
|
||||
"options": {
|
||||
"binary_sensor": "[%key:component::binary_sensor::title%]",
|
||||
"button": "[%key:component::button::title%]",
|
||||
"climate": "[%key:component::climate::title%]",
|
||||
"cover": "[%key:component::cover::title%]",
|
||||
"fan": "[%key:component::fan::title%]",
|
||||
"light": "[%key:component::light::title%]",
|
||||
@ -1004,6 +1228,13 @@
|
||||
"rgbww": "[%key:component::light::entity_component::_::state_attributes::color_mode::state::rgbww%]",
|
||||
"white": "[%key:component::light::entity_component::_::state_attributes::color_mode::state::white%]"
|
||||
}
|
||||
},
|
||||
"target_temperature_feature": {
|
||||
"options": {
|
||||
"single": "Single target temperature",
|
||||
"high_low": "Upper/lower target temperature",
|
||||
"none": "No target temperature"
|
||||
}
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
|
@ -94,6 +94,117 @@ MOCK_SUBENTRY_BUTTON_COMPONENT = {
|
||||
"entity_picture": "https://example.com/365d05e6607c4dfb8ae915cff71a954b",
|
||||
},
|
||||
}
|
||||
MOCK_SUBENTRY_CLIMATE_COMPONENT = {
|
||||
"b085c09efba7ec76acd94e2e0f851386": {
|
||||
"platform": "climate",
|
||||
"name": "Cooler",
|
||||
"entity_category": None,
|
||||
"entity_picture": "https://example.com/b085c09efba7ec76acd94e2e0f851386",
|
||||
"temperature_unit": "C",
|
||||
"mode_command_topic": "mode-command-topic",
|
||||
"mode_command_template": "{{ value }}",
|
||||
"mode_state_topic": "mode-state-topic",
|
||||
"mode_state_template": "{{ value_json.mode }}",
|
||||
"modes": ["off", "heat", "cool", "auto"],
|
||||
# single target temperature
|
||||
"temperature_command_topic": "temperature-command-topic",
|
||||
"temperature_command_template": "{{ value }}",
|
||||
"temperature_state_topic": "temperature-state-topic",
|
||||
"temperature_state_template": "{{ value_json.temperature }}",
|
||||
"min_temp": 8,
|
||||
"max_temp": 28,
|
||||
"precision": "0.1",
|
||||
"temp_step": 1.0,
|
||||
"initial": 19.0,
|
||||
# power settings
|
||||
"power_command_topic": "power-command-topic",
|
||||
"power_command_template": "{{ value }}",
|
||||
"payload_on": "ON",
|
||||
"payload_off": "OFF",
|
||||
# current action settings
|
||||
"action_topic": "action-topic",
|
||||
"action_template": "{{ value_json.current_action }}",
|
||||
# target humidity
|
||||
"target_humidity_command_topic": "target-humidity-command-topic",
|
||||
"target_humidity_command_template": "{{ value }}",
|
||||
"target_humidity_state_topic": "target-humidity-state-topic",
|
||||
"target_humidity_state_template": "{{ value_json.target_humidity }}",
|
||||
"min_humidity": 20,
|
||||
"max_humidity": 80,
|
||||
# current temperature
|
||||
"current_temperature_topic": "current-temperature-topic",
|
||||
"current_temperature_template": "{{ value_json.temperature }}",
|
||||
# current humidity
|
||||
"current_humidity_topic": "current-humidity-topic",
|
||||
"current_humidity_template": "{{ value_json.humidity }}",
|
||||
# preset mode
|
||||
"preset_mode_command_topic": "preset-mode-command-topic",
|
||||
"preset_mode_command_template": "{{ value }}",
|
||||
"preset_mode_state_topic": "preset-mode-state-topic",
|
||||
"preset_mode_value_template": "{{ value_json.preset_mode }}",
|
||||
"preset_modes": ["auto", "eco"],
|
||||
# fan mode
|
||||
"fan_mode_command_topic": "fan-mode-command-topic",
|
||||
"fan_mode_command_template": "{{ value }}",
|
||||
"fan_mode_state_topic": "fan-mode-state-topic",
|
||||
"fan_mode_state_template": "{{ value_json.fan_mode }}",
|
||||
"fan_modes": ["off", "low", "medium", "high"],
|
||||
# swing mode
|
||||
"swing_mode_command_topic": "swing-mode-command-topic",
|
||||
"swing_mode_command_template": "{{ value }}",
|
||||
"swing_mode_state_topic": "swing-mode-state-topic",
|
||||
"swing_mode_state_template": "{{ value_json.swing_mode }}",
|
||||
"swing_modes": ["off", "on"],
|
||||
# swing horizontal mode
|
||||
"swing_horizontal_mode_command_topic": "swing-horizontal-mode-command-topic",
|
||||
"swing_horizontal_mode_command_template": "{{ value }}",
|
||||
"swing_horizontal_mode_state_topic": "swing-horizontal-mode-state-topic",
|
||||
"swing_horizontal_mode_state_template": "{{ value_json.swing_horizontal_mode }}",
|
||||
"swing_horizontal_modes": ["off", "on"],
|
||||
},
|
||||
}
|
||||
MOCK_SUBENTRY_CLIMATE_HIGH_LOW_COMPONENT = {
|
||||
"b085c09efba7ec76acd94e2e0f851387": {
|
||||
"platform": "climate",
|
||||
"name": "Cooler",
|
||||
"entity_category": None,
|
||||
"entity_picture": "https://example.com/b085c09efba7ec76acd94e2e0f851387",
|
||||
"temperature_unit": "C",
|
||||
"mode_command_topic": "mode-command-topic",
|
||||
"mode_command_template": "{{ value }}",
|
||||
"mode_state_topic": "mode-state-topic",
|
||||
"mode_state_template": "{{ value_json.mode }}",
|
||||
"modes": ["off", "heat", "cool", "auto"],
|
||||
# high/low target temperature
|
||||
"temperature_low_command_topic": "temperature-low-command-topic",
|
||||
"temperature_low_command_template": "{{ value }}",
|
||||
"temperature_low_state_topic": "temperature-low-state-topic",
|
||||
"temperature_low_state_template": "{{ value_json.temperature_low }}",
|
||||
"temperature_high_command_topic": "temperature-high-command-topic",
|
||||
"temperature_high_command_template": "{{ value }}",
|
||||
"temperature_high_state_topic": "temperature-high-state-topic",
|
||||
"temperature_high_state_template": "{{ value_json.temperature_high }}",
|
||||
"min_temp": 8,
|
||||
"max_temp": 28,
|
||||
"precision": "0.1",
|
||||
"temp_step": 1.0,
|
||||
"initial": 19.0,
|
||||
},
|
||||
}
|
||||
MOCK_SUBENTRY_CLIMATE_NO_TARGET_TEMP_COMPONENT = {
|
||||
"b085c09efba7ec76acd94e2e0f851388": {
|
||||
"platform": "climate",
|
||||
"name": "Cooler",
|
||||
"entity_category": None,
|
||||
"entity_picture": "https://example.com/b085c09efba7ec76acd94e2e0f851388",
|
||||
"temperature_unit": "C",
|
||||
"mode_command_topic": "mode-command-topic",
|
||||
"mode_command_template": "{{ value }}",
|
||||
"mode_state_topic": "mode-state-topic",
|
||||
"mode_state_template": "{{ value_json.mode }}",
|
||||
"modes": ["off", "heat", "cool", "auto"],
|
||||
},
|
||||
}
|
||||
MOCK_SUBENTRY_COVER_COMPONENT = {
|
||||
"b37acf667fa04c688ad7dfb27de2178b": {
|
||||
"platform": "cover",
|
||||
@ -312,6 +423,18 @@ MOCK_BUTTON_SUBENTRY_DATA_SINGLE = {
|
||||
"device": MOCK_SUBENTRY_DEVICE_DATA | {"mqtt_settings": {"qos": 2}},
|
||||
"components": MOCK_SUBENTRY_BUTTON_COMPONENT,
|
||||
}
|
||||
MOCK_CLIMATE_SUBENTRY_DATA_SINGLE = {
|
||||
"device": MOCK_SUBENTRY_DEVICE_DATA | {"mqtt_settings": {"qos": 0}},
|
||||
"components": MOCK_SUBENTRY_CLIMATE_COMPONENT,
|
||||
}
|
||||
MOCK_CLIMATE_HIGH_LOW_SUBENTRY_DATA_SINGLE = {
|
||||
"device": MOCK_SUBENTRY_DEVICE_DATA | {"mqtt_settings": {"qos": 1}},
|
||||
"components": MOCK_SUBENTRY_CLIMATE_HIGH_LOW_COMPONENT,
|
||||
}
|
||||
MOCK_CLIMATE_NO_TARGET_TEMP_SUBENTRY_DATA_SINGLE = {
|
||||
"device": MOCK_SUBENTRY_DEVICE_DATA | {"mqtt_settings": {"qos": 2}},
|
||||
"components": MOCK_SUBENTRY_CLIMATE_NO_TARGET_TEMP_COMPONENT,
|
||||
}
|
||||
MOCK_COVER_SUBENTRY_DATA_SINGLE = {
|
||||
"device": MOCK_SUBENTRY_DEVICE_DATA | {"mqtt_settings": {"qos": 0}},
|
||||
"components": MOCK_SUBENTRY_COVER_COMPONENT,
|
||||
|
@ -29,10 +29,12 @@ from homeassistant.components.climate import (
|
||||
HVACMode,
|
||||
)
|
||||
from homeassistant.components.mqtt.climate import (
|
||||
DEFAULT_INITIAL_TEMPERATURE,
|
||||
MQTT_CLIMATE_ATTRIBUTES_BLOCKED,
|
||||
VALUE_TEMPLATE_KEYS,
|
||||
)
|
||||
from homeassistant.components.mqtt.const import (
|
||||
DEFAULT_CLIMATE_INITIAL_TEMPERATURE as DEFAULT_INITIAL_TEMPERATURE,
|
||||
)
|
||||
from homeassistant.const import ATTR_TEMPERATURE, STATE_UNKNOWN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ServiceValidationError
|
||||
|
@ -35,6 +35,9 @@ from homeassistant.helpers.service_info.hassio import HassioServiceInfo
|
||||
from .common import (
|
||||
MOCK_BINARY_SENSOR_SUBENTRY_DATA_SINGLE,
|
||||
MOCK_BUTTON_SUBENTRY_DATA_SINGLE,
|
||||
MOCK_CLIMATE_HIGH_LOW_SUBENTRY_DATA_SINGLE,
|
||||
MOCK_CLIMATE_NO_TARGET_TEMP_SUBENTRY_DATA_SINGLE,
|
||||
MOCK_CLIMATE_SUBENTRY_DATA_SINGLE,
|
||||
MOCK_COVER_SUBENTRY_DATA_SINGLE,
|
||||
MOCK_FAN_SUBENTRY_DATA_SINGLE,
|
||||
MOCK_LIGHT_BASIC_KELVIN_SUBENTRY_DATA_SINGLE,
|
||||
@ -2700,6 +2703,224 @@ async def test_migrate_of_incompatible_config_entry(
|
||||
),
|
||||
"Milk notifier Restart",
|
||||
),
|
||||
(
|
||||
MOCK_CLIMATE_SUBENTRY_DATA_SINGLE,
|
||||
{"name": "Milk notifier", "mqtt_settings": {"qos": 0}},
|
||||
{"name": "Cooler"},
|
||||
{
|
||||
"temperature_unit": "C",
|
||||
"climate_feature_action": True,
|
||||
"climate_feature_current_humidity": True,
|
||||
"climate_feature_current_temperature": True,
|
||||
"climate_feature_power": True,
|
||||
"climate_feature_preset_modes": True,
|
||||
"climate_feature_fan_modes": True,
|
||||
"climate_feature_swing_horizontal_modes": True,
|
||||
"climate_feature_swing_modes": True,
|
||||
"climate_feature_target_temperature": "single",
|
||||
"climate_feature_target_humidity": True,
|
||||
},
|
||||
(),
|
||||
{
|
||||
"mode_command_topic": "mode-command-topic",
|
||||
"mode_command_template": "{{ value }}",
|
||||
"mode_state_topic": "mode-state-topic",
|
||||
"mode_state_template": "{{ value_json.mode }}",
|
||||
"modes": ["off", "heat", "cool", "auto"],
|
||||
# single target temperature
|
||||
"target_temperature_settings": {
|
||||
"temperature_command_topic": "temperature-command-topic",
|
||||
"temperature_command_template": "{{ value }}",
|
||||
"temperature_state_topic": "temperature-state-topic",
|
||||
"temperature_state_template": "{{ value_json.temperature }}",
|
||||
"min_temp": 8,
|
||||
"max_temp": 28,
|
||||
"precision": "0.1",
|
||||
"temp_step": 1.0,
|
||||
"initial": 19.0,
|
||||
},
|
||||
# power settings
|
||||
"climate_power_settings": {
|
||||
"power_command_topic": "power-command-topic",
|
||||
"power_command_template": "{{ value }}",
|
||||
"payload_on": "ON",
|
||||
"payload_off": "OFF",
|
||||
},
|
||||
# current action settings
|
||||
"climate_action_settings": {
|
||||
"action_topic": "action-topic",
|
||||
"action_template": "{{ value_json.current_action }}",
|
||||
},
|
||||
# target humidity
|
||||
"target_humidity_settings": {
|
||||
"target_humidity_command_topic": "target-humidity-command-topic",
|
||||
"target_humidity_command_template": "{{ value }}",
|
||||
"target_humidity_state_topic": "target-humidity-state-topic",
|
||||
"target_humidity_state_template": "{{ value_json.target_humidity }}",
|
||||
"min_humidity": 20,
|
||||
"max_humidity": 80,
|
||||
},
|
||||
# current temperature
|
||||
"current_temperature_settings": {
|
||||
"current_temperature_topic": "current-temperature-topic",
|
||||
"current_temperature_template": "{{ value_json.temperature }}",
|
||||
},
|
||||
# current humidity
|
||||
"current_humidity_settings": {
|
||||
"current_humidity_topic": "current-humidity-topic",
|
||||
"current_humidity_template": "{{ value_json.humidity }}",
|
||||
},
|
||||
# preset mode
|
||||
"climate_preset_mode_settings": {
|
||||
"preset_mode_command_topic": "preset-mode-command-topic",
|
||||
"preset_mode_command_template": "{{ value }}",
|
||||
"preset_mode_state_topic": "preset-mode-state-topic",
|
||||
"preset_mode_value_template": "{{ value_json.preset_mode }}",
|
||||
"preset_modes": ["auto", "eco"],
|
||||
},
|
||||
# fan mode
|
||||
"climate_fan_mode_settings": {
|
||||
"fan_mode_command_topic": "fan-mode-command-topic",
|
||||
"fan_mode_command_template": "{{ value }}",
|
||||
"fan_mode_state_topic": "fan-mode-state-topic",
|
||||
"fan_mode_state_template": "{{ value_json.fan_mode }}",
|
||||
"fan_modes": ["off", "low", "medium", "high"],
|
||||
},
|
||||
# swing mode
|
||||
"climate_swing_mode_settings": {
|
||||
"swing_mode_command_topic": "swing-mode-command-topic",
|
||||
"swing_mode_command_template": "{{ value }}",
|
||||
"swing_mode_state_topic": "swing-mode-state-topic",
|
||||
"swing_mode_state_template": "{{ value_json.swing_mode }}",
|
||||
"swing_modes": ["off", "on"],
|
||||
},
|
||||
# swing horizontal mode
|
||||
"climate_swing_horizontal_mode_settings": {
|
||||
"swing_horizontal_mode_command_topic": "swing-horizontal-mode-command-topic",
|
||||
"swing_horizontal_mode_command_template": "{{ value }}",
|
||||
"swing_horizontal_mode_state_topic": "swing-horizontal-mode-state-topic",
|
||||
"swing_horizontal_mode_state_template": "{{ value_json.swing_horizontal_mode }}",
|
||||
"swing_horizontal_modes": ["off", "on"],
|
||||
},
|
||||
},
|
||||
(
|
||||
(
|
||||
{
|
||||
"modes": ["off", "heat", "cool", "auto"],
|
||||
"target_temperature_settings": {
|
||||
"temperature_command_topic": "test-topic#invalid"
|
||||
},
|
||||
},
|
||||
{"target_temperature_settings": "invalid_publish_topic"},
|
||||
),
|
||||
(
|
||||
{
|
||||
"modes": [],
|
||||
"target_temperature_settings": {
|
||||
"temperature_command_topic": "test-topic"
|
||||
},
|
||||
},
|
||||
{"modes": "empty_list_not_allowed"},
|
||||
),
|
||||
(
|
||||
{
|
||||
"modes": ["off", "heat", "cool", "auto"],
|
||||
"target_temperature_settings": {
|
||||
"temperature_command_topic": "test-topic",
|
||||
"min_temp": 19.0,
|
||||
"max_temp": 18.0,
|
||||
},
|
||||
"target_humidity_settings": {
|
||||
"target_humidity_command_topic": "test-topic",
|
||||
"min_humidity": 50,
|
||||
"max_humidity": 40,
|
||||
},
|
||||
"climate_preset_mode_settings": {
|
||||
"preset_mode_command_topic": "preset-mode-command-topic",
|
||||
"preset_modes": ["none"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"target_temperature_settings": "max_below_min_temperature",
|
||||
"target_humidity_settings": "max_below_min_humidity",
|
||||
"climate_preset_mode_settings": "preset_mode_none_not_allowed",
|
||||
},
|
||||
),
|
||||
),
|
||||
"Milk notifier Cooler",
|
||||
),
|
||||
(
|
||||
MOCK_CLIMATE_HIGH_LOW_SUBENTRY_DATA_SINGLE,
|
||||
{"name": "Milk notifier", "mqtt_settings": {"qos": 0}},
|
||||
{"name": "Cooler"},
|
||||
{
|
||||
"temperature_unit": "C",
|
||||
"climate_feature_action": False,
|
||||
"climate_feature_current_humidity": False,
|
||||
"climate_feature_current_temperature": False,
|
||||
"climate_feature_power": False,
|
||||
"climate_feature_preset_modes": False,
|
||||
"climate_feature_fan_modes": False,
|
||||
"climate_feature_swing_horizontal_modes": False,
|
||||
"climate_feature_swing_modes": False,
|
||||
"climate_feature_target_temperature": "high_low",
|
||||
"climate_feature_target_humidity": False,
|
||||
},
|
||||
(),
|
||||
{
|
||||
"mode_command_topic": "mode-command-topic",
|
||||
"mode_command_template": "{{ value }}",
|
||||
"mode_state_topic": "mode-state-topic",
|
||||
"mode_state_template": "{{ value_json.mode }}",
|
||||
"modes": ["off", "heat", "cool", "auto"],
|
||||
# high/low target temperature
|
||||
"target_temperature_settings": {
|
||||
"temperature_low_command_topic": "temperature-low-command-topic",
|
||||
"temperature_low_command_template": "{{ value }}",
|
||||
"temperature_low_state_topic": "temperature-low-state-topic",
|
||||
"temperature_low_state_template": "{{ value_json.temperature_low }}",
|
||||
"temperature_high_command_topic": "temperature-high-command-topic",
|
||||
"temperature_high_command_template": "{{ value }}",
|
||||
"temperature_high_state_topic": "temperature-high-state-topic",
|
||||
"temperature_high_state_template": "{{ value_json.temperature_high }}",
|
||||
"min_temp": 8,
|
||||
"max_temp": 28,
|
||||
"precision": "0.1",
|
||||
"temp_step": 1.0,
|
||||
"initial": 19.0,
|
||||
},
|
||||
},
|
||||
(),
|
||||
"Milk notifier Cooler",
|
||||
),
|
||||
(
|
||||
MOCK_CLIMATE_NO_TARGET_TEMP_SUBENTRY_DATA_SINGLE,
|
||||
{"name": "Milk notifier", "mqtt_settings": {"qos": 0}},
|
||||
{"name": "Cooler"},
|
||||
{
|
||||
"temperature_unit": "C",
|
||||
"climate_feature_action": False,
|
||||
"climate_feature_current_humidity": False,
|
||||
"climate_feature_current_temperature": False,
|
||||
"climate_feature_power": False,
|
||||
"climate_feature_preset_modes": False,
|
||||
"climate_feature_fan_modes": False,
|
||||
"climate_feature_swing_horizontal_modes": False,
|
||||
"climate_feature_swing_modes": False,
|
||||
"climate_feature_target_temperature": "none",
|
||||
"climate_feature_target_humidity": False,
|
||||
},
|
||||
(),
|
||||
{
|
||||
"mode_command_topic": "mode-command-topic",
|
||||
"mode_command_template": "{{ value }}",
|
||||
"mode_state_topic": "mode-state-topic",
|
||||
"mode_state_template": "{{ value_json.mode }}",
|
||||
"modes": ["off", "heat", "cool", "auto"],
|
||||
},
|
||||
(),
|
||||
"Milk notifier Cooler",
|
||||
),
|
||||
(
|
||||
MOCK_COVER_SUBENTRY_DATA_SINGLE,
|
||||
{"name": "Milk notifier", "mqtt_settings": {"qos": 0}},
|
||||
@ -3130,6 +3351,9 @@ async def test_migrate_of_incompatible_config_entry(
|
||||
ids=[
|
||||
"binary_sensor",
|
||||
"button",
|
||||
"climate_single",
|
||||
"climate_high_low",
|
||||
"climate_no_target_temp",
|
||||
"cover",
|
||||
"fan",
|
||||
"notify_with_entity_name",
|
||||
@ -3631,8 +3855,144 @@ async def test_subentry_reconfigure_edit_entity_multi_entitites(
|
||||
},
|
||||
{"optimistic", "state_value_template", "entity_picture"},
|
||||
),
|
||||
(
|
||||
(
|
||||
ConfigSubentryData(
|
||||
data=MOCK_CLIMATE_SUBENTRY_DATA_SINGLE,
|
||||
subentry_type="device",
|
||||
title="Mock subentry",
|
||||
),
|
||||
),
|
||||
(),
|
||||
{
|
||||
"climate_feature_action": False,
|
||||
"climate_feature_current_humidity": False,
|
||||
"climate_feature_current_temperature": False,
|
||||
"climate_feature_power": False,
|
||||
"climate_feature_preset_modes": False,
|
||||
"climate_feature_fan_modes": False,
|
||||
"climate_feature_swing_horizontal_modes": False,
|
||||
"climate_feature_swing_modes": False,
|
||||
"climate_feature_target_temperature": "high_low",
|
||||
"climate_feature_target_humidity": False,
|
||||
},
|
||||
{
|
||||
"mode_command_topic": "mode-command-topic",
|
||||
"mode_command_template": "{{ value }}",
|
||||
"mode_state_topic": "mode-state-topic",
|
||||
"mode_state_template": "{{ value_json.mode }}",
|
||||
"modes": ["off", "heat", "cool"],
|
||||
# high/low target temperature
|
||||
"target_temperature_settings": {
|
||||
"temperature_low_command_topic": "temperature-low-command-topic",
|
||||
"temperature_low_command_template": "{{ value }}",
|
||||
"temperature_low_state_topic": "temperature-low-state-topic",
|
||||
"temperature_low_state_template": "{{ value_json.temperature_low }}",
|
||||
"temperature_high_command_topic": "temperature-high-command-topic",
|
||||
"temperature_high_command_template": "{{ value }}",
|
||||
"temperature_high_state_topic": "temperature-high-state-topic",
|
||||
"temperature_high_state_template": "{{ value_json.temperature_high }}",
|
||||
"min_temp": 8,
|
||||
"max_temp": 28,
|
||||
"precision": "0.1",
|
||||
"temp_step": 1.0,
|
||||
"initial": 19.0,
|
||||
},
|
||||
},
|
||||
{},
|
||||
{
|
||||
"current_humidity_topic",
|
||||
"action_topic",
|
||||
"swing_modes",
|
||||
"max_humidity",
|
||||
"fan_modes",
|
||||
"action_template",
|
||||
"current_temperature_template",
|
||||
"temperature_state_template",
|
||||
"entity_picture",
|
||||
"target_humidity_state_template",
|
||||
"fan_mode_state_topic",
|
||||
"swing_horizontal_mode_command_template",
|
||||
"power_command_template",
|
||||
"swing_horizontal_modes",
|
||||
"current_temperature_topic",
|
||||
"temperature_command_topic",
|
||||
"swing_mode_command_topic",
|
||||
"fan_mode_command_template",
|
||||
"swing_horizontal_mode_state_template",
|
||||
"preset_mode_command_template",
|
||||
"swing_mode_command_template",
|
||||
"temperature_state_topic",
|
||||
"preset_mode_value_template",
|
||||
"fan_mode_state_template",
|
||||
"swing_horizontal_mode_command_topic",
|
||||
"min_humidity",
|
||||
"temperature_command_template",
|
||||
"preset_modes",
|
||||
"swing_horizontal_mode_state_topic",
|
||||
"target_humidity_state_topic",
|
||||
"target_humidity_command_topic",
|
||||
"preset_mode_command_topic",
|
||||
"payload_on",
|
||||
"payload_off",
|
||||
"power_command_topic",
|
||||
"current_humidity_template",
|
||||
"preset_mode_state_topic",
|
||||
"fan_mode_command_topic",
|
||||
"swing_mode_state_template",
|
||||
"target_humidity_command_template",
|
||||
"swing_mode_state_topic",
|
||||
},
|
||||
),
|
||||
(
|
||||
(
|
||||
ConfigSubentryData(
|
||||
data=MOCK_CLIMATE_HIGH_LOW_SUBENTRY_DATA_SINGLE,
|
||||
subentry_type="device",
|
||||
title="Mock subentry",
|
||||
),
|
||||
),
|
||||
(),
|
||||
{
|
||||
"climate_feature_action": False,
|
||||
"climate_feature_current_humidity": False,
|
||||
"climate_feature_current_temperature": False,
|
||||
"climate_feature_power": False,
|
||||
"climate_feature_preset_modes": False,
|
||||
"climate_feature_fan_modes": False,
|
||||
"climate_feature_swing_horizontal_modes": False,
|
||||
"climate_feature_swing_modes": False,
|
||||
"climate_feature_target_temperature": "high_low",
|
||||
"climate_feature_target_humidity": False,
|
||||
},
|
||||
{
|
||||
"mode_command_topic": "mode-command-topic",
|
||||
"mode_command_template": "{{ value }}",
|
||||
"mode_state_topic": "mode-state-topic",
|
||||
"mode_state_template": "{{ value_json.mode }}",
|
||||
"modes": ["off", "heat", "cool"],
|
||||
# high/low target temperature
|
||||
"target_temperature_settings": {
|
||||
"temperature_low_command_topic": "temperature-low-command-topic",
|
||||
"temperature_low_command_template": "{{ value }}",
|
||||
"temperature_low_state_topic": "temperature-low-state-topic",
|
||||
"temperature_low_state_template": "{{ value_json.temperature_low }}",
|
||||
"temperature_high_command_topic": "temperature-high-command-topic",
|
||||
"temperature_high_command_template": "{{ value }}",
|
||||
"temperature_high_state_topic": "temperature-high-state-topic",
|
||||
"temperature_high_state_template": "{{ value_json.temperature_high }}",
|
||||
"min_temp": 8,
|
||||
"max_temp": 28,
|
||||
"precision": "0.1",
|
||||
"temp_step": 1.0,
|
||||
"initial": 19.0,
|
||||
},
|
||||
},
|
||||
{},
|
||||
{"entity_picture"},
|
||||
),
|
||||
],
|
||||
ids=["notify", "sensor", "light_basic"],
|
||||
ids=["notify", "sensor", "light_basic", "climate_single", "climate_high_low"],
|
||||
)
|
||||
async def test_subentry_reconfigure_edit_entity_single_entity(
|
||||
hass: HomeAssistant,
|
||||
|
Loading…
x
Reference in New Issue
Block a user