Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """Component for interacting with a Lutron RadioRA 2 system."""
2 
3 from dataclasses import dataclass
4 import logging
5 
6 from pylutron import Button, Keypad, Led, Lutron, OccupancyGroup, Output
7 
8 from homeassistant.config_entries import ConfigEntry
9 from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME, Platform
10 from homeassistant.core import HomeAssistant
11 from homeassistant.helpers import device_registry as dr, entity_registry as er
12 
13 from .const import DOMAIN
14 
15 PLATFORMS = [
16  Platform.BINARY_SENSOR,
17  Platform.COVER,
18  Platform.EVENT,
19  Platform.FAN,
20  Platform.LIGHT,
21  Platform.SCENE,
22  Platform.SWITCH,
23 ]
24 
25 _LOGGER = logging.getLogger(__name__)
26 
27 # Attribute on events that indicates what action was taken with the button.
28 ATTR_ACTION = "action"
29 ATTR_FULL_ID = "full_id"
30 ATTR_UUID = "uuid"
31 
32 
33 @dataclass(slots=True, kw_only=True)
34 class LutronData:
35  """Storage class for platform global data."""
36 
37  client: Lutron
38  binary_sensors: list[tuple[str, OccupancyGroup]]
39  buttons: list[tuple[str, Keypad, Button]]
40  covers: list[tuple[str, Output]]
41  fans: list[tuple[str, Output]]
42  lights: list[tuple[str, Output]]
43  scenes: list[tuple[str, Keypad, Button, Led]]
44  switches: list[tuple[str, Output]]
45 
46 
47 async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
48  """Set up the Lutron integration."""
49 
50  host = config_entry.data[CONF_HOST]
51  uid = config_entry.data[CONF_USERNAME]
52  pwd = config_entry.data[CONF_PASSWORD]
53 
54  lutron_client = Lutron(host, uid, pwd)
55  await hass.async_add_executor_job(lutron_client.load_xml_db)
56  lutron_client.connect()
57  _LOGGER.debug("Connected to main repeater at %s", host)
58 
59  entity_registry = er.async_get(hass)
60  device_registry = dr.async_get(hass)
61 
62  entry_data = LutronData(
63  client=lutron_client,
64  binary_sensors=[],
65  buttons=[],
66  covers=[],
67  fans=[],
68  lights=[],
69  scenes=[],
70  switches=[],
71  )
72  # Sort our devices into types
73  _LOGGER.debug("Start adding devices")
74  for area in lutron_client.areas:
75  _LOGGER.debug("Working on area %s", area.name)
76  for output in area.outputs:
77  platform = None
78  _LOGGER.debug("Working on output %s", output.type)
79  if output.type == "SYSTEM_SHADE":
80  entry_data.covers.append((area.name, output))
81  platform = Platform.COVER
82  elif output.type == "CEILING_FAN_TYPE":
83  entry_data.fans.append((area.name, output))
84  platform = Platform.FAN
85  elif output.is_dimmable:
86  entry_data.lights.append((area.name, output))
87  platform = Platform.LIGHT
88  else:
89  entry_data.switches.append((area.name, output))
90  platform = Platform.SWITCH
91 
93  hass,
94  entity_registry,
95  platform,
96  output.uuid,
97  output.legacy_uuid,
98  entry_data.client.guid,
99  )
101  hass,
102  device_registry,
103  output.uuid,
104  output.legacy_uuid,
105  entry_data.client.guid,
106  )
107 
108  for keypad in area.keypads:
109  for button in keypad.buttons:
110  # If the button has a function assigned to it, add it as a scene
111  if button.name != "Unknown Button" and button.button_type in (
112  "SingleAction",
113  "Toggle",
114  "SingleSceneRaiseLower",
115  "MasterRaiseLower",
116  ):
117  # Associate an LED with a button if there is one
118  led = next(
119  (led for led in keypad.leds if led.number == button.number),
120  None,
121  )
122  entry_data.scenes.append((area.name, keypad, button, led))
123 
124  platform = Platform.SCENE
126  hass,
127  entity_registry,
128  platform,
129  button.uuid,
130  button.legacy_uuid,
131  entry_data.client.guid,
132  )
133  if led is not None:
134  platform = Platform.SWITCH
136  hass,
137  entity_registry,
138  platform,
139  led.uuid,
140  led.legacy_uuid,
141  entry_data.client.guid,
142  )
143  if button.button_type:
144  entry_data.buttons.append((area.name, keypad, button))
145  if area.occupancy_group is not None:
146  entry_data.binary_sensors.append((area.name, area.occupancy_group))
147  platform = Platform.BINARY_SENSOR
149  hass,
150  entity_registry,
151  platform,
152  area.occupancy_group.uuid,
153  area.occupancy_group.legacy_uuid,
154  entry_data.client.guid,
155  )
157  hass,
158  device_registry,
159  area.occupancy_group.uuid,
160  area.occupancy_group.legacy_uuid,
161  entry_data.client.guid,
162  )
163 
164  device_registry.async_get_or_create(
165  config_entry_id=config_entry.entry_id,
166  identifiers={(DOMAIN, lutron_client.guid)},
167  manufacturer="Lutron",
168  name="Main repeater",
169  )
170 
171  hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = entry_data
172 
173  await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
174 
175  return True
176 
177 
179  hass: HomeAssistant,
180  entity_registry: er.EntityRegistry,
181  platform: str,
182  uuid: str,
183  legacy_uuid: str,
184  controller_guid: str,
185 ) -> None:
186  """If uuid becomes available update to use it."""
187 
188  if not uuid:
189  return
190 
191  unique_id = f"{controller_guid}_{legacy_uuid}"
192  entity_id = entity_registry.async_get_entity_id(
193  domain=platform, platform=DOMAIN, unique_id=unique_id
194  )
195 
196  if entity_id:
197  new_unique_id = f"{controller_guid}_{uuid}"
198  _LOGGER.debug("Updating entity id from %s to %s", unique_id, new_unique_id)
199  entity_registry.async_update_entity(entity_id, new_unique_id=new_unique_id)
200 
201 
203  hass: HomeAssistant,
204  device_registry: dr.DeviceRegistry,
205  uuid: str,
206  legacy_uuid: str,
207  controller_guid: str,
208 ) -> None:
209  """If uuid becomes available update to use it."""
210 
211  if not uuid:
212  return
213 
214  unique_id = f"{controller_guid}_{legacy_uuid}"
215  device = device_registry.async_get_device(identifiers={(DOMAIN, unique_id)})
216  if device:
217  new_unique_id = f"{controller_guid}_{uuid}"
218  _LOGGER.debug("Updating device id from %s to %s", unique_id, new_unique_id)
219  device_registry.async_update_device(
220  device.id, new_identifiers={(DOMAIN, new_unique_id)}
221  )
222 
223 
224 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
225  """Clean up resources and entities associated with the integration."""
226  return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:224
None _async_check_device_identifiers(HomeAssistant hass, dr.DeviceRegistry device_registry, str uuid, str legacy_uuid, str controller_guid)
Definition: __init__.py:208
None _async_check_entity_unique_id(HomeAssistant hass, er.EntityRegistry entity_registry, str platform, str uuid, str legacy_uuid, str controller_guid)
Definition: __init__.py:185
bool async_setup_entry(HomeAssistant hass, ConfigEntry config_entry)
Definition: __init__.py:47