see all /posts

Messaggini su scontrini

2026-08-28

Qualche giorno fa ho fatto un esperimento, ho messo online una pagina dove scrivevi un messaggio e lo vedevo uscire su carta da una stampante termica.

Devo dire che ha avuto un discreto successo, ho ricevuto un sacco di messaggini e qualcunǝ mi ha chiesto dettagli su come ricreare un progetto simile perciò ecco il post!

Ingredienti#

Prima di tutto procurati una stampante termica, la mia è una Nyear NP100, una stampante termica ESC/POS, ovvero che segue lo standard Epson per stampanti, in una variante adatta ai POS. Questo è molto d'aiuto, se non addirittura fondamentale, perché, essendo uno standard piuttosto diffuso, è molto facile trovare mezzi che semplifichino la comunicazione.

Dopodiché serve un computer a cui collegarla, sarà quello che fa il lavoro pesante e dovrà rimanere acceso per stampare i messaggi. Io ho usato il mio server e il fatto che sia su Linux è stato molto d'aiuto.

Facoltativi, ma apprezzati, un dominio su cui esporre tutto il progetto e un'altra macchina, magari remota, dove ricevere i messaggi.

Preparazione#

Messo il grembiulino, si parte: collega la stampante al computer. Nel mio caso l'ho fatto via Bluetooth, quindi ho lanciato

bluetoothctl
power on
agent on
default-agent
scan on

per trovare la stampante, una volta trovata ho preso nota del MAC address e ho eseguito

scan off
pair AA:BB:CC:DD:EE:FF
trust AA:BB:CC:DD:EE:FF
exit

per collegarla al computer.

Scrivere e stampare è un altro paio di maniche: questo genere di stampanti di solito supporta le porte seriali, quindi ho usato sdptool per trovare il canale corretto (di solito è 1).

sdptool records AA:BB:CC:DD:EE:FF

con un risultato simile a questo

Service Name: Serial Port Server Port 1
Service RecHandle: 0x10000
Service Class ID List:
  "Serial Port" (0x1101)
Protocol Descriptor List:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    Channel: 1

che in sostanza significa che c'è l'emulazione di una porta seriale (RS-232) e che il canale RFCOMM su cui è esposto il servizio è 1.

Quindi non ci resta che lanciare rfcomm bind 0 AA:BB:CC:DD:EE:FF 1 per creare una porta seriale virtuale verso la stampante, permettendoci di stampare su /dev/rfcomm0.

Lanciando echo -e "Test di stampa\n\n\n" | sudo tee /dev/rfcomm0 dovresti ottenere la prima stampa su scontrino: fico!

Impiattare#

Ora che hai un server che ti permette di stampare messaggi, hai un sacco di possibilità su come renderlo accessibile a internet o a chi vuoi tu. Io ho fatto un piccolo container Docker che espone un'API Node.js in grado di stampare quel che riceve.

Il compose è molto semplice

services:
  thermal-print-api:
    build: .
    container_name: thermal-print-api
    restart: unless-stopped
    env_file:
      - .env
    ports:
      - "${PORT:-3000}:${PORT:-3000}"
    devices:
      - "${SERIAL_PORT:-/dev/rfcomm0}:${SERIAL_PORT:-/dev/rfcomm0}"

Nell'ultima riga indico al container dov'è la mia porta seriale così che la parte di API possa accedervi; sul server Node.js il comando per stampare si riduce a eseguire fs.writeFile(SERIAL_PORT, message).

Ovviamente ho aggiunto un livello di sanificazione per evitare di stampare messaggi troppo lunghi e per rimuovere caratteri speciali pericolosi, rimuovo tutti i caratteri che iniziano con 0x1B e 0x1D, ovvero la maggioranza dei comandi ESC/POS e anche i caratteri non stampabili 0x00-0x1F e 0x7F (sono NUL, tab, backspace, delete...) tranne \n (new line).

Evito di spiegare nel dettaglio il funzionamento di un'API Node.js, ma alla fine ho un servizio sul mio server che espone un comando /print a cui inviare un JSON con nel body il message da stampare.

Servire#

Tutti questi livelli di astrazione servono per evitare che chi manda messaggi abbia accesso diretto al mio server o alla stampante, per questo ho creato una pagina Next.js su cui inviare i messaggi (era ospitata su hello.maletta.space).

Usando una Server Action posso tenere nascosto all'utente finale l'indirizzo della mia API e renderla operabile solo attraverso la pagina predisposta, sulla quale eseguo un'altra sanificazione, parallela alla precedente, per accertarmi di non ricevere messaggi strani.

La pagina mostrava in diretta un'anteprima di cosa sarebbe stato stampato, così da permettere anche l'invio di ASCII art, il che mi ha permesso di ricevere nudes e animaletti (big win).

Assaggiare#

Con questo progettino ho tolto la polvere accumulata su un aggeggio apparentemente inutile che avevo dimenticato in fondo a un cassetto e per qualche ora ho sentito di nuovo il brivido di quando internet ti fa sentire connessǝ con un mondo gigantesco, ottenendone un riscontro nel mondo fisico, nel mio studio, su un pezzettino di carta da 38mm che custodirò gelosamente.

Infine, se anche te metti online qualcosa di simile fammelo sapere che voglio assolutamente mandarti un messaggio carino.

Comments

from livellosegreto.it