Add downloading and seeding counts to Deluge (#150623)

This commit is contained in:
Chris Oldfield
2025-09-16 21:06:14 +10:00
committed by GitHub
parent f9b1c52d65
commit 44a95242dc
7 changed files with 92 additions and 8 deletions
+2
View File
@@ -43,3 +43,5 @@ class DelugeSensorType(enum.StrEnum):
UPLOAD_SPEED_SENSOR = "upload_speed"
PROTOCOL_TRAFFIC_UPLOAD_SPEED_SENSOR = "protocol_traffic_upload_speed"
PROTOCOL_TRAFFIC_DOWNLOAD_SPEED_SENSOR = "protocol_traffic_download_speed"
DOWNLOADING_COUNT_SENSOR = "downloading_count"
SEEDING_COUNT_SENSOR = "seeding_count"
+37 -8
View File
@@ -2,6 +2,7 @@
from __future__ import annotations
from collections import Counter
from datetime import timedelta
from ssl import SSLError
from typing import Any
@@ -14,11 +15,22 @@ from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import LOGGER, DelugeGetSessionStatusKeys
from .const import LOGGER, DelugeGetSessionStatusKeys, DelugeSensorType
type DelugeConfigEntry = ConfigEntry[DelugeDataUpdateCoordinator]
def count_states(data: dict[str, Any]) -> dict[str, int]:
"""Count the states of the provided torrents."""
counts = Counter(torrent[b"state"].decode() for torrent in data.values())
return {
DelugeSensorType.DOWNLOADING_COUNT_SENSOR.value: counts.get("Downloading", 0),
DelugeSensorType.SEEDING_COUNT_SENSOR.value: counts.get("Seeding", 0),
}
class DelugeDataUpdateCoordinator(
DataUpdateCoordinator[dict[Platform, dict[str, Any]]]
):
@@ -39,19 +51,22 @@ class DelugeDataUpdateCoordinator(
)
self.api = api
async def _async_update_data(self) -> dict[Platform, dict[str, Any]]:
"""Get the latest data from Deluge and updates the state."""
def _get_deluge_data(self):
"""Get the latest data from Deluge."""
data = {}
try:
_data = await self.hass.async_add_executor_job(
self.api.call,
data["session_status"] = self.api.call(
"core.get_session_status",
[iter_member.value for iter_member in list(DelugeGetSessionStatusKeys)],
)
data[Platform.SENSOR] = {k.decode(): v for k, v in _data.items()}
data[Platform.SWITCH] = await self.hass.async_add_executor_job(
self.api.call, "core.get_torrents_status", {}, ["paused"]
data["torrents_status_state"] = self.api.call(
"core.get_torrents_status", {}, ["state"]
)
data["torrents_status_paused"] = self.api.call(
"core.get_torrents_status", {}, ["paused"]
)
except (
ConnectionRefusedError,
TimeoutError,
@@ -66,4 +81,18 @@ class DelugeDataUpdateCoordinator(
) from ex
LOGGER.error("Unknown error connecting to Deluge: %s", ex)
raise
return data
async def _async_update_data(self) -> dict[Platform, dict[str, Any]]:
"""Get the latest data from Deluge and updates the state."""
deluge_data = await self.hass.async_add_executor_job(self._get_deluge_data)
data = {}
data[Platform.SENSOR] = {
k.decode(): v for k, v in deluge_data["session_status"].items()
}
data[Platform.SENSOR].update(count_states(deluge_data["torrents_status_state"]))
data[Platform.SWITCH] = deluge_data["torrents_status_paused"]
return data
@@ -0,0 +1,12 @@
{
"entity": {
"sensor": {
"downloading_count": {
"default": "mdi:download"
},
"seeding_count": {
"default": "mdi:upload"
}
}
}
}
+12
View File
@@ -110,6 +110,18 @@ SENSOR_TYPES: tuple[DelugeSensorEntityDescription, ...] = (
data, DelugeSensorType.PROTOCOL_TRAFFIC_DOWNLOAD_SPEED_SENSOR.value
),
),
DelugeSensorEntityDescription(
key=DelugeSensorType.DOWNLOADING_COUNT_SENSOR.value,
translation_key=DelugeSensorType.DOWNLOADING_COUNT_SENSOR.value,
state_class=SensorStateClass.TOTAL,
value=lambda data: data[DelugeSensorType.DOWNLOADING_COUNT_SENSOR.value],
),
DelugeSensorEntityDescription(
key=DelugeSensorType.SEEDING_COUNT_SENSOR.value,
translation_key=DelugeSensorType.SEEDING_COUNT_SENSOR.value,
state_class=SensorStateClass.TOTAL,
value=lambda data: data[DelugeSensorType.SEEDING_COUNT_SENSOR.value],
),
)
@@ -36,6 +36,10 @@
"idle": "[%key:common::state::idle%]"
}
},
"downloading_count": {
"name": "Downloading count",
"unit_of_measurement": "torrents"
},
"download_speed": {
"name": "Download speed"
},
@@ -45,6 +49,10 @@
"protocol_traffic_upload_speed": {
"name": "Protocol traffic upload speed"
},
"seeding_count": {
"name": "Seeding count",
"unit_of_measurement": "[%key:component::deluge::entity::sensor::downloading_count::unit_of_measurement%]"
},
"upload_speed": {
"name": "Upload speed"
}
+6
View File
@@ -21,3 +21,9 @@ GET_TORRENT_STATUS_RESPONSE = {
"dht_upload_rate": 7818.0,
"dht_download_rate": 2658.0,
}
GET_TORRENT_STATES_RESPONSE = {
"6dcd3f46d09547b62bf07ba9b2943c95d53ddae3": {b"state": b"Seeding"},
"1c56ea49918b9baed94cf4bc0ee9f324efc8841a": {b"state": b"Downloading"},
"fbf4dab701189a344fa5ab06d7b87c11a74e3da0": {b"state": b"Seeding"},
}
@@ -0,0 +1,15 @@
"""Test Deluge coordinator.py methods."""
from homeassistant.components.deluge.const import DelugeSensorType
from homeassistant.components.deluge.coordinator import count_states
from . import GET_TORRENT_STATES_RESPONSE
def test_get_count() -> None:
"""Tests count_states()."""
states = count_states(GET_TORRENT_STATES_RESPONSE)
assert states[DelugeSensorType.DOWNLOADING_COUNT_SENSOR.value] == 1
assert states[DelugeSensorType.SEEDING_COUNT_SENSOR.value] == 2