-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy paththermy.py
274 lines (249 loc) · 9.98 KB
/
thermy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
from datetime import datetime
import os
import random
import sys
import threading
import usb.core
import usb.util
import usb.backend.libusb1
from dotenv import load_dotenv
from escpos import *
from flask import Flask, request
from pyngrok import ngrok
import PySimpleGUI as sg
from twilio.twiml.messaging_response import MessagingResponse
from twilio.rest import Client
load_dotenv()
app = Flask(__name__)
logo_image_file_location = "img/logotext.png"
icon_file_location = "img/print.ico"
qrcontent_file_name = "qrcontent.txt"
log_file_name = "thermylogs.txt"
qrcontent = []
tunnel_url = ""
sms_phone_number = os.environ.get("TWILIO_PHONE_NUMBER")
logs = ""
thermy_window = ""
print_qrc_bool = True
@app.route('/printpass', methods=['GET', 'POST'])
def printpass():
body = request.values.get('Body', '').lower().split()
response = ""
sms_response = ""
cmd = body[0]
if cmd == "pp":
try:
studentName = body[1].title()
except IndexError:
studentName = ""
try:
destination = body[2].title()
except IndexError:
destination = ""
try:
reason = body[3].title()
except IndexError:
reason = ""
response = "I'll get right on that!"
thermy_print("sms", studentName, destination, reason)
if response != "":
sms_response = MessagingResponse()
sms_response.message(response)
return str(sms_response)
def start_ngrok():
global tunnel_url
ngrok.set_auth_token(os.environ.get("NGROK_AUTH_TOKEN"))
tunnel_url = ngrok.connect(5000).public_url
client = Client()
client.incoming_phone_numbers.list(
phone_number=os.environ.get('TWILIO_PHONE_NUMBER'))[0].update(
sms_url=tunnel_url + '/printpass')
def load_qrcontent():
global qrcontent
global thermy_window
try:
qr_file = open(qrcontent_file_name, 'r')
lines = qr_file.readlines()
txt_data = ""
for line in lines:
if line.strip() != "":
qrcontent.append(line.strip())
txt_data += line
thermy_window["-QRC-"].update(txt_data)
except:
pass
def save_logs():
try:
log_file = open(log_file_name, 'a')
log_file.write(logs)
log_file.close()
except:
pass
def is_printer(dev):
if dev.bDeviceClass == 7:
return True
for cfg in dev:
if usb.util.find_descriptor(cfg, bInterfaceClass=7) is not None:
return True
def find_and_connect():
'''
Default Settings for WelQuic Printer
idVendor = 0x416
idProduct = 0x5011
usb_args = None
timeout = 5
in_ep = 0x81
out_ep = 0x3
'''
idVendor = 0
idProduct = 0
usb_args = None
timeout = 0
in_ep = 0
out_ep = 0
backend = usb.backend.libusb1.get_backend(find_library=lambda x: "C:\\Windows\\System32\\libusb-1.0.dll")
for usbprinter in usb.core.find(backend=backend, find_all=True, custom_match = is_printer):
idVendor = usbprinter.idVendor
idProduct = usbprinter.idProduct
for configuration in usbprinter:
for interface in configuration:
for endpoint in interface:
if usb.util.endpoint_direction(endpoint.bEndpointAddress) == usb.util.ENDPOINT_IN:
in_ep = endpoint.bEndpointAddress
else:
out_ep = endpoint.bEndpointAddress
thermy = printer.Usb(idVendor, idProduct, usb_args, timeout, in_ep, out_ep)
return thermy
def thermy_print(requestType, studentName, studentDest, studentReason):
global logs
logs += requestType + " pass "
now = datetime.now()
origin = os.environ.get("STUDENT_ORIGIN")
dtString = now.strftime("%m/%d/%Y %I:%M %p")
try:
thermy = find_and_connect()
thermy.set(align='center', font='b', bold=True, underline=2,
width=2, height=2, density=8, invert=False, smooth=True,
flip=False, double_width=False, double_height=False,
custom_size=True)
thermy.image(logo_image_file_location, high_density_vertical=True, high_density_horizontal=True, impl="bitImageRaster",
fragment_height=1024, center=True)
thermy.textln(dtString)
logs += dtString + " "
if studentName != "":
thermy.textln(studentName)
logs += studentName
thermy.textln(" from " + origin)
if studentDest != "":
thermy.textln("to " + studentDest)
logs += " to " + studentDest
if studentReason != "":
thermy.textln("for " + studentReason)
logs += " b/c " + studentReason
if len(qrcontent) > 0 and print_qrc_bool:
thermy.qr(random.choice(qrcontent), ec=0, size=6, model=2, native=False, center=True, impl='bitImageRaster')
thermy.cut()
thermy.close()
except:
logs += "error"
if requestType == "btn":
thermy_window["-LOG-"].update(logs)
raise Exception("PrinterError")
logs += "\n"
thermy_window["-LOG-"].update(logs)
if __name__ == '__main__':
# start ngrok once
if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
start_ngrok()
# main window layout
sg.theme("Darkblue16")
input_size = (25, 1)
server_status = "offline"
if "ngrok" in tunnel_url:
server_status = "online"
sglayout_tab_pass = [
[sg.Image(logo_image_file_location, pad=(10, 10))],
[sg.Frame("info (optional)", [
[sg.Push(), sg.Text("who?"), sg.Input(size=input_size, key="-NAME-")],
[sg.Push(), sg.Text("where?"), sg.Input(size=input_size, key="-DEST-")],
[sg.Push(), sg.Text("why?"), sg.Input(size=input_size, key="-REASON-")]
], pad=(10, 10) )],
[sg.Frame("actions", [
[sg.Button("print"), sg.Checkbox(text="qrc", key="-QR_CHECK-", enable_events=True, default=True), sg.Button("about"), sg.Button("exit")]
], pad=(10, 10) )],
]
sglayout_tab_server = [
[sg.Frame("server status (" + server_status + ")", [
[sg.Text("webhook tunnel url:")],
[sg.StatusBar(tunnel_url, font="Courier 10", key="-URL-")],
[sg.Text("sms phone number:")],
[sg.StatusBar(sms_phone_number, font="Courier 10", key="-SMS-")]
], pad=(10, 10) )]
]
sglayout_tab_logs = [
#[sg.Button("refresh", pad=(5, 5))],
[sg.Multiline("", font="Courier 12", key="-LOG-", size=(60, 20), write_only=True, expand_y=True,
auto_refresh=True, horizontal_scroll=True, disabled=True)],
]
sglayout_tab_qrc = [
[sg.Multiline("", font="Courier 12", key="-QRC-", size=(60, 20), write_only=True, expand_y=True,
auto_refresh=True, horizontal_scroll=False, disabled=True)],
]
sglayout = [[sg.TabGroup([[ sg.Tab('pass', sglayout_tab_pass, element_justification="center"),
sg.Tab('qrc', sglayout_tab_qrc, element_justification="center"),
sg.Tab('server+sms', sglayout_tab_server, element_justification="center"),
sg.Tab('logs', sglayout_tab_logs, element_justification="center")
]])
]]
thermy_window = sg.Window(title="thermy v0.2",
layout=sglayout,
icon=icon_file_location,
element_justification="center",
element_padding=(5, 5),
margins=(5, 5),
font="Courier 14",
enable_close_attempted_event=True,
grab_anywhere=True,
finalize=True
)
# load qrcodes from txt file
load_qrcontent()
# start flask as deamon thread
flask_thread = threading.Thread(target=lambda: app.run(debug=False, use_reloader=False))
flask_thread.setDaemon(True)
flask_thread.start()
# note: correct startup order above is: 1) ngrok; 2) window setup; 3) load qrcontent; 4) flask.
# main window loop
while True:
event, values = thermy_window.read()
if (event == sg.WINDOW_CLOSE_ATTEMPTED_EVENT or event == 'exit') and sg.popup_yes_no('Do you really want to exit?', font="Courier 10", grab_anywhere=True) == 'Yes':
break
elif event is None:
continue
elif event == "-QR_CHECK-":
print_qrc_bool = not print_qrc_bool
elif event == "print":
thermy_window["print"].disabled = True
studentName = values['-NAME-']
studentDest = values['-DEST-']
studentReason = values['-REASON-']
try:
thermy_print("btn", studentName, studentDest, studentReason)
except:
sg.popup("Oops! Something didn't quite work.",
"Make sure your USB thermal printer is connected. Then, try again.",
"If that doesn't work, restart the program and your thermal printer.",
"Notes:",
"--Libusbk driver required (available in Zadig Automated Driver Installer).",
font="Courier 12", non_blocking=True, grab_anywhere=True)
thermy_window["print"].disabled = False
#elif event == "refresh":
# thermy_window["-LOG-"].update(logs)
elif event == "about":
sg.popup('about thermy', 'simple thermal printing', 'version 0.2', 'MIT license', font="Courier 12", non_blocking=True, grab_anywhere=True)
# cleanup and exit
thermy_window.close()
save_logs()
ngrok.disconnect(tunnel_url)
ngrok.kill()
sys.exit(0)