Gayathri Krishnan
Published © GPL3+

ESP32 Web‑Configurable Medicine Reminder with SMS Alerts

A web‑configurable ESP32 system with RTC and Twilio integration that sends SMS reminders to improve medication adherence.

IntermediateWork in progress2 hours59
ESP32 Web‑Configurable Medicine Reminder with SMS Alerts

Things used in this project

Hardware components

DS3231M MEMS Precise RTC
DFRobot DS3231M MEMS Precise RTC
×1
Jumper wires (generic)
Jumper wires (generic)
×1
ESP32
Espressif ESP32
×1

Software apps and online services

SMS Messaging API
Twilio SMS Messaging API

Story

Read more

Schematics

RTC Module Pin Connections (DS3231)

// This table shows the pin mapping between the ESP32 and DS3231 RTC module.

// No additional components are required for the RTC connection.

Code

ESP32 _MEDICINE _REMAINDER_SMS

Arduino
//Create a Twilio account and get your Account SID, Auth Token, and phone number.
// Replace these details in the code before uploading to the ESP32.
// Configure medicine name, time, and instructions via the web interface.
// The ESP32 will send SMS reminders at the scheduled time using Twilio.
#include <WiFi.h>       // ESP32 WiFi library; needed to connect to the internet.
#include <HTTPClient.h> // for sending HTTP/HTTPS requests
#include <Wire.h>       // for I2C communication
#include "RTClib.h"     //  library for DS3231 RTC
#include <WiFiClientSecure.h> // handles secure HTTPS connections for Twilio.
#include <Arduino.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>


AsyncWebServer server(80);
const char* ssid = "YOUR_WIFI_NETWORK";
const char* password = "YOUR_WIFI_PASSWORD";


const char* PARAM_INPUT_1="input1";
const char* PARAM_INPUT_2="input2";
const char* PARAM_INPUT_3="input3";
const char* PARAM_OTHER="othermed";


const char* accountSid = "YOUR_ACCOUNT_SID";
const char* authToken  = "YOUR_AUTH_TOKEN";
const char* fromNumber = "+YOUR_TWILIO_NUMBER";   // include +
const char* toNumber   = "+YOUR_PHONE_NUMBER";         // include +,country code

RTC_DS3231 rtc;   

bool sendSMS();

String med = "";
String instr = "";
int alarmHour = -1;
int alarmMinute = -1;
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html>
<head>
  <title>ESP Input Form</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script>
    function handleMedChange(selectElem) {
      var otherInput = document.getElementById('otherMedInput');

      if (selectElem.value === 'Other') {
        otherInput.style.display = 'inline';
        otherInput.required = true;
      } else {
        otherInput.style.display = 'none';
        otherInput.required = false;
      }
    }
  </script>
</head>
<body>
  <h2>Medicine Reminder</h2>

  <form action="/get" method="GET"> // creating drop down list of medicine
    <!-- Medicine name -->
    medname:
    <select name="input1" onchange="handleMedChange(this)">
      <option value="">-- Select medicine --</option>
      <option value="Metformin">Metformin</option>
      <option value="Insulin">Insulin</option>
      <option value="Aspirin">Aspirin</option>
      <option value="Atorvastatin">Atorvastatin</option>
      <option value="Metoprolol">Metoprolol</option>
      <option value="levothyroxine">levothyroxine</option>
      <option value="Other">Other</option>
    </select>

    <input
      type="text"
      id="otherMedInput"
      name="otherMed"
      placeholder="Enter medicine name"
      style="display:none; margin-left:8px;"
    >

    <br><br>

    <!-- Time -->
    Time:
    <input type="time" name="input2"> //input 2 =time

    <br><br>

    <!-- Instructions -->
    Instructions:                   //input3=dropdown list of instructions
    <select name="input3">
      <option value="">-- Select instruction --</option>
      <option value="before food">Before food</option>
      <option value="after food">After food</option>
      <option value="on empty stomach">Empty stomach</option>
      <option value=" at bedtime">At bedtime</option>
    </select>

    <br><br>

    <input type="submit" value="enter">
  </form>
</body>
</html>
)rawliteral";
void notFound(AsyncWebServerRequest *request){
  request->send(404, "text/plain", "Not found");

}





void setup() {
  // put your setup code here, to run once:
Serial.begin(115200);
  Wire.begin();

  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

   rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 


WiFi.mode(WIFI_STA);
WiFi.begin(ssid,password);
if (WiFi.waitForConnectResult()!=WL_CONNECTED){
  Serial.print("WiFi failed");
  return;
}
Serial.println();
Serial.print("IP adddress:  ");
Serial.println(WiFi.localIP());

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html);
  });
server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
    
    String timeStr = "";
    
    // GET input1 value on <ESP_IP>/get?input1=<inputMessage>
    if (request->hasParam(PARAM_INPUT_1)) {
      med = request->getParam(PARAM_INPUT_1)->value();
    }
    if (med == "Other" && request->hasParam(PARAM_OTHER)) {
      med = request->getParam(PARAM_OTHER)->value();
    }

    if (request->hasParam(PARAM_INPUT_2)) {
  String timeStr = request->getParam(PARAM_INPUT_2)->value(); //6:00
  int colonIndex = timeStr.indexOf(':');
  if (colonIndex != -1) {
    alarmHour = timeStr.substring(0, colonIndex).toInt();     //6   
    alarmMinute = timeStr.substring(colonIndex + 1).toInt();   //0  
  }
}

    if (request->hasParam(PARAM_INPUT_3)) {
      instr = request->getParam(PARAM_INPUT_3)->value();
    }
Serial.println("----- New entry -----");
    Serial.println("Medicine: " + med);
    Serial.println("Time: " + timeStr);
    Serial.println("Hour: " + String(alarmHour) + ", Minute: " + String(alarmMinute)); 
    Serial.println("Instructions (raw): " + instr);
    Serial.println("---------------------");

    String response = "Medicine reminder saved:<br>";
    response += "Medicine: " + med + "<br>";
    response += "Time: " + timeStr + "<br>";
    response += "Instructions: " + instr + "<br><br>";
    response += "<a href=\"/\">Return to Home Page</a>";

    request->send(200, "text/html", response);
  });
   server.onNotFound(notFound);
  server.begin();
}



void loop() {
  
 DateTime now = rtc.now();
  int currentHour = now.hour();
  int currentMinute = now.minute();
  int currentSecond = now.second();


  Serial.printf("Time: %02d:%02d:%02d\n", currentHour, currentMinute, currentSecond);
Serial.print("Alarm set to: ");
  Serial.print(alarmHour);
  Serial.print(":");
  Serial.println(alarmMinute);



  if (alarmHour != -1 && alarmMinute != -1) {   // only if user set a time
  if (currentHour == alarmHour && currentMinute == alarmMinute && currentSecond < 10) {
    Serial.println(" Alarm matched, calling sendSMS()");
    bool ok = sendSMS();        
    if (ok) {
      Serial.println("sendSMS() reported success.");
    } else {
      Serial.println("sendSMS() reported failure.");
    }
    delay(60000); // wait a minute so it doesn't spam
  }
}

delay(10000); // check every 10 seconds



}
 
  bool sendSMS(){
    Serial.println("sendSMS() called");
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("WiFi not connected");
    return false;
  }
  Serial.print("med = ");
  Serial.println(med);
  Serial.print("instr = ");
  Serial.println(instr);
String messageBody = "Take " + med + " " + instr; 

Serial.print("Final SMS text: ");
  Serial.println(messageBody);
 
  
  WiFiClientSecure client;
  client.setInsecure(); 
  HTTPClient https;
  String url = "https://api.twilio.com/2010-04-01/Accounts/" + String(accountSid) + "/Messages.json";

  if (!https.begin(client, url)) {
    Serial.println("HTTP begin failed");
    return false;
  }

  
  https.setAuthorization(accountSid, authToken);
  https.addHeader("Content-Type", "application/x-www-form-urlencoded");

  String body = "To=" + String(toNumber) + "&From=" + String(fromNumber) + "&Body=" + String(messageBody);

  int code = https.POST(body);

  if (code > 0) {
    String resp = https.getString();
    Serial.printf("HTTP %d\n%s\n", code, resp.c_str());
    https.end();
    return (code == 201 || code == 200);
  } else {
    Serial.printf("POST failed, error: %d\n", code);
    https.end();
    return false;
  }
}

Credits

Gayathri Krishnan
5 projects • 0 followers
I’m an MBBS doctor who has always been interested in physics, which led me into Arduino projects. I’ve been building for about three months

Comments