Compare commits

..

4 Commits

Author SHA1 Message Date
Catering-PC fe412ed9e9 Hotfix: Add missing import 2026-04-29 12:00:15 +02:00
David Rodenkirchen 147508184f Make USB printer more resilient 2026-04-29 11:51:07 +02:00
Catering-PC fef55c722b update docs 2026-04-12 13:43:36 +02:00
Catering-PC 46e6e0db67 add systemd service file 2026-04-12 13:40:38 +02:00
3 changed files with 33 additions and 15 deletions
+11 -6
View File
@@ -1,18 +1,23 @@
# Receipt Printer # Receipt Printer
This software is designed to run on a debian based system and acts as a middle-man between the EZ LAN Manager database and the USB interface of the receipt printer. This software is designed to run on a debian based system and acts as a middle-man between the EZGG LAN Manager database and the USB interface of the receipt printer.
# Notes # Notes
- Does only work on Linux - Does only work on Linux
- Needs root privileges or udev config to work
- Designed to run alone on a Raspberry Pi
- Not meant to be exposed to the internet, local deployment only - Not meant to be exposed to the internet, local deployment only
- For EZ LAN Manager configuration, check README in that repo - For EZGG LAN Manager configuration, check README in that repo
# Deploy # Deploy
1. Configure password and port in `main.py` 1. Configure password and port in `main.py`
2. Make sure USB printer is connected to device 2. Make sure USB printer is connected to device
3. Install requirements with sudo 3. Install requirements in venv
4. Run `main.py` with sudo 4. Adapt `receipt-printer.service` as needed and move to `~/.config/systemd/user`
5. Enable unit in systemd:
```sh
systemctl --user daemon-reexec
systemctl --user daemon-reload
systemctl --user enable receipt-printer
systemctl --user start receipt-printer
```
+8 -9
View File
@@ -1,5 +1,6 @@
from datetime import datetime from datetime import datetime
from typing import List from typing import List
import unicodedata
import uvicorn import uvicorn
from fastapi import FastAPI, HTTPException, Header from fastapi import FastAPI, HTTPException, Header
@@ -9,8 +10,6 @@ from escpos.printer import Usb
from escpos.capabilities import get_profile from escpos.capabilities import get_profile
from PIL import Image from PIL import Image
PRINTER = Usb(0x28e9, 0x0289, profile="simple")
MAX_LINE_LEN = 32 MAX_LINE_LEN = 32
SECRET_PASSWORD = "Alkohol1" SECRET_PASSWORD = "Alkohol1"
@@ -27,13 +26,11 @@ class Order(BaseModel):
seat_id: str seat_id: str
items: List[OrderItem] items: List[OrderItem]
def get_printer() -> Usb:
return Usb(0x28e9, 0x0289, profile="simple")
def sanitize_text(text: str) -> str: def sanitize_text(text: str) -> str:
return (text.replace("ä", "ae") return unicodedata.normalize("NFKD", text).encode("ascii", "ignore").decode()
.replace("ö", "oe")
.replace("ü", "ue")
.replace("ß", "ss"))
def build_header(order: Order, copy_num: int) -> str: def build_header(order: Order, copy_num: int) -> str:
return ( return (
@@ -89,7 +86,7 @@ api = FastAPI()
@api.post("/print_order") @api.post("/print_order")
async def print_order_api_endpoint(order: Order, x_password: str = Header(None)): def print_order_api_endpoint(order: Order, x_password: str = Header(None)):
if x_password != SECRET_PASSWORD: if x_password != SECRET_PASSWORD:
raise HTTPException(status_code=401, detail="Unauthorized") raise HTTPException(status_code=401, detail="Unauthorized")
@@ -99,7 +96,9 @@ async def print_order_api_endpoint(order: Order, x_password: str = Header(None))
for copy_num in range(1, 3): for copy_num in range(1, 3):
try: try:
print_order(order, PRINTER, copy_num) printer = get_printer()
print_order(order, printer, copy_num)
printer.close()
except Exception as e: except Exception as e:
raise HTTPException(status_code=500, detail=f"Printing failed: {str(e)}") raise HTTPException(status_code=500, detail=f"Printing failed: {str(e)}")
+14
View File
@@ -0,0 +1,14 @@
[Unit]
Description=Receipt Printer
After=network.target
[Service]
WorkingDirectory=/opt/ReceiptPrinter
ExecStart=/opt/ReceiptPrinter/printer-venv/bin/python main.py
Restart=always
RestartSec=3
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=default.target