#define BLYNK_TEMPLATE_ID "TMPL6A5Fxm5jf"
#define BLYNK_TEMPLATE_NAME "Embedded Final"
#define BLYNK_AUTH_TOKEN "lKhuCU9PiFCBdZI2JBC8V_tEvg_ySRdQ"
#include <HX711_ADC.h>
#include <EEPROM.h>
#include <BlynkSimpleEsp32.h>
#include <WiFi.h>
#include <ESP32Servo.h> // Include the ESP32Servo library
#include <HX711.h>      // Include the HX711 library

// Pins:
const int HX711_dout = 12; // MCU > HX711 dout pin
const int HX711_sck = 14;  // MCU > HX711 sck pin
#define SERVO_PIN 17        // Pin for the servo motor (D14 on ESP32)
#define SWITCH_PIN1 V0
#define SWITCH_PIN2 V1
#define SCK_PIN V14   // Pin for the HX711 SCK pin
#define DT_PIN V12    // Pin for the HX711 DT pin
#define LED_PIN 23    // Pin for the LED

// HX711 constructor:
HX711_ADC LoadCell(HX711_dout, HX711_sck);

const int calVal_eepromAdress = 0;
unsigned long t = 0;

bool askYesNoQuestion(const char *question) {
  Serial.print(question);
  Serial.println(" (y/n)");
  while (1) {
    if (Serial.available() > 0) {
      char answer = Serial.read();
      if (answer == 'y') {
        return true;
      } else if (answer == 'n') {
        return false;
      }
    }
  }
}

char ssid[] = "Wokwi-GUEST";
char password[] = "";
char auth[] = "lKhuCU9PiFCBdZI2JBC8V_tEvg_ySRdQ";

BlynkTimer timer;
Servo servo; // Create a servo object
int interval = 0; // Global variable to store the blinking interval

void setup() {
  Serial.begin(9600);
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");

  Blynk.begin(auth, ssid, password);

  servo.attach(SERVO_PIN); // Attach the servo to the specified pin

  LoadCell.begin();
  float calibrationValue; // calibration value (see example file "Calibration.ino")
  calibrationValue =  -351.78;   // uncomment this if you want to set the calibration value in the sketch
  //EEPROM.begin(512); // uncomment this if you use ESP8266/ESP32 and want to fetch the calibration value from eeprom
  //EEPROM.get(calVal_eepromAdress, calibrationValue); // uncomment this if you want to fetch the calibration value from eeprom

  unsigned long stabilizingtime = 2000; // precision right after power-up can be improved by adding a few seconds of stabilizing time
  boolean _tare = true; // set this to false if you don't want tare to be performed in the next step
  LoadCell.start(stabilizingtime, _tare);
  if (LoadCell.getTareTimeoutFlag()) {
    Serial.println("Timeout, check MCU > HX711 wiring and pin designations");
    while (1);
  }
  else {
    LoadCell.setCalFactor(calibrationValue); // set calibration value (float)
    //Serial.println("Startup is complete");
  }

  timer.setInterval(1000L, moveServo); // Call the moveServo function every second

  pinMode(LED_PIN, OUTPUT); // Set LED pin as output
}

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

  static boolean newDataReady = 0;
  const int serialPrintInterval = 500; // increase value to slow down serial print activity

  // check for new data/start next conversion:
  if (LoadCell.update()) newDataReady = true;

  // get smoothed value from the dataset:
  if (newDataReady) {
    if (millis() > t + serialPrintInterval) {
      float i = LoadCell.getData();
      Serial.println(String((round(i * 10) / 10.0), 1));
      newDataReady = 0;
      t = millis();
    }
  }

  // receive command from serial terminal, send 't' to initiate tare operation:
  if (Serial.available() > 0) {
    char inByte = Serial.read();
    if (inByte == 't') LoadCell.tareNoDelay();
  }

  // check if last tare operation is complete:
  if (LoadCell.getTareStatus() == true) {
    Serial.println("Tare complete");
  }

  // Read the sensor
  float sensorReading = LoadCell.getData();
  Serial.print("Weight: ");
  Serial.print(sensorReading);
  Serial.println(" g");

  Blynk.virtualWrite(V2, sensorReading);

  // Check if the weight reading is below 250 grams
  if (sensorReading < 250) {
    // Turn on the LED
    digitalWrite(LED_PIN, HIGH);
  } else {
    // Turn off the LED
    digitalWrite(LED_PIN, LOW);
  }

  delay(1000); // Delay for stability
}

BLYNK_WRITE(SWITCH_PIN1)
{
  int buttonValue = param.asInt(); // Read the value of the button (0 or 1)
  interval = buttonValue;          // Set the global interval variable
  Serial.print("Button 1 value: ");
  Serial.println(buttonValue);
}

BLYNK_WRITE(SWITCH_PIN2)
{
  int buttonValue = param.asInt(); // Read the value of the button (0 or 1)
  interval = buttonValue;          // Set the global interval variable
  Serial.print("Button 2 value: ");
  Serial.println(buttonValue);
}

void moveServo()
{
  if (interval > 0)
  {
    servo.write(0);         // Move the servo to 0 degrees
    delay(1000);            // Wait for 1 second
    servo.write(180);       // Move the servo to 180 degrees
    delay((interval - 1) * 1000); // Wait for the remaining duration
  }
  else
  {
    servo.write(90); // If both switches are off, keep the servo at 90 degrees
  }
}