218 lines
5.8 KiB
C++
218 lines
5.8 KiB
C++
#include <WiFi.h>
|
|
#include <WiFiClientSecure.h>
|
|
#include <UniversalTelegramBot.h>
|
|
#include <ArduinoJson.h>
|
|
#include <DHT.h>
|
|
#include <ESP32Servo.h>
|
|
#include <NTPClient.h>
|
|
#include <WiFiUdp.h>
|
|
#include <Wire.h>
|
|
#include <LiquidCrystal_I2C.h>
|
|
#include <WiFiManager.h>
|
|
|
|
// ========== Konfigurasi ==========
|
|
#define BOTtoken "7612422633:AAH898XXBYw1Ys0gMFrjoDXuq32EVZjw_c8"
|
|
#define DHTPIN 4
|
|
#define DHTTYPE DHT11
|
|
#define SERVO_PIN 15
|
|
|
|
// ========== Inisialisasi ==========
|
|
WiFiClientSecure client;
|
|
UniversalTelegramBot bot(BOTtoken, client);
|
|
|
|
DHT dht(DHTPIN, DHTTYPE);
|
|
Servo servo;
|
|
LiquidCrystal_I2C lcd(0x27, 16, 2);
|
|
WiFiUDP ntpUDP;
|
|
NTPClient timeClient(ntpUDP, "pool.ntp.org", 25200); // GMT+7
|
|
|
|
// ========== Variabel ==========
|
|
String scheduledTime = ""; // Format "HH:mm"
|
|
bool autoSend = false;
|
|
unsigned long lastTime = 0;
|
|
unsigned long timerDelay = 2000;
|
|
bool sudahBeriHariIni = false;
|
|
int lastDay = -1;
|
|
String lastChatId = "";
|
|
|
|
// ========== Setup ==========
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
|
|
lcd.init();
|
|
lcd.backlight();
|
|
lcd.setCursor(0, 0);
|
|
lcd.print("Smart Feeder");
|
|
lcd.setCursor(0, 1);
|
|
lcd.print("Loading WiFi...");
|
|
|
|
dht.begin();
|
|
servo.attach(SERVO_PIN);
|
|
servo.write(0); // Pastikan tertutup
|
|
delay(500);
|
|
|
|
WiFiManager wifiManager;
|
|
wifiManager.autoConnect("SmartFeederAP");
|
|
|
|
lcd.clear();
|
|
lcd.setCursor(0, 0);
|
|
lcd.print("WiFi Connected");
|
|
lcd.setCursor(0, 1);
|
|
lcd.print(WiFi.localIP().toString());
|
|
|
|
client.setCACert(TELEGRAM_CERTIFICATE_ROOT);
|
|
timeClient.begin();
|
|
|
|
delay(2000);
|
|
lcd.clear();
|
|
}
|
|
|
|
// ========== Loop ==========
|
|
void loop() {
|
|
timeClient.update();
|
|
String currentTime = timeClient.getFormattedTime().substring(0, 5);
|
|
int currentDay = timeClient.getDay();
|
|
|
|
if (scheduledTime != "" && currentTime == scheduledTime && !sudahBeriHariIni) {
|
|
Serial.println("⏰ Saatnya memberi pakan otomatis!");
|
|
bukaPakanOtomatis();
|
|
sudahBeriHariIni = true;
|
|
lastDay = currentDay;
|
|
}
|
|
|
|
if (currentDay != lastDay) sudahBeriHariIni = false;
|
|
|
|
if (autoSend && (millis() - lastTime > timerDelay)) {
|
|
kirimDataDHT(lastChatId);
|
|
lastTime = millis();
|
|
}
|
|
|
|
updateLCD();
|
|
|
|
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
|
|
while (numNewMessages) {
|
|
handleNewMessages(numNewMessages);
|
|
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
|
|
}
|
|
}
|
|
|
|
// ========== LCD ==========
|
|
void updateLCD() {
|
|
float h = dht.readHumidity();
|
|
float t = dht.readTemperature();
|
|
|
|
lcd.clear();
|
|
if (isnan(h) || isnan(t)) {
|
|
lcd.setCursor(0, 0);
|
|
lcd.print("Sensor error!");
|
|
} else {
|
|
lcd.setCursor(0, 0);
|
|
lcd.print("T:");
|
|
lcd.print(t, 1);
|
|
lcd.print("C H:");
|
|
lcd.print(h, 0);
|
|
lcd.print("%");
|
|
}
|
|
|
|
lcd.setCursor(0, 1);
|
|
if (scheduledTime == "") {
|
|
lcd.print("Jadwal: - ");
|
|
} else {
|
|
lcd.print("Jadwal:");
|
|
lcd.print(scheduledTime);
|
|
}
|
|
}
|
|
|
|
// ========== Handle Pesan ==========
|
|
void handleNewMessages(int numNewMessages) {
|
|
for (int i = 0; i < numNewMessages; i++) {
|
|
String chat_id = bot.messages[i].chat_id;
|
|
String text = bot.messages[i].text;
|
|
lastChatId = chat_id;
|
|
|
|
if (text == "/start") {
|
|
String msg =
|
|
"👋 Hai! Selamat datang di Smart Feeder 🐣\n\n"
|
|
"📌 Perintah:\n"
|
|
"📊 /status — Cek suhu & kelembaban\n"
|
|
"📡 /mulai — Aktifkan monitoring\n"
|
|
"🛑 /berhenti — Stop monitoring\n"
|
|
"🍽 /bukapakan — Buka pakan\n"
|
|
"🔒 /tutuppakan — Tutup pakan\n"
|
|
"⏰ /setjadwal HH:mm — Atur jadwal\n"
|
|
"📆 /jadwal — Cek jadwal\n"
|
|
"🗑 /hapusjadwal — Hapus jadwal";
|
|
bot.sendMessage(chat_id, msg, "Markdown");
|
|
}
|
|
else if (text == "/status") {
|
|
kirimDataDHT(chat_id);
|
|
}
|
|
else if (text == "/mulai") {
|
|
autoSend = true;
|
|
bot.sendMessage(chat_id, "✅ Monitoring otomatis aktif.", "Markdown");
|
|
}
|
|
else if (text == "/berhenti") {
|
|
autoSend = false;
|
|
bot.sendMessage(chat_id, "🛑 Monitoring otomatis berhenti.", "Markdown");
|
|
}
|
|
else if (text == "/bukapakan") {
|
|
bukaPakan();
|
|
bot.sendMessage(chat_id, "🍽 Pakan diberikan.", "Markdown");
|
|
}
|
|
else if (text == "/tutuppakan") {
|
|
servo.write(0);
|
|
bot.sendMessage(chat_id, "🔒 Pakan ditutup.", "Markdown");
|
|
}
|
|
else if (text.startsWith("/setjadwal ")) {
|
|
String jam = text.substring(11);
|
|
if (jam.length() == 5 && jam.charAt(2) == ':') {
|
|
scheduledTime = jam;
|
|
bot.sendMessage(chat_id, "⏰ Jadwal diatur ke " + jam + "", "Markdown");
|
|
} else {
|
|
bot.sendMessage(chat_id, "⚠ Format salah. Gunakan /setjadwal HH:mm", "Markdown");
|
|
}
|
|
}
|
|
else if (text == "/jadwal") {
|
|
if (scheduledTime != "") {
|
|
bot.sendMessage(chat_id, "📆 Jadwal aktif: " + scheduledTime + "", "Markdown");
|
|
} else {
|
|
bot.sendMessage(chat_id, "⚠ Jadwal belum diatur.", "Markdown");
|
|
}
|
|
}
|
|
else if (text == "/hapusjadwal") {
|
|
scheduledTime = "";
|
|
bot.sendMessage(chat_id, "🗑 Jadwal dihapus.", "Markdown");
|
|
}
|
|
else {
|
|
bot.sendMessage(chat_id, "❓ Perintah tidak dikenali. Gunakan /start.", "Markdown");
|
|
}
|
|
}
|
|
}
|
|
|
|
// ========== Fungsi Servo ==========
|
|
void bukaPakan() {
|
|
Serial.println("🔓 Membuka pakan...");
|
|
servo.write(90); // Buka
|
|
delay(5000); // Tunggu 5 detik
|
|
servo.write(0); // Tutup kembali
|
|
Serial.println("🔒 Pakan ditutup.");
|
|
}
|
|
|
|
void bukaPakanOtomatis() {
|
|
bukaPakan();
|
|
if (lastChatId != "") {
|
|
bot.sendMessage(lastChatId, "🍽 Pakan otomatis diberikan pada " + scheduledTime, "Markdown");
|
|
}
|
|
}
|
|
|
|
void kirimDataDHT(String chat_id) {
|
|
float h = dht.readHumidity();
|
|
float t = dht.readTemperature();
|
|
|
|
if (isnan(h) || isnan(t)) return;
|
|
|
|
String msg = "📊 Data Sensor:\n"
|
|
"🌡 Suhu: " + String(t) + "°C\n"
|
|
"💧 Kelembaban: " + String(h) + "%";
|
|
bot.sendMessage(chat_id, msg, "Markdown");
|
|
} |