#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

float totalVolume=0;
int inputReset=0;
byte sensorInt = 0; 
byte flowsensor = 2;
volatile long pulse;
unsigned long lastTime;
float volume,flowRate;

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
bool menuReset = false;
char selectedMode = ' ';                // Default selected mode is none
bool flowDetectionRunning = false;      // Flag to indicate if flow detection is running


unsigned int flowmlt;
unsigned long totalmlt;
unsigned long oldTime;

void setup()
{ 
    pulse = 0;
    flowmlt = 0;
    totalmlt = 0;
    oldTime = 0;

    pinMode(5,INPUT);
    pinMode(buzzer, OUTPUT);
    pinMode(motorDriver, OUTPUT);

    pinMode(flowsensor, INPUT);
    digitalWrite(flowsensor, HIGH);
    digitalWrite(5,HIGH);  
    lcd.init();
    lcd.backlight();
    startTime = millis(); // Record the start time
    //Liters per Minute
    pulse=0;
    attachInterrupt(sensorInt, flow, RISING);
    
    lcd.clear();
    lcd.setCursor(1, 0);
    lcd.print("Kontrol Aliran");   
    lcd.setCursor(4, 1);
    lcd.print("Tekan(A)");
    menuDisplayed = true;
}

void displayMenu()
{
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Lanjut ");
    lcd.setCursor(0, 1);
    lcd.print("Tekan A");
    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                
                menuDisplayed = true;
            }
        } 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 'A':
                        modeB(); 
                        break;
                }
            } else if (selectedMode != ' ') { // If mode is selected
                
            } else if (key =="D") {
                  
            }
        }
    }
}

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
        } else if (inputReset =="D"){
       
        }

    }
    return volume;
}

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

    while (true) 
    {
        unsigned long currentTime = millis();
        if (currentTime - oldTime >= 1000) {    // Calculate flow rate every 'interval' milliseconds         
            //detachInterrupt(sensorInt);
            
            //float flowRate = (pulse - totalPulses) * 60.0 / (interval * 7.5); // Assuming 7.5 pulses per liter
            //totalPulses = pulse;
            //lastTime = currentTime;           // Update total volume            
           // totalVolume += flowRate / 1000.0; // Convert flow rate from L/min to L/s, then accumulate 
           // lcd.setCursor(8, 1);           // Update LCD with actual accumulated volume under "Actual: " section
           // lcd.print(totalVolume, 1);    // Print actual accumulated volume with 1 decimal place
            //lcd.print(" mL");            
  
            analogWrite(motorDriver, 255); // Stop the pump
            
            flowRate = ((1000.0 / (millis() - oldTime)) * pulse) / 7.5;
            oldTime = millis();
            flowmlt = (flowRate/ 60)*1000;
            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, RISING);
    
        }
    }
}

void flow()
{
    pulse++;        
}