What's new
TerraForums Venus Flytrap, Nepenthes, Drosera and more talk

Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

So I'm working on a controller

So I made a ~$40 controller

I recently began learning to program the Arduino, a useful little microcontroller. The code is very easy to learn, and so in just a couple weeks I am already working on a few simple games.
My plan is to create a controller for terrariums and greenhouses using the Arduino Nano (or at least a clone) and a simple LCD display. 16 characters per line, 2 lines. I have already made aquarium controller code, so the greenhouse stuff should be done in just a few days.
If anybody is interested, respond and give suggestions on what you would like to see. Touch screen support is possible, but could take a while.

What you will need:
-Arduino nano or Uno, any model Arduino really
-DHT22 temperature and humidity sensor
-16x2 lcd display, 16 pin
-3 10kohm resistors
-470ohm resistor (backlight for lcd)
-2 momentary buttons
-Jumper wires
-Full-size breadboard (halfsize is usable but hard)(You could also use a protoboard)
-USB cable to connect Arduino and CPU
-Library for DHT22 (https://www.virtuabotix.com/?attachment_id=1854)

All that will come out to less than $40 is you buy on ebay and are willing to wait 1-2 weeks for shipping (epacket delivery from China is the best method; 2 week delivery for about $0.50).



Current features, 4-7-13:
-Lighting, on and off
-Humidity, max and min
-Day temperature, max and min
-Night temperature, max and min
-Clock
-LCD Display

And anything else you can think of! I will update this first post with code every few days.

Code, updated 4-7-13:
To do:
-Wiring diagram
-Watering


Code:
//Replace the three "[" thingies with "<" keys; the "<" does not show up on terraforums.com.
#include [LiquidCrystal.h>
#include [dht22.h>
#include [EEPROM.h>

// This is an arduino clock.
unsigned long start = 0;
unsigned long current = 0;
// The values that are displayed
int displaysecond = 0;
int displayminute = 0;
int displayhour = 0;


//BUTTONS
int lastchangestate;
int lastsetstate;
// Changing buttons
int changebuttonstate;
int setbuttonstate;


//lighting stuff
int onedawnhour;
int oneduskhour;


//Temp and Humidity
int chk;
dht22 DHT22;
unsigned long dhttime;
unsigned long dhtloop;
int displaytempF;
int displaytempC;
int displayhumidity;


int tempsetmin;
int tempsetmax;
int nighttempsetmin;
int nighttempsetmax;

int tempmax;
int tempmin;
int hummin;
int hummax;


int humsetmax;
int humsetmin;

int show;
boolean humon;
boolean tempon;


/*
What the pins are connected to. The LCD uses 12, 11, 5, 4, 3, and 2, but that still leaves 
all of the analog pins and many digital pins. You can wire the LCD in different ways but this is th easiest.

Oh, the analog pins are used as outputs in some cases. Table:

Pin 14 = Analog in 0
Pin 15 = Analog in 1
Pin 16 = Analog in 2
Pin 17 = Analog in 3
Pin 18 = Analog in 4
Pin 19 = Analog in 5
*/

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
//Set button is changing the values, while change button is changing what the display shows.
#define setbuttonpin             7
#define changebuttonpin          8

//Pin the relay that controls the lights is connected to.
#define lightpin                 9

//Pin the DHT22 sensor is connected to. You can use a DHT11, but it's way less accurate and has a smaller range.
#define dhtpin                   6

//Temperature and humidity outputs to relays.
#define temppin                  10
#define humpin                   13

//Liquid level sensor attached to
#define levelsensor              A0

//Relay attached to watering system
#define levelsensorout           15


void setup ()
{
  timeSetup();
  buttonSetup();
  displaySetup();
  lightSetup();
  humtempSetup();
}




void timeSetup()
{
  start = millis();
  current = start;
  displaysecond = 0;
  
  // Times that are displayed on startup. Change this to change the starting time.
  displayminute = 0;
  displayhour = 8;
}


void buttonSetup()
{
  pinMode(setbuttonpin, INPUT);
  pinMode(changebuttonpin, INPUT);
  lastchangestate = digitalRead(changebuttonpin);
  lastsetstate = digitalRead(setbuttonpin);
  changebuttonstate = digitalRead(changebuttonpin);
  setbuttonstate = digitalRead(setbuttonpin);
}

void displaySetup()
{
  lcd.begin (16,2);
}

void lightSetup()
{
  pinMode (lightpin, OUTPUT);
  //Hours of on and off for channels one and two in 24 hour time.
  onedawnhour = EEPROM.read(7);
  oneduskhour = EEPROM.read(8);
}
  
void humtempSetup()
{
  //Pin the DHT22 is attached to
  DHT22.attach(dhtpin);
  dhttime = millis();
  dhtloop = dhttime; 
  tempon = false;
  humon = false;
  
  tempsetmax = EEPROM.read(1);
  tempsetmin = EEPROM.read(2);
  nighttempsetmax = EEPROM.read(3);
  nighttempsetmin = EEPROM.read(4);
  
  humsetmax = EEPROM.read(5);
  humsetmin = EEPROM.read(6);
}







void loop()
{
  clockLoop();
  lightLoop();
  buttonLoop();
  displayLoop();
  humtempLoop();
  memoryLoop();
}



void clockLoop()
{
  current = millis();
  if (current >= start + 1000) 
  {
    displaysecond = displaysecond + 1;
    start = current;
    lcd.clear();
 }
  if (displaysecond >= 60) {
    displaysecond = 0;
    displayminute = displayminute + 1;
  }
  if (displayminute >= 60) {
    displayhour = displayhour + 1;
    displayminute = 0;
  }
  if (displayhour >= 24) {
    displayhour = 0;
  }
  
  
}


void buttonLoop()
{
  changebuttonstate = digitalRead (changebuttonpin);
  if (changebuttonstate != lastchangestate)
  {
    lastchangestate = changebuttonstate;
    if (changebuttonstate == HIGH)
    {
      if (show < 15) 
      {
        show ++;
      }
      else
      {
        show = 0;
      }
      lcd.clear();
    }
  }
  
  
  //Setting stuff
  setbuttonstate = digitalRead(setbuttonpin);
  if (setbuttonstate != lastsetstate)
  {
    lastsetstate = setbuttonstate;
    if (setbuttonstate == HIGH)
    {
      
      if(show == 3)
      {
        if(onedawnhour < 24)
        {
          onedawnhour++;
        }
        else
        {
          onedawnhour = 0;
        }
      }
      
      if(show == 4)
      {
        if(oneduskhour < 24)
        {
          oneduskhour++;
        }
        else
        {
          oneduskhour = 0;
        }
      }
      
      if(show == 6)
      {
        if(humsetmax < 100)
        {
          humsetmax++;
        }
        else
        {
          humsetmax = 0;
        }
      }
      
      if(show == 7)
      {
        if(humsetmin < 100)
        {
          humsetmin++;
        }
        else
        {
          humsetmin = 0;
        }
      }
      
      if(show == 9)
      {
        if(tempsetmax < 110)
        {
          tempsetmax++;
        }
        else
        {
          tempsetmax = 32;
        }
      }
      
      if(show == 10)
      {
        if(tempsetmin < 110)
        {
          tempsetmin++;
        }
        else
        {
          tempsetmin = 32;
        }
      }
      
      if(show == 12)
      {
        if(nighttempsetmax < 110)
        {
          nighttempsetmax++;
        }
        else
        {
          nighttempsetmax = 32;
        }
      }
      
      if(show == 13)
      {
        if(nighttempsetmin < 110)
        {
          nighttempsetmin++;
        }
        else
        {
          nighttempsetmin = 32;
        }
      }
      
      if(show == 14)
      {
        if(displayhour < 24)
        {
          displayhour++;
        }
        else
        {
          displayhour = 0;
        }
      }
      
      if(show == 15)
      {
        if(displayminute < 59)
        {
          displayminute++;
        }
        else
        {
          displayminute = 0;
        }
      }
    }
  }
}

void displayLoop()
{
  if (show == 0)
  {
    lcd.setCursor(0,0);
    lcd.print("Time: ");
    lcd.print(displayhour);
    lcd.print(":");
    if(displayminute < 10)
    {
      lcd.print("0");
    }
    lcd.print(displayminute);
    lcd.print(":");
    if(displaysecond < 10)
    {
      lcd.print("0");
    }
    lcd.print(displaysecond);
    lcd.setCursor (0,1); 
    lcd.print(displaytempF);
    lcd.print("F ");
    lcd.print(displayhumidity);
    lcd.print("%");
  }
  
  if(show == 1)
  {
    lcd.setCursor(0,0);
    lcd.print("Max temp: ");
    lcd.print(tempmax);
    lcd.print("F");
    lcd.setCursor(0, 1);
    lcd.print("Min temp: ");
    lcd.print(tempmin);
    lcd.print("F");
  }
  
  if(show == 2)
  {
    lcd.setCursor(0,0);
    lcd.print("Max humid: ");
    lcd.print(hummax);
    lcd.print("%");
    lcd.setCursor(0, 1);
    lcd.print("Min humid: ");
    lcd.print(hummin);
    lcd.print("%");
  }

  if(show == 3)
  {
    lcd.setCursor(0,0);
    lcd.print("Set light on hr ");
    lcd.setCursor(0,1);
    lcd.print(onedawnhour);
  }
  
  if(show == 4)
  {
    lcd.setCursor(0,0);
    lcd.print("Set light off hr");
    lcd.setCursor(0,1);
    lcd.print(oneduskhour);
  }
  
  if(show == 5)
  {
    lcd.setCursor(0,0);
    lcd.print("Set max hum:");
    lcd.print(humsetmax);
    lcd.print("%");
    lcd.setCursor(0,1);
    lcd.print("Set min hum:");
    lcd.print(humsetmin);
    lcd.print("%");
  }
  
  if(show == 6)
  {
    lcd.setCursor(0,0);
    lcd.print("Set max humidity:");
    lcd.setCursor(0,1);
    lcd.print(humsetmax);
    lcd.print("%");
  }
  
  if(show == 7)
  {
    lcd.setCursor(0,0);
    lcd.print("Set min humidity:");
    lcd.setCursor(0,1);
    lcd.print(humsetmin);
    lcd.print("%");
  }
  
  if(show == 8)
  {
    lcd.setCursor(0,0);
    lcd.print("Day temp max:");
    lcd.print(tempsetmax);
    lcd.setCursor(0,1);
    lcd.print("Day temp min:");
    lcd.print(tempsetmin);
  }
  
  if(show == 9)
  {
    lcd.setCursor(0,0);
    lcd.print("Set max day temp");
    lcd.setCursor(0,1);
    lcd.print(tempsetmax);
  }
  
  if(show == 10)
  {
    lcd.setCursor(0,0);
    lcd.print("Set min day temp");
    lcd.setCursor(0,1);
    lcd.print(tempsetmin);
  }
      
  if(show == 11)
  {
    lcd.setCursor(0,0);
    lcd.print("Night max:");
    lcd.print(nighttempsetmax);
    lcd.setCursor(0, 1);
    lcd.print("Night min:");
    lcd.print(nighttempsetmin);
  }
    
  
  if(show == 12)
  {
    lcd.setCursor(0,0);
    lcd.print("Set max night");
    lcd.setCursor(0,1);
    lcd.print(nighttempsetmax);
  }
  
  if(show == 13)
  {
    lcd.setCursor(0,0);
    lcd.print("Set min night");
    lcd.setCursor(0,1);
    lcd.print(nighttempsetmin);
  }
  
  if(show == 14)
  {
    lcd.setCursor(0,0);
    lcd.print("The hour is:");
    lcd.setCursor(0,1);
    lcd.print(displayhour);
  }
  
  if(show == 15)
  {
    lcd.setCursor(0,0);
    lcd.print("The minute is:");
    lcd.setCursor(0,1);
    lcd.print(displayminute);
  }
}



void lightLoop()
{
  if (displayhour >= onedawnhour && displayhour < oneduskhour)
  {
    pinMode(lightpin, HIGH);
  }
  if (displayhour < onedawnhour || displayhour >= oneduskhour)
  {
    pinMode(lightpin, LOW);
  }
}



void humtempLoop()
{
  dhttime = millis();
  
  if(dhttime >= dhtloop + 2000)
  {
    dhtloop = dhttime;
    switch (chk)
    {
      chk = DHT22.read();
      case 0: break;
      case -1: lcd.print("Checksum error"); break;
      case -2: lcd.print("Time out error"); break;
      default: lcd.print("Unknown error"); break;
    } 
  displayhumidity = (DHT22.humidity);
  displaytempC = (DHT22.temperature);
  displaytempF = (DHT22.fahrenheit());
  }
  
  if(displayhumidity < humsetmin && humon == false)
  {
    pinMode(humpin, HIGH);
    humon == true;
  }
  
  if(displayhumidity > humsetmax && humon == true)
  {
    pinMode(humpin, LOW);
    humon == false;
  }
  
  
  
  if(displayhour >= onedawnhour && displayhour < oneduskhour)
  {
    if(displaytempF < tempsetmin && tempon == false)
    {
      pinMode(humpin, HIGH);
      tempon == true;
    }
  
    if(displaytempF > tempsetmax && tempon == true)
    {
      pinMode(humpin, LOW);
      tempon == false;
    }
  }
  
  else
  {
    if(displaytempF < nighttempsetmin && tempon == false)
    {
      pinMode(humpin, HIGH);
      tempon == true;
    }
  
    if(displaytempF > nighttempsetmax && tempon == true)
    {
      pinMode(humpin, LOW);
      tempon == false;
    }
  }
  
  
  if(displaytempF > tempmax)
  {
    tempmax = displaytempF;
  }
  
  if(displaytempF < tempmin)
  {
    tempmin = displaytempF;
  }
  
  if(tempmin == 0)
  {
    tempmin = displaytempF;
  }
  
  if(displayhumidity > hummax)
  {
    hummax = displayhumidity;
  }
  
  if(displayhumidity < hummin)
  {
    hummin = displayhumidity;
  }
  
  if(hummin == 0)
  {
    hummin = displayhumidity;
  }
}




void memoryLoop()
{
  EEPROM.write(1, tempsetmax);
  EEPROM.write(2, tempsetmin);
  EEPROM.write(3, nighttempsetmax);
  EEPROM.write(4, nighttempsetmin);
  EEPROM.write(5, humsetmax);
  EEPROM.write(6, humsetmin);
  EEPROM.write(7, onedawnhour);
  EEPROM.write(8, oneduskhour);
}

//New features go here!
 
Last edited:
Got the first part of the code done. I was able to re-use a lot of the code from my aquarium lighting project.
I am currently at ~7,000 bytes of the ~14,000 byte maximum available space on the Arudino Nano 168. The 328 has 2x memory.
 
Finished with lights, humidity, and temp. The lcd takes up so many pins that there are none left for a liquid level sensor.
I might have to use the analog pins as outputs.
Also updated first page.
 
Sounds like a great project, asid. If I knew anything, whatsoever, about code, I'd try to add something constructive!
 
I recently began learning to program the Arduino, a useful little microcontroller. The code is very easy to learn, adn so in just a couple weeks I am already working on a few simple games.
My plan is to create a controller for terrariums and greenhouses using the Arduino Nano (or at least a clone) and a simple LCD display.

Nice project!

If anybody is interested, respond and give suggestions on what you would like to see.

I'd like to see a link to the DHT22 library you actually linked against your code.

The one I downloaded from https://github.com/nethoncho/Arduino-DHT22 did not compile with your code.

BTW: The two "#include" lines at the beginning of your code are truncated by the Terraforums software which is not very suitable for posting Arduino code.
 
Nice project!



I'd like to see a link to the DHT22 library you actually linked against your code.

The one I downloaded from https://github.com/nethoncho/Arduino-DHT22 did not compile with your code.

BTW: The two "#include" lines at the beginning of your code are truncated by the Terraforums software which is not very suitable for posting Arduino code.

The library for DHT22 is this one: https://www.virtuabotix.com/?attachment_id=1854
I have no idea why I used that one. Maybe adafruit used it too?

And I know about the #include thing. Kinda weird. I'm fixing it now.

EDIT: Fixed it! I'm trying to keep this simple though, so that people with no coding experience can use it. Right now I am using a half-size breadboard to put this together, but a full size one will is much better.

Pics soon!
 
Last edited:
The library for DHT22 is this one: https://www.virtuabotix.com/?attachment_id=1854
EDIT: Fixed it! I'm trying to keep this simple though, so that people with no coding experience can use it. Right now I am using a half-size breadboard to put this together, but a full size one will is much better.

OK, using that DHT22 library I could compile and run the code.

Currently I have just connected the display (no buttons and no DHT sensor connected to the Arduino).

When running the code I see:
First line of the display shows some weird and rather quickly scrolling text (can identify the word "Time" in it, followed by the time counting from the initial starting value, scrolling speed seems to vary).
Second line of the display is empty.

That doesn't look very fail-safe. The controller should be able to recognize the conditions when
- no sensor is present
- sensor does not provide correct values (receives data, checksum OK etc.)
I'd prefer to see a warning message if the sensor is not working as expected.

Is this a very early state of your code and still needs development?
 
This is early. I just streamlined the code.
I just tested it with the LCD. Found the problem and am fixing it now.

EDIT: Just fixed it. Just a matter of spacing I think.
 
Added support for different night and day times.

Error messages are hard to program in currently. I'll add one in a sec for temp and humidity though.

Oh, terraforums does not support extra spaces either. I'll attach a text document.

EDIT: Oh, I just had to wrap the whole thing in "code" for the spaces to show. Okay then.
A .txt will be available too.

DOUBLEEDIT: Can't figure out how to attach stuff, even in advanced editing. I'll post a .txt when it's done.
 
Last edited:
  • #10
Tried error messages. Didn't work. The lcd randomly prints "Time out" if I have error message code. I can add it in any time using the example code, but until then this will have to do without.
EDIT: Never mind. Turns out I was sampling it all the time.
 
  • #11
Buttons were wrong. Fixed that.
 
  • #12
I just realized you can't change the hour of day. Standby...
 
  • #13
Everything works!
I would celebrate with wine, but I'm only 14. :D
 
  • #14
Work will be stopped until the liquid level sensor I ordered is here.
 
  • #15
Updated so that if it shuts off you retain your settings other than time. Time won't be for another, oh, 5 days when I receive my RTC (real time clock).
 
  • #17
What a cool project! Those arduinos sure are useful for a lot of things.
 
  • #18
Hmm. The thing is constantly running next to my computer, but it seems to reset the time every hour or so.
Hmmm.....
 
  • #19
Hmm. The thing is constantly running next to my computer, but it seems to reset the time every hour or so.
Hmmm.....

I think that your current code is damaging the hardware.

The EEPROM memory has only limited write cycles, but you are calling this function in an unlimited number from the loop():
void memoryLoop()
{
EEPROM.write(1, tempsetmax);
EEPROM.write(2, tempsetmin);
EEPROM.write(3, nighttempsetmax);
EEPROM.write(4, nighttempsetmin);
EEPROM.write(5, humsetmax);
EEPROM.write(6, humsetmin);
EEPROM.write(7, onedawnhour);
EEPROM.write(8, oneduskhour);
}

So after short time these EEPROM cells used for writing will be unusable and have NOT the values they should have after reading from them.

Please check the logic for writing to EEPROM!

Also do a verification that the values you can read from the EEPROM memory cells 1...8 are what they should be. And if these EEPROM cells are already written to death, chose some offset for using some reliable and faultless EEPROM cells to store and read values.
 
  • #20
Oh man. thanks, I'll fix that right now.
 
Back
Top