core/homeassistant/helpers/state.py

96 lines
2.5 KiB
Python
Raw Normal View History

"""Helpers that help with state related things."""
2021-03-17 17:34:19 +00:00
from __future__ import annotations
import asyncio
from collections import defaultdict
from collections.abc import Iterable
2015-03-16 06:36:42 +00:00
import logging
from types import ModuleType
from typing import Any
2015-03-16 06:36:42 +00:00
2019-07-31 19:25:30 +00:00
from homeassistant.components.sun import STATE_ABOVE_HORIZON, STATE_BELOW_HORIZON
2015-03-17 06:32:18 +00:00
from homeassistant.const import (
2019-07-31 19:25:30 +00:00
STATE_CLOSED,
STATE_HOME,
STATE_LOCKED,
STATE_NOT_HOME,
STATE_OFF,
STATE_ON,
STATE_OPEN,
STATE_UNKNOWN,
STATE_UNLOCKED,
)
from homeassistant.core import Context, HomeAssistant, State
from homeassistant.loader import IntegrationNotFound, async_get_integration, bind_hass
2015-03-16 06:36:42 +00:00
_LOGGER = logging.getLogger(__name__)
@bind_hass
async def async_reproduce_state(
hass: HomeAssistant,
2021-03-17 17:34:19 +00:00
states: State | Iterable[State],
*,
2021-03-17 17:34:19 +00:00
context: Context | None = None,
reproduce_options: dict[str, Any] | None = None,
2019-07-31 19:25:30 +00:00
) -> None:
"""Reproduce a list of states on multiple domains."""
2015-03-16 06:36:42 +00:00
if isinstance(states, State):
states = [states]
2021-03-17 17:34:19 +00:00
to_call: dict[str, list[State]] = defaultdict(list)
for state in states:
to_call[state.domain].append(state)
2021-03-17 17:34:19 +00:00
async def worker(domain: str, states_by_domain: list[State]) -> None:
try:
integration = await async_get_integration(hass, domain)
except IntegrationNotFound:
_LOGGER.warning(
"Trying to reproduce state for unknown integration: %s", domain
)
return
try:
platform: ModuleType = integration.get_platform("reproduce_state")
except ImportError:
_LOGGER.warning("Integration %s does not support reproduce state", domain)
return
await platform.async_reproduce_states(
hass, states_by_domain, context=context, reproduce_options=reproduce_options
)
if to_call:
# run all domains in parallel
2019-07-31 19:25:30 +00:00
await asyncio.gather(
*(worker(domain, data) for domain, data in to_call.items())
)
def state_as_number(state: State) -> float:
"""Try to coerce our state to a number.
Raises ValueError if this is not possible.
"""
2019-07-31 19:25:30 +00:00
if state.state in (
STATE_ON,
STATE_LOCKED,
STATE_ABOVE_HORIZON,
STATE_OPEN,
STATE_HOME,
):
return 1
2019-07-31 19:25:30 +00:00
if state.state in (
STATE_OFF,
STATE_UNLOCKED,
STATE_UNKNOWN,
STATE_BELOW_HORIZON,
STATE_CLOSED,
STATE_NOT_HOME,
):
return 0
return float(state.state)