127 lines
5.0 KiB
JavaScript
127 lines
5.0 KiB
JavaScript
require('dotenv').config();
|
|
const mqtt = require('mqtt');
|
|
|
|
console.log('=== HIVE MQTT LATENCY TESTER ===');
|
|
console.log('Menghubungkan ke:', process.env.MQTT_BROKER_URL);
|
|
|
|
const client = mqtt.connect(process.env.MQTT_BROKER_URL, {
|
|
port: parseInt(process.env.MQTT_PORT) || 8883,
|
|
username: process.env.MQTT_USERNAME,
|
|
password: process.env.MQTT_PASSWORD,
|
|
protocol: 'mqtts',
|
|
clientId: `latency-tester-${Date.now()}`,
|
|
clean: true,
|
|
});
|
|
|
|
const TOPIC_SENSOR = 'sensor/sht31';
|
|
const TOPIC_RELAY_WILDCARD = 'cmd/relay/+';
|
|
const TOPIC_PING = 'latency/test/ping';
|
|
|
|
// Map untuk mencatat waktu kirim perintah relay
|
|
const pendingCommands = new Map();
|
|
|
|
// Map untuk melacak waktu pengiriman ping loopback
|
|
const pingSentTimes = new Map();
|
|
const pingPubAckTimes = new Map();
|
|
|
|
client.on('connect', () => {
|
|
console.log('✅ Terhubung ke HiveMQ Cloud!');
|
|
console.log('--------------------------------------------------');
|
|
console.log('1. Silakan lakukan aksi di Flutter app untuk tes latensi kontrol.');
|
|
console.log('2. Atau tekan [ENTER] di terminal ini untuk tes ping.');
|
|
console.log('--------------------------------------------------');
|
|
|
|
// Subscribe ke topik sensor, perintah, dan ping
|
|
client.subscribe([TOPIC_SENSOR, TOPIC_RELAY_WILDCARD, TOPIC_PING], (err) => {
|
|
if (err) console.error('❌ Gagal subscribe:', err.message);
|
|
});
|
|
});
|
|
|
|
client.on('message', (topic, payload) => {
|
|
const now = Date.now();
|
|
const timeStr = new Date().toLocaleTimeString();
|
|
|
|
// 1. Logika untuk Ping Loopback (Mengukur Backend -> MQTT dan MQTT -> Backend secara presisi)
|
|
if (topic === TOPIC_PING) {
|
|
try {
|
|
const data = JSON.parse(payload.toString());
|
|
const { pingId } = data;
|
|
const t_receive = now;
|
|
|
|
const t0 = pingSentTimes.get(pingId);
|
|
if (t0) {
|
|
const totalRTT = t_receive - t0; // Total waktu bolak-balik
|
|
const oneWayLatency = Math.round(totalRTT / 2); // Estimasi satu arah
|
|
|
|
console.log(`\n[${timeStr}] ⚡ HASIL PENGUKURAN LATENSI:`);
|
|
console.log(` 🔸 1. Backend ➔ MQTT Broker (Kirim Perintah) : ${oneWayLatency} ms`);
|
|
console.log(` 🔸 2. MQTT Broker ➔ Backend (Terima Data ESP) : ${oneWayLatency} ms`);
|
|
console.log(` ➔ Total Round-Trip Time (RTT) : ${totalRTT} ms`);
|
|
console.log(`--------------------------------------------------`);
|
|
|
|
// Bersihkan memori cache
|
|
pingSentTimes.delete(pingId);
|
|
pingPubAckTimes.delete(pingId);
|
|
}
|
|
} catch (e) {}
|
|
return;
|
|
}
|
|
|
|
// 2. Jika menerima pesan perintah relay
|
|
if (topic.startsWith('cmd/relay/')) {
|
|
const deviceId = topic.split('/')[2];
|
|
const state = payload.toString().trim();
|
|
console.log(`[${timeStr}] 📤 Perintah [${state}] terkirim ke device: ${deviceId}`);
|
|
pendingCommands.set(deviceId, {
|
|
targetState: state === 'ON',
|
|
sentAt: now
|
|
});
|
|
return;
|
|
}
|
|
|
|
// 3. Jika menerima data sensor dari ESP32
|
|
if (topic === TOPIC_SENSOR) {
|
|
try {
|
|
const data = JSON.parse(payload.toString());
|
|
const deviceId = data.device_id || 'esp32-01';
|
|
const relayState = data.relay_state ?? data.relay ?? false;
|
|
|
|
console.log(`[${timeStr}] 📥 Data sensor masuk dari ${deviceId} (Suhu: ${data.temp || data.temperature}°C | Hum: ${data.hum || data.humidity}% | Relay: ${relayState})`);
|
|
|
|
// Cek apakah ada perintah relay yang sedang ditunggu responnya
|
|
const pending = pendingCommands.get(deviceId);
|
|
if (pending && pending.targetState === relayState) {
|
|
const latency = now - pending.sentAt;
|
|
console.log(`🔥 [Control RTT] Perintah dikirim hingga status terkonfirmasi: ${latency} ms`);
|
|
console.log(` └─ Estimasi Latensi Kirim Perintah (Backend ➔ ESP32): ${Math.round(latency / 2)} ms`);
|
|
pendingCommands.delete(deviceId);
|
|
}
|
|
} catch (e) {
|
|
console.log(`[${timeStr}] 📥 Data sensor masuk (Bukan JSON):`, payload.toString());
|
|
}
|
|
}
|
|
});
|
|
|
|
client.on('error', (err) => {
|
|
console.error('❌ MQTT Error:', err.message);
|
|
});
|
|
|
|
// Setup agar saat menekan Enter di terminal akan memicu publish ping ke HiveMQ
|
|
process.stdin.on('data', () => {
|
|
if (client.connected) {
|
|
const pingId = Math.random().toString(36).substring(7);
|
|
const t0 = Date.now();
|
|
pingSentTimes.set(pingId, t0);
|
|
|
|
// Gunakan QoS 1 agar mendapatkan callback PUBACK dari broker saat pesan sukses diterima broker
|
|
client.publish(TOPIC_PING, JSON.stringify({ pingId }), { qos: 1 }, (err) => {
|
|
if (!err) {
|
|
const t_puback = Date.now();
|
|
pingPubAckTimes.set(pingId, t_puback);
|
|
} else {
|
|
console.error('❌ Gagal publish ping:', err.message);
|
|
}
|
|
});
|
|
}
|
|
});
|