ESP8266 Not sending email in the void loop

Hello,

I am currently working on a fall detection program and I would like to send an email every time my ESP8266 detects a fall. For some reason the email will send in the setup but not the loop if its in a separate sendMail() function or not. Some errors I've gotten was failed to log in, failed to connect, and fails at sending the message header. I got this code from the example which only ran out of the setup, does anyone know how to send it out of the void loop?

Here is my code, sorry its very messy right now, I am just copy pasting parts of the code and moving it around to see what works.

////////////////////////////////
//        New Sketch to debug wifi
//
//    PINS:
//          Forcemeter:
//      GND -> GND
//      DT -> D6
//      SCK -> D7
//      VCC -> 3.3V
//
//        Accelerometer:
//     VIN - > 3.3V
//     GND -> GND
//     SCL -> D1
//     SDA -> D2
////////////////////////////////

//Libraries
#include <Arduino.h>
#include "HX711.h"                      //Pressure sensor
#include <Adafruit_Sensor.h>            //Accel
#include <Adafruit_ADXL343.h>           //Accel
#include <ArduinoIoTCloud.h>            //IOT
#include <Arduino_ConnectionHandler.h>  //IOT
#include <ESP_Mail_Client.h>            //EMAIL
#include <ESP8266WiFi.h>                //WiFi

//Mail Define
#define WIFI_SSID "hidden wifi ssid"
#define WIFI_PASSWORD "hidden wifi password"
#define SMTP_HOST "smtp.office365.com"
#define SMTP_PORT 587
#define AUTHOR_EMAIL "hidden email"
#define AUTHOR_PASSWORD "hidden password"
#define RECIPIENT_EMAIL "hidden email"

//IoT and Wifi
const char DEVICE_LOGIN_NAME[] = "hidden device login";

//const char *SSID = WIFI_SSID;                              // Network SSID (name)
//const char *PASS = WIFI_PASSWORD;                          // Network password (use for WPA, or use as key for WEP)
const char *DEVICE_KEY = "hidden key";        // Secret device password

//HX711 LoadCell;
Adafruit_ADXL343 accel = Adafruit_ADXL343(12345);

//Database
CloudAcceleration accelerometerX;         //Cloud Accelerometer X
CloudAcceleration accelerometerY;         //Cloud Accelerometer Y
CloudAcceleration accelerometerZ;         //Cloud Accelerometer Z
String fallDeteted;                       //Cloud Fall Detercted
CloudMass forcemeter;                     //Cloud Forcemeter

//Customizable Variables
//Force Meter Variables
double Tare = 0;                          //Tare Value Variable
int TareTime = 30000;                     //Time to tare in ms
int FallTime = 10000;                     //Time to check fall in ms
float CalValue = 39.278999;               //Calibration value
int OffSet = 4294961203;                  //Offset value
double AvgF = 0, TotalF = 0;              //Variables to track total and average force
int FCount = 0;                           //Variable to count the amount of forces counted to the average

//Idle Variables
int TryBeforeOff = 10;                    //Amount of tries the accelerometer checks movement
int Trys = 0;                             //Variable to count the amount of tries

//Step Counter Variables
bool Step = false;                        //Variables to track steps
double userMass = 60;                     //Users body weight in kg
int StepCount = 0;                        //Variable to count steps

//Global variables
double LastX, LastY, LastZ;
bool Email = false;

//Prototypes
WiFiConnectionHandler ArduinoIoTPreferredConnection(WIFI_SSID, WIFI_PASSWORD);
void smtpCallback(SMTP_Status status);
void initProperties();
void accelUpdate();
void pUpdate();
void checkFall();
void SendMail();
void CheckResponse();

//Innitialize
HX711 LoadCell;
SMTPSession smtp;
SMTP_Message message;
Session_Config config;  

void setup() {
  if (Email == false)
  {
  Serial.begin(115200);

  //Connect to the WiFi
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("Connecting to Wi-Fi");
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(300);

    if (Trys > 60) {
      break;
    }

    Trys ++;
  }
  Trys = 0;



  //Accelerometer
  if (!accel.begin()) {
    Serial.println("ADXL345 not found. Check connections!");
  }

  //Pressure sensor
  LoadCell.begin(12, 13);                                   //dt, sck
  LoadCell.set_scale(CalValue);                             //Set Scale Value
  LoadCell.set_offset(OffSet);                              //Set Offset
  LoadCell.tare();                                          //Tare the loadcell

  //IoT Cloud
  initProperties();                                         //Start the cloud properties
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);        //Start the cloud
  setDebugMessageLevel(2);                                  //Debugs
  ArduinoCloud.printDebugInfo();
  }

  //Send Mail

    MailClient.networkReconnect(true);

    smtp.debug(1);
    smtp.callback(smtpCallback);

  config.server.host_name = SMTP_HOST;
  config.server.port = SMTP_PORT;
  config.login.email = AUTHOR_EMAIL;
  config.login.password = AUTHOR_PASSWORD;
 config.login.user_domain = "";

  config.time.ntp_server = F("pool.ntp.org,time.nist.gov");
  config.time.gmt_offset = 3;
  config.time.day_light_offset = 0;

  message.sender.name = F("ESP Mail");
  message.sender.email = AUTHOR_EMAIL;
  message.subject = F("Test sending html Email");
  message.addRecipient(F("Admin"), RECIPIENT_EMAIL);

  String htmlMsg = "<div style=\"color:#FF0000;\"><h1>FALL DETECTED!</h1><p>Dear user, <br> A fall has been detected on the Smart Cane, please call the subscribed individual to ensure thier safety. <br> Thank you for using the Smart Cane, and we hope everything is well <br> -Solid Step Smart Cane</p></div>"; 
  message.html.content = htmlMsg.c_str();
  message.html.content = htmlMsg.c_str();
   message.html.charSet = F("us-ascii");
  message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit;

  message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_high;

  message.addHeader(F("Message-ID: <abcde.fghij@gmail.com>"));

  MailClient.sendMail(&smtp, &message);

  if (!smtp.connect(&config))
  {
    MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s\n", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str());
    return;
  }

  if (!smtp.isLoggedIn())
  {
    Serial.println("Error, Not yet logged in.");
  }
  else
  {
    if (smtp.isAuthenticated())
      Serial.println("Successfully logged in.");
    else
      Serial.println("Connected with no Auth.");
  }

if (!MailClient.sendMail(&smtp, &message))
    MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s\n", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str());


  MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
  }

  Email = true;
}

void loop() {
  //Accelerometer update
  accelUpdate();
  //Pressure update
  pUpdate();

  //Online mode
  if (WiFi.status() == WL_CONNECTED) {
    ArduinoCloud.update();

    if (abs(accelerometerX) >= 1.95 or abs(accelerometerY) >= 1.95) {
      checkFall();
    }
  }

  //Step Counter
  if (forcemeter >= 3 && Step == false) {
    StepCount += 1;
    Step = true;
  }

  else if (forcemeter < 3 && Step == true) {
    Step = false;
  }

  print();
  CheckResponse();
}

//Function to update the accelerometer
void accelUpdate() {
  sensors_event_t event;
  accel.getEvent(&event);

  accelerometerX = event.acceleration.x/9.81;
  accelerometerY = event.acceleration.y/9.81;
  accelerometerZ = event.acceleration.z/9.81;
}

//Function to update the pressure sensor
void pUpdate()
{
  if (((millis() % TareTime) >= 0) && ((millis() % TareTime) <=50)) {
    Serial.println("Taring...");
    delay (1000);
    LoadCell.tare();
  }
  forcemeter = (LoadCell.get_units(3))/1000;

  //Find Average Force (Exclude when there was no force put on the cane)
  if (forcemeter >= 0.5) {
    FCount += 1;
    TotalF += forcemeter;
    AvgF = TotalF/FCount;
  }
}

//Function to print out the values
void print() {
  Serial.print("Mass: "); Serial.print(forcemeter); Serial.print(" Kg \t ");
  Serial.print("Average F: "); Serial.print(AvgF); Serial.print(" Kg \t ");
  Serial.print("X: "); Serial.print(accelerometerX); Serial.print(" g\t");
  Serial.print("Y: "); Serial.print(accelerometerY); Serial.print(" g\t");
  Serial.print("Z: "); Serial.print(accelerometerZ); Serial.print(" g\t");
  Serial.print("Steps: "); Serial.println(StepCount);
}

//Function to check if a fall occured
void checkFall() {
  //If there was pressure, check for a fall
  if(forcemeter >= 1) {
    Serial.println("Checking for fall...");
    delay(FallTime);
    accelUpdate();

    if (abs(round(accelerometerZ)) == 0) 
    {
      Serial.println("FALL DETECTED");
      fallDeteted = "Fall Detected at: " + String(double(millis()/3600000.00)) + " hours";
      SendMail();
      delay(1000);
    }
  }
}

//Function add cloud properties
void initProperties() {
  ArduinoCloud.setBoardId(DEVICE_LOGIN_NAME);
  ArduinoCloud.setSecretDeviceKey(DEVICE_KEY);
  ArduinoCloud.addProperty(accelerometerX, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(accelerometerY, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(accelerometerZ, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(fallDeteted, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(forcemeter, READ, ON_CHANGE, NULL);
}

//Function to send an email
void SendMail()
{
  smtp.connect(&config);
  MailClient.sendMail(&smtp, &message);
}

//Function to check if the email has been sent
void smtpCallback(SMTP_Status status)
{
  Serial.println(status.info());

  if (status.success())
  {
    Serial.println("----------------");
    MailClient.printf("Message sent success: %d\n", status.completedCount());
    MailClient.printf("Message sent failed: %d\n", status.failedCount());
    Serial.println("----------------\n");

    for (size_t i = 0; i < smtp.sendingResult.size(); i++)
    {
      SMTP_Result result = smtp.sendingResult.getItem(i);

      MailClient.printf("Message No: %d\n", i + 1);
      MailClient.printf("Status: %s\n", result.completed ? "success" : "failed");
      MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str());
      MailClient.printf("Recipient: %s\n", result.recipients.c_str());
      MailClient.printf("Subject: %s\n", result.subject.c_str());
    }
    Serial.println("----------------\n");

    smtp.sendingResult.clear();
  }
}

//Function to power down the cane to save power when there is no movement
void CheckResponse()
{
  if ((((accelerometerX - 0.02) <= LastX) && (LastX <= (accelerometerX + 0.02))) && (((accelerometerY - 0.02) <= LastY) && (LastY <= (accelerometerY + 0.02)) && (((accelerometerZ - 0.02) <= LastZ) && (LastZ <= (accelerometerZ + 0.02)))))
  {
    Trys ++;
  }
  else
  {
    LastY = accelerometerY;
    LastX = accelerometerX;
    LastZ = accelerometerZ;
  }

  if (Trys == TryBeforeOff)
  {
    LoadCell.power_down();
    while((((accelerometerX - 0.02) <= LastX) && (LastX <= (accelerometerX + 0.02))) && (((accelerometerY - 0.02) <= LastY) && (LastY <= (accelerometerY + 0.02)) && (((accelerometerZ - 0.02) <= LastZ) && (LastZ <= (accelerometerZ + 0.02)))))
    {
      accelUpdate();
      Serial.print(".");
    }
    LoadCell.power_up();
    Trys = 0;
  }
}
1 Like

A guaranteed failure method. You must learn to code. Very sorry, sounds abrupt, but it's the essence of your problem.

... I'm just moving things around to debug and isolate the issue

I highlighted things to bold but it just did that not sure why

There is the large chunk of code in the setup that works and sends an email. The code in the loop is SendMail(); and its used in checkFall();

I fixed it, should be good now

#include <EMailSender.h>

seems to work with more consistency, rather than:
#include <ESP_Mail_Client.h>

With that you can use this for messages:


EMailSender::EMailMessage message; // (I would put this as a global variable)
message.subject = "Subject";
message.message = "Body";

Send the email with:
EMailSender::Response resp = emailSend.send(RECIPIENT_EMAIL, message);

And debug with:

Serial.println("Sending status: ");

  Serial.println(resp.status);

  Serial.println(resp.code);

  Serial.println(resp.desc);

In your Send function you should confirm the success of connecting or print why it did not. Connect.

Also, not anything I know about should you need to connect or reconnect every time?

Here's a thread that gets around to sending email using ESO_Mail_Client.

HTH

a7

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.