// From https://randomnerdtutorials.com/esp32-mqtt-publish-subscribe-arduino-ide
// Faradilla Syifa Nur'Aini ; 20 ; 11 SIJA A
// TUGAS PKK
// APLIKASI APA YG DIBUAT : MENGONTROL LED DENGAN MENGGUNAKAN PERINTAH YANG DIKIRIM MELALUI PROTOKOL MQTT.
#include <WiFi.h> //blok ini digunakan untuk menghubungkan ESP32 ke jarigan WiFi
#include "PubSubClient.h" //digunakan untuk berinteraksi dengan broker MQTT
// mendeklarasikan variabel konstan
const char* ssid = "Wokwi-GUEST"; // SSID WiFi
const char* password = ""; // password WiFi
const char* mqttServer = "broker.emqx.io"; // alamat server MQTT
int port = 1883; // Port server MQTT
String stMac; // string untuk alamat MAC
char mac[50]; // array karakter untuk alamat MAC
char clientId[50]; // array karakter untuk clientId MQTT
// deklarasikan objek klien WiFi dan MQTT
WiFiClient espClient;
PubSubClient client(espClient);
// menentukan pin LED
const int ledPin = 2;
void setup() { // dijalankan sekali saat program dimulai
// CARA KERJA SETUP :
// inisialisasi komunikasi serial dengan komputer
// menghubungkan ESP32 ke WiFi dengan SSID dan password yg ditentukan
// mencetak alamat IP dan alamat MAC ESP32 ke monitor serial
// mengkonfigurasi broker MQTT dan fungsi callback
// mendefinisikan pin LED sebagai output
Serial.begin(115200); // inisialisasi komunikasi serial pada kecepatan baud rate 115200 bps.
randomSeed(analogRead(0)); // menyetel seed untuk fungsi random
delay(10); // menunda eksekusi program selama 10 milidetik
// menampilkan pesan di monitor serial
// Serial.println : untuk mengirimkan data diikuti dengan karakter carriage return (CR) dan newline (LF)
// Serial.print : mengirimkan data tanpa karakter CR dan LF
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
wifiConnect(); // memanggil fungsi untuk terhubung ke WiFi
// CARA KERJA WIFICONNECT();
// mengatur mode ESP32 sebagai stasiun
// mencoba untuk terhubung ke jaringan WiFi yg ditentukan
// menggunakan loop untuk menunggu koneksi berhasil, ditandai dengan status WL_CONNECTED
// menampilkan informasi koneksi WiFi
Serial.println(""); // mencetak baris kosong ke serial monitor
Serial.println("WiFi connected"); // mencetak pesan "WiFi connected" ke serial monitor. menunjukkan bahwa telah berhasil terhubung ke WiFi
Serial.println("IP address: "); // mencetak pesan "IP address" ke serial monitor. label untuk informasi alamat IP yang akan dicetak selanjutnya.
Serial.println(WiFi.localIP()); // mencetak alamat IP lokal. untuk mengidentifikasi ESP32 di jaringan
Serial.println(WiFi.macAddress()); // mencetak alamat MAC dari ESP32 ke serial monitor. alamat MAC adalah pengenal unik untuk perangkat jaringan
// mendapatkan alamat MAC ESP32 dan menyimpannya dalam string
stMac = WiFi.macAddress(); // mengambil alamat MAC dari perangkat WiFi dan simpan dalam variabel stMac.
stMac.replace(":", "_"); // mengganti semua kemunculan karakter (:) dalam variabel stMAC dengan karakter (_). untuk mengubah format alamat MAC jadi mudah dibaca
Serial.println(stMac); // mencetak nilai variabel stMac ke monitor serial.
// mengatur klien MQTT dengan server dan callback function
client.setServer(mqttServer, port); // mengatur alamat server MQTT dan port yg ingin dihubungi oleh klien MQTT
client.setCallback(callback); // mengatur fungsi callbacl yg akan dipanggil setiap kali pesan baru diterima oleh klien MQTT
pinMode(ledPin, OUTPUT); // menyetel pin LED sebagai output
}
// Fungsi untuk terhubung ke WiFi
void wifiConnect() {
WiFi.mode(WIFI_STA); // mengatur mode ESP32 sebagai STA (stasiun)
WiFi.begin(ssid, password); // mencoba terhubung ke WiFi dengan SSID dan password yg ditentukan
// loop while untuk menunggu koneksi berhasil
while (WiFi.status() != WL_CONNECTED) {
delay(500); // penundaan 500 milidetik
Serial.print("."); // menampilkan titik di monitor serial
}
}
// fungsi untuk koneksi ulang ke broker MQTT
void mqttReconnect() {
// CARA KERJA MQTTRECONNECT :
// looping sampai koneksi MQTT berhasil
// membangkitkan ID klien acak dan menyimpan di clientId
// mencoba koneksi ke server MQTT dengan ID klien yg dibuat
// jika berhasil, subscribe ke topik "topicName/led". jika gagal akan menampilkan pesan error
// loop while untuk terus mencoba koneksi hingga berhasil
while (!client.connected()) {
Serial.print("Attempting MQTT connection..."); // menampilkan pesan di monitor serial
// membuat clientId acak
long r = random(1000); // menghasilkan angka acak antara 0 dan 999 (inklusif). disimpan dalam variabel r.
sprintf(clientId, "clientId-%ld", r); // memformat dan menyimpan data ke dalam sebuah string
// mencoba terhubung ke broker MQTT
if (client.connect(clientId)) {
// menampilkan pesan di monitor serial
Serial.print(clientId);
Serial.println(" connected");
// berlangganan ke topik "topicName/led"
client.subscribe("topicName/led");
} else {
// menampilkan pesan di monitor serial
Serial.print("failed, rc="); // failed menunjukkan kegagalan, rc singkatan dari return code.
Serial.print(client.state()); // fungsi yg mengembalikan kode error spesifik kenapa koneksi gagal.
Serial.println(" try again in 5 seconds"); // menginformasikan bahwa program akan mencoba terhubung kembali ke MQTT broker dalam 5 detik
// penundaan 5 detik sebelum mencoba lagi
delay(5000);
}
}
}
// memproses pesan yg diterima
void callback(char* topic, byte* message, unsigned int length) {
// CARA KERJA CALLBACK
// dikonfigurasikan sebagai fungsi callback untuk menerima pesan MQTT
// mencetak informasi topik dan pesan yg diterima
// memeriksa apakah topik yg diterima sesuai dengan "topicName/led"
// jika sesuai, akan memeriksa isi pesan ("on" atau "off") dan menyalakan/mematikan LED sesuai perintah
// menampilkan informasi topik dan pesan
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(". Message: ");
String stMessage; // deklarasi string untuk menyimpan pesan
// loop untuk iterasi melalui pesan dan menampilkannya karakter per karakter
for (int i = 0; i < length; i++) {
Serial.print((char)message[i]); // menampilkan karakter pesan
stMessage += (char)message[i]; // menambahkan karakter ke string
}
// menampilkan karakter newline
Serial.println();
// mengecek apakah topik sesuai dengan "topicName/led"
if (String(topic) == "topicName/led") {
Serial.print("Changing output to ");
// mengecek isi pesan
if(stMessage == "on"){
Serial.println("on");
digitalWrite(ledPin, HIGH); // menyalakan LED
}
else if(stMessage == "off"){
Serial.println("off");
digitalWrite(ledPin, LOW); // mematikan LED
}
}
}
void loop() {
// CARA KERJA LOOP :
// loop utama program yg dijalankan berulang kali
// memeriksa koneksi MQTT, jika terputus, program akan memanggil fungsi mqttReconnect untuk mencoba terhubung kembali
// memanggil fungsi client.loop() untuk memproses komunikasi dengan broker MQTT
delay(10); //menunda eksekusi selama 10 milidetik
if (!client.connected()) { // memeriksa apakah klien mqtt masih terhubung ke broker. jika tidak terhubung maka kode akan masuk ke blok if
mqttReconnect(); // mencoba menghubungkan kembali klien mqtt ke broker
}
client.loop(); // menjalankan loop utama klien mqtt
}