core/homeassistant/components/zwave_js/services.py

140 lines
5.2 KiB
Python
Raw Normal View History

Add zwave_js.set_config_parameter service (#46673) * create zwave_js.set_config_value service * update docstring * PR comments * make proposed changes * handle providing a label for the new value * fix docstring * use new library function * config param endpoint is always 0 * corresponding changes from upstream PR * bug fixes and add tests * create zwave_js.set_config_value service * update docstring * PR comments * make proposed changes * handle providing a label for the new value * fix docstring * use new library function * config param endpoint is always 0 * corresponding changes from upstream PR * bug fixes and add tests * use lambda to avoid extra function * add services description file * bring back the missing selector * move helper functions to helper file for reuse * allow target selector for automation editor * formatting * fix service schema * update docstrings * raise error in service if call to set value is unsuccessful * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * remove extra param to vol.Optional * switch to set over list for nodes * switch to set over list for nodes Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com> Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2021-02-23 16:35:11 +00:00
"""Methods and classes related to executing Z-Wave commands and publishing these to hass."""
import logging
from typing import Dict, Set, Union
import voluptuous as vol
from zwave_js_server.model.node import Node as ZwaveNode
from zwave_js_server.util.node import async_set_config_parameter
from homeassistant.const import ATTR_DEVICE_ID, ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant, ServiceCall, callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.entity_registry import EntityRegistry
Add zwave_js.set_config_parameter service (#46673) * create zwave_js.set_config_value service * update docstring * PR comments * make proposed changes * handle providing a label for the new value * fix docstring * use new library function * config param endpoint is always 0 * corresponding changes from upstream PR * bug fixes and add tests * create zwave_js.set_config_value service * update docstring * PR comments * make proposed changes * handle providing a label for the new value * fix docstring * use new library function * config param endpoint is always 0 * corresponding changes from upstream PR * bug fixes and add tests * use lambda to avoid extra function * add services description file * bring back the missing selector * move helper functions to helper file for reuse * allow target selector for automation editor * formatting * fix service schema * update docstrings * raise error in service if call to set value is unsuccessful * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * remove extra param to vol.Optional * switch to set over list for nodes * switch to set over list for nodes Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com> Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2021-02-23 16:35:11 +00:00
from . import const
from .helpers import async_get_node_from_device_id, async_get_node_from_entity_id
_LOGGER = logging.getLogger(__name__)
def parameter_name_does_not_need_bitmask(
val: Dict[str, Union[int, str]]
) -> Dict[str, Union[int, str]]:
"""Validate that if a parameter name is provided, bitmask is not as well."""
if isinstance(val[const.ATTR_CONFIG_PARAMETER], str) and (
val.get(const.ATTR_CONFIG_PARAMETER_BITMASK)
):
raise vol.Invalid(
"Don't include a bitmask when a parameter name is specified",
path=[const.ATTR_CONFIG_PARAMETER, const.ATTR_CONFIG_PARAMETER_BITMASK],
)
return val
# Validates that a bitmask is provided in hex form and converts it to decimal
# int equivalent since that's what the library uses
BITMASK_SCHEMA = vol.All(
cv.string, vol.Lower, vol.Match(r"^(0x)?[0-9a-f]+$"), lambda value: int(value, 16)
)
class ZWaveServices:
"""Class that holds our services (Zwave Commands) that should be published to hass."""
def __init__(self, hass: HomeAssistant, ent_reg: EntityRegistry):
Add zwave_js.set_config_parameter service (#46673) * create zwave_js.set_config_value service * update docstring * PR comments * make proposed changes * handle providing a label for the new value * fix docstring * use new library function * config param endpoint is always 0 * corresponding changes from upstream PR * bug fixes and add tests * create zwave_js.set_config_value service * update docstring * PR comments * make proposed changes * handle providing a label for the new value * fix docstring * use new library function * config param endpoint is always 0 * corresponding changes from upstream PR * bug fixes and add tests * use lambda to avoid extra function * add services description file * bring back the missing selector * move helper functions to helper file for reuse * allow target selector for automation editor * formatting * fix service schema * update docstrings * raise error in service if call to set value is unsuccessful * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * remove extra param to vol.Optional * switch to set over list for nodes * switch to set over list for nodes Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com> Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2021-02-23 16:35:11 +00:00
"""Initialize with hass object."""
self._hass = hass
self._ent_reg = ent_reg
Add zwave_js.set_config_parameter service (#46673) * create zwave_js.set_config_value service * update docstring * PR comments * make proposed changes * handle providing a label for the new value * fix docstring * use new library function * config param endpoint is always 0 * corresponding changes from upstream PR * bug fixes and add tests * create zwave_js.set_config_value service * update docstring * PR comments * make proposed changes * handle providing a label for the new value * fix docstring * use new library function * config param endpoint is always 0 * corresponding changes from upstream PR * bug fixes and add tests * use lambda to avoid extra function * add services description file * bring back the missing selector * move helper functions to helper file for reuse * allow target selector for automation editor * formatting * fix service schema * update docstrings * raise error in service if call to set value is unsuccessful * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * remove extra param to vol.Optional * switch to set over list for nodes * switch to set over list for nodes Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com> Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2021-02-23 16:35:11 +00:00
@callback
def async_register(self) -> None:
"""Register all our services."""
self._hass.services.async_register(
const.DOMAIN,
const.SERVICE_SET_CONFIG_PARAMETER,
self.async_set_config_parameter,
schema=vol.All(
{
vol.Optional(ATTR_DEVICE_ID): vol.All(cv.ensure_list, [cv.string]),
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
vol.Required(const.ATTR_CONFIG_PARAMETER): vol.Any(
vol.Coerce(int), cv.string
),
vol.Optional(const.ATTR_CONFIG_PARAMETER_BITMASK): vol.Any(
vol.Coerce(int), BITMASK_SCHEMA
),
vol.Required(const.ATTR_CONFIG_VALUE): vol.Any(
vol.Coerce(int), cv.string
),
},
cv.has_at_least_one_key(ATTR_DEVICE_ID, ATTR_ENTITY_ID),
parameter_name_does_not_need_bitmask,
),
)
self._hass.services.async_register(
const.DOMAIN,
const.SERVICE_REFRESH_VALUE,
self.async_poll_value,
schema=vol.Schema(
{
vol.Required(ATTR_ENTITY_ID): cv.entity_ids,
vol.Optional(const.ATTR_REFRESH_ALL_VALUES, default=False): bool,
}
),
)
Add zwave_js.set_config_parameter service (#46673) * create zwave_js.set_config_value service * update docstring * PR comments * make proposed changes * handle providing a label for the new value * fix docstring * use new library function * config param endpoint is always 0 * corresponding changes from upstream PR * bug fixes and add tests * create zwave_js.set_config_value service * update docstring * PR comments * make proposed changes * handle providing a label for the new value * fix docstring * use new library function * config param endpoint is always 0 * corresponding changes from upstream PR * bug fixes and add tests * use lambda to avoid extra function * add services description file * bring back the missing selector * move helper functions to helper file for reuse * allow target selector for automation editor * formatting * fix service schema * update docstrings * raise error in service if call to set value is unsuccessful * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/zwave_js/services.yaml Co-authored-by: Franck Nijhof <frenck@frenck.nl> * remove extra param to vol.Optional * switch to set over list for nodes * switch to set over list for nodes Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com> Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2021-02-23 16:35:11 +00:00
async def async_set_config_parameter(self, service: ServiceCall) -> None:
"""Set a config value on a node."""
nodes: Set[ZwaveNode] = set()
if ATTR_ENTITY_ID in service.data:
nodes |= {
async_get_node_from_entity_id(self._hass, entity_id)
for entity_id in service.data[ATTR_ENTITY_ID]
}
if ATTR_DEVICE_ID in service.data:
nodes |= {
async_get_node_from_device_id(self._hass, device_id)
for device_id in service.data[ATTR_DEVICE_ID]
}
property_or_property_name = service.data[const.ATTR_CONFIG_PARAMETER]
property_key = service.data.get(const.ATTR_CONFIG_PARAMETER_BITMASK)
new_value = service.data[const.ATTR_CONFIG_VALUE]
for node in nodes:
zwave_value = await async_set_config_parameter(
node,
new_value,
property_or_property_name,
property_key=property_key,
)
if zwave_value:
_LOGGER.info(
"Set configuration parameter %s on Node %s with value %s",
zwave_value,
node,
new_value,
)
else:
raise ValueError(
f"Unable to set configuration parameter on Node {node} with "
f"value {new_value}"
)
async def async_poll_value(self, service: ServiceCall) -> None:
"""Poll value on a node."""
for entity_id in service.data[ATTR_ENTITY_ID]:
entry = self._ent_reg.async_get(entity_id)
if entry is None or entry.platform != const.DOMAIN:
raise ValueError(
f"Entity {entity_id} is not a valid {const.DOMAIN} entity."
)
async_dispatcher_send(
self._hass,
f"{const.DOMAIN}_{entry.unique_id}_poll_value",
service.data[const.ATTR_REFRESH_ALL_VALUES],
)