#define BLYNK_TEMPLATE_ID "TMPL64-PTQxbQ"
#define BLYNK_TEMPLATE_NAME "water smart systems"
#define BLYNK_AUTH_TOKEN "obfhr6knwgcSdUoKjFZEivQb14PXcg1b"

#include <BlynkSimpleEsp32.h>
#include <ArduinoJson.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <FlowMeter.h>

// char ssid[] = "afif.khoury";
// char pass[] = "jaad2013";
// char auth[] = "DyeApTOWfgJqcChV15wmL1xpykWn7jhx";
int relayPins[] = {23, 22, 21, 5};
int pushButtonPin = 18;
FlowMeter meters[] = {FlowMeter(1), FlowMeter(2), FlowMeter(3), FlowMeter(4), FlowMeter(5)};
const unsigned long period = 1000;

int relayStates[] = {HIGH, HIGH, HIGH, HIGH};
int pushButtonState = HIGH;
int currentState = 0;
unsigned long startTime = 0;

#define FLOW_CALIBRATION 7.5
#define VPIN_RESET V9

volatile long pulseCounts[5];
float flowRates[5];
unsigned long oldTimes[5];
BlynkTimer timer;


BLYNK_WRITE(V0) { toggleRelay(0); }
BLYNK_WRITE(V1) { toggleRelay(1); }
BLYNK_WRITE(V2) { toggleRelay(2); }
BLYNK_WRITE(V3) { toggleRelay(3); }
BLYNK_WRITE(V4) { handleButtonPress(); }

void toggleRelay(int index) {
  relayStates[index] = relayStates[index] == HIGH ? LOW : HIGH;
  digitalWrite(relayPins[index], relayStates[index]);

  // Update corresponding virtual pins
  switch (index) {
    case 0:
      Blynk.virtualWrite(V0, relayStates[index] == HIGH ? 0 : 1);
      Blynk.virtualWrite(V3, relayStates[index == 0 ? 3 : index - 1] == HIGH ? 0 : 1);
      break;
    case 1:
      Blynk.virtualWrite(V1, relayStates[index] == HIGH ? 0 : 1);
      break;
    case 2:
      Blynk.virtualWrite(V2, relayStates[index] == HIGH ? 0 : 1);
      break;
    case 3:
      Blynk.virtualWrite(V3, relayStates[index] == HIGH ? 0 : 1);
      Blynk.virtualWrite(V0, relayStates[index == 3 ? 0 : index + 1] == HIGH ? 0 : 1);
      break;
  }
}

void handleButtonPress() {
  Blynk.virtualWrite(V4, 1);
  int i = pushButtonState != LOW ? (toggleRelay(0), toggleRelay(1), currentState = 1, startTime = millis(), 0) : HIGH;
  pushButtonState = i == 0 ? LOW : HIGH;

  if (currentState > 0 && millis() - startTime >= 7000) {
    toggleRelay(currentState);
    toggleRelay((currentState + 1) % 4);
    currentState = (currentState + 1) % 4;
    startTime = millis();
  }
}

void checkPhysicalButton() {
  pushButtonState = digitalRead(pushButtonPin) == LOW ? (toggleRelay(0), toggleRelay(1), currentState = 1, startTime = millis(), LOW) : HIGH;

  if (currentState > 0 && millis() - startTime >= 7000) {
    toggleRelay(currentState);
    toggleRelay((currentState + 1) % 4);
    currentState = (currentState + 1) % 4;
    startTime = millis();
  }
}

void Meter1ISR() {
  meters[0].count();
}

void Meter2ISR() {
  meters[1].count();
}

void Meter3ISR() {
  meters[2].count();
}

void Meter4ISR() {
  meters[3].count();
}

void Meter5ISR() {
  meters[4].count();
}



BLYNK_WRITE(VPIN_RESET) {
  if (param.asInt() == 0) Serial.println("Clearing Data");
}

void setup() {
    Serial.begin(115200);
  WiFi.begin("Wokwi-GUEST");
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting...");
  }
  Serial.println("Connected");

  Blynk.config(BLYNK_AUTH_TOKEN);

  attachInterrupt(digitalPinToInterrupt(34), Meter1ISR, RISING);
  attachInterrupt(digitalPinToInterrupt(35), Meter2ISR, RISING);
  attachInterrupt(digitalPinToInterrupt(33), Meter3ISR, RISING);
  attachInterrupt(digitalPinToInterrupt(32), Meter4ISR, RISING);
  attachInterrupt(digitalPinToInterrupt(25), Meter5ISR, RISING);

  for (int i = 0; i < 5; ++i) {
    meters[i].reset();
  }
    for (int i = 0; i < 4; ++i) {
    pinMode(relayPins[i], OUTPUT);
    digitalWrite(relayPins[i], HIGH);
  }
  pinMode(pushButtonPin, INPUT_PULLUP);

  timer.setInterval(100L, []() { Blynk.virtualWrite(V4, 1); });
}

void loop() {
  Blynk.run();
  timer.run();
  checkPhysicalButton();

  // Non-blocking delay using millis
  static unsigned long previousMillis = 0;
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= period) {
    // Your existing loop code here

    for (int i = 0; i < 5; ++i) {
      meters[i].tick(period);
      Blynk.virtualWrite(V11 + i, meters[i].getCurrentFlowrate());
      Serial.println("M" + String(i + 1) + " " + String(meters[i].getCurrentFlowrate()) + " l/min, " + String(meters[i].getTotalVolume()) + " l total.");
    }

    previousMillis = currentMillis;
  }
}

Pulse GeneratorBreakout
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module