Make helpers.condition.* async
This commit is contained in:
parent
33a51623f8
commit
185bd6c28a
1 changed files with 78 additions and 23 deletions
|
@ -20,15 +20,43 @@ import homeassistant.util.dt as dt_util
|
|||
from homeassistant.util.async import run_callback_threadsafe
|
||||
|
||||
FROM_CONFIG_FORMAT = '{}_from_config'
|
||||
ASYNC_FROM_CONFIG_FORMAT = 'async_{}_from_config'
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# PyLint does not like the use of _threaded_factory
|
||||
# pylint: disable=invalid-name
|
||||
|
||||
def from_config(config: ConfigType, config_validation: bool=True):
|
||||
"""Turn a condition configuration into a method."""
|
||||
factory = getattr(
|
||||
sys.modules[__name__],
|
||||
FROM_CONFIG_FORMAT.format(config.get(CONF_CONDITION)), None)
|
||||
|
||||
def _threaded_factory(async_factory):
|
||||
"""Helper method to create threaded versions of async factories."""
|
||||
def factory(config, config_validation=True):
|
||||
"""Threaded factory."""
|
||||
async_check = async_factory(config, config_validation)
|
||||
|
||||
def condition_if(hass, variables=None):
|
||||
"""Validate condition."""
|
||||
return run_callback_threadsafe(
|
||||
hass.loop, async_check, hass, variables,
|
||||
).result()
|
||||
|
||||
return condition_if
|
||||
|
||||
return factory
|
||||
|
||||
|
||||
def async_from_config(config: ConfigType, config_validation: bool=True):
|
||||
"""Turn a condition configuration into a method.
|
||||
|
||||
Should be run on the event loop.
|
||||
"""
|
||||
for fmt in (ASYNC_FROM_CONFIG_FORMAT, FROM_CONFIG_FORMAT):
|
||||
factory = getattr(
|
||||
sys.modules[__name__],
|
||||
fmt.format(config.get(CONF_CONDITION)), None)
|
||||
|
||||
if factory:
|
||||
break
|
||||
|
||||
if factory is None:
|
||||
raise HomeAssistantError('Invalid condition "{}" specified {}'.format(
|
||||
|
@ -37,49 +65,70 @@ def from_config(config: ConfigType, config_validation: bool=True):
|
|||
return factory(config, config_validation)
|
||||
|
||||
|
||||
def and_from_config(config: ConfigType, config_validation: bool=True):
|
||||
from_config = _threaded_factory(async_from_config)
|
||||
|
||||
|
||||
def async_and_from_config(config: ConfigType, config_validation: bool=True):
|
||||
"""Create multi condition matcher using 'AND'."""
|
||||
if config_validation:
|
||||
config = cv.AND_CONDITION_SCHEMA(config)
|
||||
checks = [from_config(entry, False) for entry in config['conditions']]
|
||||
checks = None
|
||||
|
||||
def if_and_condition(hass: HomeAssistant,
|
||||
variables=None) -> bool:
|
||||
"""Test and condition."""
|
||||
for check in checks:
|
||||
try:
|
||||
nonlocal checks
|
||||
|
||||
if checks is None:
|
||||
checks = [async_from_config(entry, False) for entry
|
||||
in config['conditions']]
|
||||
|
||||
try:
|
||||
for check in checks:
|
||||
if not check(hass, variables):
|
||||
return False
|
||||
except Exception as ex: # pylint: disable=broad-except
|
||||
_LOGGER.warning('Error during and-condition: %s', ex)
|
||||
return False
|
||||
except Exception as ex: # pylint: disable=broad-except
|
||||
_LOGGER.warning('Error during and-condition: %s', ex)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
return if_and_condition
|
||||
|
||||
|
||||
def or_from_config(config: ConfigType, config_validation: bool=True):
|
||||
and_from_config = _threaded_factory(async_and_from_config)
|
||||
|
||||
|
||||
def async_or_from_config(config: ConfigType, config_validation: bool=True):
|
||||
"""Create multi condition matcher using 'OR'."""
|
||||
if config_validation:
|
||||
config = cv.OR_CONDITION_SCHEMA(config)
|
||||
checks = [from_config(entry, False) for entry in config['conditions']]
|
||||
checks = None
|
||||
|
||||
def if_or_condition(hass: HomeAssistant,
|
||||
variables=None) -> bool:
|
||||
"""Test and condition."""
|
||||
for check in checks:
|
||||
try:
|
||||
nonlocal checks
|
||||
|
||||
if checks is None:
|
||||
checks = [async_from_config(entry, False) for entry
|
||||
in config['conditions']]
|
||||
|
||||
try:
|
||||
for check in checks:
|
||||
if check(hass, variables):
|
||||
return True
|
||||
except Exception as ex: # pylint: disable=broad-except
|
||||
_LOGGER.warning('Error during or-condition: %s', ex)
|
||||
except Exception as ex: # pylint: disable=broad-except
|
||||
_LOGGER.warning('Error during or-condition: %s', ex)
|
||||
|
||||
return False
|
||||
|
||||
return if_or_condition
|
||||
|
||||
|
||||
or_from_config = _threaded_factory(async_or_from_config)
|
||||
|
||||
|
||||
# pylint: disable=too-many-arguments
|
||||
def numeric_state(hass: HomeAssistant, entity, below=None, above=None,
|
||||
value_template=None, variables=None):
|
||||
|
@ -125,7 +174,7 @@ def async_numeric_state(hass: HomeAssistant, entity, below=None, above=None,
|
|||
return True
|
||||
|
||||
|
||||
def numeric_state_from_config(config, config_validation=True):
|
||||
def async_numeric_state_from_config(config, config_validation=True):
|
||||
"""Wrap action method with state based condition."""
|
||||
if config_validation:
|
||||
config = cv.NUMERIC_STATE_CONDITION_SCHEMA(config)
|
||||
|
@ -139,12 +188,15 @@ def numeric_state_from_config(config, config_validation=True):
|
|||
if value_template is not None:
|
||||
value_template.hass = hass
|
||||
|
||||
return numeric_state(hass, entity_id, below, above, value_template,
|
||||
variables)
|
||||
return async_numeric_state(
|
||||
hass, entity_id, below, above, value_template, variables)
|
||||
|
||||
return if_numeric_state
|
||||
|
||||
|
||||
numeric_state_from_config = _threaded_factory(async_numeric_state_from_config)
|
||||
|
||||
|
||||
def state(hass, entity, req_state, for_period=None):
|
||||
"""Test if state matches requirements."""
|
||||
if isinstance(entity, str):
|
||||
|
@ -235,7 +287,7 @@ def async_template(hass, value_template, variables=None):
|
|||
return value.lower() == 'true'
|
||||
|
||||
|
||||
def template_from_config(config, config_validation=True):
|
||||
def async_template_from_config(config, config_validation=True):
|
||||
"""Wrap action method with state based condition."""
|
||||
if config_validation:
|
||||
config = cv.TEMPLATE_CONDITION_SCHEMA(config)
|
||||
|
@ -245,11 +297,14 @@ def template_from_config(config, config_validation=True):
|
|||
"""Validate template based if-condition."""
|
||||
value_template.hass = hass
|
||||
|
||||
return template(hass, value_template, variables)
|
||||
return async_template(hass, value_template, variables)
|
||||
|
||||
return template_if
|
||||
|
||||
|
||||
template_from_config = _threaded_factory(async_template_from_config)
|
||||
|
||||
|
||||
def time(before=None, after=None, weekday=None):
|
||||
"""Test if local time condition matches.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue