213 lines
6.3 KiB
JavaScript
213 lines
6.3 KiB
JavaScript
import pkg, { DisconnectReason } from '@whiskeysockets/baileys';
|
|
import pino from 'pino';
|
|
import mqtt from 'mqtt';
|
|
import fs from 'fs';
|
|
|
|
const {
|
|
makeWASocket,
|
|
useMultiFileAuthState,
|
|
fetchLatestBaileysVersion,
|
|
} = pkg;
|
|
|
|
const allowedNumbers = [
|
|
'62882009051780@s.whatsapp.net',
|
|
'6287862977046@s.whatsapp.net',
|
|
'6289521851079@s.whatsapp.net',
|
|
];
|
|
|
|
// Status lokal perabotan (backup jika diperlukan)
|
|
const status = {
|
|
'lampu kamar': false,
|
|
'lampu teras': false,
|
|
'kipas': false,
|
|
'pintu': false,
|
|
};
|
|
|
|
// Penyimpan siapa yang meminta status
|
|
const pendingStatusRequests = {};
|
|
|
|
// Fungsi konversi status jadi teks
|
|
|
|
function getStatusString(statusObj) {
|
|
return Object.entries(statusObj)
|
|
.map(([device, value]) => {
|
|
if (device === 'pintu') {
|
|
return `- ${device} : ${value === 'dibuka' ? '🔓 Dibuka' : '🔒 Dikunci'}`;
|
|
} else {
|
|
return `- ${device} : ${value === true || value === 'true' ? '✅ Menyala' : '❌ Mati'}`;
|
|
}
|
|
})
|
|
.join('\n');
|
|
|
|
// MQTT setup
|
|
const mqttClient = mqtt.connect('mqtt://test.mosquitto.org');
|
|
|
|
mqttClient.on('connect', () => {
|
|
console.log('📡 Terhubung ke MQTT broker: test.mosquitto.org');
|
|
});
|
|
|
|
mqttClient.on('error', (err) => {
|
|
console.error('❌ MQTT Error:', err);
|
|
});
|
|
|
|
// Tangani balasan dari ESP32 ke topik status
|
|
mqttClient.on('message', async (topic, message) => {
|
|
if (topic === 'cristine/status') {
|
|
try {
|
|
const parsedStatus = JSON.parse(message.toString());
|
|
const now = Date.now();
|
|
|
|
for (const [jid, time] of Object.entries(pendingStatusRequests)) {
|
|
if (now - time <= 10000) { // valid 10 detik
|
|
await sock.sendMessage(jid, {
|
|
text: `📊 Status Real-time:\n${getStatusString(parsedStatus)}`
|
|
});
|
|
}
|
|
}
|
|
|
|
// Kosongkan request setelah dibalas
|
|
for (const jid of Object.keys(pendingStatusRequests)) {
|
|
delete pendingStatusRequests[jid];
|
|
}
|
|
} catch (e) {
|
|
console.error('❌ Gagal parsing status dari ESP32:', e);
|
|
}
|
|
}
|
|
});
|
|
|
|
mqttClient.subscribe('cristine/status');
|
|
|
|
// Fungsi utama bot
|
|
let sock;
|
|
async function startBot() {
|
|
const { version } = await fetchLatestBaileysVersion();
|
|
const { state, saveCreds } = await useMultiFileAuthState('./auth_info_baileys');
|
|
|
|
sock = makeWASocket({
|
|
version,
|
|
auth: state,
|
|
printQRInTerminal: true,
|
|
logger: pino({ level: 'silent' }),
|
|
});
|
|
|
|
sock.ev.on('creds.update', saveCreds);
|
|
|
|
sock.ev.on('connection.update', async ({ connection, lastDisconnect }) => {
|
|
if (connection === 'close') {
|
|
const reasonCode = lastDisconnect?.error?.output?.statusCode;
|
|
const isLoggedOut = reasonCode === DisconnectReason.loggedOut;
|
|
|
|
console.log('⚠️ Koneksi terputus:', reasonCode);
|
|
|
|
if (isLoggedOut) {
|
|
fs.rmSync('./auth_info_baileys', { recursive: true, force: true });
|
|
console.log('🔁 Silakan restart untuk login ulang.');
|
|
} else {
|
|
startBot();
|
|
}
|
|
}
|
|
|
|
if (connection === 'open') {
|
|
console.log('✅ Bot WhatsApp berhasil online!');
|
|
}
|
|
});
|
|
|
|
sock.ev.on('messages.upsert', async ({ messages }) => {
|
|
const msg = messages[0];
|
|
if (!msg.message || msg.key.fromMe) return;
|
|
|
|
const sender = msg.key.remoteJid;
|
|
if (!allowedNumbers.includes(sender)) return;
|
|
|
|
const text =
|
|
msg.message.conversation ||
|
|
msg.message?.extendedTextMessage?.text ||
|
|
msg.message?.imageMessage?.caption ||
|
|
msg.message?.buttonsResponseMessage?.selectedButtonId ||
|
|
msg.message?.listResponseMessage?.singleSelectReply?.selectedRowId;
|
|
|
|
if (!text) return;
|
|
const command = text.trim().toLowerCase();
|
|
console.log(`📩 Pesan dari ${sender}:`, command);
|
|
|
|
switch (command) {
|
|
case 'menu':
|
|
await sock.sendMessage(sender, {
|
|
text: '📋 Menu Kontrol:\n' +
|
|
'- nyalakan lampu kamar\n' +
|
|
'- matikan lampu kamar\n' +
|
|
'- nyalakan lampu teras\n' +
|
|
'- matikan lampu teras\n' +
|
|
'- nyalakan kipas\n' +
|
|
'- matikan kipas\n' +
|
|
'- buka pintu\n' +
|
|
'- kunci pintu\n' +
|
|
'- status',
|
|
});
|
|
break;
|
|
|
|
case 'nyalakan lampu kamar':
|
|
status['lampu kamar'] = true;
|
|
mqttClient.publish('cristine/control/lampu_kamar', 'ON');
|
|
await sock.sendMessage(sender, { text: '💡 Lampu kamar *dinyalakan*.' });
|
|
break;
|
|
|
|
case 'matikan lampu kamar':
|
|
status['lampu kamar'] = false;
|
|
mqttClient.publish('cristine/control/lampu_kamar', 'OFF');
|
|
await sock.sendMessage(sender, { text: '💡 Lampu kamar *dimatikan*.' });
|
|
break;
|
|
|
|
case 'nyalakan lampu teras':
|
|
status['lampu teras'] = true;
|
|
mqttClient.publish('cristine/control/lampu_teras', 'ON');
|
|
await sock.sendMessage(sender, { text: '💡 Lampu teras *dinyalakan*.' });
|
|
break;
|
|
|
|
case 'matikan lampu teras':
|
|
status['lampu teras'] = false;
|
|
mqttClient.publish('cristine/control/lampu_teras', 'OFF');
|
|
await sock.sendMessage(sender, { text: '💡 Lampu teras *dimatikan*.' });
|
|
break;
|
|
|
|
case 'nyalakan kipas':
|
|
status['kipas'] = true;
|
|
mqttClient.publish('cristine/control/kipas', 'ON');
|
|
await sock.sendMessage(sender, { text: '🌀 Kipas *dinyalakan*.' });
|
|
break;
|
|
|
|
case 'matikan kipas':
|
|
status['kipas'] = false;
|
|
mqttClient.publish('cristine/control/kipas', 'OFF');
|
|
await sock.sendMessage(sender, { text: '🌀 Kipas *dimatikan*.' });
|
|
break;
|
|
|
|
case 'buka pintu':
|
|
status['pintu'] = true;
|
|
mqttClient.publish('cristine/control/pintu', 'ON');
|
|
await sock.sendMessage(sender, { text: '🚪 Pintu *dibuka*.' });
|
|
break;
|
|
|
|
case 'kunci pintu':
|
|
status['pintu'] = false;
|
|
mqttClient.publish('cristine/control/pintu', 'OFF');
|
|
await sock.sendMessage(sender, { text: '🚪 Pintu *dikunci*.' });
|
|
break;
|
|
|
|
case 'status':
|
|
pendingStatusRequests[sender] = Date.now();
|
|
mqttClient.publish('cristine/request/status', 'REQUEST');
|
|
await sock.sendMessage(sender, { text: '⏳ Meminta status dari perangkat, mohon tunggu...' });
|
|
break;
|
|
|
|
default:
|
|
await sock.sendMessage(sender, {
|
|
text: `⚠️ Perintah tidak dikenali.\nKetik *menu* untuk melihat daftar perintah.`
|
|
});
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
startBot();
|