"""Support for monitoring the qBittorrent API.""" from __future__ import annotations from collections.abc import Callable from dataclasses import dataclass import logging from typing import Any from homeassistant.components.sensor import ( SensorDeviceClass, SensorEntity, SensorEntityDescription, SensorStateClass, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import STATE_IDLE, UnitOfDataRate from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import StateType from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import DOMAIN from .coordinator import QBittorrentDataCoordinator _LOGGER = logging.getLogger(__name__) SENSOR_TYPE_CURRENT_STATUS = "current_status" SENSOR_TYPE_DOWNLOAD_SPEED = "download_speed" SENSOR_TYPE_UPLOAD_SPEED = "upload_speed" @dataclass class QBittorrentMixin: """Mixin for required keys.""" value_fn: Callable[[dict[str, Any]], StateType] @dataclass class QBittorrentSensorEntityDescription(SensorEntityDescription, QBittorrentMixin): """Describes QBittorrent sensor entity.""" def _get_qbittorrent_state(data: dict[str, Any]) -> str: download = data["server_state"]["dl_info_speed"] upload = data["server_state"]["up_info_speed"] if upload > 0 and download > 0: return "up_down" if upload > 0 and download == 0: return "seeding" if upload == 0 and download > 0: return "downloading" return STATE_IDLE def format_speed(speed): """Return a bytes/s measurement as a human readable string.""" kb_spd = float(speed) / 1024 return round(kb_spd, 2 if kb_spd < 0.1 else 1) SENSOR_TYPES: tuple[QBittorrentSensorEntityDescription, ...] = ( QBittorrentSensorEntityDescription( key=SENSOR_TYPE_CURRENT_STATUS, name="Status", value_fn=_get_qbittorrent_state, ), QBittorrentSensorEntityDescription( key=SENSOR_TYPE_DOWNLOAD_SPEED, name="Down Speed", icon="mdi:cloud-download", device_class=SensorDeviceClass.DATA_RATE, native_unit_of_measurement=UnitOfDataRate.KIBIBYTES_PER_SECOND, state_class=SensorStateClass.MEASUREMENT, value_fn=lambda data: format_speed(data["server_state"]["dl_info_speed"]), ), QBittorrentSensorEntityDescription( key=SENSOR_TYPE_UPLOAD_SPEED, name="Up Speed", icon="mdi:cloud-upload", device_class=SensorDeviceClass.DATA_RATE, native_unit_of_measurement=UnitOfDataRate.KIBIBYTES_PER_SECOND, state_class=SensorStateClass.MEASUREMENT, value_fn=lambda data: format_speed(data["server_state"]["up_info_speed"]), ), ) async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, async_add_entites: AddEntitiesCallback, ) -> None: """Set up qBittorrent sensor entries.""" coordinator: QBittorrentDataCoordinator = hass.data[DOMAIN][config_entry.entry_id] entities = [ QBittorrentSensor(description, coordinator, config_entry) for description in SENSOR_TYPES ] async_add_entites(entities) class QBittorrentSensor(CoordinatorEntity[QBittorrentDataCoordinator], SensorEntity): """Representation of a qBittorrent sensor.""" entity_description: QBittorrentSensorEntityDescription def __init__( self, description: QBittorrentSensorEntityDescription, coordinator: QBittorrentDataCoordinator, config_entry: ConfigEntry, ) -> None: """Initialize the qBittorrent sensor.""" super().__init__(coordinator) self.entity_description = description self._attr_unique_id = f"{config_entry.entry_id}-{description.key}" self._attr_name = f"{config_entry.title} {description.name}" self._attr_available = False @property def native_value(self) -> StateType: """Return value of sensor.""" return self.entity_description.value_fn(self.coordinator.data)