Programming Help with Water Detection Project

I’m having an issue with programming a water detection unit. I’m having an issue with coding. I’m still relatively new at it, so I do apologize. I found a project from a guy online that wanted to make a water detection system for his Chickens. I want to do the same thing, but I would like it to tell me when two levels of water are being detected. Like a warning and then a critical alert. My first alert for warning is working and the LED light comes in contact when I make the connection, but the Urgent alert does not. I’d also like to create a check in for every 12 hours just to make sure it’s working. Currently I’m using Pushbullet for this.

Credit: https://www.hackster.io/me-myself-and-i/eggscellent-water-level-notification-system-b4a9ba#other-projects

Can someone help me figure this out please?

// This #include statement was automatically added by the Particle IDE.
#include "elapsedMillis/elapsedMillis.h"

// This #include statement was automatically added by the Particle IDE.
#include "elapsedMillis/elapsedMillis.h"

String _version = "0.04";

//this reads the flood sensor every 2 seconds
#define FLOOD_READ_INTERVAL 2000

//this defines the frequency of the notifications sent to the user
#define FLOOD_FIRST_ALARM 10000 //10 seconds
#define FLOOD_SECOND_ALARM 60000 //1 minute
#define FLOOD_THIRD_ALARM 300000 //5 minutes
#define FLOOD_FOURTH_ALARM 900000 //15 minutes
#define FLOOD_FIFTH_ALARM 3600000 //1 hour
#define FLOOD_SIXTH_ALARM 14400000 //4 hours - and every 4 hours ever after, until the situation is rectified (ie no more water is detected)

#define FLOOD_NOTIF "FLOOD"

elapsedMillis flood_timer;
elapsedMillis flood_alarm_timer;

int flood_alarms_array[6]={FLOOD_FIRST_ALARM, FLOOD_SECOND_ALARM, FLOOD_THIRD_ALARM, FLOOD_FOURTH_ALARM, FLOOD_FIFTH_ALARM, FLOOD_SIXTH_ALARM};
int flood_alarm_index = 0;
bool flood_detected = false;
unsigned long flood_next_alarm = 0;

int FLOOD_SENSOR = D0;
int LED = D7;

void setup() {
 pinMode(FLOOD_SENSOR, INPUT_PULLUP);
 pinMode(LED, OUTPUT);
 Spark.publish("device starting", "Firmware version: " + _version, 60, PRIVATE);
}

void loop() {

    flood_check();
    
    if ( flood_detected ) {
        flood_notify_user();
    }
}

/*******************************************************************************
 * Function Name  : flood_check
 * Description    : check water leak sensor at FLOOD_READ_INTERVAL, turns on led on D7 and raises alarm if water is detected
 * Return         : 0
 *******************************************************************************/
int flood_check()
{
    if (flood_timer < FLOOD_READ_INTERVAL) {
        return 0;
    }
    
    //time is up, so reset timer
    flood_timer = 0;

    if (digitalRead(FLOOD_SENSOR)) {
        
        //if flood is already detected, no need to do anything, since an alarm will be fired
        if (flood_detected){
            return 0;
        }
        
        flood_detected = true;
    
        //reset alarm timer
        flood_alarm_timer = 0;

        //set next alarm
        flood_alarm_index = 0;
        flood_next_alarm = flood_alarms_array[0];
        
        digitalWrite(LED,HIGH);
    } else {
        
        digitalWrite(LED,LOW);
        flood_detected = false;
    }
    return 0;
}

/*******************************************************************************
 * Function Name  : flood_notify_user
 * Description    : will fire notifications to user at scheduled intervals
 * Return         : 0
 *******************************************************************************/
int flood_notify_user()
{

    if (flood_alarm_timer < flood_next_alarm) {
        return 0;
    }

    
    //time is up, so reset timer
    flood_alarm_timer = 0;
    
    //set next alarm or just keep current one if there are no more alarms to set
    if (flood_alarm_index < arraySize(flood_alarms_array)-1) {
        flood_alarm_index = flood_alarm_index + 1;
        flood_next_alarm = flood_alarms_array[flood_alarm_index];
    }

    //send an alarm to user (this one goes to the dashboard)
    Spark.publish(FLOOD_NOTIF, "Chickens need water!", 60, PRIVATE);

    //send an alarm to user (this one goes to pushbullet servers)
    Spark.publish("pushbullet", "Chickens need water!", 60, PRIVATE);
   
   return 0; 
}

@xdiminishedx, I republished the original code as yours was unformatted and and not very readable. One thing right off the bat is that this is old code using Spark.publish() which is now replaced with Particle.publish().

The elapsedMillis timer variables flood_timer and flood_alarm_timer are deceiving in that elapsedMillis increments these values “in the background”. So a line like this in flood_check():

    if (flood_timer < FLOOD_READ_INTERVAL) {

compares the (background incrementing) flood_timer value with defined interval of 2000 milliseconds and will skip the sensor check if the value is less. This causes the sensor to only be check every 2 seconds. Note that after 2 seconds, the flood_alarm_timer is reset to zero so the count can begin again.

The flood_alarms_array[] array contains the “escalating” time values for the notification delays. It is used to set the flood_next_alarm to be compare with the (background incrementing) flood_alarm_timer to trigger the user notification. It seems that each time a notification is triggered, the next interval in the flood_alarms_array[] is used until the last (4 hours) is loaded and remains as the interval until it is reset in flood_check() then the flood sensor no longer indicates a flood. Then the cycle restarts at the next flood detection.

When you say “urgent alert”, I assume you mean the very first alert? The sensor input is set for INPUT_PULLUP so the input needs to be normally grounded, otherwise it will always indicate a flood condition. With water present, this is done by having on electrode on GND and the other to the GPIO pin input (D0).

You can create, using the same elapsedMillis approach used in the code, a 12 hour timer for publishing an “I’w working” event. The code could be placed in loop() or in a function called from loop()

2 Likes