def build(self): Window.maximize() interface = FloatLayout() self.data = Data() self.frontpage = FrontPage(self.data, name='FrontPage') interface.add_widget(self.frontpage) self.nonVisibleWidgets = NonVisibleWidgets() ''' Load User Settings ''' self.data.comport = self.config.get('Makesmith Settings', 'COMport') self.data.gcodeFile = self.config.get('Makesmith Settings', 'openFile') self.data.config = self.config ''' Initializations ''' self.frontpage.setUpData(self.data) self.nonVisibleWidgets.setUpData(self.data) self.frontpage.gcodecanvas.initialzie() ''' Scheduling ''' Clock.schedule_interval(self.runPeriodically, .01) return interface
def build(self): Window.maximize() interface = FloatLayout() self.data = Data() self.frontpage = FrontPage(self.data, name='FrontPage') interface.add_widget(self.frontpage) self.nonVisibleWidgets = NonVisibleWidgets() ''' Load User Settings ''' self.config.set('Advanced Settings', 'truncate', 0) self.config.set('Advanced Settings', 'digits', 4) self.config.write() self.data.comport = self.config.get('Maslow Settings', 'COMport') self.data.gcodeFile = self.config.get('Maslow Settings', 'openFile') offsetX = float(self.config.get('Advanced Settings', 'homeX')) offsetY = float(self.config.get('Advanced Settings', 'homeY')) self.data.gcodeShift = [offsetX,offsetY] self.data.config = self.config ''' Initializations ''' self.frontpage.setUpData(self.data) self.nonVisibleWidgets.setUpData(self.data) self.frontpage.gcodecanvas.initialize() ''' Scheduling ''' Clock.schedule_interval(self.runPeriodically, .01) ''' Push settings to machine ''' self.data.bind(connectionStatus = self.push_settings_to_machine) self.data.pushSettings = self.push_settings_to_machine self.push_settings_to_machine() return interface
from flask import Flask, jsonify, render_template, current_app, request, flash, Response, send_file, send_from_directory from flask_mobility.decorators import mobile_template from werkzeug import secure_filename from Background.UIProcessor import UIProcessor # do this after socketio is declared from Background.LogStreamer import LogStreamer # do this after socketio is declared from Background.WebMCPProcessor import WebMCPProcessor from Background.WebMCPProcessor import ConsoleProcessor from DataStructures.data import Data from Connection.nonVisibleWidgets import NonVisibleWidgets from WebPageProcessor.webPageProcessor import WebPageProcessor from os import listdir from os.path import isfile, join import sys app.data = Data() app.nonVisibleWidgets = NonVisibleWidgets() app.nonVisibleWidgets.setUpData(app.data) app.data.config.computeSettings(None, None, None, True) app.data.config.parseFirmwareVersions() version = sys.version_info # this is for python newer than 3.5 if version[:2] > (3, 5): app.data.pythonVersion35 = False # set data flag print("Using routines for Python > 3.5") else: app.data.pythonVersion35 = True # set data flag print("Using routines for Python == 3.5") app.data.units = app.data.config.getValue("Computed Settings", "units") app.data.tolerance = app.data.config.getValue("Computed Settings", "tolerance") app.data.distToMove = app.data.config.getValue("Computed Settings", "distToMove")
def build(self): interface = FloatLayout() self.data = Data() if self.config.get('Maslow Settings', 'colorScheme') == 'Light': self.data.iconPath = './Images/Icons/normal/' self.data.fontColor = '[color=7a7a7a]' self.data.drawingColor = [.47, .47, .47] Window.clearcolor = (1, 1, 1, 1) self.data.posIndicatorColor = [0, 0, 0] self.data.targetInicatorColor = [1, 0, 0] elif self.config.get('Maslow Settings', 'colorScheme') == 'Dark': self.data.iconPath = './Images/Icons/highvis/' self.data.fontColor = '[color=000000]' self.data.drawingColor = [1, 1, 1] Window.clearcolor = (0, 0, 0, 1) self.data.posIndicatorColor = [1, 1, 1] self.data.targetInicatorColor = [1, 0, 0] elif self.config.get('Maslow Settings', 'colorScheme') == 'DarkGreyBlue': self.data.iconPath = './Images/Icons/darkgreyblue/' self.data.fontColor = '[color=000000]' self.data.drawingColor = [1, 1, 1] Window.clearcolor = (0.06, 0.10, 0.2, 1) self.data.posIndicatorColor = [0.51, 0.93, 0.97] self.data.targetInicatorColor = [1, 0, 0] Window.maximize() self.frontpage = FrontPage(self.data, name='FrontPage') interface.add_widget(self.frontpage) self.nonVisibleWidgets = NonVisibleWidgets() ''' Load User Settings ''' # force create an ini no matter what. self.config.write() if self.config.get('Advanced Settings', 'encoderSteps') == '8148.0': self.data.message_queue.put( "Message: This update will adjust the the number of encoder pulses per rotation from 8,148 to 8,113 in your settings which improves the positional accuracy.\n\nPerforming a calibration will help you get the most out of this update." ) self.config.set('Advanced Settings', 'encoderSteps', '8113.73') #up the maximum feedrate if self.config.get('Advanced Settings', 'maxFeedrate') == '700': self.data.message_queue.put( "Message: This update will increase the maximum feedrate of your machine. You can adjust this value under the Advanced settings." ) self.config.set('Advanced Settings', 'maxFeedrate', '800') self.config.write() self.data.comport = self.config.get('Maslow Settings', 'COMport') self.data.baudRate = int(self.config.get('Maslow Settings', 'baudRate')) self.data.gcodeFile = self.config.get('Maslow Settings', 'openFile') offsetX = float(self.config.get('Advanced Settings', 'homeX')) offsetY = float(self.config.get('Advanced Settings', 'homeY')) self.data.gcodeShift = [offsetX, offsetY] self.data.config = self.config self.config.add_callback(self.configSettingChange) # Background image setup self.data.backgroundFile = self.config.get('Background Settings', 'backgroundFile') self.data.backgroundManualReg = json.loads( self.config.get('Background Settings', 'manualReg')) if self.data.backgroundFile != "": BackgroundMenu(self.data).processBackground() ''' Initializations ''' self.frontpage.setUpData(self.data) self.nonVisibleWidgets.setUpData(self.data) self.frontpage.gcodecanvas.initialize() ''' Scheduling ''' Clock.schedule_interval(self.runPeriodically, .01) ''' Push settings to machine ''' self.data.bind(connectionStatus=self.requestMachineSettings) self.data.pushSettings = self.requestMachineSettings return interface
class FrontPage(Screen, MakesmithInitFuncs): textconsole = ObjectProperty(None) connectmenu = ObjectProperty( None) #make ConnectMenu object accessible at this scope gcodecanvas = ObjectProperty(None) screenControls = ObjectProperty(None) connectionStatus = StringProperty("Not Connected") xReadoutPos = StringProperty("0 mm") yReadoutPos = StringProperty("0 mm") zReadoutPos = StringProperty("0 mm") ReadoutVel = StringProperty(" 0 mm/m") gcodeVel = StringProperty(" 0 mm/m") percentComplete = StringProperty("0.0%") numericalPosX = 0.0 numericalPosY = 0.0 previousPosX = 0.0 previousPosY = 0.0 lastpos = (0, 0, 0) lasttime = 0.0 tick = 0 stepsizeval = 0 consoleText = StringProperty(" ") units = StringProperty("MM") gcodeLineNumber = StringProperty('0') data = Data() def __init__(self, data, **kwargs): super(FrontPage, self).__init__(**kwargs) self.data = data self.upLeftArrow.btnBackground = self.data.iconPath + 'UpLeftArrow.png' self.upArrow.btnBackground = self.data.iconPath + 'UpArrow.png' self.upRightArrow.btnBackground = self.data.iconPath + 'UpRightArrow.png' self.leftArrow.btnBackground = self.data.iconPath + 'LeftArrow.png' self.homeBtn.btnBackground = self.data.iconPath + 'Home.png' self.rightArrow.btnBackground = self.data.iconPath + 'RightArrow.png' self.downLeftArrow.btnBackground = self.data.iconPath + 'DownLeftArrow.png' self.downArrow.btnBackground = self.data.iconPath + 'DownArrow.png' self.downRightArrow.btnBackground = self.data.iconPath + 'DownRightArrow.png' self.macro1Btn.btnBackground = self.data.iconPath + 'Generic.png' self.macro1Btn.textColor = self.data.fontColor self.macro2Btn.btnBackground = self.data.iconPath + 'Generic.png' self.macro2Btn.textColor = self.data.fontColor self.zAxisBtn.btnBackground = self.data.iconPath + 'Generic.png' self.zAxisBtn.textColor = self.data.fontColor self.moveDistInput.btnBackground = self.data.iconPath + 'Generic.png' self.moveDistInput.textColor = self.data.fontColor self.unitsBtn.btnBackground = self.data.iconPath + 'Generic.png' self.unitsBtn.textColor = self.data.fontColor self.defHomeBtn.btnBackground = self.data.iconPath + 'Generic.png' self.defHomeBtn.textColor = self.data.fontColor self.zRight.btnBackground = self.data.iconPath + 'Generic.png' self.zRight.textColor = self.data.fontColor self.zLeft.btnBackground = self.data.iconPath + 'Generic.png' self.zLeft.textColor = self.data.fontColor self.oneLeft.btnBackground = self.data.iconPath + 'Generic.png' self.oneLeft.textColor = self.data.fontColor self.oneRight.btnBackground = self.data.iconPath + 'Generic.png' self.oneRight.textColor = self.data.fontColor self.run.btnBackground = self.data.iconPath + 'RunGreen.png' self.holdBtn.btnBackground = self.data.iconPath + 'HoldYellow.png' self.holdBtn.secretText = "HOLD" self.stopBtn.btnBackground = self.data.iconPath + 'StopRed.png' self.goTo.btnBackground = self.data.iconPath + 'GoTo.png' def buildReadoutString(self, value): ''' Generate the string for the the digital position readout ''' targetStringLength = 8 string = '%.2f' % (value) numberOfSpacesToPad = int(1.5 * (targetStringLength - len(string))) string = ' ' * numberOfSpacesToPad + string return string def setPosReadout(self, xPos, yPos, zPos): self.xReadoutPos = self.buildReadoutString(xPos) self.yReadoutPos = self.buildReadoutString(yPos) self.zReadoutPos = self.buildReadoutString(zPos) #So other widgets can access the position self.data.zReadoutPos = zPos #Current Velocity is done here now, not in the firmware. self.tick += 1 if self.tick >= 4: #Can't do this every time... it's too noisy, so we do it every 5rd time (0.1s). self.tick = 0 if self.lasttime <> 0.0: try: delta = sqrt((xPos - self.lastpos[0]) * (xPos - self.lastpos[0]) + (yPos - self.lastpos[1]) * (yPos - self.lastpos[1]) + (zPos - self.lastpos[2]) * (zPos - self.lastpos[2])) Vel = delta / (time() - self.lasttime) * 60.0 #In XXXX/minute except: print "unable to compute velocity" Vel = 0 else: Vel = 0 self.lasttime = time() self.lastpos = (xPos, yPos, zPos) self.ReadoutVel = self.buildReadoutString(Vel) self.numericalPosX = xPos self.numericalPosY = yPos #ToDo: Do we want to start logging errors if self.RedoutVel < self.gcodeVel? How do we know if we're supposed to be moving? def setUpData(self, data): self.gcodecanvas.setUpData(data) self.screenControls.setUpData(data) self.screenControls.setButtonAppearance() self.data.bind(connectionStatus=self.updateConnectionStatus) self.data.bind(units=self.onUnitsSwitch) self.data.bind(gcodeIndex=self.onIndexMove) self.data.bind(gcodeFile=self.onGcodeFileChange) self.data.bind(uploadFlag=self.onUploadFlagChange) self.update_macro_titles() def updateConnectionStatus(self, callback, connected): if connected: self.connectionStatus = "Connected" else: self.connectionStatus = "Connection Lost" def switchUnits(self): if self.data.units == "INCHES": self.data.units = "MM" else: self.data.units = "INCHES" def onUnitsSwitch(self, callback, newUnits): self.units = newUnits INCHESTOMM = 1 / 25.4 MMTOINCHES = 25.4 if newUnits == "INCHES": self.data.gcode_queue.put('G20 ') self.moveDistInput.text = "{0:.2f}".format( float(self.moveDistInput.text) / MMTOINCHES) self.data.tolerance = 0.020 else: self.data.gcode_queue.put('G21 ') self.moveDistInput.text = "{0:.2f}".format( float(self.moveDistInput.text) / INCHESTOMM) self.data.tolerance = 0.5 def onIndexMove(self, callback, newIndex): self.gcodeLineNumber = str(newIndex) self.percentComplete = '%.1f' % (100 * (float(newIndex) / (len(self.data.gcode) - 1))) + "%" if newIndex >= 1: gCodeLine = self.data.gcode[ newIndex - 1] #We're executing newIndex-1... about to send newIndex F = re.search("F(?=.)(([ ]*)?[+-]?([0-9]*)(\.([0-9]+))?)", gCodeLine) if F: self.gcodeVel = F.groups()[ 0] #Otherwise, it stays what it was... def onGcodeFileChange(self, callback, newGcode): pass def onUploadFlagChange(self, callback, newFlagValue): if self.data.uploadFlag is 0 and self.data.gcodeIndex > 1: #if the machine is stopped partway through a file self.holdBtn.secretText = "CONTINUE" self.holdBtn.btnBackground = self.data.iconPath + 'ContinueYellow.png' else: self.holdBtn.secretText = "HOLD" self.holdBtn.btnBackground = self.data.iconPath + 'HoldYellow.png' def moveGcodeZ(self, moves): ''' Move the gcode index by z moves ''' dist = 0 for index, zMove in enumerate(self.data.zMoves): if moves > 0 and zMove > self.data.gcodeIndex: dist = self.data.zMoves[index + moves - 1] - self.data.gcodeIndex break if moves < 0 and zMove < self.data.gcodeIndex: dist = self.data.zMoves[index + moves + 1] - self.data.gcodeIndex self.moveGcodeIndex(dist) def moveGcodeIndex(self, dist): ''' Move the gcode index by a dist number of lines ''' maxIndex = len(self.data.gcode) - 1 targetIndex = self.data.gcodeIndex + dist #check to see if we are still within the length of the file if maxIndex < 0: #break if there is no data to read return elif targetIndex < 0: #negative index not allowed self.data.gcodeIndex = 0 elif targetIndex > maxIndex: #reading past the end of the file is not allowed self.data.gcodeIndex = maxIndex else: self.data.gcodeIndex = targetIndex gCodeLine = self.data.gcode[self.data.gcodeIndex] xTarget = 0 yTarget = 0 try: x = re.search("X(?=.)([+-]?([0-9]*)(\.([0-9]+))?)", gCodeLine) if x: xTarget = float(x.groups()[0]) self.previousPosX = xTarget else: xTarget = self.previousPosX y = re.search("Y(?=.)([+-]?([0-9]*)(\.([0-9]+))?)", gCodeLine) if y: yTarget = float(y.groups()[0]) self.previousPosY = yTarget else: yTarget = self.previousPosY self.gcodecanvas.positionIndicator.setPos(xTarget, yTarget, self.data.units) except: print "Unable to update position for new gcode line" def pause(self): if self.holdBtn.secretText == "HOLD": self.data.uploadFlag = 0 print("Run Paused") else: self.data.uploadFlag = 1 self.data.quick_queue.put( "~") #send cycle resume command to unpause the machine print("Run Resumed") def jmpsize(self): try: self.stepsizeval = float(self.moveDistInput.text) except: pass def test(self): print "test has no current function" def upLeft(self): self.jmpsize() self.data.gcode_queue.put("G91 G00 X" + str(-1 * self.stepsizeval) + " Y" + str(self.stepsizeval) + " G90 ") self.gcodeVel = "[MAN]" def upRight(self): self.jmpsize() self.data.gcode_queue.put("G91 G00 X" + str(self.stepsizeval) + " Y" + str(self.stepsizeval) + " G90 ") self.gcodeVel = "[MAN]" def up(self): self.jmpsize() self.data.gcode_queue.put("G91 G00 Y" + str(self.stepsizeval) + " G90 ") self.gcodeVel = "[MAN]" def left(self): self.jmpsize() self.data.gcode_queue.put("G91 G0 X" + str(-1 * self.stepsizeval) + " G90 ") self.gcodeVel = "[MAN]" def right(self): self.jmpsize() self.data.gcode_queue.put("G91 G0 X" + str(self.stepsizeval) + " G90 ") self.gcodeVel = "[MAN]" def downLeft(self): self.jmpsize() self.data.gcode_queue.put("G91 G00 X" + str(-1 * self.stepsizeval) + " Y" + str(-1 * self.stepsizeval) + " G90 ") self.gcodeVel = "[MAN]" def down(self): self.jmpsize() self.data.gcode_queue.put("G91 G00 Y" + str(-1 * self.stepsizeval) + " G90 ") self.gcodeVel = "[MAN]" def downRight(self): self.jmpsize() self.data.gcode_queue.put("G91 G00 X" + str(self.stepsizeval) + " Y" + str(-1 * self.stepsizeval) + " G90 ") self.gcodeVel = "[MAN]" def zAxisPopup(self): self.popupContent = ZAxisPopupContent(done=self.dismissZAxisPopup) self.popupContent.data = self.data self.popupContent.initialize() self._popup = Popup(title="Z-Axis", content=self.popupContent, size_hint=(0.5, 0.5)) self._popup.open() def dismissZAxisPopup(self): ''' Close The Z-Axis Pop-up ''' self._popup.dismiss() def home(self): ''' Return the machine to it's home position. (0,0) is the default unless the origin has been moved by the user. ''' self.data.gcode_queue.put("G90 ") self.gcodeVel = "[MAN]" safeHeightMM = float( self.data.config.get('Maslow Settings', 'zAxisSafeHeight')) safeHeightInches = safeHeightMM / 25.5 if self.data.units == "INCHES": self.data.gcode_queue.put("G00 Z" + '%.3f' % (safeHeightInches)) else: self.data.gcode_queue.put("G00 Z" + str(safeHeightMM)) self.data.gcode_queue.put("G00 X" + str(self.data.gcodeShift[0]) + " Y" + str(self.data.gcodeShift[1]) + " ") self.data.gcode_queue.put("G00 Z0 ") def moveOrigin(self): ''' Move the gcode origin to the current location ''' self.data.gcodeShift = [self.numericalPosX, self.numericalPosY] self.data.config.set('Advanced Settings', 'homeX', str(self.numericalPosX)) self.data.config.set('Advanced Settings', 'homeY', str(self.numericalPosY)) def startRun(self): self.data.uploadFlag = 1 self.sendLine() def sendLine(self): try: self.data.gcode_queue.put(self.data.gcode[self.data.gcodeIndex]) self.data.gcodeIndex = self.data.gcodeIndex + 1 except: print "gcode run complete" self.gcodecanvas.uploadFlag = 0 self.data.gcodeIndex = 0 def stopRun(self): self.data.uploadFlag = 0 self.data.gcodeIndex = 0 self.data.quick_queue.put("!") with self.data.gcode_queue.mutex: self.data.gcode_queue.queue.clear() self.onUploadFlagChange(self.stopRun, 0) print("Gcode Stopped") def textInputPopup(self, target): self.targetWidget = target self.popupContent = TouchNumberInput(done=self.dismiss_popup, data=self.data) self._popup = Popup(title="Change increment size of machine movement", content=self.popupContent, size_hint=(0.9, 0.9)) self._popup.open() if global_variables._keyboard: global_variables._keyboard.bind(on_key_down=self.keydown_popup) self._popup.bind(on_dismiss=self.ondismiss_popup) def ondismiss_popup(self, event): if global_variables._keyboard: global_variables._keyboard.unbind(on_key_down=self.keydown_popup) def keydown_popup(self, keyboard, keycode, text, modifiers): if (keycode[1] == '0') or (keycode[1] == 'numpad0'): self.popupContent.addText('0') elif (keycode[1] == '1') or (keycode[1] == 'numpad1'): self.popupContent.addText('1') elif (keycode[1] == '2') or (keycode[1] == 'numpad2'): self.popupContent.addText('2') elif (keycode[1] == '3') or (keycode[1] == 'numpad3'): self.popupContent.addText('3') elif (keycode[1] == '4') or (keycode[1] == 'numpad4'): self.popupContent.addText('4') elif (keycode[1] == '5') or (keycode[1] == 'numpad5'): self.popupContent.addText('5') elif (keycode[1] == '6') or (keycode[1] == 'numpad6'): self.popupContent.addText('6') elif (keycode[1] == '7') or (keycode[1] == 'numpad7'): self.popupContent.addText('7') elif (keycode[1] == '8') or (keycode[1] == 'numpad8'): self.popupContent.addText('8') elif (keycode[1] == '9') or (keycode[1] == 'numpad9'): self.popupContent.addText('9') elif (keycode[1] == '.') or (keycode[1] == 'numpaddecimal'): self.popupContent.addText('.') elif (keycode[1] == 'backspace'): self.popupContent.textInput.text = self.popupContent.textInput.text[: -1] elif (keycode[1] == 'enter') or (keycode[1] == 'numpadenter'): self.popupContent.done() elif (keycode[1] == 'escape' ): # abort entering a number, keep the old number self.popupContent.textInput.text = '' # clear text so it isn't converted to a number self.popupContent.done() return True # always swallow keypresses since this is a modal dialog def dismiss_popup(self): ''' Close The Pop-up ''' try: tempfloat = float(self.popupContent.textInput.text) self.targetWidget.text = str( tempfloat ) # Update displayed text using standard numeric format except: pass #If what was entered cannot be converted to a number, leave the value the same self._popup.dismiss() def gotoLinePopup(self): self.popupContent = TouchGoToInput(done=self.dismiss_gotoLinePopup, data=self.data) self._popup = Popup(title="GoTo...", content=self.popupContent, size_hint=(0.9, 0.9)) self._popup.open() if global_variables._keyboard: global_variables._keyboard.bind(on_key_down=self.keydown_popup) self._popup.bind(on_dismiss=self.ondismiss_popup) def dismiss_gotoLinePopup(self): ''' Close The Pop-up ''' if self.popupContent.textInput.text: if self.popupContent.modeBtn.text == 'L': try: line = int(float(self.popupContent.textInput.text)) if line < 0: self.data.gcodeIndex = 0 elif line > len(self.data.gcode): self.data.gcodeIndex = len(self.data.gcode) else: self.data.gcodeIndex = line except: pass else: self.data.quick_queue.put(self.popupContent.modeBtn.text + self.popupContent.textInput.text) self._popup.dismiss() def macro(self, index): ''' Execute user defined macro ''' self.data.gcode_queue.put( self.data.config.get('Maslow Settings', 'macro' + str(index))) def update_macro_titles(self): self.macro1Btn.text = self.data.config.get('Maslow Settings', 'macro1_title') self.macro2Btn.text = self.data.config.get('Maslow Settings', 'macro2_title')
def build(self): interface = FloatLayout() self.data = Data() if self.config.get('Maslow Settings', 'colorScheme') == 'Light': self.data.iconPath = './Images/Icons/normal/' self.data.fontColor = '[color=7a7a7a]' self.data.drawingColor = [.47, .47, .47] Window.clearcolor = (1, 1, 1, 1) self.data.posIndicatorColor = [0, 0, 0] self.data.targetInicatorColor = [1, 0, 0] elif self.config.get('Maslow Settings', 'colorScheme') == 'Dark': self.data.iconPath = './Images/Icons/highvis/' self.data.fontColor = '[color=000000]' self.data.drawingColor = [1, 1, 1] Window.clearcolor = (0, 0, 0, 1) self.data.posIndicatorColor = [1, 1, 1] self.data.targetInicatorColor = [1, 0, 0] Window.maximize() self.frontpage = FrontPage(self.data, name='FrontPage') interface.add_widget(self.frontpage) self.nonVisibleWidgets = NonVisibleWidgets() ''' Load User Settings ''' if self.config.get('Advanced Settings', 'encoderSteps') == '8148.0': self.data.message_queue.put( "Message: This update will adjust the the number of encoder pulses per rotation from 8,148 to 8,113 in your settings which improves the positional accuracy.\n\nPerforming a calibration will help you get the most out of this update." ) self.config.set('Advanced Settings', 'encoderSteps', '8113.73') self.config.write() self.data.comport = self.config.get('Maslow Settings', 'COMport') self.data.gcodeFile = self.config.get('Maslow Settings', 'openFile') offsetX = float(self.config.get('Advanced Settings', 'homeX')) offsetY = float(self.config.get('Advanced Settings', 'homeY')) self.data.gcodeShift = [offsetX, offsetY] self.data.config = self.config ''' Initializations ''' self.frontpage.setUpData(self.data) self.nonVisibleWidgets.setUpData(self.data) self.frontpage.gcodecanvas.initialize() ''' Scheduling ''' Clock.schedule_interval(self.runPeriodically, .01) ''' Push settings to machine ''' self.data.bind(connectionStatus=self.push_settings_to_machine) self.data.pushSettings = self.push_settings_to_machine return interface