-Greenhouse Shield for Arduino
+Greenhouse Board
-This is a board my son Robert is building to monitor and control conditions
-in our back yard greenhouse. The objective is a "shield" for an Arduino
-Duemilanove board, with the following features:
+This is an accessory board for a Raspberry Pi, designed to add a real time clock, sensors,
+and relay control. The clock allows event scheduling even if there's no network connection,
+though we anticipate having our greenhouse on the net full time.
- - temperature sensor MCP9700A
- - light sensor PDV-P9007
- - humidity sensor HCH-1000 + TLC555
- - i2c real-time clock DS1307
- - i2c non-volatile memory for data logging 24AA1025
- - 4 relay-switched mains (110 volt AC)
- - electric heater (high current!)
- - electric fan
- - hydroponics pump
- - spare
- - spi TeleDongle interface for RF link
- http://altusmetrum.org/TeleDongle
+The sensors include barometric pressure, temperature, and humidity using an MS-8607, and
+a light sensor using a photocell and associated ADC.
-The idea is that we log temperature, light, and humidity every so often to
-the non-volatile memory with timestamps. On each sample, we check current
-conditions and turn the heater on if it's too cold, and the fan on if it's
-too hot. The hydroponics pump gets turned on and off on a regular schedule.
-And the RF link provides a mechanism for remotely downloading the logged data,
-changing setpoints and schedules, manual override, etc.
-
-References:
-
- various relevant circuit fragments:
- http://www.ladyada.net/learn/sensors/cds.html
- http://klk64.com/arduino-spi/
- http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1264143673
-
- pcb layout in gEDA of an Arduino shield:
- http://lowvoltagelabs.com/products/videooverlayshield/
-
- 5 to 3.3 volt level shifting with a MOSFET ...
- http://www.rocketnumbernine.com/2009/04/10/5v-33v-bidirectional-level-converter/
-
- DS1307 i2c example code
- http://www.glacialwanderer.com/hobbyrobotics/?p=12
+There are 4 GPIO-controlled AC relays with LED state indicators.
+The basic idea is to log environment conditions, present them over the web, and use the
+relays to automatically control heating and cooling systems to regulate the environmental
+conditions.
+++ /dev/null
-//
-// greenhouse monitoring and control program
-// copyright 2010 by Bdale Garbee <bdale@gag.com> GPLv2
-//
-// data logging and fan+heat control for a greenhouse for arduino duemilanove
-//
-// temperature sensor analog 0
-// light sensor analog 1
-// humidity sensor analog 2
-//
-// i2c bus analog 4,5
-// DS1307 real time clock
-// 24AA1025 128x8 EEPROM
-//
-// spi digital 10,11,12,13
-// TeleDongle
-// http://www.arduino.cc/playground/Code/Spi
-//
-// 4 relays for 120VAC digital 2,3,4,5
-//
-
-#include <Wire.h> // needed for i2c bus
-
-// analog inputs
-#define TEMPERATURE 0 // temperature sensor
-#define LIGHT 1 // light sensor
-#define HUMIDITY 2 // humidity sensor
-
-// i2c bus
-#define AA1025_ADDRESS 0x50
-#define DS1307_ADDRESS 0x68
-
-// spi bus
-
-// digital outputs
-#define RELAY_0 2
-#define RELAY_1 3
-#define RELAY_2 4
-#define RELAY_3 5
-#define LED 9
-
-// data layout in EEPROM
-#define LAST_WRITE_ADDR_MSB 0x00
-#define LAST_WRITE_ADDR_LSB 0x01
-#define MIN_WRITE_ADDR 0x02
-#define MAX_WRITE_ADDR 0xFFFF
-
-// timing values
-//#define READ_INTERVAL 900000
-#define READ_INTERVAL 3000
-#define SERIAL_WAIT_DELAY 20
-
-long last_write_addr;
-long next_read_time;
-boolean out_of_space;
-int val;
-
-void setup() {
-
-// // setup the pins
- pinMode(LED, OUTPUT);
- digitalWrite(LED, LOW);
-// pinMode(WARNING_LED, OUTPUT);
-// digitalWrite(WARNING_LED, LOW);
-
-// pinMode(DOWNLOAD_PIN, INPUT); // set pin to input
-// digitalWrite(DOWNLOAD_PIN, HIGH); // turn on pullup resistors
-
-
- // configure i2c
- Wire.begin();
- delay(50); // allow some settling time
-
- // restore last_write_addr from eeprom
- last_write_addr = i2c_eeprom_read_byte( AA1025_ADDRESS, LAST_WRITE_ADDR_MSB) << 8;
- last_write_addr += i2c_eeprom_read_byte( AA1025_ADDRESS, LAST_WRITE_ADDR_LSB);
-
- // configure async console
- Serial.begin(19200);
-
- status();
-
- next_read_time = 0;
- out_of_space = 0;
-
- Serial.println("Initialization complete");
-}
-
-void loop() {
-
- // find out if the user requests calibrations or not
- readSerial();
-
- // see if we need to save a new value
- if (millis() > next_read_time) {
- digitalWrite(LED, HIGH);
-
- next_read_time += READ_INTERVAL;
-
-
- if (last_write_addr + 5 < MAX_WRITE_ADDR) {
- last_write_addr += 4;
-
- // get the temperature
- val = analogRead(TEMPERATURE);
-Serial.print(val);
-Serial.print(",");
- // save into the next available space
- i2c_eeprom_write_byte( AA1025_ADDRESS, last_write_addr, val >> 8);
- i2c_eeprom_write_byte( AA1025_ADDRESS, last_write_addr+1, val & 0xFF);
-
- // get the photo sensor value
- val = analogRead(LIGHT);
-Serial.println(val);
- // save into the next available space
- i2c_eeprom_write_byte( AA1025_ADDRESS, last_write_addr+2, val >> 8);
- i2c_eeprom_write_byte( AA1025_ADDRESS, last_write_addr+3, val & 0xFF);
-
- // save the last write address to the eeprom in case we lose power
- i2c_eeprom_write_byte( AA1025_ADDRESS, LAST_WRITE_ADDR_MSB, last_write_addr >> 8);
- i2c_eeprom_write_byte( AA1025_ADDRESS, LAST_WRITE_ADDR_LSB, last_write_addr & 0xFF);
-
-
- }
- else {
- Serial.println("Out of space to log values");
- // flash the status LED
- out_of_space = 1;
- }
- digitalWrite(LED, LOW);
- }
- // do something if out_of_space?
-
-}
-
-void readSerial() {
- // listen for serial data
- if (Serial.available()) {
- // ensure all the data has been buffered
- delay(SERIAL_WAIT_DELAY);
-
- // read current command
- val = Serial.read();
- // clear the rest of the current serial buffer
- Serial.flush();
-
- if (val == 'd' || val == 'D') {
- // dump data over serial
- sendData();
- }
- else if (val == 'r' || val == 'R') {
- // reset
- reset();
- }
- else if (val == 's' || val == 'S') {
- // status
- status();
- }
- else {
- // inappropriate command received
- Serial.println("Inappropriate serial command received");
- Serial.println("Send 'r' to reset write pointer");
- Serial.println("Send 'd' to download all data via serial");
- return;
- }
-
- }
-}
-
-void status() {
- long l, l2;
-
- Serial.println("");
- Serial.println("");
- Serial.println("Garbee Greenhouse Controller");
-
- Serial.println("");
-
- l = (last_write_addr - MIN_WRITE_ADDR) / 2;
- l2 = (MAX_WRITE_ADDR - MIN_WRITE_ADDR) / 2;
- Serial.print("Existing records: ");
- Serial.print(l);
- Serial.print(" / ");
- Serial.print(l2);
- Serial.print(" (");
- Serial.print(((float)l / (float)l2) * 100.0);
- Serial.println("%)");
-
- Serial.print("Read interval: " );
- Serial.print(READ_INTERVAL);
- Serial.println("ms");
-
-}
-
-void reset() {
- Serial.print("Resetting write address to ");
- Serial.println((int) MIN_WRITE_ADDR);
-
- i2c_eeprom_write_byte ( AA1025_ADDRESS, LAST_WRITE_ADDR_MSB, 0x00 );
- i2c_eeprom_write_byte ( AA1025_ADDRESS, LAST_WRITE_ADDR_LSB, MIN_WRITE_ADDR );
- last_write_addr = MIN_WRITE_ADDR;
-}
-
-void sendData() {
- delay(50);
-
- long count;
-
- // send data to serial
- Serial.println("\nTemperature,Light:");
- count = 0;
- for (long addr = MIN_WRITE_ADDR; addr < last_write_addr; addr += 4){
-
- val = i2c_eeprom_read_byte( AA1025_ADDRESS, addr ) << 8;
- val += i2c_eeprom_read_byte( AA1025_ADDRESS, addr+1 );
-
- Serial.print(val);
- Serial.print(',');
-
- val = i2c_eeprom_read_byte( AA1025_ADDRESS, addr+2 ) << 8;
- val += i2c_eeprom_read_byte( AA1025_ADDRESS, addr+3 );
-
- Serial.println(val);
-
-
- count ++;
- if (count % 250 == 0) {
- Serial.print(count);
- Serial.print('/');
- Serial.print((last_write_addr - MIN_WRITE_ADDR) / 4);
- Serial.print(",");
- }
- }
-
- Serial.println("Download complete.");
- Serial.print("Sent ");
- Serial.print((last_write_addr - MIN_WRITE_ADDR) / 4);
- Serial.println(" records");
-
-}
-
-
-static void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
- delay(5);
-
- int rdata = data;
- Wire.beginTransmission(deviceaddress);
- Wire.write((int)(eeaddress >> 8)); // MSB
- Wire.write((int)(eeaddress & 0xFF)); // LSB
- Wire.write(rdata);
- Wire.endTransmission();
-}
-
-static byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
- delay(5);
- byte rdata = 0xFF;
- Wire.beginTransmission(deviceaddress);
- Wire.write((int)(eeaddress >> 8)); // MSB
- Wire.write((int)(eeaddress & 0xFF)); // LSB
- Wire.endTransmission();
- Wire.requestFrom(deviceaddress,1);
-
- if (Wire.available()) rdata = Wire.read();
- return rdata;
-}