zebra-day 2.0.0__py3-none-any.whl → 2.1.4__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 +7 -2
- zebra_day/_version.py +1 -0
- zebra_day/cli/__init__.py +80 -30
- zebra_day/cli/cognito.py +15 -9
- zebra_day/cli/gui.py +21 -16
- zebra_day/cli/printer.py +34 -27
- zebra_day/cli/template.py +19 -15
- zebra_day/cmd_mgr.py +3 -6
- zebra_day/docs/gx420d-gx430d-ug-en.pdf +0 -0
- zebra_day/docs/hardware_config_guide.md +149 -0
- zebra_day/docs/programatic_guide.md +181 -0
- zebra_day/docs/qln420_zebra_manual.pdf +0 -0
- zebra_day/docs/uid_screed_light.md +38 -0
- zebra_day/docs/zd620-zd420-ug-en.pdf +0 -0
- zebra_day/docs/zebra_day_ui_guide.md +194 -0
- zebra_day/etc/printer_config.json +7 -1
- zebra_day/etc/printer_config.template.json +3 -17
- zebra_day/etc/tmp_printers139.json +10 -0
- zebra_day/etc/tmp_printers147.json +10 -0
- zebra_day/etc/tmp_printers34.json +10 -0
- zebra_day/etc/tmp_printers389.json +10 -0
- zebra_day/etc/tmp_printers398.json +10 -0
- zebra_day/etc/tmp_printers437.json +10 -0
- zebra_day/etc/tmp_printers439.json +10 -0
- zebra_day/etc/tmp_printers440.json +10 -0
- zebra_day/etc/tmp_printers508.json +10 -0
- zebra_day/etc/tmp_printers543.json +10 -0
- zebra_day/etc/tmp_printers835.json +10 -0
- zebra_day/etc/tmp_printers842.json +10 -0
- zebra_day/etc/tmp_printers931.json +10 -0
- zebra_day/etc/tmp_printers969.json +10 -0
- zebra_day/exceptions.py +1 -1
- zebra_day/files/corners_smallTube_preview.png +0 -0
- zebra_day/files/test_png_2897.png +0 -0
- zebra_day/files/test_png_31690.png +0 -0
- zebra_day/files/test_png_33804.png +0 -0
- zebra_day/files/test_png_34737.png +0 -0
- zebra_day/files/test_png_4161.png +0 -0
- zebra_day/files/test_png_44748.png +0 -0
- zebra_day/files/test_png_4635.png +0 -0
- zebra_day/files/test_png_56349.png +0 -0
- zebra_day/files/test_png_5936.png +0 -0
- zebra_day/files/test_png_64110.png +0 -0
- zebra_day/files/test_png_64891.png +0 -0
- zebra_day/files/test_png_69002.png +0 -0
- zebra_day/files/test_png_70065.png +0 -0
- zebra_day/files/test_png_72366.png +0 -0
- zebra_day/files/test_png_77793.png +0 -0
- zebra_day/files/test_png_9572.png +0 -0
- zebra_day/imgs/.hold +0 -0
- zebra_day/imgs/bar_ltpurp.png +0 -0
- zebra_day/imgs/bar_purp.png +0 -0
- zebra_day/imgs/bar_purp3.png +0 -0
- zebra_day/imgs/bar_red.png +0 -0
- zebra_day/imgs/legacy/UBC_gantt_chart.png +0 -0
- zebra_day/imgs/legacy/gx420d_network_config.png +0 -0
- zebra_day/imgs/legacy/gx420d_printer_config.png +0 -0
- zebra_day/imgs/legacy/ngrok.png +0 -0
- zebra_day/imgs/legacy/printer_details.png +0 -0
- zebra_day/imgs/legacy/quick_start_test_label.png +0 -0
- zebra_day/imgs/legacy/quick_start_test_label2.png +0 -0
- zebra_day/imgs/legacy/zd620_network_config.png +0 -0
- zebra_day/imgs/legacy/zd620_printer_config.png +0 -0
- zebra_day/imgs/legacy/zday_quick_gui.png +0 -0
- zebra_day/imgs/legacy/zebra_day_alt_css_dog.png +0 -0
- zebra_day/imgs/legacy/zebra_day_alt_css_flower.png +0 -0
- zebra_day/imgs/legacy/zebra_day_alt_css_main.png +0 -0
- zebra_day/imgs/legacy/zebra_day_available_zpl_templates.png +0 -0
- zebra_day/imgs/legacy/zebra_day_bkup_pconfig.png +0 -0
- zebra_day/imgs/legacy/zebra_day_home.png +0 -0
- zebra_day/imgs/legacy/zebra_day_manual_print.png +0 -0
- zebra_day/imgs/legacy/zebra_day_printer_fleet_json.png +0 -0
- zebra_day/imgs/legacy/zebra_day_quick_ex.png +0 -0
- zebra_day/imgs/legacy/zebra_day_zpl_template_IRLa.png +0 -0
- zebra_day/imgs/legacy/zebra_day_zpl_template_IRLb.png +0 -0
- zebra_day/imgs/ui_api_docs.png +0 -0
- zebra_day/imgs/ui_config.png +0 -0
- zebra_day/imgs/ui_dashboard.png +0 -0
- zebra_day/imgs/ui_print_request.png +0 -0
- zebra_day/imgs/ui_printers.png +0 -0
- zebra_day/imgs/ui_templates.png +0 -0
- zebra_day/logging_config.py +4 -9
- zebra_day/mkcert.py +157 -0
- zebra_day/paths.py +1 -2
- zebra_day/print_mgr.py +165 -145
- zebra_day/templates/modern/config.html +7 -0
- zebra_day/templates/modern/print_request.html +61 -3
- zebra_day/web/__init__.py +1 -1
- zebra_day/web/app.py +21 -16
- zebra_day/web/auth.py +17 -15
- zebra_day/web/middleware.py +8 -5
- zebra_day/web/routers/__init__.py +0 -1
- zebra_day/web/routers/api.py +192 -43
- zebra_day/web/routers/ui.py +31 -33
- zebra_day/zpl_renderer.py +45 -34
- {zebra_day-2.0.0.dist-info → zebra_day-2.1.4.dist-info}/METADATA +76 -67
- {zebra_day-2.0.0.dist-info → zebra_day-2.1.4.dist-info}/RECORD +101 -29
- {zebra_day-2.0.0.dist-info → zebra_day-2.1.4.dist-info}/WHEEL +0 -0
- {zebra_day-2.0.0.dist-info → zebra_day-2.1.4.dist-info}/entry_points.txt +0 -0
- {zebra_day-2.0.0.dist-info → zebra_day-2.1.4.dist-info}/licenses/LICENSE +0 -0
- {zebra_day-2.0.0.dist-info → zebra_day-2.1.4.dist-info}/top_level.txt +0 -0
zebra_day/cli/template.py
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"""ZPL template management commands for zebra_day CLI."""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
import json
|
|
4
6
|
import os
|
|
5
7
|
import subprocess
|
|
6
8
|
from pathlib import Path
|
|
7
|
-
from typing import
|
|
9
|
+
from typing import Any
|
|
8
10
|
|
|
9
11
|
import typer
|
|
10
12
|
from rich.console import Console
|
|
@@ -37,7 +39,7 @@ def _get_template_dirs() -> list[Path]:
|
|
|
37
39
|
return dirs
|
|
38
40
|
|
|
39
41
|
|
|
40
|
-
def _find_template(name: str) ->
|
|
42
|
+
def _find_template(name: str) -> Path | None:
|
|
41
43
|
"""Find a template file by name."""
|
|
42
44
|
for template_dir in _get_template_dirs():
|
|
43
45
|
# Try exact match
|
|
@@ -59,18 +61,20 @@ def list_templates(
|
|
|
59
61
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show full paths"),
|
|
60
62
|
):
|
|
61
63
|
"""List available ZPL templates."""
|
|
62
|
-
templates = []
|
|
64
|
+
templates: list[dict[str, Any]] = []
|
|
63
65
|
|
|
64
66
|
for template_dir in _get_template_dirs():
|
|
65
67
|
for f in template_dir.iterdir():
|
|
66
68
|
if f.is_file() and not f.name.startswith("."):
|
|
67
69
|
if f.suffix in [".zpl", ".txt", ""] or f.name.startswith("zpl_"):
|
|
68
|
-
templates.append(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
templates.append(
|
|
71
|
+
{
|
|
72
|
+
"name": f.stem,
|
|
73
|
+
"path": str(f),
|
|
74
|
+
"size": f.stat().st_size,
|
|
75
|
+
"source": "user" if "zebra_day" not in str(template_dir) else "package",
|
|
76
|
+
}
|
|
77
|
+
)
|
|
74
78
|
|
|
75
79
|
# Dedupe by name, prefer user templates
|
|
76
80
|
seen = {}
|
|
@@ -107,7 +111,7 @@ def list_templates(
|
|
|
107
111
|
@template_app.command("preview")
|
|
108
112
|
def preview(
|
|
109
113
|
template_name: str = typer.Argument(..., help="Template name to preview"),
|
|
110
|
-
output:
|
|
114
|
+
output: str | None = typer.Option(None, "--output", "-o", help="Output PNG file path"),
|
|
111
115
|
):
|
|
112
116
|
"""Generate a PNG preview of a ZPL template."""
|
|
113
117
|
template_path = _find_template(template_name)
|
|
@@ -119,6 +123,7 @@ def preview(
|
|
|
119
123
|
|
|
120
124
|
try:
|
|
121
125
|
import zebra_day.print_mgr as zdpm
|
|
126
|
+
|
|
122
127
|
zp = zdpm.zpl()
|
|
123
128
|
|
|
124
129
|
# Read template
|
|
@@ -130,18 +135,18 @@ def preview(
|
|
|
130
135
|
else:
|
|
131
136
|
output_path = Path(output)
|
|
132
137
|
|
|
133
|
-
|
|
138
|
+
zp.generate_label_png(zpl_content, str(output_path), False)
|
|
134
139
|
console.print(f"[green]✓[/green] Preview generated: {output_path}")
|
|
135
140
|
|
|
136
141
|
except Exception as e:
|
|
137
142
|
console.print(f"[red]✗[/red] Preview error: {e}")
|
|
138
|
-
raise typer.Exit(1)
|
|
143
|
+
raise typer.Exit(1) from None
|
|
139
144
|
|
|
140
145
|
|
|
141
146
|
@template_app.command("edit")
|
|
142
147
|
def edit(
|
|
143
148
|
template_name: str = typer.Argument(..., help="Template name to edit"),
|
|
144
|
-
editor:
|
|
149
|
+
editor: str | None = typer.Option(None, "--editor", "-e", help="Editor command"),
|
|
145
150
|
):
|
|
146
151
|
"""Open a ZPL template in an editor."""
|
|
147
152
|
template_path = _find_template(template_name)
|
|
@@ -158,7 +163,7 @@ def edit(
|
|
|
158
163
|
subprocess.run([editor, str(template_path)])
|
|
159
164
|
except Exception as e:
|
|
160
165
|
console.print(f"[red]✗[/red] Error opening editor: {e}")
|
|
161
|
-
raise typer.Exit(1)
|
|
166
|
+
raise typer.Exit(1) from None
|
|
162
167
|
|
|
163
168
|
|
|
164
169
|
@template_app.command("show")
|
|
@@ -173,4 +178,3 @@ def show(
|
|
|
173
178
|
|
|
174
179
|
console.print(f"[dim]# {template_path}[/dim]\n")
|
|
175
180
|
console.print(template_path.read_text())
|
|
176
|
-
|
zebra_day/cmd_mgr.py
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Tools to manage a zebra printer fleet and expose an API for routing print requests.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import socket
|
|
6
6
|
|
|
7
|
-
class ZebraPrinter:
|
|
8
7
|
|
|
8
|
+
class ZebraPrinter:
|
|
9
9
|
def __init__(self, ip_address, port=9100, buffer_size=1024):
|
|
10
10
|
self.ip_address = ip_address
|
|
11
11
|
self.port = port
|
|
12
12
|
self.buffer_size = buffer_size
|
|
13
13
|
|
|
14
|
-
|
|
15
14
|
def send_command(self, command):
|
|
16
15
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
17
16
|
s.connect((self.ip_address, self.port))
|
|
@@ -19,15 +18,13 @@ class ZebraPrinter:
|
|
|
19
18
|
response = s.recv(self.buffer_size)
|
|
20
19
|
return response.decode()
|
|
21
20
|
|
|
22
|
-
|
|
23
21
|
def get_configuration(self):
|
|
24
22
|
"""Retrieve printer configuration using ^HH command"""
|
|
25
23
|
return self.send_command("^XA^HH^XZ")
|
|
26
24
|
|
|
27
|
-
|
|
28
25
|
def set_configuration(self, config):
|
|
29
26
|
"""
|
|
30
|
-
Set printer configuration.
|
|
27
|
+
Set printer configuration.
|
|
31
28
|
The `config` parameter should contain the necessary ZPL commands to adjust the configuration.
|
|
32
29
|
After sending the configuration commands, the ^JUS command saves the configuration.
|
|
33
30
|
"""
|
|
Binary file
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
## Hardware
|
|
2
|
+
|
|
3
|
+
### Zebra Printers
|
|
4
|
+
* Printers will need to be able to secure an IP address either via a wired connection or via wireless. The printers will need to be visible to the machine running this package in order to accept print requests. Further, there are tools to scan the local network and identify Zebra Printers. Identified printers are automatically configured for use by `zebra_day`.
|
|
5
|
+
|
|
6
|
+
* Network attached printers should be able to run w/out any connection to a PC/laptop. This affors much greater flexibility in placing print stations. In fact, `zebra_day` does not communicate with USB only printers.
|
|
7
|
+
* The below zebra printer models have been tested, but any zebra printer able to obtain an IP address and accept `ZPL` should also work.
|
|
8
|
+
* _IMPORTANT_, The initial configuration of zebra printers can be a little gnarly. I intend to add some notes on this topic soon. In the mean time, the GUI printer status report includes links to access the web server admin utility each zebra printer exposes.
|
|
9
|
+
* the printer admin UIs all use the default un/pw: `admin/1234`.
|
|
10
|
+
* The first thing I suggest when setting up a new printer is resetting the factory defaults - doable via the zebra printer admin UIs.
|
|
11
|
+
* Wired ethernet connections are advised for greater robustness. Configure the wired network settings to obtain an IP automatically. ask your network admins to set DNS rules which will assign the same IP to each printer. You'll need to supply the printer MAC address to do this, which you can find on via each printers admin UI.
|
|
12
|
+
* __NOTE__ Sometimes these printers can not seem to obtain an IP with DHCP, this could be a router/hub issue, but sometimes you'll need to set the printer to a static IP. This can be done via the printer admin UI. If the network config is saved with an error, you'll now need to connect to the printer via USB to reset (there might be a button seuquece cycle which can be hit to factory reset...).
|
|
13
|
+
* Wireless setup is _SUPER_ fussy. You'll need to know precisely what bands your router is running on, and the precise auth used. This can be done via the zebra printer admin UI, or when connected via a USB cable to a computer running a driver config program(not advised really).
|
|
14
|
+
* Next, you may have to mess around with calibration settings for label width and length.
|
|
15
|
+
* I have used this driver/config tool on a MAC when I have needed to connect to a printer via `USB`, [Peninsula Zebra Printer Driver](https://www.peninsula-group.com/install-zebra-printer-mac-osx/install-zebra-printer-mac-osx.html). I'm fairly sure there are several windows options.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
#### GX420d - wired, no LCD screen
|
|
19
|
+
|
|
20
|
+
These printers are NOT reccomended b/c the lack of LCD screen makes them a pain to configure. You will probably need to connect via USB to set good initial settings. If you have the `zebra_day` UI running, try connecting the printer to the network and powering on, then run the zebra printer network scan. If the printer is discovered, you're in luck and can admin it via the UI on the printer.
|
|
21
|
+
|
|
22
|
+
* [Available From Amazon](https://www.amazon.com/gp/product/B07KCQ67Y1/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1)
|
|
23
|
+
* Cost per printer : `$264.00`
|
|
24
|
+
* [manual]()
|
|
25
|
+
|
|
26
|
+
#### GX420d - wired, with LCD screen
|
|
27
|
+
These are solid, but aging out and not as easy to find for sale.
|
|
28
|
+
|
|
29
|
+
* [Available From Amazon](https://www.amazon.com/gp/product/B011Q95XX2/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1)
|
|
30
|
+
* Cost per printer : `$425.00`
|
|
31
|
+
* [manual]()
|
|
32
|
+
|
|
33
|
+
#### ZD620d - wired and wireless, with color LCD screen
|
|
34
|
+
These are solid, but aging out and not as easy to find for sale.
|
|
35
|
+
|
|
36
|
+
* [Available From Amazon](https://www.amazon.com/gp/product/B07VHDR33Z/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1)
|
|
37
|
+
* Cost per printer : `$331.00`
|
|
38
|
+
* [manual]()
|
|
39
|
+
|
|
40
|
+
#### Zebra QLn420 Direct Thermal Printer - Monochrome - Portable
|
|
41
|
+
|
|
42
|
+
* [Amazon](https://www.amazon.com/dp/B084P4KBWS?psc=1&ref=ppx_yo2ov_dt_b_product_details)
|
|
43
|
+
* Cost per printer : `$136`
|
|
44
|
+
* [manual]()
|
|
45
|
+
|
|
46
|
+
#### Zebra - ZD620d Direct Thermal Desktop Printer with LCD Screen - Print Width 4 in - 203 dpi - Interface: WiFi, Bluetooth, USB, Serial, Ethernet - ZD62142-D01L01EZ
|
|
47
|
+
|
|
48
|
+
* [Amazon](https://www.amazon.com/dp/B07VHDR33Z?psc=1&ref=ppx_yo2ov_dt_b_product_details)
|
|
49
|
+
* Cost per printer : `$331`
|
|
50
|
+
* [manual]()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
#### Zebra ZD620t Thermal Transfer Desktop Printer 203 dpi Print Width 4 in Ethernet Serial USB ZD62042
|
|
54
|
+
<font color=magenta>note, this is a thermal transfer printer & requires ribbons to print</font>
|
|
55
|
+
* [Amazon](https://www.amazon.com/dp/B08PW6ZRL6?psc=1&ref=ppx_yo2ov_dt_b_product_details)
|
|
56
|
+
* Cost per printer : `$500`
|
|
57
|
+
* [manual]()
|
|
58
|
+
|
|
59
|
+
### Initial Printer Configuration
|
|
60
|
+
Ideally, you will be able to use `zebra_day` to auto-detect printers on your network, and connect to each ones web based admin tool (links are presented on the [printer fleet summary page](), un/pw is `admin/1234` ). Failing this, you will need to connect via usb, [there are several drivers to choose from if this is necessary, I liked this one for a MAC](https://www.peninsula-group.com/mac-thermal-printer-driver/). The main changes to make (and do so after consulting each printers manual):
|
|
61
|
+
* reset to factory defaults.
|
|
62
|
+
* set the network settings (wired and wifi) & hard code IPs if needed. It is helpful if they retain the same IP over time.
|
|
63
|
+
* Set the media type to `web`, set behavior on close and restart to be calibrate.
|
|
64
|
+
* Once you begin printing, you might find you need to adjust the print width and length for some printers if they do not set properly during calibration.
|
|
65
|
+
* Increase the darkness.
|
|
66
|
+
* Decrease print speed, `IPS` to 2 or 3.
|
|
67
|
+
|
|
68
|
+
##### Reference Printer Config Reports
|
|
69
|
+
* [GX420d - printer](zebra_day/imgs/legacy/gx420d_printer_config.png) .... [GX420d - network](zebra_day/imgs/legacy/gx420d_network_config.png)
|
|
70
|
+
* [ZD620 - printer](zebra_day/imgs/legacy/zd620_printer_config.png) .... [ZD620 - network](zebra_day/imgs/legacy/zd620_network_config.png)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
### Thermal Transfer Ribbons
|
|
76
|
+
Also require distinct label stock from the direct thermal transfer printer labels.
|
|
77
|
+
|
|
78
|
+
* [Amazon](https://www.amazon.com/dp/B07FX3PJ2M?psc=1&ref=ppx_yo2ov_dt_b_product_details)
|
|
79
|
+
* Cost per roll: `$7`
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# Label Stock
|
|
83
|
+
The `zebra_day` code can easily manage a printer fleet comprised of different printing mechanism.
|
|
84
|
+
|
|
85
|
+
> Thermal Transfer vs. Direct Thermal Transfer Labels
|
|
86
|
+
* Printers are only capable of printing using one or the other method only.
|
|
87
|
+
|
|
88
|
+
> Direct thermal transfer labels require no ribbon, cheaper, can be less robust in some situations, speciality use case label stock mfgs are numerous.
|
|
89
|
+
|
|
90
|
+
> Thermal transfer labels require a ribbon, can be more durable, prone to smudging, more costly
|
|
91
|
+
|
|
92
|
+
### Aegis Labels
|
|
93
|
+
For general purpose use. Very inexpensive and easy to source.
|
|
94
|
+
|
|
95
|
+
#### 2in x 1in - Direct TT
|
|
96
|
+
Good for paperwork, some larger tubes.
|
|
97
|
+
|
|
98
|
+
* [Amazon](https://www.amazon.com/gp/product/B098Z8JYZC/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&th=1)
|
|
99
|
+
* Cost per roll : `$3.21`
|
|
100
|
+
|
|
101
|
+
#### 2in x 0.5in - Direct TT
|
|
102
|
+
Good for smaller tubes, or tubes that already have space taken up by labels.
|
|
103
|
+
|
|
104
|
+
* [Available On Amazon](https://www.amazon.com/gp/product/B098Z8JYZC/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&th=1)
|
|
105
|
+
* Cost per roll : `$3.25`
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
### [Labtag](http://www.labtag.com)
|
|
109
|
+
|
|
110
|
+
#### 2in x 1in / a few colors / cryo - Direct TT
|
|
111
|
+
|
|
112
|
+
* [LabTag](https://www.labtag.com/shop/product/cryogenic-direct-thermal-labels-2-x-1-dfp-dfpc-28-2/?attribute_pa_core-size=1&attribute_pa_qty-uom=1000&attribute_pa_color=white)
|
|
113
|
+
* Cost per roll : `$81`
|
|
114
|
+
|
|
115
|
+
#### 2in x 0.25in / plate style / cryo - Direct TT
|
|
116
|
+
|
|
117
|
+
* [LabTag](https://www.labtag.com/shop/product/cryogenic-direct-thermal-labels-2-x-0-25-dfp-227/?attribute_pa_core-size=1&attribute_pa_qty-uom=2000)
|
|
118
|
+
* Cost per roll : `$67`
|
|
119
|
+
|
|
120
|
+
#### small tube w/dot / cryo - Direct TT
|
|
121
|
+
|
|
122
|
+
* [LabTag](https://www.labtag.com/shop/product/cryogenic-direct-thermal-labels-1-25-x-0-625-0-375-dfp-103/?attribute_pa_core-size=1&attribute_pa_qty-uom=2000)
|
|
123
|
+
* Cost per roll : `$105`
|
|
124
|
+
|
|
125
|
+
#### 2in x 1in / cryo / many colors - Thermal Transfer
|
|
126
|
+
|
|
127
|
+
* [LabTag](https://www.labtag.com/shop/product/cryogenic-barcode-labels-2-x-1-jtta-28/?attribute_pa_core-size=1&attribute_pa_qty-uom=2000&attribute_pa_color=white)
|
|
128
|
+
* Cost per roll : `$117`
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
#### 2in x 0.25in / plate / cryo - Thermal Transfer
|
|
132
|
+
|
|
133
|
+
* [LabTag](https://www.labtag.com/shop/product/thermal-transfer-cryogenic-labels-for-frozen-vials-surfaces-2-x-0-25-uc-227/?attribute_pa_core-size=1&attribute_pa_qty-uom=2000)
|
|
134
|
+
* Cost per roll : `$80`
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
# Barcode Scanners
|
|
138
|
+
|
|
139
|
+
## Tera 1d, 2d, QR scanner. Corded and bluetooth and wireless
|
|
140
|
+
Programable and well supported/adopted.
|
|
141
|
+
|
|
142
|
+
* [Available From Amazon](https://www.amazon.com/dp/B0953FJZDG?psc=1&ref=ppx_yo2ov_dt_b_product_details)
|
|
143
|
+
* Cost per scanner : `$63.00`
|
|
144
|
+
|
|
145
|
+
## Tera Mini 1d 2d QR. Corded and wireless and bluetooth.
|
|
146
|
+
_experimenting_... tiny handheld pretty well behaving non-corded scanner.
|
|
147
|
+
|
|
148
|
+
* [Available From Amazon](https://www.amazon.com/dp/B08NDFWFKJ?psc=1&ref=ppx_yo2ov_dt_b_product_details)
|
|
149
|
+
* Cost per Scanner : `$38.00`
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Library Usage
|
|
2
|
+
<a href=../../README.md ><img src="http://flux.glass/format_gh_text?txt=back+home&bg_color=%23443636&txt_color=%232eecef&font=Monoid-Regular-HalfTight-Dollar-0-1-l&font_size=12&width=95&ret_type=img" /></a>
|
|
3
|
+
## Quickstart
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
import zebra_day.print_mgr as zdpm
|
|
7
|
+
|
|
8
|
+
zlab = zdpm.zpl()
|
|
9
|
+
|
|
10
|
+
zlab.probe_zebra_printers_add_to_printers_json('192.168.1') # REPLACE the IP stub with the correct value for your network. This may take a few min to run. !! This command is not required if you've sucessuflly run the quickstart already, also, won't hurt.
|
|
11
|
+
|
|
12
|
+
print(zlab.printers) # This should print out the json dict of all detected zebra printers. An empty dict, {}, is a failure of autodetection, and manual creation of the json file may be needed. If successful, the lab name assigned is 'default', this may be edited later.
|
|
13
|
+
# The json will look something like this (v2.0.0 schema with nested printers)
|
|
14
|
+
## {'schema_version': '2.0.0', 'labs': {'default': {'lab_name': 'Default', 'printers': {'192.168.1.7': {'ip_address': '192.168.1.7', ...}}}}}
|
|
15
|
+
|
|
16
|
+
# Assuming a printer was detected, send a test print request. Using the 'lab', 'printer' and 'label_zpl_style' above (you'd have your own IP/Name, other values should remain the same for now. There are multiple label ZPL formats available, the test_2inX1in is for quick testing & only formats in the two UID values specified.
|
|
17
|
+
|
|
18
|
+
zlab.print_zpl(lab='default', printer_name='192.168.1.7', label_zpl_style='test_2inX1in', uid_barcode="123aUID")
|
|
19
|
+
# ZPL code sent successfully to the printer!
|
|
20
|
+
# Out[13]: '^XA\n^FO235,20\n^BY1\n^B3N,N,40,N,N\n^FD123aUID^FS\n^FO235,70\n^ADN,30,20\n^FD123aUID^FS\n^FO235,115\n^ADN,25,12\n^FDalt_a^FS\n^FO235,145\n^ADN,25,12\n^FDalt_b^FS\n^FO70,180\n^FO235,170\n^ADN,30,20\n^FDalt_c^FS\n^FO490,180\n^ADN,25,12\n^FDalt_d^FS\n^XZ'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Primary Operations
|
|
24
|
+
|
|
25
|
+
### Init Object
|
|
26
|
+
> def zpl():
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
import zebra_day.print_mgr as zdpm
|
|
31
|
+
|
|
32
|
+
zlab = zdpm.zpl()
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The IP of the machine creating the obj is determined, and the default printer config.json is read.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
### Load/Save/Clear Printer Config json
|
|
39
|
+
|
|
40
|
+
> As of 0.6.0, printer configuration is stored in XDG-compliant locations:
|
|
41
|
+
> - **Linux**: `~/.config/zebra_day/printer_config.json`
|
|
42
|
+
> - **macOS**: `~/Library/Preferences/zebra_day/printer_config.json`
|
|
43
|
+
>
|
|
44
|
+
> Use `zday info` to see the exact path on your system.
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
# These methods now use the XDG paths automatically
|
|
48
|
+
zlab.save_printer_json()
|
|
49
|
+
zlab.load_printer_json()
|
|
50
|
+
zlab.clear_printers_json()
|
|
51
|
+
zlab.replace_printer_json_from_template()
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
When clearing or writing a new config.json, the existing one is saved to a backup location. Users can open these and effectively rollback if errors are made. Replace from template means overwriting the active one with the json example file which accompanies the repo.
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
### Scan Local Network For Zebra Printers
|
|
58
|
+
> def probe_zebra_printers_add_to_printers_json(self, ip_stub="192.168.1", scan_wait="0.25",lab="scan-results"):
|
|
59
|
+
|
|
60
|
+
### Check label styles allowed for a lab
|
|
61
|
+
> def get_valid_label_styles_for_lab(self,lab=None):
|
|
62
|
+
|
|
63
|
+
A never quite implemented idea.
|
|
64
|
+
|
|
65
|
+
### Produce a ZPL string which will be sent to a printer
|
|
66
|
+
|
|
67
|
+
> def formulate_zpl(self,uid_barcode=None, alt_a=None, alt_b=None, alt_c=None, alt_d=None, alt_e=None, alt_f=None, label_zpl_style=None):
|
|
68
|
+
|
|
69
|
+
* The `lab` & `printer_name` are used to resolve the IP address for the printer this tuple identify.
|
|
70
|
+
* `label_zpl_style` is used to find the `zpl` template file the remaining values passed in are templated in to.
|
|
71
|
+
* `uid_barcode` is the value which is encoded as a barcode and presented in human readable form. The way this value is displayed will vary by template.
|
|
72
|
+
* `alt_[a-f]` these are used diferently, or not at all, depending on the zpl template.
|
|
73
|
+
|
|
74
|
+
### Send ZPL To Zebra To Print A Label
|
|
75
|
+
> def print_zpl(self, lab=None, printer_name=None, uid_barcode='', alt_a='', alt_b='', alt_c='', alt_d='', alt_e='', alt_f='', label_zpl_style=None, client_ip='pkg', print_n=1):
|
|
76
|
+
|
|
77
|
+
With the ZPL string produced, determine the printer IP and send the string to it.
|
|
78
|
+
|
|
79
|
+
### Send ZPL To PDF Generation Service
|
|
80
|
+
> def generate_label_png(self,zpl_string=None, png_fn=None):
|
|
81
|
+
|
|
82
|
+
Rather than print a physical label, produce a `png`... this is most helpful when we get to the UI.
|
|
83
|
+
|
|
84
|
+
## Data Structures
|
|
85
|
+
|
|
86
|
+
### Printer json (v2.0.0 Schema)
|
|
87
|
+
This is the file which describes the printer fleet. It may be manually edited or edited via the GUI.
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"schema_version": "2.0.0",
|
|
92
|
+
"labs": {
|
|
93
|
+
"default": {
|
|
94
|
+
"lab_name": "Default",
|
|
95
|
+
"available_locations": ["Bench A", "Bench B"],
|
|
96
|
+
"printers": {
|
|
97
|
+
"192.168.1.7": {
|
|
98
|
+
"ip_address": "192.168.1.7",
|
|
99
|
+
"printer_name": "Main Lab Printer",
|
|
100
|
+
"lab_location": "Bench A",
|
|
101
|
+
"manufacturer": "zebra",
|
|
102
|
+
"model": "ZD620",
|
|
103
|
+
"serial": "12345",
|
|
104
|
+
"label_zpl_styles": ["tube_2inX1in", "plate_1inX0.25in"],
|
|
105
|
+
"default_label_style": "tube_2inX1in",
|
|
106
|
+
"print_method": "socket",
|
|
107
|
+
"arp_data": "",
|
|
108
|
+
"notes": "Primary sample printer"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Schema v2.0.0 Changes:**
|
|
117
|
+
- `labs` now contains nested `printers` object (not flat printer entries)
|
|
118
|
+
- Added `lab_name` and `available_locations` at lab level
|
|
119
|
+
- Added `printer_name`, `lab_location`, `manufacturer`, `default_label_style`, `notes` at printer level
|
|
120
|
+
- Added `schema_version` at root level
|
|
121
|
+
|
|
122
|
+
The `lab` key in this example is `default`, which is the lab name assigned when autodetect runs. These names are editable via the GUI. Printers are nested under the `printers` key within each lab.
|
|
123
|
+
|
|
124
|
+
### Rendering ZPL to PNG (without printing)
|
|
125
|
+
|
|
126
|
+
To generate a PNG preview of a label without sending to a printer, use the `/api/v1/render` endpoint:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# Render using a template
|
|
130
|
+
curl -X POST "https://localhost:8118/api/v1/render" \
|
|
131
|
+
-H "Content-Type: application/json" \
|
|
132
|
+
-d '{
|
|
133
|
+
"template_name": "tube_2inX1in",
|
|
134
|
+
"uid_barcode": "SAMPLE123",
|
|
135
|
+
"alt_a": "Field A",
|
|
136
|
+
"alt_b": "Field B"
|
|
137
|
+
}' \
|
|
138
|
+
--output label.png
|
|
139
|
+
|
|
140
|
+
# Render raw ZPL content
|
|
141
|
+
curl -X POST "https://localhost:8118/api/v1/render" \
|
|
142
|
+
-H "Content-Type: application/json" \
|
|
143
|
+
-d '{
|
|
144
|
+
"zpl_content": "^XA^FO50,50^ADN,36,20^FDHello World^FS^XZ"
|
|
145
|
+
}' \
|
|
146
|
+
--output label.png
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The render endpoint returns a PNG image directly. This is useful for:
|
|
150
|
+
- Previewing labels before printing
|
|
151
|
+
- Generating label images for documentation
|
|
152
|
+
- Testing ZPL templates without physical printers
|
|
153
|
+
|
|
154
|
+
### ZPL Template Files
|
|
155
|
+
These are template files for various different label styles. These may be manually edited (but its a nicer expereience using the UI)
|
|
156
|
+
|
|
157
|
+
* Template files are easiest to design via the UI. The ZPL format is very old school word processor vibes.
|
|
158
|
+
|
|
159
|
+
```text
|
|
160
|
+
^XA
|
|
161
|
+
^FO200,20
|
|
162
|
+
^BY1
|
|
163
|
+
^B3N,N,40,N,N
|
|
164
|
+
^FD{uid_barcode}^FS
|
|
165
|
+
^FO200,70
|
|
166
|
+
^ADN,30,20
|
|
167
|
+
^FD{uid_barcode}^FS
|
|
168
|
+
^FO460,18
|
|
169
|
+
^ADN,24,14
|
|
170
|
+
^FD{alt_a}^FS
|
|
171
|
+
^FO515,62
|
|
172
|
+
^ADN,40,26
|
|
173
|
+
^FD{alt_b}^FS
|
|
174
|
+
^XZ
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
* The `{}` format keys match those from above in the zpl string formulation call.
|
|
178
|
+
* [ZPL docs](https://labelary.com/zpl.html)
|
|
179
|
+
* This ZPL creates this label:<ul>
|
|
180
|
+
|
|
181
|
+
<img width="312" alt="zpl_exa" src="https://github.com/Daylily-Informatics/zebra_day/assets/4713659/9d2b53b3-03d0-4095-9622-64273734ff76">
|
|
Binary file
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Unique Identifiers **** D R A F T NOTES ****
|
|
2
|
+
|
|
3
|
+
## Maxims
|
|
4
|
+
|
|
5
|
+
### Be unique in the namespace... if possible, even outside the namespace.
|
|
6
|
+
* Be extremely cautious when working with test and sandbox environments which produce potentially overlapping UIDs to your production systems. Better yet, do not produce UIDs which overlap with other systems you control. `barcode labels IRL`.
|
|
7
|
+
* Issued by a single UID authority.
|
|
8
|
+
|
|
9
|
+
### Absolutely should not change once issued.
|
|
10
|
+
|
|
11
|
+
### Each distinct thing deserves its own UID.
|
|
12
|
+
* corrolaries:
|
|
13
|
+
* copies of things are now distinct things, and should have their own UID (metadata and relationships should be stored indicating relationships to other UIDs).
|
|
14
|
+
* In other words __at all costs, avoid re-using UIDs for children of things. This may momentarily be convenient, but I can promise you in the end, you'll have more than made up for the immediate convenience with an unecessarily fragile and opaque process/system.
|
|
15
|
+
|
|
16
|
+
### Encode only the unique ID
|
|
17
|
+
#### Vigourously avoid encoding any meta data regarding the thing identied by a UID in the UID. Similarly, avoid encoding process/state information.
|
|
18
|
+
|
|
19
|
+
* There is one exception, 'enterprise UIDs', with a brief prefix indicating object have not been a problem in my experience ([see stripe thinking on this](stripe.com)). These prefixes even offer a benefit when talking about object classes, as well as speeding up certain database queries.
|
|
20
|
+
* A few tests to apply when this temptation presents itself (and it will, more than you'd like):
|
|
21
|
+
* Is the information being added to the UID mutable ever? And if the answer is 'almost never' or 'it should not happen(but not actively blocked by a system)', this is BAD. What if there was a clerical error post UID assignment and now the UID does not reflect the corrected info? Chage the UID? (bad idea, see above)
|
|
22
|
+
* Is there a better way to accomplish whatever use case having the additional data in the UID is attempting to meet (in effectively every situation I've encountered, the answer is yes). Explore how to better serve this use case with other solutions.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Use only alpha numeric characters, ideally all uppercase alpha, no special characters.
|
|
26
|
+
* This means no `-`
|
|
27
|
+
|
|
28
|
+
### Under no circumstances should you add 0's as a prefix to a number being used as a UID
|
|
29
|
+
* If a UID is randomly assigning alphanumeric and leading 0s happen to be assigned, is the only exception I can imagine. Otherwise, this is a huge driver of errors, and mostly of the silent variety.
|
|
30
|
+
* Consider this: are `EX001` and `EX1` the same? What about `EX0001`? The answer is that to software at least, these are each unique UIDs. To people, these more often than not are all `EX1`, and are spoken about this way very frequently. Also - the leading zeros are often omitted when writing the UID down.
|
|
31
|
+
* The arguments for using padded zeros boil down to `they look good in spreadsheets`. Which is not a very compelling reason to adopt a very error prone and fragile design element.
|
|
32
|
+
* What happens when you outgrow the pre-establised number of characters?
|
|
33
|
+
* many s/w systems will auto trim the leading zeros.
|
|
34
|
+
* some barcode scanners will trim leading zeros.
|
|
35
|
+
* What if leading zeros are adjacent to the character 'O'?
|
|
36
|
+
|
|
37
|
+
### Reading and writing UIDs should not be done by hand
|
|
38
|
+
* label printers and scanners.
|
|
Binary file
|