> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/home-assistant/core/llms.txt
> Use this file to discover all available pages before exploring further.

# Device Automation

> Learn how to implement device triggers, conditions, and actions for Home Assistant automations

Device automation allows users to create automations based on device events, states, and actions without needing to know entity IDs. This guide covers how to implement device triggers, conditions, and actions for your integration.

## Overview

Device automation consists of three components:

* **Triggers**: Events that start an automation (e.g., "button pressed")
* **Conditions**: States that must be true for automation to run (e.g., "light is on")
* **Actions**: Things the automation can do (e.g., "turn on light")

## Benefits of Device Automation

1. **User-friendly**: Users select devices instead of entity IDs
2. **Discovery**: Automations are suggested based on available devices
3. **Type-safe**: Structured configuration prevents errors
4. **UI-first**: Fully integrated with the automation UI

## File Structure

Device automation implementations use separate files:

```
homeassistant/components/your_integration/
├── device_trigger.py      # Trigger implementation
├── device_condition.py    # Condition implementation
└── device_action.py       # Action implementation
```

## Implementing Device Triggers

Device triggers fire when specific events occur on a device.

### Basic Trigger Implementation

```python title="device_trigger.py" theme={null}
"""Provides device triggers for Your Integration."""
from __future__ import annotations

from typing import Any

import voluptuous as vol

from homeassistant.components.device_automation import DEVICE_TRIGGER_BASE_SCHEMA
from homeassistant.components.homeassistant.triggers import event as event_trigger
from homeassistant.const import (
    CONF_DEVICE_ID,
    CONF_DOMAIN,
    CONF_PLATFORM,
    CONF_TYPE,
)
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
from homeassistant.helpers import config_validation as cv, device_registry as dr
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
from homeassistant.helpers.typing import ConfigType

from .const import DOMAIN

# Define trigger types
TRIGGER_TYPE_BUTTON_PRESSED = "button_pressed"
TRIGGER_TYPE_BUTTON_RELEASED = "button_released"

TRIGGER_TYPES = {
    TRIGGER_TYPE_BUTTON_PRESSED,
    TRIGGER_TYPE_BUTTON_RELEASED,
}

# Schema for trigger configuration
TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
    {
        vol.Required(CONF_TYPE): vol.In(TRIGGER_TYPES),
    }
)


async def async_get_triggers(
    hass: HomeAssistant, device_id: str
) -> list[dict[str, Any]]:
    """List device triggers for a device."""
    device_registry = dr.async_get(hass)
    device = device_registry.async_get(device_id)
    
    if not device:
        return []
    
    # Return available triggers for this device
    triggers = []
    
    # Example: Button device supports both press and release
    if is_button_device(device):
        triggers.extend(
            [
                {
                    CONF_PLATFORM: "device",
                    CONF_DOMAIN: DOMAIN,
                    CONF_DEVICE_ID: device_id,
                    CONF_TYPE: TRIGGER_TYPE_BUTTON_PRESSED,
                },
                {
                    CONF_PLATFORM: "device",
                    CONF_DOMAIN: DOMAIN,
                    CONF_DEVICE_ID: device_id,
                    CONF_TYPE: TRIGGER_TYPE_BUTTON_RELEASED,
                },
            ]
        )
    
    return triggers


async def async_attach_trigger(
    hass: HomeAssistant,
    config: ConfigType,
    action: TriggerActionType,
    trigger_info: TriggerInfo,
) -> CALLBACK_TYPE:
    """Attach a trigger."""
    # Map the device trigger to an event trigger
    event_config = event_trigger.TRIGGER_SCHEMA(
        {
            event_trigger.CONF_PLATFORM: "event",
            event_trigger.CONF_EVENT_TYPE: f"{DOMAIN}_event",
            event_trigger.CONF_EVENT_DATA: {
                CONF_DEVICE_ID: config[CONF_DEVICE_ID],
                CONF_TYPE: config[CONF_TYPE],
            },
        }
    )
    
    return await event_trigger.async_attach_trigger(
        hass, event_config, action, trigger_info, platform_type="device"
    )


async def async_get_trigger_capabilities(
    hass: HomeAssistant, config: ConfigType
) -> dict[str, vol.Schema]:
    """List trigger capabilities."""
    # Return additional fields that can be configured
    return {
        "extra_fields": vol.Schema(
            {
                # Add optional fields like button number, etc.
            }
        )
    }


def is_button_device(device: dr.DeviceEntry) -> bool:
    """Check if device is a button."""
    # Implement logic to determine device type
    return True
```

### Firing Device Triggers

In your integration code, fire events when triggers occur:

```python title="__init__.py" theme={null}
# When a button is pressed:
hass.bus.async_fire(
    f"{DOMAIN}_event",
    {
        CONF_DEVICE_ID: device_id,
        CONF_TYPE: "button_pressed",
    },
)
```

### Trigger Types Examples

Common trigger types:

```python theme={null}
# Button triggers
TRIGGER_TYPE_BUTTON_SHORT_PRESS = "button_short_press"
TRIGGER_TYPE_BUTTON_LONG_PRESS = "button_long_press"
TRIGGER_TYPE_BUTTON_DOUBLE_PRESS = "button_double_press"

# Motion sensor triggers
TRIGGER_TYPE_MOTION_DETECTED = "motion_detected"
TRIGGER_TYPE_MOTION_CLEARED = "motion_cleared"

# Door/window sensor triggers
TRIGGER_TYPE_OPENED = "opened"
TRIGGER_TYPE_CLOSED = "closed"
```

## Implementing Device Conditions

Device conditions check device state in automations.

### Basic Condition Implementation

```python title="device_condition.py" theme={null}
"""Provides device conditions for Your Integration."""
from __future__ import annotations

import voluptuous as vol

from homeassistant.const import (
    CONF_CONDITION,
    CONF_DEVICE_ID,
    CONF_DOMAIN,
    CONF_ENTITY_ID,
    CONF_TYPE,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import (
    condition,
    config_validation as cv,
    device_registry as dr,
    entity_registry as er,
)
from homeassistant.helpers.typing import ConfigType

from .const import DOMAIN

# Define condition types
CONDITION_TYPE_IS_ON = "is_on"
CONDITION_TYPE_IS_OFF = "is_off"

CONDITION_TYPES = {
    CONDITION_TYPE_IS_ON,
    CONDITION_TYPE_IS_OFF,
}

# Schema for condition configuration
CONDITION_SCHEMA = cv.DEVICE_CONDITION_BASE_SCHEMA.extend(
    {
        vol.Required(CONF_ENTITY_ID): cv.entity_id,
        vol.Required(CONF_TYPE): vol.In(CONDITION_TYPES),
    }
)


async def async_get_conditions(
    hass: HomeAssistant, device_id: str
) -> list[dict[str, Any]]:
    """List device conditions for a device."""
    conditions = []
    device_registry = dr.async_get(hass)
    entity_registry = er.async_get(hass)
    
    # Get all entities for this device
    entries = er.async_entries_for_device(entity_registry, device_id)
    
    for entry in entries:
        # Only include switch entities
        if entry.domain != "switch":
            continue
        
        conditions.extend(
            [
                {
                    CONF_CONDITION: "device",
                    CONF_DEVICE_ID: device_id,
                    CONF_DOMAIN: DOMAIN,
                    CONF_ENTITY_ID: entry.entity_id,
                    CONF_TYPE: CONDITION_TYPE_IS_ON,
                },
                {
                    CONF_CONDITION: "device",
                    CONF_DEVICE_ID: device_id,
                    CONF_DOMAIN: DOMAIN,
                    CONF_ENTITY_ID: entry.entity_id,
                    CONF_TYPE: CONDITION_TYPE_IS_OFF,
                },
            ]
        )
    
    return conditions


@callback
def async_condition_from_config(
    hass: HomeAssistant, config: ConfigType
) -> condition.ConditionCheckerType:
    """Create a condition checker from config."""
    condition_type = config[CONF_TYPE]
    entity_id = config[CONF_ENTITY_ID]
    
    if condition_type == CONDITION_TYPE_IS_ON:
        state = "on"
    else:
        state = "off"
    
    @callback
    def test_is_state(hass: HomeAssistant, variables: dict = None) -> bool:
        """Test if condition is true."""
        return condition.state(hass, entity_id, state)
    
    return test_is_state


async def async_get_condition_capabilities(
    hass: HomeAssistant, config: ConfigType
) -> dict[str, vol.Schema]:
    """List condition capabilities."""
    return {}
```

## Implementing Device Actions

Device actions perform operations in automations.

### Basic Action Implementation

```python title="device_action.py" theme={null}
"""Provides device actions for Your Integration."""
from __future__ import annotations

import voluptuous as vol

from homeassistant.const import (
    CONF_DEVICE_ID,
    CONF_DOMAIN,
    CONF_ENTITY_ID,
    CONF_TYPE,
)
from homeassistant.core import Context, HomeAssistant
from homeassistant.helpers import config_validation as cv, entity_registry as er
from homeassistant.helpers.typing import ConfigType

from .const import DOMAIN

# Define action types
ACTION_TYPE_TURN_ON = "turn_on"
ACTION_TYPE_TURN_OFF = "turn_off"
ACTION_TYPE_TOGGLE = "toggle"

ACTION_TYPES = {
    ACTION_TYPE_TURN_ON,
    ACTION_TYPE_TURN_OFF,
    ACTION_TYPE_TOGGLE,
}

# Schema for action configuration
ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend(
    {
        vol.Required(CONF_TYPE): vol.In(ACTION_TYPES),
        vol.Required(CONF_ENTITY_ID): cv.entity_domain("switch"),
    }
)


async def async_get_actions(
    hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
    """List device actions for a device."""
    actions = []
    entity_registry = er.async_get(hass)
    
    # Get all entities for this device
    entries = er.async_entries_for_device(entity_registry, device_id)
    
    for entry in entries:
        # Only include switch entities
        if entry.domain != "switch":
            continue
        
        actions.extend(
            [
                {
                    CONF_DEVICE_ID: device_id,
                    CONF_DOMAIN: DOMAIN,
                    CONF_ENTITY_ID: entry.entity_id,
                    CONF_TYPE: ACTION_TYPE_TURN_ON,
                },
                {
                    CONF_DEVICE_ID: device_id,
                    CONF_DOMAIN: DOMAIN,
                    CONF_ENTITY_ID: entry.entity_id,
                    CONF_TYPE: ACTION_TYPE_TURN_OFF,
                },
                {
                    CONF_DEVICE_ID: device_id,
                    CONF_DOMAIN: DOMAIN,
                    CONF_ENTITY_ID: entry.entity_id,
                    CONF_TYPE: ACTION_TYPE_TOGGLE,
                },
            ]
        )
    
    return actions


async def async_call_action_from_config(
    hass: HomeAssistant,
    config: ConfigType,
    variables: dict,
    context: Context | None,
) -> None:
    """Execute a device action."""
    action_type = config[CONF_TYPE]
    entity_id = config[CONF_ENTITY_ID]
    
    service_data = {CONF_ENTITY_ID: entity_id}
    
    if action_type == ACTION_TYPE_TURN_ON:
        service = "turn_on"
    elif action_type == ACTION_TYPE_TURN_OFF:
        service = "turn_off"
    else:  # ACTION_TYPE_TOGGLE
        service = "toggle"
    
    await hass.services.async_call(
        "switch",
        service,
        service_data,
        blocking=True,
        context=context,
    )


async def async_get_action_capabilities(
    hass: HomeAssistant, config: ConfigType
) -> dict[str, vol.Schema]:
    """List action capabilities."""
    # Return additional fields that can be configured
    return {
        "extra_fields": vol.Schema(
            {
                # Add optional fields like brightness, color, etc.
            }
        )
    }
```

## Advanced: Entity-Based Device Automation

For simple entity-based device automation, you can use the built-in helpers:

```python title="device_trigger.py" theme={null}
"""Simplified entity-based device triggers."""
from homeassistant.components.device_automation import toggle_entity

# For binary sensors with simple on/off triggers
async def async_get_triggers(hass, device_id):
    """List device triggers."""
    return await toggle_entity.async_get_triggers(hass, device_id, "binary_sensor")

async def async_attach_trigger(hass, config, action, trigger_info):
    """Attach a trigger."""
    return await toggle_entity.async_attach_trigger(
        hass, config, action, trigger_info
    )
```

## Translations

Provide translations for device automation UI:

```json title="strings.json" theme={null}
{
  "device_automation": {
    "trigger_type": {
      "button_pressed": "Button pressed",
      "button_released": "Button released"
    },
    "condition_type": {
      "is_on": "{entity_name} is on",
      "is_off": "{entity_name} is off"
    },
    "action_type": {
      "turn_on": "Turn on {entity_name}",
      "turn_off": "Turn off {entity_name}",
      "toggle": "Toggle {entity_name}"
    }
  }
}
```

## Testing Device Automation

Test your device automation implementation:

```python title="test_device_trigger.py" theme={null}
"""Test device triggers."""
import pytest
from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.setup import async_setup_component


async def test_get_triggers(hass, device_registry, entity_registry):
    """Test we get the expected triggers."""
    # Create a test device
    config_entry = MockConfigEntry(domain="your_integration")
    device_entry = device_registry.async_get_or_create(
        config_entry_id=config_entry.entry_id,
        identifiers={("your_integration", "test-device")},
    )
    
    # Get triggers
    triggers = await async_get_device_automations(
        hass, DeviceAutomationType.TRIGGER, device_entry.id
    )
    
    # Verify triggers
    assert len(triggers) == 2
    assert triggers[0]["type"] == "button_pressed"
```

## Best Practices

### Use Clear Type Names

Choose descriptive trigger/condition/action types:

* `button_short_press` instead of `btn_sp`
* `motion_detected` instead of `motion`

### Provide Good Translations

Translations should be clear and use entity names when available:

```json theme={null}
"is_on": "{entity_name} is on"
```

### Handle Entity Registry

Always check if entities exist and handle missing entities gracefully.

### Group Related Actions

If a device supports multiple similar actions, group them logically.

### Test Thoroughly

Write tests for all trigger types, conditions, and actions.

## Common Patterns

### Multi-Button Devices

For devices with multiple buttons:

```python theme={null}
CONF_SUBTYPE = "subtype"

TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
    {
        vol.Required(CONF_TYPE): vol.In(TRIGGER_TYPES),
        vol.Required(CONF_SUBTYPE): vol.In(["button_1", "button_2", "button_3"]),
    }
)
```

### Brightness/Value Actions

For actions that accept values:

```python theme={null}
from homeassistant.components.light import ATTR_BRIGHTNESS

ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend(
    {
        vol.Required(CONF_TYPE): "set_brightness",
        vol.Required(ATTR_BRIGHTNESS): vol.All(
            vol.Coerce(int), vol.Range(min=0, max=255)
        ),
    }
)
```

## Next Steps

* [Learn about Creating Integrations](/guides/creating-integration)
* Review [existing device automation implementations](https://github.com/home-assistant/core/tree/dev/homeassistant/components)
* Read about [event triggers](https://www.home-assistant.io/docs/automation/trigger/#event-trigger)
