// // greenhouse monitoring and control program // copyright 2010 by Bdale Garbee 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 // 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; }