As my young family grows up, we have our little routines - one of which is the weekly Movie Night. On a rotating basis, each family-member gets to choose the movie that we'll watch, as a family, on a Saturday night. Looking at other screens is not allowed during this time - it's a Compulsory Family Fun Night if you like. The thing is, maybe I'm getting too old, but it frequently seems very difficult to remember whose turn it is. Maybe we skipped a week due to some other activity, or nobody can remember exactly because it was a group decision. Anyway, something that computers are especially good at is remembering things, so I decided to extend my existing OpenHAB home (device) automation to include home process automation too!
Unlike the similarly-named Amazon Alexa "skill" which appears to a) be totally random and b) not actually work very well, I wanted something that would intelligently rotate the "turn" on a given schedule (weekly being my primary requirement). I also wanted to keep the essentials running locally, on the Raspberry Pi that runs my OpenHAB setup. I'm sure you could move this entirely into the cloud should you wish, but doing it this way has allowed me to start with the basics and scale up.
First step; create a simple text file with one participant name per line: ${OPENHAB_USERDATA}/movienight.txt (i.e. /var/lib/openhab2/movienight.txt on my system):
Charlotte Mummy Daddy SophieMake sure that the openhab user can read and write it.
Now we use the exec binding to create a Thing that reads the first line of this file via the head command-line tool, once every 6 hours (21600 seconds). Unfortunately as you'll see in all the snippets below, there seems to be no way to access environment variables when defining these file locations; so while I'd love to write ${OPENHAB_USERDATA}/movienight.txt, I have to use the hard-coded path: /var/lib/openhab2/movienight.txt.
$OPENHAB_CONF/things/householdrota.things:
Thing exec:command:movienight "Movie Night" @ "Living Room" [command="head -1 /var/lib/openhab2/movienight.txt", interval=21600, timeout=5, autorun=true ]
Here are the items that fetch, display and adjust the current movie night, respectively. It's useful to be able to adjust the rotation, for example if we skipped a week, so need to back out the automatically-changed value.
$OPENHAB_CONF/items/householdrota.items:Switch FetchMovieNight {channel="exec:command:movienight:run"} String MovieNight "Whose turn is it?" {channel="exec:command:movienight:output"} Switch AdjustMovieNight
We expose the items in the sitemap:
$OPENHAB_CONF/sitemaps/default.sitemap:... Frame label="Household rotas" { Text item=MovieNight label="Whose Movie Night is it?" Switch item=AdjustMovieNight label="Adjust Movie Night" mappings=[ON="Rotate", OFF="Unrotate"] } ...Which results in the following in Basic UI:
Now for the weekly-rotation part. First, a simple Bash script to rotate the lines of a text file such as the one above. That is, after running ./rotate.sh movienight.txt, the topmost line becomes the bottom-most:
Mummy Daddy Sophie Charlotte/home/pi/rotate.sh:
#!/bin/bash TMPFILE=$(mktemp) if [[ $# -eq 2 ]] then # Assume a -r flag provided: Reverse mode TAIL=`tail -n 1 $2` echo ${TAIL} > $TMPFILE head -n -1 $2 >> $TMPFILE mv $TMPFILE $2 else HEAD=`head -1 $1` tail -n +2 $1 > $TMPFILE echo ${HEAD} >> $TMPFILE mv $TMPFILE $1 fi
And now we can automate it using a time-based rule in OpenHAB - each Saturday night at 9pm, as well as supporting rotation "by hand":
$OPENHAB_CONF/rules/householdrota.rules:
rule "Rotate Movie Night - weekly" when Time cron "0 0 21 ? * SAT *" then logInfo("cron", "Rotating movie night...") executeCommandLine( "/home/pi/rotate.sh /var/lib/openhab2/movienight.txt" ) FetchMovieNight.sendCommand(ON); end rule "Adjust Movie Night" when Item AdjustMovieNight received command then val reverseFlag = if (receivedCommand == ON) "" else "-r" val results = executeCommandLine( "/home/pi/rotate.sh " + reverseFlag + " /var/lib/openhab2/movienight.txt", 5000) # If anything went wrong it will be displayed in the log: logInfo("AdjustMovieNight", "Results: " + results) FetchMovieNight.sendCommand(ON); end
Now this is fine, but believe me when I tell you that having a text field available in a web page somewhere is simply not enough to achieve a winning SAF (Spousal Acceptance Factor). So onwards we must plunge into being able to ask the Google Home whose turn it is ...