Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The scrape component."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from collections.abc import Coroutine
7 from datetime import timedelta
8 from typing import Any
9 
10 import voluptuous as vol
11 
12 from homeassistant.components.rest import RESOURCE_SCHEMA, create_rest_data_from_config
13 from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
14 from homeassistant.config_entries import ConfigEntry
15 from homeassistant.const import (
16  CONF_ATTRIBUTE,
17  CONF_SCAN_INTERVAL,
18  CONF_VALUE_TEMPLATE,
19  Platform,
20 )
21 from homeassistant.core import HomeAssistant
22 from homeassistant.helpers import discovery, entity_registry as er
24 from homeassistant.helpers.device_registry import DeviceEntry
26  CONF_AVAILABILITY,
27  TEMPLATE_SENSOR_BASE_SCHEMA,
28 )
29 from homeassistant.helpers.typing import ConfigType
30 
31 from .const import CONF_INDEX, CONF_SELECT, DEFAULT_SCAN_INTERVAL, DOMAIN, PLATFORMS
32 from .coordinator import ScrapeCoordinator
33 
34 type ScrapeConfigEntry = ConfigEntry[ScrapeCoordinator]
35 
36 SENSOR_SCHEMA = vol.Schema(
37  {
38  **TEMPLATE_SENSOR_BASE_SCHEMA.schema,
39  vol.Optional(CONF_AVAILABILITY): cv.template,
40  vol.Optional(CONF_ATTRIBUTE): cv.string,
41  vol.Optional(CONF_INDEX, default=0): cv.positive_int,
42  vol.Required(CONF_SELECT): cv.string,
43  vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
44  }
45 )
46 
47 COMBINED_SCHEMA = vol.Schema(
48  {
49  vol.Optional(CONF_SCAN_INTERVAL): cv.time_period,
50  **RESOURCE_SCHEMA,
51  vol.Optional(SENSOR_DOMAIN): vol.All(
52  cv.ensure_list, [vol.Schema(SENSOR_SCHEMA)]
53  ),
54  }
55 )
56 
57 CONFIG_SCHEMA = vol.Schema(
58  {vol.Optional(DOMAIN): vol.All(cv.ensure_list, [COMBINED_SCHEMA])},
59  extra=vol.ALLOW_EXTRA,
60 )
61 
62 
63 async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
64  """Set up Scrape from yaml config."""
65  scrape_config: list[ConfigType] | None
66  if not (scrape_config := config.get(DOMAIN)):
67  return True
68 
69  load_coroutines: list[Coroutine[Any, Any, None]] = []
70  for resource_config in scrape_config:
71  rest = create_rest_data_from_config(hass, resource_config)
72  scan_interval: timedelta = resource_config.get(
73  CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL
74  )
75  coordinator = ScrapeCoordinator(hass, None, rest, scan_interval)
76 
77  sensors: list[ConfigType] = resource_config.get(SENSOR_DOMAIN, [])
78  if sensors:
79  load_coroutines.append(
80  discovery.async_load_platform(
81  hass,
82  Platform.SENSOR,
83  DOMAIN,
84  {"coordinator": coordinator, "configs": sensors},
85  config,
86  )
87  )
88 
89  if load_coroutines:
90  await asyncio.gather(*load_coroutines)
91 
92  return True
93 
94 
95 async def async_setup_entry(hass: HomeAssistant, entry: ScrapeConfigEntry) -> bool:
96  """Set up Scrape from a config entry."""
97 
98  rest_config: dict[str, Any] = COMBINED_SCHEMA(dict(entry.options))
99  rest = create_rest_data_from_config(hass, rest_config)
100 
101  coordinator = ScrapeCoordinator(
102  hass,
103  entry,
104  rest,
105  DEFAULT_SCAN_INTERVAL,
106  )
107  await coordinator.async_config_entry_first_refresh()
108  entry.runtime_data = coordinator
109 
110  await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
111  entry.async_on_unload(entry.add_update_listener(update_listener))
112 
113  return True
114 
115 
116 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
117  """Unload Scrape config entry."""
118  return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
119 
120 
121 async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
122  """Handle options update."""
123  await hass.config_entries.async_reload(entry.entry_id)
124 
125 
127  hass: HomeAssistant, entry: ConfigEntry, device: DeviceEntry
128 ) -> bool:
129  """Remove Scrape config entry from a device."""
130  entity_registry = er.async_get(hass)
131  for identifier in device.identifiers:
132  if identifier[0] == DOMAIN and entity_registry.async_get_entity_id(
133  SENSOR_DOMAIN, DOMAIN, identifier[1]
134  ):
135  return False
136 
137  return True
RestData create_rest_data_from_config(HomeAssistant hass, ConfigType config)
Definition: __init__.py:190
bool async_setup(HomeAssistant hass, ConfigType config)
Definition: __init__.py:63
bool async_setup_entry(HomeAssistant hass, ScrapeConfigEntry entry)
Definition: __init__.py:95
None update_listener(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:121
bool async_remove_config_entry_device(HomeAssistant hass, ConfigEntry entry, DeviceEntry device)
Definition: __init__.py:128
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:116