add ADC for light sensor
[hw/greenhouse] / greenhouse.ino
1 //
2 // greenhouse monitoring and control program 
3 // copyright 2010 by Bdale Garbee <bdale@gag.com>   GPLv2
4 //
5 // data logging and fan+heat control for a greenhouse for arduino duemilanove
6 //
7 //      temperature sensor      analog 0
8 //      light sensor            analog 1
9 //      humidity sensor         analog 2
10 //
11 //      i2c bus                 analog 4,5
12 //          DS1307 real time clock      
13 //          24AA1025 128x8 EEPROM
14 //
15 //      spi                     digital 10,11,12,13
16 //          TeleDongle
17 //              http://www.arduino.cc/playground/Code/Spi
18 //
19 //      4 relays for 120VAC     digital 2,3,4,5
20 //
21
22 #include <Wire.h>               // needed for i2c bus
23
24 // analog inputs
25 #define TEMPERATURE             0       // temperature sensor
26 #define LIGHT                   1       // light sensor
27 #define HUMIDITY                2       // humidity sensor
28
29 // i2c bus
30 #define AA1025_ADDRESS  0x50
31 #define DS1307_ADDRESS          0x68
32
33 // spi bus
34
35 // digital outputs
36 #define RELAY_0                 2
37 #define RELAY_1                 3
38 #define RELAY_2                 4
39 #define RELAY_3                 5
40 #define LED                     9
41
42 // data layout in EEPROM
43 #define LAST_WRITE_ADDR_MSB    0x00
44 #define LAST_WRITE_ADDR_LSB    0x01
45 #define MIN_WRITE_ADDR         0x02
46 #define MAX_WRITE_ADDR         0xFFFF
47
48 // timing values
49 //#define READ_INTERVAL          900000
50 #define READ_INTERVAL          3000
51 #define SERIAL_WAIT_DELAY      20
52
53 long    last_write_addr;
54 long    next_read_time;
55 boolean out_of_space;
56 int  val;
57
58 void setup() {
59
60 //  // setup the pins
61  pinMode(LED, OUTPUT);
62  digitalWrite(LED, LOW);
63 //  pinMode(WARNING_LED, OUTPUT);
64 //  digitalWrite(WARNING_LED, LOW);
65
66 //  pinMode(DOWNLOAD_PIN, INPUT);           // set pin to input
67 //  digitalWrite(DOWNLOAD_PIN, HIGH);       // turn on pullup resistors
68
69
70   // configure i2c
71   Wire.begin();
72   delay(50);                            // allow some settling time
73
74   // restore last_write_addr from eeprom
75   last_write_addr  = i2c_eeprom_read_byte( AA1025_ADDRESS, LAST_WRITE_ADDR_MSB) << 8;
76   last_write_addr += i2c_eeprom_read_byte( AA1025_ADDRESS, LAST_WRITE_ADDR_LSB);
77
78   // configure async console
79   Serial.begin(19200);
80
81   status();
82
83   next_read_time = 0;
84   out_of_space = 0;
85
86   Serial.println("Initialization complete");
87 }
88
89 void loop() {
90
91   // find out if the user requests calibrations or not
92   readSerial();
93
94   // see if we need to save a new value
95   if (millis() > next_read_time) {
96     digitalWrite(LED, HIGH);
97
98     next_read_time += READ_INTERVAL;
99
100
101     if (last_write_addr + 5 < MAX_WRITE_ADDR) {
102       last_write_addr += 4;
103
104       // get the temperature
105       val = analogRead(TEMPERATURE);
106 Serial.print(val);
107 Serial.print(",");
108       // save into the next available space
109       i2c_eeprom_write_byte( AA1025_ADDRESS, last_write_addr, val >> 8);
110       i2c_eeprom_write_byte( AA1025_ADDRESS, last_write_addr+1, val & 0xFF);
111
112       // get the photo sensor value
113       val = analogRead(LIGHT);
114 Serial.println(val);
115       // save into the next available space
116       i2c_eeprom_write_byte( AA1025_ADDRESS, last_write_addr+2, val >> 8);
117       i2c_eeprom_write_byte( AA1025_ADDRESS, last_write_addr+3, val & 0xFF);
118
119       // save the last write address to the eeprom in case we lose power  
120       i2c_eeprom_write_byte( AA1025_ADDRESS, LAST_WRITE_ADDR_MSB, last_write_addr >> 8);
121       i2c_eeprom_write_byte( AA1025_ADDRESS, LAST_WRITE_ADDR_LSB, last_write_addr & 0xFF);
122
123
124     } 
125     else {
126       Serial.println("Out of space to log values");
127       // flash the status LED
128       out_of_space = 1;
129     }
130     digitalWrite(LED, LOW);
131   }
132   // do something if out_of_space?
133
134 }
135
136 void readSerial() {
137   // listen for serial data
138   if (Serial.available()) {
139     // ensure all the data has been buffered
140     delay(SERIAL_WAIT_DELAY);
141
142     // read current command
143     val = Serial.read();
144     // clear the rest of the current serial buffer
145     Serial.flush();
146
147   if (val == 'd' || val == 'D') {
148     // dump data over serial
149     sendData();
150   }
151   else if (val == 'r' || val == 'R') {
152     // reset
153     reset();
154   } 
155   else if (val == 's' || val == 'S') {
156     // status
157     status();
158     } 
159     else {
160       // inappropriate command received
161       Serial.println("Inappropriate serial command received");
162       Serial.println("Send 'r' to reset write pointer");
163       Serial.println("Send 'd' to download all data via serial");
164       return;
165     }
166
167   }  
168 }
169
170 void status() {
171   long l, l2;
172
173   Serial.println("");
174   Serial.println("");
175   Serial.println("Garbee Greenhouse Controller");
176
177   Serial.println("");
178
179   l = (last_write_addr - MIN_WRITE_ADDR) / 2;
180   l2 = (MAX_WRITE_ADDR - MIN_WRITE_ADDR) / 2;
181   Serial.print("Existing records: ");
182   Serial.print(l);
183   Serial.print(" / ");
184   Serial.print(l2);
185   Serial.print(" (");
186   Serial.print(((float)l / (float)l2) * 100.0);
187   Serial.println("%)");
188
189   Serial.print("Read interval:    " );
190   Serial.print(READ_INTERVAL);
191   Serial.println("ms");
192
193 }
194
195 void reset() {
196   Serial.print("Resetting write address to ");
197   Serial.println((int) MIN_WRITE_ADDR);
198
199   i2c_eeprom_write_byte ( AA1025_ADDRESS, LAST_WRITE_ADDR_MSB, 0x00 );
200   i2c_eeprom_write_byte ( AA1025_ADDRESS, LAST_WRITE_ADDR_LSB, MIN_WRITE_ADDR );
201   last_write_addr = MIN_WRITE_ADDR;
202 }
203
204 void sendData() {
205   delay(50);
206   
207   long count;
208   
209   // send data to serial  
210   Serial.println("\nTemperature,Light:");
211   count = 0;
212   for (long addr = MIN_WRITE_ADDR; addr < last_write_addr; addr += 4){
213
214     val = i2c_eeprom_read_byte( AA1025_ADDRESS, addr ) << 8;
215     val += i2c_eeprom_read_byte( AA1025_ADDRESS, addr+1 );
216
217     Serial.print(val);
218     Serial.print(',');
219     
220     val = i2c_eeprom_read_byte( AA1025_ADDRESS, addr+2 ) << 8;
221     val += i2c_eeprom_read_byte( AA1025_ADDRESS, addr+3 );
222
223     Serial.println(val);
224     
225
226     count ++; 
227     if (count % 250 == 0) {
228       Serial.print(count);
229       Serial.print('/');
230       Serial.print((last_write_addr - MIN_WRITE_ADDR) / 4);
231       Serial.print(",");
232     }
233   }
234
235   Serial.println("Download complete.");
236   Serial.print("Sent ");
237   Serial.print((last_write_addr - MIN_WRITE_ADDR) / 4);
238   Serial.println(" records");
239
240 }
241
242
243 static void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
244   delay(5);
245
246   int rdata = data;
247   Wire.beginTransmission(deviceaddress);
248   Wire.write((int)(eeaddress >> 8)); // MSB
249   Wire.write((int)(eeaddress & 0xFF)); // LSB
250   Wire.write(rdata);
251   Wire.endTransmission();
252 }
253
254 static byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
255   delay(5);
256   byte rdata = 0xFF;
257   Wire.beginTransmission(deviceaddress);
258   Wire.write((int)(eeaddress >> 8)); // MSB
259   Wire.write((int)(eeaddress & 0xFF)); // LSB
260   Wire.endTransmission();
261   Wire.requestFrom(deviceaddress,1);
262
263   if (Wire.available()) rdata = Wire.read();
264   return rdata;
265 }