From e335d76ba1f5eeb025a1818d7ca472da5adcbebe Mon Sep 17 00:00:00 2001 From: Tutik Date: Mon, 30 Jun 2025 12:17:05 +0700 Subject: [PATCH] first init github --- ArduinoCode/ArduinoCode.ino | 320 ++++++++++++++++++++++++++++++ hidrofish-native/hidrofish-native | 1 + hydrofish-api | 1 + 3 files changed, 322 insertions(+) create mode 100644 ArduinoCode/ArduinoCode.ino create mode 160000 hidrofish-native/hidrofish-native create mode 160000 hydrofish-api diff --git a/ArduinoCode/ArduinoCode.ino b/ArduinoCode/ArduinoCode.ino new file mode 100644 index 0000000..5530899 --- /dev/null +++ b/ArduinoCode/ArduinoCode.ino @@ -0,0 +1,320 @@ +code asli + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// 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); +} \ No newline at end of file diff --git a/hidrofish-native/hidrofish-native b/hidrofish-native/hidrofish-native new file mode 160000 index 0000000..72e55cc --- /dev/null +++ b/hidrofish-native/hidrofish-native @@ -0,0 +1 @@ +Subproject commit 72e55ccf30d98f11d2c1048799b5ebac5eff3251 diff --git a/hydrofish-api b/hydrofish-api new file mode 160000 index 0000000..9243200 --- /dev/null +++ b/hydrofish-api @@ -0,0 +1 @@ +Subproject commit 9243200aa6e33b4f2389040f214390dd04d36dba