Skip to content

Commit 83d812d

Browse files
committed
cloneassistant initial commit
1 parent 7c15b41 commit 83d812d

25 files changed

Lines changed: 2463 additions & 2 deletions

.github/workflows/hassfest.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: Validate with hassfest
2+
3+
on:
4+
push:
5+
pull_request:
6+
schedule:
7+
- cron: "0 0 * * *"
8+
9+
jobs:
10+
validate:
11+
runs-on: "ubuntu-latest"
12+
steps:
13+
- uses: "actions/checkout@v3"
14+
- uses: home-assistant/actions/hassfest@master

.github/workflows/validate.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Validate
2+
3+
on:
4+
push:
5+
pull_request:
6+
schedule:
7+
- cron: "0 0 * * *"
8+
workflow_dispatch:
9+
10+
permissions: {}
11+
12+
jobs:
13+
validate-hacs:
14+
runs-on: "ubuntu-latest"
15+
steps:
16+
- name: HACS validation
17+
uses: "hacs/action@main"
18+
with:
19+
category: "CHANGE_ME!"

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,6 @@ cython_debug/
205205
marimo/_static/
206206
marimo/_lsp/
207207
__marimo__/
208+
209+
# macOS resource forks
210+
.DS_Store

README.md

Lines changed: 222 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,222 @@
1-
# cloneassistant
2-
Control and monitor your recurring Rclone jobs from Home Assistant dashboards.
1+
# CloneAssistant
2+
3+
Control and monitor your recurring [Rclone](https://rclone.org) jobs from [Home Assistant dashboards](https://www.home-assistant.io/dashboards/).
4+
5+
[screenshot]
6+
7+
## Features
8+
9+
- Control and Monitor Rclone jobs running on another device, via the [rc](https://rclone.org/rc/) API
10+
- Start/Stop a job from a Home Assistant "switch" device
11+
- Customizable sensors to monitor job stats and health
12+
- Easily build custom automations and dashboards
13+
- Fully local by default – no cloud access required
14+
15+
This is intended for a particular use case: you have one or more rclone commands that you want to run on a recurring schedule (for example, to [bisync](https://rclone.org/bisync/) a [local machine](https://rclone.org/local/) with an [rclone remote](https://rclone.org/overview/)), and you want to monitor the health and progress of those jobs from beautiful Home Assistant dashboards. Perhaps you also want to leverage Home Assistant's powerful [automation](https://www.home-assistant.io/docs/automation/) and [notification](https://www.home-assistant.io/integrations/notify/) features (say, to alert you if something fails, or trigger an rclone job from some other event.)
16+
17+
The rclone jobs you monitor do not necessarily need to be running on the same machine as Home Assistant. For example, Home Assistant could simultaneously monitor rclone jobs running on multiple different LAN-connected computers.
18+
19+
[more screenshots]
20+
21+
## Quick Start
22+
23+
> [!TIP]
24+
> For more detailed instructions, see [Installation](#installation) section below
25+
26+
1. Start [rclone](https://rclone.org/) with [remote control listening](https://rclone.org/commands/rclone_rcd/):
27+
28+
```sh
29+
rclone rcd -vv --rc-addr=localhost:5572 --rc-user=SOME_USERNAME --rc-pass=SOME_PASSWORD --rc-job-expire-duration=1h
30+
```
31+
32+
2. Install [integration](https://github.com/nielash/cloneassistant):
33+
34+
Copy the `custom_components/rclone` directory into your Home Assistant `config/custom_components` directory, and restart Home Assistant.
35+
36+
3. Click "[Add Entry](http://homeassistant.local:8123/config/integrations/integration/rclone)" button and follow setup wizard
37+
38+
[![Open your Home Assistant instance and show an integration.](https://my.home-assistant.io/badges/integration.svg)](https://my.home-assistant.io/redirect/integration/?domain=rclone)
39+
40+
## Installation
41+
42+
> [!NOTE]
43+
> The following steps assume you have [Home Assistant](https://www.home-assistant.io/installation/) and [Rclone](https://rclone.org/install/) installed on the device(s) where you want to run them.
44+
45+
> [!TIP]
46+
> While running Home Assistant on [dedicated hardware](https://www.home-assistant.io/installation/) is recommended, it is not required. Rclone users looking to use Home Assistant solely as an Rclone GUI could consider running Home Assistant from a [docker container](https://www.home-assistant.io/installation/#install-home-assistant-on-linux).
47+
48+
### 1. Run Rclone with remote control listening
49+
50+
On the device that you want to control, run [rclone](https://rclone.org/) with [remote control listening](https://rclone.org/commands/rclone_rcd/) enabled:
51+
52+
```sh
53+
rclone rcd -vv --rc-addr=localhost:5572 --rc-user=SOME_USERNAME --rc-pass=SOME_PASSWORD --rc-job-expire-duration=1h
54+
```
55+
56+
> [!IMPORTANT]
57+
> Authentication is required, even on `localhost`. [`--rc-user`](https://rclone.org/rc/#rc-user-value) and [`--rc-pass`](https://rclone.org/rc/#rc-pass-value) can be anything you want, as long as you use the same credentials on the server and client sides.
58+
59+
Rclone defaults to `http://localhost:5572` unless a different [`--rc-addr`](https://rclone.org/commands/rclone_rcd/#server-options) is specified. This is fine if you are running Home Assistant and Rclone on the same device. If you are running them on different local devices connected to the same LAN, you can use a local IP address like `--rc-addr=192.168.XX.XX:5572` (depending on your router settings). The port can be customized as needed.
60+
61+
> [!WARNING]
62+
> Using a public IP address is also possible, but make sure you understand the security implications first. Consider using something like [tailscale](https://tailscale.com/docs/how-to/quickstart) to mitigate risks. See also HA's docs on [remote access](https://www.home-assistant.io/docs/configuration/remote/).
63+
64+
Because rclone needs to be running continuously in order for Home Assistant to reach it, consider setting up a cron job to periodically run `rclone rcd`, to ensure rclone remains accessible in the event of fatal errors or machine restarts.
65+
66+
For example, the following cron job:
67+
68+
```sh
69+
*/5 * * * * rclone rcd -vv --rc-addr=localhost:5572 --rc-user=SOME_USERNAME --rc-pass=SOME_PASSWORD --rc-job-expire-duration=1h
70+
```
71+
72+
will attempt to run the [`rclone rcd`](https://rclone.org/commands/rclone_rcd/) command every 5 minutes. If a prior rclone instance is already running on that [`--rc-addr`](https://rclone.org/commands/rclone_rcd/#server-options), the newer instance will simply exit with `address already in use`.
73+
74+
> [!TIP]
75+
> Consider adjusting your computer's auto-sleep settings as necessary. If Home Assistant can't reach your computer because it is sleeping, the command will temporarily show as "unavailable" in Home Assistant. It should automatically become "available" again once it wakes up.
76+
77+
> [!NOTE]
78+
> `--rc-job-expire-duration=1h` (or longer) is recommended, to ensure that the [async jobs](https://rclone.org/rc/#running-asynchronous-jobs-with-async-true) do not disappear before HomeAssistant has a chance to poll them for stats. Rclone's default (`60s`) is quite short, and Home Assistant [tends to encourage longer polling intervals](https://developers.home-assistant.io/docs/core/integration-quality-scale/rules/appropriate-polling). This integration allows the polling interval for each job to be customized during setup, and the code also attempts to be efficient about not polling jobs when we already know they're not running.
79+
80+
> [!NOTE]
81+
> `-vv` just enables debug logging on the server side. Feel free to omit this if you wish.
82+
83+
### 2. Install the Rclone integration in Home Assistant
84+
85+
> [!NOTE]
86+
> For now, this is simply a ["custom integration"](https://developers.home-assistant.io/docs/creating_component_index) rather than an official published ["core" integration](https://www.home-assistant.io/integrations/?brands=featured). (I might consider submitting it at some point, if there's enough user interest.)
87+
88+
> [!TIP]
89+
> If you have [HACS](https://hacs.xyz/) installed (optional), you can install this as a ["custom repository"](https://hacs.xyz/docs/faq/custom_repositories/).
90+
91+
1. Locate your Home Assistant [`config/custom_components`](https://www.home-assistant.io/docs/configuration/#to-find-the-configuration-directory) directory. It may need to be created.
92+
93+
> [!TIP]
94+
> There are numerous options to access this directory, including the [file editor app](https://www.home-assistant.io/common-tasks/os/#installing-and-using-the-file-editor-app), the [Samba app](https://www.home-assistant.io/common-tasks/os/#installing-and-using-the-samba-app), and the [SSH app](https://www.home-assistant.io/common-tasks/os/#installing-and-using-the-ssh-app).
95+
96+
> [!TIP]
97+
> If the [Samba app](https://www.home-assistant.io/common-tasks/os/#installing-and-using-the-samba-app) is enabled, rclone itself can be used to copy files to it, using the [SMB backend](https://rclone.org/smb/).
98+
99+
2. Copy the `custom_components/rclone` directory into your Home Assistant `config/custom_components` directory, including the `rclone` folder itself.
100+
101+
The following example shows how to do this using rclone itself, assuming you have set up an [`smb`](https://rclone.org/smb/) remote named `homeassistant:`
102+
103+
```sh
104+
# download repo zip from github
105+
rclone copyurl "https://github.com/nielash/cloneassistant/archive/refs/heads/master.zip" cloneassistant.zip
106+
107+
# extract it locally
108+
rclone archive extract cloneassistant.zip cloneassistant_extracted
109+
110+
# copy to HA config/custom_components directory
111+
rclone sync cloneassistant_extracted/custom_components/rclone homeassistant:config/custom_components/rclone
112+
```
113+
114+
3. [Restart](https://www.home-assistant.io/docs/configuration/#reloading-the-configuration-to-apply-changes) Home Assistant.
115+
116+
### 3. Configure the Integration
117+
118+
1. Navigate to Settings > Devices & services > Add integration and search "rclone", or use this shortcut:
119+
120+
[![Open your Home Assistant instance and start setting up a new integration.](https://my.home-assistant.io/badges/config_flow_start.svg)](https://my.home-assistant.io/redirect/config_flow_start/?domain=rclone)
121+
122+
2. Follow the config wizard to configure your first rclone job. (An "entry" here corresponds to one rclone command.)
123+
124+
> [!NOTE]
125+
> When you configure a command and click "Submit", Home Assistant will verify that it can connect to rclone successfully. However, it will not actually run your configured command. To run it, use the provided "switch" device in the UI, or create an [automation](https://www.home-assistant.io/getting-started/automation/) that uses it as an "action".
126+
127+
| Setting | Description | Example |
128+
| ----------- | ----------- | ----------- |
129+
| `friendly_name` | A human-friendly name to identify this rclone command. Tip: keep this short. | `Bisync Laptop` |
130+
| `Host` | the `--rc-addr` for this job | `192.168.12.34:5572` |
131+
| `Username` | the `--rc-user` for this job | `nielash` |
132+
| `Password` | the `--rc-pass` for this job | `ZqOa*c!U8O^L1P&Xfi8#` |
133+
| `scan_interval` | number of seconds to wait between stats refreshes, while job is running. Default: `60`, Minimum: `5`. Shorter intervals will use more resources. | `5` |
134+
| `command` | the [rc method](https://rclone.org/rc/#supported-commands) (rclone command) you wish to run. | `sync/bisync` |
135+
| `command_args` | the parameters (flags) for the command, in [JSON blob format](https://rclone.org/rc/#json-input). See [examples](#command_args-json-examples) below. Must be [valid JSON](https://www.json.fr/). Note that `_async = true` will be added automatically; it does not need to be supplied. | `{"path1": "/some/local/path", "path2": "some_remote:path", "filtersFile": "/some/filters.txt"}` |
136+
137+
#### `command_args` JSON Examples
138+
139+
> [!TIP]
140+
> Use a [JSON validator](https://www.json.fr/) to validate (and beautify) your JSON.
141+
142+
- [Bisync JSON Example](/examples/commands/bisync_example.json)
143+
- Reference: <https://rclone.org/rc/#sync-bisync>
144+
- [Sync JSON Example](/examples/commands/sync_example.json)
145+
- Reference: <https://rclone.org/rc/#sync-sync>
146+
- [Check JSON Example](/examples/commands/check_example.json)
147+
- Reference: <https://rclone.org/rc/#operations-check>
148+
- [Delete JSON Example](/examples/commands/delete_example.json)
149+
- Reference: <https://rclone.org/rc/#operations-delete>
150+
151+
3. Enter a "Device" name (usually the suggested default will be fine) and complete setup.
152+
153+
Upon completing setup, you will see the "device" and "entities" created for this command.
154+
155+
> [!NOTE]
156+
> If the terms "device" and "entity" seem odd in this context, it is because Home Assistant is intended for physical smart home / IOT devices. An rclone command doesn't fit perfectly onto this concept, but you can think of it like a virtual light switch "device". When the switch is "on", the job is running; when it's "off", the job is not running. It has "sensor" entities that each correspond to one stats metric (bytes transferred, number of checks, start time, etc.) Because you may have more than one rclone command configured, a ["device"](https://www.home-assistant.io/getting-started/concepts-terminology/#devices) is how we logically group the "entities" for a given command to keep them together, and keep them separate from the ["entities"](https://www.home-assistant.io/getting-started/concepts-terminology/#entities) of another command.
157+
158+
You can verify that your command is working by switching it "on" in the UI.
159+
160+
> [!TIP]
161+
> The command's output (if any), can be viewed in the "Details" attributes of the "switch" entity. (Three-dots menu > "Details")
162+
163+
### 4. (Optional) Schedule the command to run
164+
165+
Home Assistant's powerful automation features make it easy to trigger your command based on schedules, events, the state of other entities, and many other things. Here's a simple example showing a command that runs every 10 minutes:
166+
167+
```yaml
168+
alias: Bisync Desktop Every 10 Minutes
169+
description: ""
170+
triggers:
171+
- trigger: time_pattern
172+
minutes: /10
173+
conditions: []
174+
actions:
175+
- type: turn_on
176+
device_id: some_device_id
177+
entity_id: some_entity_id
178+
domain: switch
179+
mode: single
180+
```
181+
182+
The easiest way to set these up is through the visual editor (Settings > Automations & scenes > Create automation). Your "action" will want to turn "on" the switch "device" corresponding to this command.
183+
184+
### 5. (Optional) Set up a Dashboard
185+
186+
While it's easy enough to monitor entities from the default "device" page, you may want to set up a "Dashboard" to emphasize the jobs and metrics that are most important to you, and customize how they are displayed. Designing dashboards is a huge topic beyond the scope of this tutorial, but for convenience, an [example template](/examples/dashboards/rclone_dashboard.yaml) is provided. You will need to replace the entities with your own.
187+
188+
### 6. Editing your Configuration
189+
190+
The settings you configured in the previous steps can be easily re-configured as necessary later, without having to delete the device and start over.
191+
192+
1. Navigate to the [integration page](https://my.home-assistant.io/redirect/integration/?domain=rclone)
193+
194+
[![Open your Home Assistant instance and show an integration.](https://my.home-assistant.io/badges/integration.svg)](https://my.home-assistant.io/redirect/integration/?domain=rclone)
195+
196+
2. To edit the `scan_interval`, `command`, or `command_args`, click the "gear" icon corresponding to the entry for the command.
197+
198+
3. To edit the `friendly_name`, `Host`, `Username`, or `Password`, click the three-dots menu corresponding to the entry for the command, and select "Reconfigure".
199+
200+
You can also change the names, icons, and units of individual entities, should you wish.
201+
202+
## Status
203+
204+
This integration is in beta. Future versions may have substantial breaking changes. User feedback is always welcome, and is especially helpful in this early development period.
205+
206+
## License
207+
208+
This is free software under the terms of the MIT license.
209+
210+
## Contributing
211+
212+
Please feel free to use Github "Issues" to submit bug reports and feature requests.
213+
214+
Please also feel free to submit "Pull requests" (which are most welcome!)
215+
216+
And if you build some cool custom dashboards/panels/cards/etc. and feel like sharing in "Discussions", I'd love to see them!
217+
218+
## Credits
219+
220+
Big thanks to [@ncw](https://github.com/ncw) for the ingenious tool that is [rclone](https://github.com/rclone/rclone).
221+
222+
And another big thanks to [@msp1974](https://github.com/msp1974), whose [HAIntegrationExamples](https://github.com/msp1974/HAIntegrationExamples) repo was hugely helpful to me in creating this integration.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
"""The Rclone integration."""
2+
3+
from __future__ import annotations
4+
5+
from dataclasses import dataclass
6+
import logging
7+
8+
from homeassistant.config_entries import ConfigEntry
9+
from homeassistant.const import Platform
10+
from homeassistant.core import HomeAssistant
11+
from homeassistant.exceptions import ConfigEntryNotReady
12+
from homeassistant.helpers.device_registry import DeviceEntry
13+
14+
from .coordinator import RcloneCoordinator
15+
16+
_LOGGER = logging.getLogger(__name__)
17+
18+
PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR, Platform.SWITCH]
19+
20+
type RcloneConfigEntry = ConfigEntry[RuntimeData]
21+
22+
23+
@dataclass
24+
class RuntimeData:
25+
"""Class to hold the data."""
26+
27+
coordinator: RcloneCoordinator
28+
29+
30+
async def async_setup_entry(
31+
hass: HomeAssistant, config_entry: RcloneConfigEntry
32+
) -> bool:
33+
"""Set up a job integration from a config entry."""
34+
35+
# Initialise the coordinator that manages data updates from the api.
36+
# This is defined in coordinator.py
37+
coordinator = RcloneCoordinator(hass, config_entry)
38+
39+
# Perform an initial data load from api.
40+
# async_config_entry_first_refresh() is special in that it does not log errors if it fails
41+
await coordinator.async_config_entry_first_refresh()
42+
43+
# Test to see if api initialised correctly, else raise ConfigNotReady to make HA retry setup
44+
if not coordinator.api.connected:
45+
raise ConfigEntryNotReady
46+
47+
# Initialise a listener for config flow options changes.
48+
# This will be removed automatically if the integraiton is unloaded.
49+
# See config_flow for defining an options setting that shows up as configure
50+
# on the integration.
51+
config_entry.async_on_unload(
52+
config_entry.add_update_listener(_async_update_listener)
53+
)
54+
55+
# Add the coordinator and update listener to config runtime data to make
56+
# accessible throughout the integration
57+
config_entry.runtime_data = RuntimeData(coordinator)
58+
59+
# Setup platforms (based on the list of entity types in PLATFORMS defined above)
60+
# This calls the async_setup method in each of the entity type files.
61+
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
62+
63+
# Return true to note a successful setup.
64+
return True
65+
66+
67+
async def _async_update_listener(hass: HomeAssistant, config_entry):
68+
"""Handle config options update."""
69+
# Reload the integration when the options change.
70+
await hass.config_entries.async_reload(config_entry.entry_id)
71+
72+
73+
async def async_remove_config_entry_device(
74+
hass: HomeAssistant, config_entry: ConfigEntry, device_entry: DeviceEntry
75+
) -> bool:
76+
"""Delete device if selected from UI."""
77+
# Adding this function shows the delete device option in the UI.
78+
return True
79+
80+
81+
async def async_unload_entry(
82+
hass: HomeAssistant, config_entry: RcloneConfigEntry
83+
) -> bool:
84+
"""Unload a config entry."""
85+
# This is called when you remove the integration or shutdown HA.
86+
# If you have created any custom services, they need to be removed here too.
87+
88+
# Unload platforms and return result
89+
return await hass.config_entries.async_unload_platforms(config_entry, PLATFORMS)

0 commit comments

Comments
 (0)