Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """Support for LG ThinQ Connect device."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from dataclasses import dataclass, field
7 import logging
8 
9 from thinqconnect import ThinQApi, ThinQAPIException
10 from thinqconnect.integration import async_get_ha_bridge_list
11 
12 from homeassistant.config_entries import ConfigEntry
13 from homeassistant.const import (
14  CONF_ACCESS_TOKEN,
15  CONF_COUNTRY,
16  EVENT_HOMEASSISTANT_STOP,
17  Platform,
18 )
19 from homeassistant.core import HomeAssistant, callback
20 from homeassistant.exceptions import ConfigEntryNotReady
21 from homeassistant.helpers import device_registry as dr
22 from homeassistant.helpers.aiohttp_client import async_get_clientsession
23 from homeassistant.helpers.event import async_track_time_interval
24 
25 from .const import CONF_CONNECT_CLIENT_ID, MQTT_SUBSCRIPTION_INTERVAL
26 from .coordinator import DeviceDataUpdateCoordinator, async_setup_device_coordinator
27 from .mqtt import ThinQMQTT
28 
29 
30 @dataclass(kw_only=True)
31 class ThinqData:
32  """A class that holds runtime data."""
33 
34  coordinators: dict[str, DeviceDataUpdateCoordinator] = field(default_factory=dict)
35  mqtt_client: ThinQMQTT | None = None
36 
37 
38 type ThinqConfigEntry = ConfigEntry[ThinqData]
39 
40 PLATFORMS = [
41  Platform.BINARY_SENSOR,
42  Platform.CLIMATE,
43  Platform.EVENT,
44  Platform.FAN,
45  Platform.NUMBER,
46  Platform.SELECT,
47  Platform.SENSOR,
48  Platform.SWITCH,
49  Platform.VACUUM,
50 ]
51 
52 _LOGGER = logging.getLogger(__name__)
53 
54 
55 async def async_setup_entry(hass: HomeAssistant, entry: ThinqConfigEntry) -> bool:
56  """Set up an entry."""
57  entry.runtime_data = ThinqData()
58 
59  access_token = entry.data[CONF_ACCESS_TOKEN]
60  client_id = entry.data[CONF_CONNECT_CLIENT_ID]
61  country_code = entry.data[CONF_COUNTRY]
62 
63  thinq_api = ThinQApi(
64  session=async_get_clientsession(hass),
65  access_token=access_token,
66  country_code=country_code,
67  client_id=client_id,
68  )
69 
70  # Setup coordinators and register devices.
71  await async_setup_coordinators(hass, entry, thinq_api)
72 
73  # Set up all platforms for this device/entry.
74  await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
75 
76  # Set up MQTT connection.
77  await async_setup_mqtt(hass, entry, thinq_api, client_id)
78 
79  # Clean up devices they are no longer in use.
81 
82  return True
83 
84 
86  hass: HomeAssistant,
87  entry: ThinqConfigEntry,
88  thinq_api: ThinQApi,
89 ) -> None:
90  """Set up coordinators and register devices."""
91  # Get a list of ha bridge.
92  try:
93  bridge_list = await async_get_ha_bridge_list(thinq_api)
94  except ThinQAPIException as exc:
95  raise ConfigEntryNotReady(exc.message) from exc
96 
97  if not bridge_list:
98  _LOGGER.warning("No devices registered with the correct profile")
99  return
100 
101  # Setup coordinator per device.
102  task_list = [
103  hass.async_create_task(async_setup_device_coordinator(hass, bridge))
104  for bridge in bridge_list
105  ]
106  task_result = await asyncio.gather(*task_list)
107  for coordinator in task_result:
108  entry.runtime_data.coordinators[coordinator.unique_id] = coordinator
109 
110 
111 @callback
112 def async_cleanup_device_registry(hass: HomeAssistant, entry: ThinqConfigEntry) -> None:
113  """Clean up device registry."""
114  new_device_unique_ids = [
115  coordinator.unique_id
116  for coordinator in entry.runtime_data.coordinators.values()
117  ]
118  device_registry = dr.async_get(hass)
119  existing_entries = dr.async_entries_for_config_entry(
120  device_registry, entry.entry_id
121  )
122 
123  # Remove devices that are no longer exist.
124  for old_entry in existing_entries:
125  old_unique_id = next(iter(old_entry.identifiers))[1]
126  if old_unique_id not in new_device_unique_ids:
127  device_registry.async_remove_device(old_entry.id)
128  _LOGGER.debug("Remove device_registry: device_id=%s", old_entry.id)
129 
130 
132  hass: HomeAssistant, entry: ThinqConfigEntry, thinq_api: ThinQApi, client_id: str
133 ) -> None:
134  """Set up MQTT connection."""
135  mqtt_client = ThinQMQTT(hass, thinq_api, client_id, entry.runtime_data.coordinators)
136  entry.runtime_data.mqtt_client = mqtt_client
137 
138  # Try to connect.
139  result = await mqtt_client.async_connect()
140  if not result:
141  _LOGGER.error("Failed to set up mqtt connection")
142  return
143 
144  # Ready to subscribe.
145  await mqtt_client.async_start_subscribes()
146 
147  entry.async_on_unload(
149  hass,
150  mqtt_client.async_refresh_subscribe,
151  MQTT_SUBSCRIPTION_INTERVAL,
152  cancel_on_shutdown=True,
153  )
154  )
155  entry.async_on_unload(
156  hass.bus.async_listen_once(
157  EVENT_HOMEASSISTANT_STOP, mqtt_client.async_disconnect
158  )
159  )
160 
161 
162 async def async_unload_entry(hass: HomeAssistant, entry: ThinqConfigEntry) -> bool:
163  """Unload the entry."""
164  if entry.runtime_data.mqtt_client:
165  await entry.runtime_data.mqtt_client.async_disconnect()
166 
167  return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
DeviceDataUpdateCoordinator async_setup_device_coordinator(HomeAssistant hass, HABridge ha_bridge)
Definition: coordinator.py:75
bool async_unload_entry(HomeAssistant hass, ThinqConfigEntry entry)
Definition: __init__.py:162
None async_cleanup_device_registry(HomeAssistant hass, ThinqConfigEntry entry)
Definition: __init__.py:112
None async_setup_mqtt(HomeAssistant hass, ThinqConfigEntry entry, ThinQApi thinq_api, str client_id)
Definition: __init__.py:133
bool async_setup_entry(HomeAssistant hass, ThinqConfigEntry entry)
Definition: __init__.py:55
None async_setup_coordinators(HomeAssistant hass, ThinqConfigEntry entry, ThinQApi thinq_api)
Definition: __init__.py:89
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)
CALLBACK_TYPE async_track_time_interval(HomeAssistant hass, Callable[[datetime], Coroutine[Any, Any, None]|None] action, timedelta interval, *str|None name=None, bool|None cancel_on_shutdown=None)
Definition: event.py:1679