Greenhouse project part 1

Description and Plan

Part 1. Data Logging

teensy_32.png

Figure 1: Teensy 3.2 wiring diagram from PJRC

For this part of the greenhouse project, I want to properly wire two temperature sensory to the teensy and read their inputs to serial. Then, I will write C++ code to sample the data streams at a regular interval and either take an average or something and write it to a file, timestamped to the SD card. Also have the light blink on data acquisition. This will be an important lesson for me in writing code to monitor and sample data. Interrupts, buffers, writing to disk, and handling data streams are all things I need to account for. Also, this provides some ability to compare the data from two sensors at the same time. How well can I process this input? This stack overflow link contains some interesting points about data logging.

Parts needed:

Wiring

Also, for wiring see this and use the analogous pins on the teensy. SPI pins for the teensy are used for writing and reading data from the SD card. SPI stands for Serial Peripheral Interface Bus, it is a method that allows for short distance communication between a master device (the teensy in this case) and one or more slave devices (the SD card breakout in this case). Read more about the SPI on Wikipedia.
I broke down the pinout here. This link provides a guide for a similar card, I also used this guide for SPI ports from the PJRC website to get this pin guide

Teensy pin SD Breakout pin
not used here CD
MISO pin 12 DO
GND GND
SCK pin 13 SCK
3.3V VCC
MOSI pin 11 DI
SS pin 10 CS

Here is a Fritzing Diagram for clarity.

data_logger_wiring.png

Figure 2: Wiring diagram for SD card reader

Verify SD card wiring

Now I want to make sure the basic read/write capability is working for the card. So I will use some basic test code for reading and writing to SD cards to test it. Use this library for that

  • Once the SD card reader is wired up, this is a nice Arduino sketch that you can upload to test the drive and verify taht everyting is working. The sketch can be found here. The links on this page have excellent documentation for the SD library and other important background information.

Using the TMP36 temperature sensor

Now I am going to hook up the temperature sensor to the teensy. This guide from Adafruit is an excellent reference. Below, I have provided a breadboard view of my Teensy 3.2 wired to the SD card reader and two temperature sensors. Temperature sensor 1 is hooked up to analog pin 14 and Temperature sensor 15 is hooked up to analog pin 1.

temperature_sensors_bb.png

Figure 3: Wiring diagram for two temperature sensors

Now lets make sure they work. We will simply use the Arduino IDE to read the temperatures and display them to the serial monitor. Use the following sketch.

Sketch is located here
This sketch is based on this example from Adafruit.

// wiring two TMP36 sensor to read temperature
const int ref_voltage = 3.3;
const int sensor_1 = 14;
const int sensor_2 = 15;

void setup() {

Serial.begin(115200);
Serial.print("Starting up");

}

void loop() {
  // read the sensors
  int reading_sensor_1 = analogRead(sensor_1);
  int reading_sensor_2 = analogRead(sensor_2);
  // convert to voltage
  float voltage_1 = reading_sensor_1*ref_voltage;
  float voltage_2 = reading_sensor_2*ref_voltage;
  float  voltage_1 /= 1024.0;
  float voltage_2 /= 1024.0;
  // convert to temperature
  Serial.println("Celcius");
  float tempC_1 = (voltage_1 - 0.5)*100;
  float tempC_2 = (voltage_2 - 0.5)*100;
  float average_celcius = (tempC_1+tempC_2)/2;
  Serial.print("Average reading "); Serial.print(average_celcius); Serial.println(" degrees F");
  Serial.println("Farenheight");
  float tempf_1 = (tempC_1 * 9.0 /5.0) +32.0;
  float tempf_2 = (tempC_2 * 9.0 /5.0) +32.0;
  float average_farenheight = (tempf_1 + tempf_2) /2;
 // farenheight
  Serial.print("Average reading "); Serial.print(average_farenheight); Serial.println(" degrees F");
  delay(1000);

}


Recording data from temperature sensors

For the next step in the data logger portion of this project, I want to aggregate all the data that I have been printing to the serial port add it to a CSV file along with some kind of timestamp. In Python, you have to first check if a file exists if you want to append data to it, as opening a file with 'write' permissions will overwrite any data already in it. I started writing a function to check if the file existed and create it if not– not too difficult, but I was having trouble figuring out how to return a file object from a function in C++. While I was searching, I actually read the documentation for the Arduino SD.h library and saw that the write operation appends data to the end of the file automatically! Great news, now all I had to do now was check if the file existed and create it if not, then proceed with writing the data I had to disk at a regular interval.
The hardest part was concatinating all the data into a string to write to the disk. As you can see, my += operations after every variable are messy. But this is only a first attempt and I will clean it up next weekend. Here is the code and the updated wiring diagram.

temperature_logger_with_indicatorLED_bb.png

Figure 4: Temperature logger Wiring diagram with indicator LED

/*
  SD Temperature logger
  Author: Nick George
  Contact: [email protected]
  nickgeorge.net
 */

#include <SPI.h>
#include <SD.h>

File temperature_log;

const int chipSelect = 10;
const int sensor_1 = 14;
const int sensor_2 = 15;
const int ref_voltage = 3.3;
const int indicator_led = 9;
int timer = 0;


void setup() {
  Serial.begin(115200);
  pinMode(indicator_led, OUTPUT);
  card_check();
  data_check();

}
void loop() {
  // read the sensors
  String dataString = timer;
  dataString += ",";
  int reading_sensor_1 = analogRead(sensor_1);
  int reading_sensor_2 = analogRead(sensor_2);
  // convert to voltage
  float voltage_1 = reading_sensor_1 = reading_sensor_1 *ref_voltage;
  float voltage_2 = reading_sensor_2 = reading_sensor_2 *ref_voltage;
  voltage_1 /= 1024.0;
  voltage_2 /= 1024.0;
  // convert to temperature
  float tempC_1 = (voltage_1 - 0.5)*100;
  dataString += tempC_1;
  dataString += ",";
  float tempC_2 = (voltage_2 - 0.5)*100;
  dataString += tempC_2;
  dataString += ",";
  float average_celcius = (tempC_1 + tempC_2)/2;
  dataString += average_celcius;
  dataString += ",";
  float tempf_1 = (tempC_1 * 9.0 /5.0) +32.0;
  dataString += tempf_1;
  dataString += ",";
  float tempf_2 = (tempC_2 * 9.0 /5.0) +32.0;
  dataString += tempf_2;
  dataString += ",";
  float average_farenheight = (tempf_1 + tempf_2) /2;
  dataString += average_farenheight;
  // write to disk
  Serial.println("writing to disk");
  digitalWrite(indicator_led, HIGH);
  temperature_log = SD.open("log.csv", FILE_WRITE);
  temperature_log.println(dataString);
  temperature_log.close();
  digitalWrite(indicator_led, LOW);
  Serial.println("done writing");
  timer += 5;
  delay(5000);
  }

void card_check(){
  Serial.println("Initializing SD card...");
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    return;
  }
  Serial.println("card initialized.");
  }
void data_check(){
  Serial.print("checking for temperature_log file on SD card.");
  if (SD.exists("log.csv")) {
    Serial.println("file exists");
    } else {
      Serial.print("doesnt exist, creating now");
      temperature_log = SD.open("log.csv", FILE_WRITE);
      Serial.print("printing file header");
      temperature_log.println("# Temperature log. Checks temperature every 5 seconds");
      temperature_log.println("# Author: Nick George");
      temperature_log.println("# Contact: [email protected]");
      temperature_log.println("# Updated: 2017-04-23");
      temperature_log.println("Timestamp (s), Sensor_1_C, Sensor_2_C, Average_C, Sensor_1_f, Sensor_2_f, Average_f");
      temperature_log.close();
      //TODO add time monitoring for timestamp https://www.pjrc.com/teensy/td_libs_Time.html#teensy3
      }
}
/*
 * TODO: interrupt to start and stop writing and break loop for safe ejection. 
 * TODO: clean up the string concatination.
 * void button_interrupt {
 * // if I push a button, start. if running, 
 * // safely close. 
 *
 * }
*/

I added an 'indicatorled' to let me know when the data was being written so I didnt unplug it in the middle of a write. The only things I want to add to this would be button control. I want to be able to start and stop it based on a button push. Button interrupts should work fine for this.
Make sure your filenames are short, I first named it temperaturelog.csv and the file was never created. This is clearly stated in the documentation, but again I had to make the mistake before I learned it.

Resources:

Data logger button control

  • button to start the data logger.
  • button to stop the data logger.

An approach may be to set a variable to 0 on startup, and if a button is pushed, set the variable to 1.
On the second button push, set it back to 0 to stop everything.

Timer functionality

Here is a picture of the (almost) finished data logger

data_logger.jpg

Figure 5: Teensy 3.2 temerature logger

Part 2. Integrating other sensors

Part 3. Doing things