TKK_E32222444/bot_wa.js

402 lines
13 KiB
JavaScript

const qrcode = require('qrcode-terminal');
const { Client, LocalAuth } = require('whatsapp-web.js');
const admin = require('firebase-admin');
const inquirer = require('inquirer').default;
const fs = require('fs');
const path = require('path');
admin.initializeApp({
credential: admin.credential.cert(require('./serviceAccountKey.json')),
databaseURL: "databaseURL"
});
const db = admin.database();
let senderNumber = null;
let recipientNumbers = [];
let lastMessagesSent = {};
function resetMessageFlag(message) {
delete lastMessagesSent[message];
}
async function loadNumbers() {
try {
const snapshot = await db.ref('/whatsappNumbers').once('value');
const data = snapshot.val() || {};
senderNumber = data.sender || null;
recipientNumbers = data.recipients || [];
console.log('✅ Data nomor berhasil dimuat dari Firebase');
} catch (error) {
console.error('❌ Gagal memuat data nomor:', error);
}
}
async function saveNumbers() {
try {
await db.ref('/whatsappNumbers').set({ sender: senderNumber, recipients: recipientNumbers });
console.log('✅ Data nomor berhasil disimpan ke Firebase');
} catch (error) {
console.error('❌ Gagal menyimpan data nomor:', error);
}
}
function clearWhatsAppSession() {
const sessionPath = path.join(__dirname, '.wwebjs_auth');
if (fs.existsSync(sessionPath)) {
fs.rmSync(sessionPath, { recursive: true, force: true });
console.log('✅ Sesi WhatsApp lama dihapus.');
}
}
function createNewClient() {
return new Client({
authStrategy: new LocalAuth(),
puppeteer: {
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox']
}
});
}
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
async function broadcastWhatsApp(client, message) {
if (lastMessagesSent[message]) return;
for (const num of recipientNumbers) {
try {
const start = Date.now();
await client.sendMessage(num, message);
const timeTaken = ((Date.now() - start) / 1000).toFixed(2);
console.log(`✅ Pesan terkirim ke ${num} dalam ${timeTaken} detik`);
console.log(` ➤ Isi Pesan: ${message}`);
await delay(1000);
} catch (e) {
console.error(`❌ Gagal kirim ke ${num}:`, e.message || e);
}
}
lastMessagesSent[message] = true;
}
async function startMonitoring() {
if (!senderNumber || recipientNumbers.length === 0) {
console.log('\n❗ Pengirim atau penerima belum diatur.');
return;
}
console.log('\n⏳ Menunggu koneksi WhatsApp...');
const client = createNewClient();
client.on('ready', () => {
console.log('✅ WhatsApp Client siap.');
const notifRef = db.ref('/notif');
const pompaRef = db.ref('/pompa/status');
const sensorApiRef = db.ref('/sensor/api');
const sensorAsapRef = db.ref('/sensor/asap');
const sensorTanahRef = db.ref('/sensor/tanah');
let lastStates = {
notif_kebakaran: '',
notif_tanah: '',
notif_pompa_off: false,
kebakaran_teratasi: false,
pompaStatus: '',
apiStatus: '',
kelembabanTanah: '',
};
let lastAsapApiNotif = '';
let pompaOnWithFireStart = null;
let problemPompaSent = false;
async function handleKebakaran(kebakaranStatus) {
const fireMsg = "🔥 Kebakaran Terdeteksi! Segera ambil tindakan!";
const apiClearMsg = "✅ Api berhasil dipadamkan, Kondisi aman.";
const prevKebakaran = lastStates.notif_kebakaran;
lastStates.notif_kebakaran = kebakaranStatus;
if (prevKebakaran === "iya" && kebakaranStatus === "tidak") {
await broadcastWhatsApp(client, apiClearMsg);
lastStates.kebakaran_teratasi = true;
}
if (kebakaranStatus === "iya" && prevKebakaran !== "iya") {
await broadcastWhatsApp(client, fireMsg);
resetMessageFlag(apiClearMsg);
lastStates.kebakaran_teratasi = false;
}
if (kebakaranStatus !== "iya") {
resetMessageFlag(fireMsg);
}
}
async function handleTanah(tanahStatus) {
const kelembaban = lastStates.kelembabanTanah;
const persen = kelembaban != null && !isNaN(kelembaban) ? ` dengan kelembaban ${kelembaban}%` : '';
const kering = `💧 Tanah terlalu kering${persen}, Segera lakukan irigasi.`;
const basah = `🌊 Tanah terlalu basah${persen}, Segera lakukan drainase.`;
const ideal = `✅ Kelembaban tanah sudah ideal${persen}.`;
if (tanahStatus !== lastStates.notif_tanah) {
if (tanahStatus === "kering") {
await broadcastWhatsApp(client, kering);
} else if (tanahStatus === "basah") {
await broadcastWhatsApp(client, basah);
} else if (tanahStatus === "ideal") {
await broadcastWhatsApp(client, ideal);
} else {
resetMessageFlag(kering);
resetMessageFlag(basah);
resetMessageFlag(ideal);
}
lastStates.notif_tanah = tanahStatus;
}
}
async function handlePompa() {
const apiClearMsg = "✅ Api berhasil dipadamkan, Kondisi aman.";
const problemPompaMsg = "⚠️ Terjadi masalah pada pompa, Segera lakukan penanganan manual!";
const { notif_kebakaran, pompaStatus, apiStatus } = lastStates;
const transisiApiPadam = lastStates.prev_kebakaran === "iya" && notif_kebakaran === "tidak";
const kondisiApiBenarBenarPadam = apiStatus === "tidak";
if (transisiApiPadam && kondisiApiBenarBenarPadam && !lastStates.kebakaran_teratasi) {
await broadcastWhatsApp(client, apiClearMsg);
lastStates.kebakaran_teratasi = true;
}
if (notif_kebakaran === "iya" && pompaStatus === "on") {
if (!pompaOnWithFireStart) {
pompaOnWithFireStart = Date.now();
problemPompaSent = false;
console.log("⏱️ Mulai hitung durasi masalah pompa...");
} else {
const duration = (Date.now() - pompaOnWithFireStart) / 1000;
if (duration >= 3) {
if (!problemPompaSent) {
problemPompaSent = true;
await broadcastWhatsApp(client, problemPompaMsg);
}
}
}
} else {
if (pompaOnWithFireStart) {
console.log("🔁 Reset durasi masalah pompa (status berubah)");
}
pompaOnWithFireStart = null;
problemPompaSent = false;
resetMessageFlag(problemPompaMsg);
}
lastStates.prev_kebakaran = notif_kebakaran;
}
async function handleAsapApi(asapStatus, apiStatus) {
const asapMsg = "🌫️ Terdeteksi asap berlebihan pada lahan, Namun tidak berpotensi kebakaran.";
const asapApiMsg = "🔥🌫️ Terdeteksi asap dan api pada lahan, Namun tidak berpotensi kebakaran.";
const key = `${asapStatus}_${apiStatus}`;
if (lastAsapApiNotif !== key) {
if (asapStatus === "iya" && apiStatus !== "iya") {
await broadcastWhatsApp(client, asapMsg);
} else if (asapStatus === "iya" && apiStatus === "iya") {
await broadcastWhatsApp(client, asapApiMsg);
} else {
resetMessageFlag(asapMsg);
resetMessageFlag(asapApiMsg);
}
lastAsapApiNotif = key;
}
}
notifRef.on('value', async snapshot => {
const notif = snapshot.val() || {};
await handleKebakaran(notif.kebakaran);
await handlePompa();
});
pompaRef.on('value', async snapshot => {
lastStates.pompaStatus = snapshot.val() || "off";
await handlePompa();
});
sensorApiRef.on('value', async snapshot => {
lastStates.apiStatus = (snapshot.val() || "").trim().toLowerCase();
await handlePompa();
const asapSnapshot = await sensorAsapRef.once('value');
const asapStatus = (asapSnapshot.val() || "").trim().toLowerCase();
await handleAsapApi(asapStatus, lastStates.apiStatus);
});
sensorAsapRef.on('value', async snapshot => {
const asapStatus = (snapshot.val() || "").trim().toLowerCase();
const apiStatus = lastStates.apiStatus;
await handleAsapApi(asapStatus, apiStatus);
});
sensorTanahRef.on('value', async snapshot => {
const value = snapshot.val();
const kelembaban = typeof value === 'number' ? value : parseFloat(value);
lastStates.kelembabanTanah = kelembaban;
let tanahStatus = '';
if (kelembaban <= 50) {
tanahStatus = 'kering';
} else if (kelembaban >= 70) {
tanahStatus = 'basah';
} else {
tanahStatus = 'ideal';
}
await handleTanah(tanahStatus);
});
setInterval(async () => {
await handlePompa();
}, 1000);
});
client.initialize();
}
async function showMainMenu() {
while (true) {
const { action } = await inquirer.prompt({
type: 'list',
name: 'action',
message: 'Menu Utama:',
choices: [
{ name: 'Tambah Nomor Pengirim', value: 'addSender' },
{ name: 'Lihat Nomor Pengirim', value: 'viewSender' },
{ name: 'Hapus Nomor Pengirim', value: 'deleteSender' },
{ name: 'Tambah Nomor Penerima', value: 'addRecipient' },
{ name: 'Lihat Nomor Penerima', value: 'viewRecipients' },
{ name: 'Hapus Nomor Penerima', value: 'deleteRecipients' },
{ name: 'Mulai Monitoring', value: 'startMonitoring' },
{ name: 'Keluar', value: 'exit' }
]
});
switch (action) {
case 'addSender': await addSenderNumber(); break;
case 'viewSender': viewSenderNumber(); break;
case 'deleteSender': await deleteSenderNumber(); break;
case 'addRecipient': await addRecipientNumber(); break;
case 'viewRecipients': viewRecipientNumbers(); break;
case 'deleteRecipients': await deleteRecipientNumbers(); break;
case 'startMonitoring': await startMonitoring(); return;
case 'exit': process.exit(0);
}
}
}
async function addSenderNumber() {
if (senderNumber) {
const { confirm } = await inquirer.prompt({
type: 'confirm',
name: 'confirm',
message: 'Sudah ada nomor pengirim. Tambah baru akan hapus yang lama. Lanjutkan?',
default: false
});
if (!confirm) return;
clearWhatsAppSession();
senderNumber = null;
await saveNumbers();
}
console.log('\nScan QR code berikut untuk menambahkan nomor pengirim:');
const tempClient = createNewClient();
return new Promise((resolve, reject) => {
let isAuthenticated = false;
tempClient.once('qr', (qr) => qrcode.generate(qr, { small: true }));
tempClient.once('authenticated', () => { console.log('✅ Autentikasi berhasil!'); isAuthenticated = true; });
tempClient.once('ready', async () => {
if (isAuthenticated) {
try {
senderNumber = tempClient.info.me._serialized;
await saveNumbers();
console.log(`Nomor pengirim berhasil ditambahkan: ${senderNumber}`);
await tempClient.destroy();
resolve();
} catch (err) {
reject(err);
}
}
});
tempClient.initialize();
});
}
function viewSenderNumber() {
console.log(senderNumber ? `\nNomor Pengirim: ${senderNumber}` : '\nBelum ada nomor pengirim.');
}
async function deleteSenderNumber() {
if (!senderNumber) return console.log('\nTidak ada nomor pengirim untuk dihapus.');
const { confirm } = await inquirer.prompt({
type: 'confirm',
name: 'confirm',
message: `Hapus nomor pengirim ${senderNumber}?`,
default: false
});
if (confirm) {
senderNumber = null;
await saveNumbers();
console.log('\nNomor pengirim dihapus.');
}
}
async function addRecipientNumber() {
const { number } = await inquirer.prompt({
type: 'input',
name: 'number',
message: 'Masukkan nomor penerima (format: 628xxxx):',
validate: input => input.startsWith('62') && input.length >= 10 ? true : 'Nomor tidak valid.'
});
const formatted = `${number}@c.us`;
if (recipientNumbers.includes(formatted)) return console.log('\nNomor sudah ada.');
recipientNumbers.push(formatted);
await saveNumbers();
console.log(`\nNomor penerima ditambahkan: ${formatted}`);
}
function viewRecipientNumbers() {
if (recipientNumbers.length === 0) return console.log('\nBelum ada nomor penerima.');
console.log('\nDaftar Nomor Penerima:');
recipientNumbers.forEach((num, i) => console.log(`${i + 1}. ${num}`));
}
async function deleteRecipientNumbers() {
if (recipientNumbers.length === 0) return console.log('\nTidak ada nomor untuk dihapus.');
const { choices } = await inquirer.prompt({
type: 'checkbox',
name: 'choices',
message: 'Pilih nomor untuk dihapus:',
choices: recipientNumbers.map((num, i) => ({ name: `${i + 1}. ${num}`, value: num }))
});
if (choices.length === 0) return;
recipientNumbers = recipientNumbers.filter(num => !choices.includes(num));
await saveNumbers();
console.log('\nNomor berhasil dihapus.');
}
(async function init() {
await loadNumbers();
console.log('\n📋 Status Awal:');
console.log(` ➤ Nomor Pengirim: ${senderNumber || 'Belum ada'}`);
console.log(` ➤ Jumlah Penerima: ${recipientNumbers.length}`);
await showMainMenu();
})();