Upload files to "/"
This commit is contained in:
parent
55efaef6de
commit
4a0af9c7d8
|
|
@ -0,0 +1,468 @@
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <Firebase_ESP_Client.h>
|
||||||
|
#include <esp_task_wdt.h>
|
||||||
|
|
||||||
|
// ================= WIFI =================
|
||||||
|
#define WIFI_SSID "Angga"
|
||||||
|
#define WIFI_PASSWORD "upinipinupin"
|
||||||
|
|
||||||
|
// ================= FIREBASE =================
|
||||||
|
#define DATABASE_URL "https://tomat2-default-rtdb.asia-southeast1.firebasedatabase.app"
|
||||||
|
#define DATABASE_SECRET "EsSGEME2IMqmVvWx2VZLkLSKAnJ4Meg6AblUOyxO"
|
||||||
|
|
||||||
|
FirebaseData fbdo;
|
||||||
|
FirebaseAuth auth;
|
||||||
|
FirebaseConfig config;
|
||||||
|
|
||||||
|
// ================= PIN =================
|
||||||
|
#define SOIL_PIN 34
|
||||||
|
#define PIR_PIN 27
|
||||||
|
#define RELAY_PIN 26
|
||||||
|
#define BUZZER_PIN 25
|
||||||
|
|
||||||
|
// ================= KALIBRASI =================
|
||||||
|
#define SOIL_DRY 2400
|
||||||
|
#define SOIL_WET 1100
|
||||||
|
|
||||||
|
// ================= GLOBAL =================
|
||||||
|
volatile bool pirFlag = false;
|
||||||
|
volatile unsigned long lastInterrupt = 0;
|
||||||
|
|
||||||
|
int pirState = 0;
|
||||||
|
unsigned long pirHoldTime = 0;
|
||||||
|
const int pirActiveDuration = 3000;
|
||||||
|
|
||||||
|
int lastMoist = -1;
|
||||||
|
int lastPir = -1;
|
||||||
|
int lastPump = -1;
|
||||||
|
|
||||||
|
int lastPumpState = 0;
|
||||||
|
|
||||||
|
String mode = "auto";
|
||||||
|
int pumpManual = 0;
|
||||||
|
|
||||||
|
int minMoist = 60;
|
||||||
|
int maxMoist = 80;
|
||||||
|
|
||||||
|
unsigned long lastSend = 0;
|
||||||
|
unsigned long lastRead = 0;
|
||||||
|
|
||||||
|
const int sendInterval = 10000;
|
||||||
|
const int readInterval = 7000;
|
||||||
|
|
||||||
|
// ================= OFFLINE =================
|
||||||
|
bool offlineMode = false;
|
||||||
|
|
||||||
|
unsigned long lastOfflineCheck = 0;
|
||||||
|
const int offlineCheckInterval = 10000;
|
||||||
|
|
||||||
|
// ================= BUZZER =================
|
||||||
|
unsigned long lastBuzz = 0;
|
||||||
|
unsigned long buzzerStart = 0;
|
||||||
|
|
||||||
|
bool buzzerActive = false;
|
||||||
|
|
||||||
|
const int buzzCooldown = 5000;
|
||||||
|
const int buzzerDuration = 2000;
|
||||||
|
|
||||||
|
bool sendPirNow = false;
|
||||||
|
|
||||||
|
// ================= ISR =================
|
||||||
|
void IRAM_ATTR pirISR() {
|
||||||
|
|
||||||
|
if (millis() - lastInterrupt > 200) {
|
||||||
|
|
||||||
|
pirFlag = true;
|
||||||
|
lastInterrupt = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= WIFI =================
|
||||||
|
void connectWiFi() {
|
||||||
|
|
||||||
|
static unsigned long lastAttempt = 0;
|
||||||
|
|
||||||
|
// sudah connect
|
||||||
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// retry tiap 10 detik
|
||||||
|
if (millis() - lastAttempt < 10000) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastAttempt = millis();
|
||||||
|
|
||||||
|
Serial.println("Connecting WiFi...");
|
||||||
|
|
||||||
|
WiFi.disconnect();
|
||||||
|
|
||||||
|
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= OFFLINE CHECK =================
|
||||||
|
void checkOfflineMode() {
|
||||||
|
|
||||||
|
// cek tiap 10 detik
|
||||||
|
if (millis() - lastOfflineCheck < offlineCheckInterval) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastOfflineCheck = millis();
|
||||||
|
|
||||||
|
// ===== WIFI PUTUS =====
|
||||||
|
if (WiFi.status() != WL_CONNECTED) {
|
||||||
|
|
||||||
|
if (!offlineMode) {
|
||||||
|
Serial.println("⚠️ OFFLINE MODE");
|
||||||
|
}
|
||||||
|
|
||||||
|
offlineMode = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== WIFI NORMAL =====
|
||||||
|
if (offlineMode) {
|
||||||
|
Serial.println("✅ BACK ONLINE");
|
||||||
|
}
|
||||||
|
|
||||||
|
offlineMode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= SAFE SEND =================
|
||||||
|
bool sendData(FirebaseJson &json) {
|
||||||
|
|
||||||
|
// jangan kirim saat offline
|
||||||
|
if (
|
||||||
|
offlineMode ||
|
||||||
|
WiFi.status() != WL_CONNECTED
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// firebase belum ready
|
||||||
|
if (!Firebase.ready()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// kirim 1x saja
|
||||||
|
return Firebase.RTDB.setJSON(
|
||||||
|
&fbdo,
|
||||||
|
"/sensor",
|
||||||
|
&json
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= SETUP =================
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
pinMode(PIR_PIN, INPUT);
|
||||||
|
|
||||||
|
pinMode(RELAY_PIN, OUTPUT);
|
||||||
|
pinMode(BUZZER_PIN, OUTPUT);
|
||||||
|
|
||||||
|
// relay OFF
|
||||||
|
digitalWrite(RELAY_PIN, HIGH);
|
||||||
|
|
||||||
|
digitalWrite(BUZZER_PIN, LOW);
|
||||||
|
|
||||||
|
analogSetAttenuation(ADC_11db);
|
||||||
|
|
||||||
|
attachInterrupt(
|
||||||
|
digitalPinToInterrupt(PIR_PIN),
|
||||||
|
pirISR,
|
||||||
|
RISING
|
||||||
|
);
|
||||||
|
|
||||||
|
// ===== WIFI =====
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.setSleep(false);
|
||||||
|
|
||||||
|
connectWiFi();
|
||||||
|
|
||||||
|
WiFi.setAutoReconnect(true);
|
||||||
|
WiFi.persistent(true);
|
||||||
|
|
||||||
|
// ===== FIREBASE =====
|
||||||
|
config.database_url = DATABASE_URL;
|
||||||
|
|
||||||
|
config.signer.tokens.legacy_token =
|
||||||
|
DATABASE_SECRET;
|
||||||
|
|
||||||
|
Firebase.begin(&config, &auth);
|
||||||
|
|
||||||
|
Firebase.reconnectWiFi(true);
|
||||||
|
|
||||||
|
fbdo.setBSSLBufferSize(2048, 512);
|
||||||
|
|
||||||
|
config.timeout.serverResponse = 3000;
|
||||||
|
|
||||||
|
// ===== WATCHDOG =====
|
||||||
|
esp_task_wdt_config_t wdt_config = {
|
||||||
|
.timeout_ms = 10000,
|
||||||
|
.idle_core_mask = (1 << portNUM_PROCESSORS) - 1,
|
||||||
|
.trigger_panic = true
|
||||||
|
};
|
||||||
|
|
||||||
|
esp_task_wdt_init(&wdt_config);
|
||||||
|
|
||||||
|
esp_task_wdt_add(NULL);
|
||||||
|
|
||||||
|
Serial.println("System Ready");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= LOOP =================
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
esp_task_wdt_reset();
|
||||||
|
|
||||||
|
// ===== CHECK ONLINE/OFFLINE =====
|
||||||
|
checkOfflineMode();
|
||||||
|
|
||||||
|
// ===== RECONNECT WIFI =====
|
||||||
|
connectWiFi();
|
||||||
|
|
||||||
|
// ================= PIR =================
|
||||||
|
if (pirFlag) {
|
||||||
|
|
||||||
|
pirFlag = false;
|
||||||
|
|
||||||
|
Serial.println("⚠️ GERAKAN!");
|
||||||
|
|
||||||
|
pirState = 1;
|
||||||
|
|
||||||
|
pirHoldTime = millis();
|
||||||
|
|
||||||
|
sendPirNow = true;
|
||||||
|
|
||||||
|
// ===== BUZZER =====
|
||||||
|
if (millis() - lastBuzz > buzzCooldown) {
|
||||||
|
|
||||||
|
lastBuzz = millis();
|
||||||
|
|
||||||
|
buzzerStart = millis();
|
||||||
|
|
||||||
|
buzzerActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= BUZZER =================
|
||||||
|
if (buzzerActive) {
|
||||||
|
|
||||||
|
static unsigned long lastToggle = 0;
|
||||||
|
static bool state = false;
|
||||||
|
|
||||||
|
if (millis() - lastToggle > 100) {
|
||||||
|
|
||||||
|
lastToggle = millis();
|
||||||
|
|
||||||
|
state = !state;
|
||||||
|
|
||||||
|
digitalWrite(BUZZER_PIN, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== STOP BUZZER =====
|
||||||
|
if (millis() - buzzerStart > buzzerDuration) {
|
||||||
|
|
||||||
|
buzzerActive = false;
|
||||||
|
|
||||||
|
digitalWrite(BUZZER_PIN, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= RESET PIR =================
|
||||||
|
if (
|
||||||
|
pirState == 1 &&
|
||||||
|
millis() - pirHoldTime > pirActiveDuration
|
||||||
|
) {
|
||||||
|
|
||||||
|
pirState = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= SENSOR =================
|
||||||
|
int soilRaw = analogRead(SOIL_PIN);
|
||||||
|
|
||||||
|
int moisture = map(
|
||||||
|
soilRaw,
|
||||||
|
SOIL_DRY,
|
||||||
|
SOIL_WET,
|
||||||
|
0,
|
||||||
|
100
|
||||||
|
);
|
||||||
|
|
||||||
|
moisture = constrain(moisture, 0, 100);
|
||||||
|
|
||||||
|
// ==================================================
|
||||||
|
// ================= LOGIKA POMPA ===================
|
||||||
|
// ==================================================
|
||||||
|
|
||||||
|
int pumpState = lastPumpState;
|
||||||
|
|
||||||
|
// ===== OFFLINE =====
|
||||||
|
if (offlineMode) {
|
||||||
|
|
||||||
|
// paksa AUTO lokal
|
||||||
|
if (moisture < minMoist) {
|
||||||
|
|
||||||
|
pumpState = 1;
|
||||||
|
|
||||||
|
} else if (moisture > maxMoist) {
|
||||||
|
|
||||||
|
pumpState = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// ===== MODE NORMAL =====
|
||||||
|
if (mode == "manual") {
|
||||||
|
|
||||||
|
pumpState = pumpManual;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (moisture < minMoist) {
|
||||||
|
|
||||||
|
pumpState = 1;
|
||||||
|
|
||||||
|
} else if (moisture > maxMoist) {
|
||||||
|
|
||||||
|
pumpState = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastPumpState = pumpState;
|
||||||
|
|
||||||
|
// relay active LOW
|
||||||
|
digitalWrite(
|
||||||
|
RELAY_PIN,
|
||||||
|
pumpState ? LOW : HIGH
|
||||||
|
);
|
||||||
|
|
||||||
|
// ================= DEBUG =================
|
||||||
|
Serial.printf(
|
||||||
|
"OFF:%d Moist:%d Pump:%d PIR:%d WiFi:%d\n",
|
||||||
|
offlineMode,
|
||||||
|
moisture,
|
||||||
|
pumpState,
|
||||||
|
pirState,
|
||||||
|
WiFi.status()
|
||||||
|
);
|
||||||
|
|
||||||
|
// ==================================================
|
||||||
|
// ============== FIREBASE DI BAWAH =================
|
||||||
|
// ==================================================
|
||||||
|
|
||||||
|
// ================= READ FIREBASE =================
|
||||||
|
if (
|
||||||
|
!offlineMode &&
|
||||||
|
millis() - lastRead > readInterval
|
||||||
|
) {
|
||||||
|
|
||||||
|
if (
|
||||||
|
WiFi.status() == WL_CONNECTED &&
|
||||||
|
Firebase.ready()
|
||||||
|
) {
|
||||||
|
|
||||||
|
Firebase.RTDB.getString(
|
||||||
|
&fbdo,
|
||||||
|
"/control/mode"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (fbdo.dataType() == "string") {
|
||||||
|
mode = fbdo.stringData();
|
||||||
|
}
|
||||||
|
|
||||||
|
Firebase.RTDB.getInt(
|
||||||
|
&fbdo,
|
||||||
|
"/control/pump"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (fbdo.dataType() == "int") {
|
||||||
|
pumpManual = fbdo.intData();
|
||||||
|
}
|
||||||
|
|
||||||
|
Firebase.RTDB.getInt(
|
||||||
|
&fbdo,
|
||||||
|
"/config/min_moisture"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (fbdo.dataType() == "int") {
|
||||||
|
minMoist = fbdo.intData();
|
||||||
|
}
|
||||||
|
|
||||||
|
Firebase.RTDB.getInt(
|
||||||
|
&fbdo,
|
||||||
|
"/config/max_moisture"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (fbdo.dataType() == "int") {
|
||||||
|
maxMoist = fbdo.intData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastRead = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= PIR REALTIME =================
|
||||||
|
if (sendPirNow) {
|
||||||
|
|
||||||
|
// reset flag dulu
|
||||||
|
sendPirNow = false;
|
||||||
|
|
||||||
|
// hanya kirim kalau online
|
||||||
|
if (!offlineMode) {
|
||||||
|
|
||||||
|
FirebaseJson json;
|
||||||
|
|
||||||
|
json.set("moisture", moisture);
|
||||||
|
json.set("pir", 1);
|
||||||
|
json.set("pump", pumpState);
|
||||||
|
|
||||||
|
if (sendData(json)) {
|
||||||
|
Serial.println("🚀 PIR SENT");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= PERIODIC SEND =================
|
||||||
|
if (
|
||||||
|
!offlineMode &&
|
||||||
|
millis() - lastSend > sendInterval
|
||||||
|
) {
|
||||||
|
|
||||||
|
if (
|
||||||
|
abs(moisture - lastMoist) > 3 ||
|
||||||
|
pirState != lastPir ||
|
||||||
|
pumpState != lastPump
|
||||||
|
) {
|
||||||
|
|
||||||
|
FirebaseJson json;
|
||||||
|
|
||||||
|
json.set("moisture", moisture);
|
||||||
|
json.set("pir", pirState);
|
||||||
|
json.set("pump", pumpState);
|
||||||
|
|
||||||
|
if (sendData(json)) {
|
||||||
|
|
||||||
|
Serial.printf(
|
||||||
|
"SEND → M:%d PIR:%d P:%d\n",
|
||||||
|
moisture,
|
||||||
|
pirState,
|
||||||
|
pumpState
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastMoist = moisture;
|
||||||
|
lastPir = pirState;
|
||||||
|
lastPump = pumpState;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastSend = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(20);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue