Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The pi_hole component."""
2 
3 from __future__ import annotations
4 
5 from dataclasses import dataclass
6 import logging
7 
8 from hole import Hole
9 from hole.exceptions import HoleError
10 
11 from homeassistant.config_entries import ConfigEntry
12 from homeassistant.const import (
13  CONF_API_KEY,
14  CONF_HOST,
15  CONF_LOCATION,
16  CONF_NAME,
17  CONF_SSL,
18  CONF_VERIFY_SSL,
19  Platform,
20 )
21 from homeassistant.core import HomeAssistant, callback
22 from homeassistant.exceptions import ConfigEntryAuthFailed
23 from homeassistant.helpers import entity_registry as er
24 from homeassistant.helpers.aiohttp_client import async_get_clientsession
25 from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
26 
27 from .const import CONF_STATISTICS_ONLY, DOMAIN, MIN_TIME_BETWEEN_UPDATES
28 
29 _LOGGER = logging.getLogger(__name__)
30 
31 
32 PLATFORMS = [
33  Platform.BINARY_SENSOR,
34  Platform.SENSOR,
35  Platform.SWITCH,
36  Platform.UPDATE,
37 ]
38 
39 type PiHoleConfigEntry = ConfigEntry[PiHoleData]
40 
41 
42 @dataclass
43 class PiHoleData:
44  """Runtime data definition."""
45 
46  api: Hole
47  coordinator: DataUpdateCoordinator[None]
48 
49 
50 async def async_setup_entry(hass: HomeAssistant, entry: PiHoleConfigEntry) -> bool:
51  """Set up Pi-hole entry."""
52  name = entry.data[CONF_NAME]
53  host = entry.data[CONF_HOST]
54  use_tls = entry.data[CONF_SSL]
55  verify_tls = entry.data[CONF_VERIFY_SSL]
56  location = entry.data[CONF_LOCATION]
57  api_key = entry.data.get(CONF_API_KEY, "")
58 
59  # remove obsolet CONF_STATISTICS_ONLY from entry.data
60  if CONF_STATISTICS_ONLY in entry.data:
61  entry_data = entry.data.copy()
62  entry_data.pop(CONF_STATISTICS_ONLY)
63  hass.config_entries.async_update_entry(entry, data=entry_data)
64 
65  _LOGGER.debug("Setting up %s integration with host %s", DOMAIN, host)
66 
67  name_to_key = {
68  "Core Update Available": "core_update_available",
69  "Web Update Available": "web_update_available",
70  "FTL Update Available": "ftl_update_available",
71  "Status": "status",
72  "Ads Blocked Today": "ads_blocked_today",
73  "Ads Percentage Blocked Today": "ads_percentage_today",
74  "Seen Clients": "clients_ever_seen",
75  "DNS Queries Today": "dns_queries_today",
76  "Domains Blocked": "domains_being_blocked",
77  "DNS Queries Cached": "queries_cached",
78  "DNS Queries Forwarded": "queries_forwarded",
79  "DNS Unique Clients": "unique_clients",
80  "DNS Unique Domains": "unique_domains",
81  }
82 
83  @callback
84  def update_unique_id(
85  entity_entry: er.RegistryEntry,
86  ) -> dict[str, str] | None:
87  """Update unique ID of entity entry."""
88  unique_id_parts = entity_entry.unique_id.split("/")
89  if len(unique_id_parts) == 2 and unique_id_parts[1] in name_to_key:
90  name = unique_id_parts[1]
91  new_unique_id = entity_entry.unique_id.replace(name, name_to_key[name])
92  _LOGGER.debug("Migrate %s to %s", entity_entry.unique_id, new_unique_id)
93  return {"new_unique_id": new_unique_id}
94 
95  return None
96 
97  await er.async_migrate_entries(hass, entry.entry_id, update_unique_id)
98 
99  session = async_get_clientsession(hass, verify_tls)
100  api = Hole(
101  host,
102  session,
103  location=location,
104  tls=use_tls,
105  api_token=api_key,
106  )
107 
108  async def async_update_data() -> None:
109  """Fetch data from API endpoint."""
110  try:
111  await api.get_data()
112  await api.get_versions()
113  except HoleError as err:
114  raise UpdateFailed(f"Failed to communicate with API: {err}") from err
115  if not isinstance(api.data, dict):
116  raise ConfigEntryAuthFailed
117 
118  coordinator = DataUpdateCoordinator(
119  hass,
120  _LOGGER,
121  config_entry=entry,
122  name=name,
123  update_method=async_update_data,
124  update_interval=MIN_TIME_BETWEEN_UPDATES,
125  )
126 
127  await coordinator.async_config_entry_first_refresh()
128 
129  entry.runtime_data = PiHoleData(api, coordinator)
130 
131  await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
132 
133  return True
134 
135 
136 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
137  """Unload Pi-hole entry."""
138  return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
dict[str, str]|None update_unique_id(er.RegistryEntry entity_entry, str unique_id)
Definition: __init__.py:168
bool async_setup_entry(HomeAssistant hass, PiHoleConfigEntry entry)
Definition: __init__.py:50
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:136
aiohttp.ClientSession async_get_clientsession(HomeAssistant hass, bool verify_ssl=True, socket.AddressFamily family=socket.AF_UNSPEC, ssl_util.SSLCipherList ssl_cipher=ssl_util.SSLCipherList.PYTHON_DEFAULT)