|
@@ -2,552 +2,25 @@
|
2
|
2
|
|
3
|
3
|
# OctoTray Linux Qt System Tray OctoPrint client
|
4
|
4
|
#
|
5
|
|
-# depends on:
|
6
|
|
-# - python-pyqt5
|
|
5
|
+# OctoTray.py
|
7
|
6
|
#
|
8
|
|
-# see also:
|
9
|
|
-# https://doc.qt.io/qt-5/qtwidgets-widgets-imageviewer-example.html
|
10
|
|
-# https://stackoverflow.com/a/22618496
|
|
7
|
+# Main application logic.
|
11
|
8
|
|
12
|
9
|
import json
|
13
|
10
|
import sys
|
14
|
|
-import os
|
15
|
11
|
import time
|
16
|
|
-import string
|
17
|
12
|
import urllib.parse
|
18
|
13
|
import urllib.request
|
19
|
|
-import signal
|
20
|
14
|
import operator
|
21
|
15
|
import socket
|
22
|
16
|
from os import path
|
23
|
|
-from PyQt5 import QtWidgets, QtGui, QtCore, QtNetwork
|
24
|
|
-from PyQt5.QtWidgets import QSystemTrayIcon, QAction, QMenu, QMessageBox, QWidget, QLabel, QVBoxLayout, QHBoxLayout, QDesktopWidget, QSizePolicy, QSlider, QLayout, QTableWidget, QTableWidgetItem, QPushButton, QApplication, QLineEdit, QGridLayout
|
25
|
|
-from PyQt5.QtGui import QIcon, QPixmap, QImageReader, QDesktopServices, QFontDatabase, QCursor, QIntValidator
|
26
|
|
-from PyQt5.QtCore import QCoreApplication, QSettings, QUrl, QTimer, QSize, Qt, QSettings
|
27
|
|
-
|
28
|
|
-class SettingsWindow(QWidget):
|
29
|
|
- columns = [ "Hostname", "API Key", "Tool Preheat", "Bed Preheat" ]
|
30
|
|
- presets = [ "octopi.local", "000000000_API_KEY_HERE_000000000", "0", "0" ]
|
31
|
|
-
|
32
|
|
- def __init__(self, parent, *args, **kwargs):
|
33
|
|
- super(SettingsWindow, self).__init__(*args, **kwargs)
|
34
|
|
- self.parent = parent
|
35
|
|
-
|
36
|
|
- self.setWindowTitle(parent.name + " Settings")
|
37
|
|
- self.setWindowIcon(parent.icon)
|
38
|
|
-
|
39
|
|
-
|
40
|
|
- box = QVBoxLayout()
|
41
|
|
- self.setLayout(box)
|
42
|
|
-
|
43
|
|
- staticSettings = QGridLayout()
|
44
|
|
- box.addLayout(staticSettings, 0)
|
45
|
|
-
|
46
|
|
- self.jogSpeedText = QLabel("Jog Speed")
|
47
|
|
- staticSettings.addWidget(self.jogSpeedText, 0, 0)
|
48
|
|
-
|
49
|
|
- self.jogSpeed = QLineEdit(str(self.parent.jogMoveSpeed))
|
50
|
|
- self.jogSpeed.setValidator(QIntValidator(1, 6000))
|
51
|
|
- staticSettings.addWidget(self.jogSpeed, 0, 1)
|
52
|
|
-
|
53
|
|
- self.jogSpeedUnitText = QLabel("mm/min")
|
54
|
|
- staticSettings.addWidget(self.jogSpeedUnitText, 0, 2)
|
55
|
|
-
|
56
|
|
- self.jogLengthText = QLabel("Jog Length")
|
57
|
|
- staticSettings.addWidget(self.jogLengthText, 1, 0)
|
58
|
|
-
|
59
|
|
- self.jogLength = QLineEdit(str(self.parent.jogMoveLength))
|
60
|
|
- self.jogLength.setValidator(QIntValidator(1, 100))
|
61
|
|
- staticSettings.addWidget(self.jogLength, 1, 1)
|
62
|
|
-
|
63
|
|
- self.jogLengthUnitText = QLabel("mm")
|
64
|
|
- staticSettings.addWidget(self.jogLengthUnitText, 1, 2)
|
65
|
|
-
|
66
|
|
- helpText = "Usage:\n"
|
67
|
|
- helpText += "1st Column: Printer Hostname or IP address\n"
|
68
|
|
- helpText += "2nd Column: OctoPrint API Key (32 char hexadecimal)\n"
|
69
|
|
- helpText += "3rd Column: Tool Preheat Temperature (0 to disable)\n"
|
70
|
|
- helpText += "4th Column: Bed Preheat Temperature (0 to disable)"
|
71
|
|
- self.helpText = QLabel(helpText)
|
72
|
|
- box.addWidget(self.helpText, 0)
|
73
|
|
- box.setAlignment(self.helpText, Qt.AlignHCenter)
|
74
|
|
-
|
75
|
|
- buttons = QHBoxLayout()
|
76
|
|
- box.addLayout(buttons, 0)
|
77
|
|
-
|
78
|
|
- self.add = QPushButton("&Add Printer")
|
79
|
|
- self.add.clicked.connect(self.addPrinter)
|
80
|
|
- buttons.addWidget(self.add)
|
81
|
|
-
|
82
|
|
- self.remove = QPushButton("&Remove Printer")
|
83
|
|
- self.remove.clicked.connect(self.removePrinter)
|
84
|
|
- buttons.addWidget(self.remove)
|
85
|
|
-
|
86
|
|
- printers = self.parent.readSettings()
|
87
|
|
- self.rows = len(printers)
|
88
|
|
- self.table = QTableWidget(self.rows, len(self.columns))
|
89
|
|
- box.addWidget(self.table, 1)
|
90
|
|
-
|
91
|
|
- for i in range(0, self.rows):
|
92
|
|
- p = printers[i]
|
93
|
|
- for j in range(0, len(self.columns)):
|
94
|
|
- text = p[j]
|
95
|
|
- if (j >= 2) and (j <= 3) and (text == None):
|
96
|
|
- text = "0"
|
97
|
|
- item = QTableWidgetItem(text)
|
98
|
|
- self.table.setItem(i, j, item)
|
99
|
|
- if j == 1:
|
100
|
|
- font = item.font()
|
101
|
|
- font.setFamily(QFontDatabase.systemFont(QFontDatabase.FixedFont).family())
|
102
|
|
- item.setFont(font)
|
103
|
|
-
|
104
|
|
- buttons2 = QHBoxLayout()
|
105
|
|
- box.addLayout(buttons2, 0)
|
106
|
|
-
|
107
|
|
- self.up = QPushButton("Move &Up")
|
108
|
|
- self.up.clicked.connect(self.moveUp)
|
109
|
|
- buttons2.addWidget(self.up)
|
110
|
|
-
|
111
|
|
- self.down = QPushButton("Move &Down")
|
112
|
|
- self.down.clicked.connect(self.moveDown)
|
113
|
|
- buttons2.addWidget(self.down)
|
114
|
|
-
|
115
|
|
- self.openWeb = QPushButton("&Open Web UI of selected")
|
116
|
|
- self.openWeb.clicked.connect(self.openWebUI)
|
117
|
|
- box.addWidget(self.openWeb, 0)
|
118
|
|
-
|
119
|
|
- self.table.setHorizontalHeaderLabels(self.columns)
|
120
|
|
- self.table.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
|
121
|
|
- self.table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows);
|
122
|
|
- self.table.resizeColumnsToContents()
|
123
|
|
-
|
124
|
|
- if self.rows <= 0:
|
125
|
|
- self.addPrinter()
|
126
|
|
-
|
127
|
|
- def tableToList(self):
|
128
|
|
- printers = []
|
129
|
|
- for i in range(0, self.rows):
|
130
|
|
- p = []
|
131
|
|
- for j in range(0, len(self.columns)):
|
132
|
|
- text = self.table.item(i, j).text()
|
133
|
|
- if (j >= 2) and (j <= 3) and (text == "0"):
|
134
|
|
- text = None
|
135
|
|
- p.append(text)
|
136
|
|
- printers.append(p)
|
137
|
|
- return printers
|
138
|
|
-
|
139
|
|
- def settingsValid(self, printers):
|
140
|
|
- for p in printers:
|
141
|
|
- # p[0] needs to be valid hostname or IP
|
142
|
|
- # TODO
|
143
|
|
-
|
144
|
|
- # p[1] needs to be valid API key (hexadecimal, 32 chars)
|
145
|
|
- if (len(p[1]) != 32) or not all(c in string.hexdigits for c in p[1]):
|
146
|
|
- return (False, "API Key not 32-digit hexadecimal")
|
147
|
|
-
|
148
|
|
- # p[2] and p[3] need to be integer temperatures (0...999)
|
149
|
|
- for s in [ p[2], p[3] ]:
|
150
|
|
- if s == None:
|
151
|
|
- s = "0"
|
152
|
|
- if (len(s) < 1) or (len(s) > 3) or not all(c in string.digits for c in s):
|
153
|
|
- return (False, "Temperature not a number from 0...999")
|
154
|
|
-
|
155
|
|
- js = int(self.jogSpeed.text())
|
156
|
|
- if (js < 1) or (js > 6000):
|
157
|
|
- return (False, "Jog Speed not a number from 1...6000")
|
158
|
|
-
|
159
|
|
- jl = int(self.jogLength.text())
|
160
|
|
- if (jl < 1) or (jl > 100):
|
161
|
|
- return (False, "Jog Length not a number from 1...100")
|
162
|
|
-
|
163
|
|
- return (True, "")
|
164
|
|
-
|
165
|
|
- def closeEvent(self, event):
|
166
|
|
- oldPrinters = [item[0:len(self.columns)] for item in self.parent.printers]
|
167
|
|
- newPrinters = self.tableToList()
|
168
|
|
-
|
169
|
|
- valid, errorText = self.settingsValid(newPrinters)
|
170
|
|
- if valid == False:
|
171
|
|
- r = self.parent.showDialog(self.parent.name + " Settings Invalid", errorText + "!", "Do you want to edit it again?", True, True, False)
|
172
|
|
- if r == True:
|
173
|
|
- event.ignore()
|
174
|
|
- return
|
175
|
|
- else:
|
176
|
|
- self.parent.removeSettingsWindow()
|
177
|
|
- return
|
178
|
|
-
|
179
|
|
- js = int(self.jogSpeed.text())
|
180
|
|
- jl = int(self.jogLength.text())
|
181
|
|
-
|
182
|
|
- if (oldPrinters != newPrinters) or (js != self.parent.jogMoveSpeed) or (jl != self.parent.jogMoveLength):
|
183
|
|
- r = self.parent.showDialog(self.parent.name + " Settings Changed", "Do you want to save the new configuration?", "This will restart the application!", True, False, False)
|
184
|
|
- if r == True:
|
185
|
|
- self.parent.jogMoveSpeed = js
|
186
|
|
- self.parent.jogMoveLength = jl
|
187
|
|
- self.parent.writeSettings(newPrinters)
|
188
|
|
- self.parent.restartApp()
|
189
|
|
-
|
190
|
|
- self.parent.removeSettingsWindow()
|
191
|
|
-
|
192
|
|
- def addPrinter(self):
|
193
|
|
- self.rows += 1
|
194
|
|
- self.table.setRowCount(self.rows)
|
195
|
|
- for i in range(0, len(self.columns)):
|
196
|
|
- item = QTableWidgetItem(self.presets[i])
|
197
|
|
- self.table.setItem(self.rows - 1, i, item)
|
198
|
|
- if i == 1:
|
199
|
|
- font = item.font()
|
200
|
|
- font.setFamily(QFontDatabase.systemFont(QFontDatabase.FixedFont).family())
|
201
|
|
- item.setFont(font)
|
202
|
|
- self.table.resizeColumnsToContents()
|
203
|
|
- self.table.setCurrentItem(self.table.item(self.rows - 1, 0))
|
204
|
|
-
|
205
|
|
- def removePrinter(self):
|
206
|
|
- r = self.table.currentRow()
|
207
|
|
- if (r >= 0) and (r < self.rows):
|
208
|
|
- self.rows -= 1
|
209
|
|
- self.table.removeRow(r)
|
210
|
|
- self.table.setCurrentItem(self.table.item(min(r, self.rows - 1), 0))
|
211
|
|
-
|
212
|
|
- def moveUp(self):
|
213
|
|
- i = self.table.currentRow()
|
214
|
|
- if i <= 0:
|
215
|
|
- return
|
216
|
|
- host = self.table.item(i, 0).text()
|
217
|
|
- key = self.table.item(i, 1).text()
|
218
|
|
- self.table.item(i, 0).setText(self.table.item(i - 1, 0).text())
|
219
|
|
- self.table.item(i, 1).setText(self.table.item(i - 1, 1).text())
|
220
|
|
- self.table.item(i - 1, 0).setText(host)
|
221
|
|
- self.table.item(i - 1, 1).setText(key)
|
222
|
|
- self.table.setCurrentItem(self.table.item(i - 1, 0))
|
223
|
|
-
|
224
|
|
- def moveDown(self):
|
225
|
|
- i = self.table.currentRow()
|
226
|
|
- if i >= (self.rows - 1):
|
227
|
|
- return
|
228
|
|
- host = self.table.item(i, 0).text()
|
229
|
|
- key = self.table.item(i, 1).text()
|
230
|
|
- self.table.item(i, 0).setText(self.table.item(i + 1, 0).text())
|
231
|
|
- self.table.item(i, 1).setText(self.table.item(i + 1, 1).text())
|
232
|
|
- self.table.item(i + 1, 0).setText(host)
|
233
|
|
- self.table.item(i + 1, 1).setText(key)
|
234
|
|
- self.table.setCurrentItem(self.table.item(i + 1, 0))
|
235
|
|
-
|
236
|
|
- def openWebUI(self):
|
237
|
|
- host = self.table.item(self.table.currentRow(), 0).text()
|
238
|
|
- self.parent.openBrowser(host)
|
239
|
|
-
|
240
|
|
-class AspectRatioPixmapLabel(QLabel):
|
241
|
|
- def __init__(self, *args, **kwargs):
|
242
|
|
- super(AspectRatioPixmapLabel, self).__init__(*args, **kwargs)
|
243
|
|
- self.setMinimumSize(1, 1)
|
244
|
|
- self.setScaledContents(False)
|
245
|
|
- self.pix = QPixmap(0, 0)
|
246
|
|
-
|
247
|
|
- def setPixmap(self, p):
|
248
|
|
- self.pix = p
|
249
|
|
- super(AspectRatioPixmapLabel, self).setPixmap(self.scaledPixmap())
|
250
|
|
-
|
251
|
|
- def heightForWidth(self, width):
|
252
|
|
- if self.pix.isNull():
|
253
|
|
- return self.height()
|
254
|
|
- else:
|
255
|
|
- return (self.pix.height() * width) / self.pix.width()
|
256
|
|
-
|
257
|
|
- def sizeHint(self):
|
258
|
|
- w = self.width()
|
259
|
|
- return QSize(int(w), int(self.heightForWidth(w)))
|
260
|
|
-
|
261
|
|
- def scaledPixmap(self):
|
262
|
|
- return self.pix.scaled(self.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
263
|
|
-
|
264
|
|
- def resizeEvent(self, e):
|
265
|
|
- if not self.pix.isNull():
|
266
|
|
- super(AspectRatioPixmapLabel, self).setPixmap(self.scaledPixmap())
|
267
|
|
-
|
268
|
|
-class CamWindow(QWidget):
|
269
|
|
- reloadDelayDefault = 1000 # in ms
|
270
|
|
- statusDelayFactor = 2
|
271
|
|
- reloadOn = True
|
272
|
|
- sliderFactor = 100
|
273
|
|
-
|
274
|
|
- def __init__(self, parent, printer, *args, **kwargs):
|
275
|
|
- super(CamWindow, self).__init__(*args, **kwargs)
|
276
|
|
- self.app = parent.app
|
277
|
|
- self.manager = parent.manager
|
278
|
|
- self.manager.finished.connect(self.handleResponse)
|
279
|
|
- self.parent = parent
|
280
|
|
- self.printer = printer
|
281
|
|
- self.host = self.printer[0]
|
282
|
|
- self.url = "http://" + self.host + ":8080/?action=snapshot"
|
283
|
|
-
|
284
|
|
- self.setWindowTitle(parent.name + " Webcam Stream")
|
285
|
|
- self.setWindowIcon(parent.icon)
|
286
|
|
-
|
287
|
|
- box = QVBoxLayout()
|
288
|
|
- self.setLayout(box)
|
289
|
|
-
|
290
|
|
- label = QLabel(self.url)
|
291
|
|
- box.addWidget(label, 0)
|
292
|
|
- box.setAlignment(label, Qt.AlignHCenter)
|
293
|
|
-
|
294
|
|
- slide = QHBoxLayout()
|
295
|
|
- box.addLayout(slide, 0)
|
296
|
|
-
|
297
|
|
- self.slideStaticLabel = QLabel("Refresh")
|
298
|
|
- slide.addWidget(self.slideStaticLabel, 0)
|
299
|
|
-
|
300
|
|
- self.slider = QSlider(Qt.Horizontal)
|
301
|
|
- self.slider.setMinimum(int(100 / self.sliderFactor))
|
302
|
|
- self.slider.setMaximum(int(2000 / self.sliderFactor))
|
303
|
|
- self.slider.setTickInterval(int(100 / self.sliderFactor))
|
304
|
|
- self.slider.setPageStep(int(100 / self.sliderFactor))
|
305
|
|
- self.slider.setSingleStep(int(100 / self.sliderFactor))
|
306
|
|
- self.slider.setTickPosition(QSlider.TicksBelow)
|
307
|
|
- self.slider.setValue(int(self.reloadDelayDefault / self.sliderFactor))
|
308
|
|
- self.slider.valueChanged.connect(self.sliderChanged)
|
309
|
|
- slide.addWidget(self.slider, 1)
|
310
|
|
-
|
311
|
|
- self.slideLabel = QLabel(str(self.reloadDelayDefault) + "ms")
|
312
|
|
- slide.addWidget(self.slideLabel, 0)
|
313
|
|
-
|
314
|
|
- self.img = AspectRatioPixmapLabel()
|
315
|
|
- self.img.setPixmap(QPixmap(640, 480))
|
316
|
|
- box.addWidget(self.img, 1)
|
317
|
|
-
|
318
|
|
- self.statusLabel = QLabel("Status: unavailable")
|
319
|
|
- box.addWidget(self.statusLabel, 0)
|
320
|
|
- box.setAlignment(self.statusLabel, Qt.AlignHCenter)
|
321
|
|
-
|
322
|
|
- self.method = self.parent.getMethod(self.printer[0], self.printer[1])
|
323
|
|
- if self.method != "unknown":
|
324
|
|
- controls_power = QHBoxLayout()
|
325
|
|
- box.addLayout(controls_power, 0)
|
326
|
|
-
|
327
|
|
- self.turnOnButton = QPushButton("Turn O&n")
|
328
|
|
- self.turnOnButton.clicked.connect(self.turnOn)
|
329
|
|
- controls_power.addWidget(self.turnOnButton)
|
330
|
|
-
|
331
|
|
- self.turnOffButton = QPushButton("Turn O&ff")
|
332
|
|
- self.turnOffButton.clicked.connect(self.turnOff)
|
333
|
|
- controls_power.addWidget(self.turnOffButton)
|
334
|
|
-
|
335
|
|
- controls_temp = QHBoxLayout()
|
336
|
|
- box.addLayout(controls_temp, 0)
|
337
|
|
-
|
338
|
|
- self.cooldownButton = QPushButton("&Cooldown")
|
339
|
|
- self.cooldownButton.clicked.connect(self.cooldown)
|
340
|
|
- controls_temp.addWidget(self.cooldownButton)
|
341
|
|
-
|
342
|
|
- self.preheatToolButton = QPushButton("Preheat &Tool")
|
343
|
|
- self.preheatToolButton.clicked.connect(self.preheatTool)
|
344
|
|
- controls_temp.addWidget(self.preheatToolButton)
|
345
|
|
-
|
346
|
|
- self.preheatBedButton = QPushButton("Preheat &Bed")
|
347
|
|
- self.preheatBedButton.clicked.connect(self.preheatBed)
|
348
|
|
- controls_temp.addWidget(self.preheatBedButton)
|
349
|
|
-
|
350
|
|
- controls_home = QHBoxLayout()
|
351
|
|
- box.addLayout(controls_home, 0)
|
352
|
|
-
|
353
|
|
- self.homeAllButton = QPushButton("Home &All")
|
354
|
|
- self.homeAllButton.clicked.connect(self.homeAll)
|
355
|
|
- controls_home.addWidget(self.homeAllButton, 1)
|
356
|
|
-
|
357
|
|
- self.homeXButton = QPushButton("Home &X")
|
358
|
|
- self.homeXButton.clicked.connect(self.homeX)
|
359
|
|
- controls_home.addWidget(self.homeXButton, 0)
|
360
|
|
-
|
361
|
|
- self.homeYButton = QPushButton("Home &Y")
|
362
|
|
- self.homeYButton.clicked.connect(self.homeY)
|
363
|
|
- controls_home.addWidget(self.homeYButton, 0)
|
364
|
|
-
|
365
|
|
- self.homeZButton = QPushButton("Home &Z")
|
366
|
|
- self.homeZButton.clicked.connect(self.homeZ)
|
367
|
|
- controls_home.addWidget(self.homeZButton, 0)
|
368
|
|
-
|
369
|
|
- controls_move = QHBoxLayout()
|
370
|
|
- box.addLayout(controls_move, 0)
|
371
|
|
-
|
372
|
|
- self.XPButton = QPushButton("X+")
|
373
|
|
- self.XPButton.clicked.connect(self.moveXP)
|
374
|
|
- controls_move.addWidget(self.XPButton)
|
375
|
|
-
|
376
|
|
- self.XMButton = QPushButton("X-")
|
377
|
|
- self.XMButton.clicked.connect(self.moveXM)
|
378
|
|
- controls_move.addWidget(self.XMButton)
|
379
|
|
-
|
380
|
|
- self.YPButton = QPushButton("Y+")
|
381
|
|
- self.YPButton.clicked.connect(self.moveYP)
|
382
|
|
- controls_move.addWidget(self.YPButton)
|
383
|
|
-
|
384
|
|
- self.YMButton = QPushButton("Y-")
|
385
|
|
- self.YMButton.clicked.connect(self.moveYM)
|
386
|
|
- controls_move.addWidget(self.YMButton)
|
387
|
|
-
|
388
|
|
- self.ZPButton = QPushButton("Z+")
|
389
|
|
- self.ZPButton.clicked.connect(self.moveZP)
|
390
|
|
- controls_move.addWidget(self.ZPButton)
|
391
|
|
-
|
392
|
|
- self.ZMButton = QPushButton("Z-")
|
393
|
|
- self.ZMButton.clicked.connect(self.moveZM)
|
394
|
|
- controls_move.addWidget(self.ZMButton)
|
395
|
|
-
|
396
|
|
- controls_job = QHBoxLayout()
|
397
|
|
- box.addLayout(controls_job, 0)
|
398
|
|
-
|
399
|
|
- self.PauseButton = QPushButton("Pause/Resume")
|
400
|
|
- self.PauseButton.clicked.connect(self.pauseResume)
|
401
|
|
- controls_job.addWidget(self.PauseButton)
|
402
|
|
-
|
403
|
|
- self.CancelButton = QPushButton("Cancel Job")
|
404
|
|
- self.CancelButton.clicked.connect(self.cancelJob)
|
405
|
|
- controls_job.addWidget(self.CancelButton)
|
406
|
|
-
|
407
|
|
- self.loadImage()
|
408
|
|
- self.loadStatus()
|
409
|
|
-
|
410
|
|
- def pauseResume(self):
|
411
|
|
- self.parent.printerPauseResume(self.printer)
|
412
|
|
-
|
413
|
|
- def cancelJob(self):
|
414
|
|
- self.parent.printerJobCancel(self.printer)
|
415
|
|
-
|
416
|
|
- def moveXP(self):
|
417
|
|
- self.parent.printerMoveAction(self.printer, "x", int(self.parent.jogMoveLength), True)
|
418
|
|
-
|
419
|
|
- def moveXM(self):
|
420
|
|
- self.parent.printerMoveAction(self.printer, "x", -1 * int(self.parent.jogMoveLength), True)
|
421
|
|
-
|
422
|
|
- def moveYP(self):
|
423
|
|
- self.parent.printerMoveAction(self.printer, "y", int(self.parent.jogMoveLength), True)
|
424
|
|
-
|
425
|
|
- def moveYM(self):
|
426
|
|
- self.parent.printerMoveAction(self.printer, "y", -1 * int(self.parent.jogMoveLength), True)
|
427
|
|
-
|
428
|
|
- def moveZP(self):
|
429
|
|
- self.parent.printerMoveAction(self.printer, "z", int(self.parent.jogMoveLength), True)
|
430
|
|
-
|
431
|
|
- def moveZM(self):
|
432
|
|
- self.parent.printerMoveAction(self.printer, "z", -1 * int(self.parent.jogMoveLength), True)
|
433
|
|
-
|
434
|
|
- def homeX(self):
|
435
|
|
- self.parent.printerHomingAction(self.printer, "x")
|
436
|
|
-
|
437
|
|
- def homeY(self):
|
438
|
|
- self.parent.printerHomingAction(self.printer, "y")
|
439
|
|
-
|
440
|
|
- def homeZ(self):
|
441
|
|
- self.parent.printerHomingAction(self.printer, "z")
|
442
|
|
-
|
443
|
|
- def homeAll(self):
|
444
|
|
- self.parent.printerHomingAction(self.printer, "xyz")
|
445
|
|
-
|
446
|
|
- def turnOn(self):
|
447
|
|
- if self.method == "psucontrol":
|
448
|
|
- self.parent.printerOnAction(self.printer)
|
449
|
|
- elif self.method == "system":
|
450
|
|
- cmds = self.parent.getSystemCommands(self.printer[0], self.printer[1])
|
451
|
|
- for cmd in cmds:
|
452
|
|
- if "on" in cmd:
|
453
|
|
- self.parent.setSystemCommand(self.printer[0], self.printer[1], cmd)
|
454
|
|
- break
|
455
|
|
-
|
456
|
|
- def turnOff(self):
|
457
|
|
- if self.method == "psucontrol":
|
458
|
|
- self.parent.printerOffAction(self.printer)
|
459
|
|
- elif self.method == "system":
|
460
|
|
- cmds = self.parent.getSystemCommands(self.printer[0], self.printer[1])
|
461
|
|
- for cmd in cmds:
|
462
|
|
- if "off" in cmd:
|
463
|
|
- self.parent.setSystemCommand(self.printer[0], self.printer[1], cmd)
|
464
|
|
- break
|
465
|
|
-
|
466
|
|
- def cooldown(self):
|
467
|
|
- self.parent.printerCooldown(self.printer)
|
468
|
|
-
|
469
|
|
- def preheatTool(self):
|
470
|
|
- self.parent.printerHeatTool(self.printer)
|
471
|
|
-
|
472
|
|
- def preheatBed(self):
|
473
|
|
- self.parent.printerHeatBed(self.printer)
|
474
|
|
-
|
475
|
|
- def getHost(self):
|
476
|
|
- return self.host
|
477
|
|
-
|
478
|
|
- def sliderChanged(self):
|
479
|
|
- self.slideLabel.setText(str(self.slider.value() * self.sliderFactor) + "ms")
|
480
|
|
-
|
481
|
|
- def closeEvent(self, event):
|
482
|
|
- self.reloadOn = False
|
483
|
|
- self.url = ""
|
484
|
|
- self.parent.removeWebcamWindow(self)
|
485
|
|
-
|
486
|
|
- def scheduleLoadImage(self):
|
487
|
|
- if self.reloadOn:
|
488
|
|
- QTimer.singleShot(self.slider.value() * self.sliderFactor, self.loadImage)
|
489
|
|
-
|
490
|
|
- def scheduleLoadStatus(self):
|
491
|
|
- if self.reloadOn:
|
492
|
|
- QTimer.singleShot(self.slider.value() * self.sliderFactor * self.statusDelayFactor, self.loadStatus)
|
493
|
|
-
|
494
|
|
- def loadImage(self):
|
495
|
|
- url = QUrl(self.url)
|
496
|
|
- request = QtNetwork.QNetworkRequest(url)
|
497
|
|
- self.manager.get(request)
|
498
|
|
-
|
499
|
|
- def loadStatus(self):
|
500
|
|
- s = "Status: "
|
501
|
|
- t = self.parent.getTemperatureString(self.host, self.printer[1])
|
502
|
|
- if len(t) > 0:
|
503
|
|
- s += t
|
504
|
|
- else:
|
505
|
|
- s += "Unknown"
|
506
|
|
-
|
507
|
|
- progress = self.parent.getProgress(self.host, self.printer[1])
|
508
|
|
- if ("completion" in progress) and ("printTime" in progress) and ("printTimeLeft" in progress) and (progress["completion"] != None) and (progress["printTime"] != None) and (progress["printTimeLeft"] != None):
|
509
|
|
- s += " - %.1f%%" % progress["completion"]
|
510
|
|
- s += " - runtime "
|
511
|
|
- s += time.strftime("%H:%M:%S", time.gmtime(progress["printTime"]))
|
512
|
|
- s += " - "
|
513
|
|
- s += time.strftime("%H:%M:%S", time.gmtime(progress["printTimeLeft"])) + " left"
|
514
|
|
-
|
515
|
|
- self.statusLabel.setText(s)
|
516
|
|
- self.scheduleLoadStatus()
|
517
|
|
-
|
518
|
|
- def handleResponse(self, reply):
|
519
|
|
- if reply.url().url() == self.url:
|
520
|
|
- if reply.error() == QtNetwork.QNetworkReply.NoError:
|
521
|
|
- reader = QImageReader(reply)
|
522
|
|
- reader.setAutoTransform(True)
|
523
|
|
- image = reader.read()
|
524
|
|
- if image != None:
|
525
|
|
- if image.colorSpace().isValid():
|
526
|
|
- image.convertToColorSpace(QColorSpace.SRgb)
|
527
|
|
- self.img.setPixmap(QPixmap.fromImage(image))
|
528
|
|
- self.scheduleLoadImage()
|
529
|
|
- else:
|
530
|
|
- print("Error decoding image: " + reader.errorString())
|
531
|
|
- else:
|
532
|
|
- print("Error loading image: " + reply.errorString())
|
533
|
|
-
|
534
|
|
-class MainWindow(QWidget):
|
535
|
|
- def __init__(self, parent, *args, **kwargs):
|
536
|
|
- super(MainWindow, self).__init__(*args, **kwargs)
|
537
|
|
- self.parent = parent
|
538
|
|
-
|
539
|
|
- self.mainLayout = QVBoxLayout()
|
540
|
|
- self.setLayout(self.mainLayout)
|
541
|
|
- self.mainLayout.addWidget(self.parent.menu)
|
542
|
|
-
|
543
|
|
- self.parent.menu.aboutToHide.connect(self.aboutToHide)
|
544
|
|
-
|
545
|
|
- def aboutToHide(self):
|
546
|
|
- self.parent.menu.show()
|
547
|
|
-
|
548
|
|
- def closeEvent(self, event):
|
549
|
|
- self.parent.exit()
|
550
|
|
- event.accept()
|
|
17
|
+from PyQt5 import QtNetwork
|
|
18
|
+from PyQt5.QtWidgets import QSystemTrayIcon, QAction, QMenu, QMessageBox, QDesktopWidget
|
|
19
|
+from PyQt5.QtGui import QIcon, QPixmap, QDesktopServices, QCursor
|
|
20
|
+from PyQt5.QtCore import QCoreApplication, QSettings, QUrl
|
|
21
|
+from CamWindow import CamWindow
|
|
22
|
+from SettingsWindow import SettingsWindow
|
|
23
|
+from MainWindow import MainWindow
|
551
|
24
|
|
552
|
25
|
class OctoTray():
|
553
|
26
|
name = "OctoTray"
|
|
@@ -696,7 +169,7 @@ class OctoTray():
|
696
|
169
|
|
697
|
170
|
self.iconPathName = None
|
698
|
171
|
for p in self.iconPaths:
|
699
|
|
- if os.path.isfile(path.join(p, self.iconName)):
|
|
172
|
+ if path.isfile(path.join(p, self.iconName)):
|
700
|
173
|
self.iconPathName = path.join(p, self.iconName)
|
701
|
174
|
break
|
702
|
175
|
if self.iconPathName == None:
|
|
@@ -1181,23 +654,3 @@ class OctoTray():
|
1181
|
654
|
self.trayIcon.setVisible(False)
|
1182
|
655
|
else:
|
1183
|
656
|
self.mainWindow.setVisible(False)
|
1184
|
|
-
|
1185
|
|
-if __name__ == "__main__":
|
1186
|
|
- app = QApplication(sys.argv)
|
1187
|
|
- app.setQuitOnLastWindowClosed(False)
|
1188
|
|
-
|
1189
|
|
- signal.signal(signal.SIGINT, signal.SIG_DFL)
|
1190
|
|
-
|
1191
|
|
- inSysTray = QSystemTrayIcon.isSystemTrayAvailable()
|
1192
|
|
- if ("windowed" in sys.argv) or ("--windowed" in sys.argv) or ("-w" in sys.argv):
|
1193
|
|
- inSysTray = False
|
1194
|
|
-
|
1195
|
|
- tray = OctoTray(app, inSysTray)
|
1196
|
|
- rc = app.exec_()
|
1197
|
|
-
|
1198
|
|
- while rc == 42:
|
1199
|
|
- tray.closeAll()
|
1200
|
|
- tray = OctoTray(app, inSysTray)
|
1201
|
|
- rc = app.exec_()
|
1202
|
|
-
|
1203
|
|
- sys.exit(rc)
|