Hans Sassenburg
Published

Chicken Coop Controller

Sophisticated ESP8266/Cayenne-based chicken coop controller, managing door/light/heater, outputs accessible through web server.

AdvancedFull instructions provided2,316
Chicken Coop Controller

Things used in this project

Hardware components

ESP8266MOD (Wemos D1)
×1
Resistor 220 ohm
×3
LED (red)
×1
LED (yellow)
×1
LED (blue)
×1
BC547 (NPN-transistor)
×2
Resistor 10k ohm
×2
AM2302 (temp/hum sensor)
×1
Solid State Relay (LRSSR-DD, DC input/output)
×1
Solid State Relay (LRSSR-DA, DC input, AC output)
×1
Automatic Chicken Coop door (Kerbl)
×1
Heating plate (24V, VOSS)
×1
Light (220V)
×1
Wires, cables, etc.
×1
Diode 1N4148
×2
LCD display (alphanumeric, 20x4)
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Wiring schematics

Code

Chicken Coop Controller - C file

C/C++
Source code
#include <SD.h>

/*
*/

#define CAYENNE_DEBUG
#define CAYENNE_PRINT Serial
#include <CayenneMQTTESP8266.h>

#include <Wire.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <DHT.h>
#include "pitches.h"
#include <LiquidCrystal_I2C.h>

// Cayenne channels as used on Dashboard
#define CAY_LIGHT       3
#define CAY_DOOR        4
#define CAY_HEATER      5
#define CAY_MANUAL      7
#define CAY_TEMP        8
#define CAY_HUM         9
#define CAY_RESET      10

// Leds
#define OUT_HEATER     D11
#define OUT_LIGHT      D10
#define OUT_DOOR       D2
// door control
#define OUT_DOOR_OPEN  D12
#define OUT_DOOR_CLOSE D13
// temperature/humidity
#define DHT_PIN        D9  
#define DHT_TYPE       DHT22

// geographical time constants 
#define TIME_MIDDAY   (60*12)+31
float   latitude    = 46.00 + (31.00/60);
// light-on time in minutes (corrected for sunrise/sunset); important so chicken eat enough as protection against cold
#define LIGHT_ON_TIME 60*13

#define SR_DOOR_OPEN_OFFSET     0 // offset for opening door AFTER sunrise
#define SS_DOOR_CLOSE_OFFSET   45 // offset for closing door AFTER sunset
#define SR_LIGHT_ON_OFFSET     30 // offset for switching  on light BEFORE sunsrise
#define SS_LIGHT_ON_OFFSET     45 // offset for switching  on light BEFORE sunset
#define SS_LIGHT_OFF_OFFSET    90 // offset for switching off light AFTER  sunset

// temperature constants (below threshold-hysteris -> heater on; above threshold+hysteris -> heater off
#define TEMP_HEAT_THRESHOLD   8.0
#define HEAT_HYSTERESIS       1.0
// below this temperature: door will not be opened
#define TEMP_CLOSE_DOOR      -5.0

DHT     dhtSensor (DHT_PIN, DHT_TYPE); 

LiquidCrystal_I2C lcd (0x3f, 20, 4);

// Define NTP Client to get real-time date/time
WiFiClient  espClient;
WiFiUDP     ntpUDP;

// webserver
ESP8266WebServer server(80);

// Set offset time in seconds to adjust for Lenk timezone (GMT-1: 3600)
NTPClient timeClient(ntpUDP,"europe.pool.ntp.org", 3600, 60000);

// number of days past at start of each month, not corrected yet for leap years, used to caclulate day of year
int     numberDaysSinceJan01[12] = { 0,31,59, 90,120,151,181,212,243,273,304,334};

// WiFi networks info
char*   ssid[] = {"<your SSID1>", "<your SSID2>"};                      
char*   pass[] = {"<your pass1>", "your pass2>"}; 
#define SSID_COUNT (sizeof(ssid)/sizeof(ssid[0]))
#define WIFI_TIMEOUT  10

#define TEST
// Cayenne authentication info (obtained from the Cayenne Dashboard)
char    username[] = "<your Cayenne username>";
char    password[] = "<your Cayenne password>";
#ifdef TEST
char    clientID[] = "<your Cayenne client id for testing>";
#else
char    clientID[] = "<your Cayenne client if for installed device>";
#endif

#define HUM_INITIAL_VALUE 38.00
#define TMP_INITIAL_VALUE 21.00
float   humidity        = HUM_INITIAL_VALUE;     // Initial value
float   humMin          = 99.99;
float   humMax          = 0;
String  humMinT         = "     ";
String  humMaxT         = "     ";
float   temperature     = TMP_INITIAL_VALUE;     // Initial value
float   tmpMin          = 99.99;
float   tmpMax          = 0;
String  tmpMinT         = "     ";
String  tmpMaxT         = "     ";
bool    lightOn         = false;  // Light off
bool    automaticLight  = true;   // Automatic light algorithm enabled
bool    doorClosed      = true;   // Door closed (because restart takes place every midnight)
bool    automaticDoor   = true;   // Automatic door algorithm enabled
bool    heaterOn        = false;  // Heater off
bool    automaticHeater = true;   // Automatic heater algorithm enabled
bool    manual          = false;  // Automatic mode disabled, no LCD display
String  eventList       = "\nTime  Device  state   trigger\n_____ ______  _______ ______________\n";
 
// real-time values from NTP Client
int     hours;
int     minutes; 
int     seconds;
int     day;
int     month;
int     year;
bool    leapYear = false;
 
// astro values
int     daysSinceJan01;
int     sunRise;       // computed real-time, includes eot
int     sunSet;        // computed real-time, includes eot
float   eot;           // computed real-time (angular offset of the Sun from its mean position on the celestial sphere)
float   dayLength;     // computed real-time
String  currentDate = "     ";
String  currentTime = "     ";
 
// use "timers" to keep update-frequencies (Cayenne, dht sensor) low (i.e., 60 seconds)
#define  UPDATE_INTERVAL 60000
unsigned long cayLastMillis = UPDATE_INTERVAL + 1;
unsigned long dhtLastMillis = UPDATE_INTERVAL + 1;
 
// FUNCTION: read temperature and humidity sensor values if interval expired
void UpdateEnvData ()
{
  float value;
 
  if (millis() - dhtLastMillis > UPDATE_INTERVAL)
  { 
    value = dhtSensor.readTemperature();
    if ((value > -30.0) && (value < 100.0))
    { 
      temperature = value;
      if (tmpMin > temperature)
      {
        tmpMin  = temperature;       
        tmpMinT = currentTime; 
      }
      if (tmpMax < temperature)
      {
        tmpMax  = temperature;       
        tmpMaxT = currentTime;
      }
    }
    value = dhtSensor.readHumidity();
    if ((value > 0.0) && (value < 100.0))
    { 
      humidity = value;
      if (humMin > humidity)
      {
        humMin  = humidity;  
        humMinT = currentTime;     
      }
      if (humMax < humidity)
      {
        humMax  = humidity;    
        humMaxT = currentTime;   
      }
    }
    dhtLastMillis = millis();
  }
}
 
// FUNCTION: read temperature and humidity sensor values, as well as status of light (off/on) and door (open/closed)
void DisplayEnvData ()
{
  lcd.setCursor (0,0);
  lcd.print ("T  ");
  lcd.print (temperature);
  lcd.print ("   H = ");
  lcd.print (humidity);
  lcd.setCursor (0,3);
  lcd.print ("D: ");    
  lcd.print (doorClosed);
  lcd.print ("    L: ");
  lcd.print (lightOn);
  lcd.print ("    H: ");
  lcd.print (heaterOn);
}
 
// FUNCTION: calculate all relevant astro data for this day
void UpdateAstroData ()
{
  unsigned long epochTime;
  float x;
  float P;
  // Get real-time date/time
  while(!timeClient.update())
  {
    timeClient.forceUpdate();
  }
 
  epochTime = timeClient.getEpochTime();
  if ((epochTime > EPOCH_MIN) && (epochTime < EPOCH_MAX))
  {
    hours   = timeClient.getHours();
    minutes = timeClient.getMinutes();
    seconds = timeClient.getSeconds();
  }
  if (hours < 10)
  {
    currentTime = "0" + String(hours) + ":";
  }
  else
  {
    currentTime = String(hours) + ":";     
  }
  if (minutes < 10)
  {
    currentTime += "0" + String(minutes);
  }
  else
  {
    currentTime += String(minutes); 
  }
 
  struct tm *ptm = gmtime ((time_t *)&epochTime);
 
  if ((epochTime > EPOCH_MIN) && (epochTime < EPOCH_MAX))
  {
    day   = ptm->tm_mday;
    month = ptm->tm_mon+1;
    year  = ptm->tm_year+1900;
  }
   
  if (day < 10)
  {
    currentDate = "0" + String(day) + "-";
  }
  else
  { 
    currentDate = String(day) + "-";     
  }
  if (month < 10)
  {
    currentDate += "0" + String(month) + "-" + String(year);
  }
  else
  { 
    currentDate += String(month) + "-" + String(year);
  }
 
  // calculate day of the year, note: daysSinceJan01 = 0 on Jan. 1st, so subtract 1
  daysSinceJan01 = numberDaysSinceJan01[month-1]+day-1;     
  // check for leap year
  if((month >= 3) && (year % 4 == 0))
  {
    daysSinceJan01 += 1;
    leapYear = true;
  }
  Serial.print ("DOOR:   Days since Jan. 01 = ");
  Serial.print (daysSinceJan01);
 
  // calculate daylength
  P = asin(0.39795*cos(0.2163108 + 2*atan(0.9671396*tan(0.00860*(daysSinceJan01-186)))));
  dayLength = 24 - (24/PI)*acos((sin(0.8333*PI/180)+sin(latitude*PI/180)*sin(P))/(cos(latitude*PI/180)*cos(P))); 
  Serial.print (", Day length = ");
  Serial.print (dayLength);
 
  // calculate equation of time
  x = 2*PI*(daysSinceJan01)/365.242;
  eot = 0.258*cos(x) - 7.416*sin(x) - 3.648*cos(2*x) - 9.228*sin(2*x);
  Serial.print (", EOT = ");
  Serial.println (eot);
  sunRise = TIME_MIDDAY - int(60*dayLength/2) - int(eot);
  sunSet  = TIME_MIDDAY + int(60*dayLength/2) - int(eot);
 
  // check for restart time (midnight)
  if ((hours == 0) && (minutes == 0))
  {
    // wait 1 minute (to prevent another restart) and restart the ESP
    Serial.println ("Reset config (midnight)");
   
    delay (60000);
    ESP.restart();
  }
}
 
// FUNCTION: check whether light must be turned off/on
void CheckLight ()
{
  Serial.print ("LIGHT:  Int. bandwidth(lz) = ");
  Serial.print (sunSet + SS_LIGHT_OFF_OFFSET - LIGHT_ON_TIME);
  Serial.print (" - ");
  Serial.print (sunSet + SS_LIGHT_OFF_OFFSET);
  Serial.print (", Ext. bandwidth(sr-ss) = ");
  Serial.print (sunRise+SR_LIGHT_ON_OFFSET);
  Serial.print (" - ");
  Serial.print (sunSet-SS_LIGHT_ON_OFFSET); 
  Serial.print (", Actual value = ");
  Serial.println (60*hours + minutes);
 
  if ( (60*hours + minutes >= sunSet + SS_LIGHT_OFF_OFFSET - LIGHT_ON_TIME) && (60*hours + minutes < sunSet + SS_LIGHT_OFF_OFFSET) )
  {
    if ((60*hours + minutes < sunRise + SR_LIGHT_ON_OFFSET) || (60*hours + minutes >= sunSet - SS_LIGHT_ON_OFFSET))
    {   
      if (lightOn == false)
      {
        Serial.println ("LIGHT (auto): turn on (inside int bandwidth (lz), outside ext bandwidth (sr'-ss').");
        if (60*hours + minutes <= sunRise + SR_LIGHT_ON_OFFSET)
        {
          eventList += currentTime + " Light   on      morning\n";             
        }
        else
        {
          eventList += currentTime + " Light   on      evening\n";            
        }
         
        digitalWrite (OUT_LIGHT, HIGH);
        lightOn = true;
      }
    }
    else
    {
      if (lightOn == true)
      {
        Serial.println ("LIGHT (auto): turn off (inside int bandwidth (lz), inside ext bandwidth (sr'-ss').");
        eventList += currentTime + " Light   off     daylight\n";  
                    
        digitalWrite (OUT_LIGHT, LOW);
        lightOn = false;
      }
    }
  }
  else
  {
    if (lightOn == true)
    {
      Serial.println ("LIGHT (auto): turn off (outside both bandwidths).");
      eventList += currentTime + " Light   off     night\n";
                     
      digitalWrite (OUT_LIGHT, LOW);
      lightOn = false;
    }
  }
}
 
// FUNCTION: check whether door must be opened/closed
void CheckDoor ()
{
  UpdateAstroData ();
   
  // Check against sunrise/sunset times
  if (60*hours + minutes < sunRise + SR_DOOR_OPEN_OFFSET)
  {
    if (doorClosed == false)
    {
      Serial.println ("DOOR (auto): Early morning, open -> closing ...");
      eventList += currentTime + " Door    closed  night\n";      
       
      digitalWrite (OUT_DOOR_CLOSE, LOW);
      delay (1000);
      digitalWrite (OUT_DOOR_CLOSE, HIGH);
      doorClosed = true;
      digitalWrite (OUT_DOOR, HIGH);        
    }
  }
  else if (60*hours + minutes < sunSet + SS_DOOR_CLOSE_OFFSET)
  {
    if ((doorClosed == true) && (temperature > TEMP_CLOSE_DOOR))
    {
      Serial.println ("DOOR (auto): During day, closed -> opening ...");
      eventList += currentTime + " Door    opened  daylight\n";
        
      digitalWrite (OUT_DOOR_OPEN, LOW);
      delay (1000);
      digitalWrite (OUT_DOOR_OPEN, HIGH);
      doorClosed = false;
      digitalWrite (OUT_DOOR, LOW);  
    }
  }   
  else if (60*hours + minutes >= sunSet + SS_DOOR_CLOSE_OFFSET)
  {
    if (doorClosed == false)
    {
      Serial.println ("DOOR (auto): Evening, open -> closing ...");
      eventList += currentTime + " Door    closed  night\n";
      
      digitalWrite (OUT_DOOR_CLOSE, LOW);
      delay (1000);
      digitalWrite (OUT_DOOR_CLOSE, HIGH);
      doorClosed = true;
      digitalWrite (OUT_DOOR, HIGH); 
    }  
  }
}
 
// FUNCTION: check whether heater must be turned off/on
void CheckHeater ()
{ 
  Serial.print ("HEATER: Treshold = ");
  Serial.print (TEMP_HEAT_THRESHOLD);
  Serial.print (", Hysteresis = ");
  Serial.print (HEAT_HYSTERESIS);
  Serial.print (", T(close door) = ");
  Serial.print (TEMP_CLOSE_DOOR);
  Serial.print (", T = ");
  Serial.println (temperature);
  if (temperature <= TEMP_HEAT_THRESHOLD - HEAT_HYSTERESIS)
  {
    if (heaterOn == false)
    {
      Serial.println ("HEATER (auto): Turning on (below threshold-hysteresis).");
      eventList += currentTime + " Heater  on      below threshold\n";
            
      digitalWrite (OUT_HEATER, HIGH); 
      heaterOn = true;
    } 
  }             
  else if (temperature >= TEMP_HEAT_THRESHOLD + HEAT_HYSTERESIS)
  {
    if (heaterOn == true)
    {
      Serial.println ("HEATER (auto): Turning off (above threshold+hysteresis).");
      eventList += currentTime + " Heater  off     above threshold\n";
                  
      digitalWrite (OUT_HEATER, LOW); 
      heaterOn = false;
    }       
  } 
}
 
// FUNCTION: display date and time on LCD display
void DisplayDateTime ()
{
  lcd.setCursor (0,0);
  lcd.print (currentDate);
  lcd.setCursor (10,0);
  lcd.print ("     ");
  lcd.print (currentTime);
}
 
// FUNCTION: display astro data on LCD display
void DisplayAstroData ()
{  
  lcd.setCursor (0,1);
  lcd.print ("SR ");
  if(int(sunRise/60) < 10)
  {
    lcd.print ("0");   
  }
  lcd.print (int(sunRise/60));
  lcd.print (":");
  if(int(sunRise - 60*int(sunRise/60)) < 10)
  {
    lcd.print ("0");   
  }
  lcd.print (int(sunRise - 60*int(sunRise/60)));
  lcd.setCursor (0,2);
  lcd.print ("SS ");
  if(int(sunSet/60) < 10)
  {
    lcd.print ("0");   
  }
  lcd.print (int(sunSet/60));
  lcd.print (":");
  if(int(sunSet - 60*int(sunSet/60)) < 10)
  {
    lcd.print ("0");   
  } 
  lcd.print (int(sunSet - 60*int(sunSet/60)));
 
  lcd.setCursor (11,1);
  lcd.print ("DL  ");
  if(dayLength < 10)
  {
    lcd.print ("0");   
  } 
  lcd.print (dayLength);
  lcd.setCursor (11,2);
  lcd.print ("EoT ");
  if(eot < 10)
  {
    lcd.print ("0");   
  } 
  lcd.print (eot);
} 
 
// FUNCTION: convert number of minutes since 00:00 to string hh:mm
void MinutesToString (int minutes, String *result)
{ 
  *result = "";
 
  if(int(minutes/60) < 10)
  {
    *result += "0";   
  }
  *result += String(int(minutes/60));
  *result += ":";
  if(int(minutes - 60*int(minutes/60)) < 10)
  {
    *result += "0"; 
  }
  *result += String(int(minutes - 60*int(minutes/60)));
}
 
// FUNCTION: convert numeric value between -99 and +99 to string xx.yy
void ValueToString (float value, String *result)
{ 
  *result = "";
 
  if(value <= -10.00)
  {
    *result += "-";   
    value = -value;
  }
  else if (value < 0.00)
  {
    *result += "- ";  
    value = -value;
  }
  else if (value <= 10.00)
  {
    *result += "  ";   
  }
  else
  {
    *result += " ";   
  } 
  *result += String(value);
}
 
// FUNCTION: update currrent status on web server
void HandleServerMessage()
{
  String sign         = " ";
  String stringSr     = "    ";
  String stringSs     = "    ";
  String stringDl     = "    ";
  String stringEot    = "    ";
  String stringDoor   = "    ";
  String stringLight  = "    ";
  String stringTmpVal = "     ";
  String stringTmpMin = "     ";
  String stringTmpMax = "     ";
  String stringHumVal = "     ";
  String stringHumMin = "     ";
  String stringHumMax = "     ";
     
  String title    = "CHICKEN COOP LENK    -     STATUS REPORT\n________________________________________\n";
  String dateTime = "Date: " + currentDate + "             Time: " + currentTime + "\n\n\n";
 
  // convert float temperature/humidity values to strings
  ValueToString (temperature, &stringTmpVal); 
  ValueToString (     tmpMin, &stringTmpMin);
  ValueToString (     tmpMax, &stringTmpMax);
  ValueToString (   humidity, &stringHumVal); 
  ValueToString (     humMin, &stringHumMin);
  ValueToString (     humMax, &stringHumMax);   
  String tmpData  = "              " + stringTmpMin + " oC (min at " + tmpMinT +")\n";
  tmpData += "Temperature = " + stringTmpVal + " oC\n";
  tmpData += "              " + stringTmpMax + " oC (max at " + tmpMaxT + ")\n\n";
  String humData  = "              " + stringHumMin + "  % (min at " + humMinT + ")\n";
  humData += "Humidity    = " + stringHumVal + "  %\n";
  humData += "              " + stringHumMax + "  % (max at " + humMaxT + ")\n\n";
  MinutesToString (60*dayLength, &stringDl );
  if (eot < 0.00)
  {
    sign = "-";   
  }
  MinutesToString (60*     fabs(eot), &stringEot);
  String dayData  = "Day number  =    ";
  if (daysSinceJan01+1 < 10)
  {
    dayData += "  ";   
  } 
  else if (daysSinceJan01+1 < 100)
  {
    dayData += " ";   
  } 
  dayData += String(daysSinceJan01+1);
  if ( leapYear == true)
  {
    dayData += "  (leap year) ";   
  } 
  dayData += "\nDay length  =  " + stringDl + "  (hrs)\nEoT         = " + sign + stringEot + "  (min)\n\n";
 
  MinutesToString (sunRise, &stringSr);
  MinutesToString (sunSet,  &stringSs);
  String sunData  = "Sunrise    at  " + stringSr + "\nSunset     at  " + stringSs + "\n\n";
  String cfgData = "Light      ->  "; 
  if (lightOn == false)
  {
    if (60*hours + minutes > sunSet + SS_LIGHT_OFF_OFFSET)
    {
      MinutesToString (sunSet + SS_LIGHT_OFF_OFFSET - LIGHT_ON_TIME, &stringLight);
    }
    else
    {
      MinutesToString (sunSet-SS_LIGHT_ON_OFFSET, &stringLight);
    }       
    cfgData += "Off    (on     at ~" + stringLight + ")\n";   
  }
  else
  {
    if (60*hours + minutes < TIME_MIDDAY)
    {
      MinutesToString (sunRise+SR_LIGHT_ON_OFFSET, &stringLight);
    }
    else
    {
      MinutesToString (sunSet+SS_LIGHT_OFF_OFFSET, &stringLight);
    }     
    cfgData += "On     (off    at ~" + stringLight + ")\n";   
  } 
  cfgData  += "Door       ->  ";
  if (doorClosed == false)
  {
    MinutesToString (sunSet + SS_DOOR_CLOSE_OFFSET, &stringDoor);
    cfgData += "Open   (close  at ~" + stringDoor + ")\n";   
  }
  else
  {
    MinutesToString (sunRise + SR_DOOR_OPEN_OFFSET, &stringDoor);
    cfgData += "Closed (open   at ~" + stringDoor + ")\n";   
  } 
  cfgData += "Heater     ->  "; 
  if (heaterOn == false)
  {
    cfgData += "Off";   
  }
  else
  {
    cfgData += "On ";   
  } 
  cfgData += "    (hys: " + String(TEMP_HEAT_THRESHOLD-HEAT_HYSTERESIS) + " - " + String(TEMP_HEAT_THRESHOLD+HEAT_HYSTERESIS)+ ")\n\n";
 
  server.send(200, "text/plain", title + dateTime + tmpData + humData + dayData + sunData + cfgData + eventList);
}
 
// FUNCTION: : report that web server could not be found
void HandleServerNotFound()
{
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++)
  {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
}
 
// FUNCTION: connect to any of the specified WIFI networks
int ConnectToWifi ()
{
  int i = 0;
  int w = 0;
 
  WiFi.begin(ssid[0], pass[0]);
  delay (1000);
  lcd.setCursor (0,0);
  lcd.print ("SSID: ");
  lcd.print (ssid[0]);
  lcd.setCursor (0,1);
  Serial.print ("Connecting to ");
  Serial.println (ssid[0]);
 
  while (WiFi.status() != WL_CONNECTED)
  {
    //If timeout is reached, increment w counter, try the next wifi network
    if (i == WIFI_TIMEOUT)
    {
      Serial.println("");
      w++;
      //Make sure we havent reached the end of the list of SSIDs
      if (w < SSID_COUNT)
      {
        Serial.print("Timeout. Switching to alternate SSID: ");
        Serial.println(ssid[w]);
        WiFi.begin(ssid[w], pass[w]);
        delay(1000);
      }
      else
      {
        //If we have tried all the defined SSIDs, reboot and try again, or change to break; and continue on with program
        Serial.println("No WiFi connection available, rebooting...");
        ESP.restart();
      }
      i = 0;
    }
    else
    {
      lcd.print (".");
      Serial.print(".");
      delay(1000);
    }
    i++;
  }
 
  return (w);
}
 
// FUNCTION: initialise
void setup ()
{
  int netw;
               
                Wire.begin();
                Serial.begin (9600);
 
  // Initialize LCD display
  lcd.begin (20, 4);
  lcd.init();
  lcd.clear ();
  lcd.backlight ();
 
  // Initialize leds/outputs: light off, heater off, door nothing
  pinMode (OUT_LIGHT, OUTPUT);
  digitalWrite (OUT_LIGHT,  LOW );
 
  pinMode (OUT_DOOR, OUTPUT);
  digitalWrite (OUT_DOOR, LOW);
 
  pinMode (OUT_HEATER, OUTPUT);
  digitalWrite (OUT_HEATER, LOW);
 
  pinMode (OUT_DOOR_CLOSE, OUTPUT);
  digitalWrite (OUT_DOOR_CLOSE, HIGH);
  pinMode (OUT_DOOR_OPEN, OUTPUT);
  digitalWrite (OUT_DOOR_OPEN, HIGH);
 
  // connect to Wifi, initialize Cayenne interface     
  WiFi.mode(WIFI_STA);
  netw = ConnectToWifi ();
  Cayenne.begin (username, password, clientID, ssid[netw], pass[netw]);
   
  lcd.setCursor (0,2);
  lcd.print ("Cayenne active.");
  lcd.setCursor (0,3);
  lcd.print ("IP: ");
  lcd.print (WiFi.localIP());
  Serial.print ("IP address: ");
  Serial.println (WiFi.localIP());
      
  delay (2000);
 
  // Initialize temp/humidity sensor
  pinMode (DHT_PIN, INPUT);
  dhtSensor.begin ();
 
  // Initialize a NTPClient to get time
  timeClient.begin();
 
  // put LCD display to rest
  lcd.noDisplay();
  lcd.clear ();
  lcd.noBacklight();
 
  server.on("/", HandleServerMessage);
  server.onNotFound (HandleServerNotFound);
  server.begin();
 
  UpdateAstroData ();
  eventList += currentTime + " ESP     started reboot\n";    
 
  tmpMinT = currentTime;
  tmpMaxT = currentTime;
  humMinT = currentTime;
  humMaxT = currentTime;
}
 
// FUNCTION: "while true do"
void loop ()
{
  // update environmental data (temp, hum)
  UpdateEnvData   ();
  // update astro data (date, time, sunrise/sunset, eot, ...
  UpdateAstroData ();
 
  // check light, door and heater; only if automation is turned on
  if (automaticLight == true)
  { 
    CheckLight ();
  }
  if (automaticDoor == true)
  { 
    CheckDoor ();
  }
  if (automaticHeater == true)
  { 
    CheckHeater ();
  }
  // display environmental, date/time, and astro data if in manual mode
  if (manual == true)
  {
    DisplayEnvData ();
    delay (1000);
    DisplayDateTime ();
    DisplayAstroData ();
  }
 
  // display current configuration for light, heater and door
  Serial.print ("CONFIG: L = ");
  Serial.print (lightOn);
  Serial.print (" (");
  Serial.print (automaticLight);
  Serial.print (")");
  Serial.print (", H = ");
  Serial.print (heaterOn);
  Serial.print (" (");
  Serial.print (automaticHeater);
  Serial.print (")");
  Serial.print (", D = ");
  Serial.print (doorClosed);
  Serial.print (" (");
  Serial.print (automaticDoor);
  Serial.print (")");
  Serial.print (", Manual/LCD = ");
  Serial.println (manual);
                   
  // sync with Cayenne dashboard
  Cayenne.loop ();
 
  // process server requests
  server.handleClient();
 
  delay (500);
}
 
// Default function for sending sensor data at intervals to Cayenne.
CAYENNE_IN_DEFAULT()
{
}
 
CAYENNE_IN (CAY_LIGHT)
{
  // turn light on/off, if in manual mode
 
  if (manual == true)
  {
    if (getValue.asInt() == 1)
    {
      digitalWrite (OUT_LIGHT, HIGH);
      lightOn = true;
    }
    else
    {
      digitalWrite (OUT_LIGHT, LOW);
      lightOn = false;
    }
    eventList += currentTime + " Manual  mode    switch light\n";
  }
}
 
 
CAYENNE_IN (CAY_HEATER)
{
  // turn heater on/off, if in manual mode
 
  if (manual == true)
  {
    if (getValue.asInt() == 1)
    {
      digitalWrite (OUT_HEATER, HIGH);
      heaterOn = true;
    }
    else
    {
      digitalWrite (OUT_HEATER, LOW);
      heaterOn = false;
    }
    eventList += currentTime + " Manual  mode    switch heater\n"; 
  }
}
 
CAYENNE_IN (CAY_DOOR)
{
  // open/close door, if in manual mode
 
  if (manual == true)
  {           
    if (getValue.asInt() == 1)
    {
      digitalWrite (OUT_DOOR, HIGH);  
      digitalWrite (OUT_DOOR_CLOSE, LOW);
      delay (1000);
      digitalWrite (OUT_DOOR_CLOSE, HIGH);
      doorClosed = true;
    }
    else
    {
      digitalWrite (OUT_DOOR_OPEN, LOW);
      delay (1000);
      digitalWrite (OUT_DOOR_OPEN, HIGH);
      digitalWrite (OUT_DOOR, LOW); 
      doorClosed = false;
    }
    eventList += currentTime + " Manual  mode    switch door\n";            
  }
}
 
CAYENNE_IN (CAY_MANUAL)
{
  // enable/disable manual mode, disable/enable automatic mode for door/light/heater
 
  if (getValue.asInt() == 1)
  {
    eventList += currentTime + " Manual  mode    enabled\n";
    
    automaticDoor   = false;
    automaticLight  = false;
    automaticHeater = false;
    lcd.display();
    lcd.clear ();
    lcd.backlight ();
    manual = true;
  }
  else
  {
    eventList += currentTime + " Manual  mode    disabled\n";
    
    automaticDoor   = true;
    automaticLight  = true;
    automaticHeater = true;
    lcd.noDisplay();
    lcd.clear ();
    lcd.noBacklight();
    manual = false;
  }
}
 
CAYENNE_IN (CAY_RESET)
{
  // restart if in manual mode
 
  if (manual == true)
  {
    if (getValue.asInt() == 1)
    {
      ESP.restart();
    }
  }
}
 
// You can also use functions for specific channels, e.g CAYENNE_OUT(1) for sending channel 1 data.
CAYENNE_OUT_DEFAULT ()
{
  // update every minute to avoid too much network traffic
 
  if (millis() - cayLastMillis > UPDATE_INTERVAL)
  {
    // Write data to Cayenne here
    Cayenne.virtualWrite (CAY_TEMP, temperature);
    Cayenne.virtualWrite (CAY_HUM,  humidity   );
 
    cayLastMillis = millis();
  }
}

Credits

Hans Sassenburg

Hans Sassenburg

1 project • 3 followers

Comments