Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The Search integration."""
2 
3 from __future__ import annotations
4 
5 from collections import defaultdict
6 from collections.abc import Iterable
7 from enum import StrEnum
8 import logging
9 from typing import Any
10 
11 import voluptuous as vol
12 
13 from homeassistant.components import automation, group, person, script, websocket_api
15 from homeassistant.core import HomeAssistant, callback, split_entity_id
16 from homeassistant.helpers import (
17  area_registry as ar,
18  config_validation as cv,
19  device_registry as dr,
20  entity_registry as er,
21 )
22 from homeassistant.helpers.entity import (
23  EntityInfo,
24  entity_sources as get_entity_sources,
25 )
26 from homeassistant.helpers.typing import ConfigType
27 
28 DOMAIN = "search"
29 _LOGGER = logging.getLogger(__name__)
30 
31 CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)
32 
33 
34 # enum of item types
35 class ItemType(StrEnum):
36  """Item types."""
37 
38  AREA = "area"
39  AUTOMATION = "automation"
40  AUTOMATION_BLUEPRINT = "automation_blueprint"
41  CONFIG_ENTRY = "config_entry"
42  DEVICE = "device"
43  ENTITY = "entity"
44  FLOOR = "floor"
45  GROUP = "group"
46  INTEGRATION = "integration"
47  LABEL = "label"
48  PERSON = "person"
49  SCENE = "scene"
50  SCRIPT = "script"
51  SCRIPT_BLUEPRINT = "script_blueprint"
52 
53 
54 async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
55  """Set up the Search component."""
56  websocket_api.async_register_command(hass, websocket_search_related)
57  return True
58 
59 
60 @websocket_api.websocket_command( { vol.Required("type"): "search/related",
61  vol.Required("item_type"): vol.Coerce(ItemType),
62  vol.Required("item_id"): str,
63  }
64 )
65 @callback
67  hass: HomeAssistant,
69  msg: dict[str, Any],
70 ) -> None:
71  """Handle search."""
72  searcher = Searcher(hass, get_entity_sources(hass))
73  connection.send_result(
74  msg["id"], searcher.async_search(msg["item_type"], msg["item_id"])
75  )
76 
77 
78 class Searcher:
79  """Find related things."""
80 
81  EXIST_AS_ENTITY = {"automation", "group", "person", "scene", "script"}
82 
83  def __init__(
84  self,
85  hass: HomeAssistant,
86  entity_sources: dict[str, EntityInfo],
87  ) -> None:
88  """Search results."""
89  self.hasshass = hass
90  self._area_registry_area_registry = ar.async_get(hass)
91  self._device_registry_device_registry = dr.async_get(hass)
92  self._entity_registry_entity_registry = er.async_get(hass)
93  self._entity_sources_entity_sources = entity_sources
94  self.results: defaultdict[ItemType, set[str]] = defaultdict(set)
95 
96  @callback
97  def async_search(self, item_type: ItemType, item_id: str) -> dict[str, set[str]]:
98  """Find results."""
99  _LOGGER.debug("Searching for %s/%s", item_type, item_id)
100  getattr(self, f"_async_search_{item_type}")(item_id)
101 
102  # Remove the original requested item from the results (if present)
103  if item_type in self.results and item_id in self.results[item_type]:
104  self.results[item_type].remove(item_id)
105 
106  # Filter out empty sets.
107  return {key: val for key, val in self.results.items() if val}
108 
109  @callback
110  def _add(self, item_type: ItemType, item_id: str | Iterable[str] | None) -> None:
111  """Add an item (or items) to the results."""
112  if item_id is None:
113  return
114 
115  if isinstance(item_id, str):
116  self.results[item_type].add(item_id)
117  else:
118  self.results[item_type].update(item_id)
119 
120  @callback
121  def _async_search_area(self, area_id: str, *, entry_point: bool = True) -> None:
122  """Find results for an area."""
123  if not (area_entry := self._async_resolve_up_area_async_resolve_up_area(area_id)):
124  return
125 
126  if entry_point:
127  # Add labels of this area
128  self._add_add(ItemType.LABEL, area_entry.labels)
129 
130  # Automations referencing this area
131  self._add_add(
132  ItemType.AUTOMATION, automation.automations_with_area(self.hasshass, area_id)
133  )
134 
135  # Scripts referencing this area
136  self._add_add(ItemType.SCRIPT, script.scripts_with_area(self.hasshass, area_id))
137 
138  # Entity in this area, will extend this with the entities of the devices in this area
139  entity_entries = er.async_entries_for_area(self._entity_registry_entity_registry, area_id)
140 
141  # Devices in this area
142  for device in dr.async_entries_for_area(self._device_registry_device_registry, area_id):
143  self._add_add(ItemType.DEVICE, device.id)
144 
145  # Config entries for devices in this area
146  if device_entry := self._device_registry_device_registry.async_get(device.id):
147  self._add_add(ItemType.CONFIG_ENTRY, device_entry.config_entries)
148 
149  # Automations referencing this device
150  self._add_add(
151  ItemType.AUTOMATION,
152  automation.automations_with_device(self.hasshass, device.id),
153  )
154 
155  # Scripts referencing this device
156  self._add_add(ItemType.SCRIPT, script.scripts_with_device(self.hasshass, device.id))
157 
158  # Entities of this device
159  for entity_entry in er.async_entries_for_device(
160  self._entity_registry_entity_registry, device.id
161  ):
162  # Skip the entity if it's in a different area
163  if entity_entry.area_id is not None:
164  continue
165  entity_entries.append(entity_entry)
166 
167  # Process entities in this area
168  for entity_entry in entity_entries:
169  self._add_add(ItemType.ENTITY, entity_entry.entity_id)
170 
171  # If this entity also exists as a resource, we add it.
172  if entity_entry.domain in self.EXIST_AS_ENTITYEXIST_AS_ENTITY:
173  self._add_add(ItemType(entity_entry.domain), entity_entry.entity_id)
174 
175  # Automations referencing this entity
176  self._add_add(
177  ItemType.AUTOMATION,
178  automation.automations_with_entity(self.hasshass, entity_entry.entity_id),
179  )
180 
181  # Scripts referencing this entity
182  self._add_add(
183  ItemType.SCRIPT,
184  script.scripts_with_entity(self.hasshass, entity_entry.entity_id),
185  )
186 
187  # Groups that have this entity as a member
188  self._add_add(
189  ItemType.GROUP,
190  group.groups_with_entity(self.hasshass, entity_entry.entity_id),
191  )
192 
193  # Persons that use this entity
194  self._add_add(
195  ItemType.PERSON,
196  person.persons_with_entity(self.hasshass, entity_entry.entity_id),
197  )
198 
199  # Scenes that reference this entity
200  self._add_add(
201  ItemType.SCENE,
202  scene.scenes_with_entity(self.hasshass, entity_entry.entity_id),
203  )
204 
205  # Config entries for entities in this area
206  self._add_add(ItemType.CONFIG_ENTRY, entity_entry.config_entry_id)
207 
208  @callback
209  def _async_search_automation(self, automation_entity_id: str) -> None:
210  """Find results for an automation."""
211  # Up resolve the automation entity itself
212  if entity_entry := self._async_resolve_up_entity_async_resolve_up_entity(automation_entity_id):
213  # Add labels of this automation entity
214  self._add_add(ItemType.LABEL, entity_entry.labels)
215 
216  # Find the blueprint used in this automation
217  self._add_add(
218  ItemType.AUTOMATION_BLUEPRINT,
219  automation.blueprint_in_automation(self.hasshass, automation_entity_id),
220  )
221 
222  # Floors referenced in this automation
223  self._add_add(
224  ItemType.FLOOR,
225  automation.floors_in_automation(self.hasshass, automation_entity_id),
226  )
227 
228  # Areas referenced in this automation
229  for area in automation.areas_in_automation(self.hasshass, automation_entity_id):
230  self._add_add(ItemType.AREA, area)
231  self._async_resolve_up_area_async_resolve_up_area(area)
232 
233  # Devices referenced in this automation
234  for device in automation.devices_in_automation(self.hasshass, automation_entity_id):
235  self._add_add(ItemType.DEVICE, device)
236  self._async_resolve_up_device_async_resolve_up_device(device)
237 
238  # Entities referenced in this automation
239  for entity_id in automation.entities_in_automation(
240  self.hasshass, automation_entity_id
241  ):
242  self._add_add(ItemType.ENTITY, entity_id)
243  self._async_resolve_up_entity_async_resolve_up_entity(entity_id)
244 
245  # If this entity also exists as a resource, we add it.
246  domain = split_entity_id(entity_id)[0]
247  if domain in self.EXIST_AS_ENTITYEXIST_AS_ENTITY:
248  self._add_add(ItemType(domain), entity_id)
249 
250  # For an automation, we want to unwrap the groups, to ensure we
251  # relate this automation to all those members as well.
252  if domain == "group":
253  for group_entity_id in group.get_entity_ids(self.hasshass, entity_id):
254  self._add_add(ItemType.ENTITY, group_entity_id)
255  self._async_resolve_up_entity_async_resolve_up_entity(group_entity_id)
256 
257  # For an automation, we want to unwrap the scenes, to ensure we
258  # relate this automation to all referenced entities as well.
259  if domain == "scene":
260  for scene_entity_id in scene.entities_in_scene(self.hasshass, entity_id):
261  self._add_add(ItemType.ENTITY, scene_entity_id)
262  self._async_resolve_up_entity_async_resolve_up_entity(scene_entity_id)
263 
264  # Fully search the script if it is part of an automation.
265  # This makes the automation return all results of the embedded script.
266  if domain == "script":
267  self._async_search_script_async_search_script(entity_id, entry_point=False)
268 
269  @callback
270  def _async_search_automation_blueprint(self, blueprint_path: str) -> None:
271  """Find results for an automation blueprint."""
272  self._add_add(
273  ItemType.AUTOMATION,
274  automation.automations_with_blueprint(self.hasshass, blueprint_path),
275  )
276 
277  @callback
278  def _async_search_config_entry(self, config_entry_id: str) -> None:
279  """Find results for a config entry."""
280  for device_entry in dr.async_entries_for_config_entry(
281  self._device_registry_device_registry, config_entry_id
282  ):
283  self._add_add(ItemType.DEVICE, device_entry.id)
284  self._async_search_device_async_search_device(device_entry.id, entry_point=False)
285 
286  for entity_entry in er.async_entries_for_config_entry(
287  self._entity_registry_entity_registry, config_entry_id
288  ):
289  self._add_add(ItemType.ENTITY, entity_entry.entity_id)
290  self._async_search_entity_async_search_entity(entity_entry.entity_id, entry_point=False)
291 
292  @callback
293  def _async_search_device(self, device_id: str, *, entry_point: bool = True) -> None:
294  """Find results for a device."""
295  if not (device_entry := self._async_resolve_up_device_async_resolve_up_device(device_id)):
296  return
297 
298  if entry_point:
299  # Add labels of this device
300  self._add_add(ItemType.LABEL, device_entry.labels)
301 
302  # Automations referencing this device
303  self._add_add(
304  ItemType.AUTOMATION,
305  automation.automations_with_device(self.hasshass, device_id),
306  )
307 
308  # Scripts referencing this device
309  self._add_add(ItemType.SCRIPT, script.scripts_with_device(self.hasshass, device_id))
310 
311  # Entities of this device
312  for entity_entry in er.async_entries_for_device(
313  self._entity_registry_entity_registry, device_id
314  ):
315  self._add_add(ItemType.ENTITY, entity_entry.entity_id)
316  # Add all entity information as well
317  self._async_search_entity_async_search_entity(entity_entry.entity_id, entry_point=False)
318 
319  @callback
320  def _async_search_entity(self, entity_id: str, *, entry_point: bool = True) -> None:
321  """Find results for an entity."""
322  # Resolve up the entity itself
323  entity_entry = self._async_resolve_up_entity_async_resolve_up_entity(entity_id)
324 
325  if entity_entry and entry_point:
326  # Add labels of this entity
327  self._add_add(ItemType.LABEL, entity_entry.labels)
328 
329  # Automations referencing this entity
330  self._add_add(
331  ItemType.AUTOMATION,
332  automation.automations_with_entity(self.hasshass, entity_id),
333  )
334 
335  # Scripts referencing this entity
336  self._add_add(ItemType.SCRIPT, script.scripts_with_entity(self.hasshass, entity_id))
337 
338  # Groups that have this entity as a member
339  self._add_add(ItemType.GROUP, group.groups_with_entity(self.hasshass, entity_id))
340 
341  # Persons referencing this entity
342  self._add_add(ItemType.PERSON, person.persons_with_entity(self.hasshass, entity_id))
343 
344  # Scenes referencing this entity
345  self._add_add(ItemType.SCENE, scene.scenes_with_entity(self.hasshass, entity_id))
346 
347  @callback
348  def _async_search_floor(self, floor_id: str) -> None:
349  """Find results for a floor."""
350  # Automations referencing this floor
351  self._add_add(
352  ItemType.AUTOMATION,
353  automation.automations_with_floor(self.hasshass, floor_id),
354  )
355 
356  # Scripts referencing this floor
357  self._add_add(ItemType.SCRIPT, script.scripts_with_floor(self.hasshass, floor_id))
358 
359  for area_entry in ar.async_entries_for_floor(self._area_registry_area_registry, floor_id):
360  self._add_add(ItemType.AREA, area_entry.id)
361  self._async_search_area_async_search_area(area_entry.id, entry_point=False)
362 
363  @callback
364  def _async_search_group(self, group_entity_id: str) -> None:
365  """Find results for a group.
366 
367  Note: We currently only support the classic groups, thus
368  we don't look up the area/floor for a group entity.
369  """
370  # Automations referencing this group
371  self._add_add(
372  ItemType.AUTOMATION,
373  automation.automations_with_entity(self.hasshass, group_entity_id),
374  )
375 
376  # Scripts referencing this group
377  self._add_add(
378  ItemType.SCRIPT, script.scripts_with_entity(self.hasshass, group_entity_id)
379  )
380 
381  # Scenes that reference this group
382  self._add_add(ItemType.SCENE, scene.scenes_with_entity(self.hasshass, group_entity_id))
383 
384  # Entities in this group
385  for entity_id in group.get_entity_ids(self.hasshass, group_entity_id):
386  self._add_add(ItemType.ENTITY, entity_id)
387  self._async_resolve_up_entity_async_resolve_up_entity(entity_id)
388 
389  @callback
390  def _async_search_label(self, label_id: str) -> None:
391  """Find results for a label."""
392 
393  # Areas with this label
394  for area_entry in ar.async_entries_for_label(self._area_registry_area_registry, label_id):
395  self._add_add(ItemType.AREA, area_entry.id)
396 
397  # Devices with this label
398  for device in dr.async_entries_for_label(self._device_registry_device_registry, label_id):
399  self._add_add(ItemType.DEVICE, device.id)
400 
401  # Entities with this label
402  for entity_entry in er.async_entries_for_label(self._entity_registry_entity_registry, label_id):
403  self._add_add(ItemType.ENTITY, entity_entry.entity_id)
404 
405  # If this entity also exists as a resource, we add it.
406  domain = split_entity_id(entity_entry.entity_id)[0]
407  if domain in self.EXIST_AS_ENTITYEXIST_AS_ENTITY:
408  self._add_add(ItemType(domain), entity_entry.entity_id)
409 
410  # Automations referencing this label
411  self._add_add(
412  ItemType.AUTOMATION,
413  automation.automations_with_label(self.hasshass, label_id),
414  )
415 
416  # Scripts referencing this label
417  self._add_add(ItemType.SCRIPT, script.scripts_with_label(self.hasshass, label_id))
418 
419  @callback
420  def _async_search_person(self, person_entity_id: str) -> None:
421  """Find results for a person."""
422  # Up resolve the scene entity itself
423  if entity_entry := self._async_resolve_up_entity_async_resolve_up_entity(person_entity_id):
424  # Add labels of this person entity
425  self._add_add(ItemType.LABEL, entity_entry.labels)
426 
427  # Automations referencing this person
428  self._add_add(
429  ItemType.AUTOMATION,
430  automation.automations_with_entity(self.hasshass, person_entity_id),
431  )
432 
433  # Scripts referencing this person
434  self._add_add(
435  ItemType.SCRIPT, script.scripts_with_entity(self.hasshass, person_entity_id)
436  )
437 
438  # Add all member entities of this person
439  self._add_add(
440  ItemType.ENTITY, person.entities_in_person(self.hasshass, person_entity_id)
441  )
442 
443  @callback
444  def _async_search_scene(self, scene_entity_id: str) -> None:
445  """Find results for a scene."""
446  # Up resolve the scene entity itself
447  if entity_entry := self._async_resolve_up_entity_async_resolve_up_entity(scene_entity_id):
448  # Add labels of this scene entity
449  self._add_add(ItemType.LABEL, entity_entry.labels)
450 
451  # Automations referencing this scene
452  self._add_add(
453  ItemType.AUTOMATION,
454  automation.automations_with_entity(self.hasshass, scene_entity_id),
455  )
456 
457  # Scripts referencing this scene
458  self._add_add(
459  ItemType.SCRIPT, script.scripts_with_entity(self.hasshass, scene_entity_id)
460  )
461 
462  # Add all entities in this scene
463  for entity in scene.entities_in_scene(self.hasshass, scene_entity_id):
464  self._add_add(ItemType.ENTITY, entity)
465  self._async_resolve_up_entity_async_resolve_up_entity(entity)
466 
467  @callback
469  self, script_entity_id: str, *, entry_point: bool = True
470  ) -> None:
471  """Find results for a script."""
472  # Up resolve the script entity itself
473  entity_entry = self._async_resolve_up_entity_async_resolve_up_entity(script_entity_id)
474 
475  if entity_entry and entry_point:
476  # Add labels of this script entity
477  self._add_add(ItemType.LABEL, entity_entry.labels)
478 
479  # Find the blueprint used in this script
480  self._add_add(
481  ItemType.SCRIPT_BLUEPRINT,
482  script.blueprint_in_script(self.hasshass, script_entity_id),
483  )
484 
485  # Floors referenced in this script
486  self._add_add(ItemType.FLOOR, script.floors_in_script(self.hasshass, script_entity_id))
487 
488  # Areas referenced in this script
489  for area in script.areas_in_script(self.hasshass, script_entity_id):
490  self._add_add(ItemType.AREA, area)
491  self._async_resolve_up_area_async_resolve_up_area(area)
492 
493  # Devices referenced in this script
494  for device in script.devices_in_script(self.hasshass, script_entity_id):
495  self._add_add(ItemType.DEVICE, device)
496  self._async_resolve_up_device_async_resolve_up_device(device)
497 
498  # Entities referenced in this script
499  for entity_id in script.entities_in_script(self.hasshass, script_entity_id):
500  self._add_add(ItemType.ENTITY, entity_id)
501  self._async_resolve_up_entity_async_resolve_up_entity(entity_id)
502 
503  # If this entity also exists as a resource, we add it.
504  domain = split_entity_id(entity_id)[0]
505  if domain in self.EXIST_AS_ENTITYEXIST_AS_ENTITY:
506  self._add_add(ItemType(domain), entity_id)
507 
508  # For an script, we want to unwrap the groups, to ensure we
509  # relate this script to all those members as well.
510  if domain == "group":
511  for group_entity_id in group.get_entity_ids(self.hasshass, entity_id):
512  self._add_add(ItemType.ENTITY, group_entity_id)
513  self._async_resolve_up_entity_async_resolve_up_entity(group_entity_id)
514 
515  # For an script, we want to unwrap the scenes, to ensure we
516  # relate this script to all referenced entities as well.
517  if domain == "scene":
518  for scene_entity_id in scene.entities_in_scene(self.hasshass, entity_id):
519  self._add_add(ItemType.ENTITY, scene_entity_id)
520  self._async_resolve_up_entity_async_resolve_up_entity(scene_entity_id)
521 
522  # Fully search the script if it is nested.
523  # This makes the script return all results of the embedded script.
524  if domain == "script":
525  self._async_search_script_async_search_script(entity_id, entry_point=False)
526 
527  @callback
528  def _async_search_script_blueprint(self, blueprint_path: str) -> None:
529  """Find results for a script blueprint."""
530  self._add_add(
531  ItemType.SCRIPT, script.scripts_with_blueprint(self.hasshass, blueprint_path)
532  )
533 
534  @callback
535  def _async_resolve_up_device(self, device_id: str) -> dr.DeviceEntry | None:
536  """Resolve up from a device.
537 
538  Above a device is an area or floor.
539  Above a device is also the config entry.
540  """
541  if device_entry := self._device_registry_device_registry.async_get(device_id):
542  if device_entry.area_id:
543  self._add_add(ItemType.AREA, device_entry.area_id)
544  self._async_resolve_up_area_async_resolve_up_area(device_entry.area_id)
545 
546  self._add_add(ItemType.CONFIG_ENTRY, device_entry.config_entries)
547  for config_entry_id in device_entry.config_entries:
548  if entry := self.hasshass.config_entries.async_get_entry(config_entry_id):
549  self._add_add(ItemType.INTEGRATION, entry.domain)
550 
551  return device_entry
552 
553  @callback
554  def _async_resolve_up_entity(self, entity_id: str) -> er.RegistryEntry | None:
555  """Resolve up from an entity.
556 
557  Above an entity is a device, area or floor.
558  Above an entity is also the config entry.
559  """
560  if entity_entry := self._entity_registry_entity_registry.async_get(entity_id):
561  # Entity has an overridden area
562  if entity_entry.area_id:
563  self._add_add(ItemType.AREA, entity_entry.area_id)
564  self._async_resolve_up_area_async_resolve_up_area(entity_entry.area_id)
565 
566  # Inherit area from device
567  elif entity_entry.device_id and (
568  device_entry := self._device_registry_device_registry.async_get(entity_entry.device_id)
569  ):
570  if device_entry.area_id:
571  self._add_add(ItemType.AREA, device_entry.area_id)
572  self._async_resolve_up_area_async_resolve_up_area(device_entry.area_id)
573 
574  # Add device that provided this entity
575  self._add_add(ItemType.DEVICE, entity_entry.device_id)
576 
577  # Add config entry that provided this entity
578  if entity_entry.config_entry_id:
579  self._add_add(ItemType.CONFIG_ENTRY, entity_entry.config_entry_id)
580 
581  if entry := self.hasshass.config_entries.async_get_entry(
582  entity_entry.config_entry_id
583  ):
584  # Add integration that provided this entity
585  self._add_add(ItemType.INTEGRATION, entry.domain)
586 
587  elif source := self._entity_sources_entity_sources.get(entity_id):
588  # Add config entry that provided this entity
589  self._add_add(ItemType.CONFIG_ENTRY, source.get("config_entry"))
590  self._add_add(ItemType.INTEGRATION, source["domain"])
591 
592  return entity_entry
593 
594  @callback
595  def _async_resolve_up_area(self, area_id: str) -> ar.AreaEntry | None:
596  """Resolve up from an area.
597 
598  Above an area can be a floor.
599  """
600  if area_entry := self._area_registry_area_registry.async_get_area(area_id):
601  self._add_add(ItemType.FLOOR, area_entry.floor_id)
602 
603  return area_entry
604 
None _async_search_script(self, str script_entity_id, *bool entry_point=True)
Definition: __init__.py:472
None _async_search_automation(self, str automation_entity_id)
Definition: __init__.py:211
None __init__(self, HomeAssistant hass, dict[str, EntityInfo] entity_sources)
Definition: __init__.py:89
None _async_search_automation_blueprint(self, str blueprint_path)
Definition: __init__.py:272
None _async_search_config_entry(self, str config_entry_id)
Definition: __init__.py:280
dict[str, set[str]] async_search(self, ItemType item_type, str item_id)
Definition: __init__.py:99
None _async_search_scene(self, str scene_entity_id)
Definition: __init__.py:446
None _async_search_device(self, str device_id, *bool entry_point=True)
Definition: __init__.py:295
None _async_search_entity(self, str entity_id, *bool entry_point=True)
Definition: __init__.py:322
dr.DeviceEntry|None _async_resolve_up_device(self, str device_id)
Definition: __init__.py:537
None _async_search_person(self, str person_entity_id)
Definition: __init__.py:422
None _async_search_area(self, str area_id, *bool entry_point=True)
Definition: __init__.py:123
er.RegistryEntry|None _async_resolve_up_entity(self, str entity_id)
Definition: __init__.py:556
None _async_search_group(self, str group_entity_id)
Definition: __init__.py:366
None _async_search_script_blueprint(self, str blueprint_path)
Definition: __init__.py:530
None _async_search_floor(self, str floor_id)
Definition: __init__.py:350
ar.AreaEntry|None _async_resolve_up_area(self, str area_id)
Definition: __init__.py:597
None _add(self, ItemType item_type, str|Iterable[str]|None item_id)
Definition: __init__.py:112
None _async_search_label(self, str label_id)
Definition: __init__.py:392
bool add(self, _T matcher)
Definition: match.py:185
bool remove(self, _T matcher)
Definition: match.py:214
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
IssData update(pyiss.ISS iss)
Definition: __init__.py:33
None websocket_search_related(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
Definition: __init__.py:72
bool async_setup(HomeAssistant hass, ConfigType config)
Definition: __init__.py:54
tuple[str, str] split_entity_id(str entity_id)
Definition: core.py:214
AreaRegistry async_get(HomeAssistant hass)