Upload files to "/"
This commit is contained in:
parent
45823b7a38
commit
4caaac305e
|
|
@ -0,0 +1,520 @@
|
|||
#include <ESP8266WiFi.h>
|
||||
#include <Firebase_ESP_Client.h>
|
||||
|
||||
#include "addons/TokenHelper.h"
|
||||
#include "addons/RTDBHelper.h"
|
||||
|
||||
#include <OneWire.h>
|
||||
#include <DallasTemperature.h>
|
||||
#include <SimpleKalmanFilter.h>
|
||||
#include <time.h>
|
||||
|
||||
/* ================= 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue