/* SIJA 2024 - Praktikum
  Judul Aplikasi    : ESP32 MQTT Publisher
  Deskripsi         : mengirimkan data angka over internet 
                      menggunakan protokol MQTT
  Author            : Sugiarto
--------------------------------------------------------- */

// Mengakses library
#include <WiFi.h>           // library WiFi esp32
#include <PubSubClient.h>   // library MQTT

// Data akun Wifi yang disediakan wokwi
const char* ssid = "Wokwi-GUEST";
const char* password = "";

// Data MQTT Broker
char *mqttServer  = "broker.hivemq.com";
int mqttPort      = 1883;
char *mqttTopic   = "sija/iot/mqtt/demo";

// Variabel data yang dikirim
int angka = 0;      // variabel angka bertipe integer
String myString ;   // variabel myString bertipe string

// Membuat object 
WiFiClient wifiClient;                // Membuat objek wifiClient
PubSubClient mqttClient(wifiClient);  // Membuat  objek mqttClient dengan konstruktor objek WiFiClient (Permintaan dari Lib)

// Mendeklarasikan function
void connectToInternet();
void setupMQTT();
void reconnectMQTT();

// blok setup menginisalisasi program
// konfigurasi program sebelum dijalankan
void setup() {
  pinMode(2, OUTPUT);
   Serial.begin(115200);   //mengaktifkan Serial monitor

  // memanggil function connectToInternet() untuk koneksi ke SSID
  //connectToInternet();

  // memanggil function setupMQTT() untuk koneksi ke MQQ Broker
  //setupMQTT(); // setup koneksi ke broker
  connectToInternet(); //memanggil void setup_wifi untuk dieksekusi
  mqttClient.setServer(mqttServer, 1883); //perintah connecting
  mqttClient.setCallback(callback); //perintah menghubungkan ke mqtt broker untuk subscribe data
}

// Program utama atau main program
void loop() {
    //Mengecek koneksi ke MQTT Broker
  if (!mqttClient.connected()){
    reconnectMQTT(); // jika putus koneksi, dicoba lagi  
  }
    // koneksi ke MQTT broker lancar
 // mengirimkan data angka 0 - 100 dengan jeda 1 detik 
  if (angka<100){
    //menampilkan data pada Serial monitor
    Serial.print("Angka : ");
    Serial.println(angka);

    // mempublish data angka ke MQTT broker
    // data yang dikirim harus bertipe string
    // data angka dikonversi ke string dengan object String().c_str()
    mqttClient.publish(mqttTopic,String(angka).c_str());
    delay(1000);

    // menambah counter angka
     angka++;
  }
  else {
    // angka direset kembali ke nol
    angka = 0;
  }
}

// function connectToInternet()
// bertugas menjalankan tugas konek ke SSID
void connectToInternet(){
  WiFi.begin(ssid, password);   // Mencoba connect ke Wifi

  // Melakukan pengecekan terhadap status koneksi ke WI-Fi
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    } 
    Serial.println("");
    Serial.println("Connected to Wi-Fi");
}


// mengatur dan menginisialisasi koneksi ke broker MQTT 
void setupMQTT() {
  mqttClient.setServer(mqttServer, mqttPort); // Mengatur detail broker target  yang digunakan
  subscribeMQTT(); // subscribe ke topik MQTT
}

// fungsi callback untuk menangani pesan yang masuk dari broker MQTT
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

// menambahkan fungsi subscriber ke broker MQTT
void subscribeMQTT() {
  mqttClient.setCallback(callback); // menghubungkan callback dengan subscriber
  mqttClient.subscribe(mqttTopic); // subscribe ke topik yang ditentukan
}

// untuk melakukan koneksi ulang (reconnect) ke broker MQTT 
// jika klien kehilangan koneksi dengan broker 
// atau gagal melakukan koneksi saat pertama kali menjalankan program.
// ESP32 Reconnect to broker
void reconnectMQTT() {
  Serial.println("Connecting to MQTT Broker...");
  while (!mqttClient.connected()) {
      Serial.println("Reconnecting to MQTT Broker..");

      //membuat Cliend ID untuk setiap device
      String clientId = "ESP32Client-";
      clientId += String(random(0xffff), HEX);
      
      // menampilkan pesan koneksi ke MTQQ broker sukses
      if (mqttClient.connect(clientId.c_str())) {
        Serial.println("Connected.");
        mqttClient.subscribe("sija/iot/mqtt/demo"); //perintah subscribe data ke mqtt broker
    } else {
        Serial.print("failed, rc=");
        Serial.print(mqttClient.state());
        Serial.println(" try again in 5 seconds");
        // Wait 5 seconds before retrying
        delay(5000);
      }      
  }
}