#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHTesp.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <WiFiUdp.h>
#include <ESP32Servo.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
#define BUZZER 5
#define LED_1 15
#define PB_CANCEL 34
#define PB_OK 26
#define PB_UP 27
#define PB_DOWN 35
#define DHTPIN 12
//changed accordingly
#define NTP_SERVER "pool.ntp.org"
int UTC_OFFSET = 0;
#define UTC_OFFSET_DST 0
int c = 262;
int d = 294;
int e = 330;
int f = 349;
int g = 492;
int a = 440;
int b = 494;
int c_h = 523;
int notes[] = {c, d, e, f, g, a, b, c_h};
int n_Notes = 8;
int seconds = 0;
int minutes = 0;
int hours = 0;
int days = 0;
//variables for time zone setting
int offset[] = {0, 0} ;
int increment_hours = 5;
int increment_minutes = 30;
unsigned long timeNow = 0;
unsigned long timeLast = 0;
// changed the n alarms accordingly and hours and time
bool alarm_enabled = true;
int n_alarms = 3;
int alarm_hours[] = {20, 0, 0};
int alarm_minutes[] = {27, 0, 0};
bool alarm_triggered[] = {false, false, false};
//menu options
//these are changed acrrordingly to add another alarm
int current_mode = 0;
int max_modes = 5; //max no of modes
String modes[] = {"1 - Set Time Zone", "2 - Set Alarm 1", "3 - Set Alarm 2", "4 - Set Alarm 3", "5 - Disable Alarms" };
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET );
DHTesp dhtSensor;
//new
#include <cstdlib>
WiFiClient espClient;
PubSubClient mqttClient(espClient);
int analogValueLeft = 0;
#define LDRL_PIN 32
#define LDRR_PIN 33
#define servoPin 18
char LDRLeftAr[6];
char LDRRightAr[6];
double minAngle = 30;
double controlFactor = 0;
double D = 0;
double I = 0;
double calulated = 0;
int brightnessL = 0;
int brightnessL1 = 0;
int brightnessR = 0;
int brightnessR1 = 0;
boolean calculate = false;
boolean calculate1 = false;
boolean calculate2 = false;
boolean previousState = false;
double I2 = 0;
boolean isDefined = true;
Servo servo;
int pos = 0;
int state = 0;
int previousState1 = 0;
int previousState2 = 0;
void setup() {
// put your setup code here, to run once:
pinMode(BUZZER, OUTPUT);
pinMode(LED_1, OUTPUT);
pinMode(PB_CANCEL, INPUT);
pinMode(PB_OK, INPUT);
pinMode(PB_UP, INPUT);
pinMode(PB_DOWN, INPUT);
dhtSensor.setup(DHTPIN, DHTesp::DHT22);
// initialize serial monitor and OLED display
Serial.begin(9600);
if (! display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
{
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
// turn on OLED display
display.display();
delay(2000);
WiFi.begin("Wokwi-GUEST", "", 6);
while (WiFi.status() != WL_CONNECTED) {
display.clearDisplay();
print_line("Connecting to WIFI", 0, 0, 2);
}
display.clearDisplay();
print_line("Connected to WIFI", 0, 0, 2);
display.clearDisplay();
print_line("Welcome to Medi Box!", 0, 0, 2);
display.clearDisplay();
delay(1000);
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
update_time();
print_time_now();
//new
setupMqtt();
servo.attach(servoPin, 500, 2400);
}
void loop() {
delay(10);
update_time_with_chech_alarm();
if (digitalRead(PB_OK) == LOW) {
delay(200);
go_to_menu();
}
//new
check_temp();
if (!mqttClient.connected()) {
connectToBroker();
}
mqttClient.loop();
updateLeftLDR();
updateRightLDR();
//Serial.print("L ");
//Serial.println(LDRLeftAr);
mqttClient.publish("210470C-LEFT-LDR", LDRLeftAr);
mqttClient.publish("210470C-RIGHT-LDR", LDRRightAr);
delay(1000);
if (isDefined){
state =0;
calulated = motorAngle1( 0.75, 30);
}
if (calculate and calculate1) {
if (calculate2){
state =0;
calulated = motorAngle1( controlFactor, minAngle);
//Serial.print("cal");
Serial.println(calulated);
}
}
if (previousState1!= floor(calulated)){
if(previousState1 < calulated){
controlMotor(calulated, previousState1);
}else{
reverseMotor(calulated, previousState1);
}
}
/*
if (!previousState && isCalculated){
controlMotor(calulated, pos, state);
}*/
}
//Added a set time zone function
void set_time_zone() {
int temp_offset_hours = increment_hours;
while (true) {
display.clearDisplay();
print_line("Enter offset hour : " + String(temp_offset_hours), 0, 0, 2);
int pressed = wait_for_button_press(); // when a button is pressed it is assigned to this
if (pressed == PB_UP) {
delay(200);
temp_offset_hours += 1;
temp_offset_hours = temp_offset_hours % 24;
}
else if (pressed == PB_DOWN) {
delay(200);
temp_offset_hours -= 1;
if (temp_offset_hours < -12) {
temp_offset_hours = 0;
}
}
else if (pressed == PB_OK) {
delay(200);
increment_hours = temp_offset_hours;
offset[0] = increment_hours;
break;
}
else if (pressed == PB_CANCEL) {
delay(200);
break;
}
}
int temp_offset_minutes = increment_minutes;
while (true) {
display.clearDisplay();
print_line("Enter minutes : " + String(temp_offset_minutes), 0, 0, 2);
int pressed = wait_for_button_press(); // when a button is pressed it is assigned to this
if (pressed == PB_UP) {
delay(200);
temp_offset_minutes += 1;
temp_offset_minutes = temp_offset_minutes % 60;
}
else if (pressed == PB_DOWN) {
delay(200);
temp_offset_minutes -= 1;
if (temp_offset_minutes < 0) {
temp_offset_minutes = 60;
}
}
else if (pressed == PB_OK) {
delay(200);
increment_minutes = temp_offset_minutes;
offset[1] = increment_minutes;
break;
}
else if (pressed == PB_CANCEL) {
delay(200);
break;
}
}
display.clearDisplay();
print_line("Time zone is SET", 0, 0, 2);
delay(1000);
}
void run_mode(int mode) {
if (mode == 0) {
set_time_zone();
UTC_OFFSET = 0;
// if the time zone is negative use a negative offset
if (offset[0] < 0 ) {
UTC_OFFSET = (UTC_OFFSET + (offset[0] * 60 * 60 - 1 * offset[1] * 60));
}
else {
UTC_OFFSET = UTC_OFFSET + (offset[0] * 60 * 60 + offset[1] * 60);
}
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
}
else if (mode == 1 || mode == 2 || mode == 3) {
//mode-1 is used as the index of the alarm array
set_alarm((mode - 1));
}
else if (mode == 4 ) {
alarm_enabled = false;
}
}
void check_temp() {
TempAndHumidity data = dhtSensor.getTempAndHumidity();
if (data.temperature >= 26 || data.temperature <= 32) {
//display.clearDisplay();
print_line("TEMP OK", 0, 40, 1);
delay(100);
}
else if (data.temperature < 26) {
print_warning("TEMP HIGH");
}
else if (data.temperature > 32) {
print_warning("TEMP HIGH");
}
if (data.humidity >= 60 || data.humidity <= 80) {
display.clearDisplay();
print_line("HUMID OK", 0, 50, 1);
delay(100);
}
else if (data.humidity < 60) {
print_warning("HUMID LOW");
}
else if (data.humidity > 80) {
print_warning("HUMID HIGH");
}
}
void print_warning(String message) {
display.clearDisplay();
digitalWrite(LED_1, HIGH);
print_line(message, 0, 0, 2);
delay(100);
digitalWrite(LED_1, LOW);
}
void print_line(String message, int column, int row, int text_size) {
//display.clearDisplay();
display.setTextSize(text_size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(column, row);
display.println(message);// display a custom message
display.display();
}
void print_time_now(void) {
display.clearDisplay();
print_line(String(days), 0, 0, 2);
print_line(":", 20, 0, 2);
print_line(String(hours), 30, 0, 2);
print_line(":", 50, 0, 2);
print_line(String(minutes), 60, 0, 2);
print_line(":", 80, 0, 2);
print_line(String(seconds), 90, 0, 2);
}
void update_time(void) {
struct tm timeinfo;
getLocalTime(&timeinfo);
char timeHour[3];
strftime(timeHour, 3, "%H", &timeinfo);
hours = atoi(timeHour);
char timeMinute[3];
strftime(timeMinute, 3, "%M", &timeinfo);
minutes = atoi(timeMinute);
char timeSecond[3];
strftime(timeSecond, 3, "%S", &timeinfo);
seconds = atoi(timeSecond);
char timeDay[3];
strftime(timeDay, 3, "%d", &timeinfo);
days = atoi(timeDay);
}
void ring_alarm(void) {
display.clearDisplay();
print_line("MEDICINE TIME", 0, 0, 2);
digitalWrite(LED_1, HIGH);
bool break_happened = false;
//ring the buzzer
while (break_happened == false && digitalRead(PB_CANCEL) == HIGH) {
for (int i = 0; i < n_Notes; i++ ) {
if (digitalRead(PB_CANCEL) == LOW) {
delay(200);
break_happened = true;
break;
}
tone(BUZZER, notes[i]);
delay((500));
noTone(BUZZER);
delay((2));
}
}
digitalWrite(LED_1, LOW);
display.clearDisplay();
}
void update_time_with_chech_alarm(void) {
update_time();
print_time_now();
if (alarm_enabled == true) {
for (int i = 0; i < n_alarms; i++) {
if (alarm_triggered[i] == false && alarm_hours[i] == hours && alarm_minutes[i] == minutes) {
ring_alarm();
alarm_triggered[i] = true;
}
}
}
}
int wait_for_button_press() {
while (true) {
if (digitalRead(PB_UP) == LOW) {
delay(200);
return PB_UP;
}
else if (digitalRead(PB_DOWN) == LOW) {
delay(200);
return PB_DOWN;
}
else if (digitalRead(PB_OK) == LOW) {
delay(200);
return PB_OK;
}
else if (digitalRead(PB_CANCEL) == LOW) {
delay(200);
return PB_CANCEL;
}
update_time();
}
}
void go_to_menu(void) {
while (digitalRead(PB_CANCEL) == HIGH) {
display.clearDisplay();
print_line(modes[current_mode], 0, 0, 2);
int pressed = wait_for_button_press(); // when a button is pressed it is assigned to this
if (pressed == PB_UP) {
delay(200);
current_mode += 1;
current_mode = current_mode % max_modes;
}
else if (pressed == PB_DOWN) {
delay(200);
current_mode -= 1;
if (current_mode < 0) {
current_mode = max_modes - 1;
}
}
else if (pressed == PB_OK) {
delay(200);
run_mode(current_mode);
}
else if (pressed == PB_CANCEL) {
delay(200);
break;
}
}
}
void set_alarm(int alarm) {
int temp_hours = alarm_hours[alarm];
while (true) {
display.clearDisplay();
print_line("Enter hour : " + String(temp_hours), 0, 0, 2);
int pressed = wait_for_button_press(); // when a button is pressed it is assigned to this
if (pressed == PB_UP) {
delay(200);
temp_hours += 1;
temp_hours = temp_hours % 24;
}
else if (pressed == PB_DOWN) {
delay(200);
temp_hours -= 1;
if (temp_hours < 0) {
temp_hours = 23;
}
}
else if (pressed == PB_OK) {
delay(200);
alarm_hours[alarm] = temp_hours;
break;
}
else if (pressed == PB_CANCEL) {
delay(200);
break;
}
}
int temp_minutes = alarm_minutes[alarm];
while (true) {
display.clearDisplay();
print_line("Enter minutes : " + String(temp_minutes), 0, 0, 2);
int pressed = wait_for_button_press(); // when a button is pressed it is assigned to this
if (pressed == PB_UP) {
delay(200);
temp_minutes += 1;
temp_minutes = temp_minutes % 60;
}
else if (pressed == PB_DOWN) {
delay(200);
temp_minutes -= 1;
if (temp_minutes < 0) {
temp_minutes = 59;
}
}
else if (pressed == PB_OK) {
delay(200);
alarm_minutes[alarm] = temp_minutes;
break;
}
else if (pressed == PB_CANCEL) {
delay(200);
break;
}
alarm_triggered[alarm] = false;
}
display.clearDisplay();
print_line("Alarm is SET", 0, 0, 2);
delay(1000);
}
//new
void setupMqtt() {
mqttClient.setServer("test.mosquitto.org", 1883);
mqttClient.setCallback(receiveCallback); //to handle incoming messages
}
void receiveCallback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("]");
String Aa = "";
char payloadCharAr[length]; //varibale to store incoming data
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
payloadCharAr[i] = (char)payload[i];
Aa += (char)payload[i];
}
Serial.println();
if (strcmp(topic, "210470C-min") == 0) {
isDefined = false;
calculate1 = true;
minAngle = std::atof(payloadCharAr);
}
if (strcmp(topic, "210470C-cf") == 0) {
calculate2 = true;
controlFactor = std::atof(payloadCharAr);
}
if (strcmp(topic, "210470C-A") == 0) {
//state = 0;
calculate1 = false;
calculate2 = false;
calculate = true;
I = Aa.toDouble();
} else if (strcmp(topic, "210470C-B") == 0) {
//state = 0;
calculate1 = false;
calculate2 = false;
calculate = true;
I = Aa.toDouble();
} else if (strcmp(topic, "210470C-C") == 0) {
//state = 0;
calculate1 = false;
calculate2 = false;
calculate = true;
I = Aa.toDouble();
} else if (strcmp(topic, "210470C-D") == 0) {
//state = 0;
calculate1 = false;
calculate2 = false;
calculate = true;
I = Aa.toDouble();
}
//buzzerOn(payloadCharAr[0]=='1'); //same as above code
}
void connectToBroker() {
while (!mqttClient.connected()) {
Serial.println("Attempting MQTT connection.....");
//if we don't want authentication, we can have any random name
if (mqttClient.connect("ESP32-665959999")) {
Serial.println("Connected");
mqttClient.subscribe("210470C-A");
mqttClient.subscribe("210470C-B");
mqttClient.subscribe("210470C-C");
mqttClient.subscribe("210470C-D");
mqttClient.subscribe("210470C-min");
mqttClient.subscribe("210470C-cf");
//mqttClient.subscribe("ENTC-ADMIN-SCH-ON123");
} else {
Serial.println("Failed");
Serial.print(mqttClient.state());
delay(5000);
}
}
}
void updateLeftLDR() {
analogValueLeft = 4063-analogRead(LDRL_PIN);
brightnessL = map(analogValueLeft, 32, 4063, 0, 1023);
brightnessL1 = map(analogValueLeft, 0, 1023, 0, 1);
dtostrf(brightnessL, 0, 0, LDRLeftAr);
}
void updateRightLDR() {
int analogValueRight = 4063-analogRead(LDRR_PIN);
brightnessR = map(analogValueRight, 32, 4063, 0, 1023);
brightnessR1 = map(analogValueRight, 0, 1023, 0, 1);
dtostrf(brightnessR, 0, 0, LDRRightAr);
}
double motorAngle1(double controlFactor,double minAngle) {
/*
minAngle = 30;
controlFactor = 0.2;*/
if (brightnessR1 < brightnessL1) {
D = 1.5;
I2=brightnessL1 ;
} else {
D = 0.5;
I2 = brightnessR1;
}
calulated = minAngle * D + (180 - minAngle) * I2 * controlFactor;
if (calulated > 180) {
calulated = 180;
}
return calulated;
}
void controlMotor(double calulated, double previousAngle){
for (int pos = previousAngle; pos <= calulated; pos += 1) {
servo.write(pos);
previousState1 = pos;
delay(10);
}
Serial.println(previousState1);
previousState = true;
}
void reverseMotor(double position, double angle){
for (int pos2 = angle; pos2 >position; pos2 -= 1) {
servo.write(pos2);
previousState1 = pos2;
delay(10);
}
}