Files
photoBooth/Opencode/scripts/script_print.sh
T
admin 8a70dea240
🚀 Deploy — JH Photomaton / 🔍 Vérification (push) Has been cancelled
🚀 Deploy — JH Photomaton / 🍓 Deploy sur le Pi (push) Has been cancelled
feat: détection erreurs imprimante via IPP direct (Selphy CP1300)
- script_print.sh : après lp, polling CUPS + sondage IPP direct ipp://IP:631/ipp/print
  Détecte input-tray-missing / media-empty en ~3-6s sans attendre le timeout CUPS
- printer_service.py : ajout _get_printer_ip(), _query_ipp_direct()
  _get_printer_status() utilise IPP pour état/raisons/encre (source de vérité)
- Timeout porté à 120s côté Python, fallback lpstat conservé
2026-07-17 17:08:00 +02:00

212 lines
8.0 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# =============================================================================
# script_print.sh - Impression photo pour photomaton
# =============================================================================
# Usage: script_print.sh "<filename>" "<media_type>" "<action_config_name>" "<copies>"
# Appele par photobooth-app via l'action Share "Impression"
#
# Imprimantes: Canon Selphy CP1300 x2 via WiFi (blanche + noire)
# Load balancing: utilise l'imprimante idle, sinon file d'attente sur la 1ere
#
# Sortie stdout parsable par Node-RED:
# PRINTED:<printer_name>:<copies> en cas de succes
# PRINT_ERROR:<printer_name> en cas d'erreur
# =============================================================================
set -uo pipefail
# --- Parametres ---
filename="${1:-}"
media_type="${2:-}"
action_config_name="${3:-}"
copies="${4:-1}"
# --- Noms des imprimantes CUPS (WiFi) ---
PRINTER_1="Selphy_Blanche_WiFi"
PRINTER_2="Selphy_Noire_WiFi"
# --- Options d'impression Selphy ---
# Mode raw : envoie le JPEG directement a la Selphy
# Postcard.Fullbleed : impression sans bordures
PRINT_OPTIONS="-o media=Postcard.Fullbleed -o raw"
# --- Calibrage bordures pour impression Fullbleed ---
# La Selphy deborde de quelques mm en mode Fullbleed
# On ajoute des marges noires pour compenser et eviter de couper la photo
# Valeurs calibrees pour Canon Selphy CP1300 via WiFi
PRINT_EXTENT="2114x1418"
PRINT_ROLL="-12+8"
# --- Logging ---
LOG_TAG="photomaton-print"
log_info() { logger -t "$LOG_TAG" "[INFO] $1"; echo "[INFO] $1"; }
log_error() { logger -t "$LOG_TAG" "[ERROR] $1"; echo "[ERROR] $1"; }
# --- Validation ---
if [ -z "$filename" ]; then
log_error "Aucun fichier specifie"
exit 1
fi
if [ ! -f "$filename" ]; then
log_error "Fichier introuvable: $filename"
exit 1
fi
if [ "$copies" -lt 1 ] || [ "$copies" -gt 3 ]; then
log_error "Nombre de copies invalide: $copies (doit etre entre 1 et 3)"
exit 1
fi
# --- Preparation de l'image pour impression ---
# Resize a 2000x1333 (ratio 3:2), ajout de marges noires pour compenser
# le debordement Fullbleed, puis decalage pour centrer correctement
filename_no_ext="${filename%.jpg}"
filename_print="${filename_no_ext}_print.jpg"
if command -v convert &>/dev/null; then
log_info "Preparation de l'image pour impression Fullbleed..."
if convert "$filename" \
-resize 2000x1333 \
-background black \
-gravity center \
-extent ${PRINT_EXTENT} \
-roll ${PRINT_ROLL} \
-quality 95 \
"$filename_print" 2>/dev/null; then
FILE_TO_PRINT="$filename_print"
log_info "Image preparee: $filename_print"
else
log_error "Echec de la preparation, impression de l'original"
FILE_TO_PRINT="$filename"
fi
else
log_error "ImageMagick (convert) non installe, impression de l'original"
FILE_TO_PRINT="$filename"
fi
# --- Selection de l'imprimante (load balancing) ---
printer_1_status=$(lpstat -p "$PRINTER_1" 2>/dev/null || echo "not found")
printer_2_status=$(lpstat -p "$PRINTER_2" 2>/dev/null || echo "not found")
SELECTED_PRINTER=""
if [[ "$printer_1_status" == *"idle"* ]]; then
SELECTED_PRINTER="$PRINTER_1"
log_info "Imprimante selectionnee: $PRINTER_1 (idle)"
elif [[ "$printer_2_status" == *"idle"* ]]; then
SELECTED_PRINTER="$PRINTER_2"
log_info "Imprimante selectionnee: $PRINTER_2 (idle)"
else
# Aucune idle : choisir celle avec le moins de jobs en attente
jobs_1=$(lpstat -o "$PRINTER_1" 2>/dev/null | wc -l)
jobs_2=$(lpstat -o "$PRINTER_2" 2>/dev/null | wc -l)
if [ "$jobs_1" -le "$jobs_2" ] 2>/dev/null; then
SELECTED_PRINTER="$PRINTER_1"
else
SELECTED_PRINTER="$PRINTER_2"
fi
log_info "Aucune imprimante idle, file d'attente sur: $SELECTED_PRINTER (jobs: P1=$jobs_1, P2=$jobs_2)"
fi
# --- Impression ---
log_info "Impression x${copies} sur $SELECTED_PRINTER: $FILE_TO_PRINT"
# Envoi du job CUPS et capture du job ID
job_output=$(lp -n "$copies" -d "$SELECTED_PRINTER" $PRINT_OPTIONS "$FILE_TO_PRINT" 2>&1)
lp_exit=$?
if [ $lp_exit -ne 0 ]; then
log_error "lp a echoue (exit $lp_exit): $job_output"
echo "PRINT_ERROR:${SELECTED_PRINTER}:lp_failed"
[ -f "$filename_print" ] && rm -f "$filename_print" 2>/dev/null
exit 1
fi
# Extraction du job ID (ex: "request id is Selphy_Blanche_WiFi-42 (1 file(s))")
JOB_ID=$(echo "$job_output" | grep -oE '[A-Za-z0-9_-]+-[0-9]+' | head -1)
log_info "Job CUPS accepte: ${JOB_ID:-inconnu}"
# Si le job ID est introuvable, comportement legacy (retour immediat)
if [ -z "$JOB_ID" ]; then
log_info "Job ID non extrait impression reputee reussie"
echo "PRINTED:${SELECTED_PRINTER}:${copies}"
[ "$FILE_TO_PRINT" = "$filename_print" ] && (sleep 30 && rm -f "$filename_print" 2>/dev/null) &
exit 0
fi
# --- Preparation du sondage IPP direct sur l'imprimante ---
# La Selphy CP1300 expose un serveur IPP natif (port 631, sans auth).
# Cela permet de detecter les erreurs physiques en quelques secondes
# sans attendre un timeout CUPS (qui ne rapporte pas les erreurs papier).
PRINTER_IP=$(lpstat -v "$SELECTED_PRINTER" 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
IPP_URI=""
IPP_TEST="/usr/share/cups/ipptool/get-printer-attributes.test"
if [ -n "$PRINTER_IP" ] && command -v ipptool &>/dev/null && [ -f "$IPP_TEST" ]; then
IPP_URI="ipp://${PRINTER_IP}:631/ipp/print"
log_info "Sondage IPP direct actif: $IPP_URI"
else
log_info "Sondage IPP desactive (IP=${PRINTER_IP:-inconnu}, ipptool=$(command -v ipptool || echo absent))"
fi
# Mots-cles d'erreur dans printer-state-reasons
IPP_ERROR_REASONS="input-tray-missing|media-empty|media-needed|marker-supply-empty|cover-open|door-open|offline-report"
# --- Suivi du job CUPS (attend la completion physique) ---
MAX_WAIT=90 # secondes max (Selphy CP1300 imprime en ~47s)
POLL_INTERVAL=3
elapsed=0
log_info "Suivi du job CUPS (max ${MAX_WAIT}s)..."
while [ $elapsed -lt $MAX_WAIT ]; do
sleep $POLL_INTERVAL
elapsed=$((elapsed + POLL_INTERVAL))
# 1. Succes : job dans la liste des jobs termines par CUPS
if lpstat -W completed 2>/dev/null | grep -q "^${JOB_ID} "; then
log_info "Job $JOB_ID termine avec succes (${elapsed}s)"
echo "PRINTED:${SELECTED_PRINTER}:${copies}"
[ "$FILE_TO_PRINT" = "$filename_print" ] && rm -f "$filename_print" 2>/dev/null
exit 0
fi
# 2. Sondage IPP direct (detecte papier absent, capot ouvert, etc. en ~3s)
if [ -n "$IPP_URI" ]; then
ipp_reasons=$(ipptool -tv "$IPP_URI" "$IPP_TEST" 2>/dev/null \
| grep "printer-state-reasons" | head -1)
if echo "$ipp_reasons" | grep -qiE "$IPP_ERROR_REASONS"; then
reason=$(echo "$ipp_reasons" | grep -oiE "$IPP_ERROR_REASONS" | head -1)
log_error "Erreur imprimante detectee via IPP: $reason (${elapsed}s)"
cancel "$JOB_ID" 2>/dev/null || true
echo "PRINT_ERROR:${SELECTED_PRINTER}:${reason}"
[ -f "$filename_print" ] && rm -f "$filename_print" 2>/dev/null
exit 1
fi
fi
# 3. Fallback CUPS : imprimante stoppee cote CUPS
printer_state=$(lpstat -p "$SELECTED_PRINTER" 2>/dev/null || true)
if echo "$printer_state" | grep -qiE "stopped|disabled"; then
reason=$(lpstat -l -p "$SELECTED_PRINTER" 2>/dev/null \
| grep -i "Reason:" | head -1 \
| sed 's/.*Reason:[[:space:]]*//' | xargs)
log_error "Imprimante $SELECTED_PRINTER stoppee (CUPS): ${reason:-stopped} (${elapsed}s)"
cancel "$JOB_ID" 2>/dev/null || true
echo "PRINT_ERROR:${SELECTED_PRINTER}:${reason:-stopped}"
[ -f "$filename_print" ] && rm -f "$filename_print" 2>/dev/null
exit 1
fi
log_info "Impression en cours... (${elapsed}s / ${MAX_WAIT}s)"
done
# Timeout : annule le job CUPS
log_error "Timeout impression apres ${MAX_WAIT}s (job: $JOB_ID)"
cancel "$JOB_ID" 2>/dev/null || true
echo "PRINT_ERROR:${SELECTED_PRINTER}:timeout_${MAX_WAIT}s"
[ -f "$filename_print" ] && rm -f "$filename_print" 2>/dev/null
exit 1