1 """The thread websocket API."""
3 from __future__
import annotations
7 from python_otbr_api.tlv_parser
import TLVError
8 import voluptuous
as vol
13 from .
import dataset_store, discovery
18 """Set up the sensor websocket API."""
19 websocket_api.async_register_command(hass, ws_add_dataset)
20 websocket_api.async_register_command(hass, ws_delete_dataset)
21 websocket_api.async_register_command(hass, ws_discover_routers)
22 websocket_api.async_register_command(hass, ws_get_dataset)
23 websocket_api.async_register_command(hass, ws_list_datasets)
24 websocket_api.async_register_command(hass, ws_set_preferred_border_agent)
25 websocket_api.async_register_command(hass, ws_set_preferred_dataset)
28 @websocket_api.require_admin
29 @websocket_api.websocket_command(
{
vol.Required("type"):
"thread/add_dataset_tlv",
30 vol.Required(
"source"): str,
31 vol.Required(
"tlv"): str,
34 @websocket_api.async_response
38 """Add a thread dataset."""
39 source = msg[
"source"]
43 await dataset_store.async_add_dataset(hass, source, tlv)
44 except TLVError
as exc:
45 connection.send_error(msg[
"id"], websocket_api.ERR_INVALID_FORMAT,
str(exc))
48 connection.send_result(msg[
"id"])
51 @websocket_api.require_admin
52 @websocket_api.websocket_command(
{
vol.Required("type"):
"thread/set_preferred_border_agent",
53 vol.Required(
"dataset_id"): str,
54 vol.Required(
"border_agent_id"): vol.Any(str,
None),
55 vol.Required(
"extended_address"): str,
58 @websocket_api.async_response
62 """Set the preferred border agent's border agent ID and extended address."""
63 dataset_id = msg[
"dataset_id"]
64 border_agent_id = msg[
"border_agent_id"]
65 extended_address = msg[
"extended_address"]
66 store = await dataset_store.async_get_store(hass)
67 store.async_set_preferred_border_agent(
68 dataset_id, border_agent_id, extended_address
70 connection.send_result(msg[
"id"])
73 @websocket_api.require_admin
74 @websocket_api.websocket_command(
{
vol.Required("type"):
"thread/set_preferred_dataset",
75 vol.Required(
"dataset_id"): str,
78 @websocket_api.async_response
82 """Add a thread dataset."""
83 dataset_id = msg[
"dataset_id"]
85 store = await dataset_store.async_get_store(hass)
87 store.preferred_dataset = dataset_id
89 connection.send_error(msg[
"id"], websocket_api.ERR_NOT_FOUND,
"unknown dataset")
92 connection.send_result(msg[
"id"])
95 @websocket_api.require_admin
96 @websocket_api.websocket_command(
{
vol.Required("type"):
"thread/delete_dataset",
97 vol.Required(
"dataset_id"): str,
100 @websocket_api.async_response
104 """Delete a thread dataset."""
105 dataset_id = msg[
"dataset_id"]
107 store = await dataset_store.async_get_store(hass)
109 store.async_delete(dataset_id)
110 except KeyError
as exc:
111 connection.send_error(msg[
"id"], websocket_api.ERR_NOT_FOUND,
str(exc))
114 connection.send_error(msg[
"id"], websocket_api.ERR_NOT_ALLOWED,
str(exc))
117 connection.send_result(msg[
"id"])
120 @websocket_api.require_admin
121 @websocket_api.websocket_command(
{
vol.Required("type"):
"thread/get_dataset_tlv",
122 vol.Required(
"dataset_id"): str,
125 @websocket_api.async_response
129 """Get a thread dataset in TLV format."""
130 dataset_id = msg[
"dataset_id"]
132 store = await dataset_store.async_get_store(hass)
133 if not (dataset := store.async_get(dataset_id)):
134 connection.send_error(msg[
"id"], websocket_api.ERR_NOT_FOUND,
"unknown dataset")
137 connection.send_result(msg[
"id"], {
"tlv": dataset.tlv})
140 @websocket_api.require_admin
141 @websocket_api.websocket_command(
{
vol.Required("type"):
"thread/list_datasets",
144 @websocket_api.async_response
148 """Get a list of thread datasets."""
150 store = await dataset_store.async_get_store(hass)
151 preferred_dataset = store.preferred_dataset
154 "channel": dataset.channel,
155 "created": dataset.created,
156 "dataset_id": dataset.id,
157 "extended_pan_id": dataset.extended_pan_id,
158 "network_name": dataset.network_name,
159 "pan_id": dataset.pan_id,
160 "preferred": dataset.id == preferred_dataset,
161 "preferred_border_agent_id": dataset.preferred_border_agent_id,
162 "preferred_extended_address": dataset.preferred_extended_address,
163 "source": dataset.source,
165 for dataset
in store.datasets.values()
168 connection.send_result(msg[
"id"], {
"datasets": result})
171 @websocket_api.require_admin
172 @websocket_api.websocket_command(
{
vol.Required("type"):
"thread/discover_routers",
175 @websocket_api.async_response
179 """Discover Thread routers."""
183 """Forward router discovery or update to websocket."""
185 connection.send_message(
186 websocket_api.event_message(
189 "type":
"router_discovered",
197 def router_removed(key: str) ->
None:
198 """Forward router removed to websocket."""
200 connection.send_message(
201 websocket_api.event_message(
204 "type":
"router_removed",
211 def stop_discovery() -> None:
212 """Stop discovery."""
213 hass.async_create_task(thread_discovery.async_stop())
217 hass, router_discovered, router_removed
219 await thread_discovery.async_start()
220 connection.subscriptions[msg[
"id"]] = stop_discovery
222 connection.send_message(websocket_api.result_message(msg[
"id"]))
223
None ws_set_preferred_dataset(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None ws_discover_routers(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None ws_delete_dataset(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None async_setup(HomeAssistant hass)
None ws_add_dataset(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None ws_get_dataset(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None ws_list_datasets(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None ws_set_preferred_border_agent(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)