#define BLYNK_TEMPLATE_ID "TMPL6bPeeICSM"
#define BLYNK_TEMPLATE_NAME "Aquarium"
#define BLYNK_AUTH_TOKEN "wiKhO7Y2DSyvT7anhFkIdT11mkbGW1bF"

#include <WiFi.h>
#include <PubSubClient.h>
#include <ESP32Servo.h>
#include <Adafruit_NeoPixel.h>
#include <BlynkSimpleEsp32.h>

char auth[] = BLYNK_AUTH_TOKEN;
BlynkTimer timer;

const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqtt_server = "free.mqtt.iyoti.id";    // BROKER
const char* mqtt_client_id = "mqtt_iyoti_Z56vBeiiJp";
const int mqtt_port = 8083;
const char* mqtt_topic_subscribe_light = "smart_aquarium_sister/light";
const char* mqtt_topic_subscribe_water = "smart_aquarium_sister/water";
const char* mqtt_topic_publish_light = "smart_aquarium_sister/light";
const char* mqtt_topic_publish_water = "smart_aquarium_sister/water";

WiFiClient espClient;
PubSubClient client(espClient);
Servo myservo;

const int trigPin = 18;
const int echoPin = 17;
const int ldrPin = 34;
const int servoPin = 4;
const int neoPin = 35; 
const int neoLength = 16; 
const int neoDIN = 12; 
const int SwitchPin = 19;
// #define RelayPin 23
int pakan = 0;
int lastSwitchState = LOW;  // To store the last state of the switch

Adafruit_NeoPixel strip(neoLength, neoDIN, NEO_GRB + NEO_KHZ800);

void beripakan() {
  // Read physical switch state
  int switchState = digitalRead(SwitchPin);
  if (switchState != lastSwitchState) {
    lastSwitchState = switchState;
    pakan = (switchState == HIGH) ? 1 : 0;
    Blynk.virtualWrite(V1, pakan);
  }

  // Control servo based on switch state
  if (pakan == 1) {
    myservo.write(180); // Feed the fish
    Serial.println("Feeding the fish");
  } else {
    myservo.write(0); // Stop feeding
    Serial.println("Fish has been fed");
  }
}

BLYNK_WRITE(V1) {
  pakan = param.asInt();
  digitalWrite(SwitchPin, pakan);
  if (pakan == 1) {
    myservo.write(180); // Feed the fish
    digitalWrite(SwitchPin, HIGH);
    Serial.println("Feeding the fish");
  } else {
    myservo.write(0); // Stop feeding
    digitalWrite(SwitchPin, LOW);
    Serial.println("Fish has been fed");
  }
}

// Setup WiFi
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("WiFi connected - IP address: ");
  Serial.println(WiFi.localIP());
}

// MQTT Callback
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  String messageTemp;

  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    messageTemp += (char)payload[i];
  }
  Serial.println();

  // Handle the incoming message based on the topic
  if (String(topic) == mqtt_topic_subscribe_water) {
    Serial.print("Water level: ");
    Serial.println(messageTemp);
    // Process water level data
  } else if (String(topic) == mqtt_topic_subscribe_light) {
    Serial.print("Light level: ");
    Serial.println(messageTemp);
    // Process light level data
  }
}

// MQTT Reconnect
void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect("ESP32Client")) {
      Serial.println("connected");
      client.subscribe(mqtt_topic_subscribe_water);
      client.subscribe(mqtt_topic_subscribe_light);
      Serial.println("Subscribed to topics");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
  myservo.attach(servoPin);
  strip.begin();
  strip.show();
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(SwitchPin, INPUT);
  // pinMode(RelayPin, INPUT);

  Blynk.begin(auth, ssid, password);
  timer.setInterval(2000L, beripakan);
}

void loop() {
  Blynk.run();
  timer.run();
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  // Handle distance measurement
  long duration, distance;
  digitalWrite(trigPin, LOW);
  delayMicroseconds(5);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(15);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = duration * 0.034 / 2;  // Use the correct conversion factor for cm
  String distanceString = String(distance);
  client.publish(mqtt_topic_publish_water, distanceString.c_str());

  Serial.print("Distance: ");
  Serial.print(distance);
  Serial.println(" cm");

  // Handle light measurement
  int ldrValue = analogRead(ldrPin);
  String ldrStringValue = String(ldrValue);
  client.publish(mqtt_topic_publish_light, ldrStringValue.c_str());
  Serial.print("LDR Value: ");
  Serial.println(ldrValue);
  int neoBrightness = map(ldrValue, 0, 1023, 0, 255);

  Serial.println("Adjusting NeoPixel brightness");
  for(int i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, strip.Color(neoBrightness, neoBrightness, neoBrightness));
  }
  strip.show();
  delay(1000);
}
NOCOMNCVCCGNDINLED1PWRRelay Module