Refactoring server/client communication to utilize socket.io instead of 500ms-polling for server-side updates
parent
a777c369c7
commit
ddc3ff9563
|
@ -22,62 +22,80 @@ def getConnectionOptions():
|
|||
"baudratePreference": settings().getInt("serial", "baudrate")
|
||||
}
|
||||
|
||||
def _getFormattedTimeDelta(d):
|
||||
hours = d.seconds // 3600
|
||||
minutes = (d.seconds % 3600) // 60
|
||||
seconds = d.seconds % 60
|
||||
return "%02d:%02d:%02d" % (hours, minutes, seconds)
|
||||
|
||||
class Printer():
|
||||
def __init__(self):
|
||||
# state
|
||||
self.temps = {
|
||||
self._temp = None
|
||||
self._bedTemp = None
|
||||
self._targetTemp = None
|
||||
self._targetBedTemp = None
|
||||
self._temps = {
|
||||
"actual": [],
|
||||
"target": [],
|
||||
"actualBed": [],
|
||||
"targetBed": []
|
||||
}
|
||||
self.messages = []
|
||||
self.log = []
|
||||
self.state = None
|
||||
self.currentZ = None
|
||||
self.progress = None
|
||||
self.printTime = None
|
||||
self.printTimeLeft = None
|
||||
self.currentTemp = None
|
||||
self.currentBedTemp = None
|
||||
self.currentTargetTemp = None
|
||||
self.currentBedTargetTemp = None
|
||||
|
||||
self.gcode = None
|
||||
self.gcodeList = None
|
||||
self.filename = None
|
||||
self._latestMessage = None
|
||||
self._messages = []
|
||||
|
||||
self.gcodeLoader = None
|
||||
self._latestLog = None
|
||||
self._log = []
|
||||
|
||||
self.feedrateModifierMapping = {"outerWall": "WALL-OUTER", "innerWall": "WALL_INNER", "fill": "FILL", "support": "SUPPORT"}
|
||||
self._state = None
|
||||
|
||||
self.timelapse = None
|
||||
self._currentZ = None
|
||||
|
||||
self._progress = None
|
||||
self._printTime = None
|
||||
self._printTimeLeft = None
|
||||
|
||||
# gcode handling
|
||||
self._gcode = None
|
||||
self._gcodeList = None
|
||||
self._filename = None
|
||||
self._gcodeLoader = None
|
||||
|
||||
# feedrate
|
||||
self._feedrateModifierMapping = {"outerWall": "WALL-OUTER", "innerWall": "WALL_INNER", "fill": "FILL", "support": "SUPPORT"}
|
||||
|
||||
# timelapse
|
||||
self._timelapse = None
|
||||
|
||||
# comm
|
||||
self.comm = None
|
||||
self._comm = None
|
||||
|
||||
# callbacks
|
||||
self._callbacks = []
|
||||
|
||||
#~~ callback registration
|
||||
|
||||
def registerCallback(self, callback):
|
||||
self._callbacks.append(callback)
|
||||
self._sendInitialStateUpdate(callback)
|
||||
|
||||
def unregisterCallback(self, callback):
|
||||
if callback in self._callbacks:
|
||||
self._callbacks.remove(callback)
|
||||
|
||||
#~~ printer commands
|
||||
|
||||
def connect(self, port=None, baudrate=None):
|
||||
"""
|
||||
Connects to the printer. If port and/or baudrate is provided, uses these settings, otherwise autodetection
|
||||
will be attempted.
|
||||
"""
|
||||
if self.comm is not None:
|
||||
self.comm.close()
|
||||
self.comm = comm.MachineCom(port, baudrate, callbackObject=self)
|
||||
if self._comm is not None:
|
||||
self._comm.close()
|
||||
self._comm = comm.MachineCom(port, baudrate, callbackObject=self)
|
||||
|
||||
def disconnect(self):
|
||||
"""
|
||||
Closes the connection to the printer.
|
||||
"""
|
||||
if self.comm is not None:
|
||||
self.comm.close()
|
||||
self.comm = None
|
||||
if self._comm is not None:
|
||||
self._comm.close()
|
||||
self._comm = None
|
||||
|
||||
def command(self, command):
|
||||
"""
|
||||
|
@ -90,152 +108,272 @@ class Printer():
|
|||
Sends multiple gcode commands (provided as a list) to the printer.
|
||||
"""
|
||||
for command in commands:
|
||||
self.comm.sendCommand(command)
|
||||
self._comm.sendCommand(command)
|
||||
|
||||
def setFeedrateModifier(self, structure, percentage):
|
||||
if (not self.feedrateModifierMapping.has_key(structure)) or percentage < 0:
|
||||
if (not self._feedrateModifierMapping.has_key(structure)) or percentage < 0:
|
||||
return
|
||||
|
||||
self.comm.setFeedrateModifier(self.feedrateModifierMapping[structure], percentage / 100.0)
|
||||
self._comm.setFeedrateModifier(self._feedrateModifierMapping[structure], percentage / 100.0)
|
||||
|
||||
def loadGcode(self, file):
|
||||
"""
|
||||
Loads the gcode from the given file as the new print job.
|
||||
Aborts if the printer is currently printing or another gcode file is currently being loaded.
|
||||
"""
|
||||
if (self._comm is not None and self._comm.isPrinting()) or (self._gcodeLoader is not None):
|
||||
return
|
||||
|
||||
self._setJobData(None, None, None)
|
||||
|
||||
self._gcodeLoader = GcodeLoader(file, self)
|
||||
self._gcodeLoader.start()
|
||||
|
||||
def startPrint(self):
|
||||
"""
|
||||
Starts the currently loaded print job.
|
||||
Only starts if the printer is connected and operational, not currently printing and a printjob is loaded
|
||||
"""
|
||||
if self._comm is None or not self._comm.isOperational():
|
||||
return
|
||||
if self._gcodeList is None:
|
||||
return
|
||||
if self._comm.isPrinting():
|
||||
return
|
||||
|
||||
self._setCurrentZ(-1)
|
||||
self._comm.printGCode(self._gcodeList)
|
||||
|
||||
def togglePausePrint(self):
|
||||
"""
|
||||
Pause the current printjob.
|
||||
"""
|
||||
if self._comm is None:
|
||||
return
|
||||
self._comm.setPause(not self._comm.isPaused())
|
||||
|
||||
def cancelPrint(self, disableMotorsAndHeater=True):
|
||||
"""
|
||||
Cancel the current printjob.
|
||||
"""
|
||||
if self._comm is None:
|
||||
return
|
||||
self._comm.cancelPrint()
|
||||
if disableMotorsAndHeater:
|
||||
self.commands(["M84", "M104 S0", "M140 S0"]) # disable motors, switch off heaters
|
||||
|
||||
# reset line, height, print time
|
||||
self._setCurrentZ(None)
|
||||
self._setProgressData(None, None, None)
|
||||
|
||||
#~~ state monitoring
|
||||
|
||||
def setTimelapse(self, timelapse):
|
||||
if self.timelapse is not None and self.isPrinting():
|
||||
self.timelapse.onPrintjobStopped()
|
||||
del self.timelapse
|
||||
self.timelapse = timelapse
|
||||
if self._timelapse is not None and self.isPrinting():
|
||||
self._timelapse.onPrintjobStopped()
|
||||
del self._timelapse
|
||||
self._timelapse = timelapse
|
||||
|
||||
def getTimelapse(self):
|
||||
return self.timelapse
|
||||
return self._timelapse
|
||||
|
||||
def mcLog(self, message):
|
||||
def _setCurrentZ(self, currentZ):
|
||||
self._currentZ = currentZ
|
||||
|
||||
for callback in self._callbacks:
|
||||
try: callback.zChangeCB(self._currentZ)
|
||||
except: pass
|
||||
|
||||
def _setState(self, state):
|
||||
self._state = state
|
||||
|
||||
for callback in self._callbacks:
|
||||
try: callback.stateChangeCB(self._state, self.getStateString(), self._getStateFlags())
|
||||
except: pass
|
||||
|
||||
def _addLog(self, log):
|
||||
"""
|
||||
Callback method for the comm object, called upon log output.
|
||||
Log line is stored in internal buffer, which is truncated to the last 300 lines.
|
||||
"""
|
||||
self.log.append(message)
|
||||
self.log = self.log[-300:]
|
||||
self._latestLog = log
|
||||
self._log.append(log)
|
||||
self._log = self._log[-300:]
|
||||
|
||||
def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
|
||||
for callback in self._callbacks:
|
||||
try: callback.logChangeCB(log, self._log)
|
||||
except: pass
|
||||
|
||||
def _addMessage(self, message):
|
||||
self._latestMessage = message
|
||||
self._messages.append(message)
|
||||
self._messages = self._messages[-300:]
|
||||
|
||||
for callback in self._callbacks:
|
||||
try: callback.messageChangeCB(message, self._messages)
|
||||
except: pass
|
||||
|
||||
def _setProgressData(self, progress, printTime, printTimeLeft):
|
||||
self._progress = progress
|
||||
self._printTime = printTime
|
||||
self._printTimeLeft = printTimeLeft
|
||||
|
||||
for callback in self._callbacks:
|
||||
try: callback.progressChangeCB(self._progress, self._printTime, self._printTimeLeft)
|
||||
except: pass
|
||||
|
||||
|
||||
def _addTemperatureData(self, temp, bedTemp, targetTemp, bedTargetTemp):
|
||||
"""
|
||||
Callback method for the comm object, called upon receiving new temperature information.
|
||||
Temperature information (actual and target) for print head and print bed is stored in corresponding
|
||||
temperature history (including timestamp), history is truncated to 300 entries.
|
||||
"""
|
||||
currentTime = int(time.time() * 1000)
|
||||
|
||||
self.temps["actual"].append((currentTime, temp))
|
||||
self.temps["actual"] = self.temps["actual"][-300:]
|
||||
self._temps["actual"].append((currentTime, temp))
|
||||
self._temps["actual"] = self._temps["actual"][-300:]
|
||||
|
||||
self.temps["target"].append((currentTime, targetTemp))
|
||||
self.temps["target"] = self.temps["target"][-300:]
|
||||
self._temps["target"].append((currentTime, targetTemp))
|
||||
self._temps["target"] = self._temps["target"][-300:]
|
||||
|
||||
self.temps["actualBed"].append((currentTime, bedTemp))
|
||||
self.temps["actualBed"] = self.temps["actualBed"][-300:]
|
||||
self._temps["actualBed"].append((currentTime, bedTemp))
|
||||
self._temps["actualBed"] = self._temps["actualBed"][-300:]
|
||||
|
||||
self.temps["targetBed"].append((currentTime, bedTargetTemp))
|
||||
self.temps["targetBed"] = self.temps["targetBed"][-300:]
|
||||
self._temps["targetBed"].append((currentTime, bedTargetTemp))
|
||||
self._temps["targetBed"] = self._temps["targetBed"][-300:]
|
||||
|
||||
self.currentTemp = temp
|
||||
self.currentTargetTemp = targetTemp
|
||||
self.currentBedTemp = bedTemp
|
||||
self.currentBedTargetTemp = bedTargetTemp
|
||||
self._temp = temp
|
||||
self._bedTemp = bedTemp
|
||||
self._targetTemp = targetTemp
|
||||
self._targetBedTemp = bedTargetTemp
|
||||
|
||||
for callback in self._callbacks:
|
||||
try: callback.temperatureChangeCB(self._temp, self._bedTemp, self._targetTemp, self._targetBedTemp, self._temps)
|
||||
except: pass
|
||||
|
||||
def _setJobData(self, filename, gcode, gcodeList):
|
||||
self._filename = filename
|
||||
self._gcode = gcode
|
||||
self._gcodeList = gcodeList
|
||||
|
||||
for callback in self._callbacks:
|
||||
try: callback.jobDataChangeCB(filename, len(gcodeList), self._gcode.totalMoveTimeMinute, self._gcode.extrusionAmount)
|
||||
except: pass
|
||||
|
||||
def _sendInitialStateUpdate(self, callback):
|
||||
lines = None
|
||||
if self._gcodeList:
|
||||
lines = len(self._gcodeList)
|
||||
|
||||
estimatedPrintTime = None
|
||||
filament = None
|
||||
if self._gcode:
|
||||
estimatedPrintTime = self._gcode.totalMoveTimeMinute
|
||||
filament = self._gcode.extrusionAmount
|
||||
|
||||
try:
|
||||
callback.zChangeCB(self._currentZ)
|
||||
callback.stateChangeCB(self._state, self.getStateString(), self._getStateFlags())
|
||||
callback.logChangeCB(self._latestLog, self._log)
|
||||
callback.messageChangeCB(self._latestMessage, self._messages)
|
||||
callback.progressChangeCB(self._progress, self._printTime, self._printTimeLeft)
|
||||
callback.temperatureChangeCB(self._temp, self._bedTemp, self._targetTemp, self._targetBedTemp, self._temps)
|
||||
callback.jobDataChangeCB(self._filename, lines, estimatedPrintTime, filament)
|
||||
except Exception, err:
|
||||
import sys
|
||||
sys.stderr.write("ERROR: %s\n" % str(err))
|
||||
pass
|
||||
|
||||
def _getStateFlags(self):
|
||||
return {
|
||||
"operational": self.isOperational(),
|
||||
"printing": self.isPrinting(),
|
||||
"closedOrError": self.isClosedOrError(),
|
||||
"error": self.isError(),
|
||||
"loading": self.isLoading(),
|
||||
"paused": self.isPaused(),
|
||||
"ready": self.isReady()
|
||||
}
|
||||
|
||||
#~~ callbacks triggered from self._comm
|
||||
|
||||
def mcLog(self, message):
|
||||
"""
|
||||
Callback method for the comm object, called upon log output.
|
||||
"""
|
||||
self._addLog(message)
|
||||
|
||||
def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
|
||||
self._addTemperatureData(temp, bedTemp, targetTemp, bedTargetTemp)
|
||||
|
||||
def mcStateChange(self, state):
|
||||
"""
|
||||
Callback method for the comm object, called if the connection state changes.
|
||||
New state is stored for retrieval by the frontend.
|
||||
"""
|
||||
oldState = self.state
|
||||
self.state = state
|
||||
oldState = self._state
|
||||
|
||||
if self._timelapse is not None:
|
||||
if oldState == self._comm.STATE_PRINTING:
|
||||
self._timelapse.onPrintjobStopped()
|
||||
elif state == self._comm.STATE_PRINTING:
|
||||
self._timelapse.onPrintjobStarted(self._filename)
|
||||
|
||||
self._setState(state)
|
||||
|
||||
if self.timelapse is not None:
|
||||
if oldState == self.comm.STATE_PRINTING:
|
||||
self.timelapse.onPrintjobStopped()
|
||||
elif state == self.comm.STATE_PRINTING:
|
||||
self.timelapse.onPrintjobStarted(self.filename)
|
||||
|
||||
def mcMessage(self, message):
|
||||
"""
|
||||
Callback method for the comm object, called upon message exchanges via serial.
|
||||
Stores the message in the message buffer, truncates buffer to the last 300 lines.
|
||||
"""
|
||||
self.messages.append(message)
|
||||
self.messages = self.messages[-300:]
|
||||
self._addMessage(message)
|
||||
|
||||
def mcProgress(self, lineNr):
|
||||
"""
|
||||
Callback method for the comm object, called upon any change in progress of the printjob.
|
||||
Triggers storage of new values for printTime, printTimeLeft and the current line.
|
||||
"""
|
||||
self.printTime = self.comm.getPrintTime()
|
||||
self.printTimeLeft = self.comm.getPrintTimeRemainingEstimate()
|
||||
oldProgress = self.progress;
|
||||
self.progress = self.comm.getPrintPos()
|
||||
if self.timelapse is not None:
|
||||
self.timelapse.onPrintjobProgress(oldProgress, self.progress, int(round(self.progress * 100 / len(self.gcodeList))))
|
||||
oldProgress = self._progress
|
||||
|
||||
if self._timelapse is not None:
|
||||
try: self._timelapse.onPrintjobProgress(oldProgress, self._progress, int(round(self._progress * 100 / len(self._gcodeList))))
|
||||
except: pass
|
||||
|
||||
self._setProgressData(self._comm.getPrintPos(), self._comm.getPrintTime(), self._comm.getPrintTimeRemainingEstimate())
|
||||
|
||||
|
||||
def mcZChange(self, newZ):
|
||||
"""
|
||||
Callback method for the comm object, called upon change of the z-layer.
|
||||
"""
|
||||
oldZ = self.currentZ
|
||||
self.currentZ = newZ
|
||||
if self.timelapse is not None:
|
||||
self.timelapse.onZChange(oldZ, self.currentZ)
|
||||
if self._timelapse is not None:
|
||||
self._timelapse.onZChange(oldZ, newZ)
|
||||
|
||||
def onGcodeLoaded(self, gcodeLoader):
|
||||
"""
|
||||
Callback method for the gcode loader, gets called when the gcode for the new printjob has finished loading.
|
||||
Takes care to set filename, gcode and commandlist from the gcode loader and reset print job progress.
|
||||
"""
|
||||
self.filename = gcodeLoader.filename
|
||||
self.gcode = gcodeLoader.gcode
|
||||
self.gcodeList = gcodeLoader.gcodeList
|
||||
self.currentZ = None
|
||||
self.progress = None
|
||||
self.printTime = None
|
||||
self.printTimeLeft = None
|
||||
self._setCurrentZ(newZ)
|
||||
|
||||
self.gcodeLoader = None
|
||||
#~~ callbacks triggered by gcodeLoader
|
||||
|
||||
def jobData(self):
|
||||
"""
|
||||
Returns statistics regarding the currently loaded printjob, or None if no printjob is loaded.
|
||||
"""
|
||||
if self.gcode is not None:
|
||||
formattedPrintTime = None
|
||||
if (self.printTime):
|
||||
formattedPrintTime = _getFormattedTimeDelta(datetime.timedelta(seconds=self.printTime))
|
||||
def onGcodeLoadingProgress(self, progress):
|
||||
for callback in self._callbacks:
|
||||
try: callback.gcodeChangeCB(self._gcodeLoader._filename, progress)
|
||||
except Exception, err:
|
||||
import sys
|
||||
sys.stderr.write("ERROR: %s\n" % str(err))
|
||||
pass
|
||||
|
||||
formattedPrintTimeLeft = None
|
||||
if (self.printTimeLeft):
|
||||
formattedPrintTimeLeft = _getFormattedTimeDelta(datetime.timedelta(minutes=self.printTimeLeft))
|
||||
def onGcodeLoaded(self):
|
||||
self._setJobData(self._gcodeLoader._filename, self._gcodeLoader._gcode, self._gcodeLoader._gcodeList)
|
||||
self._setCurrentZ(None)
|
||||
self._setProgressData(None, None, None)
|
||||
|
||||
formattedPrintTimeEstimation = None
|
||||
formattedFilament = None
|
||||
if self.gcode:
|
||||
if self.gcode.totalMoveTimeMinute:
|
||||
formattedPrintTimeEstimation = _getFormattedTimeDelta(datetime.timedelta(minutes=self.gcode.totalMoveTimeMinute))
|
||||
if self.gcode.extrusionAmount:
|
||||
formattedFilament = "%.2fm" % (self.gcode.extrusionAmount / 1000)
|
||||
self._gcodeLoader = None
|
||||
|
||||
formattedCurrentZ = None
|
||||
if self.currentZ:
|
||||
formattedCurrentZ = "%.2f mm" % (self.currentZ)
|
||||
for callback in self._callbacks:
|
||||
try: callback.stateChangeCB(self._state, self.getStateString(), self._getStateFlags())
|
||||
except: pass
|
||||
|
||||
#~~ state reports
|
||||
|
||||
data = {
|
||||
"filename": self.filename,
|
||||
"currentZ": formattedCurrentZ,
|
||||
"line": self.progress,
|
||||
"totalLines": len(self.gcodeList),
|
||||
"printTime": formattedPrintTime,
|
||||
"printTimeLeft": formattedPrintTimeLeft,
|
||||
"filament": formattedFilament,
|
||||
"estimatedPrintTime": formattedPrintTimeEstimation
|
||||
}
|
||||
else:
|
||||
data = None
|
||||
return data
|
||||
|
||||
def gcodeState(self):
|
||||
if self.gcodeLoader is not None:
|
||||
|
@ -247,12 +385,12 @@ class Printer():
|
|||
return None
|
||||
|
||||
def feedrateState(self):
|
||||
if self.comm is not None:
|
||||
feedrateModifiers = self.comm.getFeedrateModifiers()
|
||||
if self._comm is not None:
|
||||
feedrateModifiers = self._comm.getFeedrateModifiers()
|
||||
result = {}
|
||||
for structure in self.feedrateModifierMapping.keys():
|
||||
if (feedrateModifiers.has_key(self.feedrateModifierMapping[structure])):
|
||||
result[structure] = int(round(feedrateModifiers[self.feedrateModifierMapping[structure]] * 100))
|
||||
for structure in self._feedrateModifierMapping.keys():
|
||||
if (feedrateModifiers.has_key(self._feedrateModifierMapping[structure])):
|
||||
result[structure] = int(round(feedrateModifiers[self._feedrateModifierMapping[structure]] * 100))
|
||||
else:
|
||||
result[structure] = 100
|
||||
return result
|
||||
|
@ -263,84 +401,31 @@ class Printer():
|
|||
"""
|
||||
Returns a human readable string corresponding to the current communication state.
|
||||
"""
|
||||
if self.comm is None:
|
||||
if self._comm is None:
|
||||
return "Offline"
|
||||
else:
|
||||
return self.comm.getStateString()
|
||||
return self._comm.getStateString()
|
||||
|
||||
def isClosedOrError(self):
|
||||
return self.comm is None or self.comm.isClosedOrError()
|
||||
return self._comm is None or self._comm.isClosedOrError()
|
||||
|
||||
def isOperational(self):
|
||||
return self.comm is not None and self.comm.isOperational()
|
||||
return self._comm is not None and self._comm.isOperational()
|
||||
|
||||
def isPrinting(self):
|
||||
return self.comm is not None and self.comm.isPrinting()
|
||||
return self._comm is not None and self._comm.isPrinting()
|
||||
|
||||
def isPaused(self):
|
||||
return self.comm is not None and self.comm.isPaused()
|
||||
return self._comm is not None and self._comm.isPaused()
|
||||
|
||||
def isError(self):
|
||||
return self.comm is not None and self.comm.isError()
|
||||
return self._comm is not None and self._comm.isError()
|
||||
|
||||
def isReady(self):
|
||||
return self.gcodeLoader is None and self.gcodeList and len(self.gcodeList) > 0
|
||||
return self._gcodeLoader is None and self._gcodeList and len(self._gcodeList) > 0
|
||||
|
||||
def isLoading(self):
|
||||
return self.gcodeLoader is not None
|
||||
|
||||
def loadGcode(self, file):
|
||||
"""
|
||||
Loads the gcode from the given file as the new print job.
|
||||
Aborts if the printer is currently printing or another gcode file is currently being loaded.
|
||||
"""
|
||||
if (self.comm is not None and self.comm.isPrinting()) or (self.gcodeLoader is not None):
|
||||
return
|
||||
|
||||
self.filename = None
|
||||
self.gcode = None
|
||||
self.gcodeList = None
|
||||
|
||||
self.gcodeLoader = GcodeLoader(file, self)
|
||||
self.gcodeLoader.start()
|
||||
|
||||
def startPrint(self):
|
||||
"""
|
||||
Starts the currently loaded print job.
|
||||
Only starts if the printer is connected and operational, not currently printing and a printjob is loaded
|
||||
"""
|
||||
if self.comm is None or not self.comm.isOperational():
|
||||
return
|
||||
if self.gcodeList is None:
|
||||
return
|
||||
if self.comm.isPrinting():
|
||||
return
|
||||
self.currentZ = -1
|
||||
self.comm.printGCode(self.gcodeList)
|
||||
|
||||
def togglePausePrint(self):
|
||||
"""
|
||||
Pause the current printjob.
|
||||
"""
|
||||
if self.comm is None:
|
||||
return
|
||||
self.comm.setPause(not self.comm.isPaused())
|
||||
|
||||
def cancelPrint(self, disableMotorsAndHeater=True):
|
||||
"""
|
||||
Cancel the current printjob.
|
||||
"""
|
||||
if self.comm is None:
|
||||
return
|
||||
self.comm.cancelPrint()
|
||||
if disableMotorsAndHeater:
|
||||
self.commands(["M84", "M104 S0", "M140 S0"]) # disable motors, switch off heaters
|
||||
|
||||
# reset line, height, print time
|
||||
self.currentZ = None
|
||||
self.progress = None
|
||||
self.printTime = None
|
||||
self.printTimeLeft = None
|
||||
return self._gcodeLoader is not None
|
||||
|
||||
class GcodeLoader(Thread):
|
||||
"""
|
||||
|
@ -352,19 +437,19 @@ class GcodeLoader(Thread):
|
|||
def __init__(self, filename, printerCallback):
|
||||
Thread.__init__(self);
|
||||
|
||||
self.printerCallback = printerCallback;
|
||||
self._printerCallback = printerCallback;
|
||||
|
||||
self.filename = filename
|
||||
self.progress = None
|
||||
self._filename = filename
|
||||
self._progress = None
|
||||
|
||||
self.gcode = None
|
||||
self.gcodeList = None
|
||||
self._gcode = None
|
||||
self._gcodeList = None
|
||||
|
||||
def run(self):
|
||||
#Send an initial M110 to reset the line counter to zero.
|
||||
prevLineType = lineType = "CUSTOM"
|
||||
gcodeList = ["M110"]
|
||||
with open(self.filename, "r") as file:
|
||||
with open(self._filename, "r") as file:
|
||||
for line in file:
|
||||
if line.startswith(";TYPE:"):
|
||||
lineType = line[6:].strip()
|
||||
|
@ -378,13 +463,38 @@ class GcodeLoader(Thread):
|
|||
gcodeList.append(line)
|
||||
prevLineType = lineType
|
||||
|
||||
self.gcodeList = gcodeList
|
||||
self.gcode = gcodeInterpreter.gcode()
|
||||
self.gcode.progressCallback = self.onProgress
|
||||
self.gcode.loadList(self.gcodeList)
|
||||
self._gcodeList = gcodeList
|
||||
self._gcode = gcodeInterpreter.gcode()
|
||||
self._gcode.progressCallback = self.onProgress
|
||||
self._gcode.loadList(self._gcodeList)
|
||||
|
||||
self.printerCallback.onGcodeLoaded(self)
|
||||
self._printerCallback.onGcodeLoaded()
|
||||
|
||||
def onProgress(self, progress):
|
||||
self.progress = progress
|
||||
self._progress = progress
|
||||
self._printerCallback.onGcodeLoadingProgress(progress)
|
||||
|
||||
class PrinterCallback(object):
|
||||
def zChangeCB(self, newZ):
|
||||
pass
|
||||
|
||||
def progressChangeCB(self, currentLine, printTime, printTimeLeft):
|
||||
pass
|
||||
|
||||
def temperatureChangeCB(self, temp, bedTemp, targetTemp, bedTargetTemp, history):
|
||||
pass
|
||||
|
||||
def stateChangeCB(self, state, stateString, booleanStates):
|
||||
pass
|
||||
|
||||
def logChangeCB(self, line, history):
|
||||
pass
|
||||
|
||||
def messageChangeCB(self, line, history):
|
||||
pass
|
||||
|
||||
def gcodeChangeCB(self, filename, progress):
|
||||
pass
|
||||
|
||||
def jobDataChangeCB(self, filename, lines, estimatedPrintTime, filamentLength):
|
||||
pass
|
|
@ -4,13 +4,16 @@ __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agp
|
|||
|
||||
from flask import Flask, request, render_template, jsonify, send_from_directory, abort, url_for
|
||||
from werkzeug import secure_filename
|
||||
|
||||
from printer_webui.printer import Printer, getConnectionOptions
|
||||
from printer_webui.settings import settings
|
||||
import timelapse
|
||||
import tornadio2
|
||||
|
||||
import os
|
||||
import fnmatch
|
||||
import datetime
|
||||
import time
|
||||
|
||||
from printer_webui.printer import Printer, getConnectionOptions, PrinterCallback
|
||||
from printer_webui.settings import settings
|
||||
import printer_webui.timelapse as timelapse
|
||||
|
||||
BASEURL = "/ajax/"
|
||||
SUCCESS = {}
|
||||
|
@ -30,64 +33,78 @@ def index():
|
|||
|
||||
#~~ Printer state
|
||||
|
||||
@app.route(BASEURL + "state", methods=["GET"])
|
||||
def printerState():
|
||||
temp = printer.currentTemp
|
||||
bedTemp = printer.currentBedTemp
|
||||
targetTemp = printer.currentTargetTemp
|
||||
bedTargetTemp = printer.currentBedTargetTemp
|
||||
jobData = printer.jobData()
|
||||
gcodeState = printer.gcodeState()
|
||||
feedrateState = printer.feedrateState()
|
||||
class PrinterStateConnection(tornadio2.SocketConnection, PrinterCallback):
|
||||
def __init__(self, session, endpoint=None):
|
||||
tornadio2.SocketConnection.__init__(self, session, endpoint)
|
||||
self._lastProgressReport = None
|
||||
|
||||
result = {
|
||||
"state": printer.getStateString(),
|
||||
"temp": temp,
|
||||
"bedTemp": bedTemp,
|
||||
"targetTemp": targetTemp,
|
||||
"targetBedTemp": bedTargetTemp,
|
||||
"operational": printer.isOperational(),
|
||||
"closedOrError": printer.isClosedOrError(),
|
||||
"error": printer.isError(),
|
||||
"printing": printer.isPrinting(),
|
||||
"paused": printer.isPaused(),
|
||||
"ready": printer.isReady(),
|
||||
"loading": printer.isLoading()
|
||||
}
|
||||
def on_open(self, info):
|
||||
printer.registerCallback(self)
|
||||
|
||||
if jobData is not None:
|
||||
jobData["filename"] = jobData["filename"].replace(UPLOAD_FOLDER + os.sep, "")
|
||||
result["job"] = jobData
|
||||
def on_close(self):
|
||||
printer.unregisterCallback(self)
|
||||
|
||||
if gcodeState is not None:
|
||||
gcodeState["filename"] = gcodeState["filename"].replace(UPLOAD_FOLDER + os.sep, "")
|
||||
result["gcode"] = gcodeState
|
||||
def zChangeCB(self, currentZ):
|
||||
formattedCurrentZ = None
|
||||
if currentZ:
|
||||
formattedCurrentZ = "%.2f mm" % (currentZ)
|
||||
|
||||
if feedrateState is not None:
|
||||
result["feedrate"] = feedrateState
|
||||
self.emit("zChange", {"currentZ": formattedCurrentZ})
|
||||
|
||||
if request.values.has_key("temperatures"):
|
||||
result["temperatures"] = printer.temps
|
||||
def progressChangeCB(self, currentLine, printTimeInSeconds, printTimeLeftInMinutes):
|
||||
if self._lastProgressReport and time.time() + 0.5 < self._lastProgressReport:
|
||||
return
|
||||
|
||||
if request.values.has_key("log"):
|
||||
result["log"] = printer.log
|
||||
formattedPrintTime = None
|
||||
if (printTimeInSeconds):
|
||||
formattedPrintTime = _getFormattedTimeDelta(datetime.timedelta(seconds=printTimeInSeconds))
|
||||
|
||||
if request.values.has_key("messages"):
|
||||
result["messages"] = printer.messages
|
||||
formattedPrintTimeLeft = None
|
||||
if (printTimeLeftInMinutes):
|
||||
formattedPrintTimeLeft = _getFormattedTimeDelta(datetime.timedelta(minutes=printTimeLeftInMinutes))
|
||||
|
||||
return jsonify(result)
|
||||
self._lastProgressReport = time.time()
|
||||
self.emit("printProgress", {
|
||||
"currentLine": currentLine,
|
||||
"printTime": formattedPrintTime,
|
||||
"printTimeLeft": formattedPrintTimeLeft
|
||||
})
|
||||
|
||||
@app.route(BASEURL + "state/messages", methods=["GET"])
|
||||
def printerMessages():
|
||||
return jsonify(messages=printer.messages)
|
||||
def temperatureChangeCB(self, temp, bedTemp, targetTemp, bedTargetTemp, history):
|
||||
self.emit("temperature", {
|
||||
"currentTemp": temp,
|
||||
"currentBedTemp": bedTemp,
|
||||
"currentTargetTemp": targetTemp,
|
||||
"currentTargetBedTemp": bedTargetTemp,
|
||||
"history": history
|
||||
})
|
||||
|
||||
@app.route(BASEURL + "state/log", methods=["GET"])
|
||||
def printerLogs():
|
||||
return jsonify(log=printer.log)
|
||||
def stateChangeCB(self, state, stateString, booleanStates):
|
||||
self.emit("state", {"currentState": stateString, "flags": booleanStates})
|
||||
|
||||
@app.route(BASEURL + "state/temperatures", methods=["GET"])
|
||||
def printerTemperatures():
|
||||
return jsonify(temperatures = printer.temps)
|
||||
def logChangeCB(self, line, history):
|
||||
self.emit("log", {"line": line, "history": history})
|
||||
|
||||
def messageChangeCB(self, line, history):
|
||||
self.emit("message", {"line": line, "history": history})
|
||||
|
||||
def gcodeChangeCB(self, filename, progress):
|
||||
self.emit("jobData", {"filename": "Loading... (%d%%)" % (round(progress * 100)), "lineCount": None, "estimatedPrintTime": None, "filament": None})
|
||||
|
||||
def jobDataChangeCB(self, filename, lines, estimatedPrintTimeInMinutes, filamentLengthInMillimeters):
|
||||
formattedPrintTimeEstimation = None
|
||||
if estimatedPrintTimeInMinutes:
|
||||
formattedPrintTimeEstimation = _getFormattedTimeDelta(datetime.timedelta(minutes=estimatedPrintTimeInMinutes))
|
||||
|
||||
formattedFilament = None
|
||||
if filamentLengthInMillimeters:
|
||||
formattedFilament = "%.2fm" % (filamentLengthInMillimeters / 1000)
|
||||
|
||||
formattedFilename = None
|
||||
if filename:
|
||||
formattedFilename = filename.replace(UPLOAD_FOLDER + os.sep, "")
|
||||
|
||||
self.emit("jobData", {"filename": formattedFilename, "lineCount": lines, "estimatedPrintTime": formattedPrintTimeEstimation, "filament": formattedFilament})
|
||||
|
||||
#~~ Printer control
|
||||
|
||||
|
@ -315,6 +332,12 @@ def setSettings():
|
|||
|
||||
#~~ helper functions
|
||||
|
||||
def _getFormattedTimeDelta(d):
|
||||
hours = d.seconds // 3600
|
||||
minutes = (d.seconds % 3600) // 60
|
||||
seconds = d.seconds % 60
|
||||
return "%02d:%02d:%02d" % (hours, minutes, seconds)
|
||||
|
||||
def sizeof_fmt(num):
|
||||
"""
|
||||
Taken from http://stackoverflow.com/questions/1094841/reusable-library-to-get-human-readable-version-of-file-size
|
||||
|
@ -331,8 +354,21 @@ def allowed_file(filename, extensions):
|
|||
#~~ startup code
|
||||
|
||||
def run(host = "0.0.0.0", port = 5000, debug = False):
|
||||
from tornado.wsgi import WSGIContainer
|
||||
from tornado.httpserver import HTTPServer
|
||||
from tornado.ioloop import IOLoop
|
||||
from tornado.web import Application, FallbackHandler
|
||||
|
||||
print "Listening on http://%s:%d" % (host, port)
|
||||
app.debug = debug
|
||||
app.run(host=host, port=port, use_reloader=False)
|
||||
|
||||
router = tornadio2.TornadioRouter(PrinterStateConnection)
|
||||
tornado_app = Application(router.urls + [
|
||||
(".*", FallbackHandler, {"fallback": WSGIContainer(app)})
|
||||
])
|
||||
server = HTTPServer(tornado_app)
|
||||
server.listen(port, address=host)
|
||||
IOLoop.instance().start()
|
||||
|
||||
def main():
|
||||
from optparse import OptionParser
|
||||
|
|
|
@ -122,3 +122,7 @@ table th.timelapse_files_action, table td.timelapse_files_action {
|
|||
text-align: center;
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
#webcam_container {
|
||||
width: 100%;
|
||||
}
|
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -49,16 +49,16 @@ function ConnectionViewModel() {
|
|||
self.saveSettings(false);
|
||||
}
|
||||
|
||||
self.fromStateResponse = function(response) {
|
||||
self.fromStateEvent = function(data) {
|
||||
self.previousIsOperational = self.isOperational();
|
||||
|
||||
self.isErrorOrClosed(response.closedOrError);
|
||||
self.isOperational(response.operational);
|
||||
self.isPaused(response.paused);
|
||||
self.isPrinting(response.printing);
|
||||
self.isError(response.error);
|
||||
self.isReady(response.ready);
|
||||
self.isLoading(response.loading);
|
||||
self.isErrorOrClosed(data.flags.closedOrError);
|
||||
self.isOperational(data.flags.operational);
|
||||
self.isPaused(data.flags.paused);
|
||||
self.isPrinting(data.flags.printing);
|
||||
self.isError(data.flags.error);
|
||||
self.isReady(data.flags.ready);
|
||||
self.isLoading(data.flags.loading);
|
||||
|
||||
var connectionTab = $("#connection");
|
||||
if (self.previousIsOperational != self.isOperational()) {
|
||||
|
@ -139,39 +139,36 @@ function PrinterStateViewModel() {
|
|||
return "Pause";
|
||||
});
|
||||
|
||||
self.fromResponse = function(response) {
|
||||
self.stateString(response.state);
|
||||
self.isErrorOrClosed(response.closedOrError);
|
||||
self.isOperational(response.operational);
|
||||
self.isPaused(response.paused);
|
||||
self.isPrinting(response.printing);
|
||||
self.isError(response.error);
|
||||
self.isReady(response.ready);
|
||||
self.isLoading(response.loading);
|
||||
self.fromStateEvent = function(data) {
|
||||
self.stateString(data.currentState);
|
||||
self.isErrorOrClosed(data.flags.closedOrError);
|
||||
self.isOperational(data.flags.operational);
|
||||
self.isPaused(data.flags.paused);
|
||||
self.isPrinting(data.flags.printing);
|
||||
self.isError(data.flags.error);
|
||||
self.isReady(data.flags.ready);
|
||||
self.isLoading(data.flags.loading);
|
||||
}
|
||||
|
||||
if (response.job) {
|
||||
self.filename(response.job.filename);
|
||||
self.filament(response.job.filament);
|
||||
self.estimatedPrintTime(response.job.estimatedPrintTime);
|
||||
self.printTime(response.job.printTime);
|
||||
self.printTimeLeft(response.job.printTimeLeft);
|
||||
self.currentLine(response.job.line ? response.job.line : 0);
|
||||
self.totalLines(response.job.totalLines ? response.job.totalLines : 0);
|
||||
self.currentHeight(response.job.currentZ);
|
||||
} else {
|
||||
if (response.loading && response.gcode) {
|
||||
self.filename("Loading... (" + Math.round(response.gcode.progress * 100) + "%)");
|
||||
} else {
|
||||
self.filename(undefined);
|
||||
}
|
||||
self.filament(undefined);
|
||||
self.estimatedPrintTime(undefined);
|
||||
self.printTime(undefined);
|
||||
self.printTimeLeft(undefined);
|
||||
self.currentLine(undefined);
|
||||
self.totalLines(undefined);
|
||||
self.currentHeight(undefined);
|
||||
}
|
||||
self.fromJobEvent = function(data) {
|
||||
self.filename(data.filename);
|
||||
self.totalLines(data.lineCount);
|
||||
self.estimatedPrintTime(data.estimatedPrintTime);
|
||||
self.filament(data.filament);
|
||||
}
|
||||
|
||||
self.fromProgressEvent = function(data) {
|
||||
self.currentLine(data.currentLine);
|
||||
self.printTime(data.printTime);
|
||||
self.printTimeLeft(data.printTimeLeft);
|
||||
}
|
||||
|
||||
self.fromZChangeEvent = function(data) {
|
||||
self.currentHeight(data.currentZ);
|
||||
}
|
||||
|
||||
self.fromGcodeEvent = function(data) {
|
||||
self.filename("Loading... (" + Math.round(data.progress * 100) + "%)");
|
||||
}
|
||||
}
|
||||
var printerStateViewModel = new PrinterStateViewModel();
|
||||
|
@ -238,20 +235,22 @@ function TemperatureViewModel() {
|
|||
}
|
||||
}
|
||||
|
||||
self.fromResponse = function(response) {
|
||||
self.temp(response.temp);
|
||||
self.bedTemp(response.bedTemp);
|
||||
self.targetTemp(response.targetTemp);
|
||||
self.bedTargetTemp(response.bedTargetTemp);
|
||||
self.temperatures = (response.temperatures);
|
||||
self.fromStateEvent = function(data) {
|
||||
self.isErrorOrClosed(data.flags.closedOrError);
|
||||
self.isOperational(data.flags.operational);
|
||||
self.isPaused(data.flags.paused);
|
||||
self.isPrinting(data.flags.printing);
|
||||
self.isError(data.flags.error);
|
||||
self.isReady(data.flags.ready);
|
||||
self.isLoading(data.flags.loading);
|
||||
}
|
||||
|
||||
self.isErrorOrClosed(response.closedOrError);
|
||||
self.isOperational(response.operational);
|
||||
self.isPaused(response.paused);
|
||||
self.isPrinting(response.printing);
|
||||
self.isError(response.error);
|
||||
self.isReady(response.ready);
|
||||
self.isLoading(response.loading);
|
||||
self.fromTemperatureEvent = function(data) {
|
||||
self.temp(data.temp);
|
||||
self.bedTemp(data.bedTemp);
|
||||
self.targetTemp(data.targetTemp);
|
||||
self.bedTargetTemp(data.bedTargetTemp);
|
||||
self.temperatures = (data.history);
|
||||
|
||||
self.updatePlot();
|
||||
}
|
||||
|
@ -284,15 +283,16 @@ function SpeedViewModel() {
|
|||
self.isReady = ko.observable(undefined);
|
||||
self.isLoading = ko.observable(undefined);
|
||||
|
||||
self.fromResponse = function(response) {
|
||||
self.isErrorOrClosed(response.closedOrError);
|
||||
self.isOperational(response.operational);
|
||||
self.isPaused(response.paused);
|
||||
self.isPrinting(response.printing);
|
||||
self.isError(response.error);
|
||||
self.isReady(response.ready);
|
||||
self.isLoading(response.loading);
|
||||
self.fromStateEvent = function(data) {
|
||||
self.isErrorOrClosed(data.closedOrError);
|
||||
self.isOperational(data.operational);
|
||||
self.isPaused(data.paused);
|
||||
self.isPrinting(data.printing);
|
||||
self.isError(data.error);
|
||||
self.isReady(data.ready);
|
||||
self.isLoading(data.loading);
|
||||
|
||||
/*
|
||||
if (response.feedrate) {
|
||||
self.outerWall(response.feedrate.outerWall);
|
||||
self.innerWall(response.feedrate.innerWall);
|
||||
|
@ -304,6 +304,7 @@ function SpeedViewModel() {
|
|||
self.fill(undefined);
|
||||
self.support(undefined);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
var speedViewModel = new SpeedViewModel();
|
||||
|
@ -313,9 +314,26 @@ function TerminalViewModel() {
|
|||
|
||||
self.log = undefined;
|
||||
|
||||
self.fromResponse = function(response) {
|
||||
self.log = response.log;
|
||||
self.isErrorOrClosed = ko.observable(undefined);
|
||||
self.isOperational = ko.observable(undefined);
|
||||
self.isPrinting = ko.observable(undefined);
|
||||
self.isPaused = ko.observable(undefined);
|
||||
self.isError = ko.observable(undefined);
|
||||
self.isReady = ko.observable(undefined);
|
||||
self.isLoading = ko.observable(undefined);
|
||||
|
||||
self.fromStateEvent = function(data) {
|
||||
self.isErrorOrClosed(data.flags.closedOrError);
|
||||
self.isOperational(data.flags.operational);
|
||||
self.isPaused(data.flags.paused);
|
||||
self.isPrinting(data.flags.printing);
|
||||
self.isError(data.flags.error);
|
||||
self.isReady(data.flags.ready);
|
||||
self.isLoading(data.flags.loading);
|
||||
}
|
||||
|
||||
self.fromLogEvent = function(data) {
|
||||
self.log = data.history;
|
||||
self.updateOutput();
|
||||
}
|
||||
|
||||
|
@ -334,10 +352,6 @@ function TerminalViewModel() {
|
|||
container.scrollTop(container[0].scrollHeight - container.height())
|
||||
}
|
||||
}
|
||||
|
||||
self.sendCommand = function(command) {
|
||||
|
||||
}
|
||||
}
|
||||
var terminalViewModel = new TerminalViewModel();
|
||||
|
||||
|
@ -413,7 +427,7 @@ function WebcamViewModel() {
|
|||
type: "GET",
|
||||
dataType: "json",
|
||||
success: self.fromResponse
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
self.fromResponse = function(response) {
|
||||
|
@ -427,14 +441,14 @@ function WebcamViewModel() {
|
|||
}
|
||||
}
|
||||
|
||||
self.fromStateResponse = function(response) {
|
||||
self.isErrorOrClosed(response.closedOrError);
|
||||
self.isOperational(response.operational);
|
||||
self.isPaused(response.paused);
|
||||
self.isPrinting(response.printing);
|
||||
self.isError(response.error);
|
||||
self.isReady(response.ready);
|
||||
self.isLoading(response.loading);
|
||||
self.fromStateEvent = function(data) {
|
||||
self.isErrorOrClosed(data.flags.closedOrError);
|
||||
self.isOperational(data.flags.operational);
|
||||
self.isPaused(data.flags.paused);
|
||||
self.isPrinting(data.flags.printing);
|
||||
self.isError(data.flags.error);
|
||||
self.isReady(data.flags.ready);
|
||||
self.isLoading(data.flags.loading);
|
||||
}
|
||||
|
||||
self.removeFile = function() {
|
||||
|
@ -470,11 +484,6 @@ var webcamViewModel = new WebcamViewModel();
|
|||
function DataUpdater(connectionViewModel, printerStateViewModel, temperatureViewModel, speedViewModel, terminalViewModel, webcamViewModel) {
|
||||
var self = this;
|
||||
|
||||
self.updateInterval = 500;
|
||||
self.updateIntervalOnError = 10000;
|
||||
self.includeTemperatures = true;
|
||||
self.includeLogs = true;
|
||||
|
||||
self.connectionViewModel = connectionViewModel;
|
||||
self.printerStateViewModel = printerStateViewModel;
|
||||
self.temperatureViewModel = temperatureViewModel;
|
||||
|
@ -482,6 +491,32 @@ function DataUpdater(connectionViewModel, printerStateViewModel, temperatureView
|
|||
self.speedViewModel = speedViewModel;
|
||||
self.webcamViewModel = webcamViewModel;
|
||||
|
||||
self.socket = io.connect();
|
||||
|
||||
self.socket.on("state", function(data) {
|
||||
self.printerStateViewModel.fromStateEvent(data);
|
||||
self.connectionViewModel.fromStateEvent(data);
|
||||
self.temperatureViewModel.fromStateEvent(data);
|
||||
self.terminalViewModel.fromStateEvent(data);
|
||||
self.speedViewModel.fromStateEvent(data);
|
||||
self.webcamViewModel.fromStateEvent(data);
|
||||
})
|
||||
self.socket.on("temperature", function(data) {
|
||||
self.temperatureViewModel.fromTemperatureEvent(data);
|
||||
})
|
||||
self.socket.on("jobData", function(data) {
|
||||
self.printerStateViewModel.fromJobEvent(data);
|
||||
})
|
||||
self.socket.on("log", function(data) {
|
||||
self.terminalViewModel.fromLogEvent(data);
|
||||
})
|
||||
self.socket.on("printProgress", function(data) {
|
||||
self.printerStateViewModel.fromProgressEvent(data);
|
||||
})
|
||||
self.socket.on("zChange", function(data) {
|
||||
self.printerStateViewModel.fromZChangeEvent(data);
|
||||
})
|
||||
|
||||
self.requestData = function() {
|
||||
var parameters = {};
|
||||
|
||||
|
@ -496,8 +531,10 @@ function DataUpdater(connectionViewModel, printerStateViewModel, temperatureView
|
|||
dataType: "json",
|
||||
data: parameters,
|
||||
success: function(response) {
|
||||
if ($("#offline_overlay").is(":visible"))
|
||||
if ($("#offline_overlay").is(":visible")) {
|
||||
$("#offline_overlay").hide();
|
||||
self.webcamViewModel.requestData();
|
||||
}
|
||||
|
||||
self.printerStateViewModel.fromResponse(response);
|
||||
self.connectionViewModel.fromStateResponse(response);
|
||||
|
@ -670,7 +707,7 @@ $(function() {
|
|||
|
||||
//~~ startup commands
|
||||
|
||||
dataUpdater.requestData();
|
||||
//dataUpdater.requestData();
|
||||
connectionViewModel.requestData();
|
||||
gcodeFilesViewModel.requestData();
|
||||
webcamViewModel.requestData();
|
||||
|
|
|
@ -9,16 +9,11 @@
|
|||
<link href="{{ url_for('static', filename='css/jquery.fileupload-ui.css') }}" rel="stylesheet" media="screen">
|
||||
<link href="{{ url_for('static', filename='css/ui.css') }}" rel="stylesheet" media="screen">
|
||||
|
||||
<script src="http://code.jquery.com/jquery-latest.js"></script>
|
||||
<script src="{{ url_for('static', filename='js/knockout-2.2.0.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/bootstrap.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery.ui.widget.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery.flot.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery.iframe-transport.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery.fileupload.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/ui.js') }}"></script>
|
||||
<script lang="javascript">
|
||||
var AJAX_BASEURL = '/ajax/';
|
||||
|
||||
var WEB_SOCKET_SWF_LOCATION = "{{ url_for('static', filename='js/WebSocketMain.swf') }}";
|
||||
var WEB_SOCKET_DEBUG = true;
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -283,5 +278,15 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="http://code.jquery.com/jquery-latest.js"></script>
|
||||
<script src="{{ url_for('static', filename='js/knockout-2.2.0.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/bootstrap.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery.ui.widget.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery.flot.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery.iframe-transport.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery.fileupload.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/socket.io.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/ui.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue