#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <NewPing.h>  // Include the NewPing library for HC-SR04

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define OLED_RESET    -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define TRIGGER_PIN  2  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN     3  // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 400 // Maximum distance we want to ping for (in centimeters).

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

int potPin = A0;              // Analog pin connected to the potentiometer
int tankHeight = 200;         // Default total tank height in centimeters
int waterLevel = 0;           // Current water level percentage

const int relayPin = 4;       // Pin connected to relay
const int buttonPin = 6;      // Pin connected to push button
bool manualOverride = false;  // Manual relay override flag
bool relayState = false;      // Current state of the relay

void setup() 
{
  Serial.begin(9600);

  // Initialize relay and button pins
  pinMode(relayPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);  // Button pin with internal pull-up resistor

  // Initialize potentiometer pin
  pinMode(potPin, INPUT);

  // Initialize OLED display
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) 
  {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }

  display.clearDisplay(); // Clear the display buffer
  display.display(); // Display the cleared buffer

  delay(2000);  // Pause for 2 seconds

  display.clearDisplay(); // Clear the display buffer again
}

void loop() 
{
  // Read potentiometer value and map it to tank height range (2cm to 400cm)
  int potValue = analogRead(potPin);
  tankHeight = map(potValue, 0, 1023, 2, 400);

  // Measure distance with HC-SR04 and calculate water level percentage
  unsigned int distance = sonar.ping_cm();  // Get distance in centimeters

  // Calculate water level percentage
  if (distance != 0 && distance <= tankHeight) 
  {
    waterLevel = map(distance, 0, tankHeight, 100, 0);  // Invert mapping for display
    waterLevel = constrain(waterLevel, 0, 100); // Ensure waterLevel is between 0 and 100%
  } 
  else 
  {
    waterLevel = 0;  // No water detected or out of range
  }

  // Manual override logic (button toggles relay state only if water level < 90%)
  if (waterLevel < 90 && digitalRead(buttonPin) == LOW) 
  {
    delay(200);  // Simple debounce delay
    if (digitalRead(buttonPin) == LOW)  // If button is still pressed after debounce
    {
      manualOverride = !manualOverride; // Toggle manual override mode
      relayState = !relayState;  // Toggle relay state
      digitalWrite(relayPin, relayState ? LOW : HIGH);  // Update relay (low active type)
    }
    while (digitalRead(buttonPin) == LOW);  // Wait until button is released
  }

  // Ensure relay turns off if water level exceeds 98%, even in manual override mode
  if (waterLevel > 98) 
  {
    relayState = false;  // Turn relay off
    digitalWrite(relayPin, HIGH); // Deactivate relay
    manualOverride = false;  // Exit manual override mode
  }

  // Auto control logic when not manually overridden and water level below 10%
  if (!manualOverride && waterLevel < 10) 
  {
    relayState = true;  // Turn relay on
    digitalWrite(relayPin, LOW);  // Activate relay (low active type)
  }

  // Exit manual override mode and activate relay if water level drops below 10%
  if (waterLevel < 10) 
  {
    manualOverride = false;  // Exit manual override mode
    relayState = true;  // Turn relay on
    digitalWrite(relayPin, LOW);  // Activate relay (low active type)
  }

  display.clearDisplay();

  // Draw tank outline (vertical)
  display.drawRect(10, 18, 34, 44, WHITE);

  // Calculate bar height increment based on the tank height and the number of bars
  int barHeightIncrement = 40 / 4; // Adjust this value based on the tank height and the number of bars
  int barWidth = 30; // Width of each bar

  // Determine which bar to show based on water level percentage
  int numBars = 0;
  if (waterLevel >= 10 && waterLevel <= 24) 
  {
    numBars = 1;
  } 
  else if (waterLevel >= 25 && waterLevel <= 49) 
  {
    numBars = 2;
  } 
  else if (waterLevel >= 50 && waterLevel <= 74) 
  {
    numBars = 3;
  } 
  else if (waterLevel >= 75 && waterLevel <= 100) 
  {
    numBars = 4;
  }

  // Draw bars
  for (int i = 0; i < numBars; i++) 
  {
    int barHeight = 50 - i * barHeightIncrement;  // Calculate bar height from bottom up
    display.fillRect(12, barHeight, barWidth, 10, WHITE);  // Draw bars vertically
  }

  // Display pump status based on relay state
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(49, 45);
  if (digitalRead(relayPin) == LOW) 
  {
    display.print("Pump: ON");  // Display pump is on
  } 
  else 
  {
    display.print("Pump: OFF");  // Display pump is off
  }

  // Headline
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(10, 5);
  display.print("Smart Tank Monitor");

  // Display water level percentage
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(49, 18);
  display.print("Water Level: ");

  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(55, 30);
  display.print(waterLevel);
  display.print("%");

  // Display tank height setting
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(49, 55);
  display.print("Tank(H):");
  display.print(tankHeight);
  display.print("cm");

  display.display();
  delay(1000);  // Adjust delay as needed for refresh rate
}
NOCOMNCVCCGNDINLED1PWRRelay Module