Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The qbittorrent component."""
2 
3 import logging
4 from typing import Any
5 
6 from qbittorrentapi import APIConnectionError, Forbidden403Error, LoginFailed
7 
8 from homeassistant.config_entries import ConfigEntry
9 from homeassistant.const import (
10  ATTR_DEVICE_ID,
11  CONF_PASSWORD,
12  CONF_URL,
13  CONF_USERNAME,
14  CONF_VERIFY_SSL,
15  Platform,
16 )
17 from homeassistant.core import HomeAssistant, ServiceCall, SupportsResponse
18 from homeassistant.exceptions import ConfigEntryNotReady, ServiceValidationError
19 from homeassistant.helpers import config_validation as cv, device_registry as dr
20 from homeassistant.helpers.typing import ConfigType
21 
22 from .const import (
23  DOMAIN,
24  SERVICE_GET_ALL_TORRENTS,
25  SERVICE_GET_TORRENTS,
26  STATE_ATTR_ALL_TORRENTS,
27  STATE_ATTR_TORRENTS,
28  TORRENT_FILTER,
29 )
30 from .coordinator import QBittorrentDataCoordinator
31 from .helpers import format_torrents, setup_client
32 
33 _LOGGER = logging.getLogger(__name__)
34 
35 CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)
36 
37 PLATFORMS = [Platform.SENSOR, Platform.SWITCH]
38 
39 CONF_ENTRY = "entry"
40 
41 
42 async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
43  """Set up qBittorrent services."""
44 
45  async def handle_get_torrents(service_call: ServiceCall) -> dict[str, Any] | None:
46  device_registry = dr.async_get(hass)
47  device_entry = device_registry.async_get(service_call.data[ATTR_DEVICE_ID])
48 
49  if device_entry is None:
51  translation_domain=DOMAIN,
52  translation_key="invalid_device",
53  translation_placeholders={
54  "device_id": service_call.data[ATTR_DEVICE_ID]
55  },
56  )
57 
58  entry_id = None
59 
60  for key, value in device_entry.identifiers:
61  if key == DOMAIN:
62  entry_id = value
63  break
64  else:
66  translation_domain=DOMAIN,
67  translation_key="invalid_entry_id",
68  translation_placeholders={"device_id": entry_id or ""},
69  )
70 
71  coordinator: QBittorrentDataCoordinator = hass.data[DOMAIN][entry_id]
72  items = await coordinator.get_torrents(service_call.data[TORRENT_FILTER])
73  info = format_torrents(items)
74  return {
75  STATE_ATTR_TORRENTS: info,
76  }
77 
78  hass.services.async_register(
79  DOMAIN,
80  SERVICE_GET_TORRENTS,
81  handle_get_torrents,
82  supports_response=SupportsResponse.ONLY,
83  )
84 
85  async def handle_get_all_torrents(
86  service_call: ServiceCall,
87  ) -> dict[str, Any] | None:
88  torrents = {}
89 
90  for key, value in hass.data[DOMAIN].items():
91  coordinator: QBittorrentDataCoordinator = value
92  items = await coordinator.get_torrents(service_call.data[TORRENT_FILTER])
93  torrents[key] = format_torrents(items)
94 
95  return {
96  STATE_ATTR_ALL_TORRENTS: torrents,
97  }
98 
99  hass.services.async_register(
100  DOMAIN,
101  SERVICE_GET_ALL_TORRENTS,
102  handle_get_all_torrents,
103  supports_response=SupportsResponse.ONLY,
104  )
105 
106  return True
107 
108 
109 async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
110  """Set up qBittorrent from a config entry."""
111 
112  try:
113  client = await hass.async_add_executor_job(
114  setup_client,
115  config_entry.data[CONF_URL],
116  config_entry.data[CONF_USERNAME],
117  config_entry.data[CONF_PASSWORD],
118  config_entry.data[CONF_VERIFY_SSL],
119  )
120  except LoginFailed as err:
121  raise ConfigEntryNotReady("Invalid credentials") from err
122  except Forbidden403Error as err:
123  raise ConfigEntryNotReady("Fail to log in, banned user ?") from err
124  except APIConnectionError as exc:
125  raise ConfigEntryNotReady("Fail to connect to qBittorrent") from exc
126 
127  coordinator = QBittorrentDataCoordinator(hass, client)
128 
129  await coordinator.async_config_entry_first_refresh()
130  hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = coordinator
131 
132  await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
133 
134  return True
135 
136 
137 async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
138  """Unload qBittorrent config entry."""
139  if unload_ok := await hass.config_entries.async_unload_platforms(
140  config_entry, PLATFORMS
141  ):
142  del hass.data[DOMAIN][config_entry.entry_id]
143  if not hass.data[DOMAIN]:
144  del hass.data[DOMAIN]
145  return unload_ok
dict[str, dict[str, Any]] format_torrents(TorrentInfoList torrents)
Definition: helpers.py:42
bool async_setup(HomeAssistant hass, ConfigType config)
Definition: __init__.py:42
bool async_unload_entry(HomeAssistant hass, ConfigEntry config_entry)
Definition: __init__.py:137
bool async_setup_entry(HomeAssistant hass, ConfigEntry config_entry)
Definition: __init__.py:109