Here’s the latest QR code for the project
and the latest version of the software. All the listed features, including fan failure detection, are included and functional. I had to break the code down into two separate chunks as it all can’t fit into one post.
/* Updated 5/20/2017
TERRARIUM HVAC & LIGHTING CONTROL powered by BLYNK.
Humidity & Temperature levels are sensed by an Adafruit SHT10 soil Humidity/Temp sensor, and logic is used to determine
if measured Humidity and/or Temperature parameters require adjustment.
All control commands are sent via I2C to an MCP23017 I/O port expander or PCA9685 led controller IC to save precious I/O pins on the ESP8266.
All relay control signals are held HIGH before being driven LOW to activate 4 "active LOW' relays.
Relay #1 controls the Humidifier's A/C line directly.
Relays #2 & 3 are used to toggle the direction of 12V current through a 60watt peltier device.
Relays #2 & 3 are wired in such a way that both the Peltiers positive & negative wires are on the ground side of the circuit when the relays are at rest.
a Heating or Cooling command energizes one of the two relays, passing +12V through the Peltier device in one direction for heaating and the other for cooling.
Led lighting has Sunrise/Sunset dimming capabilities controlled by a PCA9685 IC. A Slider Widget determines the Maximum "Brightness", another slider widget sets the Fade Duration
while a Timer Input Widget sets the length of the photoperiod.
Relay #4 is used to switch ON/OFF a conventional 120V light bulb or "Basking Lamp", following the same schedule as the leds.
BLYNK DASHBOARD SETUP-
"MEASURED HUMIDITY" GAUGE ON (V0) output set 0 to 100, LABEL /pin./ %
"MEASURED TEMP (F)" GAUGE ON (V1) output set 50 to 100, LABEL /pin./ *F
"DESIRED HUMIDITY" GAUGE ON (V5) output set 5 to 100, LABEL /pin./ %
"DESIRED TEMPERATURE" GAUGE ON (V3) output set 50 to 100, LABEL /pin./ *F
HUMIDITY setting STEP ON (V4) output set 5 to 100, STEP-1.0, SEND STEP- NO, LOOP VALUES= ON, ICONS +/-
TEMPERATURE setting STEP ON (V2) output set 50 to 100, STEP-1.0, SEND STEP- NO, LOOP VALUES= ON, ICONS +/-
TIMER INPUT Ch 1 ON (V13) START/STOP= YES, DAYOFWEEK= NO, SUNRISE/SUSET= YES, TIMEZONE SELECTION= NO.
TIMER INPUT Ch 2 ON (V20) START/STOP= YES, DAYOFWEEK= NO, SUNRISE/SUSET= YES, TIMEZONE SELECTION= NO.
LED MAX LEVEL Ch 1 SLIDER ON (V12) output set 0 to 100, SEND ON RELEASE= ON.
LED MAX LEVEL Ch 2 SLIDER ON (V18) output set 0 to 100, SEND ON RELEASE= ON.
LED FADE TIME Ch 1 SLIDER ON (V14) output set 0 to 180, SEND ON RELEASE= ON.
LED FADE TIME Ch 2 SLIDER ON (V19) output set 0 to 180, SEND ON RELEASE= ON.
LED CURRENT LEVEL CH 1 LABELED VALUE Display ON (V15), set to PUSH
LED CURRENT LEVEL CH 2 LABELED VALUE Display ON (V17), set to PUSH
TIME of DAY LABELED VALUE Display ON (V16), set to PUSH
LED INDICATOR WIDGETS- (V6) COLOR= blue LABEL- "HUM"
(V7) COLOR= red LABEL- "H"
(V8) COLOR= blue LABEL- "C"
(V9) COLOR= red LABEL- "M"
(V10)COLOR= geeen LABEL- "OK"
(V11)COLOR= green LABEL- "OK"
CODE FEATURES COMPLETED-
Auto save Humidity & Temperaature settings to EEPROM - DONE
WiFiManager autoconnect AP and BLYNK TOKEN (needed for login to Blynk server)- DONE
RTC- DONE
TIMER INPUT- For led & conventional lighting On/OFF period control- DONE
Read Teperature/Humidity data using a Sensirion SHT10 sensor. - DONE
Humidity/Temp Gauges & Settings step widgets- DONE
Add ESP8266 OTA code to sketch - DONE
Temperature and Humidity Relay control functions via MCP23017 port expander.- DONE
Relay control code for external A/C light - DONE
PWM LED lighting Sunrise/Sunset dimming control logic for two independent channels (PCA9685 Based)- DONE
Fan failure detection & notification - DONE.
*/
#include <FS.h> // https://github.com/tzapu/WiFiManager This Library needs to be included FIRST!
#define BLYNK_PRINT Serial // comment this out to save space
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
#include <Wire.h>
#include <Centipede.h> // Library used to control the MCP23017 port expander chip. download available here - http://macetech.com/Centipede.zip
#include <ArduinoOTA.h>
//included libraries for WiFiManager - AutoConnectWithFSParameters
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
#include <ArduinoJson.h> //https://github.com/bblanchon/ArduinoJson
#include <EEPROM.h>
//added for RTC Widget (BLYNK app)
#include <TimeLib.h>
#include <WidgetRTC.h>
//added from Sensirion library for use with the SHT10 Humidity/Temp sensor- https://github.com/spease/Sensirion
#include <Sensirion.h> // comment out the line of code below found in the sensirion.cpp file to prevent compiler issues when using the code with the Wemos D1 Mini.
// "const float D1 = -40.1; // for deg C @ 5V"
//Library used to control the PCA9685 PWM Controller IC https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
#include <Adafruit_PWMServoDriver.h>
// ALL other libraries can be found here- https://github.com/blynkkk/blynk-library/releases/tag/v0.4.6
//LED status indicator widgets
WidgetLED led1(V6); //led assigned to virtual pin V6 used for HUMIDIFIER ON/OFF indication
WidgetLED led2(V7); //led assigned to virtual pin V7 used for HEATER ON/OFF indication
WidgetLED led3(V8); //led assigned to virtual pin V8 used for COOLER ON/OFF indication
WidgetLED led4(V9); //led assigned to virtual pin V9 used for SHT1X sensor malfunction indication
WidgetLED led5(V10); //led assigned to virtual pin V10 used for TEMP IN RANGE indication
WidgetLED led6(V11); //led assigned to virtual pin V11 used for HUMIDITY IN RANGE indication
// Sensirion sensor constants and variables.
const uint8_t dataPin = D0; // SHT serial data on pin D0 of the WEMOS D1 Mini.
const uint8_t sclkPin = D3; // SHT serial clock on pin D3 of the WEMOS D1 Mini.
const uint32_t TRHSTEP = 5000UL; // Sensor query period
uint16_t rawData;
byte measActive = false;
byte measType = TEMP;
unsigned long trhMillis = 0; // Time interval tracking
Sensirion sht = Sensirion(dataPin, sclkPin);
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
WidgetRTC rtc;// REAL TIME CLOCK added to BLYNK app dashboard
Centipede CS; // From the Centipede library, it's functions are used to interact with the MCP23017 I2C I/O expander chip.
SimpleTimer timer;// From the SimpleTimer Library. it creates a timer object.
bool isFirstConnect = true;
// Humidity and Temperature variables
unsigned int desiredHum; // variable used to store the setpoint value for the desired humidity, once the measured humidity is lower than this value - the humDiff, start humidification.
int PreviousdesiredHum;// variable used to compare curent desired Humidity setting with the stored EEProm value.
int humDiff = 10; // a negative differential that's used to prevent constant humidifier relay cycling near the desired setpoint.
float humidity;// the humidity reading from the SHT10 sensor
int desiredTemp; //variable used to store the setpoint value for the desired temperture, once the measured temperture is more/less than this value (+/- the tempDiff), heating or cooling will be activated.
int PreviousdesiredTemp;// variable used to compare curent desired Temperature setting with the stored EEProm value.
int tempDiff = 1; // the +/- temperature differential.
float temp;// the temperature reading from the SHT10 sensor
// FAN failure detection variables
int fanState1;// returns either HIGH or LOW
int fanState2;// returns either HIGH or LOW
int previousfanState1;// count of all HIGH's returned from the digitalRead(). Count is reset to 0 whenever a LOW is returned.
int previousfanState2;// count of all HIGH's returned from the digitalRead(). Count is reset to 0 whenever a LOW is returned.
////Led lighting & timing variables.
long nowseconds; // time now in seconds
long startseconds0; // start time in seconds for pwmLED0
long stopseconds0; // stop time in seconds for pwmLED0
long startseconds1; // start time in seconds for pwmLED1
long stopseconds1; // stop time in seconds for pwmLED1
int fadetime0;
int fadetime1;
long fadetimemillis0; // fadetime in millis() for pwmLED0
long fadetimemillis1; // fadetime in millis() for pwmLED1
int minPWM = 1;// variable for min PWM value. Needs to be >= 1.
int maxPWM0; // variable for max PWM value attached to BLYNK Virtual pin.
int maxPWM1; // variable for max PWM value attached to BLYNK Virtual pin.
int currentFadePosition0;// don't change this!
int currentFadePosition1;// don't change this!
byte fadeIncrement = 1; //How smooth to fade? a setting of 1 uses all 12 bits (4096 steps).
unsigned long previousFadeMillis0;// millis() timing Variable, just for fading
unsigned long previousFadeMillis1;// millis() timing Variable, just for fading
int desiredledLevel0;
int desiredledLevel1;
int LedLevelNow0;
int LedLevelNow1;
long stepWaitTime0; //How long to watch the clock before incrementing each step. (time in milliseconds)
long stepWaitTime1; //How long to watch the clock before incrementing each step. (time in milliseconds)
// divide your desired dimming time duration(in millis) by the maxPWM variable value / fadeIncrement variable value to
// get the stepWaitTime variable value needed.
// EXAMPLE: (maxPWM = 4095/fadeIncrement = 1) to dim over 1 hour is == 3600000/4095/1 == stepWaitTime of 879 millis.
char blynk_token[34] = "YOUR_BLYNK_TOKEN";//added from WiFiManager - AutoConnectWithFSParameters
#define TestLED 2 // on board LED pin assignment
char Date[16];
char Time[16];
//flag for saving data
bool shouldSaveConfig = false;
//callback notifying the need to save config
void saveConfigCallback () {
Serial.println("Should save config");
shouldSaveConfig = true;
}
// All Relay Outputs correspond to PORT A pins on a MCP23017 chip at I2C address = 0x20;.
// All 4 Relay controlled loads are switched ON when MCP23017 outputs go LOW.
// Humidifier_Relay #1 = GPA3 // the pin number of the Humidifier relay. Centipede control pin #3 on the MCP23017 chip.
// Heater Relay #2 = GPA2 // the pin number of the Heater relay. Centipede control pin #2 on the MCP23017 chip.
// Cooler Relay #3 = GPA1 // the pin number of the Cooler relay. Centipede control pin #1 on the MCP23017 chip.
// Lighting Relay #4 = GPA0 // the pin number of the Lighting relay. Centipede control pin #0 on the MCP23017 chip.
// Additional control using PORT B pins on the MCP23017 chip.
// FAN CONTROL Activation Signal = GPB0 // Centipede control pin #8 on the MCP23017 chip.
// FAN CONTROL Input Tach Signal = GPB1 // Centipede control pin #9 on the MCP23017 chip.
// FAN CONTROL Input Tach Signal = GPB2 // Centipede control pin #10 on the MCP23017 chip.
// This function runs the SHT10 sensor and sends Humidity and Temperature values to gauge widgets in the BLYNK app.
// Humidity readings on (V0)
// Temperature readings on (V1)
void sendSensor() {
// Read values from the SHT10 sensor
unsigned long curMillis = millis(); // Get current time in millis
// non-blocking calls to SHT10 sensor
if (curMillis - trhMillis >= TRHSTEP) { // Time for new measurements?
measActive = true;
measType = TEMP;
sht.meas(TEMP, &rawData, NONBLOCK); // Start temp measurement
trhMillis = curMillis;
}
if (measActive && sht.measRdy()) { // Note: no error checking
if (measType == TEMP) { // Process temp or humi?
measType = HUMI;
temp = sht.calcTemp(rawData); // Convert raw sensor data
sht.meas(HUMI, &rawData, NONBLOCK); // Start humidity measurement
} else {
measActive = false;
humidity = sht.calcHumi(rawData, temp); // Convert raw sensor data
logData();
}
}
Blynk.virtualWrite(V0, humidity); // guage in BLYNK app showing "Actual Humidity" as reported by the SH10 sensor.
Blynk.virtualWrite(V1, temp); // guage in BLYNK app showing "Actual Temp" as reported by the SHR10 sensor.
}
void logData() {
Serial.print("Temperature = ");
Serial.print(temp);
Serial.println(" F ");
Serial.print("Humidity = ");
Serial.print(humidity);
Serial.println(" % ");
}
///// Humidity & Temperature step settings & Gauge Widget functions. Used to set and provide an eye appealing Desired Humidity & Temperature gauge readout.
BLYNK_WRITE(V2) {// step widget to set the Desired Temp in BLYNK app.
desiredTemp = param.asInt();
Blynk.virtualWrite(V3, desiredTemp);// Gauge widget showing desired Temp In BLYNK app.
}
BLYNK_WRITE(V4) { // step widget to set the desired Humidity in BLYNK app.
desiredHum = param.asInt();
Blynk.virtualWrite(V5, desiredHum);// Gauge widget showing desired Humidity In BLYNK app.
}
// LED lighting functions...
void setLed() {
if (currentFadePosition0 <= 1) {
stepWaitTime0 = (fadetimemillis0 / maxPWM0);
pwm.setPWM(0, 0, 0);
}
else {
stepWaitTime0 = (fadetimemillis0 / maxPWM0);
pwm.setPWM(0, 0, currentFadePosition0);
}
if (currentFadePosition1 <= 1) {
stepWaitTime1 = (fadetimemillis1 / maxPWM1);
pwm.setPWM(1, 0, 0);
}
else {
stepWaitTime1 = (fadetimemillis1 / maxPWM1);
pwm.setPWM(1, 0, currentFadePosition1);
}
Serial.print("desiredledLevel0 = ");
Serial.println(desiredledLevel0);
Serial.print("desiredledLevel1 = ");
Serial.println(desiredledLevel1);
Serial.print("stepWaitTime0 = ");
Serial.println(stepWaitTime0);
Serial.print("stepWaitTime1 = ");
Serial.println(stepWaitTime1);
Serial.print("currentFadePosition0 = ");
Serial.println(currentFadePosition0);
Serial.print("currentFadePosition1 = ");
Serial.println(currentFadePosition1);
}
// Led fading function for pwmLED0, LED channel 1.
void ledFade0(unsigned long thisMillis0) {
if (nowseconds < startseconds0) {
currentFadePosition0 = minPWM;
}
if (nowseconds > startseconds0 && nowseconds < stopseconds0) {
// is it time to start the Sunrise?
// if not, nothing happens
if (thisMillis0 - previousFadeMillis0 >= stepWaitTime0) {
currentFadePosition0 = currentFadePosition0 + fadeIncrement;
if (currentFadePosition0 >= maxPWM0) {
// At max limit stop the fade
currentFadePosition0 = maxPWM0;
}
// put actionable () here.
// reset millis for the next iteration (fade timer only)
previousFadeMillis0 = thisMillis0;
}
}
if (nowseconds > stopseconds0) {
// is it time to start the Sunset yet?
// if not, nothing happens
if (thisMillis0 - previousFadeMillis0 >= stepWaitTime0) {
currentFadePosition0 = currentFadePosition0 - fadeIncrement;
if (currentFadePosition0 <= minPWM) {
// At min limit stop the fade
currentFadePosition0 = minPWM;
}
// put actionable () here
// reset millis for the next iteration (fade timer only)
previousFadeMillis0 = thisMillis0;
}
}
}
// Led fading function for pwmLED1, LED channnel 2.
void ledFade1(unsigned long thisMillis1) {
if (nowseconds < startseconds1) {
currentFadePosition1 = minPWM;
}
if (nowseconds > startseconds1 && nowseconds < stopseconds1) {
// is it time to start the Sunrise?
// if not, nothing happens
if (thisMillis1 - previousFadeMillis1 >= stepWaitTime1) {
currentFadePosition1 = currentFadePosition1 + fadeIncrement;
if (currentFadePosition1 >= maxPWM1) {
// At max limit stop the fade
currentFadePosition1 = maxPWM1;
}
// put actionable () here.
// reset millis for the next iteration (fade timer only)
previousFadeMillis1 = thisMillis1;
}
}
if (nowseconds > stopseconds1) {
// is it time to start the Sunset yet?
// if not, nothing happens
if (thisMillis1 - previousFadeMillis1 >= stepWaitTime1) {
currentFadePosition1 = currentFadePosition1 - fadeIncrement;
if (currentFadePosition1 <= minPWM) {
// At min limit stop the fade
currentFadePosition1 = minPWM;
}
// put actionable () here
// reset millis for the next iteration (fade timer only)
previousFadeMillis1 = thisMillis1;
}
}
}
// Digital clock display of the time
void clockDisplay()
{
// You can call hour(), minute(), ... at any time
// Please see Time library examples for details
String currentDate = String(month()) + " " + day() + " " + year();
// You can call hour(), minute(), ... at any time
// Please see Time library examples for details
if (minute() < 10 && second() < 10) {
String currentTime = String(hour()) + ":0" + minute() + ":0" + second();// adds leading 0 to minutes and seconds.
Blynk.virtualWrite(V16, currentTime);
}
if (minute() < 10 && second() > 9 ) {
String currentTime = String(hour()) + ":0" + minute() + ":" + second();// adds leading 0 to minutes only.
Blynk.virtualWrite(V16, currentTime);
}
if (minute() > 9 && second() < 10) {
String currentTime = String(hour()) + ":" + minute() + ":0" + second();// adds leading 0 to seconds only.
Blynk.virtualWrite(V16, currentTime);
}
if (minute() >= 10 && second() >= 10) {
String currentTime = String(hour()) + ":" + minute() + ":" + second();// no leading 0's added.
Blynk.virtualWrite(V16, currentTime);
}
nowseconds = ((hour() * 3600) + (minute() * 60) + second());
Serial.print("Nowseconds =");
Serial.println(nowseconds);
// Send curent time of day in seconds to the App.
Blynk.virtualWrite(V15, LedLevelNow0);// shows current led intensity pecentage 0 - 100%.
LedLevelNow0 = map(currentFadePosition0, 1, 4095, 0, 100);
Blynk.virtualWrite(V17, LedLevelNow1);// shows current led intensity pecentage 0 - 100%.
LedLevelNow1 = map(currentFadePosition1, 1, 4095, 0, 100);
}
BLYNK_WRITE(V12) {// slider widget to set the maximum led level from the Blynk App.
desiredledLevel0 = param.asInt();
maxPWM0 = map(desiredledLevel0, 0, 100, minPWM, 4095);
}
BLYNK_WRITE(V18) {// slider widget to set the maximum led level from the Blynk App.
desiredledLevel1 = param.asInt();
maxPWM1 = map(desiredledLevel1, 0, 100, minPWM, 4095);
}
BLYNK_WRITE(V14) {// slider widget to set the led fade duration up tp 3 hours.
fadetime0 = param.asInt();
fadetimemillis0 = map(fadetime0, 0, 180, 1, 10800000);// 3 hour fade duration is max
}
BLYNK_WRITE(V19) {// slider widget to set the led fade duration up tp 3 hours.
fadetime1 = param.asInt();
fadetimemillis1 = map(fadetime1, 0, 180, 1, 10800000);// 3 hour fade duration is max
}
//Humidifier control functions- Switches Relay#1 ON/OFF to control A/C powered Humidifier.
void determineHumidifierOnOff()
{
/// logic used to determine whether or not relative humidity should be raised.
if (humidity > 1 && humidity < desiredHum - humDiff )// This function looks at the humidity level and subtracts the differential (humDiff) and switches the humidifier on if the prpoer conditions are met. humDiff = 5 points under desired Humidity level.
{ // HUMIDIFIER ON
CS.digitalWrite(3, LOW);//Humidifier Relay ON. Pin# assigment corresponds to MCP23017 I/O PORT A register #'s
Serial.println("HUMIDIFIER ON");
led1.on();//HUMIDIFIER INDICATOR ON
led4.off();//MALFUNCTION INDICATOR OFF
led6.off();//DESIRED RANGE INDICATION OFF
}
if (humidity < 1) // this function stops the humidifier if a non valid reading is received from the SHT1X sensor.
{ // HUMIDIFIER OFF
CS.digitalWrite(3, HIGH);//Humidifier Relay OFF. Pin# assigment corresponds to MCP23017 I/O PORT A register #'s
Serial.println("SHT10 Sensor Malfunction- HUMIDIFIER operation terminated");
led1.off();////HUMIDIFIER INDICATOR OFF
led4.on();//MALFUNCTION INDICATOR ON
led6.off();//DESIRED RANGE INDICATION OFF
Blynk.notify("TERRA HVAC Controller: SENSOR Malfuction");
}
if (humidity >= desiredHum)// this function stops the humidifier if the measured humidity is in the desired range.
{ // HUMIDIFIER OFF
CS.digitalWrite(3, HIGH);//Hunidifier Relay OFF. Pin# assigment corresponds to MCP23017 I/O PORT A register #'s
Serial.println("HUMIDIFIER OFF");
led1.off();//HUMIDIFIER INDICATOR OFF
led4.off();//MALFUNCTION INDICATOR OFF
led6.on();//DESIRED RANGE INDICATION ON
}
if (humidity >= desiredHum - humDiff)
{
led6.on();//DESIRED RANGE INDICATION ON
}
}
// Temperature Control function used to switch Heating/Cooling on/off by toggling the direction of current
// through a 60 watt Peltier device. The fans used to provide heating or cooling airflow are activated through a separate
// circuit, anytime current is flowing through the Peltier device.
void determineHeatorCool()
{
/// logic used to determine whether or not heating or cooling is needed. Relay #2 = HEATER, Relay #3 = COOLER.
if (temp < 6)// an unplugged sensor reads a constant 5 degrees.
{ // HEATER/COOLER OFF This function stops Heating/Cooling if a non valid value is received from the SHT10 sensor.
CS.digitalWrite(2, HIGH);//Heater Relay OFF. Pin# assigment corresponds to MCP23017 I/O PORT A&B register #'s
CS.digitalWrite(1, HIGH);//Cooler Relay OFF
CS.digitalWrite(8, LOW);//FAN CONTROLLER OFF
Serial.println("SHT10 Sensor Malfunction- HEATING/COOLING operation terminated");
led2.off();//HEATING INDICATOR OFF
led3.off();//COOLING INDICATOR OFF
led4.on();//MALFUNCTION INDICATOR ON
led5.off();//TEMP IN RANGE OFF
Blynk.notify("TERRA HVAC Controller: SENSOR Malfuction");
}
if (temp > 10 && temp < desiredTemp - tempDiff)
{ // HEATER ON / COOLER OFF
CS.digitalWrite(2, LOW);//Heater Relay ON. Pin# assigment corresponds to MCP23017 I/O PORT A&B register #'s
CS.digitalWrite(1, HIGH);//Cooler Relay OFF
CS.digitalWrite(8, HIGH);//FAN CONTROLLLER ON
Serial.println("HEATING");
led2.on();//HEATING INDICATOR ON
led3.off();//COOLING INDICATOR OFF
led4.off();//MALFUNCTION INDICATOR OFF
led5.off();//TEMP IN RANGE OFF
checkFanState();// Function checks for fan failure and send a notification to the Blynk App.
}
if (temp > desiredTemp + tempDiff )
{ // HEATER OFF/ COOLER ON
CS.digitalWrite(2, HIGH);//Heater Relay OFF. Pin# assigment corresponds to MCP23017 I/O PORT A register #'s
CS.digitalWrite(1, LOW);//Cooler Relay ON
CS.digitalWrite(8, HIGH);//FAN CONTROLLER ON
Serial.println("COOLING");
led2.off();//HEATING INDICATOR OFF
led3.on();//COOLING INDICATOR ON
led4.off();//MALFUNCTION INDICATOR OFF
led5.off();//TEMP IN RANGE OFF
checkFanState();// Function checks for fan failure and send a notification to the Blynk App.
}
if (temp > desiredTemp - tempDiff && temp < desiredTemp + tempDiff)
{ // HEATER OFF/ COOLER OFF.... TEMP IN DESIRED RANGE.
CS.digitalWrite(2, HIGH);//Heater Relay OFF. Pin# assigment corresponds to MCP23017 I/O PORT A&B register #'s
CS.digitalWrite(1, HIGH);//Cooler Relay OFF
CS.digitalWrite(8, LOW);//FAN CONTROLLER OFF
Serial.println("TEMP = DESIRED RANGE");
led2.off();//HEATING INDICATOR OFF
led3.off();//COOLING INDICATOR OFF
led4.off();//MALFUNCTION INDICATOR OFF
led5.on();//TEMP IN RANGE ON
}
}
void LightsOn()// relay #4 tied to (GPA I/Opin 0).
{
CS.digitalWrite(0, LOW);//LIGHT Relay ON
}
void LightsOff()// relay #4 tied to (GPA I/Opin 0).
{
CS.digitalWrite(0, HIGH);//LIGHT Relay OFF
}
void checkFanState() {
fanState1 = CS.digitalRead(9);// digitalRead() will toggle between 0 and 1, depending on the reading frequency of the function & the RPM of the fan.
fanState2 = CS.digitalRead(10);// 0 or LOW returned = Fans are ON. A continuously returned 1 or HIGH indicates that the fan is NOT rotating.
previousfanState1 = previousfanState1 + fanState1;// creates an counter that increments by 1 for each digitalRead() that returns HIGH.
previousfanState2 = previousfanState2 + fanState2;// creates an counter that increments by 1 for each digitalRead() that returns HIGH.
if (fanState1 < 1 ) {// if a LOW is returned....
previousfanState1 = 0;// reset the HIGH count to 0
Serial.print("FAN1 ON");// Normal Fan operation
Serial.println();
}
if (previousfanState1 > 10){// if a HIGH is returned more than 10 times in a row...we're assuming there's a problem.
Serial.print("FAN1 MALFUNCTION");
Serial.println();
Blynk.notify("FAN1 MALFUNCTION");
}
else{
Serial.println(previousfanState1);
}
if (fanState2 < 1 ) {// if a LOW is returned....
previousfanState2 = 0;// reset the HIGH count to 0
Serial.print("FAN2 ON");// Normal Fan operation
Serial.println();
}
if (previousfanState2 > 10){// if a HIGH is returned more than 10 times in a row...we're assuming there's a problem.
Serial.print("FAN2 MALFUNCTION");
Serial.println();
Blynk.notify("FAN2 MALFUNCTION");
}
else{
Serial.println(previousfanState2);
}
}
void GetPresets() {// Pre-set Humidity/Temperature values are stored in ESP8266 memory.
if (desiredTemp != PreviousdesiredTemp) { //update the EEPROM if desired temperature has changed.
EEPROM.write(1, desiredTemp);
EEPROM.commit();
Serial.print(F("New desired temperature saved: "));
Serial.println(desiredTemp);
PreviousdesiredTemp = desiredTemp;
}
desiredTemp = EEPROM.read(1);
if ((desiredTemp < 50) || (desiredTemp > 100)) {
desiredTemp = 75;
Serial.println(F("No saved temperature setting."));
}
if (desiredHum != PreviousdesiredHum) { //update the EEPROM if desired temperature has changed.
EEPROM.write(2, desiredHum);
EEPROM.commit();
Serial.print(F("New desired humidity level saved: "));
Serial.println(desiredHum);
PreviousdesiredHum = desiredHum;
}
desiredHum = EEPROM.read(2);
if ((desiredHum < 0) || (desiredHum > 100)) {
desiredHum = 50;
Serial.println(F("No saved humidity setting."));
}
}
void activetoday() { // check if schedule should run today
if (year() != 1970) {
Blynk.syncVirtual(V13); // sync timeinput widget
}
}
BLYNK_WRITE(V13) {
sprintf(Date, "%02d/%02d/%04d", day(), month(), year());
sprintf(Time, "%02d:%02d:%02d", hour(), minute(), second());
TimeInputParam t(param);
Serial.print("Checked schedule at: ");
Serial.println(Time);
int dayadjustment = -1;
if (weekday() == 1) {
dayadjustment = 6; // needed for Sunday, Time library is day 1 and Blynk is day 7
}
if (t.isWeekdaySelected((weekday() + dayadjustment))) { //Time library starts week on Sunday, Blynk on Monday
Serial.println("Schedule ACTIVE today");
if (t.hasStartTime()) // Process start time
{
Serial.println(String("Start: ") + t.getStartHour() + ":" + t.getStartMinute());
}
if (t.hasStopTime()) // Process stop time
{
Serial.println(String("Stop : ") + t.getStopHour() + ":" + t.getStopMinute());
}
// Display timezone details, for information purposes only
Serial.println(String("Time zone: ") + t.getTZ()); // Timezone is already added to start/stop time
Serial.println(String("Time zone offset: ") + t.getTZ_Offset()); // Get timezone offset (in seconds)
for (int i = 1; i <= 7; i++) { // Process weekdays (1. Mon, 2. Tue, 3. Wed, ...)
if (t.isWeekdaySelected(i)) {
Serial.println(String("Day ") + i + " is selected");
}
}
nowseconds = ((hour() * 3600) + (minute() * 60) + second());
startseconds0 = (t.getStartHour() * 3600) + (t.getStartMinute() * 60);
//Serial.println(startsecondswd); // used for debugging
if (nowseconds >= startseconds0) {
Serial.print("LIGHTS ON");
Serial.println(String(" ") + t.getStartHour() + ":" + t.getStartMinute());
if (nowseconds <= startseconds0 + 90) { // 90s on 60s timer ensures 1 trigger command is sent
digitalWrite(TestLED, LOW); // set LED ON
// code here to switch the leds & Light ON
LightsOn();
}
}
else {
Serial.println("LIGHTS OFF");
// nothing more to do here, waiting for motor to be turned on later today
}
stopseconds0 = (t.getStopHour() * 3600) + (t.getStopMinute() * 60);
//Serial.println(stopsecondswd); // used for debugging
if (nowseconds >= stopseconds0) {
Serial.print("LEDs STOPPED at");
Serial.println(String(" ") + t.getStopHour() + ":" + t.getStopMinute());
if (nowseconds <= stopseconds0 + 90) { // 90s on 60s timer ensures 1 trigger command is sent
digitalWrite(TestLED, HIGH); // set LED OFF
// code here to switch the leds & Light OFF
LightsOff();
}
}
else {
if (nowseconds >= startseconds0) { // only show if motor has already started today
Serial.println("LIGHTS ON");
// nothing more to do here, waiting for motor to be turned off later today
}
}
}
else {
Serial.println("LIGHTS OFF");
// nothing to do today, check again in 1 minutes time
}
Serial.println();
}
BLYNK_WRITE(V20) {
TimeInputParam t(param);
Serial.print("Checked schedule at: ");
Serial.println(Time);
int dayadjustment = -1;
if (weekday() == 1) {
dayadjustment = 6; // needed for Sunday, Time library is day 1 and Blynk is day 7
}
if (t.isWeekdaySelected((weekday() + dayadjustment))) { //Time library starts week on Sunday, Blynk on Monday
Serial.println("Schedule ACTIVE today");
nowseconds = ((hour() * 3600) + (minute() * 60) + second());
startseconds1 = (t.getStartHour() * 3600) + (t.getStartMinute() * 60);
if (nowseconds >= startseconds1) {
if (nowseconds <= startseconds1 + 90) { // 90s on 60s timer ensures 1 trigger command is sent
// code here
}
}
else {
Serial.println("Relay not on");// nothing more to do here, waiting for relay to be turned on later today
}
stopseconds1 = (t.getStopHour() * 3600) + (t.getStopMinute() * 60);
if (nowseconds >= stopseconds1) {
// 90s on 60s timer ensures 1 trigger command is sent
if (nowseconds <= stopseconds1 + 90) {
// code here
}
}
else {
if (nowseconds >= startseconds1) { // only show if motor has already started today
Serial.println("Relay is still ON");
// nothing more to do here, waiting for motor to be turned off later today
}
}
}
else {
Serial.println("Schedule INACTIVE today");
// nothing to do today, check again in 1 minutes time
}
Serial.println();
}
void reconnectBlynk() {
if (!Blynk.connected()) {
if (Blynk.connect()) {
BLYNK_LOG("Reconnected");
} else {
BLYNK_LOG("Not reconnected");
}
}
}