Raspberry Pis remind me of the early days of the ZX Spectrum. There’s that same excitement at learning your first bit of code and realising that a whole world just opened up for you, only this generation isn’t going to re-create Manic Miner. They’re learning to make computers interact with the world around them. I wanted to join in. But what to code? Soon after the Pi was first released I copied a game written in Python from a magazine. (Boy did that take me back…) It gave me a taster of some of the syntax but didn’t offer much scope for hacking. And games felt a long way short of the possibilities that the Pi was offering. The next thing I knew, everyone was building robots without any obvious intermediate step! I have small children! I didn’t have time to build a robot! The peripherals weren’t providing any great ideas, either.
Inspiration finally arrived in the last edition of MagPi (#42 Feb 2016). They had some code to let you turn one of those 8×8 LED displays – that I’d never previously seen the point of – into a binary clock. So I did. Then I created one in Excel using VBA. No-one was terribly impressed. They couldn’t read binary. They also made clear they were actively opposed to learning.
There was only one thing for it. I was going to have to build an actual clock.
You will need:
- Raspberry Pi
- 40 GPIO pins.
- internet connection.
- (current kernel for Rasbian is Jessie 4.1)
- Pimoroni Unicorn HAT 64 LED display.
- ‘A good 2A power source’. The official Pi product is suitable.
One of my favourite things about this project has been working out how to use the 64 pixels most effectively. The binary clock included the date as well as the time, but even then had masses of wasted space. I wanted no dead-space, and ideally something a little more visually arresting, but with only 64 pixels to play with I needed to be creative.
To force denominators of 60 I started by dividing the LEDs with a cross, 2 pixels wide. That reduced the circumference of the display to 20 pixels. My second-hand would just need to complete three circuits for every minute. The cross also reduced the ring inside to 12 pixels, each of which would represent 5 minutes. Ring three bisected the cross in order to provide 12 pixels for the hours. By starting counting in the top-right quadrant* it meant that I’d be presenting the time in the same format as it would appear on a standard clock-face. I also wanted to ensure that the cross was not dead-space, so I decided to make it a sort of AM/PM indicator. It would start off a dark-blue at midnight, which would change imperceptibly (minute by minute) over the course of the day to a light-green at noon, and then back again.
I kept things simple for my first pass, with each pixel individually defined. The seconds gradually filled their circuit, changing colour with each pass. There were five different colours of minute pixel, indicating which of the five minutes it currently was. The cross wasn’t changing colour correctly but that aside I’d done it! My first Python program! Here it is! analog_clock
It’s far from elegant but starting like this has several advantages. It means I don’t have to grapple with too much new syntax at once. I’m also used to a much more linear style of coding, so as I get to grips with this more modular approach it helps to know I’ve got everything in the right section and am working from a functioning base before I start building the complexity. Quite aside from all that, psychologically it always helps to be able to see progress as well, and it means you get a feel for which ideas worked better in your head than reality.
The next night I started working to remove the repetition from the code, one function-definition at a time. The main challenges here were the layout of each data-type (small-squares-with-gaps didn’t lend themselves to simple loops) and the order of logic functions. I replaced the seconds with a single pixel that moved around the perimeter, and also decided that the one-colour-per-minute idea didn’t work terribly well, ditching them for a single colour for minutes 1 thru 4 on each pixel.
By the time I finished I’d reduced the file size from over 9kB to under 3.5kB.
There was just one problem left to resolve: the central cross still wasn’t changing colour as it was supposed to. The theory was pretty simple: I knew the Red/Green/Blue values that I wanted to see at mid-day. I’d adjust them each minute, proportionate to the change required to reach the RGB value I wanted to see at mid-night. The colour was changing, but not gradually. The cross was green in the AM and blue in PM. PRINTing out my ratio calculations to the terminal confirmed that my calculation wasn’t returning a ratio, but either 1 or 0. It was rounding up. I’ve (hopefully) made it sound pretty clear here, and in truth it was. If I hadn’t got bogged-down in checking my syntax and calculations then I’d probably have solved it long before 3am. A quick internet search introduced me to the FLOAT function, and two minutes later it was working.
Here’s the finished code! analog_clock_2-3 It just needs to be copied to Notepad, and saved with a .py suffix to your pi directory and it’s good to go!
Here’s what 10:47pm and 2:37pm look like!
(The LED brightness makes it difficult to manage a photograph does justice to how the thing looks in real life.)
An additional bonus: my six-year-old daughter and I today wrote her first bit of code – playing with the positioning and colouring of an LED on the display – on the back of having played with the colours in the clock code!
I sometimes struggle to find information online that applies to someone of my experience level and free-time so who knows, this may be of interest to someone. On the off chance anyone stumbles across this blog then feel free to use and play around with the code as you see fit. Let me know how you get on!
NB: I’m entirely self-taught. My code would doubtless cause a trained Python dev to splatter comment sections with terse self-importance at my abuse of correct process and form.
That said, I welcome good-humoured, constructive feedback and suggestions as for improvements.
* The inner/hour square on the diagram is incorrect – it should show the 1 where the 12 is, and the rest of the numbers shifted accordingly.
8-Feb-2016 : Corrected spelling of kernel