Temp & Humidity Monitor w/Buzzer Alarm and Button Delay for just alarm

Hello Arduino people! This is my first post here so please let me know if I'm in the wrong section or improper etiquette.

Anyhow I'm in the process of making a Temp & Humidity data logger for my work, which I've got working properly, but I've been asked by the powers that be to add a buzzer activated by temp (no problems there) and a button to silence the buzzer for a period of time. The only way i can think to do this is to add a delay function in an if statement with the buttons input, but if I'm not mistaken that will cause it to not be data logging for however long, and that's a major problem for this devices application.
I suggested we just put a switch on the buzzer to turn it off when it goes off, but that relies on someone remembering to turn it back on after the temp has stabilized so its a no go unless its our only option.

So people who are wiser than me; Is this possible, and if so how do I go about it?

Thank you for any help!

Go to File → Examples → 02.Digital → BlinkWithoutDelay example.

When you press the button store the current time in a variable and in your loop you compare it to the new current time. When the time interval is too large and the temperature is still too high you start the buzzer again.

You are right using the delay function is usualy not a good idea.

If you does not fully understand the example code that mentioned by Klaus_K, you can see the tutorial: Arduino - LED - Blink Without Delay. This tutorial provide the detail explanation an instruction.

WELCOME !!!

well done on posting a good subject line.

when it comes time to post example code, please make sure you follow the method in #7 of
HOW TO USE THIS FORUM

system timer is millis() and counts in miliseconds.

1000 = 1 second.

there are a lot of variations for using BlinkWithoutDelay or BWD.

a simple and crude example is

if delay_sequence = low // button not pressed recently
if silence_switch, goes high // button gets pressed
then = millis() // lock in the time now
delay_sequence = high // set this to show silence timing is occurring

if delay_sequence = high
do your thing to silence the alarm // silence horn
duration = millis() - then // checks how long the timer is running
if duration >= your_period // 1000 = 1 second
do that thing to reset the alarm // alarm can go off if condition exists
delay_sequence = low // you can press silence button again if needed.

this is a very crude example sequence, not workable code.
duration and then should be unsigned longs

Have a look at using millis for timing for a deeper explanation

Alright so I’ve been very busy for the last couple months so this project took a backseat and I’m finally getting back to it. I’ve got some code written for it but it doesn’t seem to be working properly. When it reaches the high temp which triggers the alarm, it tends to just sound the alarm for 10s, then turn it off, then just go back on which leads to believe that its not recording the button presses, its just going off of the button snooze time (10s right now for testing purposes). I’ve still got the delay function in there as to not spam the web monitoring service I’m using (adafruit.io) too intensely, I plan to add a publish function using millis down the line too so that i don’t have to run any delays, but one step at a time.

I appreciate any advice anyone more knowledgeable/experienced can give me, thank you!

Hardware I’m using:
Particle Photon Board
Adafruit Si7021 Temp and Humidity Monitor
Generic LED’s
Generic Push Button Switch
Generic Piezo Buzzer

// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_Si7021.h>

// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_IO_Particle.h>
#include <Adafruit_IO_Client.h>

#define IO_USERNAME  "myusernamenotforyou"
#define AIO_KEY "Mykeyalsonotforyou"

TCPClient client;

//create AIO Client Object
Adafruit_IO_Client AIOClient = Adafruit_IO_Client(client, AIO_KEY);

Adafruit_IO_Feed feedTemp   = AIOClient.getFeed("ca-test.temperature");
Adafruit_IO_Feed feedHum = AIOClient.getFeed("ca-test.humidity");

// Connect Vin to 3-5VDC
// Connect GND to ground
// Connect SCL to I2C clock pin (D1 on Photon/Electron)
// Connect SDA to I2C data pin  (D0 on Photon/Electron)


Adafruit_Si7021 sensor = Adafruit_Si7021();
double h;
double t;

const int temp = 1.8*t+32; //convert c to F

const int yesLED = D2;
const int warmLED = D3;
const int hotLED = D4;
const int Buzzer = D5;
int Butt = D7;

const int hot = 25;
const int warm = 23;

const int SnoozeTime = 10000; //snooze duration, currently 30s
const int ReadDelay = 10000; //how fast data is read/published, currently every 10 seconds

//Variables

byte yesState = LOW;
byte warmState = LOW;
byte hotState = LOW;
byte ButtState = LOW;
byte BuzzerState = HIGH;

unsigned long readtime; // store time
unsigned long ButtPush = 0; // store last time button was pressed
unsigned long LastRead = 0; // store last time t&h was published
void setup() {
    
    AIOClient.begin();
    
    sensor.begin();
    
    pinMode(yesLED, OUTPUT);
    pinMode(warmLED, OUTPUT);
    pinMode(hotLED, OUTPUT);
    pinMode(Buzzer, OUTPUT);
    pinMode (Butt, INPUT);
    
    // Variable for IFTTT
    Particle.variable("t", &t, DOUBLE);
    Particle.variable("h", &h, DOUBLE);
}

void loop() {
    readtime = millis();
    
    h = sensor.readHumidity();
    int t = sensor.readTemperature();

    String temperature = String(t);
    String humidity = String(h);
    
    temperature = temperature.format("%1.2f", (1.8*t+32));
    
    if (digitalRead(Butt) == HIGH) {
        ButtPush = readtime; // update the time when button was pushed
    }
  

    Particle.publish("temperature", temperature, PRIVATE);
    Particle.publish("humidity", humidity, PRIVATE);
    feedTemp.send (String(temperature));
    feedHum.send (String(humidity));
    
    if (t >= hot) {
        if(readtime - ButtPush <= SnoozeTime) {
        digitalWrite(yesLED, LOW);
        digitalWrite(warmLED,  LOW);
        digitalWrite(hotLED, HIGH);
        digitalWrite(Buzzer, LOW);
        Particle.publish("We're quietly burning");
        }
        else{
        digitalWrite(yesLED, LOW);
        digitalWrite(warmLED,  LOW);
        digitalWrite(hotLED, HIGH);
        digitalWrite(Buzzer, HIGH);
        Particle.publish("We're burning up here");
        }   
    }
    
    else if (t >= warm) {
        digitalWrite(yesLED, LOW);
        digitalWrite(warmLED,  HIGH);
        digitalWrite(hotLED, LOW);
        digitalWrite(Buzzer, LOW);
        Particle.publish("T shirt weather baby");
    }
    if (t < warm) {
        digitalWrite(yesLED, HIGH);
        digitalWrite(warmLED, LOW);
        digitalWrite(hotLED, LOW);
        digitalWrite(Buzzer, LOW);
        Particle.publish("Saul Goodman");
    }
    
    delay (10000);
}

Here are a few tips that might help you solve your issue.

  • I noticed your code indentation and variable naming is not consistent (you clearly started in the right direction). Use the Arduino Tool → “Auto Format” function. You can adjust the formatting to your taste using a formatter.conf file. e.g.
# This configuration file contains a selection of the available options provided by the formatting tool "Artistic Style"
# http://astyle.sourceforge.net/astyle.html
#
# If you wish to change them, don't edit this file.
# Instead, copy it in the same folder of file "preferences.txt" and modify the copy. This way, you won't lose your custom formatter settings when upgrading the IDE
# If you don't know where file preferences.txt is stored, open the IDE, File -> Preferences and you'll find a link

mode=c

# 2 spaces indentation
indent=spaces=2

# also indent macros
indent-preprocessor

# indent classes, switches (and cases), comments starting at column 1
indent-classes
indent-switches
indent-cases
indent-col1-comments

# put a space around operators
 pad-oper
 
# Insert space padding around parent on the inside only. 
 --pad-paren-in -D

# put a space after if/for/while
 pad-header

# Move opening brackets onto new line
 --style=allman --style=bsd --style=break -A1

# Insert space padding around operators.
 --pad-oper
 
# if you like one-liners, keep them
 keep-one-line-statements
  • For the constants naming, many programmers use ALL_CAPITAL_UNDERSCORE e.g. OUTPUT, LOW and often you can see names with common prefix or post-fix e.g.

BUZZER_PIN, HOT_LED_PIN,
TEMPERATURE_LEVEL_HOT, TEMPERATURE_LEVEL_WARM

  • For variables the recommendation is to start with small letters and then camel case. Sometimes it is useful to include the type e.g.

int temperature;
String temperatureString;

This links the two variables for the reader. This would also change the following line

feedTemp.send (String(temperature)); → feedTemp.send (String(temperatureString));

which would raise the question whether it should be

feedTemp.send (temperatureString);

Maybe, maybe not. Please let me know.

  • If you change the following lines, they will become clearer and allow you to remove the comments

readtime = millis(); → timeNow = millis();

const int SNOOZE_DURATION = 10000; // you can also use defines
#define PUBLISH_INTERVAL 10000

unsigned long timeLastButtonPush = 0;
unsigned long timeLastPublish = 0;

  • The statement “if (t < warm) {” should just be an “else”. This will make the “else” part of the previous if statement. Right now, it is separate and will always be tested even if the previous part of the code was already true.

ElZesto:
I’ve still got the delay function in there as to not spam the web monitoring service I’m using (adafruit.io) too intensely, I plan to add a publish function using millis down the line too so that i don’t have to run any delays, but one step at a time.

You can simply comment the Particle.publish() lines and place some Serial.print() at each location while you write and debug your code.

  • The following line of code is not correct; it would create a one-time value. You could create a small function.

const int temp = 1.8*t+32;

int celciusToFahrenheit( int temperatureC ) // type could be float or double too
{
  return 1.8 * temperatureC + 32;
}

I hope this is helpful.

Klaus_K:
Here are a few tips that might help you solve your issue.

  • I noticed your code indentation and variable naming is not consistent (you clearly started in the right direction). Use the Arduino Tool → “Auto Format” function. You can adjust the formatting to your taste using a formatter.conf file. e.g.
# This configuration file contains a selection of the available options provided by the formatting tool "Artistic Style"

Artistic Style

If you wish to change them, don’t edit this file.

Instead, copy it in the same folder of file “preferences.txt” and modify the copy. This way, you won’t lose your custom formatter settings when upgrading the IDE

If you don’t know where file preferences.txt is stored, open the IDE, File → Preferences and you’ll find a link

mode=c

2 spaces indentation

indent=spaces=2

also indent macros

indent-preprocessor

indent classes, switches (and cases), comments starting at column 1

indent-classes
indent-switches
indent-cases
indent-col1-comments

put a space around operators

pad-oper

Insert space padding around parent on the inside only.

–pad-paren-in -D

put a space after if/for/while

pad-header

Move opening brackets onto new line

–style=allman --style=bsd --style=break -A1

Insert space padding around operators.

–pad-oper

if you like one-liners, keep them

keep-one-line-statements

I appreciate the tip on this but I’m not using arduino IDE so I’m not sure i can use these formatting tools. I’ll download it and copy my code over in the future to play with this formatting to clean up the code a little more. Currently I’m using a particle web IDE since it allows me to flash the devices with code over wifi, which is pretty beneficial since two of the devices are inside some outdoor freezers (not the ones im adding buttons to, but still convenient).

Klaus_K:
Here are a few tips that might help you solve your issue.

  • For the constants naming, many programmers use ALL_CAPITAL_UNDERSCORE e.g. OUTPUT, LOW and often you can see names with common prefix or post-fix e.g.

BUZZER_PIN, HOT_LED_PIN,
TEMPERATURE_LEVEL_HOT, TEMPERATURE_LEVEL_WARM

  • For variables the recommendation is to start with small letters and then camel case. Sometimes it is useful to include the type e.g.

int temperature;
String temperatureString;

This links the two variables for the reader. This would also change the following line

feedTemp.send (String(temperature)); → feedTemp.send (String(temperatureString));

which would raise the question whether it should be

feedTemp.send (temperatureString);

Maybe, maybe not. Please let me know.

I went back through the code and renamed things and thank you for the tip for good habits, its much easier to understand now. I wasn’t able to figure out how to change the string code you were talking about with out getting a string not defined in this scope error in compilation so i’m just going to leave it for now.

Thanks for the advice overall, this is the first actual program I’ve made its been quite the learning experience. I really appreciate your time in letting me know how to form good habits while learning this stuff. I won’t be able to test this code until monday at the earliest when I’m back at work but it still could be longer. My job is actually a CAM programmer and CAD designing so this is more of a side project I’ve been developing on downtime.

Here’s the updated code, hope it should look better now :slight_smile: :

// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_Si7021.h>

// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_IO_Particle.h>
#include <Adafruit_IO_Client.h>

#define IO_USERNAME  "MY_USERNAME"
#define AIO_KEY "MY_KEY"

TCPClient client;

//create AIO Client Object
Adafruit_IO_Client AIOClient = Adafruit_IO_Client(client, AIO_KEY);

Adafruit_IO_Feed feedTemp   = AIOClient.getFeed("ca-test.temperature");
Adafruit_IO_Feed feedHum = AIOClient.getFeed("ca-test.humidity");

// Connect Vin to 3-5VDC
// Connect GND to ground
// Connect SCL to I2C clock pin (D1 on Photon/Electron)
// Connect SDA to I2C data pin  (D0 on Photon/Electron)


Adafruit_Si7021 sensor = Adafruit_Si7021();
double h;
double t;
//-----Constants

int celciusToFahrenheit( int temperatureC ) // type could be float or double too
{
  return 1.8 * temperatureC + 32;
}

const int YES_LED_PIN = D2;
const int WARM_LED_PIN = D3;
const int HOT_LED_PIN = D4;
const int BUZZER_PIN = D5;
int BUTTON_PIN = D7;

const int hot = 25;
const int warm = 23;

const int SnoozeDuration = 10000; //snooze duration, currently 30s
const int ReadDelay = 10000; //how fast data is read/published, currently every 10 seconds

//Variables

byte yesState = LOW;
byte warmState = LOW;
byte hotState = LOW;
byte ButtState = LOW;
byte BuzzerState = HIGH;

unsigned long timeNow = 0; // store time
unsigned long timeLastButtonPush = 0; // store last time button was pressed
unsigned long timeLastPublish = 0; // store last time t&h was published


void setup() {
    
    AIOClient.begin();
    
    sensor.begin();
    
    pinMode(YES_LED_PIN, OUTPUT);
    pinMode(WARM_LED_PIN, OUTPUT);
    pinMode(HOT_LED_PIN, OUTPUT);
    pinMode(BUZZER_PIN, OUTPUT);
    pinMode (BUTTON_PIN, INPUT);
    
    // Variable for IFTTT
    Particle.variable("t", &t, DOUBLE);
    Particle.variable("h", &h, DOUBLE);
}

void loop() {
    timeNow = millis();
    
    h = sensor.readHumidity();
    int t = sensor.readTemperature();

    String temperature = String(t);
    String humidity = String(h);
    
    temperature = temperature.format("%1.2f", (1.8*t+32));
    
    if (digitalRead(BUTTON_PIN) == HIGH) {
        timeLastButtonPush = timeNow; // update the time when button was pushed
    }
  

    Particle.publish("temperature", temperature, PRIVATE);
    Particle.publish("humidity", humidity, PRIVATE);
    feedTemp.send (String(temperature));
    feedHum.send (String(humidity));
    
    if (t >= hot) {
        if(timeNow - timeLastButtonPush >= SnoozeDuration) {
        digitalWrite(YES_LED_PIN, LOW);
        digitalWrite(WARM_LED_PIN,  LOW);
        digitalWrite(HOT_LED_PIN, HIGH);
        digitalWrite(BUZZER_PIN, LOW);
        Particle.publish("We're quietly burning");
        }
        else{
        digitalWrite(YES_LED_PIN, LOW);
        digitalWrite(WARM_LED_PIN,  LOW);
        digitalWrite(HOT_LED_PIN, HIGH);
        digitalWrite(BUZZER_PIN, HIGH);
        Particle.publish("We're burning up here");
        }   
    }
    
    else if (t >= warm) {
        digitalWrite(YES_LED_PIN, LOW);
        digitalWrite(WARM_LED_PIN,  HIGH);
        digitalWrite(HOT_LED_PIN, LOW);
        digitalWrite(BUZZER_PIN, LOW);
        Particle.publish("T shirt weather baby");
    }
    else if (t < warm) {
        digitalWrite(YES_LED_PIN, HIGH);
        digitalWrite(WARM_LED_PIN, LOW);
        digitalWrite(HOT_LED_PIN, LOW);
        digitalWrite(BUZZER_PIN, LOW);
        Particle.publish("Saul Goodman");
    }
    
    delay (10000);
}