def test_g28(self): # no parameters gcode = "G28" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G28") self.assertDictEqual({}, parsed.parameters) # all parameters, funky spaces gcode = "g 2 8 xy zw; some kind of comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G28") self.assertIsNone(parsed.parameters["X"]) self.assertIsNone(parsed.parameters["Y"]) self.assertIsNone(parsed.parameters["Z"]) self.assertIsNone(parsed.parameters["W"]) # all parameters, no spaces gcode = "g28wzxy; some kind of comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G28") self.assertIsNone(parsed.parameters["X"]) self.assertIsNone(parsed.parameters["Y"]) self.assertIsNone(parsed.parameters["Z"]) self.assertIsNone(parsed.parameters["W"]) # some parameters gcode = "g28 xy; some kind of comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G28") self.assertIsNone(parsed.parameters["X"]) self.assertIsNone(parsed.parameters["Y"]) self.assertNotIn("Z", parsed.parameters) self.assertNotIn("W", parsed.parameters)
def test_unknown_command(self): gcode = "G9999fdafdsafdafsd" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G9999") self.assertIsNone(parsed.parameters) gcode = "G9999" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G9999") self.assertIsNone(parsed.parameters)
def test_g21(self): # no parameters gcode = "G21" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G21") self.assertDictEqual({}, parsed.parameters) # with parameters (bogus) gcode = "G21X100fdafdsa; Here is a comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G21") self.assertDictEqual({}, parsed.parameters)
def test_IsAtCurrentPosition(self): # Received: x:119.91,y:113.34,z:2.1,e:0.0, Expected: # x:119.9145519,y:113.33847,z:2.1 # G1 X119.915 Y113.338 F7200 position = Position(self.Settings, self.OctoprintPrinterProfile, False) position.update(Commands.parse("M83")) position.update(Commands.parse("G90")) position.update(Commands.parse("G28")) position.update(Commands.parse("G1 X119.915 Y113.338 Z2.1 F7200")) self.assertTrue(position.is_at_current_position(119.91, 113.34, 2.1)) position.update(Commands.parse("g0 x120 y121 z2.1")) self.assertTrue(position.is_at_previous_position(119.91, 113.34, 2.1))
def test_reset(self): """Test init state.""" position = Position(self.Settings, self.OctoprintPrinterProfile, False) # reset all initialized vars to something else position.update(Commands.parse("G28")) position.update(Commands.parse("G0 X1 Y1 Z1")) # reset position = Position(self.Settings, self.OctoprintPrinterProfile, False) # test initial state self.assertEqual(len(position.Positions), 0) self.assertIsNone(position.SavedPosition)
def test_parameter_repetition(self): # test parameter repetition gcode = "g28 xxz" parsed = Commands.parse(gcode) self.assertIsNone(parsed.cmd) self.assertIsNotNone(parsed.error) self.assertNotEqual(len(parsed.error), 0) # test parameter repetition wrapped in comments gcode = "(comment in the front)g(comment in middle)2()8x(another comment in middle)x(comment between" \ " address and value)100()1 . 1(another); Here is a comment" parsed = Commands.parse(gcode) self.assertIsNone(parsed.cmd) self.assertIsNotNone(parsed.error) self.assertNotEqual(len(parsed.error), 0)
def test_m105(self): gcode = "m105;" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "M105") self.assertDictEqual(parsed.parameters, {}) gcode = "m105X1;" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "M105") self.assertDictEqual(parsed.parameters, {}) gcode = "m105fdsafdsafdsfsdfsd;" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "M105") self.assertDictEqual(parsed.parameters, {})
def test_multiple_signs_parameter(self): # test multiple signs in parameter 1 gcode = "(comment in the front)g(comment in middle)2()8(another comment in middle)x(comment between" \ " address and value)+100()1 . 1+(another); Here is a comment" parsed = Commands.parse(gcode) self.assertIsNone(parsed.cmd) self.assertIsNotNone(parsed.error) self.assertNotEqual(len(parsed.error), 0) # test multiple signs in parameter 2 gcode = "(comment in the front)g(comment in middle)2()8x(another comment in middle)x(comment between" \ " address and value)++100()1 . 1(another); Here is a comment" parsed = Commands.parse(gcode) self.assertIsNone(parsed.cmd) self.assertIsNotNone(parsed.error) self.assertNotEqual(len(parsed.error), 0)
def test_multiple_decimals_command(self): # test multiple decimal points in parameter 2 gcode = "G28.0." parsed = Commands.parse(gcode) self.assertIsNone(parsed.cmd) self.assertIsNotNone(parsed.error) self.assertNotEqual(len(parsed.error), 0)
def setUp(self): new_settings, defaults_loaded = OctolapseSettings.load( "C:\\Users\\Brad\\AppData\\Roaming\\OctoPrint\\data\\octolapse\\settings.json", "0.4.0rc1.dev0", "C:\\Users\\Brad\\AppData\\Roaming\\OctoPrint\\data\\octolapse\\", "settings.json") self.Commands = Commands() self.Settings = new_settings self.Printer = self.Settings.profiles.current_printer() self.Stabilization = self.Settings.profiles.current_stabilization() self.Printer.auto_detect_position = False # since we've set auto_detect_position to false, we need to set # an origin, else X,Y and Z will still be None after a home command self.Printer.home_x = 0 self.Printer.home_y = 0 self.Printer.home_z = 0 assert (isinstance(self.Printer, PrinterProfile)) self.Printer.slicer_type = SlicerSettings.SlicerTypeSlic3rPe slicer_settings = self.Printer.get_current_slicer_settings() assert (isinstance(slicer_settings, Slic3rPeSettings)) slicer_settings.retract_length = 0.8 slicer_settings.retract_speed = 2400 / 60 self.OctoprintPrinterProfile = self.create_octolapse_printer_profile()
def test_parse_int_negative(self): # test negative F error gcode = "G00 F- 1 09 " parsed = Commands.parse(gcode) self.assertIsNone(parsed.cmd) self.assertIsNotNone(parsed.error) self.assertNotEqual(len(parsed.error), 0)
def test_g0(self): # no parameters gcode = "g0" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G0") self.assertDictEqual({}, parsed.parameters) # no parameters, double 0 gcode = "g00" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G0") self.assertDictEqual({}, parsed.parameters) # all parameters with comment gcode = "g0 x100 y200.0 z3.0001 e1.1 f7200.000; Here is a comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G0") self.assertEqual(parsed.parameters["X"], 100) self.assertEqual(parsed.parameters["Y"], 200.0) self.assertEqual(parsed.parameters["Z"], 3.0001) self.assertEqual(parsed.parameters["E"], 1.1) self.assertEqual(parsed.parameters["F"], 7200.000) # all parameters, no spaces gcode = "g0x100y200.0z3.0001e1.1f7200.000" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G0") self.assertEqual(parsed.parameters["X"], 100) self.assertEqual(parsed.parameters["Y"], 200.0) self.assertEqual(parsed.parameters["Z"], 3.0001) self.assertEqual(parsed.parameters["E"], 1.1) self.assertEqual(parsed.parameters["F"], 7200.000) # all parameters, funky spaces gcode = "g 0 x 10 0 y2 00 .0z 3.0 001 e1. 1 f72 00 .000 " parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G0") self.assertEqual(parsed.parameters["X"], 100) self.assertEqual(parsed.parameters["Y"], 200.0) self.assertEqual(parsed.parameters["Z"], 3.0001) self.assertEqual(parsed.parameters["E"], 1.1) self.assertEqual(parsed.parameters["F"], 7200.000)
def test_g90_influences_extruder_UpdatePosition(self): """Test G90 for machines where it influences the coordinate system of the extruder.""" position = Position(self.Settings, self.OctoprintPrinterProfile, True) # Make sure the axis is homed position.update(Commands.parse("G28")) # set absolute mode with G90 position.update(Commands.parse("g90")) # update the position to 10 (absolute) position.update_position(e=10) self.assertEqual(position.e(), 10) # update the position to 10 again (absolute) to make sure we are in absolute # coordinates. position.update_position(e=10) self.assertEqual(position.e(), 10) # set relative mode with G90 position.update(Commands.parse("g91")) # update the position to 20 (relative) position.update_position(e=20) self.assertEqual(position.e(), 30)
def test_G92AbsoluteMovement(self): """Test the G92 command, move in absolute mode and test results.""" position = Position(self.Settings, self.OctoprintPrinterProfile, False) # set homed axis, absolute coordinates, and set position position.update(Commands.parse("G28")) position.update(Commands.parse("G90")) position.update(Commands.parse("G1 x100 y200 z150")) position.update(Commands.parse("G92 x10 y20 z30")) self.assertEqual(position.x(), 100) self.assertEqual(position.x_offset(), 90) self.assertEqual(position.y(), 200) self.assertEqual(position.y_offset(), 180) self.assertEqual(position.z(), 150) self.assertEqual(position.z_offset(), 120) # move to origin position.update(Commands.parse("G1 x-90 y-180 z-120")) self.assertEqual(position.x(), 0) self.assertEqual(position.x_offset(), 90) self.assertEqual(position.y(), 0) self.assertEqual(position.y_offset(), 180) self.assertEqual(position.z(), 0) self.assertEqual(position.z_offset(), 120) # move back position.update(Commands.parse("G1 x0 y0 z0")) self.assertEqual(position.x(), 90) self.assertEqual(position.x_offset(), 90) self.assertEqual(position.y(), 180) self.assertEqual(position.y_offset(), 180) self.assertEqual(position.z(), 120) self.assertEqual(position.z_offset(), 120)
def test_t(self): gcode = "T?" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "T") self.assertDictEqual(parsed.parameters, {"T": None}) gcode = " T? " parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "T") self.assertDictEqual(parsed.parameters, {"T": None}) gcode = " T ? " parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "T") self.assertDictEqual(parsed.parameters, {"T": None}) gcode = "T1;" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "T") self.assertDictEqual(parsed.parameters, {"T": 1}) gcode = "T 1 ;" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "T") self.assertDictEqual(parsed.parameters, {"T": 1}) gcode = "T 1.11 ;" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "T") self.assertDictEqual(parsed.parameters, {"T": 1})
def test_GetSnapshotGcode_Fixed_AbsoluteCoordintes_ExtruderRelative(self): """Test snapshot gcode in absolute coordinate system with relative extruder and fixed coordinate stabilization """ # adjust the settings for absolute position and create the snapshot gcode generator self.Settings.profiles.current_stabilization().x_type = "fixed_coordinate" self.Settings.profiles.current_stabilization().x_fixed_coordinate = 10 self.Settings.profiles.current_stabilization().y_type = "fixed_coordinate" self.Settings.profiles.current_stabilization().y_fixed_coordinate = 20 snapshot_gcode_generator = SnapshotGcodeGenerator( self.Settings, self.create_octoprint_printer_profile()) self.Extruder.is_retracted = lambda: True self.Position.update(Commands.parse("G90")) self.Position.update(Commands.parse("M83")) self.Position.update(Commands.parse("G28")) self.Position.update(Commands.parse("G0 X95 Y95 Z0.2 F3600")) parsed_command = Commands.parse("G0 X100 Y100") self.Position.update(parsed_command) snapshot_gcode = snapshot_gcode_generator.create_snapshot_gcode( self.Position, None, parsed_command) gcode_commands = snapshot_gcode.snapshot_gcode() # verify the created gcodegcode_commands self.assertEqual(gcode_commands[0], "G1 E-4.00000 F4800") self.assertEqual(gcode_commands[1], "G1 X10.000 Y20.000 F10800") self.assertEqual(gcode_commands[2], "G1 X100.000 Y100.000") self.assertEqual(gcode_commands[3], "G1 E4.00000 F3000") self.assertEqual(gcode_commands[4], "G1 F3600") self.assertEqual(gcode_commands[5], parsed_command.gcode) # verify the return coordinates self.assertEqual(snapshot_gcode.ReturnX, 100) self.assertEqual(snapshot_gcode.ReturnY, 100) self.assertEqual(snapshot_gcode.ReturnZ, 0.2) self.assertEqual(snapshot_gcode.X, 10) self.assertEqual(snapshot_gcode.Y, 20) self.assertEqual(snapshot_gcode.Z, None)
def test_G92SetPosition(self): """Test the G92 command, settings the position.""" position = Position(self.Settings, self.OctoprintPrinterProfile, False) # no homed axis position.update(Commands.parse("G92 x10 y20 z30")) self.assertEqual(position.x(), 10) self.assertEqual(position.y(), 20) self.assertEqual(position.z(), 30) self.assertFalse(position.has_homed_axes()) # set homed axis, absolute coordinates, and set position position.update(Commands.parse("G28")) position.update(Commands.parse("G90")) position.update(Commands.parse("G1 x100 y200 z150")) position.update(Commands.parse("G92 x10 y20 z30")) self.assertEqual(position.x(), 100) self.assertEqual(position.x_offset(), 90) self.assertEqual(position.y(), 200) self.assertEqual(position.y_offset(), 180) self.assertEqual(position.z(), 150) self.assertEqual(position.z_offset(), 120) # Move to same position and retest position.update(Commands.parse("G1 x0 y0 z0")) self.assertEqual(position.x(), 90) self.assertEqual(position.x_offset(), 90) self.assertEqual(position.y(), 180) self.assertEqual(position.y_offset(), 180) self.assertEqual(position.z(), 120) self.assertEqual(position.z_offset(), 120) # Move and retest position.update(Commands.parse("G1 x-10 y10 z20")) self.assertEqual(position.x(), 80) self.assertEqual(position.x_offset(), 90) self.assertEqual(position.y(), 190) self.assertEqual(position.y_offset(), 180) self.assertEqual(position.z(), 140) self.assertEqual(position.z_offset(), 120) # G92 with no parameters position.update(Commands.parse("G92")) self.assertEqual(position.x(), 80) self.assertEqual(position.x_offset(), 80) self.assertEqual(position.y(), 190) self.assertEqual(position.y_offset(), 190) self.assertEqual(position.z(), 140) self.assertEqual(position.z_offset(), 140)
def test_g1(self): # no parameters gcode = "g1" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G1") self.assertDictEqual({}, parsed.parameters) # no parameters, double 0 gcode = "g01" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G1") self.assertDictEqual({}, parsed.parameters) # all parameters with comment gcode = "g1 x100 y200.0 z3.0001 e1.1 f7200.000; Here is a comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G1") self.assertEqual(parsed.parameters["X"], 100) self.assertEqual(parsed.parameters["Y"], 200.0) self.assertEqual(parsed.parameters["Z"], 3.0001) self.assertEqual(parsed.parameters["E"], 1.1) self.assertEqual(parsed.parameters["F"], 7200.000) # all parameters, no spaces gcode = "g1x100y200.0z3.0001e1.1f7200.000" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G1") self.assertEqual(parsed.parameters["X"], 100) self.assertEqual(parsed.parameters["Y"], 200.0) self.assertEqual(parsed.parameters["Z"], 3.0001) self.assertEqual(parsed.parameters["E"], 1.1) self.assertEqual(parsed.parameters["F"], 7200.000) # all parameters, funky spaces gcode = "g 01 x 10 0 y2 00 .0z 3.0 001 e1. 1 f72 00 .000 " parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G1") self.assertEqual(parsed.parameters["X"], 100) self.assertEqual(parsed.parameters["Y"], 200.0) self.assertEqual(parsed.parameters["Z"], 3.0001) self.assertEqual(parsed.parameters["E"], 1.1) self.assertEqual(parsed.parameters["F"], 7200.000) # from issue 86 gcode = "G1 X -18 Y95 F1000" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G1") self.assertEqual(parsed.parameters["X"], -18) self.assertEqual(parsed.parameters["Y"], 95) self.assertNotIn("Z", parsed.parameters) self.assertNotIn("E", parsed.parameters) self.assertEqual(parsed.parameters["F"], 1000)
def test_G92RelativeMovement(self): """Test the G92 command, move in relative mode and test results.""" position = Position(self.Settings, self.OctoprintPrinterProfile, False) # set homed axis, relative coordinates, and set position position.update(Commands.parse("G28")) position.update(Commands.parse("G91")) position.update(Commands.parse("G1 x100 y200 z150")) position.update(Commands.parse("G92 x10 y20 z30")) self.assertEqual(position.x(), 100) self.assertEqual(position.x_offset(), 90) self.assertEqual(position.y(), 200) self.assertEqual(position.y_offset(), 180) self.assertEqual(position.z(), 150) self.assertEqual(position.z_offset(), 120) # move to origin position.update(Commands.parse("G1 x-100 y-200 z-150")) self.assertEqual(position.x(), 0) self.assertEqual(position.x_offset(), 90) self.assertEqual(position.y(), 0) self.assertEqual(position.y_offset(), 180) self.assertEqual(position.z(), 0) self.assertEqual(position.z_offset(), 120) # advance each axis position.update(Commands.parse("G1 x1 y2 z3")) self.assertEqual(position.x(), 1) self.assertEqual(position.x_offset(), 90) self.assertEqual(position.y(), 2) self.assertEqual(position.y_offset(), 180) self.assertEqual(position.z(), 3) self.assertEqual(position.z_offset(), 120) # advance again position.update(Commands.parse("G1 x1 y2 z3")) self.assertEqual(position.x(), 2) self.assertEqual(position.x_offset(), 90) self.assertEqual(position.y(), 4) self.assertEqual(position.y_offset(), 180) self.assertEqual(position.z(), 6) self.assertEqual(position.z_offset(), 120)
def test_UpdatePosition_force(self): """Test the UpdatePosition function with the force option set to true.""" position = Position(self.Settings, self.OctoprintPrinterProfile, False) position.update(Commands.parse("G28")) position.update_position(x=0, y=0, z=0, e=0, force=True) self.assertEqual(position.x(), 0) self.assertEqual(position.y(), 0) self.assertEqual(position.z(), 0) self.assertEqual(position.e(), 0) position.update_position(x=1, y=2, z=3, e=4, force=True) self.assertEqual(position.x(), 1) self.assertEqual(position.y(), 2) self.assertEqual(position.z(), 3) self.assertEqual(position.e(), 4) position.update_position(x=None, y=None, z=None, e=None, force=True) self.assertEqual(position.x(), 1) self.assertEqual(position.y(), 2) self.assertEqual(position.z(), 3) self.assertEqual(position.e(), 4)
def test_inline_comments(self): gcode = "g28(this is an inline commentx)yz; Here is a comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G28") self.assertFalse("X" in parsed.parameters) self.assertIsNone(parsed.parameters["Y"]) self.assertIsNone(parsed.parameters["Z"]) gcode = "g28(this is an inline commentx); Here is a comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G28") self.assertFalse("X" in parsed.parameters) self.assertFalse("Y" in parsed.parameters) self.assertFalse("Z" in parsed.parameters) gcode = "(comment in the front)g28; Here is a comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G28") self.assertFalse("X" in parsed.parameters) self.assertFalse("Y" in parsed.parameters) self.assertFalse("Z" in parsed.parameters) gcode = "(comment in the front)g28(comment in back); Here is a comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G28") self.assertFalse("X" in parsed.parameters) self.assertFalse("Y" in parsed.parameters) self.assertFalse("Z" in parsed.parameters) gcode = "(comment in the front)g(comment in middle)28(comment in back); Here is a comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G28") self.assertFalse("X" in parsed.parameters) self.assertFalse("Y" in parsed.parameters) self.assertFalse("Z" in parsed.parameters) gcode = "(comment in the front)g(comment in middle)2()8(another comment in middle)x(comment between" \ "address and value)100()1 . 1(another); Here is a comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G28") self.assertEqual(parsed.parameters["X"], 1001.1) self.assertFalse("Y" in parsed.parameters) self.assertFalse("Z" in parsed.parameters)
def take_snapshots(self, metadata={}, no_wait=False): logger.info("Starting snapshot acquisition") start_time = time() before_snapshot_threads = [] snapshot_threads = [] after_snapshot_threads = [] results = [] for current_camera in self.Cameras: camera_info = self.CameraInfos["{}".format(current_camera.guid)] # pre_snapshot threads if current_camera.on_before_snapshot_script: before_snapshot_job_info = SnapshotJobInfo( self.TimelapseJobInfo, self.temporary_directory, camera_info.snapshot_attempt, current_camera, 'before-snapshot', metadata=metadata) thread = ExternalScriptSnapshotJob(before_snapshot_job_info, 'before-snapshot') thread.daemon = True before_snapshot_threads.append(thread) snapshot_job_info = SnapshotJobInfo(self.TimelapseJobInfo, self.temporary_directory, camera_info.snapshot_attempt, current_camera, 'snapshot', metadata=metadata) if current_camera.camera_type == "script": thread = ExternalScriptSnapshotJob( snapshot_job_info, 'snapshot', on_new_thumbnail_available_callback=self. OnNewThumbnailAvailableCallback, on_post_processing_error_callback=self. on_post_processing_error_callback) thread.daemon = True snapshot_threads.append((thread, snapshot_job_info, None)) elif current_camera.camera_type == "webcam": download_started_event = Event() thread = WebcamSnapshotJob( snapshot_job_info, download_started_event=download_started_event, on_new_thumbnail_available_callback=self. OnNewThumbnailAvailableCallback, on_post_processing_error_callback=self. on_post_processing_error_callback) thread.daemon = True snapshot_threads.append( (thread, snapshot_job_info, download_started_event)) # post_snapshot threads if current_camera.on_after_snapshot_script: after_snapshot_job_info = SnapshotJobInfo( self.TimelapseJobInfo, self.temporary_directory, camera_info.snapshot_attempt, current_camera, 'after-snapshot', metadata=metadata) thread = ExternalScriptSnapshotJob(after_snapshot_job_info, 'after-snapshot') thread.daemon = True after_snapshot_threads.append(thread) # Now that the before snapshot threads are prepared, send any before snapshot gcodes for current_camera in self.Cameras: if current_camera.on_before_snapshot_gcode: on_before_snapshot_gcode = Commands.string_to_gcode_array( current_camera.on_before_snapshot_gcode) if len(on_before_snapshot_gcode) > 0: logger.info( "Sending on_before_snapshot_gcode for the %s camera.", current_camera.name) self.SendGcodeArrayCallback( on_before_snapshot_gcode, current_camera.timeout_ms / 1000.0, wait_for_completion=not no_wait, tags={'before-snapshot-gcode'}) if len(before_snapshot_threads) > 0: logger.info("Starting %d before snapshot threads", len(before_snapshot_threads)) # start the pre-snapshot threads for t in before_snapshot_threads: t.start() # join the pre-snapshot threads for t in before_snapshot_threads: if not no_wait: snapshot_job_info = t.join() assert (isinstance(snapshot_job_info, SnapshotJobInfo)) if t.snapshot_thread_error: snapshot_job_info.success = False snapshot_job_info.error = t.snapshot_thread_error else: snapshot_job_info.success = True else: snapshot_job_info.success = True results.append(snapshot_job_info) if len(before_snapshot_threads) > 0: logger.info("Before snapshot threads finished.") if len(snapshot_threads) > 0: logger.info("Starting %d snapshot threads.", len(snapshot_threads)) # start the snapshot threads, then wait for all threads to signal before continuing for t in snapshot_threads: t[0].start() # now send any gcode for gcode cameras for current_camera in self.Cameras: if current_camera.camera_type == "gcode": script_sent = False if current_camera.gcode_camera_script: gcode_camera_script = Commands.string_to_gcode_array( current_camera.gcode_camera_script) if len(gcode_camera_script) > 0: logger.info("Sending snapshot gcode array to %s.", current_camera.name) # just send the gcode now so it all goes in order self.SendGcodeArrayCallback( Commands.string_to_gcode_array( current_camera.gcode_camera_script), current_camera.timeout_ms / 1000.0, wait_for_completion=not no_wait) script_sent = True if not script_sent: logger.warning( "The gcode camera '%s' is enabled, but failed to produce any snapshot gcode.", current_camera.name) for t, snapshot_job_info, event in snapshot_threads: if not no_wait: if event: event.wait() else: snapshot_job_info = t.join() if t.snapshot_thread_error: snapshot_job_info.success = False snapshot_job_info.error = t.snapshot_thread_error elif t.post_processing_error: snapshot_job_info.success = False snapshot_job_info.error = t.post_processing_error else: snapshot_job_info.success = True else: snapshot_job_info.success = True info = self.CameraInfos[snapshot_job_info.camera_guid] info.snapshot_attempt += 1 if snapshot_job_info.success: info.snapshot_count += 1 self.SnapshotsTotal += 1 else: info.errors_count += 1 self.ErrorsTotal += 1 info.save(self.temporary_directory, self.TimelapseJobInfo.JobGuid, snapshot_job_info.camera_guid) results.append(snapshot_job_info) if len(snapshot_threads) > 0: logger.info( "Snapshot threads complete, but may be post-processing.") if len(after_snapshot_threads) > 0: logger.info("Starting %d after snapshot threads.", len(after_snapshot_threads)) # Now that the after snapshot threads are prepared, send any after snapshot gcodes for current_camera in self.Cameras: if current_camera.on_after_snapshot_gcode: on_after_snapshot_gcode = Commands.string_to_gcode_array( current_camera.on_after_snapshot_gcode) if len(on_after_snapshot_gcode) > 0: logger.info( "Sending on_after_snapshot_gcode for the %s camera.", current_camera.name) self.SendGcodeArrayCallback( on_after_snapshot_gcode, current_camera.timeout_ms / 1000.0, wait_for_completion=not no_wait, tags={'after-snapshot-gcode'}) # start the after-snapshot threads for t in after_snapshot_threads: t.start() # join the after-snapshot threads for t in after_snapshot_threads: if not no_wait: snapshot_job_info = t.join() assert (isinstance(snapshot_job_info, SnapshotJobInfo)) info = self.CameraInfos[snapshot_job_info.camera_guid] if t.snapshot_thread_error: snapshot_job_info.success = False snapshot_job_info.error = t.snapshot_thread_error else: snapshot_job_info.success = True else: snapshot_job_info.success = True results.append(snapshot_job_info) if len(after_snapshot_threads) > 0: logger.info("After snapshot threads complete.") logger.info("Snapshot acquisition completed in %.3f seconds.", time() - start_time) return results
def test_comments(self): """Try to parse the G0 Command, parsed.parameters and comment""" gcode = ";" parsed = Commands.parse(gcode) self.assertIsNone(parsed.cmd) self.assertIsNone(parsed.parameters) gcode = " ;" parsed = Commands.parse(gcode) self.assertIsNone(parsed.cmd) self.assertIsNone(parsed.parameters) gcode = "; " parsed = Commands.parse(gcode) self.assertIsNone(parsed.cmd) self.assertIsNone(parsed.parameters) gcode = "; " parsed = Commands.parse(gcode) self.assertIsNone(parsed.cmd) self.assertIsNone(parsed.parameters) gcode = "%" parsed = Commands.parse(gcode) self.assertIsNone(parsed.cmd) self.assertIsNone(parsed.parameters) gcode = "% " parsed = Commands.parse(gcode) self.assertIsNone(parsed.cmd) self.assertIsNone(parsed.parameters) gcode = "% " parsed = Commands.parse(gcode) self.assertIsNone(parsed.cmd) self.assertIsNone(parsed.parameters) gcode = " % this is a comment" parsed = Commands.parse(gcode) self.assertIsNone(parsed.cmd) self.assertIsNone(parsed.parameters) gcode = "g0 x100 y200.0 z3.0001 e1.1 f7200.000; Here is a comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G0") self.assertEqual(parsed.parameters["X"], 100) self.assertEqual(parsed.parameters["Y"], 200.0) self.assertEqual(parsed.parameters["Z"], 3.0001) self.assertEqual(parsed.parameters["E"], 1.1) self.assertEqual(parsed.parameters["F"], 7200.000) gcode = "g0x100y200.0z3.0001e1.1f7200.000; Here is a comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G0") self.assertEqual(parsed.parameters["X"], 100) self.assertEqual(parsed.parameters["Y"], 200.0) self.assertEqual(parsed.parameters["Z"], 3.0001) self.assertEqual(parsed.parameters["E"], 1.1) self.assertEqual(parsed.parameters["F"], 7200.000) # test signs 1 gcode = "g0x+100y-200.0z - 3.0001e +1.1f 7200.000; Here is a comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G0") self.assertEqual(parsed.parameters["X"], 100) self.assertEqual(parsed.parameters["Y"], -200.0) self.assertEqual(parsed.parameters["Z"], -3.0001) self.assertEqual(parsed.parameters["E"], 1.1) self.assertEqual(parsed.parameters["F"], 7200.000) # test signs 2 gcode = "g0x-100y + 200.0z+ 3.0001e -1.1f + 7200.000; Here is a comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G0") self.assertEqual(parsed.parameters["X"], -100) self.assertEqual(parsed.parameters["Y"], 200.0) self.assertEqual(parsed.parameters["Z"], 3.0001) self.assertEqual(parsed.parameters["E"], -1.1) self.assertEqual(parsed.parameters["F"], 7200.000) gcode = "g28xyz; Here is a comment" parsed = Commands.parse(gcode) self.assertEqual(parsed.cmd, "G28") self.assertIsNone(parsed.parameters["X"]) self.assertIsNone(parsed.parameters["Y"]) self.assertIsNone(parsed.parameters["Z"])
def test_UpdatePosition_noforce(self): """Test the UpdatePosition function with the force option set to true.""" position = Position(self.Settings, self.OctoprintPrinterProfile, False) # no homed axis position.update_position(x=0, y=0, z=0, e=0) self.assertIsNone(position.x()) self.assertIsNone(position.y()) self.assertIsNone(position.z()) self.assertIsNone(position.e(), 0) # set homed axis, test absolute position (default) position.update(Commands.parse("G28")) position.update_position(x=0, y=0, z=0) self.assertEqual(position.x(), 0) self.assertEqual(position.y(), 0) self.assertEqual(position.z(), 0) self.assertEqual(position.e(), 0) # update absolute position position.update_position(x=1, y=2, z=3) self.assertEqual(position.x(), 1) self.assertEqual(position.y(), 2) self.assertEqual(position.z(), 3) self.assertEqual(position.e(), 0) # set relative position position.update(Commands.parse("G91")) position.update_position(x=1, y=1, z=1) self.assertEqual(position.x(), 2) self.assertEqual(position.y(), 3) self.assertEqual(position.z(), 4) self.assertEqual(position.e(), 0) # set extruder absolute position.update(Commands.parse("M82")) position.update_position(e=100) self.assertEqual(position.x(), 2) self.assertEqual(position.y(), 3) self.assertEqual(position.z(), 4) self.assertEqual(position.e(), 100) position.update_position(e=-10) self.assertEqual(position.x(), 2) self.assertEqual(position.y(), 3) self.assertEqual(position.z(), 4) self.assertEqual(position.e(), -10) # set extruder relative position.update(Commands.parse("M83")) position.update_position(e=20) self.assertEqual(position.x(), 2) self.assertEqual(position.y(), 3) self.assertEqual(position.z(), 4) self.assertEqual(position.e(), 10) position.update_position(e=-1) self.assertEqual(position.x(), 2) self.assertEqual(position.y(), 3) self.assertEqual(position.z(), 4) self.assertEqual(position.e(), 9) position.update_position(x=1, y=2, z=3, e=4, force=True) self.assertEqual(position.x(), 1) self.assertEqual(position.y(), 2) self.assertEqual(position.z(), 3) self.assertEqual(position.e(), 4) position.update_position(x=None, y=None, z=None, e=None, force=True) self.assertEqual(position.x(), 1) self.assertEqual(position.y(), 2) self.assertEqual(position.z(), 3) self.assertEqual(position.e(), 4)
def test_HeightAndLayerChanges(self): """Test the height and layer changes.""" position = Position(self.Settings, self.OctoprintPrinterProfile, False) # test initial state self.assertIsNone(position.height()) self.assertIsNone(position.layer(), None) self.assertFalse(position.is_layer_change()) # check without homed axis position.update(Commands.parse("G1 x0 y0 z0.20000 e1")) self.assertEqual(position.height(), 0) self.assertEqual(position.layer(), 0) self.assertFalse(position.is_layer_change()) # set homed axis, absolute xyz coordinates, relative extruder coordinates and check height and layer position.update(Commands.parse("M83")) position.update(Commands.parse("G90")) position.update(Commands.parse("G28")) self.assertEqual(position.height(), 0) self.assertEqual(position.layer(), 0) self.assertFalse(position.is_layer_change()) # move without extruding, height and layer should not change position.update(Commands.parse("G1 x100 y200 z150")) self.assertEqual(position.height(), 0) self.assertEqual(position.layer(), 0) self.assertFalse(position.is_layer_change()) # move to origin, height and layer stuff should stay the same position.update(Commands.parse("G1 x0 y0 z0")) self.assertEqual(position.height(), 0) self.assertEqual(position.layer(), 0) self.assertFalse(position.is_layer_change()) # extrude, height change! position.update(Commands.parse("G1 x0 y0 z0 e1")) self.assertEqual(position.height(), 0) self.assertEqual(position.layer(), 1) self.assertTrue(position.is_layer_change()) # extrude higher, update layer., this will get rounded to 0.2 position.update(Commands.parse("G1 x0 y0 z0.1999 e1")) self.assertEqual(position.height(), 0.2) self.assertEqual(position.layer(), 2) self.assertTrue(position.is_layer_change()) # extrude just slightly higher, but with rounding on the same layer position.update(Commands.parse("G1 x0 y0 z0.20000 e1")) self.assertEqual(position.height(), .2) self.assertEqual(position.layer(), 2) self.assertFalse(position.is_layer_change()) # extrude again on same layer - Height Previous should now be updated, and # is_layer_change should be false position.update(Commands.parse("G1 x0 y0 z0.20000 e1")) self.assertEqual(position.height(), .2) self.assertEqual(position.layer(), 2) self.assertFalse(position.is_layer_change()) # extrude again on same layer - No changes position.update(Commands.parse("G1 x0 y0 z0.20000 e1")) self.assertEqual(position.height(), .2) self.assertEqual(position.layer(), 2) self.assertFalse(position.is_layer_change()) # extrude below the current layer - No changes position.update(Commands.parse("G1 x0 y0 z0.00000 e1")) self.assertEqual(position.height(), .2) self.assertEqual(position.layer(), 2) self.assertFalse(position.is_layer_change()) # extrude up higher and change the height/layer. Should never happen, but # it's an interesting test case position.update(Commands.parse("G1 x0 y0 z0.60000 e1")) self.assertEqual(position.height(), .6) self.assertEqual(position.layer(), 3) self.assertTrue(position.is_layer_change()) # extrude up again position.update(Commands.parse("G1 x0 y0 z0.65000 e1")) self.assertEqual(position.height(), .65) self.assertEqual(position.layer(), 4) self.assertTrue(position.is_layer_change()) # extrude on previous layer position.update(Commands.parse("G1 x0 y0 z0.60000 e1")) self.assertEqual(position.height(), .65) self.assertEqual(position.layer(), 4) self.assertFalse(position.is_layer_change()) # extrude on previous layer again position.update(Commands.parse("G1 x0 y0 z0.60000 e1")) self.assertEqual(position.height(), .65) self.assertEqual(position.layer(), 4) self.assertFalse(position.is_layer_change()) # move up but do not extrude position.update(Commands.parse("G1 x0 y0 z0.70000")) self.assertEqual(position.height(), .65) self.assertEqual(position.layer(), 4) self.assertFalse(position.is_layer_change()) # move up but do not extrude a second time position.update(Commands.parse("G1 x0 y0 z0.80000")) self.assertEqual(position.height(), .65) self.assertEqual(position.layer(), 4) self.assertFalse(position.is_layer_change()) # extrude at a different height position.update(Commands.parse("G1 x0 y0 z0.80000 e.1")) position.update(Commands.parse("G1 x0 y0 z0.85000 e.1")) self.assertEqual(.85, position.height()) self.assertEqual(6, position.layer()) self.assertTrue(position.is_layer_change())
def test_ExtruderMovement(self): """Test the M82 and M83 command.""" position = Position(self.Settings, self.OctoprintPrinterProfile, False) previous_pos = Pos(self.Settings.profiles.current_printer(), self.OctoprintPrinterProfile) # test initial position self.assertIsNone(position.e()) self.assertIsNone(position.is_extruder_relative()) self.assertIsNone(position.e_relative_pos(previous_pos)) # set extruder to relative coordinates position.update(Commands.parse("M83")) # test movement previous_pos = Pos(self.Settings.profiles.current_printer(), self.OctoprintPrinterProfile, position.get_position()) position.update(Commands.parse("G0 E100")) self.assertEqual(position.e(), 100) # this is somewhat reversed from what we do in the position.py module # there we update the pos() object and compare to the current state, so # comparing the current state to the # previous will result in the opposite sign self.assertEqual(position.e_relative_pos(previous_pos), -100) # switch to absolute movement previous_pos = Pos(self.Settings.profiles.current_printer(), self.OctoprintPrinterProfile, position.get_position()) position.update(Commands.parse("M82")) self.assertFalse(position.is_extruder_relative()) self.assertEqual(position.e(), 100) self.assertEqual(position.e_relative_pos(previous_pos), 0) # move to -25 previous_pos = Pos(self.Settings.profiles.current_printer(), self.OctoprintPrinterProfile, position.get_position()) position.update(Commands.parse("G0 E-25")) self.assertEqual(position.e(), -25) self.assertEqual(position.e_relative_pos(previous_pos), 125) # test movement to origin previous_pos = Pos(self.Settings.profiles.current_printer(), self.OctoprintPrinterProfile, position.get_position()) position.update(Commands.parse("G0 E0")) self.assertEqual(position.e(), 0) self.assertEqual(position.e_relative_pos(previous_pos), -25) # switch to relative position previous_pos = Pos(self.Settings.profiles.current_printer(), self.OctoprintPrinterProfile, position.get_position()) position.update(Commands.parse("M83")) position.update(Commands.parse("G0 e1.1")) self.assertEqual(position.e(), 1.1) self.assertEqual(position.e_relative_pos(previous_pos), -1.1) # move and test previous_pos = Pos(self.Settings.profiles.current_printer(), self.OctoprintPrinterProfile, position.get_position()) position.update(Commands.parse("G0 e1.1")) self.assertEqual(position.e(), 2.2) self.assertEqual(position.e_relative_pos(previous_pos), -1.1) # move and test previous_pos = Pos(self.Settings.profiles.current_printer(), self.OctoprintPrinterProfile, position.get_position()) position.update(Commands.parse("G0 e-2.2")) self.assertEqual(position.e(), 0) self.assertEqual(position.e_relative_pos(previous_pos), 2.2)
def test_zHop(self): """Test zHop detection.""" # set zhop distance self.Settings.profiles.current_printer().z_hop = .5 position = Position(self.Settings, self.OctoprintPrinterProfile, False) # test initial state self.assertFalse(position.is_zhop()) # check without homed axis position.update(Commands.parse("G1 x0 y0 z0")) self.assertFalse(position.is_zhop()) position.update(Commands.parse("G1 x0 y0 z0.5")) self.assertFalse(position.is_zhop()) # set relative extruder, absolute xyz, home axis, check again position.update(Commands.parse("M83")) position.update(Commands.parse("G90")) position.update(Commands.parse("G28")) self.assertFalse(position.is_zhop()) # Position reports as NotHomed (misnomer, need to replace), needs to get # coordinates position.update(Commands.parse("G1 x0 y0 z0")) # Move up without extrude, this is not a zhop since we haven't extruded # anything! position.update(Commands.parse("g0 z0.5")) self.assertFalse(position.is_zhop()) # move back down to 0 and extrude position.update(Commands.parse("g0 z0 e1")) self.assertFalse(position.is_zhop()) # Move up without extrude, this should trigger zhop start position.update(Commands.parse("g0 z0.5")) self.assertTrue(position.is_zhop()) # move below zhop threshold position.update(Commands.parse("g0 z0.3")) self.assertFalse(position.is_zhop()) # move right up to zhop without going over, we are within the rounding error position.update(Commands.parse("g0 z0.4999")) self.assertTrue(position.is_zhop()) # Extrude on z5 position.update(Commands.parse("g0 z0.5 e1")) self.assertFalse(position.is_zhop()) # partial z lift, , we are within the rounding error position.update(Commands.parse("g0 z0.9999")) self.assertTrue(position.is_zhop()) # Still hopped! position.update(Commands.parse("g0 z1")) self.assertTrue(position.is_zhop()) # test with extrusion start at 1.5 position.update(Commands.parse("g0 z1.5 e1")) self.assertFalse(position.is_zhop()) # test with extrusion at 2 position.update(Commands.parse("g0 z2 e1")) self.assertFalse(position.is_zhop()) # zhop position.update(Commands.parse("g0 z2.5 e0")) self.assertTrue(position.is_zhop()) position.update(Commands.parse("no-command")) self.assertTrue(position.is_zhop())
def test_unknown_word(self): gcode = "K100" parsed = Commands.parse(gcode) self.assertIsNone(parsed.cmd) self.assertIsNone(parsed.parameters)
def setUp(self): self.Commands = Commands() self.Comments = ""
def test_Update(self): """Test the Update() function, which accepts gcode and updates the current position state and extruder state.""" position = Position(self.Settings, self.OctoprintPrinterProfile, False) # no homed axis position.update(Commands.parse("G1 x100 y200 z300")) self.assertIsNone(position.x()) self.assertIsNone(position.y()) self.assertIsNone(position.z()) # set relative extruder and absolute xyz, home axis and update absolute position position.update(Commands.parse("M83")) position.update(Commands.parse("G90")) position.update(Commands.parse("G28")) position.update(Commands.parse("G1 x100 y200 z150")) self.assertEqual(position.x(), 100) self.assertEqual(position.y(), 200) self.assertEqual(position.z(), 150) # move again and retest position.update(Commands.parse("G1 x101 y199 z151")) self.assertEqual(position.x(), 101) self.assertEqual(position.y(), 199) self.assertEqual(position.z(), 151) # switch to relative and update position position.update(Commands.parse("G91")) position.update(Commands.parse("G1 x-1 y-1 z1.0")) self.assertEqual(position.x(), 100) self.assertEqual(position.y(), 198) self.assertEqual(position.z(), 152) # move again and retest position.update(Commands.parse("G1 x-99 y-196 z-149.0")) self.assertEqual(position.x(), 1) self.assertEqual(position.y(), 2) self.assertEqual(position.z(), 3) # go back to absolute and move to origin position.update(Commands.parse("G90")) position.update(Commands.parse("G1 x0 y0 z0.0")) self.assertEqual(position.x(), 0) self.assertEqual(position.y(), 0) self.assertEqual(position.z(), 0)