première iteration du buzzer-manager
This commit is contained in:
		
							
								
								
									
										181
									
								
								services/buzzer-manager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								services/buzzer-manager.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,181 @@ | ||||
| // 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; | ||||
| } | ||||
|  | ||||
| // 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; | ||||
|         } | ||||
|  | ||||
|         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`); | ||||
|         } | ||||
|         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 | ||||
|  | ||||
|         // Ignore if the buzzer is in tilt mode | ||||
|         if (tiltBuzzers.has(buzzerId)) { | ||||
|             console.log(`[INFO] Buzzer ID ${buzzerId} ignored (Tilt mode active)`); | ||||
|             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() | ||||
|         })); | ||||
|  | ||||
|         // Confirm buzzer press receipt | ||||
|         client.publish(`brainblast/buzzer/confirmation/${buzzerId}`, JSON.stringify({ | ||||
|             status: "received", | ||||
|             buzzer_id: buzzerId, | ||||
|             message: `Buzzer ID ${buzzerId} activated with 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() | ||||
|         })); | ||||
|  | ||||
|         // 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...'); | ||||
							
								
								
									
										497
									
								
								services/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										497
									
								
								services/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,497 @@ | ||||
| { | ||||
|   "name": "services", | ||||
|   "lockfileVersion": 3, | ||||
|   "requires": true, | ||||
|   "packages": { | ||||
|     "": { | ||||
|       "dependencies": { | ||||
|         "mqtt": "^5.10.1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@babel/runtime": { | ||||
|       "version": "7.25.7", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", | ||||
|       "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "regenerator-runtime": "^0.14.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=6.9.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/node": { | ||||
|       "version": "22.7.4", | ||||
|       "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", | ||||
|       "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "undici-types": "~6.19.2" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/readable-stream": { | ||||
|       "version": "4.0.15", | ||||
|       "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.15.tgz", | ||||
|       "integrity": "sha512-oAZ3kw+kJFkEqyh7xORZOku1YAKvsFTogRY8kVl4vHpEKiDkfnSA/My8haRE7fvmix5Zyy+1pwzOi7yycGLBJw==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@types/node": "*", | ||||
|         "safe-buffer": "~5.1.1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/ws": { | ||||
|       "version": "8.5.12", | ||||
|       "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", | ||||
|       "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@types/node": "*" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/abort-controller": { | ||||
|       "version": "3.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", | ||||
|       "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "event-target-shim": "^5.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=6.5" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/base64-js": { | ||||
|       "version": "1.5.1", | ||||
|       "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", | ||||
|       "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", | ||||
|       "funding": [ | ||||
|         { | ||||
|           "type": "github", | ||||
|           "url": "https://github.com/sponsors/feross" | ||||
|         }, | ||||
|         { | ||||
|           "type": "patreon", | ||||
|           "url": "https://www.patreon.com/feross" | ||||
|         }, | ||||
|         { | ||||
|           "type": "consulting", | ||||
|           "url": "https://feross.org/support" | ||||
|         } | ||||
|       ], | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/bl": { | ||||
|       "version": "6.0.16", | ||||
|       "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.16.tgz", | ||||
|       "integrity": "sha512-V/kz+z2Mx5/6qDfRCilmrukUXcXuCoXKg3/3hDvzKKoSUx8CJKudfIoT29XZc3UE9xBvxs5qictiHdprwtteEg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@types/readable-stream": "^4.0.0", | ||||
|         "buffer": "^6.0.3", | ||||
|         "inherits": "^2.0.4", | ||||
|         "readable-stream": "^4.2.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/buffer": { | ||||
|       "version": "6.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", | ||||
|       "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", | ||||
|       "funding": [ | ||||
|         { | ||||
|           "type": "github", | ||||
|           "url": "https://github.com/sponsors/feross" | ||||
|         }, | ||||
|         { | ||||
|           "type": "patreon", | ||||
|           "url": "https://www.patreon.com/feross" | ||||
|         }, | ||||
|         { | ||||
|           "type": "consulting", | ||||
|           "url": "https://feross.org/support" | ||||
|         } | ||||
|       ], | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "base64-js": "^1.3.1", | ||||
|         "ieee754": "^1.2.1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/buffer-from": { | ||||
|       "version": "1.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", | ||||
|       "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/commist": { | ||||
|       "version": "3.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz", | ||||
|       "integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/concat-stream": { | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", | ||||
|       "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", | ||||
|       "engines": [ | ||||
|         "node >= 6.0" | ||||
|       ], | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "buffer-from": "^1.0.0", | ||||
|         "inherits": "^2.0.3", | ||||
|         "readable-stream": "^3.0.2", | ||||
|         "typedarray": "^0.0.6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/concat-stream/node_modules/readable-stream": { | ||||
|       "version": "3.6.2", | ||||
|       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", | ||||
|       "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "inherits": "^2.0.3", | ||||
|         "string_decoder": "^1.1.1", | ||||
|         "util-deprecate": "^1.0.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/debug": { | ||||
|       "version": "4.3.7", | ||||
|       "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", | ||||
|       "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "ms": "^2.1.3" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=6.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "supports-color": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/event-target-shim": { | ||||
|       "version": "5.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", | ||||
|       "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/events": { | ||||
|       "version": "3.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", | ||||
|       "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=0.8.x" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/fast-unique-numbers": { | ||||
|       "version": "8.0.13", | ||||
|       "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-8.0.13.tgz", | ||||
|       "integrity": "sha512-7OnTFAVPefgw2eBJ1xj2PGGR9FwYzSUso9decayHgCDX4sJkHLdcsYTytTg+tYv+wKF3U8gJuSBz2jJpQV4u/g==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@babel/runtime": "^7.23.8", | ||||
|         "tslib": "^2.6.2" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=16.1.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/help-me": { | ||||
|       "version": "5.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", | ||||
|       "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/ieee754": { | ||||
|       "version": "1.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", | ||||
|       "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", | ||||
|       "funding": [ | ||||
|         { | ||||
|           "type": "github", | ||||
|           "url": "https://github.com/sponsors/feross" | ||||
|         }, | ||||
|         { | ||||
|           "type": "patreon", | ||||
|           "url": "https://www.patreon.com/feross" | ||||
|         }, | ||||
|         { | ||||
|           "type": "consulting", | ||||
|           "url": "https://feross.org/support" | ||||
|         } | ||||
|       ], | ||||
|       "license": "BSD-3-Clause" | ||||
|     }, | ||||
|     "node_modules/inherits": { | ||||
|       "version": "2.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", | ||||
|       "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", | ||||
|       "license": "ISC" | ||||
|     }, | ||||
|     "node_modules/js-sdsl": { | ||||
|       "version": "4.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", | ||||
|       "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", | ||||
|       "license": "MIT", | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/js-sdsl" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/lru-cache": { | ||||
|       "version": "10.4.3", | ||||
|       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", | ||||
|       "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", | ||||
|       "license": "ISC" | ||||
|     }, | ||||
|     "node_modules/minimist": { | ||||
|       "version": "1.2.8", | ||||
|       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", | ||||
|       "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", | ||||
|       "license": "MIT", | ||||
|       "funding": { | ||||
|         "url": "https://github.com/sponsors/ljharb" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/mqtt": { | ||||
|       "version": "5.10.1", | ||||
|       "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.10.1.tgz", | ||||
|       "integrity": "sha512-hXCOki8sANoQ7w+2OzJzg6qMBxTtrH9RlnVNV8panLZgnl+Gh0J/t4k6r8Az8+C7y3KAcyXtn0mmLixyUom8Sw==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@types/readable-stream": "^4.0.5", | ||||
|         "@types/ws": "^8.5.9", | ||||
|         "commist": "^3.2.0", | ||||
|         "concat-stream": "^2.0.0", | ||||
|         "debug": "^4.3.4", | ||||
|         "help-me": "^5.0.0", | ||||
|         "lru-cache": "^10.0.1", | ||||
|         "minimist": "^1.2.8", | ||||
|         "mqtt-packet": "^9.0.0", | ||||
|         "number-allocator": "^1.0.14", | ||||
|         "readable-stream": "^4.4.2", | ||||
|         "reinterval": "^1.1.0", | ||||
|         "rfdc": "^1.3.0", | ||||
|         "split2": "^4.2.0", | ||||
|         "worker-timers": "^7.1.4", | ||||
|         "ws": "^8.17.1" | ||||
|       }, | ||||
|       "bin": { | ||||
|         "mqtt": "build/bin/mqtt.js", | ||||
|         "mqtt_pub": "build/bin/pub.js", | ||||
|         "mqtt_sub": "build/bin/sub.js" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=16.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/mqtt-packet": { | ||||
|       "version": "9.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.0.tgz", | ||||
|       "integrity": "sha512-8v+HkX+fwbodsWAZIZTI074XIoxVBOmPeggQuDFCGg1SqNcC+uoRMWu7J6QlJPqIUIJXmjNYYHxBBLr1Y/Df4w==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "bl": "^6.0.8", | ||||
|         "debug": "^4.3.4", | ||||
|         "process-nextick-args": "^2.0.1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/ms": { | ||||
|       "version": "2.1.3", | ||||
|       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", | ||||
|       "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/number-allocator": { | ||||
|       "version": "1.0.14", | ||||
|       "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz", | ||||
|       "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "debug": "^4.3.1", | ||||
|         "js-sdsl": "4.3.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/process": { | ||||
|       "version": "0.11.10", | ||||
|       "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", | ||||
|       "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">= 0.6.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/process-nextick-args": { | ||||
|       "version": "2.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", | ||||
|       "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/readable-stream": { | ||||
|       "version": "4.5.2", | ||||
|       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", | ||||
|       "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "abort-controller": "^3.0.0", | ||||
|         "buffer": "^6.0.3", | ||||
|         "events": "^3.3.0", | ||||
|         "process": "^0.11.10", | ||||
|         "string_decoder": "^1.3.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/regenerator-runtime": { | ||||
|       "version": "0.14.1", | ||||
|       "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", | ||||
|       "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/reinterval": { | ||||
|       "version": "1.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", | ||||
|       "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/rfdc": { | ||||
|       "version": "1.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", | ||||
|       "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/safe-buffer": { | ||||
|       "version": "5.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", | ||||
|       "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/split2": { | ||||
|       "version": "4.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", | ||||
|       "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", | ||||
|       "license": "ISC", | ||||
|       "engines": { | ||||
|         "node": ">= 10.x" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/string_decoder": { | ||||
|       "version": "1.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", | ||||
|       "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "safe-buffer": "~5.2.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/string_decoder/node_modules/safe-buffer": { | ||||
|       "version": "5.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", | ||||
|       "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", | ||||
|       "funding": [ | ||||
|         { | ||||
|           "type": "github", | ||||
|           "url": "https://github.com/sponsors/feross" | ||||
|         }, | ||||
|         { | ||||
|           "type": "patreon", | ||||
|           "url": "https://www.patreon.com/feross" | ||||
|         }, | ||||
|         { | ||||
|           "type": "consulting", | ||||
|           "url": "https://feross.org/support" | ||||
|         } | ||||
|       ], | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/tslib": { | ||||
|       "version": "2.7.0", | ||||
|       "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", | ||||
|       "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", | ||||
|       "license": "0BSD" | ||||
|     }, | ||||
|     "node_modules/typedarray": { | ||||
|       "version": "0.0.6", | ||||
|       "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", | ||||
|       "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/undici-types": { | ||||
|       "version": "6.19.8", | ||||
|       "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", | ||||
|       "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/util-deprecate": { | ||||
|       "version": "1.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", | ||||
|       "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/worker-timers": { | ||||
|       "version": "7.1.8", | ||||
|       "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-7.1.8.tgz", | ||||
|       "integrity": "sha512-R54psRKYVLuzff7c1OTFcq/4Hue5Vlz4bFtNEIarpSiCYhpifHU3aIQI29S84o1j87ePCYqbmEJPqwBTf+3sfw==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@babel/runtime": "^7.24.5", | ||||
|         "tslib": "^2.6.2", | ||||
|         "worker-timers-broker": "^6.1.8", | ||||
|         "worker-timers-worker": "^7.0.71" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/worker-timers-broker": { | ||||
|       "version": "6.1.8", | ||||
|       "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-6.1.8.tgz", | ||||
|       "integrity": "sha512-FUCJu9jlK3A8WqLTKXM9E6kAmI/dR1vAJ8dHYLMisLNB/n3GuaFIjJ7pn16ZcD1zCOf7P6H62lWIEBi+yz/zQQ==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@babel/runtime": "^7.24.5", | ||||
|         "fast-unique-numbers": "^8.0.13", | ||||
|         "tslib": "^2.6.2", | ||||
|         "worker-timers-worker": "^7.0.71" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/worker-timers-worker": { | ||||
|       "version": "7.0.71", | ||||
|       "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-7.0.71.tgz", | ||||
|       "integrity": "sha512-ks/5YKwZsto1c2vmljroppOKCivB/ma97g9y77MAAz2TBBjPPgpoOiS1qYQKIgvGTr2QYPT3XhJWIB6Rj2MVPQ==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@babel/runtime": "^7.24.5", | ||||
|         "tslib": "^2.6.2" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/ws": { | ||||
|       "version": "8.18.0", | ||||
|       "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", | ||||
|       "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=10.0.0" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "bufferutil": "^4.0.1", | ||||
|         "utf-8-validate": ">=5.0.2" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "bufferutil": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "utf-8-validate": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										5
									
								
								services/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								services/package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| { | ||||
|   "dependencies": { | ||||
|     "mqtt": "^5.10.1" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										142
									
								
								services/test-buzzer-manager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								services/test-buzzer-manager.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| // Import necessary modules | ||||
| const mqtt = require('mqtt'); | ||||
|  | ||||
| // MQTT broker configuration | ||||
| const brokerUrl = 'mqtt://localhost'; // Broker URL (change if needed) | ||||
| const options = { | ||||
|     clientId: 'test_buzzer_manager', | ||||
|     clean: true | ||||
| }; | ||||
|  | ||||
| // Set up MQTT client | ||||
| const client = mqtt.connect(brokerUrl, options); | ||||
|  | ||||
| // Variables for tracking test results | ||||
| let testResults = { | ||||
|     buzzerActivity: false, | ||||
|     confirmationReceived: false, | ||||
|     statusBlocked: false, | ||||
|     statusUnblocked: false, | ||||
|     tiltAdded: false, | ||||
|     tiltIgnored: false, | ||||
|     tiltRemoved: false, | ||||
|     unlockConfirmation: false | ||||
| }; | ||||
|  | ||||
| // Subscribe to topics to capture the responses from the buzzer manager | ||||
| client.on('connect', () => { | ||||
|     console.log('[INFO] Connected to MQTT broker for testing'); | ||||
|  | ||||
|     // Subscribe to all topics related to the buzzer manager | ||||
|     client.subscribe('brainblast/buzzer/#', (err) => { | ||||
|         if (err) console.error('[ERROR] Failed to subscribe to topics for testing'); | ||||
|         else console.log('[INFO] Subscribed to topics successfully'); | ||||
|     }); | ||||
|  | ||||
|     // Run the test sequence after a short delay | ||||
|     setTimeout(runTestSequence, 500); | ||||
| }); | ||||
|  | ||||
| // Capture and process incoming MQTT messages | ||||
| client.on('message', (topic, message) => { | ||||
|     const payload = JSON.parse(message.toString()); | ||||
|     console.log(`[INFO] Message received on ${topic}: ${message.toString()}`); | ||||
|  | ||||
|     // Track the test results based on the topics and payloads | ||||
|     if (topic.startsWith('brainblast/buzzer/activity') && payload.buzzer_id === 1) { | ||||
|         testResults.buzzerActivity = true; | ||||
|     } | ||||
|  | ||||
|     if (topic.startsWith(`brainblast/buzzer/confirmation/1`) && payload.status === "received") { | ||||
|         testResults.confirmationReceived = true; | ||||
|     } | ||||
|  | ||||
|     if (topic === 'brainblast/buzzer/status' && payload.status === "blocked") { | ||||
|         testResults.statusBlocked = true; | ||||
|     } | ||||
|  | ||||
|     if (topic === 'brainblast/buzzer/status' && payload.status === "unblocked") { | ||||
|         testResults.statusUnblocked = true; | ||||
|     } | ||||
|  | ||||
|     if (topic === 'brainblast/buzzer/unlock/confirmation' && payload.status === "received") { | ||||
|         testResults.unlockConfirmation = true; | ||||
|     } | ||||
|  | ||||
|     if (topic === 'brainblast/buzzer/activity' && payload.buzzer_id === 2 && payload.status === "blocked") { | ||||
|         testResults.tiltIgnored = true; | ||||
|     } | ||||
|  | ||||
|     if (topic.startsWith('brainblast/buzzer/status') && payload.message.includes('Tilt removed')) { | ||||
|         testResults.tiltRemoved = true; | ||||
|     } | ||||
| }); | ||||
|  | ||||
| // Function to run the complete test sequence | ||||
| function runTestSequence() { | ||||
|     console.log('[INFO] Starting test sequence...'); | ||||
|  | ||||
|     // 1. Simulate a buzzer press (buzzer 1, color red) | ||||
|     console.log('[TEST] Simulating buzzer press (ID 1, color #FF0000)...'); | ||||
|     client.publish('brainblast/buzzer/pressed/1', JSON.stringify({ | ||||
|         buzzer_id: 1, | ||||
|         color: "#FF0000" | ||||
|     })); | ||||
|  | ||||
|     // 2. Simulate a second buzzer press (buzzer 2, color blue) to check blocking | ||||
|     setTimeout(() => { | ||||
|         console.log('[TEST] Simulating second buzzer press (ID 2, color #0000FF)...'); | ||||
|         client.publish('brainblast/buzzer/pressed/2', JSON.stringify({ | ||||
|             buzzer_id: 2, | ||||
|             color: "#0000FF" | ||||
|         })); | ||||
|     }, 1000); | ||||
|  | ||||
|     // 3. Simulate adding a buzzer to tilt mode (buzzer 2) | ||||
|     setTimeout(() => { | ||||
|         console.log('[TEST] Adding buzzer ID 2 to tilt mode...'); | ||||
|         client.publish('brainblast/buzzer/tilt', JSON.stringify({ | ||||
|             buzzer_id: 2, | ||||
|             status: "add" | ||||
|         })); | ||||
|         testResults.tiltAdded = true; | ||||
|     }, 1500); | ||||
|  | ||||
|     // 4. Simulate pressing a buzzer in tilt mode (should be ignored) | ||||
|     setTimeout(() => { | ||||
|         console.log('[TEST] Simulating tilt buzzer press (ID 2, color #0000FF)...'); | ||||
|         client.publish('brainblast/buzzer/pressed/2', JSON.stringify({ | ||||
|             buzzer_id: 2, | ||||
|             color: "#0000FF" | ||||
|         })); | ||||
|     }, 2000); | ||||
|  | ||||
|     // 5. Remove tilt mode from buzzer 2 | ||||
|     setTimeout(() => { | ||||
|         console.log('[TEST] Removing tilt mode for buzzer ID 2...'); | ||||
|         client.publish('brainblast/buzzer/tilt', JSON.stringify({ | ||||
|             buzzer_id: 2, | ||||
|             status: "remove" | ||||
|         })); | ||||
|     }, 2500); | ||||
|  | ||||
|     // 6. Unlock buzzers to reset state | ||||
|     setTimeout(() => { | ||||
|         console.log('[TEST] Unlocking buzzers...'); | ||||
|         client.publish('brainblast/buzzer/unlock', '{}'); | ||||
|     }, 3000); | ||||
|  | ||||
|     // 7. Display results | ||||
|     setTimeout(() => { | ||||
|         console.log('[INFO] Test sequence complete. Results:'); | ||||
|         console.log(`1. Buzzer activity detected for buzzer 1: ${testResults.buzzerActivity ? 'PASSED' : 'FAILED'}`); | ||||
|         console.log(`2. Confirmation received for buzzer 1: ${testResults.confirmationReceived ? 'PASSED' : 'FAILED'}`); | ||||
|         console.log(`3. Buzzer 1 status set to "blocked": ${testResults.statusBlocked ? 'PASSED' : 'FAILED'}`); | ||||
|         console.log(`4. Buzzer status set to "unblocked": ${testResults.statusUnblocked ? 'PASSED' : 'FAILED'}`); | ||||
|         console.log(`5. Tilt mode added for buzzer 2: ${testResults.tiltAdded ? 'PASSED' : 'FAILED'}`); | ||||
|         console.log(`6. Tilted buzzer press ignored: ${testResults.tiltIgnored ? 'PASSED' : 'FAILED'}`); | ||||
|         console.log(`7. Tilt mode removed for buzzer 2: ${testResults.tiltRemoved ? 'PASSED' : 'FAILED'}`); | ||||
|         console.log(`8. Unlock confirmation received: ${testResults.unlockConfirmation ? 'PASSED' : 'FAILED'}`); | ||||
|         client.end(); // End the MQTT connection | ||||
|     }, 4000); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user