#define BLYNK_TEMPLATE_ID "TMPL2L1JAtM3R" // Define the Blynk template ID #define BLYNK_TEMPLATE_NAME "ESP32 FINAL PROJECT" // Define the Blynk template name #define BLYNK_AUTH_TOKEN "vbwqd0jSgHx8SR12pEOhHkTO03UNKGyk" // Define the Blynk authentication token /* Comment this out to disable prints and save space */ #define BLYNK_PRINT Serial // Enable Serial output for debugging #include // Include the WiFi library for ESP32 #include // Include the WiFi client library #include // Include the Blynk library for ESP32 #include // Include the flow sensor library #include // Include the I2C communication library #include // Include the Adafruit GFX library for graphics #include // Include the Adafruit SSD1306 library for OLED display // Your WiFi credentials char ssid[] = "Depa703"; // SSID where I made my project char pass[] = "borgono10000"; // Password of the wifi network // Flow sensor setup FlowSensor Sensor(150, 8); // Create a flow sensor object with specific parameters unsigned long lastCheck = 0; // Variable to keep track of the last check time const int solenoidPinUP = 4; // Pin connected to the UP solenoid valve const int solenoidPinUNDER = 2; // Pin connected to the UNDER solenoid valve const int mosfetPinPump = 3; // Pin connected to the MOSFET for the pump // OLED display setup #define SCREEN_WIDTH 128 // Define the width of the OLED display #define SCREEN_HEIGHT 64 // Define the height of the OLED display #define OLED_RESET -1 // Define the OLED reset pin (not used here) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // Create an OLED display object // System states enum SystemState { NORMAL_FLOW, ALERT, DISPLAY_FLOW_RATE, DISPLAY_COST }; SystemState currentState = NORMAL_FLOW; // Set the initial system state to NORMAL_FLOW unsigned long stateStartTime = 0; // Variable to store the state start time unsigned long stateDuration = 0; // Variable to store the state duration // Variables to control the solenoids and the pump from Blynk bool solenoidUPState = false; // Initial state of the UP solenoid valve bool solenoidUNDERState = false; // Initial state of the UNDER solenoid valve bool pumpState = true; // Turn on the pump by default void count() { Sensor.count(); // Increment the flow sensor counter } void setup() { // Debug console Serial.begin(115200); // Initialize the Serial communication at 115200 baud rate // Connect to Blynk Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass); // Connect to Blynk using the authentication token and WiFi credentials // Initialize the flow sensor Sensor.begin(count); // Initialize the flow sensor with the count function // Set the pins as outputs and activate them pinMode(solenoidPinUP, OUTPUT); // Set the UP solenoid pin as an output pinMode(solenoidPinUNDER, OUTPUT); // Set the UNDER solenoid pin as an output pinMode(mosfetPinPump, OUTPUT); // Set the MOSFET pump pin as an output // Turn on the pump at the start digitalWrite(mosfetPinPump, HIGH); // Turn on the pump by setting the pin HIGH // Initialize the OLED display if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Initialize the display with I2C address 0x3C Serial.println(F("SSD1306 allocation failed")); // Print an error message if the display initialization fails for (;;); // Enter an infinite loop if the initialization fails } display.display(); // Display the initial buffer delay(2000); // Small delay for the display initialization display.clearDisplay(); // Clear the display buffer display.setTextSize(2); // Set the text size for the display display.setTextColor(SSD1306_WHITE); // Set the text color for the display Serial.println(F("OLED display initialized successfully")); // Print a success message for the display initialization // Set the initial state currentState = NORMAL_FLOW; // Set the initial state to NORMAL_FLOW stateStartTime = millis(); // Record the current time as the state start time stateDuration = 10000; // Set the duration for NORMAL_FLOW state to 10 seconds // Ensure the solenoids and pump are in the correct state at the start digitalWrite(solenoidPinUP, solenoidUPState); // Set the UP solenoid state digitalWrite(solenoidPinUNDER, solenoidUNDERState); // Set the UNDER solenoid state digitalWrite(mosfetPinPump, pumpState); // Set the pump state } // Blynk functions to handle the solenoid and pump switches BLYNK_WRITE(V0) { solenoidUPState = param.asInt(); // Get the value from the Blynk app for the UP solenoid digitalWrite(solenoidPinUP, solenoidUPState); // Set the UP solenoid state Blynk.virtualWrite(V0, solenoidUPState); // Update the switch state in the Blynk dashboard } BLYNK_WRITE(V2) { solenoidUNDERState = param.asInt(); // Get the value from the Blynk app for the UNDER solenoid digitalWrite(solenoidPinUNDER, solenoidUNDERState); // Set the UNDER solenoid state Blynk.virtualWrite(V2, solenoidUNDERState); // Update the switch state in the Blynk dashboard } BLYNK_WRITE(V3) { pumpState = param.asInt(); // Get the value from the Blynk app for the pump digitalWrite(mosfetPinPump, pumpState); // Set the pump state Blynk.virtualWrite(V3, pumpState); // Update the switch state in the Blynk dashboard } void loop() { Blynk.run(); // Run the Blynk main loop unsigned long currentTime = millis(); // Get the current time if (currentTime - stateStartTime >= stateDuration) { // Change state if the duration has passed switch (currentState) { case NORMAL_FLOW: currentState = ALERT; // Change to ALERT state stateDuration = 2000; // Set duration for ALERT state break; case ALERT: currentState = DISPLAY_FLOW_RATE; // Change to DISPLAY_FLOW_RATE state stateDuration = 2000; // Set duration for DISPLAY_FLOW_RATE state break; case DISPLAY_FLOW_RATE: currentState = DISPLAY_COST; // Change to DISPLAY_COST state stateDuration = 2000; // Set duration for DISPLAY_COST state break; case DISPLAY_COST: { static int cycleCount = 0; // Static variable to count cycles cycleCount++; if (cycleCount >= 3) { // Repeat the cycle 3 times cycleCount = 0; // Reset cycle count currentState = NORMAL_FLOW; // Change back to NORMAL_FLOW state stateDuration = 10000; // Set duration for NORMAL_FLOW state } else { currentState = ALERT; // Change back to ALERT state stateDuration = 2000; // Set duration for ALERT state } break; } } stateStartTime = currentTime; // Update the state start time // Actions based on the current state switch (currentState) { case NORMAL_FLOW: digitalWrite(solenoidPinUP, HIGH); // Open UP solenoid digitalWrite(solenoidPinUNDER, LOW); // Close UNDER solenoid display.clearDisplay(); // Clear the display display.setCursor((SCREEN_WIDTH - 12 * 6) / 2, (SCREEN_HEIGHT - 16) / 2); // Center text display.println("NORMAL"); // Display NORMAL display.setCursor((SCREEN_WIDTH - 4 * 6) / 2, (SCREEN_HEIGHT - 16) / 2 + 16); // Center text display.println("FLOW"); // Display FLOW display.display(); // Update the display Serial.println("State: NORMAL_FLOW"); // Print state to Serial break; case ALERT: digitalWrite(solenoidPinUP, LOW); // Close UP solenoid digitalWrite(solenoidPinUNDER, HIGH); // Open UNDER solenoid display.clearDisplay(); // Clear the display display.setCursor((SCREEN_WIDTH - 5 * 6) / 2, 0); // Center text display.println("ALERT"); // Display ALERT display.setCursor((SCREEN_WIDTH - 5 * 6) / 2, 24); // Center text display.println("ALERT"); // Display ALERT display.setCursor((SCREEN_WIDTH - 5 * 6) / 2, 48); // Center text display.println("ALERT"); // Display ALERT display.display(); // Update the display Serial.println("State: ALERT"); // Print state to Serial break; case DISPLAY_FLOW_RATE: { Sensor.read(); // Read the flow sensor float flowRate = Sensor.getFlowRate_m(); // Get the flow rate in L/min Blynk.virtualWrite(V1, flowRate); // Update the flow rate in the Blynk app display.clearDisplay(); // Clear the display display.setCursor(0, 0); // Set cursor position display.println("Flow Rate:"); // Display Flow Rate label display.print(flowRate); // Display the flow rate display.println(" L/min"); // Display units display.display(); // Update the display Serial.print("Flow Rate: "); // Print flow rate to Serial Serial.print(flowRate); // Print the flow rate value Serial.println(" L/min"); // Print units to Serial break; } case DISPLAY_COST: { Sensor.read(); // Read the flow sensor float flowRate = Sensor.getFlowRate_m(); // Get the flow rate in L/min float monthlyCost = flowRate * 60 * 24 * 30 * 0.005 / 4; // Calculate the monthly cost display.clearDisplay(); // Clear the display display.setCursor(0, 0); // Set cursor position display.println("Cost/Month"); // Display Cost/Month label display.setCursor(0, 32); // Set cursor position display.print("$"); // Display currency symbol display.println(monthlyCost); // Display the monthly cost display.display(); // Update the display Serial.print("Cost/Month: $"); // Print monthly cost to Serial Serial.println(monthlyCost); // Print the cost value to Serial break; } } } // Update the state of the solenoids and pump in the Blynk dashboard Blynk.virtualWrite(V0, digitalRead(solenoidPinUP)); // Update UP solenoid state Blynk.virtualWrite(V2, digitalRead(solenoidPinUNDER)); // Update UNDER solenoid state Blynk.virtualWrite(V3, digitalRead(mosfetPinPump)); // Update pump state }