Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The Hunter Douglas PowerView integration."""
2 
3 import logging
4 from typing import TYPE_CHECKING
5 
6 from aiopvapi.resources.model import PowerviewData
7 from aiopvapi.rooms import Rooms
8 from aiopvapi.scenes import Scenes
9 from aiopvapi.shades import Shades
10 
11 from homeassistant.const import CONF_API_VERSION, CONF_HOST, Platform
12 from homeassistant.core import HomeAssistant
13 from homeassistant.exceptions import ConfigEntryNotReady
15 
16 from .const import DOMAIN, HUB_EXCEPTIONS
17 from .coordinator import PowerviewShadeUpdateCoordinator
18 from .model import PowerviewConfigEntry, PowerviewEntryData
19 from .shade_data import PowerviewShadeData
20 from .util import async_connect_hub
21 
22 PARALLEL_UPDATES = 1
23 
24 
25 PLATFORMS = [
26  Platform.BUTTON,
27  Platform.COVER,
28  Platform.NUMBER,
29  Platform.SCENE,
30  Platform.SELECT,
31  Platform.SENSOR,
32 ]
33 _LOGGER = logging.getLogger(__name__)
34 
35 
36 async def async_setup_entry(hass: HomeAssistant, entry: PowerviewConfigEntry) -> bool:
37  """Set up Hunter Douglas PowerView from a config entry."""
38  config = entry.data
39  hub_address: str = config[CONF_HOST]
40  api_version: int | None = config.get(CONF_API_VERSION)
41  _LOGGER.debug("Connecting %s at %s with v%s api", DOMAIN, hub_address, api_version)
42 
43  # default 15 second timeout for each call in upstream
44  try:
45  api = await async_connect_hub(hass, hub_address, api_version)
46  except HUB_EXCEPTIONS as err:
47  raise ConfigEntryNotReady(
48  f"Connection error to PowerView hub {hub_address}: {err}"
49  ) from err
50 
51  hub = api.hub
52  pv_request = api.pv_request
53  device_info = api.device_info
54 
55  if hub.role != "Primary":
56  # this should be caught in config_flow, but account for a hub changing roles
57  # this will only happen manually by a user
58  _LOGGER.error(
59  "%s (%s) is performing role of %s Hub. "
60  "Only the Primary Hub can manage shades",
61  hub.name,
62  hub.hub_address,
63  hub.role,
64  )
65  return False
66 
67  try:
68  rooms = Rooms(pv_request)
69  room_data: PowerviewData = await rooms.get_rooms()
70 
71  scenes = Scenes(pv_request)
72  scene_data: PowerviewData = await scenes.get_scenes()
73 
74  shades = Shades(pv_request)
75  shade_data: PowerviewData = await shades.get_shades()
76  except HUB_EXCEPTIONS as err:
77  raise ConfigEntryNotReady(
78  f"Connection error to PowerView hub {hub_address}: {err}"
79  ) from err
80 
81  if not device_info:
82  raise ConfigEntryNotReady(f"Unable to initialize PowerView hub: {hub_address}")
83 
84  if CONF_API_VERSION not in config:
85  new_data = {**entry.data}
86  new_data[CONF_API_VERSION] = hub.api_version
87  hass.config_entries.async_update_entry(entry, data=new_data)
88 
89  if entry.unique_id is None:
90  hass.config_entries.async_update_entry(
91  entry, unique_id=device_info.serial_number
92  )
93 
94  coordinator = PowerviewShadeUpdateCoordinator(hass, shades, hub)
95  coordinator.async_set_updated_data(PowerviewShadeData())
96  # populate raw shade data into the coordinator for diagnostics
97  coordinator.data.store_group_data(shade_data)
98 
99  entry.runtime_data = PowerviewEntryData(
100  api=pv_request,
101  room_data=room_data.processed,
102  scene_data=scene_data.processed,
103  shade_data=shade_data.processed,
104  coordinator=coordinator,
105  device_info=device_info,
106  )
107 
108  await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
109 
110  return True
111 
112 
113 async def async_unload_entry(hass: HomeAssistant, entry: PowerviewConfigEntry) -> bool:
114  """Unload a config entry."""
115  return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
116 
117 
118 async def async_migrate_entry(hass: HomeAssistant, entry: PowerviewConfigEntry) -> bool:
119  """Migrate entry."""
120 
121  _LOGGER.debug("Migrating from version %s.%s", entry.version, entry.minor_version)
122 
123  if entry.version == 1:
124  # 1 -> 2: Unique ID from integer to string
125  if entry.minor_version == 1:
126  if entry.unique_id is None:
127  await _async_add_missing_entry_unique_id(hass, entry)
128  await _migrate_unique_ids(hass, entry)
129  hass.config_entries.async_update_entry(entry, minor_version=2)
130 
131  _LOGGER.debug("Migrated to version %s.%s", entry.version, entry.minor_version)
132 
133  return True
134 
135 
137  hass: HomeAssistant, entry: PowerviewConfigEntry
138 ) -> None:
139  """Add the unique id if its missing."""
140  address: str = entry.data[CONF_HOST]
141  api_version: int | None = entry.data.get(CONF_API_VERSION)
142  api = await async_connect_hub(hass, address, api_version)
143  hass.config_entries.async_update_entry(
144  entry, unique_id=api.device_info.serial_number
145  )
146 
147 
148 async def _migrate_unique_ids(hass: HomeAssistant, entry: PowerviewConfigEntry) -> None:
149  """Migrate int based unique ids to str."""
150  entity_registry = er.async_get(hass)
151  registry_entries = er.async_entries_for_config_entry(
152  entity_registry, entry.entry_id
153  )
154  if TYPE_CHECKING:
155  assert entry.unique_id
156  for reg_entry in registry_entries:
157  if isinstance(reg_entry.unique_id, int) or (
158  isinstance(reg_entry.unique_id, str)
159  and not reg_entry.unique_id.startswith(entry.unique_id)
160  ):
161  _LOGGER.debug(
162  "Migrating %s: %s to %s_%s",
163  reg_entry.entity_id,
164  reg_entry.unique_id,
165  entry.unique_id,
166  reg_entry.unique_id,
167  )
168  entity_registry.async_update_entity(
169  reg_entry.entity_id,
170  new_unique_id=f"{entry.unique_id}_{reg_entry.unique_id}",
171  )
PowerviewAPI async_connect_hub(HomeAssistant hass, str address, int|None api_version=None)
Definition: util.py:26
None _async_add_missing_entry_unique_id(HomeAssistant hass, PowerviewConfigEntry entry)
Definition: __init__.py:138
None _migrate_unique_ids(HomeAssistant hass, PowerviewConfigEntry entry)
Definition: __init__.py:148
bool async_migrate_entry(HomeAssistant hass, PowerviewConfigEntry entry)
Definition: __init__.py:118
bool async_unload_entry(HomeAssistant hass, PowerviewConfigEntry entry)
Definition: __init__.py:113
bool async_setup_entry(HomeAssistant hass, PowerviewConfigEntry entry)
Definition: __init__.py:36