Problems creating a loop that runs 1 time based on time limit.

I’d like to explain my system to anyone who wants to help and be caught up. So basically I’m constructing a data logging system that should send an E-mail out every 24hours, in which contains data logged each hour on that 24 hour basis. I also want to run an alert system that is triggered by 3 things.

  1. The activation of a emergency push button
  2. High Temperature set point has been surpassed.
  3. Low Temperature set point has been surpassed.

I want to trigger an alternate E-mail on this alert.

Now, my issue now is the fact that when i surpass let’s say, 29 degrees Celsius, i want my system to send 1 e-mail now unfortunately, i get spammed with E-mails over and over until that setpoint is no longer crossed. My first instinct was to run a system like such :

void loop() {

if ( LeftFloatTemp[x] <= 25.00){
    EmailStatus = 0;  
  }
 if (buttonPressed == LOW || LeftFloatTemp[x] >= 29.00) {
      
      if(EmailStatus != 2)
        {
               EmailStatus = 1;
        }

      if(EmailStatus == 1){
          SendingAlertEmail();
          calls++;
          EmailStatus = 2;
         }
  } 

}

Alright so i kinda just cut this out of my code this is alot more code in between filled with things like variables and other stuff that i believe is irrelevent information for what i know. Anyhow, I followed the value of my EmailStatus integer to see when i can and can’t send an E-mail but basically i had it set where until my values are respected i don’t want to be able to send a second E-mail my value seems to always hop to 0 or 1 which i know are both valid to send emails based off my one If statement.

I was just wondering if someone sees a better way I can run this code or make it work more effeciently and have it not work properly.

Keep in mind that i appreciate all notices of error in possible coding but i’m mainly looking for a solution to how to run the system over syntax.

All help is greatly appreciated.

Thank you,

Trevor

The approach is right but to make the code more readable I would use a boolean variable called, perhaps, warningEmailSent normally set to false. Test it before sending the warning email. Set it to true when the warning email has been sent and back to false when the temperature falls below the trigger level.

By using a boolean variable you can write code such as

if (temperature >= 25 && !warningEmailSent)
{
  //code here to send email
  warningEmailSent = true;
}

To my mind this is easier to read and understand than using 0, 1, whatever for the flag variable

I don't have an issue following it, I'm using 0,1,2 to keep it available for more improvement, even if i change it to the boolean I will still have the same issue I believe.

If it will help you help me, solve this issue tho I could happily change it up. I just dont get why my status get reset to 0 sometimes. and still spams. I'm wondering if im writing something wrong.

We will need to see the full program in order to provide help.

The problem is not in the code you posted. You need to post the entire sketch for us to find the problem.

Prepare for a big chunk of Code, Excuse me if it’s different then the original code because of minor changes i’ve been doing to test it. Keep it mind for hardware I have an Arduino Mega, with Ethernet Shield, 2 TMP36’s a RTC and a simple bush button.

/* Setup shield-specific #include statements and RTC Setup*/
#include <Time.h>
#include <Wire.h>
#include <DS1307RTC.h>
#include <SPI.h>
#include <Dhcp.h>
#include <Dns.h>
#include <Ethernet.h>
#include <EthernetClient.h>
#include <Temboo.h>
#include "TembooAccount.h" // Contains Temboo account information

//Declaring Variables.
int calls = 0;
int inputPin = 8;
float LeftTemp;
float RightTemp;
float voltageR;
float voltageL;
float LeftTempCel;
float RightTempCel;
float LeftFloatTemp[24];
float RightFloatTemp[24];
int x = 0;
int interval;
int sec5;
int buttonPressed;
int EmailStatus = 0;
char MessageBodyValue[127];
String Time[24];

byte ethernetMACAddress[] = ETHERNET_SHIELD_MAC;
EthernetClient client;

// The number of times to trigger the action if the condition is met.
// We limit this so you won't use all of your Temboo calls while testing.
int maxCalls = 3;
int secondSpot = -1;


// The number of times this Choreo has been run so far in this sketch.



void setup() {
  Serial.begin(9600);
  setSyncProvider(RTC.get);
  // For debugging, wait until the serial console is connected.
  delay(4000);
  while (!Serial);

  Serial.print("DHCP:");
  if (Ethernet.begin(ethernetMACAddress) == 0) {
    Serial.println("FAIL");
    while (true);
  }
  Serial.println("OK");
  delay(5000);

  // initialize pins
  pinMode(inputPin, INPUT_PULLUP);

  //Serial.println("Setup complete.\n");
}

void loop() {
  //Private variables
  int j = 0; 
  int days;
  int hours; // These are variables to help control which array we are currently in based off the time.
  int minutes;
  int seconds;
  
  
  days = day();
  hours = hour();
  minutes = minute();
  seconds = second();
  
 
  
  //Algorithm for our seconds to round up to control the interval of x and the arrays
  if(seconds % 5 > 0) j = 1; 
  else j = 0;
  sec5 = ((seconds /5) + j) * 5;
  interval = (((minutes % 2) * 60) + (sec5)) /5;
  x = interval -1;
  
  if (x < 0) {  //To prevent bugs forcing the hour to 11PM if it ever goes below zero
    x = 23;
  }
  
  
  
  //Calling to the Right TMP for its readings.  
    RightTemp = analogRead(A0);
    voltageR = RightTemp * 5.0;
    voltageR /= 1024.0;
    RightTempCel = (voltageR - 0.5) * 100;

    //Calling to the Left TMP for its readings.
    LeftTemp = analogRead(A1);
    voltageL = LeftTemp * 5.0;
    voltageL /= 1024.0;
    LeftTempCel = (voltageL - 0.5) * 100;
    
    
      if (seconds % 5 == 0) {
        SaveData();
      }
  if ( LeftFloatTemp[x] <= 25.00 && EmailStatus == 2){
    EmailStatus = 0;  
  }
        buttonPressed = digitalRead(inputPin);
    if ((buttonPressed == LOW && EmailStatus != 2) || (LeftFloatTemp[x] >= 29.00 && EmailStatus != 2)) {
        
               EmailStatus = 1;      
     
      if (calls < maxCalls) {
        Serial.println("\nTriggered! Calling /Library/Google/Gmail/SendEmail...");
        if(EmailStatus == 1){
          SendingAlertEmail();
          calls++;
          EmailStatus = 2;
         }
      }
    } else if ((minutes % 2 == 0) && (seconds == 0)) {
    if (calls < maxCalls) {
        Serial.println("\nTriggered! Calling /Library/Google/Gmail/SendEmail...");

        DailyReportEmail();
        calls++;
      }
    }
}

void SendingAlertEmail() {
  TembooChoreo SendEmailChoreo(client);

  // Set Temboo account credentials
  SendEmailChoreo.setAccountName(TEMBOO_ACCOUNT);
  SendEmailChoreo.setAppKeyName(TEMBOO_APP_KEY_NAME);
  SendEmailChoreo.setAppKey(TEMBOO_APP_KEY);

  // Set profile to use for execution
  SendEmailChoreo.setProfile("GmailTesting");
  
  //Set Choreo inputs
  
   //Setting the Subject of the E-mail
  String SubjectValue = "WARNING!! DANGEROUS TEMPERATURES";
  SendEmailChoreo.addInput("Subject", SubjectValue);
  
  //Setting the Varied Bodies of the Alert Email
  char MessageBodyWarning[127];
  if(buttonPressed == LOW) { 
    
    sprintf(MessageBodyWarning, "WARNING!!! Emergency button has been activated. \nTime of Occurance: %02d:%02d:%02d \n ", hour(), minute(), second());
  }
  else {
    char FloatValue[10];
    dtostrf(LeftFloatTemp[x], 5, 2, FloatValue);
    sprintf(MessageBodyWarning, "WARNING!!! Your Temperature is at an unstable level: %s degrees Celsius \nTime of Occurance: %02d:%02d:%02d \n ", FloatValue, hour(), minute(), second());
  }
    String MessageBodyTotal = String(MessageBodyWarning);
    SendEmailChoreo.addInput("MessageBody", MessageBodyTotal);
    
  // identify the Choreo to run
  SendEmailChoreo.setChoreo("/Library/Google/Gmail/SendEmail");

  // Run the Choreo
  unsigned int returnCode = SendEmailChoreo.run();

  // A return code of zero means everithing worked
    if (returnCode == 0) {
      digitalWrite(inputPin, HIGH);
    }

  SendEmailChoreo.close();
}
void DailyReportEmail() {
  TembooChoreo SendEmailChoreo(client);

  // Set Temboo account credentials
  SendEmailChoreo.setAccountName(TEMBOO_ACCOUNT);
  SendEmailChoreo.setAppKeyName(TEMBOO_APP_KEY_NAME);
  SendEmailChoreo.setAppKey(TEMBOO_APP_KEY);

  // Set profile to use for execution
  SendEmailChoreo.setProfile("GmailTesting");
  
  //Subject for the 24 hour report Inluding mm/dd/yyyy
  char SubjectTotal[127];
    
  sprintf(SubjectTotal, "%02d/%02d/%02d's temperature readings ", month(), day(), year());
    
  String SubjectValue = SubjectTotal;
  SendEmailChoreo.addInput("Subject", SubjectValue);
  
  // Set Choreo inputs
  String MessageBodyTotal[24];
    for (int i = 0; i < 24; i++) {
      MessageBodyTotal[i] = "Current time is: " + Time[i] + " Left Temp : " + String(LeftFloatTemp[i]) + " Right Temp: " + String(RightFloatTemp[i]);
    }
  
  //Message for 24 hour report Email  
  String MessageBody = StringArrayString(MessageBodyTotal);
  SendEmailChoreo.addInput("MessageBody", MessageBody);

  // Identify the Choreo to run
  SendEmailChoreo.setChoreo("/Library/Google/Gmail/SendEmail");

  // Run the Choreo
  unsigned int returnCode = SendEmailChoreo.run();

  // A return code of zero means everything worked
    if (returnCode == 0) {
      digitalWrite(inputPin, HIGH);
    }

  SendEmailChoreo.close();
}

   //Array Function
String StringArrayString(String arr[])
{
  String retStr = "";
    for (int i = 0; i < 24; i++)
      {
        retStr += arr[i] + "\n";
        //Serial.println(arr[i]);
      }
  return retStr;
}
// Function to transfer my data into specific arrays.
void SaveData(){
        LeftFloatTemp[x] = LeftTempCel;
        RightFloatTemp[x] = RightTempCel;
        sprintf(MessageBodyValue, "%02d:%02d:%02d", hour(), minute(), second() );
        Time[x] = String(MessageBodyValue);
        //Serial.println(Time[x] + " " + sec5 + " " + interval + " " + x);
        Serial.println(String(LeftFloatTemp[x]) + "    " + EmailStatus);
 }

I found the issues guys, I was doing the compare in the if statements here

if ( LeftFloatTemp[x] <= 25.00 && EmailStatus == 2){
    EmailStatus = 0;  
  }

and here

if ((buttonPressed == LOW && EmailStatus != 2) || (LeftFloatTemp[x] >= 29.00 && EmailStatus != 2)) {

with LeftFloatTemp which is a variable that only gets posted when every 5 seconds based off my code. Instead i switched it to LeftTempCel which is a constant reading of my TMP sensor. It was my issue thanks for the help guys sorry for the troubles.

And if you want to speed up the program A LOT. Get rid of all the floats. They are slow and you don't need them (because your reading of the ADC is also just a byte/int/long) :wink:

I want to keep some floats because I want an accurate reading, without eliminating my precision are there any floats you suggest I can still remove?

Uhm, by using floats you CREATE inaccuracy instead of making it more accurate. :wink: Floats ARE inaccurate. The bigger the more inaccurate but the are inaccurate.

And if you need decimals (I guess that's why you use floats) change everything to nog need floats :wink:

For example, if I would like to store a amount om money with two decimals (like €1,38) you indeed can't store 1.38 in a int (or byte or long). But using a float you can but you don't actual store 1.38 but you store 1.3799999952316284. (Look at this site for floats) It's close, but it has an error! But if I know I want 2 decimal of accuracy, why not store it in cents? I can store 138 in a byte (or int or long)! And as long I keep in mind I store cents, not Euro (or Dollar :stuck_out_tongue: ) you're fine! And it's a hell lot quicker (and a hell more accurate)!

You can do the same for temperature or voltage or whatever. If you need 3 decimal accuracy, just store 1.428 as 1428. Just multiply with 10 until you are rid of the decimal sign :grinning:

Life is so much easier without floats :smiley:

This is true I have had issues using float the whole way through the code. I have just about finished the system so Ill most likely re modify it after with ints for now ill keep it as it is functioning. But i enjoy your suggestion and it will most likely take part in the Improvement side of the project. Thank you!