# POS_PRINT.md — Printing to the Epson TM-m30 Quick-reference for any agent or script that needs to print arbitrary content on the receipt printer. USER may explicitly use this file in lieu of a formal request to print. ## Printer Details Exact model reference: `https://www.amazon.com/dp/B01GO08MW2` ### Core | Field | Value | |---|---| | Model | Epson TM-m30 | | Print method | Thermal | | Print speed | 200 mm/second | | Print resolution | 203 dpi | | Print direction | Vertical and horizontal | | Protocol used here | ESC/POS over raw TCP | | IP | `192.168.0.137` | | Port | `9100` | | Profile | `default` (python-escpos) | ### Fonts and characters | Field | Value | |---|---| | Fonts / columns | Font A: 12 x 24, 48 cpl (default); Font B: 10 x 24, 57 cpl; Font C: 9 x 17, 64 cpl | | Character size | Font A: 1.25 x 3.00 mm; Font B: 1.13 x 3.00 mm; Font C: 0.88 x 2.13 mm | | Character set | 95 alphanumeric, 18 international, 128 x 43 | ### Barcode and 2D symbols | Field | Value | |---|---| | Barcode | UPC-A, UPC-E, JAN8 / EAN8, JAN13 / EAN13, Code39, Code93, Code128, ITF, CODABAR (NW-7), GS1-128, GS1 DataBar | | 2D symbols | PDF417, QR Code, MaxiCode, Data Matrix, Aztec Code, 2D GS1 DataBar, Composite Symbology | ### Media handling | Field | Value | |---|---| | Type | Thermal roll paper | | Paper feed method | Friction feed | | Width | 3.12 in / 79.5 mm | | Paper loading | Drop-in | | Roll diameter (max) | 3.27 in / 83 mm | | Core diameter (min) | 0.71 in / 18 mm | | Paper guide | Yes | | Auto cutter | Yes | ### Connectivity | Field | Value | |---|---| | Ethernet model | Built-in USB + Ethernet 10/100Base-T/TX | | Bluetooth model | Built-in USB + Bluetooth 3.0 (EDR supported) + Ethernet 10/100Base-T/TX | | Wi-Fi model | Built-in USB + 802.11b/g/n (2.4 GHz) and 802.11a/n (5 GHz) + Ethernet 10/100Base-T/TX | | Wireless security mode | WEP, WPA, WPA2 Personal/Enterprise | | Supported mobile OS | iOS, Android, Windows (Store Apps) | | Easy setting | SimpleAP, TM Utility, NFC, QR Code | ### General | Field | Value | |---|---| | Printer reliability | 15 million printing lines | | Auto cutter reliability | 1.5 million cuts | | NV bit image memory | 12 KB (max) | | NV graphics | 384 KB (max) | | Receive buffer | 4 KB or 45 bytes | | Printer drivers | ePOS-Print SDK, Windows Driver (APD), OPOS, OPOS.NET, JavaPOS (Win), JavaPOS (Linux), TM Virtual Port Driver, CUPS Driver (Linux), Mac Driver | | Software | TM Utility (iOS, Android), TM-m30 Utility (Windows Desktop), EpsonNet Config (Win, Mac), TM Bluetooth Connector, Deployment Tool, Monitoring Tool | | Audible alert | Optional external buzzer | | LED indicators | Blue LED = Power, Orange LED = Error and/or Paper Out | | Sensors | Paper End, Cover Open | | D.K.D. function | Yes | | Power consumption | Approx. 1.5 A (mean) | | Power source | Adapter C, Adapter RA (printer powers tablet SKU only) | | Power saving | Yes | | Temperature | 5 C to 45 C | | Relative humidity | 10 to 90% | | Acoustic noise level | 55 dB | | Standards and approvals | EMI FCC Class A, CAN ICES-3(A)/NMB-3(A), UL60950-1/CSA C22.2 No.60950-1 | | Dimensions (W x D x H) | 5 x 5 x 5 in (127 x 127 x 127 mm) | | Weight | 2.64 lb / 1200 g | | Color | Epson Black, Epson Ultra White | | Options | Mounting brackets, external buzzer | ## Minimal Print Example ```python import socket from escpos.printer import Dummy PRINTER_IP = "192.168.0.137" PRINTER_PORT = 9100 COLS = 57 # Font B on 80mm paper # 1. Build the receipt with a Dummy (in-memory) printer p = Dummy(profile="default") p.set(font='b', align='center', bold=True) p.text("Hello from the POS printer!\n") p.set(font='b', align='left', bold=False) p.text("This is normal left-aligned text.\n") p.cut() # 2. Send raw bytes over TCP with socket.create_connection((PRINTER_IP, PRINTER_PORT), timeout=10) as sock: sock.sendall(p.output) ``` **Dependencies:** `pip3 install python-escpos` (plus `qrcode` if you use QR codes) ## How It Works The pattern is always the same — **build bytes, then send bytes**: 1. **Build** — Instantiate `escpos.printer.Dummy`. Call formatting/content methods on it. All ESC/POS command bytes accumulate in `p.output`. 2. **Send** — Open a raw TCP socket to `192.168.0.137:9100` and `sendall(p.output)`. The printer interprets the byte stream natively. No driver, no CUPS, no PDF. ## Formatting Reference All formatting is done via `p.set()`. Always pass `font='b'` (Font B gives 57 columns on 80 mm paper; Font A gives fewer). ```python # Bold, centered header p.set(font='b', align='center', bold=True) p.text("TITLE\n") # Normal left-aligned body text p.set(font='b', align='left', bold=False) p.text("Body text here.\n") # Right-aligned p.set(font='b', align='right', bold=False) p.text("Right side\n") ``` ### Available `p.set()` kwargs | Kwarg | Values | Notes | |---|---|---| | `font` | `'a'`, `'b'` | Always use `'b'` for 57-col width | | `align` | `'left'`, `'center'`, `'right'` | | | `bold` | `True` / `False` | | | `underline` | `0`, `1`, `2` | 0=off, 1=single, 2=double | | `width` | `1`–`8` | Character width multiplier | | `height` | `1`–`8` | Character height multiplier | | `density` | `0`–`8` | Print density | | `invert` | `True` / `False` | White on black | | `smooth` | `True` / `False` | Smoothing mode | | `flip` | `True` / `False` | Upside-down printing | ### Content Methods ```python p.text("Plain text with newlines\n") # Text (wrap manually at COLS) p.qr("https://example.com", native=True, size=3) # QR code (native=True uses printer HW) p.image(pil_image) # PIL Image object p.barcode("123456", "EAN13") # Barcode p.cut() # Paper cut (always do this at the end) ``` ### Separators ```python COLS = 57 p.text("=" * COLS + "\n") # Thick separator p.text("-" * COLS + "\n") # Thin separator ``` ## Reusable Send Function ```python import socket def send_to_printer(raw_bytes, ip="192.168.0.137", port=9100): """Send raw ESC/POS bytes to the TM-m30 over TCP.""" with socket.create_connection((ip, port), timeout=10) as sock: sock.sendall(raw_bytes) ``` ## Troubleshooting - **Printer unreachable:** `192.168.0.137` can have intermittent ARP issues from some CTs. Ping first or retry. - **Garbled output:** You probably mixed Font A and Font B column math. Stick to Font B (`font='b'`) and `COLS = 57`. - **No cut at end:** Always call `p.cut()` as the last content method. Without it the receipt hangs out of the printer. - **QR code not printing:** Ensure `native=True` is passed to `p.qr()`. The TM-m30 supports hardware QR generation. Also needs the `qrcode` pip package installed. ## Daily Briefing Project For printing a full daily news briefing (FreshRSS headlines summarized by Ollama, weather, ZFS status, Grafana metrics, market data, Reddit top post, QR codes), see: - **Project:** `/root/bin/POS-Automation/` - **Main script:** `/root/bin/POS-Automation/pos_briefing.py` - **Context:** `/root/bin/POS-Automation/CONTEXT.md` - **Gitea:** `https://git.sethpc.xyz/Seth/POS-Automation` That project's `build_receipt()` function (line 356) is the most complete example of a multi-section ESC/POS receipt with headers, dashboard data, QR codes, and article summaries. Fork it or import its patterns if you need structured receipt layouts.