HEX
Server: Apache/2.4.63 (Unix)
System: Linux Synopilou92 4.4.302+ #72806 SMP Mon Jul 21 23:16:00 CST 2025 x86_64
User: pilou92 (1026)
PHP: 8.0.30
Disabled: NONE
Upload Files
File: /volume1/docker/homeassistant2025/custom_components/xiaomi_miot/alarm_control_panel.py
"""Support alarm_control_panel entity for Xiaomi Miot."""
import logging

from homeassistant.components.alarm_control_panel import (
    DOMAIN as ENTITY_DOMAIN,
    AlarmControlPanelEntity,
    AlarmControlPanelEntityFeature,  # v2022.5
)

from . import (
    DOMAIN,
    CONF_MODEL,
    XIAOMI_CONFIG_SCHEMA as PLATFORM_SCHEMA,  # noqa: F401
    HassEntry,
    MiotEntity,
    async_setup_config_entry,
    bind_services_to_entries,
)
from .core.miot_spec import (
    MiotSpec,
    MiotService,
)
from .core.const import AlarmControlPanelState

_LOGGER = logging.getLogger(__name__)
DATA_KEY = f'{ENTITY_DOMAIN}.{DOMAIN}'

SERVICE_TO_METHOD = {}


async def async_setup_entry(hass, config_entry, async_add_entities):
    HassEntry.init(hass, config_entry).new_adder(ENTITY_DOMAIN, async_add_entities)
    await async_setup_config_entry(hass, config_entry, async_setup_platform, async_add_entities, ENTITY_DOMAIN)


async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
    hass.data.setdefault(DATA_KEY, {})
    hass.data[DOMAIN]['add_entities'][ENTITY_DOMAIN] = async_add_entities
    config['hass'] = hass
    model = str(config.get(CONF_MODEL) or '')
    spec = hass.data[DOMAIN]['miot_specs'].get(model)
    entities = []
    if isinstance(spec, MiotSpec):
        for srv in spec.get_services('arming'):
            if not srv.get_property('arming_mode'):
                continue
            entities.append(MiotAlarmEntity(config, srv))
    for entity in entities:
        hass.data[DOMAIN]['entities'][entity.unique_id] = entity
    async_add_entities(entities, update_before_add=True)
    bind_services_to_entries(hass, SERVICE_TO_METHOD)


class MiotAlarmEntity(MiotEntity, AlarmControlPanelEntity):
    def __init__(self, config, miot_service: MiotService):
        super().__init__(miot_service, config=config, logger=_LOGGER)
        self._attr_code_arm_required = False
        self._is_mgl03 = self.model == 'lumi.gateway.mgl03'
        self._prop_mode = miot_service.get_property('arming_mode')
        if self._prop_mode:
            if self._prop_mode.list_value('home_arming') is not None:
                self._supported_features |= AlarmControlPanelEntityFeature.ARM_HOME
            if self._prop_mode.list_value('away_arming') is not None:
                self._supported_features |= AlarmControlPanelEntityFeature.ARM_AWAY
            if self._prop_mode.list_value('sleep_arming') is not None:
                self._supported_features |= AlarmControlPanelEntityFeature.ARM_NIGHT
            if self._is_mgl03:
                self._supported_features |= AlarmControlPanelEntityFeature.TRIGGER

    async def async_update(self):
        await super().async_update()
        if not self._available:
            return
        self.update_state()

    def update_state(self):
        sta = None
        if self._prop_mode:
            val = self._prop_mode.from_device(self.device)
            des = self._prop_mode.list_description(val) if val is not None else None
            if des is not None:
                des = f'{des}'.lower()
                if 'basic' in des:
                    sta = AlarmControlPanelState.DISARMED
                elif 'home' in des:
                    sta = AlarmControlPanelState.ARMED_HOME
                elif 'away' in des:
                    sta = AlarmControlPanelState.ARMED_AWAY
                elif 'sleep' in des:
                    sta = AlarmControlPanelState.ARMED_NIGHT
        if self._is_mgl03:
            if self.device.props.get('arming.alarm'):
                sta = AlarmControlPanelState.TRIGGERED
        if hasattr(self, '_attr_alarm_state'):
            self._attr_alarm_state = sta
        else:
            self._attr_state = sta

    async def async_set_arm_mode(self, mode):
        ret = False
        val = self._prop_mode.list_value(mode)
        if val is not None:
            ret = await self.async_set_property(self._prop_mode, val)
        if ret:
            self.update_state()
        return ret

    async def async_alarm_disarm(self, code=None):
        """Send disarm command."""
        return await self.async_set_arm_mode('basic_arming')

    async def async_alarm_arm_home(self, code=None):
        """Send arm home command."""
        return await self.async_set_arm_mode('home_arming')

    async def async_alarm_arm_away(self, code=None):
        """Send arm away command."""
        return await self.async_set_arm_mode('away_arming')

    async def async_alarm_arm_night(self, code=None):
        """Send arm night command."""
        return await self.async_set_arm_mode('sleep_arming')

    def alarm_arm_vacation(self, code=None):
        """Send arm vacation command."""
        raise NotImplementedError()

    async def async_alarm_trigger(self, code=None):
        """Send alarm trigger command."""
        if self._is_mgl03:
            return await self.async_set_miot_property(3, 22, 1)
        raise NotImplementedError()

    def alarm_arm_custom_bypass(self, code=None):
        """Send arm custom bypass command."""
        raise NotImplementedError()