diff --git a/homeassistant/components/qbittorrent/__init__.py b/homeassistant/components/qbittorrent/__init__.py index fb781dd1a0c..d95136965f8 100644 --- a/homeassistant/components/qbittorrent/__init__.py +++ b/homeassistant/components/qbittorrent/__init__.py @@ -34,7 +34,7 @@ _LOGGER = logging.getLogger(__name__) CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN) -PLATFORMS = [Platform.SENSOR] +PLATFORMS = [Platform.SENSOR, Platform.SWITCH] CONF_ENTRY = "entry" diff --git a/homeassistant/components/qbittorrent/coordinator.py b/homeassistant/components/qbittorrent/coordinator.py index 0ef36d2a954..c590bb9d81a 100644 --- a/homeassistant/components/qbittorrent/coordinator.py +++ b/homeassistant/components/qbittorrent/coordinator.py @@ -30,6 +30,7 @@ class QBittorrentDataCoordinator(DataUpdateCoordinator[SyncMainDataDictionary]): def __init__(self, hass: HomeAssistant, client: Client) -> None: """Initialize coordinator.""" self.client = client + self._is_alternative_mode_enabled = False # self.main_data: dict[str, int] = {} self.total_torrents: dict[str, int] = {} self.active_torrents: dict[str, int] = {} @@ -47,7 +48,13 @@ class QBittorrentDataCoordinator(DataUpdateCoordinator[SyncMainDataDictionary]): async def _async_update_data(self) -> SyncMainDataDictionary: try: - return await self.hass.async_add_executor_job(self.client.sync_maindata) + data = await self.hass.async_add_executor_job(self.client.sync_maindata) + self._is_alternative_mode_enabled = ( + await self.hass.async_add_executor_job( + self.client.transfer_speed_limits_mode + ) + == "1" + ) except (LoginFailed, Forbidden403Error) as exc: raise HomeAssistantError( translation_domain=DOMAIN, translation_key="login_error" @@ -56,6 +63,19 @@ class QBittorrentDataCoordinator(DataUpdateCoordinator[SyncMainDataDictionary]): raise HomeAssistantError( translation_domain=DOMAIN, translation_key="cannot_connect" ) from exc + return data + + def set_alt_speed_enabled(self, is_enabled: bool) -> None: + """Set the alternative speed mode.""" + self.client.transfer_toggle_speed_limits_mode(is_enabled) + + def toggle_alt_speed_enabled(self) -> None: + """Toggle the alternative speed mode.""" + self.client.transfer_toggle_speed_limits_mode() + + def get_alt_speed_enabled(self) -> bool: + """Get the alternative speed mode.""" + return self._is_alternative_mode_enabled async def get_torrents(self, torrent_filter: TorrentStatusesT) -> TorrentInfoList: """Async method to get QBittorrent torrents.""" diff --git a/homeassistant/components/qbittorrent/helpers.py b/homeassistant/components/qbittorrent/helpers.py index fac0a6033fa..6b459e99741 100644 --- a/homeassistant/components/qbittorrent/helpers.py +++ b/homeassistant/components/qbittorrent/helpers.py @@ -8,7 +8,6 @@ from qbittorrentapi import Client, TorrentDictionary, TorrentInfoList def setup_client(url: str, username: str, password: str, verify_ssl: bool) -> Client: """Create a qBittorrent client.""" - client = Client( url, username=username, password=password, VERIFY_WEBUI_CERTIFICATE=verify_ssl ) diff --git a/homeassistant/components/qbittorrent/strings.json b/homeassistant/components/qbittorrent/strings.json index 948e9dca8e9..fe27beb2a2d 100644 --- a/homeassistant/components/qbittorrent/strings.json +++ b/homeassistant/components/qbittorrent/strings.json @@ -47,6 +47,11 @@ "all_torrents": { "name": "All torrents" } + }, + "switch": { + "alternative_speed": { + "name": "Alternative speed" + } } }, "services": { diff --git a/homeassistant/components/qbittorrent/switch.py b/homeassistant/components/qbittorrent/switch.py new file mode 100644 index 00000000000..f12118e5233 --- /dev/null +++ b/homeassistant/components/qbittorrent/switch.py @@ -0,0 +1,104 @@ +"""Support for monitoring the qBittorrent API.""" + +from __future__ import annotations + +from collections.abc import Callable +from dataclasses import dataclass +from typing import Any + +from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .const import DOMAIN +from .coordinator import QBittorrentDataCoordinator + + +@dataclass(frozen=True, kw_only=True) +class QBittorrentSwitchEntityDescription(SwitchEntityDescription): + """Describes qBittorren switch.""" + + is_on_func: Callable[[QBittorrentDataCoordinator], bool] + turn_on_fn: Callable[[QBittorrentDataCoordinator], None] + turn_off_fn: Callable[[QBittorrentDataCoordinator], None] + toggle_func: Callable[[QBittorrentDataCoordinator], None] + + +SWITCH_TYPES: tuple[QBittorrentSwitchEntityDescription, ...] = ( + QBittorrentSwitchEntityDescription( + key="alternative_speed", + translation_key="alternative_speed", + icon="mdi:speedometer-slow", + is_on_func=lambda coordinator: coordinator.get_alt_speed_enabled(), + turn_on_fn=lambda coordinator: coordinator.set_alt_speed_enabled(True), + turn_off_fn=lambda coordinator: coordinator.set_alt_speed_enabled(False), + toggle_func=lambda coordinator: coordinator.toggle_alt_speed_enabled(), + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + config_entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up qBittorrent switch entries.""" + + coordinator: QBittorrentDataCoordinator = hass.data[DOMAIN][config_entry.entry_id] + + async_add_entities( + QBittorrentSwitch(coordinator, config_entry, description) + for description in SWITCH_TYPES + ) + + +class QBittorrentSwitch(CoordinatorEntity[QBittorrentDataCoordinator], SwitchEntity): + """Representation of a qBittorrent switch.""" + + _attr_has_entity_name = True + entity_description: QBittorrentSwitchEntityDescription + + def __init__( + self, + coordinator: QBittorrentDataCoordinator, + config_entry: ConfigEntry, + entity_description: QBittorrentSwitchEntityDescription, + ) -> None: + """Initialize qBittorrent switch.""" + super().__init__(coordinator) + self.entity_description = entity_description + self._attr_unique_id = f"{config_entry.entry_id}-{entity_description.key}" + self._attr_device_info = DeviceInfo( + entry_type=DeviceEntryType.SERVICE, + identifiers={(DOMAIN, config_entry.entry_id)}, + manufacturer="QBittorrent", + ) + + @property + def is_on(self) -> bool: + """Return true if device is on.""" + return self.entity_description.is_on_func(self.coordinator) + + async def async_turn_on(self, **kwargs: Any) -> None: + """Turn on this switch.""" + await self.hass.async_add_executor_job( + self.entity_description.turn_on_fn, self.coordinator + ) + await self.coordinator.async_request_refresh() + + async def async_turn_off(self, **kwargs: Any) -> None: + """Turn off this switch.""" + await self.hass.async_add_executor_job( + self.entity_description.turn_off_fn, self.coordinator + ) + await self.coordinator.async_request_refresh() + + async def async_toggle(self, **kwargs: Any) -> None: + """Toggle the device.""" + await self.hass.async_add_executor_job( + self.entity_description.toggle_func, self.coordinator + ) + await self.coordinator.async_request_refresh()