From 4bdd3f6dd8c2d0423c07c3a4422bdb6c51e119e3 Mon Sep 17 00:00:00 2001 From: FaezerWasTaken <123196189+FaezerWasTaken@users.noreply.github.com> Date: Tue, 19 Aug 2025 14:17:01 +0200 Subject: [PATCH 1/2] Update README.md European localization --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 03e449c..30bb010 100644 --- a/README.md +++ b/README.md @@ -39,11 +39,11 @@ This project is born from the idea of "bringing receipts" for the life you lead/ Affiliate links to grab the components (if you want to use them): -| Component | Amazon US | Amazon UK | AliExpress | -| --------------------------------- | ----------------------- | ----------------------- | ----------------------------------------- | -| Microcontroller (USB-C D1 Mini) | https://amzn.to/4h2zQYO | https://amzn.to/4gRFgFe | - | -| Thermal Printer (CSN-A4L) | https://amzn.to/4kr5ksq | - | https://s.click.aliexpress.com/e/_opjoNrw | -| Paper Rolls, BPA-free (57.5x30mm) | https://amzn.to/4kpOREP | https://amzn.to/44nqGCg | - | +| Component | Amazon US | Amazon UK | AliExpress | Europe | +| --------------------------------- | ----------------------- | ----------------------- | ----------------------------------------- | -------- | +| Microcontroller (USB-C D1 Mini) | https://amzn.to/4h2zQYO | https://amzn.to/4gRFgFe | - | https://amzn.eu/d/c7Gh3AX | +| Thermal Printer (CSN-A4L) | https://amzn.to/4kr5ksq | - | https://s.click.aliexpress.com/e/_opjoNrw | https://de.aliexpress.com/item/1005004083860562.html (TAKE TTL NOT RS232) | +| Paper Rolls, BPA-free (57.5x30mm) | https://amzn.to/4kpOREP | https://amzn.to/44nqGCg | - | hard to find | **Important Note (Thanks to the community for pointed this out!):** Do your own due diligence regarding thermal paper types - the thermal paper we handle everyday (e.g. through receipts from the grocery store, restaurants, takeaway, taxis, etc.) will contain BPA. When choosing your rolls for this, you should definitely go for BPA-free paper just to be on the safer side - the links provided are for BPA-free paper. If you can, go a step further and look for “phenol-free” paper. Three types that do not contain BPA or BPS and are competitively priced contain either ascorbic acid (vitamin C), urea-based Pergafast 201, or a technology without developers, Blue4est. From df123ff0aaf4075a898807784854b18f2b458683 Mon Sep 17 00:00:00 2001 From: FaezerWasTaken <123196189+FaezerWasTaken@users.noreply.github.com> Date: Tue, 19 Aug 2025 14:18:54 +0200 Subject: [PATCH 2/2] Update firmware v1.ino MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Orientation reliability - Added ensureUpsideDown(): sends ESC { 1 to enforce 180° rotation. - Called ensureUpsideDown() at the start of printReceipt() and printServerInfo(). - Added a priming newline right after ESC { 1 in initializePrinter() to prevent the first command/character from being dropped on some printers. Text input & web UI - Increased form limit to 250 characters: * -
200 characters left
+
250 characters left
@@ -340,16 +342,30 @@ void initializePrinter() { // Enable 180° rotation (which also reverses the line order) printer.write(0x1B); printer.write('{'); printer.write(0x01); // ESC { 1 + + // Prime a newline so the first real command/char isn't dropped + printer.write('\n'); + delay(20); Serial.println("Printer initialized"); } +// Force upside-down mode; resend cmd to survive dropped first byte +void ensureUpsideDown() { + printer.write(0x1B); printer.write('{'); printer.write(0x01); // ESC { 1 + delay(10); +} + void printReceipt() { + ensureUpsideDown(); // ensure orientation before each job Serial.println("Printing receipt..."); // Print wrapped message first (appears at bottom after rotation) printWrappedUpsideDown(currentReceipt.message); + // Insert a blank line before the date for an easier tear line + printLine(""); // blank line + // Print header last (appears at top after rotation) setInverse(true); printLine(currentReceipt.timestamp); @@ -362,6 +378,7 @@ void printReceipt() { } void printServerInfo() { + ensureUpsideDown(); // ensure orientation before this job Serial.println("=== Server Info ==="); Serial.print("Local IP: "); Serial.println(WiFi.localIP()); @@ -389,6 +406,8 @@ void setInverse(bool enable) { } void printLine(String line) { + // Replace umlauts before printing (German to ASCII workaround) + line = replaceUmlauts(line); printer.println(line); } @@ -398,26 +417,67 @@ void advancePaper(int lines) { } } +// Updated text wrapping with explicit newline handling and CR/LF normalization void printWrappedUpsideDown(String text) { + // Normalize line endings to '\n' to handle Windows/Mac inputs + text.replace("\r\n", "\n"); + text.replace("\r", "\n"); + + // Apply umlaut workaround + text = replaceUmlauts(text); + String lines[100]; int lineCount = 0; - + + // First split the incoming text by explicit newline characters + int nlIndex = text.indexOf('\n'); + while (nlIndex != -1) { + String oneLine = text.substring(0, nlIndex); + text = text.substring(nlIndex + 1); + + // Wrap this single logical line + while (oneLine.length() > 0) { + if (oneLine.length() <= maxCharsPerLine) { + lines[lineCount++] = oneLine; + break; + } + int lastSpace = oneLine.lastIndexOf(' ', maxCharsPerLine); + if (lastSpace == -1) lastSpace = maxCharsPerLine; + lines[lineCount++] = oneLine.substring(0, lastSpace); + oneLine = oneLine.substring(lastSpace); + oneLine.trim(); + } + + nlIndex = text.indexOf('\n'); + } + + // Wrap the remaining text after the last newline while (text.length() > 0) { - int breakIndex = maxCharsPerLine; if (text.length() <= maxCharsPerLine) { lines[lineCount++] = text; break; } - int lastSpace = text.lastIndexOf(' ', maxCharsPerLine); if (lastSpace == -1) lastSpace = maxCharsPerLine; - lines[lineCount++] = text.substring(0, lastSpace); text = text.substring(lastSpace); text.trim(); } - + + // Print in reverse order to achieve upside-down final layout for (int i = lineCount - 1; i >= 0; i--) { printLine(lines[i]); } } + +// === umlaut replacement === +String replaceUmlauts(String text) { + text.replace("ä", "ae"); + text.replace("ö", "oe"); + text.replace("ü", "ue"); + text.replace("Ä", "Ae"); + text.replace("Ö", "Oe"); + text.replace("Ü", "Ue"); + text.replace("ß", "ss"); + return text; +}