From c6d0c12617f696511cf9dff99157808eebedeb72 Mon Sep 17 00:00:00 2001 From: Wildan_Abbrhory Date: Mon, 28 Jul 2025 10:40:42 +0700 Subject: [PATCH] Upload files to "/" --- bot_wa.js | 402 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 402 insertions(+) create mode 100644 bot_wa.js diff --git a/bot_wa.js b/bot_wa.js new file mode 100644 index 0000000..0091172 --- /dev/null +++ b/bot_wa.js @@ -0,0 +1,402 @@ +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(); +})(); \ No newline at end of file