Arduino Controlled Grow and PC Program - Work In Progress

Skutch

Member
Hi,
I've been "playing" with an arduino for a while, grow on soil and am building a hobby related data-logger.

Project is far from ready, I'd guess a zillion sub-projects are possible, emphasis (for me...) should be reliability. I wouldn't want a light/pump to stay on since my program got stuck in an unforeseen loop. So far I store soil-wetness, humidity and temperature at regular intervals to SD and/or serial port. I've programmed a daily timer for the 5 pins I had left to operate relays.

Anyway, I have only glanced at the firmata examples of arduino and processing (IDE similar to arduino for PC) and still know little about firmata, I'm also more an electronics kind of guy as PC-programmer. One thing I do wonder about is setting up an arduino as intelligent firmata-device.

Correct me if I'm wrong, as far as I understand one now uses the PC to read sensors/control devices with firmata. Should the PC, for whatever reason, stop sending firmata-info, the arduino's silent as well ? The firmata-code on the arduino isn't that big and I wondered whether you've thought of writing/merging autonomous code for the arduino as well. For example to read an real time clock-chip and still be able to switch lights/pumps on/off should the PC not respond.

I like what you're doing with your project, personally I wouldn't mind using the PC as little as possible though. It's a great tool, but it uses a lot of energy I'd rather invest in a clones-/seedlings-box. I've also seen a few BSODs too many to think of a pc as reliable.

By the way, has anyone seen http://www.420magazine.com/forums/do-yourself/153079-arduino-based-room-controller.html, it's a different approach, also not completely ready yet, but quite interesting.
 

AdvancedNewbie

Well-Known Member
Yes, I have thought about this and eventually I would like the program to be more or less a settings changer for the arduino. The program would have the same interface, but instead of doing the 'thinking' the AI will be left to the arduino. I was thinking of scrapping the whole project and making it completely arduino-based with a LCD - screen for options, etc... But I guess you could say I'm in the same "mood" as you... I think I'd like to control fans, nute mixing, etc... (and data logging and remote monitoring), but I think I'm going to leave my lights and pumps on the good ol' trusty mechanical timers. I think I was going a little over board with trying to make this so universal that I forgot the fact that a good system usually is comprised of sub-systems that do ONE thing and do that ONE thing PERFECT everytime. The arduino should be able to handle the lights n' things - but simple is better and find the mechanical timers very simple and, given my current grow, have proven themselves. But I think I'll do more complex things like nutrient mixing with the arduino but I'd still like to be able to change the settings via PC for the nute mixing, intake/extra exhaust fans (would keep the carbon filter fan plugged in at all times - no arduino), AC Control, Humidity Control, etc

I've been so busy and feel bad for letting this project down really, but I think you're right about keeping the code on the arduino. I can imagine if Windows went to sleep or 'windozed' off. The whole grow would be crap.

So for now, it's going to have to wait; but I will be working on it when I get the time - data logging, remote monitoring via PC or Smartphone, settings change via PC.

Edit: I would think that having a button to have to manually start the auto-nute mixing would be good too... I don't really want to have it mixing unless I'm observing.

Edit2: I think I'm going to scrap firmata too and program the communications myself - especially if I'm going to be changing the settings remotely - firmata doesn't do that sort of thing
 

AdvancedNewbie

Well-Known Member
Skutch;

I'd probably stay away from "processing apps" like your friend their has suggested for use on the PC. Do you have any code right now? I'd love to hack away at it and make a nice 'historical' type datalog interface. I think that's all this project is really lacking. I'm really feeling bummed out about scrapping everything - but it's time for some Spring cleaning I think. Everything must be kept simple and clean.

May the most simple and effective tools win!
 

Afistakis

Member
Please don't give up yet! I have all my arduino mega gear already on the way in the mail. I have been salivating since you started this project. I joined here just so that I could lurk and follow this thread! I played with arduino quite some time ago in college and recently with quadcopters. I am most interested in the data logging and remote monitoring. I appreciate the work you have already done and it seems that it is only a few tweaks away from being reliable and operational. Monitoring/logging vital information, even with mechanical timers for everything, will give me a much greater sense of security while away.

I can control my multiwii arduino flight controller with my phone to read and upload new settings over bluetooth with an app. Something stand alone like that would be legit even using wireless with a computer while keeping processing on board.

I am excited to play with this next week when my stuff finally makes it here, if I am to trust the Chinese shipping companies.

Thanks for the hard work and initiative!
 

AdvancedNewbie

Well-Known Member
:lol: I'm not giving up yet, lol... But yes, processing must be done on the board. I might be able to tweak the arduino code a bit and still use some of the code from the VB.NET app - so it's not a complete loss. I can't wait to see what my mega can do. It would be nice to have something similar to an iPonic in the end.
 

Afistakis

Member
:lol: I'm not giving up yet, lol... But yes, processing must be done on the board. I might be able to tweak the arduino code a bit and still use some of the code from the VB.NET app - so it's not a complete loss. I can't wait to see what my mega can do. It would be nice to have something similar to an iPonic in the end.
I think that the IPonic is an over glorified home thermostat and $1200 seems a little spendy. I think that there is much more room for customization and control vs their hard wiring on the board and limited power control. The only nice piece of candy is the nice interface but there are many options including cheap older tablets for remote control. I was thinking about grabbing this but I have no idea how to create or interface the gui. It looks pretty though. Using something commercial for cabling and slapping it in a nice box will accomplish the same for much less.

iPonic 600 IncludesRemote Combination Sensor
• CO2
• Temperature
• Humidity
• Light

The manual shows it only controlling outlet plugs. It mentions CO2 but I don't see any tds, ph, or submersible temp probes. What you have started looks much more capable to me.
 

AdvancedNewbie

Well-Known Member
Oh for sure, we can make it better... Customizable. I don't have much experience with those touch screens but from what I've seen the functions for drawing 'buttons', shapes, text, etc... are pretty limited. You could save the screens as an image and basically create a hotspot (if x and y coordinates of your 'touch' are within the boundaries of a rectangle shape (ie. button) then you clicked that button). I see this as being a pain, unless there are some libraries on that stuff... Somebody has to have made it easy. But I'm pretty sure you'll have to end up saving the images on a sd card, or draw each page using shapes and text. I don't think I'm going to go there too soon, but it is definitely something to think about. I've seen those too - always wanted to mess around with them.

Edit: Just noticed the library on that page... Hmm... SD card slot too... Hmm. :)

Edit 2: Check this out... Has an overview of the functions in the library.

Edit 3: Heeeeeere we go. http://www.henningkarlsen.com/electronics/library.php?id=51

Edit 4: http://www.youtube.com/watch?v=rn0abZE5YzA&feature=endscreen

Edit 5: Ahh, what the hell I'll buy one... lol
 

Afistakis

Member
I just found this. I am not sure how different beside the price and snazzy video. It looks very similar. It looks like he is just playing with the pre loaded gpu code. I will order something like this or that to play with after I get a data logging tri meter setup. GLB isn't fast on shipping unless you pay for the expedite. I think the ship with tracking is a waste of $1.70. I have gotten stuff before I got tracking information! I'm okay with slow if it's cheap though.
 

Skutch

Member
Skutch;

I'd probably stay away from "processing apps" like your friend their has suggested for use on the PC. Do you have any code right now? I'd love to hack away at it and make a nice 'historical' type datalog interface. I think that's all this project is really lacking. I'm really feeling bummed out about scrapping everything - but it's time for some Spring cleaning I think. Everything must be kept simple and clean.

May the most simple and effective tools win!
Remember I've been programming in Basic far too long and hardly had any education in C(++), I hope it's readable without getting a headache :lol:
Sofar it works on arduino uno- and the latest 0022-IDE, but I'm still far from satisfied. I'm using an Nano by the way for this project.

I'm using gypsum soil sensors now (cheap&easy) that I'd rather replace with capacitive ones since those won't interact with the soil on a chemical or electrical basis.
The only thing controllable by PC now is setting the time of the RTC-clock, it is possible to change the
device timers (in EEPROM), but you'll have to do it in code.

Reading the ds18b20 sensors (wich are quite accurate), but still gives me a problem I haven't addressed yet. To read 'm you first have to command 'm a new readingcycle has started, wait ages (well... 750mS), and command them to send the data. I still have to seperate those two which would give me the opportunity to do most other stuff in those 750 mS.

Data is stored on SD in a map called logs. Create it on SD before running the program. Every day a new file name is chosen based on year,month,day.
Once every minute the arduino shows the filenames in that map plus the amount of space (days) left on the SD to serial port.
The sampling rate is quite high, about once a second, resulting in about a one year capacity using a 2 GB SD.
One thing I noticed was that I still didn't change the routine named tos() which checks wheter it's time to change the filename to a new date.Name of subroutine is lame.

All data spewed is in CSV-format, Comma Separated Volume, but I still haven't written a PC-program to analyze the data.

Unfortunately it also uses a lot of programming space, probably because I've used quite a number of libraries. It probably is possible to shrink those since I only use parts of their functions. With an arduino uno one would have 1.5 KB extra room, but I wouldn't mind migrating this project to a 64KB controller to have some more space for future implications.
I unfortunately don't know how it will operate on a MEGA-board, I'd guess one will have to change the pins for SD and analog readings.

It tries to log with a resolution of once a second, far more as needed in a 'slow' project like this, but depending on the speed of the SD, it may skip a second every now and then.


A lot of the functions written are unfortunately not the best/easiest/fastest, remember I'm still busy learning C++.

Anyway, good luck untangling my spaghetti :lol:
I'm not a licensing kind of guy, so, feel free to use it any way you like.

P.s. I'll try to make an electronic schematic although I unfortunately can't see which components are used on the Ebay SD module.

Code:
/*
Growroom logger/ device timer.
 Logs humidity, temperature and soilmoisture.
 Daily timer for 5 devices included
 
 Pins used  
 0-1       Serial port
 2,3,5,7,9 individual timer switches
 4         DHT humidity sensor
 6         Onewire-bus 4 x ds18b20 attached
 8         pin for temporary powering gypsum soilsensors, temporary to prevent electrolysis
 10-13     SD card to log CSV-files
 A0-A3     Gypsum soil-wetness sensors  http://www.cheapvegetablegardener.com/2009/11/how-to-make-cheap-soil-moisture-sensor-2.html
 A4-A5     I2C bus
 
 */

#include <OneWire.h>             // OneWire library needed for DS18b20 sensor                  http://www.pjrc.com/teensy/td_libs_OneWire.html
#include <DallasTemperature.h>   // ds18b20 temperature sensor library                         http://milesburton.com/index.php?title=Dallas_Temperature_Control_Library
#include <DHT.h>                 // DHT library for  DHT11, DHT21 and DHT22                    https://github.com/adafruit/DHT-sensor-library 
#include <Wire.h>                // I2C library                                                Standard arduino library
#include <Time.h>                // Time library                                               http://www.arduino.cc/playground/uploads/Code/Time.zip
#include <DS1307RTC.h>           // a basic DS1307 library that returns time as Unix epoch     http://www.arduino.cc/playground/uploads/Code/Time.zip
#include <EEPROM.h>              // EEPROM library to support timer switch configuration       Standard arduino library
#include <SdFat.h>               // SDfat is used to read/write SD files                       http://code.google.com/p/sdfatlib/downloads/detail?name=sdfatlib20111205.zip&can=2&q=
#include <SdFatUtil.h>           // SD tools library                                           http://code.google.com/p/sdfatlib/downloads/detail?name=sdfatlib20111205.zip&can=2&q=

#define TIME_MSG_LEN  11         // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'         // Header tag for serial time sync message
#define DHTPIN 4                 // Data pin DHT 11 humidity sensor
#define ONE_WIRE_BUS 6           // data pin 1-wire bus
#define TEMPERATURE_PRECISION 12 // temperature sensor resolution 9-12 bits

// Uncomment whatever type you're using!
#define DHTTYPE DHT11          // DHT 11 
//#define DHTTYPE DHT22          // DHT 22  (AM2302)
//#define DHTTYPE DHT21          // DHT 21 (AM2301)
DHT dht(DHTPIN, DHTTYPE);        // name library

const int chipSelect = 10;       // SPI SS pin for SD
Sd2Card card;                    // needed to read size SD and space free
SdVolume vol;                    // needed to read size SD and space free
SdFat sd;                        // 
SdFile myFile;                   //

OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);
DeviceAddress t0, t1, t2, t3;

byte Debug = 0;                  // Used to display (1) msgs, or not (0) while developing
long tooktime;
float dhtdat;                    //Array to hold humidity data. DHT11
int save = 1;                    // store readings to disk 1/0
int show = 1;                    // send  readings to serial port 
int soilWetness[4];              // Array to store soil wetness results
byte deviceStatus[5];
unsigned long lastnow;           // las noted value (second)  of now()- function 
int currentminute;               // closes/opens file for writing every minute
float w[5];                      // Temperature Array
char name[] = "01234567.CSV";    // variable used to store date based filename
int oh;                          // last detected hour
unsigned long deviceonAt[6], deviceoffAt[6]; // array for devicetimers 
int devicePin[6]= {
  0,2,3,5,7,9};   // pins used by daily timers

void writeconfig(void){
  //  === Timer for 1st device
  EEPROM.write(0,22); // device on at  Hour
  EEPROM.write(1,0);  //               Minute
  EEPROM.write(2,0);  //               Second
  EEPROM.write(3,21); // device off at Hour 
  EEPROM.write(4,0);  //               Minute
  EEPROM.write(5,0);  //               Second

  //  === Timer for 2nd device (Explantion as timer for first device)
  EEPROM.write(6,15); 
  EEPROM.write(7,0); 
  EEPROM.write(8,0); 
  EEPROM.write(9,22);
  EEPROM.write(10,0); 
  EEPROM.write(11,0);

  //  === Timer for 3rd device (Explantion as timer for first device)
  EEPROM.write(12,23); 
  EEPROM.write(13,30);  
  EEPROM.write(14,2);  
  EEPROM.write(15,7); 
  EEPROM.write(16,30); 
  EEPROM.write(17,00); 

  //  === Timer for 4th device (Explantion as timer for first device)
  EEPROM.write(18,3); 
  EEPROM.write(19,0);
  EEPROM.write(20,0);
  EEPROM.write(21,16);
  EEPROM.write(22,0); 
  EEPROM.write(23,0);

  //  === Timer for 5th device (Explantion as timer for first device)
  EEPROM.write(24,22); 
  EEPROM.write(25,0);  
  EEPROM.write(26,0);  
  EEPROM.write(27,23); 
  EEPROM.write(28,0); 
  EEPROM.write(29,0); 

  
}


void setup(void)
{
  tooktime = micros(); // Debug variable to measure time
  pinMode(8, OUTPUT); // configure moisture sensor "ON" pin
  digitalWrite (8,LOW);// and pull low to prevent electrolyzing effects
  dht.begin(); // start DHT humidity sensor
  Serial.begin(115200);  // start serial port
  sensors.begin(); // onewire ds18b20 start
  setres();        // onewire ds18b20 set resolution
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet) Serial.println("RTC Error, clock not set");      
  if (!sensors.getAddress(t0, 0)) Serial.println("Error DS18B20 1"); 
  if (!sensors.getAddress(t1, 1)) Serial.println("Error DS18B20 2"); 
  if (!sensors.getAddress(t2, 2)) Serial.println("Error DS18B20 3"); 
  if (!sensors.getAddress(t3, 3)) Serial.println("Error DS18B20 4"); 
  if (save==1){
    if (!sd.init(SPI_FULL_SPEED, chipSelect)) sd.initErrorHalt();
    sd.chdir("/logs");
    tos();
    if (!myFile.open(name, O_RDWR | O_CREAT | O_AT_END)) {
      sd.errorHalt("opening logfile failed.");
    }
  }
  writeconfig(); // write device timer configuration
  readconfig(); //   read   "      "         "  

  if (Debug){
    Serial.print ("Setup took ");
    Serial.print (micros()-tooktime);
    Serial.println (" Micro - seconds.");
  }

}

void loop(void){ 
  Tupdate();                    // check for external rtc update (T + 10 digit Unix epoch at serial port)
  if (lastnow != now()){        // performs action needed every second
    lastnow = now();            // log last detected second
    if (oh != hour()) tos();    // change date based filename to new date if needed.
    readsensors();              // reads all available sensors
    DataDump();                 // Dumps sensorinfo to SD/serial port
    chk_devicetimer();          // Turns timer-devices on/off when needed.
  }
}

time_t processSyncMessage() {
  // return the time if a valid sync message is received on the serial port.
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
    char c = Serial.read() ; 
    Serial.print(c);  
    if( c == TIME_HEADER ) {       
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){   
        c = Serial.read();          
        if( c >= '0' && c <= '9'){   
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number    
        }
      }   
      return pctime; 
    }  
  }
  return 0;
}




void setres(){
  // Sets resolution of ds18b20 temperature sensors
  sensors.setResolution(t0, TEMPERATURE_PRECISION);
  sensors.setResolution(t1, TEMPERATURE_PRECISION);
  sensors.setResolution(t2, TEMPERATURE_PRECISION);
  sensors.setResolution(t3, TEMPERATURE_PRECISION);
}  




void Tstamp(){
  if (! myFile.timestamp(T_CREATE,year(),month(),day(),hour(),  minute(),second())) {
    Serial.println("SD create time error");
  }
  // set write/modification date time
  if (!myFile.timestamp(T_WRITE,year(),month(),day(),hour(),minute(),second())) {
    Serial.println("SD write time error");
  }
  // set access date
  if (!myFile.timestamp(T_ACCESS,year(),month(),day(),hour(),minute(),second())) {
    Serial.println("SD access time error");
  }
}

void readTemp(void){
  // Read temperature from 1-wire DS18B20 sensors
  sensors.requestTemperatures(); // Send the command to get temperatures
  w[0] = sensors.getTempC(t0);// and retrieve them
  w[1] = sensors.getTempC(t1);
  w[2] = sensors.getTempC(t2);
  w[3] = sensors.getTempC(t3);
}

void Tupdate(void){
  if(Serial.available()){
    time_t t = processSyncMessage();
    if(t >0){
      RTC.set(t);   // set the RTC and the system time to the received value
      setTime(t);          
    }
  }
}

void DataDump(void){
  // fileWrite, logs time and last sensordata to current logfile.
  if(save){
    chkMinute();
    myFile.print(lastnow);
    myFile.print(",");
    myFile.print(w[0]);
    myFile.print(",");
    myFile.print(w[1]);
    myFile.print(",");
    myFile.print(w[2]);
    myFile.print(",");
    myFile.print(w[3]);
    myFile.print(",");
    myFile.print(dhtdat);
    myFile.print(",");
    myFile.print(soilWetness[0]);
    myFile.print(",");
    myFile.print(soilWetness[1]);
    myFile.print(",");
    myFile.print(soilWetness[2]);
    myFile.print(",");
    myFile.print(soilWetness[3]);
    myFile.print(",");
    myFile.print(deviceStatus[0]);
    myFile.print(",");
    myFile.print(deviceStatus[1]);
    myFile.print(",");
    myFile.print(deviceStatus[2]);
    myFile.print(",");
    myFile.print(deviceStatus[3]);
    myFile.print(",");
    myFile.println(deviceStatus[4]);

  }
  if (show){
    // serial portWrite, logs time and last sensordata to serial port. 
    Serial.print(lastnow);
    Serial.print(",");
    Serial.print(w[0]);
    Serial.print(",");
    Serial.print(w[1]);
    Serial.print(",");
    Serial.print(w[2]);
    Serial.print(",");
    Serial.print(w[3]);
    Serial.print(",");
    Serial.print(dhtdat);
    Serial.print(",");
    Serial.print(soilWetness[0]);
    Serial.print(",");
    Serial.print(soilWetness[1]);
    Serial.print(",");
    Serial.print(soilWetness[2]);
    Serial.print(",");
    Serial.print(soilWetness[3]);
    Serial.print(",");
    Serial.print(deviceStatus[0]);
    Serial.print(",");
    Serial.print(deviceStatus[1]);
    Serial.print(",");
    Serial.print(deviceStatus[2]);
    Serial.print(",");
    Serial.print(deviceStatus[3]);
    Serial.print(",");
    Serial.println(deviceStatus[4]);

  }
}

char tos(void){
  // Creates CSV logfile name based on date/time
  // 
  // 20121110.CSV
  // ||||----- century (20)12
  //     ||--- Month 11, november
  //       ||- Day 10
  int rest;
  int mo1;
  int mo2;
  int d1;
  int d2;
  int millenium = (year()/1000);
  rest = year()-(millenium*1000);
  int century = rest/100;
  rest = rest - (century*100);
  int decade = rest/10;
  rest = rest -(decade *10);
  mo1 = (month()/ 10);
  mo2 = month()- (mo1 *10);
  d1 = day()/10;
  d2 = day() - (d1 *10);
  oh = hour();
  name[0] = char(50);        // millenium (2)
  name[1] = char(48);        // century   (0)
  name[2] = char(decade+48); // decade
  name[3] = char(rest+48);   // year
  name[4] = char(mo1+48);    // first digit month
  name[5] = char(mo2+48);    // last    ''    ''
  name[6] = char(d1+48);     // first digit days
  name[7] = char(d2+48);     // last    ''   ''
}

void chkMinute(){
  // Close and open file once a minute
  if (save==1){
    if (currentminute != minute()){
      currentminute = minute();
      Tstamp();// update date filestamp
      myFile.close();
      tos();// check if new hourly filename is needed
      if (!myFile.open(name, O_RDWR | O_CREAT | O_AT_END)) {
        sd.errorHalt("opening test.txt for write failed");
      }
      InfoSD();

    }
  }
}

void CHKearth(){
  // check gypsum sensors
  // Apply 5 volts to gypsym sensor/resistor voltage divider. Apply as short as possible to prevent electrolysis.

  digitalWrite (8,HIGH);
  delayMicroseconds(150);
  soilWetness[0]=analogRead(A0);
  delayMicroseconds(150);
  soilWetness[1]=analogRead(A1);
  delayMicroseconds(150);
  soilWetness[2]=analogRead(A2);
  delayMicroseconds(150);
  soilWetness[3]=analogRead(A3);
  digitalWrite (8,LOW);
}

void chk_devicetimer(void){
  for (int x = 1; x < 6; x++){
    deviceStatus[x-1] = lightcheck(x);
    digitalWrite(devicePin[x],deviceStatus[x-1]);
  } 
}

int lightcheck(int devicenr){
  int result; // result variable
  unsigned long tc = (hour()*3600)+(minute()*60)+second();// calculate current minute
  if (deviceonAt[devicenr] > deviceoffAt[devicenr]){ // starts late, stops earlier the following day
    if (tc >= deviceoffAt[devicenr] && tc <deviceonAt[devicenr]) result = 0;
    if (tc < deviceoffAt[devicenr] || tc >=deviceonAt[devicenr]) result = 1; 
  }
  if (deviceonAt[devicenr] < deviceoffAt[devicenr]){ //Starts early, stops later same day
    if (tc >= deviceoffAt[devicenr] || tc < deviceonAt[devicenr]) result = 0;
    if (tc >= deviceonAt[devicenr] && tc < deviceoffAt[devicenr]) result = 1;
  }
  return result;
}

void readconfig(void){
  // Read Configuration of growroom controller

  //==========================================
  // Read settings Growroom controller
  // deviceonAt, deviceoffAt, daily timersettings 
  deviceonAt[1] = (EEPROM.read(0)*3600)+(EEPROM.read(1)*60)+EEPROM.read(2);
  deviceoffAt[1] = (EEPROM.read(3)*3600)+(EEPROM.read(4)*60)+EEPROM.read(5);
  deviceonAt[2] = (EEPROM.read(6)*3600)+(EEPROM.read(7)*60)+EEPROM.read(8);
  deviceoffAt[2] = (EEPROM.read(9)*3600)+(EEPROM.read(10)*60)+EEPROM.read(11);
  deviceonAt[3] = (EEPROM.read(12)*3600)+(EEPROM.read(13)*60)+EEPROM.read(14);
  deviceoffAt[3] = (EEPROM.read(15)*3600)+(EEPROM.read(16)*60)+EEPROM.read(17);
  deviceonAt[4] = (EEPROM.read(18)*3600)+(EEPROM.read(19)*60)+EEPROM.read(20);
  deviceoffAt[4] = (EEPROM.read(21)*3600)+(EEPROM.read(22)*60)+EEPROM.read(23);
  deviceonAt[5] = (EEPROM.read(24)*3600)+(EEPROM.read(25)*60)+EEPROM.read(26);
  deviceoffAt[5] = (EEPROM.read(27)*3600)+(EEPROM.read(28)*60)+EEPROM.read(29);

}

void InfoSD(void) {
  // list logfiles available on diskfile date and size
  Serial.println("Logs Found, Size in bytes :");
  Serial.println("===========================");
  sd.chdir("/logs");
  sd.ls(LS_DATE | LS_SIZE);
  if (!card.init(SPI_FULL_SPEED, chipSelect)) {
    //sdErrorMsg("\ncard.init failed");
    return;
  }
  if (!vol.init(&card)) {
    // sdErrorMsg("\nvol.init failed");
    return;
  }
  int bpc = int(vol.blocksPerCluster());
  long DS= (vol.clusterCount()*int(vol.blocksPerCluster()))/2 ;
  long DF= (vol.freeClusterCount()*int(vol.blocksPerCluster()))/2 ;
  Serial.print("=== Disksize : ");
  Serial.print(DS/1024);
  Serial.print(" MB, ");
  Serial.print(DF/1024);
  Serial.print(" MB Free, still room for about ");
  Serial.print (DF/5540);
  Serial.println(" days");
}

void readsensors(void){
  tooktime = micros(); 
  readTemp();                                   // read all ds18b20s temperature sensors
  if (Debug){
    Serial.print ("ds18b20 sensors took ");
    Serial.print (micros()-tooktime);
    Serial.println (" Micro - seconds.");
  }
  tooktime = micros(); 

  dhtdat = dht.readHumidity();                  // read dht air humidity sensor
  if (isnan(dhtdat)) {                          // Error from DHT
    Serial.println("Failed to read from DHT");
  } 
  if (Debug){
    Serial.print ("dht sensor took ");
    Serial.print (micros()-tooktime);
    Serial.println (" Micro - seconds.");
  }
  tooktime = micros(); 

  CHKearth();                                   // read moisture sensors earth
    if (Debug){
    Serial.print ("dht sensor took ");
    Serial.print (micros()-tooktime);
    Serial.println (" Micro - seconds.");
  }

}
 

Skutch

Member
Part 2 of the spaghetti, the schematics.

ABC.jpg
Unfortunately the image is resized by the forum, hope it's still readable.
 

AdvancedNewbie

Well-Known Member
Looks like you're on the right track. I've got an ethernet shield too, so I think I'm going to use the SD card as a buffer, until the arduino can dump everything on the computer. I have those DHT11's too - haven't got to try them out yet, how are they working for you? Thanks for the schematics as well, as I haven't looked it up for those yet, but now I don't have to. What benefit are you getting from the DS1307 besides battery backup? Does the time library have problems?
 

ommpCaregiver

Active Member
Awesome project. I worked on something similar : whttp://www.github.com/pleasuretek/opengreenhouse . and am currently working on the project with a beaglebone (embedded linux with database in the load center). I had a PC controlling my garden for quite some time, until the server one day just died on me (wont post, even after replacing CMOS battery). I think the environment of a greenhouse killed it ( I did not put the server in a box with HEPA filtration).

Also I just sourced a good c02 sensor today from DCS (Digital Control Systems) (been looking at them for a while). Model number 305e. NDIR sensor with SPI and 5v power, for $103 a piece for 1-10 of them... It is the same sensor Green Air Products uses in their sensors (I have one taken apart on my office floor right now after bad customer support experience).

In my personal project, I started to add an ethernet shield (with SD card for local logging of CSV file), but decided the linux stack of encryption, servers, databases, and variaty of languages would be a huge help. Also learning about the beaglebone has been a really fun learning experience.

I feel this problem has been taken on by a few people already, and it is important for us to share info and all contribute to an open source controller/software stack. It could not only help us all grow better plants, as well as help to feed the world healthy food.

Here is a link to my current parts list (reworking the relay section for DIN mount relays instead of hockeypuck style): https://docs.google.com/spreadsheet/ccc?key=0AkU3fFID7_H5dEE4VldmZ0U0eEEyVXpKbXkyN0otNVE
 

ommpCaregiver

Active Member
Thought I would post some pics of the build I had working on arduino platform. There were 3 'high' power relays (only 25A 120v - not running ballasts) to control A/C and dehumidifier and fans, and three low power (relays are in the junction box the outlets are mounted in). The power line went straight to a 30A 120v breaker in the main load center. It worked great turning lights on and off on time, and keeping temps and humidity under control (and loging to database) until I woke up one morning and the server that was running the control software was dead. And the control software is written in C++ with Qt, so it will run native on Windows, MacOSX, and Linux (multi architechture as long as you have an abi for gcc to use, I have ran it on a beagleboard)

The relays in the last image are the typer I used to use. You can get them for cheap around town and they are very reliable (no moving parts like mechanical relays, opto-isolater + triac). The model numbers for the 25A versions are "Crydom d2425" or the USA manufactured "Opto22d 24od25", there are also 10A versions for lighter loads, however A/Cs and other big devices need bigger relays. I suggest using a power meter to test the actual load of each device (including spikes) to determine the proper size of relay.

I used Maxim DS18B20 (dallas one wire) temp sensors, and DHT11 temp and humidity sensor for sensors. I still use the DS18B20's as they work with the owfs for Linux, but the humidity sensor I have chosen to re-source for one with i2c or SPI so I don't have to write any drivers.

IMG_20120523_114225.jpgIMG_20120523_121453.jpgIMG_20120523_121540.jpgIMG_20120523_121655.jpgIMG_20120530_223610.jpg
 

AdvancedNewbie

Well-Known Member
I'm liking those relays, I'm going to add this one (in which I already bought) to my outlet box: http://www.idec.com/language/english/catalog/Relays/RSSSeries.pdf <--- 25A

There's a nice little example for the DHT11's here: http://www.ladyada.net/learn/sensors/dht.html

Includes a DHT library. Shows Humidity and Temp. But the DHT11 is only accurate within +/- 2.0 degrees - not the most accurate in world.

The owfs seems really smart, 'why not have you temperature sensor as part of your filesystem?' lol
 

ommpCaregiver

Active Member
Yeah the DHT-11 was working great on the arduino with that library. But that library is written for AVR micros, and taking that logic and implementing it as a linux kernel module is a little over my head. Also everything in linux is a file... so to read the temps from the DS18B20, you simply open a file for reading. This makes it easy to interface with w1(one-wire), i2c, and SPI devices through any language that can read or write files.

The version I am building right now is going to take 80A into a DIN mount distribution block, from there to DIN mount SSRs. The 5v power supply for the beagle bone is also DIN mount. It will keep the inside of the box much more organized as well as finger friendly (I almost lost a finger during this project, my multimeter probe tip touched the 30A rail (yes accidents happen) and caused a spark that could of melted my bone (I was safe), and damaged my first beagleboard and the multimeter).


I really like your software layout. Do you have any experience with coding in c++ or Python? How about GUI toolkits, any experience with Qt or GTK+ ? I started to code this projec in c++ with Qt but c++ gets a little wonky when you get deep into memory management (pointers, references, registers oh my), which is why I have chosen this time ( 5th times a charm right) to start writing the project in python. Right now it is a console program that puts sensor data into database, and makes decisions (turn on or off) based on the curves of the sample data. I am up in the air about which GUI toolkit to use, Qt I have 3+ years coding with ( meaning I know how deep the rabbit hole goes, and how bad nokia has mangled the libs), or GTK that has better support on a wider range of OSes... Also to note, the GUI is viewed with SSH X forwarding - running on beaglebone (armv7) showing GUI with 'native' look and feel on OSX, windows and Android (I dont know of an app that can display X on iPhone nor do I care, apple is evil (just like microshaft) and in 1000 years not a bit of OSX or Windows code will still be in use due to the proprietary closed source selfishness... Where Linux is a block in the great pyramid, the stairs to the stars, a stepping stone for us (as a race) to conquer the heavens by allowing all that inherit from earth to freely build upon it...). Once again I really like the layout and the logic you have created with your program, however IMO anything written in VB.NET has inherent security flaws... meaning if this device was on a network that was connected to the internet, If I so had some motivation, I could turn your lights on and off, causing hermies, meaning your crop isn't worth as much as mine now... That is just one use case of the problems inherited with using the microsoft stack ( more like weave there are so many holes and free space in inject subroutines ) - Also the beaglebone is running ARM instructions, the opcodes are way different so every scriptKiddie with a pile of x86 - IA64 shellcode wont be able to attack it ( of coarse if one can write ARM asm ( like for a RTOS) then one can craft ARM shellcodez, but those people generally have great jobs ).

Ok Im stoned, rambling (I can ramble about security for probably about 29 years), and have to go to work. Really awesome project you have started, tonight I am going to have a look at teh codez, see If I can port the overall logic onto a markerboard, and see where this takes us (I bet its further ;)
 

ommpCaregiver

Active Member
I like the SSR you posted a datasheet for, however, the beaglebone is a 3.3v device (out of the GPIO (like digital pin)). So I look for relays that can be switched with a minimum input load of 3v (that one is 4v) so that I don't have to use a logic level shifter. Also I use the crydom ones (they are 3v-32vdc) when i can find a cheap lot on ebay, but I like the opto22 brand since they are manufactured in USA, meaning some monkey around here is getting a paycheck from us using them, vs more of asia making the profit and buying up all the buildings downtown and owning most of our dept.

And that datasheet says DIN mount, but they are flat bottom hockey puck, you need an adapter (usually a heatsink) to actually mount them on the DIN rail. I have been spec'ing similar relays but the heatsink and DIN mount are all a part of the relay.

Also if you are controlling a semi high load ( like a 12A A/C ) make sure to test the temps of the relay (temp gun bottom metal heatsink plate), as you may need a heatsink to avoid setting your house on fire.

One more thing... If you need a parts list to build a MLC like lighting relay controller (with trigger chord to plug into our duino/beagle boxxes) I have a spreadsheet around for that too, as I build all my lighting relays myself these days (dpst no 30A relay in a junctionbox (all pats from grainger supply))
 

AdvancedNewbie

Well-Known Member
Well thanks, I guess you could do a lot to make it safe; running in a Virtual Machine and keeping the network on a VPN, etc, etc.... Yeah, it has security flaws, but so does everything; I think SSHing might be in need here, but that's another topic, like you said could probably ramble on about security for 29 years. I do have some programing experience with C++ but it's always been on the microcontroller side and only console apps in windoze, never anything with a GUI... But as I understand it, you can use a designer to come up with the 'layout' code for you, and from there it should be similar to C++ console programming. Since I'm hopping over the fence here and am going to have the code primary on the microcontroller, I'm assuming that the PC code should be easy and straightforward. As it stands, my project is/was sort of setup to be able to do anything from brewing beer to growing weed to analyzing a gryo in an airplane...

I think it's going a little over the top; my original idea: "Make a program that can analyze data from sensors and act on that data with 'on the fly' IF statements or Timers." (VB mindset)

New Idea: "Make a great Environment Controller that logs data that can be viewed remotely (even if it's in the next room) on a PC or smartphone for under $250." (C++ mindset)

But I have a little time this weekend (and right now) so I'm going to play with my mega and LCD screen and try and write a quick sketch. I think I'm going to try and make a historical style program in VB.NET too. I'm also going to go specific rather than broad this time, so no firmata... This should be easy - I might steal some firmata code though, they seem to know what they're doing.

I'm also interested in the calculus behind the data logging and the PID loops. Could get interesting real quick. I'll keep you guys posted. Seems like we just got a bunch of motivation in one spot. Now we just gotta build it.
 

Afistakis

Member
Awesome project. I worked on something similar : whttp://www.github.com/pleasuretek/opengreenhouse . and am currently working on the project with a beaglebone (embedded linux with database in the load center). I had a PC controlling my garden for quite some time, until the server one day just died on me (wont post, even after replacing CMOS battery). I think the environment of a greenhouse killed it ( I did not put the server in a box with HEPA filtration).

Also I just sourced a good c02 sensor today from DCS (Digital Control Systems) (been looking at them for a while). Model number 305e. NDIR sensor with SPI and 5v power, for $103 a piece for 1-10 of them... It is the same sensor Green Air Products uses in their sensors (I have one taken apart on my office floor right now after bad customer support experience).

In my personal project, I started to add an ethernet shield (with SD card for local logging of CSV file), but decided the linux stack of encryption, servers, databases, and variaty of languages would be a huge help. Also learning about the beaglebone has been a really fun learning experience.

I feel this problem has been taken on by a few people already, and it is important for us to share info and all contribute to an open source controller/software stack. It could not only help us all grow better plants, as well as help to feed the world healthy food.

Here is a link to my current parts list (reworking the relay section for DIN mount relays instead of hockeypuck style): https://docs.google.com/spreadsheet/ccc?key=0AkU3fFID7_H5dEE4VldmZ0U0eEEyVXpKbXkyN0otNVE
I just got mental whiplash from so many acronyms! I have no idea what was just said but I suppose I have time to read a book... Thanks for the parts list and additional direction.

I received my mega and a few shields and sensors in the mail today. I'm still waiting on some key components to fully start, but it's time to see what I can put together.
 
Top