#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
#include <Keypad.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// WiFi credentials
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* botToken = "7201605990:AAFog60V0ShPJFeKwMGeb1k685vapi22XjE";
// Telegram Chat ID
const String chat_id = "412434642";
// Initialize Telegram BOT
WiFiClientSecure client;
UniversalTelegramBot bot(botToken, client);
// Initialize LCD I2C
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, LCD 16x2
// Initialize Keypad
const byte ROWS = 4; // Empat baris
const byte COLS = 4; // Empat kolom
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {13, 12, 14, 27}; // Keypad pin kolom
byte colPins[COLS] = {26, 25, 33, 32}; // Keypad pin baris
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// Relay pins
const int relayPaketPin = 15;
const int relayPintu1Pin = 16;
const int relayPintu2Pin = 18;
// Variables to store statuses and counts
int pintu1 = 0; // Inisialisasi variabel
int pintu2 = 0; // Inisialisasi variabel
int codCount = 0; // Count of COD packages
int nonCodCount = 0; // Count of Non-COD packages
bool wifiConnectedMessageSent = false;
unsigned long lastTelegramCheck = 0;
const unsigned long telegramCheckInterval = 5000; // Check every 5 seconds
// State machine states
enum State { MAIN_MENU, COD_MENU, NON_COD_MENU, WAIT_FOR_COMPLETION };
State currentState = MAIN_MENU;
// Timer variables
unsigned long lastLCDUpdate = 0;
const unsigned long lcdUpdateInterval = 2000; // Update LCD setiap 2 detik
bool lcdMessageComplete = false;
String codInput = ""; // Variable untuk menyimpan input COD
void setup() {
Serial.begin(115200);
// Initialize LCD I2C
lcd.init();
lcd.backlight();
lcd.print("Menyambungkan WiFi...");
// Initialize relay pins as outputs
pinMode(relayPaketPin, OUTPUT);
pinMode(relayPintu1Pin, OUTPUT);
pinMode(relayPintu2Pin, OUTPUT);
digitalWrite(relayPaketPin, LOW);
digitalWrite(relayPintu1Pin, LOW);
digitalWrite(relayPintu2Pin, LOW);
// Connect to Wi-Fi
connectToWiFi();
// Disable SSL certificate verification
client.setInsecure();
// Show main menu after setup is complete
showMainMenu();
}
void loop() {
// Check for input from keypad as a priority
char key = keypad.getKey();
if (key) {
Serial.print("Key pressed: ");
Serial.println(key);
handleKeypadInput(key);
}
// Handle LCD message display
if (lcdMessageComplete && millis() - lastLCDUpdate >= lcdUpdateInterval) {
lcd.clear();
showMainMenu();
lcdMessageComplete = false;
}
// Check for new messages from Telegram periodically
if (millis() - lastTelegramCheck >= telegramCheckInterval) {
lastTelegramCheck = millis();
checkTelegramMessages();
}
}
void connectToWiFi() {
Serial.print("Menyambungkan WiFi...");
lcd.setCursor(0, 0);
lcd.print("Menyambungkan WiFi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
lcd.print(".");
}
Serial.println("WiFi Terhubung!");
lcd.clear();
lcd.print("Wifi Terhubung!");
delay(2000);
lcd.clear();
}
void sendWifiConnectedMessage() {
// Check if already sent
if (wifiConnectedMessageSent) {
return;
}
String status = "WiFi: " + String(WiFi.status() == WL_CONNECTED ? "Terhubung" : "Terputus");
String message = "packet Box tersambung ke WiFi.\n\nPerintah yang disarankan:\n/start - Cek status WiFi\n/status - Cek nominal dan status paket\n/setpintu1 [value] - Set nominal untuk pintu 1\n/setpintu2 [value] - Set nominal untuk pintu 2\n/reset - Reset semua pengaturan\n\n" + status;
bot.sendMessage(chat_id, message, "");
// Send /status message
String statusMessage = "Nominal Pintu 1: " + String(pintu1) + "\nNominal Pintu 2: " + String(pintu2) + "\nJumlah COD: " + String(codCount) + "\nJumlah Non-COD: " + String(nonCodCount);
bot.sendMessage(chat_id, statusMessage, "");
// Mark message as sent
wifiConnectedMessageSent = true;
}
void checkTelegramMessages() {
if (WiFi.status() == WL_CONNECTED) {
if (!wifiConnectedMessageSent) {
sendWifiConnectedMessage();
wifiConnectedMessageSent = true;
}
Serial.println("Memeriksa Pesan Baru...");
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
Serial.print("Pesan Baru Diterima: ");
Serial.println(numNewMessages);
if (numNewMessages) {
handleNewMessages(numNewMessages);
}
} else {
wifiConnectedMessageSent = false;
}
}
void handleNewMessages(int numNewMessages) {
Serial.print("handleNewMessages ");
Serial.println(numNewMessages);
for (int i = 0; i < numNewMessages; i++) {
String chat_id = String(bot.messages[i].chat_id);
String text = bot.messages[i].text;
Serial.print("Received message: ");
Serial.println(text);
if (text == "/start") {
String status = "WiFi: " + String(WiFi.status() == WL_CONNECTED ? "Terhubung" : "Terputus");
bot.sendMessage(chat_id, status, "");
} else if (text == "/status") {
String status = "Nominal Pintu 1: " + String(pintu1) + "\nNominal Pintu 2: " + String(pintu2) + "\nJumlah COD: " + String(codCount) + "\nJumlah Non-COD: " + String(nonCodCount);
bot.sendMessage(chat_id, status, "");
Serial.println("Pintu 1: " + String(pintu1));
Serial.println("Pintu 2: " + String(pintu2));
Serial.println("Jumlah COD: " + String(codCount));
Serial.println("Jumlah Non-COD: " + String(nonCodCount));
} else if (text.startsWith("/setpintu1 ")) {
pintu1 = text.substring(10).toInt();
bot.sendMessage(chat_id, "Nominal Pintu 1 diset ke: " + String(pintu1), "");
} else if (text.startsWith("/setpintu2 ")) {
pintu2 = text.substring(10).toInt();
bot.sendMessage(chat_id, "Nominal Pintu 2 diset ke: " + String(pintu2), "");
} else if (text == "/reset") {
pintu1 = 0;
pintu2 = 0;
codCount = 0;
nonCodCount = 0;
bot.sendMessage(chat_id, "Semua pengaturan telah direset.", "");
} else {
bot.sendMessage(chat_id, "Perintah tidak valid.", "");
}
}
}
void handleKeypadInput(char key) {
switch (currentState) {
case MAIN_MENU:
if (key == 'A') {
currentState = COD_MENU;
codInput = ""; // Clear the input buffer
lcd.clear();
lcd.print("Masukkan Nominal");
lcd.setCursor(0, 1);
lcd.print("COD:");
} else if (key == 'B') {
currentState = NON_COD_MENU;
lcd.clear();
lcd.print("MASUKKAN PAKET");
lcd.setCursor(0, 1);
lcd.print("TEKAN D SELESAI");
controlRelay(relayPaketPin, true);
}
break;
case COD_MENU:
if (key >= '0' && key <= '9') {
codInput += key;
lcd.setCursor(4, 1);
lcd.print(codInput);
} else if (key == 'C') { // Use 'C' to clear the input
codInput = "";
lcd.clear();
lcd.print("Masukkan Nominal");
lcd.setCursor(0, 1);
lcd.print("COD:");
} else if (key == 'D') { // Use 'D' as the enter key
int codValue = codInput.toInt();
if (codValue != 0 && (codValue == pintu1 || codValue == pintu2)) {
lcd.clear();
lcd.print("MASUKKAN PAKET");
lcd.setCursor(0, 1);
lcd.print("TEKAN D SELESAI");
controlRelay(relayPaketPin, true);
currentState = WAIT_FOR_COMPLETION;
// Hapus nilai pada pintu yang sesuai
if (codValue == pintu1) {
pintu1 = 0;
} else if (codValue == pintu2) {
pintu2 = 0;
}
} else {
lcd.clear();
lcd.print("Nominal Salah");
lastLCDUpdate = millis(); // Start timer for showing main menu again
lcdMessageComplete = true;
currentState = MAIN_MENU;
}
}
break;
case NON_COD_MENU:
if (key == 'D') {
controlRelay(relayPaketPin, false);
nonCodCount++;
String message = "Paket Non-COD diterima!";
bot.sendMessage(chat_id, message, "");
Serial.println(message);
lcd.clear();
lcd.print("Paket diterima!"); // Display message on LCD
lastLCDUpdate = millis(); // Start timer for showing main menu again
lcdMessageComplete = true;
currentState = MAIN_MENU;
} else if (key == 'C') {
controlRelay(relayPaketPin, false);
showMainMenu();
currentState = MAIN_MENU;
}
break;
case WAIT_FOR_COMPLETION:
if (key == 'D') {
controlRelay(relayPaketPin, false);
codCount++;
String message = "Paket COD diterima!";
bot.sendMessage(chat_id, message, "");
Serial.println(message);
lcd.clear();
lcd.print("Paket diterima!"); // Display message on LCD
lastLCDUpdate = millis(); // Start timer for showing main menu again
lcdMessageComplete = true;
currentState = MAIN_MENU;
} else if (key == 'C') {
controlRelay(relayPaketPin, false);
showMainMenu();
currentState = MAIN_MENU;
}
break;
default:
break;
}
}
void showMainMenu() {
lcd.clear();
lcd.print("Tekan A: COD");
lcd.setCursor(0, 1);
lcd.print("Tekan B: NON COD");
delay(2000); // Tampilkan pesan awal selama 2 detik
}
void controlRelay(int pin, bool state) {
digitalWrite(pin, state ? HIGH : LOW);
Serial.print("Relay on pin ");
Serial.print(pin);
Serial.println(state ? " turned ON" : " turned OFF");
}