Compare commits
16 Commits
update/imp
...
ed9a939121
| Author | SHA1 | Date | |
|---|---|---|---|
| ed9a939121 | |||
| a15d811092 | |||
| bab961ace7 | |||
| 07d76a7669 | |||
| 3f63801df9 | |||
| 66c9e68eb7 | |||
| cc9cf987b1 | |||
| 212e2f350f | |||
| 5379e0ed53 | |||
| 6403b8a299 | |||
| 827427ed28 | |||
| 4efe3b00c4 | |||
| a844c21a1b | |||
| f7e2a7a37e | |||
| 4c1fac7543 | |||
| 98b084724e |
@@ -81,6 +81,9 @@
|
|||||||
client.on('connect', () => {
|
client.on('connect', () => {
|
||||||
console.log('CardButtonScore: Connected to MQTT broker at', config.mqttBrokerUrl);
|
console.log('CardButtonScore: Connected to MQTT broker at', config.mqttBrokerUrl);
|
||||||
client.subscribe('game/score');
|
client.subscribe('game/score');
|
||||||
|
|
||||||
|
console.log("CardButtonScore: Requesting scores.");
|
||||||
|
client.publish('game/score/request', '{}');
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('error', (err) => {
|
client.on('error', (err) => {
|
||||||
|
|||||||
@@ -91,7 +91,6 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, reactive } from 'vue';
|
import { onMounted, ref, reactive } from 'vue';
|
||||||
import variables from '@/variables.js';
|
|
||||||
import mqtt from 'mqtt'
|
import mqtt from 'mqtt'
|
||||||
import config from '@/config.js'
|
import config from '@/config.js'
|
||||||
|
|
||||||
@@ -131,24 +130,6 @@ function handleMessage(topic, message) {
|
|||||||
scores.BlueRoundScore = parsedMessage.TEAM.Blue.RoundScore
|
scores.BlueRoundScore = parsedMessage.TEAM.Blue.RoundScore
|
||||||
scores.YellowRoundScore = parsedMessage.TEAM.Yellow.RoundScore
|
scores.YellowRoundScore = parsedMessage.TEAM.Yellow.RoundScore
|
||||||
scores.GreenRoundScore = parsedMessage.TEAM.Green.RoundScore
|
scores.GreenRoundScore = parsedMessage.TEAM.Green.RoundScore
|
||||||
// Mettre à jour l'état des buzzers en fonction des messages
|
|
||||||
/*
|
|
||||||
switch (buzzer) {
|
|
||||||
case 'redBuzzerIP':
|
|
||||||
redBuzzerState.value = status === "online" ? 1 : 0;
|
|
||||||
break;
|
|
||||||
case 'blueBuzzerIP':
|
|
||||||
blueBuzzerState.value = status === "online" ? 1 : 0;
|
|
||||||
break;
|
|
||||||
case 'yellowBuzzerIP':
|
|
||||||
yellowBuzzerState.value = status === "online" ? 1 : 0;
|
|
||||||
break;
|
|
||||||
case 'greenBuzzerIP':
|
|
||||||
greenBuzzerState.value = status === "online" ? 1 : 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -162,7 +143,9 @@ onMounted(() => {
|
|||||||
subscribeToTopic('game/score', (topic, message) => {
|
subscribeToTopic('game/score', (topic, message) => {
|
||||||
handleMessage(topic, message);
|
handleMessage(topic, message);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Request score refresh
|
||||||
|
client.publish('game/score/request', '{}');
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
const disabled = ref(false)
|
const disabled = ref(false)
|
||||||
|
|
||||||
const _publishMessage = () => {
|
const _publishMessage = () => {
|
||||||
|
console.log('MqttButton: Publishing', props.topic, props.message)
|
||||||
publishMessage(props.topic, props.message)
|
publishMessage(props.topic, props.message)
|
||||||
disabled.value = true
|
disabled.value = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,20 +5,14 @@
|
|||||||
<v-container class="score_div color-blue">
|
<v-container class="score_div color-blue">
|
||||||
<div class="d-flex flex-column align-center">
|
<div class="d-flex flex-column align-center">
|
||||||
<Transition name="score-fade" mode="out-in">
|
<Transition name="score-fade" mode="out-in">
|
||||||
<span :key="scores.BlueRoundScore" class="v-label-round-score">Manche : {{ scores.BlueRoundScore }}</span>
|
<span :key="scores.BlueTotalScore" class="v-label-score">{{ scores.BlueRoundScore }}</span>
|
||||||
</Transition>
|
|
||||||
<Transition name="score-fade" mode="out-in">
|
|
||||||
<span :key="scores.BlueTotalScore" class="v-label-score">{{ scores.BlueTotalScore }}</span>
|
|
||||||
</Transition>
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</v-container>
|
</v-container>
|
||||||
<v-container class="score_div color-red">
|
<v-container class="score_div color-red">
|
||||||
<div class="d-flex flex-column align-center">
|
<div class="d-flex flex-column align-center">
|
||||||
<Transition name="score-fade" mode="out-in">
|
<Transition name="score-fade" mode="out-in">
|
||||||
<span :key="scores.RedRoundScore" class="v-label-round-score">Manche : {{ scores.RedRoundScore }}</span>
|
<span :key="scores.RedTotalScore" class="v-label-score">{{ scores.RedRoundScore }}</span>
|
||||||
</Transition>
|
|
||||||
<Transition name="score-fade" mode="out-in">
|
|
||||||
<span :key="scores.RedTotalScore" class="v-label-score">{{ scores.RedTotalScore }}</span>
|
|
||||||
</Transition>
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</v-container>
|
</v-container>
|
||||||
@@ -28,20 +22,14 @@
|
|||||||
<v-container class="score_div color-green">
|
<v-container class="score_div color-green">
|
||||||
<div class="d-flex flex-column align-center">
|
<div class="d-flex flex-column align-center">
|
||||||
<Transition name="score-fade" mode="out-in">
|
<Transition name="score-fade" mode="out-in">
|
||||||
<span :key="scores.GreenRoundScore" class="v-label-round-score">Manche : {{ scores.GreenRoundScore }}</span>
|
<span :key="scores.GreenTotalScore" class="v-label-score">{{ scores.GreenRoundScore }}</span>
|
||||||
</Transition>
|
|
||||||
<Transition name="score-fade" mode="out-in">
|
|
||||||
<span :key="scores.GreenTotalScore" class="v-label-score">{{ scores.GreenTotalScore }}</span>
|
|
||||||
</Transition>
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</v-container>
|
</v-container>
|
||||||
<v-container class="score_div color-yellow">
|
<v-container class="score_div color-yellow">
|
||||||
<div class="d-flex flex-column align-center">
|
<div class="d-flex flex-column align-center">
|
||||||
<Transition name="score-fade" mode="out-in">
|
<Transition name="score-fade" mode="out-in">
|
||||||
<span :key="scores.YellowRoundScore" class="v-label-round-score">Manche : {{ scores.YellowRoundScore }}</span>
|
<span :key="scores.YellowTotalScore" class="v-label-score">{{ scores.YellowRoundScore }}</span>
|
||||||
</Transition>
|
|
||||||
<Transition name="score-fade" mode="out-in">
|
|
||||||
<span :key="scores.YellowTotalScore" class="v-label-score">{{ scores.YellowTotalScore }}</span>
|
|
||||||
</Transition>
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</v-container>
|
</v-container>
|
||||||
@@ -56,7 +44,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
//import VideoPlayer from "@/components/VideoPlayer.vue"
|
|
||||||
import GameMedia from "@/components/GameMedia.vue"
|
import GameMedia from "@/components/GameMedia.vue"
|
||||||
import HidingOverlay from "@/components/HidingOverlay.vue"
|
import HidingOverlay from "@/components/HidingOverlay.vue"
|
||||||
import { onMounted, reactive } from 'vue';
|
import { onMounted, reactive } from 'vue';
|
||||||
@@ -64,9 +51,11 @@
|
|||||||
import config from '@/config.js'
|
import config from '@/config.js'
|
||||||
import quizStore from '@/store/quizStore';
|
import quizStore from '@/store/quizStore';
|
||||||
|
|
||||||
|
// Configuration MQTT
|
||||||
const mqttBrokerUrl = config.mqttBrokerUrl
|
const mqttBrokerUrl = config.mqttBrokerUrl
|
||||||
const client = mqtt.connect(mqttBrokerUrl)
|
const client = mqtt.connect(mqttBrokerUrl)
|
||||||
|
|
||||||
|
// Objet réactif pour stocker les scores des équipes
|
||||||
const scores = reactive({
|
const scores = reactive({
|
||||||
RedTotalScore: 0,
|
RedTotalScore: 0,
|
||||||
BlueTotalScore: 0,
|
BlueTotalScore: 0,
|
||||||
@@ -79,14 +68,17 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
// Variable réactive pour l'affichage du timer
|
||||||
const timerDisplay = ref('00:00');
|
const timerDisplay = ref('00:00');
|
||||||
|
|
||||||
|
// Fonction pour formater le temps en mm:ss
|
||||||
function formatTime(seconds) {
|
function formatTime(seconds) {
|
||||||
const mins = Math.floor(seconds / 60);
|
const mins = Math.floor(seconds / 60);
|
||||||
const secs = seconds % 60;
|
const secs = seconds % 60;
|
||||||
return `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
|
return `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fonction de gestion des messages MQTT reçus
|
||||||
function handleMessage(topic, message) {
|
function handleMessage(topic, message) {
|
||||||
let parsedMessage;
|
let parsedMessage;
|
||||||
try {
|
try {
|
||||||
@@ -96,6 +88,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mise à jour des scores si le message vient du topic 'game/score'
|
||||||
if (topic === 'game/score' && parsedMessage.TEAM) {
|
if (topic === 'game/score' && parsedMessage.TEAM) {
|
||||||
scores.RedTotalScore = parsedMessage.TEAM.Red.TotalScore
|
scores.RedTotalScore = parsedMessage.TEAM.Red.TotalScore
|
||||||
scores.BlueTotalScore = parsedMessage.TEAM.Blue.TotalScore
|
scores.BlueTotalScore = parsedMessage.TEAM.Blue.TotalScore
|
||||||
@@ -108,11 +101,13 @@
|
|||||||
scores.GreenRoundScore = parsedMessage.TEAM.Green.RoundScore
|
scores.GreenRoundScore = parsedMessage.TEAM.Green.RoundScore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mise à jour du timer si le message vient du topic 'game/timer'
|
||||||
if (topic === 'game/timer' && parsedMessage.time !== undefined) {
|
if (topic === 'game/timer' && parsedMessage.time !== undefined) {
|
||||||
timerDisplay.value = formatTime(parsedMessage.time);
|
timerDisplay.value = formatTime(parsedMessage.time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fonction utilitaire pour s'abonner à un topic MQTT
|
||||||
function subscribeToTopic(topic, callback) {
|
function subscribeToTopic(topic, callback) {
|
||||||
client.subscribe(topic)
|
client.subscribe(topic)
|
||||||
client.on('message', (receivedTopic, message) => { callback(receivedTopic.toString(), message.toString())
|
client.on('message', (receivedTopic, message) => { callback(receivedTopic.toString(), message.toString())
|
||||||
@@ -120,14 +115,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
// Initialisation du store du quiz
|
||||||
quizStore.actions.init();
|
quizStore.actions.init();
|
||||||
|
|
||||||
|
// Abonnement aux topics MQTT pour les scores et le timer
|
||||||
subscribeToTopic('game/score', (topic, message) => {
|
subscribeToTopic('game/score', (topic, message) => {
|
||||||
handleMessage(topic, message);
|
handleMessage(topic, message);
|
||||||
});
|
});
|
||||||
subscribeToTopic('game/timer', (topic, message) => {
|
subscribeToTopic('game/timer', (topic, message) => {
|
||||||
handleMessage(topic, message);
|
handleMessage(topic, message);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Demande de rafraîchissement des scores au chargement
|
||||||
|
// Cela permet de récupérer les scores actuels même après un rechargement de page
|
||||||
|
client.publish('game/score/request', '{}');
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -10,14 +10,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="score-main">
|
<div class="score-main">
|
||||||
<div class="team-score main-score">{{ scores.BlueRoundScore }}</div>
|
<Transition name="score-pop" mode="out-in">
|
||||||
|
<div :key="scores.BlueRoundScore" class="team-score main-score">{{ scores.BlueRoundScore }}</div>
|
||||||
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="score-cell cell-red color-red">
|
<div class="score-cell cell-red color-red">
|
||||||
<div class="score-content">
|
<div class="score-content">
|
||||||
<div class="score-main">
|
<div class="score-main">
|
||||||
<div class="team-score main-score">{{ scores.RedRoundScore }}</div>
|
<Transition name="score-pop" mode="out-in">
|
||||||
|
<div :key="scores.RedRoundScore" class="team-score main-score">{{ scores.RedRoundScore }}</div>
|
||||||
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
<div class="score-info info-right">
|
<div class="score-info info-right">
|
||||||
<div class="team-name">Rouge</div>
|
<div class="team-name">Rouge</div>
|
||||||
@@ -38,14 +42,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="score-main">
|
<div class="score-main">
|
||||||
<div class="team-score main-score">{{ scores.GreenRoundScore }}</div>
|
<Transition name="score-pop" mode="out-in">
|
||||||
|
<div :key="scores.GreenRoundScore" class="team-score main-score">{{ scores.GreenRoundScore }}</div>
|
||||||
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="score-cell cell-yellow color-yellow">
|
<div class="score-cell cell-yellow color-yellow">
|
||||||
<div class="score-content">
|
<div class="score-content">
|
||||||
<div class="score-main">
|
<div class="score-main">
|
||||||
<div class="team-score main-score">{{ scores.YellowRoundScore }}</div>
|
<Transition name="score-pop" mode="out-in">
|
||||||
|
<div :key="scores.YellowRoundScore" class="team-score main-score">{{ scores.YellowRoundScore }}</div>
|
||||||
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
<div class="score-info info-right">
|
<div class="score-info info-right">
|
||||||
<div class="team-name">Jaune</div>
|
<div class="team-name">Jaune</div>
|
||||||
@@ -132,6 +140,8 @@
|
|||||||
subscribeToTopic('game/timer', (topic, message) => {
|
subscribeToTopic('game/timer', (topic, message) => {
|
||||||
handleMessage(topic, message);
|
handleMessage(topic, message);
|
||||||
});
|
});
|
||||||
|
// Request score refresh
|
||||||
|
client.publish('game/score/request', '{}');
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
@@ -299,4 +309,34 @@
|
|||||||
.color-yellow {
|
.color-yellow {
|
||||||
background: linear-gradient(135deg, rgb(var(--v-theme-YellowBuzzer)), #5a5a1a);
|
background: linear-gradient(135deg, rgb(var(--v-theme-YellowBuzzer)), #5a5a1a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Score Pop Animation */
|
||||||
|
.score-pop-enter-active {
|
||||||
|
animation: pop-in 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
|
}
|
||||||
|
.score-pop-leave-active {
|
||||||
|
animation: pop-out 0.2s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pop-in {
|
||||||
|
0% {
|
||||||
|
transform: scale(0.5);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pop-out {
|
||||||
|
0% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1.5);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
84
VHard/affichage_score_kiosque.md
Normal file
84
VHard/affichage_score_kiosque.md
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# Documentation Déploiement Kiosque - Tableau de Score
|
||||||
|
|
||||||
|
Ce document décrit la configuration du serveur Fedora pour lancer automatiquement Google Chrome en mode plein écran au démarrage via un compositeur Wayland minimaliste (Cage).
|
||||||
|
|
||||||
|
## 1. Installation des dépendances
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo dnf install -y https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm
|
||||||
|
sudo dnf install -y cage
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Configuration de l'Autologin (Systemd)
|
||||||
|
|
||||||
|
Créer le fichier d'override pour que le serveur se connecte seul sur le TTY1 :
|
||||||
|
`sudo systemctl edit getty@tty1.service`
|
||||||
|
|
||||||
|
Coller le contenu suivant :
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[Service]
|
||||||
|
ExecStart=
|
||||||
|
ExecStart=-/sbin/agetty --autologin VOTRE_USER --noclear %I $TERM
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Script de lancement et Watchdog
|
||||||
|
|
||||||
|
Créer un script nommé `kiosk-waiter.sh` dans votre dossier personnel pour relancer Chrome s'il crash :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# kiosk-waiter.sh
|
||||||
|
|
||||||
|
URL="https://votre-url-quizz.com"
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
cage -- google-chrome-stable \
|
||||||
|
--kiosk \
|
||||||
|
--no-first-run \
|
||||||
|
--password-store=basic \
|
||||||
|
--ozone-platform=wayland \
|
||||||
|
--autoplay-policy=no-user-gesture-required \
|
||||||
|
--disable-component-update \
|
||||||
|
"$URL"
|
||||||
|
|
||||||
|
echo "Chrome s'est arrêté. Relancement dans 2 secondes..."
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
*N'oubliez pas : `chmod +x ~/kiosk-waiter.sh*`
|
||||||
|
|
||||||
|
## 4. Configuration Zsh (`~/.zlogin`)
|
||||||
|
|
||||||
|
Ajouter ces lignes à la fin de votre fichier `~/.zlogin` pour déclencher l'affichage uniquement sur le port HDMI physique (TTY1) :
|
||||||
|
|
||||||
|
```zsh
|
||||||
|
# Empêcher la mise en veille de l'écran
|
||||||
|
setterm --blank 0 --powersave off --powerdown 0
|
||||||
|
|
||||||
|
if [[ -z "$DISPLAY" && "$XDG_VTNR" -eq 1 ]]; then
|
||||||
|
export MOZ_ENABLE_WAYLAND=1
|
||||||
|
export XDG_SESSION_TYPE=wayland
|
||||||
|
|
||||||
|
# Lancement du script de monitoring
|
||||||
|
exec ~/kiosk-waiter.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Debug et Commandes utiles
|
||||||
|
|
||||||
|
* **Relancer le navigateur à distance (SSH) :**
|
||||||
|
`pkill -u $USER cage` (Le script de boucle le relancera instantanément).
|
||||||
|
* **Vérifier les logs :**
|
||||||
|
`journalctl -u getty@tty1.service`
|
||||||
|
* **Forcer l'arrêt :**
|
||||||
|
Supprimer temporairement l'appel dans `~/.zlogin` ou tuer le script `kiosk-waiter.sh`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Note : Si vous utilisez Podman pour le reste du projet (Vulture), ce setup "Bare Metal" pour l'affichage garantit une latence minimale pour les animations du tableau de score.*
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
// 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,
|
|
||||||
tiltAddConfirmed: false,
|
|
||||||
tiltRemoveConfirmed: false,
|
|
||||||
tiltIgnored: false,
|
|
||||||
unlockConfirmation: false,
|
|
||||||
tiltUpdateAdd: false,
|
|
||||||
tiltUpdateRemove: 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('vulture/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('vulture/buzzer/activity') && payload.buzzer_id === 1) {
|
|
||||||
testResults.buzzerActivity = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (topic.startsWith(`vulture/buzzer/confirmation/1`) && payload.status === "received") {
|
|
||||||
testResults.confirmationReceived = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (topic === 'vulture/buzzer/status' && payload.status === "blocked") {
|
|
||||||
testResults.statusBlocked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (topic === 'vulture/buzzer/status' && payload.status === "unblocked") {
|
|
||||||
testResults.statusUnblocked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (topic.startsWith(`vulture/buzzer/tilt/confirmation/2`) && payload.status === "received" && payload.action === "add") {
|
|
||||||
testResults.tiltAddConfirmed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (topic.startsWith(`vulture/buzzer/tilt/confirmation/2`) && payload.status === "received" && payload.action === "remove") {
|
|
||||||
testResults.tiltRemoveConfirmed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (topic === `vulture/buzzer/tilt/ignored/2` && payload.status === "tilt_ignored") {
|
|
||||||
testResults.tiltIgnored = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (topic === 'vulture/buzzer/status' && payload.status === "tilt_update") {
|
|
||||||
// Check for tilt update with added buzzer
|
|
||||||
if (payload.tilt_buzzers.includes(2) && payload.message.includes("added")) {
|
|
||||||
testResults.tiltUpdateAdd = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for tilt update with removed buzzer
|
|
||||||
if (!payload.tilt_buzzers.includes(2) && payload.message.includes("removed")) {
|
|
||||||
testResults.tiltUpdateRemove = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (topic === 'vulture/buzzer/unlock/confirmation' && payload.status === "received") {
|
|
||||||
testResults.unlockConfirmation = 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('vulture/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('vulture/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('vulture/buzzer/tilt', JSON.stringify({
|
|
||||||
buzzer_id: 2,
|
|
||||||
status: "add"
|
|
||||||
}));
|
|
||||||
}, 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('vulture/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('vulture/buzzer/tilt', JSON.stringify({
|
|
||||||
buzzer_id: 2,
|
|
||||||
status: "remove"
|
|
||||||
}));
|
|
||||||
}, 2500);
|
|
||||||
|
|
||||||
// 6. Unlock buzzers to reset state
|
|
||||||
setTimeout(() => {
|
|
||||||
console.log('[TEST] Unlocking buzzers...');
|
|
||||||
client.publish('vulture/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 add confirmed for buzzer 2: ${testResults.tiltAddConfirmed ? 'PASSED' : 'FAILED'}`);
|
|
||||||
console.log(`6. Tilted buzzer press ignored: ${testResults.tiltIgnored ? 'PASSED' : 'FAILED'}`);
|
|
||||||
console.log(`7. Tilt status update sent (add): ${testResults.tiltUpdateAdd ? 'PASSED' : 'FAILED'}`);
|
|
||||||
console.log(`8. Tilt mode remove confirmed for buzzer 2: ${testResults.tiltRemoveConfirmed ? 'PASSED' : 'FAILED'}`);
|
|
||||||
console.log(`9. Tilt status update sent (remove): ${testResults.tiltUpdateRemove ? 'PASSED' : 'FAILED'}`);
|
|
||||||
console.log(`10. Unlock confirmation received: ${testResults.unlockConfirmation ? 'PASSED' : 'FAILED'}`);
|
|
||||||
client.end(); // End the MQTT connection
|
|
||||||
}, 4000);
|
|
||||||
}
|
|
||||||
@@ -13,7 +13,7 @@ const { mqttHost, hosts: { buzzers: { IP: buzzerIPs, MQTTconfig: { mqttTopic } }
|
|||||||
const client = mqtt.connect(mqttHost);
|
const client = mqtt.connect(mqttHost);
|
||||||
|
|
||||||
client.on('connect', () => {
|
client.on('connect', () => {
|
||||||
console.log(`Connecté au broker MQTT à ${mqttHost}`);
|
console.log(`[INFO] Connecté au broker MQTT à ${mqttHost}`);
|
||||||
|
|
||||||
// Fonction pour pinger les buzzers et publier l'état
|
// Fonction pour pinger les buzzers et publier l'état
|
||||||
const pingAndPublish = async () => {
|
const pingAndPublish = async () => {
|
||||||
@@ -24,9 +24,8 @@ client.on('connect', () => {
|
|||||||
|
|
||||||
// Publication du statut dans le topic MQTT
|
// Publication du statut dans le topic MQTT
|
||||||
client.publish(`${mqttTopic}`, JSON.stringify({ buzzer: buzzerName, ip, status }));
|
client.publish(`${mqttTopic}`, JSON.stringify({ buzzer: buzzerName, ip, status }));
|
||||||
console.log(`Ping ${buzzerName} (${ip}) - Status: ${status}`);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Erreur avec le buzzer ${buzzerName} (${ip}):`, error.message);
|
console.error(`[ERREUR] Erreur avec le buzzer ${buzzerName} (${ip}):`, error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -36,5 +35,5 @@ client.on('connect', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
client.on('error', (error) => {
|
client.on('error', (error) => {
|
||||||
console.error('Erreur de connexion au broker MQTT:', error.message);
|
console.error('[ERREUR] Erreur de connexion au broker MQTT:', error.message);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
"score": {
|
"score": {
|
||||||
"MQTTconfig": {
|
"MQTTconfig": {
|
||||||
"mqttScoreTopic": "game/score",
|
"mqttScoreTopic": "game/score",
|
||||||
"mqttScoreChangeTopic": "game/score/update"
|
"mqttScoreChangeTopic": "game/score/update",
|
||||||
|
"mqttScoreRequestTopic": "game/score/request"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"quizzcollector": {
|
"quizzcollector": {
|
||||||
@@ -27,4 +28,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,14 +33,14 @@ fs.access(filePath, fs.constants.F_OK, (err) => {
|
|||||||
// Le fichier existe, on le lit et on le parse en JSON
|
// Le fichier existe, on le lit et on le parse en JSON
|
||||||
fs.readFile(filePath, 'utf8', (err, data) => {
|
fs.readFile(filePath, 'utf8', (err, data) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error("Erreur de lecture du fichier :", err);
|
console.error("[ERREUR] Erreur de lecture du fichier :", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
global.jsonData = JSON.parse(data);
|
global.jsonData = JSON.parse(data);
|
||||||
console.log("Propriétés importées depuis le fichier JSON :");
|
console.log("[INFO] Propriétés importées depuis le fichier JSON :");
|
||||||
} catch (parseErr) {
|
} catch (parseErr) {
|
||||||
console.error("Erreur de parsing JSON :", parseErr);
|
console.error("[ERREUR] Erreur de parsing JSON :", parseErr);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -82,10 +82,10 @@ fs.access(filePath, fs.constants.F_OK, (err) => {
|
|||||||
|
|
||||||
fs.writeFile(newFilePath, JSON.stringify(initialContent, null, 2), (err) => {
|
fs.writeFile(newFilePath, JSON.stringify(initialContent, null, 2), (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error("Erreur de création du fichier :", err);
|
console.error("[ERREUR] Erreur de création du fichier :", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log(`Fichier JSON créé avec succès : ${newFilePath}`);
|
console.log(`[INFO] Fichier JSON créé avec succès : ${newFilePath}`);
|
||||||
// Mettre à jour ScoreFile et filePath
|
// Mettre à jour ScoreFile et filePath
|
||||||
|
|
||||||
// Charger les données initiales si nécessaire
|
// Charger les données initiales si nécessaire
|
||||||
@@ -99,14 +99,14 @@ fs.access(filePath, fs.constants.F_OK, (err) => {
|
|||||||
function updateTeamTotalScore(teamColor, points) {
|
function updateTeamTotalScore(teamColor, points) {
|
||||||
fs.readFile(filePath, 'utf8', (err, data) => {
|
fs.readFile(filePath, 'utf8', (err, data) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error("Erreur de lecture du fichier :", err);
|
console.error("[ERREUR] Erreur de lecture du fichier :", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const jsonData = JSON.parse(data);
|
const jsonData = JSON.parse(data);
|
||||||
// Vérifier si l'équipe existe
|
// Vérifier si l'équipe existe
|
||||||
if (!jsonData.TEAM.hasOwnProperty(teamColor)) {
|
if (!jsonData.TEAM.hasOwnProperty(teamColor)) {
|
||||||
console.error(`L'équipe ${teamColor} n'existe pas.`);
|
console.error(`[ERREUR] L'équipe ${teamColor} n'existe pas.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,18 +114,22 @@ function updateTeamTotalScore(teamColor, points) {
|
|||||||
|
|
||||||
// Mettre à jour le score
|
// Mettre à jour le score
|
||||||
jsonData.TEAM[teamColor].TotalScore += points;
|
jsonData.TEAM[teamColor].TotalScore += points;
|
||||||
console.log(`Le score total pour l'équipe ${teamColor} est de ${jsonData.TEAM[teamColor].TotalScore} points !`)
|
|
||||||
|
// Update global state
|
||||||
|
global.jsonData = jsonData;
|
||||||
|
|
||||||
|
console.log(`[INFO] Le score total pour l'équipe ${teamColor} est de ${jsonData.TEAM[teamColor].TotalScore} points !`)
|
||||||
// Enregistrer les modifications dans le fichier
|
// Enregistrer les modifications dans le fichier
|
||||||
client.publish(mqttScoreTopic, JSON.stringify(jsonData));
|
client.publish(mqttScoreTopic, JSON.stringify(jsonData));
|
||||||
fs.writeFile(filePath, JSON.stringify(jsonData, null, 2), (err) => {
|
fs.writeFile(filePath, JSON.stringify(jsonData, null, 2), (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error("Erreur lors de l'écriture du fichier :", err);
|
console.error("[ERREUR] Erreur lors de l'écriture du fichier :", err);
|
||||||
} else {
|
} else {
|
||||||
console.log(`Le score total de l'équipe ${teamColor} a été mis à jour avec succès dans le fichier json !`);
|
console.log(`[INFO] Le score total de l'équipe ${teamColor} a été mis à jour avec succès dans le fichier json !`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (parseErr) {
|
} catch (parseErr) {
|
||||||
console.error("Erreur de parsing JSON :", parseErr);
|
console.error("[ERREUR] Erreur de parsing JSON :", parseErr);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -136,26 +140,45 @@ const configPath = path.join(__dirname, '../config/configuration.json');
|
|||||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||||
|
|
||||||
// Extraction des informations de config
|
// Extraction des informations de config
|
||||||
const { mqttHost, services: { score: { MQTTconfig: { mqttScoreTopic, mqttScoreChangeTopic } } } } = config;
|
const { mqttHost, services: { score: { MQTTconfig: { mqttScoreTopic, mqttScoreChangeTopic, mqttScoreRequestTopic } } } } = config;
|
||||||
console.log("DEBUG: Config loaded from:", configPath);
|
console.log("------------------------------------------------------------------------------");
|
||||||
console.log("DEBUG: MQTT Host:", mqttHost);
|
console.log("[CONFIG] Configuration chargée depuis :", configPath);
|
||||||
console.log("DEBUG: Topics:", mqttScoreTopic, mqttScoreChangeTopic);
|
console.log("[CONFIG] Hôte MQTT :", mqttHost);
|
||||||
|
console.log("[CONFIG] Topics chargés :", mqttScoreTopic, mqttScoreChangeTopic, mqttScoreRequestTopic);
|
||||||
|
console.log("------------------------------------------------------------------------------");
|
||||||
|
|
||||||
// Connexion au broker MQTT
|
// Connexion au broker MQTT
|
||||||
const client = mqtt.connect(mqttHost);
|
const client = mqtt.connect(mqttHost);
|
||||||
|
|
||||||
client.on('connect', () => {
|
client.on('connect', () => {
|
||||||
console.log(`Connecté au broker MQTT à ${mqttHost}`);
|
console.log(`[INFO] Connecté au broker MQTT à ${mqttHost}`);
|
||||||
|
|
||||||
client.subscribe(mqttScoreChangeTopic, (err) => {
|
client.subscribe(mqttScoreChangeTopic, (err) => {
|
||||||
if (err) console.error('[ERROR] impossible de souscrire au topic de gestion du score total');
|
if (err) console.error('[ERREUR] impossible de souscrire au topic de gestion du score total');
|
||||||
else console.log(`[INFO] Souscription réalisée avec succès au topic ${mqttScoreChangeTopic}]`);
|
else console.log(`[INFO] Souscription réalisée avec succès au topic ${mqttScoreChangeTopic}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.subscribe(mqttScoreRequestTopic, (err) => {
|
||||||
|
if (err) console.error('[ERREUR] impossible de souscrire au topic de demande de score');
|
||||||
|
else console.log(`[INFO] Souscription réalisée avec succès au topic ${mqttScoreRequestTopic}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Gestion des messages entrants
|
// Gestion des messages entrants
|
||||||
client.on('message', (topic, message) => {
|
client.on('message', (topic, message) => {
|
||||||
|
// Gestion de la demande de score (REFRESH)
|
||||||
|
if (topic === mqttScoreRequestTopic) {
|
||||||
|
console.log(`[INFO] Demande de rafraîchissement des scores reçue sur ${topic}`);
|
||||||
|
if (global.jsonData) {
|
||||||
|
client.publish(mqttScoreTopic, JSON.stringify(global.jsonData));
|
||||||
|
console.log(`[INFO] Scores envoyés sur ${mqttScoreTopic}`);
|
||||||
|
} else {
|
||||||
|
console.warn("[INFO] Aucune donnée de score disponible pour le rafraîchissement");
|
||||||
|
}
|
||||||
|
return; // Fin du traitement pour ce message
|
||||||
|
}
|
||||||
|
|
||||||
let payload;
|
let payload;
|
||||||
let process;
|
let process;
|
||||||
let Team;
|
let Team;
|
||||||
@@ -167,7 +190,7 @@ client.on('message', (topic, message) => {
|
|||||||
// Analyse du message reçu
|
// Analyse du message reçu
|
||||||
payload = JSON.parse(message.toString());
|
payload = JSON.parse(message.toString());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`[ERROR] Invalid JSON message received on topic ${topic}: ${message.toString()}`);
|
console.error(`[ERREUR] Invalid JSON message received on topic ${topic}: ${message.toString()}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Vérifie que le payload est bien un objet
|
// Vérifie que le payload est bien un objet
|
||||||
@@ -202,7 +225,7 @@ client.on('message', (topic, message) => {
|
|||||||
if (!isNaN(change)) {
|
if (!isNaN(change)) {
|
||||||
updateTeamTotalScore(Team, change);
|
updateTeamTotalScore(Team, change);
|
||||||
} else {
|
} else {
|
||||||
console.error(`Action invalide : ${Action}`);
|
console.error(`[ERREUR] Action invalide : ${Action}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,7 +236,7 @@ client.on('message', (topic, message) => {
|
|||||||
function updateTeamScoreAbsolute(teamColor, totalScore, roundScore) {
|
function updateTeamScoreAbsolute(teamColor, totalScore, roundScore) {
|
||||||
fs.readFile(filePath, 'utf8', (err, data) => {
|
fs.readFile(filePath, 'utf8', (err, data) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error("Erreur de lecture du fichier :", err);
|
console.error("[ERREUR] Erreur de lecture du fichier :", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -232,26 +255,26 @@ function updateTeamScoreAbsolute(teamColor, totalScore, roundScore) {
|
|||||||
|
|
||||||
console.log(`Mise à jour absolue pour ${teamColor} -> Total: ${jsonData.TEAM[teamColor].TotalScore}, Round: ${jsonData.TEAM[teamColor].RoundScore}`);
|
console.log(`Mise à jour absolue pour ${teamColor} -> Total: ${jsonData.TEAM[teamColor].TotalScore}, Round: ${jsonData.TEAM[teamColor].RoundScore}`);
|
||||||
|
|
||||||
|
// Update global state
|
||||||
|
global.jsonData = jsonData;
|
||||||
|
|
||||||
client.publish(mqttScoreTopic, JSON.stringify(jsonData));
|
client.publish(mqttScoreTopic, JSON.stringify(jsonData));
|
||||||
fs.writeFile(filePath, JSON.stringify(jsonData, null, 2), (err) => {
|
fs.writeFile(filePath, JSON.stringify(jsonData, null, 2), (err) => {
|
||||||
if (err) console.error("Erreur d'écriture :", err);
|
if (err) console.error("[ERREUR] Erreur d'écriture :", err);
|
||||||
});
|
});
|
||||||
} catch (parseErr) {
|
} catch (parseErr) {
|
||||||
console.error("Erreur JSON :", parseErr);
|
console.error("[ERREUR] Erreur JSON :", parseErr);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
while (true) {
|
while (true) {
|
||||||
console.log("Boucle en arrière-plan");
|
|
||||||
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 2000)); // Pause de 2 secondes
|
await new Promise((resolve) => setTimeout(resolve, 2000)); // Pause de 2 secondes
|
||||||
//client.publish(mqttScoreTopic, JSON.stringify(global.jsonData));
|
//client.publish(mqttScoreTopic, JSON.stringify(global.jsonData));
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
client.on('error', (error) => {
|
client.on('error', (error) => {
|
||||||
console.error('Erreur de connexion au broker MQTT:', error.message);
|
console.error("[ERREUR] Erreur de connexion au broker MQTT:", error.message);
|
||||||
});
|
});
|
||||||
|
|
||||||
Reference in New Issue
Block a user