Add an HTTP view to dump the Z-Wave JS state (#45452)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com> Co-authored-by: Bram Kragten <mail@bramkragten.nl>pull/45560/head
parent
260d9f8e16
commit
b9a525a9a7
|
@ -16,7 +16,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||
class RequestDataValidator:
|
||||
"""Decorator that will validate the incoming data.
|
||||
|
||||
Takes in a voluptuous schema and adds 'post_data' as
|
||||
Takes in a voluptuous schema and adds 'data' as
|
||||
keyword argument to the function call.
|
||||
|
||||
Will return a 400 if no JSON provided or doesn't match schema.
|
||||
|
|
|
@ -14,6 +14,7 @@ from homeassistant.helpers import device_registry
|
|||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
|
||||
from .api import async_register_api
|
||||
from .const import (
|
||||
DATA_CLIENT,
|
||||
DATA_UNSUBSCRIBE,
|
||||
|
@ -22,7 +23,6 @@ from .const import (
|
|||
PLATFORMS,
|
||||
)
|
||||
from .discovery import async_discover_values
|
||||
from .websocket_api import async_register_api
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
CONNECT_TIMEOUT = 10
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
"""Websocket API for Z-Wave JS."""
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from aiohttp import hdrs, web, web_exceptions
|
||||
import voluptuous as vol
|
||||
from zwave_js_server import dump
|
||||
from zwave_js_server.client import Client as ZwaveClient
|
||||
from zwave_js_server.model.node import Node as ZwaveNode
|
||||
|
||||
from homeassistant.components import websocket_api
|
||||
from homeassistant.components.http.view import HomeAssistantView
|
||||
from homeassistant.components.websocket_api.connection import ActiveConnection
|
||||
from homeassistant.const import CONF_URL
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import device_registry
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.device_registry import DeviceEntry
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
|
||||
|
@ -32,6 +37,7 @@ def async_register_api(hass: HomeAssistant) -> None:
|
|||
websocket_api.async_register_command(hass, websocket_stop_inclusion)
|
||||
websocket_api.async_register_command(hass, websocket_remove_node)
|
||||
websocket_api.async_register_command(hass, websocket_stop_exclusion)
|
||||
hass.http.register_view(DumpView) # type: ignore
|
||||
|
||||
|
||||
@websocket_api.require_admin
|
||||
|
@ -54,7 +60,7 @@ def websocket_network_status(
|
|||
},
|
||||
"controller": {
|
||||
"home_id": client.driver.controller.data["homeId"],
|
||||
"node_count": len(client.driver.controller.nodes),
|
||||
"nodes": list(client.driver.controller.nodes),
|
||||
},
|
||||
}
|
||||
connection.send_result(
|
||||
|
@ -278,3 +284,31 @@ async def remove_from_device_registry(
|
|||
return
|
||||
|
||||
registry.async_remove_device(device.id)
|
||||
|
||||
|
||||
class DumpView(HomeAssistantView):
|
||||
"""View to dump the state of the Z-Wave JS server."""
|
||||
|
||||
url = "/api/zwave_js/dump/{config_entry_id}"
|
||||
name = "api:zwave_js:dump"
|
||||
|
||||
async def get(self, request: web.Request, config_entry_id: str) -> web.Response:
|
||||
"""Dump the state of Z-Wave."""
|
||||
hass = request.app["hass"]
|
||||
|
||||
if config_entry_id not in hass.data[DOMAIN]:
|
||||
raise web_exceptions.HTTPBadRequest
|
||||
|
||||
entry = hass.config_entries.async_get_entry(config_entry_id)
|
||||
|
||||
msgs = await dump.dump_msgs(
|
||||
entry.data[CONF_URL], async_get_clientsession(hass), wait_nodes_ready=False
|
||||
)
|
||||
|
||||
return web.Response(
|
||||
body="\n".join(json.dumps(msg) for msg in msgs) + "\n",
|
||||
headers={
|
||||
hdrs.CONTENT_TYPE: "application/jsonl",
|
||||
hdrs.CONTENT_DISPOSITION: 'attachment; filename="zwave_js_dump.jsonl"',
|
||||
},
|
||||
)
|
|
@ -4,5 +4,6 @@
|
|||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/zwave_js",
|
||||
"requirements": ["zwave-js-server-python==0.13.0"],
|
||||
"codeowners": ["@home-assistant/z-wave"]
|
||||
"codeowners": ["@home-assistant/z-wave"],
|
||||
"dependencies": ["http", "websocket_api"]
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
"""Test the Z-Wave JS Websocket API."""
|
||||
from unittest.mock import patch
|
||||
|
||||
from zwave_js_server.event import Event
|
||||
|
||||
from homeassistant.components.zwave_js.api import ENTRY_ID, ID, NODE_ID, TYPE
|
||||
from homeassistant.components.zwave_js.const import DOMAIN
|
||||
from homeassistant.components.zwave_js.websocket_api import ENTRY_ID, ID, NODE_ID, TYPE
|
||||
from homeassistant.helpers.device_registry import async_get_registry
|
||||
|
||||
|
||||
|
@ -151,3 +153,22 @@ async def test_remove_node(
|
|||
identifiers={(DOMAIN, "3245146787-67")},
|
||||
)
|
||||
assert device is None
|
||||
|
||||
|
||||
async def test_dump_view(integration, hass_client):
|
||||
"""Test the HTTP dump view."""
|
||||
client = await hass_client()
|
||||
with patch(
|
||||
"zwave_js_server.dump.dump_msgs",
|
||||
return_value=[{"hello": "world"}, {"second": "msg"}],
|
||||
):
|
||||
resp = await client.get(f"/api/zwave_js/dump/{integration.entry_id}")
|
||||
assert resp.status == 200
|
||||
assert await resp.text() == '{"hello": "world"}\n{"second": "msg"}\n'
|
||||
|
||||
|
||||
async def test_dump_view_invalid_entry_id(integration, hass_client):
|
||||
"""Test an invalid config entry id parameter."""
|
||||
client = await hass_client()
|
||||
resp = await client.get("/api/zwave_js/dump/INVALID")
|
||||
assert resp.status == 400
|
Loading…
Reference in New Issue