#define BLYNK_TEMPLATE_ID "TMPL6gz3IjEGg"
#define BLYNK_TEMPLATE_NAME "Smart water distribution system"
#define BLYNK_AUTH_TOKEN "DyeApTOWfgJqcChV15wmL1xpykWn7jhx"

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

#define PULSE_PIN 5  // Example Pin - Change as needed
#define FLOW_CALIBRATION 7.5  // Example value - Change as needed

// Blynk virtual pin settings for Flow Sensor
#define VPIN_TOTAL_LITERS V10
#define VPIN_FLOW_RATE V8
#define VPIN_FLOW_RATE1 V11
#define VPIN_FLOW_RATE2 V12
#define VPIN_FLOW_RATE3 V13
#define VPIN_FLOW_RATE4 V14
#define VPIN_RESET V9
#define PULSE_PIN_1 36
#define PULSE_PIN_2 39
#define PULSE_PIN_3 34
#define PULSE_PIN_4 35

// Relay control settings
int relay1State = HIGH;
int relay2State = HIGH;
int relay3State = HIGH;
int relay4State = HIGH;
int pushButton1State = HIGH;

int RELAY_PIN_1 = 23;
int RELAY_PIN_2 = 22;
int RELAY_PIN_3 = 21;
int RELAY_PIN_4 = 19;
static int currentState = 0;
static unsigned long startTime = 0;
int PUSH_BUTTON_1 = 18;

// Flow Sensor Water Meter settings
volatile long pulseCount = 0;
float flowRate;
float flowRate1;
float flowRate2;
float flowRate3;
float flowRate4;

unsigned int flowMilliLitres;
unsigned long totalMilliLitres;
float totalLitres;
float totalLitresold;
unsigned long oldTime;

// Blynk Timer
BlynkTimer timer;

BLYNK_WRITE(V0) {
  relay1State = param.asInt() == HIGH ? LOW : HIGH;
  digitalWrite(RELAY_PIN_1, relay1State);
}

BLYNK_WRITE(V1) {
  relay2State = param.asInt() == HIGH ? LOW : HIGH;
  digitalWrite(RELAY_PIN_2, relay2State);
}

BLYNK_WRITE(V2) {
  relay3State = param.asInt() == HIGH ? LOW : HIGH;
  digitalWrite(RELAY_PIN_3, relay3State);
}

BLYNK_WRITE(V3) {
  relay4State = param.asInt() == HIGH ? LOW : HIGH;
  digitalWrite(RELAY_PIN_4, relay4State);
}

BLYNK_WRITE(V4) {
int i = param.asInt();
  if (i == 0) {
    if (pushButton1State != LOW) {
      relay1State = !relay1State;
      relay2State = !relay2State;

      digitalWrite(RELAY_PIN_1, relay1State);
      digitalWrite(RELAY_PIN_2, relay2State);
      Blynk.virtualWrite(V0, relay1State == HIGH ? LOW : HIGH);
      Blynk.virtualWrite(V1, relay2State == HIGH ? LOW : HIGH);
      startTime = millis();
      currentState = 1;
    }
    pushButton1State = LOW;
  } else {
    pushButton1State = HIGH;
  }

  if (currentState == 1 && millis() - startTime >= 7000) {
    currentState = 2;
    relay2State = !relay2State;
    relay3State = !relay3State;
    digitalWrite(RELAY_PIN_2, relay2State);
    digitalWrite(RELAY_PIN_3, relay3State);
    Blynk.virtualWrite(V1, relay2State == HIGH ? LOW : HIGH);
    Blynk.virtualWrite(V2, relay3State == HIGH ? LOW : HIGH);
    startTime = millis();
  } else if (currentState == 2 && millis() - startTime >= 7000) {
    currentState = 3;
    relay3State = !relay3State;
    relay4State = !relay4State;
    digitalWrite(RELAY_PIN_3, relay3State);
    digitalWrite(RELAY_PIN_4, relay4State);
    Blynk.virtualWrite(V2, relay3State == HIGH ? LOW : HIGH);
    Blynk.virtualWrite(V3, relay4State == HIGH ? LOW : HIGH);
    startTime = millis();
  } else if (currentState == 3 && millis() - startTime >= 7000) {
    currentState = 0;
    relay4State = !relay4State;
    relay1State = !relay1State;
    digitalWrite(RELAY_PIN_1, relay1State);
    digitalWrite(RELAY_PIN_4, relay4State);
    Blynk.virtualWrite(V0, relay1State == HIGH ? LOW : HIGH);
    Blynk.virtualWrite(V3, relay4State == HIGH ? LOW : HIGH);
  }
}

void checkPhysicalButton() {
    if (digitalRead(PUSH_BUTTON_1) == LOW) {
    if (pushButton1State != LOW) {
      relay1State = !relay1State;
      relay2State = !relay2State;

      digitalWrite(RELAY_PIN_1, relay1State);
      digitalWrite(RELAY_PIN_2, relay2State);
      Blynk.virtualWrite(V0, relay1State == HIGH ? LOW : HIGH);
      Blynk.virtualWrite(V1, relay2State == HIGH ? LOW : HIGH);

      startTime = millis();
      currentState = 1;
    }
    pushButton1State = LOW;
  } else {
    pushButton1State = HIGH;
  }

  if (currentState == 1 && millis() - startTime >= 7000) {
    currentState = 2;
    relay2State = !relay2State;
    relay3State = !relay3State;
    digitalWrite(RELAY_PIN_2, relay2State);
    digitalWrite(RELAY_PIN_3, relay3State);
    Blynk.virtualWrite(V1, relay2State == HIGH ? LOW : HIGH);
    Blynk.virtualWrite(V2, relay3State == HIGH ? LOW : HIGH);
    startTime = millis();
  } else if (currentState == 2 && millis() - startTime >= 7000) {
    currentState = 3;
    relay3State = !relay3State;
    relay4State = !relay4State;
    digitalWrite(RELAY_PIN_3, relay3State);
    digitalWrite(RELAY_PIN_4, relay4State);
    Blynk.virtualWrite(V2, relay3State == HIGH ? LOW : HIGH);
    Blynk.virtualWrite(V3, relay4State == HIGH ? LOW : HIGH);
    startTime = millis();
  } else if (currentState == 3 && millis() - startTime >= 7000) {
    currentState = 0;
    relay4State = !relay4State;
    relay1State = !relay1State;
    digitalWrite(RELAY_PIN_1, relay1State);
    digitalWrite(RELAY_PIN_4, relay4State);
    Blynk.virtualWrite(V0, relay1State == HIGH ? LOW : HIGH);
    Blynk.virtualWrite(V3, relay4State == HIGH ? LOW : HIGH);
  }
}

// Blynk Timer function for Flow Sensor
void sendtoBlynk() {
  // Your existing code for sending data to Blynk
}

// Interrupt service routine for the flow sensor
void pulseCounter() {
  // Your existing code for pulse counter
}

void pulseCounter1() {
  // Your existing code for pulse counter 1
}

void pulseCounter2() {
  // Your existing code for pulse counter 2
}

void pulseCounter3() {
  // Your existing code for pulse counter 3
}

void pulseCounter4() {
  // Your existing code for pulse counter 4
}

// Function to calculate flow rate and update total liters
void flow() {
  // Your existing code for flow calculation
}

void flow1() {
  // Your existing code for flow calculation 1
}

void flow2() {
  // Your existing code for flow calculation 2
}

void flow3() {
  // Your existing code for flow calculation 3
}

void flow4() {
  // Your existing code for flow calculation 4
}

BLYNK_WRITE(VPIN_RESET) {
  // Your existing code for handling virtual pin V9
}

void setup() {
  Serial.begin(115200);
  
  // Connect to Wokwi-GUEST virtual WiFi (open network)
  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");

  pinMode(RELAY_PIN_1, OUTPUT);
  pinMode(RELAY_PIN_2, OUTPUT);
  pinMode(RELAY_PIN_3, OUTPUT);
  pinMode(RELAY_PIN_4, OUTPUT);
  digitalWrite(RELAY_PIN_1, HIGH);
  digitalWrite(RELAY_PIN_2, HIGH);
  digitalWrite(RELAY_PIN_3, HIGH);
  digitalWrite(RELAY_PIN_4, HIGH);
  pinMode(PUSH_BUTTON_1, INPUT_PULLUP);

  // Flow sensor setup
  pinMode(PULSE_PIN, INPUT);
  attachInterrupt(PULSE_PIN, pulseCounter, FALLING);

  pinMode(PULSE_PIN_2, INPUT);
  attachInterrupt(PULSE_PIN_2, pulseCounter2, FALLING);

  pinMode(PULSE_PIN_3, INPUT);
  attachInterrupt(PULSE_PIN_3, pulseCounter3, FALLING);

  pinMode(PULSE_PIN_4, INPUT);
  attachInterrupt(PULSE_PIN_4, pulseCounter4, FALLING);
Blynk.config(BLYNK_AUTH_TOKEN);
  // Blynk setup
  //Blynk.begin(BLYNK_AUTH_TOKEN, "YourTemplateName", BLYNK_TEMPLATE_ID);
  timer.setInterval(100L, checkPhysicalButton);
  timer.setInterval(100L, sendtoBlynk); // send values to Blynk server every 10 sec
}

void loop() {
  Blynk.run();
  timer.run();
  flow(); // Call flow function to calculate flow rate and update total liters
  flow1();
  flow2();
  flow3();
  flow4();
}
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module