1 """Web socket API for Zigbee Home Automation devices."""
3 from __future__
import annotations
7 from typing
import TYPE_CHECKING, Any, Literal, NamedTuple, cast
9 import voluptuous
as vol
10 from zha.application.const
import (
24 ATTR_WARNING_DEVICE_DURATION,
25 ATTR_WARNING_DEVICE_MODE,
26 ATTR_WARNING_DEVICE_STROBE,
27 ATTR_WARNING_DEVICE_STROBE_DUTY_CYCLE,
28 ATTR_WARNING_DEVICE_STROBE_INTENSITY,
29 CLUSTER_COMMAND_SERVER,
30 CLUSTER_COMMANDS_CLIENT,
31 CLUSTER_COMMANDS_SERVER,
34 WARNING_DEVICE_MODE_EMERGENCY,
35 WARNING_DEVICE_SOUND_HIGH,
36 WARNING_DEVICE_SQUAWK_MODE_ARMED,
37 WARNING_DEVICE_STROBE_HIGH,
38 WARNING_DEVICE_STROBE_YES,
39 ZHA_CLUSTER_HANDLER_MSG,
41 from zha.application.gateway
import Gateway
42 from zha.application.helpers
import (
43 async_is_bindable_target,
48 from zha.zigbee.cluster_handlers.const
import CLUSTER_HANDLER_IAS_WD
49 from zha.zigbee.device
import Device
50 from zha.zigbee.group
import GroupMemberReference
52 from zigpy.config
import CONF_DEVICE
53 from zigpy.config.validators
import cv_boolean
54 from zigpy.types.named
import EUI64, KeyData
55 from zigpy.zcl.clusters.security
import IasAce
56 import zigpy.zdo.types
as zdo_types
70 async_get_active_network_settings,
84 from .helpers
import (
85 CONF_ZHA_ALARM_SCHEMA,
86 CONF_ZHA_OPTIONS_SCHEMA,
90 cluster_command_schema_to_vol_schema,
93 get_zha_gateway_proxy,
99 _LOGGER = logging.getLogger(__name__)
104 RESPONSE =
"response"
105 DEVICE_INFO =
"device_info"
107 ATTR_DURATION =
"duration"
109 ATTR_IEEE_ADDRESS =
"ieee_address"
110 ATTR_INSTALL_CODE =
"install_code"
111 ATTR_NEW_CHANNEL =
"new_channel"
112 ATTR_SOURCE_IEEE =
"source_ieee"
113 ATTR_TARGET_IEEE =
"target_ieee"
114 ATTR_QR_CODE =
"qr_code"
116 BINDINGS =
"bindings"
118 SERVICE_PERMIT =
"permit"
119 SERVICE_REMOVE =
"remove"
120 SERVICE_SET_ZIGBEE_CLUSTER_ATTRIBUTE =
"set_zigbee_cluster_attribute"
121 SERVICE_ISSUE_ZIGBEE_CLUSTER_COMMAND =
"issue_zigbee_cluster_command"
122 SERVICE_ISSUE_ZIGBEE_GROUP_COMMAND =
"issue_zigbee_group_command"
123 SERVICE_DIRECT_ZIGBEE_BIND =
"issue_direct_zigbee_bind"
124 SERVICE_DIRECT_ZIGBEE_UNBIND =
"issue_direct_zigbee_unbind"
125 SERVICE_WARNING_DEVICE_SQUAWK =
"warning_device_squawk"
126 SERVICE_WARNING_DEVICE_WARN =
"warning_device_warn"
127 SERVICE_ZIGBEE_BIND =
"service_zigbee_bind"
128 IEEE_SERVICE =
"ieee_based_service"
130 IEEE_SCHEMA = vol.All(cv.string, EUI64.convert)
133 def _ensure_list_if_present[_T](value: _T |
None) -> list[_T] | list[Any] |
None:
134 """Wrap value in list if it is provided and not one."""
137 return cast(
"list[_T]", value)
if isinstance(value, list)
else [value]
140 SERVICE_PERMIT_PARAMS: VolDictType = {
141 vol.Optional(ATTR_IEEE): IEEE_SCHEMA,
142 vol.Optional(ATTR_DURATION, default=60): vol.All(
143 vol.Coerce(int), vol.Range(0, 254)
145 vol.Inclusive(ATTR_SOURCE_IEEE,
"install_code"): IEEE_SCHEMA,
146 vol.Inclusive(ATTR_INSTALL_CODE,
"install_code"): vol.All(
147 cv.string, convert_install_code
149 vol.Exclusive(ATTR_QR_CODE,
"install_code"): vol.All(cv.string, qr_to_install_code),
152 SERVICE_SCHEMAS: dict[str, VolSchemaType] = {
153 SERVICE_PERMIT: vol.Schema(
155 cv.deprecated(ATTR_IEEE_ADDRESS, replacement_key=ATTR_IEEE),
156 SERVICE_PERMIT_PARAMS,
159 IEEE_SERVICE: vol.Schema(
161 cv.deprecated(ATTR_IEEE_ADDRESS, replacement_key=ATTR_IEEE),
162 {vol.Required(ATTR_IEEE): IEEE_SCHEMA},
165 SERVICE_SET_ZIGBEE_CLUSTER_ATTRIBUTE: vol.Schema(
167 vol.Required(ATTR_IEEE): IEEE_SCHEMA,
168 vol.Required(ATTR_ENDPOINT_ID): cv.positive_int,
169 vol.Required(ATTR_CLUSTER_ID): cv.positive_int,
170 vol.Optional(ATTR_CLUSTER_TYPE, default=CLUSTER_TYPE_IN): cv.string,
171 vol.Required(ATTR_ATTRIBUTE): vol.Any(cv.positive_int, str),
172 vol.Required(ATTR_VALUE): vol.Any(int, cv.boolean, cv.string),
173 vol.Optional(ATTR_MANUFACTURER): vol.All(
174 vol.Coerce(int), vol.Range(min=-1)
178 SERVICE_WARNING_DEVICE_SQUAWK: vol.Schema(
180 vol.Required(ATTR_IEEE): IEEE_SCHEMA,
182 ATTR_WARNING_DEVICE_MODE, default=WARNING_DEVICE_SQUAWK_MODE_ARMED
185 ATTR_WARNING_DEVICE_STROBE, default=WARNING_DEVICE_STROBE_YES
188 ATTR_LEVEL, default=WARNING_DEVICE_SOUND_HIGH
192 SERVICE_WARNING_DEVICE_WARN: vol.Schema(
194 vol.Required(ATTR_IEEE): IEEE_SCHEMA,
196 ATTR_WARNING_DEVICE_MODE, default=WARNING_DEVICE_MODE_EMERGENCY
199 ATTR_WARNING_DEVICE_STROBE, default=WARNING_DEVICE_STROBE_YES
202 ATTR_LEVEL, default=WARNING_DEVICE_SOUND_HIGH
204 vol.Optional(ATTR_WARNING_DEVICE_DURATION, default=5): cv.positive_int,
206 ATTR_WARNING_DEVICE_STROBE_DUTY_CYCLE, default=0x00
209 ATTR_WARNING_DEVICE_STROBE_INTENSITY, default=WARNING_DEVICE_STROBE_HIGH
213 SERVICE_ISSUE_ZIGBEE_CLUSTER_COMMAND: vol.All(
216 vol.Required(ATTR_IEEE): IEEE_SCHEMA,
217 vol.Required(ATTR_ENDPOINT_ID): cv.positive_int,
218 vol.Required(ATTR_CLUSTER_ID): cv.positive_int,
219 vol.Optional(ATTR_CLUSTER_TYPE, default=CLUSTER_TYPE_IN): cv.string,
220 vol.Required(ATTR_COMMAND): cv.positive_int,
221 vol.Required(ATTR_COMMAND_TYPE): cv.string,
222 vol.Exclusive(ATTR_ARGS,
"attrs_params"): _ensure_list_if_present,
223 vol.Exclusive(ATTR_PARAMS,
"attrs_params"): dict,
224 vol.Optional(ATTR_MANUFACTURER): vol.All(
225 vol.Coerce(int), vol.Range(min=-1)
229 cv.deprecated(ATTR_ARGS),
230 cv.has_at_least_one_key(ATTR_ARGS, ATTR_PARAMS),
232 SERVICE_ISSUE_ZIGBEE_GROUP_COMMAND: vol.Schema(
234 vol.Required(ATTR_GROUP): cv.positive_int,
235 vol.Required(ATTR_CLUSTER_ID): cv.positive_int,
236 vol.Optional(ATTR_CLUSTER_TYPE, default=CLUSTER_TYPE_IN): cv.string,
237 vol.Required(ATTR_COMMAND): cv.positive_int,
238 vol.Optional(ATTR_ARGS, default=[]): cv.ensure_list,
239 vol.Optional(ATTR_MANUFACTURER): vol.All(
240 vol.Coerce(int), vol.Range(min=-1)
247 ZHA_CONFIG_SCHEMAS = {
248 ZHA_OPTIONS: CONF_ZHA_OPTIONS_SCHEMA,
249 ZHA_ALARM_OPTIONS: CONF_ZHA_ALARM_SCHEMA,
254 """Describes a cluster binding."""
263 """Transform a group member."""
264 return GroupMemberReference(
265 ieee=value[ATTR_IEEE],
266 endpoint_id=value[ATTR_ENDPOINT_ID],
271 """Transform a cluster binding."""
273 name=value[ATTR_NAME],
274 type=value[ATTR_TYPE],
276 endpoint_id=value[ATTR_ENDPOINT_ID],
281 """Transform a zigpy network backup."""
284 return zigpy.backups.NetworkBackup.from_dict(value)
285 except ValueError
as err:
286 raise vol.Invalid(
str(err))
from err
289 GROUP_MEMBER_SCHEMA = vol.All(
292 vol.Required(ATTR_IEEE): IEEE_SCHEMA,
293 vol.Required(ATTR_ENDPOINT_ID): vol.Coerce(int),
300 CLUSTER_BINDING_SCHEMA = vol.All(
303 vol.Required(ATTR_NAME): cv.string,
304 vol.Required(ATTR_TYPE): cv.string,
305 vol.Required(ATTR_ID): vol.Coerce(int),
306 vol.Required(ATTR_ENDPOINT_ID): vol.Coerce(int),
313 @websocket_api.require_admin
314 @websocket_api.websocket_command(
{
vol.Required("type"):
"zha/devices/permit",
315 **SERVICE_PERMIT_PARAMS,
318 @websocket_api.async_response
320 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
322 """Permit ZHA zigbee devices."""
324 duration: int = msg[ATTR_DURATION]
325 ieee: EUI64 |
None = msg.get(ATTR_IEEE)
327 async
def forward_messages(data):
328 """Forward events to websocket."""
329 connection.send_message(websocket_api.event_message(msg[
"id"], data))
332 hass,
"zha_gateway_message", forward_messages
337 """Remove signal listener and turn off debug mode."""
338 zha_gateway_proxy.async_disable_debug_mode()
339 remove_dispatcher_function()
341 connection.subscriptions[msg[
"id"]] = async_cleanup
342 zha_gateway_proxy.async_enable_debug_mode()
345 if ATTR_SOURCE_IEEE
in msg:
346 src_ieee = msg[ATTR_SOURCE_IEEE]
347 link_key = msg[ATTR_INSTALL_CODE]
348 _LOGGER.debug(
"Allowing join for %s device with link key", src_ieee)
349 await zha_gateway_proxy.gateway.application_controller.permit_with_link_key(
350 time_s=duration, node=src_ieee, link_key=link_key
352 elif ATTR_QR_CODE
in msg:
353 src_ieee, link_key = msg[ATTR_QR_CODE]
354 _LOGGER.debug(
"Allowing join for %s device with link key", src_ieee)
355 await zha_gateway_proxy.gateway.application_controller.permit_with_link_key(
356 time_s=duration, node=src_ieee, link_key=link_key
359 await zha_gateway_proxy.gateway.application_controller.permit(
360 time_s=duration, node=ieee
362 connection.send_result(msg[ID])
365 @websocket_api.require_admin
366 @websocket_api.websocket_command({vol.Required(TYPE):
"zha/devices"})
367 @websocket_api.async_response
369 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
371 """Get ZHA devices."""
374 device.zha_device_info
for device
in zha_gateway_proxy.device_proxies.values()
376 connection.send_result(msg[ID], devices)
381 entity_registry = er.async_get(zha_gateway.hass)
382 entry = entity_registry.async_get(entity_ref.ha_entity_id)
383 return entry.name
if entry
else None
388 zha_gateway: Gateway, entity_ref: EntityReference
390 entity_registry = er.async_get(zha_gateway.hass)
391 entry = entity_registry.async_get(entity_ref.ha_entity_id)
392 return entry.original_name
if entry
else None
395 @websocket_api.require_admin
396 @websocket_api.websocket_command({vol.Required(TYPE):
"zha/devices/groupable"})
397 @websocket_api.async_response
399 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
401 """Get ZHA devices that can be grouped."""
406 for device
in zha_gateway_proxy.device_proxies.values()
407 if device.device.is_groupable
409 groupable_devices: list[dict[str, Any]] = []
411 for device
in devices:
412 entity_refs = zha_gateway_proxy.ha_entity_refs[device.device.ieee]
413 groupable_devices.extend(
415 "endpoint_id": ep_id,
420 zha_gateway_proxy, entity_ref
423 for entity_ref
in entity_refs
424 if list(entity_ref.entity_data.entity.cluster_handlers.values())[
426 ].cluster.endpoint.endpoint_id
429 "device": device.zha_device_info,
431 for ep_id
in device.device.async_get_groupable_endpoints()
434 connection.send_result(msg[ID], groupable_devices)
437 @websocket_api.require_admin
438 @websocket_api.websocket_command({vol.Required(TYPE):
"zha/groups"})
439 @websocket_api.async_response
441 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
443 """Get ZHA groups."""
445 groups = [group.group_info
for group
in zha_gateway_proxy.group_proxies.values()]
446 connection.send_result(msg[ID], groups)
449 @websocket_api.require_admin
450 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/device",
451 vol.Required(ATTR_IEEE): IEEE_SCHEMA,
454 @websocket_api.async_response
456 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
458 """Get ZHA devices."""
460 ieee: EUI64 = msg[ATTR_IEEE]
462 if not (zha_device := zha_gateway_proxy.device_proxies.get(ieee)):
463 connection.send_message(
464 websocket_api.error_message(
465 msg[ID], websocket_api.ERR_NOT_FOUND,
"ZHA Device not found"
470 device_info = zha_device.zha_device_info
471 connection.send_result(msg[ID], device_info)
474 @websocket_api.require_admin
475 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/group",
476 vol.Required(GROUP_ID): cv.positive_int,
479 @websocket_api.async_response
481 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
485 group_id: int = msg[GROUP_ID]
487 if not (zha_group := zha_gateway_proxy.group_proxies.get(group_id)):
488 connection.send_message(
489 websocket_api.error_message(
490 msg[ID], websocket_api.ERR_NOT_FOUND,
"ZHA Group not found"
495 group_info = zha_group.group_info
496 connection.send_result(msg[ID], group_info)
499 @websocket_api.require_admin
500 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/group/add",
501 vol.Required(GROUP_NAME): cv.string,
502 vol.Optional(GROUP_ID): cv.positive_int,
503 vol.Optional(ATTR_MEMBERS): vol.All(cv.ensure_list, [GROUP_MEMBER_SCHEMA]),
506 @websocket_api.async_response
508 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
510 """Add a new ZHA group."""
512 group_name: str = msg[GROUP_NAME]
513 group_id: int |
None = msg.get(GROUP_ID)
514 members: list[GroupMemberReference] |
None = msg.get(ATTR_MEMBERS)
515 group = await zha_gateway.gateway.async_create_zigpy_group(
516 group_name, members, group_id
519 connection.send_result(
520 msg[ID], zha_gateway.group_proxies[group.group_id].group_info
524 @websocket_api.require_admin
525 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/group/remove",
526 vol.Required(GROUP_IDS): vol.All(cv.ensure_list, [cv.positive_int]),
529 @websocket_api.async_response
531 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
533 """Remove the specified ZHA groups."""
535 group_ids: list[int] = msg[GROUP_IDS]
537 if len(group_ids) > 1:
539 zha_gateway.gateway.async_remove_zigpy_group(group_id)
540 for group_id
in group_ids
542 await asyncio.gather(*tasks)
544 await zha_gateway.gateway.async_remove_zigpy_group(group_ids[0])
545 ret_groups = [group.group_info
for group
in zha_gateway.group_proxies.values()]
546 connection.send_result(msg[ID], ret_groups)
549 @websocket_api.require_admin
550 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/group/members/add",
551 vol.Required(GROUP_ID): cv.positive_int,
552 vol.Required(ATTR_MEMBERS): vol.All(cv.ensure_list, [GROUP_MEMBER_SCHEMA]),
555 @websocket_api.async_response
557 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
559 """Add members to a ZHA group."""
562 group_id: int = msg[GROUP_ID]
563 members: list[GroupMemberReference] = msg[ATTR_MEMBERS]
565 if not (zha_group := zha_gateway.groups.get(group_id)):
566 connection.send_message(
567 websocket_api.error_message(
568 msg[ID], websocket_api.ERR_NOT_FOUND,
"ZHA Group not found"
573 await zha_group.async_add_members(members)
574 ret_group = zha_gateway_proxy.get_group_proxy(group_id)
576 connection.send_result(msg[ID], ret_group.group_info)
579 @websocket_api.require_admin
580 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/group/members/remove",
581 vol.Required(GROUP_ID): cv.positive_int,
582 vol.Required(ATTR_MEMBERS): vol.All(cv.ensure_list, [GROUP_MEMBER_SCHEMA]),
585 @websocket_api.async_response
587 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
589 """Remove members from a ZHA group."""
592 group_id: int = msg[GROUP_ID]
593 members: list[GroupMemberReference] = msg[ATTR_MEMBERS]
595 if not (zha_group := zha_gateway.groups.get(group_id)):
596 connection.send_message(
597 websocket_api.error_message(
598 msg[ID], websocket_api.ERR_NOT_FOUND,
"ZHA Group not found"
603 await zha_group.async_remove_members(members)
604 ret_group = zha_gateway_proxy.get_group_proxy(group_id)
606 connection.send_result(msg[ID], ret_group.group_info)
609 @websocket_api.require_admin
610 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/devices/reconfigure",
611 vol.Required(ATTR_IEEE): IEEE_SCHEMA,
614 @websocket_api.async_response
616 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
618 """Reconfigure a ZHA nodes entities by its ieee address."""
620 ieee: EUI64 = msg[ATTR_IEEE]
621 device: Device |
None = zha_gateway.get_device(ieee)
623 async
def forward_messages(data):
624 """Forward events to websocket."""
625 connection.send_message(websocket_api.event_message(msg[
"id"], data))
628 hass, ZHA_CLUSTER_HANDLER_MSG, forward_messages
633 """Remove signal listener."""
634 remove_dispatcher_function()
636 connection.subscriptions[msg[
"id"]] = async_cleanup
638 _LOGGER.debug(
"Reconfiguring node with ieee_address: %s", ieee)
640 hass.async_create_task(device.async_configure())
643 @websocket_api.require_admin
644 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/topology/update",
647 @websocket_api.async_response
649 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
651 """Update the ZHA network topology."""
653 hass.async_create_task(zha_gateway.application_controller.topology.scan())
656 @websocket_api.require_admin
657 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/devices/clusters",
658 vol.Required(ATTR_IEEE): IEEE_SCHEMA,
661 @websocket_api.async_response
663 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
665 """Return a list of device clusters."""
667 ieee: EUI64 = msg[ATTR_IEEE]
668 zha_device = zha_gateway.get_device(ieee)
669 response_clusters = []
670 if zha_device
is not None:
671 clusters_by_endpoint = zha_device.async_get_clusters()
672 for ep_id, clusters
in clusters_by_endpoint.items():
673 for c_id, cluster
in clusters[CLUSTER_TYPE_IN].items():
674 response_clusters.append(
676 TYPE: CLUSTER_TYPE_IN,
678 ATTR_NAME: cluster.__class__.__name__,
679 "endpoint_id": ep_id,
682 for c_id, cluster
in clusters[CLUSTER_TYPE_OUT].items():
683 response_clusters.append(
685 TYPE: CLUSTER_TYPE_OUT,
687 ATTR_NAME: cluster.__class__.__name__,
688 "endpoint_id": ep_id,
692 connection.send_result(msg[ID], response_clusters)
695 @websocket_api.require_admin
696 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/devices/clusters/attributes",
697 vol.Required(ATTR_IEEE): IEEE_SCHEMA,
698 vol.Required(ATTR_ENDPOINT_ID): int,
699 vol.Required(ATTR_CLUSTER_ID): int,
700 vol.Required(ATTR_CLUSTER_TYPE): str,
703 @websocket_api.async_response
705 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
707 """Return a list of cluster attributes."""
709 ieee: EUI64 = msg[ATTR_IEEE]
710 endpoint_id: int = msg[ATTR_ENDPOINT_ID]
711 cluster_id: int = msg[ATTR_CLUSTER_ID]
712 cluster_type: str = msg[ATTR_CLUSTER_TYPE]
713 cluster_attributes: list[dict[str, Any]] = []
714 zha_device = zha_gateway.get_device(ieee)
716 if zha_device
is not None:
717 attributes = zha_device.async_get_cluster_attributes(
718 endpoint_id, cluster_id, cluster_type
720 if attributes
is not None:
721 for attr_id, attr
in attributes.items():
722 cluster_attributes.append({ID: attr_id, ATTR_NAME: attr.name})
724 "Requested attributes for: %s: %s, %s: '%s', %s: %s, %s: %s",
735 connection.send_result(msg[ID], cluster_attributes)
738 @websocket_api.require_admin
739 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/devices/clusters/commands",
740 vol.Required(ATTR_IEEE): IEEE_SCHEMA,
741 vol.Required(ATTR_ENDPOINT_ID): int,
742 vol.Required(ATTR_CLUSTER_ID): int,
743 vol.Required(ATTR_CLUSTER_TYPE): str,
746 @websocket_api.async_response
748 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
750 """Return a list of cluster commands."""
751 import voluptuous_serialize
754 ieee: EUI64 = msg[ATTR_IEEE]
755 endpoint_id: int = msg[ATTR_ENDPOINT_ID]
756 cluster_id: int = msg[ATTR_CLUSTER_ID]
757 cluster_type: str = msg[ATTR_CLUSTER_TYPE]
758 zha_device = zha_gateway.get_device(ieee)
759 cluster_commands: list[dict[str, Any]] = []
761 if zha_device
is not None:
762 commands = zha_device.async_get_cluster_commands(
763 endpoint_id, cluster_id, cluster_type
766 if commands
is not None:
767 for cmd_id, cmd
in commands[CLUSTER_COMMANDS_CLIENT].items():
768 cluster_commands.append(
773 "schema": voluptuous_serialize.convert(
775 custom_serializer=cv.custom_serializer,
779 for cmd_id, cmd
in commands[CLUSTER_COMMANDS_SERVER].items():
780 cluster_commands.append(
782 TYPE: CLUSTER_COMMAND_SERVER,
785 "schema": voluptuous_serialize.convert(
787 custom_serializer=cv.custom_serializer,
792 "Requested commands for: %s: %s, %s: '%s', %s: %s, %s: %s",
803 connection.send_result(msg[ID], cluster_commands)
806 @websocket_api.require_admin
807 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/devices/clusters/attributes/value",
808 vol.Required(ATTR_IEEE): IEEE_SCHEMA,
809 vol.Required(ATTR_ENDPOINT_ID): int,
810 vol.Required(ATTR_CLUSTER_ID): int,
811 vol.Required(ATTR_CLUSTER_TYPE): str,
812 vol.Required(ATTR_ATTRIBUTE): int,
813 vol.Optional(ATTR_MANUFACTURER): cv.positive_int,
816 @websocket_api.async_response
818 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
820 """Read zigbee attribute for cluster on ZHA entity."""
822 ieee: EUI64 = msg[ATTR_IEEE]
823 endpoint_id: int = msg[ATTR_ENDPOINT_ID]
824 cluster_id: int = msg[ATTR_CLUSTER_ID]
825 cluster_type: str = msg[ATTR_CLUSTER_TYPE]
826 attribute: int = msg[ATTR_ATTRIBUTE]
827 manufacturer: int |
None = msg.get(ATTR_MANUFACTURER)
828 zha_device = zha_gateway.get_device(ieee)
831 if zha_device
is not None:
832 cluster = zha_device.async_get_cluster(
833 endpoint_id, cluster_id, cluster_type=cluster_type
835 success, failure = await cluster.read_attributes(
836 [attribute], allow_cache=
False, only_cache=
False, manufacturer=manufacturer
840 "Read attribute for: %s: [%s] %s: [%s] %s: [%s] %s: [%s] %s: [%s] %s: [%s]"
854 str(success.get(attribute)),
858 connection.send_result(msg[ID],
str(success.get(attribute)))
861 @websocket_api.require_admin
862 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/devices/bindable",
863 vol.Required(ATTR_IEEE): IEEE_SCHEMA,
866 @websocket_api.async_response
868 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
870 """Directly bind devices."""
872 source_ieee: EUI64 = msg[ATTR_IEEE]
873 source_device = zha_gateway_proxy.device_proxies.get(source_ieee)
874 assert source_device
is not None
877 device.zha_device_info
878 for device
in zha_gateway_proxy.device_proxies.values()
879 if async_is_bindable_target(source_device.device, device.device)
883 "Get bindable devices: %s: [%s], %s: [%s]",
890 connection.send_message(websocket_api.result_message(msg[ID], devices))
893 @websocket_api.require_admin
894 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/devices/bind",
895 vol.Required(ATTR_SOURCE_IEEE): IEEE_SCHEMA,
896 vol.Required(ATTR_TARGET_IEEE): IEEE_SCHEMA,
899 @websocket_api.async_response
901 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
903 """Directly bind devices."""
905 source_ieee: EUI64 = msg[ATTR_SOURCE_IEEE]
906 target_ieee: EUI64 = msg[ATTR_TARGET_IEEE]
908 zha_gateway, source_ieee, target_ieee, zdo_types.ZDOCmd.Bind_req
911 "Devices bound: %s: [%s] %s: [%s]",
917 connection.send_result(msg[ID])
920 @websocket_api.require_admin
921 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/devices/unbind",
922 vol.Required(ATTR_SOURCE_IEEE): IEEE_SCHEMA,
923 vol.Required(ATTR_TARGET_IEEE): IEEE_SCHEMA,
926 @websocket_api.async_response
928 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
930 """Remove a direct binding between devices."""
932 source_ieee: EUI64 = msg[ATTR_SOURCE_IEEE]
933 target_ieee: EUI64 = msg[ATTR_TARGET_IEEE]
935 zha_gateway, source_ieee, target_ieee, zdo_types.ZDOCmd.Unbind_req
938 "Devices un-bound: %s: [%s] %s: [%s]",
944 connection.send_result(msg[ID])
947 @websocket_api.require_admin
948 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/groups/bind",
949 vol.Required(ATTR_SOURCE_IEEE): IEEE_SCHEMA,
950 vol.Required(GROUP_ID): cv.positive_int,
951 vol.Required(BINDINGS): vol.All(cv.ensure_list, [CLUSTER_BINDING_SCHEMA]),
954 @websocket_api.async_response
956 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
958 """Directly bind a device to a group."""
960 source_ieee: EUI64 = msg[ATTR_SOURCE_IEEE]
961 group_id: int = msg[GROUP_ID]
962 bindings: list[ClusterBinding] = msg[BINDINGS]
963 source_device = zha_gateway.get_device(source_ieee)
965 await source_device.async_bind_to_group(group_id, bindings)
966 connection.send_result(msg[ID])
969 @websocket_api.require_admin
970 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/groups/unbind",
971 vol.Required(ATTR_SOURCE_IEEE): IEEE_SCHEMA,
972 vol.Required(GROUP_ID): cv.positive_int,
973 vol.Required(BINDINGS): vol.All(cv.ensure_list, [CLUSTER_BINDING_SCHEMA]),
976 @websocket_api.async_response
978 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
980 """Unbind a device from a group."""
982 source_ieee: EUI64 = msg[ATTR_SOURCE_IEEE]
983 group_id: int = msg[GROUP_ID]
984 bindings: list[ClusterBinding] = msg[BINDINGS]
985 source_device = zha_gateway.get_device(source_ieee)
987 await source_device.async_unbind_from_group(group_id, bindings)
988 connection.send_result(msg[ID])
992 zha_gateway: Gateway,
995 operation: zdo_types.ZDOCmd,
997 """Create or remove a direct zigbee binding between 2 devices."""
999 source_device = zha_gateway.get_device(source_ieee)
1000 target_device = zha_gateway.get_device(target_ieee)
1002 assert source_device
1003 assert target_device
1004 clusters_to_bind = await get_matched_clusters(source_device, target_device)
1006 zdo = source_device.device.zdo
1008 for binding_pair
in clusters_to_bind:
1009 op_msg =
"cluster: %s %s --> [%s]"
1011 binding_pair.source_cluster.cluster_id,
1015 zdo.debug(f
"processing {op_msg}", *op_params)
1022 binding_pair.source_cluster.endpoint.endpoint_id,
1023 binding_pair.source_cluster.cluster_id,
1024 binding_pair.destination_address,
1030 res = await asyncio.gather(*(t[0]
for t
in bind_tasks), return_exceptions=
True)
1031 for outcome, log_msg
in zip(res, bind_tasks, strict=
False):
1032 if isinstance(outcome, Exception):
1033 fmt = f
"{log_msg[1]} failed: %s"
1035 fmt = f
"{log_msg[1]} completed: %s"
1036 zdo.debug(fmt, *(log_msg[2] + (outcome,)))
1039 @websocket_api.require_admin
1040 @websocket_api.websocket_command({vol.Required(TYPE):
"zha/configuration"})
1041 @websocket_api.async_response
1043 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
1045 """Get ZHA configuration."""
1047 import voluptuous_serialize
1050 """Serialize additional types for voluptuous_serialize."""
1051 if schema
is cv_boolean:
1052 return {
"type":
"bool"}
1053 if schema
is vol.Schema:
1054 return voluptuous_serialize.convert(
1055 schema, custom_serializer=custom_serializer
1058 return cv.custom_serializer(schema)
1060 data: dict[str, dict[str, Any]] = {
"schemas": {},
"data": {}}
1061 for section, schema
in ZHA_CONFIG_SCHEMAS.items():
1063 hass, IasAce.cluster_id
1066 data[
"schemas"][section] = voluptuous_serialize.convert(
1067 schema, custom_serializer=custom_serializer
1069 data[
"data"][section] = config_entry.options.get(CUSTOM_CONFIGURATION, {}).
get(
1074 for entry
in data[
"schemas"][section]:
1075 if data[
"data"][section].
get(entry[
"name"])
is None:
1076 data[
"data"][section][entry[
"name"]] = entry[
"default"]
1078 connection.send_result(msg[ID], data)
1081 @websocket_api.require_admin
1082 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/configuration/update",
1083 vol.Required(
"data"): ZHA_CONFIG_SCHEMAS,
1086 @websocket_api.async_response
1088 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
1090 """Update the ZHA configuration."""
1092 options = config_entry.options
1093 data_to_save = {**options, CUSTOM_CONFIGURATION: msg[
"data"]}
1095 for section, schema
in ZHA_CONFIG_SCHEMAS.items():
1096 for entry
in schema.schema:
1099 data_to_save[CUSTOM_CONFIGURATION].
get(section, {}).
get(entry)
1102 data_to_save[CUSTOM_CONFIGURATION][section].pop(entry)
1105 not data_to_save[CUSTOM_CONFIGURATION].
get(section)
1106 and section
in data_to_save[CUSTOM_CONFIGURATION]
1108 data_to_save[CUSTOM_CONFIGURATION].pop(section)
1112 not data_to_save.get(CUSTOM_CONFIGURATION)
1113 and CUSTOM_CONFIGURATION
in data_to_save
1115 data_to_save.pop(CUSTOM_CONFIGURATION)
1118 "Updating ZHA custom configuration options from %s to %s",
1123 hass.config_entries.async_update_entry(config_entry, options=data_to_save)
1124 status = await hass.config_entries.async_reload(config_entry.entry_id)
1125 connection.send_result(msg[ID], status)
1128 @websocket_api.require_admin
1129 @websocket_api.websocket_command({vol.Required(TYPE):
"zha/network/settings"})
1130 @websocket_api.async_response
1132 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
1134 """Get ZHA network settings."""
1138 connection.send_result(
1142 "device": zha_gateway.application_controller.config[CONF_DEVICE],
1143 "settings": backup.as_dict(),
1148 @websocket_api.require_admin
1149 @websocket_api.websocket_command({vol.Required(TYPE):
"zha/network/backups/list"})
1150 @websocket_api.async_response
1152 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
1154 """Get ZHA network settings."""
1156 application_controller = zha_gateway.application_controller
1159 connection.send_result(
1160 msg[ID], [backup.as_dict()
for backup
in application_controller.backups]
1164 @websocket_api.require_admin
1165 @websocket_api.websocket_command({vol.Required(TYPE):
"zha/network/backups/create"})
1166 @websocket_api.async_response
1168 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
1170 """Create a ZHA network backup."""
1172 application_controller = zha_gateway.application_controller
1175 backup = await application_controller.backups.create_backup(load_devices=
True)
1176 connection.send_result(
1179 "backup": backup.as_dict(),
1180 "is_complete": backup.is_complete(),
1185 @websocket_api.require_admin
1186 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/network/backups/restore",
1187 vol.Required(
"backup"): _cv_zigpy_network_backup,
1188 vol.Optional(
"ezsp_force_write_eui64", default=
False): cv.boolean,
1191 @websocket_api.async_response
1193 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
1195 """Restore a ZHA network backup."""
1197 application_controller = zha_gateway.application_controller
1198 backup = msg[
"backup"]
1200 if msg[
"ezsp_force_write_eui64"]:
1201 backup.network_info.stack_specific.setdefault(
"ezsp", {})[
1202 EZSP_OVERWRITE_EUI64
1207 await application_controller.backups.restore_backup(backup)
1208 except ValueError
as err:
1209 connection.send_error(msg[ID], websocket_api.ERR_INVALID_FORMAT,
str(err))
1211 connection.send_result(msg[ID])
1214 @websocket_api.require_admin
1215 @websocket_api.websocket_command(
{
vol.Required(TYPE):
"zha/network/change_channel",
1216 vol.Required(ATTR_NEW_CHANNEL): vol.Any(
"auto", vol.Range(11, 26)),
1219 @websocket_api.async_response
1221 hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
1223 """Migrate the Zigbee network to a new channel."""
1224 new_channel = cast(Literal[
"auto"] | int, msg[ATTR_NEW_CHANNEL])
1226 connection.send_result(msg[ID])
1231 """Set up the web socket API."""
1233 application_controller = zha_gateway.application_controller
1235 async
def permit(service: ServiceCall) ->
None:
1236 """Allow devices to join this network."""
1237 duration: int = service.data[ATTR_DURATION]
1238 ieee: EUI64 |
None = service.data.get(ATTR_IEEE)
1241 if ATTR_SOURCE_IEEE
in service.data:
1242 src_ieee = service.data[ATTR_SOURCE_IEEE]
1243 link_key = service.data[ATTR_INSTALL_CODE]
1244 _LOGGER.info(
"Allowing join for %s device with link key", src_ieee)
1245 await application_controller.permit_with_link_key(
1246 time_s=duration, node=src_ieee, link_key=link_key
1250 if ATTR_QR_CODE
in service.data:
1251 src_ieee, link_key = service.data[ATTR_QR_CODE]
1252 _LOGGER.info(
"Allowing join for %s device with link key", src_ieee)
1253 await application_controller.permit_with_link_key(
1254 time_s=duration, node=src_ieee, link_key=link_key
1259 _LOGGER.info(
"Permitting joins for %ss on %s device", duration, ieee)
1261 _LOGGER.info(
"Permitting joins for %ss", duration)
1262 await application_controller.permit(time_s=duration, node=ieee)
1265 hass, DOMAIN, SERVICE_PERMIT, permit, schema=SERVICE_SCHEMAS[SERVICE_PERMIT]
1268 async
def remove(service: ServiceCall) ->
None:
1269 """Remove a node from the network."""
1271 ieee: EUI64 = service.data[ATTR_IEEE]
1272 _LOGGER.info(
"Removing node %s", ieee)
1273 await zha_gateway.async_remove_device(ieee)
1276 hass, DOMAIN, SERVICE_REMOVE, remove, schema=SERVICE_SCHEMAS[IEEE_SERVICE]
1279 async
def set_zigbee_cluster_attributes(service: ServiceCall) ->
None:
1280 """Set zigbee attribute for cluster on zha entity."""
1281 ieee: EUI64 = service.data[ATTR_IEEE]
1282 endpoint_id: int = service.data[ATTR_ENDPOINT_ID]
1283 cluster_id: int = service.data[ATTR_CLUSTER_ID]
1284 cluster_type: str = service.data[ATTR_CLUSTER_TYPE]
1285 attribute: int | str = service.data[ATTR_ATTRIBUTE]
1286 value: int | bool | str = service.data[ATTR_VALUE]
1287 manufacturer: int |
None = service.data.get(ATTR_MANUFACTURER)
1288 zha_device = zha_gateway.get_device(ieee)
1290 if zha_device
is not None:
1291 response = await zha_device.write_zigbee_attribute(
1296 cluster_type=cluster_type,
1297 manufacturer=manufacturer,
1300 raise ValueError(f
"Device with IEEE {ieee!s} not found")
1304 "Set attribute for: %s: [%s] %s: [%s] %s: [%s] %s: [%s] %s: [%s] %s:"
1326 SERVICE_SET_ZIGBEE_CLUSTER_ATTRIBUTE,
1327 set_zigbee_cluster_attributes,
1328 schema=SERVICE_SCHEMAS[SERVICE_SET_ZIGBEE_CLUSTER_ATTRIBUTE],
1331 async
def issue_zigbee_cluster_command(service: ServiceCall) ->
None:
1332 """Issue command on zigbee cluster on ZHA entity."""
1333 ieee: EUI64 = service.data[ATTR_IEEE]
1334 endpoint_id: int = service.data[ATTR_ENDPOINT_ID]
1335 cluster_id: int = service.data[ATTR_CLUSTER_ID]
1336 cluster_type: str = service.data[ATTR_CLUSTER_TYPE]
1337 command: int = service.data[ATTR_COMMAND]
1338 command_type: str = service.data[ATTR_COMMAND_TYPE]
1339 args: list |
None = service.data.get(ATTR_ARGS)
1340 params: dict |
None = service.data.get(ATTR_PARAMS)
1341 manufacturer: int |
None = service.data.get(ATTR_MANUFACTURER)
1342 zha_device = zha_gateway.get_device(ieee)
1343 if zha_device
is not None:
1344 if cluster_id >= MFG_CLUSTER_ID_START
and manufacturer
is None:
1345 manufacturer = zha_device.manufacturer_code
1347 await zha_device.issue_cluster_command(
1354 cluster_type=cluster_type,
1355 manufacturer=manufacturer,
1359 "Issued command for: %s: [%s] %s: [%s] %s: [%s] %s: [%s] %s: [%s]"
1360 " %s: [%s] %s: [%s] %s: [%s]"
1380 raise ValueError(f
"Device with IEEE {ieee!s} not found")
1385 SERVICE_ISSUE_ZIGBEE_CLUSTER_COMMAND,
1386 issue_zigbee_cluster_command,
1387 schema=SERVICE_SCHEMAS[SERVICE_ISSUE_ZIGBEE_CLUSTER_COMMAND],
1390 async
def issue_zigbee_group_command(service: ServiceCall) ->
None:
1391 """Issue command on zigbee cluster on a zigbee group."""
1392 group_id: int = service.data[ATTR_GROUP]
1393 cluster_id: int = service.data[ATTR_CLUSTER_ID]
1394 command: int = service.data[ATTR_COMMAND]
1395 args: list = service.data[ATTR_ARGS]
1396 manufacturer: int |
None = service.data.get(ATTR_MANUFACTURER)
1397 group = zha_gateway.get_group(group_id)
1398 if cluster_id >= MFG_CLUSTER_ID_START
and manufacturer
is None:
1399 _LOGGER.error(
"Missing manufacturer attribute for cluster: %d", cluster_id)
1401 if group
is not None:
1402 cluster = group.endpoint[cluster_id]
1403 response = await cluster.command(
1404 command, *args, manufacturer=manufacturer, expect_reply=
True
1407 "Issued group command for: %s: [%s] %s: [%s] %s: %s %s: [%s] %s: %s",
1423 SERVICE_ISSUE_ZIGBEE_GROUP_COMMAND,
1424 issue_zigbee_group_command,
1425 schema=SERVICE_SCHEMAS[SERVICE_ISSUE_ZIGBEE_GROUP_COMMAND],
1428 def _get_ias_wd_cluster_handler(zha_device):
1429 """Get the IASWD cluster handler for a device."""
1430 cluster_handlers = {
1432 for endpoint
in zha_device.endpoints.values()
1433 for ch
in endpoint.claimed_cluster_handlers.values()
1435 return cluster_handlers.get(CLUSTER_HANDLER_IAS_WD)
1437 async
def warning_device_squawk(service: ServiceCall) ->
None:
1438 """Issue the squawk command for an IAS warning device."""
1439 ieee: EUI64 = service.data[ATTR_IEEE]
1440 mode: int = service.data[ATTR_WARNING_DEVICE_MODE]
1441 strobe: int = service.data[ATTR_WARNING_DEVICE_STROBE]
1442 level: int = service.data[ATTR_LEVEL]
1444 if (zha_device := zha_gateway.get_device(ieee))
is not None:
1445 if cluster_handler := _get_ias_wd_cluster_handler(zha_device):
1446 await cluster_handler.issue_squawk(mode, strobe, level)
1449 "Squawking IASWD: %s: [%s] is missing the required IASWD cluster handler!",
1455 "Squawking IASWD: %s: [%s] could not be found!", ATTR_IEEE,
str(ieee)
1458 "Squawking IASWD: %s: [%s] %s: [%s] %s: [%s] %s: [%s]",
1461 ATTR_WARNING_DEVICE_MODE,
1463 ATTR_WARNING_DEVICE_STROBE,
1472 SERVICE_WARNING_DEVICE_SQUAWK,
1473 warning_device_squawk,
1474 schema=SERVICE_SCHEMAS[SERVICE_WARNING_DEVICE_SQUAWK],
1477 async
def warning_device_warn(service: ServiceCall) ->
None:
1478 """Issue the warning command for an IAS warning device."""
1479 ieee: EUI64 = service.data[ATTR_IEEE]
1480 mode: int = service.data[ATTR_WARNING_DEVICE_MODE]
1481 strobe: int = service.data[ATTR_WARNING_DEVICE_STROBE]
1482 level: int = service.data[ATTR_LEVEL]
1483 duration: int = service.data[ATTR_WARNING_DEVICE_DURATION]
1484 duty_mode: int = service.data[ATTR_WARNING_DEVICE_STROBE_DUTY_CYCLE]
1485 intensity: int = service.data[ATTR_WARNING_DEVICE_STROBE_INTENSITY]
1487 if (zha_device := zha_gateway.get_device(ieee))
is not None:
1488 if cluster_handler := _get_ias_wd_cluster_handler(zha_device):
1489 await cluster_handler.issue_start_warning(
1490 mode, strobe, level, duration, duty_mode, intensity
1494 "Warning IASWD: %s: [%s] is missing the required IASWD cluster handler!",
1500 "Warning IASWD: %s: [%s] could not be found!", ATTR_IEEE,
str(ieee)
1503 "Warning IASWD: %s: [%s] %s: [%s] %s: [%s] %s: [%s]",
1506 ATTR_WARNING_DEVICE_MODE,
1508 ATTR_WARNING_DEVICE_STROBE,
1517 SERVICE_WARNING_DEVICE_WARN,
1518 warning_device_warn,
1519 schema=SERVICE_SCHEMAS[SERVICE_WARNING_DEVICE_WARN],
1522 websocket_api.async_register_command(hass, websocket_permit_devices)
1523 websocket_api.async_register_command(hass, websocket_get_devices)
1524 websocket_api.async_register_command(hass, websocket_get_groupable_devices)
1525 websocket_api.async_register_command(hass, websocket_get_groups)
1526 websocket_api.async_register_command(hass, websocket_get_device)
1527 websocket_api.async_register_command(hass, websocket_get_group)
1528 websocket_api.async_register_command(hass, websocket_add_group)
1529 websocket_api.async_register_command(hass, websocket_remove_groups)
1530 websocket_api.async_register_command(hass, websocket_add_group_members)
1531 websocket_api.async_register_command(hass, websocket_remove_group_members)
1532 websocket_api.async_register_command(hass, websocket_bind_group)
1533 websocket_api.async_register_command(hass, websocket_unbind_group)
1534 websocket_api.async_register_command(hass, websocket_reconfigure_node)
1535 websocket_api.async_register_command(hass, websocket_device_clusters)
1536 websocket_api.async_register_command(hass, websocket_device_cluster_attributes)
1537 websocket_api.async_register_command(hass, websocket_device_cluster_commands)
1538 websocket_api.async_register_command(hass, websocket_read_zigbee_cluster_attributes)
1539 websocket_api.async_register_command(hass, websocket_get_bindable_devices)
1540 websocket_api.async_register_command(hass, websocket_bind_devices)
1541 websocket_api.async_register_command(hass, websocket_unbind_devices)
1542 websocket_api.async_register_command(hass, websocket_update_topology)
1543 websocket_api.async_register_command(hass, websocket_get_configuration)
1544 websocket_api.async_register_command(hass, websocket_update_zha_configuration)
1545 websocket_api.async_register_command(hass, websocket_get_network_settings)
1546 websocket_api.async_register_command(hass, websocket_list_network_backups)
1547 websocket_api.async_register_command(hass, websocket_create_network_backup)
1548 websocket_api.async_register_command(hass, websocket_restore_network_backup)
1549 websocket_api.async_register_command(hass, websocket_change_channel)
1554 """Unload the ZHA API."""
1555 hass.services.async_remove(DOMAIN, SERVICE_PERMIT)
1556 hass.services.async_remove(DOMAIN, SERVICE_REMOVE)
1557 hass.services.async_remove(DOMAIN, SERVICE_SET_ZIGBEE_CLUSTER_ATTRIBUTE)
1558 hass.services.async_remove(DOMAIN, SERVICE_ISSUE_ZIGBEE_CLUSTER_COMMAND)
1559 hass.services.async_remove(DOMAIN, SERVICE_ISSUE_ZIGBEE_GROUP_COMMAND)
1560 hass.services.async_remove(DOMAIN, SERVICE_WARNING_DEVICE_SQUAWK)
1561 hass.services.async_remove(DOMAIN, SERVICE_WARNING_DEVICE_WARN)
1562
bool remove(self, _T matcher)
web.Response get(self, web.Request request, str config_key)
HabiticaConfigEntry get_config_entry(HomeAssistant hass, str entry_id)
None async_change_channel(HomeAssistant hass, OTBRData data, int channel, float delay)
NetworkBackup async_get_active_network_settings(HomeAssistant hass)
RadioType async_get_radio_type(HomeAssistant hass, ConfigEntry|None config_entry=None)
Gateway get_zha_gateway(HomeAssistant hass)
vol.Schema cluster_command_schema_to_vol_schema(CommandSchema schema)
ZHAGatewayProxy get_zha_gateway_proxy(HomeAssistant hass)
def async_cluster_exists(HomeAssistant hass, cluster_id, skip_coordinator=True)
None websocket_reconfigure_node(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_update_topology(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_get_devices(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_get_device(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_unbind_devices(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_remove_groups(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
str|None _get_entity_name(Gateway zha_gateway, EntityReference entity_ref)
GroupMemberReference _cv_group_member(dict[str, Any] value)
None websocket_bind_group(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_change_channel(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_get_network_settings(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_get_group(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
zigpy.backups.NetworkBackup _cv_zigpy_network_backup(dict[str, Any] value)
None websocket_device_clusters(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_unbind_group(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
str|None _get_entity_original_name(Gateway zha_gateway, EntityReference entity_ref)
None websocket_get_groups(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_get_bindable_devices(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_restore_network_backup(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
ClusterBinding _cv_cluster_binding(dict[str, Any] value)
None websocket_bind_devices(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_permit_devices(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_device_cluster_attributes(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_remove_group_members(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_create_network_backup(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None async_load_api(HomeAssistant hass)
None websocket_read_zigbee_cluster_attributes(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_list_network_backups(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None async_unload_api(HomeAssistant hass)
None websocket_update_zha_configuration(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_get_configuration(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_add_group(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_get_groupable_devices(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None websocket_add_group_members(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
None async_binding_operation(Gateway zha_gateway, EUI64 source_ieee, EUI64 target_ieee, zdo_types.ZDOCmd operation)
None websocket_device_cluster_commands(HomeAssistant hass, ActiveConnection connection, dict[str, Any] msg)
Any custom_serializer(Any schema)
None async_cleanup(HomeAssistant hass, DeviceRegistry dev_reg, entity_registry.EntityRegistry ent_reg)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
None async_register_admin_service(HomeAssistant hass, str domain, str service, Callable[[ServiceCall], Awaitable[None]|None] service_func, VolSchemaType schema=vol.Schema({}, extra=vol.PREVENT_EXTRA))