Skip to content

Assembling Electronics and Codes

We tested most of the electronics individually and then combined them to get the final result. When combining electronics we had to to care of a lot of things:

Obstacles

  • Number of Pins needed: We knew we had to use Arduino Mega to accommodate the number of electronics we wanted to use. You can see just how many components we used in the circuit below:
Click to expand for the circuit

Edit this project interactively in Cirkit Designer.

  • Resistors for LEDs: Each LED is recommended to be connected to a 220 ohm resistor to limit the current running through it and mitigate the risk of the LED burning out. We decided to solder the necessary resistors onto the LEDs and then apply heat shrink tubing onto the exposed metallic connections in order to prevent short circuits. This was a good idea on paper, however, when we finished the soldering the heat shrink we did not test the LED to see if they were functional (big whoops), we only tested them before soldering. As such, the green LED and the 3rd blue LED do not work and we have to replace them.

  • Power supply: Because so many of our components require a 5v power supply, when assembling the entire device we found that the LCD and the speaker do not work properly. We were advised by our instructor Haitham to use a 12v Power connector in addition to the 5v supplied to the Arduino Mega from USB. We first made sure that the Arduino Mega could handle this additional voltage, since apparently it can handle up to 20v. This solved the issue and all the devices now function as expected.

  • Disregarding Bracelet for Proximity: Our initial idea included a bracelet that would vibrate to indicate when it was time for medicine, in addition, to sensing how close the user is to the device in order to trigger the motivational message automatically when they are in range to hear it. I even tested out using BLE for proximity in week 5. However, because of the complexity of the device on its own, and because of the fact that we needed to create another smart device to put inside this bracelet, we decided to abandon this idea and instead incorporate some of its features in the phone app. We also decided to change the motivational message to play after the user has opened the medicine door, this does have its advantages since now there is a direct positive affirmation tied to the negativity of having to take medication.

  • Operating the Device: The Blynk Wifi code takes priority over everything else when starting the device, so we have to wait until the device prints “Ready” in the serial monitor before we can test or use anything. Additionally, when trying to start the device or upload code to the Arduino we found that we had to disconnect the additional power supply and the USB connection, then connect the USB and wait for the Arduino Mega to be identified in Arduino IDE, and only then can we upload the code. After the code has been uploaded and the device prints “Ready” in the serial monitor, you can connect the additional 12v power source.

  • Dispensing Button: Because the device is set to dispense based on predetermined times for each medicine, showcasing it in a presentation would be difficult. To remedy this, we added a dispensing button in the app itself.

Final Code

The code is so long that I had to research how to make collapsible blocks.

Click to expand for final code
#define BLYNK_TEMPLATE_ID "TMPL64N6YLX1h"  //these two are from blynk template
#define BLYNK_TEMPLATE_NAME "Medicine Test"
#define BLYNK_AUTH_TOKEN "XW0Bxb8MA0d52NcIff_Wobxc1Aua_in6"  //this is from device

#define BLYNK_PRINT Serial

#include <ESP8266_Lib.h>               //wifi module
#include <BlynkSimpleShieldEsp8266.h>  //wifi app
#include <TimeLib.h>                   //these two are for wifi based RTC
#include <WidgetRTC.h>
#include <Stepper.h>  //stepper motor
#include <Wire.h>
#include <LiquidCrystal_I2C.h>  //lcd
#include "pitches.h"            // for the buzzer

// Set password to "" for open networks.
char ssid[] = "BSC-F2";
char pass[] = "bsc@2030";


// Hardware Serial on Mega, Leonardo, Micro...
// On Mega Serial1 is pins 18 and 19
#define EspSerial Serial1

// or Software Serial on Uno, Nano...
//#include <SoftwareSerial.h>
//SoftwareSerial EspSerial(6, 7);
// These are arduino's RX, TX.  Don't connect the reset pin

BlynkTimer timer;      //initiate timer function for blynk
WidgetRTC rtc;         //wifi based RTC

//Record
#define Record_Button 34
const int Record_LED = 38;
//LED for when pill is ready for taking
#define Ready_Led 53
//LEDs for when pills remaining are less than 5
#define Pills_Low_1 50
#define Pills_Low_2 51
#define Pills_Low_3 52

#define Tilt_Switch 22

#define Record_Button 34  // the number of the pushbutton pin
int buttonState = 0;

#define PLAY_E 2                     // defining pin 2 to playPack_edge for the speaker
LiquidCrystal_I2C lcd(0x27, 16, 2);  //I2C LCD definition. 0x27 is address, 16 is rows, 2 is columns

const int stepsPerRevolution = 2048;  // change this to fit the number of steps per revolution
int rpm = 15;                         //seems to be optimal
int rpm_2 = 7;
int rpm_3 = 13;                         //for the third motor since its week

//Defining stepper motor pins. last 3 must be PWM
Stepper Stepper3(stepsPerRevolution, 8, 10, 9, 11);

Stepper Stepper2(stepsPerRevolution, 4, 3, 5, 6);

Stepper Stepper1(stepsPerRevolution, 46, 44, 45, 47);

// define the pins of the joy stick.
int xPin = A2;
int yPin = A3;
#define Joystick_Button 28

int Joystick_Button_State = 0;

// define veriables to the values, to read later.
int xPosition = 0;
int yPosition = 0;

// map function sets the limits for the joy stick
int mapX = 0;
int mapY = 0;

#define ESP8266_BAUD 9600

ESP8266 wifi(&EspSerial);

//Medicine Data (There should be a better way)
String Medicine1_Name = "Nexium";
String Medicine2_Name = "Tic Tac";
String Medicine3_Name = "Cipralex";

byte Medicine1_Pills = 40;
byte Medicine2_Pills = 3;
byte Medicine3_Pills = 25;

int Add_Med_1 = 0;
int Add_Med_2 = 0;
int Add_Med_3 = 0;

byte Medicine1_Hours1 = 12;
byte Medicine1_Minutes1 = 27;
byte Medicine1_Hours2 = 14;
byte Medicine1_Minutes2 = 0;
byte Medicine1_Hours3 = 21;
byte Medicine1_Minutes3 = 24;

byte Medicine2_Hours1 = 8;
byte Medicine2_Minutes1 = 20;
byte Medicine2_Hours2 = 12;
byte Medicine2_Minutes2 = 20;
byte Medicine2_Hours3 = 21;
byte Medicine2_Minutes3 = 25;

byte Medicine3_Hours1 = 10;
byte Medicine3_Minutes1 = 52;
byte Medicine3_Hours2 = 13;
byte Medicine3_Minutes2 = 56;
byte Medicine3_Hours3 = 18;
byte Medicine3_Minutes3 = 19;

//for the buzzer
int melody[] = {
  NOTE_C4, NOTE_E4, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_E4, NOTE_C4,
  NOTE_E4, NOTE_G4, NOTE_B4, NOTE_D5, NOTE_B4, NOTE_G4, NOTE_E4
};

int noteDurations[] = {
  8, 8, 8, 4, 8, 8, 8,
  8, 8, 8, 4, 8, 8, 8
};

//These are for the dispensing buttons
int dispense1 = 0;
int dispense2 = 0;
int dispense3 = 0;

BLYNK_CONNECTED() {
  // Synchronize time on connection
  rtc.begin();
}

BLYNK_WRITE(V4) {
  // These functions are used to receive data from the web.
  // They are called when the datastream V4 value changes.
  // They assign incoming value from pin V4 to a variable
  // according to the datastream data type
  int Add_Med_1 = param.asInt();

  Medicine1_Pills = Medicine1_Pills + Add_Med_1; //This is for adding more pills
}

BLYNK_WRITE(V5) {
  int Add_Med_2 = param.asInt();

  Medicine2_Pills = Medicine2_Pills + Add_Med_2;
}

BLYNK_WRITE(V6) {
  int Add_Med_3 = param.asInt();

  Medicine3_Pills = Medicine3_Pills + Add_Med_3;
}

BLYNK_WRITE(V10) {
  //This is for the dispensing buttons on the app
  int Dispense_1 = param.asInt();

  dispense1 = Dispense_1;
}

BLYNK_WRITE(V11) {
  int Dispense_2 = param.asInt();

  dispense2 = Dispense_2;
}

BLYNK_WRITE(V12) {
  int Dispense_3 = param.asInt();

  dispense3 = Dispense_3;
}

void myTimer() {
  // This function describes what will happen with each timer tick.
  //I am using it to send the pill count to the web app, by assigning them to virtual pins on blynk
  Blynk.virtualWrite(V1, Medicine1_Pills); //This function is used to send data to the web
  Blynk.virtualWrite(V2, Medicine2_Pills);
  Blynk.virtualWrite(V3, Medicine3_Pills);
}

void setup() {
  Serial.begin(9600);
  EspSerial.begin(ESP8266_BAUD); //make sure this is the same as serial baud rate
  delay(10);

  //Blynk.begin(BLYNK_AUTH_TOKEN, wifi, ssid, pass);  //This is the normal setting
  // You can also specify server:
  Blynk.begin(BLYNK_AUTH_TOKEN, wifi, ssid, pass, "blynk.cloud", 80);  // I like to use the new blynk cloud server
  //Blynk.begin(BLYNK_AUTH_TOKEN, wifi, ssid, pass, IPAddress(192,168,1,100), 8080);

  //time interval between sending data to blynk cloud
  timer.setInterval(1000L, myTimer);  //This means the web app updates every second

  setSyncInterval(10 * 60);  // wifi RTC Sync interval in seconds (10 minutes)

  Stepper1.setSpeed(rpm);
  Stepper2.setSpeed(rpm_2);
  Stepper3.setSpeed(rpm_3);

  lcd.init();       // initilize the screen
  lcd.backlight();  // Turn on the light of the screen
  lcd.clear();      // Clears any previous data in the screen

  // define the state of the pins
  pinMode(xPin, INPUT);
  pinMode(yPin, INPUT);
  pinMode(Joystick_Button, INPUT);

  pinMode(Tilt_Switch, INPUT);
  digitalWrite(Tilt_Switch, HIGH); //not sure why

  // initialize the LED pin as an output:
  pinMode(Record_LED, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(Record_Button, INPUT);
  // define the speaker pin
  pinMode(PLAY_E, OUTPUT);
  //this is the green LED
  pinMode(Ready_Led, OUTPUT);

}

void loop() {
  Blynk.run();  //This starts the wifi stuff from the blynk library
  timer.run();  //timer for wifi to send data not too frequently

  //Screen and Analog:
  xPosition = analogRead(xPin);
  yPosition = analogRead(yPin);

  // target = map(source, sourceLow, sourceHigh, targetLow, targetHigh)
  mapX = map(xPosition, 0, 1023, -512, 512);
  mapY = map(yPosition, 0, 1023, -512, 512);

//Down
  if ((mapX < -200) && (mapY > - 200)) {
    lcd.setCursor(0, 0);
    lcd.print("                ");
    lcd.setCursor(0, 0);
    lcd.print("Made By: Hassan");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    lcd.setCursor(0, 1);
    lcd.print("Ali, Saeed, Sara");
  }

//Up
  if ((mapX > 200) && (mapY < 200)) {
    lcd.setCursor(0, 0);
    lcd.print("                ");
    lcd.setCursor(0, 0);
    lcd.print(Medicine2_Name);

    lcd.setCursor(0, 1);
    lcd.print("                ");
    lcd.setCursor(0, 1);
    lcd.print("Pills Left: ");

    lcd.setCursor(13, 1);
    lcd.print(Medicine2_Pills);
  }

//Left
  if ((mapX < 200) && (mapY < -200)) {
    lcd.setCursor(0, 0);
    lcd.print("                ");
    lcd.setCursor(0, 0);
    lcd.print(Medicine1_Name);

    lcd.setCursor(0, 1);
    lcd.print("                ");
    lcd.setCursor(0, 1);
    lcd.print("Pills Left: ");

    lcd.setCursor(13, 1);
    lcd.print(Medicine1_Pills);
  }

//Right
  if ((mapX > -200) && (mapY > 200)) {
    lcd.setCursor(0, 0);
    lcd.print("                ");
    lcd.setCursor(0, 0);
    lcd.print(Medicine3_Name);

    lcd.setCursor(0, 1);
    lcd.print("                ");
    lcd.setCursor(0, 1);
    lcd.print("Pills Left: ");

    lcd.setCursor(13, 1);
    lcd.print(Medicine3_Pills);
  }

  //Medicine One Trigger
  if ( ( (hour() == Medicine1_Hours1) && (minute() == Medicine1_Minutes1) && (second() == 0)) || 
       ( (hour() == Medicine1_Hours2) && (minute() == Medicine1_Minutes2) && (second() == 0)) || 
       ( (hour() == Medicine1_Hours3) && (minute() == Medicine1_Minutes3) && (second() == 0)) ||
       ( dispense1 == 1 ) ) //this is the dispense button on the app
  {
    Blynk.logEvent("medicine_time");
    Serial.println("Medicine1 Time");
    Medicine1_Pills--;  //reduces pill count by 1
    Serial.println(Medicine1_Pills);
    digitalWrite(Ready_Led, HIGH);  //make green led turn on

    //below is the buzzer code
    for (int thisNote = 0; thisNote < 8; thisNote++) {
      int noteDuration = 1000 / noteDurations[thisNote];
      tone(13, melody[thisNote], noteDuration);

      int pauseBetweenNotes = noteDuration * 1.30;
      delay(pauseBetweenNotes);
      noTone(8);
    }
    Stepper1.step(stepsPerRevolution);
  }

  //Medicine two trigger
  if ( ( (hour() == Medicine2_Hours1) && (minute() == Medicine2_Minutes1) && (second() == 0)) || 
       ( (hour() == Medicine2_Hours2) && (minute() == Medicine2_Minutes2) && (second() == 0)) || 
       ( (hour() == Medicine2_Hours3) && (minute() == Medicine2_Minutes3) && (second() == 0)) ||
       ( dispense2 == 1 ) ) 
  {
    Blynk.logEvent("medicine_time");

    Serial.println("Medicine2 Time");
    Medicine2_Pills--;  //reduces pill count by 1
    Serial.println(Medicine2_Pills);
    digitalWrite(Ready_Led, HIGH);  //make led turn on

    for (int thisNote = 0; thisNote < 8; thisNote++) {
      int noteDuration = 1000 / noteDurations[thisNote];
      tone(13, melody[thisNote], noteDuration);

      int pauseBetweenNotes = noteDuration * 1.30;
      delay(pauseBetweenNotes);
      noTone(8);
    }

    Stepper2.step(-stepsPerRevolution*1.1);  //for some reason this motors turns in the opposite direction
  }

  //Medicine three trigger
  if ( ( (hour() == Medicine3_Hours1) && (minute() == Medicine3_Minutes1) && (second() == 0)) ||
       ( (hour() == Medicine3_Hours2) && (minute() == Medicine3_Minutes2) && (second() == 0)) ||
       ( (hour() == Medicine3_Hours3) && (minute() == Medicine3_Minutes3) && (second() == 0)) ||
         ( dispense3 == 1 ) ) 
  {
    Blynk.logEvent("medicine_time");
    Serial.println("Medicine3 Time");
    Medicine3_Pills--;  //reduces pill count by 1
    Serial.println(Medicine3_Pills);
    digitalWrite(Ready_Led, HIGH);  //make led turn on

    for (int thisNote = 0; thisNote < 8; thisNote++) {
      int noteDuration = 1000 / noteDurations[thisNote];
      tone(13, melody[thisNote], noteDuration);

      int pauseBetweenNotes = noteDuration * 1.30;
      delay(pauseBetweenNotes);
      noTone(8);
    }

    Stepper3.step(stepsPerRevolution*1.1);
  }

//For the record button and LED. The recording pin on the speaker is wired in series (no code needed)
buttonState = digitalRead(Record_Button);
  if (buttonState == HIGH) {
    digitalWrite(Record_LED, HIGH);  //this is the red LED.
  } else {
    digitalWrite(Record_LED, LOW);
  }

//For the door speaker
  if (digitalRead(Tilt_Switch) == LOW) {
    digitalWrite(PLAY_E, HIGH);  //play speaker
    delay(500);
    digitalWrite(PLAY_E, LOW);
    digitalWrite(Ready_Led, LOW);  //make green led turn off
  }

  //Medicine Low Notifications and LED
  if (Medicine1_Pills < 5) {
    Blynk.logEvent("low_medicine_1");
    digitalWrite(Pills_Low_1, HIGH);
  } else {
    digitalWrite(Pills_Low_1, LOW);
  }

  if (Medicine2_Pills < 5) {
    Blynk.logEvent("low_medicine_2");
    digitalWrite(Pills_Low_2, HIGH);

  } else {
    digitalWrite(Pills_Low_2, LOW);
  }

  if (Medicine3_Pills < 5) {
    Blynk.logEvent("low_medicine_3");
    digitalWrite(Pills_Low_3, HIGH);
  } else {
    digitalWrite(Pills_Low_3, LOW);
  }
}

Last update: September 15, 2024