ShaguftaSouleymaneKevin Vu
Published © GPL3+

MedicAlert: A Next-Generation Connected Pill Dispenser

A connected pill dispenser to stop worrying about your beloved one's medication.

IntermediateWork in progress3 hours2,753
MedicAlert: A Next-Generation Connected Pill Dispenser

Things used in this project

Hardware components

NodeMCU ESP8266 Breakout Board
NodeMCU ESP8266 Breakout Board
×1
LED (generic)
LED (generic)
×1
Resistor 10k ohm
Resistor 10k ohm
×2
A1302KUA-T - Hall Effect Sensor
×1
Servos (Tower Pro MG996R)
×2
Breadboard (generic)
Breadboard (generic)
×1
Magnet (generic)
×1

Software apps and online services

BlueMix
IBM BlueMix
Arduino IDE
Arduino IDE
Android Studio
Android Studio

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Schematics

Wiring of the system

• ESP8266 GND pin to Servo1 GND
• ESP8266 3.3V pin to Servo1 3.3V
• ESP8266 D2 pin to Servo1 data
• ESP8266 GND pin to Servo2 GND
• ESP8266 3.3V pin to Servo2 3.3V
• ESP8266 D3 pin to Servo2 data
• ESP8266 D1 pin to resistor1
• Resistor 1 to LED
• LED to ESP8266 GND
• ESP8266 D4 pin to hall effect sensor data
• ESP8266 GND pin to hall effect sensor GND
• ESP8266 3.3V pin to hall effect sensor 3.3V
• Resistor 2 between hall effect sensor 3.3V and hall effect sensor data

Code

ESP8266 code

Arduino
/*
 *  Inspired by Ivan Grokhotkov, 2015.
 *  This example is in public domain.
 */

#include <stdio.h>
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ESP8266HTTPClient.h>
#include <PubSubClient.h>
#include  <ESP8266WebServer.h>      //  Include the WebServer library
#include <Servo.h>

/***********MODIFY THIS**********/
const char* ssid = "SSID";
const char* password = "PASSWORD";
#define DEVICE_TYPE "ESP8266"
#define DEVICE_ID "ID"
/********************************/
#define ORG "ORG"
#define TOKEN "TOKEN"
#define ANGLE 19
#define ANGLE2 22 
//-------- Customise the above values --------


const char* mqtt_server = ORG ".messaging.internetofthings.ibmcloud.com";
char topic[] = "iot-2/evt/setMed/fmt/json";
char askRev[] = "iot-2/evt/askRev/fmt/String";
char prendreMedocTopic[] = "iot-2/cmd/prendreMedoc/fmt/String";
char MsgFamille[] = "iot-2/evt/MsgFamille/fmt/String";
char medocNonPris[] = "iot-2/evt/medocNonPris/fmt/String";
char stopRappel[] = "iot-2/evt/stopRappel/fmt/String";

char authMethod[] = "use-token-auth";
char token[] = TOKEN;
char clientId[] = "d:" ORG ":" DEVICE_TYPE ":" DEVICE_ID;
const int MQTTPort = 1883;

#define DELAISEC 20 //5 Min  = 300 sec

WiFiClient wifiClient;
PubSubClient client(wifiClient);

enum PERIODE_JOURNEE{MATIN, MIDI, SOIR};
enum ETAT{ATT_PRISE, PRISE_MEDOC, MEDOC_PRIS, MEDOC_NON_PRIS}; 
bool medocPris = false;
int nbRappels = 0;
long lastMsg = 0;
long lastMsg2 = 0;
bool PassageUnefois = false;

const int buttonPin = D1;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status

PERIODE_JOURNEE JourCourant = MATIN;
ETAT EtatCourant = ATT_PRISE;

unsigned long previousMillis = 0;
const long intervalLed = 1000;
int ledState = LOW;  
Servo myservo1;
Servo myservo2;
int position1 = 0;
int position2 = 0;
int roue1[3];
int roue2[3];
char msg[20];
void setup() {
  Serial.begin(9600);
  setup_wifi();
  
  pinMode(LED_BUILTIN, OUTPUT);     // Initialize the LED_BUILTIN pin as an output
  digitalWrite(LED_BUILTIN, HIGH);
  pinMode(buttonPin, INPUT);
    pinMode(D4, OUTPUT);              // LED VERTE

  client.setServer(mqtt_server, MQTTPort);
  client.setCallback(callback);
  mqttConnect();

  myservo1.attach(D2); 
  myservo2.attach(D3);
  myservo1.write(position1); 
  myservo2.write(position2);  

}

void setup_wifi(){

  Serial.println();
  Serial.print("connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    msg[i] = (char)payload[i];
    Serial.print((char)payload[i]);
  }
  Serial.println();
  Serial.println(msg);
  if(!strcmp(topic, prendreMedocTopic)){
    if((length == 8) || (length == 7)){
      EtatCourant = PRISE_MEDOC;
    }
    else if(length == 12){
      sscanf( msg, "%d;%d;%d;%d;%d;%d;", 
          &roue1[0], &roue1[1], &roue1[2], &roue2[0], &roue2[1], &roue2[2]);
      for(int i = 0; i < 3; i++){
        Serial.println(roue1[i]);
        Serial.println(roue2[i]);
      }
    }
  }
  /*// Parse JSON object
  DynamicJsonBuffer jsonBuffer;

  JsonObject& root = jsonBuffer.parseObject((char*)payload);
  if (!root.success()) {
    Serial.println("Parsing failed!");
    return;
  }
  Serial.print("reponse: ");
  */
  

}

void initManagedDevice() {
   if (client.subscribe(prendreMedocTopic)) {
     Serial.println("subscribe to PrendreMedocTopic OK");
   } else {
     Serial.println("subscribe to PrendreMedocTopic FAILED");
   }
 }

void mqttConnect() {
  if (!client.connected()) {
    Serial.print("Reconnecting MQTT client to "); Serial.println(mqtt_server);
    while (!client.connect(clientId, authMethod, token)) {
      Serial.print(".");
      delay(500);
    }
    initManagedDevice();
    Serial.println();
  }
}
  

void prendreMedoc(){
  unsigned long delaiMili = DELAISEC*1000;

  long now = millis();

  String payload= "{}";
  if ((now - lastMsg2) > (delaiMili/2)) {
    lastMsg2 = now;
    if (client.publish(askRev, (char*) payload.c_str())) {
      Serial.println("Publish ok");
    } else {
      Serial.println("Publish failed");
    }
  }

}

void tournerRoues(){
  switch(JourCourant)
  {
    case MATIN:
      for(int i = 0; i < roue1[0]*2; i++){
        myservo1.write(position1 + ANGLE);
        position1 = position1 + ANGLE+i;
        delay(1500);
      }
      for(int i = 0; i < roue2[0]*2; i++){
        myservo2.write(position2 + ANGLE2);
        position2 = position2 + ANGLE2+i;
        delay(1500);
      }
    break;

    case MIDI:
      for(int i = 0; i < roue1[1]*2; i++){
        myservo1.write(position1 + ANGLE);
        position1 = position1 + ANGLE+i;
        delay(1500);
      }
      for(int i = 0; i < roue2[1]*2; i++){
        myservo2.write(position2 + ANGLE2);
        position2 = position2 + ANGLE2+i;
        delay(1500);
      }
    break;

    case SOIR:
      for(int i = 0; i < roue1[2]*2; i++){
        myservo1.write(position1 + ANGLE);
        position1 = position1 + ANGLE+i;
        delay(1500);
      }
      for(int i = 0; i < roue2[2]*2; i++){
        myservo2.write(position2 + ANGLE2);
        position2 = position2 + ANGLE2+i;
        delay(1500);
      }
    break;
  }
}

void checkPrise(){
  //Serial.println("Dans Check Prise");
  unsigned long delaiMili = DELAISEC*1000;

  long now = millis();
  if(!medocPris){
    if ((now - lastMsg) > delaiMili) {
      //Va demarrer un timer de 30 min pour nouveau rappel
      lastMsg = now;
      String payload= "nonPris";
      if (client.publish(medocNonPris, (char*) payload.c_str())) {
        Serial.println("Publish non pris ok");
      } else {
        Serial.println("Publish failed");
      }
      EtatCourant = ATT_PRISE;   
    }  
  }
  else{
    EtatCourant = MEDOC_PRIS;
  }
  
}
void checkPriseApresRappel(){
  if(medocPris){
    EtatCourant = MEDOC_PRIS;
    String payload= "stop";
      if (client.publish(stopRappel, (char*) payload.c_str())) {
        Serial.println("Publish ok");
      } else {
        Serial.println("Publish failed");
      }  
  }

}
void actionsDeRappel(){
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis >= intervalLed) {
    previousMillis = currentMillis;   
   if (ledState == LOW){
            digitalWrite(D4, HIGH);
      ledState = HIGH;  // Note that this switches the LED *off*

    }
    else{
            digitalWrite(D4, LOW);
      ledState = LOW;   // Note that this switches the LED *on*
    }
    digitalWrite(LED_BUILTIN, ledState);
  }
}

void contacterFamille(){
      String payload= "Contact";
      if (client.publish(MsgFamille, (char*) payload.c_str())) {
        Serial.println("Publish ok");
      } else {
        Serial.println("Publish failed");
      }

      EtatCourant = ATT_PRISE;
}

void machineEtat(){
  switch(EtatCourant)
  {
    case ATT_PRISE:
      if(nbRappels){
        checkPriseApresRappel();
      }
    break;

    case PRISE_MEDOC:
        if(!nbRappels)
          tournerRoues();
        lastMsg = millis();
        nbRappels++;
        EtatCourant = MEDOC_NON_PRIS;
        Serial.print("Premier Passage dans Prise_medoc, nbRappels = ");
        Serial.println(nbRappels);
      
    break;

    case MEDOC_PRIS:
      EtatCourant = ATT_PRISE;
      nbRappels = 0;
      medocPris = false;
      PassageUnefois = false;
      //Si medicament pris, passage a la prochaine periode
      switch (JourCourant){
        case MATIN:
          JourCourant = MIDI;
        break;
        case MIDI:
          JourCourant = SOIR;
        break;
        case SOIR:
          JourCourant = MATIN;
        break;
        
    }
    break;

    case MEDOC_NON_PRIS:
        if(nbRappels > 3){
          contacterFamille();
          EtatCourant = MEDOC_PRIS;
        }
        actionsDeRappel();//Clignoter les leds, buzzer ?
        checkPrise();
            
    break;
    
  }
  
}
void verifConteneur(){
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed. If it is, the buttonState is HIGH:
  if (buttonState == LOW) {
      medocPris = true;
      Serial.println("Medoc Pris");
  } else {
    // turn LED off:
    medocPris = false;
  }
}


// Il faudrait faire une fonction qui dit à quel periode de la journée on est au tout premier lancement de l'appli/pilulier apres la configuration

void loop() {
  machineEtat();
  if(nbRappels)
    verifConteneur();
  //Ajouter fonction qui verifie que le conteneur de medicament a ete pris
  if (!client.loop()) {
    mqttConnect();
  }
  
}

Credits

Shagufta

Shagufta

1 project • 1 follower
Souleymane

Souleymane

1 project • 1 follower
Kevin Vu

Kevin Vu

1 project • 0 followers
Thanks to François Pêcheux and Nicolas Grimmer.

Comments