From dfa64ecf9a93153d910611f2ade6ca57a71666d6 Mon Sep 17 00:00:00 2001 From: gb0101010101 <7369439+gb0101010101@users.noreply.github.com> Date: Wed, 11 Mar 2020 10:02:30 -0700 Subject: [PATCH 01/17] Rewrite actions to remove huge if->elif block at top of class to group code. Standardize exception handling. Format code. --- Actions/actions.py | 1604 +++++++++++++++++++--------------- static/scripts/baseSocket.js | 18 +- 2 files changed, 926 insertions(+), 696 deletions(-) diff --git a/Actions/actions.py b/Actions/actions.py index b0d5639d..fe04191c 100644 --- a/Actions/actions.py +++ b/Actions/actions.py @@ -1,4 +1,3 @@ - from DataStructures.makesmithInitFuncs import MakesmithInitFuncs import os @@ -10,273 +9,58 @@ import time import re import zipfile -import threading from gpiozero.pins.mock import MockFactory from gpiozero import Device -''' +""" This class does most of the heavy lifting in processing messages from the UI client. -''' +""" class Actions(MakesmithInitFuncs): Device.pin_factory = MockFactory() + # These commands can be executed at any time. + _safe_commands = ["createDirectory", "stopZ", "stopRun", "pauseRun", "resumeRun", "toggleCamera", "queryCamera", "cameraStatus"] + + def _logException(self, exception, message =""): + """ + Saves exception message to console and optionally displays an Alert modal with message. + :param exception: The raised exception. + :param message: The message to be displayed in UI Alert. + """ + self.data.console_queue.put(str(exception)) + if message != "": + self.data.ui_queue1.put("Alert", "Alert", message) def processAction(self, msg): - ''' + """ When a message comes in via the UI client it gets parsed and processed here. - :param msg: json of message from UI client - :return: - ''' - try: - # Commands allowed during sending gcode. These commands won't screw something up. - if msg["data"]["command"] == "createDirectory": - if not self.createDirectory(msg["data"]["arg"]): - self.data.ui_queue1.put("Alert", "Alert", "Error with creating directory.") - elif msg["data"]["command"] == "stopZ": - if not self.stopZ(): - self.data.ui_queue1.put("Alert", "Alert", "Error with stopping Z-Axis movement") - elif msg["data"]["command"] == "stopRun": - if not self.stopRun(): - self.data.ui_queue1.put("Alert", "Alert", "Error with stopping run") - elif msg["data"]["command"] == "pauseRun": - if not self.pauseRun(): - self.data.ui_queue1.put("Alert", "Alert", "Error with pausing run") - elif msg["data"]["command"] == "resumeRun": - if not self.resumeRun(): - self.data.ui_queue1.put("Alert", "Alert", "Error with resuming run") - elif msg["data"]["command"] == "toggleCamera": - if not self.toggleCamera(): - self.data.ui_queue1.put("Alert", "Alert", "Error with toggling camera.") - elif msg["data"]["command"] == "statusRequest": - if msg["data"]["arg"] == "cameraStatus": - if not self.cameraStatus(): - self.data.ui_queue1.put("Alert", "Alert", "Error with toggling camera.") - elif msg["data"]["command"] == "queryCamera": - if not self.queryCamera(): - self.data.ui_queue1.put("Alert", "Alert", "Error with querying camera.") - elif msg["data"]["command"] == "shutdown": - if not self.shutdown(): - self.data.ui_queue1.put("Alert", "Alert", "Error with shutting down.") - elif self.data.uploadFlag == 1: - self.data.ui_queue1.put("Alert", "Alert", "Cannot issue command while sending gcode.") - # Commands not allowed during sending gcode.. if you did these commands, something could screw up. - # If uploadFlag was enabled (see above) then this would never be reached. - - elif msg["data"]["command"] == "move": - if not self.move(msg["data"]["arg"], float(msg["data"]["arg1"])): - self.data.ui_queue1.put("Alert", "Alert", "Error with initiating move.") - elif msg["data"]["command"] == "moveTo": - if not self.moveTo(msg["data"]["arg"], float(msg["data"]["arg1"])): - self.data.ui_queue1.put("Alert", "Alert", "Error with initiating move.") - elif msg["data"]["command"] == "moveZ": - if not self.moveZ(msg["data"]["arg"], float(msg["data"]["arg1"])): - self.data.ui_queue1.put("Alert", "Alert", "Error with initiating Z-Axis move.") - elif msg["data"]["command"] == "reportSettings": - self.data.gcode_queue.put("$$") - elif msg["data"]["command"] == "home": - if not self.home(): - self.data.ui_queue1.put("Alert", "Alert", "Error with returning to home.") - elif msg["data"]["command"] == "defineZ0": - if not self.data.actions.defineZ0(): - self.data.ui_queue1.put("Alert", "Alert", "Error with defining Z-Axis zero.") - elif msg["data"]["command"] == "moveToDefault": - if not self.moveToDefault(): - self.data.ui_queue1.put("Alert", "Alert", "Error with moving to default chain lengths") - elif msg["data"]["command"] == "returnToCenter": - if not self.returnToCenter(): - self.data.ui_queue1.put("Alert", "Alert", "Error with returning to center") - elif msg["data"]["command"] == "moveGcodeZ": - if not self.moveGcodeZ(int(msg["data"]["arg"])): - self.data.ui_queue1.put("Alert", "Alert", "Error with moving to Z move") - elif msg["data"]["command"] == "moveGcodeGoto": - if not self.moveGcodeIndex(int(msg["data"]["arg"]), True): - self.data.ui_queue1.put("Alert", "Alert", "Error with moving to Z move") - elif msg["data"]["command"] == "moveGcodeIndex": - if not self.moveGcodeIndex(int(msg["data"]["arg"])): - self.data.ui_queue1.put("Alert", "Alert", "Error with moving to index") - elif msg["data"]["command"] == "macro1": - if not self.macro(1): - self.data.ui_queue1.put("Alert", "Alert", "Error with performing macro") - elif msg["data"]["command"] == "macro2": - if not self.macro(2): - self.data.ui_queue1.put("Alert", "Alert", "Error with performing macro") - elif msg["data"]["command"] == "clearLogs": - if not self.clearLogs(): - self.data.ui_queue1.put("Alert", "Alert", "Error clearing log files.") - - elif self.data.uploadFlag > 1 or self.data.uploadFlag < 0 : - self.data.ui_queue1.put("Alert", "Alert", "Cannot issue command while paused sending gcode. You must press STOP before performing this action.") - # Commands not allowed while paused.. if you did these commands, something could screw up. - - elif msg["data"]["command"] == "startRun": - if not self.startRun(): - if len(self.data.gcode) > 0: - self.data.ui_queue1.put("Alert", "Alert", "Error with starting run.") - else: - self.data.ui_queue1.put("Alert", "Alert", "No GCode file loaded.") - elif msg["data"]["command"] == "update": - if not self.data.releaseManager.update(msg["data"]["arg"]): - self.data.ui_queue1.put("Alert", "Alert", "Error with updating webcontrol.") - return "Shutdown" - elif msg["data"]["command"] == "cutTriangularCalibrationPattern": - if not self.data.triangularCalibration.cutTriangularCalibrationPattern(): - self.data.ui_queue1.put("Alert", "Alert", "Error with cutting triangular calibration pattern.") - elif msg["data"]["command"] == "acceptTriangularCalibrationResults": - if not self.data.triangularCalibration.acceptTriangularCalibrationResults(): - self.data.ui_queue1.put("Alert", "Alert", "Error with accepting triangular calibration results.") - elif msg["data"]["command"] == "cutHoleyCalibrationPattern": - if not self.data.holeyCalibration.CutTestPattern(): - self.data.ui_queue1.put("Alert", "Alert", "Error with cutting holey calibration pattern.") - elif msg["data"]["command"] == "acceptHoleyCalibrationResults": - if not self.data.holeyCalibration.acceptCalibrationResults(): - self.data.ui_queue1.put("Alert", "Alert", "Error with accepting holey calibration results.") - elif msg["data"]["command"] == "resetChainLengths": - if not self.resetChainLengths(): - self.data.ui_queue1.put("Alert", "Alert", "Error with resetting chain lengths.") - elif msg["data"]["command"] == "defineHome": - print(self.data.uploadFlag) - posX= msg["data"]["arg"] - posY= msg["data"]["arg1"] - if self.defineHome(posX, posY): - ## the gcode file might change the active units so we need to inform the UI of the change. - self.data.ui_queue1.put("Action", "unitsUpdate", "") - self.data.ui_queue1.put("Action", "gcodeUpdate", "") - else: - self.data.ui_queue1.put("Alert", "Alert", "Error with defining home.") - elif msg["data"]["command"] == "testMotors": - if not self.testMotors(): - self.data.ui_queue1.put("Alert", "Alert", "Error with testing motors") - elif msg["data"]["command"] == "wipeEEPROM": - if not self.wipeEEPROM(msg["data"]["arg"]): - self.data.ui_queue1.put("Alert", "Alert", "Error with wiping EEPROM") - elif msg["data"]["command"] == "clearGCode": - if self.clearGCode(): - # send blank gcode to UI - self.data.ui_queue1.put("Action", "gcodeUpdate", "") - else: - self.data.ui_queue1.put("Alert", "Alert", "Error with clearing gcode") - elif msg["data"]["command"] == "setSprockets": - if not self.setSprockets(msg["data"]["arg"], msg["data"]["arg1"]): - self.data.ui_queue1.put("Alert", "Alert", "Error with setting sprocket") - elif msg["data"]["command"] == "rotateSprocket": - if not self.rotateSprocket(msg["data"]["arg"], msg["data"]["arg1"]): - self.data.ui_queue1.put("Alert", "Alert", "Error with setting sprocket") - elif msg["data"]["command"] == "setSprocketAutomatic": - if not self.setSprocketAutomatic(): - self.data.ui_queue1.put("Alert", "Alert", "Error with setting sprockets automatically") - elif msg["data"]["command"] == "setSprocketsZero": - if not self.setSprocketsZero(): - self.data.ui_queue1.put("Alert", "Alert", "Error with setting sprockets zero value") - elif msg["data"]["command"] == "setSprocketsDefault": - if not self.setSprocketsDefault(): - self.data.ui_queue1.put("Alert", "Alert", "Error with setting sprockets as default") - elif msg["data"]["command"] == "updatePorts": - if not self.updatePorts(): - self.data.ui_queue1.put("Alert", "Alert", "Error with updating list of ports") - elif msg["data"]["command"] == "optical_onStart": - if not self.data.opticalCalibration.on_Start(): - self.data.ui_queue1.put("Alert", "Alert", "Error with starting optical calibration") - elif msg["data"]["command"] == "optical_Calibrate": - if not self.data.opticalCalibration.on_Calibrate(msg["data"]["arg"]): - self.data.ui_queue1.put("Alert", "Alert", "Error with starting optical calibration") - elif msg["data"]["command"] == "saveOpticalCalibrationConfiguration": - if not self.data.opticalCalibration.saveOpticalCalibrationConfiguration(msg["data"]["arg"]): - self.data.ui_queue1.put("Alert", "Alert", "Error with saving optical calibration configuration") - elif msg["data"]["command"] == "stopOpticalCalibration": - if not self.data.opticalCalibration.stopOpticalCalibration(): - self.data.ui_queue1.put("Alert", "Alert", "Error with stopping optical calibration.") - elif msg["data"]["command"] == "testOpticalCalibration": - if not self.data.opticalCalibration.testImage(msg["data"]["arg"]): - self.data.ui_queue1.put("Alert", "Alert", "Error with test image.") - elif msg["data"]["command"] == "findCenterOpticalCalibration": - if not self.data.opticalCalibration.findCenter(msg["data"]["arg"]): - self.data.ui_queue1.put("Alert", "Alert", "Error with find Center.") - elif msg["data"]["command"] == "saveAndSendOpticalCalibration": - if not self.data.opticalCalibration.saveAndSend(): - self.data.ui_queue1.put("Alert", "Alert", "Error with saving and sending calibration matrix.") - elif msg["data"]["command"] == "reloadCalibration": - errorX, errorY, curveX, curveY = self.data.opticalCalibration.reloadCalibration() - if errorX is None or errorY is None or curveX is None or curveY is None: - self.data.ui_queue1.put("Alert", "Alert", "Error with (re)loading calibration.") - else: - data = {"errorX": errorX, "errorY": errorY} - self.data.ui_queue1.put("Action", "updateOpticalCalibrationError", data) - elif msg["data"]["command"] == "saveCalibrationToCSV": - if not self.data.opticalCalibration.saveCalibrationToCSV(): - self.data.ui_queue1.put("Alert", "Alert", "Error with saving calibration to CSV.") - elif msg["data"]["command"] == "clearCalibration": - if not self.data.opticalCalibration.clearCalibration(): - self.data.ui_queue1.put("Alert", "Alert", "Error with clearing calibration.") - elif msg["data"]["command"] == "curveFitOpticalCalibration": - curveX, curveY = self.data.opticalCalibration.surfaceFit() - #curveX, curveY = self.data.opticalCalibration.polySurfaceFit() - if curveX is None or curveY is None: - self.data.ui_queue1.put("Alert", "Alert", "Error with curve fitting calibration data.") - else: - data = {"curveX": curveX, "curveY": curveY} - self.data.ui_queue1.put("Action", "updateOpticalCalibrationCurve", data) - elif msg["data"]["command"] == "adjustCenter": - if not self.adjustCenter(msg["data"]["arg"]): - self.data.ui_queue1.put("Alert", "Alert", "Error with adjusting center.") - elif msg["data"]["command"] == "upgradeCustomFirmware": - if not self.upgradeFirmware(0): - self.data.ui_queue1.put("Alert", "Alert", "Error with upgrading custom firmware.") - else: - self.data.ui_queue1.put("Alert", "Alert", "Custom firmware update complete.") - elif msg["data"]["command"] == "upgradeStockFirmware": - if not self.upgradeFirmware(1): - self.data.ui_queue1.put("Alert", "Alert", "Error with upgrading stock firmware.") - else: - self.data.ui_queue1.put("Alert", "Alert", "Stock firmware update complete.") - elif msg["data"]["command"] == "upgradeHoleyFirmware": - if not self.upgradeFirmware(2): - self.data.ui_queue1.put("Alert", "Alert", "Error with upgrading holey firmware.") - else: - self.data.ui_queue1.put("Alert", "Alert", "Custom firmware update complete.") - elif msg["data"]["command"] == "adjustChain": - if not self.adjustChain(msg["data"]["arg"]): - self.data.ui_queue1.put("Alert", "Alert", "Error with adjusting chain.") - elif msg["data"]["command"] == "executeVelocityPIDTest": - if not self.velocityPIDTest(msg["data"]["arg"]): - self.data.ui_queue1.put("Alert", "Alert", "Error with executing velocity PID test.") - elif msg["data"]["command"] == "executePositionPIDTest": - if not self.positionPIDTest(msg["data"]["arg"]): - self.data.ui_queue1.put("Alert", "Alert", "Error with executing velocity PID test.") - elif msg["data"]["command"] == "boardProcessGCode": - if not self.data.boardManager.processGCode(): - self.data.ui_queue1.put("Alert", "Alert", "Error with processing gcode") - elif msg["data"]["command"] == "boardClearBoard": - if not self.data.boardManager.clearBoard(): - self.data.ui_queue1.put("Alert", "Alert", "Error with clearing board") - elif msg["data"]["command"] == "updatePyInstaller": - if not self.data.releaseManager.updatePyInstaller(): - self.data.ui_queue1.put("Alert", "Alert", "Error with updating WebControl") - return "Shutdown" - elif msg["data"]["command"] == "setFakeServo": - if not self.setFakeServo(msg["data"]["arg"]): - self.data.ui_queue1.put("Alert", "Alert", "Error with changing Fake Servo") - elif msg["data"]["command"] == "resetHomeToCenter": - if self.defineHome(0, 0): - ## notify UI of home change to request gcode update - self.data.ui_queue1.put("Action", "gcodeUpdate", "") - else: - self.data.ui_queue1.put("Alert", "Alert", "Error with resetting home to center") + :param msg: Dictionary from UI client. + :return: Boolean indicating command success. + """ + try: + command = getattr(self, msg['command'], None); + args = msg.get("args", []); + if command is not None: + if self.data.uploadFlag == 1 and command not in self._safe_commands: + self.data.ui_queue1.put("Alert", "Alert", "Cannot issue command while sending gcode.") + return False + return command(*args) else: - response = "Function not currently implemented.. Sorry." - response = response + "["+msg["data"]["command"]+"]" + response = "Function not implemented: " + "[" + msg["command"] + "]" self.data.ui_queue1.put("Alert", "Alert", response) - print(msg["data"]) - except Exception as e: - print(str(e)) + print(msg) + return False + except Exception as e: + self._logException(e, "Error processing action.") def shutdown(self): - ''' + """ If running docker, sends message to WebMCP to shutdown webcontrol. If running as pyinstaller, calls an exit function. TODO: Add option to shutdown RPI completely. :return: - ''' + """ try: print(self.data.platform) if self.data.platform == "PYINSTALLER": @@ -285,11 +69,11 @@ def shutdown(self): self.data.ui_queue1.put("WebMCP", "shutdown", "") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with shutting down.") return False - def defineHome(self, posX="", posY=""): - ''' + def defineHome(self, posX = None, posY = None): + """ Redefines the home location and sends message to update the UI client. In a break from ground control, this does not alter the gcode. Gcode is altered by the home location only when sent to the controller. posX and posY define the coordinates of home. The are populated via the right-click context menu if the user @@ -298,16 +82,20 @@ def defineHome(self, posX="", posY=""): :param posX: :param posY: :return: - ''' + """ try: if self.data.units == "MM": scaleFactor = 25.4 else: scaleFactor = 1.0 # if posX and posY have values, use them, else use the sled's position. - if posX != "" and posY != "": + if posX != None and posY != None: homeX = round(posX * scaleFactor, 4) homeY = round(posY * scaleFactor, 4) + + # Send update to UI client with new home position only if they were specified. + position = {"xval": homeX, "yval": homeY} + self.data.ui_queue1.put("Action", "homePositionMessage", position) else: homeX = round(self.data.xval, 4) homeY = round(self.data.yval, 4) @@ -315,22 +103,31 @@ def defineHome(self, posX="", posY=""): self.data.config.setValue("Advanced Settings", "homeX", str(homeX)) self.data.config.setValue("Advanced Settings", "homeY", str(homeY)) - # the moveLine function of gcodeFile is still used (though its called directly by serialThread) so I still - # track the home coordinates in gcodeShift. - self.data.gcodeShift = [ homeX, homeY ] - # send update to UI client with new home position - position = {"xval": homeX, "yval": homeY} - self.data.ui_queue1.put("Action", "homePositionMessage", position) + # The moveLine function of gcodeFile is still used (though its called directly by serialThread) + # so I still track the home coordinates in gcodeShift. + self.data.gcodeShift = [homeX, homeY] + + # TODO: Moved from elif previously at top of file. Is this needed? + # The gcode file might change the active units so we need to inform the UI of the change. + self.data.ui_queue1.put("Action", "unitsUpdate", "") + self.data.ui_queue1.put("Action", "gcodeUpdate", "") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with defining home.") + return False + + def resetHomeToCenter(self): + try: + return self.defineHome(0, 0) + except Exception as e: + self._logException(e, "Error with resetting home to center.") return False def home(self): - ''' + """ Directs controller to move to home location :return: - ''' + """ try: self.data.gcode_queue.put("G90 ") safeHeightMM = float( @@ -343,106 +140,95 @@ def home(self): self.data.gcode_queue.put("G00 Z" + str(safeHeightMM)) homeX = self.data.config.getValue("Advanced Settings", "homeX") homeY = self.data.config.getValue("Advanced Settings", "homeY") - self.data.gcode_queue.put( - "G00 X" - + str(homeX) - + " Y" - + str(homeY) - + " " - ) + self.data.gcode_queue.put("G00 X" + str(homeX) + " Y" + str(homeY) + " ") self.data.gcode_queue.put("G00 Z0 ") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with returning to home.") return False def resetChainLengths(self): - ''' + """ Sends B08 command to controller to tell controller chains are at their 'extendChainLengths' distance. (equivalent to ground control's manualCalibrateChainLengths function) :return: - ''' + """ try: self.data.gcode_queue.put("B08 ") - # not sure why this was added here. Probably not needed. Todo: cleanup if not needed. - if self.data.units == "INCHES": - self.data.gcode_queue.put("G20 ") - else: - self.data.gcode_queue.put("G21 ") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with resetting chain lengths.") return False def defineZ0(self): - ''' + """ Sends G10 Z0 to controller to set current Z height as zero. :return: - ''' + """ try: self.data.gcode_queue.put("G10 Z0 ") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with defining Z-Axis zero.") return False def stopZ(self): - ''' + """ Sends a stop signal to the controller and clears the gcode queue. This is called from the Z-Axis popup, not the frontpage. This is equivalent to ground control's stopZMove. :return: - ''' + """ try: self.data.quick_queue.put("!") with self.data.gcode_queue.mutex: self.data.gcode_queue.queue.clear() return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with stopping Z-Axis movement.") return False def startRun(self): - ''' + """ Starts the process of sending the gcode to the controller. :return: - ''' - try: - if len(self.data.gcode) > 0: - # set current Z target to the current z height in case gcode doesn't include a z move before an xy move. - # if it doesn't and the user pauses during an xy move, then the target Z is set to 0. This sets it to - # what it currently is when the user started the gcode send. - self.data.currentZTarget = self.data.zval - # if the gcode index is not 0, then make sure the machine is in the proper state before starting to send - # the gcode. - if self.data.gcodeIndex > 0: - # get machine into proper state by sending appropriate commands - self.processGCode() - # update the gcode position on the UI client.. Have to recalculate it from the gcode because - # starting at some place other than 0 - self.sendGCodePositionUpdate(recalculate=True) - self.data.uploadFlag = 1 - else: - self.data.uploadFlag = 1 - self.data.gpioActions.causeAction("PlayLED", "on") - return True - else: - return False + """ + try: + if len(self.data.gcode) < 1: + raise Exception("No GCode file loaded.") + + # Set current Z target to the current z height in case gcode doesn't include a z move before an xy move. + # If it doesn't and the user pauses during an xy move, then the target Z is set to 0. + # This sets it to what it currently is when the user started the gcode send. + self.data.currentZTarget = self.data.zval + + # If the gcode index is not 0, then make sure the machine is in the proper state before starting to send + # the gcode. + if self.data.gcodeIndex > 0: + # Get machine into proper state by sending appropriate commands + self.processGCode() + # Update the gcode position on the UI client. Have to recalculate it from the gcode because + # starting at some place other than 0 + self.sendGCodePositionUpdate(recalculate=True) + + self.data.uploadFlag = 1 + self.data.gpioActions.causeAction("PlayLED", "on") + return True except Exception as e: - # something goes wrong, stop uploading. - self.data.console_queue.put(str(e)) + # Something goes wrong, stop uploading. + self._logException(e, "Error starting run.") self.data.uploadFlag = 0 self.data.gcodeIndex = 0 return False def stopRun(self): - ''' + """ Stops the uploading of gcode. :return: - ''' + """ try: self.data.console_queue.put("stopping run") - # this is necessary because of the way PID data is being processed. Otherwise could potentially get stuck - # in PID test + # This is necessary because of the way PID data is being processed. + # Otherwise could potentially get stuck in PID test. self.data.inPIDPositionTest = False self.data.inPIDVelocityTest = False self.data.uploadFlag = 0 @@ -451,26 +237,36 @@ def stopRun(self): self.data.quick_queue.put("!") with self.data.gcode_queue.mutex: self.data.gcode_queue.queue.clear() - # TODO: app.onUploadFlagChange(self.stopRun, 0) edit: not sure this is needed anymore + # TODO: app.onUploadFlagChange(self.stopRun, 0) edit: not sure this is needed anymore. self.data.console_queue.put("Gcode stopped") self.sendGCodePositionUpdate(self.data.gcodeIndex) - # notify UI client to clear any alarm that's active because a stop has been process. + # Notify UI client to clear any alarm that's active because a stop has been process. self.data.ui_queue1.put("Action", "clearAlarm", "") self.data.gpioActions.causeAction("StopLED", "on") - # reset pause + # Reset pause. self.data.ui_queue1.put("Action", "setAsPause", "") self.data.gpioActions.causeAction("PauseLED", "off") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error stopping run.") + return False + + def statusRequest(self, item): + try: + if (item == "cameraStatus"): + return self.cameraStatus() + else: + raise Exception("Status request item [" + str(item) + "] does not exist") + except Exception as e: + self._logException(e, "Error with status request.") return False def moveToDefault(self): - ''' - Moves the sled to the spot where the chains are extended to the extendChainLength. Not regularly used, but - more for testing. Uses B09 commands (single axis moves). + """ + Moves the sled to the spot where the chains are extended to the extendChainLength. + Not regularly used, but more for testing. Uses B09 commands (single axis moves). :return: - ''' + """ try: chainLength = self.data.config.getValue( "Advanced Settings", "chainExtendLength" @@ -488,27 +284,27 @@ def moveToDefault(self): return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with moving to default chain lengths.") return False def testMotors(self): - ''' + """ Sends the test motors/encoder command, B04 :return: - ''' + """ try: self.data.gcode_queue.put("B04 ") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with testing motors.") return False def wipeEEPROM(self, extent): - ''' + """ Sends the wipe EEPROM commands :param extent: :return: - ''' + """ try: if extent == "All": self.data.gcode_queue.put("$RST=* ") @@ -519,55 +315,45 @@ def wipeEEPROM(self, extent): else: return False - #sync settings after 2 seconds (give time form controller to reset) + # sync settings after 2 seconds (give time form controller to reset) time.sleep(2) self.data.gcode_queue.put("$$") - #reset chain lengths so they aren't zero + # reset chain lengths so they aren't zero if extent == "All" or extent == "Maslow": self.resetChainLengths() # these two lines were commented out and aren't used (and may not even work). The thought was that after # the EEPROM got wiped, you need to sync settings. - #self.timer = threading.Timer(6.0, self.data.gcode_queue.put("$$")) - #self.timer.start() + # self.timer = threading.Timer(6.0, self.data.gcode_queue.put("$$")) + # self.timer.start() return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with wiping eeprom.") return False - def pauseRun(self): - ''' - Pause the current uploading of gcode. Notify UI client to change the Pause button to say Resume - :return: - ''' - try: - if self.data.uploadFlag == 1: - self.data.uploadFlag = 2 - self.data.console_queue.put("Run Paused") - self.data.ui_queue1.put("Action", "setAsResume", "") - # The idea was to be able to make sure the machine returns to - # the correct z-height after a pause in the event the user raised/lowered the bit. - #self.data.pausedzval = self.data.zval - #self.data.pausedUnits = self.data.units - self.data.pausedzval = self.data.currentZTarget - self.data.pausedUnits = self.data.units - self.data.pausedPositioningMode = self.data.positioningMode - #print("Saving paused positioning mode: " + str(self.data.pausedPositioningMode)) - self.data.gpioActions.causeAction("PauseLED", "on") - return True + def optical_onStart(self): + try: + return self.data.opticalCalibration.on_Start() except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with starting optical calibration.") + return False + + def optical_Calibrate(self, arg): + try: + return self.data.opticalCalibration.on_Calibrate(arg) + except Exception as e: + self._logException(e, "Error with starting optical calibration.") return False def resumeRun(self): - ''' + """ Resumes sending the gcode. If a tool change command was received, then the manualZAxisAdjust is enabled and the machine will be returned to the z-axis height it was when the tool change command was processed. It also makes sure the units are what they were prior to the tool change (user might have switched them up while setting z-axis to zero). :return: - ''' + """ try: # Restore self.data.upladFlag properly if self.data.manualZAxisAdjust: @@ -580,13 +366,18 @@ def resumeRun(self): # If this was M command pause, then set to 1. self.data.uploadFlag = 1 else: - self.data.uploadFlag = self.data.previousUploadStatus ### just moved this here from after if statement + self.data.uploadFlag = ( + self.data.previousUploadStatus + ) ### just moved this here from after if statement else: # User has paused and is now resuming. # User could have used UI to move z-axis so restore paused values. print("Resume run without manual z-axis adjust.") # Restore units. - if self.data.pausedUnits is not None and self.data.pausedUnits != self.data.units: + if ( + self.data.pausedUnits is not None + and self.data.pausedUnits != self.data.units + ): print("Restoring units to:" + str(self.data.pausedUnits)) if self.data.pausedUnits == "INCHES": self.data.gcode_queue.put("G20 ") @@ -595,7 +386,10 @@ def resumeRun(self): self.data.pausedUnits = None # Move the z-axis back to where it was. - if self.data.pausedzval is not None and self.data.pausedzval != self.data.zval: + if ( + self.data.pausedzval is not None + and self.data.pausedzval != self.data.zval + ): # Put in absolute mode to make z axis move. self.data.gcode_queue.put("G90 ") # THE ABOVE COMMAND IS NOT EXECUTED IN LINE AND REQUIRES THE FOLLOWING TO TRACK POSITIONING MODE @@ -605,8 +399,14 @@ def resumeRun(self): self.data.pausedzval = None # Restore the last gcode positioning mode in use before pauseRun executed. - if self.data.pausedPositioningMode is not None and self.data.positioningMode != self.data.pausedPositioningMode: - print("Restoring positioning mode: " + str(self.data.pausedPositioningMode)) + if ( + self.data.pausedPositioningMode is not None + and self.data.positioningMode != self.data.pausedPositioningMode + ): + print( + "Restoring positioning mode: " + + str(self.data.pausedPositioningMode) + ) if self.data.pausedPositioningMode == 0: # this line technically should be unreachable self.data.gcode_queue.put("G90 ") @@ -624,14 +424,22 @@ def resumeRun(self): self.data.gpioActions.causeAction("PauseLED", "off") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with resuming run.") + return False + + def reportSettings(self): + try: + self.data.gcode_queue.put("$$") + return True; + except Exception as e: + self._logException(e, "Error with reporting settings.") return False def returnToCenter(self): - ''' + """ Instructs controller to move sled to 0,0 at safe height. :return: - ''' + """ try: self.data.gcode_queue.put("G90 ") safeHeightMM = float( @@ -645,30 +453,34 @@ def returnToCenter(self): self.data.gcode_queue.put("G00 X0.0 Y0.0 ") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with returning to center.") return False def clearGCode(self): - ''' - Calls function to clear the gcode file. Probably could have just been called directly from processAction + """ + Clear the gcode file. + TODO: Probably could have just been called directly from processAction :return: - ''' + """ try: - self.data.gcodeFile.clearGcodeFile() - return True + status = self.data.gcodeFile.clearGcodeFile() + if status: + # send blank gcode to UI + self.data.ui_queue1.put("Action", "gcodeUpdate", "") + return status except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with clearing gcode.") return False def moveGcodeZ(self, moves): - ''' + """ Moves the gcode index to the next z-axis move. :param moves: :return: - ''' + """ try: dist = 0 - #determine the number of lines to move to reach the next Z-axis move. + # determine the number of lines to move to reach the next Z-axis move. 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 @@ -681,16 +493,16 @@ def moveGcodeZ(self, moves): else: return False except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with moving gcode index to Z move.") return False def moveGcodeIndex(self, dist, index=False): - ''' + """ Moves the gcodeIndex by either the distance or, in index is True, uses the dist as the index. :param dist: :param index: :return: - ''' + """ try: maxIndex = len(self.data.gcode) - 1 if index is True: @@ -716,66 +528,83 @@ def moveGcodeIndex(self, dist, index=False): return retval except Exception as e: self.data.console_queue.put(str(e)) - self.data.console_queue.put("Unable to update position for new gcode line") + self.data.console_queue.put( + "Unable to update position for new gcode line" + ) return False return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with moving to index.") return False + def moveGcodeGoto(self, dist): + return self.moveGcodeIndex(dist, True) + def move(self, direction, distToMove): - ''' + """ Issues commands to move the sled :param direction: direction to move :param distToMove: distance to move :return: - ''' - # if enabled, for diagonal movements, the x and y move distance will be calculated such that the total distance - # moved equals what was specified. For example, if enabled and command is issued to move one foot to top right, - # then the x and y coordinates will be calculated as the 0.707 feet so that a total of 1 foot is moved. If - # disabled, then the sled will move 1 foot left and 1 foot up, for a total distance of 1.414 feet. - if self.data.config.getValue("WebControl Settings","diagonalMove") == 1: - diagMove = round(math.sqrt(distToMove*distToMove/2.0), 4) - else: - diagMove = distToMove + """ + try: + distToMove = float(distToMove) + # if enabled, for diagonal movements, the x and y move distance will be calculated such that the total distance + # moved equals what was specified. For example, if enabled and command is issued to move one foot to top right, + # then the x and y coordinates will be calculated as the 0.707 feet so that a total of 1 foot is moved. If + # disabled, then the sled will move 1 foot left and 1 foot up, for a total distance of 1.414 feet. + if self.data.config.getValue("WebControl Settings", "diagonalMove") == 1: + diagMove = round(math.sqrt(distToMove * distToMove / 2.0), 4) + else: + diagMove = distToMove + self.data.gcode_queue.put("G91 ") if direction == "upLeft": - self.data.gcode_queue.put("G00 X"+ str(-1.0 * diagMove)+ " Y"+ str(diagMove)+ " ") + self.data.gcode_queue.put( + "G00 X" + str(-1.0 * diagMove) + " Y" + str(diagMove) + " " + ) elif direction == "up": self.data.gcode_queue.put("G00 Y" + str(distToMove) + " ") elif direction == "upRight": - self.data.gcode_queue.put("G00 X" + str(diagMove) + " Y" + str(diagMove) + " ") + self.data.gcode_queue.put( + "G00 X" + str(diagMove) + " Y" + str(diagMove) + " " + ) elif direction == "left": self.data.gcode_queue.put("G00 X" + str(-1.0 * distToMove) + " ") elif direction == "right": self.data.gcode_queue.put("G00 X" + str(distToMove) + " ") elif direction == "downLeft": - self.data.gcode_queue.put("G00 X" + str(-1.0 * diagMove) + " Y" + str(-1.0 * diagMove) + " ") + self.data.gcode_queue.put( + "G00 X" + str(-1.0 * diagMove) + " Y" + str(-1.0 * diagMove) + " " + ) elif direction == "down": self.data.gcode_queue.put("G00 Y" + str(-1.0 * distToMove) + " ") elif direction == "downRight": - self.data.gcode_queue.put("G00 X" + str(diagMove) + " Y" + str(-1.0 * diagMove) + " ") + self.data.gcode_queue.put( + "G00 X" + str(diagMove) + " Y" + str(-1.0 * diagMove) + " " + ) else: - return False + raise Exception("Unknown direction: " + str(direction)) + self.data.gcode_queue.put("G90 ") - # keep track of the distToMove value + # Keep track of the distToMove value self.data.config.setValue("Computed Settings", "distToMove", distToMove) return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with initiating move.") return False def moveZ(self, direction, distToMoveZ): - ''' + """ Moves the Z-Axis a distance and direction :param direction: :param distToMoveZ: :return: - ''' + """ try: - #keep track of distToMoveZ value + # keep track of distToMoveZ value self.data.config.setValue("Computed Settings", "distToMoveZ", distToMoveZ) # It's possible the front page is set for one units and when you go to z-axis control, you might switch # to a different unit. Webcontrol keeps these units separate, so we need to make sure the machine is in @@ -792,11 +621,13 @@ def moveZ(self, direction, distToMoveZ): self.data.gcode_queue.put("G90 ") elif direction == "lower": self.data.gcode_queue.put("G91 ") - self.data.gcode_queue.put("G00 Z" + str(-1.0 * float(distToMoveZ)) + " " ) + self.data.gcode_queue.put( + "G00 Z" + str(-1.0 * float(distToMoveZ)) + " " + ) self.data.gcode_queue.put("G90 ") # now, since we might have changed the units of the machine, make sure they are set back to what it was # originally. - #units = self.data.config.getValue("Computed Settings", "units") + # units = self.data.config.getValue("Computed Settings", "units") if previousUnits != unitsZ: if previousUnits == "MM": self.data.gcode_queue.put("G21 ") @@ -804,17 +635,18 @@ def moveZ(self, direction, distToMoveZ): self.data.gcode_queue.put("G20 ") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with initiating Z-Axis move.") return False - def touchZ(self): - ''' + """ Sends a gcode line to set z axis depth using touch plate. I've not personally tested this. :return: - ''' + """ try: - plungeDepth = self.data.config.getValue("Advanced Settings", "maxTouchProbePlungeDistance") + plungeDepth = self.data.config.getValue( + "Advanced Settings", "maxTouchProbePlungeDistance" + ) revertToInches = False if self.data.units == "INCHES": revertToInches = True @@ -827,31 +659,42 @@ def touchZ(self): self.data.measureRequest = self.defineZ0() return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with touch Z") return False - def updateSetting(self, setting, value, fromGcode = False): - ''' + def updateSetting(self, setting, value, fromGcode=False): + """ update settings that come from frontpage or from the gcode file. :param setting: :param value: :param fromGcode: :return: - ''' + """ try: - self.data.console_queue.put("at update setting from gcode("+str(fromGcode)+"): "+setting+" with value: "+str(value)) + self.data.console_queue.put( + "at update setting from gcode(" + + str(fromGcode) + + "): " + + setting + + " with value: " + + str(value) + ) # if front page button has been pressed or serialPortThread is going to send gcode with a G21 or G20.. if setting == "toInches" or setting == "toMM": # this shouldn't be reached any more after I reordered the processActions function # todo: remove this if if not needed. if self.data.uploadFlag == 1 and fromGcode == False: - self.data.ui_queue1.put("Alert", "Alert", "Cannot change units while sending gcode.") + self.data.ui_queue1.put( + "Alert", "Alert", "Cannot change units while sending gcode." + ) return True scaleFactor = 0 if fromGcode: # if from a gcode line, then update the get the distToMove value from storage and figure out the # scaleFactor - value = float(self.data.config.getValue("Computed Settings", "distToMove")) + value = float( + self.data.config.getValue("Computed Settings", "distToMove") + ) if self.data.units == "INCHES": if setting == "toMM": value = value * 25.4 @@ -868,45 +711,64 @@ def updateSetting(self, setting, value, fromGcode = False): if setting == "toInches": # was metric, now going to imperial self.data.units = "INCHES" - self.data.config.setValue("Computed Settings", "units", self.data.units) + self.data.config.setValue( + "Computed Settings", "units", self.data.units + ) # if scaleFactor == 0, then it wasn't previously set by the if fromGcode. if scaleFactor == 0: - scaleFactor = 1.0/25.4 + scaleFactor = 1.0 / 25.4 self.data.tolerance = 0.020 - self.data.config.setValue("Computed Settings", "tolerance", self.data.tolerance) + self.data.config.setValue( + "Computed Settings", "tolerance", self.data.tolerance + ) # only send G20 to the controller if not already sending G20 if not fromGcode: self.data.gcode_queue.put("G20 ") else: # was imperial, now going to metric self.data.units = "MM" - self.data.config.setValue("Computed Settings", "units", self.data.units) + self.data.config.setValue( + "Computed Settings", "units", self.data.units + ) # if scaleFactor == 0, then it wasn't previously set by the if fromGcode. if scaleFactor == 0: scaleFactor = 25.4 self.data.tolerance = 0.5 - self.data.config.setValue("Computed Settings", "tolerance", self.data.tolerance) + self.data.config.setValue( + "Computed Settings", "tolerance", self.data.tolerance + ) # only send G21 to the controller if not already sending G21 if not fromGcode: self.data.gcode_queue.put("G21 ") # update the gcodeShift coordinates to match units self.data.gcodeShift = [ - self.data.gcodeShift[0] * scaleFactor, - self.data.gcodeShift[1] * scaleFactor, + self.data.gcodeShift[0] * scaleFactor, + self.data.gcodeShift[1] * scaleFactor, ] # The UI client sending this has already converted the distToMove to the correct value for the units self.data.config.setValue("Computed Settings", "distToMove", value) # get the current homeX and homeY coordinates - oldHomeX = float(self.data.config.getValue("Advanced Settings", "homeX")) - oldHomeY = float(self.data.config.getValue("Advanced Settings", "homeY")) + oldHomeX = float( + self.data.config.getValue("Advanced Settings", "homeX") + ) + oldHomeY = float( + self.data.config.getValue("Advanced Settings", "homeY") + ) # convert homeX and homeY to the correct units and save - self.data.config.setValue("Advanced Settings", "homeX", oldHomeX * scaleFactor) - self.data.config.setValue("Advanced Settings", "homeY", oldHomeY * scaleFactor) + self.data.config.setValue( + "Advanced Settings", "homeX", oldHomeX * scaleFactor + ) + self.data.config.setValue( + "Advanced Settings", "homeY", oldHomeY * scaleFactor + ) # notify all UI clients that units have been changed and distToMove has been changed self.data.ui_queue1.put("Action", "unitsUpdate", "") self.data.ui_queue1.put("Action", "distToMoveUpdate", "") # update the home position.. - position = {"xval": oldHomeX * scaleFactor, "yval": oldHomeY * scaleFactor} + position = { + "xval": oldHomeX * scaleFactor, + "yval": oldHomeY * scaleFactor, + } self.data.ui_queue1.put("Action", "homePositionMessage", position) # update the gcode position self.sendGCodePositionUpdate(recalculate=True) @@ -914,13 +776,13 @@ def updateSetting(self, setting, value, fromGcode = False): # this shouldn't be reached any more after I reordered the processActions function # todo: remove this if if not needed. if self.data.uploadFlag == 1: - self.data.ui_queue1.put("Alert", "Alert", "Cannot change units while sending gcode.") + self.data.ui_queue1.put( + "Alert", "Alert", "Cannot change units while sending gcode." + ) return True - #self.data.units = "INCHES" ### commented this out and added the unitZ - self.data.config.setValue( - "Computed Settings", "unitsZ", "INCHES" - ) + # self.data.units = "INCHES" ### commented this out and added the unitZ + self.data.config.setValue("Computed Settings", "unitsZ", "INCHES") self.data.config.setValue("Computed Settings", "distToMoveZ", value) self.data.ui_queue1.put("Action", "unitsUpdateZ", "") self.data.ui_queue1.put("Action", "distToMoveUpdateZ", "") @@ -929,48 +791,47 @@ def updateSetting(self, setting, value, fromGcode = False): # this shouldn't be reached any more after I reordered the processActions function # todo: remove this if if not needed. if self.data.uploadFlag == 1: - self.data.ui_queue1.put("Alert", "Alert", "Cannot change units while sending gcode.") + self.data.ui_queue1.put( + "Alert", "Alert", "Cannot change units while sending gcode." + ) return True - #self.data.units = "MM" ### commented this out - self.data.config.setValue( - "Computed Settings", "unitsZ", "MM" - ) + # self.data.units = "MM" ### commented this out + self.data.config.setValue("Computed Settings", "unitsZ", "MM") self.data.config.setValue("Computed Settings", "distToMoveZ", value) self.data.ui_queue1.put("Action", "unitsUpdateZ", "") self.data.ui_queue1.put("Action", "distToMoveUpdateZ", "") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with update settings.") return False def rotateSprocket(self, sprocket, time): - ''' + """ Turns sprocket at 100 speed for given amount of time using B11 command This command is used in PID tuning to try to get sprockets in a position without using encoder. :param sprocket: :param time: :return: - ''' + """ try: - if time > 0: - self.data.gcode_queue.put("B11 "+sprocket+" S100 T"+str(time)) + if time > 0: + self.data.gcode_queue.put("B11 " + sprocket + " S100 T" + str(time)) else: - self.data.gcode_queue.put("B11 "+sprocket+" S-100 T"+str(abs(time))) + self.data.gcode_queue.put("B11 " + sprocket + " S-100 T" + str(abs(time))) return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with rotating sprockets.") return False - def setSprockets(self, sprocket, degrees): - ''' + """ Moves sprocket a specified number of degrees. :param sprocket: :param degrees: :return: - ''' + """ try: - # calculate the amoount of chain to be fed out/in based upon sprocket circumference and degree + # Calculate the amoount of chain to be fed out/in based upon sprocket circumference and degree. degValue = round( float(self.data.config.getValue("Advanced Settings", "gearTeeth")) * float(self.data.config.getValue("Advanced Settings", "chainPitch")) @@ -978,47 +839,52 @@ def setSprockets(self, sprocket, degrees): * degrees, 4, ) - # Adjust distance based upon chainOverSprocket value + # Adjust distance based upon chainOverSprocket value. self.data.gcode_queue.put("G91 ") - if ( - self.data.config.getValue("Advanced Settings", "chainOverSprocket") - == "Bottom" - ): + if (self.data.config.getValue("Advanced Settings", "chainOverSprocket") == "Bottom"): degValue *= -1.0 - if self.data.config.getValue("Advanced Settings", "chainOverSprocket") == "Bottom": - if self.data.config.getValue("Computed Settings", "chainOverSprocketComputed") != 2: - self.data.ui_queue1.put("Alert", "Alert", "mismatch between setting and computed setting. set for bottom feed, but computed !=2. report as issue on github please") - if self.data.config.getValue("Advanced Settings", "chainOverSprocket") == "Top": - if self.data.config.getValue("Computed Settings", "chainOverSprocketComputed") != 1: - self.data.ui_queue1.put("Alert", "Alert", "mismatch between setting and computed setting. set for top feed, but computed != 1. report as issue on github please") + if (self.data.config.getValue("Advanced Settings", "chainOverSprocket") == "Bottom"): + if (self.data.config.getValue("Computed Settings", "chainOverSprocketComputed") != 2): + self.data.ui_queue1.put( + "Alert", + "Alert", + "Mismatch between setting and computed setting. Set for bottom feed, but computed !=2. Report as issue on github please.", + ) + if (self.data.config.getValue("Advanced Settings", "chainOverSprocket") == "Top"): + if (self.data.config.getValue("Computed Settings", "chainOverSprocketComputed") != 1): + self.data.ui_queue1.put( + "Alert", + "Alert", + "Mismatch between setting and computed setting. Set for top feed, but computed != 1. Report as issue on github please", + ) # send command self.data.gcode_queue.put("B09 " + sprocket + str(degValue) + " ") self.data.gcode_queue.put("G90 ") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with setting sprockets.") return False def setSprocketAutomatic(self): - ''' + """ Sets the call back for the automatic sprocket alignment and requests the measurement. - ''' + """ try: self.data.measureRequest = self.getLeftChainLength - # request a measurement + # Request a measurement. self.data.gcode_queue.put("B10 L") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with setting sprockets automatically.") return False def getLeftChainLength(self, dist): - ''' + """ Part of setSprocketAutomatic. Is called after the measurement is received. Left chain measurement is logged and then callback is set to get the right chain measurement. :param dist: :return: - ''' + """ self.leftChainLength = dist # set the call back for the measurement self.data.measureRequest = self.getRightChainLength @@ -1026,21 +892,21 @@ def getLeftChainLength(self, dist): self.data.gcode_queue.put("B10 R") def getRightChainLength(self, dist): - ''' + """ Part of setSprocketAutomatic. Is called after the measurement is received. Right chain measurement is logged and then moveToVertical is called. :param dist: :return: - ''' + """ self.rightChainLength = dist self.moveToVertical() def moveToVertical(self): - ''' + """ Using distances logged from previous calls, calculates how much to move the sprockets so that one tooth is vertical. :return: - ''' + """ chainPitch = float(self.data.config.getValue("Advanced Settings", "chainPitch")) gearTeeth = float(self.data.config.getValue("Advanced Settings", "gearTeeth")) distPerRotation = chainPitch * gearTeeth @@ -1055,42 +921,42 @@ def moveToVertical(self): self.data.gcode_queue.put("G90 ") def setSprocketsZero(self): - ''' + """ Notify controller that the chain length is zero. This is called by the user after the sprockets are set to vertical. :return: - ''' + """ try: self.data.gcode_queue.put("B06 L0 R0 ") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with setting sprockets zero value.") return False def setSprocketsDefault(self): - ''' + """ Notify controller that the chain length is equal to the extendChainLength distance. This is called by the user after setting both sprockets to vertical and reapplying the appropriate chain links to the top teeth. https://forums.maslowcnc.com/t/how-to-manually-reset-chains-the-easy-way/ :return: - ''' + """ try: self.data.gcode_queue.put("B08 ") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with setting sprockets as default.") return False def updatePorts(self): - ''' + """ Updates the list of ports found on the computer. :return: - ''' + """ self.data.console_queue.put("at Update Ports") portsList = [] try: if sys.platform.startswith("linux") or sys.platform.startswith("cygwin"): - # this excludes your current terminal "/dev/tty" + # This excludes your current terminal "/dev/tty". sysports = glob.glob("/dev/tty[A-Za-z]*") for port in sysports: portsList.append(port) @@ -1105,38 +971,46 @@ def updatePorts(self): if len(portsList) == 0: portsList.append("None") self.data.comPorts = portsList - # send updated list to UI client + # Send updated list to UI client. self.data.ui_queue1.put("Action", "updatePorts", "") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with updating list of ports.") return False def acceptTriangularKinematicsResults(self): - ''' + """ Calls function to accept the results of the triangular calibration. Todo: call directly from processActions. :return: - ''' + """ try: - self.data.triangularCalibration.acceptTriangularKinematicsResults() - return True + return self.data.triangularCalibration.acceptTriangularKinematicsResults() except Exception as e: self.data.console_queue.put(str(e)) return False - + def acceptHoleyCalibrationResults(self): + try: + return self.data.holeyCalibration.acceptCalibrationResults() + except Exception as e: + self._logException(e, "Error with accepting holey calibration results.") + return False + def calibrate(self, result): - ''' + """ Sends form data for triangular calibration to the triangular calibration routine to calculate and then return results to the UI client :param result: :return: - ''' + """ try: - motorYoffsetEst, rotationRadiusEst, chainSagCorrectionEst, cut34YoffsetEst = self.data.triangularCalibration.calculate( - result - ) + ( + motorYoffsetEst, + rotationRadiusEst, + chainSagCorrectionEst, + cut34YoffsetEst, + ) = self.data.triangularCalibration.calculate(result) if not motorYoffsetEst: # if something didn't go correctly, motorYoffsetEst would have been returned as none return False @@ -1147,20 +1021,24 @@ def calibrate(self, result): cut34YoffsetEst, ) except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with triangular calibration.") return False def holeyCalibrate(self, result): - ''' + """ Sends form data for holey calibration to the triangular calibration routine to calculate and then return results to the UI client :param result: :return: - ''' + """ try: - motorYoffsetEst, distanceBetweenMotors, leftChainTolerance, rightChainTolerance, calibrationError = self.data.holeyCalibration.Calibrate( - result - ) + ( + motorYoffsetEst, + distanceBetweenMotors, + leftChainTolerance, + rightChainTolerance, + calibrationError, + ) = self.data.holeyCalibration.Calibrate(result) if not motorYoffsetEst: # if something didn't go correctly, motorYoffsetEst would have been returned as none return False @@ -1172,16 +1050,15 @@ def holeyCalibrate(self, result): calibrationError, ) except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with holey calibration.") return False - def sendGCode(self, gcode): - ''' + """ Sends gcode entered to controller. Comes from the Gcode->Send GCode function :param gcode: :return: - ''' + """ try: self.data.sentCustomGCode = gcode gcodeLines = gcode.splitlines() @@ -1189,16 +1066,16 @@ def sendGCode(self, gcode): self.data.gcode_queue.put(line) return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with sending gcode.") return False - + def macro(self, number): - ''' + """ Sends gcode associated with macro buttons :param number: :return: - ''' - ''' + """ + """ Ignore this stuff in this comment block.. used for testing gpio try: if number == 1: @@ -1215,54 +1092,69 @@ def macro(self, number): self.data.console_queue.put(str(e)) return False - ''' + """ try: - if number == 1: - macro = self.data.config.getValue("Maslow Settings", "macro1") - else: - macro = self.data.config.getValue("Maslow Settings", "macro2") + if (number != 1 and number != 2): + raise Exception('Macro number must be 1 or 2.') + + macro_name = "macro" + str(number) + macro = self.data.config.getValue("Maslow Settings", macro_name) + if macro is None: + raise Exception('Macro [' + macro_name + '] not set.') + self.data.gcode_queue.put(macro) return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with performing macro.") return False + def macro1(self): + return self.macro(self, 1) + + def macro2(self): + return self.macro(self, 2) + def testImage(self): - ''' + """ Calls function to send the test image from optical calibration Todo: move to processAction :return: - ''' + """ try: self.data.opticalCalibration.testImage() return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with optical calibration test image.") return False def adjustCenter(self, dist): - ''' + """ Used in optical calibration to allow user to raise/lower the center point and then move there. :param dist: :return: - ''' + """ try: - motorOffsetY = float(self.data.config.getValue("Maslow Settings","motorOffsetY"))+dist - self.data.config.setValue('Maslow Settings', 'motorOffsetY', str(motorOffsetY)) + motorOffsetY = ( + float(self.data.config.getValue("Maslow Settings", "motorOffsetY")) + + dist + ) + self.data.config.setValue( + "Maslow Settings", "motorOffsetY", str(motorOffsetY) + ) if not self.returnToCenter(): return False return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with adjusting center.") return False def processSettingRequest(self, section, setting): - ''' + """ Returns requested settings to the UI clients. Needed when a client connects or reconnects to get in sync :param section: :param setting: :return: - ''' + """ try: if setting == "homePosition": # send home position @@ -1274,32 +1166,88 @@ def processSettingRequest(self, section, setting): elif setting == "calibrationCurve": # send optical calibration curve values try: - xCurve = [0,0,0,0,0,0] - yCurve = [0,0,0,0,0,0] - xCurve[0] = float(self.data.config.getValue('Optical Calibration Settings', 'calX0')) - xCurve[1] = float(self.data.config.getValue('Optical Calibration Settings', 'calX1')) - xCurve[2] = float(self.data.config.getValue('Optical Calibration Settings', 'calX2')) - xCurve[3] = float(self.data.config.getValue('Optical Calibration Settings', 'calX3')) - xCurve[4] = float(self.data.config.getValue('Optical Calibration Settings', 'calX4')) - xCurve[5] = float(self.data.config.getValue('Optical Calibration Settings', 'calX5')) - yCurve[0] = float(self.data.config.getValue('Optical Calibration Settings', 'calY0')) - yCurve[1] = float(self.data.config.getValue('Optical Calibration Settings', 'calY1')) - yCurve[2] = float(self.data.config.getValue('Optical Calibration Settings', 'calY2')) - yCurve[3] = float(self.data.config.getValue('Optical Calibration Settings', 'calY3')) - yCurve[4] = float(self.data.config.getValue('Optical Calibration Settings', 'calY4')) - yCurve[5] = float(self.data.config.getValue('Optical Calibration Settings', 'calY5')) + xCurve = [0, 0, 0, 0, 0, 0] + yCurve = [0, 0, 0, 0, 0, 0] + xCurve[0] = float( + self.data.config.getValue( + "Optical Calibration Settings", "calX0" + ) + ) + xCurve[1] = float( + self.data.config.getValue( + "Optical Calibration Settings", "calX1" + ) + ) + xCurve[2] = float( + self.data.config.getValue( + "Optical Calibration Settings", "calX2" + ) + ) + xCurve[3] = float( + self.data.config.getValue( + "Optical Calibration Settings", "calX3" + ) + ) + xCurve[4] = float( + self.data.config.getValue( + "Optical Calibration Settings", "calX4" + ) + ) + xCurve[5] = float( + self.data.config.getValue( + "Optical Calibration Settings", "calX5" + ) + ) + yCurve[0] = float( + self.data.config.getValue( + "Optical Calibration Settings", "calY0" + ) + ) + yCurve[1] = float( + self.data.config.getValue( + "Optical Calibration Settings", "calY1" + ) + ) + yCurve[2] = float( + self.data.config.getValue( + "Optical Calibration Settings", "calY2" + ) + ) + yCurve[3] = float( + self.data.config.getValue( + "Optical Calibration Settings", "calY3" + ) + ) + yCurve[4] = float( + self.data.config.getValue( + "Optical Calibration Settings", "calY4" + ) + ) + yCurve[5] = float( + self.data.config.getValue( + "Optical Calibration Settings", "calY5" + ) + ) data = {"curveX": xCurve, "curveY": yCurve} - self.data.ui_queue1.put("Action", "updateOpticalCalibrationCurve", data) + self.data.ui_queue1.put( + "Action", "updateOpticalCalibrationCurve", data + ) except Exception as e: self.data.console_queue.put(str(e)) elif setting == "calibrationError": # send calibration error matrix try: - xyErrorArray = self.data.config.getValue("Optical Calibration Settings","xyErrorArray") + xyErrorArray = self.data.config.getValue( + "Optical Calibration Settings", "xyErrorArray" + ) # parse the error array because its stored as a long string - errorX, errorY = self.data.config.parseErrorArray(xyErrorArray, True) + errorX, errorY = self.data.config.parseErrorArray( + xyErrorArray, True + ) data = {"errorX": errorX, "errorY": errorY} - self.data.ui_queue1.put("Action", "updateOpticalCalibrationError", data) + self.data.ui_queue1.put( + "Action", "updateOpticalCalibrationError", data + ) except Exception as e: self.data.console_queue.put(str(e)) elif setting == "pauseButtonSetting": @@ -1322,15 +1270,16 @@ def processSettingRequest(self, section, setting): # return the setting requested and its value. return setting, retval except Exception as e: + # TODO: Why it this ignoring exceptions? pass return None, None def upgradeFirmware(self, version): - ''' + """ Upgrades the firmware in the controller :param version: :return: - ''' + """ try: # if this is a pyinstaller release, find out where the root is... it could be a temp directory if single # file @@ -1339,22 +1288,34 @@ def upgradeFirmware(self, version): else: home = "." if version == 0: - self.data.ui_queue1.put("SpinnerMessage", "", "Custom Firmware Update in Progress, Please Wait.") - path = home+"/firmware/madgrizzle/*.hex" + self.data.ui_queue1.put( + "SpinnerMessage", + "", + "Custom Firmware Update in Progress, Please Wait.", + ) + path = home + "/firmware/madgrizzle/*.hex" if version == 1: - self.data.ui_queue1.put("SpinnerMessage", "", "Stock Firmware Update in Progress, Please Wait.") - path = home+"/firmware/maslowcnc/*.hex" + self.data.ui_queue1.put( + "SpinnerMessage", + "", + "Stock Firmware Update in Progress, Please Wait.", + ) + path = home + "/firmware/maslowcnc/*.hex" if version == 2: - self.data.ui_queue1.put("SpinnerMessage", "", "Holey Firmware Update in Progress, Please Wait.") - path = home+"/firmware/holey/*.hex" + self.data.ui_queue1.put( + "SpinnerMessage", + "", + "Holey Firmware Update in Progress, Please Wait.", + ) + path = home + "/firmware/holey/*.hex" # wait half second.. not sure why.. - time.sleep(.5) - t0 = time.time()*1000 + time.sleep(0.5) + t0 = time.time() * 1000 portClosed = False # request the the serial port is closed self.data.serialPort.closeConnection() # give it five seconds to close - while (time.time()*1000 - t0) < 5000: + while (time.time() * 1000 - t0) < 5000: if self.data.serialPort.getConnectionStatus(): portClosed = True break @@ -1366,16 +1327,25 @@ def upgradeFirmware(self, version): for filename in glob.glob(path): port = self.data.comport # this was commented out below. probably not needed. Todo: cleanup - #if home != "": + # if home != "": # cmd = "\"C:\\Program Files (x86)\\Arduino\\hardware\\tools\\avr\\bin\\avrdude\" -Cavr/avrdude.conf -v -patmega2560 -cwiring -P" + port + " -b115200 -D -Uflash:w:" + filename + ":i" - #else: - cmd = home+"/tools/avrdude -C"+home+"/tools/avrdude.conf -v -patmega2560 -cwiring -P"+port+" -b115200 -D -Uflash:w:"+filename+":i" - #print(cmd) + # else: + cmd = ( + home + + "/tools/avrdude -C" + + home + + "/tools/avrdude.conf -v -patmega2560 -cwiring -P" + + port + + " -b115200 -D -Uflash:w:" + + filename + + ":i" + ) + # print(cmd) # I think this is blocking.. x = os.system(cmd) self.data.connectionStatus = 0 - #print(x) - #print("closing modals") + # print(x) + # print("closing modals") # close off the modals and put away the spinner. self.data.ui_queue1.put("Action", "closeModals", "Notification:") return True @@ -1384,16 +1354,24 @@ def upgradeFirmware(self, version): print("Port not closed") return False except Exception as e: - self.data.console_log.put(str(e)) + self._logException(e, "Error with upgrading firmware.") return False + def upgradeCustomFirmware(self): + return self.upgradeFirmware(0) + + def upgradeStockFirmware(self): + return self.upgradeFirmware(1) + + def upgradeHoleyFirmware(self): + return self.upgradeFirmware(2) def createDirectory(self, _directory): - ''' + """ Called to create a directory when saving gcode :param _directory: :return: - ''' + """ try: home = self.data.config.getHome() directory = home + "/.WebControl/gcode/" + _directory @@ -1401,23 +1379,132 @@ def createDirectory(self, _directory): os.mkdir(directory) data = {"directory": _directory} self.data.ui_queue1.put("Action", "updateDirectories", data) + return True except Exception as e: - print(e) - return True + self._logException(e, "Error with creating directory.") + return False + + def acceptTriangularCalibrationResults(self): + try: + return self.data.triangularCalibration.acceptTriangularCalibrationResults() + except Exception as e: + self._logException(e, "Error with accepting triangular calibration results.") + return False + + def cutTriangularCalibrationPattern(self): + try: + return self.data.triangularCalibration.cutTriangularCalibrationPattern() + except Exception as e: + self._logException(e, "Error with cutting triangular calibration pattern.") + return False + + def cutHoleyCalibrationPattern(self): + try: + return self.data.holeyCalibration.CutTestPattern() + except Exception as e: + self._logException(e, "Error with cutting holey calibration pattern.") + return False + + def saveOpticalCalibrationConfiguration(self, arg): + try: + return self.data.opticalCalibration.saveOpticalCalibrationConfiguration(arg) + except Exception as e: + self._logException(e, "Error with saving optical calibration configuration.") + return False + + def stopOpticalCalibration(self): + try: + return self.data.opticalCalibration.stopOpticalCalibration() + except Exception as e: + self._logException(e, "Error with stopping optical calibration.") + return False + + def testOpticalCalibration(self, arg): + try: + return self.data.opticalCalibration.testImage(arg) + except Exception as e: + self._logException(e, "Error with test image.") + return False + + def findCenterOpticalCalibration(self, arg): + try: + return self.data.opticalCalibration.findCenter(arg) + except Exception as e: + self._logException(e, "Error with find Center.") + return False + + def saveAndSendOpticalCalibration(self): + try: + return self.data.opticalCalibration.saveAndSend() + except Exception as e: + self._logException(e, "Error with saving and sending calibration matrix.") + return False + + def reloadCalibration(self): + try: + ( + errorX, + errorY, + curveX, + curveY, + ) = self.data.opticalCalibration.reloadCalibration() + + if errorX is None or errorY is None or curveX is None or curveY is None: + raise Exception("Reload calibration returned values as None.") + + data = { "errorX": errorX, "errorY": errorY } + self.data.ui_queue1.put( + "Action", "updateOpticalCalibrationError", data + ) + return True; + except Exception as e: + self._logException(e, "Error with (re)loading calibration.") + return False + + def saveCalibrationToCSV(self): + try: + return self.data.opticalCalibration.saveCalibrationToCSV() + except Exception as e: + self._logException(e, "Error with saving calibration to CSV.") + return False + + def clearCalibration(self): + try: + return self.data.opticalCalibration.clearCalibration() + except Exception as e: + self._logException(e, "Error with clearing calibration.") + return False + + def curveFitOpticalCalibration(self): + try: + curveX, curveY = self.data.opticalCalibration.surfaceFit() + if curveX is None or curveY is None: + raise Exception("Curve fit returned values as None.") + + data = {"curveX": curveX, "curveY": curveY} + self.data.ui_queue1.put("Action", "updateOpticalCalibrationCurve", data) + return True + except Exception as e: + self._logException(e, "Error with curve fitting calibration data.") + return False def sendGCodePositionUpdate(self, gCodeLineIndex=None, recalculate=False): - ''' + """ Send the updated gcode position. :param gCodeLineIndex: Specific gcode index to send position based upon :param recalculate: recalculate position by parsing through the gcode file. :return: - ''' + """ if self.data.gcode: if gCodeLineIndex is None: gCodeLineIndex = self.data.gcodeIndex gCodeLine = self.data.gcode[gCodeLineIndex] - if not recalculate and gCodeLine.find("(") == -1 and gCodeLine.find(";") == -1: + if ( + not recalculate + and gCodeLine.find("(") == -1 + and gCodeLine.find(";") == -1 + ): # parse the position from the gcode line or use previous x, y, or z position if not present. Works only # if in absolute mode x = re.search("X(?=.)([+-]?([0-9]*)(\.([0-9]+))?)", gCodeLine) @@ -1460,59 +1547,77 @@ def sendGCodePositionUpdate(self, gCodeLineIndex=None, recalculate=False): # the front page to imperial and then changes the gcode index. scaleFactor = 1.0 if self.data.gcodeFileUnits == "MM" and self.data.units == "INCHES": - scaleFactor = 1/25.4 + scaleFactor = 1 / 25.4 if self.data.gcodeFileUnits == "INCHES" and self.data.units == "MM": scaleFactor = 25.4 # send the position to the UI client - position = {"xval": xTarget * scaleFactor, "yval": yTarget * scaleFactor,"zval": zTarget * scaleFactor, "gcodeLine": gCodeLine, "gcodeLineIndex": gCodeLineIndex} + position = { + "xval": xTarget * scaleFactor, + "yval": yTarget * scaleFactor, + "zval": zTarget * scaleFactor, + "gcodeLine": gCodeLine, + "gcodeLineIndex": gCodeLineIndex, + } self.data.ui_queue1.put("Action", "gcodePositionMessage", position) return True def moveTo(self, posX, posY): - ''' + """ Commands controller to move sled to specified coordinates from the contextmenu moveto command(always in inches) :param posX: :param posY: :return: - ''' - # make sure not out of range. - bedHeight = float(self.data.config.getValue("Maslow Settings","bedHeight"))/25.4 - bedWidth = float(self.data.config.getValue("Maslow Settings", "bedWidth"))/25.4 + """ + + # TODO: Maslow fimware uses measurements in MM for better precision. Convert all inches to MM. try: - if posX<=bedWidth/2 and posX>=bedWidth/-2 and posY<=bedHeight/2 and posY>=bedHeight/-2: + # Make sure not out of range. + bedHeight = ( + float(self.data.config.getValue("Maslow Settings", "bedHeight")) / 25.4 + ) + bedWidth = ( + float(self.data.config.getValue("Maslow Settings", "bedWidth")) / 25.4 + ) + + if ( + posX <= bedWidth / 2 + and posX >= bedWidth / -2 + and posY <= bedHeight / 2 + and posY >= bedHeight / -2 + ): if self.data.units == "INCHES": - posX=round(posX,4) - posY=round(posY,4) + posX = round(posX, 4) + posY = round(posY, 4) else: # convert to mm - posX=round(posX*25.4,4) - posY=round(posY*25.4,4) + posX = round(posX * 25.4, 4) + posY = round(posY * 25.4, 4) self.data.gcode_queue.put( - "G90 G00 X" - + str(posX) - + " Y" - + str(posY) - + " " + "G90 G00 X" + str(posX) + " Y" + str(posY) + " " ) return True return False except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with initiating move.") return False def processGCode(self): - ''' + """ This function processes the gcode up to the current gcode index to develop a set of gcodes to send to the controller upon the user starting a run. This function is intended to ensure that the sled is in the correct location and the controller is in the correct state prior to starting the current gcode move. Currently processed are relative/absolute positioning (G90/G91), imperial/metric units (G20/G21) and x, y and z positions - ''' + """ positioning = "G90 " - zAxisSafeHeight = float(self.data.config.getValue("Maslow Settings", "zAxisSafeHeight")) + zAxisSafeHeight = float( + self.data.config.getValue("Maslow Settings", "zAxisSafeHeight") + ) zAxisFeedRate = 12.8 # currently hardcoded, but Todo: Add setting - xyAxisFeedRate = float(self.data.config.getValue("Advanced Settings", "maxFeedrate")) + xyAxisFeedRate = float( + self.data.config.getValue("Advanced Settings", "maxFeedrate") + ) positioning = "G90 " units = "G20 " homeX = float(self.data.config.getValue("Advanced Settings", "homeX")) @@ -1531,10 +1636,16 @@ def processGCode(self): dwell = None # start parsing through gcode file up to the index for x in range(self.data.gcodeIndex): - filtersparsed = re.sub(r'\(([^)]*)\)', '', self.data.gcode[x]) # replace mach3 style gcode comments with newline - filtersparsed = re.sub(r';([^\n]*)?', '\n', filtersparsed) # replace standard ; initiated gcode comments with nothing - if not filtersparsed.isspace(): # if all spaces, don't send. likely a comment. #self.data.gcode[x][0] != "(": - #lines = self.data.gcode[x].split(" ") + filtersparsed = re.sub( + r"\(([^)]*)\)", "", self.data.gcode[x] + ) # replace mach3 style gcode comments with newline + filtersparsed = re.sub( + r";([^\n]*)?", "\n", filtersparsed + ) # replace standard ; initiated gcode comments with nothing + if ( + not filtersparsed.isspace() + ): # if all spaces, don't send. likely a comment. #self.data.gcode[x][0] != "(": + # lines = self.data.gcode[x].split(" ") lines = filtersparsed.split(" ") if lines: finalLines = [] @@ -1542,20 +1653,27 @@ def processGCode(self): # I must of had a reason to do so for line in lines: if len(line) > 0: - if line[0] == "M" or line[0] == "G" or line[0] == "T" or len(finalLines) == 0: + if ( + line[0] == "M" + or line[0] == "G" + or line[0] == "T" + or len(finalLines) == 0 + ): finalLines.append(line) else: finalLines[-1] = finalLines[-1] + " " + line # start processing the lines, keeping track of the state variables. for line in finalLines: - if line[0]=='G': + if line[0] == "G": if line.find("G90") != -1: positioning = "G90 " if line.find("G91") != -1: positioning = "G91 " if line.find("G20") != -1: units = "G20 " - if previousUnits != units: #previous metrics now imperial + if ( + previousUnits != units + ): # previous metrics now imperial homeX = xpos / 25.4 homeY = ypos / 25.4 xpos = xpos / 25.4 @@ -1563,28 +1681,36 @@ def processGCode(self): previousUnits = units if line.find("G21") != -1: units = "G21 " - if previousUnits != units: #previous imperial now metrics + if ( + previousUnits != units + ): # previous imperial now metrics homeX = xpos * 25.4 homeY = ypos * 25.4 xpos = xpos * 25.4 ypos = ypos * 25.4 previousUnits = units if line.find("X") != -1: - _xpos = re.search("X(?=.)(([ ]*)?[+-]?([0-9]*)(\.([0-9]+))?)", line) + _xpos = re.search( + "X(?=.)(([ ]*)?[+-]?([0-9]*)(\.([0-9]+))?)", line + ) if positioning == "G91 ": - xpos = xpos+float(_xpos.groups()[0]) + xpos = xpos + float(_xpos.groups()[0]) else: - xpos = float(_xpos.groups()[0])+homeX + xpos = float(_xpos.groups()[0]) + homeX if line.find("Y") != -1: - _ypos = re.search("Y(?=.)(([ ]*)?[+-]?([0-9]*)(\.([0-9]+))?)", line) + _ypos = re.search( + "Y(?=.)(([ ]*)?[+-]?([0-9]*)(\.([0-9]+))?)", line + ) if positioning == "G91 ": - ypos = ypos+float(_ypos.groups()[0]) + ypos = ypos + float(_ypos.groups()[0]) else: - ypos = float(_ypos.groups()[0])+homeY + ypos = float(_ypos.groups()[0]) + homeY if line.find("Z") != -1: - _zpos = re.search("Z(?=.)(([ ]*)?[+-]?([0-9]*)(\.([0-9]+))?)", line) + _zpos = re.search( + "Z(?=.)(([ ]*)?[+-]?([0-9]*)(\.([0-9]+))?)", line + ) if positioning == "G91 ": - zpos = zpos+float(_zpos.groups()[0]) + zpos = zpos + float(_zpos.groups()[0]) else: zpos = float(_zpos.groups()[0]) if line.find("G4") != -1: @@ -1592,13 +1718,15 @@ def processGCode(self): if line.find("G04") != -1: dwell = line[4:] if line.find("F") != -1: - _feedRate = re.search("F(?=.)(([ ]*)?[+-]?([0-9]*)(\.([0-9]+))?)", line) + _feedRate = re.search( + "F(?=.)(([ ]*)?[+-]?([0-9]*)(\.([0-9]+))?)", line + ) _feedRateFloat = float(_feedRate.groups()[0]) if line.find("X") != -1 or line.find("Y") == -1: xyAxisFeedRate = _feedRateFloat if line.find("Z") != -1: zAxisFeedRate = _feedRateFloat - if line[0] == 'M': + if line[0] == "M": if line.find("M3") != -1 or line.find("M03") != -1: spindle = "M3 " if line.find("M4") != -1 or line.find("M05") != -1: @@ -1611,15 +1739,15 @@ def processGCode(self): laser = "M107 " if line.find("M16") != -1: laser = "M107 " - if line[0] == 'T': - tool = line[1:] #slice off the T + if line[0] == "T": + tool = line[1:] # slice off the T # now, after all that processing has been done, put machine in the correct state # first, send the units command. self.data.gcode_queue.put(units) # if units is imperial, then change the zAxisSafeHeight if units == "G20 ": zAxisSafeHeight = zAxisSafeHeight / 25.4 - ''' + """ I had commented this out.. don't think it should be done since the units above will do it. if units == "G20 ": print("is G20") @@ -1628,17 +1756,29 @@ def processGCode(self): else: print("is G21") self.data.actions.updateSetting("toMM", 0, True) # value = doesn't matter - ''' + """ # move the Z-axis to the safe height print("moving to safe height as part of processgcode") - #force into absolute mode + # force into absolute mode self.data.gcode_queue.put("G90 ") - self.data.gcode_queue.put("G0 Z"+str(round(zAxisSafeHeight, 4))+" F"+str(round(zAxisFeedRate, 4))) + self.data.gcode_queue.put( + "G0 Z" + + str(round(zAxisSafeHeight, 4)) + + " F" + + str(round(zAxisFeedRate, 4)) + ) # move the sled to the x, y coordinate it is supposed to be. - self.data.gcode_queue.put("G0 X"+str(round(xpos, 4))+" Y"+str(round(ypos, 4))+" F"+str(round(xyAxisFeedRate, 4))) + self.data.gcode_queue.put( + "G0 X" + + str(round(xpos, 4)) + + " Y" + + str(round(ypos, 4)) + + " F" + + str(round(xyAxisFeedRate, 4)) + ) # if there is a tool, then send tool change command. if tool is not None: - self.data.gcode_queue.put("T"+tool+" M6 ") + self.data.gcode_queue.put("T" + tool + " M6 ") # if there is a spindle command, then send it. if spindle is not None: self.data.gcode_queue.put(spindle) @@ -1647,7 +1787,7 @@ def processGCode(self): self.data.gcode_queue.put(laser) # if there is a dwell command, then send it. if dwell is not None: - self.data.gcode_queue.put("G4 "+dwell) + self.data.gcode_queue.put("G4 " + dwell) # move the z-axis to where it is supposed to be. print("moving to where it should be as part of processgcode") self.data.gcode_queue.put("G0 Z" + str(round(zpos, 4)) + " ") @@ -1656,59 +1796,77 @@ def processGCode(self): self.data.gcode_queue.put(positioning) def findPositionAt(self, index): - ''' + """ Find the x,y,z gcode position at a given index when simple calcs don't work. Parse through the file. :param index: :return: - ''' + """ xpos = 0 ypos = 0 zpos = 0 for x in range(index): - filtersparsed = re.sub(r'\(([^)]*)\)', '', self.data.gcode[x]) # replace mach3 style gcode comments with newline - filtersparsed = re.sub(r';([^\n]*)?', '\n', filtersparsed) # replace standard ; initiated gcode comments with "" - if not filtersparsed.isspace(): # if all spaces, don't send. likely a comment. #self.data.gcode[x][0] != "(": - listOfLines = filter(None, re.split("(G)", filtersparsed)) # self.data.gcode[x])) # self.data.gcode[x].split("G") + filtersparsed = re.sub( + r"\(([^)]*)\)", "", self.data.gcode[x] + ) # replace mach3 style gcode comments with newline + filtersparsed = re.sub( + r";([^\n]*)?", "\n", filtersparsed + ) # replace standard ; initiated gcode comments with "" + if ( + not filtersparsed.isspace() + ): # if all spaces, don't send. likely a comment. #self.data.gcode[x][0] != "(": + listOfLines = filter( + None, re.split("(G)", filtersparsed) + ) # self.data.gcode[x])) # self.data.gcode[x].split("G") # it is necessary to split the lines along G commands so that commands concatenated on one line # are processed correctly for line in listOfLines: - line = 'G'+line - if line[0] == 'G': + line = "G" + line + if line[0] == "G": if line.find("G90") != -1: positioning = "G90 " if line.find("G91") != -1: positioning = "G91 " if line.find("X") != -1: - _xpos = re.search("X(?=.)(([ ]*)?[+-]?([0-9]*)(\.([0-9]+))?)", line) + _xpos = re.search( + "X(?=.)(([ ]*)?[+-]?([0-9]*)(\.([0-9]+))?)", line + ) if positioning == "G91 ": xpos = xpos + float(_xpos.groups()[0]) else: xpos = float(_xpos.groups()[0]) if line.find("Y") != -1: - _ypos = re.search("Y(?=.)(([ ]*)?[+-]?([0-9]*)(\.([0-9]+))?)", line) + _ypos = re.search( + "Y(?=.)(([ ]*)?[+-]?([0-9]*)(\.([0-9]+))?)", line + ) if positioning == "G91 ": ypos = ypos + float(_ypos.groups()[0]) else: ypos = float(_ypos.groups()[0]) if line.find("Z") != -1: - _zpos = re.search("Z(?=.)(([ ]*)?[+-]?([0-9]*)(\.([0-9]+))?)", line) + _zpos = re.search( + "Z(?=.)(([ ]*)?[+-]?([0-9]*)(\.([0-9]+))?)", line + ) if positioning == "G91 ": zpos = zpos + float(_zpos.groups()[0]) else: zpos = float(_zpos.groups()[0]) - #print("xpos="+str(xpos)+", ypos="+str(ypos)+", zpoz="+str(zpos)+" for index="+str(index)) + # print("xpos="+str(xpos)+", ypos="+str(ypos)+", zpoz="+str(zpos)+" for index="+str(index)) return xpos, ypos, zpos def adjustChain(self, chain): - ''' + """ Called during the chain extend routine :param chain: :return: - ''' + """ try: for x in range(6): - self.data.ui_queue1.put("Action", "updateTimer", chain+":"+str(5-x)) - self.data.console_queue.put("Action:updateTimer_" + chain + ":" + str(5 - x)) + self.data.ui_queue1.put( + "Action", "updateTimer", chain + ":" + str(5 - x) + ) + self.data.console_queue.put( + "Action:updateTimer_" + chain + ":" + str(5 - x) + ) time.sleep(1) if chain == "left": self.data.gcode_queue.put("B02 L1 R0 ") @@ -1720,7 +1878,7 @@ def adjustChain(self, chain): self.data.gcode_queue.put("B10 R") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with adjusting chain.") return False def issueStopCommand(self, distance): @@ -1734,10 +1892,10 @@ def issueStopCommand(self, distance): return False def toggleCamera(self): - ''' + """ Turns camera on or off. If its suspended, it's read (though I can't explain why at this moment). :return: - ''' + """ try: status = self.data.camera.status() if status == "stopped": @@ -1748,15 +1906,15 @@ def toggleCamera(self): self.data.camera.stop() return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with toggling camera.") return False def cameraStatus(self): - ''' + """ Sends the status of the camera to the UI client. Not sure why its not called requestCameraStatus Todo: update name to request cameraStatus :return: - ''' + """ try: status = self.data.camera.status() if status == "stopped": @@ -1767,51 +1925,62 @@ def cameraStatus(self): self.data.ui_queue1.put("Action", "updateCamera", "on") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with getting camera status.") return False def queryCamera(self): - ''' + """ Query the camera's settings. Probably could be called directly by processAction Todo: move to processAction :return: - ''' + """ try: self.data.camera.getSettings() return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with querying camera.") return False def velocityPIDTest(self, parameters): - ''' + """ Send commands to start the veloctiy pid test Todo: further explain this :param parameters: :return: - ''' + """ try: print(parameters) print(parameters["KpV"]) self.data.config.setValue("Advanced Settings", "KpV", parameters["KpV"]) self.data.config.setValue("Advanced Settings", "KiV", parameters["KiV"]) self.data.config.setValue("Advanced Settings", "KdV", parameters["KdV"]) - gcodeString = "B13 "+parameters["vMotor"]+"1 S"+parameters["vStart"]+" F"+parameters["vStop"]+" I"+parameters["vSteps"]+" V"+parameters["vVersion"] + gcodeString = ( + "B13 " + + parameters["vMotor"] + + "1 S" + + parameters["vStart"] + + " F" + + parameters["vStop"] + + " I" + + parameters["vSteps"] + + " V" + + parameters["vVersion"] + ) print(gcodeString) self.data.PIDVelocityTestVersion = parameters["vVersion"] self.data.gcode_queue.put(gcodeString) return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with executing velocity PID test.") return False - def positionPIDTest(self, parameters): - ''' + def executePositionPIDTest(self, parameters): + """ Send commands to start the position pid test Todo: further explain this :param parameters: :return: - ''' + """ try: print(parameters) @@ -1820,97 +1989,141 @@ def positionPIDTest(self, parameters): self.data.config.setValue("Advanced Settings", "KiPos", parameters["KiP"]) self.data.config.setValue("Advanced Settings", "KdPos", parameters["KdP"]) - gcodeString = "B14 "+parameters["pMotor"]+"1 S"+parameters["pStart"]+" F"+parameters["pStop"]+" I"+parameters["pSteps"]+" T"+parameters["pTime"]+" V"+parameters["pVersion"] + gcodeString = ( + "B14 " + + parameters["pMotor"] + + "1 S" + + parameters["pStart"] + + " F" + + parameters["pStop"] + + " I" + + parameters["pSteps"] + + " T" + + parameters["pTime"] + + " V" + + parameters["pVersion"] + ) print(gcodeString) self.data.PIDPositionTestVersion = parameters["pVersion"] self.data.gcode_queue.put(gcodeString) return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with executing position PID test.") return False def velocityPIDTestRun(self, command, msg): - ''' + """ :param command: :param msg: :return: - ''' + """ try: - if command == 'stop': + if command == "stop": self.data.inPIDVelocityTest = False print("PID velocity test stopped") print(self.data.PIDVelocityTestData) - data = json.dumps({"result": "velocity", "version": self.data.PIDVelocityTestVersion, "data": self.data.PIDVelocityTestData}) + data = json.dumps( + { + "result": "velocity", + "version": self.data.PIDVelocityTestVersion, + "data": self.data.PIDVelocityTestData, + } + ) self.data.ui_queue1.put("Action", "updatePIDData", data) self.stopRun() - if command == 'running': + if command == "running": if msg.find("Kp=") == -1: if self.data.PIDVelocityTestVersion == "2": if msg.find("setpoint") == -1: self.data.PIDVelocityTestData.append(msg) else: self.data.PIDVelocityTestData.append(float(msg)) - if command == 'start': + if command == "start": self.data.inPIDVelocityTest = True self.data.PIDVelocityTestData = [] print("PID velocity test started") except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with executing velocity PID test run.") return False def positionPIDTestRun(self, command, msg): try: - if command == 'stop': + if command == "stop": self.data.inPIDPositionTest = False print("PID position test stopped") print(self.data.PIDPositionTestData) - data = json.dumps({"result": "position", "version": self.data.PIDPositionTestVersion, "data": self.data.PIDPositionTestData}) + data = json.dumps( + { + "result": "position", + "version": self.data.PIDPositionTestVersion, + "data": self.data.PIDPositionTestData, + } + ) self.data.ui_queue1.put("Action", "updatePIDData", data) self.stopRun() - if command == 'running': + if command == "running": if msg.find("Kp=") == -1: if self.data.PIDPositionTestVersion == "2": if msg.find("setpoint") == -1: self.data.PIDPositionTestData.append(msg) else: self.data.PIDPositionTestData.append(float(msg)) - if command == 'start': + if command == "start": self.data.inPIDPositionTest = True self.data.PIDPositionTestData = [] print("PID position test started") except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with executing poisition PID test run.") return False def updateGCode(self, gcode): try: - #print(gcode) + # print(gcode) homeX = float(self.data.config.getValue("Advanced Settings", "homeX")) homeY = float(self.data.config.getValue("Advanced Settings", "homeY")) - - if self.data.units == "MM": - scaleFactor = 25.4 - else: - scaleFactor = 1.0 - self.data.gcodeShift = [ - homeX, - homeY - ] - + self.data.gcodeShift = [homeX, homeY] self.data.gcodeFile.loadUpdateFile(gcode) self.data.ui_queue1.put("Action", "gcodeUpdate", "") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with update gcode.") + return False + + def update(self, arg): + try: + status = self.data.releaseManager.update(arg) + if status: + # TODO: Why is this returning "shutdown" text? + return "Shutdown" + return False + except Exception as e: + self._logException(e, "Error with updating webcontrol.") + return False + + def updatePyInstaller(self): + try: + status = self.data.releaseManager.updatePyInstaller() + if status: + # TODO: Why is this returning "shutdown" text? + return "Shutdown" + return False + except Exception as e: + self._logException(e, "Error with updating pyInstaller.") return False def downloadDiagnostics(self): try: timestr = time.strftime("%Y%m%d-%H%M%S") - filename = self.data.config.home+"/.WebControl/"+"wc_diagnostics_"+timestr+".zip" - zipObj = zipfile.ZipFile(filename, 'w') - path1 = self.data.config.home+"/.WebControl/webcontrol.json" + filename = ( + self.data.config.home + + "/.WebControl/" + + "wc_diagnostics_" + + timestr + + ".zip" + ) + zipObj = zipfile.ZipFile(filename, "w") + path1 = self.data.config.home + "/.WebControl/webcontrol.json" zipObj.write(path1, os.path.basename(path1)) path1 = self.data.config.home + "/.WebControl/alog.txt" zipObj.write(path1, os.path.basename(path1)) @@ -1919,7 +2132,7 @@ def downloadDiagnostics(self): zipObj.close() return filename except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with downloading diagnostics") return False def clearLogs(self): @@ -1927,9 +2140,10 @@ def clearLogs(self): retval = self.data.logger.deleteLogFiles() return retval except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error clearing log files.") return False - ''' + + """ def checkForLatestPyRelease(self): if True: #self.data.platform=="PYINSTALLER": print("check for pyrelease") @@ -2024,7 +2238,7 @@ def make_executable(self, path): print("3") os.chmod(path, mode) print("4") - ''' + """ def addDirToZip(self, zipHandle, path, basePath=""): basePath = basePath.rstrip("\\/") + "" @@ -2040,7 +2254,7 @@ def addDirToZip(self, zipHandle, path, basePath=""): zipHandle.write(filePath, inZipPath) def zipfolder(self, filename, target_dir): - zipobj = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED) + zipobj = zipfile.ZipFile(filename, "w", zipfile.ZIP_DEFLATED) rootlen = len(target_dir) + 1 for base, dirs, files in os.walk(target_dir): for file in files: @@ -2048,35 +2262,47 @@ def zipfolder(self, filename, target_dir): zipobj.write(fn, fn[rootlen:]) zipobj.close() - def backupWebControl(self): try: timestr = time.strftime("%Y%m%d-%H%M%S") home = self.data.config.getHome() - filename = home+"/wc_backup_"+timestr+".zip" + filename = home + "/wc_backup_" + timestr + ".zip" print(filename) - folder = self.data.config.home+'/.WebControl' + folder = self.data.config.home + "/.WebControl" print(folder) self.zipfolder(filename, folder) - #self.addDirToZip(zipObj, self.data.config.home+'/.Webcontrol') - #zipObj.close() + # self.addDirToZip(zipObj, self.data.config.home+'/.Webcontrol') + # zipObj.close() return filename except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with backing up webcontrol config.") return False + def boardProcessGCode(self): + try: + return self.data.boardManager.processGCode() + except Exception as e: + self._logException(e, "Error with processing gcode.") + return False + + def boardClearBoard(self): + try: + return self.data.boardManager.boardClearBoard() + except Exception as e: + self._logException(e, "Error with clearing board.") + return False def restoreWebControl(self, fileName): try: - with zipfile.ZipFile(fileName, 'r') as zipObj: + with zipfile.ZipFile(fileName, "r") as zipObj: # Extract all the contents of zip file in different directory - zipObj.extractall(self.data.config.home+'/.Webcontrol') + zipObj.extractall(self.data.config.home + "/.Webcontrol") retval = self.data.config.reloadWebControlJSON() if retval is True: self.data.gcode_queue.put("$$") return retval except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with restoring webcontrol config.") return False def setFakeServo(self, value): @@ -2087,5 +2313,5 @@ def setFakeServo(self, value): self.data.gcode_queue.put("B99 OFF") return True except Exception as e: - self.data.console_queue.put(str(e)) + self._logException(e, "Error with changing Fake Servo.") return False diff --git a/static/scripts/baseSocket.js b/static/scripts/baseSocket.js index 76fa990c..d40ae1c2 100644 --- a/static/scripts/baseSocket.js +++ b/static/scripts/baseSocket.js @@ -252,13 +252,17 @@ function setListeners(){ } -function action(command, arg, arg1){ - if (arg==null) - arg = ""; - if (arg1==null) - arg1 = ""; - console.log("action="+command); - socket.emit('action',{data:{command:command,arg:arg, arg1:arg1}}); +function action() { + var msg = {"command": arguments[0]}; + if (arguments.length > 1 ) { + var args = new Array() + for (var i=1; i < arguments.length; i++) { + args[i-1] = arguments[i]; + } + msg["args"] = args; + } + console.log("action=" + arguments[0]); + socket.emit('action', msg); } function move(direction){ From 0c0f4160df36749ccbd2c35f4927fd8430c415b2 Mon Sep 17 00:00:00 2001 From: gb0101010101 <7369439+gb0101010101@users.noreply.github.com> Date: Fri, 13 Mar 2020 17:53:23 -0700 Subject: [PATCH 02/17] Remove unused functions move() and moveZ() which have been replaced with action('move') and action('moveZ'). --- static/scripts/baseSocket.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/static/scripts/baseSocket.js b/static/scripts/baseSocket.js index d40ae1c2..d6ce9272 100644 --- a/static/scripts/baseSocket.js +++ b/static/scripts/baseSocket.js @@ -265,17 +265,6 @@ function action() { socket.emit('action', msg); } -function move(direction){ - distToMove = $("#distToMove").val(); - console.log(distToMove) - socket.emit('move',{data:{direction:direction,distToMove:distToMove}}); -} - -function moveZ(direction){ - distToMoveZ = $("#distToMoveZ").val(); - console.log(distToMoveZ) - socket.emit('moveZ',{data:{direction:direction,distToMoveZ:distToMoveZ}}); -} function settingRequest(section,setting){ console.log("requesting..") From f40828e6d9c7f0a9d8f747e7c581c9c0eddab23b Mon Sep 17 00:00:00 2001 From: gb0101010101 <7369439+gb0101010101@users.noreply.github.com> Date: Sun, 15 Mar 2020 18:15:38 -0700 Subject: [PATCH 03/17] Backup Webcontrol: Change datestamp format to make more legible, remove debugging print(), remove legacy commented code, send file as attachment to retain filename with datestamp. --- Actions/actions.py | 6 +----- main.py | 4 +--- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Actions/actions.py b/Actions/actions.py index fe04191c..f06269d1 100644 --- a/Actions/actions.py +++ b/Actions/actions.py @@ -2264,15 +2264,11 @@ def zipfolder(self, filename, target_dir): def backupWebControl(self): try: - timestr = time.strftime("%Y%m%d-%H%M%S") + timestr = time.strftime("%Y-%m-%d_%H-%M-%S") home = self.data.config.getHome() filename = home + "/wc_backup_" + timestr + ".zip" - print(filename) folder = self.data.config.home + "/.WebControl" - print(folder) self.zipfolder(filename, folder) - # self.addDirToZip(zipObj, self.data.config.home+'/.Webcontrol') - # zipObj.close() return filename except Exception as e: self._logException(e, "Error with backing up webcontrol config.") diff --git a/main.py b/main.py index 3d6faf51..5127b99c 100644 --- a/main.py +++ b/main.py @@ -521,14 +521,12 @@ def backupWebControl(): if request.method == "GET": returnVal = app.data.actions.backupWebControl() if returnVal != False: - print(returnVal) - return send_file(returnVal) + return send_file(returnVal, as_attachment=True) else: resp = jsonify("failed") resp.status_code = 500 return resp - @app.route("/editBoard", methods=["POST"]) def editBoard(): app.data.logger.resetIdler() From 9e91be1ffad4c8f0dde3a3e35b74821ee987171a Mon Sep 17 00:00:00 2001 From: gb0101010101 <7369439+gb0101010101@users.noreply.github.com> Date: Sun, 15 Mar 2020 19:27:58 -0700 Subject: [PATCH 04/17] Restore WebControl Backup: Pass '.zip' mimetype to importFile.html template to restrict selection of files. Make mimetype variable optional for backwards compatibility when not provided. --- WebPageProcessor/webPageProcessor.py | 2 +- templates/importFile.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WebPageProcessor/webPageProcessor.py b/WebPageProcessor/webPageProcessor.py index d9171f75..0f268d32 100644 --- a/WebPageProcessor/webPageProcessor.py +++ b/WebPageProcessor/webPageProcessor.py @@ -234,7 +234,7 @@ def createWebPage(self, pageID, isMobile, args): return page, "Import webcontrol.json", False, "medium", "content", False elif pageID == "restoreWebControl": url = "importRestoreWebControl" - page = render_template("importFile.html", url=url) + page = render_template("importFile.html", url=url, mimetypes=".zip") return page, "Restore WebControl", False, "medium", "content", False elif pageID == "actions": if self.data.controllerFirmwareVersion < 100: diff --git a/templates/importFile.html b/templates/importFile.html index fd0a6114..ea10357a 100644 --- a/templates/importFile.html +++ b/templates/importFile.html @@ -4,7 +4,7 @@
From 62de3ca1077e3e17ab71ad776ca98a44ce7e8941 Mon Sep 17 00:00:00 2001 From: gb0101010101 <7369439+gb0101010101@users.noreply.github.com> Date: Sun, 15 Mar 2020 19:32:33 -0700 Subject: [PATCH 05/17] Import GroundControl.ini: Restrict file selection to *.ini files. --- WebPageProcessor/webPageProcessor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WebPageProcessor/webPageProcessor.py b/WebPageProcessor/webPageProcessor.py index 0f268d32..03d66dd5 100644 --- a/WebPageProcessor/webPageProcessor.py +++ b/WebPageProcessor/webPageProcessor.py @@ -13,6 +13,7 @@ import socket from github import Github import markdown +import mimetypes class WebPageProcessor: @@ -226,7 +227,7 @@ def createWebPage(self, pageID, isMobile, args): return page, "Upload GCode", False, "medium", "content", "footerSubmit" elif pageID == "importGCini": url = "importFile" - page = render_template("importFile.html", url=url) + page = render_template("importFile.html", url=url, mimetypes=".ini") return page, "Import groundcontrol.ini", False, "medium", "content", False elif pageID == "importWCJSON": url = "importFileWCJSON" From 82e8d57b106f1ad64feef4f65e154137a2811bed Mon Sep 17 00:00:00 2001 From: gb0101010101 <7369439+gb0101010101@users.noreply.github.com> Date: Sun, 15 Mar 2020 20:42:19 -0700 Subject: [PATCH 06/17] logger.py -> deleteLogFiles() iterateates from 0 -> 1000 for no reason and does not delete existing log files. Add TODO comments to fix this later. --- DataStructures/logger.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DataStructures/logger.py b/DataStructures/logger.py index 32e7445f..190b069d 100644 --- a/DataStructures/logger.py +++ b/DataStructures/logger.py @@ -155,6 +155,7 @@ def deleteLogFiles(self): """ Delete log files """ + #TODO: This is wrong and executes file check on