Ejemplo n.º 1
0
async def async_validate_condition_config(hass: HomeAssistant,
                                          config: ConfigType) -> ConfigType:
    """Validate config."""
    config = CONDITION_SCHEMA(config)

    # We return early if the config entry for this device is not ready because we can't
    # validate the value without knowing the state of the device
    try:
        device_config_entry_not_loaded = async_is_device_config_entry_not_loaded(
            hass, config[CONF_DEVICE_ID])
    except ValueError as err:
        raise InvalidDeviceAutomationConfig(
            f"Device {config[CONF_DEVICE_ID]} not found") from err

    if device_config_entry_not_loaded:
        return config

    if config[CONF_TYPE] == VALUE_TYPE:
        try:
            node = async_get_node_from_device_id(hass, config[CONF_DEVICE_ID])
            get_zwave_value_from_config(node, config)
        except vol.Invalid as err:
            raise InvalidDeviceAutomationConfig(err.msg) from err

    return config
Ejemplo n.º 2
0
async def async_attach_trigger(
    hass: "HomeAssistant",
    config: ConfigType,
    action: "AutomationActionType",
    automation_info: "AutomationTriggerInfo",
) -> CALLBACK_TYPE:
    """Listen for state changes based on configuration."""
    device_id = config[CONF_DEVICE_ID]
    # lookup device in HASS DeviceRegistry
    dev_reg: dr.DeviceRegistry = dr.async_get(hass)
    device_entry = dev_reg.async_get(device_id)
    if device_entry is None:
        raise InvalidDeviceAutomationConfig(
            f"Device ID {device_id} is not valid")

    for conf_entry_id in device_entry.config_entries:
        if conf_entry_id not in hass.data[DOMAIN]:
            continue
        bridge: "HueBridge" = hass.data[DOMAIN][conf_entry_id]
        if bridge.api_version == 1:
            return await async_attach_trigger_v1(bridge, device_entry, config,
                                                 action, automation_info)
        return await async_attach_trigger_v2(bridge, device_entry, config,
                                             action, automation_info)
    raise InvalidDeviceAutomationConfig(
        f"Device ID {device_id} is not found on any Hue bridge")
Ejemplo n.º 3
0
async def async_validate_trigger_config(hass: HomeAssistant,
                                        config: ConfigType) -> ConfigType:
    """Validate config."""
    config = TRIGGER_SCHEMA(config)

    # We return early if the config entry for this device is not ready because we can't
    # validate the value without knowing the state of the device
    try:
        bypass_dynamic_config_validation = async_bypass_dynamic_config_validation(
            hass, config[CONF_DEVICE_ID])
    except ValueError as err:
        raise InvalidDeviceAutomationConfig(
            f"Device {config[CONF_DEVICE_ID]} not found") from err

    if bypass_dynamic_config_validation:
        return config

    trigger_type = config[CONF_TYPE]
    if get_trigger_platform_from_type(
            trigger_type) == VALUE_UPDATED_PLATFORM_TYPE:
        try:
            node = async_get_node_from_device_id(hass, config[CONF_DEVICE_ID])
            get_zwave_value_from_config(node, config)
        except vol.Invalid as err:
            raise InvalidDeviceAutomationConfig(err.msg) from err

    return config
Ejemplo n.º 4
0
async def async_validate_trigger_config(hass, config):
    """Validate config."""
    config = TRIGGER_SCHEMA(config)

    device_registry = await hass.helpers.device_registry.async_get_registry()
    device = device_registry.async_get(config[CONF_DEVICE_ID])

    trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])

    if (
        not device
        or device.model not in REMOTES
        or trigger not in REMOTES[device.model]
    ):
        if not device:
            raise InvalidDeviceAutomationConfig(
                f"deCONZ trigger {trigger} device with id "
                f"{config[CONF_DEVICE_ID]} not found"
            )
        raise InvalidDeviceAutomationConfig(
            f"deCONZ trigger {trigger} is not valid for device "
            f"{device} ({config[CONF_DEVICE_ID]})"
        )

    return config
async def async_validate_trigger_config(
    hass: HomeAssistant,
    config: dict[str, Any],
) -> vol.Schema:
    """Validate config."""
    config = TRIGGER_SCHEMA(config)

    device_registry = dr.async_get(hass)
    device = device_registry.async_get(config[CONF_DEVICE_ID])

    trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])

    if not device:
        raise InvalidDeviceAutomationConfig(
            f"deCONZ trigger {trigger} device with ID "
            f"{config[CONF_DEVICE_ID]} not found"
        )

    if device.model not in REMOTES or trigger not in REMOTES[device.model]:
        raise InvalidDeviceAutomationConfig(
            f"deCONZ trigger {trigger} is not valid for device "
            f"{device} ({config[CONF_DEVICE_ID]})"
        )

    return config
Ejemplo n.º 6
0
def async_get_device_trigger_types(hass: HomeAssistant,
                                   nest_device_id: str) -> list[str]:
    """List event triggers supported for a Nest device."""
    device_manager: DeviceManager = hass.data[DOMAIN][DATA_DEVICE_MANAGER]
    if not (nest_device := device_manager.devices.get(nest_device_id)):
        raise InvalidDeviceAutomationConfig(
            f"Nest device not found {nest_device_id}")
Ejemplo n.º 7
0
async def async_get_triggers(hass: HomeAssistant,
                             device_id: str) -> list[dict[str, str]]:
    """List device triggers for lutron caseta devices."""
    triggers = []

    if not (device := get_button_device_by_dr_id(hass, device_id)):
        raise InvalidDeviceAutomationConfig(f"Device not found: {device_id}")
Ejemplo n.º 8
0
async def async_get_condition_capabilities(
        hass: HomeAssistant, config: ConfigType) -> dict[str, vol.Schema]:
    """List condition capabilities."""
    try:
        unit_of_measurement = get_unit_of_measurement(hass,
                                                      config[CONF_ENTITY_ID])
    except HomeAssistantError:
        unit_of_measurement = None

    if not unit_of_measurement:
        raise InvalidDeviceAutomationConfig(
            "No unit of measurement found for condition entity {config[CONF_ENTITY_ID]}"
        )

    return {
        "extra_fields":
        vol.Schema({
            vol.Optional(CONF_ABOVE,
                         description={"suffix": unit_of_measurement}):
            vol.Coerce(float),
            vol.Optional(CONF_BELOW,
                         description={"suffix": unit_of_measurement}):
            vol.Coerce(float),
        })
    }
Ejemplo n.º 9
0
async def async_attach_trigger(hass, config, action, automation_info):
    """Listen for state changes based on configuration."""
    device_registry = await hass.helpers.device_registry.async_get_registry()
    device = device_registry.async_get(config[CONF_DEVICE_ID])

    trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])

    trigger = REMOTES[device.model][trigger]

    deconz_event = _get_deconz_event_from_device_id(hass, device.id)
    if deconz_event is None:
        raise InvalidDeviceAutomationConfig(
            f'No deconz_event tied to device "{device.name}" found')

    event_id = deconz_event.serial

    event_config = {
        event_trigger.CONF_PLATFORM: "event",
        event_trigger.CONF_EVENT_TYPE: CONF_DECONZ_EVENT,
        event_trigger.CONF_EVENT_DATA: {
            CONF_UNIQUE_ID: event_id,
            **trigger
        },
    }

    event_config = event_trigger.TRIGGER_SCHEMA(event_config)
    return await event_trigger.async_attach_trigger(hass,
                                                    event_config,
                                                    action,
                                                    automation_info,
                                                    platform_type="device")
Ejemplo n.º 10
0
async def async_get_triggers(hass: HomeAssistant,
                             device_id: str) -> list[dict[str, Any]]:
    """List device triggers for Shelly devices."""
    triggers = []

    wrapper = get_device_wrapper(hass, device_id)
    if not wrapper:
        raise InvalidDeviceAutomationConfig(f"Device not found: {device_id}")

    if wrapper.model in SHBTN_MODELS:
        for trigger in SHBTN_INPUTS_EVENTS_TYPES:
            triggers.append({
                CONF_PLATFORM: "device",
                CONF_DEVICE_ID: device_id,
                CONF_DOMAIN: DOMAIN,
                CONF_TYPE: trigger,
                CONF_SUBTYPE: "button",
            })
        return triggers

    for block in wrapper.device.blocks:
        input_triggers = get_input_triggers(wrapper.device, block)

        for trigger, subtype in input_triggers:
            triggers.append({
                CONF_PLATFORM: "device",
                CONF_DEVICE_ID: device_id,
                CONF_DOMAIN: DOMAIN,
                CONF_TYPE: trigger,
                CONF_SUBTYPE: subtype,
            })

    return triggers
Ejemplo n.º 11
0
async def async_validate_trigger_config(
        hass: HomeAssistant, config: dict[str, Any]) -> dict[str, Any]:
    """Validate config."""
    config = TRIGGER_SCHEMA(config)

    # if device is available verify parameters against device capabilities
    trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])

    if config[CONF_TYPE] in RPC_INPUTS_EVENTS_TYPES:
        rpc_wrapper = get_rpc_device_wrapper(hass, config[CONF_DEVICE_ID])
        if not rpc_wrapper or not rpc_wrapper.device.initialized:
            return config

        input_triggers = get_rpc_input_triggers(rpc_wrapper.device)
        if trigger in input_triggers:
            return config

    elif config[CONF_TYPE] in BLOCK_INPUTS_EVENTS_TYPES:
        block_wrapper = get_block_device_wrapper(hass, config[CONF_DEVICE_ID])
        if not block_wrapper or not block_wrapper.device.initialized:
            return config

        assert block_wrapper.device.blocks

        for block in block_wrapper.device.blocks:
            input_triggers = get_block_input_triggers(block_wrapper.device,
                                                      block)
            if trigger in input_triggers:
                return config

    raise InvalidDeviceAutomationConfig(
        f"Invalid ({CONF_TYPE},{CONF_SUBTYPE}): {trigger}")
Ejemplo n.º 12
0
async def async_get_trigger_capabilities(hass, config):
    """List trigger capabilities."""
    try:
        unit_of_measurement = get_unit_of_measurement(hass,
                                                      config[CONF_ENTITY_ID])
    except HomeAssistantError:
        unit_of_measurement = None

    if not unit_of_measurement:
        raise InvalidDeviceAutomationConfig(
            f"No unit of measurement found for trigger entity {config[CONF_ENTITY_ID]}"
        )

    return {
        "extra_fields":
        vol.Schema({
            vol.Optional(CONF_ABOVE,
                         description={"suffix": unit_of_measurement}):
            vol.Coerce(float),
            vol.Optional(CONF_BELOW,
                         description={"suffix": unit_of_measurement}):
            vol.Coerce(float),
            vol.Optional(CONF_FOR):
            cv.positive_time_period_dict,
        })
    }
Ejemplo n.º 13
0
async def async_get_condition_capabilities(hass, config):
    """List condition capabilities."""
    state = hass.states.get(config[CONF_ENTITY_ID])
    unit_of_measurement = (
        state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) if state else None
    )

    if not state or not unit_of_measurement:
        raise InvalidDeviceAutomationConfig(
            "No state or unit of measurement found for "
            f"condition entity {config[CONF_ENTITY_ID]}"
        )

    return {
        "extra_fields": vol.Schema(
            {
                vol.Optional(
                    CONF_ABOVE, description={"suffix": unit_of_measurement}
                ): vol.Coerce(float),
                vol.Optional(
                    CONF_BELOW, description={"suffix": unit_of_measurement}
                ): vol.Coerce(float),
            }
        )
    }
Ejemplo n.º 14
0
async def async_validate_trigger_config(bridge, device_entry, config):
    """Validate config."""
    config = TRIGGER_SCHEMA(config)
    trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])

    if not device_entry:
        raise InvalidDeviceAutomationConfig(
            f"Device {config[CONF_DEVICE_ID]} not found")

    if device_entry.model not in REMOTES:
        raise InvalidDeviceAutomationConfig(
            f"Device model {device_entry.model} is not a remote")

    if trigger not in REMOTES[device_entry.model]:
        raise InvalidDeviceAutomationConfig(
            f"Device does not support trigger {trigger}")

    return config
async def async_get_device_trigger_types(hass: HomeAssistant,
                                         nest_device_id: str) -> list[str]:
    """List event triggers supported for a Nest device."""
    # All devices should have already been loaded so any failures here are
    # "shouldn't happen" cases
    subscriber = hass.data[DOMAIN][DATA_SUBSCRIBER]
    device_manager = await subscriber.async_get_device_manager()
    if not (nest_device := device_manager.devices.get(nest_device_id)):
        raise InvalidDeviceAutomationConfig(
            f"Nest device not found {nest_device_id}")
Ejemplo n.º 16
0
async def async_validate_trigger_config(hass: HomeAssistant,
                                        config: ConfigType) -> ConfigType:
    """Validate config."""
    config = TRIGGER_SCHEMA(config)

    try:
        if async_is_device_config_entry_not_loaded(hass,
                                                   config[CONF_DEVICE_ID]):
            return config
    except ValueError as err:
        raise InvalidDeviceAutomationConfig(err) from err

    if config[CONF_TYPE] == TURN_ON_PLATFORM_TYPE:
        device_id = config[CONF_DEVICE_ID]
        try:
            device = async_get_device_entry_by_device_id(hass, device_id)
            async_get_client_wrapper_by_device_entry(hass, device)
        except ValueError as err:
            raise InvalidDeviceAutomationConfig(err) from err

    return config
Ejemplo n.º 17
0
async def async_attach_trigger(
    hass: HomeAssistant,
    config: ConfigType,
    action: AutomationActionType,
    automation_info: AutomationTriggerInfo,
) -> CALLBACK_TYPE:
    """Listen for state changes based on configuration."""
    device_id = config[CONF_DEVICE_ID]
    # lookup device in HASS DeviceRegistry
    dev_reg: dr.DeviceRegistry = dr.async_get(hass)
    if (device_entry := dev_reg.async_get(device_id)) is None:
        raise InvalidDeviceAutomationConfig(f"Device ID {device_id} is not valid")
Ejemplo n.º 18
0
async def async_validate_action_config(hass, config):
    """Validate config."""
    config = ACTION_SCHEMA(config)
    commands, _ = _get_commands(hass, config[CONF_DEVICE_ID],
                                config[CONF_TYPE])
    sub_type = config[CONF_SUBTYPE]

    if sub_type not in commands.values():
        raise InvalidDeviceAutomationConfig(
            f"Subtype {sub_type} not found in device commands {commands}")

    return config
Ejemplo n.º 19
0
async def async_validate_trigger_config(hass: HomeAssistant,
                                        config: ConfigType) -> ConfigType:
    """Validate config."""
    config = TRIGGER_SCHEMA(config)

    device_registry = dr.async_get(hass)
    device = device_registry.async_get(config[CONF_DEVICE_ID])

    if not device:
        raise InvalidDeviceAutomationConfig(
            f"Trigger invalid, device with ID {config[CONF_DEVICE_ID]} not found"
        )

    trigger = config[CONF_TYPE]

    if (not device or device.model not in DEVICES
            or trigger not in DEVICES[device.model]):
        raise InvalidDeviceAutomationConfig(
            f"Unsupported model {device.model}")

    return config
Ejemplo n.º 20
0
async def async_validate_trigger_config(hass: "HomeAssistant",
                                        config: ConfigType):
    """Validate config."""
    if DOMAIN not in hass.data:
        # happens at startup
        return config
    device_id = config[CONF_DEVICE_ID]
    # lookup device in HASS DeviceRegistry
    dev_reg: dr.DeviceRegistry = dr.async_get(hass)
    if (device_entry := dev_reg.async_get(device_id)) is None:
        raise InvalidDeviceAutomationConfig(
            f"Device ID {device_id} is not valid")
Ejemplo n.º 21
0
async def async_get_triggers(hass: HomeAssistant,
                             device_id: str) -> list[dict[str, Any]]:
    """List device triggers for a Nest device."""
    nest_device_id = await async_get_nest_device_id(hass, device_id)
    if not nest_device_id:
        raise InvalidDeviceAutomationConfig(f"Device not found {device_id}")
    trigger_types = await async_get_device_trigger_types(hass, nest_device_id)
    return [{
        CONF_PLATFORM: DEVICE,
        CONF_DEVICE_ID: device_id,
        CONF_DOMAIN: DOMAIN,
        CONF_TYPE: trigger_type,
    } for trigger_type in trigger_types]
Ejemplo n.º 22
0
async def async_validate_trigger_config(hass: HomeAssistant,
                                        config: ConfigType):
    """Validate config."""
    # if device is available verify parameters against device capabilities
    device = get_button_device_by_dr_id(hass, config[CONF_DEVICE_ID])

    if not device:
        return config

    if not (schema := DEVICE_TYPE_SCHEMA_MAP.get(device["type"])):
        raise InvalidDeviceAutomationConfig(
            f"Device type {device['type']} not supported: {config[CONF_DEVICE_ID]}"
        )
Ejemplo n.º 23
0
async def async_validate_trigger_config(hass, config):
    """Validate config."""
    config = TRIGGER_SCHEMA(config)

    device_registry = await hass.helpers.device_registry.async_get_registry()
    device = device_registry.async_get(config[CONF_DEVICE_ID])

    trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])

    if not device:
        raise InvalidDeviceAutomationConfig(
            "Device {config[CONF_DEVICE_ID]} not found")

    if device.model not in REMOTES:
        raise InvalidDeviceAutomationConfig(
            f"Device model {device.model} is not a remote")

    if trigger not in REMOTES[device.model]:
        raise InvalidDeviceAutomationConfig(
            "Device does not support trigger {trigger}")

    return config
Ejemplo n.º 24
0
def _get_deconz_event_from_device(
    hass: HomeAssistant,
    device: dr.DeviceEntry,
) -> DeconzAlarmEvent | DeconzEvent:
    """Resolve deconz event from device."""
    for gateway in hass.data.get(DOMAIN, {}).values():
        for deconz_event in gateway.events:
            if device.id == deconz_event.device_id:
                return deconz_event

    raise InvalidDeviceAutomationConfig(
        f'No deconz_event tied to device "{device.name}" found'
    )
Ejemplo n.º 25
0
async def async_validate_trigger_config(hass, config):
    """Validate config."""
    config = TRIGGER_SCHEMA(config)

    device = async_get_device_object(hass, config[CONF_DEVICE_ID])

    action_type = config[CONF_TYPE]
    sub_type = config[CONF_SUBTYPE]
    commands = getattr(device, TRIGGER_SELECTION[action_type], {})
    if config[CONF_SUBTYPE] not in commands.values():
        raise InvalidDeviceAutomationConfig(
            f"Subtype {sub_type} not found in device triggers {commands}")

    return config
Ejemplo n.º 26
0
async def async_validate_trigger_config(hass, config):
    """Validate config."""
    config = TRIGGER_SCHEMA(config)

    device_registry = await hass.helpers.device_registry.async_get_registry()
    device = device_registry.async_get(config[CONF_DEVICE_ID])

    trigger = config[CONF_TYPE]

    if (not device or device.model not in DEVICES
            or trigger not in DEVICES[device.model]):
        raise InvalidDeviceAutomationConfig(
            f"Unsupported model {device.model}")

    return config
Ejemplo n.º 27
0
async def async_validate_trigger_config(hass, config):
    """Validate config."""
    config = TRIGGER_SCHEMA(config)

    # if device is available verify parameters against device capabilities
    wrapper = get_device_wrapper(hass, config[CONF_DEVICE_ID])
    if not wrapper:
        return config

    trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])

    for block in wrapper.device.blocks:
        input_triggers = get_input_triggers(wrapper.device, block)
        if trigger in input_triggers:
            return config

    raise InvalidDeviceAutomationConfig(
        f"Invalid ({CONF_TYPE},{CONF_SUBTYPE}): {trigger}")
Ejemplo n.º 28
0
async def async_get_device_trigger_types(
    hass: HomeAssistant, nest_device_id: str
) -> List[str]:
    """List event triggers supported for a Nest device."""
    # All devices should have already been loaded so any failures here are
    # "shouldn't happen" cases
    subscriber = hass.data[DOMAIN][DATA_SUBSCRIBER]
    device_manager = await subscriber.async_get_device_manager()
    nest_device = device_manager.devices.get(nest_device_id)
    if not nest_device:
        raise InvalidDeviceAutomationConfig(f"Nest device not found {nest_device_id}")

    # Determine the set of event types based on the supported device traits
    trigger_types = []
    for trait in nest_device.traits:
        trigger_type = DEVICE_TRAIT_TRIGGER_MAP.get(trait)
        if trigger_type:
            trigger_types.append(trigger_type)
    return trigger_types
Ejemplo n.º 29
0
async def async_validate_trigger_config(hass: "HomeAssistant", config: ConfigType):
    """Validate config."""
    if DOMAIN not in hass.data:
        # happens at startup
        return config
    device_id = config[CONF_DEVICE_ID]
    # lookup device in HASS DeviceRegistry
    dev_reg: dr.DeviceRegistry = dr.async_get(hass)
    device_entry = dev_reg.async_get(device_id)
    if device_entry is None:
        raise InvalidDeviceAutomationConfig(f"Device ID {device_id} is not valid")

    for conf_entry_id in device_entry.config_entries:
        if conf_entry_id not in hass.data[DOMAIN]:
            continue
        bridge: HueBridge = hass.data[DOMAIN][conf_entry_id]
        if bridge.api_version == 1:
            return await async_validate_trigger_config_v1(bridge, device_entry, config)
        return await async_validate_trigger_config_v2(bridge, device_entry, config)
Ejemplo n.º 30
0
async def async_get_triggers(hass: HomeAssistant,
                             device_id: str) -> list[dict[str, Any]]:
    """List device triggers for lutron caseta devices."""
    triggers = []

    device = get_button_device_by_dr_id(hass, device_id)
    if not device:
        raise InvalidDeviceAutomationConfig(f"Device not found: {device_id}")

    valid_buttons = DEVICE_TYPE_SUBTYPE_MAP.get(device["type"], [])

    for trigger in SUPPORTED_INPUTS_EVENTS_TYPES:
        for subtype in valid_buttons:
            triggers.append({
                CONF_PLATFORM: "device",
                CONF_DEVICE_ID: device_id,
                CONF_DOMAIN: DOMAIN,
                CONF_TYPE: trigger,
                CONF_SUBTYPE: subtype,
            })

    return triggers