Skip to content

Unusable implementation of getStatuses on some printers like TM-m30iii #108

Description

@Schlumpf9

getStatuses() always rejects on devices that fragment the status response (e.g. TM-m30III over LAN)

Thanks for this library! Printer.getStatuses() is unusable against printers that return the four real-time status bytes across multiple
data events instead of one — which includes the Epson TM-m30III over LAN, where each status byte arrives in its own TCP packet.

Environment

  • @node-escpos/core@0.6.0
  • @node-escpos/network-adapter@0.0.1
  • Node 24
  • Hardware: Epson TM-m30III (LAN, port 9100) — validated live

Problem

getStatuses() sends the four DLE EOT queries, then reads only the first data event and rejects unless all four bytes are present
in that single chunk:

  // @node-escpos/core – getStatuses()
  // reads one 'data' event, then:
  //   buffer.length < 4  ->  reject

Real devices don't guarantee one packet. The TM-m30III sends the four status bytes as four separate data events (observed on the wire:
0x16, 0x12, 0x12, 0x12 in four packets). So the first event carries one byte, the length check fails, and getStatuses() always
rejects
— it can never succeed against this printer.

Repro

  const { Printer } = require('@node-escpos/core');
  const Network = require('@node-escpos/network-adapter').default;

  const printer = new Printer(new Network('<m30III-ip>', 9100, 5000));
  await new Promise((res, rej) => printer.adapter.open(e => e ? rej(e) : res()));

  await printer.getStatuses();
  // -> rejects; the first 'data' event has fewer than 4 bytes

Root cause

The reader resolves/rejects on the first data event rather than accumulating until the expected number of bytes has arrived.

Suggested fix

Accumulate bytes across data events until the expected count (4) is reached, with a timeout to bound the wait:

  // pseudocode
  const bytes = [];
  const onData = (buf) => {
      for (const b of buf) bytes.push(b);
      if (bytes.length >= 4) finish(resolve, bytes.slice(0, 4));
  };
  const timer = setTimeout(() => finish(reject, new Error('status read timeout')), timeoutMs);
  // ...then send the DLE EOT queries

This makes getStatuses() robust to packet fragmentation while remaining correct for devices that do send all four bytes at once.

Workaround

For anyone hitting this: read the status bytes yourself with an accumulating listener (gather across data events until you have 4, then
parse) instead of getStatuses().

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions