1 """Support for monitoring the Transmission BitTorrent client API."""
3 from __future__
import annotations
5 from collections.abc
import Callable
6 from contextlib
import suppress
7 from dataclasses
import dataclass
10 from transmission_rpc.torrent
import Torrent
15 SensorEntityDescription,
24 from .
import TransmissionConfigEntry
27 STATE_ATTR_TORRENT_INFO,
31 SUPPORTED_ORDER_MODES,
33 from .coordinator
import TransmissionDataUpdateCoordinator
35 MODES: dict[str, list[str] |
None] = {
36 "started_torrents": [
"downloading"],
37 "completed_torrents": [
"seeding"],
38 "paused_torrents": [
"stopped"],
43 "total_torrents":
None,
47 @dataclass(frozen=True, kw_only=True)
49 """Entity description class for Transmission sensors."""
51 val_func: Callable[[TransmissionDataUpdateCoordinator], StateType]
52 extra_state_attr_func: Callable[[Any], dict[str, str]] |
None =
None
55 SENSOR_TYPES: tuple[TransmissionSensorEntityDescription, ...] = (
58 translation_key=
"download_speed",
59 device_class=SensorDeviceClass.DATA_RATE,
60 native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
61 suggested_display_precision=2,
62 suggested_unit_of_measurement=UnitOfDataRate.MEGABYTES_PER_SECOND,
63 val_func=
lambda coordinator:
float(coordinator.data.download_speed),
67 translation_key=
"upload_speed",
68 device_class=SensorDeviceClass.DATA_RATE,
69 native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
70 suggested_display_precision=2,
71 suggested_unit_of_measurement=UnitOfDataRate.MEGABYTES_PER_SECOND,
72 val_func=
lambda coordinator:
float(coordinator.data.upload_speed),
76 translation_key=
"transmission_status",
77 device_class=SensorDeviceClass.ENUM,
78 options=[STATE_IDLE, STATE_UP_DOWN, STATE_SEEDING, STATE_DOWNLOADING],
80 coordinator.data.upload_speed, coordinator.data.download_speed
84 key=
"active_torrents",
85 translation_key=
"active_torrents",
86 val_func=
lambda coordinator: coordinator.data.active_torrent_count,
88 coordinator=coordinator, key=
"active_torrents"
92 key=
"paused_torrents",
93 translation_key=
"paused_torrents",
94 val_func=
lambda coordinator: coordinator.data.paused_torrent_count,
96 coordinator=coordinator, key=
"paused_torrents"
100 key=
"total_torrents",
101 translation_key=
"total_torrents",
102 val_func=
lambda coordinator: coordinator.data.torrent_count,
104 coordinator=coordinator, key=
"total_torrents"
108 key=
"completed_torrents",
109 translation_key=
"completed_torrents",
110 val_func=
lambda coordinator: len(
114 coordinator=coordinator, key=
"completed_torrents"
118 key=
"started_torrents",
119 translation_key=
"started_torrents",
120 val_func=
lambda coordinator: len(
124 coordinator=coordinator, key=
"started_torrents"
132 config_entry: TransmissionConfigEntry,
133 async_add_entities: AddEntitiesCallback,
135 """Set up the Transmission sensors."""
137 coordinator = config_entry.runtime_data
145 CoordinatorEntity[TransmissionDataUpdateCoordinator], SensorEntity
147 """A base class for all Transmission sensors."""
149 entity_description: TransmissionSensorEntityDescription
150 _attr_has_entity_name =
True
154 coordinator: TransmissionDataUpdateCoordinator,
155 entity_description: TransmissionSensorEntityDescription,
157 """Initialize the sensor."""
161 f
"{coordinator.config_entry.entry_id}-{entity_description.key}"
164 entry_type=DeviceEntryType.SERVICE,
165 identifiers={(DOMAIN, coordinator.config_entry.entry_id)},
166 manufacturer=
"Transmission",
171 """Return the value of the sensor."""
176 """Return the state attributes, if any."""
178 return attr_func(self.coordinator)
183 """Get current download/upload state."""
184 if upload > 0
and download > 0:
186 if upload > 0
and download == 0:
188 if upload == 0
and download > 0:
189 return STATE_DOWNLOADING
194 torrents: list[Torrent], statuses: list[str] |
None =
None
198 for torrent
in torrents
199 if statuses
is None or torrent.status
in statuses
204 coordinator: TransmissionDataUpdateCoordinator, key: str
208 torrents = SUPPORTED_ORDER_MODES[coordinator.order](torrents)
209 for torrent
in torrents[: coordinator.limit]:
210 info = infos[torrent.name] = {
211 "added_date": torrent.added_date,
212 "percent_done": f
"{torrent.percent_done * 100:.2f}",
213 "status": torrent.status,
216 with suppress(ValueError):
217 info[
"eta"] =
str(torrent.eta)
218 return {STATE_ATTR_TORRENT_INFO: infos}
None __init__(self, TransmissionDataUpdateCoordinator coordinator, TransmissionSensorEntityDescription entity_description)
StateType native_value(self)
dict[str, Any]|None extra_state_attributes(self)
list[Torrent] _filter_torrents(list[Torrent] torrents, list[str]|None statuses=None)
str get_state(int upload, int download)
dict[str, Any] _torrents_info_attr(TransmissionDataUpdateCoordinator coordinator, str key)
None async_setup_entry(HomeAssistant hass, TransmissionConfigEntry config_entry, AddEntitiesCallback async_add_entities)