A lightweight Go backend that serves a REST API for a connected thermal printer (defaulting to /dev/usb/lp0). This service receives text via HTTP POST requests, formats it specifically for this thermal printer hardware, and sends the raw bytes to the device.
- Automatic Text Wrapping: Intelligently wraps long text to the printer's maximum width of 24 characters, preserving word boundaries where possible.
- CP850 Encoding Support: The printer expects characters in the CP850 DOS encodings (Code Page 850). This application automatically converts UTF-8 strings to CP850 to properly support special characters like German Umlaute (
äöüß). - CRLF Conversions: Automatically sanitizes the input replacing
\nwith\r\n(DOS line endings). - Mocking Support: Includes a developer mock mode to print logs to the console rather than requiring physical printer hardware.
- Docker Ready: Provides an optimized 10MB multi-stage Docker image and a
docker-compose.ymlpre-configured to mount host USB devices.
Endpoint: POST /print
{
"text": "Hello Printer, this string will be converted, wrapped and encoded as CP850.",
"align": "center"
}- text (string, required): The content to print.
- align (string, optional): Text alignment. Allowed values:
"left","center","right". Defaults to"left".
curl -X POST http://localhost:8080/print \
-H "Content-Type: application/json" \
-d '{"text": "abcdefghijklmnopqrstuvwxyzäöüßABCDEFGHIJKLMNOPQRSTUVWXY"}'This backend also functions as an MCP (Model Context Protocol) server via SSE, exposing the print_text tool to compatible AI interfaces.
To use the thermal printer in OpenWebUI:
- Go to Workspace -> Tools (or Settings -> Connections, depending on your version).
- Add a new MCP Server connection.
- Select SSE as the transport type.
- Set the URL to:
http://<your-printer-ip>:8080/mcp - Save the configuration. AI models in OpenWebUI can now seamlessly invoke the
print_texttool to print messages or notes directly!
To run the application locally without an attached thermal printer, use the mock device:
PRINTER_DEVICE=mock go run ./cmd/server/main.goAny print requests sent to the local server will be logged with their byte sequences lossy-string conversions.
By default, the application writes to /dev/usb/lp0. Run natively compiled:
go build -o thermo-printer ./cmd/server
./thermo-printer(Optionally define a custom path with PRINTER_DEVICE=/dev/ttyUSB0 ./thermo-printer)
For easy deployment, run the included docker-compose.yml. This automatically mounts the host's /dev/usb/lp0 into the container and runs the latest main branch image.
# Start the container
docker-compose up -d
# Or force a local build instead of pulling the image
docker-compose up -d --buildYou can customize the device mount inside docker-compose.yml if your printer resolves to a different character device on the host.
If you prefer not to use Docker Compose, you can run the container directly with docker run. You must map the printer device and provide access to the lp (printer) group (often GID 7 on Debian/Alpine/Raspberry Pi):
docker run -d \
--name thermoprinter \
-p 8080:8080 \
--device=/dev/usb/lp0:/dev/usb/lp0 \
--group-add 7 \
-e PRINTER_DEVICE=/dev/usb/lp0 \
-e PRINTER_DELAY_MS=500 \
menschomat/d10-thermoprinter:main| Variable | Description | Default |
|---|---|---|
PORT |
The HTTP port the server listens on | 8080 |
PRINTER_DEVICE |
Path to the printer device. Set to mock for testing. |
/dev/usb/lp0 |
PRINTER_DELAY_MS |
Delay in milliseconds between writing each line to the printer buffer | 500 |
PRINTER_BLANK_LINES |
Number of trailing blank lines to append after each print job | 4 |
PRINTER_MAX_BYTES |
Maximum allowed request body size in bytes | 10240 |
PRINTER_MAX_TEXT_LENGTH |
Maximum allowed characters in the print text | 1000 |
Unit tests cover the heavy lifting of CP850 mappings and intelligent text wrapping. To run all tests:
go test -v ./...