first commit
This commit is contained in:
commit
01772b32e9
|
@ -0,0 +1,530 @@
|
|||
#include <DHT.h>
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
#include <Wire.h>
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
// Pin Definitions
|
||||
#define DHT_PIN 2
|
||||
#define DHT_TYPE DHT22
|
||||
|
||||
// Relay pins
|
||||
#define RELAY_POMPA_A 3
|
||||
#define RELAY_POMPA_B 4
|
||||
#define RELAY_POMPA_PH_UP 5
|
||||
#define RELAY_POMPA_PH_DOWN 6
|
||||
#define RELAY_GROW_LIGHT 7
|
||||
#define RELAY_AERATOR 8
|
||||
#define RELAY_KIPAS 9
|
||||
#define RELAY_FOGGER 10
|
||||
|
||||
// Sensor pins
|
||||
#define PH_SENSOR_PIN A1
|
||||
#define TDS_SENSOR_PIN A0
|
||||
|
||||
// *** TAMBAHAN UNTUK KOMUNIKASI ESP32 ***
|
||||
#define ESP32_TX_PIN 1 // Pin TX Arduino (D1) -> RX ESP32 (GPIO 16)
|
||||
#define ESP32_RX_PIN 0 // Pin RX Arduino (tidak digunakan dalam kasus ini)
|
||||
// Gunakan Serial hardware untuk komunikasi ke ESP32
|
||||
// SoftwareSerial esp32Serial(ESP32_RX_PIN, ESP32_TX_PIN); // Alternatif jika butuh software serial
|
||||
|
||||
// Constants moved to PROGMEM to save RAM
|
||||
const float VOLTAGE_REF = 5.0;
|
||||
|
||||
// pH Calibration constants (dari kalibrasi 2 titik)
|
||||
const float PH_SLOPE = -4.0787;
|
||||
const float PH_OFFSET = 16.764;
|
||||
|
||||
// Timing constants
|
||||
const unsigned long SENSOR_INTERVAL = 3000;
|
||||
const unsigned long DHT_INTERVAL = 5000;
|
||||
const unsigned long DISPLAY_INTERVAL = 1000;
|
||||
const unsigned long DEBUG_INTERVAL = 5000;
|
||||
const unsigned long ESP32_SEND_INTERVAL = 2000; // *** TAMBAHAN: Interval kirim data ke ESP32 ***
|
||||
const unsigned long PUMP_DURATION = 5000;
|
||||
const unsigned long GROW_LIGHT_ON_TIME = 43200000UL;
|
||||
const unsigned long GROW_LIGHT_OFF_TIME = 43200000UL;
|
||||
|
||||
// Initialize components
|
||||
DHT dht(DHT_PIN, DHT_TYPE);
|
||||
LiquidCrystal_I2C lcd(0x27, 16, 2);
|
||||
|
||||
// Sensor variables
|
||||
float humidity = 0;
|
||||
float temperature = 0;
|
||||
float phValue = 0;
|
||||
float tdsValue = 0;
|
||||
int phRawADC = 0;
|
||||
int tdsRawADC = 0;
|
||||
|
||||
// Timing variables
|
||||
unsigned long lastSensorRead = 0;
|
||||
unsigned long lastDHTRead = 0;
|
||||
unsigned long lastDisplayUpdate = 0;
|
||||
unsigned long lastDebugOutput = 0;
|
||||
unsigned long lastDHTStatus = 0;
|
||||
unsigned long lastESP32Send = 0; // *** TAMBAHAN: Timer untuk kirim data ***
|
||||
unsigned long pumpStartTime = 0;
|
||||
unsigned long growLightStartTime = 0;
|
||||
|
||||
// Control flags
|
||||
struct {
|
||||
bool pumpPhUpRunning : 1;
|
||||
bool pumpPhDownRunning : 1;
|
||||
bool growLightState : 1;
|
||||
bool aeratorState : 1;
|
||||
bool debugMode : 1;
|
||||
bool dhtError : 1;
|
||||
bool phError : 1;
|
||||
bool tdsError : 1;
|
||||
bool esp32CommError : 1; // *** TAMBAHAN: Flag error komunikasi ESP32 ***
|
||||
} flags = {false, false, false, true, true, false, false, false, false};
|
||||
|
||||
// DHT22 monitoring variables
|
||||
int dhtErrorCount = 0;
|
||||
int dhtSuccessCount = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600); // Untuk komunikasi dengan ESP32
|
||||
Serial.println(F("=== HYDROPONIC SYSTEM STARTUP ==="));
|
||||
|
||||
// Initialize LCD
|
||||
Wire.begin();
|
||||
lcd.init();
|
||||
lcd.backlight();
|
||||
lcd.setCursor(0, 0);
|
||||
lcd.print(F("Init LCD..."));
|
||||
delay(1000);
|
||||
|
||||
// Initialize relay pins
|
||||
pinMode(RELAY_POMPA_A, OUTPUT);
|
||||
pinMode(RELAY_POMPA_B, OUTPUT);
|
||||
pinMode(RELAY_POMPA_PH_UP, OUTPUT);
|
||||
pinMode(RELAY_POMPA_PH_DOWN, OUTPUT);
|
||||
pinMode(RELAY_GROW_LIGHT, OUTPUT);
|
||||
pinMode(RELAY_AERATOR, OUTPUT);
|
||||
pinMode(RELAY_KIPAS, OUTPUT);
|
||||
pinMode(RELAY_FOGGER, OUTPUT);
|
||||
|
||||
// Set relay initial states (HIGH = OFF untuk relay aktif LOW)
|
||||
digitalWrite(RELAY_POMPA_A, HIGH);
|
||||
digitalWrite(RELAY_POMPA_B, HIGH);
|
||||
digitalWrite(RELAY_POMPA_PH_UP, HIGH);
|
||||
digitalWrite(RELAY_POMPA_PH_DOWN, HIGH);
|
||||
digitalWrite(RELAY_GROW_LIGHT, HIGH);
|
||||
digitalWrite(RELAY_AERATOR, HIGH);
|
||||
digitalWrite(RELAY_KIPAS, HIGH);
|
||||
digitalWrite(RELAY_FOGGER, HIGH);
|
||||
|
||||
lcd.clear();
|
||||
lcd.print(F("Init Relays..."));
|
||||
delay(1000);
|
||||
|
||||
// Initialize DHT sensor
|
||||
lcd.clear();
|
||||
lcd.print(F("Init DHT22..."));
|
||||
|
||||
dht.begin();
|
||||
delay(2000);
|
||||
|
||||
// Test DHT22
|
||||
bool dhtOK = false;
|
||||
for (int attempt = 1; attempt <= 5; attempt++) {
|
||||
float testTemp = dht.readTemperature();
|
||||
float testHum = dht.readHumidity();
|
||||
|
||||
if (!isnan(testTemp) && !isnan(testHum) &&
|
||||
testTemp > -40 && testTemp < 80 &&
|
||||
testHum > 0 && testHum < 100) {
|
||||
dhtOK = true;
|
||||
temperature = testTemp;
|
||||
humidity = testHum;
|
||||
break;
|
||||
}
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
if (!dhtOK) {
|
||||
flags.dhtError = true;
|
||||
lcd.clear();
|
||||
lcd.setCursor(0, 0);
|
||||
lcd.print(F("DHT22 ERROR!"));
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print(F("Check wiring"));
|
||||
delay(3000);
|
||||
} else {
|
||||
flags.dhtError = false;
|
||||
lcd.clear();
|
||||
lcd.setCursor(0, 0);
|
||||
lcd.print(F("DHT22 OK!"));
|
||||
delay(2000);
|
||||
}
|
||||
|
||||
// Nyalakan aerator
|
||||
if (!flags.dhtError) {
|
||||
digitalWrite(RELAY_AERATOR, LOW);
|
||||
flags.aeratorState = true;
|
||||
}
|
||||
|
||||
// Initialize timers
|
||||
growLightStartTime = millis();
|
||||
lastSensorRead = millis();
|
||||
lastDHTRead = millis();
|
||||
lastDisplayUpdate = millis();
|
||||
lastDebugOutput = millis();
|
||||
lastDHTStatus = millis();
|
||||
lastESP32Send = millis(); // *** TAMBAHAN ***
|
||||
|
||||
lcd.clear();
|
||||
lcd.setCursor(0, 0);
|
||||
lcd.print(F("System Ready!"));
|
||||
delay(2000);
|
||||
lcd.clear();
|
||||
|
||||
// *** TAMBAHAN: Test komunikasi ESP32 ***
|
||||
Serial.println(F("Testing ESP32 communication..."));
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
unsigned long currentTime = millis();
|
||||
|
||||
// Read sensors
|
||||
if (currentTime - lastSensorRead >= SENSOR_INTERVAL) {
|
||||
readOtherSensors();
|
||||
lastSensorRead = currentTime;
|
||||
}
|
||||
|
||||
if (currentTime - lastDHTRead >= DHT_INTERVAL) {
|
||||
readDHTSensor();
|
||||
lastDHTRead = currentTime;
|
||||
}
|
||||
|
||||
// *** TAMBAHAN: Kirim data ke ESP32 ***
|
||||
if (currentTime - lastESP32Send >= ESP32_SEND_INTERVAL) {
|
||||
sendDataToESP32();
|
||||
lastESP32Send = currentTime;
|
||||
}
|
||||
|
||||
// Control systems
|
||||
controlHumidity();
|
||||
controlPH();
|
||||
controlTDS();
|
||||
controlGrowLight();
|
||||
controlAerator();
|
||||
controlPumps();
|
||||
|
||||
// Update display
|
||||
if (currentTime - lastDisplayUpdate >= DISPLAY_INTERVAL) {
|
||||
updateDisplay();
|
||||
lastDisplayUpdate = currentTime;
|
||||
}
|
||||
|
||||
// Debug output (comment out jika tidak perlu untuk mengurangi interference)
|
||||
// if (flags.debugMode && (currentTime - lastDebugOutput >= DEBUG_INTERVAL)) {
|
||||
// debugOutput();
|
||||
// lastDebugOutput = currentTime;
|
||||
// }
|
||||
|
||||
// Monitor DHT22 health
|
||||
monitorDHT();
|
||||
|
||||
delay(50);
|
||||
}
|
||||
|
||||
// *** FUNGSI BARU: Kirim data ke ESP32 ***
|
||||
void sendDataToESP32() {
|
||||
// Format: temperature,humidity,pH,TDS
|
||||
// Pastikan data valid sebelum dikirim
|
||||
float tempToSend = flags.dhtError ? -999 : temperature;
|
||||
float humToSend = flags.dhtError ? -999 : humidity;
|
||||
float phToSend = flags.phError ? -999 : phValue;
|
||||
float tdsToSend = flags.tdsError ? -999 : tdsValue;
|
||||
|
||||
// Kirim data dengan format CSV
|
||||
Serial.print(tempToSend, 2);
|
||||
Serial.print(",");
|
||||
Serial.print(humToSend, 2);
|
||||
Serial.print(",");
|
||||
Serial.print(phToSend, 2);
|
||||
Serial.print(",");
|
||||
Serial.print(tdsToSend, 0);
|
||||
Serial.println(); // Newline sebagai delimiter
|
||||
|
||||
// Optional: Indikator di LCD bahwa data terkirim
|
||||
// lcd.setCursor(15, 0);
|
||||
// lcd.print(">");
|
||||
}
|
||||
|
||||
// Fungsi baca DHT22 yang diperbaiki
|
||||
void readDHTSensor() {
|
||||
bool aeratorWasOn = (digitalRead(RELAY_AERATOR) == LOW);
|
||||
bool kipasWasOn = (digitalRead(RELAY_KIPAS) == LOW);
|
||||
|
||||
if (aeratorWasOn) {
|
||||
digitalWrite(RELAY_AERATOR, HIGH);
|
||||
}
|
||||
if (kipasWasOn) {
|
||||
digitalWrite(RELAY_KIPAS, HIGH);
|
||||
}
|
||||
|
||||
delay(100);
|
||||
|
||||
float h = NAN, t = NAN;
|
||||
int retries = 0;
|
||||
const int maxRetries = 3;
|
||||
|
||||
while (retries < maxRetries) {
|
||||
h = dht.readHumidity();
|
||||
t = dht.readTemperature();
|
||||
|
||||
if (!isnan(h) && !isnan(t) &&
|
||||
t > -40 && t < 80 &&
|
||||
h > 0 && h < 100) {
|
||||
break;
|
||||
}
|
||||
|
||||
retries++;
|
||||
if (retries < maxRetries) {
|
||||
delay(500);
|
||||
}
|
||||
}
|
||||
|
||||
if (aeratorWasOn) {
|
||||
digitalWrite(RELAY_AERATOR, LOW);
|
||||
}
|
||||
if (kipasWasOn) {
|
||||
digitalWrite(RELAY_KIPAS, LOW);
|
||||
}
|
||||
|
||||
if (retries >= maxRetries || isnan(h) || isnan(t)) {
|
||||
flags.dhtError = true;
|
||||
dhtErrorCount++;
|
||||
} else {
|
||||
flags.dhtError = false;
|
||||
humidity = h;
|
||||
temperature = t;
|
||||
dhtSuccessCount++;
|
||||
dhtErrorCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void readOtherSensors() {
|
||||
phValue = readPH();
|
||||
flags.phError = (phValue < 0 || phValue > 14);
|
||||
|
||||
tdsValue = readTDS();
|
||||
flags.tdsError = (tdsValue < 0);
|
||||
|
||||
// DEBUG: Tampilkan nilai TDS ke Serial Monitor
|
||||
Serial.print(F("[DEBUG] TDS Value: "));
|
||||
Serial.print(tdsValue);
|
||||
Serial.println(F(" ppm"));
|
||||
}
|
||||
|
||||
|
||||
float getAverageVoltage(int pin, int samples = 20) {
|
||||
long total = 0;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
total += analogRead(pin);
|
||||
delay(5);
|
||||
}
|
||||
float avgADC = total / (float)samples;
|
||||
float voltage = avgADC * (5.0 / 1023.0);
|
||||
return voltage;
|
||||
}
|
||||
|
||||
float readPH() {
|
||||
float voltage = getAverageVoltage(PH_SENSOR_PIN, 20);
|
||||
|
||||
if (voltage < 0.1 || voltage > 4.9) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
float esp32_equivalent_voltage = voltage * (3.3/5.0) * (4095.0/1023.0);
|
||||
float ph = PH_SLOPE * esp32_equivalent_voltage + PH_OFFSET;
|
||||
|
||||
if (ph < 0) ph = 0;
|
||||
if (ph > 14) ph = 14;
|
||||
|
||||
return ph;
|
||||
}
|
||||
|
||||
float readTDS() {
|
||||
int buffer_arr[10];
|
||||
for (int i = 0; i < 10; i++) {
|
||||
buffer_arr[i] = analogRead(TDS_SENSOR_PIN);
|
||||
delay(30);
|
||||
}
|
||||
|
||||
// Urutkan nilai buffer
|
||||
for (int i = 0; i < 9; i++) {
|
||||
for (int j = i + 1; j < 10; j++) {
|
||||
if (buffer_arr[i] > buffer_arr[j]) {
|
||||
int temp = buffer_arr[i];
|
||||
buffer_arr[i] = buffer_arr[j];
|
||||
buffer_arr[j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hitung rata-rata dari nilai tengah (tanpa outlier)
|
||||
int avgval = 0;
|
||||
for (int i = 2; i < 8; i++) {
|
||||
avgval += buffer_arr[i];
|
||||
}
|
||||
|
||||
float voltage = (float)avgval * 5.0 / 1023.0 / 6.0;
|
||||
|
||||
// Konversi tegangan ke TDS dengan rumus kalibrasi dan faktor
|
||||
float calibrationFactor = 0.71;
|
||||
float tds = (133.42 * pow(voltage, 3)
|
||||
- 255.86 * pow(voltage, 2)
|
||||
+ 857.39 * voltage) * 0.5;
|
||||
tds *= calibrationFactor;
|
||||
|
||||
if (tds < 0 || tds > 2000) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return tds;
|
||||
}
|
||||
|
||||
|
||||
void controlHumidity() {
|
||||
if (flags.dhtError) {
|
||||
digitalWrite(RELAY_FOGGER, HIGH);
|
||||
digitalWrite(RELAY_KIPAS, HIGH);
|
||||
return;
|
||||
}
|
||||
|
||||
if (humidity < 85.0) {
|
||||
digitalWrite(RELAY_FOGGER, LOW);
|
||||
digitalWrite(RELAY_KIPAS, HIGH);
|
||||
} else if (humidity > 95.0) {
|
||||
digitalWrite(RELAY_FOGGER, HIGH);
|
||||
digitalWrite(RELAY_KIPAS, LOW);
|
||||
} else {
|
||||
digitalWrite(RELAY_FOGGER, HIGH);
|
||||
digitalWrite(RELAY_KIPAS, HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
void controlPH() {
|
||||
if (flags.phError) return;
|
||||
|
||||
if (phValue > 6.5 && !flags.pumpPhDownRunning && !flags.pumpPhUpRunning) {
|
||||
digitalWrite(RELAY_POMPA_PH_DOWN, LOW);
|
||||
flags.pumpPhDownRunning = true;
|
||||
pumpStartTime = millis();
|
||||
} else if (phValue < 5.0 && !flags.pumpPhUpRunning && !flags.pumpPhDownRunning) {
|
||||
digitalWrite(RELAY_POMPA_PH_UP, LOW);
|
||||
flags.pumpPhUpRunning = true;
|
||||
pumpStartTime = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void controlTDS() {
|
||||
if (flags.tdsError) {
|
||||
digitalWrite(RELAY_POMPA_A, HIGH);
|
||||
digitalWrite(RELAY_POMPA_B, HIGH);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tdsValue < 1000.0) {
|
||||
digitalWrite(RELAY_POMPA_A, LOW);
|
||||
digitalWrite(RELAY_POMPA_B, LOW);
|
||||
} else {
|
||||
digitalWrite(RELAY_POMPA_A, HIGH);
|
||||
digitalWrite(RELAY_POMPA_B, HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
void controlGrowLight() {
|
||||
unsigned long currentTime = millis();
|
||||
unsigned long elapsedTime = currentTime - growLightStartTime;
|
||||
|
||||
if (!flags.growLightState && elapsedTime >= GROW_LIGHT_OFF_TIME) {
|
||||
digitalWrite(RELAY_GROW_LIGHT, LOW);
|
||||
flags.growLightState = true;
|
||||
growLightStartTime = currentTime;
|
||||
} else if (flags.growLightState && elapsedTime >= GROW_LIGHT_ON_TIME) {
|
||||
digitalWrite(RELAY_GROW_LIGHT, HIGH);
|
||||
flags.growLightState = false;
|
||||
growLightStartTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
void controlAerator() {
|
||||
if (flags.aeratorState && !flags.dhtError) {
|
||||
digitalWrite(RELAY_AERATOR, LOW);
|
||||
} else {
|
||||
digitalWrite(RELAY_AERATOR, HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
void controlPumps() {
|
||||
unsigned long currentTime = millis();
|
||||
|
||||
if (flags.pumpPhUpRunning && (currentTime - pumpStartTime >= PUMP_DURATION)) {
|
||||
digitalWrite(RELAY_POMPA_PH_UP, HIGH);
|
||||
flags.pumpPhUpRunning = false;
|
||||
}
|
||||
|
||||
if (flags.pumpPhDownRunning && (currentTime - pumpStartTime >= PUMP_DURATION)) {
|
||||
digitalWrite(RELAY_POMPA_PH_DOWN, HIGH);
|
||||
flags.pumpPhDownRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
void updateDisplay() {
|
||||
lcd.clear();
|
||||
|
||||
lcd.setCursor(0, 0);
|
||||
if (flags.dhtError) {
|
||||
lcd.print(F("T:ERR H:ERR"));
|
||||
} else {
|
||||
lcd.print(F("T:"));
|
||||
lcd.print(temperature, 1);
|
||||
lcd.print(F("C H:"));
|
||||
lcd.print(humidity, 1);
|
||||
lcd.print(F("%"));
|
||||
}
|
||||
|
||||
lcd.setCursor(0, 1);
|
||||
if (flags.phError) {
|
||||
lcd.print(F("pH:ERR "));
|
||||
} else {
|
||||
lcd.print(F("pH:"));
|
||||
lcd.print(phValue, 1);
|
||||
lcd.print(F(" "));
|
||||
}
|
||||
|
||||
if (flags.tdsError) {
|
||||
lcd.print(F("TDS:ERR"));
|
||||
} else {
|
||||
lcd.print(F("TDS:"));
|
||||
lcd.print(tdsValue, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void monitorDHT() {
|
||||
static unsigned long lastDHTCheck = 0;
|
||||
|
||||
if (millis() - lastDHTCheck >= 30000) {
|
||||
if (flags.dhtError && dhtErrorCount >= 5) {
|
||||
dht.begin();
|
||||
delay(2000);
|
||||
|
||||
float testT = dht.readTemperature();
|
||||
float testH = dht.readHumidity();
|
||||
|
||||
if (!isnan(testT) && !isnan(testH)) {
|
||||
flags.dhtError = false;
|
||||
dhtErrorCount = 0;
|
||||
temperature = testT;
|
||||
humidity = testH;
|
||||
}
|
||||
}
|
||||
lastDHTCheck = millis();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
#include <WiFi.h>
|
||||
#include <FirebaseESP32.h> // Gunakan library "Firebase ESP32 Client" by Mobizt
|
||||
|
||||
#define RXD2 16 // RX pin ESP32
|
||||
#define TXD2 17 // TX pin ESP32
|
||||
|
||||
// WiFi credentials
|
||||
#define WIFI_SSID "hydrop"
|
||||
#define WIFI_PASSWORD "123123123"
|
||||
|
||||
// Firebase config
|
||||
#define FIREBASE_HOST "https://hydrop-a1e64-default-rtdb.firebaseio.com"
|
||||
#define FIREBASE_AUTH "4lJpDHPo9LGh6WCYpjs1aRB6ABJZwHLOXkaCoLAV"
|
||||
|
||||
// Firebase objects
|
||||
FirebaseData fbdo;
|
||||
FirebaseAuth auth;
|
||||
FirebaseConfig config;
|
||||
|
||||
struct SensorData {
|
||||
float temperature;
|
||||
float humidity;
|
||||
float ph;
|
||||
float tds;
|
||||
bool tempValid;
|
||||
bool humValid;
|
||||
bool phValid;
|
||||
bool tdsValid;
|
||||
unsigned long lastUpdate;
|
||||
} sensorData;
|
||||
|
||||
struct CommStats {
|
||||
unsigned long totalReceived;
|
||||
unsigned long validData;
|
||||
unsigned long errorData;
|
||||
unsigned long lastReceived;
|
||||
} commStats = {0, 0, 0, 0};
|
||||
|
||||
const unsigned long DATA_TIMEOUT = 10000;
|
||||
const unsigned long STATS_INTERVAL = 30000;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
|
||||
|
||||
// Koneksi WiFi
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
||||
Serial.print("Connecting to WiFi");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(500);
|
||||
}
|
||||
Serial.println("\nWiFi connected!");
|
||||
|
||||
// Konfigurasi Firebase
|
||||
config.database_url = FIREBASE_HOST;
|
||||
config.signer.tokens.legacy_token = FIREBASE_AUTH;
|
||||
|
||||
Firebase.begin(&config, &auth);
|
||||
Firebase.reconnectWiFi(true);
|
||||
|
||||
Serial.println("Firebase initialized.");
|
||||
|
||||
sensorData = {0, 0, 0, 0, false, false, false, false, 0};
|
||||
|
||||
Serial.println("=== ESP32 Hydroponic Receiver ===");
|
||||
Serial.println("Menunggu data dari Arduino...");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (Serial2.available()) {
|
||||
String rawData = Serial2.readStringUntil('\n');
|
||||
rawData.trim();
|
||||
|
||||
commStats.totalReceived++;
|
||||
commStats.lastReceived = millis();
|
||||
|
||||
if (parseAndValidateData(rawData)) {
|
||||
commStats.validData++;
|
||||
sensorData.lastUpdate = millis();
|
||||
|
||||
displaySensorData();
|
||||
sendToFirebase();
|
||||
} else {
|
||||
commStats.errorData++;
|
||||
Serial.print("ERROR: Invalid data format: ");
|
||||
Serial.println(rawData);
|
||||
}
|
||||
}
|
||||
|
||||
checkDataTimeout();
|
||||
displayStats();
|
||||
|
||||
delay(100);
|
||||
}
|
||||
|
||||
bool parseAndValidateData(String data) {
|
||||
if (data.length() < 5) return false;
|
||||
|
||||
int idx1 = data.indexOf(',');
|
||||
int idx2 = data.indexOf(',', idx1 + 1);
|
||||
int idx3 = data.indexOf(',', idx2 + 1);
|
||||
if (idx1 <= 0 || idx2 <= 0 || idx3 <= 0) return false;
|
||||
|
||||
String tempStr = data.substring(0, idx1);
|
||||
String humStr = data.substring(idx1 + 1, idx2);
|
||||
String phStr = data.substring(idx2 + 1, idx3);
|
||||
String tdsStr = data.substring(idx3 + 1);
|
||||
|
||||
float temp = tempStr.toFloat();
|
||||
float hum = humStr.toFloat();
|
||||
float ph = phStr.toFloat();
|
||||
float tds = tdsStr.toFloat();
|
||||
|
||||
sensorData.temperature = temp;
|
||||
sensorData.humidity = hum;
|
||||
sensorData.ph = ph;
|
||||
sensorData.tds = tds;
|
||||
sensorData.tempValid = validateTemperature(temp);
|
||||
sensorData.humValid = validateHumidity(hum);
|
||||
sensorData.phValid = validatePH(ph);
|
||||
sensorData.tdsValid = validateTDS(tds);
|
||||
|
||||
return (sensorData.tempValid || sensorData.humValid || sensorData.phValid || sensorData.tdsValid);
|
||||
}
|
||||
|
||||
void sendToFirebase() {
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.println("WiFi disconnected, skipping Firebase upload.");
|
||||
return;
|
||||
}
|
||||
|
||||
FirebaseJson json;
|
||||
json.set("temperature", sensorData.tempValid ? sensorData.temperature : -999);
|
||||
json.set("humidity", sensorData.humValid ? sensorData.humidity : -999);
|
||||
json.set("ph", sensorData.phValid ? sensorData.ph : -999);
|
||||
json.set("tds", sensorData.tdsValid ? sensorData.tds : -999);
|
||||
json.set("timestamp", millis());
|
||||
|
||||
if (Firebase.updateNode(fbdo, "/sensorData", json)) {
|
||||
Serial.println("Data sent to Firebase.");
|
||||
} else {
|
||||
Serial.print("Firebase failed: ");
|
||||
Serial.println(fbdo.errorReason());
|
||||
}
|
||||
}
|
||||
|
||||
bool validateTemperature(float temp) {
|
||||
return temp != -999 && temp >= -10 && temp <= 60;
|
||||
}
|
||||
|
||||
bool validateHumidity(float hum) {
|
||||
return hum != -999 && hum >= 0 && hum <= 100;
|
||||
}
|
||||
|
||||
bool validatePH(float ph) {
|
||||
return ph != -999 && ph >= 0 && ph <= 14;
|
||||
}
|
||||
|
||||
bool validateTDS(float tds) {
|
||||
return tds != -999 && tds >= 0 && tds <= 3000;
|
||||
}
|
||||
|
||||
void displaySensorData() {
|
||||
Serial.println("=== SENSOR DATA RECEIVED ===");
|
||||
Serial.print("Temperature: ");
|
||||
Serial.println(sensorData.tempValid ? String(sensorData.temperature, 2) + " °C" : "INVALID");
|
||||
|
||||
Serial.print("Humidity: ");
|
||||
Serial.println(sensorData.humValid ? String(sensorData.humidity, 2) + " %" : "INVALID");
|
||||
|
||||
Serial.print("pH: ");
|
||||
Serial.println(sensorData.phValid ? String(sensorData.ph, 2) : "INVALID");
|
||||
|
||||
Serial.print("TDS: ");
|
||||
Serial.println(sensorData.tdsValid ? String(sensorData.tds, 0) + " ppm" : "INVALID");
|
||||
|
||||
Serial.println("===========================");
|
||||
}
|
||||
|
||||
void checkDataTimeout() {
|
||||
static unsigned long lastTimeoutCheck = 0;
|
||||
if (millis() - lastTimeoutCheck >= 5000) {
|
||||
if (sensorData.lastUpdate > 0 && (millis() - sensorData.lastUpdate) > DATA_TIMEOUT) {
|
||||
Serial.println("⚠️ WARNING: No valid data for 10 seconds!");
|
||||
sensorData.tempValid = false;
|
||||
sensorData.humValid = false;
|
||||
sensorData.phValid = false;
|
||||
sensorData.tdsValid = false;
|
||||
}
|
||||
lastTimeoutCheck = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void displayStats() {
|
||||
static unsigned long lastStatsDisplay = 0;
|
||||
if (millis() - lastStatsDisplay >= STATS_INTERVAL) {
|
||||
Serial.println("=== STATISTIK KOMUNIKASI ===");
|
||||
Serial.print("Total diterima: ");
|
||||
Serial.println(commStats.totalReceived);
|
||||
Serial.print("Valid: ");
|
||||
Serial.println(commStats.validData);
|
||||
Serial.print("Error: ");
|
||||
Serial.println(commStats.errorData);
|
||||
|
||||
if (commStats.totalReceived > 0) {
|
||||
float success = (float)commStats.validData / commStats.totalReceived * 100;
|
||||
Serial.print("Success rate: ");
|
||||
Serial.print(success, 1);
|
||||
Serial.println(" %");
|
||||
}
|
||||
|
||||
Serial.print("Terakhir diterima: ");
|
||||
Serial.println((millis() - commStats.lastReceived) / 1000);
|
||||
|
||||
Serial.println("=============================");
|
||||
lastStatsDisplay = millis();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue