#include <BH1750.h>
#include <Adafruit_HDC1000.h>
#include <U8g2lib.h>
#include <EEPROM.h>
#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
#include <OneWire.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);
const int NextButton = 25;
const int BackButton = 24; // Pin for the "Back" button
int lastBackButtonState = HIGH; // Declare and initialize lastBackButtonState
// Define the sensor objects
Adafruit_HDC1000 hdc1080;
BH1750 lightMeter;
#define ph_Pin A0 //pH meter Analog output to Arduino Analog Input 0
#define TdsSensorPin A1
int WaterTemp_sensor = 22;
OneWire ds(WaterTemp_sensor);
const int MoistureLevelPin1 = A2; // Analog pin for the water level sensor
const int MoistureLevelPin2 = A3;
const int MoistureLevelPin3 = A4;
const int MoistureLevelPin4 = A5;
const int MoistureLevelPin5 = A6;
const int MoistureLevelPin6 = A7;
int SoilMoist1;
int SoilMoist2;
int SoilMoist3;
int SoilMoist4;
int SoilMoist5;
int SoilMoist6;
float SoilMoistAverage;
String PumpStatus;
String ShadeStatus;
String FanStatus;
float WaterTemp;
float TDS;
float EC;
float temperature;
float humidity;
float PPFD;
float PH;
float calibration_value = 21.2;
unsigned long int avgValue; //Store the average value of the sensor feedback
int buf[10], temp;
#define VREF 4.9 // analog reference voltage(Volt) of the ADC
#define SCOUNT 30 // sum of sample point
int analogBuffer[SCOUNT]; // store the analog value in the array, read from ADC
int analogBufferTemp[SCOUNT];
int analogBufferIndex = 0, copyIndex = 0;
float averageVoltage = 0, tdsValue = 0;
#define BLYNK_TEMPLATE_ID "TMPL6nbINoFLa"
#define BLYNK_TEMPLATE_NAME "SmartField Co"
#define BLYNK_AUTH_TOKEN "VLzoDUg8OgnDUuK6se_YmTFxkOiVh3mF"
#include <ESP8266_Lib.h>
/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial
#include <BlynkSimpleShieldEsp8266.h>
char auth[] = "VLzoDUg8OgnDUuK6se_YmTFxkOiVh3mF";
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "Coline";
char pass[] = "12345678";
// Hardware Serial on Mega, Leonardo, Micro...
#define EspSerial Serial1
// Your ESP8266 baud rate:
#define ESP8266_BAUD 115200
ESP8266 wifi(&EspSerial);
BlynkTimer timer;
unsigned long lastConnectionAttempt = 0;
const unsigned long connectionInterval = 900000; // Reconnect every 15 minutes
bool isEspConnected;
//display
static const unsigned char image_Layer_18_bits[] U8X8_PROGMEM = { 0x10, 0x10, 0x38, 0x7c, 0x7c, 0x78, 0x7f, 0xff, 0xf8, 0xe0, 0x80 };
static const unsigned char image_Layer_19_bits[] U8X8_PROGMEM = { 0x10, 0x10, 0x38, 0x7c, 0x7c, 0x78, 0x7f, 0xff, 0xf8, 0xe0, 0x80 };
static const unsigned char image_display_brightness_bits[] U8X8_PROGMEM = { 0x80, 0x00, 0x84, 0x10, 0x08, 0x08, 0xc0, 0x01, 0x31, 0x46, 0x12, 0x24, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x12, 0x24, 0x31, 0x46, 0xc0, 0x01, 0x08, 0x08, 0x84, 0x10, 0x80, 0x00, 0x00, 0x00 };
static const unsigned char image_weather_temperature_bits[] U8X8_PROGMEM = { 0x38, 0x00, 0x44, 0x40, 0xd4, 0xa0, 0x54, 0x40, 0xd4, 0x1c, 0x54, 0x06, 0xd4, 0x02, 0x54, 0x02, 0x54, 0x06, 0x92, 0x1c, 0x39, 0x01, 0x75, 0x01, 0x7d, 0x01, 0x39, 0x01, 0x82, 0x00, 0x7c, 0x00 };
static const unsigned char image_weather_wind_bits[] U8X8_PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xc0, 0x11, 0x20, 0x22, 0x20, 0x22, 0x00, 0x22, 0x00, 0x11, 0xff, 0x4c, 0x00, 0x00, 0xb5, 0x41, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x80, 0x04, 0x00, 0x03 };
static const unsigned char image_weather_sun_bits[] U8X8_PROGMEM = { 0x80, 0x00, 0x84, 0x10, 0x08, 0x08, 0xc0, 0x01, 0x31, 0x46, 0x12, 0x24, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x12, 0x24, 0x31, 0x46, 0xc0, 0x01, 0x08, 0x08, 0x84, 0x10, 0x80, 0x00, 0x00, 0x00 };
static const unsigned char image_weather_humidity_bits[] U8X8_PROGMEM = { 0x20, 0x00, 0x20, 0x00, 0x30, 0x00, 0x70, 0x00, 0x78, 0x00, 0xf8, 0x00, 0xfc, 0x01, 0xfc, 0x01, 0x7e, 0x03, 0xfe, 0x02, 0xff, 0x06, 0xff, 0x07, 0xfe, 0x03, 0xfe, 0x03, 0xfc, 0x01, 0xf0, 0x00 };
static const unsigned char image_earth_bits[] U8X8_PROGMEM = { 0xe0, 0x03, 0x78, 0x0e, 0xe4, 0x1f, 0x86, 0x27, 0xc2, 0x27, 0xe1, 0x53, 0xf9, 0x6f, 0xfb, 0x41, 0xfb, 0x41, 0xc7, 0x43, 0x86, 0x2f, 0x0e, 0x2f, 0x8c, 0x1f, 0xd8, 0x0f, 0xe0, 0x03, 0x00, 0x00 };
static const unsigned char image_Clock_bits[] U8X8_PROGMEM = { 0xc0, 0x0f, 0x00, 0xf0, 0x3f, 0x00, 0xf8, 0x7f, 0x00, 0x1c, 0xe0, 0x00, 0xbe, 0xf7, 0x01, 0xbe, 0xf7, 0x01, 0xbf, 0xf7, 0x03, 0x7f, 0xfb, 0x03, 0xff, 0xfc, 0x03, 0xff, 0xfc, 0x03, 0x7f, 0xf9, 0x03, 0xbf, 0xf2, 0x03, 0x3e, 0xf5, 0x01, 0xbe, 0xf2, 0x01, 0x1c, 0xe0, 0x00, 0xf8, 0x7f, 0x00, 0xf0, 0x3f, 0x00, 0xc0, 0x0f, 0x00 };
static const unsigned char image_Voltage_bits[] U8X8_PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x80, 0x01, 0xc0, 0x01, 0xe0, 0x00, 0xf0, 0x07, 0x80, 0x03, 0xc0, 0x01, 0xc0, 0x00, 0x60, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const unsigned char image_menu_settings_gear_bits[] U8X8_PROGMEM = { 0xc0, 0x03, 0x48, 0x12, 0x34, 0x2c, 0x02, 0x40, 0xc4, 0x23, 0x24, 0x24, 0x13, 0xc8, 0x11, 0x88, 0x11, 0x88, 0x13, 0xc8, 0x24, 0x24, 0xc4, 0x23, 0x02, 0x40, 0x34, 0x2c, 0x48, 0x12, 0xc0, 0x03 };
// images from https://lopaka.app/
bool loadingComplete = false;
int progress = 0; // progress of the progressbar
char buffer[32]; // helper buffer to construct a string to be displayed
enum State {
LIGHT_VALUE,
AMB_TEMP,
AMB_HUM,
PH_LVL,
EC_LVL,
TDS_LVL,
SOIL_MOIST,
ACT_STAT
};
State currentState = LIGHT_VALUE;
int buttonState = HIGH;
int lastButtonState = HIGH;
int PumpSwitch = 26;
int FanSwitch = 27;
#define ShadeNetSwitch 28
#define LimitSwitch1 30
#define LimitSwitch2 29
int RelayFan1 = 31;
int RelayFan2 = 32;
int RelayPump = 35;
#define EN2 6
#define INA2 7
#define INB2 8
#define PWM2 9
#define EN4 42
#define INA4 43
#define INB4 44
#define PWM4 45
bool isMotorRunning = false;
bool isLimitSwitch1Clicked = false;
bool isLimitSwitch2Clicked = false;
int ShadeNetSwitch_State;
bool isPumpRunning = false;
bool isFanAutomated = true;
bool isFanRunning = false;
bool isPumpAutomated = true;
bool isNetAutomated = true;
int FanSwitch_Iot = 1;
int PumpSwitch_Iot = 1;
int ShadeNetSwitch_Iot = 1;
int FanSwitch_State;
int PumpSwitch_State;
void TCA9548A(uint8_t bus) {
Wire.beginTransmission(0x70); // TCA9548A address is 0x70
Wire.write(1 << bus); // send byte to select bus
Wire.endTransmission();
}
void connectToWiFi()
{
// Configure Blynk with Auth Token
Blynk.config(wifi, BLYNK_AUTH_TOKEN, "sgp1.blynk.cloud", 80);
// Set up WiFi connection
Blynk.connectWiFi(ssid, pass);
Blynk.connect();
// Check connection status
if (Blynk.connected())
{
isEspConnected = true;
Serial.println("Connected to Blynk server.");
}
else
{
isEspConnected = false;
Serial.println("Connection to Blynk server failed.");
}
}
void SensorTimer()
{
Blynk.virtualWrite(V1, temperature);
Blynk.virtualWrite(V2, humidity);
Blynk.virtualWrite(V3, EC);
Blynk.virtualWrite(V4, TDS);
Blynk.virtualWrite(V5, PPFD);
Blynk.virtualWrite(V6, PH);
Blynk.virtualWrite(V7, SoilMoistAverage);
}
BLYNK_WRITE(V8)
{
ShadeNetSwitch_Iot = param.asInt(); // Get the state of the Button widget (0 or 1)
}
BLYNK_WRITE(V9)
{
PumpSwitch_Iot = param.asInt(); // Get the state of the Button widget (0 or 1)
}
BLYNK_WRITE(V10)
{
FanSwitch_Iot = param.asInt(); // Get the state of the Button widget (0 or 1)
}
void setup() {
Serial.begin(115200);
Wire.begin();
u8g2.begin();
TCA9548A(0); // Selecting Bus 0
lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE_2);
TCA9548A(1);
hdc1080.begin(0x40); //initialization
pinMode(NextButton, INPUT_PULLUP);
pinMode(BackButton, INPUT_PULLUP);
pinMode(ShadeNetSwitch, INPUT);
pinMode(LimitSwitch1, INPUT_PULLUP);
pinMode(LimitSwitch2, INPUT_PULLUP);
pinMode(MoistureLevelPin1, INPUT);
pinMode(MoistureLevelPin2, INPUT);
pinMode(MoistureLevelPin3, INPUT);
pinMode(MoistureLevelPin4, INPUT);
pinMode(MoistureLevelPin5, INPUT);
pinMode(MoistureLevelPin6, INPUT);
pinMode(ph_Pin, INPUT);
pinMode(PWM2, OUTPUT);
pinMode(INA2, OUTPUT);
pinMode(INB2, OUTPUT);
pinMode(EN2, OUTPUT);
pinMode(PWM4, OUTPUT);
pinMode(INA4, OUTPUT);
pinMode(INB4, OUTPUT);
pinMode(EN4, OUTPUT);
pinMode(FanSwitch, INPUT); // Set RelayPin as an INPUT pin
pinMode(PumpSwitch, INPUT);
pinMode(RelayPump, OUTPUT);
pinMode(RelayFan1, OUTPUT);
pinMode(RelayFan2, OUTPUT);
digitalWrite(RelayPump, HIGH);
digitalWrite(RelayFan1, HIGH);
digitalWrite(RelayFan2, HIGH);
digitalWrite(EN2, HIGH);
digitalWrite(EN4, HIGH);
EspSerial.begin(ESP8266_BAUD);
delay(10);
// Connect to WiFi and Blynk
connectToWiFi();
// You can also specify the server:
// Blynk.begin(BLYNK_AUTH_TOKEN, wifi, ssid, pass, "blynk.cloud", 80);
timer.setInterval(1000L, SensorTimer);
}
float luxToPPFD(float lux) {
return lux * 0.0185;
}
void ReadLight() {
TCA9548A(0); // Selecting Bus 0
float lux = lightMeter.readLightLevel();
PPFD = luxToPPFD(lux); // Convert lux to PPFD
}
void ReadHDC1080() {
TCA9548A(1);
temperature = hdc1080.readTemperature();
humidity = hdc1080.readHumidity();
}
void ReadPH() {
for (int i = 0; i < 10; i++) { //Get 10 sample value from the sensor for smooth the value
buf[i] = analogRead(ph_Pin);
delay(10);
}
for (int i = 0; i < 9; i++) { //sort the analog from small to large
for (int j = i + 1; j < 10; j++) {
if (buf[i] > buf[j]) {
temp = buf[i];
buf[i] = buf[j];
buf[j] = temp;
}
}
}
avgValue = 0;
for (int i = 2; i < 8; i++) avgValue += buf[i]; //take the average value of 6 center sample
float phValue = (float)avgValue * 5.0 / 1024 / 6; //convert the analog into millivolt
PH = -5.70 * phValue + calibration_value; //convert the millivolt into pH value
}
float getTemp() {
// Returns the temperature from one DS18S20 in DEG Celsius
byte data[12];
byte addr[8];
if (!ds.search(addr)) {
// No more sensors on chain, reset search
ds.reset_search();
return -1000;
}
if (OneWire::crc8(addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return -1000;
}
if (addr[0] != 0x10 && addr[0] != 0x28) {
Serial.print("Device is not recognized");
return -1000;
}
ds.reset();
ds.select(addr);
ds.write(0x44, 1); // Start conversion, with parasite power on at the end
byte present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
for (int i = 0; i < 9; i++) { // We need 9 bytes
data[i] = ds.read();
}
ds.reset_search();
byte MSB = data[1];
byte LSB = data[0];
float tempRead = ((MSB << 8) | LSB); // Using two's complement
float TemperatureSum = tempRead / 16;
return TemperatureSum;
}
void ReadWaterTemp() {
WaterTemp = getTemp(); // Read temperature from first sensor
}
void ReadTDS() {
ReadWaterTemp();
static unsigned long analogSampleTimepoint = millis();
if (millis() - analogSampleTimepoint > 40U) //every 40 milliseconds,read the analog value from the ADC
{
analogSampleTimepoint = millis();
analogBuffer[analogBufferIndex] = analogRead(TdsSensorPin); //read the analog value and store into the buffer
analogBufferIndex++;
if (analogBufferIndex == SCOUNT)
analogBufferIndex = 0;
}
static unsigned long printTimepoint = millis();
if (millis() - printTimepoint > 800U) {
printTimepoint = millis();
for (copyIndex = 0; copyIndex < SCOUNT; copyIndex++)
analogBufferTemp[copyIndex] = analogBuffer[copyIndex];
averageVoltage = getMedianNum(analogBufferTemp, SCOUNT) * (float)VREF / 1024.0; // read the analog value more stable by the median filtering algorithm, and convert to voltage value
float compensationCoefficient = 1.0 + 0.02 * (WaterTemp - 25.0); //temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.02*(fTP-25.0));
float compensationVolatge = averageVoltage / compensationCoefficient; //temperature compensation
tdsValue = (133.42 * compensationVolatge * compensationVolatge * compensationVolatge - 255.86 * compensationVolatge * compensationVolatge + 857.39 * compensationVolatge) * 0.5;
TDS = tdsValue/1.8;
EC = TDS*2;
}
}
int getMedianNum(int bArray[], int iFilterLen) {
int bTab[iFilterLen];
for (byte i = 0; i < iFilterLen; i++)
bTab[i] = bArray[i];
int i, j, bTemp;
for (j = 0; j < iFilterLen - 1; j++) {
for (i = 0; i < iFilterLen - j - 1; i++) {
if (bTab[i] > bTab[i + 1]) {
bTemp = bTab[i];
bTab[i] = bTab[i + 1];
bTab[i + 1] = bTemp;
}
}
}
if ((iFilterLen & 1) > 0)
bTemp = bTab[(iFilterLen - 1) / 2];
else
bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
return bTemp;
}
void ReadSoilMoisture() {
// Read the water level from the analog pin
int MoistureLevel1 = analogRead(MoistureLevelPin1);
int MoistureLevel2 = analogRead(MoistureLevelPin2);
int MoistureLevel3 = analogRead(MoistureLevelPin3);
int MoistureLevel4 = analogRead(MoistureLevelPin4);
int MoistureLevel5 = analogRead(MoistureLevelPin5);
int MoistureLevel6 = analogRead(MoistureLevelPin6);
// Map the analog reading to a range (adjust these values based on your sensor and requirements)
SoilMoist1 = map(MoistureLevel1, 372, 892, 100, 0);
SoilMoist2 = map(MoistureLevel2, 386, 911, 100, 0);
SoilMoist3 = map(MoistureLevel3, 400, 819, 100, 0);
SoilMoist4 = map(MoistureLevel4, 380, 885, 100, 0);
SoilMoist5 = map(MoistureLevel5, 385, 908, 100, 0);
SoilMoist6 = map(MoistureLevel6, 383, 892, 100, 0);
SoilMoistAverage = ((SoilMoist1 + SoilMoist2 + SoilMoist3 + SoilMoist4 + SoilMoist5 + SoilMoist6) / 6);
}
void ShadeNetManual() {
int LimitSwitch1_State = digitalRead(LimitSwitch1);
int LimitSwitch2_State = digitalRead(LimitSwitch2);
ShadeNetSwitch_State = digitalRead(ShadeNetSwitch);
if (((ShadeNetSwitch_State == HIGH && ShadeNetSwitch_Iot == HIGH) || (ShadeNetSwitch_State == LOW && ShadeNetSwitch_Iot == LOW) || (ShadeNetSwitch_State == HIGH && ShadeNetSwitch_Iot == LOW)) && !isMotorRunning && isNetAutomated)
{
ShadeStatus = "ACTIVE";
OpenShadeNet();
isMotorRunning = true;
isNetAutomated = false;
Serial.println("Shade Net is Opening");
}
if (((ShadeNetSwitch_State == HIGH && ShadeNetSwitch_Iot == HIGH) || (ShadeNetSwitch_State == LOW && ShadeNetSwitch_Iot == LOW) || (ShadeNetSwitch_State == HIGH && ShadeNetSwitch_Iot == LOW)) && isMotorRunning && !isLimitSwitch1Clicked && LimitSwitch1_State == LOW && !isNetAutomated)
{
// Limit switch 1 is clicked
// Stop the motors and set switch 1 flag
stopMotors();
isNetAutomated = false;
isLimitSwitch1Clicked = true;
Serial.println("Limit switch 1 clicked, Motor Stops");
}
if (isLimitSwitch1Clicked && ShadeNetSwitch_State == LOW && ShadeNetSwitch_Iot == HIGH && !isLimitSwitch2Clicked && !isNetAutomated) {
// Soil moisture is less than or equal to 30 and switch 1 is clicked
// Rotate motors counterclockwise and set switch 2 flag
CloseShadeNet();
isNetAutomated = false;
isLimitSwitch2Clicked = true;
Serial.println("Shade Net Closing");
}
if (isMotorRunning && isLimitSwitch2Clicked && ShadeNetSwitch_State == LOW && ShadeNetSwitch_Iot == HIGH && LimitSwitch2_State == LOW && !isNetAutomated) {
// Limit switch 2 is clicked
// Stop the motors
ShadeStatus = "INACTIVE";
stopMotors();
isMotorRunning = false;
isLimitSwitch1Clicked = false;
isLimitSwitch2Clicked = false;
isNetAutomated = true;
Serial.println("Limit switch 2 clicked, Motors stopped");
}
}
void ShadeNetAutomation()
{
int LimitSwitch1_State = digitalRead(LimitSwitch1);
int LimitSwitch2_State = digitalRead(LimitSwitch2);
if (PPFD > 200 && !isMotorRunning && isNetAutomated && ShadeNetSwitch_State == LOW && ShadeNetSwitch_Iot == HIGH) {
// Turn on the motors and rotate clockwise
OpenShadeNet();
isMotorRunning = true;
isNetAutomated = true;
Serial.println("Shade Net is Opening");
}
if (isMotorRunning && !isLimitSwitch1Clicked && LimitSwitch1_State == LOW && isNetAutomated && ShadeNetSwitch_State == LOW && ShadeNetSwitch_Iot == HIGH) {
// Limit switch 1 is clicked
// Stop the motors and set switch 1 flag
stopMotors();
isLimitSwitch1Clicked = true;
isNetAutomated = true;
Serial.println("Limit switch 1 clicked, Motor Stops");
}
if (isLimitSwitch1Clicked && PPFD <= 200 && !isLimitSwitch2Clicked && isNetAutomated && ShadeNetSwitch_State == LOW && ShadeNetSwitch_Iot == HIGH) {
// Soil moisture is less than or equal to 30 and switch 1 is clicked
// Rotate motors counterclockwise and set switch 2 flag
CloseShadeNet();
isLimitSwitch2Clicked = true;
isNetAutomated = true;
Serial.println("Shade Net Closing");
}
if (isMotorRunning && isLimitSwitch2Clicked && LimitSwitch2_State == LOW && isNetAutomated && ShadeNetSwitch_State == LOW && ShadeNetSwitch_Iot == HIGH) {
// Limit switch 2 is clicked
// Stop the motors
stopMotors();
isNetAutomated = true;
isMotorRunning = false;
isLimitSwitch1Clicked = false;
isLimitSwitch2Clicked = false;
Serial.println("Limit switch 2 clicked, Motors stopped");
}
}
void PumpManual() {
PumpSwitch_State = digitalRead(PumpSwitch);
if (!isPumpRunning && ((PumpSwitch_State == HIGH && PumpSwitch_Iot == HIGH) || (PumpSwitch_State == LOW && PumpSwitch_Iot == LOW) || (PumpSwitch_State == HIGH && PumpSwitch_Iot == LOW)) && !isPumpRunning && isPumpAutomated) {
PumpStatus = "ACTIVE";
digitalWrite(RelayPump, LOW);
isPumpRunning = true;
isPumpAutomated = false;
}
if (isPumpRunning && PumpSwitch_State == LOW && PumpSwitch_Iot == HIGH && isPumpRunning && !isPumpAutomated) {
PumpStatus = "INACTIVE";
digitalWrite(RelayPump, HIGH);
isPumpRunning = false;
isPumpAutomated = true;
}
}
void PumpAutomation()
{
PumpSwitch_State = digitalRead(PumpSwitch);
if ((SoilMoist1 < 50 || SoilMoist2 < 50 || SoilMoist3 < 50 || SoilMoist4 < 50 || SoilMoist5 < 50 || SoilMoist6 < 50) && !isPumpRunning && isPumpAutomated && PumpSwitch_State == LOW && PumpSwitch_Iot == HIGH)
{
digitalWrite(RelayPump, LOW);
isPumpRunning = true;
PumpStatus = "ACTIVE";
}
if (SoilMoist1 > 65 && SoilMoist2 > 65 && SoilMoist3 > 65 && SoilMoist4 > 65 && SoilMoist5 > 65 && SoilMoist6 > 65 && isPumpRunning && isPumpAutomated && PumpSwitch_State == LOW && PumpSwitch_Iot == HIGH)
{
digitalWrite(RelayPump, HIGH);
isPumpRunning = false;
PumpStatus = "INACTIVE";
}
}
void FanManual() {
FanSwitch_State = digitalRead(FanSwitch);
// Check if the fan is not running and the switch is pressed
if (!isFanRunning && ((FanSwitch_State == HIGH && FanSwitch_Iot == HIGH) || (FanSwitch_State == LOW && FanSwitch_Iot == LOW || (FanSwitch_State == HIGH && FanSwitch_Iot == LOW)))) {
FanStatus = "ACTIVE";
digitalWrite(RelayFan1, LOW);
digitalWrite(RelayFan2, LOW);
isFanRunning = true;
isFanAutomated = false; // Ensure automated mode is disabled
}
// Check if the fan is running and the switch is released
if (isFanRunning && FanSwitch_State == LOW && FanSwitch_Iot == HIGH && !isFanAutomated) {
FanStatus = "INACTIVE";
digitalWrite(RelayFan1, HIGH);
digitalWrite(RelayFan2, HIGH);
isFanRunning = false;
isFanAutomated = true; // Re-enable automated mode after manual operation
}
}
void FanAutomation() {
FanSwitch_State = digitalRead(FanSwitch);
// Add delay to avoid interference between manual and automated control
delay(100); // Adjust the delay time as needed
if (temperature > 30 && !isFanRunning && isFanAutomated && FanSwitch_State == LOW && FanSwitch_Iot == HIGH)
{
digitalWrite(RelayFan1, LOW);
digitalWrite(RelayFan2, LOW);
isFanRunning = true;
FanStatus = "ACTIVE";
}
if (temperature <= 25 && isFanRunning && isFanAutomated && FanSwitch_State == LOW && FanSwitch_Iot == HIGH)
{
digitalWrite(RelayFan1, HIGH);
digitalWrite(RelayFan2, HIGH);
isFanRunning = false;
FanStatus = "INACTIVE";
}
}
void loadingScreen() {
u8g2.clearBuffer();
u8g2.setBitmapMode(1);
u8g2.drawFrame(12, 21, 104, 20);
u8g2.drawBox(14, 23, progress, 16);
u8g2.setFont(u8g2_font_helvB08_tr);
sprintf(buffer, "Progress: %d%%", progress);
u8g2.drawStr(33, 53, buffer);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(5, 7, " SYSTEM INITIALIZATION ");
u8g2.drawLine(0, 9, 127, 9);
u8g2.sendBuffer();
delay(150);
progress += 5; // Increment progress by 5
if (progress >= 100) { // If progress reaches 100 or more
progress = 0; // Reset progress to 0
loadingComplete = true; // Set loadingComplete to true
}
}
void displayLightValue() {
u8g2.clearBuffer();
u8g2.setBitmapMode(1);
u8g2.setFontMode(1);
u8g2.drawFrame(1, 0, 127, 64);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(7, 16, "L I G H T I N T E N S I T Y");
u8g2.drawFrame(4, 5, 105, 15);
u8g2.setFont(u8g2_font_profont22_tr);
u8g2.setCursor(20, 49);
u8g2.print(PPFD);
u8g2.drawLine(7, 37, 17, 27);
u8g2.drawLine(17, 27, 108, 27);
u8g2.drawLine(109, 27, 118, 36);
u8g2.drawLine(7, 37, 7, 46);
u8g2.drawLine(7, 47, 16, 56);
u8g2.drawLine(17, 56, 109, 56);
u8g2.drawLine(118, 36, 118, 47);
u8g2.drawLine(118, 48, 110, 56);
u8g2.drawXBMP(111, 5, 15, 16, image_display_brightness_bits);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(83, 46, "P P F D");
u8g2.sendBuffer();
}
void displayAmbTemp() {
u8g2.clearBuffer();
u8g2.setBitmapMode(1);
u8g2.setFontMode(1);
u8g2.drawFrame(0, 0, 127, 64);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(8, 23, "T E M P E R A T U R E");
u8g2.drawFrame(5, 3, 93, 23);
u8g2.setFont(u8g2_font_profont22_tr);
u8g2.setCursor(20, 51);
u8g2.print(temperature);
u8g2.print(" °C");
u8g2.drawLine(7, 38, 16, 29);
u8g2.drawLine(17, 29, 109, 29);
u8g2.drawLine(110, 29, 118, 37);
u8g2.drawLine(7, 38, 7, 47);
u8g2.drawLine(7, 48, 16, 57);
u8g2.drawLine(17, 57, 109, 57);
u8g2.drawLine(118, 37, 118, 48);
u8g2.drawLine(118, 49, 110, 57);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(23, 13, " A M B I E N T");
u8g2.drawXBMP(104, 7, 16, 16, image_weather_temperature_bits);
u8g2.sendBuffer();
}
void displayAmbHum() {
u8g2.clearBuffer();
u8g2.setBitmapMode(1);
u8g2.setFontMode(1);
u8g2.drawFrame(0, 0, 127, 64);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(36, 23, "H U M I D I T Y");
u8g2.drawFrame(31, 3, 65, 22);
u8g2.setFont(u8g2_font_profont22_tr);
u8g2.setCursor(21, 50);
u8g2.print(humidity);
u8g2.print(" %");
u8g2.drawLine(7, 37, 16, 28);
u8g2.drawLine(17, 28, 109, 28);
u8g2.drawLine(110, 28, 118, 36);
u8g2.drawLine(7, 37, 7, 46);
u8g2.drawLine(7, 47, 16, 56);
u8g2.drawLine(17, 56, 109, 56);
u8g2.drawLine(118, 36, 118, 47);
u8g2.drawLine(118, 48, 110, 56);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(32, 13, " R E L A T I V E");
u8g2.drawXBMP(101, 5, 15, 16, image_weather_wind_bits);
u8g2.drawXBMP(11, 7, 15, 16, image_weather_sun_bits);
u8g2.sendBuffer();
}
void displayPhLvl() {
u8g2.clearBuffer();
u8g2.setBitmapMode(1);
u8g2.setFontMode(1);
u8g2.drawFrame(0, 0, 127, 64);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(33, 16, "P H L E V E L");
u8g2.drawFrame(25, 5, 70, 15);
u8g2.setFont(u8g2_font_profont22_tr);
u8g2.setCursor(22, 49);
u8g2.print(PH);
u8g2.print("pH");
u8g2.drawXBMP(9, 4, 11, 16, image_weather_humidity_bits);
u8g2.drawXBMP(101, 4, 18, 18, image_Clock_bits);
u8g2.drawLine(7, 37, 17, 27);
u8g2.drawLine(17, 27, 108, 27);
u8g2.drawLine(109, 27, 118, 36);
u8g2.drawLine(7, 37, 7, 46);
u8g2.drawLine(7, 47, 16, 56);
u8g2.drawLine(17, 56, 109, 56);
u8g2.drawLine(118, 36, 118, 47);
u8g2.drawLine(118, 48, 110, 56);
u8g2.sendBuffer();
}
void displayEcLvl() {
u8g2.clearBuffer();
u8g2.setBitmapMode(1);
u8g2.setFontMode(1);
u8g2.drawFrame(1, 0, 127, 64);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(37, 16, "E C L E V E L");
u8g2.drawFrame(30, 5, 70, 15);
u8g2.setFont(u8g2_font_profont22_tr);
u8g2.setCursor(16, 49);
u8g2.print(EC);
u8g2.drawXBMP(11, 5, 11, 16, image_weather_humidity_bits);
u8g2.drawLine(7, 37, 17, 27);
u8g2.drawLine(17, 27, 108, 27);
u8g2.drawLine(109, 27, 118, 36);
u8g2.drawLine(7, 37, 7, 46);
u8g2.drawLine(7, 47, 16, 56);
u8g2.drawLine(17, 56, 109, 56);
u8g2.drawLine(118, 36, 118, 47);
u8g2.drawLine(118, 48, 110, 56);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(76, 46, " u S/c m");
u8g2.drawXBMP(103, 5, 16, 16, image_Voltage_bits);
u8g2.sendBuffer();
}
void displayTdsLvl() {
u8g2.clearBuffer();
u8g2.setBitmapMode(1);
u8g2.setFontMode(1);
u8g2.drawFrame(1, 0, 127, 64);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(33, 16, "T D S L E V E L");
u8g2.drawFrame(30, 5, 71, 15);
u8g2.setFont(u8g2_font_profont22_tr);
u8g2.setCursor(23, 49);
u8g2.print(TDS);
u8g2.drawXBMP(11, 5, 11, 16, image_weather_humidity_bits);
u8g2.drawLine(7, 37, 17, 27);
u8g2.drawLine(17, 27, 108, 27);
u8g2.drawLine(109, 27, 118, 36);
u8g2.drawLine(7, 37, 7, 46);
u8g2.drawLine(7, 47, 16, 56);
u8g2.drawLine(17, 56, 109, 56);
u8g2.drawLine(118, 36, 118, 47);
u8g2.drawLine(118, 48, 110, 56);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(85, 45, " p p m");
u8g2.drawXBMP(103, 5, 16, 16, image_Voltage_bits);
u8g2.sendBuffer();
}
void displaySoilMoist() {
u8g2.clearBuffer();
u8g2.setBitmapMode(1);
u8g2.setFontMode(1);
u8g2.drawFrame(1, 0, 127, 64);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(5, 14, "S O I L M O I S T U R E");
u8g2.drawLine(4, 15, 94, 15);
u8g2.drawXBMP(98, 2, 11, 16, image_weather_humidity_bits);
u8g2.drawXBMP(110, 3, 15, 16, image_earth_bits);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(6, 32, "S M 1");
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(6, 45, "S M 2");
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(6, 57, "S M 3");
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(66, 32, "S M 4");
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(66, 45, "S M 5");
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(66, 57, "S M 6");
u8g2.drawLine(5, 21, 124, 21);
u8g2.drawLine(4, 21, 4, 59);
u8g2.drawLine(4, 60, 123, 60);
u8g2.drawLine(30, 21, 30, 59);
u8g2.drawLine(91, 21, 91, 59);
u8g2.drawLine(63, 22, 63, 59);
u8g2.drawLine(124, 22, 124, 60);
u8g2.drawLine(5, 34, 123, 34);
u8g2.drawLine(5, 47, 124, 47);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.setCursor(34, 32); //sm1 -1ST -
u8g2.print(SoilMoist1); //A2 - OK
u8g2.print(" %");
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.setCursor(34, 57); //sm3 -5TH - 3RD
u8g2.print(SoilMoist4); //A3 -> A5
u8g2.print(" %");
u8g2.setCursor(95, 32); //SM4 - 2ND - 4TH
u8g2.print(SoilMoist6); //A4 -> A7
u8g2.print(" %");
u8g2.setCursor(95, 57); // SM6 -3RD - 6TH
u8g2.print(SoilMoist5); //A5 -> A6
u8g2.print(" %");
u8g2.setCursor(34, 44); // SM2 -6TH -2ND
u8g2.print(SoilMoist3); //A6 -> A4
u8g2.print(" %");
u8g2.setCursor(95, 44); // SM5 -4TH -5TH
u8g2.print(SoilMoist2); //A7 -> A3
u8g2.print(" %");
u8g2.sendBuffer();
}
void displayActuatorStatus() {
u8g2.clearBuffer();
u8g2.setFontMode(1);
u8g2.setBitmapMode(1);
u8g2.drawFrame(0, 0, 127, 64);
u8g2.setFont(u8g2_font_haxrcorp4089_tr);
u8g2.drawStr(36, 16, "");
u8g2.setFont(u8g2_font_t0_13_tr);
u8g2.drawStr(20, 15, "ACTUATOR STATUS");
u8g2.drawXBMP(3, 2, 16, 16, image_menu_settings_gear_bits);
u8g2.drawFrame(4, 21, 120, 40);
u8g2.drawLine(21, 17, 122, 17);
u8g2.drawLine(5, 34, 122, 34);
u8g2.drawLine(4, 47, 122, 47);
u8g2.drawLine(34, 23, 34, 59);
u8g2.setFont(u8g2_font_t0_11_tr);
u8g2.drawStr(10, 58, "NET");
u8g2.drawStr(8, 45, "PUMP");
u8g2.drawStr(7, 32, "FANS");
u8g2.setCursor(54, 58);
u8g2.print(ShadeStatus);
u8g2.setCursor(54, 45);
u8g2.print(PumpStatus);
u8g2.setCursor(54, 32);
u8g2.print(FanStatus);
u8g2.sendBuffer();
}
void ReadSensors()
{
ReadLight();
ReadHDC1080();
ReadPH();
ReadTDS();
ReadSoilMoisture();
}
void Automation()
{
FanAutomation();
PumpAutomation();
ShadeNetAutomation();
}
void Manual()
{
PumpManual();
FanManual();
ShadeNetManual();
}
void updateState() {
currentState = static_cast<State>((currentState + 1) % 8); //CYCLE THROUGH 0-7
}
void backState() {
currentState = static_cast<State>((currentState - 1 + 8) % 8); // Ensure non-negative result
}
void Display() {
int nextButtonState = digitalRead(NextButton);
int backButtonState = digitalRead(BackButton);
if (nextButtonState != lastButtonState || backButtonState != lastBackButtonState) {
delay(20); // Debounce delay
}
if (nextButtonState == LOW && lastButtonState == HIGH) {
updateState();
}
if (backButtonState == LOW && lastBackButtonState == HIGH) {
backState();
}
lastButtonState = nextButtonState;
lastBackButtonState = backButtonState;
switch (currentState) {
case LIGHT_VALUE:
displayLightValue();
break;
case AMB_TEMP:
displayAmbTemp();
break;
case AMB_HUM:
displayAmbHum();
break;
case PH_LVL:
displayPhLvl();
break;
case EC_LVL:
displayEcLvl();
break;
case TDS_LVL:
displayTdsLvl();
break;
case SOIL_MOIST:
displaySoilMoist();
break;
case ACT_STAT:
displayActuatorStatus();
break;
}
}
void loop()
{
if (!loadingComplete)
{
loadingScreen();
}
if (loadingComplete)
{
if (isEspConnected)
{
Display();
ReadSensors();
Automation();
Manual();
timer.run();
Blynk.run();
}
if (!isEspConnected)
{
Display();
ReadSensors();
Automation();
Manual();
if (millis() - lastConnectionAttempt >= connectionInterval)
{
connectToWiFi();
lastConnectionAttempt = millis();
}
}
}
}
void OpenShadeNet() {
digitalWrite(INA4, HIGH);
digitalWrite(INB4, LOW);
digitalWrite(EN4, HIGH);
digitalWrite(INA2, LOW);
digitalWrite(INB2, HIGH);
digitalWrite(EN2, HIGH);
analogWrite(PWM2, 155);
analogWrite(PWM4, 80);
}
void CloseShadeNet() {
digitalWrite(INA4, LOW);
digitalWrite(INB4, HIGH);
digitalWrite(EN4, HIGH);
digitalWrite(INA2, HIGH);
digitalWrite(INB2, LOW);
digitalWrite(EN2, HIGH);
analogWrite(PWM2, 65);
analogWrite(PWM4, 200);
}
void stopMotors() {
digitalWrite(INA2, LOW);
digitalWrite(INB2, LOW);
digitalWrite(EN2, LOW);
digitalWrite(INA4, LOW);
digitalWrite(INB4, LOW);
digitalWrite(EN4, LOW);
}
You should read this…
Pete.
You should also read this…