Home Assistant Unofficial Reference 2024.12.1
diagnostics.py
Go to the documentation of this file.
1 """Diagnostics support for HomeKit Controller."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 from aiohomekit.model.characteristics.characteristic_types import CharacteristicsTypes
8 
9 from homeassistant.components.diagnostics import REDACTED, async_redact_data
10 from homeassistant.config_entries import ConfigEntry
11 from homeassistant.core import HomeAssistant, callback
12 from homeassistant.helpers import device_registry as dr, entity_registry as er
13 from homeassistant.helpers.device_registry import DeviceEntry
14 
15 from .connection import HKDevice
16 from .const import KNOWN_DEVICES
17 
18 REDACTED_CHARACTERISTICS = [
19  CharacteristicsTypes.SERIAL_NUMBER,
20 ]
21 
22 REDACTED_CONFIG_ENTRY_KEYS = [
23  "AccessoryIP",
24  "iOSDeviceLTSK",
25 ]
26 
27 REDACTED_STATE = ["access_token", "entity_picture"]
28 
29 
31  hass: HomeAssistant, entry: ConfigEntry
32 ) -> dict[str, Any]:
33  """Return diagnostics for a config entry."""
34  return _async_get_diagnostics(hass, entry)
35 
36 
38  hass: HomeAssistant, entry: ConfigEntry, device: DeviceEntry
39 ) -> dict[str, Any]:
40  """Return diagnostics for a device entry."""
41  return _async_get_diagnostics(hass, entry, device)
42 
43 
44 @callback
46  hass: HomeAssistant, device: DeviceEntry
47 ) -> dict[str, Any]:
48  data: dict[str, Any] = {}
49 
50  data["name"] = device.name
51  data["model"] = device.model
52  data["manfacturer"] = device.manufacturer
53  data["sw_version"] = device.sw_version
54  data["hw_version"] = device.hw_version
55 
56  entities = data["entities"] = []
57 
58  hass_entities = er.async_entries_for_device(
59  er.async_get(hass),
60  device_id=device.id,
61  include_disabled_entities=True,
62  )
63 
64  hass_entities.sort(key=lambda entry: entry.original_name or "")
65 
66  for entity_entry in hass_entities:
67  state = hass.states.get(entity_entry.entity_id)
68  state_dict = None
69  if state:
70  state_dict = async_redact_data(state.as_dict(), REDACTED_STATE)
71  state_dict.pop("context", None)
72 
73  entities.append(
74  {
75  "original_name": entity_entry.original_name,
76  "original_device_class": entity_entry.original_device_class,
77  "entity_category": entity_entry.entity_category,
78  "original_icon": entity_entry.original_icon,
79  "icon": entity_entry.icon,
80  "unit_of_measurement": entity_entry.unit_of_measurement,
81  "device_class": entity_entry.device_class,
82  "disabled": entity_entry.disabled,
83  "disabled_by": entity_entry.disabled_by,
84  "state": state_dict,
85  }
86  )
87 
88  return data
89 
90 
91 @callback
93  hass: HomeAssistant, entry: ConfigEntry, device: DeviceEntry | None = None
94 ) -> dict[str, Any]:
95  """Return diagnostics for a config entry."""
96  hkid = entry.data["AccessoryPairingID"]
97  connection: HKDevice = hass.data[KNOWN_DEVICES][hkid]
98 
99  data: dict[str, Any] = {
100  "config-entry": {
101  "title": entry.title,
102  "version": entry.version,
103  "data": async_redact_data(entry.data, REDACTED_CONFIG_ENTRY_KEYS),
104  }
105  }
106 
107  # This is the raw data as returned by homekit
108  # It is roughly equivalent to what is in .storage/homekit_controller-entity-map
109  # But it also has the latest values seen by the polling or events
110  data["entity-map"] = accessories = connection.entity_map.serialize()
111  data["config-num"] = connection.config_num
112 
113  # It contains serial numbers, which we should strip out
114  for accessory in accessories:
115  for service in accessory.get("services", []):
116  for char in service.get("characteristics", []):
117  if char["type"] in REDACTED_CHARACTERISTICS:
118  char["value"] = REDACTED
119 
120  if device:
121  data["device"] = _async_get_diagnostics_for_device(hass, device)
122  else:
123  device_registry = dr.async_get(hass)
124 
125  devices = data["devices"] = []
126  for device_id in connection.devices.values():
127  if not (device := device_registry.async_get(device_id)):
128  continue
129  devices.append(_async_get_diagnostics_for_device(hass, device))
130 
131  return data
dict async_redact_data(Mapping data, Iterable[Any] to_redact)
Definition: util.py:14
dict[str, Any] async_get_config_entry_diagnostics(HomeAssistant hass, ConfigEntry entry)
Definition: diagnostics.py:32
dict[str, Any] _async_get_diagnostics_for_device(HomeAssistant hass, DeviceEntry device)
Definition: diagnostics.py:47
dict[str, Any] _async_get_diagnostics(HomeAssistant hass, ConfigEntry entry, DeviceEntry|None device=None)
Definition: diagnostics.py:94
dict[str, Any] async_get_device_diagnostics(HomeAssistant hass, ConfigEntry entry, DeviceEntry device)
Definition: diagnostics.py:39