Skip to content

Commit

Permalink
Merge pull request #351 from astrandb/DeviceAutomations
Browse files Browse the repository at this point in the history
Add device automation triggers and conditions
  • Loading branch information
astrandb authored Oct 29, 2023
2 parents 6b3420b + 0a8dd01 commit b134f8d
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 4 deletions.
70 changes: 70 additions & 0 deletions custom_components/miele/device_condition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""Provide the device conditions for Miele integration."""
from __future__ import annotations

import voluptuous as vol

from homeassistant.const import (
ATTR_ENTITY_ID,
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,
entity_registry as er,
)
from homeassistant.helpers.typing import ConfigType, TemplateVarsType

from .const import DOMAIN, STATE_STATUS

CONDITION_TYPES = list(STATE_STATUS.values())

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, str]]:
"""List device conditions for miele devices."""
registry = er.async_get(hass)
conditions = []

# Get all the integrations entities for this device
for entry in er.async_entries_for_device(registry, device_id):
if entry.translation_key == "status":
# Add conditions for each entity that belongs to this integration
base_condition = {
CONF_CONDITION: "device",
CONF_DEVICE_ID: device_id,
CONF_DOMAIN: DOMAIN,
CONF_ENTITY_ID: entry.entity_id,
}
conditions += [
{**base_condition, CONF_TYPE: cond} for cond in CONDITION_TYPES
]

return conditions


@callback
def async_condition_from_config(
hass: HomeAssistant, config: ConfigType
) -> condition.ConditionCheckerType:
"""Create a function to test a device condition."""
state = config[CONF_TYPE]

@callback
def test_is_state(hass: HomeAssistant, variables: TemplateVarsType) -> bool:
"""Test if an entity is a certain state."""
return condition.state(hass, config[ATTR_ENTITY_ID], state)

return test_is_state
74 changes: 74 additions & 0 deletions custom_components/miele/device_trigger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"""Provides device triggers for miele 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 state as state_trigger
from homeassistant.const import (
CONF_DEVICE_ID,
CONF_DOMAIN,
CONF_ENTITY_ID,
CONF_PLATFORM,
CONF_TYPE,
)
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
from homeassistant.helpers import config_validation as cv, entity_registry as er
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
from homeassistant.helpers.typing import ConfigType

from .const import DOMAIN, STATE_STATUS

TRIGGER_TYPES = list(STATE_STATUS.values())

TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
{
vol.Required(CONF_ENTITY_ID): cv.entity_id,
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 Miele devices."""
registry = er.async_get(hass)
triggers = []

# Get all the integrations entities for this device
for entry in er.async_entries_for_device(registry, device_id):
if entry.translation_key == "status":
# Add triggers for each entity that belongs to this integration
base_trigger = {
CONF_PLATFORM: "device",
CONF_DEVICE_ID: device_id,
CONF_DOMAIN: DOMAIN,
CONF_ENTITY_ID: entry.entity_id,
}
for state_value in TRIGGER_TYPES:
triggers.append({**base_trigger, CONF_TYPE: state_value})

return triggers


async def async_attach_trigger(
hass: HomeAssistant,
config: ConfigType,
action: TriggerActionType,
trigger_info: TriggerInfo,
) -> CALLBACK_TYPE:
"""Attach a trigger."""

to_state = config[CONF_TYPE]
state_config = {
state_trigger.CONF_PLATFORM: "state",
CONF_ENTITY_ID: config[CONF_ENTITY_ID],
state_trigger.CONF_TO: to_state,
}
state_config = await state_trigger.async_validate_trigger_config(hass, state_config)
return await state_trigger.async_attach_trigger(
hass, state_config, action, trigger_info, platform_type="device"
)
48 changes: 44 additions & 4 deletions custom_components/miele/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,46 @@
}
}
},
"device_automation": {
"condition_type": {
"failure": "{entity_name} is failing",
"idle": "{entity_name} is idle",
"not_connected": "{entity_name} is not connected",
"off": "{entity_name} is off",
"on": "{entity_name} is on",
"pause": "{entity_name} is pausing",
"program_ended": "{entity_name} has ended program",
"program_interrupted": "{entity_name} has interrupted program",
"programmed": "{entity_name} is programmed",
"rinse_hold": "{entity_name} is in rinse hold",
"running": "{entity_name} is running",
"service": "{entity_name} is in service",
"supercooling": "{entity_name} is supercooling",
"supercooling_superfreezing": "{entity_name} is supercooling/superheating",
"superfreezing": "{entity_name} is superfreezing",
"superheating": "{entity_name} is superheating",
"waiting_to_start": "{entity_name} is waiting to start"
},
"trigger_type": {
"failure": "{entity_name} Failure",
"idle": "{entity_name} Idle",
"not_connected": "{entity_name} Not connected",
"off": "{entity_name} Off",
"on": "{entity_name} On",
"pause": "{entity_name} Pause",
"program_ended": "{entity_name} Program ended",
"program_interrupted": "{entity_name} Program interrupted",
"programmed": "{entity_name} Programmed",
"rinse_hold": "{entity_name} Rinse hold",
"running": "{entity_name} Running",
"service": "{entity_name} Service",
"supercooling_superfreezing": "{entity_name} Supercooling/superheating",
"supercooling": "{entity_name} Supercooling",
"superfreezing": "{entity_name} Superfreezing",
"superheating": "{entity_name} Superheating",
"waiting_to_start": "{entity_name} Waiting to start"
}
},
"entity": {
"binary_sensor": {
"door": {
Expand Down Expand Up @@ -169,7 +209,7 @@
"descaling": "Appliance descaling",
"down_duvets": "Down duvets",
"down_filled_items": "Down-filled items",
"drain_spin": "Drain\/spin",
"drain_spin": "Drain/spin",
"eco": "ECO",
"eco_40_60": "ECO 40-60",
"eco_fan_heat": "Eco fan heat",
Expand Down Expand Up @@ -217,7 +257,7 @@
"rinse": "Rinse",
"rinse_out_lint": "Rinse out lint",
"ristretto": "Ristretto",
"separate_rinse_starch": "Separate rinse\/starch",
"separate_rinse_starch": "Separate rinse/starch",
"shirts": "Shirts",
"silent": "Silent",
"silks": "Silks",
Expand Down Expand Up @@ -319,7 +359,7 @@
"name": "Program type",
"state": {
"automatic_program": "Automatic program",
"cleaning_care_program": "Cleaning\/care program",
"cleaning_care_program": "Cleaning/care program",
"maintenance_program": "Maintenance program",
"normal_operation_mode": "Normal operation mode",
"own_program": "Own program"
Expand Down Expand Up @@ -356,7 +396,7 @@
"running": "Running",
"service": "Service",
"supercooling": "Supercooling",
"supercooling_superfreezing": "Supercooling\/superfreezing",
"supercooling_superfreezing": "Supercooling/superfreezing",
"superfreezing": "Superfreezing",
"superheating": "Superheating",
"waiting_to_start": "Waiting to start"
Expand Down

0 comments on commit b134f8d

Please sign in to comment.