TKK_E32220022/ArduinoCode/ArduinoCode.ino

320 lines
9.0 KiB
C++

code asli
#include <WiFi.h>
#include <Firebase_ESP_Client.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <time.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <ESP32Servo.h>
#include <RTClib.h>
#include <HTTPClient.h>
// WiFi credentials
const char* ssid = "HIDROFISH";
const char* password = "ikan1234";
// Firebase config
#define API_KEY "AIzaSyCIJ5xVWDHHuhLGKV-OFYlLXBvjrKtI7ic"
#define DATABASE_URL "https://hydrofish-e00a3-default-rtdb.firebaseio.com/"
#define LEGACY_TOKEN "m2l1lmVvUrVTfUmwfkN5bVNKzifh2nM8DNLSd3c2"
// Pin definitions
#define TDS_PIN 34
#define TURBIDITY_PIN 33
#define PH_PIN 35
#define TRIG_PIN 26
#define ECHO_PIN 25
#define DS18B20_PIN 32
#define BUZZER_PIN 15
#define LED_PIN 2
#define SERVO_PIN 19
// Objects
RTC_DS3231 rtc;
FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;
OneWire oneWire(DS18B20_PIN);
DallasTemperature sensors(&oneWire);
LiquidCrystal_I2C lcd(0x27, 16, 2);
Servo feederServo;
// Variables
bool firebaseConnected = false;
int lcdScreen = 0;
String pagiTime = "08:00";
String soreTime = "13:00";
String malemTime = "19:00";
int jumlahTakar = 1;
String lastFeedingTime = "";
unsigned long previousMillis = 0;
const long interval = 5000;
float ph_slope = -6.548;
float ph_offset = 25.69;
unsigned long lastHistorySentMillis = 0;
int intervalHistoryMinutes = 5; // default 5 menit
// ===================== SETUP =====================
void setup() {
Serial.begin(115200);
Wire.begin(22, 21);
sensors.begin();
lcd.init();
lcd.backlight();
pinMode(LED_PIN, OUTPUT);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
analogReadResolution(12);
feederServo.attach(SERVO_PIN);
feederServo.write(0);
setupWiFi();
if (!rtc.begin()) {
Serial.println("RTC tidak ditemukan!");
while (1);
}
if (rtc.lostPower()) {
Serial.println("RTC kehilangan daya, set waktu ke waktu compile.");
rtc.adjust(DateTime(F(_DATE), F(TIME_)));
}
configTime(7 * 3600, 0, "pool.ntp.org", "time.nist.gov");
setupFirebase();
}
// ===================== WIFI SETUP =====================
void setupWiFi() {
Serial.print("Menghubungkan ke WiFi...");
WiFi.begin(ssid, password);
unsigned long startTime = millis();
while (WiFi.status() != WL_CONNECTED && millis() - startTime < 10000) {
delay(500);
Serial.print(".");
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi terhubung!");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("\nGagal terhubung ke WiFi.");
}
}
// ===================== FIREBASE SETUP =====================
void setupFirebase() {
config.api_key = API_KEY;
config.database_url = DATABASE_URL;
config.signer.tokens.legacy_token = LEGACY_TOKEN;
Firebase.begin(&config, &auth);
Firebase.reconnectWiFi(true);
}
void getIntervalHistory() {
if (WiFi.status() != WL_CONNECTED) return;
if (Firebase.RTDB.getInt(&fbdo, "/setting/interval_history")) {
intervalHistoryMinutes = fbdo.intData();
Serial.print("Interval history diambil dari Firebase: ");
Serial.print(intervalHistoryMinutes);
Serial.println(" menit");
} else {
Serial.println("Gagal ambil interval_history: " + fbdo.errorReason());
}
}
void kirimHistoryKeServer(float ph, float suhu, float tds, float tinggi, String turbidity) {
if (WiFi.status() != WL_CONNECTED) return;
HTTPClient http;
http.begin("https://hydrofish-api-2ywj.vercel.app/api/kirimdata");
http.addHeader("Content-Type", "application/json");
// Dapatkan waktu UTC ISO 8601
time_t now;
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Gagal mendapatkan waktu");
return;
}
char timestamp[30];
strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S.000Z", &timeinfo);
String json = "{";
json += "\"ph_air\":" + String(ph, 2) + ",";
json += "\"suhu_air\":" + String(suhu, 2) + ",";
json += "\"tds\":" + String(tds, 2) + ",";
json += "\"timestamp\":\"" + String(timestamp) + "\",";
json += "\"tinggi_air\":" + String(tinggi, 1) + ",";
json += "\"turbidity\":\"" + turbidity + "\"";
json += "}";
int httpResponseCode = http.POST(json);
if (httpResponseCode > 0) {
Serial.print("Data history terkirim: ");
Serial.println(httpResponseCode);
} else {
Serial.print("Gagal kirim data history: ");
Serial.println(httpResponseCode);
}
http.end();
}
// ===================== WAKTU =====================
String getRTCTime() {
DateTime now = rtc.now();
char buffer[6];
sprintf(buffer, "%02d:%02d", now.hour(), now.minute());
return String(buffer);
}
String getCurrentTime() {
struct tm timeinfo;
if (WiFi.status() == WL_CONNECTED && getLocalTime(&timeinfo)) {
char buffer[6];
sprintf(buffer, "%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
return String(buffer);
} else {
return getRTCTime(); // fallback ke RTC
}
}
// ===================== SENSOR =====================
float konversiKeNTU(float voltage) {
float ntu = -1120.4 * voltage * voltage + 5742.3 * voltage - 4352.9;
return (ntu < 0) ? 0 : ntu;
}
String bacaKekeruhan(float voltage) {
return (konversiKeNTU(voltage) < 1500.0) ? "Keruh" : "Jernih";
}
void cekKekeruhan(float voltage) {
digitalWrite(BUZZER_PIN, (konversiKeNTU(voltage) < 1500.0) ? HIGH : LOW);
}
void updateLCD(float tds, float turbidity, float phV, float ph, float tinggi, float suhu) {
lcd.clear();
switch (lcdScreen) {
case 0: lcd.setCursor(0, 0); lcd.print("Hydrofish"); lcd.setCursor(0, 1); lcd.print("Monitoring..."); break;
case 1: lcd.setCursor(0, 0); lcd.print("pH Air: "); lcd.print(ph, 2); break;
case 2: lcd.setCursor(0, 0); lcd.print("Suhu: "); lcd.print(suhu, 1); lcd.print((char)223); lcd.print("C"); break;
case 3: lcd.setCursor(0, 0); lcd.print("TDS: "); lcd.print(tds, 2); lcd.print(" ppm"); break;
case 4: lcd.setCursor(0, 0); lcd.print("Tinggi: "); lcd.print(tinggi, 1); lcd.print(" cm"); break;
case 5: lcd.setCursor(0, 0); lcd.print("Kekeruhan: "); lcd.setCursor(0, 1); lcd.print(bacaKekeruhan(turbidity)); break;
}
lcdScreen = (lcdScreen + 1) % 6;
}
void kirimKeFirebase(float tds, String status, float phV, float ph, float tinggi, float suhu) {
if (WiFi.status() != WL_CONNECTED || !Firebase.ready()) return;
FirebaseJson json;
json.set("tds", tds);
json.set("turbidity", status);
json.set("ph_voltage", phV);
json.set("ph", ph);
json.set("tinggi_air", tinggi);
json.set("suhu", suhu);
if (Firebase.RTDB.setJSON(&fbdo, "/sensor_data", &json)) {
Serial.println("Data terkirim ke Firebase");
} else {
Serial.println("Gagal kirim: " + fbdo.errorReason());
}
}
void getFeedingSchedule() {
if (WiFi.status() != WL_CONNECTED) return;
if (Firebase.RTDB.getString(&fbdo, "/jadwal_pakan/pagi")) pagiTime = fbdo.stringData();
if (Firebase.RTDB.getString(&fbdo, "/jadwal_pakan/sore")) soreTime = fbdo.stringData();
if (Firebase.RTDB.getString(&fbdo, "/jadwal_pakan/malem")) malemTime = fbdo.stringData();
if (Firebase.RTDB.getInt(&fbdo, "/jadwal_pakan/jumlah_takar")) jumlahTakar = fbdo.intData();
}
void sendFeedingStatus(bool status) {
if (WiFi.status() != WL_CONNECTED) return;
FirebaseJson json;
json.set("status_pakan", status);
Firebase.RTDB.setJSON(&fbdo, "/sensor_data", &json);
}
void performFeeding() {
for (int i = 0; i < jumlahTakar; i++) {
feederServo.write(180);
delay(2000);
feederServo.write(0);
delay(2000);
}
}
// ===================== LOOP =====================
void loop() {
if (!firebaseConnected && WiFi.status() == WL_CONNECTED && Firebase.ready()) {
firebaseConnected = true;
digitalWrite(LED_PIN, HIGH);
Serial.println("Firebase connected.");
}
String currentTime = getCurrentTime();
getFeedingSchedule();
getIntervalHistory(); // Ambil interval dari Firebase
if ((currentTime == pagiTime || currentTime == soreTime || currentTime == malemTime) && lastFeedingTime != currentTime) {
performFeeding();
sendFeedingStatus(true);
lastFeedingTime = currentTime;
}
float tdsV = (analogRead(TDS_PIN) / 4095.0) * 3.3;
float turbV = (analogRead(TURBIDITY_PIN) / 4095.0) * 3.3;
float phV = (analogRead(PH_PIN) / 4095.0) * 3.3;
float ph = ph_slope * phV + ph_offset;
digitalWrite(TRIG_PIN, LOW); delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH); delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH);
float tinggiAir = duration * 0.034 / 2;
sensors.requestTemperatures();
float suhu = sensors.getTempCByIndex(0);
cekKekeruhan(turbV);
updateLCD(tdsV, turbV, phV, ph, tinggiAir, suhu);
Serial.print("Jam Sekarang: "); Serial.println(currentTime);
Serial.print("pH Tegangan: "); Serial.print(phV, 3); Serial.print(" V | pH: "); Serial.println(ph, 2);
if (millis() - previousMillis >= interval) {
previousMillis = millis();
kirimKeFirebase(tdsV, bacaKekeruhan(turbV), phV, ph, tinggiAir, suhu);
}
if (millis() - lastHistorySentMillis >= intervalHistoryMinutes * 60000UL) {
lastHistorySentMillis = millis();
kirimHistoryKeServer(ph, suhu, tdsV, tinggiAir, bacaKekeruhan(turbV));
}
delay(500);
}