Automating Repetitive Tasks

Lather, Rinse, Repeat

We all have plenty of things we do every day, every week, or on some other similar type of schedule. We all have monthly bills that need to be paid, for example. Do you turn outside lights on and off at certain times of day? How often do you back up the data on your computer or phone? How many of these things have you taken steps to either fully or partially automate so that you don’t have to do them directly yourself every time?

I try to automate things as much as reasonably possible in my day-to-day life. And when I say as much as reasonably possible, I’m referring to a combination of how much effort it takes compared to how much time it will save as well as just how much I actually want fully automated – not everything should be done exactly the same all of the time! Let’s take a look at some of the things I’ve automated and how I did it.

Finances

I have some items fully automated, some partially automated, and some still entirely manual. For the fully automated, My mortgage is paid completely automatically. First, I set up an autodraft process with the holding back to automatically debit my checking account on the first of the month for the full amount. Second, I set up an automatic transfer on the first to move the correct amount of money from my savings account to my checking account so there are no overdraft issues. Done. I only need to revisit the transfer once each year when my escrow account amounts are updated and there is a shift in the total mortgage payment amount. I have a similar transfer set for the 15th of the month that will transfer the correct amount to cover the payment for my truck.

For the partially automated, it’s really a combination of fully automated and fully manual for my credit cards. The cards themselves are all set to automatically pay the balance in full each month on the payment due date. I don’t need to do anything at all for any of my cards directly. However, I do need to add up the amounts and coordinate a transfer to make sure the money is in the checking account in time. Fortunately for me, my few cards all have a due date that is close to each other so I can do this all with a single transfer each month.

I am able to pay our electric bill each month via credit card without any additional fees, but there is no way to set this up as an automatic process. As a result, this utility bill remains a manually paid process item but I get the CC cash back rewards from paying the bill that way. So, I’m happy to do it. 🙂

Media Systems

I am currently running both Plex and Emby. I fully automated the update process for Plex quite some time ago and am currently creating a similar process for Emby. For Plex, the general process includes checking the latest version available versus the version installed, downloading the latest version available if it’s newer than what’s installed, then installing the latest version when the Plex server isn’t “busy” with playback or recording.

Checking for updates: I was able to find a script online that was built for Ubuntu and Debian systems but nothing for openSUSE. So, I modified the Ubuntu-specific script to work for my system. Here’s the modified script…

#!/bin/bash
# Uncomment the next line if the script will be run as a cron job.
PATH=/usr/local/sbin:/usr/sbin:/sbin:$PATH

plex_token=PUTYOURSHERE
beta_channel=false
dry_run=true
force_installation=false
overwrite_file=false
display_help=false

while getopts 'bhfno-:' opt; do
    case "$opt" in
        b) beta_channel=true ;;
        h) display_help=true ;;
        f) force_installation=true ;;
        n) dry_run=true ;;
        o) overwrite_file=true ;;
        -) case "${OPTARG}" in
             beta) beta_channel=true ;;
             dry-run) dry_run=true ;;
             force) force_installation=true ;;
             help) display_help=true ;;
             overwrite) overwrite_file=true ;;
             *) if [ "$OPTERR" = 1 ] && [ "${opt:0:1}" != ":" ]; then
                        echo "Unknown option --${OPTARG}" >&2
                        exit 1
                fi ;;
           esac ;;
        *) echo "Error: the only valid options are --beta, -b, --dry-run, -n, --force, -f, --help, -h, --overwrite, -o" >&2
           exit 1
    esac
done

if [[ $display_help == true ]]; then
  echo "usage: $0 -h, --help, -b, --beta, -f, --force, -n, --dry-run, -o, --overwrite"
  exit 2
fi

echo "Beta Channel = $beta_channel"
echo "Dry Run = $dry_run"
echo "Force Download = $force_installation"
echo "Overwrite File = $overwrite_file"

# Ubuntu
#detected_arch=`dpkg --print-architecture`
# SUSE
detected_arch=`uname -m`

case $detected_arch in
    "arm64"|"amd64"|"i386"|"armhf"|"x86_64") echo "Architecture = $detected_arch" ;; # Plex's download page has 4 architectures available
    *) echo -e "\e[31mYour architecture is not supported by Plex! \e[0m" && exit 1 ;; # need to stop the script early if the architecture detection line fails (i.e. a user running PowerPC or any OS other than Debian/Ubuntu)
esac

if [[ $EUID -ne 0 ]]; then
    echo "$0 is not running as root. Try using sudo."
    exit 2
fi

if [ "$beta_channel" == true ]; then
    rawjson=`curl -s "https://plex.tv/api/downloads/5.json?channel=plexpass" -H "X-Plex-Token: $plex_token"`
else
    rawjson=`curl -s "https://plex.tv/api/downloads/5.json"`
fi

#url=`echo $rawjson | jq -r -c '.computer.Linux.releases | .[] | select(.url | contains("'$detected_arch'")) | select(.url | contains("debian")) | .url'`
url=`echo $rawjson | jq -r -c '.computer.Linux.releases | .[] | select(.url | contains("'$detected_arch'")) | select(.url | contains("redhat")) | .url'`
echo "URL =  $url"
latestversion=`echo $rawjson | jq -r -c '.computer.Linux.version'`
baselatestversion=`echo $rawjson | jq -r -c '.computer.Linux.version' | cut -d'-' -f1`
#installedversion=`dpkg -s plexmediaserver | grep -i '^Version' | cut -d' ' -f2`
#baseinstalledversion=`dpkg -s plexmediaserver | grep -i '^Version' | cut -d' ' -f2 | cut -d'-' -f1`
installedrelease=`rpm -qi plexmediaserver | grep -i '^Release' | cut -d':' -f2 | cut -d ' ' -f2`
baseinstalledversion=`rpm -qi plexmediaserver | grep -i '^Version' | cut -d':' -f2 | cut -d' ' -f2`
installedversion=$baseinstalledversion"-"$installedrelease
echo "Latest version:    $latestversion"
echo "Installed version: $installedversion"
echo "------------------------------------------------------------"
result=$(awk -v n1="$baseinstalledversion" -v n2="$baselatestversion" 'BEGIN{ print (n1 > n2) }')
if [ "$installedversion" == "$latestversion" ]; then
  echo "Already on latest version."
  filename=${url##*/}
  filename='<PathToDownload>'$filename
  echo "Filename = $filename"
    #curl -sL -o $filename $url
elif [ "$result" == 1 ]; then
  echo "Newer version already installed."
else
  echo "Need to upgrade..."
  echo "Found latest version at $url"
  filename=${url##*/}
  filename='<PathToDownload>'$filename
  if [ -f "$filename" ] && [ "$overwrite_file" == false ]; then
    echo "File already exists, not going to download it again"
  else
    echo "Downloading $filename..."
    curl -sL -o $filename $url
    curl --header 'Access-Token: <PushBullet API Token>' --header 'Content-Type: application/json' --data-binary '{"body":"New Version Downloaded","title":"<Servername>","type":"note"}' --request POST https://api.pushbullet.com/v2/pushes
  fi
  if [ "$dry_run" == false ]; then
    echo "Installing it now..."
    dpkg -i $filename
    echo "$filename installed"
  fi
fi
echo "Done"
exit 0



Some things to note about the script… Areas inside of greater/less than symbols are where you will need to make changes to suit your system. I had to modify some of the system-level commands for openSUSE and I also added a PushBullet notification call so that I would be made aware of when a new version was downloaded and from which system as I have multiple. Commands and sections that only work on Ubuntu/Debian were commented out.

The next step is to check to see if the server is idle and install the updates if it is. That looks like this:

#!/bin/bash
#
# This script applies "updates" to the Plex install
#
#
# Base directory for media content:
SOURCEDIR=<PathToDownload from other script>
ENDDIR=<dir to move installed versions into for long-term retention>
CURRSTATUS=`curl -s -H "accept: application/json" http://<server>:32400/status/sessions?X-Plex-Token=myPlexToken | jq .MediaContainer.size`
echo $CURRSTATUS

VAR1="$1"

MINTIME="30"
if [ "$VAR1" == "force" ]; then
  MINTIME="0"
fi

echo "Checking $SOURCEDIR for an update . . ."

for f in $SOURCEDIR/plexmedia*.rpm
  do
      if [ $CURRSTATUS -eq 0 ]; then
              if curl -s "http://<server>:32400/activities?X-Plex-Token=<Plex Token>" | grep -qE 'type="media\.download"|type="media\.offline\.transcode"|type="grabber\.grab"' ; then
                      echo "Server busy"
                      exit 1
              fi
      if test "`find "$f" -type f -mmin +$MINTIME`"; then
        systemctl stop plexmediaserver.service
        rpm -Uvh "$f"
        systemctl start plexmediaserver.service
        systemctl daemon-reload
        mv "$f" "$ENDDIR"
        /opt/myutils/notify.sh "MOVIESRV2 Plex Updated"
        curl --header 'Access-Token: <PushBullet API Token>' --header 'Content-Type: application/json' --data-binary '{"body":"New Version Installed","title":"<Servername>","type":"note"}' --request POST https://api.pushbullet.com/v2/pushes
      else
        echo "If update file exists, may need to use the force parameter"
      fi
      fi
  done


The script contains commands that work on openSUSE and I send a PushBullet notification at the end so I know that the software was updated. The Plex token is not needed for the first status command query but it is needed for the second one. I use a 30 minute minimum age on the downloaded file to ensure that nothing is currently attempting to modify that file before trying to install it, and items in bold are where you need to set specific parameters. The script will accept a “force” command line parameter that will skip time-checking the downloaded file. As with the first script, items inside of greater/less than symbols will need modification to suit your system.

Home Automation

I have a HomeAssistant deployment that manages and maintains a lot of things for me around my home. I have some simple automations that turn on the outside lights at sunset and then off again at sunrise. I have some more integrated automations that do things like turn the overhead lights on in the garage when the overhead door opens and then turn them back off again about a minute after the door closes.

And then, I have some more complex automations that manage the heat on the second floor of my house in a way that helps to ensure I will never have to deal with a frozen heating pipe again. The general issue for me is that my two-story house has a separate heating zone for the second floor that sometimes is affected by heat from the first floor. During the evening, the downstairs is warmed to a more comfortable temperature for dinner and such. That increased warming makes its way up the stairwell and ‘tricks’ the upstairs thermostat into thinking it’s a few degrees warmer everywhere than it actually is. For sleeping, this is completely fine. But, lengthy delays on when the second floor zone calls for heat can make extended periods of time where a section of the heating pipes may be exposed to colder temperatures because they run through an overhang area. I wrote an automation that tracks the outside temperature and ensures that the upstairs zone calls for heat long enough to circulate warm water through the pipes without actually warming enough to “heat” any of the upstairs area. This water circulation ensures that any cooling or even preliminary freezing of water in the pipes is completely offset, and the colder it is outside, the more frequently this runs.

What Have You Automated?

There are certainly many other things that I’ve already automated or am in the process of automating, and the few examples here are really just scratching the surface of what I did even for the ones I mentioned. Something like the upstairs heating item took some time and effort to create and tune, but it was important to me to ensure that I never had to deal with a frozen pipe or any repair bills from frozen pipes again. What things have you decided to automate to make your life simpler?

Leave a Reply

Your email address will not be published. Required fields are marked *