Improve zwave_js custom triggers and services (#67461)

* Improve zwave_js custom triggers and services

* Switch from pop to get

* Support string boolean values

* refactor and add coverage

* comments and additional assertions
This commit is contained in:
Raman Gupta 2022-03-05 03:00:31 -05:00 committed by GitHub
parent cdb463ea55
commit 9632cbeffa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 222 additions and 135 deletions

View file

@ -25,11 +25,8 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_send
from . import const
from .helpers import (
async_get_node_from_device_id,
async_get_node_from_entity_id,
async_get_nodes_from_area_id,
)
from .config_validation import BITMASK_SCHEMA, VALUE_SCHEMA
from .helpers import async_get_nodes_from_targets
_LOGGER = logging.getLogger(__name__)
@ -80,38 +77,16 @@ class ZWaveServices:
@callback
def get_nodes_from_service_data(val: dict[str, Any]) -> dict[str, Any]:
"""Get nodes set from service data."""
nodes: set[ZwaveNode] = set()
# Convert all entity IDs to nodes
for entity_id in expand_entity_ids(self._hass, val.pop(ATTR_ENTITY_ID, [])):
try:
nodes.add(
async_get_node_from_entity_id(
self._hass, entity_id, self._ent_reg, self._dev_reg
)
)
except ValueError as err:
const.LOGGER.warning(err.args[0])
val[const.ATTR_NODES] = async_get_nodes_from_targets(
self._hass, val, self._ent_reg, self._dev_reg
)
return val
# Convert all area IDs to nodes
for area_id in val.pop(ATTR_AREA_ID, []):
nodes.update(
async_get_nodes_from_area_id(
self._hass, area_id, self._ent_reg, self._dev_reg
)
)
# Convert all device IDs to nodes
for device_id in val.pop(ATTR_DEVICE_ID, []):
try:
nodes.add(
async_get_node_from_device_id(
self._hass, device_id, self._dev_reg
)
)
except ValueError as err:
const.LOGGER.warning(err.args[0])
val[const.ATTR_NODES] = nodes
@callback
def has_at_least_one_node(val: dict[str, Any]) -> dict[str, Any]:
"""Validate that at least one node is specified."""
if not val.get(const.ATTR_NODES):
raise vol.Invalid(f"No {const.DOMAIN} nodes found for given targets")
return val
@callback
@ -120,6 +95,9 @@ class ZWaveServices:
nodes: set[ZwaveNode] = val[const.ATTR_NODES]
broadcast: bool = val[const.ATTR_BROADCAST]
if not broadcast:
has_at_least_one_node(val)
# User must specify a node if they are attempting a broadcast and have more
# than one zwave-js network.
if (
@ -150,12 +128,20 @@ class ZWaveServices:
def validate_entities(val: dict[str, Any]) -> dict[str, Any]:
"""Validate entities exist and are from the zwave_js platform."""
val[ATTR_ENTITY_ID] = expand_entity_ids(self._hass, val[ATTR_ENTITY_ID])
invalid_entities = []
for entity_id in val[ATTR_ENTITY_ID]:
entry = self._ent_reg.async_get(entity_id)
if entry is None or entry.platform != const.DOMAIN:
raise vol.Invalid(
f"Entity {entity_id} is not a valid {const.DOMAIN} entity."
const.LOGGER.info(
"Entity %s is not a valid %s entity.", entity_id, const.DOMAIN
)
invalid_entities.append(entity_id)
# Remove invalid entities
val[ATTR_ENTITY_ID] = list(set(val[ATTR_ENTITY_ID]) - set(invalid_entities))
if not val[ATTR_ENTITY_ID]:
raise vol.Invalid(f"No {const.DOMAIN} entities found in service call")
return val
@ -177,10 +163,10 @@ class ZWaveServices:
vol.Coerce(int), cv.string
),
vol.Optional(const.ATTR_CONFIG_PARAMETER_BITMASK): vol.Any(
vol.Coerce(int), const.BITMASK_SCHEMA
vol.Coerce(int), BITMASK_SCHEMA
),
vol.Required(const.ATTR_CONFIG_VALUE): vol.Any(
vol.Coerce(int), const.BITMASK_SCHEMA, cv.string
vol.Coerce(int), BITMASK_SCHEMA, cv.string
),
},
cv.has_at_least_one_key(
@ -188,6 +174,7 @@ class ZWaveServices:
),
parameter_name_does_not_need_bitmask,
get_nodes_from_service_data,
has_at_least_one_node,
),
),
)
@ -211,10 +198,8 @@ class ZWaveServices:
vol.Coerce(int),
{
vol.Any(
vol.Coerce(int), const.BITMASK_SCHEMA, cv.string
): vol.Any(
vol.Coerce(int), const.BITMASK_SCHEMA, cv.string
)
vol.Coerce(int), BITMASK_SCHEMA, cv.string
): vol.Any(vol.Coerce(int), BITMASK_SCHEMA, cv.string)
},
),
},
@ -222,6 +207,7 @@ class ZWaveServices:
ATTR_DEVICE_ID, ATTR_ENTITY_ID, ATTR_AREA_ID
),
get_nodes_from_service_data,
has_at_least_one_node,
),
),
)
@ -265,16 +251,15 @@ class ZWaveServices:
vol.Coerce(int), str
),
vol.Optional(const.ATTR_ENDPOINT): vol.Coerce(int),
vol.Required(const.ATTR_VALUE): const.VALUE_SCHEMA,
vol.Required(const.ATTR_VALUE): VALUE_SCHEMA,
vol.Optional(const.ATTR_WAIT_FOR_RESULT): cv.boolean,
vol.Optional(const.ATTR_OPTIONS): {
cv.string: const.VALUE_SCHEMA
},
vol.Optional(const.ATTR_OPTIONS): {cv.string: VALUE_SCHEMA},
},
cv.has_at_least_one_key(
ATTR_DEVICE_ID, ATTR_ENTITY_ID, ATTR_AREA_ID
),
get_nodes_from_service_data,
has_at_least_one_node,
),
),
)
@ -302,10 +287,8 @@ class ZWaveServices:
vol.Coerce(int), str
),
vol.Optional(const.ATTR_ENDPOINT): vol.Coerce(int),
vol.Required(const.ATTR_VALUE): const.VALUE_SCHEMA,
vol.Optional(const.ATTR_OPTIONS): {
cv.string: const.VALUE_SCHEMA
},
vol.Required(const.ATTR_VALUE): VALUE_SCHEMA,
vol.Optional(const.ATTR_OPTIONS): {cv.string: VALUE_SCHEMA},
},
vol.Any(
cv.has_at_least_one_key(
@ -338,6 +321,7 @@ class ZWaveServices:
ATTR_DEVICE_ID, ATTR_ENTITY_ID, ATTR_AREA_ID
),
get_nodes_from_service_data,
has_at_least_one_node,
),
),
)