mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Add Z-Wave JS lookup_device API (#140802)
* ZwaveJS lookup_device API * add FailedCommand test * test tweak
This commit is contained in:
parent
12f5bd2aea
commit
516aaa741d
@ -405,6 +405,7 @@ def async_register_api(hass: HomeAssistant) -> None:
|
|||||||
websocket_api.async_register_command(
|
websocket_api.async_register_command(
|
||||||
hass, websocket_try_parse_dsk_from_qr_code_string
|
hass, websocket_try_parse_dsk_from_qr_code_string
|
||||||
)
|
)
|
||||||
|
websocket_api.async_register_command(hass, websocket_lookup_device)
|
||||||
websocket_api.async_register_command(hass, websocket_supports_feature)
|
websocket_api.async_register_command(hass, websocket_supports_feature)
|
||||||
websocket_api.async_register_command(hass, websocket_stop_inclusion)
|
websocket_api.async_register_command(hass, websocket_stop_inclusion)
|
||||||
websocket_api.async_register_command(hass, websocket_stop_exclusion)
|
websocket_api.async_register_command(hass, websocket_stop_exclusion)
|
||||||
@ -1138,6 +1139,41 @@ async def websocket_try_parse_dsk_from_qr_code_string(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@websocket_api.require_admin
|
||||||
|
@websocket_api.websocket_command(
|
||||||
|
{
|
||||||
|
vol.Required(TYPE): "zwave_js/lookup_device",
|
||||||
|
vol.Required(ENTRY_ID): str,
|
||||||
|
vol.Required(MANUFACTURER_ID): int,
|
||||||
|
vol.Required(PRODUCT_TYPE): int,
|
||||||
|
vol.Required(PRODUCT_ID): int,
|
||||||
|
vol.Optional(APPLICATION_VERSION): str,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@websocket_api.async_response
|
||||||
|
@async_handle_failed_command
|
||||||
|
@async_get_entry
|
||||||
|
async def websocket_lookup_device(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
connection: ActiveConnection,
|
||||||
|
msg: dict[str, Any],
|
||||||
|
entry: ConfigEntry,
|
||||||
|
client: Client,
|
||||||
|
driver: Driver,
|
||||||
|
) -> None:
|
||||||
|
"""Look up the definition of a given device in the configuration DB."""
|
||||||
|
device = await driver.config_manager.lookup_device(
|
||||||
|
msg[MANUFACTURER_ID],
|
||||||
|
msg[PRODUCT_TYPE],
|
||||||
|
msg[PRODUCT_ID],
|
||||||
|
msg.get(APPLICATION_VERSION),
|
||||||
|
)
|
||||||
|
if device is None:
|
||||||
|
connection.send_error(msg[ID], ERR_NOT_FOUND, "Device not found")
|
||||||
|
else:
|
||||||
|
connection.send_result(msg[ID], device.to_dict())
|
||||||
|
|
||||||
|
|
||||||
@websocket_api.require_admin
|
@websocket_api.require_admin
|
||||||
@websocket_api.websocket_command(
|
@websocket_api.websocket_command(
|
||||||
{
|
{
|
||||||
|
@ -5,7 +5,7 @@ from http import HTTPStatus
|
|||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import json
|
import json
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import MagicMock, PropertyMock, patch
|
from unittest.mock import AsyncMock, MagicMock, PropertyMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from zwave_js_server.const import (
|
from zwave_js_server.const import (
|
||||||
@ -5577,3 +5577,127 @@ async def test_subscribe_s2_inclusion(
|
|||||||
msg = await ws_client.receive_json()
|
msg = await ws_client.receive_json()
|
||||||
assert not msg["success"]
|
assert not msg["success"]
|
||||||
assert msg["error"]["code"] == ERR_NOT_FOUND
|
assert msg["error"]["code"] == ERR_NOT_FOUND
|
||||||
|
|
||||||
|
|
||||||
|
async def test_lookup_device(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
integration: MockConfigEntry,
|
||||||
|
client: MagicMock,
|
||||||
|
hass_ws_client: WebSocketGenerator,
|
||||||
|
) -> None:
|
||||||
|
"""Test lookup_device websocket command."""
|
||||||
|
entry = integration
|
||||||
|
ws_client = await hass_ws_client(hass)
|
||||||
|
|
||||||
|
# Create mock device response
|
||||||
|
mock_device = MagicMock()
|
||||||
|
mock_device.to_dict.return_value = {
|
||||||
|
"manufacturer": "Test Manufacturer",
|
||||||
|
"label": "Test Device",
|
||||||
|
"description": "Test Device Description",
|
||||||
|
"devices": [{"productType": 1, "productId": 2}],
|
||||||
|
"firmwareVersion": {"min": "1.0", "max": "2.0"},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test successful lookup
|
||||||
|
client.driver.config_manager.lookup_device = AsyncMock(return_value=mock_device)
|
||||||
|
|
||||||
|
await ws_client.send_json_auto_id(
|
||||||
|
{
|
||||||
|
TYPE: "zwave_js/lookup_device",
|
||||||
|
ENTRY_ID: entry.entry_id,
|
||||||
|
MANUFACTURER_ID: 1,
|
||||||
|
PRODUCT_TYPE: 2,
|
||||||
|
PRODUCT_ID: 3,
|
||||||
|
APPLICATION_VERSION: "1.5",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
msg = await ws_client.receive_json()
|
||||||
|
|
||||||
|
assert msg["success"]
|
||||||
|
assert msg["result"] == mock_device.to_dict.return_value
|
||||||
|
|
||||||
|
client.driver.config_manager.lookup_device.assert_called_once_with(1, 2, 3, "1.5")
|
||||||
|
|
||||||
|
# Reset mock
|
||||||
|
client.driver.config_manager.lookup_device.reset_mock()
|
||||||
|
|
||||||
|
# Test lookup without optional application_version
|
||||||
|
await ws_client.send_json_auto_id(
|
||||||
|
{
|
||||||
|
TYPE: "zwave_js/lookup_device",
|
||||||
|
ENTRY_ID: entry.entry_id,
|
||||||
|
MANUFACTURER_ID: 4,
|
||||||
|
PRODUCT_TYPE: 5,
|
||||||
|
PRODUCT_ID: 6,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
msg = await ws_client.receive_json()
|
||||||
|
|
||||||
|
assert msg["success"]
|
||||||
|
assert msg["result"] == mock_device.to_dict.return_value
|
||||||
|
|
||||||
|
client.driver.config_manager.lookup_device.assert_called_once_with(4, 5, 6, None)
|
||||||
|
|
||||||
|
# Test device not found
|
||||||
|
with patch.object(
|
||||||
|
client.driver.config_manager,
|
||||||
|
"lookup_device",
|
||||||
|
return_value=None,
|
||||||
|
):
|
||||||
|
await ws_client.send_json_auto_id(
|
||||||
|
{
|
||||||
|
TYPE: "zwave_js/lookup_device",
|
||||||
|
ENTRY_ID: entry.entry_id,
|
||||||
|
MANUFACTURER_ID: 99,
|
||||||
|
PRODUCT_TYPE: 99,
|
||||||
|
PRODUCT_ID: 99,
|
||||||
|
APPLICATION_VERSION: "9.9",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
msg = await ws_client.receive_json()
|
||||||
|
|
||||||
|
assert not msg["success"]
|
||||||
|
assert msg["error"]["code"] == ERR_NOT_FOUND
|
||||||
|
assert msg["error"]["message"] == "Device not found"
|
||||||
|
|
||||||
|
# Test sending command with improper entry ID fails
|
||||||
|
await ws_client.send_json_auto_id(
|
||||||
|
{
|
||||||
|
TYPE: "zwave_js/lookup_device",
|
||||||
|
ENTRY_ID: "invalid_entry_id",
|
||||||
|
MANUFACTURER_ID: 1,
|
||||||
|
PRODUCT_TYPE: 1,
|
||||||
|
PRODUCT_ID: 1,
|
||||||
|
APPLICATION_VERSION: "1.0",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
msg = await ws_client.receive_json()
|
||||||
|
assert not msg["success"]
|
||||||
|
assert msg["error"]["code"] == ERR_NOT_FOUND
|
||||||
|
assert msg["error"]["message"] == "Config entry invalid_entry_id not found"
|
||||||
|
|
||||||
|
# Test FailedCommand exception
|
||||||
|
error_message = "Failed to execute lookup_device command"
|
||||||
|
with patch.object(
|
||||||
|
client.driver.config_manager,
|
||||||
|
"lookup_device",
|
||||||
|
side_effect=FailedCommand("lookup_device", error_message),
|
||||||
|
):
|
||||||
|
# Send the subscription request
|
||||||
|
await ws_client.send_json_auto_id(
|
||||||
|
{
|
||||||
|
TYPE: "zwave_js/lookup_device",
|
||||||
|
ENTRY_ID: entry.entry_id,
|
||||||
|
MANUFACTURER_ID: 1,
|
||||||
|
PRODUCT_TYPE: 2,
|
||||||
|
PRODUCT_ID: 3,
|
||||||
|
APPLICATION_VERSION: "1.0",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Verify error response
|
||||||
|
msg = await ws_client.receive_json()
|
||||||
|
assert not msg["success"]
|
||||||
|
assert msg["error"]["code"] == error_message
|
||||||
|
assert msg["error"]["message"] == f"Command failed: {error_message}"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user