mirror of
https://github.com/home-assistant/core.git
synced 2025-07-10 23:07:09 +00:00
Add support for area ID in zwave_js service calls (#54940)
This commit is contained in:
parent
1f6d18c517
commit
ef9ad89c23
@ -13,14 +13,7 @@ from homeassistant.config_entries import ConfigEntry
|
|||||||
from homeassistant.const import __version__ as HA_VERSION
|
from homeassistant.const import __version__ as HA_VERSION
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers.device_registry import (
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||||
DeviceRegistry,
|
|
||||||
async_get as async_get_dev_reg,
|
|
||||||
)
|
|
||||||
from homeassistant.helpers.entity_registry import (
|
|
||||||
EntityRegistry,
|
|
||||||
async_get as async_get_ent_reg,
|
|
||||||
)
|
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -79,7 +72,7 @@ def get_home_and_node_id_from_device_id(device_id: tuple[str, ...]) -> list[str]
|
|||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_get_node_from_device_id(
|
def async_get_node_from_device_id(
|
||||||
hass: HomeAssistant, device_id: str, dev_reg: DeviceRegistry | None = None
|
hass: HomeAssistant, device_id: str, dev_reg: dr.DeviceRegistry | None = None
|
||||||
) -> ZwaveNode:
|
) -> ZwaveNode:
|
||||||
"""
|
"""
|
||||||
Get node from a device ID.
|
Get node from a device ID.
|
||||||
@ -87,7 +80,7 @@ def async_get_node_from_device_id(
|
|||||||
Raises ValueError if device is invalid or node can't be found.
|
Raises ValueError if device is invalid or node can't be found.
|
||||||
"""
|
"""
|
||||||
if not dev_reg:
|
if not dev_reg:
|
||||||
dev_reg = async_get_dev_reg(hass)
|
dev_reg = dr.async_get(hass)
|
||||||
device_entry = dev_reg.async_get(device_id)
|
device_entry = dev_reg.async_get(device_id)
|
||||||
|
|
||||||
if not device_entry:
|
if not device_entry:
|
||||||
@ -138,8 +131,8 @@ def async_get_node_from_device_id(
|
|||||||
def async_get_node_from_entity_id(
|
def async_get_node_from_entity_id(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entity_id: str,
|
entity_id: str,
|
||||||
ent_reg: EntityRegistry | None = None,
|
ent_reg: er.EntityRegistry | None = None,
|
||||||
dev_reg: DeviceRegistry | None = None,
|
dev_reg: dr.DeviceRegistry | None = None,
|
||||||
) -> ZwaveNode:
|
) -> ZwaveNode:
|
||||||
"""
|
"""
|
||||||
Get node from an entity ID.
|
Get node from an entity ID.
|
||||||
@ -147,7 +140,7 @@ def async_get_node_from_entity_id(
|
|||||||
Raises ValueError if entity is invalid.
|
Raises ValueError if entity is invalid.
|
||||||
"""
|
"""
|
||||||
if not ent_reg:
|
if not ent_reg:
|
||||||
ent_reg = async_get_ent_reg(hass)
|
ent_reg = er.async_get(hass)
|
||||||
entity_entry = ent_reg.async_get(entity_id)
|
entity_entry = ent_reg.async_get(entity_id)
|
||||||
|
|
||||||
if entity_entry is None or entity_entry.platform != DOMAIN:
|
if entity_entry is None or entity_entry.platform != DOMAIN:
|
||||||
@ -159,6 +152,46 @@ def async_get_node_from_entity_id(
|
|||||||
return async_get_node_from_device_id(hass, entity_entry.device_id, dev_reg)
|
return async_get_node_from_device_id(hass, entity_entry.device_id, dev_reg)
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_get_nodes_from_area_id(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
area_id: str,
|
||||||
|
ent_reg: er.EntityRegistry | None = None,
|
||||||
|
dev_reg: dr.DeviceRegistry | None = None,
|
||||||
|
) -> set[ZwaveNode]:
|
||||||
|
"""Get nodes for all Z-Wave JS devices and entities that are in an area."""
|
||||||
|
nodes: set[ZwaveNode] = set()
|
||||||
|
if ent_reg is None:
|
||||||
|
ent_reg = er.async_get(hass)
|
||||||
|
if dev_reg is None:
|
||||||
|
dev_reg = dr.async_get(hass)
|
||||||
|
# Add devices for all entities in an area that are Z-Wave JS entities
|
||||||
|
nodes.update(
|
||||||
|
{
|
||||||
|
async_get_node_from_device_id(hass, entity.device_id, dev_reg)
|
||||||
|
for entity in er.async_entries_for_area(ent_reg, area_id)
|
||||||
|
if entity.platform == DOMAIN and entity.device_id is not None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
# Add devices in an area that are Z-Wave JS devices
|
||||||
|
for device in dr.async_entries_for_area(dev_reg, area_id):
|
||||||
|
if next(
|
||||||
|
(
|
||||||
|
config_entry_id
|
||||||
|
for config_entry_id in device.config_entries
|
||||||
|
if cast(
|
||||||
|
ConfigEntry,
|
||||||
|
hass.config_entries.async_get_entry(config_entry_id),
|
||||||
|
).domain
|
||||||
|
== DOMAIN
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
):
|
||||||
|
nodes.add(async_get_node_from_device_id(hass, device.id, dev_reg))
|
||||||
|
|
||||||
|
return nodes
|
||||||
|
|
||||||
|
|
||||||
def get_zwave_value_from_config(node: ZwaveNode, config: ConfigType) -> ZwaveValue:
|
def get_zwave_value_from_config(node: ZwaveNode, config: ConfigType) -> ZwaveValue:
|
||||||
"""Get a Z-Wave JS Value from a config."""
|
"""Get a Z-Wave JS Value from a config."""
|
||||||
endpoint = None
|
endpoint = None
|
||||||
@ -183,14 +216,14 @@ def get_zwave_value_from_config(node: ZwaveNode, config: ConfigType) -> ZwaveVal
|
|||||||
def async_get_node_status_sensor_entity_id(
|
def async_get_node_status_sensor_entity_id(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
device_id: str,
|
device_id: str,
|
||||||
ent_reg: EntityRegistry | None = None,
|
ent_reg: er.EntityRegistry | None = None,
|
||||||
dev_reg: DeviceRegistry | None = None,
|
dev_reg: dr.DeviceRegistry | None = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Get the node status sensor entity ID for a given Z-Wave JS device."""
|
"""Get the node status sensor entity ID for a given Z-Wave JS device."""
|
||||||
if not ent_reg:
|
if not ent_reg:
|
||||||
ent_reg = async_get_ent_reg(hass)
|
ent_reg = er.async_get(hass)
|
||||||
if not dev_reg:
|
if not dev_reg:
|
||||||
dev_reg = async_get_dev_reg(hass)
|
dev_reg = dr.async_get(hass)
|
||||||
device = dev_reg.async_get(device_id)
|
device = dev_reg.async_get(device_id)
|
||||||
if not device:
|
if not device:
|
||||||
raise HomeAssistantError("Invalid Device ID provided")
|
raise HomeAssistantError("Invalid Device ID provided")
|
||||||
|
@ -18,15 +18,18 @@ from zwave_js_server.util.node import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from homeassistant.components.group import expand_entity_ids
|
from homeassistant.components.group import expand_entity_ids
|
||||||
from homeassistant.const import ATTR_DEVICE_ID, ATTR_ENTITY_ID
|
from homeassistant.const import ATTR_AREA_ID, ATTR_DEVICE_ID, ATTR_ENTITY_ID
|
||||||
from homeassistant.core import HomeAssistant, ServiceCall, callback
|
from homeassistant.core import HomeAssistant, ServiceCall, callback
|
||||||
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.device_registry import DeviceRegistry
|
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
from homeassistant.helpers.entity_registry import EntityRegistry
|
|
||||||
|
|
||||||
from . import const
|
from . import const
|
||||||
from .helpers import async_get_node_from_device_id, async_get_node_from_entity_id
|
from .helpers import (
|
||||||
|
async_get_node_from_device_id,
|
||||||
|
async_get_node_from_entity_id,
|
||||||
|
async_get_nodes_from_area_id,
|
||||||
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -81,7 +84,10 @@ class ZWaveServices:
|
|||||||
"""Class that holds our services (Zwave Commands) that should be published to hass."""
|
"""Class that holds our services (Zwave Commands) that should be published to hass."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, hass: HomeAssistant, ent_reg: EntityRegistry, dev_reg: DeviceRegistry
|
self,
|
||||||
|
hass: HomeAssistant,
|
||||||
|
ent_reg: er.EntityRegistry,
|
||||||
|
dev_reg: dr.DeviceRegistry,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize with hass object."""
|
"""Initialize with hass object."""
|
||||||
self._hass = hass
|
self._hass = hass
|
||||||
@ -96,6 +102,7 @@ class ZWaveServices:
|
|||||||
def get_nodes_from_service_data(val: dict[str, Any]) -> dict[str, Any]:
|
def get_nodes_from_service_data(val: dict[str, Any]) -> dict[str, Any]:
|
||||||
"""Get nodes set from service data."""
|
"""Get nodes set from service data."""
|
||||||
nodes: set[ZwaveNode] = set()
|
nodes: set[ZwaveNode] = set()
|
||||||
|
# Convert all entity IDs to nodes
|
||||||
for entity_id in expand_entity_ids(self._hass, val.pop(ATTR_ENTITY_ID, [])):
|
for entity_id in expand_entity_ids(self._hass, val.pop(ATTR_ENTITY_ID, [])):
|
||||||
try:
|
try:
|
||||||
nodes.add(
|
nodes.add(
|
||||||
@ -105,6 +112,16 @@ class ZWaveServices:
|
|||||||
)
|
)
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
const.LOGGER.warning(err.args[0])
|
const.LOGGER.warning(err.args[0])
|
||||||
|
|
||||||
|
# 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, []):
|
for device_id in val.pop(ATTR_DEVICE_ID, []):
|
||||||
try:
|
try:
|
||||||
nodes.add(
|
nodes.add(
|
||||||
@ -170,6 +187,9 @@ class ZWaveServices:
|
|||||||
schema=vol.Schema(
|
schema=vol.Schema(
|
||||||
vol.All(
|
vol.All(
|
||||||
{
|
{
|
||||||
|
vol.Optional(ATTR_AREA_ID): vol.All(
|
||||||
|
cv.ensure_list, [cv.string]
|
||||||
|
),
|
||||||
vol.Optional(ATTR_DEVICE_ID): vol.All(
|
vol.Optional(ATTR_DEVICE_ID): vol.All(
|
||||||
cv.ensure_list, [cv.string]
|
cv.ensure_list, [cv.string]
|
||||||
),
|
),
|
||||||
@ -184,7 +204,9 @@ class ZWaveServices:
|
|||||||
vol.Coerce(int), BITMASK_SCHEMA, cv.string
|
vol.Coerce(int), BITMASK_SCHEMA, cv.string
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
cv.has_at_least_one_key(ATTR_DEVICE_ID, ATTR_ENTITY_ID),
|
cv.has_at_least_one_key(
|
||||||
|
ATTR_DEVICE_ID, ATTR_ENTITY_ID, ATTR_AREA_ID
|
||||||
|
),
|
||||||
parameter_name_does_not_need_bitmask,
|
parameter_name_does_not_need_bitmask,
|
||||||
get_nodes_from_service_data,
|
get_nodes_from_service_data,
|
||||||
),
|
),
|
||||||
@ -198,6 +220,9 @@ class ZWaveServices:
|
|||||||
schema=vol.Schema(
|
schema=vol.Schema(
|
||||||
vol.All(
|
vol.All(
|
||||||
{
|
{
|
||||||
|
vol.Optional(ATTR_AREA_ID): vol.All(
|
||||||
|
cv.ensure_list, [cv.string]
|
||||||
|
),
|
||||||
vol.Optional(ATTR_DEVICE_ID): vol.All(
|
vol.Optional(ATTR_DEVICE_ID): vol.All(
|
||||||
cv.ensure_list, [cv.string]
|
cv.ensure_list, [cv.string]
|
||||||
),
|
),
|
||||||
@ -212,7 +237,9 @@ class ZWaveServices:
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
cv.has_at_least_one_key(ATTR_DEVICE_ID, ATTR_ENTITY_ID),
|
cv.has_at_least_one_key(
|
||||||
|
ATTR_DEVICE_ID, ATTR_ENTITY_ID, ATTR_AREA_ID
|
||||||
|
),
|
||||||
get_nodes_from_service_data,
|
get_nodes_from_service_data,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -242,6 +269,9 @@ class ZWaveServices:
|
|||||||
schema=vol.Schema(
|
schema=vol.Schema(
|
||||||
vol.All(
|
vol.All(
|
||||||
{
|
{
|
||||||
|
vol.Optional(ATTR_AREA_ID): vol.All(
|
||||||
|
cv.ensure_list, [cv.string]
|
||||||
|
),
|
||||||
vol.Optional(ATTR_DEVICE_ID): vol.All(
|
vol.Optional(ATTR_DEVICE_ID): vol.All(
|
||||||
cv.ensure_list, [cv.string]
|
cv.ensure_list, [cv.string]
|
||||||
),
|
),
|
||||||
@ -258,7 +288,9 @@ class ZWaveServices:
|
|||||||
vol.Optional(const.ATTR_WAIT_FOR_RESULT): cv.boolean,
|
vol.Optional(const.ATTR_WAIT_FOR_RESULT): cv.boolean,
|
||||||
vol.Optional(const.ATTR_OPTIONS): {cv.string: VALUE_SCHEMA},
|
vol.Optional(const.ATTR_OPTIONS): {cv.string: VALUE_SCHEMA},
|
||||||
},
|
},
|
||||||
cv.has_at_least_one_key(ATTR_DEVICE_ID, ATTR_ENTITY_ID),
|
cv.has_at_least_one_key(
|
||||||
|
ATTR_DEVICE_ID, ATTR_ENTITY_ID, ATTR_AREA_ID
|
||||||
|
),
|
||||||
get_nodes_from_service_data,
|
get_nodes_from_service_data,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -271,6 +303,9 @@ class ZWaveServices:
|
|||||||
schema=vol.Schema(
|
schema=vol.Schema(
|
||||||
vol.All(
|
vol.All(
|
||||||
{
|
{
|
||||||
|
vol.Optional(ATTR_AREA_ID): vol.All(
|
||||||
|
cv.ensure_list, [cv.string]
|
||||||
|
),
|
||||||
vol.Optional(ATTR_DEVICE_ID): vol.All(
|
vol.Optional(ATTR_DEVICE_ID): vol.All(
|
||||||
cv.ensure_list, [cv.string]
|
cv.ensure_list, [cv.string]
|
||||||
),
|
),
|
||||||
@ -288,7 +323,9 @@ class ZWaveServices:
|
|||||||
vol.Optional(const.ATTR_OPTIONS): {cv.string: VALUE_SCHEMA},
|
vol.Optional(const.ATTR_OPTIONS): {cv.string: VALUE_SCHEMA},
|
||||||
},
|
},
|
||||||
vol.Any(
|
vol.Any(
|
||||||
cv.has_at_least_one_key(ATTR_DEVICE_ID, ATTR_ENTITY_ID),
|
cv.has_at_least_one_key(
|
||||||
|
ATTR_DEVICE_ID, ATTR_ENTITY_ID, ATTR_AREA_ID
|
||||||
|
),
|
||||||
broadcast_command,
|
broadcast_command,
|
||||||
),
|
),
|
||||||
get_nodes_from_service_data,
|
get_nodes_from_service_data,
|
||||||
@ -304,12 +341,17 @@ class ZWaveServices:
|
|||||||
schema=vol.Schema(
|
schema=vol.Schema(
|
||||||
vol.All(
|
vol.All(
|
||||||
{
|
{
|
||||||
|
vol.Optional(ATTR_AREA_ID): vol.All(
|
||||||
|
cv.ensure_list, [cv.string]
|
||||||
|
),
|
||||||
vol.Optional(ATTR_DEVICE_ID): vol.All(
|
vol.Optional(ATTR_DEVICE_ID): vol.All(
|
||||||
cv.ensure_list, [cv.string]
|
cv.ensure_list, [cv.string]
|
||||||
),
|
),
|
||||||
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
|
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
|
||||||
},
|
},
|
||||||
cv.has_at_least_one_key(ATTR_DEVICE_ID, ATTR_ENTITY_ID),
|
cv.has_at_least_one_key(
|
||||||
|
ATTR_DEVICE_ID, ATTR_ENTITY_ID, ATTR_AREA_ID
|
||||||
|
),
|
||||||
get_nodes_from_service_data,
|
get_nodes_from_service_data,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -26,7 +26,9 @@ from homeassistant.components.zwave_js.const import (
|
|||||||
SERVICE_SET_CONFIG_PARAMETER,
|
SERVICE_SET_CONFIG_PARAMETER,
|
||||||
SERVICE_SET_VALUE,
|
SERVICE_SET_VALUE,
|
||||||
)
|
)
|
||||||
from homeassistant.const import ATTR_DEVICE_ID, ATTR_ENTITY_ID
|
from homeassistant.components.zwave_js.helpers import get_device_id
|
||||||
|
from homeassistant.const import ATTR_AREA_ID, ATTR_DEVICE_ID, ATTR_ENTITY_ID
|
||||||
|
from homeassistant.helpers.area_registry import async_get as async_get_area_reg
|
||||||
from homeassistant.helpers.device_registry import (
|
from homeassistant.helpers.device_registry import (
|
||||||
async_entries_for_config_entry,
|
async_entries_for_config_entry,
|
||||||
async_get as async_get_dev_reg,
|
async_get as async_get_dev_reg,
|
||||||
@ -226,6 +228,52 @@ async def test_set_config_parameter(hass, client, multisensor_6, integration):
|
|||||||
|
|
||||||
client.async_send_command_no_wait.reset_mock()
|
client.async_send_command_no_wait.reset_mock()
|
||||||
|
|
||||||
|
# Test using area ID
|
||||||
|
area_reg = async_get_area_reg(hass)
|
||||||
|
area = area_reg.async_get_or_create("test")
|
||||||
|
ent_reg.async_update_entity(entity_entry.entity_id, area_id=area.id)
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SET_CONFIG_PARAMETER,
|
||||||
|
{
|
||||||
|
ATTR_AREA_ID: area.id,
|
||||||
|
ATTR_CONFIG_PARAMETER: "Temperature Threshold (Unit)",
|
||||||
|
ATTR_CONFIG_VALUE: "Fahrenheit",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(client.async_send_command_no_wait.call_args_list) == 1
|
||||||
|
args = client.async_send_command_no_wait.call_args[0][0]
|
||||||
|
assert args["command"] == "node.set_value"
|
||||||
|
assert args["nodeId"] == 52
|
||||||
|
assert args["valueId"] == {
|
||||||
|
"commandClassName": "Configuration",
|
||||||
|
"commandClass": 112,
|
||||||
|
"endpoint": 0,
|
||||||
|
"property": 41,
|
||||||
|
"propertyName": "Temperature Threshold (Unit)",
|
||||||
|
"propertyKey": 15,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": True,
|
||||||
|
"writeable": True,
|
||||||
|
"valueSize": 3,
|
||||||
|
"min": 1,
|
||||||
|
"max": 2,
|
||||||
|
"default": 1,
|
||||||
|
"format": 0,
|
||||||
|
"allowManualEntry": False,
|
||||||
|
"states": {"1": "Celsius", "2": "Fahrenheit"},
|
||||||
|
"label": "Temperature Threshold (Unit)",
|
||||||
|
"isFromConfig": True,
|
||||||
|
},
|
||||||
|
"value": 0,
|
||||||
|
}
|
||||||
|
assert args["value"] == 2
|
||||||
|
|
||||||
|
client.async_send_command_no_wait.reset_mock()
|
||||||
|
|
||||||
# Test setting parameter by property and bitmask
|
# Test setting parameter by property and bitmask
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
@ -478,6 +526,33 @@ async def test_bulk_set_config_parameters(hass, client, multisensor_6, integrati
|
|||||||
|
|
||||||
client.async_send_command_no_wait.reset_mock()
|
client.async_send_command_no_wait.reset_mock()
|
||||||
|
|
||||||
|
# Test using area ID
|
||||||
|
area_reg = async_get_area_reg(hass)
|
||||||
|
area = area_reg.async_get_or_create("test")
|
||||||
|
dev_reg.async_update_device(device.id, area_id=area.id)
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_BULK_SET_PARTIAL_CONFIG_PARAMETERS,
|
||||||
|
{
|
||||||
|
ATTR_AREA_ID: area.id,
|
||||||
|
ATTR_CONFIG_PARAMETER: 102,
|
||||||
|
ATTR_CONFIG_VALUE: 241,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(client.async_send_command_no_wait.call_args_list) == 1
|
||||||
|
args = client.async_send_command_no_wait.call_args[0][0]
|
||||||
|
assert args["command"] == "node.set_value"
|
||||||
|
assert args["nodeId"] == 52
|
||||||
|
assert args["valueId"] == {
|
||||||
|
"commandClass": 112,
|
||||||
|
"property": 102,
|
||||||
|
}
|
||||||
|
assert args["value"] == 241
|
||||||
|
|
||||||
|
client.async_send_command_no_wait.reset_mock()
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_BULK_SET_PARTIAL_CONFIG_PARAMETERS,
|
SERVICE_BULK_SET_PARTIAL_CONFIG_PARAMETERS,
|
||||||
@ -808,6 +883,47 @@ async def test_set_value(hass, client, climate_danfoss_lc_13, integration):
|
|||||||
|
|
||||||
client.async_send_command.reset_mock()
|
client.async_send_command.reset_mock()
|
||||||
|
|
||||||
|
# Test using area ID
|
||||||
|
area_reg = async_get_area_reg(hass)
|
||||||
|
area = area_reg.async_get_or_create("test")
|
||||||
|
dev_reg.async_update_device(device.id, area_id=area.id)
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SET_VALUE,
|
||||||
|
{
|
||||||
|
ATTR_AREA_ID: area.id,
|
||||||
|
ATTR_COMMAND_CLASS: 117,
|
||||||
|
ATTR_PROPERTY: "local",
|
||||||
|
ATTR_VALUE: "0x2",
|
||||||
|
ATTR_WAIT_FOR_RESULT: 1,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(client.async_send_command.call_args_list) == 1
|
||||||
|
args = client.async_send_command.call_args[0][0]
|
||||||
|
assert args["command"] == "node.set_value"
|
||||||
|
assert args["nodeId"] == 5
|
||||||
|
assert args["valueId"] == {
|
||||||
|
"commandClassName": "Protection",
|
||||||
|
"commandClass": 117,
|
||||||
|
"endpoint": 0,
|
||||||
|
"property": "local",
|
||||||
|
"propertyName": "local",
|
||||||
|
"ccVersion": 2,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": True,
|
||||||
|
"writeable": True,
|
||||||
|
"label": "Local protection state",
|
||||||
|
"states": {"0": "Unprotected", "2": "NoOperationPossible"},
|
||||||
|
},
|
||||||
|
"value": 0,
|
||||||
|
}
|
||||||
|
assert args["value"] == 2
|
||||||
|
|
||||||
|
client.async_send_command.reset_mock()
|
||||||
|
|
||||||
# Test groups get expanded
|
# Test groups get expanded
|
||||||
assert await async_setup_component(hass, "group", {})
|
assert await async_setup_component(hass, "group", {})
|
||||||
await Group.async_create_group(hass, "test", [CLIMATE_DANFOSS_LC13_ENTITY])
|
await Group.async_create_group(hass, "test", [CLIMATE_DANFOSS_LC13_ENTITY])
|
||||||
@ -888,6 +1004,8 @@ async def test_set_value(hass, client, climate_danfoss_lc_13, integration):
|
|||||||
}
|
}
|
||||||
assert args["value"] == 2
|
assert args["value"] == 2
|
||||||
|
|
||||||
|
client.async_send_command.reset_mock()
|
||||||
|
|
||||||
# Test missing device and entities keys
|
# Test missing device and entities keys
|
||||||
with pytest.raises(vol.MultipleInvalid):
|
with pytest.raises(vol.MultipleInvalid):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
@ -1017,6 +1135,49 @@ async def test_multicast_set_value(
|
|||||||
|
|
||||||
client.async_send_command.reset_mock()
|
client.async_send_command.reset_mock()
|
||||||
|
|
||||||
|
# Test using area ID
|
||||||
|
dev_reg = async_get_dev_reg(hass)
|
||||||
|
device_eurotronic = dev_reg.async_get_device(
|
||||||
|
{get_device_id(client, climate_eurotronic_spirit_z)}
|
||||||
|
)
|
||||||
|
assert device_eurotronic
|
||||||
|
device_danfoss = dev_reg.async_get_device(
|
||||||
|
{get_device_id(client, climate_danfoss_lc_13)}
|
||||||
|
)
|
||||||
|
assert device_danfoss
|
||||||
|
area_reg = async_get_area_reg(hass)
|
||||||
|
area = area_reg.async_get_or_create("test")
|
||||||
|
dev_reg.async_update_device(device_eurotronic.id, area_id=area.id)
|
||||||
|
dev_reg.async_update_device(device_danfoss.id, area_id=area.id)
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_MULTICAST_SET_VALUE,
|
||||||
|
{
|
||||||
|
ATTR_AREA_ID: area.id,
|
||||||
|
ATTR_COMMAND_CLASS: 67,
|
||||||
|
ATTR_PROPERTY: "setpoint",
|
||||||
|
ATTR_PROPERTY_KEY: 1,
|
||||||
|
ATTR_VALUE: "0x2",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(client.async_send_command.call_args_list) == 1
|
||||||
|
args = client.async_send_command.call_args[0][0]
|
||||||
|
assert args["command"] == "multicast_group.set_value"
|
||||||
|
assert args["nodeIDs"] == [
|
||||||
|
climate_eurotronic_spirit_z.node_id,
|
||||||
|
climate_danfoss_lc_13.node_id,
|
||||||
|
]
|
||||||
|
assert args["valueId"] == {
|
||||||
|
"commandClass": 67,
|
||||||
|
"property": "setpoint",
|
||||||
|
"propertyKey": 1,
|
||||||
|
}
|
||||||
|
assert args["value"] == 2
|
||||||
|
|
||||||
|
client.async_send_command.reset_mock()
|
||||||
|
|
||||||
# Test groups get expanded for multicast call
|
# Test groups get expanded for multicast call
|
||||||
assert await async_setup_component(hass, "group", {})
|
assert await async_setup_component(hass, "group", {})
|
||||||
await Group.async_create_group(
|
await Group.async_create_group(
|
||||||
@ -1228,6 +1389,16 @@ async def test_ping(
|
|||||||
integration,
|
integration,
|
||||||
):
|
):
|
||||||
"""Test ping service."""
|
"""Test ping service."""
|
||||||
|
dev_reg = async_get_dev_reg(hass)
|
||||||
|
device_radio_thermostat = dev_reg.async_get_device(
|
||||||
|
{get_device_id(client, climate_radio_thermostat_ct100_plus_different_endpoints)}
|
||||||
|
)
|
||||||
|
assert device_radio_thermostat
|
||||||
|
device_danfoss = dev_reg.async_get_device(
|
||||||
|
{get_device_id(client, climate_danfoss_lc_13)}
|
||||||
|
)
|
||||||
|
assert device_danfoss
|
||||||
|
|
||||||
client.async_send_command.return_value = {"responded": True}
|
client.async_send_command.return_value = {"responded": True}
|
||||||
|
|
||||||
# Test successful ping call
|
# Test successful ping call
|
||||||
@ -1243,7 +1414,57 @@ async def test_ping(
|
|||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# assert client.async_send_command.call_args_list is None
|
assert len(client.async_send_command.call_args_list) == 2
|
||||||
|
args = client.async_send_command.call_args_list[0][0][0]
|
||||||
|
assert args["command"] == "node.ping"
|
||||||
|
assert (
|
||||||
|
args["nodeId"]
|
||||||
|
== climate_radio_thermostat_ct100_plus_different_endpoints.node_id
|
||||||
|
)
|
||||||
|
args = client.async_send_command.call_args_list[1][0][0]
|
||||||
|
assert args["command"] == "node.ping"
|
||||||
|
assert args["nodeId"] == climate_danfoss_lc_13.node_id
|
||||||
|
|
||||||
|
client.async_send_command.reset_mock()
|
||||||
|
|
||||||
|
# Test successful ping call with devices
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_PING,
|
||||||
|
{
|
||||||
|
ATTR_DEVICE_ID: [
|
||||||
|
device_radio_thermostat.id,
|
||||||
|
device_danfoss.id,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(client.async_send_command.call_args_list) == 2
|
||||||
|
args = client.async_send_command.call_args_list[0][0][0]
|
||||||
|
assert args["command"] == "node.ping"
|
||||||
|
assert (
|
||||||
|
args["nodeId"]
|
||||||
|
== climate_radio_thermostat_ct100_plus_different_endpoints.node_id
|
||||||
|
)
|
||||||
|
args = client.async_send_command.call_args_list[1][0][0]
|
||||||
|
assert args["command"] == "node.ping"
|
||||||
|
assert args["nodeId"] == climate_danfoss_lc_13.node_id
|
||||||
|
|
||||||
|
client.async_send_command.reset_mock()
|
||||||
|
|
||||||
|
# Test successful ping call with area
|
||||||
|
area_reg = async_get_area_reg(hass)
|
||||||
|
area = area_reg.async_get_or_create("test")
|
||||||
|
dev_reg.async_update_device(device_radio_thermostat.id, area_id=area.id)
|
||||||
|
dev_reg.async_update_device(device_danfoss.id, area_id=area.id)
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_PING,
|
||||||
|
{ATTR_AREA_ID: area.id},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
assert len(client.async_send_command.call_args_list) == 2
|
assert len(client.async_send_command.call_args_list) == 2
|
||||||
args = client.async_send_command.call_args_list[0][0][0]
|
args = client.async_send_command.call_args_list[0][0][0]
|
||||||
assert args["command"] == "node.ping"
|
assert args["command"] == "node.ping"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user