TKK_E32222306/index.js

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();