Zum Inhalt
RAWCaptureBooth Manuale d'uso
Versione 3.29.0

Webhook di stato

La cabina invia a intervalli regolari il proprio stato a un indirizzo inserito dal gestore. Ogni messaggio è un JSON con gli stessi valori che il portale di gestione remota mostra per questa cabina. Cosa farne lo decide il destinatario.

Si attiva nell'area di amministrazione « Luci e accessori » > « Webhook di stato ». La gestione remota non è necessaria: il webhook funziona anche su una cabina senza portale.

A cosa serve#

  • Mostrare sul proprio sito se la cabina è in funzione e quante foto sono già state scattate.
  • Tenere una propria panoramica di più cabine, in un sistema già esistente.
  • Ricevere un avviso quando la carta sta finendo, la batteria della fotocamera cala o una cabina non si fa più sentire - tramite domotica o una chat.
  • Registrare i contatori, ad esempio per la fatturazione al cliente.

Webhook di stato o attivatori?#

Entrambi inviano verso l'esterno, ma in modo diverso:

Webhook di statoAttivatori per programmi esterni
Quandoa intervallo fisso, di default ogni 30 secondinel momento in cui avviene un passaggio
Cosalo stato completo della cabinaun singolo evento con pochi valori
Doveun indirizzo su Internet o in reteun indirizzo o un programma sulla cabina
Uso tipicovisualizzazione, monitoraggio, statisticheluci, prese, script durante la sessione

Si possono usare entrambi contemporaneamente. Gli attivatori sono descritti nel capitolo Attivatori per programmi esterni.

Configurazione#

  1. Predisporre un destinatario: un indirizzo che accetti una richiesta POST con JSON e risponda con uno stato tra 200 e 299. Gli esempi più sotto bastano.
  2. Nell'area « Webhook di stato » inserire l'indirizzo e salvare. Viene così creata la chiave per la firma.
  3. Prendere la chiave con « Copia » e inserirla presso il destinatario.
  4. Premere « Invia messaggio di prova ». Sotto compaiono la risposta del destinatario e il contenuto inviato.
  5. Attivare « Usa il webhook di stato ». Il primo messaggio parte subito, poi all'intervallo impostato.

Cosa arriva#

Ogni messaggio è una richiesta POST con queste intestazioni:

IntestazioneContenuto
Content-Typeapplication/json; charset=utf-8
User-AgentRAWCaptureBooth-Statuswebhook/<versione>
X-RAWCaptureBooth-TimestampMomento del messaggio in secondi dal 1970 (tempo Unix)
X-RAWCaptureBooth-Signaturesha256= seguito dalla firma, vedi sotto

Il contenuto ha questo aspetto (ridotto a una stampante e 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 (Sala feste)",
  "connectivity_mode": "online",
  "email_enabled": true,
  "print_enabled": true,
  "cloud_enabled": false,
  "event_name": "Matrimonio Rossi",
  "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
    }
  ]
}

« Invia messaggio di prova » mostra il contenuto reale della propria cabina sotto « Contenuto inviato ».

I campi#

Un campo senza valore è null. Nelle versioni successive possono aggiungersi nuovi campi; un destinatario ignora ciò che non conosce. schema_version aumenta solo se cambia il significato di un campo o se un campo viene eliminato.

CampoContenuto
schema_versionStruttura del messaggio, attualmente 1
sent_atMomento dell'invio nell'ora locale della cabina, con fuso orario
report_interval_secondsIntervallo di segnalazione in secondi
computer_nameNome del computer della cabina - l'identificativo quando più cabine inviano allo stesso destinatario
rawcapturebooth_versionVersione installata
rawcapturebooth_latest_versionUltima versione pubblicata, vuoto finché la cabina non ha potuto recuperarla
cockpit_version, cockpit_latest_versionLo stesso per RAWCaptureBooth Cockpit, vuoto senza Cockpit
uptimeTempo di funzionamento dall'avvio del programma, ad esempio 5:12:03 o 1 day, 2:03:04
network_statusSituazione di rete effettiva: LAN, WLAN (nome della rete), Online o Offline
connectivity_modeModalità di funzionamento impostata: online o offline
email_enabled, print_enabled, cloud_enabledSe invio e-mail, stampa e caricamento nel cloud sono attivi
event_nameNome dell'evento attivo
sessions_total, sessions_since_startSessioni in totale e dall'avvio del programma
session_limitNumero massimo di sessioni, 0 significa nessun limite
total_print_jobs, print_jobs_since_start, print_limitLo stesso per le stampe
ai_portraits_total, ai_portraits_since_start, ai_portrait_limitLo stesso per i ritratti IA
ai_portrait_warn_thresholdDa questo numero di ritratti IA la cabina avvisa, 0 significa disattivato
last_session_at, last_capture_atMomento dell'ultima sessione e dell'ultimo scatto, di solito in UTC (termina con Z)
error_countErrori dall'avvio del programma
last_error, last_error_atL'ultimo errore come testo, con il suo momento
cpu_used_percentCarico del processore dall'ultimo messaggio, vuoto nel primo messaggio dopo l'avvio
memory_used_percentMemoria occupata
disk_free_gb, disk_total_gbSpazio libero e totale dell'unità con gli scatti
outbox_pendingE-mail e caricamenti in attesa, ad esempio senza rete
outbox_email_pending, outbox_cloud_pendingDi cui e-mail e caricamenti nel cloud
camera_battery_percentBatteria della fotocamera in percentuale, vuoto con alimentatore o se la fotocamera non la segnala
camera_power_sourcebattery, ac (alimentatore) o vuoto
printersUna voce per stampante, vedi sotto
buzzersUna voce per buzzer wireless, vedi sotto

Una voce in printers:

CampoContenuto
roleprint (stampante foto) o strip (stampante per strisce)
modesingle (una stampante) o pool (pool di stampanti, con in più strategy)
nameNome della stampante in Windows
availableSe la stampante è pronta
stateStato, ad esempio ready, printing, paused, error, offline o unknown
queue_lengthLavori in coda
issuesElenco dei problemi segnalati, vuoto se non ce ne sono
media_remaining, media_capacityMateriale residuo e capacità in fogli, vuoto se la stampante non li segnala
total_printsStampe nell'intera vita della stampante, solo stampanti DNP

Una voce in buzzers:

CampoContenuto
nameNome del buzzer wireless
connectionconnected, sleeping, disconnected, never (mai connesso) o unavailable (Bluetooth non disponibile)
battery_levelBatteria in tre livelli: 3 piena, 2 a metà, 1 scarica, 0 sconosciuta
millivoltTensione della batteria in millivolt
seconds_since_pressSecondi dall'ultima pressione, vuoto se non ancora premuto

Verificare la firma#

Ogni messaggio è firmato con la chiave dell'area di amministrazione. Il destinatario ricalcola la firma e accetta il messaggio solo se le due coincidono:

  1. Leggere il contenuto così come arriva, come byte - senza prima interpretarlo come JSON e poi riscriverlo.
  2. Unire il timestamp di X-RAWCaptureBooth-Timestamp, un punto e il contenuto.
  3. Calcolare su questo un HMAC-SHA256 con la chiave, come stringa esadecimale, e anteporre sha256=.
  4. Confrontare con X-RAWCaptureBooth-Signature, in tempo costante.
  5. Rifiutare i messaggi il cui timestamp si discosta di più di cinque minuti dal proprio orologio. Così un messaggio intercettato non può essere reinviato in seguito.

« Genera nuova » nell'area di amministrazione sostituisce la chiave. Finché non è stata inserita presso il destinatario, questo rifiuta ogni messaggio.

Esempio: visualizzazione sul proprio sito#

Un sito web non può ricevere da solo un messaggio - serve un piccolo script sul server. Questo script PHP verifica la firma e salva in un file fotobox-status.json solo i valori destinati al pubblico:

<?php
// fotobox-webhook.php - da inserire come indirizzo nell'area di amministrazione
$secret = 'INSERIRE-QUI-LA-CHIAVE';

$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;
}

// Trasmettere solo ciò che va sul sito
$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);

Il sito legge il file e decide da sé se la cabina è raggiungibile:

<p id="fotobox">Cabina: caricamento …</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
      ? 'Cabina in funzione, ' + status.sessions_since_start + ' sessioni dall\'avvio'
      : 'Cabina al momento non raggiungibile';
  });
</script>

Esempio: destinatario in Node.js#

Senza pacchetti aggiuntivi, con il modulo integrato http:

const http = require('http');
const crypto = require('crypto');

const SECRET = 'INSERIRE-QUI-LA-CHIAVE';

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);

Riconoscere che una cabina non si fa più sentire#

Una cabina non può segnalare da sola di essere « offline » - senza connessione non arriva nemmeno alcun messaggio. Il destinatario memorizza quindi quando è arrivato l'ultimo messaggio. Se non ne arrivano per più di due intervalli (report_interval_seconds), la cabina non è raggiungibile. Due intervalli invece di uno assorbono un singolo messaggio in ritardo.

Risoluzione dei problemi#

  • « Invia messaggio di prova » restituisce HTTP 401 o 403: Il destinatario rifiuta la firma. La chiave è corretta? Viene verificato il contenuto grezzo (vedi sopra)? L'orologio del server è giusto?
  • HTTP 404: L'indirizzo è errato - controllare percorso e nome del file.
  • « Reindirizzamento a … »: L'indirizzo reindirizza, spesso da http:// a https:// o a un indirizzo con www. La cabina non segue i reindirizzamenti; inserire direttamente l'indirizzo di destinazione indicato nel messaggio.
  • « Nessuna risposta entro 15 secondi »: Il destinatario non è raggiungibile o risponde troppo lentamente. Dovrebbe accettare il messaggio e rispondere subito, invece di elaborarlo prima.
  • I messaggi arrivano meno spesso di quanto impostato: Dopo un errore la cabina attende più a lungo prima del tentativo successivo - prima 15 secondi, poi ogni volta il doppio, al massimo un quarto d'ora. Al primo successo torna a valere l'intervallo impostato. Quanti tentativi consecutivi sono falliti è indicato nell'area sotto « Test e stato ».

Aggiornato: 01.10.2026 · Versione 3.29.0