zebra-day 1.0.2__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 +101 -13
- 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 +5 -11
- zebra_day/etc/printer_config.template.json +5 -11
- zebra_day/etc/tmp_printers120.json +10 -0
- zebra_day/etc/tmp_printers139.json +10 -0
- zebra_day/etc/tmp_printers145.json +10 -0
- zebra_day/etc/tmp_printers147.json +10 -0
- zebra_day/etc/tmp_printers207.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_printers469.json +10 -0
- zebra_day/etc/tmp_printers485.json +10 -0
- zebra_day/etc/tmp_printers508.json +10 -0
- zebra_day/etc/tmp_printers531.json +10 -0
- zebra_day/etc/tmp_printers540.json +10 -0
- zebra_day/etc/tmp_printers542.json +10 -0
- zebra_day/etc/tmp_printers543.json +10 -0
- zebra_day/etc/tmp_printers552.json +10 -0
- zebra_day/etc/tmp_printers715.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/etc/tmp_printers972.json +10 -0
- zebra_day/exceptions.py +1 -1
- zebra_day/files/blank_preview.png +0 -0
- zebra_day/files/corners_20cmX30cm_preview.png +0 -0
- zebra_day/files/corners_smallTube_preview.png +0 -0
- zebra_day/files/generic_2inX1in_preview.png +0 -0
- zebra_day/files/test_png_12020.png +0 -0
- zebra_day/files/test_png_12352.png +0 -0
- zebra_day/files/test_png_15472.png +0 -0
- zebra_day/files/test_png_24493.png +0 -0
- zebra_day/files/test_png_2897.png +0 -0
- zebra_day/files/test_png_30069.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_47791.png +0 -0
- zebra_day/files/test_png_47799.png +0 -0
- zebra_day/files/test_png_55588.png +0 -0
- zebra_day/files/test_png_56349.png +0 -0
- zebra_day/files/test_png_58809.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_67242.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_89893.png +0 -0
- zebra_day/files/test_png_9572.png +0 -0
- zebra_day/files/tube_20mmX30mmA_preview.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 +261 -185
- zebra_day/templates/modern/config.html +7 -0
- zebra_day/templates/modern/config_backups.html +59 -0
- zebra_day/templates/modern/config_editor.html +95 -0
- zebra_day/templates/modern/config_new.html +93 -0
- zebra_day/templates/modern/print_request.html +70 -8
- zebra_day/templates/modern/printer_detail.html +161 -34
- zebra_day/templates/modern/printers.html +17 -6
- zebra_day/templates/modern/template_editor.html +7 -4
- zebra_day/web/__init__.py +1 -1
- zebra_day/web/app.py +99 -17
- 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 +330 -31
- zebra_day/web/routers/ui.py +174 -591
- zebra_day/zpl_renderer.py +45 -34
- {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/METADATA +144 -74
- zebra_day-2.1.4.dist-info/RECORD +240 -0
- zebra_day/bin/fetch_zebra_config.py +0 -15
- zebra_day/bin/generate_coord_grid_zpl.py +0 -50
- zebra_day/bin/print_zpl_from_file.py +0 -21
- zebra_day/bin/probe_new_label_dimensions.py +0 -75
- zebra_day/bin/scan_for_networed_zebra_printers.py +0 -23
- zebra_day/bin/scan_for_networed_zebra_printers_arp_scan.sh +0 -1
- zebra_day/bin/scan_for_networed_zebra_printers_curl.sh +0 -30
- zebra_day/bin/zserve.py +0 -1062
- zebra_day/templates/base.html +0 -36
- zebra_day/templates/bpr.html +0 -72
- zebra_day/templates/build_new_config.html +0 -36
- zebra_day/templates/build_print_request.html +0 -32
- zebra_day/templates/chg_ui_style.html +0 -19
- zebra_day/templates/edit_template.html +0 -128
- zebra_day/templates/edit_zpl.html +0 -37
- zebra_day/templates/index.html +0 -82
- zebra_day/templates/legacy/base.html +0 -37
- zebra_day/templates/legacy/bpr.html +0 -72
- zebra_day/templates/legacy/build_new_config.html +0 -36
- zebra_day/templates/legacy/build_print_request.html +0 -32
- zebra_day/templates/legacy/chg_ui_style.html +0 -19
- zebra_day/templates/legacy/edit_template.html +0 -128
- zebra_day/templates/legacy/edit_zpl.html +0 -37
- zebra_day/templates/legacy/index.html +0 -82
- zebra_day/templates/legacy/list_prior_configs.html +0 -24
- zebra_day/templates/legacy/print_result.html +0 -30
- zebra_day/templates/legacy/printer_details.html +0 -25
- zebra_day/templates/legacy/printer_status.html +0 -70
- zebra_day/templates/legacy/save_result.html +0 -17
- zebra_day/templates/legacy/send_print_request.html +0 -34
- zebra_day/templates/legacy/simple_print.html +0 -94
- zebra_day/templates/legacy/view_pstation_json.html +0 -29
- zebra_day/templates/list_prior_configs.html +0 -24
- zebra_day/templates/print_result.html +0 -30
- zebra_day/templates/printer_details.html +0 -25
- zebra_day/templates/printer_status.html +0 -70
- zebra_day/templates/save_result.html +0 -17
- zebra_day/templates/send_print_request.html +0 -34
- zebra_day/templates/simple_print.html +0 -94
- zebra_day/templates/view_pstation_json.html +0 -29
- zebra_day-1.0.2.dist-info/RECORD +0 -179
- {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/WHEEL +0 -0
- {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/entry_points.txt +0 -0
- {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/licenses/LICENSE +0 -0
- {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/top_level.txt +0 -0
zebra_day/print_mgr.py
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
Primary zebra_day module. Primary functions: consistent and clear management
|
|
3
|
+
of 1+ networked zebra printers, automated discovery of printers on a
|
|
4
|
+
network. Clear formulation and delivery of ZPL strings to destination
|
|
5
|
+
printers. Management of zpl template files, which may have format value
|
|
6
|
+
components for inserting data on the fly. (elsewhere, a simple ui on
|
|
7
|
+
top of this).
|
|
8
|
+
|
|
9
|
+
This module is primarily focused on print request and package config mgmt.
|
|
10
|
+
See 'cmd_mgr' for interacting with zebras printer config capabilities.
|
|
11
11
|
"""
|
|
12
|
+
|
|
12
13
|
from __future__ import annotations
|
|
13
14
|
|
|
14
15
|
import datetime
|
|
@@ -17,19 +18,18 @@ import os
|
|
|
17
18
|
import shutil
|
|
18
19
|
import socket
|
|
19
20
|
import subprocess
|
|
20
|
-
import sys
|
|
21
21
|
import time
|
|
22
|
-
from pathlib import Path
|
|
23
|
-
|
|
24
22
|
from importlib.resources import files
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from typing import Literal
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
import zebra_day.cmd_mgr as zdcm
|
|
27
27
|
from zebra_day import paths as xdg
|
|
28
|
+
from zebra_day.logging_config import get_logger
|
|
28
29
|
|
|
29
30
|
_log = get_logger(__name__)
|
|
30
31
|
|
|
31
32
|
|
|
32
|
-
|
|
33
33
|
def get_current_date():
|
|
34
34
|
"""
|
|
35
35
|
get the current datetime
|
|
@@ -45,11 +45,11 @@ def send_zpl_code(zpl_code, printer_ip, printer_port=9100, is_test=False):
|
|
|
45
45
|
The bit which passes the zpl to the specified printer.
|
|
46
46
|
Port is more or less hard coded upstream from here fwiw
|
|
47
47
|
"""
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
# In the case we are testing only, return None
|
|
50
50
|
if is_test:
|
|
51
51
|
return None
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
# Create a socket object
|
|
54
54
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
55
55
|
timeout = 5
|
|
@@ -63,18 +63,23 @@ def send_zpl_code(zpl_code, printer_ip, printer_port=9100, is_test=False):
|
|
|
63
63
|
# ... the zebra printer will not throw an error if the request
|
|
64
64
|
# content is incorrect, or for any reason except to reject request to the wrong port.
|
|
65
65
|
return_code = sock.sendall(zpl_code.encode())
|
|
66
|
-
if return_code
|
|
66
|
+
if return_code in [None]:
|
|
67
67
|
_log.info("ZPL code sent successfully to printer %s:%d", printer_ip, printer_port)
|
|
68
68
|
else:
|
|
69
|
-
raise Exception(
|
|
70
|
-
|
|
69
|
+
raise Exception(
|
|
70
|
+
f"\n\nPrint request to {printer_ip}:{printer_port} did not return None, but instead: {return_code} ... zpl: {zpl_code}\n"
|
|
71
|
+
)
|
|
72
|
+
|
|
71
73
|
except ConnectionError as e:
|
|
72
|
-
raise Exception(
|
|
74
|
+
raise Exception(
|
|
75
|
+
f"Error connecting to the printer: {printer_ip} on port {printer_port} \n\n\t" + str(e)
|
|
76
|
+
) from e
|
|
73
77
|
|
|
74
78
|
finally:
|
|
75
79
|
# Close the socket connection
|
|
76
80
|
sock.close()
|
|
77
81
|
|
|
82
|
+
|
|
78
83
|
"""
|
|
79
84
|
The zpl.printers object is critical part of zebra_day. There is an in memory js on which can be stored to an active use json file. This active use file is
|
|
80
85
|
used when creating a new zpl() class. If absent, a minimal viable json
|
|
@@ -92,7 +97,7 @@ class zpl:
|
|
|
92
97
|
from zebra_day import print_mgr as zd
|
|
93
98
|
zd_pm = zd.zpl()
|
|
94
99
|
"""
|
|
95
|
-
|
|
100
|
+
|
|
96
101
|
def __init__(self, json_config: str | None = None):
|
|
97
102
|
"""
|
|
98
103
|
Initialize the class.
|
|
@@ -106,10 +111,10 @@ class zpl:
|
|
|
106
111
|
|
|
107
112
|
# Determine config file location (XDG first, then package fallback)
|
|
108
113
|
xdg_config = xdg.get_printer_config_path()
|
|
109
|
-
pkg_config = Path(str(files(
|
|
114
|
+
pkg_config = Path(str(files("zebra_day"))) / "etc" / "printer_config.json"
|
|
110
115
|
|
|
111
116
|
if json_config:
|
|
112
|
-
jcfg = Path(json_config) if not json_config.startswith(
|
|
117
|
+
jcfg = Path(json_config) if not json_config.startswith("/") else Path(json_config)
|
|
113
118
|
elif xdg_config.exists():
|
|
114
119
|
jcfg = xdg_config
|
|
115
120
|
elif pkg_config.exists():
|
|
@@ -122,10 +127,12 @@ class zpl:
|
|
|
122
127
|
else:
|
|
123
128
|
self.create_new_printers_json_with_single_test_printer(str(jcfg))
|
|
124
129
|
|
|
125
|
-
|
|
126
|
-
|
|
130
|
+
def probe_zebra_printers_add_to_printers_json(
|
|
131
|
+
self, ip_stub="192.168.1", scan_wait="0.25", lab="default", relative=False
|
|
132
|
+
):
|
|
127
133
|
"""
|
|
128
|
-
Scan the network for zebra printers
|
|
134
|
+
Scan the network for zebra printers.
|
|
135
|
+
|
|
129
136
|
NOTE! this should work with no dependencies on a MAC
|
|
130
137
|
UBUNTU requires system wide net-tools (for arp)
|
|
131
138
|
Others... well, this may not work
|
|
@@ -133,66 +140,102 @@ class zpl:
|
|
|
133
140
|
---
|
|
134
141
|
Requires:
|
|
135
142
|
curl is pretty standard, arp seems less so
|
|
136
|
-
arp
|
|
143
|
+
arp
|
|
137
144
|
---
|
|
138
|
-
|
|
139
|
-
ip_stub = all 255 possibilities will be probed beneath this
|
|
140
|
-
stub provided
|
|
141
145
|
|
|
142
|
-
|
|
143
|
-
default may be too
|
|
144
|
-
|
|
145
|
-
lab = code for the lab key to add/update to given finding
|
|
146
|
-
new printers. Existing printers will be over written.
|
|
146
|
+
ip_stub = all 255 possibilities will be probed beneath this stub provided
|
|
147
|
+
scan_wait = seconds to re-try probing until moving on. 0.25 default may be too quick
|
|
148
|
+
lab = code for the lab key to add/update to given finding new printers
|
|
147
149
|
"""
|
|
148
|
-
|
|
149
|
-
if
|
|
150
|
-
self.printers[
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
[
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
150
|
+
# Ensure schema version is set
|
|
151
|
+
if "schema_version" not in self.printers:
|
|
152
|
+
self.printers["schema_version"] = "2.0.0"
|
|
153
|
+
|
|
154
|
+
# Initialize lab with v2 structure if not exists
|
|
155
|
+
if lab not in self.printers["labs"]:
|
|
156
|
+
self.printers["labs"][lab] = {
|
|
157
|
+
"lab_name": lab.replace("-", " ").title(),
|
|
158
|
+
"available_locations": [],
|
|
159
|
+
"printers": {},
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
# Ensure lab has printers sub-object (migration from v1)
|
|
163
|
+
if "printers" not in self.printers["labs"][lab]:
|
|
164
|
+
self.printers["labs"][lab]["printers"] = {}
|
|
165
|
+
self.printers["labs"][lab].setdefault("lab_name", lab.replace("-", " ").title())
|
|
166
|
+
self.printers["labs"][lab].setdefault("available_locations", [])
|
|
167
|
+
|
|
168
|
+
# Scan network for Zebra printers using pure Python
|
|
169
|
+
wait_time = float(scan_wait) if scan_wait else 0.25
|
|
170
|
+
|
|
171
|
+
for i in range(1, 255):
|
|
172
|
+
ip = f"{ip_stub}.{i}"
|
|
173
|
+
try:
|
|
174
|
+
# Try to connect to ZPL port (9100)
|
|
175
|
+
import socket
|
|
176
|
+
|
|
177
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
178
|
+
sock.settimeout(wait_time)
|
|
179
|
+
result = sock.connect_ex((ip, 9100))
|
|
180
|
+
sock.close()
|
|
181
|
+
|
|
182
|
+
if result == 0:
|
|
183
|
+
# Port is open, try to get printer info
|
|
184
|
+
model = "Unknown"
|
|
185
|
+
serial = "Unknown"
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
# Query printer for model and serial
|
|
189
|
+
printer = zdcm.ZebraPrinter(ip)
|
|
190
|
+
config = printer.get_configuration()
|
|
191
|
+
|
|
192
|
+
# Parse model from config
|
|
193
|
+
if "MODEL" in config:
|
|
194
|
+
for line in config.split("\n"):
|
|
195
|
+
if "MODEL" in line.upper():
|
|
196
|
+
parts = line.split(":")
|
|
197
|
+
if len(parts) > 1:
|
|
198
|
+
model = parts[1].strip()
|
|
199
|
+
break
|
|
200
|
+
|
|
201
|
+
# Parse serial from config
|
|
202
|
+
if "SERIAL" in config.upper():
|
|
203
|
+
for line in config.split("\n"):
|
|
204
|
+
if "SERIAL" in line.upper():
|
|
205
|
+
parts = line.split(":")
|
|
206
|
+
if len(parts) > 1:
|
|
207
|
+
serial = parts[1].strip()
|
|
208
|
+
break
|
|
209
|
+
except Exception:
|
|
210
|
+
pass # Use defaults if we can't query printer
|
|
211
|
+
|
|
212
|
+
if ip not in self.printers["labs"][lab]["printers"]:
|
|
213
|
+
# The label formats set here are the installed defaults
|
|
214
|
+
self.printers["labs"][lab]["printers"][ip] = {
|
|
215
|
+
"ip_address": ip,
|
|
216
|
+
"printer_name": None, # User can set friendly name later
|
|
217
|
+
"lab_location": None, # User can set location later
|
|
218
|
+
"manufacturer": "zebra",
|
|
219
|
+
"model": model,
|
|
220
|
+
"serial": serial,
|
|
221
|
+
"label_zpl_styles": [
|
|
222
|
+
"tube_2inX1in",
|
|
223
|
+
"plate_1inX0.25in",
|
|
224
|
+
"tube_2inX0.3in",
|
|
225
|
+
],
|
|
226
|
+
"default_label_style": "tube_2inX1in", # Default to first style
|
|
227
|
+
"print_method": "socket",
|
|
228
|
+
"arp_data": "",
|
|
229
|
+
"notes": "",
|
|
230
|
+
}
|
|
231
|
+
except Exception:
|
|
232
|
+
pass # Skip unreachable IPs
|
|
191
233
|
|
|
192
234
|
self.save_printer_json(self.printers_filename, relative=False)
|
|
193
235
|
|
|
194
|
-
|
|
195
|
-
|
|
236
|
+
def save_printer_json(
|
|
237
|
+
self, json_filename: str = "/etc/printer_config.json", relative: bool = True
|
|
238
|
+
) -> None:
|
|
196
239
|
"""
|
|
197
240
|
Save the current self.printers to the specified JSON file.
|
|
198
241
|
|
|
@@ -204,12 +247,12 @@ class zpl:
|
|
|
204
247
|
"""
|
|
205
248
|
# Resolve the target path
|
|
206
249
|
if relative:
|
|
207
|
-
json_path = Path(str(files(
|
|
250
|
+
json_path = Path(str(files("zebra_day"))) / json_filename.lstrip("/")
|
|
208
251
|
else:
|
|
209
252
|
json_path = Path(json_filename)
|
|
210
253
|
|
|
211
254
|
# Create backup if file exists
|
|
212
|
-
if hasattr(self,
|
|
255
|
+
if hasattr(self, "printers_filename") and Path(self.printers_filename).exists():
|
|
213
256
|
backup_dir = xdg.get_config_backups_dir()
|
|
214
257
|
rec_date = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
|
215
258
|
backup_path = backup_dir / f"{rec_date}_printer_config.json"
|
|
@@ -221,70 +264,68 @@ class zpl:
|
|
|
221
264
|
|
|
222
265
|
# Save the config
|
|
223
266
|
json_path.parent.mkdir(parents=True, exist_ok=True)
|
|
224
|
-
with open(json_path,
|
|
267
|
+
with open(json_path, "w") as json_file:
|
|
225
268
|
json.dump(self.printers, json_file, indent=4)
|
|
226
269
|
|
|
227
270
|
self.load_printer_json(str(json_path), relative=False)
|
|
228
271
|
|
|
229
|
-
|
|
230
|
-
def load_printer_json(self, json_file=f"etc/printer_config.json", relative=True):
|
|
272
|
+
def load_printer_json(self, json_file="etc/printer_config.json", relative=True):
|
|
231
273
|
"""
|
|
232
274
|
Loads printer json from a specified file, saves it to the active json.
|
|
233
275
|
If specified file does not exist, it is created with the base
|
|
234
276
|
printers json
|
|
235
|
-
|
|
277
|
+
|
|
236
278
|
json_file = path to file
|
|
237
279
|
"""
|
|
238
280
|
if relative:
|
|
239
281
|
json_file = f"{str(files('zebra_day'))}/{json_file}"
|
|
240
282
|
else:
|
|
241
283
|
pass
|
|
242
|
-
|
|
284
|
+
|
|
243
285
|
_log.debug("Loading printer config from: %s", json_file)
|
|
244
286
|
|
|
245
287
|
if not os.path.exists(json_file):
|
|
246
|
-
raise Exception(
|
|
288
|
+
raise Exception(
|
|
289
|
+
f"""The file specified does not exist. Consider specifying the default 'etc/printer_config.json , provided: {json_file}, which had {str(files("zebra_day"))} prefixed to it', for {json_file}"""
|
|
290
|
+
)
|
|
247
291
|
fh = open(json_file)
|
|
248
292
|
self.printers_filename = json_file
|
|
249
293
|
self.printers = json.load(fh)
|
|
250
294
|
# self.save_printer_json() <--- use the save_printer_json call after calling this. Else, recursion.
|
|
251
|
-
|
|
252
295
|
|
|
253
296
|
def create_new_printers_json_with_single_test_printer(self, fn=None):
|
|
254
297
|
"""
|
|
255
298
|
Create a new printers json with just the png printer defined
|
|
256
299
|
"""
|
|
257
300
|
|
|
258
|
-
|
|
259
301
|
if fn in [None]:
|
|
260
|
-
fn = str(files(
|
|
261
|
-
|
|
262
|
-
if not hasattr(self,
|
|
302
|
+
fn = str(files("zebra_day")) + "/etc/printer_config.json"
|
|
303
|
+
|
|
304
|
+
if not hasattr(self, "printers"):
|
|
263
305
|
self.printers = {}
|
|
264
306
|
self.printers_filename = fn
|
|
265
307
|
|
|
266
308
|
jdat = None
|
|
267
|
-
with open(f"{str(files('zebra_day'))}/etc/printer_config.template.json"
|
|
309
|
+
with open(f"{str(files('zebra_day'))}/etc/printer_config.template.json") as file:
|
|
268
310
|
jdat = json.load(file)
|
|
269
|
-
|
|
311
|
+
|
|
270
312
|
self.printers = jdat
|
|
271
|
-
|
|
272
|
-
self.save_printer_json(fn, relative=False)
|
|
273
313
|
|
|
314
|
+
self.save_printer_json(fn, relative=False)
|
|
274
315
|
|
|
275
316
|
def clear_printers_json(self, json_file: str = "/etc/printer_config.json") -> None:
|
|
276
317
|
"""
|
|
277
|
-
Reset printers JSON to empty minimal structure.
|
|
318
|
+
Reset printers JSON to empty minimal v2.0.0 structure.
|
|
278
319
|
|
|
279
320
|
Args:
|
|
280
321
|
json_file: Path to the config file (relative to package)
|
|
281
322
|
"""
|
|
282
|
-
json_path = Path(str(files(
|
|
323
|
+
json_path = Path(str(files("zebra_day"))) / json_file.lstrip("/")
|
|
283
324
|
|
|
284
|
-
# Write empty config
|
|
285
|
-
empty_config = {"labs": {}}
|
|
325
|
+
# Write empty config with v2 schema
|
|
326
|
+
empty_config = {"schema_version": "2.0.0", "labs": {}}
|
|
286
327
|
json_path.parent.mkdir(parents=True, exist_ok=True)
|
|
287
|
-
with open(json_path,
|
|
328
|
+
with open(json_path, "w") as f:
|
|
288
329
|
json.dump(empty_config, f, indent=4)
|
|
289
330
|
|
|
290
331
|
self.printers_filename = str(json_path)
|
|
@@ -298,7 +339,7 @@ class zpl:
|
|
|
298
339
|
|
|
299
340
|
Copies the template JSON to the active config location.
|
|
300
341
|
"""
|
|
301
|
-
pkg_path = Path(str(files(
|
|
342
|
+
pkg_path = Path(str(files("zebra_day")))
|
|
302
343
|
template_path = pkg_path / "etc" / "printer_config.template.json"
|
|
303
344
|
target_path = pkg_path / "etc" / "printer_config.json"
|
|
304
345
|
|
|
@@ -311,33 +352,42 @@ class zpl:
|
|
|
311
352
|
|
|
312
353
|
self.save_printer_json(self.printers_filename, relative=False)
|
|
313
354
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
def get_valid_label_styles_for_lab(self,lab=None):
|
|
355
|
+
def get_valid_label_styles_for_lab(self, lab=None):
|
|
317
356
|
"""
|
|
318
|
-
|
|
319
|
-
being requested for use in printing to some printer
|
|
320
|
-
was 'allowed' by checking with that printers printer json
|
|
321
|
-
for the array of valid templates.
|
|
357
|
+
Get all unique label styles available for printers in a lab.
|
|
322
358
|
|
|
323
|
-
|
|
359
|
+
The intention for this method was to confirm a template
|
|
360
|
+
being requested for use in printing to some printer
|
|
361
|
+
was 'allowed' by checking with that printers printer json
|
|
362
|
+
for the array of valid templates.
|
|
324
363
|
|
|
364
|
+
This was a huge PITA in testing, could be re-enabled at some point.
|
|
325
365
|
It is used once, but prints a warning only.
|
|
326
366
|
"""
|
|
327
|
-
|
|
328
367
|
unique_labels = set()
|
|
329
368
|
|
|
330
|
-
|
|
331
|
-
|
|
369
|
+
# Access printers via nested 'printers' key (v2 schema)
|
|
370
|
+
lab_printers = self.printers["labs"][lab].get("printers", {})
|
|
371
|
+
for _printer_id, printer_data in lab_printers.items():
|
|
372
|
+
for style in printer_data.get("label_zpl_styles", []):
|
|
332
373
|
unique_labels.add(style)
|
|
333
374
|
|
|
334
375
|
result = list(unique_labels)
|
|
335
376
|
return result
|
|
336
377
|
|
|
337
|
-
|
|
338
378
|
# Given these inputs, format them in to the specified zpl template and
|
|
339
379
|
# prepare a string to send to a printer
|
|
340
|
-
def formulate_zpl(
|
|
380
|
+
def formulate_zpl(
|
|
381
|
+
self,
|
|
382
|
+
uid_barcode=None,
|
|
383
|
+
alt_a=None,
|
|
384
|
+
alt_b=None,
|
|
385
|
+
alt_c=None,
|
|
386
|
+
alt_d=None,
|
|
387
|
+
alt_e=None,
|
|
388
|
+
alt_f=None,
|
|
389
|
+
label_zpl_style=None,
|
|
390
|
+
):
|
|
341
391
|
"""
|
|
342
392
|
Produce a ZPL string using the specified zpl template file, and
|
|
343
393
|
formatting in the values, where appropriate.
|
|
@@ -350,21 +400,30 @@ class zpl:
|
|
|
350
400
|
the zpl templates. They may be used in any way. uid_barcode
|
|
351
401
|
just differntiates one.
|
|
352
402
|
"""
|
|
353
|
-
|
|
354
|
-
zpl_file = str(files(
|
|
403
|
+
|
|
404
|
+
zpl_file = str(files("zebra_day")) + f"/etc/label_styles/{label_zpl_style}.zpl"
|
|
355
405
|
if not os.path.exists(zpl_file):
|
|
356
|
-
zpl_file = str(files(
|
|
406
|
+
zpl_file = str(files("zebra_day")) + f"/etc/label_styles/tmps/{label_zpl_style}.zpl"
|
|
357
407
|
if not os.path.exists(zpl_file):
|
|
358
|
-
raise Exception(
|
|
408
|
+
raise Exception(
|
|
409
|
+
f"ZPL File : {zpl_file} does not exist in the TOPLEVEL or TMPS zebra_day/etc/label_styles dir."
|
|
410
|
+
)
|
|
359
411
|
|
|
360
|
-
with open(zpl_file
|
|
412
|
+
with open(zpl_file) as file:
|
|
361
413
|
content = file.read()
|
|
362
|
-
zpl_string = content.format(
|
|
414
|
+
zpl_string = content.format(
|
|
415
|
+
uid_barcode=uid_barcode,
|
|
416
|
+
alt_a=alt_a,
|
|
417
|
+
alt_b=alt_b,
|
|
418
|
+
alt_c=alt_c,
|
|
419
|
+
alt_d=alt_d,
|
|
420
|
+
alt_e=alt_e,
|
|
421
|
+
alt_f=alt_f,
|
|
422
|
+
label_zpl_style=label_zpl_style,
|
|
423
|
+
)
|
|
363
424
|
|
|
364
425
|
return zpl_string
|
|
365
426
|
|
|
366
|
-
|
|
367
|
-
|
|
368
427
|
def generate_label_png(self, zpl_string=None, png_fn=None, relative=False):
|
|
369
428
|
"""
|
|
370
429
|
Generate a PNG image from ZPL string using local renderer.
|
|
@@ -384,10 +443,10 @@ class zpl:
|
|
|
384
443
|
from zebra_day.zpl_renderer import render_zpl_to_png
|
|
385
444
|
|
|
386
445
|
if relative:
|
|
387
|
-
png_fn = str(files(
|
|
446
|
+
png_fn = str(files("zebra_day")) + "/" + png_fn
|
|
388
447
|
|
|
389
448
|
if zpl_string is None or png_fn is None:
|
|
390
|
-
raise ValueError(
|
|
449
|
+
raise ValueError("ERROR: zpl_string and png_fn may not be None.")
|
|
391
450
|
|
|
392
451
|
try:
|
|
393
452
|
result = render_zpl_to_png(zpl_string, png_fn)
|
|
@@ -396,90 +455,110 @@ class zpl:
|
|
|
396
455
|
except Exception as e:
|
|
397
456
|
_log.error("Failed to convert ZPL to image: %s", e)
|
|
398
457
|
raise
|
|
399
|
-
|
|
400
458
|
|
|
401
|
-
def print_raw_zpl(self,zpl_content,printer_ip, port=9100):
|
|
459
|
+
def print_raw_zpl(self, zpl_content, printer_ip, port=9100):
|
|
402
460
|
"""
|
|
403
461
|
For use when no use of the printer mapping config json is needed. This assumes you know which IP is your desired printer. The spcified zpl_content will be sent to that IP+port.
|
|
404
462
|
"""
|
|
405
463
|
send_zpl_code(zpl_content, printer_ip, printer_port=port)
|
|
406
464
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
465
|
+
def print_zpl(
|
|
466
|
+
self,
|
|
467
|
+
lab=None,
|
|
468
|
+
printer_name=None,
|
|
469
|
+
uid_barcode="",
|
|
470
|
+
alt_a="",
|
|
471
|
+
alt_b="",
|
|
472
|
+
alt_c="",
|
|
473
|
+
alt_d="",
|
|
474
|
+
alt_e="",
|
|
475
|
+
alt_f="",
|
|
476
|
+
label_zpl_style=None,
|
|
477
|
+
client_ip="pkg",
|
|
478
|
+
print_n=1,
|
|
479
|
+
zpl_content=None,
|
|
480
|
+
):
|
|
411
481
|
"""
|
|
412
482
|
The main print method. Accepts info to determine the desired
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
lab = top level key in self.printers['labs']
|
|
417
|
-
printer_name = key for printer info (ie: ip_address) needed
|
|
418
|
-
to satisfy print requests.
|
|
419
|
-
label_zpl_style = template code, see above for addl deets
|
|
420
|
-
client_ip = optional, this is logged with print request info
|
|
421
|
-
print_n = integer, > 0
|
|
422
|
-
zpl_content = DO NOT USE -- hacky way to directly pass a zpl
|
|
423
|
-
string to a printer. to do: write a cleaner
|
|
424
|
-
string+ip method of printing.
|
|
425
|
-
"""
|
|
483
|
+
printer IP and to request the desired ZPL string to be sent
|
|
484
|
+
to the printer.
|
|
426
485
|
|
|
486
|
+
Args:
|
|
487
|
+
lab: top level key in self.printers['labs']
|
|
488
|
+
printer_name: key for printer info (ie: ip_address) needed
|
|
489
|
+
to satisfy print requests.
|
|
490
|
+
label_zpl_style: template code, see above for addl deets
|
|
491
|
+
client_ip: optional, this is logged with print request info
|
|
492
|
+
print_n: integer, > 0
|
|
493
|
+
zpl_content: DO NOT USE -- hacky way to directly pass a zpl
|
|
494
|
+
string to a printer. to do: write a cleaner
|
|
495
|
+
string+ip method of printing.
|
|
496
|
+
"""
|
|
427
497
|
if print_n < 1:
|
|
428
498
|
raise Exception(f"\n\nprint_n < 1 , specified {print_n}")
|
|
429
499
|
|
|
430
|
-
rec_date = str(datetime.datetime.now()).replace(' ','_')
|
|
431
500
|
print_n = int(print_n)
|
|
432
501
|
|
|
433
|
-
if printer_name in [
|
|
434
|
-
raise Exception(
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
502
|
+
if printer_name in ["", "None", None] and lab in [None, "", "None"]:
|
|
503
|
+
raise Exception(
|
|
504
|
+
f"lab and printer_name are both required to route a zebra print request, the following was what was received: lab:{lab} & printer_name:{printer_name}"
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
# Access printer via nested 'printers' key (v2 schema)
|
|
508
|
+
printer_data = self.printers["labs"][lab]["printers"][printer_name]
|
|
509
|
+
|
|
510
|
+
if label_zpl_style in [None, "", "None"]:
|
|
511
|
+
# Use default_label_style if set, otherwise fall back to first in list
|
|
512
|
+
label_zpl_style = (
|
|
513
|
+
printer_data.get("default_label_style") or printer_data["label_zpl_styles"][0]
|
|
514
|
+
)
|
|
515
|
+
elif label_zpl_style not in printer_data["label_zpl_styles"]:
|
|
439
516
|
_log.warning(
|
|
440
517
|
"ZPL style '%s' is not valid for %s/%s. Valid styles: %s",
|
|
441
|
-
label_zpl_style,
|
|
442
|
-
|
|
518
|
+
label_zpl_style,
|
|
519
|
+
lab,
|
|
520
|
+
printer_name,
|
|
521
|
+
printer_data["label_zpl_styles"],
|
|
443
522
|
)
|
|
444
523
|
|
|
445
|
-
printer_ip =
|
|
524
|
+
printer_ip = printer_data["ip_address"]
|
|
446
525
|
|
|
447
|
-
zpl_string =
|
|
526
|
+
zpl_string = ""
|
|
448
527
|
if zpl_content in [None]:
|
|
449
|
-
zpl_string = self.formulate_zpl(
|
|
528
|
+
zpl_string = self.formulate_zpl(
|
|
529
|
+
uid_barcode=uid_barcode,
|
|
530
|
+
alt_a=alt_a,
|
|
531
|
+
alt_b=alt_b,
|
|
532
|
+
alt_c=alt_c,
|
|
533
|
+
alt_d=alt_d,
|
|
534
|
+
alt_e=alt_e,
|
|
535
|
+
alt_f=alt_f,
|
|
536
|
+
label_zpl_style=label_zpl_style,
|
|
537
|
+
)
|
|
450
538
|
else:
|
|
451
539
|
zpl_string = zpl_content
|
|
452
540
|
|
|
453
541
|
# Log print request to file (using pathlib, not shell)
|
|
454
542
|
log_file = xdg.get_logs_dir() / "print_requests.log"
|
|
455
543
|
log_entry = f"{lab}\t{printer_name}\t{uid_barcode}\t{label_zpl_style}\t{printer_ip}\t{print_n}\t{client_ip}\t{zpl_content}\n"
|
|
456
|
-
with open(log_file,
|
|
544
|
+
with open(log_file, "a") as f:
|
|
457
545
|
f.write(log_entry)
|
|
458
546
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
ret_s = self.generate_label_png(zpl_string, png_fn, False)
|
|
547
|
+
# Send to printer
|
|
548
|
+
for _ in range(print_n):
|
|
549
|
+
send_zpl_code(zpl_string, printer_ip)
|
|
463
550
|
|
|
464
|
-
|
|
465
|
-
pn = 1
|
|
466
|
-
while pn <= print_n:
|
|
467
|
-
send_zpl_code(zpl_string, printer_ip)
|
|
468
|
-
pn += 1
|
|
469
|
-
|
|
470
|
-
ret_s = zpl_string
|
|
471
|
-
|
|
472
|
-
return ret_s
|
|
551
|
+
return zpl_string
|
|
473
552
|
|
|
474
553
|
|
|
475
554
|
def _get_local_ip() -> str:
|
|
476
555
|
"""Get the local IP address of this machine."""
|
|
477
556
|
ipcmd = r"""(ip addr show | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' || ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1') 2>/dev/null"""
|
|
478
557
|
result = subprocess.run(ipcmd, shell=True, capture_output=True, text=True)
|
|
479
|
-
return result.stdout.strip().split(
|
|
558
|
+
return result.stdout.strip().split("\n")[0] if result.stdout.strip() else "127.0.0.1"
|
|
480
559
|
|
|
481
560
|
|
|
482
|
-
def _parse_auth_args() ->
|
|
561
|
+
def _parse_auth_args() -> Literal["none", "cognito"]:
|
|
483
562
|
"""Parse --auth CLI argument.
|
|
484
563
|
|
|
485
564
|
Returns:
|
|
@@ -496,7 +575,8 @@ def _parse_auth_args() -> str:
|
|
|
496
575
|
help="Authentication mode: 'none' (public, default) or 'cognito' (AWS Cognito)",
|
|
497
576
|
)
|
|
498
577
|
args, _ = parser.parse_known_args()
|
|
499
|
-
|
|
578
|
+
auth_mode: Literal["none", "cognito"] = args.auth
|
|
579
|
+
return auth_mode
|
|
500
580
|
|
|
501
581
|
|
|
502
582
|
def zday_start() -> None:
|
|
@@ -515,14 +595,13 @@ def zday_start() -> None:
|
|
|
515
595
|
zday_start --auth cognito # Enable Cognito authentication
|
|
516
596
|
"""
|
|
517
597
|
import warnings
|
|
598
|
+
|
|
518
599
|
warnings.warn(
|
|
519
600
|
"zday_start is deprecated. Use 'zday gui start' instead.",
|
|
520
601
|
DeprecationWarning,
|
|
521
602
|
stacklevel=2,
|
|
522
603
|
)
|
|
523
|
-
_log.warning(
|
|
524
|
-
"DEPRECATED: zday_start is deprecated. Use 'zday gui start' instead."
|
|
525
|
-
)
|
|
604
|
+
_log.warning("DEPRECATED: zday_start is deprecated. Use 'zday gui start' instead.")
|
|
526
605
|
|
|
527
606
|
from zebra_day.web.app import run_server
|
|
528
607
|
|
|
@@ -550,6 +629,7 @@ def main() -> None:
|
|
|
550
629
|
zday_quickstart --auth cognito # Enable Cognito authentication
|
|
551
630
|
"""
|
|
552
631
|
import warnings
|
|
632
|
+
|
|
553
633
|
warnings.warn(
|
|
554
634
|
"zday_quickstart is deprecated. Use 'zday bootstrap' then 'zday gui start' instead.",
|
|
555
635
|
DeprecationWarning,
|
|
@@ -565,7 +645,7 @@ def main() -> None:
|
|
|
565
645
|
auth_mode = _parse_auth_args()
|
|
566
646
|
|
|
567
647
|
ip = _get_local_ip()
|
|
568
|
-
ip_root = ".".join(ip.split(
|
|
648
|
+
ip_root = ".".join(ip.split(".")[:-1])
|
|
569
649
|
|
|
570
650
|
_log.info("IP detected: %s ... using IP root: %s", ip, ip_root)
|
|
571
651
|
_log.info("Scanning for zebra printers on this network (may take a few minutes)...")
|
|
@@ -576,8 +656,7 @@ def main() -> None:
|
|
|
576
656
|
|
|
577
657
|
_log.info("Zebra Printer Scan Complete. Results: %s", zp.printers)
|
|
578
658
|
_log.info(
|
|
579
|
-
"Starting zebra_day web GUI at %s:8118 (auth=%s). "
|
|
580
|
-
"Press Ctrl+C to shut down.",
|
|
659
|
+
"Starting zebra_day web GUI at %s:8118 (auth=%s). Press Ctrl+C to shut down.",
|
|
581
660
|
ip,
|
|
582
661
|
auth_mode,
|
|
583
662
|
)
|
|
@@ -586,10 +665,7 @@ def main() -> None:
|
|
|
586
665
|
run_server(host="0.0.0.0", port=8118, reload=False, auth=auth_mode)
|
|
587
666
|
|
|
588
667
|
_log.info("EXITING ZDAY QUICKSTART")
|
|
589
|
-
_log.info(
|
|
590
|
-
"If the web GUI did not run, check if a service is already running at %s:8118",
|
|
591
|
-
ip
|
|
592
|
-
)
|
|
668
|
+
_log.info("If the web GUI did not run, check if a service is already running at %s:8118", ip)
|
|
593
669
|
|
|
594
670
|
|
|
595
671
|
if __name__ == "__main__":
|
|
@@ -604,5 +680,5 @@ if __name__ == "__zday_start__":
|
|
|
604
680
|
"""
|
|
605
681
|
entry point for zday_start
|
|
606
682
|
"""
|
|
607
|
-
|
|
683
|
+
|
|
608
684
|
zday_start()
|