1039 lines
18 KiB
C++
1039 lines
18 KiB
C++
#include "HX711.h"
|
|
#include <WiFi.h>
|
|
#include <Firebase_ESP_Client.h>
|
|
#include <Wire.h>
|
|
#include <RTClib.h>
|
|
#include "time.h"
|
|
|
|
// ======================================================
|
|
// WIFI
|
|
// ======================================================
|
|
const char* ssid = "Rio";
|
|
const char* password = "Rio1234567";
|
|
|
|
// ======================================================
|
|
// FIREBASE
|
|
// ======================================================
|
|
#define API_KEY "AIzaSyC-YYniuYaVJAZl0LywCbC-HKvMED0_uUY"
|
|
#define DATABASE_URL "https://poultryrail-1205e-default-rtdb.firebaseio.com/"
|
|
#define USER_EMAIL "esp32@gmail.com"
|
|
#define USER_PASSWORD "12345678"
|
|
#define FIREBASE_PROJECT_ID "poultryrail-1205e"
|
|
|
|
FirebaseData fbdo;
|
|
FirebaseAuth auth;
|
|
FirebaseConfig config;
|
|
|
|
// ======================================================
|
|
// RTC
|
|
// ======================================================
|
|
RTC_DS3231 rtc;
|
|
|
|
// ======================================================
|
|
// STEPPER A4988
|
|
// ======================================================
|
|
#define STEP_PIN 4
|
|
#define DIR_PIN 2
|
|
#define EN_PIN 5
|
|
|
|
long totalSteps = 3900;
|
|
long posisiStepper = 0;
|
|
|
|
// ======================================================
|
|
// HX711
|
|
// ======================================================
|
|
#define DT1 25
|
|
#define SCK1 26
|
|
|
|
#define DT2 32
|
|
#define SCK2 33
|
|
|
|
HX711 scale1;
|
|
HX711 scale2;
|
|
|
|
float calibration_factor1 = 422;
|
|
float calibration_factor2 = 399;
|
|
|
|
// ======================================================
|
|
// TIMER
|
|
// ======================================================
|
|
unsigned long lastRTC = 0;
|
|
unsigned long lastRead = 0;
|
|
unsigned long lastJadwal = 0;
|
|
unsigned long lastHeartbeat = 0;
|
|
unsigned long lastManual = 0;
|
|
|
|
void updateHeartbeat() {
|
|
|
|
if (millis() - lastHeartbeat >= 5000) {
|
|
|
|
lastHeartbeat = millis();
|
|
|
|
Firebase.RTDB.setInt(
|
|
&fbdo,
|
|
"/status/heartbeat",
|
|
millis()
|
|
);
|
|
}
|
|
}
|
|
|
|
String lastTrigger = "";
|
|
|
|
bool wifiTerhubungSebelumnya = true;
|
|
|
|
void kirimNotifikasi(String pesan) {
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/notifikasi/pesan",
|
|
pesan
|
|
);
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/notifikasi/status",
|
|
"baru"
|
|
);
|
|
}
|
|
|
|
void simpanRiwayat(
|
|
String waktu,
|
|
String jam,
|
|
String tanggal,
|
|
String status
|
|
);
|
|
|
|
void simpanRiwayatFirestore(
|
|
String waktu,
|
|
String jam,
|
|
String tanggal,
|
|
String status,
|
|
float beratKanan,
|
|
float beratKiri
|
|
);
|
|
|
|
// ======================================================
|
|
// STEPPER
|
|
// ======================================================
|
|
void stepMotor(long jumlahStep,
|
|
int speedDelay,
|
|
bool maju) {
|
|
|
|
for (long i = 0; i < jumlahStep; i++) {
|
|
|
|
if (i % 500 == 0) {
|
|
updateHeartbeat();
|
|
}
|
|
|
|
|
|
digitalWrite(STEP_PIN, HIGH);
|
|
delayMicroseconds(speedDelay);
|
|
|
|
digitalWrite(STEP_PIN, LOW);
|
|
delayMicroseconds(speedDelay);
|
|
}
|
|
|
|
// simpan posisi stepper
|
|
if (maju) {
|
|
|
|
posisiStepper += jumlahStep;
|
|
}
|
|
else {
|
|
|
|
posisiStepper -= jumlahStep;
|
|
|
|
if (posisiStepper < 0) {
|
|
posisiStepper = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ======================================================
|
|
// BACA BERAT
|
|
// ======================================================
|
|
float bacaBerat1() {
|
|
|
|
float b1 = scale1.get_units(3);
|
|
|
|
if (abs(b1) < 10) b1 = 0;
|
|
|
|
return round(b1 * 10) / 10.0;
|
|
}
|
|
|
|
float bacaBerat2() {
|
|
|
|
float b2 = scale2.get_units(3);
|
|
|
|
if (abs(b2) < 10) b2 = 0;
|
|
|
|
return round(b2 * 10) / 10.0;
|
|
}
|
|
|
|
|
|
// BACA JARAK DARI FIREBASE
|
|
|
|
float bacaJarakFirebase() {
|
|
|
|
if (Firebase.RTDB.getFloat(
|
|
&fbdo,
|
|
"/sensor/jarak")) {
|
|
|
|
return fbdo.floatData();
|
|
}
|
|
|
|
return 999;
|
|
}
|
|
|
|
// ======================================================
|
|
// HENTAKAN PAKAN
|
|
// ======================================================
|
|
void hentakanPakan() {
|
|
|
|
// maju sedikit
|
|
digitalWrite(DIR_PIN, HIGH);
|
|
|
|
stepMotor(50, 800, true);
|
|
|
|
delay(50);
|
|
|
|
// mundur sedikit
|
|
digitalWrite(DIR_PIN, LOW);
|
|
|
|
stepMotor(50, 800, false);
|
|
|
|
delay(50);
|
|
|
|
// balik maju lagi
|
|
digitalWrite(DIR_PIN, HIGH);
|
|
}
|
|
|
|
void prosesPemberianPakan(
|
|
String key,
|
|
String waktu,
|
|
String jam,
|
|
String tanggal
|
|
)
|
|
{
|
|
float jarakAwal = bacaJarakFirebase();
|
|
|
|
Serial.print("Jarak Awal: ");
|
|
Serial.println(jarakAwal);
|
|
|
|
// stok kurang dari 15%
|
|
if (jarakAwal >= 13) {
|
|
|
|
Serial.println("STOK PAKAN KURANG");
|
|
Serial.println("JADWAL DIBATALKAN");
|
|
|
|
kirimNotifikasi(
|
|
"Pemberian pakan gagal karena stok habis"
|
|
);
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/jadwal/" + key + "/status",
|
|
"Pemberian Pakan gagal dijalankan karena stok habis"
|
|
);
|
|
|
|
simpanRiwayatFirestore(
|
|
waktu,
|
|
jam,
|
|
tanggal,
|
|
"Pemberian Pakan gagal dijalankan karena stok habis",
|
|
bacaBerat1(), // kanan
|
|
bacaBerat2() // kiri
|
|
);
|
|
|
|
Firebase.RTDB.deleteNode(
|
|
&fbdo,
|
|
"/jadwal/" + key
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
float sisaKanan = bacaBerat1();
|
|
float sisaKiri = bacaBerat2();
|
|
|
|
bool isiKanan = (sisaKanan <= 30);
|
|
bool isiKiri = (sisaKiri <= 30);
|
|
|
|
// jika keduanya masih banyak
|
|
if (!isiKanan && !isiKiri) {
|
|
|
|
String pesan =
|
|
"Pemberian pakan gagal karena kedua wadah masih diatas 30 gram";
|
|
|
|
Serial.println(pesan);
|
|
|
|
if (key != "manual") {
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/jadwal/" + key + "/status",
|
|
pesan
|
|
);
|
|
|
|
Firebase.RTDB.deleteNode(
|
|
&fbdo,
|
|
"/jadwal/" + key
|
|
);
|
|
}
|
|
|
|
simpanRiwayatFirestore(
|
|
waktu,
|
|
jam,
|
|
tanggal,
|
|
pesan,
|
|
sisaKanan,
|
|
sisaKiri
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/jadwal/" + key + "/status",
|
|
"running"
|
|
);
|
|
|
|
// ======================================================
|
|
// PAGI / SORE
|
|
// ======================================================
|
|
int jumlahTitik;
|
|
long langkahPerTitik;
|
|
|
|
if (waktu == "Pagi") {
|
|
|
|
jumlahTitik = 3;
|
|
langkahPerTitik = 1250;
|
|
}
|
|
else {
|
|
|
|
jumlahTitik = 3;
|
|
langkahPerTitik = 1250;
|
|
}
|
|
|
|
// ======================================================
|
|
// TARGET
|
|
// ======================================================
|
|
float maxKeluar1 = 5.0;
|
|
float maxKeluar2 = 5.0;
|
|
|
|
// ======================================================
|
|
// DRIVER ON
|
|
// ======================================================
|
|
digitalWrite(EN_PIN, LOW);
|
|
|
|
// ======================================================
|
|
// ARAH MAJU
|
|
// ======================================================
|
|
digitalWrite(DIR_PIN, HIGH);
|
|
|
|
// ======================================================
|
|
// LOOP TITIK
|
|
// ======================================================
|
|
for (int titik = 1; titik <= jumlahTitik; titik++) {
|
|
|
|
updateHeartbeat();
|
|
|
|
// CEK STOK SAAT BERJALAN
|
|
float jarakSekarang =
|
|
bacaJarakFirebase();
|
|
|
|
Serial.print("Jarak Sekarang: ");
|
|
Serial.println(jarakSekarang);
|
|
|
|
// stok habis
|
|
// ==========================================
|
|
// CEK ULANG STOK
|
|
// ==========================================
|
|
int deteksiHabis = 0;
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
float cekUlang = bacaJarakFirebase();
|
|
|
|
Serial.print("Cek Ulang ");
|
|
Serial.print(i);
|
|
Serial.print(" : ");
|
|
Serial.println(cekUlang);
|
|
|
|
if (cekUlang >= 13) {
|
|
|
|
deteksiHabis++;
|
|
}
|
|
|
|
delay(50);
|
|
}
|
|
|
|
// ==========================================
|
|
// JIKA 3X TERDETEK HABIS
|
|
// ==========================================
|
|
if (deteksiHabis >= 3) {
|
|
|
|
Serial.println("PAKAN HABIS");
|
|
Serial.println("KEMBALI KE AWAL");
|
|
|
|
kirimNotifikasi(
|
|
"Pakan habis saat proses pemberian berjalan"
|
|
);
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/servo1/action",
|
|
"close"
|
|
);
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/servo2/action",
|
|
"close"
|
|
);
|
|
|
|
delay(300);
|
|
|
|
digitalWrite(DIR_PIN, LOW);
|
|
|
|
stepMotor(posisiStepper, 800, false);
|
|
|
|
digitalWrite(EN_PIN, HIGH);
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/jadwal/" + key + "/status",
|
|
"Pemberian pakan belum tercapai stok habis dijalan"
|
|
);
|
|
|
|
simpanRiwayatFirestore(
|
|
waktu,
|
|
jam,
|
|
tanggal,
|
|
"Pemberian pakan belum tercapai stok habis dijalan",
|
|
bacaBerat1(), // kanan
|
|
bacaBerat2() // kiri
|
|
);
|
|
|
|
Firebase.RTDB.deleteNode(
|
|
&fbdo,
|
|
"/jadwal/" + key
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
Serial.print("TITIK KE : ");
|
|
Serial.println(titik);
|
|
|
|
// ==========================================
|
|
// STEPPER MAJU
|
|
// ==========================================
|
|
stepMotor(langkahPerTitik, 700, true);
|
|
|
|
delay(300);
|
|
|
|
// ==========================================
|
|
// BERAT AWAL
|
|
// ==========================================
|
|
float awal1 = bacaBerat1();
|
|
float awal2 = bacaBerat2();
|
|
|
|
// ==========================================
|
|
// BUKA SERVO
|
|
// ==========================================
|
|
bool close1 = !isiKanan;
|
|
bool close2 = !isiKiri;
|
|
|
|
if (isiKanan) {
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/servo2/action",
|
|
"open"
|
|
);
|
|
|
|
Serial.println("SERVO1 OPEN");
|
|
}
|
|
|
|
if (isiKiri) {
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/servo1/action",
|
|
"open"
|
|
);
|
|
|
|
Serial.println("SERVO2 OPEN");
|
|
}
|
|
|
|
// ==========================================
|
|
// LOOP PAKAN
|
|
// ==========================================
|
|
while (!close1 || !close2) {
|
|
|
|
updateHeartbeat();
|
|
|
|
hentakanPakan();
|
|
|
|
float sekarang1 = bacaBerat1();
|
|
float sekarang2 = bacaBerat2();
|
|
|
|
float keluar1 =
|
|
sekarang1 - awal1;
|
|
|
|
float keluar2 =
|
|
sekarang2 - awal2;
|
|
|
|
if (keluar1 < 0) keluar1 = 0;
|
|
if (keluar2 < 0) keluar2 = 0;
|
|
|
|
Firebase.RTDB.setFloat(
|
|
&fbdo,
|
|
"/sensor/keluar1",
|
|
keluar1
|
|
);
|
|
|
|
Firebase.RTDB.setFloat(
|
|
&fbdo,
|
|
"/sensor/keluar2",
|
|
keluar2
|
|
);
|
|
|
|
Serial.print("Keluar1: ");
|
|
Serial.print(keluar1);
|
|
|
|
Serial.print(" | Keluar2: ");
|
|
Serial.println(keluar2);
|
|
|
|
// ==========================================
|
|
// SERVO1 CLOSE
|
|
// ==========================================
|
|
if (isiKanan &&
|
|
!close1 &&
|
|
keluar1 >= maxKeluar1)
|
|
{
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/servo2/action",
|
|
"close"
|
|
);
|
|
|
|
close1 = true;
|
|
|
|
Serial.println("SERVO2 CLOSE");
|
|
}
|
|
|
|
// ==========================================
|
|
// SERVO2 CLOSE
|
|
// ==========================================
|
|
if (isiKiri &&
|
|
!close2 &&
|
|
keluar2 >= maxKeluar2)
|
|
{
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/servo1/action",
|
|
"close"
|
|
);
|
|
|
|
close2 = true;
|
|
|
|
Serial.println("SERVO1 CLOSE");
|
|
}
|
|
|
|
delay(10);
|
|
}
|
|
|
|
Serial.println("SEMUA SERVO TUTUP");
|
|
|
|
delay(300);
|
|
}
|
|
|
|
// ======================================================
|
|
// PAKSA TUTUP
|
|
// ======================================================
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/servo1/action",
|
|
"close"
|
|
);
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/servo2/action",
|
|
"close"
|
|
);
|
|
|
|
delay(500);
|
|
|
|
// ======================================================
|
|
// BALIK AWAL
|
|
// ======================================================
|
|
digitalWrite(DIR_PIN, LOW);
|
|
|
|
stepMotor(posisiStepper, 800, false);
|
|
|
|
// ======================================================
|
|
// DRIVER OFF
|
|
// ======================================================
|
|
digitalWrite(EN_PIN, HIGH);
|
|
|
|
// ======================================================
|
|
// DONE
|
|
// ======================================================
|
|
if (key != "manual") {
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/jadwal/" + key + "/status",
|
|
"done"
|
|
);
|
|
|
|
Firebase.RTDB.deleteNode(
|
|
&fbdo,
|
|
"/jadwal/" + key
|
|
);
|
|
}
|
|
|
|
simpanRiwayatFirestore(
|
|
waktu,
|
|
jam,
|
|
tanggal,
|
|
"done",
|
|
bacaBerat1(), // kanan
|
|
bacaBerat2() // kiri
|
|
);
|
|
|
|
Firebase.RTDB.deleteNode(
|
|
&fbdo,
|
|
"/jadwal/" + key
|
|
);
|
|
|
|
kirimNotifikasi(
|
|
"Pemberian pakan selesai"
|
|
);
|
|
|
|
Serial.println("SELESAI");
|
|
}
|
|
|
|
// ======================================================
|
|
// CEK JADWAL
|
|
// ======================================================
|
|
void cekJadwal() {
|
|
|
|
if (!Firebase.ready()) return;
|
|
|
|
if (!Firebase.RTDB.getJSON(&fbdo, "/jadwal")) {
|
|
return;
|
|
}
|
|
|
|
FirebaseJson &json = fbdo.jsonObject();
|
|
|
|
size_t len = json.iteratorBegin();
|
|
|
|
if (len == 0) {
|
|
|
|
json.iteratorEnd();
|
|
return;
|
|
}
|
|
|
|
DateTime now = rtc.now();
|
|
|
|
char jamNow[6];
|
|
|
|
sprintf(jamNow,
|
|
"%02d:%02d",
|
|
now.hour(),
|
|
now.minute());
|
|
|
|
String tglFix =
|
|
String(now.day()) + "-" +
|
|
String(now.month()) + "-" +
|
|
String(now.year());
|
|
|
|
|
|
// ======================================================
|
|
// LOOP JADWAL
|
|
// ======================================================
|
|
for (size_t i = 0; i < len; i++) {
|
|
|
|
String key, value;
|
|
int type;
|
|
|
|
json.iteratorGet(i, type, key, value);
|
|
|
|
FirebaseJsonData data;
|
|
json.get(data, key);
|
|
|
|
FirebaseJson obj;
|
|
obj.setJsonData(data.stringValue);
|
|
|
|
FirebaseJsonData jam, tanggal, status, waktu;
|
|
|
|
obj.get(jam, "jam");
|
|
obj.get(tanggal, "tanggal");
|
|
obj.get(status, "status");
|
|
obj.get(waktu, "waktu");
|
|
|
|
bool matchJam =
|
|
(jam.stringValue.substring(0,5)
|
|
== String(jamNow));
|
|
|
|
bool matchTanggal =
|
|
(tanggal.stringValue == tglFix);
|
|
|
|
bool statusIdle =
|
|
(status.stringValue == "idle" ||
|
|
status.stringValue == "");
|
|
|
|
String id = key + String(jamNow);
|
|
|
|
// ======================================================
|
|
// JALANKAN
|
|
// ======================================================
|
|
if (matchJam &&
|
|
matchTanggal &&
|
|
statusIdle &&
|
|
id != lastTrigger)
|
|
{
|
|
lastTrigger = id;
|
|
|
|
Serial.println("JADWAL JALAN");
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/jadwal/" + key + "/status",
|
|
"running"
|
|
);
|
|
|
|
prosesPemberianPakan(
|
|
key,
|
|
waktu.stringValue,
|
|
jam.stringValue,
|
|
tanggal.stringValue
|
|
);
|
|
}
|
|
|
|
}
|
|
json.iteratorEnd();
|
|
}
|
|
|
|
void simpanRiwayatFirestore(
|
|
String waktu,
|
|
String jam,
|
|
String tanggal,
|
|
String status,
|
|
float beratKanan,
|
|
float beratKiri
|
|
) {
|
|
|
|
FirebaseJson content;
|
|
|
|
content.set("fields/waktu/stringValue", waktu);
|
|
content.set("fields/jam/stringValue", jam);
|
|
content.set("fields/tanggal/stringValue", tanggal);
|
|
content.set("fields/status/stringValue", status);
|
|
|
|
content.set("fields/beratKanan/doubleValue", beratKanan);
|
|
content.set("fields/beratKiri/doubleValue", beratKiri);
|
|
|
|
content.set(
|
|
"fields/timestamp/integerValue",
|
|
String(time(nullptr))
|
|
);
|
|
|
|
String documentPath =
|
|
"riwayat/" + String(millis());
|
|
|
|
Firebase.Firestore.createDocument(
|
|
&fbdo,
|
|
FIREBASE_PROJECT_ID,
|
|
"",
|
|
documentPath.c_str(),
|
|
content.raw());
|
|
}
|
|
|
|
void cekManual() {
|
|
|
|
if (Firebase.RTDB.getString(&fbdo, "/manual/action")) {
|
|
|
|
String cmd = fbdo.stringData();
|
|
|
|
if (cmd == "start") {
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/manual/action",
|
|
"running"
|
|
);
|
|
|
|
DateTime now = rtc.now();
|
|
|
|
char jamManual[6];
|
|
sprintf(
|
|
jamManual,
|
|
"%02d:%02d",
|
|
now.hour(),
|
|
now.minute()
|
|
);
|
|
|
|
String tanggalManual =
|
|
String(now.day()) + "-" +
|
|
String(now.month()) + "-" +
|
|
String(now.year());
|
|
|
|
prosesPemberianPakan(
|
|
"manual",
|
|
"Manual",
|
|
String(jamManual),
|
|
tanggalManual
|
|
);
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/manual/action",
|
|
"done"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ======================================================
|
|
// SETUP
|
|
// ======================================================
|
|
void setup() {
|
|
|
|
Serial.begin(115200);
|
|
|
|
// ======================================================
|
|
// STEPPER
|
|
// ======================================================
|
|
pinMode(STEP_PIN, OUTPUT);
|
|
pinMode(DIR_PIN, OUTPUT);
|
|
pinMode(EN_PIN, OUTPUT);
|
|
|
|
digitalWrite(EN_PIN, HIGH);
|
|
|
|
// ======================================================
|
|
// HX711
|
|
// ======================================================
|
|
scale1.begin(DT1, SCK1);
|
|
scale2.begin(DT2, SCK2);
|
|
|
|
delay(1000);
|
|
|
|
scale1.set_scale(calibration_factor1);
|
|
scale2.set_scale(calibration_factor2);
|
|
|
|
scale1.tare();
|
|
scale2.tare();
|
|
|
|
// ======================================================
|
|
// RTC
|
|
// ======================================================
|
|
Wire.begin(21, 22);
|
|
|
|
if (!rtc.begin()) {
|
|
|
|
Serial.println("RTC ERROR");
|
|
|
|
kirimNotifikasi(
|
|
"RTC DS3231 tidak terdeteksi"
|
|
);
|
|
|
|
while (1);
|
|
}
|
|
|
|
// ======================================================
|
|
// WIFI
|
|
// ======================================================
|
|
WiFi.begin(ssid, password);
|
|
|
|
Serial.print("CONNECT WIFI");
|
|
|
|
while (WiFi.status() != WL_CONNECTED) {
|
|
|
|
delay(500);
|
|
Serial.print(".");
|
|
}
|
|
|
|
Serial.println("");
|
|
Serial.println("WIFI CONNECT");
|
|
|
|
// ======================================================
|
|
// WAKTU INTERNET
|
|
// ======================================================
|
|
configTime(7 * 3600, 0,
|
|
"pool.ntp.org",
|
|
"time.nist.gov");
|
|
|
|
struct tm timeinfo;
|
|
|
|
if (getLocalTime(&timeinfo)) {
|
|
|
|
rtc.adjust(DateTime(
|
|
timeinfo.tm_year + 1900,
|
|
timeinfo.tm_mon + 1,
|
|
timeinfo.tm_mday,
|
|
timeinfo.tm_hour,
|
|
timeinfo.tm_min,
|
|
timeinfo.tm_sec
|
|
));
|
|
}
|
|
|
|
// ======================================================
|
|
// FIREBASE
|
|
// ======================================================
|
|
config.api_key = API_KEY;
|
|
config.database_url = DATABASE_URL;
|
|
|
|
auth.user.email = USER_EMAIL;
|
|
auth.user.password = USER_PASSWORD;
|
|
|
|
Firebase.begin(&config, &auth);
|
|
Firebase.reconnectWiFi(true);
|
|
|
|
Serial.println("READY");
|
|
}
|
|
|
|
// ======================================================
|
|
// LOOP
|
|
// ======================================================
|
|
void loop() {
|
|
|
|
// =======================================
|
|
// CEK WIFI
|
|
// =======================================
|
|
if (WiFi.status() != WL_CONNECTED) {
|
|
|
|
if (wifiTerhubungSebelumnya) {
|
|
|
|
Serial.println("WIFI PUTUS");
|
|
|
|
wifiTerhubungSebelumnya = false;
|
|
}
|
|
|
|
WiFi.reconnect();
|
|
|
|
delay(1000);
|
|
|
|
return;
|
|
}
|
|
else {
|
|
|
|
// WiFi baru tersambung lagi
|
|
if (!wifiTerhubungSebelumnya) {
|
|
|
|
wifiTerhubungSebelumnya = true;
|
|
|
|
kirimNotifikasi(
|
|
"Koneksi WiFi kembali normal"
|
|
);
|
|
}
|
|
}
|
|
|
|
// =======================================
|
|
// CEK FIREBASE
|
|
// =======================================
|
|
if (!Firebase.ready()) {
|
|
|
|
kirimNotifikasi(
|
|
"Koneksi ke Firebase terputus"
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
// =======================================
|
|
// HEARTBEAT
|
|
// =======================================
|
|
if (millis() - lastHeartbeat > 5000) {
|
|
|
|
lastHeartbeat = millis();
|
|
|
|
Firebase.RTDB.setInt(
|
|
&fbdo,
|
|
"/status/heartbeat",
|
|
millis()
|
|
);
|
|
|
|
}
|
|
|
|
// ======================================================
|
|
// RTC
|
|
// ======================================================
|
|
if (millis() - lastRTC > 5000) {
|
|
|
|
Firebase.RTDB.setInt(
|
|
&fbdo,
|
|
"/status/heartbeat",
|
|
millis()
|
|
);
|
|
|
|
lastRTC = millis();
|
|
|
|
DateTime now = rtc.now();
|
|
|
|
char waktu[9];
|
|
|
|
sprintf(waktu,
|
|
"%02d:%02d:%02d",
|
|
now.hour(),
|
|
now.minute(),
|
|
now.second());
|
|
|
|
Firebase.RTDB.setString(
|
|
&fbdo,
|
|
"/rtc/time",
|
|
waktu
|
|
);
|
|
}
|
|
|
|
|
|
// ======================================================
|
|
// CEK JADWAL
|
|
// ======================================================
|
|
if (millis() - lastJadwal > 5000) {
|
|
|
|
lastJadwal = millis();
|
|
|
|
cekJadwal();
|
|
}
|
|
|
|
if (millis() - lastManual > 1000) {
|
|
|
|
lastManual = millis();
|
|
|
|
cekManual();
|
|
}
|
|
|
|
// ======================================================
|
|
// BERAT REALTIME
|
|
// ======================================================
|
|
if (millis() - lastRead > 1000) {
|
|
|
|
lastRead = millis();
|
|
|
|
float b1 = bacaBerat1();
|
|
float b2 = bacaBerat2();
|
|
|
|
Firebase.RTDB.setFloat(
|
|
&fbdo,
|
|
"/sensor/berat1",
|
|
b1
|
|
);
|
|
|
|
Firebase.RTDB.setFloat(
|
|
&fbdo,
|
|
"/sensor/berat2",
|
|
b2
|
|
);
|
|
|
|
Serial.print("B1: ");
|
|
Serial.print(b1);
|
|
|
|
Serial.print(" | B2: ");
|
|
Serial.println(b2);
|
|
}
|
|
} |