
Saturday, 15 June 2024
Home-Cooked and Delicious

Sunday, 30 May 2021
Using the Velleman K8055 USB Experiment board with OpenHAB 3.x
The venerable Velleman K8055 USB Experimenter's Board is a neat way to interface a modern computer with a selection of analog and digital I/O ports. Unfortunately, support for using it within the OpenHAB home-automation framework (where it seems like a natural fit for tinkering) has fallen by the wayside - it had a proper binding in OpenHAB v1, and kinda-sorta still worked in OpenHAB v2, but it's a non-starter in 2021 with OpenHAB v3.x.
If you're running your OpenHAB (and a connected K8055) off a Raspberry Pi however, you're in luck. Simply head over to Github where some outstanding humans have done all the hard work to get your K8055 working again. It's all nicely-documented, so go ahead and give it a try. Come back here when you've got the k8055 command-line program running and making the LEDs go on and off; I'll wait.
Right. Let's get it cooking with OpenHAB, but without going through the hoops of building a new binding. Instead, we'll harness the power of OpenHAB's exec binding, and use OpenHAB's built-in state management to get persistent control of the K8055's outputs. What do I mean by that? Well, the k8055 program is completely stateless; whenever you tell it to set the digital outputs to 147 (i.e. 8, 5, 2 and 1 HIGH), it does just that, ignoring how bits 7, 6, 4 and 3 were set before - they're going to be LOW. It doesn't OR them or mask them with the current state. In fact, it can't even tell you the current state, only what it should be AFTER executing your instructions...
On your Pi, head to ${OPENHAB_CONF}, and add:
items/velleman.items
Group:Number:SUM gVellemanOutputs "Velleman output sum" Number VellemanD1 (gVellemanOutputs) Number VellemanD2 (gVellemanOutputs) Number VellemanD3 (gVellemanOutputs) Number VellemanD4 (gVellemanOutputs) Number VellemanD5 (gVellemanOutputs) Number VellemanD6 (gVellemanOutputs) Number VellemanD7 (gVellemanOutputs) Number VellemanD8 (gVellemanOutputs) Number VellemanA1 Number VellemanA2 // Arguments to be placed for '%2$s' in command line String VellemanOutputArgs {channel="exec:command:setoutputs:input"}
things/velleman.things
Thing exec:command:setoutputs [command="/usr/local/bin/k8055 %2$s", interval=0, autorun=true]
misc/exec.whitelist
/usr/local/bin/k8055 %2$s(In OpenHAB 3, for security, you've got to allow-list all the commands that exec can run)
Now we can add a stanza to our sitemap, to get some UI controls:
sitemaps/default.sitemap
... Frame label="Velleman Outputs" { Switch item=VellemanD1 label="Digital 1" mappings=[0="OFF",1="ON"] Switch item=VellemanD2 label="Digital 2" mappings=[0="OFF",2="ON"] Switch item=VellemanD3 label="Digital 3" mappings=[0="OFF",4="ON"] Switch item=VellemanD4 label="Digital 4" mappings=[0="OFF",8="ON"] Switch item=VellemanD5 label="Digital 5" mappings=[0="OFF",16="ON"] Switch item=VellemanD6 label="Digital 6" mappings=[0="OFF",32="ON"] Switch item=VellemanD7 label="Digital 7" mappings=[0="OFF",64="ON"] Switch item=VellemanD8 label="Digital 8" mappings=[0="OFF",128="ON"] Slider item=VellemanA1 label="Analog 1" minValue=0 maxValue=255 Slider item=VellemanA2 label="Analog 2" minValue=0 maxValue=255 } ...
This gives us all the controls for all of the outputs the Velleman K8055 supports:
Now we're ready to write a rule that ties everything together and makes it work persistently:
rules/velleman.rules
rule "Velleman Hardware Sync" when Item gVellemanDigitals changed or Member of gVellemanAnalogs changed then val dState = if (gVellemanDigitals.state == NULL) "" else "-d:" + gVellemanDigitals.state val a1State = if (VellemanA1.state == NULL) "" else "-a1:" + VellemanA1.state val a2State = if (VellemanA2.state == NULL) "" else "-a2:" + VellemanA2.state val formattedCommand = dState + " " + a1State + " " + a2State // logInfo("velleman.rules", formattedCommand) // Diagnostics if needed VellemanOutputArgs.sendCommand(formattedCommand) end
So the neat "tricks" here I think are:
- Baking the bit-twiddling logic into each Switch - some might object to putting values like 32 or 128 directly into the sitemap. I figure, you're going to have repetitive code up here in the UI, may as well extract some value out of it if it makes the logic in the rules simpler ... and it really does
- Using the Group:Number:SUM derived group state to generate the final output byte - the other part of the solution that keeps the rule really clean - OpenHAB itself recalculates the sum of all the switch values that belong to the group gVellemanOutputs
- Using Member of gVellemanAnalogs to reduce repetition in the when clause on the analog outputs - it's only a little thing, but I like it
Saturday, 31 August 2019
Serviio 2.0 on Raspbian "Buster"
After a recent SD card corruption (a whole-house power outage while the Raspberry Pi Model 3B must have been writing to the SD card), I have been forced to rebuild the little guy. It's been a good opportunity to get the latest-and-greatest, even if it means sometimes the various instructional guides are slightly out-of-date. Here's what I did to get the Serviio Media Streamer, version 2.0, to work on Raspbian Buster [Lite](*):
Install dependencies
Coming from the "lite" install, we'll need a JDK, plus the various encode/decode tools Serviio uses to do the heavy lifting:
$ sudo su # apt-get update # apt-get install ffmpeg x264 dcraw # apt-get install --no-install-recommends openjdk-11-jdk
Download and unpack Serviio 2.0
This will result in serviio being located in /opt/serviio-2.0:# wget http://download.serviio.org/releases/serviio-2.0-linux.tar.gz # tar -xvzf serviio-2.0-linux.tar.gz -C /opt
Set up the Serviio service in systemd
Create a serviio user, and give them ownership of the install directory:# useradd -U -s /sbin/nologin serviio # chown -R serviio:serviio /opt/serviio-2.0Create the a file serviio.service with the following contents:
[Unit] Description=Serviio media Server After=syslog.target network.target [Service] User=serviio ExecStart=/opt/serviio-2.0/bin/serviio.sh ExecStop=/opt/serviio-2.0/bin/serviio.sh -stop [Install] WantedBy=multi-user.targetCopy it into position, enable the service, and reboot:
# cp serviio.service /etc/systemd/system # systemctl enable serviio.service # reboot
Verify, Configure, Enjoy
After reboot, check things are happy:$ sudo systemctl status serviio.service ● serviio.service - Serviio media Server Loaded: loaded (/etc/systemd/system/serviio.service; enabled;) Active: active (running) since Sat 2019-08-31 16:54:48 AEST; 7min ago ...It's also very handy to watch the logs while using Serviio:
$ tail -f /opt/serviio-2.0/logs/serviio.logThis is also a good time to set up the filesystem mount of the video media directory from my NAS, which the NAS user naspi has been given read-only access to:
$ sudo apt-get install cifs-utils $ sudo vim /etc/fstab (add line:) //mynas/video /mnt/NAS cifs username=naspi,password=naspi,autoNext, use a client app (I enjoy the Serviidroid app for Android devices) to locate and configure the instance, remembering that paths to media directories are always from the Pi's point of view, e.g. /mnt/NAS/movies if using the above example mount.
* This guide is very much based on the linuxconfig.org guide for Serviio 1.9, with updates as needed.
Thursday, 28 February 2019
Whose Turn Is it? An OpenHAB Hack (part 1)
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 ...
Friday, 4 May 2018
Raspberry Pi 3 Model B+
But that was before I knew about the Raspberry Pi 3, Model B+. This little rocket boots up its Raspbian (tweaked Debian) OS in a few seconds, has 1Gb of RAM and a quad-core 1.4GHz ARM processor that does a great job with the Java workloads I'm throwing at it. And look at the thing - it's about the size of a pack of cards:
With wired and wireless Ethernet, scads of USB 3.0 ports and interesting GPIO pin possibilities, this thing is ideal for my home automation projects. And priced so affordably that (should it become necessary) running a fleet of these little guys is quite plausible. If like me, you had thought the Raspberry Pi was a bit of a toy, take another look!