Time-Automated Data Logger

 

Here's a very useful project that's easy to put together! It's a time-automated data logger! You can instruct the Arduino x Andee to automatically start and stop logging sensor information from a user specified dates and times. You can also set the frequency of each data point too!

And the best part? All data will be stored on an SD Card (which you insert into the Annikken Andee) as a CSV file so that you can easily open it up as a spreadsheet and plot graphs if you need to.

To demonstrate the data logging capabilities of the Andee, I have made a simple temperature data logger using a TMP36 temperature sensor. We will just record the date/time of each data point and sensor-read temperature.

Data Logger in Action

Here's how the user interface looks on the smartphone when you just start up the Arduino x Andee:

2013-11-08 19.22.56.png


Once you've set the start and end dates and timings, the buttons will change to displays, like so:

2013-11-08 19.27.14.png


Now all we've got to do now is to wait until the scheduled data logging begins!

Data logging has started!

2013-11-08 19.29.29.png


We've set the Arduino x Andee to log data once every 5 seconds. So, every 5 seconds, the temperature at the captured time will be stored onto the SD Card as a CSV (comma-separated values) file.

Once data logging is complete, you can remove the SD Card from the Annikken Andee and insert it into your computer. Since it is a CSV file, you can easily open it up using Excel or some other spreadsheet software, and use the data points to plot a graph like this:

Excelchart datalogging screenshot.png


And that's how our time-automated data logger works with the Arduino and Annikken Andee!

The Setup

Setup is really easy. It just involves connecting a TMP36 temperature sensor to the Arduino x Andee, like this:

2013-11-08 19.23.59.jpg


You can refer to the guide on how to connect the TMP36 to the Arduino by Adafruit Learning System

For better precision in my readings, I have attached the VCC pin of the TMP36 to the 3.3V pin as well as to the AREF pin so that I can use the 3.3V as my analog reference.

If you do this, be sure to add "analogReference(EXTERNAL);" in the setup() function of your code.

If you don't have a temperature sensor, you might be able to use your Arduino to do the job! Certain models, like the Arduino Uno, have a temperature sensor built in! If you want to find out which Arduino model has a built-in temperature sensor, and how you can make use of it, refer to this guide at the Arduino Playground.

The Code

Here's the code to get the Arduino x Andee working as a data logger!

#include <SPI.h> // These are the essential libraries you need
#include <Andee.h>
#include <String.h>

AndeeHelper displayCurrentInfo; // Display current date/time and temperature reading
AndeeHelper btnStartTime; // Button to schedule start time of logging
AndeeHelper btnStartDate; // Button to schedule start date of logging
AndeeHelper btnEndTime; // Button to schedule end time of logging
AndeeHelper btnEndDate; // Button to schedule end date of logging
AndeeHelper btnSetLogFreq; // Button to set logging frequency (in seconds)
AndeeHelper displayLogStatus; // Display logging status
const int pinTempSensor = A0; // Our temp sensor is connected to pin A0

// String buffers to store the contents of sprintf() before displaying them
char outputString[50];
char tempStr[50];

// Flags
int clockOK = 0; // Flag to check whether a set of instructions have been run once
int flagLogging = 0; // Flag to indicate whether logging has started or not

// Date/time variables for start, end, and current. Start and end variables
// are initialised as 99 to indicate that the time/date hasn't been configured
int s_hh = 99, s_mm = 99, s_ss = 99, s_d = 99, s_m = 99, s_y = 99;
int e_hh = 99, e_mm = 99, e_ss = 99, e_d = 99, e_m = 99, e_y = 99;
int hh, mm, ss, d, m, y;
int freq = 0; // Frequency in seconds
int logcount = 0; // Counter
long timenow; // Store timestamp
long timeold; // Store old timestamp to check if time is due for the next log

// Variables necessary for SD card read/write
char filename[] = "log.csv";
int offset=0;
char errorMsgBuffer[64];

void setup()
{
  Andee.begin(); // Sets up the communication link between Arduino and the Annikken Andee
  Andee.clear(); // Clear the screen of any previous displays
  setInitialData(); // Define objects to be drawn on the screen
  
  analogReference(EXTERNAL); // External analog reference in use for temp sensor
  
  // Write table headers to SD card
  sprintf(outputString, "Time, Temperature\n");
  offset = Andee.writeSD(filename, outputString, offset, errorMsgBuffer);
  
  // Show error message on screen if there's a problem, e.g. no SD card found
  if(offset == -1) displayLogStatus.updateData(errorMsgBuffer);
  
  delay(1000);
}

void setInitialData()
{  
  displayCurrentInfo.setId(0);
  displayCurrentInfo.setType(DATA_OUT);
  displayCurrentInfo.setLocation(0,0,FULL);
  displayCurrentInfo.setTitle("Arduino x Andee DataLogger");
  displayCurrentInfo.setData("");
  
  btnStartTime.setId(1);
  btnStartTime.setType(TIME_IN);
  btnStartTime.setLocation(1,0,ONE_QUART);
  btnStartTime.setTitle("Set Start Time");
  
  btnStartDate.setId(2);
  btnStartDate.setType(DATE_IN);
  btnStartDate.setLocation(1,1,ONE_QUART);
  btnStartDate.setTitle("Set Start Date");
  
  btnEndTime.setId(3);
  btnEndTime.setType(TIME_IN);
  btnEndTime.setLocation(1,2,ONE_QUART);
  btnEndTime.setTitle("Set End Time");
  
  btnEndDate.setId(4);
  btnEndDate.setType(DATE_IN);
  btnEndDate.setLocation(1,3,ONE_QUART);
  btnEndDate.setTitle("Set End Date");
  
  btnSetLogFreq.setId(5);
  btnSetLogFreq.setType(KEYBOARD_IN);
  btnSetLogFreq.setKeyboardType(ANDROID_NUMERIC);
  btnSetLogFreq.setLocation(2,0,FULL);
  btnSetLogFreq.setTitle("Set Logging Frequency (in seconds)");
  
  displayLogStatus.setId(6);
  displayLogStatus.setType(DATA_OUT);
  displayLogStatus.setLocation(3,0,FULL);
  displayLogStatus.setTitle("Logging Status");
  displayLogStatus.setData("Waiting to Start");
} 

double getTemp()
{
  // Reads analog sensor reading, and translates sensor reading to
  // temperature in degrees Celsius
  return ((analogRead(pinTempSensor) * 3.3 / 1024.0) - 0.5) * 100.0;
}

void loop()
{
  // Button Actions
  if(btnStartTime.isPressed())
  {
    // Get time input and store hour, min, seconds into these three variables
    btnStartTime.getTimeInput(&s_hh, &s_mm, &s_ss);
    btnStartTime.ack();

    // Once user has input time, change button to a display and show the start time
    sprintf(tempStr, "%02d:%02d:%02d", s_hh, s_mm, s_ss);
    btnStartTime.setType(DATA_OUT);
    btnStartTime.setTitle("Start Time");
    btnStartTime.setData(tempStr);
    btnStartTime.update();
  }
  if(btnEndTime.isPressed())
  {
    // Get time input and store hour, min, seconds into these three variables
    btnEndTime.getTimeInput(&e_hh, &e_mm, &e_ss);
    btnEndTime.ack();

    // Once user has input time, change button to display and show the end time
    sprintf(tempStr, "%02d:%02d:%02d", e_hh, e_mm, e_ss);
    btnEndTime.setType(DATA_OUT);
    btnEndTime.setTitle("End Time");
    btnEndTime.setData(tempStr); 
    btnEndTime.update();
  }
  if(btnStartDate.isPressed())
  {    
    // Get date input and store day, month, year into these three variables
    btnStartDate.getDateInput(&s_d, &s_m, &s_y);
    btnStartDate.ack();
 
    // Change button to display and show start date   
    sprintf(tempStr, "%02d/%02d/%4d", s_d, s_m, s_y);    
    btnStartDate.setType(DATA_OUT);
    btnStartDate.setTitle("Start Date");
    btnStartDate.setData(tempStr); 
    btnStartDate.update(); 
  }
  if(btnEndDate.isPressed())
  {    
    // Get date input and store day, month, year into these three variables
    btnEndDate.getDateInput(&e_d, &e_m, &e_y);
    btnEndDate.ack();

    // Change button to display and show end date
    sprintf(tempStr, "%02d/%02d/%4d", e_d, e_m, e_y); 
    btnEndDate.setType(DATA_OUT);
    btnEndDate.setTitle("End Date");
    btnEndDate.setData(tempStr);   
    btnEndDate.update(); 
  }
  if(btnSetLogFreq.isPressed())
  {
    // Get user input for logging frequency (in seconds)
    btnSetLogFreq.getKeyboardMessage(tempStr);
    btnSetLogFreq.ack();
    
    freq = atoi(tempStr); // Convert from string to int

    // Change button to display, showing frequency
    btnSetLogFreq.setType(DATA_OUT);
    btnSetLogFreq.setTitle("Logging Frequency");
    sprintf(tempStr, "Every %d seconds", freq);
    btnSetLogFreq.update(); 
  }

  // If smartphone is JUST connected to the Andee.
  // Runs this code once at the start of connection  
  if(Andee.isConnected() && clockOK == 0)
  {
    clockOK = 1; // Flags that Andee is connected and we're ready to roll
    
    displayCurrentInfo.update();
    btnStartTime.update();
    btnStartDate.update();
    btnEndTime.update();
    btnEndDate.update();
    btnSetLogFreq.update(); 
    displayLogStatus.update();
    // We're drawing these just once as the buttons don't need to be frequently updated. This is done to conserve system resources.
  }

  // Upon disconnect, reset flag
  if(!Andee.isConnected() && clockOK == 1)
  {
    clockOK = 0;
  }

  // Whenever the Andee is connected, do these things:
  if(Andee.isConnected())
  {
    Andee.getDeviceTime(&hh, &mm, &ss); // Get current time
    Andee.getDeviceDate(&d, &m, &y); // Get current date
    dtostrf(getTemp(), 5, 2, tempStr); // Convert float value to string
    timenow = Andee.getDeviceTimeStamp(); // Get current time stamp
    // Timestamp refers to the system time in seconds. 
    // We're going to calculate the difference in timestamps for greater 
    // accuracy in our logging frequency. Doing this will ensure that our 
    // logs are on time

    // Put all these stuff together into a string    
    sprintf(outputString, "%d-%02d-%02d %02d:%02d:%02d, %s\n", y, m, d, hh, mm, ss, tempStr);

    // If current time/date is now the schedule time/date to start logging    
    if(s_hh == hh && s_mm == mm && s_ss >= ss && s_d == d && s_m == m && s_y == y && flagLogging == 0)
    {
      timeold = timenow; 
      flagLogging = 1; // Activate logging flag
      displayCurrentInfo.setColor(RED);
      displayCurrentInfo.setTitleColor(RED);
      displayCurrentInfo.setTitle("Logging in Progress");
    }     

    // If we just started logging, or difference in timestamp equals logging frequency, write current temperature into SD card      
    if(flagLogging == 1 && (timenow - timeold >= freq || timenow - timeold == 0))
    {
      timeold = timenow;
      sprintf(outputString, "%d-%02d-%02d %02d:%02d:%02d, %s\n", y, m, d, hh, mm, ss, tempStr);
      offset = Andee.writeSD(filename, outputString, offset, errorMsgBuffer);
      if(offset == -1) displayLogStatus.updateData(errorMsgBuffer);
      else
      {
        logcount++; // Increase counter
        sprintf(tempStr, "No. of Entries Logged: %d", logcount);
        displayLogStatus.setData(tempStr);
        displayLogStatus.update();
      }
    }

    // If we are in the midst of logging, and the current time/date is now the scheduled time/date to stop logging    
    if(e_hh == hh && e_mm == mm && e_ss >= ss && e_d == d && e_m == m && e_y == y && flagLogging == 1)
    {
      flagLogging = 0; // Reset flag to stop logging
      displayCurrentInfo.setColor(BLUE);
      displayCurrentInfo.setTitleColor(BLUE);
      displayCurrentInfo.setTitle("Logging Complete!");
    }       
      
    // Print current time
    displayCurrentInfo.setData(outputString);
    displayCurrentInfo.update();
  } 
  delay(500); // Refresh displays every 0.5 second
}
comments powered by Disqus