MIF_E31221269/lib/IOT.ino

739 lines
26 KiB
C++

#include <ESP8266WiFi.h>
#include <FirebaseESP8266.h>
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
// Konfigurasi WiFi
const char* ssid = "Combat2024";
const char* password = "12345678";
// Konfigurasi Firebase
#define FIREBASE_HOST "https://jago-9a9a6-default-rtdb.firebaseio.com/"
#define FIREBASE_AUTH "Q3i1jDmc3Xh9UiUTaGUmOw4tVztV5TJ3INU9RoWN"
// NTP Client untuk mendapatkan waktu
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");
FirebaseData firebaseData;
FirebaseConfig config;
FirebaseAuth auth;
#define DHTPIN D5
#define RELAY_TEMP D3 // Relay untuk suhu (kipas)
#define RELAY_HUMIDITY D6 // Relay untuk kelembapan (lampu)
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2); // Pastikan alamat sesuai dengan modul yang digunakan
int ageInWeeks = 1; // Default, nanti diambil dari Firebase
// Variabel untuk mode kontrol
bool autoModeFan = true; // Default: mode otomatis untuk kipas
bool autoModeLight = true; // Default: mode otomatis untuk lampu
bool fanStatus = false; // Status kipas (ON/OFF)
bool lightStatus = false; // Status lampu (ON/OFF)
// Variabel untuk rentang suhu dan kelembapan dinamis
struct Range {
float min;
float max;
float target;
};
Range tempRanges[4] = {
{33, 35, 34}, // Minggu 1
{30, 33, 31.5}, // Minggu 2
{28, 30, 29}, // Minggu 3
{25, 28, 26.5} // Minggu 4
};
Range humidityRanges[4] = {
{60, 70, 65}, // Minggu 1
{60, 65, 62.5}, // Minggu 2
{60, 65, 62.5}, // Minggu 3
{55, 60, 57.5} // Minggu 4
};
// Variabel untuk pengaturan tampilan LCD
unsigned long lastDisplayToggle = 0;
bool showMainDisplay = true; // Untuk mengganti tampilan LCD
// Variabel untuk reconnect
unsigned long lastReconnectAttempt = 0;
const unsigned long reconnectInterval = 30000; // 30 detik
// Variabel untuk menyimpan status koneksi WiFi sebelumnya
bool previousWiFiStatus = false;
// Fungsi untuk logging ke Firebase dengan timestamp
void logToFirebase(const String& path, const String& message) {
String timestamp = getCurrentTimestamp();
String logMessage = timestamp + ": " + message;
// Kirim log ke Firebase, menggunakan setString untuk memperbarui entri
Firebase.setString(firebaseData, path, logMessage);
}
// Fungsi untuk mendapatkan waktu dari NTP
String getCurrentTimestamp() {
timeClient.update();
return String(timeClient.getEpochTime());
}
// Variabel untuk memeriksa koneksi WiFi
unsigned long lastWiFiCheck = 0;
const unsigned long wifiCheckInterval = 2000; // 2 detik
// Fungsi untuk memeriksa dan memulihkan koneksi WiFi
void checkWiFiConnection() {
if (WiFi.status() != WL_CONNECTED) {
unsigned long currentMillis = millis();
// Coba reconnect setiap interval tertentu
if (currentMillis - lastReconnectAttempt >= reconnectInterval) {
logToFirebase("/logs/wifi", "WiFi Disconnected. Attempting to Reconnect");
// Matikan WiFi dan nyalakan kembali
WiFi.disconnect();
delay(1000);
WiFi.begin(ssid, password);
lastReconnectAttempt = currentMillis;
}
// Tambahkan log ketika WiFi terputus
if (previousWiFiStatus) {
logToFirebase("/logs/wifi", "WiFi Connection Failed");
previousWiFiStatus = false;
}
} else {
// Jika WiFi terhubung, periksa apakah statusnya berubah
if (!previousWiFiStatus) {
logToFirebase("/logs/wifi", "WiFi Connected Successfully");
Serial.println("\nWiFi connected");
previousWiFiStatus = true;
}
}
}
void setup() {
Serial.begin(115200);
// Inisialisasi pin relay
pinMode(RELAY_TEMP, OUTPUT);
pinMode(RELAY_HUMIDITY, OUTPUT);
digitalWrite(RELAY_TEMP, HIGH); // Pastikan relay mulai dalam keadaan OFF
digitalWrite(RELAY_HUMIDITY, HIGH);
// Inisialisasi LCD dengan deteksi kesalahan
logToFirebase("/logs/lcd", "LCD Initialization Started");
// Coba inisialisasi LCD dengan timeout
bool lcdInitSuccess = false;
Wire.begin();
// Periksa apakah LCD merespons
Wire.beginTransmission(0x27); // Alamat I2C LCD
byte error = Wire.endTransmission();
if (error == 0) {
// LCD ditemukan, coba inisialisasi
lcd.init();
lcd.backlight();
lcd.clear();
lcd.begin(16,2);
lcd.print("Initializing...");
lcdInitSuccess = true;
}
if (lcdInitSuccess) {
logToFirebase("/logs/lcd", "LCD Ready and Initialized");
Serial.println("LCD initialized successfully");
} else {
logToFirebase("/logs/lcd", "LCD Initialization Failed - Check Connections");
Serial.println("LCD initialization failed! Check wiring (GND, VCC, SDA, SCL)");
}
// Inisialisasi WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
// Tunggu koneksi WiFi
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
logToFirebase("/logs/wifi", "WiFi Connected Successfully");
Serial.println("\nWiFi connected");
// Inisialisasi NTP Client
timeClient.begin();
timeClient.setTimeOffset(25200); // Offset untuk WIB (GMT+7)
} else {
logToFirebase("/logs/wifi", "WiFi Connection Failed");
Serial.println("\nWiFi connection failed");
}
// Inisialisasi DHT
dht.begin();
logToFirebase("/logs/sensor", "DHT Sensor Initialized");
// Konfigurasi Firebase
config.host = FIREBASE_HOST;
config.signer.tokens.legacy_token = FIREBASE_AUTH;
Firebase.begin(&config, &auth);
Firebase.reconnectWiFi(true);
// Inisialisasi variabel kontrol di Firebase
Firebase.setBool(firebaseData, "/control/fan/auto", autoModeFan);
Firebase.setBool(firebaseData, "/control/light/auto", autoModeLight);
Firebase.setBool(firebaseData, "/control/fan/status", fanStatus);
Firebase.setBool(firebaseData, "/control/light/status", lightStatus);
// Inisialisasi rentang di Firebase jika belum ada
for (int i = 0; i < 4; i++) {
String tempPath = "/ranges/week" + String(i+1) + "/temperature";
String humidityPath = "/ranges/week" + String(i+1) + "/humidity";
// Inisialisasi rentang suhu
Firebase.setFloat(firebaseData, tempPath + "/min", tempRanges[i].min);
Firebase.setFloat(firebaseData, tempPath + "/max", tempRanges[i].max);
Firebase.setFloat(firebaseData, tempPath + "/target", tempRanges[i].target);
// Inisialisasi rentang kelembapan
Firebase.setFloat(firebaseData, humidityPath + "/min", humidityRanges[i].min);
Firebase.setFloat(firebaseData, humidityPath + "/max", humidityRanges[i].max);
Firebase.setFloat(firebaseData, humidityPath + "/target", humidityRanges[i].target);
}
}
void loop() {
unsigned long currentMillis = millis();
// Periksa koneksi WiFi setiap 2 detik
if (currentMillis - lastWiFiCheck >= wifiCheckInterval) {
checkWiFiConnection();
lastWiFiCheck = currentMillis;
}
// Periksa koneksi LCD secara berkala
checkLCDConnection();
// Update NTP Client
timeClient.update();
// Baca sensor suhu dan kelembapan
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
// Periksa pembacaan sensor
if (isnan(temperature) || isnan(humidity)) {
logToFirebase("/logs/sensor", "Failed to Read from DHT Sensor");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Sensor Error!");
lcd.setCursor(0, 1);
lcd.print("Check DHT sensor");
delay(2000);
return;
} else {
// Log pembacaan sensor berhasil (setiap 2 detik)
static unsigned long lastSensorLog = 0;
if (millis() - lastSensorLog > 2000) { // Log setiap 2 detik
logToFirebase("/logs/sensor", "DHT Sensor Reading Successful");
lastSensorLog = millis();
}
}
// Ambil umur ayam dari Firebase
if (Firebase.getInt(firebaseData, "/chicken_age")) {
ageInWeeks = firebaseData.intData();
Serial.print("Age: ");
Serial.println(ageInWeeks);
} else {
Serial.print("Failed to get age from Firebase: ");
Serial.println(firebaseData.errorReason());
// Inisialisasi jika data belum ada
if (firebaseData.errorReason() == "path not exist") {
Firebase.setInt(firebaseData, "/chicken_age", 1);
logToFirebase("/logs/system", "Initialized /chicken_age with default value 1");
}
}
// Periksa mode kontrol (manual atau otomatis)
checkControlMode();
// Ganti tampilan LCD setiap 5 detik
if (currentMillis - lastDisplayToggle >= 5000) {
showMainDisplay = !showMainDisplay;
lastDisplayToggle = currentMillis;
}
// Update tampilan LCD berdasarkan mode
if (showMainDisplay) {
updateMainDisplay(temperature, humidity);
} else {
updateModeDisplay();
}
// Kontrol suhu dan kelembapan berdasarkan mode
if (autoModeFan) {
// Mode otomatis untuk kipas (menggunakan fuzzy logic)
controlTemperature(temperature);
} else {
// Mode manual untuk kipas
if (fanStatus) {
digitalWrite(RELAY_TEMP, LOW); // Kipas ON
} else {
digitalWrite(RELAY_TEMP, HIGH); // Kipas OFF
}
}
if (autoModeLight) {
// Mode otomatis untuk lampu (menggunakan fuzzy logic)
controlHumidity(humidity, temperature);
} else {
// Mode manual untuk lampu
if (lightStatus) {
digitalWrite(RELAY_HUMIDITY, LOW); // Lampu ON
} else {
digitalWrite(RELAY_HUMIDITY, HIGH); // Lampu OFF
}
}
// Kirim data ke Firebase
Firebase.setFloat(firebaseData, "/sensor/temperature", temperature);
Firebase.setFloat(firebaseData, "/sensor/Humidity", humidity);
Firebase.setBool(firebaseData, "/relay/Kipas", digitalRead(RELAY_TEMP) == LOW);
Firebase.setBool(firebaseData, "/relay/Lampu", digitalRead(RELAY_HUMIDITY) == LOW);
// Perbarui rentang dari Firebase
updateRangesFromFirebase();
delay(1000); // Tunggu 1 detik antara siklus
}
// Fungsi untuk tampilan utama (Temp, Hum, Age)
void updateMainDisplay(float temperature, float humidity) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Temp:");
lcd.print(temperature, 1);
lcd.print((char)223); // Simbol derajat
lcd.print("C");
lcd.setCursor(0, 1);
lcd.print("Hum:");
lcd.print(humidity, 1);
lcd.print("% Age:");
lcd.print(ageInWeeks);
lcd.print("w");
}
// Fungsi untuk tampilan mode (Auto/Manual)
void updateModeDisplay() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Fan: ");
lcd.print(autoModeFan ? "AUTO" : "MANUAL");
lcd.print(" ");
lcd.print(digitalRead(RELAY_TEMP) == LOW ? "ON" : "OFF");
lcd.setCursor(0, 1);
lcd.print("Light: ");
lcd.print(autoModeLight ? "AUTO" : "MANUAL");
lcd.print(" ");
lcd.print(digitalRead(RELAY_HUMIDITY) == LOW ? "ON" : "OFF");
}
// Definisi fungsi fuzzy logic untuk kontrol suhu
void controlTemperature(float temp) {
float minTemp = tempRanges[ageInWeeks-1].min;
float maxTemp = tempRanges[ageInWeeks-1].max;
float targetTemp = tempRanges[ageInWeeks-1].target;
// Menghitung derajat keanggotaan untuk berbagai kondisi suhu
float veryLow = 0; // Suhu sangat rendah (kondisi kritis)
float tooLow = 0; // Suhu terlalu rendah
float optimal = 0; // Suhu optimal
float tooHigh = 0; // Suhu terlalu tinggi
float veryHigh = 0; // Suhu sangat tinggi (kondisi kritis)
// Keanggotaan "sangat rendah" - kondisi kritis
if (temp < minTemp - 2) {
veryLow = 1.0; // Sangat rendah, kondisi kritis
} else if (temp >= minTemp - 2 && temp < minTemp - 1) {
veryLow = (minTemp - 1 - temp); // Agak sangat rendah
veryLow = constrain(veryLow, 0, 1);
}
// Keanggotaan "terlalu rendah"
if (temp >= minTemp - 1.5 && temp < minTemp) {
tooLow = (minTemp - temp) / 1.5; // Agak rendah
tooLow = constrain(tooLow, 0, 1);
}
// Keanggotaan "optimal"
if (temp >= minTemp && temp <= maxTemp) {
// Semakin dekat ke targetTemp, semakin optimal
optimal = 1.0 - abs(temp - targetTemp) / ((maxTemp - minTemp) / 2.0);
optimal = constrain(optimal, 0, 1);
}
// Keanggotaan "terlalu tinggi"
if (temp > maxTemp && temp <= maxTemp + 1.5) {
tooHigh = (temp - maxTemp) / 1.5; // Agak tinggi
tooHigh = constrain(tooHigh, 0, 1);
}
// Keanggotaan "sangat tinggi" - kondisi kritis
if (temp > maxTemp + 2) {
veryHigh = 1.0; // Sangat tinggi, kondisi kritis
} else if (temp > maxTemp + 1 && temp <= maxTemp + 2) {
veryHigh = (temp - (maxTemp + 1)) / 1.0; // Agak sangat tinggi
veryHigh = constrain(veryHigh, 0, 1);
}
// Simpan status suhu untuk digunakan oleh fungsi controlHumidity
bool isTempVeryCold = (veryLow > 0.3);
bool isTempTooCold = (tooLow > 0.3);
bool isTempVeryHot = (veryHigh > 0.3);
// Kirim nilai fuzzy ke Firebase untuk monitoring
Firebase.setFloat(firebaseData, "/fuzzy/temperature/veryLow", veryLow);
Firebase.setFloat(firebaseData, "/fuzzy/temperature/tooLow", tooLow);
Firebase.setFloat(firebaseData, "/fuzzy/temperature/optimal", optimal);
Firebase.setFloat(firebaseData, "/fuzzy/temperature/tooHigh", tooHigh);
Firebase.setFloat(firebaseData, "/fuzzy/temperature/veryHigh", veryHigh);
// Keputusan berdasarkan derajat keanggotaan dan prioritas
// Prioritas: Sangat tinggi > Sangat rendah > Terlalu tinggi > Optimal > Terlalu rendah
if (veryHigh > 0.3) { // Jika suhu sangat tinggi (kondisi kritis)
digitalWrite(RELAY_TEMP, LOW); // Kipas ON pada kecepatan maksimal
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/temperature", "Sangat Tinggi - Kipas ON (Kritis)");
Firebase.setBool(firebaseData, "/emergency/high_temperature", true);
} else if (veryLow > 0.3) { // Jika suhu sangat rendah (kondisi kritis)
digitalWrite(RELAY_TEMP, HIGH); // Kipas OFF
// Nyalakan lampu untuk membantu meningkatkan suhu
// Ini akan di-override oleh controlHumidity jika diperlukan
digitalWrite(RELAY_HUMIDITY, LOW); // Lampu ON untuk membantu meningkatkan suhu
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/temperature", "Sangat Rendah - Kipas OFF, Lampu ON");
Firebase.setBool(firebaseData, "/emergency/low_temperature", true);
Firebase.setBool(firebaseData, "/emergency/high_temperature", false);
} else if (tooHigh > 0.3) { // Jika suhu terlalu tinggi
digitalWrite(RELAY_TEMP, LOW); // Kipas ON
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/temperature", "Tinggi - Kipas ON");
Firebase.setBool(firebaseData, "/emergency/low_temperature", false);
Firebase.setBool(firebaseData, "/emergency/high_temperature", false);
} else if (optimal > 0.7) { // Jika suhu sangat optimal
digitalWrite(RELAY_TEMP, HIGH); // Kipas OFF
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/temperature", "Optimal - Kipas OFF");
Firebase.setBool(firebaseData, "/emergency/low_temperature", false);
Firebase.setBool(firebaseData, "/emergency/high_temperature", false);
} else if (tooLow > 0.3) { // Jika suhu terlalu rendah
digitalWrite(RELAY_TEMP, HIGH); // Kipas OFF
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/temperature", "Rendah - Kipas OFF");
Firebase.setBool(firebaseData, "/emergency/low_temperature", true);
Firebase.setBool(firebaseData, "/emergency/high_temperature", false);
} else {
// Kasus lain, gunakan pendekatan proporsional
// Jika suhu mendekati batas atas rentang, nyalakan kipas
float distanceToMax = maxTemp - temp;
if (distanceToMax < 1.0) {
digitalWrite(RELAY_TEMP, LOW); // Kipas ON
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/temperature", "Mendekati Tinggi - Kipas ON");
} else {
digitalWrite(RELAY_TEMP, HIGH); // Kipas OFF
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/temperature", "Normal - Kipas OFF");
}
Firebase.setBool(firebaseData, "/emergency/low_temperature", false);
Firebase.setBool(firebaseData, "/emergency/high_temperature", false);
}
}
// Definisi fungsi fuzzy logic untuk kontrol kelembapan
void controlHumidity(float humidity, float temperature) {
float minHumidity = humidityRanges[ageInWeeks-1].min;
float maxHumidity = humidityRanges[ageInWeeks-1].max;
float targetHumidity = humidityRanges[ageInWeeks-1].target;
float minTemp = tempRanges[ageInWeeks-1].min;
float maxTemp = tempRanges[ageInWeeks-1].max;
// Periksa apakah suhu terlalu rendah (kondisi darurat)
bool isTemperatureEmergency = false;
if (temperature < minTemp - 1.5) {
isTemperatureEmergency = true;
}
// Menghitung derajat keanggotaan untuk berbagai kondisi kelembapan
float veryLow = 0; // Kelembapan sangat rendah (kondisi kritis)
float tooLow = 0; // Kelembapan terlalu rendah
float optimal = 0; // Kelembapan optimal
float tooHigh = 0; // Kelembapan terlalu tinggi
float veryHigh = 0; // Kelembapan sangat tinggi (kondisi kritis)
// Keanggotaan "sangat rendah" - kondisi kritis
if (humidity < minHumidity - 5) {
veryLow = 1.0; // Sangat rendah, kondisi kritis
} else if (humidity >= minHumidity - 5 && humidity < minHumidity - 3) {
veryLow = (minHumidity - 3 - humidity) / 2.0; // Agak sangat rendah
veryLow = constrain(veryLow, 0, 1);
}
// Keanggotaan "terlalu rendah"
if (humidity >= minHumidity - 3 && humidity < minHumidity) {
tooLow = (minHumidity - humidity) / 3.0; // Agak rendah
tooLow = constrain(tooLow, 0, 1);
}
// Keanggotaan "optimal"
if (humidity >= minHumidity && humidity <= maxHumidity) {
// Semakin dekat ke targetHumidity, semakin optimal
optimal = 1.0 - abs(humidity - targetHumidity) / ((maxHumidity - minHumidity) / 2.0);
optimal = constrain(optimal, 0, 1);
}
// Keanggotaan "terlalu tinggi"
if (humidity > maxHumidity && humidity <= maxHumidity + 3) {
tooHigh = (humidity - maxHumidity) / 3.0; // Agak tinggi
tooHigh = constrain(tooHigh, 0, 1);
}
// Keanggotaan "sangat tinggi" - kondisi kritis
if (humidity > maxHumidity + 5) {
veryHigh = 1.0; // Sangat tinggi, kondisi kritis
} else if (humidity > maxHumidity + 3 && humidity <= maxHumidity + 5) {
veryHigh = (humidity - (maxHumidity + 3)) / 2.0; // Agak sangat tinggi
veryHigh = constrain(veryHigh, 0, 1);
}
// Kirim nilai fuzzy ke Firebase untuk monitoring
Firebase.setFloat(firebaseData, "/fuzzy/humidity/veryLow", veryLow);
Firebase.setFloat(firebaseData, "/fuzzy/humidity/tooLow", tooLow);
Firebase.setFloat(firebaseData, "/fuzzy/humidity/optimal", optimal);
Firebase.setFloat(firebaseData, "/fuzzy/humidity/tooHigh", tooHigh);
Firebase.setFloat(firebaseData, "/fuzzy/humidity/veryHigh", veryHigh);
// Keputusan berdasarkan derajat keanggotaan dan prioritas
// Jika suhu dalam kondisi darurat, prioritaskan pemanasan
if (isTemperatureEmergency) {
digitalWrite(RELAY_HUMIDITY, LOW); // Lampu ON untuk membantu meningkatkan suhu
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/humidity", "Suhu Darurat - Lampu ON untuk Pemanasan");
Firebase.setBool(firebaseData, "/emergency/low_humidity", false); // Reset emergency flag
Firebase.setBool(firebaseData, "/emergency/high_humidity", false); // Reset emergency flag
return; // Keluar dari fungsi, prioritaskan penanganan suhu
}
// Prioritas: Kelembapan sangat tinggi > Kelembapan sangat rendah > Terlalu tinggi > Optimal > Terlalu rendah
if (veryHigh > 0.3) { // Jika kelembapan sangat tinggi (kondisi kritis)
digitalWrite(RELAY_HUMIDITY, LOW); // Lampu ON untuk mengurangi kelembapan
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/humidity", "Sangat Tinggi - Lampu ON (Kritis)");
Firebase.setBool(firebaseData, "/emergency/high_humidity", true);
Firebase.setBool(firebaseData, "/emergency/low_humidity", false);
} else if (veryLow > 0.3) { // Jika kelembapan sangat rendah (kondisi kritis)
digitalWrite(RELAY_HUMIDITY, HIGH); // Lampu OFF untuk mempertahankan kelembapan
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/humidity", "Sangat Rendah - Lampu OFF");
Firebase.setBool(firebaseData, "/emergency/low_humidity", true);
Firebase.setBool(firebaseData, "/emergency/high_humidity", false);
} else if (tooHigh > 0.4) { // Jika kelembapan terlalu tinggi
digitalWrite(RELAY_HUMIDITY, LOW); // Lampu ON untuk mengurangi kelembapan
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/humidity", "Tinggi - Lampu ON");
Firebase.setBool(firebaseData, "/emergency/low_humidity", false);
Firebase.setBool(firebaseData, "/emergency/high_humidity", false);
} else if (optimal > 0.6) { // Jika kelembapan optimal
// Periksa juga suhu - jika suhu rendah, nyalakan lampu meskipun kelembapan optimal
if (temperature < minTemp) {
digitalWrite(RELAY_HUMIDITY, LOW); // Lampu ON untuk membantu meningkatkan suhu
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/humidity", "Optimal, Suhu Rendah - Lampu ON");
}
// Jika kelembapan mendekati batas atas rentang optimal, nyalakan lampu
else if (humidity > targetHumidity + ((maxHumidity - minHumidity) / 4)) {
digitalWrite(RELAY_HUMIDITY, LOW); // Lampu ON
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/humidity", "Optimal Tinggi - Lampu ON");
} else {
digitalWrite(RELAY_HUMIDITY, HIGH); // Lampu OFF
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/humidity", "Optimal - Lampu OFF");
}
Firebase.setBool(firebaseData, "/emergency/low_humidity", false);
Firebase.setBool(firebaseData, "/emergency/high_humidity", false);
} else if (tooLow > 0.3) { // Jika kelembapan terlalu rendah
// Periksa juga suhu - jika suhu sangat rendah, prioritaskan pemanasan
if (temperature < minTemp - 1) {
digitalWrite(RELAY_HUMIDITY, LOW); // Lampu ON untuk membantu meningkatkan suhu
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/humidity", "Rendah, Suhu Sangat Rendah - Lampu ON");
} else {
digitalWrite(RELAY_HUMIDITY, HIGH); // Lampu OFF untuk mempertahankan kelembapan
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/humidity", "Rendah - Lampu OFF");
}
Firebase.setBool(firebaseData, "/emergency/low_humidity", true);
Firebase.setBool(firebaseData, "/emergency/high_humidity", false);
} else {
// Kasus lain, gunakan pendekatan proporsional
// Periksa juga suhu - jika suhu rendah, nyalakan lampu
if (temperature < minTemp) {
digitalWrite(RELAY_HUMIDITY, LOW); // Lampu ON untuk membantu meningkatkan suhu
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/humidity", "Normal, Suhu Rendah - Lampu ON");
}
// Jika kelembapan mendekati batas atas, nyalakan lampu
else if (humidity > maxHumidity - 1.5) {
digitalWrite(RELAY_HUMIDITY, LOW); // Lampu ON
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/humidity", "Mendekati Tinggi - Lampu ON");
} else {
digitalWrite(RELAY_HUMIDITY, HIGH); // Lampu OFF
// Log status ke Firebase
Firebase.setString(firebaseData, "/status/humidity", "Normal - Lampu OFF");
}
Firebase.setBool(firebaseData, "/emergency/low_humidity", false);
Firebase.setBool(firebaseData, "/emergency/high_humidity", false);
}
}
// Fungsi untuk memeriksa mode kontrol dari Firebase
void checkControlMode() {
// Periksa mode kipas (otomatis/manual)
if (Firebase.getBool(firebaseData, "/control/fan/auto")) {
bool newAutoModeFan = firebaseData.boolData();
if (newAutoModeFan != autoModeFan) {
autoModeFan = newAutoModeFan;
}
}
// Periksa mode lampu (otomatis/manual)
if (Firebase.getBool(firebaseData, "/control/light/auto")) {
bool newAutoModeLight = firebaseData.boolData();
if (newAutoModeLight != autoModeLight) {
autoModeLight = newAutoModeLight;
}
}
// Jika dalam mode manual, ambil status dari Firebase
if (!autoModeFan) {
if (Firebase.getBool(firebaseData, "/control/fan/status")) {
bool newFanStatus = firebaseData.boolData();
if (newFanStatus != fanStatus) {
fanStatus = newFanStatus;
}
}
}
if (!autoModeLight) {
if (Firebase.getBool(firebaseData, "/control/light/status")) {
bool newLightStatus = firebaseData.boolData();
if (newLightStatus != lightStatus) {
lightStatus = newLightStatus;
}
}
}
}
// Tambahkan fungsi untuk memeriksa LCD secara berkala
void checkLCDConnection() {
static unsigned long lastLCDCheck = 0;
static bool lastLCDStatus = true;
// Periksa LCD setiap 30 detik
if (millis() - lastLCDCheck > 30000) {
Wire.beginTransmission(0x27); // Alamat I2C LCD
byte error = Wire.endTransmission();
bool currentLCDStatus = (error == 0);
// Jika status berubah, kirim log
if (currentLCDStatus != lastLCDStatus) {
if (currentLCDStatus) {
// LCD terdeteksi kembali, jalankan proses inisialisasi lengkap
logToFirebase("/logs/lcd", "LCD Connection Restored");
logToFirebase("/logs/lcd", "LCD Initialization Started");
// Coba inisialisasi LCD
lcd.init(); // Panggil init() tanpa memeriksa nilai kembali
lcd.backlight();
lcd.clear();
lcd.begin(16,2);
lcd.print("Reconnected...");
// Anggap inisialisasi berhasil jika kita sampai di sini
logToFirebase("/logs/lcd", "LCD Ready and Initialized");
Serial.println("LCD reinitialized successfully");
} else {
logToFirebase("/logs/lcd", "LCD Connection Lost - Check Wiring");
}
lastLCDStatus = currentLCDStatus;
}
lastLCDCheck = millis();
}
}
// Fungsi untuk memperbarui rentang dari Firebase
void updateRangesFromFirebase() {
static unsigned long lastUpdate = 0;
if (millis() - lastUpdate > 5000) { // Update setiap 5 detik
String path = "/ranges/week" + String(ageInWeeks);
// Ambil rentang suhu
if (Firebase.getFloat(firebaseData, path + "/temperature/min")) {
tempRanges[ageInWeeks-1].min = firebaseData.floatData();
}
if (Firebase.getFloat(firebaseData, path + "/temperature/max")) {
tempRanges[ageInWeeks-1].max = firebaseData.floatData();
}
if (Firebase.getFloat(firebaseData, path + "/temperature/target")) {
tempRanges[ageInWeeks-1].target = firebaseData.floatData();
}
// Ambil rentang kelembapan
if (Firebase.getFloat(firebaseData, path + "/humidity/min")) {
humidityRanges[ageInWeeks-1].min = firebaseData.floatData();
}
if (Firebase.getFloat(firebaseData, path + "/humidity/max")) {
humidityRanges[ageInWeeks-1].max = firebaseData.floatData();
}
if (Firebase.getFloat(firebaseData, path + "/humidity/target")) {
humidityRanges[ageInWeeks-1].target = firebaseData.floatData();
}
lastUpdate = millis();
}
}