#include <WiFi.h>
#include <PubSubClient.h>
// #include <stdlib.h>
#include <ArduinoJson.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define LEBAR_LAYAR 128
#define TINGGI_LAYAR 64
Adafruit_SSD1306 display(LEBAR_LAYAR, TINGGI_LAYAR, &Wire, -1);
// =================== KONFIGURASI WI-FI ===================
// const char* ssid = "Galaxy1"; // Ganti dengan WiFi Anda
// const char* password = "12345678"; // Ganti dengan Password WiFi
const char* ssid = "Wokwi-GUEST"; // Setting your AP SSID
const char* password = ""; // Setting your AP PSK
// =================== KONFIGURASI MQTT ====================
const char* mqtt_server = "test.mosquitto.org";
const int mqtt_port = 1883;
// String clientId = "SF_A_" + String(random(1000, 9999));
String clientId = "SF_A_kel1_AIUKSW";
WiFiClient espClient;
PubSubClient client(espClient);
// =================== PIN & VARIABEL ======================
// const int pinSoilSensorA1 = 36;
// const int pinSoilSensorA2 = 39;
// const int relayA1 = 33; // Relay untuk Pompa A1
// const int relayA2 = 32; // Relay untuk Pompa A2 (kontrol dari SF_B)
const int pinSoilSensorA1 = 34;
const int pinSoilSensorA2 = 35;
const int relayA1 = 32; // Relay untuk Pompa A1
const int relayA2 = 33; // Relay untuk Pompa A2 (kontrol dari SF_B)
// Kalibrasi sensor (hasil dari kamu)
const int NILAI_KERING_1 = 2755;
const int NILAI_BASAH_1 = 2015;
const int NILAI_KERING_2 = 3000;
const int NILAI_BASAH_2 = 1885;
const int BATAS_KELEMBAPAN = 30;
const unsigned long INTERVAL = 30000;
unsigned long lastMillis = 0;
unsigned long waktuSekarang = 0;
unsigned long sisaWaktuCekH2 = 0;
int H2_dari_B = 100; // nilai awal aman (tidak aktifkan pompa)
bool sudahKirimKontrol = false;
unsigned long waktuKirimKontrol = 0;
const unsigned long DELAY_CEK_H2 = 30000; // 30 detik untuk cek H2 SF_B naik atau tidak
String prefix = "KelasAIUKSW2025ya/";
String topicKirim = prefix + "SF_A"; // Publish ke sini
String topicTerima = prefix + "SF_B"; // Subscribe dari sini
// =================== SETUP WIFI ==========================
void setup_wifi() {
delay(10);
Serial.println("[WiFi] Menghubungkan ke WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\n[WiFi] Terhubung!");
}
// =================== KONVERSI KELEMBAPAN ==================
int hitungPersen(int adc, int kering, int basah) {
int persen = map(adc, kering, basah, 0, 100);
return constrain(persen, 0, 100);
}
// =================== CALLBACK ============================
void callback(char* topic, byte* payload, unsigned int length) {
String msg;
for (int i = 0; i < length; i++) msg += (char)payload[i];
Serial.printf("[MQTT] Diterima di %s: %s\n", topic, msg.c_str());
StaticJsonDocument<200> doc;
DeserializationError err = deserializeJson(doc, msg);
if (err) {
Serial.println("[ERROR] Gagal parse JSON");
return;
}
int H2 = doc["H2"];
int control = doc["Control"];
H2_dari_B = H2;
Serial.printf("[SF_A] Dari SF_B → H2:%d%%, Control:%d\n", H2, control);
if (control == 1) {
Serial.println("[SF_A] [AKSI A2] Pompa A2 nyala 3 detik dari instruksi SF_B");
digitalWrite(relayA2, LOW);
delay(3000);
digitalWrite(relayA2, HIGH);
}
}
// =================== RECONNECT MQTT ======================
void reconnect() {
while (!client.connected()) {
Serial.print("[MQTT] Menghubungkan...");
if (client.connect(clientId.c_str())) {
Serial.println("terhubung!");
client.subscribe(topicTerima.c_str());
} else {
Serial.print("gagal, rc=");
Serial.print(client.state());
Serial.println(" coba lagi...");
delay(2000);
}
}
}
// =================== SETUP ===============================
void setup() {
Serial.begin(115200);
pinMode(relayA1, OUTPUT);
pinMode(relayA2, OUTPUT);
digitalWrite(relayA1, HIGH); // Nonaktif default
digitalWrite(relayA2, HIGH); // Nonaktif default
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("Inisialisasi OLED gagal"));
while (1);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
}
// =================== LOOP ================================
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
if (millis() - lastMillis > INTERVAL) {
lastMillis = millis();
int adcA1 = analogRead(pinSoilSensorA1);
int adcA2 = analogRead(pinSoilSensorA2);
int kelembapanA1 = hitungPersen(adcA1, NILAI_BASAH_1, NILAI_KERING_1);
int kelembapanA2 = hitungPersen(adcA2, NILAI_BASAH_2, NILAI_KERING_2);
int suhu = random(28, 33); // Simulasi suhu
int kontrol = 0;
if (kelembapanA1 < BATAS_KELEMBAPAN) {
Serial.println("[SF_A] [AKSI A1] Pompa A1 nyala 3 detik karena H2 SF_A rendah");
digitalWrite(relayA1, LOW);
delay(3000);
digitalWrite(relayA1, HIGH);
}
if (H2_dari_B < BATAS_KELEMBAPAN) {
if (!sudahKirimKontrol) {
kontrol = 1;
sudahKirimKontrol = true;
waktuKirimKontrol = millis();
Serial.println("[SF_A] [KONTROL] Control=1 karena H2 SF_B rendah");
} else if (millis() - waktuKirimKontrol >= DELAY_CEK_H2) {
if (H2_dari_B < BATAS_KELEMBAPAN) {
kontrol = 1;
waktuKirimKontrol = millis(); // reset timer
Serial.println("[SF_A] [ULANG] Control=1 lagi karena H2 SF_B masih rendah");
} else {
sudahKirimKontrol = false;
Serial.println("[SF_A] [OK] H2 SF_B sudah naik, reset status kontrol");
}
}
} else {
sudahKirimKontrol = false;
}
StaticJsonDocument<200> doc;
doc["Tim_1"] = "SF_A";
doc["T"] = suhu;
doc["H1"] = kelembapanA1;
doc["H2"] = kelembapanA2;
doc["Control"] = kontrol;
char buffer[200];
serializeJson(doc, buffer);
client.publish(topicKirim.c_str(), buffer);
display.clearDisplay();
display.setCursor(0, 0);
display.print("SF_A Monitoring");
display.setCursor(0, 16);
display.printf("T:%dC C:%d", suhu, kontrol);
display.setCursor(0, 32);
display.printf("H1:%d%% H2:%d%%", kelembapanA1, kelembapanA2);
display.setCursor(0, 48);
display.printf("H2_B:%d%% %s", H2_dari_B, (H2_dari_B < BATAS_KELEMBAPAN ? "↓" : "↑"));
display.display();
Serial.printf("[SF_A] Kirim → Tim_1:%s, T:%d, H1:%d%%, H2:%d%%, Control:%d\n",
"SF_A", suhu, kelembapanA1, kelembapanA2, kontrol);
}
// Hitung sisa waktu delay cek H2
if (sudahKirimKontrol) {
waktuSekarang = millis();
if (waktuSekarang - waktuKirimKontrol < DELAY_CEK_H2) {
sisaWaktuCekH2 = (DELAY_CEK_H2 - (waktuSekarang - waktuKirimKontrol)) / 1000;
} else {
sisaWaktuCekH2 = 0;
}
display.setCursor(90, 0); // pojok kanan atas
display.printf("%lds", sisaWaktuCekH2);
}
display.display();
}5 V
5 V
3 V