#include <Wire.h>
#include <WiFi.h>
#include "HX711.h"
#include <HCSR04.h>
#include <PubSubClient.h>
#include <LiquidCrystal_I2C.h>

#define MSG_BUFFER_SIZE  (150)
char msg[MSG_BUFFER_SIZE] ="{\"Tinggi\":\"%d\",\"Berat\":\"%s\"}";
char pesan[150];

const char* ssid     = "Wokwi-GUEST";
const char* password = "";
const char* mqtt_server = "mqtt.telkomiot.id";
const char* topik = "v2.0/pubs/APP64fa8fd39af6262241/DEV64ff3887eb9dc37638";
String AccessKey = "18a72cd8229e1b2c";
String AccessToken = "18a72cd8229ededb";
String clientId = "Dev1";

float scale_offset = 8384633;
float calibration_factor = -14.7;
float GRAM;
bool locked = false;
static unsigned long previousMillis = 0;
static long previousWeight = 0;
static bool isStable = false;
unsigned long currentMillis ;
long weightDiff;
float mem_gram = 0;
long timer;
int jarak;
float kg;
String payload;

const int Trig = 25; 
const int Echo = 26;

HX711 scale;


LiquidCrystal_I2C lcd(0x27, 16, 2);

WiFiClient espClient;
PubSubClient client(espClient);

void setup(){
  Serial.begin(115200);
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  Serial.begin(115200);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  client.setServer(mqtt_server, 1883);
  Serial.println("");
  scale.begin(2, 4);
  scale.set_offset(scale_offset);
  scale.set_scale();
  long zero_factor = scale.read_average();
  Serial.print("Zero factor: ");
  Serial.println(zero_factor);
  pinMode(Trig, OUTPUT);
  pinMode(Echo, INPUT);
  lcd.init();
  lcd.backlight();
  
}

void reconnect(){
  while (!client.connected()) {
  Serial.print("Attempting MQTT connection...");
    if (client.connect(clientId.c_str(), AccessKey.c_str(), AccessToken.c_str())) {
      Serial.println("connected");
      client.publish(topik, "Timbangan");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

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

  sprintf(pesan, msg,jarak,kg);
  Serial.print("Publish Mesasage");
  Serial.println(pesan);
  client.publish(topik,pesan);
  delay(1000);
// ultrasonic 
  digitalWrite(Trig, LOW);
  delayMicroseconds(2);
  digitalWrite(Trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(Trig, LOW);
  timer = pulseIn(Echo, HIGH);
  jarak = timer / 58;
  delay(300);

  if (jarak <= 100){
    Serial.print("Jarak = ");
    Serial.print(jarak);
    Serial.println(" cm");
    lcd.setCursor(0, 0);
    lcd.print("Tinggi = ");
    lcd.setCursor(8, 0);
    lcd.print(jarak);
    lcd.setCursor(12, 0);
    lcd.print("CM");
  } else {
    lcd.clear();
    Serial.println("ERROR");
    lcd.setCursor(0, 0);
    lcd.print("Error");
  }
  //  load cell
  scale.set_scale(calibration_factor);
  GRAM = scale.get_units(), 4;
  if (GRAM < 1000)
  {
    GRAM = 0;
  }
  if ((!locked) && (GRAM > 10000))
  {
    locked = true;
  }
  if (GRAM < 10000)
  {
    locked = false;
  }
  mem_gram = GRAM;
  isStable = false;
  currentMillis = millis();
  if (currentMillis - previousMillis >= 2000)
  {
    mem_gram = scale.get_units(), 4;
    if (mem_gram > 10000)
      Serial.println(mem_gram / 1000);
    previousMillis = currentMillis;
    weightDiff = abs(mem_gram - previousWeight);
    previousWeight = mem_gram;
    if (weightDiff <= 500)
      isStable = true;
    else
      isStable = false;
    if (weightDiff <= 500 && isStable)
    {
      if (locked)
      {
        if (mem_gram > 100000)
        {
          float kg = mem_gram / 1000;
          String payload = String(kg, 2) ;
          Serial.print("Berat = ");
          Serial.print(payload);
          Serial.print("kg");
          lcd.setCursor(0,1);
          lcd.print("Berat = ");
          lcd.setCursor(8,1);
          lcd.print(payload);
          lcd.setCursor(11,1);
          lcd.print("kg");
          while (locked)
          {
            GRAM = scale.get_units(), 4;
            if (GRAM < 10000)
            {
              locked = false;
              // Serial.println("0.1");
              // lcd.clear();
              // lcd.setCursor(0,1);
              // lcd.print("Errror")
            }
          }
        }
        else
        {
          float kg = mem_gram / 1000;
          String payload = String(kg, 2) ;
          Serial.println(payload);
          while (locked)
          {
            GRAM = scale.get_units(), 4;
            if (GRAM < 10000)
            {
              locked = false;
              Serial.println("0.0");
            }
          }
        }
      }
    }
  }
}