From 4caaac305e43480a9a464d5e501ce7c893025480 Mon Sep 17 00:00:00 2001 From: waldan88 Date: Wed, 1 Jul 2026 09:41:37 +0700 Subject: [PATCH] Upload files to "/" --- tempe.ino | 520 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 520 insertions(+) create mode 100644 tempe.ino diff --git a/tempe.ino b/tempe.ino new file mode 100644 index 0000000..1128a41 --- /dev/null +++ b/tempe.ino @@ -0,0 +1,520 @@ +#include +#include + +#include "addons/TokenHelper.h" +#include "addons/RTDBHelper.h" + +#include +#include +#include +#include + +/* ================= WIFI ================= */ +#define WIFI_SSID "WONG PUSAT" +#define WIFI_PASSWORD "probolinggo01" + +/* ================= FIREBASE ================= */ +#define API_KEY "AIzaSyANiVsJP6_-x7EWlCyFs3wzRHiHVE92gZg" +#define DATABASE_URL "https://tempe-56d26-default-rtdb.firebaseio.com/" +#define FIREBASE_PROJECT_ID "tempe-56d26" + +/* ================= PIN ================= */ +#define ONE_WIRE_BUS D4 +#define RELAY_HEATER D1 +#define RELAY_FAN_HOT D2 +#define RELAY_FAN_COLD D5 + +/* ================= FIREBASE ================= */ +FirebaseData fbdo; +FirebaseAuth auth; +FirebaseConfig config; +FirebaseData firestoreData; + +/* ================= SENSOR ================= */ +OneWire oneWire(ONE_WIRE_BUS); +DallasTemperature sensors(&oneWire); + +/* ================= LINKED LIST ================= */ +class LinkedList { + + private: + float* arr; + int max_size; + int current_size; + + public: + + LinkedList(int size) { + + max_size = size; + current_size = 0; + arr = new float[max_size]; + } + + void update(float value) { + + if (current_size < max_size) { + + arr[current_size++] = value; + } + else { + + for (int i = 1; i < max_size; i++) { + arr[i - 1] = arr[i]; + } + + arr[max_size - 1] = value; + } + } + + float getIndex(int index) { + + if (index < 0 || index >= current_size) + return 0; + + return arr[index]; + } + + int size() { + return current_size; + } +}; + +/* ================= REGRESI ================= */ +class LinearRegression { + + public: + + LinearRegression(int max_size) { + data = new LinkedList(max_size); + } + + void update(float new_data) { + data->update(new_data); + } + + float predict(int n_next = 1) { + + int n = data->size(); + + if (n < 2) + return data->getIndex(0); + + float sumX = 0; + float sumY = 0; + float sumXY = 0; + float sumX2 = 0; + + for (int i = 0; i < n; i++) { + + sumX += i; + sumY += data->getIndex(i); + sumXY += i * data->getIndex(i); + sumX2 += i * i; + } + + float denominator = (n * sumX2 - sumX * sumX); + + if (denominator == 0) + return data->getIndex(n - 1); + + float m = (n * sumXY - sumX * sumY) / denominator; + + float c = (sumY - m * sumX) / n; + + return m * (n + n_next - 1) + c; + } + + private: + LinkedList* data; +}; + +/* ================= REGRESI ================= */ +LinearRegression lr(5); + +/* ================= VAR ================= */ +float t1, t2, t3; +float tf1, tf2, tf3; + +float tMin, tMax, tAvg; +float prediksi; + +/* ================= ERROR ================= */ +float prediksi_lama = 0; +unsigned long waktu_prediksi = 0; +bool siapBanding = false; +float errorTerakhir = 0; + +unsigned long lastUpload = 0; +const unsigned long uploadInterval = 60000; // 1 menit + +/* ================= KALMAN ================= */ +SimpleKalmanFilter kf1(2, 2, 0.01); +SimpleKalmanFilter kf2(2, 2, 0.01); +SimpleKalmanFilter kf3(2, 2, 0.01); + +/* ================= PEMBULATAN ================= */ +float bulat2(float x) { + return round(x * 100.0) / 100.0; +} + +void kontrolSuhu(); +void tampilSerial(); +void kirimFirebase(); +void kirimFirestore(); + +/* ================= SETUP ================= */ +void setup() { + + Serial.begin(9600); + delay(2000); + + pinMode(RELAY_HEATER, OUTPUT); + pinMode(RELAY_FAN_HOT, OUTPUT); + pinMode(RELAY_FAN_COLD, OUTPUT); + + digitalWrite(RELAY_HEATER, HIGH); + digitalWrite(RELAY_FAN_HOT, HIGH); + digitalWrite(RELAY_FAN_COLD, HIGH); + + sensors.begin(); + + Serial.println("=== SISTEM FERMENTASI TEMPE IoT ==="); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + + Serial.print("Menghubungkan WiFi"); + + unsigned long startTime = millis(); + +while (time(nullptr) < 100000 && + millis() - startTime < 30000) { + Serial.print("."); + delay(500); +} + +if (time(nullptr) < 100000) { + Serial.println("Gagal sinkron waktu, lanjutkan program"); +} else { + Serial.println("Waktu berhasil sinkron"); +} + + Serial.println("\nWiFi Terhubung"); + Serial.println(WiFi.localIP()); + configTime(7 * 3600, 0, "pool.ntp.org", "time.nist.gov"); + +Serial.print("Sinkronisasi waktu"); + +while (time(nullptr) < 100000) { + Serial.print("."); + delay(500); +} + +Serial.println("\nWaktu berhasil sinkron"); + + config.api_key = API_KEY; + config.database_url = DATABASE_URL; + + if (Firebase.signUp(&config, &auth, "", "")) { + + Serial.println("Firebase signup berhasil"); + } + else { + + Serial.printf("Signup gagal: %s\n", + config.signer.signupError.message.c_str()); + } + config.token_status_callback = tokenStatusCallback; + Firebase.begin(&config, &auth); + Firebase.reconnectWiFi(true); + + Serial.print("Jumlah sensor terdeteksi: "); + Serial.println(sensors.getDeviceCount()); +} + +/* ================= LOOP ================= */ +void loop() { + + if (millis() - lastUpload >= uploadInterval) { + + lastUpload = millis(); + + /* ===== BACA SENSOR ===== */ + sensors.requestTemperatures(); + + t1 = sensors.getTempCByIndex(0); + t2 = sensors.getTempCByIndex(1); + t3 = sensors.getTempCByIndex(2); + + /* ===== VALIDASI SENSOR ===== */ + if (t1 == -127 || t1 == 85) t1 = tf1; + if (t2 == -127 || t2 == 85) t2 = tf2; + if (t3 == -127 || t3 == 85) t3 = tf3; + + /* ===== FILTER KALMAN ===== */ + tf1 = bulat2(kf1.updateEstimate(t1)); + tf2 = bulat2(kf2.updateEstimate(t2)); + tf3 = bulat2(kf3.updateEstimate(t3)); + + /* ===== STATISTIK ===== */ + tMin = min(min(tf1, tf2), tf3); + tMax = max(max(tf1, tf2), tf3); + + tMin = bulat2(tMin); + tMax = bulat2(tMax); + + tAvg = bulat2((tf1 + tf2 + tf3) / 3.0); + + /* ===== REGRESI ===== */ + lr.update(tAvg); + + prediksi = bulat2(lr.predict(5)); + + /* ===== ERROR PREDIKSI ===== */ + if (!siapBanding) { + prediksi_lama = prediksi; + waktu_prediksi = millis(); + siapBanding = true; + } + + if (siapBanding && + millis() - waktu_prediksi >= 300000) { + + errorTerakhir = abs(prediksi_lama - tAvg); + siapBanding = false; + } + + /* ===== KONTROL ===== */ + kontrolSuhu(); + + /* ===== SERIAL ===== */ + tampilSerial(); + + /* ===== FIREBASE ===== */ + kirimFirebase(); + kirimFirestore(); + + Serial.println("Upload berhasil"); + } +} + +void kirimFirestore() { + + if (!Firebase.ready() || auth.token.uid == "") + return; + + FirebaseJson content; + + content.set("fields/sensor1/doubleValue", tf1); + content.set("fields/sensor2/doubleValue", tf2); + content.set("fields/sensor3/doubleValue", tf3); + + content.set("fields/min/doubleValue", tMin); + content.set("fields/max/doubleValue", tMax); + content.set("fields/rata_rata/doubleValue", tAvg); + + content.set("fields/prediksi/doubleValue", prediksi); + content.set("fields/error/doubleValue", errorTerakhir); + + content.set( + "fields/pemanas/stringValue", + digitalRead(RELAY_HEATER) == LOW ? "ON" : "OFF"); + + content.set( + "fields/kipas_panas/stringValue", + digitalRead(RELAY_FAN_HOT) == LOW ? "ON" : "OFF"); + + content.set( + "fields/kipas_dingin/stringValue", + digitalRead(RELAY_FAN_COLD) == LOW ? "ON" : "OFF"); + + time_t now = time(nullptr); +struct tm *tm_info = localtime(&now); + +char tanggal[11]; +char jam[6]; + +strftime(tanggal, sizeof(tanggal), "%Y-%m-%d", tm_info); +strftime(jam, sizeof(jam), "%H:%M", tm_info); + +content.set("fields/tanggal/stringValue", tanggal); +content.set("fields/jam/stringValue", jam); + +String documentPath = + String("monitoring/") + + tanggal + + "/data/" + + jam; + + if (Firebase.Firestore.createDocument( + &firestoreData, + FIREBASE_PROJECT_ID, + "", + documentPath.c_str(), + content.raw())) { + + Serial.println("Firestore berhasil"); + } + else { + + Serial.println("Firestore gagal"); + Serial.println(firestoreData.errorReason()); + } +} + +/* ================= KONTROL ================= */ +void kontrolSuhu() { + + if (tMin < 30) { + + digitalWrite(RELAY_HEATER, LOW); + digitalWrite(RELAY_FAN_HOT, LOW); + digitalWrite(RELAY_FAN_COLD, HIGH); + } + + else if (tMax > 40) { + + digitalWrite(RELAY_HEATER, HIGH); + digitalWrite(RELAY_FAN_HOT, HIGH); + digitalWrite(RELAY_FAN_COLD, LOW); + } + + else { + + if (prediksi < 30) { + + digitalWrite(RELAY_HEATER, LOW); + digitalWrite(RELAY_FAN_HOT, LOW); + digitalWrite(RELAY_FAN_COLD, HIGH); + } + + else if (prediksi > 40) { + + digitalWrite(RELAY_HEATER, HIGH); + digitalWrite(RELAY_FAN_HOT, HIGH); + digitalWrite(RELAY_FAN_COLD, LOW); + } + + else { + + digitalWrite(RELAY_HEATER, HIGH); + digitalWrite(RELAY_FAN_HOT, HIGH); + digitalWrite(RELAY_FAN_COLD, HIGH); + } + } +} + +/* ================= SERIAL ================= */ +void tampilSerial() { + + String statusPemanas = "OFF"; + String statusKipasPanas = "OFF"; + String statusKipasDingin = "OFF"; + + if (digitalRead(RELAY_HEATER) == LOW) + statusPemanas = "ON"; + + if (digitalRead(RELAY_FAN_HOT) == LOW) + statusKipasPanas = "ON"; + + if (digitalRead(RELAY_FAN_COLD) == LOW) + statusKipasDingin = "ON"; + + Serial.println("\n=================================================="); + Serial.println(" MONITORING FERMENTASI TEMPE"); + Serial.println("=================================================="); + + Serial.println("\n[SENSOR SUHU]"); + + Serial.print(" S1 : "); + Serial.print(tf1, 2); + Serial.println(" °C"); + + Serial.print(" S2 : "); + Serial.print(tf2, 2); + Serial.println(" °C"); + + Serial.print(" S3 : "); + Serial.print(tf3, 2); + Serial.println(" °C"); + + Serial.println("\n[STATISTIK]"); + + Serial.print(" Min : "); + Serial.print(tMin, 2); + Serial.println(" °C"); + + Serial.print(" Max : "); + Serial.print(tMax, 2); + Serial.println(" °C"); + + Serial.print(" Rata : "); + Serial.print(tAvg, 2); + Serial.println(" °C"); + + Serial.println("\n[PREDIKSI]"); + + Serial.print(" 5 Menit ke depan : "); + Serial.print(prediksi, 2); + Serial.println(" °C"); + + Serial.println("\n[STATUS SISTEM]"); + + Serial.print(" Pemanas : "); + Serial.println(statusPemanas); + + Serial.print(" Kipas Panas : "); + Serial.println(statusKipasPanas); + + Serial.print(" Kipas Dingin : "); + Serial.println(statusKipasDingin); + + Serial.println("==================================================\n"); +} + +/* ================= FIREBASE ================= */ +void kirimFirebase() { + + if (Firebase.ready()) { + + FirebaseJson json; + + /* ===== SENSOR ===== */ + json.set("sensor1", tf1); + json.set("sensor2", tf2); + json.set("sensor3", tf3); + + /* ===== STATISTIK ===== */ + json.set("min", tMin); + json.set("max", tMax); + json.set("rata_rata", tAvg); + + /* ===== PREDIKSI ===== */ + json.set("prediksi", prediksi); + + /* ===== ERROR ===== */ + json.set("error", errorTerakhir); + + /* ===== STATUS ===== */ + json.set("status/pemanas", + digitalRead(RELAY_HEATER) == LOW ? "ON" : "OFF"); + + json.set("status/kipas_panas", + digitalRead(RELAY_FAN_HOT) == LOW ? "ON" : "OFF"); + + json.set("status/kipas_dingin", + digitalRead(RELAY_FAN_COLD) == LOW ? "ON" : "OFF"); + + /* ===== KIRIM KE FIREBASE ===== */ + if (Firebase.RTDB.setJSON(&fbdo, + "/fermentasi", + &json)) { + + } + else { + + Serial.println("Firebase gagal"); + Serial.println(fbdo.errorReason()); + } + } +} \ No newline at end of file