Add host field to add_torrent service (#28653)
* Add host field to add_torrent service * Code cleanup * use name instead of host for service * update add_torrent
This commit is contained in:
parent
f8a36499c1
commit
a5960830d7
7 changed files with 79 additions and 64 deletions
|
@ -1,42 +1,34 @@
|
|||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Host is already configured.",
|
||||
"one_instance_allowed": "Only a single instance is necessary."
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Unable to Connect to host",
|
||||
"name_exists": "Name already exists",
|
||||
"wrong_credentials": "Wrong username or password"
|
||||
},
|
||||
"title": "Transmission",
|
||||
"step": {
|
||||
"options": {
|
||||
"data": {
|
||||
"scan_interval": "Update frequency"
|
||||
},
|
||||
"title": "Configure Options"
|
||||
},
|
||||
"user": {
|
||||
"title": "Setup Transmission Client",
|
||||
"data": {
|
||||
"host": "Host",
|
||||
"name": "Name",
|
||||
"host": "Host",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"port": "Port",
|
||||
"username": "Username"
|
||||
},
|
||||
"title": "Setup Transmission Client"
|
||||
"port": "Port"
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": "Transmission"
|
||||
"error": {
|
||||
"name_exists": "Name already exists",
|
||||
"wrong_credentials": "Wrong username or password",
|
||||
"cannot_connect": "Unable to Connect to host"
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "Host is already configured."
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"title": "Configure options for Transmission",
|
||||
"data": {
|
||||
"scan_interval": "Update frequency"
|
||||
},
|
||||
"description": "Configure options for Transmission",
|
||||
"title": "Configure options for Transmission"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ from homeassistant.exceptions import ConfigEntryNotReady
|
|||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.dispatcher import dispatcher_send
|
||||
from homeassistant.helpers.event import async_track_time_interval
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from .const import (
|
||||
ATTR_TORRENT,
|
||||
|
@ -28,13 +27,16 @@ from .const import (
|
|||
DEFAULT_SCAN_INTERVAL,
|
||||
DOMAIN,
|
||||
SERVICE_ADD_TORRENT,
|
||||
DATA_UPDATED,
|
||||
)
|
||||
from .errors import AuthenticationError, CannotConnect, UnknownError
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
SERVICE_ADD_TORRENT_SCHEMA = vol.Schema({vol.Required(ATTR_TORRENT): cv.string})
|
||||
SERVICE_ADD_TORRENT_SCHEMA = vol.Schema(
|
||||
{vol.Required(ATTR_TORRENT): cv.string, vol.Required(CONF_NAME): cv.string}
|
||||
)
|
||||
|
||||
TRANS_SCHEMA = vol.All(
|
||||
vol.Schema(
|
||||
|
@ -55,6 +57,8 @@ CONFIG_SCHEMA = vol.Schema(
|
|||
{DOMAIN: vol.All(cv.ensure_list, [TRANS_SCHEMA])}, extra=vol.ALLOW_EXTRA
|
||||
)
|
||||
|
||||
PLATFORMS = ["sensor", "switch"]
|
||||
|
||||
|
||||
async def async_setup(hass, config):
|
||||
"""Import the Transmission Component from config."""
|
||||
|
@ -82,15 +86,15 @@ async def async_setup_entry(hass, config_entry):
|
|||
|
||||
async def async_unload_entry(hass, config_entry):
|
||||
"""Unload Transmission Entry from config_entry."""
|
||||
client = hass.data[DOMAIN][config_entry.entry_id]
|
||||
hass.services.async_remove(DOMAIN, client.service_name)
|
||||
client = hass.data[DOMAIN].pop(config_entry.entry_id)
|
||||
if client.unsub_timer:
|
||||
client.unsub_timer()
|
||||
|
||||
for component in "sensor", "switch":
|
||||
await hass.config_entries.async_forward_entry_unload(config_entry, component)
|
||||
for platform in PLATFORMS:
|
||||
await hass.config_entries.async_forward_entry_unload(config_entry, platform)
|
||||
|
||||
hass.data[DOMAIN].pop(config_entry.entry_id)
|
||||
if not hass.data[DOMAIN]:
|
||||
hass.services.async_remove(DOMAIN, SERVICE_ADD_TORRENT)
|
||||
|
||||
return True
|
||||
|
||||
|
@ -128,14 +132,10 @@ class TransmissionClient:
|
|||
"""Initialize the Transmission RPC API."""
|
||||
self.hass = hass
|
||||
self.config_entry = config_entry
|
||||
self.tm_api = None
|
||||
self._tm_data = None
|
||||
self.unsub_timer = None
|
||||
|
||||
@property
|
||||
def service_name(self):
|
||||
"""Return the service name."""
|
||||
return slugify(f"{SERVICE_ADD_TORRENT}_{self.config_entry.data[CONF_NAME]}")
|
||||
|
||||
@property
|
||||
def api(self):
|
||||
"""Return the tm_data object."""
|
||||
|
@ -145,20 +145,20 @@ class TransmissionClient:
|
|||
"""Set up the Transmission client."""
|
||||
|
||||
try:
|
||||
api = await get_api(self.hass, self.config_entry.data)
|
||||
self.tm_api = await get_api(self.hass, self.config_entry.data)
|
||||
except CannotConnect:
|
||||
raise ConfigEntryNotReady
|
||||
except (AuthenticationError, UnknownError):
|
||||
return False
|
||||
|
||||
self._tm_data = TransmissionData(self.hass, self.config_entry, api)
|
||||
self._tm_data = TransmissionData(self.hass, self.config_entry, self.tm_api)
|
||||
|
||||
await self.hass.async_add_executor_job(self._tm_data.init_torrent_list)
|
||||
await self.hass.async_add_executor_job(self._tm_data.update)
|
||||
self.add_options()
|
||||
self.set_scan_interval(self.config_entry.options[CONF_SCAN_INTERVAL])
|
||||
|
||||
for platform in ["sensor", "switch"]:
|
||||
for platform in PLATFORMS:
|
||||
self.hass.async_create_task(
|
||||
self.hass.config_entries.async_forward_entry_setup(
|
||||
self.config_entry, platform
|
||||
|
@ -167,18 +167,26 @@ class TransmissionClient:
|
|||
|
||||
def add_torrent(service):
|
||||
"""Add new torrent to download."""
|
||||
tm_client = None
|
||||
for entry in self.hass.config_entries.async_entries(DOMAIN):
|
||||
if entry.data[CONF_NAME] == service.data[CONF_NAME]:
|
||||
tm_client = self.hass.data[DOMAIN][entry.entry_id]
|
||||
break
|
||||
if tm_client is None:
|
||||
_LOGGER.error("Transmission instance is not found")
|
||||
return
|
||||
torrent = service.data[ATTR_TORRENT]
|
||||
if torrent.startswith(
|
||||
("http", "ftp:", "magnet:")
|
||||
) or self.hass.config.is_allowed_path(torrent):
|
||||
api.add_torrent(torrent)
|
||||
tm_client.tm_api.add_torrent(torrent)
|
||||
else:
|
||||
_LOGGER.warning(
|
||||
"Could not add torrent: unsupported type or no permission"
|
||||
)
|
||||
|
||||
self.hass.services.async_register(
|
||||
DOMAIN, self.service_name, add_torrent, schema=SERVICE_ADD_TORRENT_SCHEMA
|
||||
DOMAIN, SERVICE_ADD_TORRENT, add_torrent, schema=SERVICE_ADD_TORRENT_SCHEMA
|
||||
)
|
||||
|
||||
self.config_entry.add_update_listener(self.async_options_updated)
|
||||
|
@ -200,7 +208,7 @@ class TransmissionClient:
|
|||
def set_scan_interval(self, scan_interval):
|
||||
"""Update scan interval."""
|
||||
|
||||
async def refresh(event_time):
|
||||
def refresh(event_time):
|
||||
"""Get the latest data from Transmission."""
|
||||
self._tm_data.update()
|
||||
|
||||
|
@ -240,9 +248,9 @@ class TransmissionData:
|
|||
return self.config.data[CONF_HOST]
|
||||
|
||||
@property
|
||||
def signal_options_update(self):
|
||||
"""Option update signal per transmission entry."""
|
||||
return f"tm-options-{self.host}"
|
||||
def signal_update(self):
|
||||
"""Update signal per transmission entry."""
|
||||
return f"{DATA_UPDATED}-{self.host}"
|
||||
|
||||
def update(self):
|
||||
"""Get the latest data from Transmission instance."""
|
||||
|
@ -260,7 +268,7 @@ class TransmissionData:
|
|||
except TransmissionError:
|
||||
self.available = False
|
||||
_LOGGER.error("Unable to connect to Transmission client %s", self.host)
|
||||
dispatcher_send(self.hass, self.signal_options_update)
|
||||
dispatcher_send(self.hass, self.signal_update)
|
||||
|
||||
def init_torrent_list(self):
|
||||
"""Initialize torrent lists."""
|
||||
|
|
|
@ -16,9 +16,19 @@ from . import get_api
|
|||
from .const import DEFAULT_NAME, DEFAULT_PORT, DEFAULT_SCAN_INTERVAL, DOMAIN
|
||||
from .errors import AuthenticationError, CannotConnect, UnknownError
|
||||
|
||||
DATA_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_NAME, default=DEFAULT_NAME): str,
|
||||
vol.Required(CONF_HOST): str,
|
||||
vol.Optional(CONF_USERNAME): str,
|
||||
vol.Optional(CONF_PASSWORD): str,
|
||||
vol.Required(CONF_PORT, default=DEFAULT_PORT): int,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class TransmissionFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a UniFi config flow."""
|
||||
"""Handle Tansmission config flow."""
|
||||
|
||||
VERSION = 1
|
||||
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
|
||||
|
@ -57,17 +67,7 @@ class TransmissionFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
data_schema=vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_NAME, default=DEFAULT_NAME): str,
|
||||
vol.Required(CONF_HOST): str,
|
||||
vol.Optional(CONF_USERNAME): str,
|
||||
vol.Optional(CONF_PASSWORD): str,
|
||||
vol.Required(CONF_PORT, default=DEFAULT_PORT): int,
|
||||
}
|
||||
),
|
||||
errors=errors,
|
||||
step_id="user", data_schema=DATA_SCHEMA, errors=errors,
|
||||
)
|
||||
|
||||
async def async_step_import(self, import_config):
|
||||
|
|
|
@ -52,6 +52,7 @@ class TransmissionSensor(Entity):
|
|||
self._data = None
|
||||
self.client_name = client_name
|
||||
self.type = sensor_type
|
||||
self.unsub_update = None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
@ -92,9 +93,9 @@ class TransmissionSensor(Entity):
|
|||
|
||||
async def async_added_to_hass(self):
|
||||
"""Handle entity which will be added."""
|
||||
async_dispatcher_connect(
|
||||
self.unsub_update = async_dispatcher_connect(
|
||||
self.hass,
|
||||
self._tm_client.api.signal_options_update,
|
||||
self._tm_client.api.signal_update,
|
||||
self._schedule_immediate_update,
|
||||
)
|
||||
|
||||
|
@ -102,6 +103,12 @@ class TransmissionSensor(Entity):
|
|||
def _schedule_immediate_update(self):
|
||||
self.async_schedule_update_ha_state(True)
|
||||
|
||||
async def will_remove_from_hass(self):
|
||||
"""Unsubscribe from update dispatcher."""
|
||||
if self.unsub_update:
|
||||
self.unsub_update()
|
||||
self.unsub_update = None
|
||||
|
||||
def update(self):
|
||||
"""Get the latest data from Transmission and updates the state."""
|
||||
self._data = self._tm_client.api.data
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
add_torrent:
|
||||
description: Add a new torrent to download (URL, magnet link or Base64 encoded).
|
||||
fields:
|
||||
name:
|
||||
description: Instance name as entered during entry config
|
||||
example: Transmission
|
||||
torrent:
|
||||
description: URL, magnet link or Base64 encoded file.
|
||||
example: http://releases.ubuntu.com/19.04/ubuntu-19.04-desktop-amd64.iso.torrent
|
||||
|
|
|
@ -40,6 +40,7 @@ class TransmissionSwitch(ToggleEntity):
|
|||
self._tm_client = tm_client
|
||||
self._state = STATE_OFF
|
||||
self._data = None
|
||||
self.unsub_update = None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
@ -93,9 +94,9 @@ class TransmissionSwitch(ToggleEntity):
|
|||
|
||||
async def async_added_to_hass(self):
|
||||
"""Handle entity which will be added."""
|
||||
async_dispatcher_connect(
|
||||
self.unsub_update = async_dispatcher_connect(
|
||||
self.hass,
|
||||
self._tm_client.api.signal_options_update,
|
||||
self._tm_client.api.signal_update,
|
||||
self._schedule_immediate_update,
|
||||
)
|
||||
|
||||
|
@ -103,6 +104,12 @@ class TransmissionSwitch(ToggleEntity):
|
|||
def _schedule_immediate_update(self):
|
||||
self.async_schedule_update_ha_state(True)
|
||||
|
||||
async def will_remove_from_hass(self):
|
||||
"""Unsubscribe from update dispatcher."""
|
||||
if self.unsub_update:
|
||||
self.unsub_update()
|
||||
self.unsub_update = None
|
||||
|
||||
def update(self):
|
||||
"""Get the latest data from Transmission and updates the state."""
|
||||
active = None
|
||||
|
|
|
@ -98,7 +98,6 @@ async def test_flow_works(hass, api):
|
|||
assert result["data"][CONF_NAME] == NAME
|
||||
assert result["data"][CONF_HOST] == HOST
|
||||
assert result["data"][CONF_PORT] == PORT
|
||||
# assert result["data"]["options"][CONF_SCAN_INTERVAL] == DEFAULT_SCAN_INTERVAL
|
||||
|
||||
# test with all provided
|
||||
result = await flow.async_step_user(MOCK_ENTRY)
|
||||
|
@ -110,7 +109,6 @@ async def test_flow_works(hass, api):
|
|||
assert result["data"][CONF_USERNAME] == USERNAME
|
||||
assert result["data"][CONF_PASSWORD] == PASSWORD
|
||||
assert result["data"][CONF_PORT] == PORT
|
||||
# assert result["data"]["options"][CONF_SCAN_INTERVAL] == DEFAULT_SCAN_INTERVAL
|
||||
|
||||
|
||||
async def test_options(hass):
|
||||
|
|
Loading…
Add table
Reference in a new issue