The old X10 devices were getting really unreliable: seldom firing at all, getting far too hot, bringing a whole lot of not working to my life. So while it was kind of cool to have my lights controlled by an original 256 MB Raspberry Pi Model B from 2012, it was maybe working one schedule out of ten.
So it had to go: replaced by a Raspberry Pi Zero W and a whole lot of IKEA TRÅDFRI kit. I was deeply unimpressed with the IKEA Home smart app, though: you couldn’t use even basic schedules with more than one light cycle per day. So while I know there are lots of clever home automation systems, I wanted to replace my old cron scripts and set about writing some simple command tools. The result is ihsctrl: very limited, but good enough for me. It’s been working exactly as expected for the last week, so I’ll finally get to wade through 8 years of cobwebs and dismantle the old X10 setup. I already miss the 06:30 clonk of the X10 controller turning the front light on — that was my alarm clock (or alarm clonk) every morning.
I wanted to have a “Hey, be here now!” ping throughout the working day. Something loud enough to hear, but not irritating.
Doing this with cron was harder than you might expect. It seems that sound is typically part of the X11 display infrastructure, so you need to give the command permission to make a noise on this particular machine’s display. Here’s the crontab line I came up with:
# m h dom mon dow command
0 9-17 * * 1-5 export DISPLAY=:0 && /usr/bin/play -q /home/scruss/sounds/ting/ting.wav
That translates as: at 0 minutes past the hours of 09:00 to 17:00 on any weekday (day of week = 1-5, and we don’t care about day of month or which month it is), execute the command play (part of the sox package) with no text output (-q). cron needs environment variables like DISPLAY set, and prefers full command paths. It may trigger a second or so after the turn of the hour; this is good enough for me.
As for the alert, I wanted something distinctive — percussive, short, bright — but with a tiny bit of modulation to stop it sounding like a bland computer-generated sine wave. This is what I made; click on the image and the sound should play or download:
It’s essentially a 2093 Hz (C7) sine wave, mixed with itself frequency-modulated at 7 Hz. Why 7 Hz? Apart from sounding about right, 2093 is exactly divisible by 7, 13 & 23, so I used a factor for neatness.
There was some later messing about in Audacity (mostly fades and length edits; I forget exactly what). The two components were generated using sox:
sox -n ting-plain.wav synth 1 sine C7 fade l 0 1 1
sox -n ting-vibrato.wav synth 1 sin C7 synth 1 sine fmod 7 fade l 0 1 1
Yes, sox does have pretty horrible syntax, doesn’t it?
The frequency-modulated one seems to be pretty close to the final result. It would be less time spent trying to save time …
Yep, springtime’s coming, and today’s the first day I know it, despite the -5.8°C outside. I know spring is coming because my sunrise-adjusted lights came on before my alarm today. I’m controlling them with a Raspberry Pi, cron, and X10.
I’d described how to build and use heyu previously, so I won’t go into it further. I use sunwait to control the timing relative to local sunrise and sunset. Sunwait is a simple C program which builds quickly, and you can put the executable somewhere in your path.
(NB: newer versions of sunwait use a completely incompatible command line format. Everything here refers to the 2004 version I linked to above, which does exactly what I need in the way it’s described here.)
You need to know your latitude and longitude to use sunwait. To check its setting for the day, you can call it with the -p option:
$ sunwait -p 43.729N 79.292W
Using location: 43.729000N, 79.292000W
Date: 6 Feb 2013
Local time: 7:44
Day length: 10:13 hours
With civil twilight 11:10 hours
With nautical twilight 12:18 hours
With astronomical twilight 13:25 hours
Length of twilight: civil 0:28 hours
nautical 1:02 hours
astronomical 1:35 hours
Current specified time zone: EST (-5 from UTC)
Sun transits meridian 1231 EST
Sun rises 0726 EST, sets 1736 EST
Civil twilight starts 0656 EST, ends 1806 EST
Nautical twilight starts 0622 EST, ends 1840 EST
Astronomical twilight starts 0548 EST, ends 1913 EST
So for me, today’s sunrise is at 0726, and sunset is at 1736. All sunwait does is wait until a specific solar time is reached, and then exit. Whatever command you call after sunwait, therefore, is what gets run at the right time. So if I wanted X10 device H1 to come on an hour before sunrise, I’d run:
sunwait sun up -1:00:00 43.729N 79.292W; heyu on h1
Remembering to run this every day before sunrise would be a pain, so this is where cron helps. cron uses a slightly odd config file that is edited using the crontab -e command. Here’s the relevant bit of my crontab, showing the light control times:
# m h dom mon dow command
01 00 * * * /usr/local/bin/sunwait sun up -1:00:00 43.729N 79.292W; /usr/local/bin/heyu on h1
02 00 * * * /usr/local/bin/sunwait sun up +1:00:00 43.729N 79.292W; /usr/local/bin/heyu off h1
03 00 * * * /usr/local/bin/sunwait sun down -1:00:00 43.729N 79.292W; /usr/local/bin/heyu on h1
45 22 * * * /usr/local/bin/heyu off h1
(you can view your crontab with crontab -l)
The columns in crontab are:
day of month
day of week
So the four crontab lines mean:
Every day at 00:01, wait until an hour beforesunrise and turn light H1 on
Every day at 00:02, wait until an hour aftersunrise and turn light H1 off
Every day at 00:03, wait until an hour beforesunset and turn light H1 on
At 22:45, turn light H1 off.
So for quite a bit of the day, there are a couple of sunwait tasks just quietly waiting until sunrise or sunset to do their thing. cron, incidentally, is picky about executable paths; that’s why I specified full paths to both sunwait and heyu.
What I’d really like to do is have time on this machine update without a network connection, because it’s running from a particularly messy router set up in a spare bedroom. I should investigate a real-time clock, with GPS time updates from an I²C GPS, talking through a bluetooth console. In my copious free time, of course.