Is there some reason that I’m currently not seeing that when I modify the Email Alert code to utilize a static IP address that it cannot connect to the email server? If I use the tutorial code for email alert, the esp32 can connect to smtp server each time an alarm occurs. If I use the piece of code to connect to my local network with a static IP address, esp32 connects fine at assigned static address. When I combine the code so the esp32 with a static IP address can connect to smtp server upon an alarm, the serial monitor wil display “Error sending Email, could not connect to server”.
Hi.
You said it didn’t work with static ip address?
I was asking for your code that sets static ip address to check if I can spot something wrong. The Code you shared doesn’t have the static ip.
Regards,
Sara
Hi.
Did you happen to change anything on the network password and ssid? Or the email and app password?
Those are the main reasons for that error.
However, I’m not sure why, some libraries don’t work properly when using static ip addresses.
Can you show me the section that sets the static ip address?
Regards,
Sara
Sara,
Previously I sent the wrong code. Here is the non-working request for email to be sent. ESP32 does get assigned 10.0.0.109 as assigned in the code, but will not connect to email server.
Below is the code. SSID, Network Password, Email Sender Account and Email Sender Password are copied from working copy of Email Alert program.
Thanks for looking.
Tom
/*********
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.
This code was modified by Tom Wollney to read Hall Sensor 3144E and DS18B20 temp sensors to control a enable
freezer alarm based on freezer air temperature > frztempsp or door open after a delay. Alarm delay time (5 min.) is entered in
minutes, but readout display is in seconds..
A Red LED lights and a relay energizes upon an ALARM condition
A Green LED lights when connected to the network.
A Blue LED blinks to indicate a heartbeat (program running)
Program and web page can be updated over a network connection
Version Date Change By Description
——- ———- ——— ——————————————————
1.0 06/17/2023 TW Original Version: Read Temperature and door position and generate an ALARM
1.1 06/29/2023 TW Changed Temp Alm parameters and email text
1.2 07/03/2023 TW Changed update parameter, static address assignment, heartbeat timing
1.3 08/24/2023 TW Attemp to fix timer resets
1.4 05/27/2024 TW Add WiFi Reconnect
1.5 08/27/2024 TW Fix Static IP
**********************************************************************************************/
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SPIFFS.h>
#include “ESP32_MailClient.h”
// To send Emails using Gmail on port 465 (SSL), you need to create an app password: https://support.google.com/accounts/answer/185833
#define emailSenderAccount “SSSSS@gmail.com”
#define emailSenderPassword “SPSPSPSP”
#define smtpServer “smtp.gmail.com”
#define smtpServerPort 465
//#define smtpServerPort 587
#define emailSubject “[ALERT] ESP32 Freezer”
// Default Recipient Email Address
String inputMessage = “tomwollney@gmail.com”;
unsigned long prevReconMillis = 0; //1.4
unsigned long reconInterval = 30000; //1.4
//***** Temperature Sensor
const int oneWireBus = 32; //GPIO 4 where the DS18B20 is connected
const int tempDiff = 2; //Temperature Differential between ALARM and NORMAL
float tempAlarmRelayStatus = 0.0; //temporary storage variable
bool warmTemp = false; //temporary storage variable
bool warmTime = false; //temporary storage variable
unsigned long prevTempMillis = 0; // will store elapsed time for temperature alarm
unsigned long tempElapsedTime = 0;
// Updates readings every 10 second
unsigned long tempInterval = 0; // delay storage for temperature alarm in minutes
const int tmpAlarmmDelay = 15.0; // alarm delay in minutes (original was 5.0)
// Stores Relay status
String tempRelayStatus;
//******************* Temperature Sensor
//******************* Hall Sensor
const int hallPin = 36; // ESP32 Analog Pin = 36 GPIO36
const int doorPin = 23; // ESP32 Digital Pin = 23 GPIO23
const int hallSp = 512; // half of open value
bool doorTime = false;
bool hallThreshold = false;
float doorAlarmRelayStatus = 0.0;
bool doorStatus;
int hallVal;
int doorVal;
unsigned long prevDoorMillis = 0; // will store elapsed time for door open alarm
unsigned long doorElapsedTime = 0; // time door is open
// Updates readings every 10 second
unsigned long doorInterval = 0; // delay time for door open alarm in minutes
const int doorAlarmDelay = 5.0; // alarm delay in minutes (default is 5.0)
// Stores door status
String doorRelayStatus;
//****************** Hall Sensor
//****************** Freezer Alarm
const int freezerAlarmRelay = 15; //GPIO 15 where the relay/led is connected
int freezerAlarm = 0.0;
String frzAlarmStatus;
//****************** Freezer Alarm
//****************** Network Parameters
// Replace with your network credentials
const char* ssid = “XXXXX”;
const char* password = “PPPPP”;
const char* ProgramName = “Freezer Alarm with Reconnect and Static IP”;
const char* Version = “1.5”;
int rssi = 0.0;
//******************* Network Parameters
const int heartBeat = 16;
const int netStatus = 17;
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(oneWireBus);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);
// current temperature updated in loop()
float frzsensor = 31.0;
float frztemp = 30.0;
int frztempsp = 80.0; //original 10.0
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Generally, you should use “unsigned long” for variables that hold time
// The value will quickly become too large for an int to store
// unsigned long currentMillis = millis();
unsigned long previousMillis = 0; // will store elapsed time for heartbeat
// Updates readings every 1 second (now 10 seconds) – affects heartbeat 421-429
const long interval = 10000; // was 1000
// Set your Static IP address
IPAddress local_IP(10,0,0,109);
// Set your gateway IP address
IPAddress gateway(10,0,0,1);
// Set your subnet IP address
IPAddress subnet(255,255,255,0);
// Replaces placeholder with live values
String processor(const String& var) {
Serial.println(var);
if (var == “STATE”) {
return String(tempRelayStatus);
}
else if(var == “FRZTEMPERATURE”) {
return String(frztemp);
}
else if(var == “FRZTEMPSP”) {
return String(frztempsp);
}
else if(var == “TEMPELAPSEDTIME”) {
return String(tempElapsedTime);
}
else if(var == “TEMPRELAYSTATUS”) {
return String(tempRelayStatus);
}
else if(var == “DOORVAL”) {
return String(doorVal);
}
else if(var == “HALLVAL”) {
return String(hallVal);
}
else if(var == “DOORRELAYSTATUS”) {
return String(doorRelayStatus);
}
else if(var == “DOORELAPSEDTIME”) {
return String(doorElapsedTime);
}
else if(var == “FRZALARMSTATUS”) {
return String(frzAlarmStatus);
}
else if(var == “RSSIVAL”) {
return String(rssi);
}
return String();
}
// Flag variable to keep track if email notification was sent or not
bool emailSent = false;
// The Email Sending data object contains config and data to send
SMTPData smtpData;
void initWiFi() {
if (!WiFi.config(local_IP, gateway, subnet)) //1.5
Serial.println(“STA Failed to configure”);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print(“Connecting to WiFi ..”);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(‘.’);
delay(1000);
}
Serial.println(WiFi.localIP());
// Serial.println(WiFi.subnet());
}
void setup() {
// Serial port for debugging purposes
Serial.begin(115200);
// Start the DS18B20 sensor
sensors.begin();
// Freezer Alarm Relay
pinMode(freezerAlarmRelay, OUTPUT);
digitalWrite(freezerAlarmRelay, LOW);
// Door Switch
pinMode(doorPin, INPUT);
// heartbeat LED
pinMode(heartBeat, OUTPUT); // heartbeat LED toggle
digitalWrite(heartBeat,HIGH);
// Network Connected
pinMode(netStatus, OUTPUT); // ON when connected to network
digitalWrite(netStatus, LOW);
// Initialize SPIFFS
if(!SPIFFS.begin()){
Serial.println(“An Error has occurred while mounting SPIFFS”);
return;
}
initWiFi();
// Print ESP8266 Local IP Address
Serial.print(“Connecting to Network: “);
Serial.println(ssid);
Serial.print(“RRSI: “);
Serial.println(WiFi.RSSI());
Serial.print(“Program Name: “);
Serial.println(ProgramName);
Serial.print(“Version Number: “);
Serial.println(Version);
Serial.println(“”);
// Route for root / web page
server.on(“/”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, “/index.html”, String(), false, processor);
});
// Route to load style.css file
server.on(“/style.css”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, “/style.css”, “text/css”);
});
server.on(“/frztemperature”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, “text/plain”, String(frztemp).c_str());
});
server.on(“/frztempsp”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, “text/plain”, String(frztempsp).c_str());
});
server.on(“/temprelaystatus”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, “text/plain”, String(tempRelayStatus).c_str());
});
server.on(“/tempelapsedtime”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, “text/plain”, String(tempElapsedTime).c_str());
});
server.on(“/doorval”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, “text/plain”, String(doorVal).c_str());
});
server.on(“/hallval”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, “text/plain”, String(hallVal).c_str());
});
server.on(“/doorrelaystatus”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, “text/plain”, String(doorRelayStatus).c_str());
});
server.on(“/doorelapsedtime”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, “text/plain”, String(doorElapsedTime).c_str());
});
server.on(“/frzalarmstatus”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, “text/plain”, String(frzAlarmStatus).c_str());
});
server.on(“/rssi”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, “text/plain”, String(rssi).c_str());
});
// Start Elegant OTA server
AsyncElegantOTA.begin(&server);
// Start server
server.begin();
}
void loop() {
unsigned long currentMillis = millis();
// if WiFi is down, try reconnecting every CHECK_WIFI_TIME seconds
if ((WiFi.status() != WL_CONNECTED) && (currentMillis – prevReconMillis >= reconInterval)) {
Serial.print(millis());
Serial.println(“Reconnecting to WiFi…”);
WiFi.disconnect();
WiFi.reconnect();
prevReconMillis = currentMillis;
}
rssi = WiFi.RSSI();
if (currentMillis – previousMillis >= interval) {
previousMillis = currentMillis;
//***** Temperature Sensor
if (not (warmTemp)) {
prevTempMillis = currentMillis;
}
sensors.requestTemperatures();
// Temperature in Fahrenheit degrees
frzsensor = sensors.getTempFByIndex(0); //was frztemp
if (frzsensor > -20) {
frztemp = frzsensor;
}
else {frztemp = frztemp;
}
// print the readings in the Serial Monitor Serial.print(“Freezer Temperature: “);
Serial.print(“Controller IP address is: “);
Serial.println(WiFi.localIP());
Serial.print(“Freezer Sensor is: “);
Serial.print(frzsensor);
Serial.println(“ºF”);
Serial.print(“Freezer Temperature is: “);
Serial.print(frztemp);
Serial.println(“ºF”);
Serial.print(“Freezer Temperature Sp: “);
Serial.print(frztempsp);
Serial.println(“ºF”);
if (frztemp > frztempsp) { //Condition for ALARM
warmTemp = true;
}
if (frztemp < (frztempsp – tempDiff)) { //Condition for RETURN to NORMAL
warmTemp = false;
}
Serial.print(“warmTemp is: “);
Serial.println(warmTemp);
tempInterval = tmpAlarmmDelay * 60000; //Convert Minutes delay parameter to milliseconds
tempElapsedTime = (currentMillis – prevTempMillis);
warmTime = ((tempElapsedTime) >= tempInterval);
tempElapsedTime = tempElapsedTime / 1000; //Convert milliseconds to seconds for display
Serial.print(“WarmTime is: “);
Serial.println(warmTime);
if (warmTime && warmTemp) { //Condition for ALARM to occur
tempAlarmRelayStatus = 1.0;
tempRelayStatus = “ALARM”;
}
else { //Condition for RETURN to NORMAL to occur
tempAlarmRelayStatus = 0.0;
tempRelayStatus = “NORMAL”;
}
Serial.print(“Elapsed Temp Alarm Timer: “);
Serial.print(tempElapsedTime);
Serial.println(” Seconds”);
Serial.print(“tempRelayStatus: “);
Serial.println(tempRelayStatus);
Serial.println(“/t”);
//***** Temperature Sensor
//***** Hall Sensor
hallVal = analogRead(hallPin); //read hall value 1024 is no magnet – low is magnet present
doorVal = digitalRead(doorPin); //read hall switch value – 0 = door closed, 1 = door open
if (not (doorVal || hallThreshold)) { // either readout can cause ALARM condition
prevDoorMillis = currentMillis;
}
if (analogRead(hallPin) > hallSp) { // analog reading to cause ALARM
hallThreshold = true;
}
if (analogRead(hallPin) < hallSp ) { // analog reading to cause RETURN to NORMAL
hallThreshold = false;
}
Serial.print(“Hall Value is: “);
Serial.println(hallVal);
Serial.print(“hallThreshold is: “);
Serial.println(hallThreshold);
Serial.print(“Door Switch is: “);
Serial.println(doorVal);
doorInterval = doorAlarmDelay * 60000; //Converts delay time to minutes
doorElapsedTime = (currentMillis – prevDoorMillis);
doorTime = ((doorElapsedTime) >= doorInterval);
doorElapsedTime = doorElapsedTime / 1000; //Converts elapsed time to seconds for display
doorStatus = doorVal || hallThreshold;
if (doorStatus && doorTime) {
doorAlarmRelayStatus = 1.0;
doorRelayStatus = “ALARM”;
}
else {
doorAlarmRelayStatus = 0.0;
doorRelayStatus = “NORMAL”;
}
Serial.print(“Door Open Time is: “);
Serial.print(doorElapsedTime);
Serial.println(” Seconds”);
Serial.print(“Door Alarm Relay is: “);
Serial.println(doorRelayStatus);
Serial.println(“/t”);
//***** Hall Sensor
//***** Freezer Alarm
freezerAlarm = (tempAlarmRelayStatus + doorAlarmRelayStatus);
if (freezerAlarm >= 1.0) {
digitalWrite(freezerAlarmRelay,HIGH);
}
else {
digitalWrite(freezerAlarmRelay,LOW);
}
if (digitalRead(freezerAlarmRelay)) {
frzAlarmStatus = “ALARM”;
}
else {
frzAlarmStatus = “NORMAL”;
}
Serial.print(“Freezer Alarm Relay: “);
Serial.println(digitalRead(freezerAlarmRelay));
Serial.print(“Freezer Alarm Status: “);
Serial.println(frzAlarmStatus);
if (WiFi.status() != WL_CONNECTED) {
digitalWrite(netStatus, LOW); // Network Disconnected
}
else {
digitalWrite(netStatus, HIGH); // Network Connected
}
//***** Freezer Alarm
// heartbeat LED blink every 10 sec Check line 133
digitalWrite(heartBeat, HIGH); // heartbeat Led On
delay(10000);
// heartbeat LED blink every 10 sec (matches delay above)
digitalWrite(heartBeat, LOW); // heartbeat Led Off
delay(10000);
//***** Send Email Alert
// Check if temperature is above threshold and if it needs to send the Email alert
// Check if temperature is above threshold and if it needs to send the Email alert
if ((digitalRead(freezerAlarmRelay)) && !emailSent){
String emailMessage = String(“Temperature is above Alarm Setpoint or Door is Open.”) + “/ ” + String(“Current temperature is: “) +
String(frztemp) + String(” F”) + “/ ” + String(“Door Status is: “) + String(doorRelayStatus);
if(sendEmailNotification(emailMessage)) {
Serial.println(emailMessage);
emailSent = true;
}
else {
Serial.println(“Email failed to send”);
}
}
// Check if freezer is NORMAL and if it needs to send the Email alert
else if(!(digitalRead(freezerAlarmRelay)) && emailSent) {
String emailMessage = String(“Temperature is NOT above Alarm Setpoint and Door CLOSED.”) + “/ ” + String(“Current temperature is: “) +
String(frztemp) + String(” F”) + “/ ” + String(“Door Status is: “) + String(doorRelayStatus);
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(“—————-“);
}
}
Hi.
Have you checked that the IP address you’re attributing is availabe?
// Set your Static IP address
IPAddress local_IP(10,0,0,109);
// Set your gateway IP address
IPAddress gateway(10,0,0,1);
// Set your subnet IP address
IPAddress subnet(255,255,255,0);
Additionally, add the primary and secondary DNS values as in this tutorial: https://randomnerdtutorials.com/esp32-static-fixed-ip-address-arduino-ide/ (even though it mentions it is optional).
Regards,
Sara
Sara,
I have verified that 10.0.0.109 is unused on my network before connecting my esp32. I also added the two optional DNS entries to the code as shown in the tutorial. This didn’t make a difference in ability of esp32 to connect to smtp server.
I’m currently powering esp32 with usb connection to my computer. I will investigate using a higher (7-12 v) power supply to power esp32. Any other suggestions will be appreciated, otherwise, thanks for your help.
Tom