#define BLYNK_TEMPLATE_ID "TMPL6gz3IjEGg"
#define BLYNK_TEMPLATE_NAME "Smart water distribution"
#define BLYNK_AUTH_TOKEN "DyeApTOWfgJqcChV15wmL1xpykWn7jhx"
#include <BlynkSimpleEsp32.h>
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <FlowMeter.h>

int relayPins[] = {23, 22, 21, 5};
int pushButtonPin = 18;
FlowMeter meters[] = {FlowMeter(34), FlowMeter(35), FlowMeter(33), FlowMeter(32), FlowMeter(25)};
const unsigned long period = 1000;

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

BlynkTimer timer;

void toggleRelay(int index) {
  relayStates[index] = !relayStates[index];
  digitalWrite(relayPins[index], relayStates[index]);
  
  int prevIndex = (index == 0) ? 3 : index - 1;
  Blynk.virtualWrite(V0 + index, relayStates[index]);
  Blynk.virtualWrite(V3 + index, relayStates[prevIndex]);

  if (index == 3) {
    int nextIndex = (index == 3) ? 0 : index + 1;
    Blynk.virtualWrite(V0, relayStates[nextIndex]);
  }
}

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 meterISR(int index) {
  meters[index].count();
}

void meterISR_0() { meterISR(0); }
void meterISR_1() { meterISR(1); }
void meterISR_2() { meterISR(2); }
void meterISR_3() { meterISR(3); }
void meterISR_4() { meterISR(4); }

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

void setup() {
  Serial.begin(115200);
  WiFi.begin("Wokwi-GUEST");

  // Wait for WiFi to connect
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to Wokwi-GUEST...");
  }
  Serial.println("Connected to Wokwi-GUEST");

  Blynk.config(BLYNK_AUTH_TOKEN);
  for (int i = 0; i < 5; ++i) {
    attachInterrupt(digitalPinToInterrupt(34 + i), meterISR_0, RISING);
    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();
  delay(period);

  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.");
  }
}
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module