//============================================================ Deklarasi Library ===========================================================
#include <WiFi.h> //Pemanggilan Library WiFi
#include <PubSubClient.h> //Pemanggilan Library PubSubClient
#include <LiquidCrystal_I2C.h> //Pemanggilan Library LiquidCrystal_I2C
//======================================================= Inisialisasi: Constructor ========================================================
LiquidCrystal_I2C lcd(0x27, 16, 2); //Constructor LiquidCrystal_I2C
WiFiClient espClient; //Constructor WiFiClient
PubSubClient client(espClient); //Constructor PubSubClient
//===================================================== Deklarasi Variabel: Tipe Data ======================================================
//Tipe data Char
char payload_Publish[4];
//Tipe data Float
float payload_Subscribe;
float old_pHValue = 0, pHValue;
//Tipe data Boolean
bool relayON = LOW;
bool relayOFF = HIGH;
bool isPumpOn = false;
unsigned long currentMillis;
unsigned long startTime1 = 0;
unsigned long startTime2 = 0;
const unsigned long delayTime1 = 1000;
const unsigned long delayTime2 = 5000;
unsigned long pumpStartTime1 = 0;
unsigned long pumpStartTime2 = 0;
const unsigned long pumpDuration1 = 10000;
const unsigned long pumpDuration2 = 25000;
bool isMillisFinished = false;
//============================================================= Define Variabel ============================================================
#define ssid "Wokwi-GUEST" //Nama wifi router
#define password "" //Password wifi router
#define mqtt_server "broker.emqx.io" //Nama Platform IoT (Broker)
#define mqtt_port 1883 //Port Io-t.net
#define mqtt_username "" //Username Io-t.net
#define mqtt_password "" //Password Io-t.net
#define mqtt_clientID "client-001" //Client ID Io-t.net
#define INrespYes "INrespYes" //Callback Inline Respon Iya ke-1
#define INrespNo "INrespNo" //Callback Inline Respon Tidak ke-1
#define INrespYes1 "INrespYes1" //Callback Inline Respon Iya ke-2
#define INrespYes2 "INrespYes2" //Callback Inline Respon Iya ke-3
#define INrespNo1 "INrespNo1" //Callback Inline Respon Tidak ke-2
#define INrespYes3 "INrespYes3" //Callback Inline Respon Iya ke-4
#define INrespYes4 "INrespYes4" //Callback Inline Respon Iya ke-5
#define INrespNo2 "INrespNo2" //Callback Inline Respon Tidak ke-3
#define INrespYes5 "INrespYes5" //Callback Inline Respon Iya ke-6
#define INrespYes6 "INrespYes6" //Callback Inline Respon Iya ke-7
#define INrespNo3 "INrespNo3" //Callback Inline Respon Tidak ke-4
#define Topic "detect" //Topic MQTT : detect pH
//============================================================== Method Setup ===============================================================
void setup(){
LCDinit(); //Memanggil method LCDinit
Serial.begin(9600); //Memulai komunikasi serial dengan baud rate 9600
connectWiFi(); //Memanggil method connectWiFi
connectIoT(); //Memanggil method connectIoT (i-ot.net)
Loading(); //LCD view Loading
//Atur waktu agar fungsi millis langsung menyala
startTime1 = millis() - delayTime1;
startTime2 = millis() - delayTime2;
pumpStartTime1 = millis() - pumpDuration1;
pumpStartTime2 = millis() - pumpDuration2;
}
//============================================================== Method Loop ===============================================================
void loop(){
//Ambil waktu saat ini
currentMillis = millis();
//Jika proses sudah selesai, hentikan pemeriksaan millis
if (isMillisFinished) {
return; //Keluar dari loop() tanpa melakukan apa-apa
}
//Pertahankan koneksi IoT
if (!client.connected()) { reconnect(); }
client.loop();
//Jika waktu sekarang dikurangi waktu terakhir lebih besar dari 1 detik maka :
if ((currentMillis - startTime1) > delayTime1) {
readPublishPH(); //Memanggil method readPublishPH
startTime1 = currentMillis; //Perbarui waktu terakhir dijalankan
}
// Viewnow();
LCDAllpHON();
// LCDAllpHOFF();
// LCDpHUpON();
// LCDpHUpOFF();
// LCDpHDownON();
// LCDpHDownOFF();
}
//============================================================= Method LCD Init ============================================================
void LCDinit(){
//Memulai komunikasi serial dengan LCD
lcd.init();
//Start LCD
lcd.clear(); lcd.backlight(); lcd.setCursor(1,0); lcd.print("Memulai"); lcd.setCursor(1,1); lcd.print("Sistem pH..."); delay(1000);
//Welcome LCD
lcd.clear(); lcd.backlight(); lcd.setCursor(1,0); lcd.print("Welcome to"); lcd.setCursor(1,1); lcd.print("PHIOTNET...."); delay(1000);
}
//========================================================== Method Konfigurasi WiFi =======================================================
void connectWiFi(){
Serial.println("\n==================================================================================");
Serial.print("[Konfigurasi Wi-Fi]\nmencoba menghubungkan ke Wi-Fi : ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED){
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("\nstatus :\nWi-Fi berhasil tersambung");
Serial.println(WiFi.localIP());
WiFi.setAutoReconnect(true); //Menyambungkan kembali secara otomatis setelah sambungan terputus
WiFi.persistent(true); //Menyambungkan kembali ke Access Point
delay(1000);
}
//============================================================= Method Koneksi IoT =========================================================
void connectIoT(){
Serial.print("\n[Konfigurasi IoT]\nmencoba menghubungkan ke Platform : ");
Serial.println(mqtt_server);
client.setServer(mqtt_server, mqtt_port);
client.setCallback(receivedCallback);
}
//==================================================== Method Menghubungkan Ulang Jaringan =================================================
void reconnect(){
while(!client.connected()){
if(client.connect(mqtt_clientID, mqtt_username, mqtt_password)){
Serial.println("\nstatus :"); Serial.print(mqtt_server);
Serial.println(" berhasil tersambung");
client.subscribe(Topic);
}
else{
Serial.println("\nstatus :"); Serial.print(mqtt_server);
Serial.print(" gagal tersambung (" + String(client.state()) + ")\nmenyambungkan kembali");
LCDfailIoT(); //LCD view Fail
while(!client.connect(mqtt_clientID, mqtt_username, mqtt_password)){
delay(500);
Serial.print(".");
}
delay(1000);
}
}
}
//===================================================== Method Pemanggilan Topik Subscribe =================================================
void receivedCallback(char* topic, byte* payload, unsigned int length) {
char message[length + 1]; //Membuat variable array untuk menampung data payload
for (int i = 0; i < length; i++) { message[i] = (char)payload[i]; } //Menampung data payload
message[length] = '\0'; //Null terminator
payload_Subscribe = atof(message); //Ubah string ke float dan masukkan ke variabel payload_Subscribe
}
//==================================================== Method Debugging untuk Subscribe ==================================================
void debuggingSubscribe(){
if(payload_Subscribe != 0){
Serial.println("\n[Pemeriksaan Subscribe MQTT]");
Serial.println("Payload: " + String(payload_Subscribe));
Serial.println("\n==================================================================================");
}
}
//============================================================== Method Read pH ============================================================
void readPublishPH(){
pHValue = 7.53; //Menyimpan nilai ke variabel pHValue
//Cek nilai pH ada perubahan atau tidak, jika ada perubahan maka:
if(pHValue != old_pHValue){
dtostrf(pHValue, 4, 2, payload_Publish); //Float -> String
client.publish(Topic, payload_Publish, true); //Publish topik beserta payloadnya menggunakan retain message
// debuggingSubscribe(); //Memanggil method debuggingSubscribe => Jika tidak digunakan sebaiknya dibuat komentar saja
old_pHValue = pHValue; //Menyimpan nilai pH saat ini ke variabel old_pHValue
}
}
//============================================================ Method Output LCD ===========================================================
void Loading(){
lcd.clear(); lcd.backlight(); lcd.setCursor(1,0); lcd.print("Loading...."); delay(5000); Waiting();
}
void Waiting(){
lcd.clear(); lcd.backlight(); lcd.setCursor(1,0); lcd.print("Menunggu"); lcd.setCursor(1,1); lcd.print("Perintah..."); delay(1000);
}
void LCDfailIoT(){
lcd.clear(); lcd.backlight(); lcd.setCursor(1,0); lcd.print("IoT Gagal"); lcd.setCursor(1,1); lcd.print("Tersambung..."); delay(5000);
}
void Viewnow(){
//Jika waktu sekarang dikurangi waktu terakhir lebih besar sama dengan 1 detik maka :
if ((currentMillis - startTime1) >= delayTime1) {
lcd.clear(); lcd.backlight(); lcd.setCursor(2,0); lcd.print("pH Air : "+ String(payload_Subscribe));
startTime1 = currentMillis; //Perbarui waktu terakhir dijalankan
} Waiting();
}
void LCDAllpHON(){
//Jika waktu sekarang dikurangi waktu terakhir lebih besar sama dengan 5 detik maka :
if ((currentMillis - startTime2) >= delayTime2) {
lcd.clear(); lcd.backlight(); lcd.setCursor(4,0); lcd.print("All pH :"); lcd.setCursor(6,1); lcd.print("(ON)");
startTime2 = currentMillis; //Perbarui waktu terakhir dijalankan
} Waiting();
}
void LCDAllpHOFF(){
//Jika waktu sekarang dikurangi waktu terakhir lebih besar sama dengan 5 detik maka :
if ((currentMillis - startTime2) >= delayTime2) {
lcd.clear(); lcd.backlight(); lcd.setCursor(4,0); lcd.print("All pH :"); lcd.setCursor(5,1); lcd.print("(OFF)");
startTime2 = currentMillis; //Perbarui waktu terakhir dijalankan
} Waiting();
}
void LCDpHUpON(){
//Jika waktu sekarang dikurangi waktu terakhir lebih besar sama dengan 5 detik maka :
if ((currentMillis - startTime2) >= delayTime2) {
lcd.clear(); lcd.backlight(); lcd.setCursor(4,0); lcd.print("pH Up :"); lcd.setCursor(6,1); lcd.print("(ON)");
startTime2 = currentMillis; //Perbarui waktu terakhir dijalankan
} Waiting();
}
void LCDpHUpOFF(){
//Jika waktu sekarang dikurangi waktu terakhir lebih besar sama dengan 5 detik maka :
if ((currentMillis - startTime2) >= delayTime2) {
lcd.clear(); lcd.backlight(); lcd.setCursor(4,0); lcd.print("pH Up :"); lcd.setCursor(5,1); lcd.print("(OFF)");
startTime2 = currentMillis; //Perbarui waktu terakhir dijalankan
} Waiting();
}
void LCDpHDownON(){
//Jika waktu sekarang dikurangi waktu terakhir lebih besar sama dengan 5 detik maka :
if ((currentMillis - startTime2) >= delayTime2) {
lcd.clear(); lcd.backlight(); lcd.setCursor(4,0); lcd.print("pH Down:"); lcd.setCursor(6,1); lcd.print("(ON)");
startTime2 = currentMillis; //Perbarui waktu terakhir dijalankan
} Waiting();
}
void LCDpHDownOFF(){
//Jika waktu sekarang dikurangi waktu terakhir lebih besar sama dengan 5 detik maka :
if ((currentMillis - startTime2) >= delayTime2) {
lcd.clear(); lcd.backlight(); lcd.setCursor(4,0); lcd.print("pH Down:"); lcd.setCursor(6,1); lcd.print("(OFF)");
startTime2 = currentMillis; //Perbarui waktu terakhir dijalankan
} Waiting();
}