diff --git a/homeassistant/components/zwave_js/__init__.py b/homeassistant/components/zwave_js/__init__.py index 87f9dad9184..25e886ea1bf 100644 --- a/homeassistant/components/zwave_js/__init__.py +++ b/homeassistant/components/zwave_js/__init__.py @@ -16,6 +16,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send from .const import DATA_CLIENT, DATA_UNSUBSCRIBE, DOMAIN, PLATFORMS from .discovery import async_discover_values +from .websocket_api import async_register_api LOGGER = logging.getLogger(__name__) CONNECT_TIMEOUT = 10 @@ -127,6 +128,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: DATA_UNSUBSCRIBE: unsubs, } + # Set up websocket API + async_register_api(hass) + async def start_platforms() -> None: """Start platforms and perform discovery.""" # wait until all required platforms are ready diff --git a/homeassistant/components/zwave_js/websocket_api.py b/homeassistant/components/zwave_js/websocket_api.py new file mode 100644 index 00000000000..532b53695e1 --- /dev/null +++ b/homeassistant/components/zwave_js/websocket_api.py @@ -0,0 +1,52 @@ +"""Websocket API for Z-Wave JS.""" + +import logging + +import voluptuous as vol + +from homeassistant.components import websocket_api +from homeassistant.components.websocket_api.connection import ActiveConnection +from homeassistant.core import HomeAssistant, callback + +from .const import DATA_CLIENT, DOMAIN + +_LOGGER = logging.getLogger(__name__) + +ID = "id" +ENTRY_ID = "entry_id" +TYPE = "type" + + +@callback +def async_register_api(hass: HomeAssistant) -> None: + """Register all of our api endpoints.""" + websocket_api.async_register_command(hass, websocket_network_status) + + +@websocket_api.require_admin +@websocket_api.websocket_command( + {vol.Required(TYPE): "zwave_js/network_status", vol.Required(ENTRY_ID): str} +) +@callback +def websocket_network_status( + hass: HomeAssistant, connection: ActiveConnection, msg: dict +) -> None: + """Get the status of the Z-Wave JS network.""" + entry_id = msg[ENTRY_ID] + client = hass.data[DOMAIN][entry_id][DATA_CLIENT] + data = { + "client": { + "ws_server_url": client.ws_server_url, + "state": client.state, + "driver_version": client.version.driver_version, + "server_version": client.version.server_version, + }, + "controller": { + "home_id": client.driver.controller.data["homeId"], + "node_count": len(client.driver.controller.nodes), + }, + } + connection.send_result( + msg[ID], + data, + ) diff --git a/tests/components/zwave_js/conftest.py b/tests/components/zwave_js/conftest.py index 173d9af2728..1d92a73d84d 100644 --- a/tests/components/zwave_js/conftest.py +++ b/tests/components/zwave_js/conftest.py @@ -5,6 +5,7 @@ from unittest.mock import DEFAULT, patch import pytest from zwave_js_server.model.driver import Driver from zwave_js_server.model.node import Node +from zwave_js_server.version import VersionInfo from homeassistant.helpers.device_registry import ( async_get_registry as async_get_device_registry, @@ -25,6 +26,17 @@ def controller_state_fixture(): return json.loads(load_fixture("zwave_js/controller_state.json")) +@pytest.fixture(name="version_state", scope="session") +def version_state_fixture(): + """Load the version state fixture data.""" + return { + "type": "version", + "driverVersion": "6.0.0-beta.0", + "serverVersion": "1.0.0", + "homeId": 1234567890, + } + + @pytest.fixture(name="multisensor_6_state", scope="session") def multisensor_6_state_fixture(): """Load the multisensor 6 node state fixture data.""" @@ -50,13 +62,17 @@ def bulb_6_multi_color_state_fixture(): @pytest.fixture(name="client") -def mock_client_fixture(controller_state): +def mock_client_fixture(controller_state, version_state): """Mock a client.""" with patch( "homeassistant.components.zwave_js.ZwaveClient", autospec=True ) as client_class: driver = Driver(client_class.return_value, controller_state) + version = VersionInfo.from_message(version_state) client_class.return_value.driver = driver + client_class.return_value.version = version + client_class.return_value.ws_server_url = "ws://test:3000/zjs" + client_class.return_value.state = "connected" yield client_class.return_value diff --git a/tests/components/zwave_js/test_websocket_api.py b/tests/components/zwave_js/test_websocket_api.py new file mode 100644 index 00000000000..b5fb97feff1 --- /dev/null +++ b/tests/components/zwave_js/test_websocket_api.py @@ -0,0 +1,18 @@ +"""Test the Z-Wave JS Websocket API.""" + +from homeassistant.components.zwave_js.websocket_api import ENTRY_ID, ID, TYPE + + +async def test_websocket_api(hass, integration, hass_ws_client): + """Test the network_status websocket command.""" + entry = integration + ws_client = await hass_ws_client(hass) + + await ws_client.send_json( + {ID: 2, TYPE: "zwave_js/network_status", ENTRY_ID: entry.entry_id} + ) + msg = await ws_client.receive_json() + result = msg["result"] + + assert result["client"]["ws_server_url"] == "ws://test:3000/zjs" + assert result["client"]["server_version"] == "1.0.0"