State is now sent in update bundles to the frontend if updates are available, but not more frequently than every 500ms.
parent
4983a00adf
commit
e8a633db8b
|
@ -3,7 +3,10 @@ __author__ = "Gina Häußge <osd@foosel.net>"
|
|||
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
||||
|
||||
import time
|
||||
from threading import Thread, Event, Lock
|
||||
import datetime
|
||||
import threading
|
||||
import copy
|
||||
import os
|
||||
|
||||
import printer_webui.util.comm as comm
|
||||
from printer_webui.util import gcodeInterpreter
|
||||
|
@ -71,9 +74,19 @@ class Printer():
|
|||
self._callbacks = []
|
||||
self._lastProgressReport = None
|
||||
|
||||
self._stateMonitor = StateMonitor(ratelimit=0.5, updateCallback=self._sendCurrentDataCallbacks)
|
||||
self._stateMonitor = StateMonitor(
|
||||
ratelimit=0.5,
|
||||
updateCallback=self._sendCurrentDataCallbacks,
|
||||
addTemperatureCallback=self._sendAddTemperatureCallbacks,
|
||||
addLogCallback=self._sendAddLogCallbacks,
|
||||
addMessageCallback=self._sendAddMessageCallbacks
|
||||
)
|
||||
self._stateMonitor.reset(
|
||||
state={"state": self._state, "stateString": self.getStateString(), "flags": self._getStateFlags()}
|
||||
state={"state": None, "stateString": self.getStateString(), "flags": self._getStateFlags()},
|
||||
jobData={"filename": None, "lines": None, "estimatedPrintTime": None, "filament": None},
|
||||
gcodeData={"filename": None, "progress": None},
|
||||
progress={"progress": None, "printTime": None, "printTimeLeft": None},
|
||||
currentZ=None
|
||||
)
|
||||
|
||||
#~~ callback handling
|
||||
|
@ -86,9 +99,24 @@ class Printer():
|
|||
if callback in self._callbacks:
|
||||
self._callbacks.remove(callback)
|
||||
|
||||
def _sendAddTemperatureCallbacks(self, data):
|
||||
for callback in self._callbacks:
|
||||
try: callback.addTemperature(data)
|
||||
except: pass
|
||||
|
||||
def _sendAddLogCallbacks(self, data):
|
||||
for callback in self._callbacks:
|
||||
try: callback.addLog(data)
|
||||
except: pass
|
||||
|
||||
def _sendAddMessageCallbacks(self, data):
|
||||
for callback in self._callbacks:
|
||||
try: callback.addMessage(data)
|
||||
except: pass
|
||||
|
||||
def _sendCurrentDataCallbacks(self, data):
|
||||
for callback in self._callbacks:
|
||||
try: callback.sendCurrentData(data)
|
||||
try: callback.sendCurrentData(copy.deepcopy(data))
|
||||
except: pass
|
||||
|
||||
#~~ printer commands
|
||||
|
@ -139,9 +167,11 @@ class Printer():
|
|||
|
||||
self._setJobData(None, None, None)
|
||||
|
||||
self._gcodeLoader = GcodeLoader(file, self)
|
||||
self._gcodeLoader = GcodeLoader(file, self._onGcodeLoadingProgress, self._onGcodeLoaded)
|
||||
self._gcodeLoader.start()
|
||||
|
||||
self._stateMonitor.setState({"state": self._state, "stateString": self.getStateString(), "flags": self._getStateFlags()})
|
||||
|
||||
def startPrint(self):
|
||||
"""
|
||||
Starts the currently loaded print job.
|
||||
|
@ -192,11 +222,15 @@ class Printer():
|
|||
|
||||
def _setCurrentZ(self, currentZ):
|
||||
self._currentZ = currentZ
|
||||
self._stateMonitor.setCurrentZ(self._currentZ)
|
||||
|
||||
formattedCurrentZ = None
|
||||
if self._currentZ:
|
||||
formattedCurrentZ = "%.2f mm" % (self._currentZ)
|
||||
self._stateMonitor.setCurrentZ(formattedCurrentZ)
|
||||
|
||||
def _setState(self, state):
|
||||
self._state = state
|
||||
self._stateMonitor.setState({"state": self._state, "stateString": self.getStateString(), "stateFlags": self._getStateFlags()})
|
||||
self._stateMonitor.setState({"state": self._state, "stateString": self.getStateString(), "flags": self._getStateFlags()})
|
||||
|
||||
def _addLog(self, log):
|
||||
self._log.append(log)
|
||||
|
@ -212,7 +246,16 @@ class Printer():
|
|||
self._progress = progress
|
||||
self._printTime = printTime
|
||||
self._printTimeLeft = printTimeLeft
|
||||
self._stateMonitor.setProgress({"progress": self._progress, "printTime": self._printTime, "printTimeLeft": self._printTimeLeft})
|
||||
|
||||
formattedPrintTime = None
|
||||
if (self._printTime):
|
||||
formattedPrintTime = _getFormattedTimeDelta(datetime.timedelta(seconds=self._printTime))
|
||||
|
||||
formattedPrintTimeLeft = None
|
||||
if (self._printTimeLeft):
|
||||
formattedPrintTimeLeft = _getFormattedTimeDelta(datetime.timedelta(minutes=self._printTimeLeft))
|
||||
|
||||
self._stateMonitor.setProgress({"progress": self._progress, "printTime": formattedPrintTime, "printTimeLeft": formattedPrintTimeLeft})
|
||||
|
||||
def _addTemperatureData(self, temp, bedTemp, targetTemp, bedTargetTemp):
|
||||
currentTime = int(time.time() * 1000)
|
||||
|
@ -245,25 +288,21 @@ class Printer():
|
|||
if self._gcodeList:
|
||||
lines = len(self._gcodeList)
|
||||
|
||||
estimatedPrintTime = None
|
||||
filament = None
|
||||
formattedPrintTimeEstimation = None
|
||||
formattedFilament = None
|
||||
if self._gcode:
|
||||
estimatedPrintTime = self._gcode.totalMoveTimeMinute
|
||||
filament = self._gcode.extrusionAmount
|
||||
if self._gcode.totalMoveTimeMinute:
|
||||
formattedPrintTimeEstimation = _getFormattedTimeDelta(datetime.timedelta(minutes=self._gcode.totalMoveTimeMinute))
|
||||
if self._gcode.extrusionAmount:
|
||||
formattedFilament = "%.2fm" % (self._gcode.extrusionAmount / 1000)
|
||||
|
||||
self._stateMonitor.setJobData({"filename": self._filename, "lines": lines, "estimatedPrintTime": estimatedPrintTime, "filament": filament})
|
||||
formattedFilename = None
|
||||
if self._filename:
|
||||
formattedFilename = os.path.basename(self._filename)
|
||||
|
||||
self._stateMonitor.setJobData({"filename": formattedFilename, "lines": lines, "estimatedPrintTime": formattedPrintTimeEstimation, "filament": formattedFilament})
|
||||
|
||||
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:
|
||||
data = self._stateMonitor.getCurrentData()
|
||||
data.update({
|
||||
|
@ -346,16 +385,24 @@ class Printer():
|
|||
|
||||
#~~ callbacks triggered by gcodeLoader
|
||||
|
||||
def onGcodeLoadingProgress(self, progress):
|
||||
self._stateMonitor.setGcodeData({"filename": self._gcodeLoader._filename, "progress": progress})
|
||||
def _onGcodeLoadingProgress(self, filename, progress):
|
||||
formattedFilename = None
|
||||
if filename is not None:
|
||||
formattedFilename = os.path.basename(filename)
|
||||
|
||||
def onGcodeLoaded(self):
|
||||
self._setJobData(self._gcodeLoader._filename, self._gcodeLoader._gcode, self._gcodeLoader._gcodeList)
|
||||
self._stateMonitor.setGcodeData({"filename": formattedFilename, "progress": progress})
|
||||
|
||||
def _onGcodeLoaded(self, filename, gcode, gcodeList):
|
||||
formattedFilename = None
|
||||
if filename is not None:
|
||||
formattedFilename = os.path.basename(filename)
|
||||
|
||||
self._setJobData(formattedFilename, gcode, gcodeList)
|
||||
self._setCurrentZ(None)
|
||||
self._setProgressData(None, None, None)
|
||||
self._gcodeLoader = None
|
||||
|
||||
self._stateMonitor.setState({"state": self._state, "stateString": self.getStateString(), "stateFlags": self._getStateFlags()})
|
||||
self._stateMonitor.setState({"state": self._state, "stateString": self.getStateString(), "flags": self._getStateFlags()})
|
||||
|
||||
#~~ state reports
|
||||
|
||||
|
@ -402,17 +449,18 @@ class Printer():
|
|||
def isLoading(self):
|
||||
return self._gcodeLoader is not None
|
||||
|
||||
class GcodeLoader(Thread):
|
||||
class GcodeLoader(threading.Thread):
|
||||
"""
|
||||
The GcodeLoader takes care of loading a gcode-File from disk and parsing it into a gcode object in a separate
|
||||
thread while constantly notifying interested listeners about the current progress.
|
||||
The progress is returned as a float value between 0 and 1 which is to be interpreted as the percentage of completion.
|
||||
"""
|
||||
|
||||
def __init__(self, filename, printerCallback):
|
||||
Thread.__init__(self)
|
||||
def __init__(self, filename, progressCallback, loadedCallback):
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
self._printerCallback = printerCallback
|
||||
self._progressCallback = progressCallback
|
||||
self._loadedCallback = loadedCallback
|
||||
|
||||
self._filename = filename
|
||||
self._progress = None
|
||||
|
@ -443,11 +491,11 @@ class GcodeLoader(Thread):
|
|||
self._gcode.progressCallback = self.onProgress
|
||||
self._gcode.loadList(self._gcodeList)
|
||||
|
||||
self._printerCallback.onGcodeLoaded()
|
||||
self._loadedCallback(self._filename, self._gcode, self._gcodeList)
|
||||
|
||||
def onProgress(self, progress):
|
||||
self._progress = progress
|
||||
self._printerCallback.onGcodeLoadingProgress(progress)
|
||||
self._progressCallback(self._filename, self._progress)
|
||||
|
||||
class PrinterCallback(object):
|
||||
def sendCurrentData(self, data):
|
||||
|
@ -456,48 +504,52 @@ class PrinterCallback(object):
|
|||
def sendHistoryData(self, data):
|
||||
pass
|
||||
|
||||
def addTemperature(self, data):
|
||||
pass
|
||||
|
||||
def addLog(self, data):
|
||||
pass
|
||||
|
||||
def addMessage(self, data):
|
||||
pass
|
||||
|
||||
class StateMonitor(object):
|
||||
def __init__(self, ratelimit, updateCallback):
|
||||
def __init__(self, ratelimit, updateCallback, addTemperatureCallback, addLogCallback, addMessageCallback):
|
||||
self._ratelimit = ratelimit
|
||||
self._updateCallback = updateCallback
|
||||
self._addTemperatureCallback = addTemperatureCallback
|
||||
self._addLogCallback = addLogCallback
|
||||
self._addMessageCallback = addMessageCallback
|
||||
|
||||
self._state = None
|
||||
self._jobData = None
|
||||
self._gcodeData = None
|
||||
self._currentZ = None
|
||||
self._progress = None
|
||||
self._logBacklog = []
|
||||
self._logHistory = []
|
||||
self._messageBacklog = []
|
||||
self._messageHistory = []
|
||||
self._temperatureBacklog = []
|
||||
self._temperatureHistory = []
|
||||
|
||||
self._temperatureBacklogMutex = Lock()
|
||||
self._logBacklogMutex = Lock()
|
||||
self._messageBacklogMutex = Lock()
|
||||
self._changeEvent = Event()
|
||||
self._changeEvent = threading.Event()
|
||||
|
||||
self._lastUpdate = time.time()
|
||||
self._worker = Thread(target=self._work)
|
||||
self._worker = threading.Thread(target=self._work)
|
||||
self._worker.start()
|
||||
|
||||
def reset(self, state=None):
|
||||
def reset(self, state=None, jobData=None, gcodeData=None, progress=None, currentZ=None):
|
||||
self.setState(state)
|
||||
self.setJobData(jobData)
|
||||
self.setGcodeData(gcodeData)
|
||||
self.setProgress(progress)
|
||||
self.setCurrentZ(currentZ)
|
||||
|
||||
def addTemperature(self, temperature):
|
||||
with self._temperatureBacklogMutex:
|
||||
self._temperatureBacklog.append(temperature)
|
||||
self._addTemperatureCallback(temperature)
|
||||
self._changeEvent.set()
|
||||
|
||||
def addLog(self, log):
|
||||
with self._logBacklogMutex:
|
||||
self._logBacklog.append(log)
|
||||
self._addLogCallback(log)
|
||||
self._changeEvent.set()
|
||||
|
||||
def addMessage(self, message):
|
||||
with self._messageBacklogMutex:
|
||||
self._messageBacklog.append(message)
|
||||
self._addMessageCallback(message)
|
||||
self._changeEvent.set()
|
||||
|
||||
def setCurrentZ(self, currentZ):
|
||||
|
@ -523,28 +575,14 @@ class StateMonitor(object):
|
|||
def _work(self):
|
||||
while True:
|
||||
self._changeEvent.wait()
|
||||
additionalWaitTime = time.time() + self._ratelimit - self._lastUpdate
|
||||
|
||||
now = time.time()
|
||||
delta = now - self._lastUpdate
|
||||
additionalWaitTime = self._ratelimit - delta
|
||||
if additionalWaitTime > 0:
|
||||
time.sleep(additionalWaitTime)
|
||||
|
||||
with self._temperatureBacklogMutex:
|
||||
temperatures = self._temperatureBacklog
|
||||
self._temperatureBacklog = []
|
||||
|
||||
with self._logBacklogMutex:
|
||||
logs = self._logBacklog
|
||||
self._logBacklog = []
|
||||
|
||||
with self._messageBacklogMutex:
|
||||
messages = self._messageBacklog
|
||||
self._messageBacklog = []
|
||||
|
||||
data = self.getCurrentData()
|
||||
data.update({
|
||||
"temperatures": temperatures,
|
||||
"logs": logs,
|
||||
"messages": messages
|
||||
})
|
||||
self._updateCallback(data)
|
||||
self._lastUpdate = time.time()
|
||||
self._changeEvent.clear()
|
||||
|
@ -554,5 +592,14 @@ class StateMonitor(object):
|
|||
"state": self._state,
|
||||
"job": self._jobData,
|
||||
"gcode": self._gcodeData,
|
||||
"currentZ": self._currentZ
|
||||
"currentZ": self._currentZ,
|
||||
"progress": self._progress
|
||||
}
|
||||
|
||||
def _getFormattedTimeDelta(d):
|
||||
if d is None:
|
||||
return None
|
||||
hours = d.seconds // 3600
|
||||
minutes = (d.seconds % 3600) // 60
|
||||
seconds = d.seconds % 60
|
||||
return "%02d:%02d:%02d" % (hours, minutes, seconds)
|
||||
|
|
|
@ -8,7 +8,7 @@ import tornadio2
|
|||
|
||||
import os
|
||||
import fnmatch
|
||||
import datetime
|
||||
import threading
|
||||
|
||||
from printer_webui.printer import Printer, getConnectionOptions, PrinterCallback
|
||||
from printer_webui.settings import settings
|
||||
|
@ -33,25 +33,63 @@ def index():
|
|||
#~~ Printer state
|
||||
|
||||
class PrinterStateConnection(tornadio2.SocketConnection, PrinterCallback):
|
||||
def __init__(self, session, endpoint=None):
|
||||
tornadio2.SocketConnection.__init__(self, session, endpoint)
|
||||
|
||||
self._temperatureBacklog = []
|
||||
self._temperatureBacklogMutex = threading.Lock()
|
||||
self._logBacklog = []
|
||||
self._logBacklogMutex = threading.Lock()
|
||||
self._messageBacklog = []
|
||||
self._messageBacklogMutex = threading.Lock()
|
||||
|
||||
def on_open(self, info):
|
||||
print("Opened socket")
|
||||
print("New connection from client")
|
||||
printer.registerCallback(self)
|
||||
|
||||
def on_close(self):
|
||||
print("Closed socket")
|
||||
print("Closed client connection")
|
||||
printer.unregisterCallback(self)
|
||||
|
||||
def on_message(self, message):
|
||||
pass
|
||||
|
||||
def sendCurrentData(self, data):
|
||||
print("Sending current data...")
|
||||
# add current temperature, log and message backlogs to sent data
|
||||
with self._temperatureBacklogMutex:
|
||||
temperatures = self._temperatureBacklog
|
||||
self._temperatureBacklog = []
|
||||
|
||||
with self._logBacklogMutex:
|
||||
logs = self._logBacklog
|
||||
self._logBacklog = []
|
||||
|
||||
with self._messageBacklogMutex:
|
||||
messages = self._messageBacklog
|
||||
self._messageBacklog = []
|
||||
|
||||
data.update({
|
||||
"temperatures": temperatures,
|
||||
"logs": logs,
|
||||
"messages": messages
|
||||
})
|
||||
self.emit("current", data)
|
||||
|
||||
def sendHistoryData(self, data):
|
||||
print("Sending history...")
|
||||
self.emit("history", data)
|
||||
|
||||
def addLog(self, data):
|
||||
with self._logBacklogMutex:
|
||||
self._logBacklog.append(data)
|
||||
|
||||
def addMessage(self, data):
|
||||
with self._messageBacklogMutex:
|
||||
self._messageBacklog.append(data)
|
||||
|
||||
def addTemperature(self, data):
|
||||
with self._temperatureBacklogMutex:
|
||||
self._temperatureBacklog.append(data)
|
||||
|
||||
#~~ Printer control
|
||||
|
||||
@app.route(BASEURL + "control/connectionOptions", methods=["GET"])
|
||||
|
@ -278,12 +316,6 @@ 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
|
||||
|
|
|
@ -49,6 +49,10 @@ function ConnectionViewModel() {
|
|||
self.saveSettings(false);
|
||||
}
|
||||
|
||||
self.fromHistoryData = function(data) {
|
||||
self._processStateData(data.state);
|
||||
}
|
||||
|
||||
self.fromCurrentData = function(data) {
|
||||
self._processStateData(data.state);
|
||||
}
|
||||
|
@ -102,7 +106,6 @@ function ConnectionViewModel() {
|
|||
}
|
||||
}
|
||||
}
|
||||
var connectionViewModel = new ConnectionViewModel();
|
||||
|
||||
function PrinterStateViewModel() {
|
||||
var self = this;
|
||||
|
@ -144,17 +147,21 @@ function PrinterStateViewModel() {
|
|||
});
|
||||
|
||||
self.fromCurrentData = function(data) {
|
||||
self._processStateData(data.state);
|
||||
self._fromData(data);
|
||||
}
|
||||
|
||||
self.fromHistoryData = function(data) {
|
||||
self._fromData(data);
|
||||
}
|
||||
|
||||
self._fromData = function(data) {
|
||||
self._processStateData(data.state)
|
||||
self._processJobData(data.job);
|
||||
self._processGcodeData(data.gcode);
|
||||
self._processProgressData(data.progress);
|
||||
self._processZData(data.currentZ);
|
||||
}
|
||||
|
||||
self.fromHistoryData = function(data) {
|
||||
self._processStateData(data.state)
|
||||
}
|
||||
|
||||
self._processStateData = function(data) {
|
||||
self.stateString(data.stateString);
|
||||
self.isErrorOrClosed(data.flags.closedOrError);
|
||||
|
@ -168,7 +175,7 @@ function PrinterStateViewModel() {
|
|||
|
||||
self._processJobData = function(data) {
|
||||
self.filename(data.filename);
|
||||
self.totalLines(data.lineCount);
|
||||
self.totalLines(data.lines);
|
||||
self.estimatedPrintTime(data.estimatedPrintTime);
|
||||
self.filament(data.filament);
|
||||
}
|
||||
|
@ -180,16 +187,15 @@ function PrinterStateViewModel() {
|
|||
}
|
||||
|
||||
self._processProgressData = function(data) {
|
||||
self.currentLine(data.currentLine);
|
||||
self.currentLine(data.progress);
|
||||
self.printTime(data.printTime);
|
||||
self.printTimeLeft(data.printTimeLeft);
|
||||
}
|
||||
|
||||
self._processZData = function(data) {
|
||||
self.currentHeight(data.currentZ);
|
||||
self.currentHeight(data);
|
||||
}
|
||||
}
|
||||
var printerStateViewModel = new PrinterStateViewModel();
|
||||
|
||||
function TemperatureViewModel() {
|
||||
var self = this;
|
||||
|
@ -304,15 +310,15 @@ function TemperatureViewModel() {
|
|||
self.temperatures.actualBed = self.temperatures.actualBed.slice(-300);
|
||||
self.temperatures.targetBed = self.temperatures.targetBed.slice(-300);
|
||||
|
||||
self._updatePlot();
|
||||
self.updatePlot();
|
||||
}
|
||||
|
||||
self._processTemperatureHistoryData = function(data) {
|
||||
self.temperatures = data;
|
||||
self._updatePlot();
|
||||
self.updatePlot();
|
||||
}
|
||||
|
||||
self._updatePlot = function() {
|
||||
self.updatePlot = function() {
|
||||
var data = [
|
||||
{label: "Actual", color: "#FF4040", data: self.temperatures.actual},
|
||||
{label: "Target", color: "#FFA0A0", data: self.temperatures.target},
|
||||
|
@ -322,7 +328,6 @@ function TemperatureViewModel() {
|
|||
$.plot($("#temperature-graph"), data, self.plotOptions);
|
||||
}
|
||||
}
|
||||
var temperatureViewModel = new TemperatureViewModel();
|
||||
|
||||
function SpeedViewModel() {
|
||||
var self = this;
|
||||
|
@ -340,14 +345,23 @@ function SpeedViewModel() {
|
|||
self.isReady = ko.observable(undefined);
|
||||
self.isLoading = ko.observable(undefined);
|
||||
|
||||
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);
|
||||
self._fromCurrentData = function(data) {
|
||||
self._processStateData(data.state);
|
||||
}
|
||||
|
||||
self._fromHistoryData = function(data) {
|
||||
self._processStateData(data.state);
|
||||
}
|
||||
|
||||
self._processStateData = 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);
|
||||
}
|
||||
|
||||
/*
|
||||
if (response.feedrate) {
|
||||
|
@ -362,9 +376,7 @@ function SpeedViewModel() {
|
|||
self.support(undefined);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
var speedViewModel = new SpeedViewModel();
|
||||
|
||||
function TerminalViewModel() {
|
||||
var self = this;
|
||||
|
@ -379,7 +391,29 @@ function TerminalViewModel() {
|
|||
self.isReady = ko.observable(undefined);
|
||||
self.isLoading = ko.observable(undefined);
|
||||
|
||||
self.fromStateEvent = function(data) {
|
||||
self.fromCurrentData = function(data) {
|
||||
self._processStateData(data.state);
|
||||
self._processCurrentLogData(data.logs);
|
||||
}
|
||||
|
||||
self.fromHistoryData = function(data) {
|
||||
self._processStateData(data.state);
|
||||
self._processHistoryLogData(data.logHistory);
|
||||
}
|
||||
|
||||
self._processCurrentLogData = function(data) {
|
||||
if (!self.log)
|
||||
self.log = []
|
||||
self.log = self.log.concat(data)
|
||||
self.updateOutput();
|
||||
}
|
||||
|
||||
self._processHistoryLogData = function(data) {
|
||||
self.log = data;
|
||||
self.updateOutput();
|
||||
}
|
||||
|
||||
self._processStateData = function(data) {
|
||||
self.isErrorOrClosed(data.flags.closedOrError);
|
||||
self.isOperational(data.flags.operational);
|
||||
self.isPaused(data.flags.paused);
|
||||
|
@ -389,18 +423,6 @@ function TerminalViewModel() {
|
|||
self.isLoading(data.flags.loading);
|
||||
}
|
||||
|
||||
self.fromLogEvent = function(data) {
|
||||
if (!self.log)
|
||||
self.log = []
|
||||
self.log.concat(data.line)
|
||||
self.updateOutput();
|
||||
}
|
||||
|
||||
self.fromHistoryEvent = function(data) {
|
||||
self.log = data;
|
||||
self.updateOutput();
|
||||
}
|
||||
|
||||
self.updateOutput = function() {
|
||||
if (!self.log)
|
||||
return;
|
||||
|
@ -420,7 +442,6 @@ function TerminalViewModel() {
|
|||
}
|
||||
}
|
||||
}
|
||||
var terminalViewModel = new TerminalViewModel();
|
||||
|
||||
function GcodeFilesViewModel() {
|
||||
var self = this;
|
||||
|
@ -463,7 +484,6 @@ function GcodeFilesViewModel() {
|
|||
})
|
||||
}
|
||||
}
|
||||
var gcodeFilesViewModel = new GcodeFilesViewModel();
|
||||
|
||||
function WebcamViewModel() {
|
||||
var self = this;
|
||||
|
@ -508,7 +528,15 @@ function WebcamViewModel() {
|
|||
}
|
||||
}
|
||||
|
||||
self.fromStateEvent = function(data) {
|
||||
self.fromCurrentData = function(data) {
|
||||
self._processStateData(data.state);
|
||||
}
|
||||
|
||||
self.fromHistoryData = function(data) {
|
||||
self._processStateData(data.state);
|
||||
}
|
||||
|
||||
self._processStateData = function(data) {
|
||||
self.isErrorOrClosed(data.flags.closedOrError);
|
||||
self.isOperational(data.flags.operational);
|
||||
self.isPaused(data.flags.paused);
|
||||
|
@ -546,7 +574,6 @@ function WebcamViewModel() {
|
|||
})
|
||||
}
|
||||
}
|
||||
var webcamViewModel = new WebcamViewModel();
|
||||
|
||||
function DataUpdater(connectionViewModel, printerStateViewModel, temperatureViewModel, speedViewModel, terminalViewModel, webcamViewModel) {
|
||||
var self = this;
|
||||
|
@ -558,41 +585,50 @@ function DataUpdater(connectionViewModel, printerStateViewModel, temperatureView
|
|||
self.speedViewModel = speedViewModel;
|
||||
self.webcamViewModel = webcamViewModel;
|
||||
|
||||
self.socket = io.connect();
|
||||
self.socket.on("connect", function() {
|
||||
self._socket = io.connect();
|
||||
self._socket.on("connect", function() {
|
||||
if ($("#offline_overlay").is(":visible")) {
|
||||
$("#offline_overlay").hide();
|
||||
self.webcamViewModel.requestData();
|
||||
}
|
||||
})
|
||||
self.socket.on("disconnect", function() {
|
||||
self._socket.on("disconnect", function() {
|
||||
// if the updated fails to communicate with the backend, we interpret this as a missing backend
|
||||
if (!$("#offline_overlay").is(":visible"))
|
||||
$("#offline_overlay").show();
|
||||
})
|
||||
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("history", function(data) {
|
||||
self._socket.on("history", function(data) {
|
||||
self.connectionViewModel.fromHistoryData(data);
|
||||
self.printerStateViewModel.fromHistoryData(data);
|
||||
self.temperatureViewModel.fromHistoryData(data);
|
||||
//self.terminalViewModel.fromHistoryData(data);
|
||||
self.terminalViewModel.fromHistoryData(data);
|
||||
self.webcamViewModel.fromHistoryData(data);
|
||||
})
|
||||
self.socket.on("current", function(data) {
|
||||
self._socket.on("current", function(data) {
|
||||
self.connectionViewModel.fromCurrentData(data);
|
||||
self.printerStateViewModel.fromCurrentData(data);
|
||||
self.temperatureViewModel.fromCurrentData(data);
|
||||
self.terminalViewModel.fromCurrentData(data);
|
||||
self.webcamViewModel.fromCurrentData(data);
|
||||
})
|
||||
|
||||
self.reconnect = function() {
|
||||
self._socket.socket.connect();
|
||||
}
|
||||
}
|
||||
var dataUpdater = new DataUpdater(connectionViewModel, printerStateViewModel, temperatureViewModel, speedViewModel, terminalViewModel, webcamViewModel);
|
||||
|
||||
$(function() {
|
||||
|
||||
//~~ View models
|
||||
var connectionViewModel = new ConnectionViewModel();
|
||||
var printerStateViewModel = new PrinterStateViewModel();
|
||||
var temperatureViewModel = new TemperatureViewModel();
|
||||
var speedViewModel = new SpeedViewModel();
|
||||
var terminalViewModel = new TerminalViewModel();
|
||||
var gcodeFilesViewModel = new GcodeFilesViewModel();
|
||||
var webcamViewModel = new WebcamViewModel();
|
||||
var dataUpdater = new DataUpdater(connectionViewModel, printerStateViewModel, temperatureViewModel, speedViewModel, terminalViewModel, webcamViewModel);
|
||||
|
||||
//~~ Print job control
|
||||
|
||||
$("#job_print").click(function() {
|
||||
|
@ -641,6 +677,9 @@ $(function() {
|
|||
success: function() {$("#temp_newBedTemp").val("")}
|
||||
})
|
||||
})
|
||||
$('#tabs a[data-toggle="tab"]').on('shown', function (e) {
|
||||
temperatureViewModel.updatePlot();
|
||||
});
|
||||
|
||||
//~~ Jog controls
|
||||
|
||||
|
@ -719,7 +758,7 @@ $(function() {
|
|||
});
|
||||
|
||||
//~~ Offline overlay
|
||||
$("#offline_overlay_reconnect").click(function() {dataUpdater.requestData()});
|
||||
$("#offline_overlay_reconnect").click(function() {dataUpdater.reconnect()});
|
||||
|
||||
//~~ knockout.js bindings
|
||||
|
||||
|
@ -738,7 +777,6 @@ $(function() {
|
|||
|
||||
//~~ startup commands
|
||||
|
||||
//dataUpdater.requestData();
|
||||
connectionViewModel.requestData();
|
||||
gcodeFilesViewModel.requestData();
|
||||
webcamViewModel.requestData();
|
||||
|
|
|
@ -105,11 +105,11 @@
|
|||
</div>
|
||||
|
||||
<div class="tabbable span8">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#temp" data-toggle="tab">Temp</a></li>
|
||||
<li><a href="#jog" data-toggle="tab">Jog</a></li>
|
||||
<li><a href="#speed" data-toggle="tab">Speed</a></li>
|
||||
<li><a href="#term" data-toggle="tab">Term</a></li>
|
||||
<ul class="nav nav-tabs" id="tabs">
|
||||
<li class="active"><a href="#temp" data-toggle="tab">Temperature</a></li>
|
||||
<li><a href="#jog" data-toggle="tab">Controls</a></li>
|
||||
<!--<li><a href="#speed" data-toggle="tab">Speed</a></li>-->
|
||||
<li><a href="#term" data-toggle="tab">Terminal</a></li>
|
||||
{% if webcamStream %}<li><a href="#webcam" data-toggle="tab">Webcam</a></li>{% endif %}
|
||||
</ul>
|
||||
|
||||
|
|
Loading…
Reference in New Issue