1 """Support for Template alarm control panels."""
3 from __future__
import annotations
9 import voluptuous
as vol
13 PLATFORM_SCHEMA
as ALARM_CONTROL_PANEL_PLATFORM_SCHEMA,
14 AlarmControlPanelEntity,
15 AlarmControlPanelEntityFeature,
16 AlarmControlPanelState,
41 from .const
import DOMAIN
42 from .template_entity
import TemplateEntity, rewrite_common_legacy_to_modern_conf
44 _LOGGER = logging.getLogger(__name__)
46 AlarmControlPanelState.ARMED_AWAY,
47 AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
48 AlarmControlPanelState.ARMED_HOME,
49 AlarmControlPanelState.ARMED_NIGHT,
50 AlarmControlPanelState.ARMED_VACATION,
51 AlarmControlPanelState.ARMING,
52 AlarmControlPanelState.DISARMED,
53 AlarmControlPanelState.PENDING,
54 AlarmControlPanelState.TRIGGERED,
58 CONF_ARM_AWAY_ACTION =
"arm_away"
59 CONF_ARM_CUSTOM_BYPASS_ACTION =
"arm_custom_bypass"
60 CONF_ARM_HOME_ACTION =
"arm_home"
61 CONF_ARM_NIGHT_ACTION =
"arm_night"
62 CONF_ARM_VACATION_ACTION =
"arm_vacation"
63 CONF_DISARM_ACTION =
"disarm"
64 CONF_TRIGGER_ACTION =
"trigger"
65 CONF_ALARM_CONTROL_PANELS =
"panels"
66 CONF_CODE_ARM_REQUIRED =
"code_arm_required"
67 CONF_CODE_FORMAT =
"code_format"
71 """Class to represent different code formats."""
74 number = CodeFormat.NUMBER
75 text = CodeFormat.TEXT
78 ALARM_CONTROL_PANEL_SCHEMA = vol.Schema(
80 vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
81 vol.Optional(CONF_DISARM_ACTION): cv.SCRIPT_SCHEMA,
82 vol.Optional(CONF_ARM_AWAY_ACTION): cv.SCRIPT_SCHEMA,
83 vol.Optional(CONF_ARM_CUSTOM_BYPASS_ACTION): cv.SCRIPT_SCHEMA,
84 vol.Optional(CONF_ARM_HOME_ACTION): cv.SCRIPT_SCHEMA,
85 vol.Optional(CONF_ARM_NIGHT_ACTION): cv.SCRIPT_SCHEMA,
86 vol.Optional(CONF_ARM_VACATION_ACTION): cv.SCRIPT_SCHEMA,
87 vol.Optional(CONF_TRIGGER_ACTION): cv.SCRIPT_SCHEMA,
88 vol.Optional(CONF_CODE_ARM_REQUIRED, default=
True): cv.boolean,
89 vol.Optional(CONF_CODE_FORMAT, default=TemplateCodeFormat.number.name): cv.enum(
92 vol.Optional(CONF_NAME): cv.string,
93 vol.Optional(CONF_UNIQUE_ID): cv.string,
97 PLATFORM_SCHEMA = ALARM_CONTROL_PANEL_PLATFORM_SCHEMA.extend(
99 vol.Required(CONF_ALARM_CONTROL_PANELS): cv.schema_with_slug_keys(
100 ALARM_CONTROL_PANEL_SCHEMA
105 ALARM_CONTROL_PANEL_CONFIG_SCHEMA = vol.Schema(
107 vol.Required(CONF_NAME): cv.template,
108 vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
109 vol.Optional(CONF_DISARM_ACTION): cv.SCRIPT_SCHEMA,
110 vol.Optional(CONF_ARM_AWAY_ACTION): cv.SCRIPT_SCHEMA,
111 vol.Optional(CONF_ARM_CUSTOM_BYPASS_ACTION): cv.SCRIPT_SCHEMA,
112 vol.Optional(CONF_ARM_HOME_ACTION): cv.SCRIPT_SCHEMA,
113 vol.Optional(CONF_ARM_NIGHT_ACTION): cv.SCRIPT_SCHEMA,
114 vol.Optional(CONF_ARM_VACATION_ACTION): cv.SCRIPT_SCHEMA,
115 vol.Optional(CONF_TRIGGER_ACTION): cv.SCRIPT_SCHEMA,
116 vol.Optional(CONF_CODE_ARM_REQUIRED, default=
True): cv.boolean,
117 vol.Optional(CONF_CODE_FORMAT, default=TemplateCodeFormat.number.name): cv.enum(
120 vol.Optional(CONF_DEVICE_ID): selector.DeviceSelector(),
126 hass: HomeAssistant, config: dict[str, Any]
127 ) -> list[AlarmControlPanelTemplate]:
128 """Create Template Alarm Control Panels."""
129 alarm_control_panels = []
131 for object_id, entity_config
in config[CONF_ALARM_CONTROL_PANELS].items():
133 unique_id = entity_config.get(CONF_UNIQUE_ID)
135 alarm_control_panels.append(
144 return alarm_control_panels
149 config_entry: ConfigEntry,
150 async_add_entities: AddEntitiesCallback,
152 """Initialize config entry."""
153 _options =
dict(config_entry.options)
154 _options.pop(
"template_type")
162 config_entry.entry_id,
171 async_add_entities: AddEntitiesCallback,
172 discovery_info: DiscoveryInfoType |
None =
None,
174 """Set up the Template Alarm Control Panels."""
179 """Representation of a templated Alarm Control Panel."""
181 _attr_should_poll =
False
188 unique_id: str |
None,
190 """Initialize the panel."""
192 hass, config=config, fallback_name=object_id, unique_id=unique_id
195 ENTITY_ID_FORMAT, object_id, hass=hass
198 assert name
is not None
199 self.
_template_template = config.get(CONF_VALUE_TEMPLATE)
201 self._attr_code_arm_required: bool = config[CONF_CODE_ARM_REQUIRED]
203 if (disarm_action := config.get(CONF_DISARM_ACTION))
is not None:
206 if (arm_away_action := config.get(CONF_ARM_AWAY_ACTION))
is not None:
209 if (arm_home_action := config.get(CONF_ARM_HOME_ACTION))
is not None:
212 if (arm_night_action := config.get(CONF_ARM_NIGHT_ACTION))
is not None:
215 if (arm_vacation_action := config.get(CONF_ARM_VACATION_ACTION))
is not None:
219 arm_custom_bypass_action := config.get(CONF_ARM_CUSTOM_BYPASS_ACTION)
222 hass, arm_custom_bypass_action, name, DOMAIN
225 if (trigger_action := config.get(CONF_TRIGGER_ACTION))
is not None:
228 self.
_state_state: AlarmControlPanelState |
None =
None
231 config.get(CONF_DEVICE_ID),
235 supported_features = (
236 supported_features | AlarmControlPanelEntityFeature.ARM_NIGHT
240 supported_features = (
241 supported_features | AlarmControlPanelEntityFeature.ARM_HOME
245 supported_features = (
246 supported_features | AlarmControlPanelEntityFeature.ARM_AWAY
250 supported_features = (
251 supported_features | AlarmControlPanelEntityFeature.ARM_VACATION
255 supported_features = (
256 supported_features | AlarmControlPanelEntityFeature.ARM_CUSTOM_BYPASS
260 supported_features = (
261 supported_features | AlarmControlPanelEntityFeature.TRIGGER
266 """Restore last state."""
270 and last_state.state
not in (STATE_UNKNOWN, STATE_UNAVAILABLE)
271 and last_state.state
in _VALID_STATES
274 and self.
_state_state
is None
276 self.
_state_state = AlarmControlPanelState(last_state.state)
280 """Return the state of the device."""
285 if isinstance(result, TemplateError):
290 if result
in _VALID_STATES:
291 self.
_state_state = result
292 _LOGGER.debug(
"Valid state - %s", result)
296 "Received invalid alarm panel state: %s for entity %s. Expected: %s",
299 ", ".join(_VALID_STATES),
305 """Set up templates."""
313 """Arm the panel to specified state with supplied script."""
314 optimistic_set =
False
318 optimistic_set =
True
321 script, run_variables={ATTR_CODE: code}, context=self.
_context_context
328 """Arm the panel to Away."""
330 AlarmControlPanelState.ARMED_AWAY,
336 """Arm the panel to Home."""
338 AlarmControlPanelState.ARMED_HOME,
344 """Arm the panel to Night."""
346 AlarmControlPanelState.ARMED_NIGHT,
352 """Arm the panel to Vacation."""
354 AlarmControlPanelState.ARMED_VACATION,
360 """Arm the panel to Custom Bypass."""
362 AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
368 """Disarm the panel."""
370 AlarmControlPanelState.DISARMED, script=self.
_disarm_script_disarm_script, code=code
374 """Trigger the panel."""
376 AlarmControlPanelState.TRIGGERED,
AlarmControlPanelEntityFeature
None async_alarm_arm_vacation(self, str|None code=None)
None async_added_to_hass(self)
None async_alarm_arm_custom_bypass(self, str|None code=None)
None async_alarm_disarm(self, str|None code=None)
AlarmControlPanelState|None alarm_state(self)
None async_alarm_trigger(self, str|None code=None)
None async_alarm_arm_home(self, str|None code=None)
None async_alarm_arm_night(self, str|None code=None)
def _update_state(self, result)
None async_alarm_arm_away(self, str|None code=None)
None __init__(self, HomeAssistant hass, str object_id, dict config, str|None unique_id)
None _async_setup_templates(self)
_arm_custom_bypass_script
def _async_alarm_arm(self, state, script, code)
None _update_state(self, str|TemplateError result)
None async_run_script(self, Script script, *_VarsType|None run_variables=None, Context|None context=None)
None add_template_attribute(self, str attribute, Template template, Callable[[Any], Any]|None validator=None, Callable[[Any], None]|None on_update=None, bool none_on_template_error=False)
None async_write_ha_state(self)
State|None async_get_last_state(self)
ALARM_CONTROL_PANEL_CONFIG_SCHEMA
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
list[AlarmControlPanelTemplate] _async_create_entities(HomeAssistant hass, dict[str, Any] config)
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
dict[str, Any] rewrite_common_legacy_to_modern_conf(HomeAssistant hass, dict[str, Any] entity_cfg, dict[str, str]|None extra_legacy_fields=None)
dr.DeviceInfo|None async_device_info_to_link_from_device_id(HomeAssistant hass, str|None device_id)
str async_generate_entity_id(str entity_id_format, str|None name, Iterable[str]|None current_ids=None, HomeAssistant|None hass=None)