Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion homeassistant/components/http/data_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
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.
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/zwave_js/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
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,
Expand All @@ -22,7 +23,6 @@
PLATFORMS,
)
from .discovery import async_discover_values
from .websocket_api import async_register_api

LOGGER = logging.getLogger(__name__)
CONNECT_TIMEOUT = 10
Expand Down
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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
Expand All @@ -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(
Expand Down Expand Up @@ -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",
Comment thread
MartinHjelmare marked this conversation as resolved.
headers={
hdrs.CONTENT_TYPE: "application/jsonl",
hdrs.CONTENT_DISPOSITION: 'attachment; filename="zwave_js_dump.jsonl"',
},
)
3 changes: 2 additions & 1 deletion homeassistant/components/zwave_js/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
}
Original file line number Diff line number Diff line change
@@ -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


Expand Down Expand Up @@ -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