Skip to main content

Print Flow

The PC printer driver intentionally returns quickly from /print. Actual printer I/O happens in the background worker for the target printer.

End-to-End Flow

  1. Plato Console renders a receipt, ticket, or report to a PNG blob.
  2. The Console WIN_DRIVER adapter converts the image to black/white raster rows.
  3. Raster rows are split into chunks of 128 rows.
  4. Each chunk is encoded as an ESC/POS raster command and base64 encoded.
  5. Console sends POST /print with ip_address, port, and chunks.
  6. The driver wraps chunks with small delays, appends feed/cut, and optionally adds beep commands.
  7. The job is added to that printer’s BullMQ queue.
  8. The worker opens a TCP socket to the printer.
  9. The worker sends ESC/POS initialize, then each chunk.
  10. The worker closes the printer connection after the job.

Console Chunking

The Console adapter uses:
SettingValue
Driver typeWIN_DRIVER
Raster chunk height128 rows
Status timeout3000ms
Print request timeout5000ms
Cash drawer timeout3000ms
The browser sends already-encoded raster chunks. The driver does not render HTML.

Driver Chunk Wrapping

receipt-encoder.ts turns incoming chunks into job chunks:
  • Each incoming chunk is decoded from base64.
  • Each print chunk gets delayAfterMs: 25.
  • A feed and partial cut command is appended.
  • If beep is true, 18 beep commands are appended.
  • Each beep chunk has delayAfterMs: 150.

ESC/POS Commands

CommandBytesPurpose
Initialize1B 40Reset printer before each job.
Raster image1D 76 30 00 ...Sent by Console chunks.
Feed0A 0A 0A 0AFeed before cut.
Partial cutEncoder-generatedPartial paper cut.
Beep1B 42 01 01Beep command repeated by the driver.
Cash drawer1B 70 00 19 FAKick drawer pulse.

Socket Lifecycle

The current worker opens and closes the printer connection for each job.
ConstantValuePurpose
OPEN_ATTEMPT_TIMEOUT_MS2000Max time to open TCP socket.
CONNECTION_COOLDOWN_MS250Minimum delay after close before another open.
CLOSE_TIMEOUT_MS250Max wait for graceful close before destroy.
WRITE_TIMEOUT_MS6000Max time for one socket write.
There is also an idle-release timer of 3000ms, but the current process path closes the connection immediately after each successful job.

Failure Path

If opening or writing fails:
  1. The printer is marked offline.
  2. The socket is released/destroyed.
  3. The BullMQ job fails.
  4. BullMQ retries after queue.retryDelayMs.
  5. When the printer is reached again, delayed retry jobs are promoted unless they are intentionally scheduled with a future runAt.

Status Probing

POST /status can probe the printer only when queue work is not active. This avoids opening a probe socket while the same printer is busy printing.