Video & GitHub Repo
- A beginner-friendly playlist with step-by-step instructions on this build can be found at: https://bit.ly/pi-cabinet
- Jump directly to the primary build video tutorial: https://youtu.be/e1_tQ9RsY2A
- The GitHub repo with python code used in this project can be found at: https://github.com/gallaugher/pi-cabinet
Introduction
It can be tough to remember to take medications or daily supplements. This tutorial illustrates a beginner-friendly, no-solder, tech-for-good project to create a pill box with an LED light that will light up to remind you that it’s time to take your meds. The project works as follows:
- When the Raspberry Pi is plugged in, an external LED light on the box begins to flash, indicating that the device is working.
- Opening and closing the box lid will turn off the flashing LED and schedule the light to turn on again at any time listed in the alarm_times list in the project’s python code. The tutorial will illustrate how you can set your own schedule times in the alarm_times list.
- When the light goes on, open the lid and take your meds. The light turns off when the lid is opened. It’s the user’s responsibility to remember to take their meds and put them back in the box. The light will go on again at the next time scheduled in the alarm_times list.
- If the power goes out, the Raspberry Pi should restart and the LED will begin flashing, indicating that the Pi has lost power since the last time that the lid was opened. But opening and closing the lid will re-set the alarm so the LED will turn on at the next time in the alarm_times list.
This is a demonstration project for STEM learning and to help students begin thinking about building products that promote “tech for good”. This project is not meant as a medical device, nor is any warranty expressed or implied. It should not be used as the sole method for notifying someone to take their medication.
The steps in this tutorial are illustrated using a Mac. Windows users won’t have the Mac Terminal program, which I use to connect to the Pi using ssh (steps described below). If you’re a Windows user and are comfortable launching and running the PuTTY program for ssh sessions, you should otherwise find this tutorial easy to follow.
Parts List
To build this project you’ll need:
- A Raspberry Pi with Header Pins, capable of connecting to a Wi-Fi network. While any Wi-Fi-capable Pi with headers will work for this project, I’ve used the low-cost Raspberry Pi Zero WH, which comes with header pins pre-installed.
- A microSD card that works with the Pi. A minimum 8GB, max 32GB card is appropriate – this is an example of a card I’ve used for similar projects. It’s assumed that you’ve already added Raspberry Pi OS to the card, configured it to run on your Wi-Fi network, and that you’ve installed CircuitPython. If you’ve not done this before, step-by-step instructions, along with a setup tutorial video, are linked below:
- A power supply and cable appropriate for your Raspberry Pi. I used this power supply and cable for the Pi Zero WH in this project.
- Four socket on both ends jumper wires (sometimes out-datedly referred to as female/female jumper wires). Wires can be a short length for this project.
- An LED bulb. Any size 10mm or smaller is fine for this project. I’ve used a larger 10mm red bulb, purchased in this package of multi-colored LED bulbs.
- A resistor appropriate for the LED used in this project (the tutorial will mention how to calculate resistor size). A 100 ohm resistor should be fine for most red LEDs (note ohm is sometimes written as Ω), and you can purchase these resistors in a small package for less than a dollar. Make sure you use a 100 Ω and not a 100K Ω resistor. If you’re going to be working on other maker projects, you might want to buy a box of variously-sized resistors.
- A box with a hinged lid (think cigar box) large enough to hold your supplements or meds. You may have one, but I purchased this clear, acrylic box for less than $10, and it was large enough to hold several pill bottles.
- A magnetic switch that can detect if a cabinet door is open or closed.
Additional Supplies (that you may already have)
- Wire cutters or strong scissors for trimming the thin wires on the resistor and LED bulb.
- A cordless drill or other method to punch a hole in the back of your hinged-lid box. You can also use a hobby knife to cut a hole in the back of the box.
- Electrical tape, which can be used to secure the resistor wire that you’ll wind to the positive LED wire. You can also use electrical tape to secure LEDs and wires that are attached to jumper wire outlet connectors. It is possible to solder the resistor onto the LED if you have a soldering iron and are comfortable soldering, but you absolutely do not need to perform any soldering to build this project.
- Double-sided foam tape, to secure the two ends of the magnetic switch to the box and lid, respectively. Tape can also be used to secure the LED bulb to the back of the hinged box, and the Pi to the back of the box, if you’d like.
Step-by-Step Instructions
Again, this project assumes you’ve got a Raspberry Pi with Raspberry Pi OS configured and running on your local Wi-Fi network, and that you’ve installed CircuitPython on the Pi. If not, see the step-by-step tutorials linked above.
How do I know what resistor size I need?
If you’re using the LED and resistor components that I’ve listed in the parts list above, you can use a 100 ohm resistor with the red 10mm LED and you’ll be fine and you can even skip ahead to the next section. But if you’re curious how I calculated this (and how you can choose the right resistors for future projects) read through this section. There’s also a short video that describes these steps and shows where I found the numbers at: https://youtu.be/J_kmgWj_JBU (this video is also in the playlist of videos for this project).
There are lots of tutorials that will suggest using a 220 ohm resistor as a rule of thumb when lighting an LED. But how should we really be thinking about resistors? Well, first know that we use a resistor to limit the current that flows through a circuit. If we don’t use a resistor, or if we use a resistor that’s substantially less than what is needed, our LED may burn out or have a diminished life. In some cases, using parts without required resistors could also damage the programmable board we’re using (like the Pi). If we use a resistor with a value much greater than we need, the LED will be dimmer when lit, or might stay dark.
Without getting too deep into the theory of electricity, let’s show how to use Ohm’s Law to figure out the size of a resistor to use. Ohm’s Law has three inputs: V = voltage (in volts), I = current (in amps, or usually milliamps in simple projects like this one), and R = resistance (in ohms). Why I for current and not C? The formula was popularized in languages that referred to the “intensity” of current (hence the “I”).
Once you’ve got two of the values in Ohm’s Law, you can use algebra to get the third, so the formula we’ll use is:
R = V/I
Now V is calculated as the supply voltage minus the forward voltage drop of the component we’re using. The Raspberry Pi delivers 3.3v to the GPIO pins, while the page where I ordered these LEDs says the red LED I’m using use between 2.0 and 2.2v. To conservative (which would give me a bigger resistor value), I’ll 2.0, so that gives us:
3.3v (Pi value) – 2.0 (used by the LED) = 1.3v
Now what’s the I (current)? Looking at the specs for the LED I’m using (listed on the web page where I placed my order), it says forward current is 20mA, (or .020A). You can do the simple math, or you can one of the many nifty Ohm’s Law calculators you’ll find online. Either way, you’ll get:
1.3v / .02A = a resistor of 65 ohms
65 ohms is a non-standard resistor size, but it’s perfectly fine to use the closest resistor size or, to be even safer, to use the next larger size. 100 ohms is a standard size, so that’s what I’m using in this project.
Twist the Resistor Around the LED’s Positive Leg
In most cases, the positive leg of an LED is the longest leg. If you think yours might be different, check the spec sheet of the LEDs, or any online documentation where you bought the LEDs from. All of my LEDs have the positive leg as the longer leg, so I’ll assume that’s the case for everyone following this tutorial.
- Attach one end of the resistor (any end is fine) to the positive leg (longer leg) of the LED. If you’re adept as soldering, feel free to solder these together, however it’s perfectly fine to twist these together as shown.
- Trim any excess from the resistor wire and positive leg.
- Trim down the end of the resistor wire and the negative leg.
- Wrap electrical tape around the positive leg / resistor to prevent these wires from touching the negative wire. The positive/resistor side and negative side should never touch.
Prepare the Box/Cabinet and Wire Components to the Raspberry Pi
- Poke a hole in the back of the box on the bottom back corner of the same side where you’ll place your sensors. If you’re using an acrylic box, like the one shown, you can use a cordless drill to drill a 1/4″ hole in the back of the box. If you don’t have a cordless drill, you can carefully use a utility knife to cut an opening in the acrylic box (watch your fingers). Use scissors or a utility knife to peel away any plastic left from drilling.
The magnetic sensor comes in two parts: we’ll place the wired part inside the box adjacent to the lid, and the unwired part on the lid itself. The magnetic switch doesn’t have polarity – meaning we can connect either wire to the data pin (GPIO 23 in our case) as long as the other wire is connected to ground. We also don’t need a resistor for the switch. Everything that handles detection of door closed (switch parts close together), or door open (switch parts about 0.5″ or greater apart) is done in our software.
- Thread the two wires from the wired part of the magnetic switch from the inside of the box, through the hole and out the back of the box.
- Use double-sided foam tape to secure the wired part of the magnetic switch to the side of the box, and the other, unwired part of the switch to the box lid. Make sure the two parts of the switch line up before securing with tape (diagram above right).
Attach jumpers to the Raspberry Pi headers GPIO 23 and Ground, then attach the magnetic switch wires to the other ends of these jumper wires. Note that GPIO 23 is referred to as D23 in our python code.
- Plug one jumper into pin GPIO 23 (labeled), the other jumper into the ground pin next to it.
- Plug one of the wires from the magnetic switch into one of the free jumper ends, and plug the other magnetic switch wire into the other jumper end. As mentioned above, a magnetic switch has no “polarity”, meaning it doesn’t matter which switch wire is plugged into GPIO 23 and which is plugged into ground.
- Use electrical tape to secure the jumper wire / magnetic switch wire connections so that the wires don’t fall out.
Attach jumpers to the Raspberry Pi headers GPIO 24 and Ground, then attach the positive LED wire (the one with the resistor) to GPIO 24, and the negative wire to the ground. Note that GPIO 24 is referred to as D24 in our python code.
- Plug one jumper into pin GPIO 24 (labeled).
- Plug the positive end of the LED pin (the one with the resistor attached) into the other end of this jumper wire. LEDs are directional, and the LED will not light if it’s plugged in backwards.
- Plug the last jumper into the ground pin next to GPIO 24 (labeled).
- Plug the ground wire of the LED (the one without the resistor) into the socket of this last jumper wire.
- Use double-sided foam to secure the LED to the back of the box. Be sure to position the LED so that it’s not severely bent back when the box lid is opened.
Log into the Raspberry Pi and Install the Schedule Python Library
- Turn on the Raspberry Pi (it should take about 30 seconds to power up).
- Open the Terminal program (Mac users launch Spotlight by typing Command+space bar, then type Terminal and press the return key. Windows users, launch PuTTY).
- Log into your Raspberry Pi from the terminal prompt by typing the command below and pressing the return key, substituting hostname with the hostname for your Pi.
ssh [email protected]
- If you want to change the hostname for the Pi used in this project, you can launch the raspi-config program by typing the command below and pressing the return key. You can then change the hostname by selecting System Options, then Hostname.
sudo raspi-config
Be sure to exit the raspi-config program if you’ve changed your hostname – you can reboot then use the ssh command to log back into your Pi when prompted (remember your Pi will take about 30 seconds to reboot). It’s very important to remember that if you change your Pi’s hostname, then this will be the new hostname that you use to log in using the ssh command, as listed above.
- If you want to change the hostname for the Pi used in this project, you can launch the raspi-config program by typing the command below and pressing the return key. You can then change the hostname by selecting System Options, then Hostname.
- Type the command below to add the schedule library so that it can add scheduling commands to the python programming language. Python doesn’t come with scheduling features, but by adding this library, the code we’ll use can properly schedule LED lights to light up at pre-determined times. After typing the command below, it might at first appear that your Pi has stalled. Be patient – sometimes the command takes several seconds to show any progress. Once the install starts, the entire install should take less than one minute.
pip3 install schedule
Use raspi-config to set the proper timezone for your Raspberry Pi
You need to set the current time zone for your Raspberry Pi for your project to work properly. Once the time zone is set, an Internet-connected Raspberry Pi will use the Internet to set and maintain the current time. Set the time zone using the raspi-config utility.
- From the command prompt, enter the command below and press the return key to launch the raspi-config program:
sudo raspi-config
- Use the arrow keys to select Localisation Options to Configure language and regional settings. Press return. The Localisation options menu will appear (note the British spelling of localisation. The Raspberry Pi Foundation is a British non-profit organization).
- Use the arrow keys to select Timezone to Configure time zone. Press the return key. The raspi-config screen may pause a bit and flash but will eventually show the Configuring tzdata screen.
- Use the arrow keys to select your continent. Press the return key.
- The next screen prompts you to Please select the city or region corresponding to your time zone. Use the arrow keys to select a listed city or region that is in your same time zone, then press the return key.
Since I’m on the East Coast of the United States, but my city, Boston, isn’t in the list, I’ve selected New York, which is also in the same time zone as Boston. There are lots of cities and regions listed, so you might have to scroll through several screens to find a city near you.
Once a city or region is selected, the Pi may briefly flash your time to the console then return you to raspi-config. - Press the right-arrow key until Finish is selected, then press the return key. You’ll be returned to the command prompt.
You should now see the current time and universal (UTC) time printed above the prompt.
Add the smart_cabinet.py python code to this project and modify the alarm_times
- While logged into your Pi, type the command below at the terminal prompt, then press the return key. This will launch the nano text editor program and will begin creating a blank file, to be named smart_cabinet.py
nano smart_cabinet.py
- Open a browser and visit the URL below to access the GitHub-stored files for this project.
https://github.com/gallaugher/pi-cabinet/ - The main page includes README background information. To access the code we’ll use in this project, click the file name smart_cabinet.py. This will open a page showing the project’s python code.
- Feel free to scroll through the code. Any text on a line that’s after a # character is a comment, meant to document the code. Reading the comments can help even a non-python programmer get a sense of how the program works.
- The only line we’ll eventually modify will be the one about halfway down, shown below. This line defines the list of times when the LED light should turn on.
alarm_times = ['05:00', '17:00', '22:00']
By default this line sets the LED light to light up after 5am, 5pm, and 10pm. We won’t change this now – but finding this in the code will give you a sense of where it is when we modify the code in later steps.
- Now highlight all of the code to the right of the numbers in this file, clicking to the left of the first # after line 1, and dragging through the very last character of the very last numbered lines. The code will highlight, but the numbers wont.
- Copy the highlighted code.
- Return to the Terminal program.
- Paste the copied code into nano. The code will automatically advance through as many screens as needed in order to paste in the entire code.
Now let’s page through the code and find the line we want to modify.
- Press the up arrow key on the keyboard repeatedly until you reach the top of the window. Pressing it one more time will change the screen to show the previous page of this program code and position the cursor in the middle of the page. Keep pressing the up arrow until you’ve found the screen with the line containing the code below (you might page through the top of three screens before you find this):
alarm_times = ['05:00', '17:00', '22:00']
This line defines the times when the LED light should turn on, indicating that it’s time to take your meds. Each time must be written in 24 hr time (e.g. midnight is ’00:00′, noon is ’12:00′, and 11:59 pm is ’23:59′. All times must be enclosed in single quotes. Times are separated by commas, and the entire list of times is enclosed in between square bracket characters [ ].
- Use the cursor and delete keys to move to this line and delete unwanted times, then properly enter any times when you want the LED to light up.
Be careful when moving around in nano and pay attention to what you type, where the cursor moves, and what changes are made, if any. If you add any unwanted characters accidentally when using the cursor and delete keys, you may be modifying the working python code with unwanted characters that will cause the code to crash.
If you only have a single time to take meds each day, you can enter a single time between single quotes and brackets. For example, I want to take my vitamins when I wake up, so I have changed the line as indicated below to begin lighting up at 5am.
alarm_times = ['05:00']
Once you’ve properly updated the alarm_times line, you’re ready to exit nano and save your changes.
- Type Control+X. Nano will ask you if you’d like to save your modified buffer (that means save your changes).
- Type Y. Nano will indicate that the file name to write is smart_cabinet.py.
- Press the return key. You’ll be returned to the prompt.
Run the smart_cabinet.py program
- Make sure the project is wired up as illustrated above – jumper wires in the correct pins, and the LED properly positioned so that the positive leg is in jumper attached to pin GPIO 24 the ground leg attached to the pin plugged into ground. The magnetic switch should have one wire plugged into the jumper attached to pin GPIO 23, the other to a wire attached to a ground pin.
- Run the smart_cabinet python code that we just modified by typing the line below, then pressing the return key:
python3 smart_cabinet.py
Note: If things aren’t working properly you can scroll below to the section labeled Help! My Code Isn’t Working! If everything is working properly, you should see the terminal list the Raspberry Pi’s current time, then all times that are scheduled for the LED to light up. The LED light should also be flashing.
- Open the box’s lid. You should see the LED turn off and the terminal will begin printing the line: “*** DOOR OPEN!” approximately every half second.
- Close the lid and the box should remain off. You should see the terminal output print the line “DOOR CLOSED” approximately every half second.
You can open and close the door repeatedly and you should see the printed line change as indicated above. This shows the sensor is working properly. If so, congratulations! You’ve successfully built a smart medicine cabinet!
You can stop the program from executing at any time by typing Control+C in the terminal. This will show output indicating the line where the code was stopped (which isn’t really important), then you will be returned to the command prompt.
To rerun the code, simply enter the line you used above at the prompt, python3 smart_cabinet.py then press return.
Feel free to experiment to make certain that your box is working properly. If you want to change the alarm_times, you can get back into your smart_cabinet.py code in nano by using the command below, which you’d used earlier:
nano smart_cabinet.py
This time your cursor will be positioned at the start of the first line in the code (previously, when you first pasted code into nano, your cursor was at the end of the file). Use the down arrow key to move the cursor to the bottom of the screen, then press the down arrow once more to load the next page full of code. If you’d like, you page through multiple pages and find the line beginning with the code: alarm_times = [, then you can add a list of times that, say, start a minute from the current time and are separated by one or two minutes. If you quit out of nano and save your work (remember Control+X, as illustrated above), you can then return to the prompt and type python3 smart_cabinet.py again to re-run your code. You can then open and close the cabinet to turn off the flashing light. Then each time a time listed in alarm_times is reached, the light should turn red until you open the lid. This is a nice way to quickly test that timing and your LED and switch are working before finishing the project.
Scheduling the smart_cabinet.py program to run automatically by using the cron utility
Once the time is set, we want to be able to plug our project in and have it just work, no additional login or configuration required. We can do this using the cron utility to run our python code each time the Raspberry Pi boots. This has the added benefit of rebooting our Pi and restarting our code if the power temporarily goes out. To set up the cron to run our code:
- If your code is still running, stop execution using a Control+C so that you return to the command prompt.
- At the command prompt, enter the line below so that you can edit the cron commands:
crontab -e
- The first time you run this command, your Raspberry Pi will ask you which text editor to use. It will likely show option #1 as /bin/nano <- easiest. Since we’ve been working with this option, press 1 (which should be the number for the nano option). This will launch the nano editor with our crontab file, which contains all of the commands run by cron.
- Press the down arrow key repeatedly to page through all screens in this file until you’ve arrived at the very last line.
- On this new line, enter the text below, then press return:
@reboot python3 smart_cabinet.py &
Now exit nano, saving your cron file.
- Type Control+X
- When asked to “Save the modified buffer?” type Y
- The filename to write will be listed at the correct directory. Simply press the return key. The file will be saved and you’ll be returned to the prompt.
Now lets make sure everything is working properly:
- Reboot your Pi by typing the command below at the prompt, then press the return key:
sudo reboot
This will log you out of your Pi and reboot the device. Don’t bother logging back in. After about 30 seconds you should see the LED flash, indicating that your smart_cabinet.py program is running. If so, congratulations! Your project is working!
Neaten up the build
You can certainly use the cabinet as is, but I’ve neatened up my cabinet by attaching the Pi to the left side using a piece of double-sided foam tape, and I’ve wrangled the wires so they’re flush to the back of the cabinet by using clear packing tape. You can experiment to find the technique that works best for the look you’re trying to achieve.
I place my cabinet near my coffee maker so I can see the light reminding me to take supplements with my morning cup. Others might find this works best in their bathroom, or bedroom nightstand. Once it’s been setup, I simply plug a microUSB cable into the Pi and the other end into the USB port on an outlet plug in the kitchen, so I can keep the Pi’s power supply and the on-off switch cable for other projects with different Pis.
❖ ❖ ❖ ❖ ❖
Help! My Code Isn’t Working!
If you type the line: python3 smart_cabinet.py and press return, but there is an error in your code, it won’t run and you’ll likely see some sort of error output message instead of the output of scheduled times. In the example below, I’ve deliberately put an error in my code and when I used the python3 command, the following output showed up in the terminal:
pi@picabinet:~ $ python3 smart_cabinet.py File "smart_cabinet.py", line 46 alarm_times = ['05:00', '17:00', '22:00] ^ SyntaxError: EOL while scanning string literal
then I’m returned to the terminal prompt.
While this command isn’t super friendly, it shows the line where the error in the python code was found (line 46), it then prints the line, and the ^ character below even helpfully points to the problem. This error isn’t especially friendly to the newbie. But EOL stands for End Of Line, meaning python found that the line had ended before it found an end to the String (another name for a group of text). Now the Strings (text) in this line are enclosed in single characters, but can you see the problem above?
’22:00 starts with a single quote, but I forgot to put the closing single quote at the end. If you run into an error like this, write down the error that shows up in the terminal, then enter nano and look at your code. Sometimes the error is actually in the line above or below your code. Common errors include things like forgetting quotation marks, commas between values, closing brackets, colons in locations where colons are used, or not using proper indentation (python is very fussy about indents). If you want to learn more python, there are lots of great tutorials online, including a whole series I’ve created for learning CircuitPython using the low-cost, sensor-rich CircuitPlayground Bluefruit device.
Help! My LED light isn’t lit, or my sensors aren’t showing the DOOR OPEN or DOOR CLOSED!
If you’re not getting an error when running your code, but your door sensor isn’t indicating when the door is open or closed, or the light isn’t turning on, this is probably a problem with the wiring connections or circuit. Check to make sure the wires are plugged into the pins, as illustrated above. Make sure that the sensor wires are pushed into the sockets in the jumper wires – if they come loose, your circuit is broken and your program won’t be able to tell if the door is open or closed. Similarly, if your LED isn’t lighting up it could be one of several problems, including
- A leg of the LED popped out of the jumper socket.
- The jumper sockets are in the wrong Raspberry Pi header pins.
- The resistor that is supposed to be wrapped to the + leg of the LED isn’t actually touching the leg, so the circuit is broken.
- The + leg (long) and – leg (short) on the LED are connected to the opposite pins (current only flows with resistor and + pin connected to the GPIO 24 pin and the -ground leg connected to the ground pin.
- You could possibly have a burnt out or broken LED.
Still stuck? There are LOTS of great forums online, including support forums from Adafruit that you can use if you buy products from my favorite electronics supplier, as well as the Raspberry Pi forums. Just be sure to be positive and supportive. And when you skill up – pay it forward by returning to the forums to help others!
❖ ❖ ❖ ❖ ❖
Ready for more? Check out tutorials on Robotics, Wearables, App Development and more at: https://youtube.com/profgallaugher. Please consider subscribing and do share with others who may be interested!
Want to learn to build apps? The same content I use in my semester-long online course (videos and tutorial content) is available for less than $25 via links you’ll find at https://gallaugher.com/swift.
Look for more updates at gallaugher.com as well as on Twitter @gallaugher