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;
}
}