diff --git a/app.py b/app.py index 8fc242e..de38850 100644 --- a/app.py +++ b/app.py @@ -1,8 +1,7 @@ # app.py import asyncio from functools import lru_cache -from io import BytesIO -from typing import List +from typing import List, Optional from barcode import Code128 from barcode.writer import ImageWriter @@ -20,10 +19,25 @@ if not hasattr(Image, "ANTIALIAS"): app = FastAPI(title="QL-1060N Stacked Barcode Printer") +class PrintRequest(BaseModel): + # from LABEL_PRINTER_PARAMS + printer_ip: str = Field(..., description="QL-1060N IP on LAN") + model: str = Field(..., description="Brother model") + label: str = Field(..., description="12 mm tape") + # grocy payload: + grocycode: str = Field(..., description="Raw GrocyCode") + product: str = Field(..., description="Product name") + due_date: str = Field(None, description="Due date from stock entry") + + class Config: + # ignore any other fields Grocy might send + extra = "ignore" + + @lru_cache(maxsize=256) -def make_code128(data: str) -> Image.Image: +def make_code128(grocycode: str, product_name: str, due_date: Optional[str]) -> Image.Image: # 1) Instantiate the barcode object (checksum auto-added for Code128) - code = Code128(data, writer=ImageWriter()) + code = Code128(grocycode, writer=ImageWriter()) # 2) Render to a PIL.Image, passing any writer options and optional text override pil_img = code.render( @@ -35,7 +49,7 @@ def make_code128(data: str) -> Image.Image: "text_distance": 5.0, # gap between bars and text # you can also pass 'format': 'PNG' here if needed }, - text=data, # explicitly draw your data string under the bars + text=" | ".join([product_name, due_date]), # explicitly draw your data string under the bars ) # 3) Convert to 1-bit for your Brother QL workflow @@ -43,21 +57,12 @@ def make_code128(data: str) -> Image.Image: @lru_cache(maxsize=256) -def make_datamatrix(data: str) -> Image.Image: - dm = encode(data.encode("utf-8")) +def make_datamatrix(grocycode: str) -> Image.Image: + dm = encode(grocycode.encode("utf-8")) pil_img = Image.frombytes("RGB", (dm.width, dm.height), dm.pixels) return pil_img.convert("1") -class PrintRequest(BaseModel): - data: str = Field(..., description="String to encode") - printer_ip: str = Field( - "192.168.178.49", description="Brother QL-1060N IP on your LAN" - ) - model: str = Field("QL-1060N", description="Brother model") - label: str = Field("12", description="12 mm continuous tape") - - def compose_label(images: List[Image.Image]) -> Image.Image: """ Horizontally stack each barcode image with padding, @@ -119,16 +124,15 @@ def send_to_printer(image: Image.Image, printer_ip: str, model: str, label: str) @app.post("/print", summary="Print Code128 + DataMatrix side-by-side") -async def print_stacked(req: PrintRequest): +async def print_from_grocy(req: PrintRequest): try: loop = asyncio.get_running_loop() - code_task = loop.run_in_executor(None, make_code128, req.data) - dm_task = loop.run_in_executor(None, make_datamatrix, req.data) - code_img, dm_img = await asyncio.gather(code_task, dm_task) - + code_img, dm_img = await asyncio.gather( + loop.run_in_executor(None, make_code128, req.grocycode, req.product, req.due_date), + loop.run_in_executor(None, make_datamatrix, req.grocycode), + ) label_img = compose_label([code_img, dm_img]) send_to_printer(label_img, req.printer_ip, req.model, req.label) - except Exception as e: raise HTTPException(status_code=500, detail=str(e))