Home Assistant Unofficial Reference 2024.12.1
diagnostics.py
Go to the documentation of this file.
1 """Support for the Airzone Cloud diagnostics."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Mapping
6 from typing import Any
7 
8 from aioairzone_cloud.const import (
9  API_CITY,
10  API_GROUP_ID,
11  API_GROUPS,
12  API_LOCATION_ID,
13  API_OLD_ID,
14  API_PIN,
15  API_STAT_AP_MAC,
16  API_STAT_SSID,
17  API_USER_ID,
18  AZD_WIFI_MAC,
19  RAW_DEVICES_STATUS,
20  RAW_INSTALLATIONS,
21  RAW_WEBSERVERS,
22 )
23 
24 from homeassistant.components.diagnostics import async_redact_data
25 from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
26 from homeassistant.core import HomeAssistant
27 
28 from . import AirzoneCloudConfigEntry
29 
30 TO_REDACT_API = [
31  API_CITY,
32  API_LOCATION_ID,
33  API_OLD_ID,
34  API_PIN,
35  API_STAT_AP_MAC,
36  API_STAT_SSID,
37  API_USER_ID,
38 ]
39 
40 TO_REDACT_CONFIG = [
41  CONF_PASSWORD,
42  CONF_USERNAME,
43 ]
44 
45 TO_REDACT_COORD = [
46  AZD_WIFI_MAC,
47 ]
48 
49 
50 def gather_ids(api_data: dict[str, Any]) -> dict[str, Any]:
51  """Return dict with IDs."""
52  ids: dict[str, Any] = {}
53 
54  dev_idx = 1
55  for dev_id in api_data[RAW_DEVICES_STATUS]:
56  if dev_id not in ids:
57  ids[dev_id] = f"device{dev_idx}"
58  dev_idx += 1
59 
60  group_idx = 1
61  inst_idx = 1
62  for inst_id, inst_data in api_data[RAW_INSTALLATIONS].items():
63  if inst_id not in ids:
64  ids[inst_id] = f"installation{inst_idx}"
65  inst_idx += 1
66  for group in inst_data[API_GROUPS]:
67  group_id = group[API_GROUP_ID]
68  if group_id not in ids:
69  ids[group_id] = f"group{group_idx}"
70  group_idx += 1
71 
72  ws_idx = 1
73  for ws_id in api_data[RAW_WEBSERVERS]:
74  if ws_id not in ids:
75  ids[ws_id] = f"webserver{ws_idx}"
76  ws_idx += 1
77 
78  return ids
79 
80 
81 def redact_keys(data: Any, ids: dict[str, Any]) -> Any:
82  """Redact sensitive keys in a dict."""
83  if not isinstance(data, (Mapping, list)):
84  return data
85 
86  if isinstance(data, list):
87  return [redact_keys(val, ids) for val in data]
88 
89  redacted = {**data}
90 
91  keys = list(redacted)
92  for key in keys:
93  if key in ids:
94  redacted[ids[key]] = redacted.pop(key)
95  elif isinstance(redacted[key], Mapping):
96  redacted[key] = redact_keys(redacted[key], ids)
97  elif isinstance(redacted[key], list):
98  redacted[key] = [redact_keys(item, ids) for item in redacted[key]]
99 
100  return redacted
101 
102 
103 def redact_values(data: Any, ids: dict[str, Any]) -> Any:
104  """Redact sensitive values in a dict."""
105  if not isinstance(data, (Mapping, list)):
106  if data in ids:
107  return ids[data]
108  return data
109 
110  if isinstance(data, list):
111  return [redact_values(val, ids) for val in data]
112 
113  redacted = {**data}
114 
115  for key, value in redacted.items():
116  if value is None:
117  continue
118  if isinstance(value, Mapping):
119  redacted[key] = redact_values(value, ids)
120  elif isinstance(value, list):
121  redacted[key] = [redact_values(item, ids) for item in value]
122  elif value in ids:
123  redacted[key] = ids[value]
124 
125  return redacted
126 
127 
129  data: dict[str, Any], ids: dict[str, Any], to_redact: list[str]
130 ) -> dict[str, Any]:
131  """Redact sensitive data."""
132  _data = redact_keys(data, ids)
133  _data = redact_values(_data, ids)
134  return async_redact_data(_data, to_redact)
135 
136 
138  hass: HomeAssistant, config_entry: AirzoneCloudConfigEntry
139 ) -> dict[str, Any]:
140  """Return diagnostics for a config entry."""
141  coordinator = config_entry.runtime_data
142  raw_data = coordinator.airzone.raw_data()
143  ids = gather_ids(raw_data)
144 
145  return {
146  "api_data": redact_all(raw_data, ids, TO_REDACT_API),
147  "config_entry": redact_all(config_entry.as_dict(), ids, TO_REDACT_CONFIG),
148  "coord_data": redact_all(coordinator.data, ids, TO_REDACT_COORD),
149  }
dict[str, Any] redact_all(dict[str, Any] data, dict[str, Any] ids, list[str] to_redact)
Definition: diagnostics.py:130
Any redact_keys(Any data, dict[str, Any] ids)
Definition: diagnostics.py:81
dict[str, Any] gather_ids(dict[str, Any] api_data)
Definition: diagnostics.py:50
Any redact_values(Any data, dict[str, Any] ids)
Definition: diagnostics.py:103
dict[str, Any] async_get_config_entry_diagnostics(HomeAssistant hass, AirzoneCloudConfigEntry config_entry)
Definition: diagnostics.py:139
dict async_redact_data(Mapping data, Iterable[Any] to_redact)
Definition: util.py:14