Asking the printer about paper
Send three bytes and the printer says whether it has paper. It answers in three bytes too, and two different answers start with the same one — which is how a check that stops too early reports an empty roll on a full printer.
Three bytes out, three bytes back
10 04 01 is the question, and both printers answer it. It is worth wiring for:
a printer that can say "I am out of paper" is a device that can be left
unattended, and one that cannot is a device somebody has to watch.
10 04 01 is the question. Run it and watch what comes back — and note that this only works if the printer’s TXD is wired back to your board’s RX. With that wire missing the query is sent and nothing ever answers.The trap is the first byte. 1A opens the reply whether the answer is good news
or bad, and the verdict is in the second byte — FE for paper loaded, EF
for out of paper. Anything that decides on one byte gets it wrong half the time,
and gets it wrong in the direction that stops a working machine.
The label kit's library does exactly this: its noPaper() helper compares the
first byte with 1A and returns true. On a printer with a full roll it reports
an empty one. Read the three bytes yourself.
No answer is not the same as no paper
If the printer's TXD is not wired back to your board's RX, the query goes out and nothing ever returns. A sketch that treats a timeout as "out of paper" will sit there reporting an empty roll on a printer that is printing happily.
Three outcomes, not two: paper, no paper, and no answer. The third is a wiring fault and should be reported as one.
Flush before you ask
The printers also send packets nobody asked for — a notice when a job finishes, another when one fails. Those sit in the buffer, and the next status query reads the stale packet instead of the fresh reply. Emptying the buffer before sending the question costs one line and removes a whole class of confusing results.
The code
A status query once a second, with the whole three-byte reply read and decoded. It prints the bytes to the Serial Monitor as well as its verdict, so you can see what your own printer actually sends — take the roll out while it runs and watch the second byte change.
// Receipt printer wiring for this sketch.
//
// USB-C PD charger (9 V capable) -> base board PD TYPE-C
// base board PRINTER POWER -> printer POWER socket
// base board PRINTER DATA TTL -> printer TTL socket
//
// base board 3V3 MCU header -> ESP32-S3:
// TX -> GPIO16 (this board's RX - required here, not optional)
// RX -> GPIO17 (this board's TX)
// 3V3 -> 3V3
// GND -> GND
//
// Arduino IDE: Tools > Board "ESP32S3 Dev Module", Tools > USB CDC On Boot
// "Enabled". No library needed.
#define PRN_RX 16
#define PRN_TX 17
#define PRN_BAUD 9600
HardwareSerial printer(2);
enum Status { PAPER_OK, PAPER_OUT, NO_ANSWER };
Status askAboutPaper() {
while (printer.available()) printer.read(); // drop anything stale
printer.write(0x10); printer.write(0x04); printer.write(0x01);
printer.flush();
uint8_t reply[3];
uint8_t got = 0;
unsigned long started = millis();
while (got < 3 && millis() - started < 1000) {
if (printer.available()) reply[got++] = printer.read();
}
if (got < 3) return NO_ANSWER;
Serial.printf("reply: %02X %02X %02X\n", reply[0], reply[1], reply[2]);
// The first byte opens both answers. The second one carries the verdict.
if (reply[0] == 0x1A && reply[1] == 0xFE && reply[2] == 0x23) return PAPER_OK;
if (reply[0] == 0x1A && reply[1] == 0xEF && reply[2] == 0x23) return PAPER_OUT;
if (reply[0] == 0x1A && reply[1] == 0xFC && reply[2] == 0x6E) return PAPER_OUT;
return NO_ANSWER;
}
void setup() {
Serial.begin(115200);
printer.begin(PRN_BAUD, SERIAL_8N1, PRN_RX, PRN_TX);
delay(500);
printer.write(0x1B); printer.write(0x40);
}
void loop() {
switch (askAboutPaper()) {
case PAPER_OK: Serial.println("paper loaded"); break;
case PAPER_OUT: Serial.println("out of paper"); break;
case NO_ANSWER: Serial.println("no answer - check the RX wire"); break;
}
delay(1000);
}This needs the return wire. The printer's TXD has to reach your board's RX or the query goes out and nothing ever comes back, which this sketch reports as no answer rather than as no paper. That distinction is the point of the whole article.
When it does not work
Printing only needs one wire; asking needs two. The printer's TXD must reach your board's RX pin. Without it the query goes out and nothing comes back, and a sketch that treats silence as out-of-paper will report an empty roll forever.
Read all three bytes. The reply 1A FE 23 means paper is loaded and 1A EF 23 means it is not, so a check that looks only at the first byte and treats 1A as empty gets the answer backwards half the time. Decide on the second byte.
It compares the first byte of the reply with 1A and calls that out-of-paper, but 1A opens both replies. Prefer your own three-byte read, as in the sketch here, or treat the library's result as a prompt to check rather than as an answer.
The printer sends its own unsolicited packets after a job — a print-finished or a print-failed notice — and those are still sitting in the buffer when the next query goes out, so the reply you read is the old packet. Flush anything waiting before you ask, which is what the first line of the function does.
Four silences that look identical from the sketch, and the single observation that tells each one apart.
When nothing prints →Edit this page — content/books/thermal-printer/asking-about-paper.mdx
Questions about this product
See what other owners have asked, and read their solutions.
This page covers several products. Choose yours to see the right discussions.
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.