-
-
Save m1cr0lab/365858ec1ac4976c2efedf2a11f7777b to your computer and use it in GitHub Desktop.
/********* | |
Rui Santos | |
Complete project details at https://RandomNerdTutorials.com/esp32-email-alert-temperature-threshold/ | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files. | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
*********/ | |
#include <WiFi.h> | |
#include <AsyncTCP.h> | |
#include <ESPAsyncWebServer.h> | |
#include <OneWire.h> | |
#include <DallasTemperature.h> | |
#include "ESP32_MailClient.h" | |
// REPLACE WITH YOUR NETWORK CREDENTIALS | |
const char* ssid = "REPLACE_WITH_YOUR_SSID"; | |
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; | |
// To send Email using Gmail use port 465 (SSL) and SMTP Server smtp.gmail.com | |
// YOU MUST ENABLE less secure app option https://myaccount.google.com/lesssecureapps?pli=1 | |
#define emailSenderAccount "example_sender_account@gmail.com" | |
#define emailSenderPassword "email_sender_password" | |
#define smtpServer "smtp.gmail.com" | |
#define smtpServerPort 465 | |
#define emailSubject "[ALERT] ESP32 Temperature" | |
// Default Recipient Email Address | |
String inputMessage = "your_email_recipient@gmail.com"; | |
String enableEmailChecked = "checked"; | |
String inputMessage2 = "true"; | |
// Default Temperature Thresholds | |
String inputMessage3 = "25.0"; | |
String inputMessage4 = "6.0"; | |
String lastTemperature; | |
// HTML web page to handle 3 input fields (email_input, enable_email_input, threshold_input) | |
const char index_html[] PROGMEM = R"rawliteral( | |
<!DOCTYPE HTML><html><head> | |
<title>Email Notification with Temperature</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
</head><body> | |
<h2>DS18B20 Temperature</h2> | |
<h3>%TEMPERATURE% °C</h3> | |
<h2>ESP Email Notification</h2> | |
<form action="/get"> | |
Email Address <input type="email" name="email_input" value="%EMAIL_INPUT%" required><br> | |
Enable Email Notification <input type="checkbox" name="enable_email_input" value="true" %ENABLE_EMAIL%><br> | |
Upper Temperature Threshold <input type="number" step="0.1" name="upper_threshold_input" value="%UPPER_THRESHOLD%" required><br> | |
Lower Temperature Threshold <input type="number" step="0.1" name="lower_threshold_input" value="%LOWER_THRESHOLD%" required><br> | |
<input type="submit" value="Submit"> | |
</form> | |
</body></html>)rawliteral"; | |
void notFound(AsyncWebServerRequest *request) { | |
request->send(404, "text/plain", "Not found"); | |
} | |
AsyncWebServer server(80); | |
// Replaces placeholder with DS18B20 values | |
String processor(const String& var){ | |
//Serial.println(var); | |
if(var == "TEMPERATURE"){ | |
return lastTemperature; | |
} | |
else if(var == "EMAIL_INPUT"){ | |
return inputMessage; | |
} | |
else if(var == "ENABLE_EMAIL"){ | |
return enableEmailChecked; | |
} | |
else if(var == "UPPER_THRESHOLD"){ | |
return inputMessage3; | |
} | |
else if(var == "LOWER_THRESHOLD"){ | |
return inputMessage4; | |
} | |
return String(); | |
} | |
// Flag variable to keep track if email notification was sent or not | |
bool emailSent = false; | |
const char* PARAM_INPUT_1 = "email_input"; | |
const char* PARAM_INPUT_2 = "enable_email_input"; | |
const char* PARAM_INPUT_3 = "upper_threshold_input"; | |
const char* PARAM_INPUT_4 = "lower_threshold_input"; | |
// Interval between sensor readings. Learn more about timers: https://RandomNerdTutorials.com/esp32-pir-motion-sensor-interrupts-timers/ | |
unsigned long previousMillis = 0; | |
const long interval = 5000; | |
// GPIO where the DS18B20 is connected to | |
const int oneWireBus = 4; | |
// Setup a oneWire instance to communicate with any OneWire devices | |
OneWire oneWire(oneWireBus); | |
// Pass our oneWire reference to Dallas Temperature sensor | |
DallasTemperature sensors(&oneWire); | |
// The Email Sending data object contains config and data to send | |
SMTPData smtpData; | |
void setup() { | |
Serial.begin(115200); | |
WiFi.mode(WIFI_STA); | |
WiFi.begin(ssid, password); | |
if (WiFi.waitForConnectResult() != WL_CONNECTED) { | |
Serial.println("WiFi Failed!"); | |
return; | |
} | |
Serial.println(); | |
Serial.print("ESP IP Address: http://"); | |
Serial.println(WiFi.localIP()); | |
// Start the DS18B20 sensor | |
sensors.begin(); | |
// Send web page to client | |
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ | |
request->send_P(200, "text/html", index_html, processor); | |
}); | |
// Receive an HTTP GET request at <ESP_IP>/get?email_input=<inputMessage>&enable_email_input=<inputMessage2>&threshold_input=<inputMessage3> | |
server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) { | |
// GET email_input value on <ESP_IP>/get?email_input=<inputMessage> | |
if (request->hasParam(PARAM_INPUT_1)) { | |
inputMessage = request->getParam(PARAM_INPUT_1)->value(); | |
// GET enable_email_input value on <ESP_IP>/get?enable_email_input=<inputMessage2> | |
if (request->hasParam(PARAM_INPUT_2)) { | |
inputMessage2 = request->getParam(PARAM_INPUT_2)->value(); | |
enableEmailChecked = "checked"; | |
} | |
else { | |
inputMessage2 = "false"; | |
enableEmailChecked = ""; | |
} | |
// GET threshold_input value on <ESP_IP>/get?upper_threshold_input=<inputMessage3> | |
if (request->hasParam(PARAM_INPUT_3)) { | |
inputMessage3 = request->getParam(PARAM_INPUT_3)->value(); | |
} | |
// GET threshold_input value on <ESP_IP>/get?lower_threshold_input=<inputMessage3> | |
if (request->hasParam(PARAM_INPUT_4)) { | |
inputMessage4 = request->getParam(PARAM_INPUT_4)->value(); | |
} | |
} | |
else { | |
inputMessage = "No message sent"; | |
} | |
Serial.println(inputMessage); | |
Serial.println(inputMessage2); | |
Serial.println(inputMessage3); | |
Serial.println(inputMessage4); | |
request->send(200, "text/html", "HTTP GET request sent to your ESP.<br><a href=\"/\">Return to Home Page</a>"); | |
}); | |
server.onNotFound(notFound); | |
server.begin(); | |
} | |
void loop() { | |
unsigned long currentMillis = millis(); | |
if (currentMillis - previousMillis >= interval) { | |
previousMillis = currentMillis; | |
sensors.requestTemperatures(); | |
// Temperature in Celsius degrees | |
float temperature = sensors.getTempCByIndex(0); | |
Serial.print(temperature); | |
Serial.println(" *C"); | |
// Temperature in Fahrenheit degrees | |
/*float temperature = sensors.getTempFByIndex(0); | |
SerialMon.print(temperature); | |
SerialMon.println(" *F");*/ | |
lastTemperature = String(temperature); | |
// Check if temperature is above threshold and if it needs to send the Email alert | |
if(temperature > inputMessage3.toFloat() && inputMessage2 == "true" && !emailSent){ | |
String emailMessage = String("Temperature above threshold. Current temperature: ") + | |
String(temperature) + String("C"); | |
if(sendEmailNotification(emailMessage)) { | |
Serial.println(emailMessage); | |
emailSent = true; | |
} | |
else { | |
Serial.println("Email failed to send"); | |
} | |
} | |
// Check if temperature is below threshold and if it needs to send the Email alert | |
else if((temperature < inputMessage4.toFloat()) && inputMessage2 == "true" && emailSent) { | |
String emailMessage = String("Temperature below threshold. Current temperature: ") + | |
String(temperature) + String(" C"); | |
if(sendEmailNotification(emailMessage)) { | |
Serial.println(emailMessage); | |
emailSent = false; | |
} | |
else { | |
Serial.println("Email failed to send"); | |
} | |
} | |
} | |
} | |
bool sendEmailNotification(String emailMessage){ | |
// Set the SMTP Server Email host, port, account and password | |
smtpData.setLogin(smtpServer, smtpServerPort, emailSenderAccount, emailSenderPassword); | |
// For library version 1.2.0 and later which STARTTLS protocol was supported,the STARTTLS will be | |
// enabled automatically when port 587 was used, or enable it manually using setSTARTTLS function. | |
//smtpData.setSTARTTLS(true); | |
// Set the sender name and Email | |
smtpData.setSender("ESP32", emailSenderAccount); | |
// Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest) | |
smtpData.setPriority("High"); | |
// Set the subject | |
smtpData.setSubject(emailSubject); | |
// Set the message with HTML format | |
smtpData.setMessage(emailMessage, true); | |
// Add recipients | |
smtpData.addRecipient(inputMessage); | |
smtpData.setSendCallback(sendCallback); | |
// Start sending Email, can be set callback function to track the status | |
if (!MailClient.sendMail(smtpData)) { | |
Serial.println("Error sending Email, " + MailClient.smtpErrorReason()); | |
return false; | |
} | |
// Clear all data from Email object to free memory | |
smtpData.empty(); | |
return true; | |
} | |
// Callback function to get the Email sending status | |
void sendCallback(SendStatus msg) { | |
// Print the current status | |
Serial.println(msg.info()); | |
// Do something when complete | |
if (msg.success()) { | |
Serial.println("----------------"); | |
} | |
} |
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "ESP32_MailClient.h"
// REPLACE WITH YOUR NETWORK CREDENTIALS
const char* ssid = "Home Wifi";
const char* password = "123456";
// To send Email using Gmail use port 465 (SSL) and SMTP Server smtp.gmail.com
// YOU MUST ENABLE less secure app option https://myaccount.google.com/lesssecureapps?pli=1
#define emailSenderAccount "building"
#define emailSenderPassword "123456"
#define smtpServer "smtp.gmail.com"
#define smtpServerPort 465
#define emailSubject "[ALERT] Building Loop Temperature"
// Default Recipient Email Address
String inputMessage = "lp14255@gmail.com";
String enableEmailChecked = "checked";
String inputMessage2 = "true";
// Default Temperature Thresholds
String inputMessage3 = "75";
String inputMessage4 = "72";
String lastTemperature;
// HTML web page to handle 3 input fields (email_input, enable_email_input, threshold_input)
const char index_html[] PROGMEM = R"rawliteral(
DS18B20 Temperature
%TEMPERATURE% °C
ESP Email Notification
Email AddressEnable Email Notification
Upper Temperature Threshold
Lower Temperature Threshold
Building Controls
%BUTTONPLACEHOLDER% <script>function toggleCheckbox(element) { var xhr = new XMLHttpRequest(); if(element.checked){ xhr.open("GET", "/update?output="+element.id+"&state=1", true); } else { xhr.open("GET", "/update?output="+element.id+"&state=0", true); } xhr.send(); } )rawliteral";void notFound(AsyncWebServerRequest *request) {
request->send(404, "text/plain", "Not found");
}
AsyncWebServer server(80);
// Replaces placeholder with DS18B20 values
String processor(const String& var){
//Serial.println(var);
if(var == "TEMPERATURE"){
return lastTemperature;
}
else if(var == "EMAIL_INPUT"){
return inputMessage;
}
else if(var == "ENABLE_EMAIL"){
return enableEmailChecked;
}
else if(var == "UPPER_THRESHOLD"){
return inputMessage3;
}
else if(var == "LOWER_THRESHOLD"){
return inputMessage4;
}
// Replaces placeholder with button section in your web page
if(var == "BUTTONPLACEHOLDER"){
String buttons = "";
buttons += "
Output - GPIO 2
<label class="switch"><input type="checkbox" onchange="toggleCheckbox(this)" id="2" " + outputState(2) + "><span class="slider">";buttons += "
Output - GPIO 4
<label class="switch"><input type="checkbox" onchange="toggleCheckbox(this)" id="4" " + outputState(4) + "><span class="slider">";buttons += "
Output - GPIO 33
<label class="switch"><input type="checkbox" onchange="toggleCheckbox(this)" id="33" " + outputState(33) + "><span class="slider">";return buttons;
}
return String();
}
String outputState(int output){
if(digitalRead(output)){
return "checked";
}
else {
return "";
}
}
// Flag variable to keep track if email notification was sent or not
bool emailSent = false;
const char* PARAM_INPUT_1 = "email_input";
const char* PARAM_INPUT_2 = "enable_email_input";
const char* PARAM_INPUT_3 = "upper_threshold_input";
const char* PARAM_INPUT_4 = "lower_threshold_input";
const char* PARAM_INPUT_5 = "output";
const char* PARAM_INPUT_6 = "state";
// Interval between sensor readings. Learn more about timers: https://RandomNerdTutorials.com/esp32-pir-motion-sensor-interrupts-timers/
unsigned long previousMillis = 0;
const long interval = 5000;
// GPIO where the DS18B20 is connected to
const int oneWireBus = 4;
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(oneWireBus);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);
// The Email Sending data object contains config and data to send
SMTPData smtpData;
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Failed!");
return;
}
Serial.println();
Serial.print("ESP IP Address: http://");
Serial.println(WiFi.localIP());
pinMode(2, OUTPUT);
digitalWrite(2, LOW);
pinMode(4, OUTPUT);
digitalWrite(4, LOW);
pinMode(33, OUTPUT);
digitalWrite(33, LOW);
// Start the DS18B20 sensor
sensors.begin();
// Send web page to client
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
// Receive an HTTP GET request at <ESP_IP>/get?email_input=&enable_email_input=&threshold_input=
server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
// GET email_input value on <ESP_IP>/get?email_input=
if (request->hasParam(PARAM_INPUT_1)) {
inputMessage = request->getParam(PARAM_INPUT_1)->value();
// GET enable_email_input value on <ESP_IP>/get?enable_email_input=
if (request->hasParam(PARAM_INPUT_2)) {
inputMessage2 = request->getParam(PARAM_INPUT_2)->value();
enableEmailChecked = "checked";
}
else {
inputMessage2 = "false";
enableEmailChecked = "";
}
// GET threshold_input value on <ESP_IP>/get?upper_threshold_input=
if (request->hasParam(PARAM_INPUT_3)) {
inputMessage3 = request->getParam(PARAM_INPUT_3)->value();
}
// GET threshold_input value on <ESP_IP>/get?lower_threshold_input=
if (request->hasParam(PARAM_INPUT_4)) {
inputMessage4 = request->getParam(PARAM_INPUT_4)->value();
}
}
else {
inputMessage = "No message sent";
}
// Send a GET request to <ESP_IP>/update?output=&state=
server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request) {
String inputMessage5;
String inputMessage6;
// GET input5 value on <ESP_IP>/update?output=&state=
if (request->hasParam(PARAM_INPUT_5) && request->hasParam(PARAM_INPUT_6)) {
inputMessage5 = request->getParam(PARAM_INPUT_5)->value();
inputMessage6 = request->getParam(PARAM_INPUT_6)->value();
digitalWrite(inputMessage5.toInt(), inputMessage6.toInt());
}
else {
inputMessage5 = "No message sent";
inputMessage6 = "No message sent";
}
Serial.println(inputMessage);
Serial.println(inputMessage2);
Serial.println(inputMessage3);
Serial.println(inputMessage4);
Serial.print("GPIO: ");
Serial.print(inputMessage5);
Serial.print(" - Set to: ");
Serial.println(inputMessage6);
request->send(200, "text/html", "HTTP GET request sent to your ESP.<br><a href=\"/\">Return to Home Page</a>");
});
server.onNotFound(notFound);
server.begin();
}
);
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
sensors.requestTemperatures();
// Temperature in Fahrenheit degrees
float temperature = sensors.getTempCByIndex(0);
Serial.print(temperature);
Serial.println(" *F");
// Temperature in Fahrenheit degrees
/*float temperature = sensors.getTempFByIndex(0);
SerialMon.print(temperature);
SerialMon.println(" *F");*/
lastTemperature = String(temperature);
// Check if temperature is above threshold and if it needs to send the Email alert
if(temperature > inputMessage3.toFloat() && inputMessage2 == "true" && !emailSent){
String emailMessage = String("Temperature above threshold. Current temperature: ") +
String(temperature) + String("F");
if(sendEmailNotification(emailMessage)) {
Serial.println(emailMessage);
emailSent = true;
}
else {
Serial.println("Email failed to send");
}
}
// Check if temperature is below threshold and if it needs to send the Email alert
else if((temperature < inputMessage4.toFloat()) && inputMessage2 == "true" && emailSent) {
String emailMessage = String("Temperature below threshold. Current temperature: ") +
String(temperature) + String(" F");
if(sendEmailNotification(emailMessage)) {
Serial.println(emailMessage);
emailSent = false;
}
else {
Serial.println("Email failed to send");
}
}
}
}
bool sendEmailNotification(String emailMessage){
// Set the SMTP Server Email host, port, account and password
smtpData.setLogin(smtpServer, smtpServerPort, emailSenderAccount, emailSenderPassword);
// For library version 1.2.0 and later which STARTTLS protocol was supported,the STARTTLS will be
// enabled automatically when port 587 was used, or enable it manually using setSTARTTLS function.
//smtpData.setSTARTTLS(true);
// Set the sender name and Email
smtpData.setSender("ESP32", emailSenderAccount);
// Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest)
smtpData.setPriority("High");
// Set the subject
smtpData.setSubject(emailSubject);
// Set the message with HTML format
smtpData.setMessage(emailMessage, true);
// Add recipients
smtpData.addRecipient(inputMessage);
smtpData.setSendCallback(sendCallback);
// Start sending Email, can be set callback function to track the status
if (!MailClient.sendMail(smtpData)) {
Serial.println("Error sending Email, " + MailClient.smtpErrorReason());
return false;
}
// Clear all data from Email object to free memory
smtpData.empty();
return true;
}
// Callback function to get the Email sending status
void sendCallback(SendStatus msg) {
// Print the current status
Serial.println(msg.info());
// Do something when complete
if (msg.success()) {
Serial.println("----------------");
server.begin();
}
}
m1cr0lab
i was able to take rui's two sketchs and compile them correctly , but when i type in the ip address it say it cant find it. can you look over my sketch and see whats wrong. thank you.
For remote control of the ESP32, I suggest you read my tutorial on the subject:
ESP32 Remote Control with WebSocket
You should find the methodology to approach this type of problem and adapt it to your project.