#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <Encoder.h> // Include the Rotary Encoder library

LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2); // Initialize 16x2 LCD

#define buzzer 3
#define motorDriver 4

byte sensorInt = 0; 
byte flowsensor = 2;

float konstanta = 7.5; //konstanta flow meter
float l_minute;

volatile int pulse;
unsigned long lastTime;
float volume,flowRate;
unsigned long currentTime;
unsigned long cloopTime;

const byte ROWS = 4;
const byte COLS = 4;

char keys[ROWS][COLS] = {
    {'1', '4', '7', '*'},
    {'2', '5', '8', '0'},
    {'3', '6', '9', '#'},
    {'A', 'B', 'C', 'D'}};

const byte colPins[ROWS] = {13, 12, 11, 10};
const byte rowPins[COLS] = {9, 8, 7, 6};

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

unsigned long startTime;
bool menuDisplayed = false;             // Track if the menu is currently displayed or not
char selectedMode = ' ';                // Default selected mode is none
bool flowDetectionRunning = false;      // Flag to indicate if flow detection is running

float debit;
unsigned int flowmlt;
unsigned long totalmlt;
unsigned long oldTime;

void setup()
{ 
    pulse = 0;
    debit = 0.0;
    flowmlt = 0;
    totalmlt = 0;
    oldTime = 0;
  
    pinMode(buzzer, OUTPUT);
    pinMode(motorDriver, OUTPUT);

    pinMode(flowsensor, INPUT);
    digitalWrite(flowsensor, HIGH);
  
    lcd.init();
    lcd.backlight();
    startTime = millis(); // Record the start time
    //Liters per Minute
    pulse=0;
    attachInterrupt(sensorInt, flow, RISING);

    currentTime = millis();
    cloopTime = currentTime;

    lcd.clear();
    lcd.setCursor(1, 0);
    lcd.print("Kontrol Aliran");   
    lcd.setCursor(4, 1);
    lcd.print("Tekan(#)");
}

void displayMenu()
{
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Lanjut ");
    lcd.setCursor(0, 1);
    lcd.print("Tekan B");
    menuDisplayed = true;
}


void loop() {
    char key = keypad.getKey(); // Get the key pressed
    if (key != NO_KEY) {
        tone(buzzer, 1300, 50); // Play tone for keypress

        if (key == '#') { // If asterisk (*) key is pressed
            if (!menuDisplayed) { // If menu is not already displayed
                displayMenu(); // Display the menu                
            }
        } else if (key == '*') { // If '*' key is pressed            
        } else if (menuDisplayed) { // If menu is displayed
            if (key >= 'A' && key <= 'B' && selectedMode == ' ') { // If a valid mode key is pressed and no mode is currently running
                selectedMode = key;
                switch (selectedMode) {
                     case 'B':
                        modeB(); // Enter Mode b
                        break;
                }
            } else if (selectedMode != ' ') { // If mode is selected
                // Handle mode-specific button presses here
            }
        }
    }
}

void displayModeB(float actualVolume)
{
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Set Point:");
    lcd.setCursor(0, 1);
    lcd.print("Actual   :");
    lcd.print(actualVolume, 1); // Display the actual accumulated volume
    lcd.print(" mL");
}

void modeB() {
    displayModeB(0);
    
    // Get the desired volume from the user
    float setVolume = getSetVolume();

    if (flowDetectionRunning)   // Start flow detection
    {
        detectFlow(setVolume);
    }
}

float getSetVolume() {
    float volume = 0;
    bool volumeEntered = false;
    while (!volumeEntered) {
        char key = keypad.getKey();
        if (key >= '0' && key <= '9') {
            tone(buzzer, 1300, 50); // Play tone for keypress
            volume = volume * 10 + (key - '0');
            lcd.setCursor(10, 0);
            lcd.print(volume,0);
            lcd.setCursor(14,0);
            lcd.print("mL");
        } else if (key == '#') {
            tone(buzzer, 1300, 50); // Play tone for keypress
            volumeEntered = true; // asal true
            flowDetectionRunning = true; // Set flow detection flag diubah jadi true
        }
    }
    return volume;
}

void detectFlow(float setVolume) {
  unsigned long lastTime = 0;
  float totalVolume=0;
  
    lcd.setCursor(9, 1);
    lcd.print(":    mL"); // Clear previous value

    while (true) 
    {
        currentTime = millis();
        if (currentTime >= (cloopTime + 1000)) {    // Calculate flow rate every 'interval' milliseconds         
            //detachInterrupt(sensorInt);       
            cloopTime = currentTime; 
            if (pulse != 0) 
            {
              l_minute= (pulse / 7.5); // (Pulse frequency x 60 min) / 7.5Q = flowrate in L/hour
            
              analogWrite(motorDriver, 255); // Stop the pump

            //flowRate = ((1000.0 / (millis() - oldTime)) * pulse) / konstanta;
            //oldTime = millis();
              l_minute = (l_minute / 60);
              totalVolume += flowmlt;

              lcd.setCursor(0, 1);
              lcd.print("Volume   :");
              lcd.setCursor(10,1);
              lcd.print(totalVolume,0);
              lcd.setCursor(14,1);
              lcd.print("mL");
            
              if (totalVolume >= setVolume) 
              { // Check if accumulated volume meets or exceeds set volume                
                tone(buzzer, 1300, 50); // Play tone for keypress
                analogWrite(motorDriver, 0); // Stop the pump
                flowDetectionRunning = false; // Reset flow detection flag
                menuDisplayed = false; // Return to mode selection
                break;            
              }
            
              pulse=0;
              attachInterrupt(sensorInt, flow, FALLING);
            }
        }
    }
}

void flow()
{
    pulse++;        
}