Upload files to "/"
This commit is contained in:
parent
40f20f2d40
commit
c6d0c12617
|
@ -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();
|
||||||
|
})();
|
Loading…
Reference in New Issue