Project Development
Full documentation of the MediBee pill dispenser
Medication non-adherence is one of healthcare's most expensive, least-solved problems. Roughly half of patients on chronic medication don't take it as prescribed, driving avoidable hospitalizations, worse outcomes, and an estimated hundreds of billions in annual cost globally. Existing solutions such as pill organizers, phone alarms, blister packs, are passive. They remind, but they don't verify, dispense, or report.
MediBee is a connected automated pill dispenser that closes the loop. It dispenses the correct dose on schedule, alerts the patient, confirms the pill physically came out via onboard sensors, and reports that data to a companion app in real time.
The hardware is a custom PCB built around a XIAO ESP32C6, driving a 28BYJ-48 stepper motor (rotating a medication disc), a servo (controlling the dispensing gate), a solenoid lock, a passive buzzer, and an SSD1306 OLED display.
On the software side, a React Native Android app communicates with the device over WiFi via a REST API hosted on the ESP32.
Each subsystem had been developed separately across previous weeks. System integration meant wiring them into a single enclosure, resolving hardware conflicts, and validating end-to-end behaviour from the phone app down to physical actuation.
The full system has four layers:
The enclosure was designed in Fusion 360 and printed in PLA. The main challenge during physical assembly was fitting all of the components into the available space with real wiring.
The medication disc was designed to rotate on a 8 mm steel rod. But there was a worry that it'll slip under the load. So I made a hole to put nails into the disc. So the disc is securely attached to the motor shaft. Under the same hole, I put another one to attch a magnet. This magnet is used for homing the disc.
The Stepper motor will rotate only once during the day. Preferable in the morning, right before the first dose.
The servo controls the dispensing gate, a hinged flap that opens to drop a pill into the output chute.
With this mechanism, I can control which slot must dispense at one time. From the image, you can see that the compartment at the center is not covered. This dispenses the morning dose.
At noon, the servo rotated the door to the center, which opens the compartment at the side, and the noon dose dispenses.
The solenoid lock is mounted to the enclosure using two M2 screws through a printed bracket. Getting the angle right was important. If the solenoid was even slightly off, the plunger would catch on the latch instead of sliding through cleanly.
When the solenoid is activated, the plunger retracts and releases the door. The servo rotates the other door to the center. Then rotates back to the original position, which opens the compartment at the side, and the noon dose dispenses.
This is possible by attaching magnets to the side of the doors.
This was the hard part. The PCB, stepper motor, servo, solenoid, buzzer, OLED, and Hall sensors together produce about 30 cm of wiring inside the enclosure.
I added slots in the side of the lower half to mount the main PCB.
The enclosure is a two-part 3D-printed shell in PLA, split into an upper half housing the disc and gate mechanism, and a lower half housing the PCB, wiring, and solenoid. The two halves are held together with Magnets.
I designed the circuit boards in Kicad.
I needed two boards. One was the main board that connects to the Stepper and Servo motors, the solenoid and the buzzer. The second was the board for the Hall Effect sensors. This board will be placed close to the magnets in the enclosure.
I imported the 3D design from Kicad and added it to the enclosure.
This is how the firmware behaves from power-on: it connects to WiFi and NTP once, then runs a loop that simultaneously serves the app's REST requests, keeps the OLED updated, and checks every ten seconds whether a dose is due.
The companion app is a React Native app with four tabs — Home, Schedule, History, and Settings — that all talk to the ESP32 over the same REST API described above. It stores the device's IP address (and, optionally, WiFi credentials to push to the device) locally on the phone using AsyncStorage, so it reconnects automatically the next time the app opens.
The app polls /status every 15 seconds in the background to show an online/offline badge, independent of whichever tab is open.
Full documentation of the MediBee pill dispenser