224 lines
7.8 KiB
JavaScript
224 lines
7.8 KiB
JavaScript
// Import necessary modules
|
|
const mqtt = require('mqtt');
|
|
|
|
// MQTT broker configuration
|
|
const brokerUrl = 'mqtt://localhost'; // Broker URL (change if needed)
|
|
const clientId = 'buzzer_manager';
|
|
const options = {
|
|
clientId,
|
|
clean: true
|
|
};
|
|
|
|
// State variables
|
|
let buzzerActive = false; // Indicates if buzzers are blocked
|
|
let buzzerThatPressed = null; // Stores the ID of the buzzer that pressed first
|
|
let tiltBuzzers = new Set(); // List of buzzer IDs currently in "tilt" mode
|
|
|
|
// Connect to the MQTT broker
|
|
const client = mqtt.connect(brokerUrl, options);
|
|
|
|
client.on('connect', () => {
|
|
console.log(`[INFO] Connected to MQTT broker ${brokerUrl} with ID ${clientId}`);
|
|
|
|
// Subscribe to topics related to buzzer presses, unlocking, and tilt management
|
|
client.subscribe('brainblast/buzzer/pressed/#', (err) => {
|
|
if (err) console.error('[ERROR] Failed to subscribe to buzzer presses');
|
|
else console.log('[INFO] Successfully subscribed to buzzer presses');
|
|
});
|
|
|
|
client.subscribe('brainblast/buzzer/unlock', (err) => {
|
|
if (err) console.error('[ERROR] Failed to subscribe to buzzer unlock');
|
|
else console.log('[INFO] Successfully subscribed to buzzer unlock');
|
|
});
|
|
|
|
client.subscribe('brainblast/buzzer/tilt', (err) => {
|
|
if (err) console.error('[ERROR] Failed to subscribe to tilt management');
|
|
else console.log('[INFO] Successfully subscribed to tilt management');
|
|
});
|
|
});
|
|
|
|
// Validate buzzer payload
|
|
function validateBuzzerPayload(payload) {
|
|
const { buzzer_id, color } = payload;
|
|
|
|
// Validate buzzer ID (should be a positive integer)
|
|
if (typeof buzzer_id !== 'number' || buzzer_id <= 0) {
|
|
console.error(`[ERROR] Invalid buzzer ID: ${buzzer_id}`);
|
|
return false;
|
|
}
|
|
|
|
// Validate color (should be in the format #RRGGBB)
|
|
const validColor = /^#[0-9A-F]{6}$/i.test(color);
|
|
if (!validColor) {
|
|
console.error(`[ERROR] Invalid color: ${color}`);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Send updated tilt status
|
|
function sendTiltStatus(action, buzzerId) {
|
|
const tiltList = Array.from(tiltBuzzers); // Convert Set to Array
|
|
|
|
client.publish('brainblast/buzzer/status', JSON.stringify({
|
|
status: "tilt_update",
|
|
tilt_buzzers: tiltList,
|
|
message: `Buzzer ID ${buzzerId} ${action} to tilt mode`,
|
|
timestamp: new Date().toISOString()
|
|
}));
|
|
|
|
console.log(`[INFO] Tilt status updated: ${tiltList.length} buzzers in tilt mode`);
|
|
}
|
|
|
|
// Handle incoming messages
|
|
client.on('message', (topic, message) => {
|
|
let payload;
|
|
|
|
// Parse the incoming message
|
|
try {
|
|
payload = JSON.parse(message.toString());
|
|
} catch (e) {
|
|
console.error(`[ERROR] Invalid JSON message received on topic ${topic}: ${message.toString()}`);
|
|
return;
|
|
}
|
|
|
|
// Manage tilt mode for buzzers
|
|
if (topic === 'brainblast/buzzer/tilt') {
|
|
const { buzzer_id, status } = payload;
|
|
|
|
if (typeof buzzer_id !== 'number' || !['add', 'remove'].includes(status)) {
|
|
console.error('[ERROR] Invalid tilt payload, message ignored.');
|
|
return;
|
|
}
|
|
|
|
// Update tilt status based on the command
|
|
if (status === 'add') {
|
|
tiltBuzzers.add(buzzer_id);
|
|
console.log(`[INFO] Buzzer ID ${buzzer_id} added to tilt mode`);
|
|
} else if (status === 'remove') {
|
|
tiltBuzzers.delete(buzzer_id);
|
|
console.log(`[INFO] Buzzer ID ${buzzer_id} removed from tilt mode`);
|
|
}
|
|
|
|
// Confirm that the tilt command has been received
|
|
client.publish(`brainblast/buzzer/tilt/confirmation/${buzzer_id}`, JSON.stringify({
|
|
status: "received",
|
|
action: status,
|
|
buzzer_id: buzzer_id,
|
|
message: `Tilt command '${status}' received for buzzer ID ${buzzer_id}`,
|
|
timestamp: new Date().toISOString()
|
|
}));
|
|
|
|
// Send the updated tilt status to all components
|
|
sendTiltStatus(status === 'add' ? 'added' : 'removed', buzzer_id);
|
|
|
|
return;
|
|
}
|
|
|
|
// Detect a buzzer press
|
|
if (topic.startsWith('brainblast/buzzer/pressed/')) {
|
|
// Validate buzzer payload
|
|
if (!validateBuzzerPayload(payload)) {
|
|
console.error('[ERROR] Invalid buzzer payload, message ignored.');
|
|
return;
|
|
}
|
|
|
|
const buzzerId = payload.buzzer_id; // Unique buzzer ID
|
|
const color = payload.color; // Associated hex color
|
|
|
|
// Always send a confirmation, even if the buzzer is in tilt mode
|
|
client.publish(`brainblast/buzzer/confirmation/${buzzerId}`, JSON.stringify({
|
|
status: "received",
|
|
buzzer_id: buzzerId,
|
|
message: `Buzzer ID ${buzzerId} received (Color: ${color})`,
|
|
timestamp: new Date().toISOString()
|
|
}));
|
|
|
|
// Ignore if the buzzer is in tilt mode, but notify this event
|
|
if (tiltBuzzers.has(buzzerId)) {
|
|
console.log(`[INFO] Buzzer ID ${buzzerId} ignored (Tilt mode active)`);
|
|
|
|
// Notify that the buzzer is in tilt mode and ignored
|
|
client.publish(`brainblast/buzzer/tilt/ignored/${buzzerId}`, JSON.stringify({
|
|
status: "tilt_ignored",
|
|
buzzer_id: buzzerId,
|
|
message: `Buzzer ID ${buzzerId} is in tilt mode and ignored.`,
|
|
timestamp: new Date().toISOString()
|
|
}));
|
|
return;
|
|
}
|
|
|
|
// Notify activity even if buzzers are blocked
|
|
client.publish('brainblast/buzzer/activity', JSON.stringify({
|
|
buzzer_id: buzzerId,
|
|
color: color,
|
|
status: buzzerActive ? "blocked" : "free",
|
|
message: `Activity detected on buzzer ID ${buzzerId} (Color: ${color})`,
|
|
timestamp: new Date().toISOString()
|
|
}));
|
|
|
|
if (!buzzerActive) {
|
|
// Block further buzzers and record the first pressed ID
|
|
buzzerActive = true;
|
|
buzzerThatPressed = buzzerId;
|
|
|
|
console.log(`[INFO] Buzzer activated by ID: ${buzzerId} (Color: ${color})`);
|
|
|
|
// Notify the light manager to change to the team's color
|
|
client.publish('brainblast/light/change', JSON.stringify({
|
|
color: color,
|
|
effect: 'full_color'
|
|
}));
|
|
|
|
// Notify all components of buzzer blocking
|
|
client.publish('brainblast/buzzer/status', JSON.stringify({
|
|
status: "blocked",
|
|
buzzer_id: buzzerId,
|
|
color: color,
|
|
message: `Buzzer activated by ID ${buzzerId} (Color: ${color})`,
|
|
timestamp: new Date().toISOString()
|
|
}));
|
|
|
|
console.log(`[INFO] Buzzers blocked and notification sent`);
|
|
}
|
|
}
|
|
|
|
// Unlock buzzers
|
|
if (topic === 'brainblast/buzzer/unlock') {
|
|
console.log('[INFO] Buzzer unlock requested');
|
|
|
|
// Confirm receipt of unlock command
|
|
client.publish('brainblast/buzzer/unlock/confirmation', JSON.stringify({
|
|
status: "received",
|
|
message: "Buzzer unlock command received.",
|
|
timestamp: new Date().toISOString()
|
|
}));
|
|
// Notify the light manager to change to the team's color
|
|
client.publish('brainblast/light/change', JSON.stringify({
|
|
color: "#FFFFFF",
|
|
effect: 'rainbow'
|
|
}));
|
|
|
|
|
|
// Reset buzzer manager state
|
|
buzzerActive = false;
|
|
buzzerThatPressed = null;
|
|
|
|
// Notify all components of buzzer unlock
|
|
client.publish('brainblast/buzzer/status', JSON.stringify({
|
|
status: "unblocked",
|
|
message: "Buzzers unblocked and ready for activation.",
|
|
timestamp: new Date().toISOString()
|
|
}));
|
|
|
|
console.log('[INFO] Buzzers unblocked and notification sent');
|
|
}
|
|
});
|
|
|
|
client.on('error', (err) => {
|
|
console.error(`[ERROR] Error connecting to broker: ${err}`);
|
|
});
|
|
|
|
console.log('[INFO] Buzzer manager started...');
|