#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <ESP32Servo.h>
#include "icons.h"
#include <Wire.h>
#include "WiFi.h"

#include "ThingsBoard.h"
#include "DHTesp.h"

#ifdef CORE_DEBUG_LEVEL
#undef CORE_DEBUG_LEVEL
#endif

#define CORE_DEBUG_LEVEL 3
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG

// ini re-map pin SDA dan SCL
#define I2C_SDA 1
#define I2C_SCL 2

TwoWire I2CBME = TwoWire(0);

/* Locking mechanism definitions */
#define SERVO_PIN 41
#define SERVO_LOCK_POS   20
#define SERVO_UNLOCK_POS 90

Servo ServoMotor; // menamakan objek servo

int buzzpin  = 4;
int pinPIR   = 42;
int PIRState = LOW;

int kipasAngin = 7; // hidup kalau suhu tinggi
int pengkabut = 8; // hidup kalau kelembaban tinggi
int pemanas = 9; // hidup kalau suhu rendah
int exhauseFan = 10; // hidup kalau kipas angin hidup
int fanAmonia = 11; // hidup kalau amonia >= 20 ppm, exhause fan juga hidup
int fanCO2 = 12; // hidup kalau CO2 > 0,21% exhause juga hidup
int lampudalam = 13; // hidup kalau mulai agak gelap
int lampuluar = 14; // hidup kalau sudah gelap

int lampuDalamLDR = 16; // ini lampu dalam kandang
int lampuLuarLDR = 17; // ini lampu luar kandang

int gelapkandang; // batas kandang dikatakan gelap
// sekalian memicu lampu dalam aktif
int gelapluar; // batas luar kandang dikatakan gelap.
// sekalian memicu PIR aktif dan lampu luar aktif

int RedpinLock = 18; // indikator terkunci
int GreenpinUnlock = 15; //indikator terbuka
int position = 0;
char* password = "789"; 

boolean bolehMasuk = false;

LiquidCrystal_I2C lcd(0x27,20,4);

const uint8_t ROWS = 4;
const uint8_t COLS = 4;
char keys[ROWS][COLS] = {
  { '1', '2', '3', 'A' },
  { '4', '5', '6', 'B' },
  { '7', '8', '9', 'C' },
  { '*', '0', '#', 'D' }
};

uint8_t colPins[COLS] = { 26, 21, 20, 19 }; // Pins connected to C1, C2, C3, C4
uint8_t rowPins[ROWS] = { 36, 35, 34, 33 }; // Pins connected to R1, R2, R3, R4

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

#define WIFI_SSID           "Wokwi-GUEST" //deklarasi ssid wifi yang digunakan, disesuiakan dengan wifi yang digunakan
#define WIFI_PASSWORD       "" //deklarasi password wifi yang digunakan

// See https://thingsboard.io/docs/getting-started-guides/helloworld/
// to understand how to obtain an access token
#define TOKEN               "YhBWN8wZDWTWxFx2fdrL" //SESUAIKAN token masing-masing
#define THINGSBOARD_SERVER  "thingsboard.cloud" //alamat server dari thingsboard, jika menggunakan server probadi alamatnya bisa disesuaikan, apabila menggunakan server yang disediakan thingsboard alamatnya adalah thingsboar.cloud

const int DHTSuhuHuma_PIN = 5; //deklarasi nomor pin dht
const int DHTAmoniaCO2_PIN = 3; //deklarasi nomor pin dht

DHTesp dhtSuhu; // deklarasi objek suhu dan kelembaban
DHTesp dhtGas; // deklarasi objek gas amonia dan metana

// Deklarasi Thingsboard client dan mengubah perintah WiFiClient menjadi espClient
WiFiClient espClient; 
// Deklarasi untuk mengubah perintah Thingsboard menjadi tb dan memasukkan perintah WiFiClient yang sudah diubah menjadi espClient ke dalam library Thingsboard
ThingsBoard tb(espClient);

int status = WL_IDLE_STATUS; //deklarasi status wifi yang dimasukkan dalam variabel status

void connect() //void mengoneksikan esp dengan wifi pertama kali
{
  Serial.println("Connecting to AP ...");
  // attempt to connect to WiFi network

  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {

    delay(500);
    Serial.print(".");
  }
  Serial.println("Connected to AP");
}

void reconnect() { //perintah recconect wifi apabila esp terputus dengan jaringan wifinya
  // Loop until we're reconnected
  status = WiFi.status();
  if ( status != WL_CONNECTED) {
    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
    Serial.println("Connected to AP");
  }
}

void showStartupMessage() {
  lcd.setCursor(4, 0);
  lcd.print("Welcome!");
  delay(500);
  lcd.setCursor(0,1);
  lcd.println("IoT2-12 Kelompok 1");
  lcd.setCursor(0, 2);
  String message = "Farm Controller";
  for (byte i = 0; i < message.length(); i++) {
    lcd.print(message[i]);
    delay(50);
  }
  delay(500);
}

void setup() {
  Wire.setPins(I2C_SDA, I2C_SCL); // re-map
  lcd.init();
  lcd.backlight();
  lcd.begin(16,2);

  Serial.begin(9600);

  pinMode(SERVO_PIN, OUTPUT);
  pinMode(buzzpin, OUTPUT);
  pinMode(kipasAngin, OUTPUT);
  pinMode(pengkabut, OUTPUT);
  pinMode(pemanas, OUTPUT);
  pinMode(exhauseFan, OUTPUT);
  pinMode(fanAmonia, OUTPUT);
  pinMode(fanCO2, OUTPUT);
  pinMode(lampudalam, OUTPUT);
  pinMode(lampuluar, OUTPUT);

  pinMode(RedpinLock, OUTPUT); // indikator terkunci
  pinMode(GreenpinUnlock, OUTPUT); //indikator terbuka

  pinMode(lampuDalamLDR, INPUT);
  pinMode(lampuLuarLDR, INPUT);
  pinMode(pinPIR, INPUT);

  //wifi
  connect();

  gelapkandang = analogRead(lampuDalamLDR);
  gelapluar    = analogRead(lampuLuarLDR);

  digitalWrite(RedpinLock, HIGH); // indikator terkunci
  digitalWrite(GreenpinUnlock, LOW); //indikator terbuka  

  dhtSuhu.setup(DHTSuhuHuma_PIN, DHTesp::DHT22); // suhu dan kelembaban
  dhtGas.setup(DHTAmoniaCO2_PIN, DHTesp::DHT22); // amonia dan CO2

  init_icons(lcd);
/*
	ESP32PWM::allocateTimer(0);
	ESP32PWM::allocateTimer(1);
	ESP32PWM::allocateTimer(2);
	ESP32PWM::allocateTimer(3);
	ServoMotor.setPeriodHertz(50);    // standard 50 hz servo
*/  
  showStartupMessage();
  delay(500);
  position = 0; // posisi servo
  ServoMotor.attach(SERVO_PIN, 500, 2400);
  LockedPosition(true);

}

void loop() 
{
  //thingsboard
  if (!tb.connected()) {
    // Connect to the ThingsBoard
    Serial.print("Connecting to: ");
    Serial.print(THINGSBOARD_SERVER);
    Serial.print(" with token ");
    Serial.println(TOKEN);
    if (!tb.connect(THINGSBOARD_SERVER, TOKEN)) {
      Serial.println("Failed to connect");
      return;
    }else{

      Serial.println("Connected to thingsboard");
    }
  }
  TempAndHumidity  data = dhtSuhu.getTempAndHumidity();
  TempAndHumidity  data_gas = dhtGas.getTempAndHumidity();

  char key = keypad.getKey();
  if (key == '*' || key == '#')
    {
      position = 0;
      LockedPosition(true);
    }
  if (key == password[position])
    {
      position ++;
    }
  if (position == 3)
    {
      LockedPosition(false);
    }
  delay(100);
  if (bolehMasuk)
  {
    lcd.clear();
    /*cekPenyusup();
    cekLampuLuar();
    cekLampuKandang();
    cekSuhuKelembaban();
    cekAmoniaCO2();   
    */  
  }
  cekPenyusup();
    cekLampuLuar();
    cekLampuKandang();
    cekSuhuKelembaban();
    cekAmoniaCO2();
  tb.loop();
}

void LockedPosition(int locked)
{
  if (locked)
    {
      lcd.clear();
      lcd.setCursor(4,0);
      lcd.print("Masukkan kode"); // lode 789

      digitalWrite(RedpinLock, HIGH);
      digitalWrite(GreenpinUnlock, LOW);
      ServoMotor.write(11);
    }
  else
    {
      digitalWrite(RedpinLock, LOW);
      digitalWrite(GreenpinUnlock, HIGH);
      ServoMotor.write(90);
      delay(15);
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Kunci terbuka");        
      delay(3000);  
      bolehMasuk = true;
    }
     
}

void cekLampuKandang()
{
  int gelapkandang = analogRead(lampuDalamLDR); 
 
  if(gelapkandang <  800)
  {
    digitalWrite (lampudalam, HIGH);
    tb.sendTelemetryBool("ceklampukandang", true);
    Serial.println("Lampu kandang On");
    delay(1000);      
  }
  else
  {
    digitalWrite (lampudalam, LOW);
    tb.sendTelemetryBool("ceklampukandang", false);
    Serial.println("Lampu kandang Off");
    delay(1000);
  }  
}

void cekLampuLuar()
{
  int gelapluar = digitalRead(lampuLuarLDR); 
 
  if(gelapluar <  200)
  {
    analogWrite (lampuluar, HIGH);
    tb.sendTelemetryBool("ceklampuluar", true);
    Serial.println("Lampu luar On");
    delay(1000);
  }
  else
  {
    digitalWrite (lampuluar, LOW);
    tb.sendTelemetryBool("ceklampuluar", false);
    Serial.println("Lampu luar Off");
    delay(1000);    
  }  
}

void cekSuhuKelembaban() 
{
  float t = dhtSuhu.getTemperature();
  float h = dhtSuhu.getHumidity();

  if(t > 24 )
  {
    tone(buzzpin,1500, 250);
    digitalWrite(kipasAngin, HIGH);
    digitalWrite(exhauseFan, HIGH);
    digitalWrite(pengkabut, HIGH);
    digitalWrite(pemanas, LOW);
//    delay(1000);    
  } else 
  {
    tone(buzzpin,1500, 250);    
    digitalWrite(pemanas, HIGH);
    digitalWrite(exhauseFan, HIGH);
    digitalWrite(pengkabut, LOW);    
//    delay(1000);    
  }

  if(h > 70 )
  {
    tone(buzzpin,1000,250);
    digitalWrite(kipasAngin, HIGH);
    digitalWrite(exhauseFan, HIGH);
    digitalWrite(pengkabut, HIGH);
    digitalWrite(pemanas, HIGH);
//    delay(1000);    
  } else 
  {
    tone(buzzpin,1000, 250);    
    digitalWrite(pemanas, LOW);
    digitalWrite(pengkabut, LOW);
    digitalWrite(exhauseFan, HIGH);
//    delay(1000);    
  }

  tb.sendTelemetryFloat("temperature", t);
  tb.sendTelemetryFloat("humidity", h);

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Suhu & Kelembaban");
  lcd.setCursor(0,1);
  lcd.print("Temp: " + String(t, 2) + "°C");
  lcd.setCursor(0,2);
  lcd.print("Humidity: " + String(h, 1) + "%");
  delay(1000);
}

void cekAmoniaCO2() 
{
  float a = dhtGas.getTemperature(); // amonia
  float c = dhtGas.getHumidity(); // co2
const char* json;

  if (a > 25)
  {
    tone(buzzpin,1750, 250);      
    digitalWrite(kipasAngin, HIGH);
    digitalWrite(exhauseFan, HIGH);
    digitalWrite(fanAmonia, HIGH);
    tb.sendTelemetryBool("kipasAngin",true);
    tb.sendTelemetryBool("exhauseFan",true);
    tb.sendTelemetryBool("fanAmonia",true);
//    delay(1000);    
  }
  else
  {
    tone(buzzpin,1750, 250);         
    digitalWrite(pemanas, LOW);
    digitalWrite(pengkabut, LOW);
    digitalWrite(exhauseFan, HIGH);
    tb.sendTelemetryBool("pemanas",false);
    tb.sendTelemetryBool("pengkabut",false);
    tb.sendTelemetryBool("exhauseFan",true);
//    delay(1000);    
  }

  if (c > 50)
  {
    tone(buzzpin,1950, 250);         
    digitalWrite(kipasAngin, HIGH);
    digitalWrite(exhauseFan, HIGH);
    digitalWrite(fanCO2, HIGH);
    tb.sendTelemetryBool("kipasAngin",true);
    tb.sendTelemetryBool("exhauseFan",true);
    tb.sendTelemetryBool("fanCO2",true);
//    delay(1000);
  }
  else
  {
    tone(buzzpin,1950, 250);         
    digitalWrite(pemanas, LOW);
    digitalWrite(pengkabut, LOW);
    digitalWrite(exhauseFan, LOW);
    tb.sendTelemetryBool("pemanas",false);
    tb.sendTelemetryBool("pengkabut",false);
    tb.sendTelemetryBool("exhauseFan",false);
//    delay(1000);    
  }
  tb.sendTelemetryFloat("amonia", a);
  tb.sendTelemetryFloat("co2", c);
  
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Amonia & CO2");
  lcd.setCursor(0,1);
  lcd.print("Amonia: " + String(a, 2) + "ppm");
  lcd.setCursor(0,2);
  lcd.print("CO2   : " + String(c, 1) + "%");
  delay(1000);  
}

void cekPenyusup() 
{
  int val = digitalRead(pinPIR); 
  if (val == HIGH) {           
    if (PIRState == LOW) {
      tone(buzzpin, 800, 150);
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Motion detected!");
      PIRState = HIGH;
      digitalWrite(pinPIR, HIGH);
      delay(1000);      
    }
  } else {
    if (PIRState == HIGH) {
      tone(buzzpin,800,150);
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Motion ended!");
      PIRState = LOW;
      delay(1000);      
    }
  }  

}  

Loading
esp32-s2-devkitm-1