Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 1 addition & 17 deletions homeassistant/components/esphome/entry_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,23 +295,7 @@ async def async_update_static_infos(
needed_platforms.add(Platform.BINARY_SENSOR)
needed_platforms.add(Platform.SELECT)

ent_reg = er.async_get(hass)
registry_get_entity = ent_reg.async_get_entity_id
for info in infos:
platform = INFO_TYPE_TO_PLATFORM[type(info)]
needed_platforms.add(platform)
# If the unique id is in the old format, migrate it
# except if they downgraded and upgraded, there might be a duplicate
# so we want to keep the one that was already there.
if (
(old_unique_id := info.unique_id)
and (old_entry := registry_get_entity(platform, DOMAIN, old_unique_id))
and (new_unique_id := build_device_unique_id(mac, info))
!= old_unique_id
and not registry_get_entity(platform, DOMAIN, new_unique_id)
):
ent_reg.async_update_entity(old_entry, new_unique_id=new_unique_id)

needed_platforms.update(INFO_TYPE_TO_PLATFORM[type(info)] for info in infos)
await self._ensure_platforms_loaded(hass, entry, needed_platforms)

# Make a dict of the EntityInfo by type and send
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/esphome/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"mqtt": ["esphome/discover/#"],
"quality_scale": "platinum",
"requirements": [
"aioesphomeapi==35.0.0",
"aioesphomeapi==36.0.1",
"esphome-dashboard-api==1.3.0",
"bleak-esphome==3.1.0"
],
Expand Down
6 changes: 6 additions & 0 deletions homeassistant/components/mqtt/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ def validate_sensor_state_and_device_class_config(config: ConfigType) -> ConfigT
f"together with state class `{state_class}`"
)

unit_of_measurement: str | None
if (
unit_of_measurement := config.get(CONF_UNIT_OF_MEASUREMENT)
) is not None and not unit_of_measurement.strip():
config.pop(CONF_UNIT_OF_MEASUREMENT)

# Only allow `options` to be set for `enum` sensors
# to limit the possible sensor values
if (options := config.get(CONF_OPTIONS)) is not None:
Expand Down
105 changes: 43 additions & 62 deletions homeassistant/components/template/alarm_control_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_CODE,
CONF_DEVICE_ID,
CONF_NAME,
CONF_STATE,
CONF_UNIQUE_ID,
Expand All @@ -31,7 +30,7 @@
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import TemplateError
from homeassistant.helpers import config_validation as cv, selector, template
from homeassistant.helpers import config_validation as cv, template
from homeassistant.helpers.entity_platform import (
AddConfigEntryEntitiesCallback,
AddEntitiesCallback,
Expand All @@ -43,8 +42,16 @@
from .const import DOMAIN
from .coordinator import TriggerUpdateCoordinator
from .entity import AbstractTemplateEntity
from .helpers import async_setup_template_platform
from .template_entity import TemplateEntity, make_template_entity_common_modern_schema
from .helpers import (
async_setup_template_entry,
async_setup_template_platform,
async_setup_template_preview,
)
from .template_entity import (
TEMPLATE_ENTITY_COMMON_CONFIG_ENTRY_SCHEMA,
TemplateEntity,
make_template_entity_common_modern_schema,
)
from .trigger_entity import TriggerEntity

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -88,27 +95,7 @@ class TemplateCodeFormat(Enum):

DEFAULT_NAME = "Template Alarm Control Panel"

ALARM_CONTROL_PANEL_SCHEMA = vol.All(
vol.Schema(
{
vol.Optional(CONF_ARM_AWAY_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_ARM_CUSTOM_BYPASS_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_ARM_HOME_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_ARM_NIGHT_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_ARM_VACATION_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_CODE_ARM_REQUIRED, default=True): cv.boolean,
vol.Optional(
CONF_CODE_FORMAT, default=TemplateCodeFormat.number.name
): cv.enum(TemplateCodeFormat),
vol.Optional(CONF_DISARM_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_STATE): cv.template,
vol.Optional(CONF_TRIGGER_ACTION): cv.SCRIPT_SCHEMA,
}
).extend(make_template_entity_common_modern_schema(DEFAULT_NAME).schema)
)


LEGACY_ALARM_CONTROL_PANEL_SCHEMA = vol.Schema(
ALARM_CONTROL_PANEL_COMMON_SCHEMA = vol.Schema(
{
vol.Optional(CONF_ARM_AWAY_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_ARM_CUSTOM_BYPASS_ACTION): cv.SCRIPT_SCHEMA,
Expand All @@ -120,22 +107,16 @@ class TemplateCodeFormat(Enum):
TemplateCodeFormat
),
vol.Optional(CONF_DISARM_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_STATE): cv.template,
vol.Optional(CONF_TRIGGER_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_UNIQUE_ID): cv.string,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
}
)

PLATFORM_SCHEMA = ALARM_CONTROL_PANEL_PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_ALARM_CONTROL_PANELS): cv.schema_with_slug_keys(
LEGACY_ALARM_CONTROL_PANEL_SCHEMA
),
}
ALARM_CONTROL_PANEL_YAML_SCHEMA = ALARM_CONTROL_PANEL_COMMON_SCHEMA.extend(
make_template_entity_common_modern_schema(DEFAULT_NAME).schema
)

ALARM_CONTROL_PANEL_CONFIG_SCHEMA = vol.Schema(
ALARM_CONTROL_PANEL_LEGACY_YAML_SCHEMA = vol.Schema(
{
vol.Optional(CONF_ARM_AWAY_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_ARM_CUSTOM_BYPASS_ACTION): cv.SCRIPT_SCHEMA,
Expand All @@ -146,23 +127,25 @@ class TemplateCodeFormat(Enum):
vol.Optional(CONF_CODE_FORMAT, default=TemplateCodeFormat.number.name): cv.enum(
TemplateCodeFormat
),
vol.Optional(CONF_DEVICE_ID): selector.DeviceSelector(),
vol.Optional(CONF_DISARM_ACTION): cv.SCRIPT_SCHEMA,
vol.Required(CONF_NAME): cv.template,
vol.Optional(CONF_STATE): cv.template,
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_TRIGGER_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_UNIQUE_ID): cv.string,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
}
)

PLATFORM_SCHEMA = ALARM_CONTROL_PANEL_PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_ALARM_CONTROL_PANELS): cv.schema_with_slug_keys(
ALARM_CONTROL_PANEL_LEGACY_YAML_SCHEMA
),
}
)

def rewrite_options_to_modern_conf(option_config: dict[str, dict]) -> dict[str, dict]:
"""Rewrite option configuration to modern configuration."""
option_config = {**option_config}

if CONF_VALUE_TEMPLATE in option_config:
option_config[CONF_STATE] = option_config.pop(CONF_VALUE_TEMPLATE)

return option_config
ALARM_CONTROL_PANEL_CONFIG_ENTRY_SCHEMA = ALARM_CONTROL_PANEL_COMMON_SCHEMA.extend(
TEMPLATE_ENTITY_COMMON_CONFIG_ENTRY_SCHEMA.schema
)


async def async_setup_entry(
Expand All @@ -171,18 +154,13 @@ async def async_setup_entry(
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Initialize config entry."""
_options = dict(config_entry.options)
_options.pop("template_type")
_options = rewrite_options_to_modern_conf(_options)
validated_config = ALARM_CONTROL_PANEL_CONFIG_SCHEMA(_options)
async_add_entities(
[
StateAlarmControlPanelEntity(
hass,
validated_config,
config_entry.entry_id,
)
]
await async_setup_template_entry(
hass,
config_entry,
async_add_entities,
StateAlarmControlPanelEntity,
ALARM_CONTROL_PANEL_CONFIG_ENTRY_SCHEMA,
True,
)


Expand Down Expand Up @@ -211,11 +189,14 @@ def async_create_preview_alarm_control_panel(
hass: HomeAssistant, name: str, config: dict[str, Any]
) -> StateAlarmControlPanelEntity:
"""Create a preview alarm control panel."""
updated_config = rewrite_options_to_modern_conf(config)
validated_config = ALARM_CONTROL_PANEL_CONFIG_SCHEMA(
updated_config | {CONF_NAME: name}
return async_setup_template_preview(
hass,
name,
config,
StateAlarmControlPanelEntity,
ALARM_CONTROL_PANEL_CONFIG_ENTRY_SCHEMA,
True,
)
return StateAlarmControlPanelEntity(hass, validated_config, None)


class AbstractTemplateAlarmControlPanel(
Expand Down
49 changes: 30 additions & 19 deletions homeassistant/components/template/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
ATTR_ENTITY_ID,
ATTR_FRIENDLY_NAME,
CONF_DEVICE_CLASS,
CONF_DEVICE_ID,
CONF_ENTITY_PICTURE_TEMPLATE,
CONF_FRIENDLY_NAME_TEMPLATE,
CONF_ICON_TEMPLATE,
Expand All @@ -38,7 +37,7 @@
)
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
from homeassistant.exceptions import TemplateError
from homeassistant.helpers import config_validation as cv, selector, template
from homeassistant.helpers import config_validation as cv, template
from homeassistant.helpers.entity_platform import (
AddConfigEntryEntitiesCallback,
AddEntitiesCallback,
Expand All @@ -50,8 +49,16 @@

from . import TriggerUpdateCoordinator
from .const import CONF_AVAILABILITY_TEMPLATE
from .helpers import async_setup_template_platform
from .template_entity import TEMPLATE_ENTITY_COMMON_SCHEMA, TemplateEntity
from .helpers import (
async_setup_template_entry,
async_setup_template_platform,
async_setup_template_preview,
)
from .template_entity import (
TEMPLATE_ENTITY_COMMON_CONFIG_ENTRY_SCHEMA,
TEMPLATE_ENTITY_COMMON_SCHEMA,
TemplateEntity,
)
from .trigger_entity import TriggerEntity

CONF_DELAY_ON = "delay_on"
Expand All @@ -64,7 +71,7 @@
CONF_VALUE_TEMPLATE: CONF_STATE,
}

BINARY_SENSOR_SCHEMA = vol.Schema(
BINARY_SENSOR_COMMON_SCHEMA = vol.Schema(
{
vol.Optional(CONF_AUTO_OFF): vol.Any(cv.positive_time_period, cv.template),
vol.Optional(CONF_DELAY_OFF): vol.Any(cv.positive_time_period, cv.template),
Expand All @@ -73,15 +80,17 @@
vol.Required(CONF_STATE): cv.template,
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
}
).extend(TEMPLATE_ENTITY_COMMON_SCHEMA.schema)
)

BINARY_SENSOR_CONFIG_SCHEMA = BINARY_SENSOR_SCHEMA.extend(
{
vol.Optional(CONF_DEVICE_ID): selector.DeviceSelector(),
}
BINARY_SENSOR_YAML_SCHEMA = BINARY_SENSOR_COMMON_SCHEMA.extend(
TEMPLATE_ENTITY_COMMON_SCHEMA.schema
)

LEGACY_BINARY_SENSOR_SCHEMA = vol.All(
BINARY_SENSOR_CONFIG_ENTRY_SCHEMA = BINARY_SENSOR_COMMON_SCHEMA.extend(
TEMPLATE_ENTITY_COMMON_CONFIG_ENTRY_SCHEMA.schema
)

BINARY_SENSOR_LEGACY_YAML_SCHEMA = vol.All(
cv.deprecated(ATTR_ENTITY_ID),
vol.Schema(
{
Expand All @@ -106,7 +115,7 @@
PLATFORM_SCHEMA = BINARY_SENSOR_PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_SENSORS): cv.schema_with_slug_keys(
LEGACY_BINARY_SENSOR_SCHEMA
BINARY_SENSOR_LEGACY_YAML_SCHEMA
),
}
)
Expand Down Expand Up @@ -138,11 +147,12 @@ async def async_setup_entry(
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Initialize config entry."""
_options = dict(config_entry.options)
_options.pop("template_type")
validated_config = BINARY_SENSOR_CONFIG_SCHEMA(_options)
async_add_entities(
[StateBinarySensorEntity(hass, validated_config, config_entry.entry_id)]
await async_setup_template_entry(
hass,
config_entry,
async_add_entities,
StateBinarySensorEntity,
BINARY_SENSOR_CONFIG_ENTRY_SCHEMA,
)


Expand All @@ -151,8 +161,9 @@ def async_create_preview_binary_sensor(
hass: HomeAssistant, name: str, config: dict[str, Any]
) -> StateBinarySensorEntity:
"""Create a preview sensor."""
validated_config = BINARY_SENSOR_CONFIG_SCHEMA(config | {CONF_NAME: name})
return StateBinarySensorEntity(hass, validated_config, None)
return async_setup_template_preview(
hass, name, config, StateBinarySensorEntity, BINARY_SENSOR_CONFIG_ENTRY_SCHEMA
)


class StateBinarySensorEntity(TemplateEntity, BinarySensorEntity, RestoreEntity):
Expand Down
31 changes: 17 additions & 14 deletions homeassistant/components/template/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,41 @@
ButtonEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_DEVICE_CLASS, CONF_DEVICE_ID, CONF_NAME
from homeassistant.const import CONF_DEVICE_CLASS
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv, selector
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_platform import (
AddConfigEntryEntitiesCallback,
AddEntitiesCallback,
)
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType

from .const import CONF_PRESS, DOMAIN
from .helpers import async_setup_template_platform
from .template_entity import TemplateEntity, make_template_entity_common_modern_schema
from .helpers import async_setup_template_entry, async_setup_template_platform
from .template_entity import (
TEMPLATE_ENTITY_COMMON_CONFIG_ENTRY_SCHEMA,
TemplateEntity,
make_template_entity_common_modern_schema,
)

_LOGGER = logging.getLogger(__name__)

DEFAULT_NAME = "Template Button"
DEFAULT_OPTIMISTIC = False

BUTTON_SCHEMA = vol.Schema(
BUTTON_YAML_SCHEMA = vol.Schema(
{
vol.Required(CONF_PRESS): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
}
).extend(make_template_entity_common_modern_schema(DEFAULT_NAME).schema)

CONFIG_BUTTON_SCHEMA = vol.Schema(
BUTTON_CONFIG_ENTRY_SCHEMA = vol.Schema(
{
vol.Optional(CONF_NAME): cv.template,
vol.Optional(CONF_PRESS): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_DEVICE_ID): selector.DeviceSelector(),
}
)
).extend(TEMPLATE_ENTITY_COMMON_CONFIG_ENTRY_SCHEMA.schema)


async def async_setup_platform(
Expand All @@ -73,11 +75,12 @@ async def async_setup_entry(
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Initialize config entry."""
_options = dict(config_entry.options)
_options.pop("template_type")
validated_config = CONFIG_BUTTON_SCHEMA(_options)
async_add_entities(
[StateButtonEntity(hass, validated_config, config_entry.entry_id)]
await async_setup_template_entry(
hass,
config_entry,
async_add_entities,
StateButtonEntity,
BUTTON_CONFIG_ENTRY_SCHEMA,
)


Expand Down
Loading
Loading