An electronic device to remind us to take our medicine in the evening

Overview

Do you ever forget to take your evening medicine? We do! Morning time ends up kinda routine and works out fine, but the evening doses are so easy to miss. We could implement a simple reminder on the phone or whatever, but is that any fun? No!

VitaMinder is a small block of wood, hollowed out, and stuffed full of an Arduino and a HC-05 Bluetooth module rigged to some LEDs. Pair that with a Python app running on Raspberry Pi Zero, and you’ve got a nice little system that keeps us on schedule and healthy.

GitHub

Source code and schematic is available in the hc-vitaminder GitHub repository.

Enclosure

For the production model of VitaMinder, I wanted something rugged and plain-but-attractive-in-its-simplicity. She sits right in our kitchen in plain sight and so we can’t spoil the aesthetic. The final installation went swimmingly, achieving the perfect combination of very un-noticeable when inactive, and impossible to miss when she has something to tell us (i.e. take your meds).

VitaMinder’s enclosure is made of two wood halves. The top section is made of 3/4 inch hickory, and has the holes for the LED’s and pushbuttons. The bottom is soft pine and has a deep pocket carved to hollow it out and contain the microcontroller and bluetooth module.

view of LED holes before filling with silicone
view of LED holes after filling with silicone
view of the enclosure and electronic parts before assembly

The sheer number of tools, supplies, software, hardware, and techniques for even a simple project always amazes me. I am fortunate to have built up a nice workshop over the years, and remind myself to go slow, enjoy the process, treat every step with care.

  • Bandsaw rough cut the two halves to size
  • Drill press to bore and countersink holes for wood screws to hold the halves together
  • Pincer pliers to cut wood screws down to the perfect length
  • Belt sander to match the size of both halves
  • Sand paper to make the surface like butter
  • Easel and calipers to design the holes and pockets
  • bCNC to feed G-Code to the cnc for milling
  • Sand paper to clean up the rough edges
  • Hand file to resize the button holes
  • Drill press to widen the holes for the WS2812 LED rectangles that were a millimeter shy of awesome
  • Sanding sealer (3 coats)
  • Rasp to carve a slot for the USB wire
  • Paint (interior latex), 2 coats
  • Solder leads onto the pixels and pushbuttons
  • Carefully scrape any excess sealer and paint from the button holes
  • Cyanoacrylate glue the pixel strip into the body
  • Drill mounting holes through enclosure bottom
  • Apply silicone sealer to LED holes to make it look nice and diffuse the light
  • Install pushbuttons
  • Solder electronics in orientation that fits the enclosure bottom pocket
  • Apply silicone sealer to fix the electronics into the enclosure bottom pocket
  • Drill mounting holes through kitchen cabinet
  • Install enclosure to cabinet (wood screws)

As always with projects of this combined simplicity/complexity, things go funny along the way. Inspecting the carved bottom half pocket shows that it is 1.5mm too high in the Y-axis. All the dimensions align, but it is translated. This will be hidden in the final assembly and the offset still allows for all the electronics to line up since there was some wiggle room in the design. BUT…if this problem appears in the top half which remains visible as the front panel of the device, that’ll bother me every time I look at it, which is in my kitchen so that means like a thousand times a day.

Spent some time examining the design files in Easel, the setup and homing of the cnc mill, the squareness of the wood. Everything seems OK except the actual carve. After a while I just manually translated my machine work home coordinates Y-1.5mm and crossed my fingers. Bingo, the top looks nicely centered.

top half lined up nice and centered
bottom half lined up 1.5mm wonky
blocks of wood destined to become vitaminder

The Pups don’t enjoy construction time

The puppies get bored waiting for daddy to finish carving down cellar. Don’t worry, they already had two walks that day!

picture of dogs, why not?

Prototype

solderless breadboard
soldered permanent prototype breadboard
a cardboard box makes a great prototype enclosure

Before committing to a final design, I implemented a prototype with all the functionality of the final model but with very little time spent on a fancy enclosure or compact electronics. This allowed me several advantages:

  • Learn how to work with Bluetooth on the Raspberry Pi Zero
  • Experience the visuals and timing of the alarm as the end user in a real world setting
  • Play with cardboard, utility knife, and tape, which is always fun!

This beauty lived in our kitchen for a week and immediately paid off. A smashing success as we were on our merry way to forgetting evening meds the very first night the prototype went live, until the cardboard box turned RED.

Electronics

final electronics assembly before HC-05 installation
closeup of magnificant soldering and heat shrink tubing craftsmanship
final electronics just before sealing the enclosure

The system is controlled by an Arduino Nano. Bluetooth communication is made easy with HC-05 module, which presents itself as a simple serial connection from the perspective of the Arduino. Lighting is provided by some WS2812 addressable rgb leds.

  • Development started on a solderless breadboard, letting me test out the basics of Bluetooth comms and write the Python app on my desktop PC.
  • Then a prototype unit soldered together on a permanent breadboard, housed in a cardboard box. The host app moved from my desktop development PC to the Raspberry Pi Zero that, as fortune would have it, already lives in my kitchen for other purposes (does a nerd really need to justify getting yet another rpi?)
  • Finally, the production model lives in a nice block of wood painted to fit the kitchen color scheme, talking to the same host app as the prototype.
vitaminder schematic

Logic

The Python host application controls the logic, cycling the system through the various states for the day. The Arduino device simply takes instructions from the host app and updates the display, plus sending button press messages back home.

States

There are five states:

  • 0 - unmedicated - this is basically the inactive state where it is not yet time to take your meds
  • 1 - soft reminder - at 6pm it is time to start thinking about your meds, but maybe not quite yet since we want to coincide with dinner
  • 2 - hard reminder - at 7pm we get serious
  • 3 - snooze - press the snooze button and the reminder goes quiet for 15 minutes, mostly useful for when we’re cooking and dont want to keep looking at a hard reminder
  • 4 - nailed_it - we took our meds and life is good (until 2am when the system resets)

Error Handling

Both the Python host app and the Arduino device have their own error handling, used to represent communication failures.

To assist with this, the host app sends a heartbeat message periodically and the device sends a reply.

The Python app nudges me via email if there is no heartbeat response.

The Arduino illuminates an error LED if it receives no heartbeats for 5 minutes.

Bluetooth Messages

The protocol between the host and device consists of 8 byte serial messages sent via Bluetooth.

In essence, when the host sends a request, it expects a response from the device. When the device sends a request, it does not expect a response.

However, following most device requests, the host will want to send its own requests. For example, after receiving a device boot message, the host will wait a moment and then send set LED messages for the full range of pixels, since a freshly booted device doesn’t know what to display. Similarly, a button press typically causes a change in state, which in turn triggers some changes to display.

Message IDDescriptionRequest BytesResponse Bytes
0x00 - heartbeat host app sends request to verify comms with the device 0 : reqID 0x00
1-7 : ignored
0 : rspID 0x01
1-7 : ignored (0x01)
0x02 - set LED host app sends color for specified LEDs, along with any blink duration info. Pixel mask is a bit mask to indicate which LEDs this message applies to. 0 : reqID 0x02
1 : brightness (system-wide, not pixel specific)
2 : pixel mask
3-5 : red, green, blue
6 : off millis (div by 10) (0 means constant on)
7 : on millis (div by 10)
0 : rspID 0x03
1-7 : ignored (0x03)
0x04 - device boot device informs host it is freshly booted and unaware of current state. Host will send set LED messages (0x02) within 5 seconds of receipt 0 : reqID 0x04
1-7 : ignored (0x04)
No Response
0x06 - button press device informs host that OK or Snooze button was pressed. This is likely to trigger a state change, in which case the host will send the appropriate set LED (0x02) messages 0 : reqID 0x06
1 : OK button status (0=unpressed, 1=pressed)
2 : Snooze button status (0=unpressed, 1=pressed)
3-7 : ignored (0x06)
No Response

Bluetooth on Raspberry Pi

This is more a dump of some notes I made while feeling my way through getting Bluetooth working on a Raspberry Pi Zero W.

The application runs in a named screen session on kitchenpi.hc

  • To attach: screen -r
  • To takeover if another shell is attached: screen -d -r
  • To exit the session use ctl-a d

To start or stop the bluetooth service:

sudo systemctl start bluetooth
sudo systemctl restart bluetooth
sudo systemctl stop bluetooth

For scanning and pairing:

sudo bluetoothctl
help

Having previously paired the device with bluetoothctl, connect with:

sudo rfcomm connect /dev/rfcomm0 MAC_ADDR &

To run the vitaminder host application:

cd ~/.virtualenvs/hc-vitaminder
source ./bin/activate
python ./hc_vitaminder.py