Home Assistant is an open-source self-hosted home automation platform. It can be used to locally control a variety of different home smart devices.
There are few ways Home Assistant can be deployed. The method I currently use is Home Assistant Supervised. This runs the Home Assistant Core whilst also leveraging docker to deploy add-ons that provide additional standalone applications. Home Assistant allows custom add-ons to be written to bring extra functionally required by the user.
Home Assistant Supervised provides snapshot functionality that snapshots the current configuration of Home Assistant. These snapshots are stored locally as tar files. I needed a way to remove the unneeded older snapshots then transfer the remaining files to my network attached storage.
Produce a custom add-on that:
removes snapshots older than a specified number of days
pushes snapshots to a rsync server with and without support for authentication
The git repository of the project can be found here
Directory structure
The first task was to write config.json
; this is the configuration required by the Home Assistant Supervisor to build the add-on using the supplied Dockerfile
. Once built, the add-on is accessible through the Home Assistant web interface and allows for user configuration to be entered in json format. Required user configuration is generated by the options
key below.
config.json
{ "name": "Remove and Rsync", "version": "1.0", "slug": "remove_backups_rsync", "description": "Remove old backups and rsync to server", "url": "https://gitlab.com/jselby/hassio-addons/blob/master/README.md", "arch": ["armhf", "armv7", "aarch64", "amd64", "i386"], "startup": "once", "boot": "manual", "options": { "keep_days":7, "server_address":"", "destination_directory":"", "username":"", "password":"" }, "schema": { "keep_days":"int", "server_address":"str", "destination_directory":"str", "username":"str", "password":"str" }, "map": ["backup:rw"] }
config.json explained
Key | Type | Description |
---|---|---|
name | string | Name of the add-on |
version | string | Version of the add-on |
slug | String | Slug of the add-on; unique to repository add-on resides; url friendly |
description | string | Description of the add-on |
url | url | Homepage of the add-on |
arch | list | Supported architectures |
startup | string | ‘once’ for applications that don’t run as daemon |
boot | string | ‘manual’ manual boot |
options | dict | Default options value of the add-on |
schema | dict | Schema for options value of the add-on |
map | list | List of maps for additional folders |
Full configuration options and further details can be found here
The Dockerfile
is shown below. Home Assistant will build the container using an Alpine Linux base operating system with selection of the base image matching the machine’s architecture. The dockerfile installs the required packages and then runs the bash script run.sh
on container start.
Dockerfile
ARG BUILD_FROM FROM $BUILD_FROM ENV LANG C.UTF-8 RUN apk add --no-cache jq rsync sshpass COPY run.sh / RUN chmod a+x /run.sh CMD [ "/run.sh" ]
The required add-on functionality can be completed using bash scripting.
The bash script firstly extracts the user supplied configuration. The building of the add-on generates a file called options.json
which stores the entered user configuration entered via the web interface. Using jq
(sed for json) these variables can be extracted and assigned to variables for use in the rest of the script.
CONFIG_PATH=/data/options.json
KEEP_DAYS=$(jq --raw-output ".keep_days" $CONFIG_PATH)
RSYNC_ADDRESS=$(jq --raw-output ".server_address" $CONFIG_PATH)
RSYNC_DIR=$(jq --raw-output ".destination_directory" $CONFIG_PATH)
RSYNC_USER=$(jq --raw-output ".username" $CONFIG_PATH)
RSYNC_PASSWD=$(jq --raw-output ".password" $CONFIG_PATH)
Then the script has two parts. First part is to delete files older than a specified time. This is achieved with this command:
find \ # search for files in a directory hierarchy
/backup \ # directory to search
-mtime +$KEEP_DAYS \ # file's data was last modified n*24 hours ago; n supplied by KEEP_DAY variable
-type f \ # file is a regulare file type
--delete # delete files that match above conditions
Then the second part is to transfer the files to an rsync server. The script needed to allow for transfer to both authenticated and un-authenticated servers. Whether to use authentication is determined by testing if no username was supplied I.e RSYNC_PASSWD string is empty:
[ -z "$RSYNC_USER"] = True #$RSYNC_USER is an empty string
Un-authenticated servers are able to receive files by the following rsync command:
rsync \ # a fast, versatile, remote (and local) file-copying tool
-a \ # implies recursion and want to preserve almost everything, e.g. symbolic links, devices, attributes, permissions, ownerships
-v \ # increases the amount of information output
--delete \ # delete extraneous files from dest dirs
/backup/ \ # source directory
rsync://$RSYNC_ADDRESS/$RSYNC_DIR # remote rsync server address
Authenticated servers require the additional:
ssh-pass \ # noninteractive ssh password provider
-p $RSYNC_PASSWD \ # password is given on the command line; supplied by RSYNC_PASSWD variable
rsync... # command passwd is supplied to
The completed bash script is below:
run.sh
#!/bin/bash CONFIG_PATH=/data/options.json KEEP_DAYS=$(jq --raw-output ".keep_days" $CONFIG_PATH) RSYNC_ADDRESS=$(jq --raw-output ".server_address" $CONFIG_PATH) RSYNC_DIR=$(jq --raw-output ".destination_directory" $CONFIG_PATH) RSYNC_USER=$(jq --raw-output ".username" $CONFIG_PATH) RSYNC_PASSWD=$(jq --raw-output ".password" $CONFIG_PATH) echo "[Info] Starting remove and rsync" echo "[Info] Removing backups older than $KEEP_DAYS days" find /backup -mtime +$KEEP_DAYS -type f -delete echo "[Info] Running rsync push to $RSYNC_ADDRESS into $RSYNC_DIR" if [ -z "$RSYNC_USER" ] then echo "[Info] Pushing to rsync server without user" rsync -av --delete /backup/ rsync://$RSYNC_ADDRESS/$RSYNC_DIR else echo "[Info] Pushing to rsync server with user: $RSYNC_USER" sshpass -p $RSYNC_PASSWD rsync -av --delete /backup/ rsync://$RSYNC_USER@$RSYNC_ADDRESS/$RSYNC_DIR fi echo "[Info] Finished"
The guide at https://www.home-assistant.io/hassio/installing_third_party_addons/ explains the process of adding a custom repository. The custom repository URL is:
https://gitlab.com/jselby/hassio-addons
Follow the README on how to configure the add-on once the repository is added.
May 2020