- Python 94.5%
- Shell 5.5%
| driver_sanei_sk1-311 | ||
| .env.example | ||
| .gitignore | ||
| env_loader.py | ||
| health_check.py | ||
| install_printer.sh | ||
| printer.py | ||
| qr_handler.py | ||
| README.md | ||
| redis_listener.py | ||
| requirements.txt | ||
| test_redis_integration.py | ||
| test_stampante.py | ||
| ticket-printer.service | ||
Sistema di Stampa Ticket - Sanei SK1-311
Sistema di stampa per ticket termici su stampante Sanei SK1-311 via USB. Progetto sviluppato per sostituire CUPS che presenta problemi con i driver obsoleti della stampante, utilizzando comunicazione USB diretta tramite driver Python personalizzato.
📋 Indice
- Caratteristiche
- Requisiti
- Installazione
- Configurazione
- Struttura del Progetto
- Utilizzo
- Funzionamento
- Test
- Risoluzione Problemi
✨ Caratteristiche
- Stampa diretta USB: Comunicazione diretta con la stampante Sanei SK1-311 senza passare per CUPS
- Generazione ticket: Creazione automatica di ticket con numero di coda, QR code e loghi personalizzati
- Gestione QR Code: Generazione e decodifica di QR code per i ticket
- Download logo dinamico: Scaricamento automatico dei loghi aziendali da URL
- Driver ESC/POS: Implementazione completa del protocollo ESC/POS per stampanti termiche
- Integrazione Redis: Listener pub/sub per ricezione e stampa automatica ticket in tempo reale
- Health-check HTTP: Endpoint
/healthe/statsper monitoraggio servizio - Servizio systemd: Auto-start al boot con restart automatico
- Retry automatico: Riconnessione automatica a Redis con backoff esponenziale
🔧 Requisiti
Sistema Operativo
- Linux (testato su Ubuntu/Debian)
- Python 3.8 o superiore
Dipendenze di Sistema
# libusb per la comunicazione USB
sudo apt install libusb-1.0-0-dev
# Ghostscript per il rendering PDF (opzionale ma raccomandato)
sudo apt install ghostscript
# Font TrueType per la generazione dei ticket
sudo apt install fonts-dejavu fonts-liberation
Python
Tutte le dipendenze Python sono specificate in requirements.txt.
📦 Installazione
1. Clona o scarica il progetto
cd /percorso/progetto/migrazione_cups_sanei
2. Crea un ambiente virtuale (raccomandato)
python3 -m venv venv
source venv/bin/activate
3. Installa le dipendenze
pip install -r requirements.txt
4. Installa il driver SK1 (modalità editable)
pip install -e driver_sanei_sk1-311/
Questo installerà il driver in modalità "editable", permettendo modifiche al codice senza doverlo reinstallare.
5. Configura i permessi USB
Per evitare errori di permesso (Access denied), crea una regola udev:
# Identifica VID/PID della stampante
lsusb | grep -i seiko
# Crea file di regole udev
sudo nano /etc/udev/rules.d/99-sk1.rules
Aggiungi questa riga (sostituisci XXXX e YYYY con VID e PID):
SUBSYSTEM=="usb", ATTR{idVendor}=="XXXX", ATTR{idProduct}=="YYYY", MODE="0666"
Oppure usa il manufacturer:
SUBSYSTEM=="usb", ATTRS{manufacturer}=="Seiko Instruments", MODE="0666"
Ricarica le regole:
sudo udevadm control --reload-rules
sudo udevadm trigger
In alternativa, aggiungi l'utente al gruppo lp:
sudo usermod -a -G lp $USER
# Logout e login per applicare le modifiche
⚙️ Configurazione
File .env
Crea un file .env nella root del progetto con le seguenti variabili:
# Timeout per il download dei loghi (in secondi)
TIMEOUT_LOGO=10
# Dominio base per i loghi
DOMAIN=https://esempio.com
# ID del sito cliente (per identificazione)
CUSTOMER_SITE_ID=123
# Altre configurazioni opzionali...
Il file .env viene caricato automaticamente all'avvio tramite il modulo env_loader.py.
📁 Struttura del Progetto
migrazione_cups_sanei/
│
├── README.md # Questo file
├── requirements.txt # Dipendenze Python del progetto principale
├── .env # Variabili d'ambiente (da creare)
│
├── env_loader.py # Caricamento automatico variabili d'ambiente
├── printer.py # Modulo principale per generazione e stampa ticket
├── qr_handler.py # Gestione QR code (generazione, decodifica, ridimensionamento)
├── redis_listener.py # Listener Redis pub/sub con auto-reconnect
├── health_check.py # Server HTTP health-check e statistiche
├── test_stampante.py # Script di test per verificare il funzionamento
├── test_redis_integration.py # Test integrazione Redis end-to-end
├── ticket-printer.service # Unit systemd per auto-start
├── install_service.sh # Script installazione servizio systemd
│
└── driver_sanei_sk1-311/ # Driver USB per stampante Sanei SK1-311
├── README.md # Documentazione dettagliata del driver
├── pyproject.toml # Configurazione packaging del driver
├── requirements.txt # Dipendenze del driver
├── CHANGELOG.md # Changelog del driver
├── base_test.py # Test base del driver
│
└── src/
└── sk1_driver/ # Package del driver
├── __init__.py # Inizializzazione e export principali
├── cli.py # Interfaccia command-line
├── sk1.py # Classe principale SK1Printer
├── command_builder.py # Builder per comandi ESC/POS
├── usb_utils.py # Utilities per comunicazione USB
├── pdf_utils.py # Rendering PDF per stampa
├── image_ops.py # Operazioni su immagini
└── temp_utils.py # Gestione file temporanei
Componenti Principali
1. env_loader.py
Carica automaticamente le variabili d'ambiente dal file .env all'import del modulo. Supporta fallback a .env.cups se .env non esiste.
2. printer.py
Modulo principale che gestisce:
- Generazione dell'immagine del ticket (usando PIL/Pillow)
- Download dei loghi da URL remoti
- Rendering del testo con font TrueType
- Integrazione QR code
- Invio comandi alla stampante tramite il driver SK1
Funzioni principali:
stampa_ticket(ticket_data): Funzione principale per stampare un ticketscarica_logo(logo_url): Download logo da URLdraw_centered_text(): Rendering testo centratoget_font(size): Ottiene font TrueType
3. qr_handler.py
Gestione completa dei QR code:
genera_qr_code(data): Genera un QR code da stringadecodifica_qr_code(qr_data): Decodifica QR da base64ridimensiona_qr_code(qr_image, dimensione): Ridimensiona QR code
4. test_stampante.py
Script standalone per testare la stampante con un ticket di esempio. Verifica:
- Presenza della stampante USB
- Permessi corretti
- Funzionamento completo della stampa
5. driver_sanei_sk1-311/
Driver Python completo per la stampante Sanei SK1-311:
- Implementazione protocollo ESC/POS
- Comunicazione USB diretta tramite PyUSB
- Supporto per stampa testo, immagini e PDF
- Ottimizzazioni per prestazioni (single-write, chunking)
- CLI per comandi rapidi
Consultare driver_sanei_sk1-311/README.md per documentazione dettagliata.
<EFBFBD> Integrazione Redis
Il sistema utilizza Redis pub/sub per ricevere e stampare automaticamente i ticket in tempo reale.
Come Funziona
Server Applicativo Redis Raspberry Pi
│ │ │
│── PUBLISH ────────>│ │
│ ticket:created │── messaggio ──────>│ redis_listener.py
│ {ticket JSON} │ │ ├─ filtra customer_site_id
│ │ │ ├─ genera immagine ticket
│ │ │ └─ stampa via USB (SK1-311)
Configurazione .env
# Redis
REDIS_HOST=10.0.11.4
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
REDIS_CHANNEL=ticket:created
# Filtro: solo ticket con questo site_id vengono stampati
CUSTOMER_SITE_ID=87
# Heartbeat log ogni N secondi
HEARTBEAT_INTERVAL=30
# Porta health-check HTTP (default: 8080)
HEALTH_CHECK_PORT=8080
Formato Messaggio Redis
Il server applicativo deve pubblicare un JSON sul canale ticket:created:
{
"ticket_id": "TKT-20260206-001",
"ticket_number": 42,
"queue_name": "Sportello Anagrafe",
"queue_code": "A",
"site_name": "Comune di Milano",
"customer_site_id": "87",
"official_logo_url": "/uploads/logo.png",
"qr_code": null,
"waiting_count": 3,
"date": "06/02/2026",
"time": "14:30"
}
Avvio Manuale
source venv/bin/activate
python redis_listener.py
Installazione come Servizio (auto-start al boot)
sudo bash install_service.sh
Comandi di gestione:
sudo systemctl status ticket-printer # Stato
sudo systemctl restart ticket-printer # Riavvio
sudo systemctl stop ticket-printer # Arresto
journalctl -u ticket-printer -f # Log in tempo reale
Health-Check e Monitoring
# Stato di salute
curl http://localhost:8080/health
# {"status": "ok", "redis": true, "printer": true, ...}
# Statistiche stampa
curl http://localhost:8080/stats
# {"uptime": "2:30:15", "tickets_ok": 47, "tickets_err": 0, ...}
Stati possibili:
- ok: Redis connesso e stampante disponibile
- degraded: solo uno dei due attivo
- down: nessuno dei due attivo
Test Integrazione
# Terminal 1: avvia il listener
python redis_listener.py
# Terminal 2: esegui test end-to-end
python test_redis_integration.py
Il test verifica: connessione Redis, pubblicazione ticket, filtro site_id, health-check e statistiche.
Comportamento Retry
- Connessione iniziale: massimo 5 tentativi con backoff esponenziale (1s, 2s, 4s, 8s, 16s)
- Disconnessione durante l'ascolto: riconnessione automatica infinita
- Servizio systemd: riavvio automatico dopo 10s in caso di crash
<EFBFBD>🚀 Utilizzo
Test Rapido della Stampante
Esegui lo script di test per verificare che tutto funzioni:
python test_stampante.py
Questo script:
- Verifica che la stampante sia collegata
- Crea un ticket di test
- Lo stampa
- Fornisce feedback sul risultato
Uso Programmatico
from printer import stampa_ticket
from datetime import datetime
# Prepara i dati del ticket
ticket_data = {
'ticket_id': 'ABC-123',
'ticket_number': 42,
'queue_name': 'Sportello 1',
'queue_code': 'A',
'site_name': 'Ufficio Centrale',
'customer_site_id': '001',
'official_logo_url': '/path/to/logo.png', # URL relativo o None
'qr_code': 'dati_qr_in_base64', # Base64 o None
'waiting_count': 5,
'date': datetime.now().strftime('%d/%m/%Y'),
'time': datetime.now().strftime('%H:%M')
}
# Stampa il ticket
success = stampa_ticket(ticket_data)
if success:
print("Ticket stampato con successo!")
else:
print("Errore durante la stampa")
Uso del Driver direttamente
from sk1_driver import SK1Printer, find_sk1_devices
# Trova la stampante
devices = find_sk1_devices()
if not devices:
raise SystemExit("Nessuna stampante SK1 trovata")
# Crea istanza del printer
printer = SK1Printer(left_mm=5, top_mm=5)
try:
# Apri connessione
printer.open(device=devices[0]["device"])
printer.init()
# Stampa testo
printer.print_text("Ciao Mondo!", bold=True, size="large", align="center")
printer.feed(2)
# Taglia carta
printer.cut(full=False)
finally:
printer.close()
Comandi CLI del Driver
Il driver include anche una CLI per operazioni rapide:
# Lista stampanti collegate
sk1-cli list
# Stampa di test
sk1-cli test --left-mm 5 --top-mm 5
# Stampa un PDF
sk1-cli print-pdf documento.pdf --width-mm 80 --left-mm 5
# Stampa un'immagine
sk1-cli print-image logo.png --width-mm 60 --align center
# Pulisci file temporanei
sk1-cli clean-temp
🔍 Funzionamento
Flusso di Stampa Ticket
- Ricezione Dati: I dati del ticket arrivano (es. tramite Redis pub/sub o chiamata diretta)
- Caricamento Configurazione:
env_loadercarica variabili d'ambiente - Preparazione Immagine:
- Crea canvas bianco (576px larghezza, ~203 DPI)
- Scarica logo se presente
- Genera o decodifica QR code
- Renderizza testo (numero coda, informazioni, data/ora)
- Conversione per Stampa:
- Converte immagine in bianco/nero 1-bit
- Ottimizza per stampante termica
- Invio alla Stampante:
- Apre connessione USB
- Invia comandi ESC/POS di inizializzazione
- Trasmette immagine del ticket
- Taglia la carta
- Chiude connessione
Protocollo ESC/POS
Il driver implementa i comandi standard ESC/POS:
- ESC @: Inizializzazione stampante
- GS L: Impostazione margine sinistro (hardware)
- ESC J: Feed linee con precisione
- **ESC ***: Stampa immagini in modalità bit
- GS V: Taglio carta (full o partial)
Ottimizzazioni
- Single-write mode: Invio dell'intera immagine in un'unica operazione USB per massima velocità
- Band optimization: Salto automatico delle bande bianche
- Chunking intelligente: Suddivisione dati in chunk ottimali per USB
- Hardware margins: Uso di margini hardware invece di padding software
Gestione Errori
Il sistema include gestione robusta degli errori:
- Retry automatici: In caso di disconnessione USB
- Fallback: Da single-write a chunked mode se necessario
- Timeout configurabili: Per operazioni USB e download
- Logging dettagliato: Per debugging
🧪 Test
Test Manuale Completo
# 1. Verifica che la stampante sia visibile
lsusb | grep -i seiko
# 2. Verifica permessi
sk1-cli list
# 3. Test di stampa semplice
sk1-cli test
# 4. Test con script Python
python test_stampante.py
Test di Resilienza (Listener/Servizio)
Esegui questi test con il listener attivo (manuale o via systemd):
| Scenario | Come simularlo | Cosa ti aspetti |
|---|---|---|
| Crash | sudo kill -9 $(pgrep -f redis_listener.py) |
Riparte entro 10s (systemd) |
| Rete giu | sudo ip link set wlan0 down per 30s, poi sudo ip link set wlan0 up |
Listener resta vivo, riprende da solo |
| Reboot soft | sudo reboot |
Riparte al boot |
| Hard reboot | Stacca corrente, riattacca | Riparte al boot, log mostra wait per time-sync |
Test del Driver Standalone
cd driver_sanei_sk1-311
python base_test.py
Verifica Configurazione
# Verifica che le variabili d'ambiente siano caricate
python -c "import env_loader; import os; print(os.environ.get('DOMAIN'))"
🔧 Risoluzione Problemi
Stampante non trovata
# Verifica collegamento USB
lsusb | grep -i seiko
# Verifica modulo kernel
lsmod | grep usb
# Se usblp è caricato, rimuovilo
sudo modprobe -r usblp
Errore "Access denied" (Errno 13)
# Verifica permessi
ls -l /dev/bus/usb/*/*
# Riconfigura udev (vedi sezione Installazione)
sudo nano /etc/udev/rules.d/99-sk1.rules
# Oppure aggiungi utente al gruppo
sudo usermod -a -G lp $USER
Errore "Resource busy"
# Rimuovi driver kernel usblp
sudo modprobe -r usblp
# Verifica che nessun altro processo stia usando la stampante
lsof | grep usb
Font non trovati
# Installa font
sudo apt install fonts-dejavu fonts-liberation
# Verifica installazione
fc-list | grep -i dejavu
Download logo fallito
- Verifica la variabile
DOMAINnel file.env - Verifica che
TIMEOUT_LOGOsia sufficientemente alto - Controlla la connessione internet
- Verifica che l'URL del logo sia corretto
Stampa lenta
- Usa modalità
single-write(default) - Riduci DPI dei PDF se necessario
- Verifica che Ghostscript sia installato per rendering veloce
- Controlla i timeout USB (
--usb-timeout-ms)
File temporanei accumulati
# Pulisci file temporanei PDF
sk1-cli clean-temp
# Pulisci e rimuovi directory
sk1-cli clean-temp --remove-dir
📚 Riferimenti
📝 Note
- Il sistema è ottimizzato per stampanti termiche da 80mm (72mm area stampabile)
- DPI standard: 203 (8 dots/mm)
- Supporta solo Linux per la comunicazione USB diretta
- CUPS non è utilizzato in questo progetto per problemi con driver obsoleti
- Il driver gestisce automaticamente il detach del kernel driver se necessario
🤝 Supporto
Per problemi o domande:
- Consulta la sezione Risoluzione Problemi
- Verifica i log dettagliati con
--verbosenella CLI - Controlla la documentazione del driver per dettagli tecnici
Versione: 2.0 Ultimo aggiornamento: Febbraio 2026