zebra-day 0.0.37__py3-none-any.whl → 1.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zebra_day/__init__.py +35 -0
- zebra_day/bin/__init__.py +0 -0
- zebra_day/bin/fetch_zebra_config.py +15 -0
- zebra_day/bin/generate_coord_grid_zpl.py +50 -0
- zebra_day/bin/print_zpl_from_file.py +21 -0
- zebra_day/bin/probe_new_label_dimensions.py +75 -0
- zebra_day/bin/scan_for_networed_zebra_printers_arp_scan.sh +1 -0
- zebra_day/bin/scan_for_networed_zebra_printers_curl.sh +30 -0
- zebra_day/bin/zserve.py +701 -259
- zebra_day/cli/__init__.py +240 -0
- zebra_day/cli/cognito.py +121 -0
- zebra_day/cli/gui.py +255 -0
- zebra_day/cli/printer.py +168 -0
- zebra_day/cli/template.py +176 -0
- zebra_day/cmd_mgr.py +35 -0
- zebra_day/etc/Monoid-Regular-HalfTight-Dollar-0-1-l.ttf +0 -0
- zebra_day/etc/label_styles/blank.zpl +0 -0
- zebra_day/etc/label_styles/cornersStripOf4Squares_1inX1in.zpl +55 -0
- zebra_day/etc/label_styles/corners_1inX2in.zpl +28 -0
- zebra_day/etc/label_styles/corners_20cmX30cm.zpl +6 -0
- zebra_day/etc/label_styles/corners_smallTube.zpl +7 -0
- zebra_day/etc/label_styles/corners_unspecifiedDimensions.zpl +15 -0
- zebra_day/etc/label_styles/generic_2inX1in.zpl +21 -0
- zebra_day/etc/label_styles/plate_1inX0.25in.zpl +9 -0
- zebra_day/etc/label_styles/plate_1inX0.25inHD.zpl +9 -0
- zebra_day/etc/label_styles/smallTubeWdotHD_prod.zpl +8 -0
- zebra_day/etc/label_styles/smallTubeWdot_corners.zpl +7 -0
- zebra_day/etc/label_styles/smallTubeWdot_prod.zpl +8 -0
- zebra_day/etc/label_styles/smallTubeWdot_prodAlt1.zpl +6 -0
- zebra_day/etc/label_styles/smallTubeWdot_prodAlt1b.zpl +3 -0
- zebra_day/etc/label_styles/smallTubeWdot_prodV2.zpl +8 -0
- zebra_day/etc/label_styles/smallTubeWdot_reagent.zpl +29 -0
- zebra_day/etc/label_styles/stripOf4Squares_1inX1in.zpl +32 -0
- zebra_day/etc/label_styles/test_800dX800dCoordinateArray.zpl +1 -0
- zebra_day/etc/label_styles/tmps/.hold +0 -0
- zebra_day/etc/label_styles/tmps/tmp_zpl_templates.here +0 -0
- zebra_day/etc/label_styles/tube_20mmX30mmA.zpl +7 -0
- zebra_day/etc/label_styles/tube_2inX0.3in.zpl +15 -0
- zebra_day/etc/label_styles/tube_2inX0.5in.zpl +15 -0
- zebra_day/etc/label_styles/tube_2inX0.5inHD.zpl +15 -0
- zebra_day/etc/label_styles/tube_2inX1in.zpl +25 -0
- zebra_day/etc/label_styles/tube_2inX1inHD.zpl +22 -0
- zebra_day/etc/label_styles/tube_2inX1inHDv3.zpl +21 -0
- zebra_day/etc/old_printer_config/.hold +0 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:50:25.022846_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:50:25.033657_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:50:25.039597_printer_config.json +3 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:50:25.047295_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:50:25.055804_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:50:25.061337_printer_config.json +3 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:24.073326_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:24.081950_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:24.088251_printer_config.json +3 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:24.096501_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:24.104767_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:24.110364_printer_config.json +3 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:24.118239_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:24.125950_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:24.349866_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:24.361085_printer_config.json +3 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:24.558323_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:24.565756_printer_config.json +3 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:29.739070_printer_config.json +16 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:29.753796_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:29.760201_printer_config.json +3 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:29.768747_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:29.775312_printer_config.json +3 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:29.782533_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:29.789287_printer_config.json +1 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:29.794230_printer_config.json +3 -0
- zebra_day/etc/old_printer_config/2026-02-01_01:51:29.800021_printer_config.json +5 -0
- zebra_day/etc/printer_config.json +16 -0
- zebra_day/etc/printer_config.template.json +16 -0
- zebra_day/etc/tmp_printers0.json +5 -0
- zebra_day/etc/tmp_printers374.json +5 -0
- zebra_day/etc/tmp_printers383.json +5 -0
- zebra_day/etc/tmp_printers450.json +5 -0
- zebra_day/etc/tmp_printers504.json +5 -0
- zebra_day/etc/tmp_printers608.json +5 -0
- zebra_day/etc/tmp_printers657.json +5 -0
- zebra_day/etc/tmp_printers838.json +5 -0
- zebra_day/etc/tmp_printers839.json +5 -0
- zebra_day/etc/tmp_printers933.json +5 -0
- zebra_day/etc/tmp_printers957.json +5 -0
- zebra_day/exceptions.py +88 -0
- zebra_day/files/.hold +0 -0
- zebra_day/files/hold +0 -0
- zebra_day/files/test_png_17696.png +0 -0
- zebra_day/files/test_png_23477.png +0 -0
- zebra_day/files/test_png_28157.png +0 -0
- zebra_day/files/test_png_35832.png +0 -0
- zebra_day/files/test_png_36400.png +0 -0
- zebra_day/files/test_png_40816.png +0 -0
- zebra_day/files/test_png_49564.png +0 -0
- zebra_day/files/test_png_53848.png +0 -0
- zebra_day/files/test_png_62542.png +0 -0
- zebra_day/files/test_png_91597.png +0 -0
- zebra_day/files/test_png_93633.png +0 -0
- zebra_day/files/tmpbjo3k7q1.png +0 -0
- zebra_day/files/tmpigtr4pwy.png +0 -0
- zebra_day/files/zpl_label_tube_2inX1in_2026-02-01_01:51:24.370964.png +0 -0
- zebra_day/logging_config.py +74 -0
- zebra_day/logs/.hold +0 -0
- zebra_day/logs/print_requests.log +2 -0
- zebra_day/paths.py +143 -0
- zebra_day/print_mgr.py +487 -103
- zebra_day/static/datschund.css +140 -0
- zebra_day/static/datschund.png +0 -0
- zebra_day/static/daylily.png +0 -0
- zebra_day/static/favicon.svg +20 -0
- zebra_day/static/general.css +99 -0
- zebra_day/static/js/zebra_modern.js +172 -0
- zebra_day/static/lsmc.css +354 -0
- zebra_day/static/moon.jpeg +0 -0
- zebra_day/static/oakland.css +197 -0
- zebra_day/static/petrichor.css +150 -0
- zebra_day/static/popday_daylily.css +140 -0
- zebra_day/static/style.css +183 -0
- zebra_day/static/triangles.css +122 -0
- zebra_day/static/tron.css +277 -0
- zebra_day/static/zebra_modern.css +771 -0
- zebra_day/static/zebras.css +176 -0
- zebra_day/templates/base.html +36 -0
- zebra_day/templates/bpr.html +72 -0
- zebra_day/templates/build_new_config.html +36 -0
- zebra_day/templates/build_print_request.html +32 -0
- zebra_day/templates/chg_ui_style.html +19 -0
- zebra_day/templates/edit_template.html +128 -0
- zebra_day/templates/edit_zpl.html +37 -0
- zebra_day/templates/index.html +82 -0
- zebra_day/templates/legacy/base.html +37 -0
- zebra_day/templates/legacy/bpr.html +72 -0
- zebra_day/templates/legacy/build_new_config.html +36 -0
- zebra_day/templates/legacy/build_print_request.html +32 -0
- zebra_day/templates/legacy/chg_ui_style.html +19 -0
- zebra_day/templates/legacy/edit_template.html +128 -0
- zebra_day/templates/legacy/edit_zpl.html +37 -0
- zebra_day/templates/legacy/index.html +82 -0
- zebra_day/templates/legacy/list_prior_configs.html +24 -0
- zebra_day/templates/legacy/print_result.html +30 -0
- zebra_day/templates/legacy/printer_details.html +25 -0
- zebra_day/templates/legacy/printer_status.html +70 -0
- zebra_day/templates/legacy/save_result.html +17 -0
- zebra_day/templates/legacy/send_print_request.html +34 -0
- zebra_day/templates/legacy/simple_print.html +94 -0
- zebra_day/templates/legacy/view_pstation_json.html +29 -0
- zebra_day/templates/list_prior_configs.html +24 -0
- zebra_day/templates/modern/base.html +98 -0
- zebra_day/templates/modern/config.html +141 -0
- zebra_day/templates/modern/dashboard.html +160 -0
- zebra_day/templates/modern/print_request.html +141 -0
- zebra_day/templates/modern/print_result.html +88 -0
- zebra_day/templates/modern/printer_detail.html +117 -0
- zebra_day/templates/modern/printers.html +133 -0
- zebra_day/templates/modern/save_result.html +46 -0
- zebra_day/templates/modern/template_editor.html +172 -0
- zebra_day/templates/modern/templates.html +122 -0
- zebra_day/templates/print_result.html +30 -0
- zebra_day/templates/printer_details.html +25 -0
- zebra_day/templates/printer_status.html +70 -0
- zebra_day/templates/save_result.html +17 -0
- zebra_day/templates/send_print_request.html +34 -0
- zebra_day/templates/simple_print.html +94 -0
- zebra_day/templates/view_pstation_json.html +29 -0
- zebra_day/web/__init__.py +9 -0
- zebra_day/web/app.py +171 -0
- zebra_day/web/auth.py +172 -0
- zebra_day/web/middleware.py +159 -0
- zebra_day/web/routers/__init__.py +2 -0
- zebra_day/web/routers/api.py +163 -0
- zebra_day/web/routers/ui.py +1051 -0
- zebra_day/zpl_renderer.py +273 -0
- zebra_day-1.0.2.dist-info/METADATA +786 -0
- zebra_day-1.0.2.dist-info/RECORD +179 -0
- {zebra_day-0.0.37.dist-info → zebra_day-1.0.2.dist-info}/WHEEL +1 -1
- zebra_day-1.0.2.dist-info/entry_points.txt +4 -0
- zebra_day/bin/te.py +0 -905
- zebra_day-0.0.37.dist-info/METADATA +0 -1177
- zebra_day-0.0.37.dist-info/RECORD +0 -10
- {zebra_day-0.0.37.dist-info → zebra_day-1.0.2.dist-info/licenses}/LICENSE +0 -0
- {zebra_day-0.0.37.dist-info → zebra_day-1.0.2.dist-info}/top_level.txt +0 -0
zebra_day/cli/printer.py
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"""Printer fleet management commands for zebra_day CLI."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import socket
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.table import Table
|
|
10
|
+
|
|
11
|
+
from zebra_day import paths as xdg
|
|
12
|
+
|
|
13
|
+
printer_app = typer.Typer(help="Printer fleet management commands")
|
|
14
|
+
console = Console()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _get_local_ip() -> str:
|
|
18
|
+
"""Get local IP address."""
|
|
19
|
+
try:
|
|
20
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
21
|
+
s.connect(("8.8.8.8", 80))
|
|
22
|
+
ip = s.getsockname()[0]
|
|
23
|
+
s.close()
|
|
24
|
+
return ip
|
|
25
|
+
except Exception:
|
|
26
|
+
return "127.0.0.1"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@printer_app.command("scan")
|
|
30
|
+
def scan(
|
|
31
|
+
ip_stub: Optional[str] = typer.Option(None, "--ip-stub", "-i", help="IP stub to scan (e.g., 192.168.1)"),
|
|
32
|
+
wait: float = typer.Option(0.25, "--wait", "-w", help="Seconds to wait per IP probe"),
|
|
33
|
+
lab: str = typer.Option("scan-results", "--lab", "-l", help="Lab name to assign found printers"),
|
|
34
|
+
json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
|
|
35
|
+
):
|
|
36
|
+
"""Scan network for Zebra printers."""
|
|
37
|
+
# Determine IP stub if not provided
|
|
38
|
+
if not ip_stub:
|
|
39
|
+
local_ip = _get_local_ip()
|
|
40
|
+
ip_stub = ".".join(local_ip.split(".")[:-1])
|
|
41
|
+
|
|
42
|
+
if not json_output:
|
|
43
|
+
console.print(f"[cyan]→[/cyan] Scanning {ip_stub}.* for Zebra printers...")
|
|
44
|
+
console.print("[dim] This may take a few minutes...[/dim]")
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
import zebra_day.print_mgr as zdpm
|
|
48
|
+
zp = zdpm.zpl()
|
|
49
|
+
zp.probe_zebra_printers_add_to_printers_json(
|
|
50
|
+
ip_stub=ip_stub,
|
|
51
|
+
scan_wait=str(wait),
|
|
52
|
+
lab=lab,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
found = []
|
|
56
|
+
if hasattr(zp, "printers") and "labs" in zp.printers and lab in zp.printers["labs"]:
|
|
57
|
+
for name, info in zp.printers["labs"][lab].items():
|
|
58
|
+
if isinstance(info, dict) and info.get("ip_address") not in ["dl_png"]:
|
|
59
|
+
found.append({
|
|
60
|
+
"name": name,
|
|
61
|
+
"ip": info.get("ip_address"),
|
|
62
|
+
"model": info.get("model", "unknown"),
|
|
63
|
+
"serial": info.get("serial", "unknown"),
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
if json_output:
|
|
67
|
+
console.print(json.dumps(found, indent=2))
|
|
68
|
+
else:
|
|
69
|
+
console.print(f"\n[green]✓[/green] Found {len(found)} printer(s)")
|
|
70
|
+
if found:
|
|
71
|
+
table = Table()
|
|
72
|
+
table.add_column("Name", style="cyan")
|
|
73
|
+
table.add_column("IP Address")
|
|
74
|
+
table.add_column("Model")
|
|
75
|
+
table.add_column("Serial")
|
|
76
|
+
for p in found:
|
|
77
|
+
table.add_row(p["name"], p["ip"], p["model"], p["serial"])
|
|
78
|
+
console.print(table)
|
|
79
|
+
|
|
80
|
+
except Exception as e:
|
|
81
|
+
if json_output:
|
|
82
|
+
console.print(json.dumps({"error": str(e)}))
|
|
83
|
+
else:
|
|
84
|
+
console.print(f"[red]✗[/red] Scan error: {e}")
|
|
85
|
+
raise typer.Exit(1)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@printer_app.command("list")
|
|
89
|
+
def list_printers(
|
|
90
|
+
lab: Optional[str] = typer.Option(None, "--lab", "-l", help="Filter by lab name"),
|
|
91
|
+
json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
|
|
92
|
+
):
|
|
93
|
+
"""List configured printers."""
|
|
94
|
+
try:
|
|
95
|
+
import zebra_day.print_mgr as zdpm
|
|
96
|
+
zp = zdpm.zpl()
|
|
97
|
+
|
|
98
|
+
printers = []
|
|
99
|
+
if hasattr(zp, "printers") and "labs" in zp.printers:
|
|
100
|
+
for lab_name, lab_printers in zp.printers["labs"].items():
|
|
101
|
+
if lab and lab_name != lab:
|
|
102
|
+
continue
|
|
103
|
+
for name, info in lab_printers.items():
|
|
104
|
+
if isinstance(info, dict):
|
|
105
|
+
printers.append({
|
|
106
|
+
"lab": lab_name,
|
|
107
|
+
"name": name,
|
|
108
|
+
"ip": info.get("ip_address", "unknown"),
|
|
109
|
+
"model": info.get("model", "unknown"),
|
|
110
|
+
"styles": info.get("label_zpl_styles", []),
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
if json_output:
|
|
114
|
+
console.print(json.dumps(printers, indent=2))
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
if not printers:
|
|
118
|
+
console.print("[yellow]⚠[/yellow] No printers configured")
|
|
119
|
+
console.print(" Run [cyan]zday printer scan[/cyan] to discover printers")
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
table = Table(title="Configured Printers")
|
|
123
|
+
table.add_column("Lab", style="cyan")
|
|
124
|
+
table.add_column("Name")
|
|
125
|
+
table.add_column("IP Address")
|
|
126
|
+
table.add_column("Model")
|
|
127
|
+
table.add_column("Label Styles")
|
|
128
|
+
for p in printers:
|
|
129
|
+
styles = ", ".join(p["styles"][:2])
|
|
130
|
+
if len(p["styles"]) > 2:
|
|
131
|
+
styles += f" (+{len(p['styles'])-2})"
|
|
132
|
+
table.add_row(p["lab"], p["name"], p["ip"], p["model"], styles)
|
|
133
|
+
console.print(table)
|
|
134
|
+
|
|
135
|
+
except Exception as e:
|
|
136
|
+
if json_output:
|
|
137
|
+
console.print(json.dumps({"error": str(e)}))
|
|
138
|
+
else:
|
|
139
|
+
console.print(f"[red]✗[/red] Error: {e}")
|
|
140
|
+
raise typer.Exit(1)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@printer_app.command("test")
|
|
144
|
+
def test_print(
|
|
145
|
+
printer_name: str = typer.Argument(..., help="Printer name or IP address"),
|
|
146
|
+
lab: str = typer.Option("scan-results", "--lab", "-l", help="Lab containing the printer"),
|
|
147
|
+
label_style: str = typer.Option("tube_2inX1in", "--style", "-s", help="Label style to print"),
|
|
148
|
+
):
|
|
149
|
+
"""Send a test print to a specific printer."""
|
|
150
|
+
try:
|
|
151
|
+
import zebra_day.print_mgr as zdpm
|
|
152
|
+
zp = zdpm.zpl()
|
|
153
|
+
|
|
154
|
+
console.print(f"[cyan]→[/cyan] Sending test print to {printer_name}...")
|
|
155
|
+
result = zp.print_zpl(
|
|
156
|
+
lab=lab,
|
|
157
|
+
printer_name=printer_name,
|
|
158
|
+
uid_barcode="TEST-PRINT",
|
|
159
|
+
alt_a="Test Label",
|
|
160
|
+
alt_b="zebra_day CLI",
|
|
161
|
+
label_zpl_style=label_style,
|
|
162
|
+
)
|
|
163
|
+
console.print(f"[green]✓[/green] Test print sent successfully")
|
|
164
|
+
|
|
165
|
+
except Exception as e:
|
|
166
|
+
console.print(f"[red]✗[/red] Print error: {e}")
|
|
167
|
+
raise typer.Exit(1)
|
|
168
|
+
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""ZPL template management commands for zebra_day CLI."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import subprocess
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.table import Table
|
|
12
|
+
|
|
13
|
+
from zebra_day import paths as xdg
|
|
14
|
+
|
|
15
|
+
template_app = typer.Typer(help="ZPL template management commands")
|
|
16
|
+
console = Console()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _get_template_dirs() -> list[Path]:
|
|
20
|
+
"""Get all template directories."""
|
|
21
|
+
from importlib.resources import files
|
|
22
|
+
|
|
23
|
+
dirs = []
|
|
24
|
+
# XDG data directory
|
|
25
|
+
xdg_styles = xdg.get_label_styles_dir()
|
|
26
|
+
if xdg_styles.exists():
|
|
27
|
+
dirs.append(xdg_styles)
|
|
28
|
+
|
|
29
|
+
# Package directory
|
|
30
|
+
try:
|
|
31
|
+
pkg_styles = Path(str(files("zebra_day"))) / "etc" / "label_styles"
|
|
32
|
+
if pkg_styles.exists():
|
|
33
|
+
dirs.append(pkg_styles)
|
|
34
|
+
except Exception:
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
return dirs
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _find_template(name: str) -> Optional[Path]:
|
|
41
|
+
"""Find a template file by name."""
|
|
42
|
+
for template_dir in _get_template_dirs():
|
|
43
|
+
# Try exact match
|
|
44
|
+
for ext in ["", ".zpl", ".txt"]:
|
|
45
|
+
path = template_dir / f"{name}{ext}"
|
|
46
|
+
if path.exists():
|
|
47
|
+
return path
|
|
48
|
+
# Try with zpl_ prefix
|
|
49
|
+
for ext in ["", ".zpl", ".txt"]:
|
|
50
|
+
path = template_dir / f"zpl_{name}{ext}"
|
|
51
|
+
if path.exists():
|
|
52
|
+
return path
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@template_app.command("list")
|
|
57
|
+
def list_templates(
|
|
58
|
+
json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
|
|
59
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show full paths"),
|
|
60
|
+
):
|
|
61
|
+
"""List available ZPL templates."""
|
|
62
|
+
templates = []
|
|
63
|
+
|
|
64
|
+
for template_dir in _get_template_dirs():
|
|
65
|
+
for f in template_dir.iterdir():
|
|
66
|
+
if f.is_file() and not f.name.startswith("."):
|
|
67
|
+
if f.suffix in [".zpl", ".txt", ""] or f.name.startswith("zpl_"):
|
|
68
|
+
templates.append({
|
|
69
|
+
"name": f.stem,
|
|
70
|
+
"path": str(f),
|
|
71
|
+
"size": f.stat().st_size,
|
|
72
|
+
"source": "user" if "zebra_day" not in str(template_dir) else "package",
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
# Dedupe by name, prefer user templates
|
|
76
|
+
seen = {}
|
|
77
|
+
for t in templates:
|
|
78
|
+
if t["name"] not in seen or t["source"] == "user":
|
|
79
|
+
seen[t["name"]] = t
|
|
80
|
+
templates = list(seen.values())
|
|
81
|
+
|
|
82
|
+
if json_output:
|
|
83
|
+
console.print(json.dumps(templates, indent=2))
|
|
84
|
+
return
|
|
85
|
+
|
|
86
|
+
if not templates:
|
|
87
|
+
console.print("[yellow]⚠[/yellow] No templates found")
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
table = Table(title="ZPL Templates")
|
|
91
|
+
table.add_column("Name", style="cyan")
|
|
92
|
+
table.add_column("Source")
|
|
93
|
+
table.add_column("Size")
|
|
94
|
+
if verbose:
|
|
95
|
+
table.add_column("Path", style="dim")
|
|
96
|
+
|
|
97
|
+
for t in sorted(templates, key=lambda x: x["name"]):
|
|
98
|
+
source_style = "[green]user[/green]" if t["source"] == "user" else "[dim]package[/dim]"
|
|
99
|
+
if verbose:
|
|
100
|
+
table.add_row(t["name"], source_style, f"{t['size']} bytes", t["path"])
|
|
101
|
+
else:
|
|
102
|
+
table.add_row(t["name"], source_style, f"{t['size']} bytes")
|
|
103
|
+
|
|
104
|
+
console.print(table)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@template_app.command("preview")
|
|
108
|
+
def preview(
|
|
109
|
+
template_name: str = typer.Argument(..., help="Template name to preview"),
|
|
110
|
+
output: Optional[str] = typer.Option(None, "--output", "-o", help="Output PNG file path"),
|
|
111
|
+
):
|
|
112
|
+
"""Generate a PNG preview of a ZPL template."""
|
|
113
|
+
template_path = _find_template(template_name)
|
|
114
|
+
if not template_path:
|
|
115
|
+
console.print(f"[red]✗[/red] Template not found: {template_name}")
|
|
116
|
+
raise typer.Exit(1)
|
|
117
|
+
|
|
118
|
+
console.print(f"[cyan]→[/cyan] Generating preview for {template_name}...")
|
|
119
|
+
|
|
120
|
+
try:
|
|
121
|
+
import zebra_day.print_mgr as zdpm
|
|
122
|
+
zp = zdpm.zpl()
|
|
123
|
+
|
|
124
|
+
# Read template
|
|
125
|
+
zpl_content = template_path.read_text()
|
|
126
|
+
|
|
127
|
+
# Generate PNG
|
|
128
|
+
if not output:
|
|
129
|
+
output_path = xdg.get_generated_files_dir() / f"{template_name}_preview.png"
|
|
130
|
+
else:
|
|
131
|
+
output_path = Path(output)
|
|
132
|
+
|
|
133
|
+
result = zp.generate_label_png(zpl_content, str(output_path), False)
|
|
134
|
+
console.print(f"[green]✓[/green] Preview generated: {output_path}")
|
|
135
|
+
|
|
136
|
+
except Exception as e:
|
|
137
|
+
console.print(f"[red]✗[/red] Preview error: {e}")
|
|
138
|
+
raise typer.Exit(1)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@template_app.command("edit")
|
|
142
|
+
def edit(
|
|
143
|
+
template_name: str = typer.Argument(..., help="Template name to edit"),
|
|
144
|
+
editor: Optional[str] = typer.Option(None, "--editor", "-e", help="Editor command"),
|
|
145
|
+
):
|
|
146
|
+
"""Open a ZPL template in an editor."""
|
|
147
|
+
template_path = _find_template(template_name)
|
|
148
|
+
if not template_path:
|
|
149
|
+
console.print(f"[red]✗[/red] Template not found: {template_name}")
|
|
150
|
+
raise typer.Exit(1)
|
|
151
|
+
|
|
152
|
+
# Determine editor
|
|
153
|
+
if not editor:
|
|
154
|
+
editor = os.environ.get("VISUAL") or os.environ.get("EDITOR") or "vi"
|
|
155
|
+
|
|
156
|
+
console.print(f"[cyan]→[/cyan] Opening {template_path} with {editor}...")
|
|
157
|
+
try:
|
|
158
|
+
subprocess.run([editor, str(template_path)])
|
|
159
|
+
except Exception as e:
|
|
160
|
+
console.print(f"[red]✗[/red] Error opening editor: {e}")
|
|
161
|
+
raise typer.Exit(1)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@template_app.command("show")
|
|
165
|
+
def show(
|
|
166
|
+
template_name: str = typer.Argument(..., help="Template name to display"),
|
|
167
|
+
):
|
|
168
|
+
"""Display the contents of a ZPL template."""
|
|
169
|
+
template_path = _find_template(template_name)
|
|
170
|
+
if not template_path:
|
|
171
|
+
console.print(f"[red]✗[/red] Template not found: {template_name}")
|
|
172
|
+
raise typer.Exit(1)
|
|
173
|
+
|
|
174
|
+
console.print(f"[dim]# {template_path}[/dim]\n")
|
|
175
|
+
console.print(template_path.read_text())
|
|
176
|
+
|
zebra_day/cmd_mgr.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tools to manage a zebra printer fleet and expose an API for routing print requests.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import socket
|
|
6
|
+
|
|
7
|
+
class ZebraPrinter:
|
|
8
|
+
|
|
9
|
+
def __init__(self, ip_address, port=9100, buffer_size=1024):
|
|
10
|
+
self.ip_address = ip_address
|
|
11
|
+
self.port = port
|
|
12
|
+
self.buffer_size = buffer_size
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def send_command(self, command):
|
|
16
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
17
|
+
s.connect((self.ip_address, self.port))
|
|
18
|
+
s.sendall(command.encode())
|
|
19
|
+
response = s.recv(self.buffer_size)
|
|
20
|
+
return response.decode()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_configuration(self):
|
|
24
|
+
"""Retrieve printer configuration using ^HH command"""
|
|
25
|
+
return self.send_command("^XA^HH^XZ")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def set_configuration(self, config):
|
|
29
|
+
"""
|
|
30
|
+
Set printer configuration.
|
|
31
|
+
The `config` parameter should contain the necessary ZPL commands to adjust the configuration.
|
|
32
|
+
After sending the configuration commands, the ^JUS command saves the configuration.
|
|
33
|
+
"""
|
|
34
|
+
self.send_command(config)
|
|
35
|
+
return self.send_command("^XA^JUS^XZ")
|
|
Binary file
|
|
File without changes
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
^XA
|
|
2
|
+
^FO25,10
|
|
3
|
+
^ADN,20,12
|
|
4
|
+
^FDWW^FS
|
|
5
|
+
^FO180,10
|
|
6
|
+
^ADN,20,12
|
|
7
|
+
^FDXX^FS
|
|
8
|
+
^FO180,150
|
|
9
|
+
^ADN,20,12
|
|
10
|
+
^FDYY^FS
|
|
11
|
+
^FO25,150
|
|
12
|
+
^ADN,20,12
|
|
13
|
+
^FDZZ^FS
|
|
14
|
+
|
|
15
|
+
^FO225,10
|
|
16
|
+
^ADN,20,12
|
|
17
|
+
^FDWW^FS
|
|
18
|
+
^FO380,10
|
|
19
|
+
^ADN,20,12
|
|
20
|
+
^FDXX^FS
|
|
21
|
+
^FO380,150
|
|
22
|
+
^ADN,20,12
|
|
23
|
+
^FDYY^FS
|
|
24
|
+
^FO225,150
|
|
25
|
+
^ADN,20,12
|
|
26
|
+
^FDZZ^FS
|
|
27
|
+
|
|
28
|
+
^FO450,10
|
|
29
|
+
^ADN,20,12
|
|
30
|
+
^FDWW^FS
|
|
31
|
+
^FO570,10
|
|
32
|
+
^ADN,20,12
|
|
33
|
+
^FDXX^FS
|
|
34
|
+
^FO570,150
|
|
35
|
+
^ADN,20,12
|
|
36
|
+
^FDYY^FS
|
|
37
|
+
^FO450,150
|
|
38
|
+
^ADN,20,12
|
|
39
|
+
^FDZZ^FS
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
^FO660,10
|
|
43
|
+
^ADN,20,12
|
|
44
|
+
^FDWW^FS
|
|
45
|
+
^FO780,10
|
|
46
|
+
^ADN,20,12
|
|
47
|
+
^FDXX^FS
|
|
48
|
+
^FO780,150
|
|
49
|
+
^ADN,20,12
|
|
50
|
+
^FDYY^FS
|
|
51
|
+
^FO660,150
|
|
52
|
+
^ADN,20,12
|
|
53
|
+
^FDZZ^FS
|
|
54
|
+
|
|
55
|
+
^XZ
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
^XA ; Start of ZPL
|
|
2
|
+
^MMT ; Print mode: Tear-off
|
|
3
|
+
^PW406 ; Label width: 2 inches x 203 DPI = 406 dots
|
|
4
|
+
^LL203 ; Label length: 1 inch x 203 DPI = 203 dots
|
|
5
|
+
^LS0 ; Label shift: no shift
|
|
6
|
+
|
|
7
|
+
; Top-left 'X'
|
|
8
|
+
^FO5,5 ; Position: 5 dots from left, 5 dots from top
|
|
9
|
+
^A0N,24,24 ; Font: scalable, height: 24 dots, width: 24 dots
|
|
10
|
+
^FDX^FS ; Data: 'X'
|
|
11
|
+
|
|
12
|
+
; Top-right 'X'
|
|
13
|
+
^FO376,5 ; Position: (2 inches - width of 'X' - 5 dots) from left, 5 dots from top
|
|
14
|
+
^A0N,24,24
|
|
15
|
+
^FDX^FS
|
|
16
|
+
|
|
17
|
+
; Bottom-left 'X'
|
|
18
|
+
^FO5,174 ; Position: 5 dots from left, (1 inch - height of 'X' - 5 dots) from top
|
|
19
|
+
^A0N,24,24
|
|
20
|
+
^FDX^FS
|
|
21
|
+
|
|
22
|
+
; Bottom-right 'X'
|
|
23
|
+
^FO376,174
|
|
24
|
+
^A0N,24,24
|
|
25
|
+
^FDX^FS
|
|
26
|
+
|
|
27
|
+
^PQ1 ; Print quantity: 1 label
|
|
28
|
+
^XZ ; End of ZPL
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
^XA
|
|
2
|
+
^FO235,20
|
|
3
|
+
^BY1
|
|
4
|
+
^B3N,N,40,N,N
|
|
5
|
+
^FD{uid_barcode}^FS
|
|
6
|
+
^FO235,70
|
|
7
|
+
^ADN,30,20
|
|
8
|
+
^FD{uid_barcode}^FS
|
|
9
|
+
^FO235,115
|
|
10
|
+
^ADN,25,12
|
|
11
|
+
^FD{alt_a}^FS
|
|
12
|
+
^FO235,145
|
|
13
|
+
^ADN,25,12
|
|
14
|
+
^FD{alt_b}^FS
|
|
15
|
+
^FO235,170
|
|
16
|
+
^ADN,26,20
|
|
17
|
+
^FD{alt_c}^FS
|
|
18
|
+
^FO410,140
|
|
19
|
+
^ADN,22,10
|
|
20
|
+
^FD{alt_d}^FS
|
|
21
|
+
^XZ
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
^XA
|
|
2
|
+
^FO150,12
|
|
3
|
+
^A0N, 12, 12
|
|
4
|
+
^FDName:^FS
|
|
5
|
+
^A0N, 12, 12
|
|
6
|
+
^FO150,27
|
|
7
|
+
^FDLot Number:^FS
|
|
8
|
+
^FO150,40
|
|
9
|
+
^A0N, 12, 12
|
|
10
|
+
^FDPrep Date: DDMMMYYYY^FS
|
|
11
|
+
^FO82,40
|
|
12
|
+
^A0N, 12, 12
|
|
13
|
+
^FD123456^FS
|
|
14
|
+
^FO90,58
|
|
15
|
+
^A0N, 12, 12
|
|
16
|
+
^FD123^FS
|
|
17
|
+
^FO150,54
|
|
18
|
+
^A0N, 12, 12
|
|
19
|
+
^FDExp Date: DDMMMYYYY^FS
|
|
20
|
+
^FO150,68
|
|
21
|
+
^A0N, 12, 12
|
|
22
|
+
^FDStore At:^FS
|
|
23
|
+
^FO150,82
|
|
24
|
+
^A0N, 12, 12
|
|
25
|
+
^FDMade By:^FS
|
|
26
|
+
^FO300,27
|
|
27
|
+
^BQN,2,3
|
|
28
|
+
^FDNameLotPrepEXP^FS
|
|
29
|
+
^XZ
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
^XA
|
|
2
|
+
^FO30,30
|
|
3
|
+
^ADN,30,24
|
|
4
|
+
^FD{alt_a}^FS
|
|
5
|
+
^FO30,85
|
|
6
|
+
^ADN,20,12
|
|
7
|
+
^FD{alt_b}^FS
|
|
8
|
+
|
|
9
|
+
^FO230,30
|
|
10
|
+
^ADN,30,24
|
|
11
|
+
^FD{alt_a}^FS
|
|
12
|
+
^FO230,85
|
|
13
|
+
^ADN,20,12
|
|
14
|
+
^FD{alt_b}^FS
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
^FO450,30
|
|
18
|
+
^ADN,30,24
|
|
19
|
+
^FD{alt_a}^FS
|
|
20
|
+
^FO450,85
|
|
21
|
+
^ADN,20,12
|
|
22
|
+
^FD{alt_b}^FS
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
^FO650,30
|
|
26
|
+
^ADN,30,24
|
|
27
|
+
^FD{alt_a}^FS
|
|
28
|
+
^FO650,85
|
|
29
|
+
^ADN,20,12
|
|
30
|
+
^FD{alt_b}^FS
|
|
31
|
+
|
|
32
|
+
^XZ
|