Webhook de statut
Le photobooth transmet régulièrement son état à une adresse saisie par l'exploitant. Chaque message est un JSON contenant les mêmes valeurs que celles affichées par le portail de gestion à distance pour ce photobooth. Ce qu'en fait le destinataire ne dépend que de lui.
Il s'active dans l'espace d'administration « Éclairage et accessoires » > « Webhook de statut ». La gestion à distance n'est pas nécessaire : le webhook fonctionne aussi sur un photobooth sans portail.
À quoi cela sert#
- Afficher sur son propre site si le photobooth est en service et combien de photos ont déjà été prises.
- Tenir sa propre vue d'ensemble de plusieurs photobooths, dans un système existant.
- Être prévenu lorsque le papier s'épuise, que la batterie de l'appareil photo faiblit ou qu'un photobooth ne se signale plus - via la domotique ou une messagerie.
- Relever les compteurs, par exemple pour la facturation au client.
Webhook de statut ou déclencheurs ?#
Les deux transmettent vers l'extérieur, mais différemment :
| Webhook de statut | Déclencheurs pour programmes externes | |
|---|---|---|
| Quand | à intervalle fixe, toutes les 30 secondes par défaut | au moment où une étape a lieu |
| Quoi | l'état complet du photobooth | un événement isolé avec quelques valeurs |
| Vers | une adresse sur Internet ou sur le réseau | une adresse ou un programme sur le photobooth |
| Usage typique | affichage, surveillance, statistiques | éclairage, prises, scripts pendant la session |
Les deux peuvent être utilisés en même temps. Les déclencheurs sont décrits dans le chapitre Déclencheurs pour programmes externes.
Mise en place#
- Préparer un destinataire : une adresse qui accepte une requête POST avec du JSON et répond avec un statut entre 200 et 299. Les exemples ci-dessous suffisent.
- Dans l'espace « Webhook de statut », saisir l'adresse et enregistrer. La clé de signature est alors créée.
- Reprendre la clé avec « Copier » et la saisir chez le destinataire.
- Appuyer sur « Envoyer un message de test ». La réponse du destinataire et le contenu envoyé s'affichent en dessous.
- Activer « Utiliser le webhook de statut ». Le premier message part immédiatement, puis à l'intervalle réglé.
Ce qui arrive#
Chaque message est une requête POST avec ces en-têtes :
| En-tête | Contenu |
|---|---|
Content-Type | application/json; charset=utf-8 |
User-Agent | RAWCaptureBooth-Statuswebhook/<version> |
X-RAWCaptureBooth-Timestamp | Moment du message en secondes depuis 1970 (temps Unix) |
X-RAWCaptureBooth-Signature | sha256= suivi de la signature, voir plus bas |
Le contenu se présente ainsi (réduit à une imprimante et un buzzer) :
{
"schema_version": 1,
"sent_at": "2026-10-03T21:14:05+02:00",
"report_interval_seconds": 30,
"computer_name": "FOTOBOX-01",
"rawcapturebooth_version": "3.28.0",
"rawcapturebooth_latest_version": "3.28.0",
"cockpit_version": null,
"cockpit_latest_version": null,
"uptime": "5:12:03",
"network_status": "WLAN (Salle des fêtes)",
"connectivity_mode": "online",
"email_enabled": true,
"print_enabled": true,
"cloud_enabled": false,
"event_name": "Mariage Martin",
"sessions_total": 1843,
"sessions_since_start": 112,
"session_limit": 0,
"total_print_jobs": 2210,
"print_jobs_since_start": 131,
"print_limit": 300,
"ai_portraits_total": 0,
"ai_portraits_since_start": 0,
"ai_portrait_limit": 0,
"ai_portrait_warn_threshold": 0,
"last_session_at": "2026-10-03T19:13:40Z",
"last_capture_at": "2026-10-03T19:13:40Z",
"error_count": 0,
"last_error": null,
"last_error_at": null,
"cpu_used_percent": 23.5,
"memory_used_percent": 61.2,
"disk_free_gb": 182.4,
"disk_total_gb": 476.3,
"outbox_pending": 0,
"outbox_email_pending": 0,
"outbox_cloud_pending": 0,
"camera_battery_percent": null,
"camera_power_source": "ac",
"printers": [
{
"role": "print",
"mode": "single",
"name": "DP-DS620",
"available": true,
"state": "ready",
"queue_length": 0,
"issues": [],
"media_remaining": 268,
"media_capacity": 400,
"total_prints": 15320
}
],
"buzzers": [
{
"name": "Buzzer 1",
"connection": "connected",
"battery_level": 3,
"millivolt": 4010,
"seconds_since_press": 25
}
]
}
« Envoyer un message de test » affiche le contenu réel de son propre photobooth sous « Contenu envoyé ».
Les champs#
Un champ sans valeur vaut null. De nouveaux champs peuvent s'ajouter dans des versions ultérieures ; un destinataire ignore ce qu'il ne connaît pas. schema_version n'augmente que si la signification d'un champ change ou si un champ disparaît.
| Champ | Contenu |
|---|---|
schema_version | Structure du message, actuellement 1 |
sent_at | Moment de l'envoi à l'heure locale du photobooth, avec fuseau horaire |
report_interval_seconds | Intervalle de signalement en secondes |
computer_name | Nom de l'ordinateur du photobooth - l'identifiant lorsque plusieurs photobooths envoient au même destinataire |
rawcapturebooth_version | Version installée |
rawcapturebooth_latest_version | Dernière version publiée, vide tant que le photobooth n'a pas pu la récupérer |
cockpit_version, cockpit_latest_version | La même chose pour RAWCaptureBooth Cockpit, vide sans Cockpit |
uptime | Durée de fonctionnement depuis le démarrage du programme, par exemple 5:12:03 ou 1 day, 2:03:04 |
network_status | Situation réseau réelle : LAN, WLAN (nom du réseau), Online ou Offline |
connectivity_mode | Mode de fonctionnement réglé : online ou offline |
email_enabled, print_enabled, cloud_enabled | Si l'envoi d'e-mails, l'impression et l'envoi vers le cloud sont activés |
event_name | Nom de l'événement actif |
sessions_total, sessions_since_start | Sessions au total et depuis le démarrage du programme |
session_limit | Nombre maximal de sessions, 0 signifie sans limite |
total_print_jobs, print_jobs_since_start, print_limit | La même chose pour les impressions |
ai_portraits_total, ai_portraits_since_start, ai_portrait_limit | La même chose pour les portraits IA |
ai_portrait_warn_threshold | À partir de ce nombre de portraits IA, le photobooth avertit, 0 signifie désactivé |
last_session_at, last_capture_at | Moment de la dernière session et de la dernière prise de vue, généralement en UTC (se termine par Z) |
error_count | Erreurs depuis le démarrage du programme |
last_error, last_error_at | La dernière erreur sous forme de texte, avec son moment |
cpu_used_percent | Charge du processeur depuis le dernier message, vide dans le premier message après le démarrage |
memory_used_percent | Mémoire vive utilisée |
disk_free_gb, disk_total_gb | Espace libre et total du lecteur contenant les prises de vue |
outbox_pending | E-mails et envois en attente, par exemple sans réseau |
outbox_email_pending, outbox_cloud_pending | Dont e-mails et envois vers le cloud |
camera_battery_percent | Batterie de l'appareil photo en pourcentage, vide sur secteur ou si l'appareil ne la signale pas |
camera_power_source | battery, ac (adaptateur secteur) ou vide |
printers | Une entrée par imprimante, voir ci-dessous |
buzzers | Une entrée par buzzer sans fil, voir ci-dessous |
Une entrée dans printers :
| Champ | Contenu |
|---|---|
role | print (imprimante photo) ou strip (imprimante de bandelettes) |
mode | single (une imprimante) ou pool (pool d'imprimantes, avec en plus strategy) |
name | Nom de l'imprimante dans Windows |
available | Si l'imprimante est prête |
state | État, par exemple ready, printing, paused, error, offline ou unknown |
queue_length | Travaux dans la file d'attente |
issues | Liste des problèmes signalés, vide s'il n'y en a pas |
media_remaining, media_capacity | Consommable restant et capacité en feuilles, vide si l'imprimante ne les signale pas |
total_prints | Impressions sur toute la durée de vie, uniquement pour les imprimantes DNP |
Une entrée dans buzzers :
| Champ | Contenu |
|---|---|
name | Nom du buzzer sans fil |
connection | connected, sleeping, disconnected, never (jamais connecté) ou unavailable (Bluetooth indisponible) |
battery_level | Batterie en trois niveaux : 3 pleine, 2 à moitié, 1 faible, 0 inconnue |
millivolt | Tension de la batterie en millivolts |
seconds_since_press | Secondes depuis le dernier appui, vide s'il n'a pas encore été appuyé |
Vérifier la signature#
Chaque message est signé avec la clé de l'espace d'administration. Le destinataire recalcule la signature et n'accepte le message que si les deux correspondent :
- Lire le contenu tel qu'il arrive, sous forme d'octets - sans l'analyser d'abord comme JSON pour le réécrire ensuite.
- Assembler l'horodatage de
X-RAWCaptureBooth-Timestamp, un point et le contenu. - Calculer dessus un HMAC-SHA256 avec la clé, en chaîne hexadécimale, et placer
sha256=devant. - Comparer avec
X-RAWCaptureBooth-Signature, en temps constant. - Refuser les messages dont l'horodatage s'écarte de plus de cinq minutes de sa propre horloge. Ainsi, un message intercepté ne peut pas être rejoué plus tard.
« Générer une nouvelle clé » dans l'espace d'administration remplace la clé. Tant qu'elle n'a pas été saisie chez le destinataire, celui-ci refuse tout message.
Exemple : affichage sur son propre site#
Un site web ne peut pas recevoir un message à lui seul - il lui faut un petit script sur le serveur. Ce script PHP vérifie la signature et n'enregistre que les valeurs destinées au public dans un fichier fotobox-status.json :
<?php
// fotobox-webhook.php - à saisir comme adresse dans l'espace d'administration
$secret = 'SAISIR-LA-CLE-ICI';
$body = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_RAWCAPTUREBOOTH_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_RAWCAPTUREBOOTH_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $body, $secret);
if (!hash_equals($expected, $signature) || abs(time() - (int) $timestamp) > 300) {
http_response_code(401);
exit;
}
$status = json_decode($body, true);
if (!is_array($status)) {
http_response_code(400);
exit;
}
// Ne transmettre que ce qui a sa place sur le site
$public = [
'event_name' => $status['event_name'] ?? null,
'sessions_since_start' => $status['sessions_since_start'] ?? 0,
'report_interval_seconds' => $status['report_interval_seconds'] ?? 30,
'received_at' => time(),
];
file_put_contents(__DIR__ . '/fotobox-status.json', json_encode($public), LOCK_EX);
http_response_code(204);
Le site lit le fichier et décide lui-même si le photobooth est joignable :
<p id="fotobox">Photobooth : chargement …</p>
<script>
fetch('/fotobox-status.json', { cache: 'no-store' })
.then((response) => response.json())
.then((status) => {
const age = Date.now() / 1000 - status.received_at;
const online = age <= 2 * status.report_interval_seconds;
document.getElementById('fotobox').textContent = online
? 'Photobooth en service, ' + status.sessions_since_start + ' sessions depuis le démarrage'
: 'Photobooth actuellement injoignable';
});
</script>
Exemple : destinataire en Node.js#
Sans paquet supplémentaire, avec le module intégré http :
const http = require('http');
const crypto = require('crypto');
const SECRET = 'SAISIR-LA-CLE-ICI';
http.createServer((req, res) => {
const chunks = [];
req.on('data', (chunk) => chunks.push(chunk));
req.on('end', () => {
const body = Buffer.concat(chunks);
const timestamp = req.headers['x-rawcapturebooth-timestamp'] || '';
const signature = req.headers['x-rawcapturebooth-signature'] || '';
const expected = 'sha256=' + crypto.createHmac('sha256', SECRET)
.update(timestamp + '.').update(body).digest('hex');
const valid = signature.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
&& Math.abs(Date.now() / 1000 - Number(timestamp)) <= 300;
if (!valid) {
res.writeHead(401).end();
return;
}
const status = JSON.parse(body.toString('utf8'));
console.log(status.computer_name, status.event_name, status.sessions_total);
res.writeHead(204).end();
});
}).listen(8080);
Reconnaître qu'un photobooth ne se signale plus#
Un photobooth ne peut pas signaler lui-même qu'il est « hors ligne » - sans connexion, aucun message n'arrive non plus. Le destinataire retient donc le moment du dernier message. S'il n'en arrive plus pendant plus de deux intervalles (report_interval_seconds), le photobooth n'est pas joignable. Deux intervalles au lieu d'un absorbent un message isolé en retard.
Dépannage#
- « Envoyer un message de test » renvoie HTTP 401 ou 403 : Le destinataire refuse la signature. La clé est-elle correcte ? Le contenu brut est-il vérifié (voir plus haut) ? L'horloge du serveur est-elle à l'heure ?
- HTTP 404 : L'adresse est fausse - vérifier le chemin et le nom du fichier.
- « Redirection vers … » : L'adresse redirige, souvent de
http://vershttps://ou vers une adresse avecwww. Le photobooth ne suit pas les redirections ; saisir directement l'adresse de destination indiquée dans le message. - « Aucune réponse dans les 15 secondes » : Le destinataire n'est pas joignable ou répond trop lentement. Il devrait accepter le message et répondre immédiatement, au lieu de le traiter d'abord.
- Les messages arrivent moins souvent que réglé : Après un échec, le photobooth attend plus longtemps avant la tentative suivante - d'abord 15 secondes, puis chaque fois le double, au plus un quart d'heure. Au premier succès, l'intervalle réglé s'applique de nouveau. Le nombre de tentatives échouées d'affilée s'affiche dans l'espace sous « Test et état ».