Arduino Yún Tweet Waterlevel Tool

  • Posted on: 30 July 2014
  • By: jimusik

This build created a box that monitors water level and sends an ALARM tweet when the sump can't keep up with the water flow.  Design for St. Paul's who's current system sends an audible alarm in a basement closet when the building floods.  

Built using the following components:

  1. Arduino Yún - www.sparkfun.com/products/12053
  2. eTape Liquid Level Sensor 8" - https://www.sparkfun.com/products/10221
  3. Red Enclosure - https://www.sparkfun.com/products/11366
  4. A Red and a Green LED
  5. A Switch (to force a tweet)
  6. Mono 1/8" Female jacks
  7. Various cables and resistors

Key elements:

  • The eTape is very sensitive.  Any tweaking of the tape changes the resistance level.  It functions by connecting the 3.3V power off the board, running it through a 10k resistor and adding the tape inline to Ground.  I cut a groove on the inside of the PVC since it was just barely to small to fit the tape and kept increasing the groove until I received the level's intended for my circuit.  
  • I had to follow Temboo's instructions to store key datapoints on an SD card.  This freed up enough RAM to actually send the tweets, otherwise it erros out.  
  • I initially didn't ground out the button and was just sending 3.3v to the digital input.  It worked for some reason at the beginning then started getting stray voltage input since it didn't have a pull-down resistor.  So resoldered the switch and added the ground and moved the resistor from the 3.3v line to the ground.  Works without issues now.
  • Wireless signal.  I'm getting about 40% in the room I need the device in which turns out to be just too low for the Yún to connect.

 

/*
  WaterLevelTweet - Built from Temboo Tweet Example JDDesignLLC
*/

#include <Bridge.h> //to talk with open-wrt side of board
#include <Temboo.h> //to deal with twitter api
#include <Process.h> //to get date from bridge
#include "TembooAccount.h" // contains Temboo account information
#include <Console.h> //to activate the network console for debugging

Process date;                 // process used to get the date
int hours, minutes, seconds;  // for the results
int lastMinute = -1;          // need an impossible value for comparison
int lastSecond = -1;          // need an impossible value for comparison

int numRuns = 1;   // execution count, so this sketch doesn't run forever
int levelstrip = A0; //input with resistance over the eTape (range 30-90)
int GREENLED = 8; //set pint 8 for the Green LED
int REDLED = 13; //set pin 13 for the Red LED (this also has an LED on the board)
int waterlevel = 90; //setting water level to 90 for no input 
int button = 7; // set button input on digital pin 6
int buttonstatus = 0; //set button status to 0
int x = 0;
int alarm = 0; //says what text to send 0 = update 1 = alarm
String time, timeh, timem, tweetText; //for string time, time hours, time minutes and tweetText that goes into the tweet

void setup() {
  Bridge.begin(); //activate communication to linux
  Console.begin(); //start the network console instead of serial connection
  
 // while(!Console){;}//for debugging, wait until console is connected (comment out line later)
  delay(4000);
  
  Console.println("Initializing...");  // sends info that it's functioning
    
  if (!date.running())  { //get date to start from
    date.begin("date");
    date.addParameter("+%T");
    date.run();
                         }
  
  pinMode(levelstrip, INPUT); //activate port for the etape
  pinMode(GREENLED, OUTPUT);  //activate port for the green LED
  pinMode(REDLED, OUTPUT);  //activate port for the red LED
  pinMode(button, INPUT);  //activate port for the button input
  
}

void loop()  //this section runs and pulls data based on inputs
{
  digitalWrite(GREENLED, HIGH);  //Turn the green LED on
  delay(100); // wait 100 ms
  buttonstatus = digitalRead(button); //check button status and store
  
  gettime(); //run the date process
  
  if(lastMinute != minutes) {  //run every minute
    Console.print("TIME: ");  //print the time to the console
  Console.println(time);
  waterlevel = analogRead(levelstrip); //check the water level
  
  //wait for connector to be installed (input will jump between 700 and 1024 in unplugged
  while(waterlevel > 600) {
  if (x == 0) Console.println("ERROR: Is Sensor Connected?"); //send error only once
  x = 1;
  waterlevel = analogRead(levelstrip); //test level constantly until plugged in 
  digitalWrite(REDLED, HIGH); //flash red light in odd pattern
  delay(100);
  digitalWrite(REDLED, LOW);
  delay(100);
  digitalWrite(REDLED, HIGH); 
  delay(50);
  digitalWrite(REDLED, LOW);
  delay(500);
                      }
  Console.print("Current Analog Read: "); //tell console the waterlevel every minute
  Console.println(waterlevel);
  x = 0; //reset the test to print info only once in while loop
  }
  
  if(buttonstatus == HIGH){  //when button pressed, note in console and send update tweet
    Console.println("Sending update tweet from button");   
    alarm = 0;
    sendtweet();
                            }
                            
 if(time == "12:00"){ //send daily check in at Noon
   Console.println("Sending update tweet");
   Console.println("Noon clause was activated:");
   alarm = 0;
   sendtweet();
                 }
                 
  if(waterlevel < 35) { //when waterlevel is close to max, send alarm tweet
    Console.println("Sending alarm tweet");
    alarm = 1;
    sendtweet();
                       }
  
  digitalWrite(GREENLED, LOW); // turn off green led so it blinks regularly
  delay(100); 
  
}  

void gettime() {
  if(lastSecond != seconds) {  // if a second has passed  
  //storage of time for tweet
    if (hours <= 9)  timeh = String("0" + String(hours));
    if (hours >= 10) timeh = String(hours);
    if (minutes <= 9) timem = String("0" + String(minutes));  // adjust for 0-9
    if (minutes >= 10) timem = String(minutes);  // adjust for 0-9
    time = String(timeh + ":" + timem);
    
    // restart the date process:
    if (!date.running())  {
      date.begin("date");
      date.addParameter("+%T");
      date.run();
                           }
  }
  //if there's a result from the date process, parse it:
  while (date.available()>0) {
    // get the result of the date process (should be hh:mm:ss):
    String timeString = date.readString();   

    // find the colons:
    int firstColon = timeString.indexOf(":");
    int secondColon = timeString.lastIndexOf(":");

    // get the substrings for hour, minute second:
    String hourString = timeString.substring(0, firstColon); 
    String minString = timeString.substring(firstColon+1, secondColon);
    String secString = timeString.substring(secondColon+1);

    // convert to ints,saving the previous second:
    hours = hourString.toInt();
    lastMinute = minutes;          // save to do a time comparison
    minutes = minString.toInt();
    lastSecond = seconds;          // save to do a time comparison
    seconds = secString.toInt();
                              } 

}

void sendtweet()
{  
  Console.println("Running SendATweet - Run #" + String(numRuns++) + "...");
  
  if (alarm == 1){
    tweetText = String("Current Status: Alarm from RedBoxWaterLevel. Waterlevel: " + String(waterlevel) + " Time: " + String(time));
    Console.println(tweetText);
                }
    if (alarm == 0) {
    tweetText = String("Current Status: Update from RedBoxWaterLevel. Waterlevel: " + String(waterlevel) + " Time: " + String(time));
    Console.println(tweetText);
                }
    
    TembooChoreo StatusesUpdateChoreo;

    // invoke the Temboo client
    // NOTE that the client must be reinvoked, and repopulated with
    // appropriate arguments, each time its run() method is called.
    StatusesUpdateChoreo.begin();
    


    // identify the Temboo Library choreo to run (Twitter > Tweets > StatusesUpdate)
    StatusesUpdateChoreo.setChoreo("/Library/Twitter/Tweets/StatusesUpdate");

    StatusesUpdateChoreo.setSettingsFileToRead("/mnt/sda1/tweetSettings");

    // and the tweet we want to send
    StatusesUpdateChoreo.addInput("StatusUpdate", tweetText);

    // tell the Process to run and wait for the results. The 
    // return code (returnCode) will tell us whether the Temboo client 
    // was able to send our request to the Temboo servers
    unsigned int returnCode = StatusesUpdateChoreo.run();

    // a return code of zero (0) means everything worked
    if (returnCode == 0) {
        Console.println("Success! Tweet sent!");
    } else {
      // a non-zero return code means there was an error
      // read and print the error message
      while (StatusesUpdateChoreo.available()) {
        char c = StatusesUpdateChoreo.read();
        Console.print(c);
      }
    } 
    StatusesUpdateChoreo.close();

    // do nothing for the next 90 seconds
    Console.println("Waiting..."); 
    if (alarm == 1) {    //alarm
    for (int i = 0; i < 61; i++) {// FLASH RED LED
       digitalWrite(REDLED, HIGH); 
       delay(500);
       digitalWrite(REDLED, LOW);
       delay(500);
                                 }
                    }
    if (alarm == 0) { //update
       for (int i = 0; i < 61; i++) {// FLASH RED and Green LED
       digitalWrite(REDLED, HIGH);
       digitalWrite(GREENLED, HIGH);
       delay(500);
       digitalWrite(REDLED, LOW);
       digitalWrite(GREENLED, LOW);
       delay(500);
                                 }
                     }
}