Oh yes, Christmas! It’s almost that season of the year again. And to shorten the time between the 1st of December and Christmas Eve’, I thought about a bit more interesting advent calendar than one, that only has chocolate in it. This electronic advent calendar offers a riddle that you can create for a loved one or a friend and give it to them so they can try to solve it before Christmas arrives. It offers a clue every day and it presents all unlocked clues on a website that runs on the device itself. The only two things it needs to work is a power supply and a WiFi network it can connect to. And the best thing is: It is really simple to build and it can be re-used every year and it can also be used for other occasions (for example Valentine’s Day)!
Before you begin …
… make sure that Python, a web-server of your choice and MySQL is installed. You can also install PHPMyAdmin if you want to have a simple GUI for setting up the database.
You’ll also need to know how to run programs on Linux and how to set-up and configure a database, I won’t explain these topics in this article, but you can always leave a comment, if you want to know more about these topics.
Basically the whole advent calendar runs on a mini computer like the Raspberry Pi. However you could use any other small Linux computer that has GPIO inputs and a USB port, but I’ll go with a Raspberry Pi A+
The Raspberry Pi itself will connect to a network via a small Edimax WiFi USB dongle. These things are really cheap and they work just fine.
Other than that you’ll need:
- A push button for user-input
- A cool looking case
- One LED, so the device can give the user a little bit of feedback
- Two Resistors
- Some wires
I’ll drive my LED directly with the GPIO pins however you could use a transistor if you want to, but the current is so small, that it doesn’t really matter in my experience. This means, that the voltage provided by the Raspberry Pi is 3.3V and for a usual red LED you should be fine with a 68 ohms resistor (or something close to that value). However you can use a calculator like this one to determine the right resistor for your setup.
The second resistor can be anything really, it’s only used im combination with the push button, so that the GPIO pin doesn’t get shorted out.
As you can see, the list of materials is really short, because most of the work will be done by the software.
WiFi setup in the command line
I don’t want to re-write the necessary steps here, because a lot of other people have done this before, so I’ll just link to a working tutorial here!
Depending on the WiFi dongle you are using, there might be a power-saving routine built into the driver. Make sure you take care of this, so the Raspberry Pi doesn’t lose connection after it wasn’t used for a long time. A general way you could prevent this from happening, is to set up a cron-job that will ping the gateway once every minute:
Change this file:
sudo nano /etc/crontab
and add this line:
*/1 * * * * ping -c 1 YOUR_ROUTERS_IP
This will send one ping to the router every minute. Save the file and exit nano.
I made this illustration to show you, how to connect the GPIO pins to the other components:
As you can see, this circuit is really simple, I don’t even know what to explain here. Connect GPIO 24 to the LED’s anode (longer leg) and then connect the cathode to ground via the resistor.
Do the same thing for the momentary switch, but this time connect GPIO pin 23. It should look something like this for now (obviously this is only a test, it won’t have the bread board in the final version:
In my demonstration above the LED is flashing, I used this test script to achieve this behaviour:
# import necessary libraries import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BCM) # Setup the necessary GPIO pins GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(24, GPIO.OUT) # Callback for the interrupt def btnPressed(channel): print "Button pressed" # Create an interrupt so the program immediately detects a key press GPIO.add_event_detect(23, GPIO.FALLING, callback=btnPressed, bouncetime=250) try: # do this as long as the program does not end while(True): GPIO.output(24, 1) time.sleep(1) GPIO.output(24, 0) time.sleep(1) except KeyboardInterrupt: print "Program ended by user" # Free gpio connections GPIO.cleanup()
The code should be pretty self-explanatory as well. It’s only a test script to verify that your wiring is correct. The LED should flash and whenever the button gets pressed the console should immediately show: “Button pressed”.
Now comes the real deal: Adding the components to the case. It’s actually really simple as well: You just need to drill holes for the button and the LED and you will also need to make a cutout for the micro-USB connector to supply power to the Raspberry Pi:
Afterwards put in the LED and the switch. I used a combined solution in the final version of this build, so it looks like this:
Now secure the Raspberry Pi in the case. My case already came with screw holes, so I used these and added a tiny blob of hot glue under the USB-Port, so the Pi can’t move at all.
The last step is to finish the wiring. Just do the same thing we did earlier on the bread board, but this time in the case. Mine looks like this:
Just make sure that all cables are long enough but not too long and that there is enough space for them in your case. Then close the case and admire your work:
If you worry about the computer heating up too much, you can always use a case with venting holes in it, but I’ve checked my Raspberry Pi and it ran the whole night long and it never reached anything near a critical temperature. And now to the harder part of this build, the software.
The software consists of three different parts and is written in Python and PHP:
This small program runs in the background all the time and it’s purpose is to detect when the button was pressed and to flash the LED when a new clue is available. When the button was pressed and a new clue is available, the daemon starts the second program, which updates the database that holds the clues. This program will also create a small save-file, which stores the day on which the last clue was unlocked. This way it will immediately know whether or not there is a new clue available, even after being disconnected from power.
The unlocking script
This is the program, that unlocks a specific clue in the database. It’s only input is a parameter that the daemon sets to indicate, which clue should be unlocked.
The website & database
This page displays the clues. However it only displays the clues, that were unlocked earlier. If the user misses a day, he misses the clue.
Download the complete package with all code files here! Or use the following command to download the package on your Raspberry Pi:
On your Raspberry Pi: Move all the files in the website-folder to /var/www (or the htdocs-root folder of the web server you installed). Leave the other three files in one folder together and that’s it.
Afterwards you only need to load in the dump to your MySQL Database.
Now the last step is to get this thing up and running. Make sure everything is running and set-up correctly. Change to the program directory, which contains the software and start the daemon with the following command:
Don’t run the program as a daemon for now. This way you can end it, when everything works the way it’s supposed to be. You can end the program with Ctrl + C.
Now we’ll add a cron-job to the Raspberry Pi. This way the program will always start when the system boots up:
sudo nano /etc/crontab
Add the following line:
@reboot python /path_to_scripts/daemon.py &
Don’t forget that ampersand! This will make the program run as a daemon in the background.
Now you should be able to navigate to the website on the Raspberry Pi by writing it’s IP-Address into the address-bar of your browser on any device in the same network and you should see something like this:
I hope you liked this idea and maybe you consider building it for somebody who is into riddles!
[Fig. 1] raspberrypi.org
4 thoughts on “DIY electronic riddle advent calendar”
That push button is cool, where did you buy it?
LikeLiked by 1 person
I bought it here: https://www.conrad.at/de/drucktaster-250-vac-05-a-1-x-ausein-sci-r13-529alrt-tastend-1-st-701227.html
LikeLiked by 1 person
Thanks! It looks very nice
LikeLiked by 1 person