/*
************** UPDATED ON DEC 2017 *************
*************** GETTING BETTER THAN BEFORE *************
#############################################
FOR UPDATED 6.5 VERSION WATCH/READ DESCRIPTION:
##############################################
*** MAKING A MODULAR SYSTEM FOR D.I.Y. GROWBOX / GREENHOUSE
***Independent Grow Box Controller that can be used to Control all the Important devices to maintain
*
*
the ""Grow Environment"" for example Lights, Heater,Cooler,Fan for blowing air inside the box ,Fan for exhaust,
Humidifier or mist maker,Water pump ,Solenoids etc
*****i WILL improve it as i learn more :)
//**********************//**********************//**********************
//**********************//**********************//**********************//**********************//**********************//**********************
// Arduino Nano Grow-box / Green-House Controller v 5.0 :)
//**********************//**********************//**********************//**********************//**********************//**********************
//###############################################################
//***************************************************************
// PLEASE SUBSCRIBE
// comment for any question or help with this sketch
// My youtube Channel: https://youtube.com/CrazyGuyOfficial
//****************************************************************
//################################################################
// ***Made by Ali khan from Pakistan :)
//**********************//**********************//**********************
// **PARTS required (for this sketch to work as it is )
//**********************//**********************//**********************
1.Arduino Nano
2.A thermistor (i used A 10K WATERPROOF ONE)
3.A resistor (matching the value of the thermistor's "nominal resistance at 25 DEGREES C" for example: 5k resistor for 5k thermistor)
4.SPI OLED display ssd1306 (mine is ssd1306 but got it working by using sh1106 constructor also got rid of the "white line problem")
5. DHT 22 (WITH PULL UP RESISTOR I USED 10k OHM)
6.RELAY MODULE LOW LEVEL TRIGGER TYPE (6 Relays required in total for all the pins, can be separate 4 CAN WORK TOO )
7. DS3231 RTC MODULE (RESISTOR from charging circuit REMOVED and charging DISABLED..BECAUSE I USED CR2032(NON-rechargeable)Cell
8. AN LED WITH APPROPRIATE RESISTOR FOR USE AS A STATUS LED
9. Soil Humidity Sensor
10. Water Level Sensor
11. Two Stable 5 Volts DC Power Sources with Separate Grounds For Complete Optical Isolation (one can work)
*/
//**********************//**********************//**********************
// INCLUDE LIBRARIES make sure you have them all installed
//**********************//**********************//**********************
// Get them from within you Arduino IDE 1.6.9 that i used
// get the correct version
// by correct i mean the version that i used and
// because i can't guarantee that this sketch will work with
// other latest versions of the same libraries
#include "DHT.h" // use DHTsensorLibrary // Version 1.2.3 //latest is the AdafruitUnifiedSensorLibrary
#include <U8glib.h> // OLED // Version 1.19.1
#include <Wire.h> // I2C // Version 1.0.0
#include <Time.h> // Time Manipulation // Version 1.5.0
#include <DS1307RTC.h> // DS1307 RTC // Version 1.4.0
#include <TimeAlarms.h> // time alarm library // Version 1.5.0
// Changed Number of alarms " dtNBR_ALARMS to 8 "
// BY EDITING TIMEALARM.H FILE IN LIBRARIES FOLDER.
// increasing this number increases size of the sketch too
// and the use of ram
// if you don't want to change the number then remove alarms and keep only
// that number of Alarms that is specified in YOUR TimeAlarms Library
// I have Left 8 Alarms BELOW that Call a Function to Sync Arduino's Clock with RTC
// if you Uncomment the Rest you will get some Errors
// if you increase the Number in TimeAlarms.H file then
// Don't UN-comment Void SPrintStatusTwo
// That prints out Switch Status
// OR you will get Low Memory Error for Nano/UNO
#define DS1307_ID 0x68 // I2c Address of the RTC
//######################################################################
//******************************************************************/
// TEMPERATURE and HUMIDITY DEFAULT "CONTROL PARAMETERS"
//******************************************************************\
//######################################################################
// Default Temperature and Humidity Settings
byte Tmax = 29 ; // Set temperature Maximum point at which "Cooler" will turn ON
byte Tnor = 25 ; // Set temperature point at which "heater" and "cooler" will turn OFF
byte Tmin = 19 ; // Set temperature Minimum point at which Heater will turn ON
byte Hmax = 60 ; // set humidity max at which "bigfan" will turn ON
byte Hnor = 45 ; // Set humidity normal at which "bigfan" and "spray" will turn OFF
byte Hmin = 25 ; // Set humidity low at which "spray will turn ON
// Separate Temperature and Humidity Settings for Day and Night time can be done by Alarms function belowwww
// but anything done by Alarms is lost if a Reset happens or power up/down cycle
// and so in that case everything will return to their default state
//######################################
//*********************************/
// PUMP TURN ON/OFF Settings ####
//*********************************\
//######################################
byte pumpT = 30 ; // Time in Seconds for which the Pump will run if Soil goes Dry
// after the Time is up the pump will Turn Off
byte dryVal = 50 ; // Soil Humidity percentage Value below which the Pump will be Turned ON
// when the Alarm Calls the WateringA function
// pump will turn OFF after the Time "pumpT" is up
int DV = 1023 ; // Dry Value the MAX Analog Read Value Above which the Soil gets DRY //max 1023
int HV = 0 ; // Humid / Wet Value below which the Soil should not be watered // min 0
// these numbers are used to "map" analog read values in SoilHumCalc Function
// can be used for Calibration
byte waterOne = 50 ; // Water Level Sensor 1 percentage Value below which the water reservoir will be considered empty
int FV1 = 800 ; // MAX value when Tank is FULL // i used it because my sensor doesn't give out 5V/max 1023 when 100% wet
int EV1 = 0 ; // MIN Value Below Which Tank is Empty // min 0
// Separate Function for watering using the Digital/Analog Read method for Soil Humidity Sensor's Digital/Analog output Pins
// can be called from alarm functions belowwwww
//##################################################
//***********************************************/
// Light Timer ON/OFF Time Settings DEFAULT
//***********************************************\
//##################################################
const byte OnTime = 14 ; // Hour when Light will turn ON (24 hr format NO zeros before single digits)
const byte OffTime = 8 ; // Hour when Light will turn OFF (24 hr format NO zeros before single digits)
// SET RTC'S TIME USING DS1307 EXAMPLE SKETCH FROM ABOVE FILE > EXAMPLE > DS1307 > SETTIME
// THEN UPLOAD THIS SKETCH
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//***************************************************
// MAKING CHARACTER ARRAYS or C strings for OLED
//***************************************************
char str[10]; // for Display
//#################################################################################################################
//*****************************************************************************************************************
//************ some important variables *************** Values NOT TO BE CHANGED MANUALLY *************************
//*****************************************************************************************************************
//#################################################################################################################
float t2 = 0; // for Temperature 2 from Thermistor
float t =0; // floats for Temperature1 and Humidity from DHT
float h =0;
byte TempSts = 0 ; // used for updating the oled display
byte HumSts = 0 ;
float TmaxR = 0; // for Recording Max and Min Values from DHT
float HmaxR = 0;
float TminR = 0;
float HminR = 0;
bool DHTerr = 0 ;
bool RTCerr = 0 ;
bool LightSts = 0 ; // THESE ARE FOR STATUS UPDATES IN SERIAL MONITOR
bool CoolerSts = 0 ; // and ESP8266 to show on Html Webpage
bool HeaterSts = 0 ;
bool BigFanSts = 0 ;
bool SpraySts = 0 ;
bool PumpSts = 0 ;
int soilHumVal = 0 ; // for reading analog value from Soil Humidity Sensor's Analog output
bool waterTimeA = 0 ;
bool waterTimeD = 0 ;
int waterLvlOneVal = 0 ; // for reading analog value from Water Level Sensor's Analog output
bool REmpty = 0 ; // water reservoir empty
unsigned long Secs = 0;
unsigned long SecsTwo = 0;
unsigned long SecsThree = 0;
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//##################################
//********************************/
// PINS AND CONNECTIONS
//********************************\
//##################################
const byte Bigfan = 2 ; // Bigfan pin turns on at high humidity should be Two fans (inside,exhaust)
const byte cooler = 3 ; // Cooler pin turns on at high temp (T1 from DHT)
const byte spray = 4 ; // Spray turns on at low humidity
const byte lightone = 5 ; // Main Lights(for plants)
const byte heater = 6 ; // Heater pin turns ON at low temp (T1 from DHT)
const byte lighttwo = 7 ; // pin for "status LED'
const byte pumpPin = 8 ; // pin for turning the Water Pump ON/OFF
const byte waterLvlOne = A2 ; // pin for water level Sensor's Signal output pin it gives it gives raw voltage values
const byte soilHumD = A3 ; // pin for Soil Humidity Sensor's DIGITAL Output Signal Pin it goes High/Low
const byte soilHumA = A7 ; // pin for Soil Humidity Sensor's ANALOG Output Signal Pin it gives raw voltage values
// ******** THERMISTOR AND DHT PINS BELOW *******
// Connect the RTC according to it's pinout
// DS3231 RTC "SDA to A4", "SCL to A5"(uno/nano) "Vcc to 5V arduino pin Gnd to Gnd"
//####################################
//********************************/
// THERMISTOR PIN and SETTINGS
//********************************\
//####################################
#define THERMISTORPIN A0 // analog pin to connect to thermistor and the resistor "joint"
#define THERMISTORNOMINAL 10000 // resistance at 25 degrees C
#define TEMPERATURENOMINAL 25 // temp. for nominal resistance (almost always 25 C)
#define NUMSAMPLES 5 // how many samples to take and average,takes longer gets 'smooth'
#define BCOEFFICIENT 3500 // The beta coefficient of the thermistor (usually 3000-4000)
#define SERIESRESISTOR 9700 // the value of the 'other' resistor should be close to the thermistors nominal value
int samples[NUMSAMPLES];
//################################
//****************************/
// DHT PIN and SETTINGS
//****************************\
//################################
#define DHTPIN A1 // pin connected to DHT output
#define DHTTYPE DHT22 // DHT 22 (AM2302)
DHT dht(DHTPIN, DHTTYPE, 6); // the number 6 is for slower chips like the one used in Arduino Nano/UNO
//######################################################################
//*****************************************************************/
// OLED CONSTRUCTOR / OLED PINS that are connected to Arduino
//*****************************************************************\
//######################################################################
U8GLIB_SH1106_128X64 u8g(13, 11, 10, 9); // SW SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9 // OLED "constructor" and pins info.
// the version of oled i have has a different chip inside so the above one works for me
// before it i used the one that was supposedly for my version of oled and it was not working as expected
// if this doesn't work for you then go to Example Sketches for U8glib Library it has All the Constructors
// try them for your version of OLED
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//**************************
// SETUP BEGINS
//**************************
void setup()
{
digitalWrite(Bigfan, HIGH); // When using "LOW level trigger" type Relay module, turning a pin "HIGH" will
digitalWrite(cooler, HIGH); // turn the relay "OFF" and turning the pin "LOW" turns the relay "ON"
digitalWrite(heater, HIGH); // THIS WILL PREVENT STARTUP RELAY TRIGGERING PROBLEM
digitalWrite(spray, HIGH);
digitalWrite(pumpPin,HIGH);
digitalWrite(lightone,HIGH);
// add more if you have more relays or pins connected to something
Serial.begin(9600); // for initializing serial monitor
pinMode(Bigfan, OUTPUT) ; // set output relay pins // add more if you have more relays or pins connected to something
pinMode(cooler, OUTPUT) ;
pinMode(heater, OUTPUT) ;
pinMode(spray, OUTPUT) ;
pinMode(lightone,OUTPUT) ;
pinMode(lighttwo,OUTPUT) ;
pinMode(pumpPin,OUTPUT) ;
pinMode(soilHumD, INPUT) ;
pinMode(soilHumA,INPUT) ;
pinMode(waterLvlOne,INPUT) ;
// add more if you have more relays or pins connected to something
analogReference(EXTERNAL); // AREF connected to 3.3 ON BOARD for accuracy of thermistor
//(go to adafruit using a thermistor tutorial )
//******************************************
//********* Display at Startup ********
//******************************************
Start();
Alarm.delay(3000);
LightSet();
Alarm.delay(5000);
TempSet();
Alarm.delay(5000);
HumSet();
Alarm.delay(5000);
//**********************//**********************//***********************//**********************
//Check to see if the RTC is present.if yes then Set the ARDUINO's INTERNAL clock accordingly
//**********************//**********************//***********************//**********************
// when using timer library the Arduino's "internal clock " is used for getting "current time"
// Arduino's internal clock is NOT so accurate and gets off time so we use time from RTC (which IS
// accurate at-least for our use) and we sync Arduino's internal Clock with the time from RTC and we
// have to do this periodically (at-least once in every 24 hrs )so our tasks can be completed according
// to the correct time we can put the sync command in the Loop and Alarm Functions too
Wire.beginTransmission(DS1307_ID); // i2c devices have addresses which are used to communicate with them
Wire.write((uint8_t)0x00); // because same interface can be used to connect multiple i2c devices
setSyncProvider(RTC.get); // Configure Time to automatically called the getTimeFunction() regularly.
setSyncInterval(60);
//#####################
Alarm.timerRepeat(10, Repeats); // timer for every 10 seconds blinking LIGHT TWO (status LED)
// and Serial Prints Data
// TIMER ALARM THAT RUNS OVER AND OVER AFTER SECONDS // the Alarm in the Loop are different
// see the Example Sketches with the TimeAlarms Lib
dhtCalc() ; // call DHT,Thermistor calculation and Soil Humidity functions at setup
thermCalc() ; // so the relays don't trigger accidentally in those two seconds after which the loop calls those functions again
soilHumCalc() ;
waterLvlCalc() ;
Secs=SecsTwo=millis()/1000; // reset the timers and then in the loop it will be used again and again
}
//**************************************************************
//********* SETUP END ****************************************
//**************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*************************************************
//*** Function that Syncs Arduino's Clock with Rtc
//*************************************************
void SyncTime()
{
if (Wire.endTransmission() == 0) //Did the RTC respond?
{
setSyncProvider(RTC.get); // it did, get the time from the RTC
RTCerr=0; // set RTC error status boolean to false
// Serial.println("Got Time");
}
else
{
RTCerr=1;
}
}
//**************************************************
//*** Function For Display on the OLED *************
//**************************************************
void Start()
{
u8g.firstPage(); // START SCREEN "Picture loop" for OLED
do
{
u8g.setFont(u8g_font_helvB08); // set font for oled display
u8g.drawFrame(10, 12, 108, 31); // Draw Frame and it's Size
u8g.drawFrame(0, 0, 128, 64); // Draw Frame and it's Size
u8g.drawStr(15, 25, "Grow Box"); // Draw a string mentioned in quotes " "
u8g.setPrintPos(79,32); // Set print position for the next line
u8g.print("V 5.0"); // Print on the oled
u8g.drawStr( 16, 40, "Controller");
u8g.drawStr(53, 60, "Made by:AMK");
}
while ( u8g.nextPage() );
}
//***************************************************************
//*** Function For Light Control Settings Display on the OLED ***
//***************************************************************
void LightSet()
{
u8g.firstPage(); // START SCREEN "Picture loop" for OLED
do
{
DrawFrame();
u8g.drawStr(4, 14, "Light Control Hours");
u8g.drawStr( 4, 34,"ON:");
u8g.setPrintPos(31,34);
u8g.print(OnTime);
u8g.drawStr( 4, 46,"OFF:");
u8g.setPrintPos(37,46);
u8g.print(OffTime);
}
while ( u8g.nextPage() );
}
//*********************************************************************
//*** Function For Temperature Control Settings Display on the OLED ***
//*********************************************************************
void TempSet()
{
u8g.firstPage(); // //START SCREEN "Picture loop" for OLED
do
{
DrawFrame();
u8g.drawStr(4, 14, "Temp Control Settings");
u8g.drawStr( 4, 34,"Max:");
u8g.setPrintPos(39,34);
u8g.print(Tmax);
u8g.drawStr( 58, 34, "\260C"); // make Degree Centigrade Symbol
u8g.drawStr( 4, 46,"Nor:");
u8g.setPrintPos(39,46);
u8g.print(Tnor);
u8g.drawStr( 58, 46, "\260C");
u8g.drawStr( 4, 58,"Min:");
u8g.setPrintPos(39,58);
u8g.print(Tmin);
u8g.drawStr( 58, 58, "\260C");
}
while ( u8g.nextPage() );
}
//*********************************************************************
//*** Function For Humidity Control Settings Display on the OLED ***
//*********************************************************************
void HumSet()
{
u8g.firstPage(); // //START SCREEN "Picture loop" for OLED
do
{
DrawFrame();
u8g.drawStr(4, 14, "Humidity Settings");
u8g.drawStr( 4, 34,"Max:");
u8g.setPrintPos(39,34);
u8g.print(Hmax);
u8g.drawStr( 58, 34, "%");
u8g.drawStr( 4, 46,"Nor:");
u8g.setPrintPos(39,46);
u8g.print(Hnor);
u8g.drawStr( 58, 46, "%");
u8g.drawStr( 4, 58,"Min:");
u8g.setPrintPos(39,58);
u8g.print(Hmin);
u8g.drawStr( 58, 58, "%");
}
while ( u8g.nextPage() );
}
void DrawFrame()
{ u8g.drawFrame(0, 0, 128, 20); // Draw frame
u8g.drawFrame(0, 22, 128, 42); // Draw frame
}
//########################################################################################
//***************************************************************************************/
//************ Function Called When Repeating Timer alarm triggers ******************
//***************************************************************************************\
//########################################################################################
void Repeats()
{
if(!DHTerr && !RTCerr) // blink the light only when DHTerr is not 1 because then status LED will constantly stay ON
{
digitalWrite(lighttwo, HIGH); // it is also used to indicate Dht read failed and lights up continuously below in dht part
Alarm.delay(30);
digitalWrite(lighttwo, LOW);
}
//TimeDateDisplayOne(); // Update the Clock Display on Tx line
// this calls the function TimeDateDisplayOne
// includes time,date,day,year only numbers
// Formatted to be read by ESP8266 using Serial.Read
//SPrintStatusOne(); // SerialPrints data on the Tx line of Arduino
// by connecting the Rx line of Esp8266 / Wemos D1 mini
// that is running an html webserver
// that data is read and categorized in Arrays and then displayed
// on a simple html page
// *************
// * IMPORTANT * : if anything is changed Regarding serial.print/Serial.println
// ************* anywhere in the Sketch it WILL effect the Results of the sketch
// running in Esp8266 because of the changed position/content of the
// data printed on Tx line and Read by Rx of Esp8266 so keep it in mind
TimeDateDisplayTwo(); // For Humans Only
SPrintStatusTwo(); // For Humans Only
}
//##################################################################################################################
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//##################################################################################################################
//########################################################################
//***********************************************************************/
//********** LOOP BEGINS ******************************************
//***********************************************************************\
//########################################################################
void loop()
{
if (hour() == 0 && minute() == 0 && second() == 0) //If it is 00:00:00 MIDNIGHT UPDATE the Arduino's INTERNAL Clock
{
SyncTime();
}
//####################################################################################################
//####################################################################################################
//###### LET THERE BE LIGHT ########################################################################
//####################################################################################################
//####################################################################################################
// This will make sure that the light one (for plants) stays ON after reset or power down/up cycle
// because Alarms will trigger on a given time and will turn the pin HIGH but if after the alarm is
// triggered AND there is a reset the pin will turn off until next alarm that turns it ON again
// which can interrupt photo-period for plants So, this makes sure that LIGHTS turn ON immediately
// after reset which happens DURING the LIGHT period for plants
//####################################################################################################
// Turn Lights On/Off
//####################################################################################################
// if(!RTCerr) // only if RTC error is 0 or False
// {
// IF Turning ON the Light is Required on one day and Turning OFF on the same day
// within the 24 hrs of that day 00:00 --- 11:59
if (OffTime > OnTime) // Same Day
{ // GETS THE JOB DONE :)
if (hour() >= OnTime && hour () <= OffTime - 1)
{
// if current hour is equal to or greater than ON time
// AND equal to or less than OFF time minus 1 then turn the
// lights ON (by turning pins LOW because of using LOW level Relays)
// Minus 1 from OFF time because we are not using Minutes here
// For Example turn off time is "16" (4 PM) the hour number will be "16" from
// 16:00 till 16:59 (4:00 till 4:59)
if (!LightSts)
{
digitalWrite(lightone, LOW);
Alarm.delay(2000);
LightSts = 1 ;
}
}
else
{
digitalWrite(lightone, HIGH);
LightSts = 0 ;
}
}
//####################################################################################################
if (OffTime < OnTime) // Different Day
{
// IF Turning ON the Light is Required on ONE DAY and
// Turning OFF on the SECOND DAY
if (hour() >= OnTime || hour () <= OffTime - 1)
{
// if current hour is equal or greater than ON time
// OR equal to or less than OFF time minus 1 then turn the
// lights ON (by turning pins LOW because of using LOW level Relays)
// Minus 1 from OFF time because we are not using Minutes here
// For Example turn off time is "16" (4 PM) the hour number will be "16" from
// 16:00 till 16:59 (4:00 till 4:59)
// Minutes,Seconds even day,date,year can be used by adding code
if (!LightSts)
{
digitalWrite(lightone, LOW);
Alarm.delay(2000);
LightSts = 1 ;
}
}
else
{
digitalWrite(lightone, HIGH);
LightSts = 0 ;
}
}
// }
// else
// {
// digitalWrite (lighttwo,HIGH); // turn status LED indicate RTC error
// //Serial.println("Something Wrong with RTC.So, NOT Controlling Lights Now");
// }
if (RTCerr)
{
digitalWrite (lighttwo, HIGH); // turn status LED indicate RTC error
}
//###############################################################################################################
// *************************************************************************************************************/
// DAILY TIMED ALARMS THAT TRIGGER ON SPECIFIED TIMES
// these alarms will trigger once and will do "stuff" mentioned in the alarm functions at the end of the loop
// *************************************************************************************************************\
//###############################################################################################################
Alarm.alarmRepeat(3, 0, 0, ONAlarm); // daily Alarm 1 for example // for triggering an alarm on ""03:00:00"" in the morning AM
// ONAlarm is the name of the function that will be called when the current time matches
// the Time you have set for the specified alarm
// the ONAlarm function is defined below and the name ONAlarm can be changed
// the fuctions will be called only at the moment when the time matches the alarm time
// and if the state of switch is changed and then Arduino is reset the state will change back to default
Alarm.alarmRepeat(6, 0, 0, OFFAlarm); // daily Alarm 2
Alarm.alarmRepeat(9, 0, 0, OFFAlarm); // daily Alarm 3
Alarm.alarmRepeat(12, 0, 0, OFFAlarm); // daily Alarm 4
Alarm.alarmRepeat(15, 0, 0, OFFAlarm); // daily Alarm 5
Alarm.alarmRepeat(18, 0, 0, OFFAlarm); // daily Alarm 6
Alarm.alarmRepeat(21, 0, 0, OFFAlarm); // daily Alarm 7
/*
Alarm.alarmRepeat(15, 35, 0, ON2Alarm); // daily Alarm 5
Alarm.alarmRepeat(18, 37, 0, wateringD); // daily Alarm 6
Alarm.alarmRepeat(21, 38, 0, wateringA); // daily Alarm 7 */
//############################################################
//#####################################
// Get Sensor Values after every 2 Secs
//#####################################
if (millis() / 1000 - Secs > 2 ) // Call dht and thermistor calculation fuction every 2 secs
{
dhtCalc() ;
thermCalc() ;
soilHumCalc() ;
waterLvlCalc() ;
if (waterLvlOneVal < waterOne)
{
REmpty = 1 ;
u8g.firstPage();
do
{
DrawFrame();
u8g.drawStr(4, 14, "Water Tank");
u8g.drawStr( 14, 44, "* EMPTY *");
}
while ( u8g.nextPage() );
Alarm.delay(1300);
}
else
{
REmpty = 0 ;
}
Secs = millis() / 1000; // then reset the timer
}
//#########################################################################################################
//###############################################################################################################
// CONTROL PART turning things ON and OFF according to Temperature and Humidity (THE GOOD STUFF) "ifs"
//###############################################################################################################
//#########################################################################################################
if (!DHTerr) // only proceed to controlling things according to Temp1 and humidity
{ // if there is no DHT read error
if (t >= Tmax ) // TURN COOLER ON IF TEMPERATURE IS EQUAL TO OR EXCEEDS "Tmax" (HEATER remains OFF)
{
if (!CoolerSts)
{
digitalWrite(cooler, LOW);// Turn Cooler Pin LOW // ON because of LOW Level trigger Relay
Alarm.delay(2000);
CoolerSts = 1 ; // Cooler Status is ON // Status is used for Serial Print
}
TempSts = 4; // High Temp // Status is used by Oled
}
if (t <= Tnor ) // Turn OFF the COOLER when TEMP GETS DOWN TO "setT" OR GOES BELOW
{
digitalWrite(cooler, HIGH);
CoolerSts = 0 ;
}
if (t <= Tmin) // TURN HEATER "ON" WHEN TEMPERATURE GETS TO "Tmin" OR BELOW (cooler remains OFF)
{
if (!HeaterSts)
{
digitalWrite(heater, LOW);
Alarm.delay(2000);
HeaterSts = 1 ;
}
TempSts = 1; // Low Temp
}
if (t >= Tnor ) // TURN OFF HEATER WHEN TEMP GETS TO "setT" (and REMAINS LOWER THAN "Tmax")
{
digitalWrite (heater, HIGH);
HeaterSts = 0 ;
}
//######################################/
//######################################/
//# Just for Setting Status of things #
//######################################/
//######################################\
if (t <= Tmax && t > Tnor)
{
TempSts = 3; // Upper Range
}
if (t <= Tnor && t > Tmin)
{
TempSts = 2; // normal range
}
if ( t > TmaxR)
{
TmaxR = t; // Update Max Recorded Temperature For the Session
}
if ( t < TminR)
{
TminR = t; // Update Minimum Recorded Temperature For the Session
}
else if (TminR == 0)
{
TminR = t;
}
//#######################################################
//############### Control for HUMIDITY ###############
//#######################################################
if (h >= Hmax)
{
if (!BigFanSts)
{
digitalWrite(Bigfan, LOW); // Turn fan on when humidity is high
Alarm.delay(2000);
BigFanSts = 1 ;
}
HumSts = 4; // humidity max/high
}
if (h <= Hnor )
{
digitalWrite(Bigfan, HIGH);
BigFanSts = 0;
}
if (h <= Hmin)
{
if (!SpraySts)
{
digitalWrite(spray, LOW); // Turn Spray on when humidity is low
Alarm.delay(2000);
SpraySts = 1 ;
}
HumSts = 1; // humidity low
}
if (h >= Hnor)
{
digitalWrite(spray, HIGH); // Turn Spray off when humidity is normal or high
SpraySts = 0 ;
}
if (h > Hnor && h < Hmax)
{
HumSts = 3; // upper range
}
if (h > Hmin && h <= Hnor)
{
HumSts = 2; // normal range
}
if ( h > HmaxR)
{
HmaxR = h; // Update Max Recorded Humidity For the Session
}
if ( h < HminR)
{
HminR = h; // Update Max Recorded Humidity For the Session
}
else if (HminR == 0)
{
HminR = h;
}
}
else
{
digitalWrite (lighttwo, HIGH); // turn status LED indicate DHT error
//Serial.println("Something Wrong with DHT.So, NOT Controlling Things Now");
digitalWrite(Bigfan, HIGH);
digitalWrite(cooler, HIGH);
digitalWrite(heater, HIGH);
digitalWrite(spray, HIGH);
}
//##############################################################
//************************************************************//
//*************** Control for Water Pump ***********
//***********************************************************//
//#############################################################
//###############################################/
// Using Soil Humidity Sensor's Digital OUTPUT
//###############################################\
if(waterTimeD) // using Digital OUT Pin from Soil Humidity Sensor
{
if(digitalRead (soilHumD) == HIGH && !REmpty && !PumpSts)
{
digitalWrite(pumpPin,LOW);
Alarm.delay(2000);
PumpSts = 1 ;
}
else if (millis()/1000 -SecsThree > pumpT && PumpSts)
{
digitalWrite(pumpPin,HIGH);
PumpSts = 0 ;
waterTimeD = 0;
}
}
//###############################################/
// Using Soil Humidity Sensor's Analog OUTPUT
//###############################################\
if(waterTimeA) // Using Analog Pin from Soil Humidity Sensor
{
if(soilHumVal < dryVal && !REmpty && !PumpSts)
{
digitalWrite(pumpPin,LOW);
PumpSts = 1 ;
}
else if (millis()/1000 -SecsThree > pumpT && PumpSts)
{
digitalWrite(pumpPin,HIGH);
PumpSts = 0 ;
waterTimeA = 0;
}
}
//###################################
//###################################
Display(); // Call the Main Display Loop function (beloww) for OLED
//#######################################
// Call Recorded Max & Min Display loops
//#######################################
if(millis()/1000 -Secs > 60 ) // Call Max & Min Recorded Temp & Hum Display Loop every 60 secs
{
RecMax();
Alarm.delay(2000); // and show them for 5 secs each
RecMin();
Alarm.delay(2000);
Secs=millis()/1000; // reset the timer "secs"
}
}
//**********************//**********************//**********************
// LOOP END
//**********************//**********************//**********************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//********************//**********************//************//
// Function for DHT 22 TEMPERATURE HUMIDITY CALCULATIONS
//********************//**********************//************//
void dhtCalc()
{
h = dht.readHumidity(); // READ HUMIDITY
t = dht.readTemperature(); // Read temperature as Celsius
if (isnan(h) || isnan(t) )
{
Alarm.delay(500);
DHTerr=1;
}
else
{
DHTerr=0;
}
}
//********************************************
// Function for THERMISTOR CALCULATIONS
//********************************************
void thermCalc()
{
byte i;
float average =0 ;
for (i = 0; i < NUMSAMPLES; i++) // take "N" number of samples in a row, with a slight delay
{
samples[i] = analogRead(THERMISTORPIN);
Alarm.delay(10);
}
for (i = 0; i < NUMSAMPLES; i++) // average all the samples out
{
average += samples[i];
}
average /= NUMSAMPLES;
average = 1023 / average - 1; // convert the value to resistance
average = SERIESRESISTOR / average;
t2= average / THERMISTORNOMINAL; // (R/Ro)
t2 = log(t2); // ln(R/Ro)
t2 /= BCOEFFICIENT; // 1/B * ln(R/Ro)
t2 += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
t2 = 1.0 / t2; // Invert
t2 -= 273.15; // convert to C
}
//***************************************
// Function for Reading Soil Humidity
//***************************************
void soilHumCalc()
{
soilHumVal= analogRead(soilHumA) ;
//Serial.print("Soil Hum: ");
//Serial.println(soilHumVal);
soilHumVal = map(soilHumVal,DV,HV,0,100);
}
//***************************************
// Function for Reading Water Level
//***************************************
void waterLvlCalc()
{
waterLvlOneVal= analogRead(waterLvlOne) ;
//Serial.print("Water Lv: ");
//Serial.println(waterLvlOneVal);
waterLvlOneVal = map(waterLvlOneVal,EV1,FV1,0,100);
}
//**************************************************
// Main Loop FUNCTION FOR Main DISPLAY ON THE OLED
//**************************************************
void Display()
{
char timebuf[5]; // array for Time
tmElements_t tm; //formatting time and date before displaying
if (RTC.read(tm))
{
sprintf(timebuf, "%02d:%02d", tm.Hour, tm.Minute); // format time
}
u8g.firstPage();
do
{
DrawFrame();
if(DHTerr) // if DHT error is 1 or true then display dht error on oled
{
u8g.drawStr( 35, 14, "* DHT ERROR *");
}
else // else display values
{
switch (HumSts) // Display According to Humidity Status on OLED
{
case 4:
u8g.drawStr( 91, 14, "*H MX*"); // humidity is equal to max or more than max
break;
case 3:
u8g.drawStr( 91, 14, "*H AN*"); // above normal
break;
case 2:
u8g.drawStr( 91, 14, ">H NR<"); // Normal
break;
case 1:
u8g.drawStr( 91, 14, "*H LW*"); // Lower than Minimum Humidity
break;
}
//*********************************************************************
switch (TempSts) // Display According to Temperature Status on OLED
{
case 4:
u8g.drawStr( 34, 14, "*HI TMP*");
break;
case 3:
u8g.drawStr( 34, 14, "*ABV NR*");
break;
case 2:
u8g.drawStr( 34, 14, ">NR TMP<");
break;
case 1:
u8g.drawStr( 34, 14, "*LO TMP*");
break;
}
}
//************// Display Time on OLED//**************//
if(!RTCerr)
{
u8g.setPrintPos(2, 14); // set position for displaying time
u8g.print(timebuf); //display time
}
else
{
u8g.drawStr( 2, 14, "RtcEr");
}
//****** Display CURRENT Temperature 1 & 2 , humidity,Set Tmax,Set Tnor and Set Tmin,Soil Humidity and Water Level on OLED *********************
u8g.drawStr(2, 32, "T :"); // first digit is screen coordinate for X-axis and second for Y-axis
// (it starts on left bottom corner of the text which is to be shown on the oled)
// T for temperature from DHT22 and T2 is from Thermistor
u8g.drawStr( 21, 32, dtostrf(t, 5, 2, str));
u8g.drawStr( 51, 32, "\260C");
u8g.drawStr( 2, 42, "M :");
u8g.drawStr( 21, 42, dtostrf(Tmax, 5, 2, str));
u8g.drawStr( 51, 42, "\260C");
u8g.drawStr( 2, 52, "N ");
u8g.drawStr( 15, 52, ":");
u8g.drawStr( 21, 52, dtostrf(Tnor, 5, 2, str));
u8g.drawStr( 51, 52, "\260C");
u8g.drawStr( 2, 62, "m ");
u8g.drawStr( 15, 62, ":");
u8g.drawStr( 21, 62, dtostrf(Tmin, 5, 2, str));
u8g.drawStr( 51, 62, "\260C");
u8g.drawStr( 65, 32, "T2:");
u8g.drawStr( 83, 32, dtostrf(t2, 5, 2, str));
u8g.drawStr( 113, 32, "\260C");
u8g.drawStr( 65, 42, "H :");
u8g.drawStr( 83, 42, dtostrf(h, 5, 2, str));
u8g.drawStr( 117, 42, "%");
u8g.drawStr( 67, 52, "SH:"); // Soil Humidity Value mapped to 0-100 %
u8g.setPrintPos(92, 52);
u8g.print(soilHumVal);
u8g.drawStr( 117, 52, "%");
u8g.drawStr( 67, 62, "WL:"); // water level mapped to 0-100 %
u8g.setPrintPos( 92, 62);
u8g.print(waterLvlOneVal);
u8g.drawStr( 117,62, "%");
}
while ( u8g.nextPage() );
}
//********************************
// Display Loop for Max Recorded
//********************************
void RecMax()
{
u8g.firstPage();
do
{
DrawFrame();
u8g.drawStr(4, 14, "Max Recorded");
u8g.drawStr( 4, 34,"T Max:");
u8g.setPrintPos(47,34);
u8g.print(TmaxR);
u8g.drawStr( 75, 34, "\260C");
u8g.drawStr( 4, 46,"H Max:");
u8g.setPrintPos(47,46);
u8g.print(HmaxR);
u8g.drawStr( 79, 46, "%");
}
while ( u8g.nextPage() );
}
//********************************
// Display Loop for Min Recorded
//********************************
void RecMin()
{
u8g.firstPage();
do
{
DrawFrame();
u8g.drawStr(4, 14, "Min Recorded");
u8g.drawStr( 4, 34,"T Min:");
u8g.setPrintPos(47,34);
u8g.print(TminR);
u8g.drawStr( 75, 34, "\260C");
u8g.drawStr( 4, 46,"H Min:");
u8g.setPrintPos(47,46);
u8g.print(HminR);
u8g.drawStr( 79, 46, "%");
}
while ( u8g.nextPage() );
}
//**********************//**********************//**********************//**********************
//Functions called when daily time specific alarms (above in the loop) triggers:
//***********************************************//**********************//**********************
/*
void daySett()
{
//Tmax = 29; // set day time temperatures
//setT = 25;
//Tmin = 19;
SyncTime();
}
void nightSett()
{
//Tmax = 26; // set night time temperatures
//setT = 23;
//Tmin = 19;
SyncTime();
}
*/
void OFFAlarm() // when this fuction is called by the alarm it calls another fuction Synctime which syncs arduino's internal clock with RTC
{
SyncTime();
}
void ONAlarm() // this fuction calls two other fuctions
{
SyncTime();
}
void ON2Alarm() // this fuction calls two other fuctions
{
wateringA();
SyncTime();
}
//*******************************************************************
// Function for Watering using soil Humidity Sensor's Digital Output
//*******************************************************************
void wateringD()
{
SecsThree= millis()/1000; // reset the timer
waterTimeD= 1 ;
//Serial.println("water time D Flag set");
}
//*******************************************************************
// Function for Watering using soil Humidity Sensor's Analog Output
//*******************************************************************
void wateringA()
{
SecsThree= millis()/1000; // reset the timer
waterTimeA = 1 ;
//Serial.println("water time A Flag set");
}
///**************************************************************************************
//*** Function for Serial Printing status of switches and other values ** FOR ESP8266 *
//**************************************************************************************
/*
void SPrintStatusOne()
{
Serial.print ('L');
Serial.print (LightSts);
Serial.print ('C');
Serial.print (CoolerSts);
Serial.print('H');
Serial.print(HeaterSts);
Serial.print('B');
Serial.print(BigFanSts);
Serial.print('S');
Serial.print(SpraySts);
Serial.print('E');
Serial.print(DHTerr);
Serial.print(RTCerr);
Serial.print('t');
Serial.print(t);
Serial.print('h');
Serial.print(h);
Serial.print('r');
Serial.println(t2);
}
*/
//*************************************************************************************
//*** Function for Serial Printing status of switches and other values ** FOR HUMAN ***
//*************************************************************************************
void SPrintStatusTwo()
{
Serial.print("T1: ");
Serial.println(t);
Serial.print("H: ");
Serial.println(h);
Serial.print("T2: ");
Serial.println(t2);
Serial.print("Water Lv: ");
Serial.println(waterLvlOneVal);
Serial.print("Soil Hum: ");
Serial.println(soilHumVal);
if(LightSts)
{
Serial.println ("Light ON");
}
else
{
Serial.println("Light OFF");
}
if(CoolerSts)
{
Serial.println("Cooler ON");
}
else
{
Serial.println("Cooler OFF");
}
if(HeaterSts)
{
Serial.println("Heater ON");
}
else
{
Serial.println("Heater OFF");
}
if(BigFanSts)
{
Serial.println("Fan ON");
}
else
{
Serial.println("Fan OFF");
}
if(SpraySts)
{
Serial.println("Spray ON");
}
else
{
Serial.println("Spray OFF");
}
if(PumpSts)
{
Serial.println("Pump ON");
}
else
{
Serial.println("Pump OFF");
}
}
//**********************//**********************//********************************
//Function for digital clock display (in the SERIAL MONITOR *** FOR ESP8266 ***
//**********************//**********************//********************************
/*
void TimeDateDisplayOne() // digital clock display 24hr format // for ESP-8266 and HUM-an too :)
{
Serial.print("Z");
PrintZD(hour()); // Print Hour Digit and add a zero before single digits
PrintCD(minute()); // Print a colon sign ":" and add zero before single digits
PrintCD(second());
Serial.print('W');
Serial.print(weekday()); // there are no double digits only 7 days in a week
Serial.print('D');
PrintZD(day()); // Print the Day of the month and add zero before single digits
Serial.print('M'); // add zero before single digit month numbers
PrintZD(month());
Serial.print('Y');
Serial.print(year());
}
*/
//**********************//**********************//**********************//*****
//Function for digital clock display (in the SERIAL MONITOR *** FOR HUMAN ***
//**********************//**********************//**********************//*****
void TimeDateDisplayTwo() // digital clock display of the time 24hr format // for HUM-an
{
Serial.println("****>> 10 second timer<< ****");
Serial.println("TIME");
PrintZD(hour());
PrintCD(minute());
PrintCD(second());
Serial.println();
Serial.println("DATE");
Serial.print(dayStr(weekday()));
Serial.print("-");
Serial.print(day());
Serial.print("-");
Serial.print(monthStr(month()));
Serial.print("-");
Serial.println(year());
}
//***********************************************************************
//** Function for adding Zero before single digits before Serial print **
//***********************************************************************
void PrintZD(int D)
{
if(D < 10) // don't add brackets for this if statement it will not work
Serial.print('0');
Serial.print(D);
}
//*********************************************************************************
//** Function for adding a Colon & Zero before single digits before Serial print **
//*********************************************************************************
void PrintCD(int digits)
{
Serial.print(":");
if (digits < 10) // don't add brackets for this if statement it will not work
Serial.print('0');
Serial.print(digits);
}
//******************************
// THE END
//******************************
Do-it-yourself,DIY,How-To,Electronics,Arduino,Esp,Raspberry-Pi,Programming,Hacking Stuff,Gardening,Photography,Hobby,Fun
Arduino Grow Box Green House Controller 5.0 [OUT-DATED] Cooler,Heater,Lights,Humidifier,Fan,Water Level,Soil Humidity,Pump
ESP8266 Battery Voltmeter / Charge Controller ShutDown Reset Pi UPS Back Up Supply[OUT-DATED]
//################################/ //####################################################################
//##############################/ //#################################################_________ #########
//#############################/ //=================================================//////////##########
//####################//Esp8266 Battery Manager ------------------ // //######@@##
//########################## WEMOS D1 MINI ##############----- // O O O //#######@@##
//###############################// for------### ===============================//<<<<<<<//########@@##
//###################//UPS Back UP Power Supply for ######################################################
//#################### RASPBERRY PI 3 / SECURITY CAMERA PROJECT ########################################
//############################/ |WWWW| /##################################################################
//###########################/ \O_O/ ####################################################################
//# CAN BE USED AS A GENERAL PURPOSE BATTERY MONITOR / CHARGING ##########################################
//############# AFTER SOME MODIFICATIONS ############# NI-CD / LEAD ACID #################################
//#################################################### NOT LI-ION ########################################
//###################
///// OUTDATED //// Watch :https://www.youtube.com/watch?v=GTEyUZAViSA
//###################
// ********************************************************************************************
// ***** IMPORTANT : rest of the details will be posted later
// ********************************************************************************************
// #########################################################################
// #### I'll improve it as i learn more
// #########################################################################
// PLEASE LIKE AND SUBSCRIBE
// MY YOUTUBE CHANNEL
// YOUTUBE.COM/CRAZYGUYOFFICIAL
// Visit Blog for Sketch Updates and more Sketches and "things"
// #########################################################################
#include <ESP8266WiFi.h>
//#################################
const char* ssid = "wubbadlubba";
const char* password ="dubdub420";
WiFiServer server(80);
//#################################
//### Charge Voltage Settings #####
//#################################
float LoadOFF = 6.50 ; // Voltage at which Load will Turn OFF
float LoadON = 10.00 ; // Voltage at which Load will Turn ON
float ChargeOFF = 12.00 ; // Cut OFF Voltage at which Charging will Turn OFF
float ChargeON = 9.60 ; // Voltage at which Charging will Turn ON
//###########################################
//### Voltage to ShutDown For Raspberry pi ##
//###########################################
float PiOFF = 7.50 ; // Voltage at which pi shutdown pin will Turn ON
// telling the Pi to ShutDown
//#############################################
//###### PINS for Sensing and Switching #######
//#############################################
byte ChrgS = 2; // D4 // Charging Switch Pin // using an NPN transistor and P-channel Mosfet
byte LoadS = 5; // D1 // Load ON / OFF Pin
byte PowerS = 4; // D2 // Power Sense to check if power is available or not
//##############################################
//### Pin for Rapberry pi Shutdown / Reset ####
//##############################################
byte StfdPin = 12 ; // D6 // Pin For signaling Pi to ShutDown // pi will use Gpio to read
byte PiStsPin = 13 ; // D7 // Pin to see Pi's status // pi will use gpio to send
byte PiRst = 14 ; // D5 // pin to reset pi using NPN transistor connected to RUN pad/pin on pi
//######################################
//### ADC pin & Resistors Values #######
//######################################
float R1 = 47000.00; // resistance of R1 (47 K)
float R2 = 6650.00; // resistance of R2 (6.65 K)
byte analInput = A0; // ADC pin
//##############################################
//#### Variables used for Voltage Calculation ##
//##############################################
float Vout = 0.00;
float Vin = 0.00;
int Val = 0;
//#################################
//### Variables for Timers ########
//#################################
unsigned long Secs = 0; // Secs Counter used to Turn OFF Charging
int Time1 = 250; // Time in Seconds after which the Charging will Turn off
// after reaching Cut off voltage
unsigned long SecsTwo = 0; // Secs Counter two used to Turn ON Load
byte Time2 = 250; // Time in Seconds after which the Load will Turn On
// after reaching Load Turn On Voltage
byte Time3 = 250; // Time in Seconds after which the Pi Will be Reset
//*******************************************************************************************
//** IMPORTANT *** For Larger Values Change Variable type to "int Time" instead of byte **
//*******************************************************************************************
//################################
bool Charging = 0 ; // don't change these values
bool LoadConnect = 0 ; // manually
bool Power = 0 ;
bool PiUp = 0 ;
//################################
//###############################################################################################
//###############################################################################################
//################ SETUP START ##################################################################
//###############################################################################################
//###############################################################################################
void setup()
{
//**** OUTPUT PINS *****
pinMode(StfdPin,OUTPUT); // Shutdown Signal Pin for Pi
pinMode(PiRst, OUTPUT); // Reset Pin for Pi
pinMode(ChrgS, OUTPUT); // Charging ON / OFF Pin
pinMode(LoadS, OUTPUT); // Load ON / OFF Pin
digitalWrite (ChrgS,HIGH); // Charging ON // npn transistor and P-channel mosfet
Charging = 1 ;
digitalWrite (StfdPin,LOW); // Keep Shutdown signal pin OFF
digitalWrite (LoadS,LOW); // Keep LOAD OFF
LoadConnect = 0 ;
digitalWrite(PiRst, LOW); // Keep Pi Reset Pin OFF
//**** INPUT PINS *****
pinMode(analInput, INPUT); // Adc analog read pin //voltage divider circuit for battery voltage
pinMode(PiStsPin, INPUT) ; // Pin for Reading Pi Status using Pi's GPIO HIGH/LOW State
pinMode(PowerS, INPUT) ; // Pin for Sensing Power from Charger / Adapter using npn transistor
// and a voltage divider circuit
Power =0;
//##### Serial & WIFI Stuff ###########
Serial.begin(115200);
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.println(".");
}
Serial.println("WiFi connected");
server.begin();
Serial.println("Waiting for the IP ..");
delay(5000);
Serial.println(WiFi.localIP());
}
//###############################################################################################
//###############################################################################################
//################ SETUP END ####################################################################
//###############################################################################################
//###############################################################################################
//##############################################################################################
//##############################################################################################
//################ Function for Voltage Calculation ############################################
//##############################################################################################
//##############################################################################################
void VoltageCalc()
{
delay(1000);
Val = analogRead(analInput); // reads Analog input using A0
delay(1000); //for maintaining the speed of the output in serial monitor
Vout = (Val * 3.40/ 1024.00); // formula for calculating voltage out from the Divider circuit
Vin = Vout / (R2 / (R1 + R2)); // formula for calculating Battery voltage
if (Vin < 0.25) // set Voltage to Zero if reading less than .50 V
{
Vin = 0.00;
}
Serial.println("################");
Serial.println("Battery Voltage: ");
Serial.println(Vin);
}
//###############################################################################################
//###############################################################################################
//################ LOOP BEGINS ##################################################################
//###############################################################################################
//###############################################################################################
void loop()
{
//delay(1000); // for maintaining the speed of the output in serial monitor
VoltageCalc(); // Calculate Battery Voltage
//##########################################
//## NO POWER ### TURN LOAD OFF ### Pi OFF #
//##########################################
if (!Power) // **** IF Power is NOT Available ****
{
digitalWrite(ChrgS,HIGH); // Turn ON Charging
Charging = 1 ;
if(LoadConnect) // and Load is Connected
{
PiUp = !digitalRead(PiStsPin); // Set Pi's Status
if(Vin <= PiOFF && PiUp) // IF Voltage is less than PiOFF // and pi is running
{
Serial.println("it has been an Honour Pi");
digitalWrite(StfdPin,HIGH); // Turn Signal Pin HIGH so, Pi can shutdown properly
}
if(Vin <= LoadOFF && !PiUp) // if Voltage is less than LoadOFF
{
Serial.println ("Turned Load OFF "); // Turn Load OFF
digitalWrite(LoadS, LOW);
LoadConnect = 0;
}
}
Secs = SecsTwo = millis()/1000; // Keep BOTH Timers Updated while no power
Power = !digitalRead(PowerS); // Check for Power Availability
}
//#################################################
//## YES POWER ## TURN CHARGING / LOAD ON / OFF ###
//#################################################
//#################################
else // **** IF Power is Available *****
{ //#################################
//#################################
//##### TURN CHARGING OFF #########
//#################################
Power = !digitalRead(PowerS); // Check for Power // the "!"/not inverts the output High means OFF Low means ON
if (Charging) // IF charging is ON
{
if(Vin >= ChargeOFF) //**** IF Voltage has Reached Cut off/ ChargeOFF Value ****
{
Serial.println ("CHARGE OFF Voltage Reached");
Serial.println ("will turn off charging after time up" );
if(millis()/1000 -Secs > Time1 ) // Seconds After which charging will turn off
{
Serial.println ("Turned Charging OFF ");
digitalWrite(ChrgS, LOW); // Turn OFF Charging
Charging = 0;
}
}
else // if charging is ON but voltage has not reached Cut OFF
{
Secs = millis()/1000; // Keep Timer1 updated
Serial.println("Battery is not fully charged yet ");
}
}
//##########################################
//######### TURN CHARGING ON ###############
//##########################################
else // Power is Available but Charging is OFF
{
if(Vin <= ChargeON ) // and if Voltage has dropped to ChargeON value
{
Serial.println ("Turned Charging ON ");
digitalWrite(ChrgS, HIGH); // Turn Charging ON
Charging = 1 ;
}
Secs = millis()/1000; // update timer 1 // keep updating it while charging is off
}
//##########################################
//######### TURN LOAD ON ###################
//##########################################
//###################################
if(!LoadConnect) // Power is Available but Load is OFF
{ //###################################
if(Vin >= LoadON) // if Voltage is above Load ON
{
if(millis()/1000 -SecsTwo > Time2 ) // Seconds After the Load ON Voltage is reached
{
Serial.println ("Turned Load ON ");
digitalWrite(LoadS, HIGH); // Turn Load ON
digitalWrite(StfdPin,LOW); // Keep Signal Pin OFF
LoadConnect = 1 ;
}
}
else
{
Serial.println("Waiting for Battery to Reach Load ON Voltage");
SecsTwo = millis()/1000; // Keep Timer Two Updated while Voltage Lower than Load ON
}
}
//#################################################
else // else if Power is Available and Load is Connected
{ //#################################################
PiUp = !digitalRead(PiStsPin); // Set Pi's Status
digitalWrite(StfdPin,LOW); // Turn Signal Pin LOW
if(!PiUp && Vin >= PiOFF) // IF Pi is NOT UP then
{
Serial.println("Pi signal ON Trying to Reset Pi");
if(millis()/1000 -SecsTwo > Time3) // Count till Time 3 // maybe it's booting up
{
Serial.println("Giving a Shock to Pi ");
digitalWrite(PiRst,HIGH); // Turn PiRst Pin ON
delay(500);
digitalWrite(PiRst,LOW); // Turn PiRst Pin OFF
SecsTwo = millis()/1000;
}
}
else // if power available and load connected and pi is up
{
SecsTwo = millis()/1000; // Keep Timer Two Updated while Load ON and PI is UP
digitalWrite(StfdPin,LOW); // keep signal pin off
Serial.println("OK ");
}
}
}
//##################################
//##### SERIAL PRINT STATUS ########
//##################################
if (Power)
{
Serial.println("POWER IS AVAILABLE");
if (Charging)
{
Serial.println ("Charging ON");
}
else
{
Serial.println ("Charging OFF");
}
}
else
{
Serial.println("NO POWER AVAILABLE");
}
if (LoadConnect)
{
Serial.println ("Load ON");
if(PiUp)
{
Serial.println("Pi is ON");
}
else
{
Serial.println("Pi Is OFF");
}
}
else
{
Serial.println ("Load OFF");
}
Serial.println("################");
//##################################
//### HTML WebPage #################
//##################################
sendHtml();
}
//####################################################################################
//##################### END OF LOOP ##################################################
//####################################################################################
//#################################
//#### Function for HTML ##########
//#################################
void sendHtml()
{
WiFiClient client = server.available();
if (client)
{
Serial.println("New client");
boolean blank_line = true;
while (client.connected())
{
if (client.available())
{
char c = client.read();
if (c == '\n' && blank_line)
{
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("<head><meta http-equiv='refresh' content='2'/></head><body><h1>ESP8266 Battery Manager Ver: 1.0</h1>");
client.println("<h2>AnalogIN :");
client.println(Val);
client.println("</h2>");
client.println("<h2>Vout :");
client.println(Vout);
client.println("V</h2>");
client.println("<h2>Battery Voltage :");
client.println(Vin);
client.println("V</h2>");
client.println("<br />");
client.println("<h1>Current States </h1>");
client.println("<br />");
client.println("<h3>Charging:>>> ");
if(Power)
{
if(Charging)
{
client.println("ON </h3>");
}
else
{
client.println("OFF </h3>");
}
}
else
{
client.println("NO POWER </h3>");
}
client.println("<h3>Load:>>>");
if(LoadConnect)
{
client.println("ON </h3>");
client.println("<h3>Pi Status:>>>");
if(PiUp)
{
client.println("ON </h3>");
}
else
{
client.println("OFF </h3>");
}
}
else
{
client.println("OFF </h3>");
}
client.println("<br />");
client.println("<br />");
client.println("<br />");
char LinkOne[]= "https://youtube.com/crazyguyofficial";
client.println("<h3><a href=");
client.print(LinkOne);
client.print(">CHANNEL</a></h3>");
char LinkTwo[]= "https://amkdiyprojects.blogspot.com";
client.println("<h3><a href=");
client.print(LinkTwo);
client.print(">BLOG</a></h3>");
client.println("</body></html>");
break;
}
if (c == '\n')
{
blank_line = true;
}
else if (c != '\r')
{
blank_line = false;
}
}
}
delay(1);
client.stop(); // closing the client connection
Serial.println("Client disconnected.");
}
}
Raspberry Pi UPS Backup Using 2 Diode Switch
Raspberry pi is powered using a 5 Volts Buck Converter.
The Buck Converter needs an Input Voltage more than it's Output Voltage which, in this case is 5 Volts.
First i powered it up with only a 12 Volts Output from an AC-DC power-supply.
Then I used a 9.6 Volts Ni-Cd Battery which was fully charged and at a Voltage above 10 Volts.
After making sure that it works I used Two Silicon Diodes (A610) for Switching the Buck Converter's Input from the 12 Volts, coming from the Power Supply Unit, TO the 9.6 Volts coming from the Ni-Cd Battery and without any Interruptions.So, when the AC power goes out the Buck Converter will automatically be powered by the Battery and the Switch happens almost instantly.
As shown in the picture above the Ground is common for all as Negative terminals on the Buck Converter, the 12 V Output of the AC-DC P.S.U. and the Ni-Cd Battery are all connected together.
The Positive terminal on the 12 Volt Output from the P.S.U. connects to the Anode of the Diode 2 and the Cathode of the Diode 2 connects to the Positive terminal on the Input of the Buck Converter. At the same time, the Positive terminal on the 9.6 V Ni-Cd Battery is connected to the Anode of the Diode 1 and the Cathode of the Diode 1 is connected to the Positive terminal on the Input of the Buck Converter.
Both Cathode terminals of both Diodes are joined together at the Buck Converters Input. But it all works because of the way the diode works.
Because, the 12 Volts coming from the AC-DC Power Supply, is Higher than the 9.6 Volts coming from the Battery, the current will flow from the Output of AC-DC Power Supply to the Anode of the Diode 2 and the Diode 2 will get "Forward Biased" then it will flow through the Diode 2 Cathode terminal to BOTH ,the Input of the Buck Converter and the Cathode of the Diode 1.
The Current that goes to the Input of the Buck Converter will power the Buck Converter and the Raspberry and the Current that flows to the Cathode of the Diode 1 will "Reverse Bias" the Diode 1 there-by preventing any flow of current from the Battery.
This is only possible when the Battery Voltage is lower than the Power Supply's output voltage .
When the AC power goes out or is turned off, the Voltage from the Output of the AC-DC Power Supply will drop and as soon as it drops lower than the Battery Voltage the Diode 1 gets "Forward Biased" because now the potential is higher on it's Anode and the Current will flow from the Battery to BOTH, the Input of the Buck Converter and the Cathode of the Diode 2.
It will power the Buck Converter and the Rpi and will "Reverse bias" the Diode 2.
All of this happens almost instantly and the Pi works without any interruptions in it's 5 Volts Input.
Arduino Smart Grow Box Controller Version 4.0 [OUT-DATED]with Wifi monitoring September Update
/*
************** UPDATED ON DEC 2017 *************
*************** GETTING BETTER THAN BEFORE *************
*** MAKING A MODULAR SYSTEM FOR D.I.Y. GROWBOX / GREENHOUSE
***Independent Grow Box Controller that can be used to Control "" all the Important devices"" to maintain
*
*
the ""Grow Environment"" for example Lights, Heater,Cooler,Fan for blowing air inside the box ,Fan for exhaust,
Humidifier or mist maker
//###################################################################################
// For Water Pump,Level Sensor and Soil Humidity Sensor see V 5.0 of this Sketch
// https://amkdiyprojects.blogspot.com/2017/11/arduino-grow-box-green-house-controller.html
//###################################################################################
//**********************
// Arduino Nano Grow-box / Green-House Controller v 4.0 :)
//**********************
//###############################################################
//***************************************************************
// PLEASE SUBSCRIBE
// comment for any question or help with this sketch
// My youtube Channel: https://youtube.com/CrazyGuyOfficial
//****************************************************************
//################################################################
// ***Made by Ali khan from Pakistan :)
//**********************//**********************//**********************
// **PARTS required (for this sketch to work as it is )
//**********************//**********************//**********************
1.Arduino Nano
2.A thermistor (i used A 10K WATERPROOF ONE)
3.A resistor (matching the value of the thermistor's "nominal resistance at 25 DEGREES C" for example: 5k resistor for 5k thermistor)
4.OLED display ssd1306 (mine is ssd1306 but got it working by using sh1106 constructor also got rid of the "white line problem")
5. DHT 22 (WITH PULL UP RESISTOR I USED 10k OHM)
6.RELAY MODULE LOW LEVEL TRIGGER TYPE (5 Relays required in total for all the pins, can be seperate 4 CAN WORK TOO )
7. DS3231 RTC MODULE (RESISTOR from charging circuit REMOVED and charging DISABLED..BECAUSE I USED CR2032(NON-rechargeable)Cell
8. AN LED WITH APPROPRIATE RESISTOR FOR USING AS A STATUS LED
9. An ESP8266 / Wemos D1 / Node Mcu
If you to want to monitor it Wirelessly using a 3.3 V Esp8266 with a 5V Arduino then Two Resistors
one 1K Ohm and one 2K Ohm . Using these two resistors make a Voltage Divider Circuit by connecting
the Tx pin of Arduino to the 1K Resistor then on the other side of the 1K Resistor join the D1 pin(Rx) of Esp8266
and at the same point join the 2K Resistor and then the other side of the 2K Resistor to the Ground
The Ground Pin of Arduino and Esp8266 will also be joined together Directly
Sketch for the Esp8266 is on the blog
*/
//**********************//**********************//**********************
// INCLUDE LIBRARIES make sure you have them all installed
//**********************//**********************//**********************
// Get them from within you Arduino IDE 1.6.9 that i used
// get the correct version
// by correct i mean the version that i used and
// because i can't guarantee that this sketch will work with
// other latest versions of the same libraries
#include "DHT.h" // use DHTsensorLibrary // Version 1.2.3 //latest is the AdafruitUnifiedSensorLibrary
#include <U8glib.h> // OLED // Version 1.19.1
#include <Wire.h> // I2C // Version 1.0.0
#include <Time.h> // Time Manipulation // Version 1.5.0
#include <DS1307RTC.h> // DS1307 RTC // Version 1.4.0
#include <TimeAlarms.h> // time alarm library // Version 1.5.0
// Changed Number of alarms " dtNBR_ALARMS to 8 "
// BY EDITING TIMEALARM.H FILE IN LIBRARIES FOLDER.
// increasing this number increases size of the sketch too
// and the use of ram
// if you don't want to change the number then remove alarms and keep only
// that number of Alarms that is specified in YOUR TimeAlarms Library
// I have Left 8 Alarms BELOW that Call a Function to Sync Arduino's Clock with RTC
// if you Uncomment the Rest you will get some Errors
// if you increase the Number in TimeAlarms.H file then
// Don't UN-comment Void SPrintStatusTwo
// That prints out Switch Status
// OR you will get Low Memory Error for Nano/UNO
#define DS1307_ID 0x68 //Address of the RTC
//**********************//**********************//**********************
// TEMPERATURE and HUMIDITY DEFAULT "CONTROL PARAMETERS"
//**********************//**********************//**********************
//Default Temperature and Humidity Settings
byte Tmax = 29 ; // Set temperature Maximum point at which "Cooler" will turn ON
byte Tnor = 25 ; // Set temperature point at which "heater" and "cooler" will turn OFF
byte Tmin = 19 ; // Set temperature Minimum point at which Heater will turn ON
byte Hmax = 60 ; // set humidity max at which "bigfan" will turn ON
byte Hnor = 45 ; // Set humidity normal at which "bigfan" and "spray" will turn OFF
byte Hmin = 25 ; // Set humidity low at which "spray will turn ON
// Separate Temperature and Humidity Settings for Day and Night time can be done by Alarms function belowwww
// but anything done by Alarms is lost if a Reset happens or power up/down cycle
// and so in that case everything will return to their default state
//**********************//**********************//**********************
// Light Timer ON/OFF Time Settings DEFAULT
//**********************//**********************//**********************
const byte OnTime = 14 ; // Hour when Light will turn ON (24 hr format NO zeros before single digits)
const byte OffTime = 8 ; // Hour when Light will turn OFF (24 hr format NO zeros before single digits)
// SET RTC'S TIME USING DS1307 EXAMPLE SKETCH FROM ABOVE FILE > EXAMPLE > DS1307 > SETTIME
// THEN UPLOAD THIS SKETCH
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//**********************//**********************//**********************
// MAKING CHARACTER ARRAYS or C strings for OLED
//**********************//**********************//**********************
char str[10]; // for Display
//*****************************************************************************************************************
//*****************************************************************************************************************
//************ some important variables *************** Values NOT TO BE CHANGED MANUALLY *************************
//*****************************************************************************************************************
float t =0; // floats for Temperature1 and Humidity from DHT
float h =0;
float TmaxR = 0;
float HmaxR = 0;
float t2 =0; // for Temperature 2 from Thermistor
bool LightSts = 0 ; // DON'T CHANGE MANUALLY THESE ARE FOR STATUS UPDATES IN SERIAL MONITOR
bool CoolerSts = 0 ;
bool HeaterSts = 0 ;
bool BigFanSts = 0 ;
bool SpraySts = 0 ;
bool DHTerr = 0 ;
bool RTCerr = 0 ;
byte TempSts = 0 ; // used for updating the oled display
byte HumSts = 0 ;
byte i = 0 ;
byte a = 129 ;
byte b = 129 ;
byte c = 129 ;
unsigned long Secs = 0;
unsigned long SecsTwo = 0;
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//**********************//**********************//**********************
// PINS AND CONNECTIONS for Relays and Arduino
//**********************//**********************//**********************
// Five pins used which have to be connected to five relays(optically isolated for eliminating interference)
// usually a 4 Relay board is available so it can be used as only one of the pins for Heater/Cooler are required
// and they can be swapped according to the outdoor temperature in different seasons
// TO optically isolate them properly Two separate power supplies have to be use
// one for Arduino and one for the Relay board
// the relay board has a Removable Plastic Jumper connecting JDVCC-VCC pins, it has to be removed
// VCC pin on the Relay module is connected with the power supply one that powers Arduino
// the VCC on the Relay module powers the opto-isolators and the leds
// the In1,2,3,4 on the Relay board will be connected to Arduino's GPIOs and when the corresponding
// GPIO's are turned LOW and that Opto-Isolator will then turn ON because the In 1,2,3,4 pins are Ground pins
// for those four Isolator chips on the Relay Module and the Arduino Connects them to the Power Supply one's Ground
// To which the Arduinos Gnd pin is connected too
// Now the JDVCC pin and the Marked Gnd ground pin on the Relay module will be connected to the Second Power Supply
// and it will only power the Actual Relays on the Relay module
// it means the marked Ground pin on the module will not be connected to Arduino
// the only pins of Relay Module that connect to Arduino are VCC,IN1,IN2,IN3,IN4
// LOW-level Relay board will trigger the relay when the trigger pin is LOW/off/grounded
// so when something has to be turned ON the trigger pin ( example IN3 ) will become LOW otherwise
// it will stay HIGH (asamf) all the time during which the thing is required to be "OFF"
const byte Bigfan = 4 ; // Bigfan turns on at high humidity
const byte cooler = 5 ; // Cooler turn on at high temp (T1 from DHT)
const byte spray = 6 ; // Spray turns on at low humidity
const byte lightone = 7 ; // Main Lights(for plants)
const byte heater = 8 ; // Heater turns ON at low temp (T1 from DHT)
const byte lighttwo = 3 ; // pin for "status LED' indicating the loop is running when oled is turned OFF...
// ******** THERMISTOR AND DHT PINS BELOW *******
// Connect the RTC according to it's pinout
// DS3231 RTC "SDA to A4", "SCL to A5" "Vcc to 5V arduino pin Gnd to Gnd"
//***********************//**********************//*********************
// THERMISTOR PIN and SETTINGS
//**********************//**********************//**********************
#define THERMISTORPIN A0 // which analog pin to connect to thermistor and the resistor "joint"
#define THERMISTORNOMINAL 10000 // resistance at 25 degrees C
#define TEMPERATURENOMINAL 25 // temp. for nominal resistance (almost always 25 C)
#define NUMSAMPLES 5 // how many samples to take and average,takes longer gets 'smooth'
#define BCOEFFICIENT 3500 // The beta coefficient of the thermistor (usually 3000-4000)
#define SERIESRESISTOR 9700 // the value of the 'other' resistor should be close to the thermistors nominal value
int samples[NUMSAMPLES];
//***********************//**********************//*********************
// DHT PIN and SETTINGS
//**********************//**********************//**********************
#define DHTPIN A1 // what pin we're connected to
#define DHTTYPE DHT22 // DHT 22 (AM2302)
DHT dht(DHTPIN, DHTTYPE, 6); // the number 6 is for slower chips like the one used in Arduino Nano/UNO
//**********************//**********************//**********************
// OLED CONSTRUCTOR / OLED PINS that are connected to Arduino
//**********************//**********************//**********************
U8GLIB_SH1106_128X64 u8g(13, 11, 10, 9); // SW SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9 // OLED "constructor" and pins info.
// the version of oled i had has a different chip inside so the above one works for me
// before it i used the one that was supposedly for my version of oled and it was not working as expected
// if this doesn't work for you then go to Example Sketches for U8glib Library it has All the Constructors
// try them for your version of OLED
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//**********************//**********************//**********************//**********************//**********************//**********************
// SETUP BEGINS
//**********************//**********************//**********************//**********************//**********************//**********************
void setup()
{
Serial.begin(9600); // for initializing serial monitor
pinMode(Bigfan, OUTPUT); // set output relay pins // add more if you have more relays or pins connected to something
pinMode(cooler, OUTPUT);
pinMode(heater, OUTPUT);
pinMode(spray, OUTPUT);
pinMode(lightone,OUTPUT);
pinMode(lighttwo,OUTPUT);
// add more if you have more relays or pins connected to something
digitalWrite(Bigfan, HIGH); // When using "LOW level trigger" type Relay module, turning a pin "HIGH" will
digitalWrite(cooler, HIGH); // turn the relay "OFF" and turning the pin "LOW" turns the relay "ON"
digitalWrite(heater, HIGH); // THIS WILL PREVENT STARTUP RELAY TRIGGERING PROBLEM
digitalWrite(spray, HIGH);
digitalWrite(lightone,HIGH);
// add more if you have more relays or pins connected to something
analogReference(EXTERNAL); // AREF connected to 3.3 ON BOARD for accuracy of thermistor
//(go to adafruit using a thermistor tutorial )
//*********************************************************************
//************* Display at Startup *********************************
//*********************************************************************
Start();
Alarm.delay(3000);
for (i=125; i>0;)
{
scrollText();
a--;
b++;
c--;
i--;
}
for (i=10; i>0;)
{
scrollText();
b++;
c--;
i--;
}
for (i=50; i>0;)
{
scrollText();
c--;
i--;
}
//Alarm.delay(3000);
LightSet();
Alarm.delay(6000);
TempSet();
Alarm.delay(6000);
HumSet();
Alarm.delay(6000);
//**********************//**********************//***********************//**********************
//Check to see if the RTC is present.if yes then Set the ARDUINO's INTERNAL clock accordingly
//**********************//**********************//***********************//**********************
// when using timer library the Arduino's "internal clock " is used for getting "current time"
// Arduino's internal clock is NOT so accurate and gets off time so we use time from RTC (which IS
// accurate at-least for our use) and we sync Arduino's internal Clock with the time from RTC and we
// have to do this periodically (at-least once in every 24 hrs )so our tasks can be completed according
// to the correct time we can put the sync command in the Loop and Alarm Functions too
Wire.beginTransmission(DS1307_ID); // i2c devices have addresses which are used to communicate with them
Wire.write((uint8_t)0x00); // because same interface can be used to connect multiple i2c devices
setSyncProvider(RTC.get);
setSyncInterval(60);
//***********************//**********************//***********************//**********************
// TIMER ALARM THAT RUNS OVER AND OVER AFTER SECONDS // the Alarm in the Loop are different
// see the Example Sketches with the TimeAlarms Lib
//***********************//**********************//***********************//**********************
Alarm.timerRepeat(10, Repeats); // timer for every 10 seconds blinking LIGHT TWO (status LED)
// and Serial Prints Data
Secs=SecsTwo=millis()/1000;
dhtCalc() ;
ThermCalc();
}
//**********************//**********************//**********************
//********* SETUP END ********************************************
//**********************//**********************//**********************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*************************************************
//*** Function that Syncs Arduino's Clock with Rtc
//*************************************************
void SyncTime(){
if (Wire.endTransmission() == 0) //Did the RTC respond?
{
setSyncProvider(RTC.get); //Yes it did, get the time from the RTC
RTCerr=0;
Serial.println("Got Time");
}
else
{
RTCerr=1;
}
}
//**************************************************
//*** Function For Display on the OLED *************
//**************************************************
void Start()
{
u8g.firstPage(); // START SCREEN "Picture loop" for OLED
do {
u8g.setFont(u8g_font_helvB08); // set font for oled display
u8g.drawFrame(10, 12, 108, 31); // Draw Frame and it's Size
u8g.drawFrame(0, 0, 128, 64);
u8g.drawStr(15, 25, "Grow Box"); // Draw a string mentioned in quotes " "
u8g.setPrintPos(79,32); // Set print position for the next line
u8g.print("V 4.0"); // Print on the oled
u8g.drawStr( 16, 40, "Controller");
u8g.drawStr(53, 60, "Made by:AMK");
}
while ( u8g.nextPage() );
}
//***************************************************************
//*** Function For Light Control Settings Display on the OLED ***
//***************************************************************
void LightSet()
{
u8g.firstPage(); // START SCREEN "Picture loop" for OLED
do
{
u8g.drawFrame(0, 0, 128, 20); // Draw frame
u8g.drawFrame(0, 22, 128, 42); // Draw frame
u8g.drawStr(4, 14, "Light Control Hours");
u8g.drawStr( 4, 34,"ON:");
u8g.setPrintPos(31,34);
u8g.print(OnTime);
u8g.drawStr( 4, 46,"OFF:");
u8g.setPrintPos(37,46);
u8g.print(OffTime);
}
while ( u8g.nextPage() );
}
//*********************************************************************
//*** Function For Temperature Control Settings Display on the OLED ***
//*********************************************************************
void TempSet()
{
u8g.firstPage(); // //START SCREEN "Picture loop" for OLED
do
{
u8g.drawFrame(0, 0, 128, 20); // Draw frame
u8g.drawFrame(0, 22, 128, 42); // Draw frame
u8g.drawStr(4, 14, "Temp Control Settings");
u8g.drawStr( 4, 34,"Max:");
u8g.setPrintPos(39,34);
u8g.print(Tmax);
u8g.drawStr( 58, 34, "\260C");
u8g.drawStr( 4, 46,"Nor:");
u8g.setPrintPos(39,46);
u8g.print(Tnor);
u8g.drawStr( 58, 46, "\260C");
u8g.drawStr( 4, 58,"Min:");
u8g.setPrintPos(39,58);
u8g.print(Tmin);
u8g.drawStr( 58, 58, "\260C");
}
while ( u8g.nextPage() );
}
//*********************************************************************
//*** Function For Humidity Control Settings Display on the OLED ***
//*********************************************************************
void HumSet()
{
u8g.firstPage(); // //START SCREEN "Picture loop" for OLED
do
{
u8g.drawFrame(0, 0, 128, 20); // Draw frame
u8g.drawFrame(0, 22, 128, 42); // Draw frame
u8g.drawStr(4, 14, "Humidity Settings");
u8g.drawStr( 4, 34,"Max:");
u8g.setPrintPos(39,34);
u8g.print(Hmax);
u8g.drawStr( 58, 34, "%");
u8g.drawStr( 4, 46,"Nor:");
u8g.setPrintPos(39,46);
u8g.print(Hnor);
u8g.drawStr( 58, 46, "%");
u8g.drawStr( 4, 58,"Min:");
u8g.setPrintPos(39,58);
u8g.print(Hmin);
u8g.drawStr( 58, 58, "%");
}
while ( u8g.nextPage() );
}
// Startup display
void scrollText()
{
u8g.firstPage(); // //START SCREEN "Picture loop" for OLED
do
{
u8g.drawFrame(0, 0, 128, 64); // Draw frame
u8g.drawStr(a, 14, ">> FOR MORE <<<<<<");
u8g.drawStr(b, 26, "> Please SUBSCRIBE << ");
u8g.drawStr(c, 48, "YouTube.com/CrazyGuyOfficial");
}
while ( u8g.nextPage() );
}
//***********************//**********************//***********************//**********************
//************// Function Called When Repeating Timer alarm triggers //*******************
//***********************//**********************//***********************//**********************
void Repeats()
{
if(!DHTerr && !RTCerr) // only blink the light if DHTerr is not 1 because then status LED will constantly stay ON
{
digitalWrite(lighttwo, HIGH); // it is also used to indicate Dht read failed and lights up continuously below in dht part
Alarm.delay(30);
digitalWrite(lighttwo, LOW);
}
TimeDateDisplayOne(); // Update the Clock Display on Tx line
// this calls the function TimeDateDisplayOne
// includes time,date,day,year only numbers
// Formatted to be read by ESP8266 using Serial.Read
SPrintStatusOne(); // SerialPrints data on the Tx line of Arduino
// by connecting the Rx line of Esp8266 / Wemos D1 mini
// that is running an html webserver
// that data is read and categorized in Arrays and then displayed
// on a simple html page
// *************
// * IMPORTANT * : if anything is changed Regarding serial.print/Serial.println
// ************* anywhere in the Sketch it WILL effect the Results of the sketch
// running in Esp8266 because of the changed position/content of the
// data printed on Tx line and Read by Rx of Esp8266 so keep it in mind
// TimeDateDisplayTwo(); // For Humans Only
// SPrintStatusTwo(); // For Humans Only
}
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//***********************//**********************//***********************
//**********************//**********************//************************
//********** LOOP BEGINS ******************************************
//***********************//**********************//***********************
//**********************//**********************//************************
void loop()
{
if (hour() == 0 && minute() == 0 && second() == 0) //If it is 00:00:00 MIDNIGHT UPDATE the Arduino's INTERNAL Clock
{
SyncTime();
}
//***********************//**********************//***********************//************************
//***** LET THERE BE LIGHT ************************************************************************
//**************************************************************************************************
// This will make sure that the light one (for plants) stays ON after reset or power down/up cycle
// because Alarms will trigger on a given time and will turn the pin HIGH but if after the alarm is
// triggered AND there is a reset the pin will turn off until next alarm that turns it ON again
// which can interrupt photo-period for plants So, this makes sure that LIGHTS turn ON immediately
// after reset which happens DURING the LIGHT period for plants
//####################################################################################################
// Turn Lights On/Off
//####################################################################################################
// if(!RTCerr) // only if RTC error is 0 or False
// {
// IF Turning ON the Light is Required on one day and Turning OFF on the same day
// within the 24 hrs of that day 00:00 --- 11:59
if (OffTime > OnTime) // Same Day
{ // GETS THE JOB DONE :)
if (hour() >= OnTime && hour () <= OffTime - 1)
{
// if current hour is equal to or greater than ON time
// AND equal to or less than OFF time minus 1 then turn the
// lights ON (by turning pins LOW because of using LOW level Relays)
// Minus 1 from OFF time because we are not using Minutes here
// For Example turn off time is "16" (4 PM) the hour number will be "16" from
// 16:00 till 16:59 (4:00 till 4:59)
if (!LightSts)
{
digitalWrite(lightone, LOW);
Alarm.delay(2000);
LightSts = 1 ;
}
}
else
{
digitalWrite(lightone, HIGH);
LightSts = 0 ;
}
}
//####################################################################################################
if (OffTime < OnTime) // Different Day
{
// IF Turning ON the Light is Required on ONE DAY and
// Turning OFF on the SECOND DAY
if (hour() >= OnTime || hour () <= OffTime - 1)
{
// if current hour is equal or greater than ON time
// OR equal to or less than OFF time minus 1 then turn the
// lights ON (by turning pins LOW because of using LOW level Relays)
// Minus 1 from OFF time because we are not using Minutes here
// For Example turn off time is "16" (4 PM) the hour number will be "16" from
// 16:00 till 16:59 (4:00 till 4:59)
// Minutes,Seconds even day,date,year can be used by adding code
if (!LightSts)
{
digitalWrite(lightone, LOW);
Alarm.delay(2000);
LightSts = 1 ;
}
}
else
{
digitalWrite(lightone, HIGH);
LightSts = 0 ;
}
}
// }
// else
// {
// digitalWrite (lighttwo,HIGH); // turn status LED indicate RTC error
// //Serial.println("Something Wrong with RTC.So, NOT Controlling Lights Now");
// }
if (RTCerr)
{
digitalWrite (lighttwo, HIGH); // turn status LED indicate RTC error
}
//********************************************************************************************************************************************
// *******************************************************************************************************************************************
// DAILY TIMED ALARMS THAT TRIGGER ON SPECIFIED TIMES
// these alarms will trigger once and will do "stuff" mentioned in the alarm functions at the end of the loop
// *******************************************************************************************************************************************
Alarm.alarmRepeat(3, 0, 0, ON2Alarm); // daily Alarm 1 for example // for triggering an alarm on ""03:00:00"" in the morning
// ONAlarm is the name of the function that will be called when the current time matches
// the Time you have set for the specified alarm
// the ONAlarm function is defined below and the name ONAlarm can be changed
Alarm.alarmRepeat(6, 0, 0, ON2Alarm); //Alarm 2 // for triggering an alarm on ""06:00:00"" in the morning
Alarm.alarmRepeat(9, 0, 0, ON2Alarm); // daily Alarm 3
Alarm.alarmRepeat(12, 0, 0, ON2Alarm); // daily Alarm 4
Alarm.alarmRepeat(15, 0, 0, ON2Alarm); // daily Alarm 5
Alarm.alarmRepeat(18, 0, 0, ON2Alarm); // daily Alarm 6
Alarm.alarmRepeat(21, 0, 0, ON2Alarm); // daily Alarm 7
// Alarm.alarmRepeat(0, 0, 0, OFFAlarm); // daily Alarm 22
// Alarm.alarmRepeat(1, 0, 0, OFFAlarm); // daily Alarm 23
// Alarm.alarmRepeat(2, 0, 0, OFF2Alarm); // daily Alarm 24
if(millis()/1000 -SecsTwo > 2 ) // Every Two Seconds
{
dhtCalc() ; // Update Temperature and Humidity from DHT22
ThermCalc(); // Update Temperature from Thermistor
SecsTwo=millis()/1000;
}
//#########################################################################################################
//#########################################################################################################
// CONTROL PART turning things ON and OFF according to Temperature and Humidity (THE GOOD STUFF) "ifs"
//#########################################################################################################
//#########################################################################################################
if (!DHTerr) // only proceed to controlling things according to Temp1 and humidity
{ // if there is no DHT read error
if (t >= Tmax ) // TURN COOLER ON IF TEMPERATURE IS EQUAL TO OR EXCEEDS "Tmax" (HEATER remains OFF)
{
if (!CoolerSts)
{
digitalWrite(cooler, LOW);// Turn Cooler Pin LOW // ON because of LOW Level trigger Relay
Alarm.delay(2000);
CoolerSts = 1 ; // Cooler Status is ON // Status is used for Serial Print
}
TempSts = 4; // High Temp // Status is used by Oled
}
if (t <= Tnor ) // Turn OFF the COOLER when TEMP GETS DOWN TO "setT" OR GOES BELOW
{
digitalWrite(cooler, HIGH);
CoolerSts = 0 ;
}
if (t <= Tmin) // TURN HEATER "ON" WHEN TEMPERATURE GETS TO "Tmin" OR BELOW (cooler remains OFF)
{
if (!HeaterSts)
{
digitalWrite(heater, LOW);
Alarm.delay(2000);
HeaterSts = 1 ;
}
TempSts = 1; // Low Temp
}
if (t >= Tnor ) // TURN OFF HEATER WHEN TEMP GETS TO "setT" (and REMAINS LOWER THAN "Tmax")
{
digitalWrite (heater, HIGH);
HeaterSts = 0 ;
}
//######################################/
//######################################/
//# Just for Setting Status of things #
//######################################/
//######################################\
if (t <= Tmax && t > Tnor)
{
TempSts = 3; // Upper Range
}
if (t <= Tnor && t > Tmin)
{
TempSts = 2; // normal range
}
if ( t > TmaxR)
{
TmaxR = t; // Update Max Recorded Temperature For the Session
}
//#######################################################
//############### Control for HUMIDITY ###############
//#######################################################
if (h >= Hmax)
{
if (!BigFanSts)
{
digitalWrite(Bigfan, LOW); // Turn fan on when humidity is high
Alarm.delay(2000);
BigFanSts = 1 ;
}
HumSts = 4; // humidity max/high
}
if (h <= Hnor )
{
digitalWrite(Bigfan, HIGH);
BigFanSts = 0;
}
if (h <= Hmin)
{
if (!SpraySts)
{
digitalWrite(spray, LOW); // Turn Spray on when humidity is low
Alarm.delay(2000);
SpraySts = 1 ;
}
HumSts = 1; // humidity low
}
if (h >= Hnor)
{
digitalWrite(spray, HIGH); // Turn Spray off when humidity is normal or high
SpraySts = 0 ;
}
if (h > Hnor && h < Hmax)
{
HumSts = 3; // upper range
}
if (h > Hmin && h <= Hnor)
{
HumSts = 2; // normal range
}
if ( h > HmaxR)
{
HmaxR = h; // Update Max Recorded Humidity For the Session
}
}
else // if DHT error
{
digitalWrite (lighttwo, HIGH); // turn status LED indicate DHT error
//Serial.println("Something Wrong with DHT.So, NOT Controlling Things Now");
digitalWrite(Bigfan, HIGH);
digitalWrite(cooler, HIGH);
digitalWrite(heater, HIGH);
digitalWrite(spray, HIGH);
}
Display(); // Call the Display function below for OLED
if(millis()/1000 -Secs > 30 )
{
RecDisplay();
Alarm.delay(3000);
Secs=millis()/1000;
}
}
//**********************//**********************//**********************
// LOOP END
//**********************//**********************//**********************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//***********************//**********************//***********************//**********************
// DHT 22****** TEMPERATURE HUMIDITY CALCULATIONS
//***********************//**********************//***********************//**********************
void dhtCalc()
{
h = dht.readHumidity(); // READ HUMIDITY
t = dht.readTemperature(); // Read temperature as Celsius
// Check if any reads failed and exit early (to try again)
if (isnan(h) || isnan(t) )
{
Alarm.delay(1000);
DHTerr=1;
}
else
{
DHTerr=0;
}
/*Serial.print("Humidity: ");
Serial.print(h);
Serial.print(" %\t");
Serial.print("T1: ");
Serial.print(t);
Serial.print(" *C ");
*/
}
//***************************************************************************************************************
// THERMISTOR CALCULATIONS
//***************************************************************************************************************
void ThermCalc()
{
byte i;
float average =0 ;
for (i = 0; i < NUMSAMPLES; i++) // take "N" number of samples in a row, with a slight delay
{
samples[i] = analogRead(THERMISTORPIN);
Alarm.delay(10);
}
for (i = 0; i < NUMSAMPLES; i++) // average all the samples out
{
average += samples[i];
}
average /= NUMSAMPLES;
average = 1023 / average - 1; // convert the value to resistance
average = SERIESRESISTOR / average;
//Serial.print("Thermistor resistance ");
//Serial.println(average);
t2= average / THERMISTORNOMINAL; // (R/Ro)
t2 = log(t2); // ln(R/Ro)
t2 /= BCOEFFICIENT; // 1/B * ln(R/Ro)
t2 += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
t2 = 1.0 / t2; // Invert
t2 -= 273.15; // convert to C
/*
Serial.print("T2 "); // FOR SERIAL MONITOR
Serial.print(t2);
Serial.println(" *C");
*/
}
//***********************//**********************
// OLED PART
//FUNCTION FOR DISPLAY ON THE OLED
//***********************//**********************
void Display()
{
char timebuf[5]; // array for Time
tmElements_t tm; //formatting time and date before displaying
if (RTC.read(tm))
{
sprintf(timebuf, "%02d:%02d", tm.Hour, tm.Minute); // format time
}
u8g.firstPage();
do
{
u8g.drawFrame(0, 0, 128, 20); // Draw frame
if(DHTerr) // if DHT error is 1 or true then display dht error on oled
{
u8g.drawStr( 35, 14, "* DHT ERROR *");
}
//*******************************************************************************
else // else display values
{
switch (HumSts) // Display According to Humidity Status on OLED
{
case 4:
u8g.drawStr( 91, 14, "*H MX*"); // humidity is equal to max or more than max
break;
case 3:
u8g.drawStr( 91, 14, "*H AN*"); // above normal
break;
case 2:
u8g.drawStr( 91, 14, ">H NR<"); // Normal
break;
case 1:
u8g.drawStr( 91, 14, "*H LW*"); // Lower than Minimum Humidity
break;
}
//*********************************************************************
switch (TempSts) // Display According to Temperature Status on OLED
{
case 4:
u8g.drawStr( 34, 14, "*HI TMP*");
break;
case 3:
u8g.drawStr( 34, 14, "*ABV NR*");
break;
case 2:
u8g.drawStr( 34, 14, ">NR TMP<");
break;
case 1:
u8g.drawStr( 34, 14, "*LO TMP*");
break;
}
}
//************// Display Time on OLED//**************//
if(!RTCerr)
{
u8g.setPrintPos(2, 14); // set position for displaying time
u8g.print(timebuf); //display time
}
else
{
u8g.drawStr( 2, 14, "RtcEr");
}
//******// Display CURRENT Temperature1&2,humidity , Set Tmax ,Set Tnor and Set Tmin on OLED//*********************
u8g.drawFrame(0, 22, 128, 42); // Draw frame
u8g.drawStr(2, 32, "T :"); // first digit is screen coordinate for X-axis and second for Y-axis
// (it starts on left bottom corner of the text which is to be shown on the oled)
// T1 for temperature from DHT22 and T2 is from Thermistor
u8g.drawStr( 21, 32, dtostrf(t, 5, 2, str));
u8g.drawStr( 51, 32, "\260C");
u8g.drawStr( 2, 42, "M :");
u8g.drawStr( 21, 42, dtostrf(Tmax, 5, 2, str));
u8g.drawStr( 51, 42, "\260C");
u8g.drawStr( 2, 52, "N ");
u8g.drawStr( 15, 52, ":");
u8g.drawStr( 21, 52, dtostrf(Tnor, 5, 2, str));
u8g.drawStr( 51, 52, "\260C");
u8g.drawStr( 2, 62, "m ");
u8g.drawStr( 15, 62, ":");
u8g.drawStr( 21, 62, dtostrf(Tmin, 5, 2, str));
u8g.drawStr( 51, 62, "\260C");
u8g.drawStr( 65, 32, "T2:");
u8g.drawStr( 83, 32, dtostrf(t2, 5, 2, str));
u8g.drawStr( 113, 32, "\260C");
u8g.drawStr( 65, 42, "H :");
u8g.drawStr( 83, 42, dtostrf(h, 5, 2, str));
u8g.drawStr( 117, 42, "%");
u8g.drawStr( 65, 52, "M :");
u8g.drawStr( 83, 52, dtostrf(Hmax, 5, 2, str));
u8g.drawStr( 117, 52, "%");
u8g.drawStr( 65, 62, "m ");
u8g.drawStr( 78, 62, ":");
u8g.drawStr( 83, 62, dtostrf(Hmin, 5, 2, str));
u8g.drawStr( 117,62, "%");
//Alarm.delay(300); // Comment this line to make the oled display as fast as possible
// Keep in mind that thermistor values change really fast
// and are not so accurate so this is necessary to make the display smooth
}
while ( u8g.nextPage() );
}
void RecDisplay()
{
u8g.firstPage();
do
{
u8g.drawFrame(0, 0, 128, 20); // Draw frame
u8g.drawFrame(0, 22, 128, 42); // Draw frame
u8g.drawStr(4, 14, "Max Recorded");
u8g.drawStr( 4, 34,"T Max:");
u8g.setPrintPos(47,34);
u8g.print(TmaxR);
u8g.drawStr( 75, 34, "\260C");
u8g.drawStr( 4, 46,"H Max:");
u8g.setPrintPos(47,46);
u8g.print(HmaxR);
u8g.drawStr( 79, 46, "%");
}
while ( u8g.nextPage() );
}
//**********************//**********************//**********************//**********************
//Functions called when daily time specific alarms (above in the loop) triggers:
//***********************************************//**********************//**********************
/*
void ONAlarm()
{
// Tmax = 29; // set day time temperatures
// setT = 25;
// Tmin = 19;
}
void OFFAlarm()
{
// Tmax = 26; // set night time temperatures
// setT = 23;
// Tmin = 19;
}
*/
void ON2Alarm()
{
SyncTime();
}
void OFF2Alarm()
{
SyncTime();
}
//**************************************************************************************
//*** Function for Serial Printing status of switches and other values ** FOR ESP8266 *
//**************************************************************************************
void SPrintStatusOne()
{
Serial.print ('L');
Serial.print (LightSts);
Serial.print ('C');
Serial.print (CoolerSts);
Serial.print('H');
Serial.print(HeaterSts);
Serial.print('B');
Serial.print(BigFanSts);
Serial.print('S');
Serial.print(SpraySts);
Serial.print('E');
Serial.print(DHTerr);
Serial.print(RTCerr);
Serial.print('t');
Serial.print(t);
Serial.print('h');
Serial.print(h);
Serial.print('r');
Serial.println(t2);
}
//*************************************************************************************
//*** Function for Serial Printing status of switches and other values ** FOR HUMAN ***
//*************************************************************************************
/*
void SPrintStatusTwo()
{
Serial.print("T1: ");
Serial.println(t);
Serial.print("H: ");
Serial.println(h);
Serial.print("T2: ");
Serial.println(t2);
if(LightSts)
{
Serial.println ("Light ON");
}
else
{
Serial.println("Light OFF");
}
if(CoolerSts)
{
Serial.println("Cooler ON");
}
else
{
Serial.println("Cooler OFF");
}
if(HeaterSts)
{
Serial.println("Heater ON");
}
else
{
Serial.println("Heater OFF");
}
if(BigFanSts)
{
Serial.println("Fan ON");
}
else
{
Serial.println("Fan OFF");
}
if(SpraySts)
{
Serial.println("Spray ON");
}
else
{
Serial.println("Spray OFF");
}
}
*/
//**********************//**********************//********************************
//Function for digital clock display (in the SERIAL MONITOR *** FOR ESP8266 ***
//**********************//**********************//********************************
void TimeDateDisplayOne() // digital clock display 24hr format // for ESP-8266 and HUM-an too :)
{
Serial.print("Z");
PrintZD(hour()); // Print Hour Digit and add a zero before single digits
PrintCD(minute()); // Print a colon sign ":" and add zero before single digits
PrintCD(second());
Serial.print('W');
Serial.print(weekday()); // there are no double digits only 7 days in a week
Serial.print('D');
PrintZD(day()); // Print the Day of the month and add zero before single digits
Serial.print('M'); // add zero before single digit month numbers
PrintZD(month());
Serial.print('Y');
Serial.print(year());
}
//**********************//**********************//**********************//*****
//Function for digital clock display (in the SERIAL MONITOR *** FOR HUMAN ***
//**********************//**********************//**********************//*****
/*
void TimeDateDisplayTwo() // digital clock display of the time 24hr format // for HUM-an
{
Serial.println("****>> 10 second timer<< ****");
Serial.println("TIME");
PrintZD(hour());
PrintCD(minute());
PrintCD(second());
Serial.println();
Serial.println("DATE");
Serial.print(dayStr(weekday()));
Serial.print("-");
Serial.print(day());
Serial.print("-");
Serial.print(monthStr(month()));
Serial.print("-");
Serial.println(year());
}
*/
//***********************************************************************
//** Function for adding Zero before single digits before Serial print **
//***********************************************************************
void PrintZD(int D)
{
if(D < 10) // don't add brackets for this if statement it will not work
Serial.print('0');
Serial.print(D);
}
//*********************************************************************************
//** Function for adding a Colon & Zero before single digits before Serial print **
//*********************************************************************************
void PrintCD(int digits)
{
Serial.print(":");
if (digits < 10) // don't add brackets for this if statement it will not work
Serial.print('0');
Serial.print(digits);
}
//******************************
//*************** THE END *****
//******************************
Subscribe to:
Posts (Atom)