Config flow for elkm1 (#33297)
* Config flow for elkm1 * As entity ids can now be changed, the “alarm_control_panel” attribute “changed_by_entity_id” is now “changed_by_keypad” and will show the name of the Elk keypad instead of the entity id. * An auto configure mode has been introduced which avoids the need to setup the complex include and exclude filters. This functionality still exists when configuring from yaml for power users who want more control over which entities elkm1 generates. * restore _has_all_unique_prefixes * preserve legacy behavior of creating alarm_control_panels that have no linked keypads when auto_configure is False * unroll loop
This commit is contained in:
parent
c629e7dc0e
commit
18a4829314
18 changed files with 823 additions and 214 deletions
|
@ -1,4 +1,6 @@
|
|||
"""Each ElkM1 area will be created as a separate alarm_control_panel."""
|
||||
import logging
|
||||
|
||||
from elkm1_lib.const import AlarmState, ArmedStatus, ArmLevel, ArmUpState
|
||||
import voluptuous as vol
|
||||
|
||||
|
@ -22,24 +24,18 @@ from homeassistant.const import (
|
|||
STATE_ALARM_PENDING,
|
||||
STATE_ALARM_TRIGGERED,
|
||||
)
|
||||
from homeassistant.helpers import entity_platform
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
async_dispatcher_connect,
|
||||
async_dispatcher_send,
|
||||
)
|
||||
|
||||
from . import (
|
||||
DOMAIN,
|
||||
SERVICE_ALARM_ARM_HOME_INSTANT,
|
||||
SERVICE_ALARM_ARM_NIGHT_INSTANT,
|
||||
SERVICE_ALARM_ARM_VACATION,
|
||||
SERVICE_ALARM_DISPLAY_MESSAGE,
|
||||
ElkEntity,
|
||||
ElkAttachedEntity,
|
||||
create_elk_entities,
|
||||
)
|
||||
|
||||
SIGNAL_ARM_ENTITY = "elkm1_arm"
|
||||
SIGNAL_DISPLAY_MESSAGE = "elkm1_display_message"
|
||||
from .const import DOMAIN
|
||||
|
||||
ELK_ALARM_SERVICE_SCHEMA = vol.Schema(
|
||||
{
|
||||
|
@ -61,69 +57,57 @@ DISPLAY_MESSAGE_SERVICE_SCHEMA = vol.Schema(
|
|||
}
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Set up the ElkM1 alarm platform."""
|
||||
if discovery_info is None:
|
||||
return
|
||||
|
||||
elk_datas = hass.data[DOMAIN]
|
||||
elk_data = hass.data[DOMAIN][config_entry.entry_id]
|
||||
entities = []
|
||||
for elk_data in elk_datas.values():
|
||||
elk = elk_data["elk"]
|
||||
entities = create_elk_entities(elk_data, elk.areas, "area", ElkArea, entities)
|
||||
|
||||
elk = elk_data["elk"]
|
||||
areas_with_keypad = set()
|
||||
for keypad in elk.keypads:
|
||||
areas_with_keypad.add(keypad.area)
|
||||
|
||||
areas = []
|
||||
for area in elk.areas:
|
||||
if area.index in areas_with_keypad or elk_data["auto_configure"] is False:
|
||||
areas.append(area)
|
||||
create_elk_entities(elk_data, areas, "area", ElkArea, entities)
|
||||
async_add_entities(entities, True)
|
||||
|
||||
def _dispatch(signal, entity_ids, *args):
|
||||
for entity_id in entity_ids:
|
||||
async_dispatcher_send(hass, f"{signal}_{entity_id}", *args)
|
||||
platform = entity_platform.current_platform.get()
|
||||
|
||||
def _arm_service(service):
|
||||
entity_ids = service.data.get(ATTR_ENTITY_ID, [])
|
||||
arm_level = _arm_services().get(service.service)
|
||||
args = (arm_level, service.data.get(ATTR_CODE))
|
||||
_dispatch(SIGNAL_ARM_ENTITY, entity_ids, *args)
|
||||
|
||||
for service in _arm_services():
|
||||
hass.services.async_register(
|
||||
DOMAIN, service, _arm_service, ELK_ALARM_SERVICE_SCHEMA
|
||||
)
|
||||
|
||||
def _display_message_service(service):
|
||||
entity_ids = service.data.get(ATTR_ENTITY_ID, [])
|
||||
data = service.data
|
||||
args = (
|
||||
data["clear"],
|
||||
data["beep"],
|
||||
data["timeout"],
|
||||
data["line1"],
|
||||
data["line2"],
|
||||
)
|
||||
_dispatch(SIGNAL_DISPLAY_MESSAGE, entity_ids, *args)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_ALARM_ARM_VACATION,
|
||||
ELK_ALARM_SERVICE_SCHEMA,
|
||||
"async_alarm_arm_vacation",
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_ALARM_ARM_HOME_INSTANT,
|
||||
ELK_ALARM_SERVICE_SCHEMA,
|
||||
"async_alarm_arm_home_instant",
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_ALARM_ARM_NIGHT_INSTANT,
|
||||
ELK_ALARM_SERVICE_SCHEMA,
|
||||
"async_alarm_arm_night_instant",
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_ALARM_DISPLAY_MESSAGE,
|
||||
_display_message_service,
|
||||
DISPLAY_MESSAGE_SERVICE_SCHEMA,
|
||||
"async_display_message",
|
||||
)
|
||||
|
||||
|
||||
def _arm_services():
|
||||
return {
|
||||
SERVICE_ALARM_ARM_VACATION: ArmLevel.ARMED_VACATION.value,
|
||||
SERVICE_ALARM_ARM_HOME_INSTANT: ArmLevel.ARMED_STAY_INSTANT.value,
|
||||
SERVICE_ALARM_ARM_NIGHT_INSTANT: ArmLevel.ARMED_NIGHT_INSTANT.value,
|
||||
}
|
||||
|
||||
|
||||
class ElkArea(ElkEntity, AlarmControlPanel):
|
||||
class ElkArea(ElkAttachedEntity, AlarmControlPanel):
|
||||
"""Representation of an Area / Partition within the ElkM1 alarm panel."""
|
||||
|
||||
def __init__(self, element, elk, elk_data):
|
||||
"""Initialize Area as Alarm Control Panel."""
|
||||
super().__init__(element, elk, elk_data)
|
||||
self._changed_by_entity_id = ""
|
||||
self._changed_by_keypad = None
|
||||
self._state = None
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
|
@ -131,23 +115,13 @@ class ElkArea(ElkEntity, AlarmControlPanel):
|
|||
await super().async_added_to_hass()
|
||||
for keypad in self._elk.keypads:
|
||||
keypad.add_callback(self._watch_keypad)
|
||||
async_dispatcher_connect(
|
||||
self.hass, f"{SIGNAL_ARM_ENTITY}_{self.entity_id}", self._arm_service
|
||||
)
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
f"{SIGNAL_DISPLAY_MESSAGE}_{self.entity_id}",
|
||||
self._display_message,
|
||||
)
|
||||
|
||||
def _watch_keypad(self, keypad, changeset):
|
||||
if keypad.area != self._element.index:
|
||||
return
|
||||
if changeset.get("last_user") is not None:
|
||||
self._changed_by_entity_id = self.hass.data[DOMAIN][self._prefix][
|
||||
"keypads"
|
||||
].get(keypad.index, "")
|
||||
self.async_schedule_update_ha_state(True)
|
||||
self._changed_by_keypad = keypad.name
|
||||
self.async_write_ha_state()
|
||||
|
||||
@property
|
||||
def code_format(self):
|
||||
|
@ -178,7 +152,7 @@ class ElkArea(ElkEntity, AlarmControlPanel):
|
|||
attrs["arm_up_state"] = ArmUpState(elmt.arm_up_state).name.lower()
|
||||
if elmt.alarm_state is not None:
|
||||
attrs["alarm_state"] = AlarmState(elmt.alarm_state).name.lower()
|
||||
attrs["changed_by_entity_id"] = self._changed_by_entity_id
|
||||
attrs["changed_by_keypad"] = self._changed_by_keypad
|
||||
return attrs
|
||||
|
||||
def _element_changed(self, element, changeset):
|
||||
|
@ -225,9 +199,18 @@ class ElkArea(ElkEntity, AlarmControlPanel):
|
|||
"""Send arm night command."""
|
||||
self._element.arm(ArmLevel.ARMED_NIGHT.value, int(code))
|
||||
|
||||
async def _arm_service(self, arm_level, code):
|
||||
self._element.arm(arm_level, code)
|
||||
async def async_alarm_arm_home_instant(self, code=None):
|
||||
"""Send arm stay instant command."""
|
||||
self._element.arm(ArmLevel.ARMED_STAY_INSTANT.value, int(code))
|
||||
|
||||
async def _display_message(self, clear, beep, timeout, line1, line2):
|
||||
async def async_alarm_arm_night_instant(self, code=None):
|
||||
"""Send arm night instant command."""
|
||||
self._element.arm(ArmLevel.ARMED_NIGHT_INSTANT.value, int(code))
|
||||
|
||||
async def async_alarm_arm_vacation(self, code=None):
|
||||
"""Send arm vacation command."""
|
||||
self._element.arm(ArmLevel.ARMED_VACATION.value, int(code))
|
||||
|
||||
async def async_display_message(self, clear, beep, timeout, line1, line2):
|
||||
"""Display a message on all keypads for the area."""
|
||||
self._element.display_message(clear, beep, timeout, line1, line2)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue