Skip to main content

Christmas radvent calendar

WARNING: We must be fast approaching the giggly, festive season. Or it's simply the effects of the "grape juice for grown-ups" kicking in. Whichever the reason, there is an uncustomary sprinkling of sentimentality and holiday cheer seasoning this post.

(ANOTHER) WARNING: The names Santa Claus / Father Christmas / Saint Nicholas / Abominable Snowman are all being used interchangeably throughout this post to describe the identical, elusive character that symbolises the spirit of Christmas.  We apologise if you are offended by this carelessness generalisation. We're not that sorry, really.

Let's reflect (seriously) for a moment.  If in the often chaotic run up to Christmas, finding time to dabble in our next project (or the spare change required to fund it) appear high up in our list of festive worries, we can consider ourselves extremely fortunate.  What a luxury it is to be encountering completely trivial dilemmas, such as whether we can refill our stockings with a few more Raspberry Pi's or ESP8266's, to help fill the occasional breaks in the Christmas schedule.  Like those rare lulls between feasts of gassy vegetables and films featuring Macaulay Culkin, or when the kids have been ushered up to bed, more likely, Bruce Willis.

Therefore, we need to spare a thought for those folks from all spectrum of society who have challenges less self-indulgent than our own.  For whom Christmas is nothing but a stark reminder of those who have, and have not.  And, similarly, let's not forget those who dedicate themselves to tirelessly help those in need.

So we've made a commitment this year.  We will donate a small some each day in December to charities that help the most vulnerable, instead of placing the usual monthly order of electronic componentry for our ongoing projects.  But to put some fun into this activity, we'll build an advent calendar that not only counts up the days to Christmas Day with starry LEDs, but makes each LED represent a (semi-)randomly selected charity that we will donate to each day.

In the words of those that live on one sunny coast of the US, wouldn't that just be soooo "rad"?  Hence the radvent calendar.  Get it?

Quickly moving on...

Of course, true to our usual form, we won't pass on any opportunities to infuse some silliness into the final product.  But you are likely to have known that already.

House Rules

Despite common misconceptions, the official countdown to Christmas starts on the 1st of December.  Not on the 1st of October, when certain streaming services start recommending playlists that include Wham and Mariah Carey to signal impending danger to our bank balance.  Not even the very nanosecond Halloween finishes, when supermarket aisles begin to be commandeered for peddling Christmas paraphernalia.  1st of December.  Remember it.

Of course, this simple "1st of December" rule also helps in the forgotten art of advent calendar making.  We don't need to factor in leap years. Millennium bugs. Nor do we need to create 146 flaps / windows / bin lids to open.  Let's all stick to the 25.

Merry Making!

As this entire idea revolves around charities, we need a reliable information source that provides us with a list of bona fide charities that we can donate to easily.  Furthermore, we would like to effortlessly pre-select those that focus on helping the homeless.  In other words, no, we will not be donating to the "Save the Abominable Snowmen of the Sahara" campaign, however well-intentioned the non-existent conservation programme.

JustGiving has an API that allows us to interact with its services in a limited capacity.  While it doesn't appear to allow us to make donations programmatically, or search for - or list - charities using a filter, once we know the charity's ID, we can use the API to obtain useful information about the organisation, and keep this data up to date.  And better still, we can obtain the URL that allows us to donate easily through their platform.

There are other providers of this data (in the UK, for example, the Charity Commission appears to have an API also).  And if we would like to donate to the charity directly, we could do this outside of JustGiving.  But for the purposes of simplifying the donation process, and making use of their rather well documented API, we have concluded that this is likely to be the quickest route open to us to make this project a success in the time left until the countdown begins.

Like almost all things on the Winter Wilderness Web these days, the journey to use the JustGiving API starts with an all too familiar sign up page.

In case you were wondering, we do not write in a language that has an alphabet consisting of differently sized, black rectangles.  That would be bizarre.

Once registered, in order to access JustGiving services programmatically, we require an "Application ID", also known as an API key.  This key is unique to us, and must be embedded in our REST API request header to identify ourselves.

Never share your API keys with others, and avoid storing them in your code.  Code tends to get shared around with every Santa and his reindeer - for example using GitHub - rather like a plate of stale mince pies.  It's always preferable to store your keys as environment variables in the operating system the code is running on, or in a separate file stored securely on the filesystem, which are then imported when the program starts up.  Word!

Once we signed up, there appeared to already be a default Application ID available for us to use.  We're not sure what any of the other details here mean - but we like the green box which tells us that the "status" is Live.  We'll interpret this loosely as approval by JustGiving for us to proceed as planned.

As alluded to earlier, we (not so) thoroughly searched through JustGiving API documentation, and could not find an endpoint that allowed us to list all the charities available, either in entirety, or using a search criteria (presumably because the returned result may be huge).  However, if we have a specific charity ID in hand, we appear to be able to access information about it using this endpoint:{charityId}

This, clearly, means we need to hand craft a list of candidate charities that we will be randomly selecting from.  This also gives us an opportunity to refine the list to charities that we would really like to focus on during Christmas.  Sorry the Abominable Snowmen of a North African desert - you won't be rehoused in Lapland just yet.

So how do we get hold of these charity IDs?  We had to invest half an hour doing it, but navigating to each charity's landing page on JustGiving and hovering over links appear to do the trick.  Besides, this was actually a really great way to read about these organisations and what they offer the community.  In many of the cases, we learnt that they were in geographic locations uncomfortably close by.

For example, here is the ID for the homeless charity Shelter.

In case you missed the big, red, bold number - that says:


Testing the /charity API endpoint using this charity ID indeed reveals that we're on course for a minor victory.  Here we are, using curl on a Windows machine, pulling down lots of useful information about Shelter.  Notice how we buried our API key in the header of the request.  Or you might not, because we blanked it out.

In fact, there's just too much information here.  We'll only use couple of these attributes to maintain our sanity - but more on that later.

That was an enormous amount of unforgiving text crammed into a small unsuspecting Windows command terminal.  Quite frankly, we've now got a headache (and it's not the "grape juice", honest).  It's time to make it five times worse by visiting a local IKEA store peak-time, on a weekend, when the entire population decides to pay the Scandinavian retail establishment a visit (mainly for the meatballs in the cafe).

All the things that we do in the name of making...

So the objective here (in addition to making it out of the store alive with a belly full of meatballs) is to find something that could happily house a lot of LEDs, and could be made to resemble a calendar.  Being able to drill holes through the material and cut out sections would also be a bonus.

This little wooden container lid seemed to fit the bill perfectly.  It's got a strangely non-IKEA-esque and highly pronounceable name: "365+".  And it's only £2.00.  Right.  Time to make a quick escape before we inadvertently end up with enough furniture to start a professional nursery.

As we didn't want lots of wires (and a Pi) sticking out of the back of the calendar, we purchased the container as well.  The 2 litre version turned out to be perfect to house absolutely everything we needed for the project (except the power lead, which can be dangled out of a hole at the back).  It's also possible to rest the container horizontally as well - which means it moonlights as a stand.

There ought to be a medical term used to describe people with a compulsive desire to vandalise IKEA purchases the moment they arrive back home (free advice: don't do it while still in the store - that makes you an actual criminal... and you won't ever be allowed back into the only premier Swedish furniture retailer).  We obliterated ours using an arsenal consisting of an electric jigsaw, craft knife and some sandpaper.  The gaping rectangular hole should now allow us to slot in a 3D-printed contraption that houses an OLED screen and push switch.  Because - clearly - that's the way we roll these days.

But hang on a second.  This wooden plank doesn't look that festive yet... almost like a cheap container lid that someone barbarically tortured with a power tool.  Where's all the Winter cheer and merriment we promised you?

It's time to bring in the reinforcements... helpers that are yet to be tarnished by grown-up cynicism.  Let's convince the little one(s) to participate in a little impromptu "arts and craft" hour late on a Sunday night (when they really ought to be doing their homework instead... or sleeping).

Here's the obligatory little Santa (...or is it Father Christmas?) that our eldest daughter came up with.  She *may have* been inspired by a picture discovered on Google.  But for purposes of copyright... this is clearly an artistic interpretation of said picture found on Google.

Bit of late-night, parental geekery ensued.  We scanned the drawing, transformed it into a SVG file, then a MP3 file, a MP4 file, then a MI5 file, and only after some slapdash conversion work involving 768 other different file formats, it was finally imported into SketchUp.  There, we pushed and pulled it into a little compartment that can be 3D-printed and slotted into the aforementioned "hi-tech, on-demand latching enabler".  More commonly known as h-o-l-e™.

As with all our 3D prints to date, we exported our creation as a STL file, and printed them on our FlashForge Finder 3D printer using FlashPrint.  A little product placement never hurt anyone.  Unless the product is a cannonball, and it's placed on your head.

Incidentally, the square gap will be used by the 128×128 OLED screen, the circular hole - sorry, H.O.L.E (you don't want the advanced version of this) - for the rather prominent push switch.

After we sanded and primed the prints, our little helper added some much needed colour using acrylic paints.  Then, the creations were coated in absurdly glossy varnish.  Is it Christmas enough, now?  Huh?  Is it?

After a stint of superglue-ing, and Polyfilla-ing to close the gap left carelessly around the edges, this "Santa" centrepiece was permanently affixed to this particular IKEA memorabilia.  There is simply no going back now.  If we were still contemplating using this as a lid for storing a small surplus of Brussels sprouts cooked on Christmas Day - tough! - we're just going to have to leave them on the counter to stink up the whole kitchen.

We can stand down our little helpers now.  They can go to bed, or watch My Little Pony, or whatever it is that they do these days.

With serenity restored, and kids asleep, it's time to start bashing the keyboard like a possessed seal.  And it's probably about time to think about what to display on our titchy OLED screen.  We've got a few ideas, and it will revolve around cycling through three "screens":

1. Ghost of Christmas Past

On the first screen, we will show the following information, useful to rigorously reinforce the Christmas sprit in the household:

  • Today's date - Why not?  This stuff is always quite useful, Christmas or not.
  • Number of days left to Christmas - An essential data point, to get the kids extremely excited every morning.  For added hilarity, make it show 1, only for it to revert back to 100 the next day.
  • Temperature in Lapland - Erm... because it's useful to know this, clearly.  For the welfare of Father Christmas and his zero hour contractor workforce, and all that.  Moreover, wannabe data scientists amongst the children might further look at the correlation between temperature, and the amount of presents distributed.

The first two bits of information can easily be established in Python using datetime.

But what about current temperature in Lapland?

We learnt two VERY important facts about the home of Father Christmas:- a) Lapland actually exists, and b) its capital is called Rovaniemi.  We won't be getting into the technicalities of whether a temperature reading from Rovaniemi strictly constitutes a reading from Lapland, or whether Lapland is the home of Father Christmas, or whether - in fact - this is just an excuse to populate a spare line in the OLED screen.  Regardless, we intend to obtain temperature data from our new, favourite city (that we didn't know existed).  And yes, there's an API for that.

OpenWeatherMap provides a free API that allows us to obtain global weather data. And it's extremely easy to use.  There are many other providers of weather data... but we're really not that bothered about the accuracy of the novelty temperature reading, and our requirement here is extremely limited.

Not unlike the JustGiving API, we'll need to sign up to the OpenWeatherMap service. 

And once registered, there is an API key waiting for us to use.  Christmas has clearly come early.

This API key needs to be injected into the URL (not in the header like with JustGiving) when the REST API request is made.

The current weather API documentation tells us exactly how this needs to be done. Note the use of "metric" at the very end.  Here, in the land of this Queen and that Queen, only Celsius will do.{cityname}&APPID={apikey}&units=metric

As before, we'll first try it out using curl, just to see it in action.

Blimey, it really is quite cold in Lapland already...  Not sure if any of this information is actually relevant in a calendar.  But we promised ourselves the temperature in Lapland.  And we aim to deliver.

Once we're back in Python, we'll use the venerable Requests module to perform all of this API-ing, and access returned results as a dictionary data object.

So that's the data in our main screen sorted (while our low-light photography skills remain hilariously subpar).  What about the two others?

2. Ghost of Christmas Present

Well, on the second screen(s), we'll simply display the "randomly selected" charity of the day, and its impact statement (actually called impactStatementWhy in the REST result).  This gives us a short and useful description of the organisation.  Like: "Taking the abominable out of snowmen" for the one about their continued survival in the wild.  We eventually decided to split out the title and description out into two screens, as we often found sizeable text being returned from JustGiving for each.

We didn't invest too much time in making this display look nice.  In fact, depending on the length of the charity's name, the screen can look quite congested and hard to decipher.  This is more a consequence of the small size of the screen... although with some time invested, it would certainly be possible to work out more elegant ways to split text (by words) across lines, or even, screens.


3. Ghost of Christmas Yet-to-Come (really, why not the "Future"?)

So how do we make it easy for ourselves to donate?

In an ideal world, we could link this advent calendar up to a system that allows us to make the payment automatically.  Or maybe it could even accept payments (although the chances of this little hack meeting the threshold of being accredited to process payments is... well, zero)?  But that would take the fun out of the experience slightly, anyway.  Besides, there is something to be said about us taking the conscious step to make the donation based on the recommendation, rather than it happening automatically while we carry on with our busy lives.  Therefore, we'll provide a facility to direct ourselves to the JustGiving landing page of the charity from where we can make the donation.

...And how do we intend to make that material connection, between our dozy, slow-to-fire-up, decaffeinated morning brain, and the charity's JustGiving page?  One way these things are realised in the real world is by using a QR code.  We simply point our smartphone at the QR code, and it'll take us directly to the page.  Quick Response, as intended.

For example, during testing, here it is directing us to the Simon Community Northern Ireland page, using the QR reader on our smartphone.  The value used to generate the QR code is the "profilePageUrl" key returned by the charity API.

And that's why we've decided that our third screen will be showing the QR code of the charity's JustGiving profile page.  And for this, we use the conveniently named qrcode module.

sudo pip3 install qrcode[pil]

Once installed, we can simply do something like this in our Python code to generate the graphic.

import qrcode
qr = qrcode.QRCode(
qr.add_data(<profilePageUrl of charity>)
img = qr.make_image(fill_color="black", back_color="white")
img = img.resize((<OLED width>, <OLED height>))

After this, we end up with a pillow object, that we can display on the OLED screen using a driver.  Note that we have a final step to re-size the object to fit onto our 128×128 OLED screen.

Speaking of which, what do we do to show stuff on our screen?

Well, we described how to use a 128×32 SSD1306-based OLED screen when we went hiking in the Brecon Beacons.  We are using here, a slightly bigger 128×128 OLED screen, driven using the SSD1327 chip.  Guess what.  The wonderful luma.oled driver we can't stop using supports the SSR1327 as well... so the entire process is as easy as:

from luma.core.interface.serial import i2c
from luma.core.render import canvas
from luma.oled.device import ssd1327
serial = i2c(port=1, address=<I2C address of OLED screen>)
device = ssd1327(serial, 128, 128, mode="1")

Where img could be the QR code we generated previously.  We print text to the display, in the same way we did before for our GPS tracker.

This concludes our segment on the stuff that we're planning to display on screen (and a rather odd association with A Christmas Carol accompanying the equally ghostly night-time photography).  No, we really do not know how to succeed in low light photography.

Now, we need to address one gigantic elf in the room.  Where is the razzmatazz we promised the audience?  The Christmas sparkle.  Which bit of this creation actually resembles an advent calendar in the traditional sense?  How many reindeer does Santa have?  Will Brexit ever happen?  So many questions. So little time for answers.

After much contemplation, we reached the inevitable conclusion.  We needed to vandalise this IKEA purchase some more by drilling 25 holes in it.  And by inserting LEDs of different colours into those holes.

And before our brain said "perhaps this is not such a good idea", it was too late.  25 holes were made.  We had even 3D-printed some LED holders that could be glued onto the back of the wood.

With the view of controlling all these LEDs independently, we initially entertained the possibility of using a GPIO I/O expander with a transistor-based voltage amplifier on each output to switch the LEDs on and off individually, without blowing up the Pi.

But then again, why not just use PWM?  That way, we could also control their brightness.

This called for the use of a PWM controller (or two).  Specifically, the Adafruit 16-channel 12-bit PWM controller.  Two of these will allow us to cover the 25 channels required.  And they can be daisy-chained together, along with the OLED screen using I2C, reducing the total amount of cabling required.

These PCA9685-based PWM controllers from Adafruit have lots going for them when it comes to controlling LEDs.  They are quite small, and have 220Ω resistors on the output of all the channels (meaning we shouldn't be able to annihilate our LEDs - or the Pi - with a sizeable current draw).  In fact, using a 5V input, and considering the two different types of forward voltages our coloured LEDs will have, we should be drawing 7mA for our green/blue/white LEDs, and 14mA for our red/yellow LEDs.  All safely under the "general" 20mA figure.

The positive terminal of the LEDs simply get cabled to the PWM pin of its channel, with the negative terminal connected to the ground pin.  When everything is cabled up, we end up with a total rat's nest of cables that quite frankly should belong in a modern art museum as an exhibit.  Note that our second controller has had an I2C address selection pins shorted, to give it a different address to the first.

For now, we'll progress on the basis that the 5V line is powered by the 5V terminal on the Pi.  We suspect that all of this should be safely handled well under 1A.  If we observe indications that that the current draw is too much, we can always move the power supply to a dedicated unit.

Time for lights, camera and (hopefully) action!

We've used the Adafruit PCA9685 library before, for many of our (suspect) robot projects.  We'll experiment with 60Hz for the PWM frequency - approximately on the verge of what humans can detect - but might need to up this later if we detect some flicker.

import Adafruit_PCA9685
light_controller_1 = Adafruit_PCA9685.PCA9685(<I2C address of PWM controller>)
light_controller_1.set_pwm(<LED channel>, <tick value start>, <tick value stop>)

We will aim to always have the duty cycle start at 0, with the stop value (out of 4096) effectively controlling the brightness.

For example, very bright LED on channel 0 would be something like this.

light_controller_1.set_pwm(0, 0, 512)

Not so bright LED on channel 0 would be something like this.

light_controller_1.set_pwm(0, 0, 8)

We use threading to ensure code controlling LEDs over time isn't blocking so that they can all be controlled simultaneously, and won't impact the main routine calling APIs and displaying stuff on screen.

And that's about it.  Playing around with this indeed shows that the lights and their brightness can be controlled from Python.  With often satisfying results in the dark.

Just to re-cap, we now have 3 I2C devices daisy-chained together.  They all have different addresses which can be shown using the i2cdetect command.

I2C address...Used for?
0×3dSSD1327 OLED
0×40Adafruit PCA9685 1
0×41Adafruit PCA9685 2

These are all connected back to the Pi on the following pins:

Raspberry PiI2C...Used for?
GPIO 3 (BCM 2)I2C SDA I2C data line
GPIO 5 (BCM 3)I2C SCLI2C clock line
0V (Ground)0V0V

We've not talked much about the push switch ("push to close" / "normally open") which we've decided to connect one end to the 3.3V pin, other to GPIO pin 15 (BCM 22).  We've used a 330Ω resistor to protect our Pi by limiting current.  We then use the bog standard gpio.add_event_detect() method of the GPIO library to continually monitor the status of pin 15 and use a queue to announce the switch being pushed to all other parts of our program.

Here's the Duplo diagram of the entire circuitry:

Everything is connected.  They should be playing together nicely.  And with a whole bunch of Python code (shared at very end of this post), we should have something that does this:

  • If it hasn't already, the calendar picks a random charity (from list of those available) for the day and chooses a LED for it and lights it up.  This is stored locally in a CSV file (except the LED which is randomised everyday) so that it remembers the charities even after the calendar is powered off (by... erm... some curious little hands).  Previously selected charities are lit up by default at calendar start up.
  • The calendar will indefinitely scroll through the 4 screens - 2nd, 3rd and 4th screens will be of today's charity only (which we are reminded to donate to).
  • Each time the push button is pressed, it will toggle through the charities that have been selected to date - reminding us of all the charities that we've learnt about (and donated to).  We had an inordinate amount of fun creating a randomly named "starburst" effect which transitions between the charities' LEDs "dramatically".  Clearly, we need find a different hobby.
  • If the button isn't pressed for a set period, the calendar returns to cycling through the screens of today's charity only, but only after an equally dramatic "sparkle" effect (we must have been watching too much My Little Pony recently).

And that is it.  We've had to test this using a "Christmas Day" set in November (ignoring our very own advice from earlier on about Christmas starting in December), and this is reflected in the photos and videos that we've managed to capture of the calendar in operation.

Here it is, in all its glory (although real testing can't begin until we hit the 1st of December):

With more time and energy, this could be improved in an infinite number of ways, and given lots of other "special effects" to dazzle onlookers. Possibly even the OLED screen itself demands an upgrade to make it more legible.  But we think we've now got the moral of this particular story... and it didn't require Macaulay Culkin or Bruce Willis to educate us.

...That the build-up to Christmas should be about more than just the sum of the weird and wonderful components that we use for our making.  And - perhaps - that should even be the case all year round.  But let's take this opportunity at the end of the year to slow down, unwind, recharge our batteries (in some cases, quite literally).  And appreciate what we have, and spare a thought for those who don't.

LAST WARNING (OF THE YEAR, HOPEFULLY): Our next post is likely to arrive with an unusually large amount of nonsense and silliness (even by our standards), purely to make up for this uncharacteristically sentimental anomaly of a project.  Will next year see the return of Mr. Ted E-U (as demanded by 33% of our readership, mathematically proven using the following formula: 1/3×2, rounded down = 0 person)?  Or will a breakthrough finally be made on the scientifically impossible Rosie hexapod?  Or - more likely in our case - a hybrid teddy bear hexapod that can be featured on a Countryfile episode about extraordinary (and possibly slightly disturbing) wildlife found in the West Country.

Either way, it promises to be another exciting year here at Rosie.

Merry Christmas everyone, and a Happy New Year!

...Now, where was that Wikipedia entry on Abominable Snowmen?

Here is the list of donations made when the calendar was operational in 2018:

The Twitter thread from the 2018 adventure can be seen here:

The brilliantly festive "Beyond Wonderland" fonts used in the images and video can be found here.




LoRa-Wan Kenobi

In the regurgitated words of Michael Bublé: It's a new dawn .  It's a new day .  It's a new Star Wars film .  For me .  And I'm (George Lucas, and I'm) feeling good .  Unfortunately for Canadian Mike, the Grammy that year was won by the novelty disco classic with the famous refrain: We love IoT, even in Planet Tatooine * . *Not true. Clearly, the Star Wars producers didn't sincerely mean the last Jedi the previous time around.  Return of the Jedi, released during the decade that spearheaded cultural renaissance 2.0 with the mullet and hair-metal , was less economic with the truth.  Either way, we're going to take inspiration from the impressive longevity of the money-spinning space-opera and reboot our franchise with some Jedi mind tricks.  Except this particular flick doesn't require an ever-growing cast of unrecognisable characters, unless ASCII or UTF counts.  In place of an ensemble gathering of Hollywood stars and starlets, we will b

Battle of BLEtain

The trolling . The doxing . An army of perplexing emojis. And endless links to the same - supposedly funny - viral video of a cat confusing a reflection from a dangling key for a golden hamster, while taking part in the mice bucket challenge. Has social media really been this immense force for good? Has it actually contributed significantly to the continued enlightenment of the human (or feline) race? In order to answer these poignant existential questions about the role of prominent platforms such as Critter, StinkedIn and Binterest, employing exceptional scientific rigour equal to that demonstrated by Theranos , we're going to set up a ground-breaking experiment using the Bluetooth Low Energy feature of MicroPython v1.12, and two ESP32 development boards with inexplicable hatred for one another.  And let them hurl quintessentially British expressions (others call them abuse) at each other like two Wiltshire residents who have had their internet access curbed by the co

Hard grapht

You would all be forgiven for assuming that bar , pie and queue line are favourite pastimes of the British .  Yet, in fact – yes, we did learn this back in GCSE maths – they are also mechanisms through which meaningless, mundane data of suspect origin can be given a Gok Wan -grade makeover, with the prime objective of padding out biblical 187-page PowerPoint presentations and 871-page Word reports (*other Microsoft productivity tools are available).  In other words, documents that nobody has the intention of ever reading.  But it becomes apparent over the years; this is perhaps the one skill which serves you well for a lifetime in certain careers.  In sales.  Consultancy.  Politics.  Or any other profession in which the only known entry requirement is the ability to chat loudly over a whizzy graph of dubious quality and value, preferably while frantically waving your arms around. Nevertheless, we are acutely conscious of the fact that we have spent an inordinate amount