|
| 1 | +"""Actions for Bring! integration.""" |
| 2 | + |
| 3 | +import logging |
| 4 | +from typing import TYPE_CHECKING |
| 5 | + |
| 6 | +from bring_api import ( |
| 7 | + ActivityType, |
| 8 | + BringAuthException, |
| 9 | + BringNotificationType, |
| 10 | + BringRequestException, |
| 11 | + ReactionType, |
| 12 | +) |
| 13 | +import voluptuous as vol |
| 14 | + |
| 15 | +from homeassistant.components.event import ATTR_EVENT_TYPE |
| 16 | +from homeassistant.config_entries import ConfigEntryState |
| 17 | +from homeassistant.const import ATTR_ENTITY_ID |
| 18 | +from homeassistant.core import HomeAssistant, ServiceCall |
| 19 | +from homeassistant.exceptions import HomeAssistantError, ServiceValidationError |
| 20 | +from homeassistant.helpers import config_validation as cv, entity_registry as er |
| 21 | + |
| 22 | +from .const import ( |
| 23 | + ATTR_ACTIVITY, |
| 24 | + ATTR_REACTION, |
| 25 | + ATTR_RECEIVER, |
| 26 | + DOMAIN, |
| 27 | + SERVICE_ACTIVITY_STREAM_REACTION, |
| 28 | +) |
| 29 | +from .coordinator import BringConfigEntry |
| 30 | + |
| 31 | +_LOGGER = logging.getLogger(__name__) |
| 32 | + |
| 33 | +SERVICE_ACTIVITY_STREAM_REACTION_SCHEMA = vol.Schema( |
| 34 | + { |
| 35 | + vol.Required(ATTR_ENTITY_ID): cv.entity_id, |
| 36 | + vol.Required(ATTR_REACTION): vol.All( |
| 37 | + vol.Upper, |
| 38 | + vol.Coerce(ReactionType), |
| 39 | + ), |
| 40 | + } |
| 41 | +) |
| 42 | + |
| 43 | + |
| 44 | +def get_config_entry(hass: HomeAssistant, entry_id: str) -> BringConfigEntry: |
| 45 | + """Return config entry or raise if not found or not loaded.""" |
| 46 | + entry = hass.config_entries.async_get_entry(entry_id) |
| 47 | + if TYPE_CHECKING: |
| 48 | + assert entry |
| 49 | + if entry.state is not ConfigEntryState.LOADED: |
| 50 | + raise ServiceValidationError( |
| 51 | + translation_domain=DOMAIN, |
| 52 | + translation_key="entry_not_loaded", |
| 53 | + ) |
| 54 | + return entry |
| 55 | + |
| 56 | + |
| 57 | +def async_setup_services(hass: HomeAssistant) -> None: |
| 58 | + """Set up services for Bring! integration.""" |
| 59 | + |
| 60 | + async def async_send_activity_stream_reaction(call: ServiceCall) -> None: |
| 61 | + """Send a reaction in response to recent activity of a list member.""" |
| 62 | + |
| 63 | + if ( |
| 64 | + not (state := hass.states.get(call.data[ATTR_ENTITY_ID])) |
| 65 | + or not (entity := er.async_get(hass).async_get(call.data[ATTR_ENTITY_ID])) |
| 66 | + or not entity.config_entry_id |
| 67 | + ): |
| 68 | + raise ServiceValidationError( |
| 69 | + translation_domain=DOMAIN, |
| 70 | + translation_key="entity_not_found", |
| 71 | + translation_placeholders={ |
| 72 | + ATTR_ENTITY_ID: call.data[ATTR_ENTITY_ID], |
| 73 | + }, |
| 74 | + ) |
| 75 | + config_entry = get_config_entry(hass, entity.config_entry_id) |
| 76 | + |
| 77 | + coordinator = config_entry.runtime_data.data |
| 78 | + |
| 79 | + list_uuid = entity.unique_id.split("_")[1] |
| 80 | + |
| 81 | + activity = state.attributes[ATTR_EVENT_TYPE] |
| 82 | + |
| 83 | + reaction: ReactionType = call.data[ATTR_REACTION] |
| 84 | + |
| 85 | + if not activity: |
| 86 | + raise ServiceValidationError( |
| 87 | + translation_domain=DOMAIN, |
| 88 | + translation_key="activity_not_found", |
| 89 | + ) |
| 90 | + try: |
| 91 | + await coordinator.bring.notify( |
| 92 | + list_uuid, |
| 93 | + BringNotificationType.LIST_ACTIVITY_STREAM_REACTION, |
| 94 | + receiver=state.attributes[ATTR_RECEIVER], |
| 95 | + activity=state.attributes[ATTR_ACTIVITY], |
| 96 | + activity_type=ActivityType(activity.upper()), |
| 97 | + reaction=reaction, |
| 98 | + ) |
| 99 | + except (BringRequestException, BringAuthException) as e: |
| 100 | + raise HomeAssistantError( |
| 101 | + translation_domain=DOMAIN, |
| 102 | + translation_key="reaction_request_failed", |
| 103 | + ) from e |
| 104 | + |
| 105 | + hass.services.async_register( |
| 106 | + DOMAIN, |
| 107 | + SERVICE_ACTIVITY_STREAM_REACTION, |
| 108 | + async_send_activity_stream_reaction, |
| 109 | + SERVICE_ACTIVITY_STREAM_REACTION_SCHEMA, |
| 110 | + ) |
0 commit comments