1 """Websocket API for automation."""
6 import voluptuous
as vol
13 async_dispatcher_connect,
14 async_dispatcher_send,
18 SCRIPT_BREAKPOINT_HIT,
19 SCRIPT_DEBUG_CONTINUE_ALL,
29 from .util
import async_get_trace, async_list_contexts, async_list_traces
31 TRACE_DOMAINS = (
"automation",
"script")
36 """Set up the websocket API."""
37 websocket_api.async_register_command(hass, websocket_trace_get)
38 websocket_api.async_register_command(hass, websocket_trace_list)
39 websocket_api.async_register_command(hass, websocket_trace_contexts)
40 websocket_api.async_register_command(hass, websocket_breakpoint_clear)
41 websocket_api.async_register_command(hass, websocket_breakpoint_list)
42 websocket_api.async_register_command(hass, websocket_breakpoint_set)
43 websocket_api.async_register_command(hass, websocket_debug_continue)
44 websocket_api.async_register_command(hass, websocket_debug_step)
45 websocket_api.async_register_command(hass, websocket_debug_stop)
46 websocket_api.async_register_command(hass, websocket_subscribe_breakpoint_events)
49 @websocket_api.require_admin
50 @websocket_api.websocket_command(
{
vol.Required("type"):
"trace/get",
51 vol.Required(
"domain"): vol.In(TRACE_DOMAINS),
52 vol.Required(
"item_id"): str,
53 vol.Required(
"run_id"): str,
56 @websocket_api.async_response
62 """Get a script or automation trace."""
63 key = f
"{msg['domain']}.{msg['item_id']}"
64 run_id = msg[
"run_id"]
69 connection.send_error(
70 msg[
"id"], websocket_api.ERR_NOT_FOUND,
"The trace could not be found"
74 message = websocket_api.messages.result_message(msg[
"id"], requested_trace)
76 connection.send_message(
77 json.dumps(message, cls=ExtendedJSONEncoder, allow_nan=
False)
81 @websocket_api.require_admin
82 @websocket_api.websocket_command(
{
vol.Required("type"):
"trace/list",
83 vol.Required(
"domain",
"id"): vol.In(TRACE_DOMAINS),
84 vol.Optional(
"item_id",
"id"): str,
87 @websocket_api.async_response
93 """Summarize script and automation traces."""
94 wanted_domain = msg[
"domain"]
95 key = f
"{msg['domain']}.{msg['item_id']}" if "item_id" in msg
else None
99 connection.send_result(msg[
"id"], traces)
102 @websocket_api.require_admin
103 @websocket_api.websocket_command(
{
vol.Required("type"):
"trace/contexts",
104 vol.Inclusive(
"domain",
"id"): vol.In(TRACE_DOMAINS),
105 vol.Inclusive(
"item_id",
"id"): str,
108 @websocket_api.async_response
114 """Retrieve contexts we have traces for."""
115 key = f
"{msg['domain']}.{msg['item_id']}" if "item_id" in msg
else None
119 connection.send_result(msg[
"id"], contexts)
123 @websocket_api.require_admin
124 @websocket_api.websocket_command(
{
vol.Required("type"):
"trace/debug/breakpoint/set",
125 vol.Required(
"domain"): vol.In(TRACE_DOMAINS),
126 vol.Required(
"item_id"): str,
127 vol.Required(
"node"): str,
128 vol.Optional(
"run_id"): str,
136 """Set breakpoint."""
137 key = f
"{msg['domain']}.{msg['item_id']}"
138 node: str = msg[
"node"]
139 run_id: str |
None = msg.get(
"run_id")
142 SCRIPT_BREAKPOINT_HIT
not in hass.data.get(DATA_DISPATCHER, {})
143 or not hass.data[DATA_DISPATCHER][SCRIPT_BREAKPOINT_HIT]
148 connection.send_result(msg[
"id"], result)
152 @websocket_api.require_admin
153 @websocket_api.websocket_command(
{
vol.Required("type"):
"trace/debug/breakpoint/clear",
154 vol.Required(
"domain"): vol.In(TRACE_DOMAINS),
155 vol.Required(
"item_id"): str,
156 vol.Required(
"node"): str,
157 vol.Optional(
"run_id"): str,
165 """Clear breakpoint."""
166 key = f
"{msg['domain']}.{msg['item_id']}"
167 node: str = msg[
"node"]
168 run_id: str |
None = msg.get(
"run_id")
172 connection.send_result(msg[
"id"], result)
176 @websocket_api.require_admin
177 @websocket_api.websocket_command({vol.Required("type"):
"trace/debug/breakpoint/list"})
183 """List breakpoints."""
185 for _breakpoint
in breakpoints:
186 key = _breakpoint.pop(
"key")
187 _breakpoint[
"domain"], _breakpoint[
"item_id"] = key.split(
".", 1)
189 connection.send_result(msg[
"id"], breakpoints)
193 @websocket_api.require_admin
194 @websocket_api.websocket_command(
{vol.Required("type"):
"trace/debug/breakpoint/subscribe"}
201 """Subscribe to breakpoint events."""
204 def breakpoint_hit(key: str, run_id: str, node: str) ->
None:
205 """Forward events to websocket."""
206 domain, item_id = key.split(
".", 1)
207 connection.send_message(
208 websocket_api.event_message(
220 hass, SCRIPT_BREAKPOINT_HIT, breakpoint_hit
225 """Unsubscribe from breakpoint events."""
228 SCRIPT_BREAKPOINT_HIT
not in hass.data.get(DATA_DISPATCHER, {})
229 or not hass.data[DATA_DISPATCHER][SCRIPT_BREAKPOINT_HIT]
234 connection.subscriptions[msg[
"id"]] = unsub
236 connection.send_message(websocket_api.result_message(msg[
"id"]))
240 @websocket_api.require_admin
241 @websocket_api.websocket_command(
{
vol.Required("type"):
"trace/debug/continue",
242 vol.Required(
"domain"): vol.In(TRACE_DOMAINS),
243 vol.Required(
"item_id"): str,
244 vol.Required(
"run_id"): str,
252 """Resume execution of halted script or automation."""
253 key = f
"{msg['domain']}.{msg['item_id']}"
254 run_id: str = msg[
"run_id"]
258 connection.send_result(msg[
"id"], result)
262 @websocket_api.require_admin
263 @websocket_api.websocket_command(
{
vol.Required("type"):
"trace/debug/step",
264 vol.Required(
"domain"): vol.In(TRACE_DOMAINS),
265 vol.Required(
"item_id"): str,
266 vol.Required(
"run_id"): str,
274 """Single step a halted script or automation."""
275 key = f
"{msg['domain']}.{msg['item_id']}"
276 run_id: str = msg[
"run_id"]
280 connection.send_result(msg[
"id"], result)
284 @websocket_api.require_admin
285 @websocket_api.websocket_command(
{
vol.Required("type"):
"trace/debug/stop",
286 vol.Required(
"domain"): vol.In(TRACE_DOMAINS),
287 vol.Required(
"item_id"): str,
288 vol.Required(
"run_id"): str,
296 """Stop a halted script or automation."""
297 key = f
"{msg['domain']}.{msg['item_id']}"
298 run_id: str = msg[
"run_id"]
302 connection.send_result(msg[
"id"], result)
303
dict[str, BaseTrace] async_get_trace(HomeAssistant hass, str key, str run_id)
dict[str, dict[str, str]] async_list_contexts(HomeAssistant hass, str|None key)
list[dict[str, Any]] async_list_traces(HomeAssistant hass, str wanted_domain, str|None wanted_key)
None websocket_debug_step(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None async_setup(HomeAssistant hass)
None websocket_subscribe_breakpoint_events(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None websocket_breakpoint_clear(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None websocket_trace_contexts(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None websocket_breakpoint_list(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None websocket_breakpoint_set(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None websocket_trace_list(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None websocket_debug_stop(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None websocket_debug_continue(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None websocket_trace_get(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)
None debug_continue(HomeAssistant hass, str key, str run_id)
None breakpoint_set(HomeAssistant hass, str key, str|None run_id, str node)
list[dict[str, Any]] breakpoint_list(HomeAssistant hass)
None breakpoint_clear_all(HomeAssistant hass)
None breakpoint_clear(HomeAssistant hass, str key, str|None run_id, str node)
None debug_step(HomeAssistant hass, str key, str run_id)
None debug_stop(HomeAssistant hass, str key, str run_id)