Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The Rituals Perfume Genie integration."""
2 
3 import asyncio
4 
5 import aiohttp
6 from pyrituals import Account, Diffuser
7 
8 from homeassistant.config_entries import ConfigEntry
9 from homeassistant.const import Platform
10 from homeassistant.core import HomeAssistant, callback
11 from homeassistant.exceptions import ConfigEntryNotReady
12 from homeassistant.helpers import entity_registry as er
13 from homeassistant.helpers.aiohttp_client import async_get_clientsession
14 
15 from .const import ACCOUNT_HASH, DOMAIN, UPDATE_INTERVAL
16 from .coordinator import RitualsDataUpdateCoordinator
17 
18 PLATFORMS = [
19  Platform.BINARY_SENSOR,
20  Platform.NUMBER,
21  Platform.SELECT,
22  Platform.SENSOR,
23  Platform.SWITCH,
24 ]
25 
26 
27 async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
28  """Set up Rituals Perfume Genie from a config entry."""
29  session = async_get_clientsession(hass)
30  account = Account(session=session, account_hash=entry.data[ACCOUNT_HASH])
31 
32  try:
33  account_devices = await account.get_devices()
34  except aiohttp.ClientError as err:
35  raise ConfigEntryNotReady from err
36 
37  # Migrate old unique_ids to the new format
38  async_migrate_entities_unique_ids(hass, entry, account_devices)
39 
40  # The API provided by Rituals is currently rate limited to 30 requests
41  # per hour per IP address. To avoid hitting this limit, we will adjust
42  # the polling interval based on the number of diffusers one has.
43  update_interval = UPDATE_INTERVAL * len(account_devices)
44 
45  # Create a coordinator for each diffuser
46  coordinators = {
47  diffuser.hublot: RitualsDataUpdateCoordinator(hass, diffuser, update_interval)
48  for diffuser in account_devices
49  }
50 
51  # Refresh all coordinators
52  await asyncio.gather(
53  *[
54  coordinator.async_config_entry_first_refresh()
55  for coordinator in coordinators.values()
56  ]
57  )
58 
59  hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinators
60  await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
61 
62  return True
63 
64 
65 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
66  """Unload a config entry."""
67  unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
68  if unload_ok:
69  hass.data[DOMAIN].pop(entry.entry_id)
70 
71  return unload_ok
72 
73 
74 @callback
76  hass: HomeAssistant, config_entry: ConfigEntry, diffusers: list[Diffuser]
77 ) -> None:
78  """Migrate unique_ids in the entity registry to the new format."""
79  entity_registry = er.async_get(hass)
80  registry_entries = er.async_entries_for_config_entry(
81  entity_registry, config_entry.entry_id
82  )
83 
84  conversion: dict[tuple[str, str], str] = {
85  (Platform.BINARY_SENSOR, " Battery Charging"): "charging",
86  (Platform.NUMBER, " Perfume Amount"): "perfume_amount",
87  (Platform.SELECT, " Room Size"): "room_size_square_meter",
88  (Platform.SENSOR, " Battery"): "battery_percentage",
89  (Platform.SENSOR, " Fill"): "fill",
90  (Platform.SENSOR, " Perfume"): "perfume",
91  (Platform.SENSOR, " Wifi"): "wifi_percentage",
92  (Platform.SWITCH, ""): "is_on",
93  }
94 
95  for diffuser in diffusers:
96  for registry_entry in registry_entries:
97  if new_unique_id := conversion.get(
98  (
99  registry_entry.domain,
100  registry_entry.unique_id.removeprefix(diffuser.hublot),
101  )
102  ):
103  entity_registry.async_update_entity(
104  registry_entry.entity_id,
105  new_unique_id=f"{diffuser.hublot}-{new_unique_id}",
106  )
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:65
None async_migrate_entities_unique_ids(HomeAssistant hass, ConfigEntry config_entry, list[Diffuser] diffusers)
Definition: __init__.py:77
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:27
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)