diff --git a/apps/Buzzerapp/ChangeLog b/apps/Buzzerapp/ChangeLog new file mode 100644 index 0000000000..55ebb3e4b1 --- /dev/null +++ b/apps/Buzzerapp/ChangeLog @@ -0,0 +1 @@ +0.01: New App diff --git a/apps/Buzzerapp/README.md b/apps/Buzzerapp/README.md new file mode 100644 index 0000000000..1dfc21022c --- /dev/null +++ b/apps/Buzzerapp/README.md @@ -0,0 +1,24 @@ +# Buzzerapp + +Basically it use with puckjs for specially Quize round in school where student have to press the puck and Bangle show on it screen that who press first, second like... that +Main aim through this app is need to aware about the student how technology simply is working back side of this regular daily usage devices +## Usage + +During the quiz round, each student group is provided with a response button (puck), while the teacher operates a central control device (referred to as the "bangle"). When a student presses their group’s puck, the system registers the response time and displays the order in which each group responded—first, second, and so on—on the teacher's bangle screen. This setup ensures a fair and transparent method for determining which team answered first. + +## Features + +A dashboard where every puck show who press first, second so on.., +Different Vibration type + +## Controls + +Bangle button for every new round of quiz + +## Requests + +BK7175 + +## Creator + +Brijesh diff --git a/apps/Buzzerapp/app-icon.js b/apps/Buzzerapp/app-icon.js new file mode 100644 index 0000000000..d491b247cd --- /dev/null +++ b/apps/Buzzerapp/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("lstgn/AH4A/AH4AN/d2tHvBIv8BIPPCo/nvfM34GC/wDC7fM02fCo331uGswiC804AYP6s1p64WG/WNtXu7wGB/MAjgEB7v9xHW74WFvl7/d3IYWBiIEB/No7+K1RYG4/6vm4OAP8zOdPIOM03dvmPCon9veOtxtC0sykVIHoW4EgIsG3HXUAVAgAABgQnB/uNvYsF/+txttKQMQCoQABGoOp5PMZRHP/QVFgFv/TTGLosgCosAY44AFsAVGgSwGAAvSCo0AhIVLbgIAHr5CTIYJvL+gsIjosLY4YAEgJwLFn4sN54VK4QsIZRfTCpEAjQVJ/YVJgF/CxPYu4AIvZwLAAWFs1rCJwAD+w+B14WS4cArwVS//Z1wVTAH4A/ACXwA=")) diff --git a/apps/Buzzerapp/app.js b/apps/Buzzerapp/app.js new file mode 100644 index 0000000000..3e9948cf33 --- /dev/null +++ b/apps/Buzzerapp/app.js @@ -0,0 +1,84 @@ +Bluetooth.setConsole(false); +g.clear(); +g.setFont("6x8", 2); + +let buzzedList = []; + +// Decode DataView to string (safe for BLE characteristic) +function decodeBLEString(dataView) { + let s = ""; + for (let i = 0; i < dataView.byteLength; i++) { + s += String.fromCharCode(dataView.getUint8(i)); + } + return s; +} + +// Display buzzed order +function updateDisplay() { + g.clear(); + g.drawString("📋 Buzz Order:", 10, 10); + buzzedList.forEach((name, i) => { + g.drawString((i + 1) + ". " + name, 10, 30 + i * 20); + }); + if (buzzedList.length === 0) { + g.drawString("Waiting for buzzers...", 10, 50); + } +} + +// Feedback for buzzed-in +function alertForRank(rank) { + if (rank === 0) { + Bangle.buzz(500); + Bangle.beep(); + setTimeout(() => Bangle.beep(), 200); + } else { + Bangle.buzz(150); + } +} + +// Scan for Puck.js devices one by one +function scanForBuzzers() { + NRF.requestDevice({ filters: [{ namePrefix: "Puck" }], timeout: 20000 }) + .then(device => device.gatt.connect() + .then(gatt => gatt.getPrimaryService("6e400001-b5a3-f393-e0a9-e50e24dcca9e")) + .then(service => service.getCharacteristic("6e400003-b5a3-f393-e0a9-e50e24dcca9e")) + .then(characteristic => { + characteristic.on('characteristicvaluechanged', event => { + let value = decodeBLEString(event.target.value); + try { + let msg = JSON.parse(value); + if (msg.buzz && msg.name && !buzzedList.includes(msg.name)) { + buzzedList.push(msg.name); + alertForRank(buzzedList.length - 1); + updateDisplay(); + } + } catch (e) { + print("Parse error:", value); + } + + // Disconnect safely after receiving + let device = characteristic.device; + if (device && device.gatt && device.gatt.connected) { + device.gatt.disconnect(); + } + setTimeout(scanForBuzzers, 1000); + }); + return characteristic.startNotifications(); + }) + ) + .catch(err => { + print("Scan/connect failed:", err); + setTimeout(scanForBuzzers, 2000); + }); +} + +// Button on Bangle to reset round +setWatch(() => { + buzzedList = []; + updateDisplay(); + scanForBuzzers(); +}, BTN, { repeat: true, edge: "rising", debounce: 50 }); + +// Start initial scan +updateDisplay(); +scanForBuzzers(); diff --git a/apps/Buzzerapp/app.png b/apps/Buzzerapp/app.png new file mode 100644 index 0000000000..cf0442c353 Binary files /dev/null and b/apps/Buzzerapp/app.png differ diff --git a/apps/Buzzerapp/metadata.json b/apps/Buzzerapp/metadata.json new file mode 100644 index 0000000000..639d6edcac --- /dev/null +++ b/apps/Buzzerapp/metadata.json @@ -0,0 +1,13 @@ +{ "id": "Buzzerapp", + "name": "Buzzer APP", + "icon": "app.png", + "version":"0.01", + "description": "Quiz buzzer for school student", + "tags": "tool", + "supports" : ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"Buzzerapp.app.js","url":"app.js"}, + {"name":"Buzzerapp.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/Buzzerapp/puckjs-code.md b/apps/Buzzerapp/puckjs-code.md new file mode 100644 index 0000000000..9f10116fe4 --- /dev/null +++ b/apps/Buzzerapp/puckjs-code.md @@ -0,0 +1,15 @@ +const PUCK_NAME = "Puck A"; // Change to "Puck B", "Puck C" on others +let lastSent = 0; + +function sendBuzz() { + if (Date.now() - lastSent < 3000) return; // 3s cooldown + lastSent = Date.now(); + let msg = JSON.stringify({ buzz: true, name: PUCK_NAME }); + Bluetooth.println(msg); + LED.set(); setTimeout(() => LED.reset(), 200); +} + +setWatch(sendBuzz, BTN, { edge: "rising", repeat: true, debounce: 50 }); + +NRF.setAdvertising({}, { name: PUCK_NAME, connectable: true }); +console.log(PUCK_NAME + " ready!");