An academic project designed to explore and master the MQTT protocol through a distributed, interactive, and real-time voting application. Inspired by the iconic aesthetic of the Wii "Vote Channel", it integrates advanced game mechanics (Kahoot-style) and a custom centralized database.
This project was built to learn and implement core MQTT concepts in a real-world scenario:
- Pub/Sub Architecture: Decoupling clients (voters/animators) and the backend database.
- Last Will and Testament (LWT): Real-time presence detection for unexpected disconnects.
- Retained Messages: State synchronization for late-joining clients.
- Quality of Service (QoS): Differentiating between ephemeral data (QoS 0/1) and critical transactions like votes (QoS 2).
- Frontend: HTML5 / CSS3 / Vanilla JS (Paho MQTT & Chart.js libraries)
- Backend: Node.js (Official MQTT library, File System)
- Public Broker: broker.emqx.io
- Protocol: MQTT via WebSockets (Port 8083 for Web) & Native MQTT (Port 1883 for Backend)
- Root Topic: isen-2026-CookieDestroyer/
- "Wii Channel" Design: Immersive interface with Glassmorphism, fluid animations (floating bubbles), and reactive 3D buttons.
- Animator Dashboard (Game Master): Full control of rooms, on-the-fly question creation or series preparation (queue), integrated timer, and live result visualization.
- Player Interface: Responsive Web App. Visual lockout after voting, dynamic progress bar, and local score tracking.
- Personal History: Each player can view their isolated voting history for the current room, dynamically generated by the database.
- Session Persistence (Retain Flag):
- Questions are published with
retained: true. A player joining an active room instantly receives the current question. - Automatic Purge (Tombstones): At the end of a session or upon closing the admin tab, an empty payload
""is sent to cleanly wipe the broker's memory.
- Questions are published with
- Presence Management (LWT):
- Each player connects with a testament set to "offline". In the event of an unexpected disconnection, the broker notifies the animator, who updates the player list in real-time.
- Transfer Reliability (QoS):
- QoS 0/1 for presence, history requests, and question distribution (prioritizing speed).
- QoS 2 for vote submission, ensuring a vote is neither lost nor counted twice in case of network instability.
- Decentralized "Kahoot" Mechanic:
- The animator calculates scores based on response time (Time-to-Live of the vote).
- UUIDs prevent multiple votes and guarantee leaderboard integrity without overloading the DB.
- Ghost Filter: The Node.js backend analyzes the MQTT
packetobject to ignore old, persistent requests (packet.retain).
The architecture uses wildcards (+ and #) for dynamic management of an infinite number of simultaneous rooms.
isen-2026-CookieDestroyer/bdd/rooms/create: Room registration request.isen-2026-CookieDestroyer/bdd/request: Player requests (e.g., history).isen-2026-CookieDestroyer/bdd/response/{UUID}: Targeted DB responses.isen-2026-CookieDestroyer/room/{ROOM_ID}/presence/{UUID}: LWT and status management.isen-2026-CookieDestroyer/room/{ROOM_ID}/chat: Live chat system.isen-2026-CookieDestroyer/room/{ROOM_ID}/question: Question distribution (Retained).isen-2026-CookieDestroyer/room/{ROOM_ID}/vote: Incoming vote stream (JSON).
The project follows a modular, production-ready architecture, separating logic, configuration, and assets.
MQTT-Voting/
├── backend/
│ ├── data/
│ │ └── database.json # Persistent storage (auto-generated)
│ ├── src/
│ │ ├── app.js # Main MQTT network listener
│ │ └── database.js # JSON read/write logic
│ ├── package.json
│ └── package-lock.json
├── frontend/
│ ├── assets/
│ │ ├── audio/
│ │ │ └── theme.mp3
│ │ ├── css/
│ │ │ └── style.css
│ │ ├── js/
│ │ │ ├── admin.js # Animator logic
│ │ │ ├── config.js # Global MQTT configurations
│ │ │ ├── joueur.js # Voter logic
│ │ │ └── sounds.js # Global audio manager
│ │ └── favicon.svg
│ ├── admin.html # Animator Interface
│ ├── index.html # Main "Wii" menu
│ └── joueur.html # Voter Interface
├── LICENSE
└── README.md
The backend must run in the background to listen to rooms and record history.
cd backend
npm install
node src/app.jsNo complex web server is required for the client side.
- Simply open the
frontend/index.htmlfile in your browser. - Click on Animator Mode to create a room (e.g., TEST).
- Open one or more tabs in Voter Mode and join the room with a nickname.