// V.1.4
// Board : ESP32 dev module
#include <WiFi.h>
#include <FirebaseESP32.h> // Firebase ESP32 library
#include <Adafruit_SHT4x.h>
#include <SparkFun_SCD4x_Arduino_Library.h>
#include <RTClib.h>
const char* ssid = "SSID"; // your network SSID (name)
const char* pass = "PASSWORD"; // your network password
const char* host = "your-project-id.firebaseio.com"; // Your Firebase project ID
const char* databaseSecret = "your-database-secret"; // Your Firebase database secret
unsigned long myChannelID = 123456; // replace 123456 with your channel ID [separate for each board]
const char* myWriteAPIKey = "APIKEY"; // replace APIKEY with your channel write API Key
FirebaseData firebaseData;
WiFiClient client;
Adafruit_SHT4x sht4 = Adafruit_SHT4x();
SCD4x scd4;
RTC_DS3231 rtc;
// Pinouts
#define fanPin 19
#define ledPin 18
#define heaterPin 14
#define foggerPin 13
#define floatSW 32
#define boot 0
/* ------USER CONTROL VARIABLES------ */
// set Temperature threshold, beyond which Heater turns on/off
uint8_t setTemp = 25;
// set Humidity threshold, beyond which Fogger turns on/off
uint8_t setHum = 80;
// LED turn on time [6PM = 18*60 = 1080]
uint16_t ledOnTime = 1080;
// LED turn off time [6AM = 6*60 = 360]
uint16_t ledOffTime = 360;
// LED brightness
uint8_t brightness = 0;
// set the range value for Co2 level
uint16_t range = 500;
// variable to perform forced recalibration
bool calibrate = false;
// reference CO2 measurement
uint16_t concentration = 430;
/* ------ADMIN CONTROL VARIABLES------ */
// define fan Max speed, 255 = 100%
uint8_t maxFanPWM = 200;
// define fan Min speed, 0 = 0%
uint8_t minFanPWM = 100;
// fogger on time, 2 sec
uint8_t foggerOnTime = 2;
// fogger off time, 3 sec
uint8_t foggerOffTime = 3;
/* ------OTHER VARIABLES------ */
// select whether the fan will be always on or not.
bool alwaysOn = false;
uint16_t timeNow = 0, co2 = 0;
uint8_t tempF = 0, hum = 0;
bool light = 0, fogger = 0;
uint8_t count = 0, count2 = 0;
const int fanfreq = 5000;
const int fanPwmChannel = 0;
const int ledfreq = 5000;
const int ledPwmChannel = 4;
const int resolution = 8;
unsigned long timer = 0;
void setup() {
Serial.begin(115200);
// Connect to WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, pass);
int num = 0;
while (WiFi.status() != WL_CONNECTED) {
num++;
if (num > 10) ESP.restart();
Serial.print(".");
delay(500);
}
Serial.println("\nConnected.");
Firebase.begin(host, databaseSecret); // Initialize Firebase
if (!sht4.begin()) {
Serial.println("Couldn't find SHT4x");
while (1) delay(10);
}
shtSettings();
//scd4.enableDebugging(); // Uncomment this line to get helpful debug messages on Serial
//.begin has three boolean parameters:
// measBegin: set to true to begin periodic measurements automatically;
// set to false to leave periodic measurements disabled.
// Default is true.
// autoCalibrate: set to true to leave automatic calibration enabled;
// set to false to disable automatic calibration.
// Default is true.
// skipStopPeriodicMeasurements: set to true to make .begin skip the initial call of stopPeriodicMeasurement;
// set to false to make .begin stop periodic measurements before doing anything else.
// Default is false.
//Here, we call .begin and set autoCalibrate to false to disable automatic calibration
if (scd4.begin(true, false) == false) {
//measBegin____/ /
//autoCalibrate_____/
Serial.println(F("Couldn't find SCD4x"));
while (1) delay(10);
}
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1) delay(10);
}
if (rtc.lostPower()) {
Serial.println("RTC lost power, let's set the time!");
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
//rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
pinMode(fanPin, OUTPUT);
pinMode(heaterPin, OUTPUT);
pinMode(foggerPin, OUTPUT);
pinMode(floatSW, INPUT_PULLUP);
pinMode(boot, INPUT_PULLUP);
ledcSetup(fanPwmChannel, fanfreq, resolution);
ledcAttachPin(fanPin, fanPwmChannel);
ledcSetup(ledPwmChannel, ledfreq, resolution);
ledcAttachPin(ledPin, ledPwmChannel);
if (alwaysOn)
ledcWrite(fanPwmChannel, maxFanPWM); // turn on the fan at defined speed
else
ledcWrite(fanPwmChannel, 0);
Serial.println("Setup Finished");
}
void loop() {
if (millis() - timer >= 1000) {
timer = millis();
count += 1;
// get time
DateTime now = rtc.now();
Serial.print("Time = ");
Serial.print(now.hour());
Serial.print(" : ");
Serial.println(now.minute());
timeNow = (now.hour() * 60) + now.minute();
Serial.println(timeNow);
// get temp and hum
sensors_event_t humidity, temp;
sht4.getEvent(&humidity, &temp);
//tempC = temp.temperature;
tempF = (temp.temperature * 9 / 5) + 32;
hum = humidity.relative_humidity;
Serial.print("Temperature: ");
Serial.print(tempF);
Serial.println(" °F ");
Serial.print("Humidity: ");
Serial.print(hum);
Serial.println("%");
// get CO2 readings
if (scd4.readMeasurement()) {
co2 = scd4.getCO2();
Serial.print(F("CO2(ppm): "));
Serial.println(co2);
}
if (!digitalRead(floatSW))
Serial.println("No water");
else
Serial.println("Has water");
if (fogger) {
count2 += 1;
if (count2 <= foggerOnTime) {
digitalWrite(foggerPin, 1);
Serial.println("Fogger ON");
}
if (count2 > foggerOnTime && count2 <= foggerOffTime + foggerOnTime) {
digitalWrite(foggerPin, 0);
Serial.println("Fogger OFF");
}
if (count2 > foggerOffTime + foggerOnTime) {
count2 = 0;
Serial.println("Reset fogger counter");
}
}
// update graph every 15 sec
if (count >= 15) {
count = 0;
Serial.print("Channel update ");
// set the fields with the values
// Firebase doesn't use field numbers, so use appropriate keys
Firebase.setFloat(firebaseData, "Temperature", tempF);
Firebase.setInt(firebaseData, "Humidity", hum);
Firebase.setInt(firebaseData, "CO2", co2);
Firebase.setBool(firebaseData, "Light", light);
if (Firebase.push(firebaseData, "/")) {
Serial.println("successful.");
} else {
Serial.println("failed.");
Serial.println("Reason: " + firebaseData.errorReason());
}
}
}
// when temperature is less than defined temperature
if (tempF < setTemp) {
// turn on the heater
digitalWrite(heaterPin, 1);
}
// when temperature is greater than defined temperature
if (tempF > setTemp) {
// turn off the heater
digitalWrite(heaterPin, 0);
}
// when humidity is less than defined humidity
if (hum < setHum) {
// turn on the fogger if there is water
if (!digitalRead(floatSW)) {
fogger = false;
digitalWrite(foggerPin, 0);
} else {
fogger = true;
}
}
// when humidity is greater than defined humidity
if (hum > setHum) {
// turn off the fogger
fogger = false;
digitalWrite(foggerPin, 0);
}
// If data hits the low value for CO2
if (co2 < range) {
// fan go to the lowest PWM value
ledcWrite(fanPwmChannel, minFanPWM);
//Serial.print(F("Fan Speed: "));
//Serial.println(minFanPWM);
}
// If data hits the high value
if (co2 > range) {
// fans go to max speed
ledcWrite(fanPwmChannel, maxFanPWM);
//Serial.print(F("Fan Speed: "));
//Serial.println(maxFanPWM);
}
/***********************/
// Enter brightness value [range 0-255] on the serial monitor
if (Serial.available() > 0) {
brightness = Serial.read();
}
/***********************/
if (ledOnTime > ledOffTime) {
if (timeNow >= ledOnTime) {
// turn on the LED at defined time
ledcWrite(ledPwmChannel, brightness);
light = 1;
}
if (timeNow <= ledOffTime) {
// turn off the LED
ledcWrite(ledPwmChannel, 0);
light = 0;
}
}
else {
if (timeNow >= ledOnTime && timeNow <= ledOffTime) {
// turn on the LED at defined time
ledcWrite(ledPwmChannel, brightness);
light = 1;
}
if (timeNow >= ledOffTime) {
// turn off the LED
ledcWrite(ledPwmChannel, 0);
light = 0;
}
}
// forced recalibration
// To successfully conduct an accurate forced recalibration,
// Operate the SCD4x in normal sensor operation for > 3 minutes
// in an environment with homogeneous and constant CO2 concentration.
if (!digitalRead(boot) || calibrate) {
Serial.println(F("perform Forced Recalibration"));
scd4.stopPeriodicMeasurement();
delay(500);
Serial.println(scd4.performForcedRecalibration(concentration));
delay(400);
scd4.startPeriodicMeasurement();
calibrate = false;
}
}
void shtSettings() {
Serial.println("Found SHT4x sensor");
Serial.print("Serial number 0x");
Serial.println(sht4.readSerial(), HEX);
// You can have 3 different precisions,
// higher precision takes longer
sht4.setPrecision(SHT4X_HIGH_PRECISION);
switch (sht4.getPrecision()) {
case SHT4X_HIGH_PRECISION:
Serial.println("High precision");
break;
case SHT4X_MED_PRECISION:
Serial.println("Mid precision");
break;
case SHT4X_LOW_PRECISION:
Serial.println("Low precision");
break;
}
// You can have 6 different heater settings
// higher heat and longer times use more power
// and reads will take longer too!
sht4.setHeater(SHT4X_NO_HEATER);
switch (sht4.getHeater()) {
case SHT4X_NO_HEATER:
Serial.println("No heater");
break;
case SHT4X_HIGH_HEATER_1S:
Serial.println("High heat for 1 second");
break;
case SHT4X_HIGH_HEATER_100MS:
Serial.println("High heat for 0.1 second");
break;
case SHT4X_MED_HEATER_1S:
Serial.println("Medium heat for 1 second");
break;
case SHT4X_MED_HEATER_100MS:
Serial.println("Medium heat for 0.1 second");
break;
case SHT4X_LOW_HEATER_1S:
Serial.println("Low heat for 1 second");
break;
case SHT4X_LOW_HEATER_100MS:
Serial.println("Low heat for 0.1 second");
break;
}
}