#include <Wire.h>
#include <RTClib.h>
#include "HX711.h"
#define STEP_PIN 14
#define DIR_PIN 12
#define LED_PIN 25
#define BUZZER_PIN 26
#define HX711_DT 32
#define HX711_SCK 33
RTC_DS1307 rtc;
HX711 scale;
const int STEPS_PER_POSITION = 50;
const long WEIGHT_CHANGE_THRESHOLD = 50;
const char* names[4] = {
"Morning", "Afternoon", "Evening", "Night"
};
int doseHour[4];
int doseMinute[4];
bool doseTriggered[4] = {false, false, false, false};
int currentPosition = 0;
int inputCompartment = 0;
String timeInput = "";
bool dosePending = false;
bool repeatAlarmDone = false;
bool alarmActive = false;
bool repeatAlarmActive = false;
bool weightBaselineSet = false;
long baselineWeight = 0;
unsigned long doseStart = 0;
unsigned long alarmStart = 0;
unsigned long lastWeightPrint = 0;
void moveMotor(int steps, bool direction) {
digitalWrite(DIR_PIN, direction);
for (int i = 0; i < steps; i++) {
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds(1000);
digitalWrite(STEP_PIN, LOW);
delayMicroseconds(1000);
}
}
void startBuzzer(bool repeat) {
tone(BUZZER_PIN, 2000);
alarmStart = millis();
alarmActive = true;
repeatAlarmActive = repeat;
}
void stopBuzzer() {
noTone(BUZZER_PIN);
alarmActive = false;
repeatAlarmActive = false;
}
void startDose(int i) {
Serial.print("Dose due: ");
Serial.println(names[i]);
int movements = (i - currentPosition + 4) % 4;
moveMotor(movements * STEPS_PER_POSITION, HIGH);
currentPosition = i;
digitalWrite(LED_PIN, HIGH);
if (scale.is_ready()) {
baselineWeight = scale.read();
weightBaselineSet = true;
Serial.print("Baseline weight reading: ");
Serial.println(baselineWeight);
} else {
weightBaselineSet = false;
Serial.println("HX711 not ready. Weight detection unavailable.");
}
dosePending = true;
repeatAlarmDone = false;
doseStart = millis();
startBuzzer(false);
Serial.println("Initial buzzer reminder: 1 minute.");
}
void setup() {
Serial.begin(115200);
Wire.begin(21, 22);
pinMode(STEP_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
noTone(BUZZER_PIN);
if (!rtc.begin()) {
Serial.println("RTC not detected!");
while (true) {
delay(100);
}
}
scale.begin(HX711_DT, HX711_SCK);
Serial.println("SMART MEDICINE BOX");
Serial.println("Enter dose times in 24-hour HH:MM format.");
Serial.println("Compartment 1 - Morning: enter time.");
}
void loop() {
while (Serial.available()) {
char c = Serial.read();
if (c == '\n' || c == '\r') {
if (timeInput.length() > 0) {
int colon = timeInput.indexOf(':');
if (colon > 0 && inputCompartment < 4) {
int h = timeInput.substring(0, colon).toInt();
int m = timeInput.substring(colon + 1).toInt();
if (h >= 0 && h <= 23 && m >= 0 && m <= 59) {
doseHour[inputCompartment] = h;
doseMinute[inputCompartment] = m;
Serial.print(names[inputCompartment]);
Serial.print(" time saved: ");
Serial.println(timeInput);
inputCompartment++;
timeInput = "";
if (inputCompartment < 4) {
Serial.print("Enter ");
Serial.print(names[inputCompartment]);
Serial.println(" time:");
} else {
Serial.println("All four times saved. Schedule active.");
}
} else {
Serial.println("Invalid time. Use HH:MM.");
timeInput = "";
}
} else {
Serial.println("Invalid input.");
timeInput = "";
}
}
} else if ((c >= '0' && c <= '9') || c == ':') {
timeInput += c;
}
}
// End the initial buzzer after 1 minute.
if (alarmActive && !repeatAlarmActive &&
millis() - alarmStart >= 60000UL) {
stopBuzzer();
Serial.println("Initial buzzer stopped. LED remains on.");
}
// End the repeat buzzer after 2 minutes.
if (alarmActive && repeatAlarmActive &&
millis() - alarmStart >= 120000UL) {
stopBuzzer();
Serial.println("Repeat buzzer stopped. Still monitoring.");
}
// Check for medicine collection by detecting a weight decrease.
if (dosePending && weightBaselineSet && scale.is_ready()) {
long currentWeight = scale.read();
long decrease = baselineWeight - currentWeight;
if (millis() - lastWeightPrint >= 1000) {
Serial.print("Baseline: ");
Serial.print(baselineWeight);
Serial.print(" | Current: ");
Serial.print(currentWeight);
Serial.print(" | Decrease: ");
Serial.println(decrease);
lastWeightPrint = millis();
}
if (decrease >= WEIGHT_CHANGE_THRESHOLD) {
dosePending = false;
weightBaselineSet = false;
digitalWrite(LED_PIN, LOW);
stopBuzzer();
Serial.println("Weight decrease detected.");
Serial.println("Dose marked as collected. LED OFF.");
}
}
// Repeat reminder after 30 minutes if the dose is still pending.
if (dosePending && !repeatAlarmDone &&
millis() - doseStart >= 1800000UL) {
repeatAlarmDone = true;
startBuzzer(true);
Serial.println("Dose still pending after 30 minutes.");
Serial.println("Repeat buzzer will sound for 2 minutes.");
}
// Check the four scheduled dose times.
if (inputCompartment == 4 && !dosePending) {
DateTime now = rtc.now();
for (int i = 0; i < 4; i++) {
if (now.hour() == doseHour[i] &&
now.minute() == doseMinute[i] &&
!doseTriggered[i]) {
doseTriggered[i] = true;
startDose(i);
break;
}
}
}
delay(100);
}