#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <SoftwareSerial.h>
//pin for 8x32 leds
#define MAX_DEVICES 12
#define CLK_PIN 13
#define DATA_PIN 11
#define CS_PIN 10
#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
//pin for ultrasonic
#define trigPin 5
#define echoPin 4
#define float_switch_1 12 //this is a trigger checker if sesnor reading is correct
#define float_switch_2 9 //this is a trigger checker if sesnor reading is correct
#define float_switch_3 6 //this is a trigger checker if sesnor reading is correct
char buffer[6];
const float dis_sens_gnd = 4.0; //actual distance from water ground to sensor location in ft
String numbers[] = {"1xxxxxxxxxxx", "2xxxxxxxxxxx", "3xxxxxxxxxxx"};
String mobileNumber[] = {""};
int count = 0;
int send_multiple = 0;
//float limits[] = {0.7, 1.1, 2.2}; //converted inch value to ft according to given limits
const float lowThreshold = 0.7; // Low level threshold
const float midThreshold = 1.1; // Mid level threshold
const float highThreshold = 2.2; // High level threshold
float prev_limit = 0;
float limit_now = 1;
bool send_sms = false;
bool send_sms_request = false;
String message = "";
String recieved_message = "";
String go_nogo = "";
bool lowAlertSent = false; // Flag for low level alert
bool midAlertSent = false; // Flag for mid level alert
bool highAlertSent = false; // Flag for high level alert
SoftwareSerial mySerial(7, 8);
void setup() {
mySerial.begin(115200);
P.begin();
P.displayText("Initializing...", PA_CENTER, 50, 0, PA_PRINT, PA_SCROLL_LEFT);
P.displayAnimate();
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(float_switch_1, INPUT_PULLUP);
pinMode(float_switch_2, INPUT_PULLUP);
pinMode(float_switch_3, INPUT_PULLUP);
Serial.begin(9600);
Serial.println(" ");
}
void loop() {
int float_s_1 = digitalRead(float_switch_1);
int float_s_2 = digitalRead(float_switch_2);
int float_s_3 = digitalRead(float_switch_3);
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH);
int distance_cm = duration * 0.034 / 2;
float distance_m = distance_cm * 0.01; // Convert to meters
float distance_ft = distance_cm * 0.0328084; // Convert to feet
//set to 0 if to avoid negative measurement
if (distance_ft > dis_sens_gnd) {
distance_ft = dis_sens_gnd;
}
float actual_water_level = dis_sens_gnd - distance_ft;
dtostrf(actual_water_level, 4, 1, buffer); // Convert the float to a string with 1 decimal place to fit iin display
if (actual_water_level >= highThreshold) {
go_nogo = "Not Passable";
} else if (actual_water_level >= midThreshold || actual_water_level <= lowThreshold) {
go_nogo = "Passable";
}
String water_level =go_nogo + " " + String(buffer) + " ft";
P.displayText(water_level.c_str(), PA_CENTER, 50, 0, PA_PRINT, PA_SCROLL_LEFT);
P.displayAnimate();
//if not sending check if level change
if (!send_sms && !send_sms_request) {
if (actual_water_level >= lowThreshold && actual_water_level < midThreshold && !lowAlertSent &&
!float_s_1 && float_s_2 && float_s_3) {
lowAlertSent = true;
midAlertSent = false;
send_sms = true;
message = "Low Level Alert! " + water_level;
} else if (actual_water_level >= midThreshold && actual_water_level < highThreshold && !midAlertSent &&
!float_s_1 && !float_s_2 && float_s_3) {
midAlertSent = true;
lowAlertSent = false;
highAlertSent = false;
send_sms = true;
message = "Mid Level Alert! " + water_level;
} else if (actual_water_level >= highThreshold && !highAlertSent &&
!float_s_1 && !float_s_2 && !float_s_3) {
highAlertSent = true;
midAlertSent = false;
send_sms = true;
message = "High Level Alert! " + water_level;
}
}
//waits and read incomming message
while (mySerial.available()) {
char c = mySerial.read();
recieved_message += c;
delay(2);
}
//set all to lower case and send message if data is true
if (recieved_message.length() > 0) {
recieved_message.toLowerCase(); // Convert the string to lowercase
if (recieved_message.indexOf("request") != -1) {
mobileNumber[0] = extractMobileNumber(recieved_message);
send_sms_request = true;
}
recieved_message = "";
}
//just sending message
if (send_sms) {
// Serial.println(message);
//delay(5000);
count = sizeof(numbers) / sizeof(numbers[0]);
Send(message, send_sms, numbers, count);
} else if (send_sms_request) {
message = "Current data is at " + water_level;
count = sizeof(mobileNumber) / sizeof(mobileNumber[0]);
Send(message, send_sms_request, mobileNumber, count);
}
}
//send the message function
void Send(String text, bool &stats, String main_number[], int counts) {
//static int counts = sizeof(main_number) / sizeof(main_number[0]);
//Serial.print(counts);
static word startTimer, waitTimer; // waitTimer > 0 causes the timer to run, good up to 65 second intervals
static byte procState;
String phone = main_number[send_multiple];
if (waitTimer > 0) {
if (word(millis()) - startTimer < waitTimer) return; // time is not up yet
else waitTimer = 0; // and on to the switch-case
}
switch (procState) {
case 0:
mySerial.println("AT+CMGF=1"); // Set SMS Text Mode
procState = 1; // run case 1 next time
waitTimer = 1000;
startTimer = millis();
Serial.println("set gms to send mode");
break;
case 1:
mySerial.println("AT+CSCS=\"GSM\""); //
procState = 2; // run case 2 next time
waitTimer = 1000;
startTimer = millis();
Serial.println("AT command for send txt");
break;
case 2:
mySerial.println("AT+CMGS=\"" + phone + "\""); // send to desired phone
procState = 3; // run case 3 next time
waitTimer = 1000;
startTimer = millis();
Serial.println(phone);
Serial.println("AT command for receiver number");
break;
case 3:
mySerial.print("\"" + text + "\""); // containing desired text
procState = 4; // run case 4 next time
waitTimer = 1000;
startTimer = millis();
Serial.println("AT command for message contain");
Serial.println("message --------------------------\n");
Serial.println(text);
Serial.print("\n");
Serial.println("message --------------------------");
break;
case 4:
mySerial.print((char)26); // signals end of text message
procState = 0; // run case 0 next time
waitTimer = 500;
startTimer = millis();
Serial.println("sent");
if (counts - 1 - send_multiple == 0) {
stats = !stats;
send_multiple += 1;
Serial.print("finished sending ");
Serial.println(send_multiple);
send_multiple = 0;
} else {
send_multiple += 1;
Serial.print("still sending ");
Serial.println(send_multiple);
}
break;
}
}
//get mobile number of requestor in country format
String extractMobileNumber(String input) {
String result = "";
for (int i = 0; i < input.length(); i++) {
if (input.charAt(i) == '+' && i < input.length() - 10) {
if (input.charAt(i + 1) == '6' && input.charAt(i + 2) == '3') {
String potentialNumber = input.substring(i + 1, i + 13); // Exclude the '+' character
bool valid = true;
// Check if potentialNumber contains only digits
for (int j = 0; j < potentialNumber.length(); j++) {
if (!isDigit(potentialNumber.charAt(j))) {
valid = false;
break;
}
}
if (valid) {
result = "+" + potentialNumber;
break;
}
}
}
}
return result;
}