Beispiel #1
0
class Test_TimerTrigger(unittest.TestCase):
    def setUp(self):
        self.Settings = OctolapseSettings("c:\\test\\")
        self.OctoprintPrinterProfile = self.CreateOctoprintPrinterProfile()

    def tearDown(self):
        del self.Settings
        del self.OctoprintPrinterProfile

    def CreateOctoprintPrinterProfile(self):
        return dict(volume=dict(
            width=250,
            depth=200,
            height=200,
            formFactor="Not A Circle",
            custom_box=False,
        ))

    def test_TimerTrigger(self):
        """Test the timer trigger"""
        # use a short trigger time so that the test doesn't take too long
        self.Settings.CurrentSnapshot().timer_trigger_seconds = 2
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)
        trigger = TimerTrigger(self.Settings)
        trigger.ExtruderTriggers = ExtruderTriggers(None, None, None, None,
                                                    None, None, None, None,
                                                    None,
                                                    None)  #Ignore extruder
        trigger.RequireZHop = False  # no zhop required
        trigger.HeightIncrement = 0  # Trigger on any height change
        # test initial state
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == False)

        # set interval time to 0, send another command and test again (should not trigger, no homed axis)
        trigger.IntervalSeconds = 0
        position.Update("g0 x0 y0 z.2 e1")
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == False)

        # Home all axis and try again with interval seconds 1 - should not trigger since the timer will start after the home command
        trigger.IntervalSeconds = 2
        position.Update("g28")
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == False)

        # send another command and try again, should not trigger cause we haven't waited 2 seconds yet
        position.Update("g0 x0 y0 z.2 e1")
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == False)

        # Set the last trigger time to 1 before the previous LastTrigger time(equal to interval seconds), should not trigger
        trigger.TriggerStartTime = time.time() - 1.01
        position.Update("g0 x0 y0 z.2 e1")
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == False)

        # Set the last trigger time to 1 before the previous LastTrigger time(equal to interval seconds), should trigger
        trigger.TriggerStartTime = time.time() - 2.01
        position.Update("g0 x0 y0 z.2 e1")
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == True)
        self.assertTrue(trigger.IsWaiting == False)

    def test_TimerTrigger_ExtruderTriggers(self):
        """Test All Extruder Triggers"""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)
        # home the axis
        position.Update("G28")
        trigger = TimerTrigger(self.Settings)
        trigger.IntervalSeconds = 1
        trigger.RequireZHop = False  # no zhop required

        #Reset the extruder

        position.Extruder.Reset()
        position.Extruder.IsPrimed = False
        trigger.IsWaiting = True
        # Try on extruding start - previous position not homed, do not trigger
        trigger.ExtruderTriggers = ExtruderTriggers(True, None, None, None,
                                                    None, None, None, None,
                                                    None, None)
        position.Extruder.IsExtrudingStart = True
        trigger.TriggerStartTime = time.time() - 1.01
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == True)

        # send another command, now the previous state has been homed, should trigger
        position.Update("AnotherCommandNowPreviousHomed")
        position.Extruder.IsExtrudingStart = True  # set is extruding start, wont be set by the above command!
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == True)
        self.assertTrue(trigger.IsWaiting == False)
        #Reset the extruder
        position.Extruder.Reset()
        position.Extruder.IsPrimed = False
        trigger.IsWaiting = True
        # try out on extruding
        trigger.ExtruderTriggers = ExtruderTriggers(None, True, None, None,
                                                    None, None, None, None,
                                                    None, None)
        position.Extruder.IsExtruding = True
        trigger.TriggerStartTime = time.time() - 1.01
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == True)
        self.assertTrue(trigger.IsWaiting == False)

        #Reset the extruder
        position.Extruder.Reset()
        position.Extruder.IsPrimed = False
        trigger.IsWaiting = True
        # try out on primed
        trigger.ExtruderTriggers = ExtruderTriggers(None, None, True, None,
                                                    None, None, None, None,
                                                    None, None)
        position.Extruder.IsPrimed = True
        trigger.TriggerStartTime = time.time() - 1.01
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == True)
        self.assertTrue(trigger.IsWaiting == False)

        #Reset the extruder
        position.Extruder.Reset()
        position.Extruder.IsPrimed = False
        trigger.IsWaiting = True
        # try out on retracting start
        trigger.ExtruderTriggers = ExtruderTriggers(None, None, None, True,
                                                    None, None, None, None,
                                                    None, None)
        position.Extruder.IsRetractingStart = True
        trigger.TriggerStartTime = time.time() - 1.01
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == True)
        self.assertTrue(trigger.IsWaiting == False)

        #Reset the extruder
        position.Extruder.Reset()
        position.Extruder.IsPrimed = False
        trigger.IsWaiting = True
        # try out on retracting
        trigger.ExtruderTriggers = ExtruderTriggers(None, None, None, None,
                                                    True, None, None, None,
                                                    None, None)
        position.Extruder.IsRetracting = True
        trigger.TriggerStartTime = time.time() - 1.01
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == True)
        self.assertTrue(trigger.IsWaiting == False)

        #Reset the extruder
        position.Extruder.Reset()
        position.Extruder.IsPrimed = False
        trigger.IsWaiting = True
        # try out on partially retracted
        trigger.ExtruderTriggers = ExtruderTriggers(None, None, None, None,
                                                    None, True, None, None,
                                                    None, None)
        position.Extruder.IsPartiallyRetracted = True
        trigger.TriggerStartTime = time.time() - 1.01
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == True)
        self.assertTrue(trigger.IsWaiting == False)

        #Reset the extruder
        position.Extruder.Reset()
        position.Extruder.IsPrimed = False
        trigger.IsWaiting = True
        # try out on retracted
        trigger.ExtruderTriggers = ExtruderTriggers(None, None, None, None,
                                                    None, None, True, None,
                                                    None, None)
        position.Extruder.IsRetracted = True
        trigger.TriggerStartTime = time.time() - 1.01
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == True)
        self.assertTrue(trigger.IsWaiting == False)

        #Reset the extruder
        position.Extruder.Reset()
        position.Extruder.IsPrimed = False
        trigger.IsWaiting = True
        # try out on detracting Start
        trigger.ExtruderTriggers = ExtruderTriggers(None, None, None, None,
                                                    None, None, None, True,
                                                    None, None)
        position.Extruder.IsDetractingStart = True
        trigger.TriggerStartTime = time.time() - 1.01
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == True)
        self.assertTrue(trigger.IsWaiting == False)

        #Reset the extruder
        position.Extruder.Reset()
        position.Extruder.IsPrimed = False
        trigger.IsWaiting = True
        # try out on detracting Start
        trigger.ExtruderTriggers = ExtruderTriggers(None, None, None, None,
                                                    None, None, None, None,
                                                    True, None)
        position.Extruder.IsDetracting = True
        trigger.TriggerStartTime = time.time() - 1.01
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == True)
        self.assertTrue(trigger.IsWaiting == False)

        #Reset the extruder
        position.Extruder.Reset()
        position.Extruder.IsPrimed = False
        trigger.IsWaiting = True
        # try out on detracting Start
        trigger.ExtruderTriggers = ExtruderTriggers(None, None, None, None,
                                                    None, None, None, None,
                                                    None, True)
        position.Extruder.IsDetracted = True
        trigger.TriggerStartTime = time.time() - 1.01
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == True)
        self.assertTrue(trigger.IsWaiting == False)

    def test_TimerTrigger_ExtruderTriggerWait(self):
        """Test wait on extruder"""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)
        # home the axis
        position.Update("G28")
        trigger = TimerTrigger(self.Settings)
        trigger.RequireZHop = False  # no zhop required
        trigger.IntervalSeconds = 1

        #Reset the extruder

        position.Extruder.Reset()
        position.Extruder.IsPrimed = False
        trigger.IsWaiting = False
        # Use on extruding start for this test.
        trigger.ExtruderTriggers = ExtruderTriggers(True, None, None, None,
                                                    None, None, None, None,
                                                    None, None)
        position.Extruder.IsExtrudingStart = False
        trigger.TriggerStartTime = time.time() - 1.01
        # will not wait or trigger because the previous position state was not homed
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == False)

        # send another command and try again
        position.Update("PreviousPositionIsNowHomed")
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == True)

        # update again with no change
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == True)
        # set the trigger and try again
        position.Extruder.IsExtrudingStart = True
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == True)
        self.assertTrue(trigger.IsWaiting == False)

    def test_TimerTrigger_LayerChange_ZHop(self):
        """Test the layer trigger for layer changes triggers"""
        self.Settings.CurrentSnapshot().timer_trigger_require_zhop = True
        self.Settings.CurrentPrinter().z_hop = .5
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)
        trigger = TimerTrigger(self.Settings)
        trigger.ExtruderTriggers = ExtruderTriggers(None, None, None, None,
                                                    None, None, None, None,
                                                    None,
                                                    None)  #Ignore extruder
        trigger.IntervalSeconds = 1
        # test initial state
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == False)

        # send commands that normally would trigger a layer change, but without all axis homed.
        position.Update("g0 x0 y0 z.2 e1")
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == False)

        # Home all axis and try again, wait on zhop
        position.Update("g28")
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == False)
        position.Update("g0 x0 y0 z.2 e1")
        trigger.TriggerStartTime = time.time() - 1.01
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == True)

        # try zhop
        position.Update("g0 x0 y0 z.7 ")

        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == True)
        self.assertTrue(trigger.IsWaiting == False)

        # extrude on current layer, no trigger (wait on zhop)
        position.Update("g0 x0 y0 z.7 e1")
        trigger.TriggerStartTime = time.time() - 1.01
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == True)

        # do not extrude on current layer, still waiting
        position.Update("g0 x0 y0 z.7 ")
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == True)

        # partial hop, but close enough based on our printer measurement tolerance (0.005)
        position.Update("g0 x0 y0 z1.1999")
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == True)
        self.assertTrue(trigger.IsWaiting == False)

        # creat wait state
        position.Update("g0 x0 y0 z1.3 e1")
        trigger.TriggerStartTime = time.time() - 1.01
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == True)

        # move down (should never happen, should behave properly anyway)
        position.Update("g0 x0 y0 z.8")
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == True)

        # move back up to current layer (should NOT trigger zhop)
        position.Update("g0 x0 y0 z1.3")
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == True)

        # move up a bit, not enough to trigger zhop
        position.Update("g0 x0 y0 z1.79749")
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == False)
        self.assertTrue(trigger.IsWaiting == True)

        # move up a bit, just enough to trigger zhop
        position.Update("g0 x0 y0 z1.79751")
        trigger.Update(position)
        self.assertTrue(trigger.IsTriggered == True)
        self.assertTrue(trigger.IsWaiting == False)
Beispiel #2
0
class Test_Position(unittest.TestCase):
    def setUp(self):
        self.Commands = Commands()
        self.Settings = OctolapseSettings("c:\\temp\\octolapse.log")
        self.OctoprintPrinterProfile = self.CreateOctoprintPrinterProfile()

    def tearDown(self):
        del self.Commands
        del self.Settings

    def CreateOctoprintPrinterProfile(self):
        return {
            "volume": {
                "custom_box": False,
                "width": 250,
                "depth": 200,
                "height": 200
            }
        }

    def test_PositionError(self):
        """Test the IsInBounds function to make sure the program will not attempt to operate after being told to move out of bounds."""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)

        # Initial test, should return false without any coordinates
        self.assertTrue(not position.HasPositionError)
        self.assertTrue(position.PositionError is None)
        # home the axis and test
        position.Update("G28")
        self.assertTrue(not position.HasPositionError)
        self.assertTrue(position.PositionError is None)

        #X axis tests
        # reset, home the axis and test again
        position.Reset()
        position.Update("G28")
        self.assertTrue(not position.HasPositionError)
        self.assertTrue(position.PositionError is None)
        # move out of bounds min
        position.Update("G0 x-0.0001")
        self.assertTrue(position.HasPositionError)
        self.assertTrue(position.PositionError is not None)
        # move back in bounds
        position.Update("G0 x0.0")
        self.assertTrue(not position.HasPositionError)
        self.assertTrue(position.PositionError is None)
        # move to middle
        position.Update("G0 x125")
        self.assertTrue(not position.HasPositionError)
        self.assertTrue(position.PositionError is None)
        # move to max
        position.Update("G0 x250")
        self.assertTrue(not position.HasPositionError)
        self.assertTrue(position.PositionError is None)
        # move out of bounds max
        position.Update("G0 x250.0001")
        self.assertTrue(position.HasPositionError)
        self.assertTrue(position.PositionError is not None)

        #Y axis tests
        # reset, home the axis and test again
        position.Reset()
        position.Update("G28")
        self.assertTrue(not position.HasPositionError)
        self.assertTrue(position.PositionError is None)
        # move out of bounds min
        position.Update("G0 y-0.0001")
        self.assertTrue(position.HasPositionError)
        self.assertTrue(position.PositionError is not None)
        # move back in bounds
        position.Update("G0 y0.0")
        self.assertTrue(not position.HasPositionError)
        self.assertTrue(position.PositionError is None)
        # move to middle
        position.Update("G0 y100")
        self.assertTrue(not position.HasPositionError)
        self.assertTrue(position.PositionError is None)
        # move to max
        position.Update("G0 y200")
        self.assertTrue(not position.HasPositionError)
        self.assertTrue(position.PositionError is None)
        # move out of bounds max
        position.Update("G0 y200.0001")
        self.assertTrue(position.HasPositionError)
        self.assertTrue(position.PositionError is not None)

        #Z axis tests
        # reset, home the axis and test again
        position.Reset()
        position.Update("G28")
        self.assertTrue(not position.HasPositionError)
        self.assertTrue(position.PositionError is None)
        # move out of bounds min
        position.Update("G0 z-0.0001")
        self.assertTrue(position.HasPositionError)
        self.assertTrue(position.PositionError is not None)
        # move back in bounds
        position.Update("G0 z0.0")
        self.assertTrue(not position.HasPositionError)
        self.assertTrue(position.PositionError is None)
        # move to middle
        position.Update("G0 z100")
        self.assertTrue(not position.HasPositionError)
        self.assertTrue(position.PositionError is None)
        # move to max
        position.Update("G0 z200")
        self.assertTrue(not position.HasPositionError)
        self.assertTrue(position.PositionError is None)
        # move out of bounds max
        position.Update("G0 z200.0001")
        self.assertTrue(position.HasPositionError)
        self.assertTrue(position.PositionError is not None)

    def test_reset(self):
        """Test init state."""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)
        # reset all initialized vars to something else
        position.X = -1
        position.XOffset = -1
        position.XPrevious = -1
        position.Y = -1
        position.YOffset = -1
        position.YPrevious = -1
        position.Z = -1
        position.ZOffset = -1
        position.ZPrevious = -1
        position.E = -1
        position.EOffset = -1
        position.EPrevious = -1
        position.IsRelative = True
        position.IsExtruderRelative = False
        position.Height = -1
        position.HeightPrevious = -1
        position.ZDelta = -1
        position.ZDeltaPrevious = -1
        position.Layer = -1
        position.IsLayerChange = True
        position.IsZHop = True
        position.XHomed = True
        position.YHomed = True
        position.ZHomed = True
        position.HasPositionError = True
        position.IsZHop = True
        position.PositionError = "Error!"

        # reset
        position.Reset()

        # test initial state
        self.assertTrue(position.X is None)
        self.assertTrue(position.XOffset == 0)
        self.assertTrue(position.XPrevious is None)
        self.assertTrue(position.Y is None)
        self.assertTrue(position.YOffset == 0)
        self.assertTrue(position.YPrevious is None)
        self.assertTrue(position.Z is None)
        self.assertTrue(position.ZOffset == 0)
        self.assertTrue(position.ZPrevious is None)
        self.assertTrue(position.E == 0)
        self.assertTrue(position.EOffset == 0)
        self.assertTrue(position.EPrevious == 0)
        self.assertTrue(position.IsRelative == False)
        self.assertTrue(position.IsExtruderRelative)
        self.assertTrue(position.Height is None)
        self.assertTrue(position.HeightPrevious == 0)
        self.assertTrue(position.ZDelta is None)
        self.assertTrue(position.ZDeltaPrevious is None)
        self.assertTrue(position.Layer == 0)
        self.assertTrue(not position.IsLayerChange)
        self.assertTrue(not position.IsZHop)
        self.assertTrue(not position.XHomed)
        self.assertTrue(not position.YHomed)
        self.assertTrue(not position.ZHomed)
        self.assertTrue(not position.HasPositionError)
        self.assertTrue(not position.IsZHop)
        self.assertTrue(position.PositionError is None)

    def test_Home(self):
        """Test the home command.  Make sure the position is set to 0,0,0 after the home."""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)

        position.Update("G28")
        self.assertTrue(position.X == None)
        self.assertTrue(position.XHomed)
        self.assertTrue(position.Y == None)
        self.assertTrue(position.YHomed)
        self.assertTrue(position.ZHomed)
        self.assertTrue(position.Z == None)
        self.assertTrue(not position.HasHomedPosition())
        position.Reset()
        position.Update("G28 X")
        self.assertTrue(position.X == None)
        self.assertTrue(position.XHomed)
        self.assertTrue(position.Y is None)
        self.assertTrue(not position.YHomed)
        self.assertTrue(position.Z is None)
        self.assertTrue(not position.ZHomed)
        self.assertTrue(not position.HasHomedPosition())

        position.Reset()
        position.Update("G28 Y")
        self.assertTrue(position.X is None)
        self.assertTrue(not position.XHomed)
        self.assertTrue(position.Y is None)
        self.assertTrue(position.YHomed)
        self.assertTrue(position.Z is None)
        self.assertTrue(not position.ZHomed)
        self.assertTrue(not position.HasHomedPosition())

        position.Reset()
        position.Update("G28 Z")
        self.assertTrue(position.X is None)
        self.assertTrue(not position.XHomed)
        self.assertTrue(position.Y is None)
        self.assertTrue(not position.YHomed)
        self.assertTrue(position.Z is None)
        self.assertTrue(position.ZHomed)
        self.assertTrue(not position.HasHomedPosition())

        position.Reset()
        position.Update("G28 Z X Y")
        self.assertTrue(position.X is None)
        self.assertTrue(position.XHomed)
        self.assertTrue(position.Y is None)
        self.assertTrue(position.YHomed)
        self.assertTrue(position.Z is None)
        self.assertTrue(position.ZHomed)
        self.assertTrue(not position.HasHomedPosition())

        position.Reset()
        position.Update("G28 W")
        self.assertTrue(position.X is None)
        self.assertTrue(position.XHomed)
        self.assertTrue(position.Y is None)
        self.assertTrue(position.YHomed)
        self.assertTrue(position.Z is None)
        self.assertTrue(position.ZHomed)
        self.assertTrue(not position.HasHomedPosition())

        position.Reset()
        position.Update("g28")
        position.Update("g1 x0 y0 z0")
        # here we have seen the upded coordinates, but we do not know the position
        self.assertTrue(position.X == 0)
        self.assertTrue(position.XHomed)
        self.assertTrue(position.Y == 0)
        self.assertTrue(position.YHomed)
        self.assertTrue(position.Z == 0)
        self.assertTrue(position.ZHomed)
        self.assertTrue(not position.HasHomedPosition())
        # give it another position, now we have homed axis with a known position
        position.Update("g1 x0 y0 z0")
        self.assertTrue(position.X == 0)
        self.assertTrue(position.XHomed)
        self.assertTrue(position.Y == 0)
        self.assertTrue(position.YHomed)
        self.assertTrue(position.Z == 0)
        self.assertTrue(position.ZHomed)
        self.assertTrue(position.HasHomedPosition())

    def test_UpdatePosition_force(self):
        """Test the UpdatePosition function with the force option set to true."""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)
        position.UpdatePosition(x=0, y=0, z=0, e=0, force=True)

        self.assertTrue(position.X == 0)
        self.assertTrue(position.Y == 0)
        self.assertTrue(position.Z == 0)
        self.assertTrue(position.E == 0)

        position.UpdatePosition(x=1, y=2, z=3, e=4, force=True)
        self.assertTrue(position.X == 1)
        self.assertTrue(position.Y == 2)
        self.assertTrue(position.Z == 3)
        self.assertTrue(position.E == 4)

        position.UpdatePosition(x=None, y=None, z=None, e=None, force=True)
        self.assertTrue(position.X == 1)
        self.assertTrue(position.Y == 2)
        self.assertTrue(position.Z == 3)
        self.assertTrue(position.E == 4)

    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.UpdatePosition(x=0, y=0, z=0, e=0)
        self.assertTrue(position.X is None)
        self.assertTrue(position.Y is None)
        self.assertTrue(position.Z is None)
        self.assertTrue(position.E == 0)

        # set homed axis, test absolute position (default)
        position.XHomed = True
        position.YHomed = True
        position.ZHomed = True
        position.UpdatePosition(x=0, y=0, z=0)
        self.assertTrue(position.X == 0)
        self.assertTrue(position.Y == 0)
        self.assertTrue(position.Z == 0)
        self.assertTrue(position.E == 0)

        # update absolute position
        position.UpdatePosition(x=1, y=2, z=3)
        self.assertTrue(position.X == 1)
        self.assertTrue(position.Y == 2)
        self.assertTrue(position.Z == 3)
        self.assertTrue(position.E == 0)

        # set relative position
        position.IsRelative = True
        position.UpdatePosition(x=1, y=1, z=1)
        self.assertTrue(position.X == 2)
        self.assertTrue(position.Y == 3)
        self.assertTrue(position.Z == 4)
        self.assertTrue(position.E == 0)

        # set extruder absolute
        position.IsExtruderRelative = False
        position.UpdatePosition(e=100)
        self.assertTrue(position.X == 2)
        self.assertTrue(position.Y == 3)
        self.assertTrue(position.Z == 4)
        self.assertTrue(position.E == 100)
        position.UpdatePosition(e=-10)
        self.assertTrue(position.X == 2)
        self.assertTrue(position.Y == 3)
        self.assertTrue(position.Z == 4)
        self.assertTrue(position.E == -10)

        # set extruder relative
        position.IsExtruderRelative = True
        position.UpdatePosition(e=20)
        self.assertTrue(position.X == 2)
        self.assertTrue(position.Y == 3)
        self.assertTrue(position.Z == 4)
        self.assertTrue(position.E == 10)
        position.UpdatePosition(e=-1)
        self.assertTrue(position.X == 2)
        self.assertTrue(position.Y == 3)
        self.assertTrue(position.Z == 4)
        self.assertTrue(position.E == 9)

        position.UpdatePosition(x=1, y=2, z=3, e=4, force=True)
        self.assertTrue(position.X == 1)
        self.assertTrue(position.Y == 2)
        self.assertTrue(position.Z == 3)
        self.assertTrue(position.E == 4)

        position.UpdatePosition(x=None, y=None, z=None, e=None, force=True)
        self.assertTrue(position.X == 1)
        self.assertTrue(position.Y == 2)
        self.assertTrue(position.Z == 3)
        self.assertTrue(position.E == 4)

    def test_G90InfluencesExtruder_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.XHomed = True
        position.YHomed = True
        position.ZHomed = True
        # set absolute mode with G90
        position.Update("g90;")
        # update the position to 10 (absolute)
        position.UpdatePosition(e=10)
        self.assertTrue(position.E == 10)
        # update the position to 10 again (absolute) to make sure we are in absolute coordinates.
        position.UpdatePosition(e=10)
        self.assertTrue(position.E == 10)

        # set relative mode with G90
        position.Update("g91;")
        # update the position to 20 (relative)
        position.UpdatePosition(e=20)
        self.assertTrue(position.E == 30)

    def test_G90InfluencesExtruder_Update(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.XHomed = True
        position.YHomed = True
        position.ZHomed = True

        # set absolute mode with G90
        position.Update("g90;")
        # update the position to 10 (absolute)
        position.Update("G1 E10.0")
        self.assertTrue(position.E == 10)

        # update the position to 10 again (absolute) to make sure we are in absolute coordinates.
        position.Update("G1 E10.0")
        self.assertTrue(position.E == 10)

        # set relative mode with G90
        position.Update("g91;")
        # update the position to 20 (relative)
        position.Update("G1 E20.0")
        self.assertTrue(position.E == 30)

    def test_Update(self):
        """Test the UpdatePosition function with the force option set to true."""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)
        # no homed axis
        position.Update("G1 x100 y200 z300")
        self.assertTrue(position.X is None)
        self.assertTrue(position.Y is None)
        self.assertTrue(position.Z is None)

        # set homed axis and update absolute position
        position.Update("G28")
        position.Update("G1 x100 y200 z150")
        self.assertTrue(position.X == 100)
        self.assertTrue(position.Y == 200)
        self.assertTrue(position.Z == 150)

        # move again and retest
        position.Update("G1 x101 y199 z151")
        self.assertTrue(position.X == 101)
        self.assertTrue(position.Y == 199)
        self.assertTrue(position.Z == 151)

        # switch to relative and update position
        position.Update("G91")
        position.Update("G1 x-1 y-1 z1.0")
        self.assertTrue(position.X == 100)
        self.assertTrue(position.Y == 198)
        self.assertTrue(position.Z == 152)

        # move again and retest
        position.Update("G1 x-99 y-196 z-149.0")
        self.assertTrue(position.X == 1)
        self.assertTrue(position.Y == 2)
        self.assertTrue(position.Z == 3)

        # go back to absolute and move to origin
        position.Update("G90")
        position.Update("G1 x0 y0 z0.0")
        self.assertTrue(position.X == 0)
        self.assertTrue(position.Y == 0)
        self.assertTrue(position.Z == 0)

    #G92 Test Set Position
    def test_G92SetPosition(self):
        """Test the G92 command, settings the position."""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)
        # no homed axis
        position.Update("G92 x10 y20 z30")
        self.assertTrue(position.X is None)
        self.assertTrue(position.Y is None)
        self.assertTrue(position.Z is None)

        # set homed axis, absolute coordinates, and set position
        position.Update("G28")
        position.Update("G90")
        position.Update("G1 x100 y200 z150")
        position.Update("G92 x10 y20 z30")
        self.assertTrue(position.X == 100)
        self.assertTrue(position.XOffset == 90)
        self.assertTrue(position.Y == 200)
        self.assertTrue(position.YOffset == 180)
        self.assertTrue(position.Z == 150)
        self.assertTrue(position.ZOffset == 120)

        # Move to same position and retest
        position.Update("G1 x0 y0 z0")
        self.assertTrue(position.X == 90)
        self.assertTrue(position.XOffset == 90)
        self.assertTrue(position.Y == 180)
        self.assertTrue(position.YOffset == 180)
        self.assertTrue(position.Z == 120)
        self.assertTrue(position.ZOffset == 120)

        # Move and retest
        position.Update("G1 x-10 y10 z20")
        self.assertTrue(position.X == 80)
        self.assertTrue(position.XOffset == 90)
        self.assertTrue(position.Y == 190)
        self.assertTrue(position.YOffset == 180)
        self.assertTrue(position.Z == 140)
        self.assertTrue(position.ZOffset == 120)

        # G92 with no parameters
        position.Update("G92")
        self.assertTrue(position.X == 80)
        self.assertTrue(position.XOffset == 80)
        self.assertTrue(position.Y == 190)
        self.assertTrue(position.YOffset == 190)
        self.assertTrue(position.Z == 140)
        self.assertTrue(position.ZOffset == 140)

    #G92 Test Absolute Movement
    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("G28")
        position.Update("G90")
        position.Update("G1 x100 y200 z150")
        position.Update("G92 x10 y20 z30")
        self.assertTrue(position.X == 100)
        self.assertTrue(position.XOffset == 90)
        self.assertTrue(position.Y == 200)
        self.assertTrue(position.YOffset == 180)
        self.assertTrue(position.Z == 150)
        self.assertTrue(position.ZOffset == 120)

        # move to origin
        position.Update("G1 x-90 y-180 z-120")
        self.assertTrue(position.X == 0)
        self.assertTrue(position.XOffset == 90)
        self.assertTrue(position.Y == 0)
        self.assertTrue(position.YOffset == 180)
        self.assertTrue(position.Z == 0)
        self.assertTrue(position.ZOffset == 120)

        # move back
        position.Update("G1 x0 y0 z0")
        self.assertTrue(position.X == 90)
        self.assertTrue(position.XOffset == 90)
        self.assertTrue(position.Y == 180)
        self.assertTrue(position.YOffset == 180)
        self.assertTrue(position.Z == 120)
        self.assertTrue(position.ZOffset == 120)

    #G92 Test Relative Movement
    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("G28")
        position.Update("G91")
        position.Update("G1 x100 y200 z150")
        position.Update("G92 x10 y20 z30")
        self.assertTrue(position.X is None)
        self.assertTrue(position.XOffset == 90)
        self.assertTrue(position.Y == 200)
        self.assertTrue(position.YOffset == 180)
        self.assertTrue(position.Z == 150)
        self.assertTrue(position.ZOffset == 120)

        # move to origin
        position.Update("G1 x-100 y-200 z-150")
        self.assertTrue(position.X == 0)
        self.assertTrue(position.XOffset == 90)
        self.assertTrue(position.Y == 0)
        self.assertTrue(position.YOffset == 180)
        self.assertTrue(position.Z == 0)
        self.assertTrue(position.ZOffset == 120)

        # advance each axis
        position.Update("G1 x1 y2 z3")
        self.assertTrue(position.X == 1)
        self.assertTrue(position.XOffset == 90)
        self.assertTrue(position.Y == 2)
        self.assertTrue(position.YOffset == 180)
        self.assertTrue(position.Z == 3)
        self.assertTrue(position.ZOffset == 120)

        # advance again
        position.Update("G1 x1 y2 z3")
        self.assertTrue(position.X == 2)
        self.assertTrue(position.XOffset == 90)
        self.assertTrue(position.Y == 4)
        self.assertTrue(position.YOffset == 180)
        self.assertTrue(position.Z == 6)
        self.assertTrue(position.ZOffset == 120)

    def test_HeightAndLayerChanges(self):
        """Test the height and layer changes."""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)

        # test initial state
        self.assertTrue(position.Height is None)
        self.assertTrue(position.HeightPrevious == 0)
        self.assertTrue(position.Layer == 0)
        self.assertTrue(not position.IsLayerChange)

        # check without homed axis
        position.Update("G1 x0 y0 z0.20000 e1")
        self.assertTrue(position.Height is None)
        self.assertTrue(position.HeightPrevious is None)
        self.assertTrue(position.Layer == 0)
        self.assertTrue(not position.IsLayerChange)

        # set homed axis, absolute coordinates, and check height and layer
        position.Update("G28")
        self.assertTrue(position.Height is None)
        self.assertTrue(position.HeightPrevious is None)
        self.assertTrue(position.Layer == 0)
        self.assertTrue(not position.IsLayerChange)

        # move without extruding, height and layer should not change
        position.Update("G1 x100 y200 z150")
        self.assertTrue(position.Height is None)
        self.assertTrue(position.HeightPrevious is None)
        self.assertTrue(position.Layer == 0)
        self.assertTrue(not position.IsLayerChange)

        # move to origin, height and layer stuff should stay the same
        position.Update("G1 x0 y0 z0")
        self.assertTrue(position.Height is None)
        self.assertTrue(position.HeightPrevious is None)
        self.assertTrue(position.Layer == 0)
        self.assertTrue(not position.IsLayerChange)

        # extrude, height change!
        position.Update("G1 x0 y0 z0 e1")
        self.assertTrue(position.Height == 0)
        self.assertTrue(position.HeightPrevious == 0)
        self.assertTrue(position.Layer == 1)
        self.assertTrue(position.IsLayerChange)

        #extrude higher, update layer., this will get rounded to 0.2
        position.Update("G1 x0 y0 z0.1999 e1")
        self.assertTrue(position.Height == 0.2)
        self.assertTrue(position.HeightPrevious == 0)
        self.assertTrue(position.Layer == 2)
        self.assertTrue(position.IsLayerChange)

        # extrude just slightly higher, but with rounding on the same layer
        position.Update("G1 x0 y0 z0.20000 e1")
        self.assertTrue(position.Height == .2)
        self.assertTrue(position.HeightPrevious == 0.2)
        self.assertTrue(position.Layer == 2)
        self.assertTrue(not position.IsLayerChange)

        # extrude again on same layer - Height Previous should now be updated, and IsLayerChange should be false
        position.Update("G1 x0 y0 z0.20000 e1")
        self.assertTrue(position.Height == .2)
        self.assertTrue(position.HeightPrevious == .2)
        self.assertTrue(position.Layer == 2)
        self.assertTrue(not position.IsLayerChange)

        # extrude again on same layer - No changes
        position.Update("G1 x0 y0 z0.20000 e1")
        self.assertTrue(position.Height == .2)
        self.assertTrue(position.HeightPrevious == .2)
        self.assertTrue(position.Layer == 2)
        self.assertTrue(not position.IsLayerChange)

        # extrude below the current layer - No changes
        position.Update("G1 x0 y0 z0.00000 e1")
        self.assertTrue(position.Height == .2)
        self.assertTrue(position.HeightPrevious == .2)
        self.assertTrue(position.Layer == 2)
        self.assertTrue(not position.IsLayerChange)

        # extrude up higher and change the height/layer.  Should never happen, but it's an interesting test case
        position.Update("G1 x0 y0 z0.60000 e1")
        self.assertTrue(position.Height == .6)
        self.assertTrue(position.HeightPrevious == .2)
        self.assertTrue(position.Layer == 3)
        self.assertTrue(position.IsLayerChange)

        # extrude up again
        position.Update("G1 x0 y0 z0.65000 e1")
        self.assertTrue(position.Height == .65)
        self.assertTrue(position.HeightPrevious == .6)
        self.assertTrue(position.Layer == 4)
        self.assertTrue(position.IsLayerChange)

        # extrude on previous layer
        position.Update("G1 x0 y0 z0.60000 e1")
        self.assertTrue(position.Height == .65)
        self.assertTrue(position.HeightPrevious == .65)
        self.assertTrue(position.Layer == 4)
        self.assertTrue(not position.IsLayerChange)

        # extrude on previous layer again
        position.Update("G1 x0 y0 z0.60000 e1")
        self.assertTrue(position.Height == .65)
        self.assertTrue(position.HeightPrevious == .65)
        self.assertTrue(position.Layer == 4)
        self.assertTrue(not position.IsLayerChange)

        # move up but do not extrude
        position.Update("G1 x0 y0 z0.70000")
        self.assertTrue(position.Height == .65)
        self.assertTrue(position.HeightPrevious == .65)
        self.assertTrue(position.Layer == 4)
        self.assertTrue(not position.IsLayerChange)

        # move up but do not extrude a second time
        position.Update("G1 x0 y0 z0.80000")
        self.assertTrue(position.Height == .65)
        self.assertTrue(position.HeightPrevious == .65)
        self.assertTrue(position.Layer == 4)
        self.assertTrue(not position.IsLayerChange)

        # extrude at a different height
        position.Update("G1 x0 y0 z0.85000 e.001")
        self.assertTrue(position.Height == .85)
        self.assertTrue(position.HeightPrevious == .65)
        self.assertTrue(position.Layer == 5)
        self.assertTrue(position.IsLayerChange)

    #M82 and M83 - Test extruder movement
    def test_ExtruderMovement(self):
        """Test the M82 and M83 command."""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)

        # test initial position
        self.assertTrue(position.E == 0)
        self.assertTrue(position.IsExtruderRelative == True)
        self.assertTrue(position.ERelative() == 0)

        # test movement
        position.Update("G0 E100")
        self.assertTrue(position.E == 100)
        self.assertTrue(position.ERelative() == 100)

        # switch to absolute movement
        position.Update("M82")
        self.assertTrue(position.IsExtruderRelative == False)
        self.assertTrue(position.E == 100)
        self.assertTrue(position.ERelative() == 0)

        # move to -25
        position.Update("G0 E-25")
        self.assertTrue(position.E == -25)
        self.assertTrue(position.ERelative() == -125)

        # test movement to origin
        position.Update("G0 E0")
        self.assertTrue(position.E == 0)
        self.assertTrue(position.ERelative() == 25)

        # switch to relative position
        position.Update("M83")
        position.Update("G0 e1.1")
        self.assertTrue(position.E == 1.1)
        self.assertTrue(position.ERelative() == 1.1)

        # move and test
        position.Update("G0 e1.1")
        self.assertTrue(position.E == 2.2)
        self.assertTrue(position.ERelative() == 1.1)

        # move and test
        position.Update("G0 e-2.2")
        self.assertTrue(position.E == 0)
        self.assertTrue(position.ERelative() == -2.2)

    def test_zHop(self):
        """Test zHop detection."""
        # set zhop distance
        self.Settings.CurrentPrinter().z_hop = .5
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)

        # test initial state
        self.assertTrue(not position.IsZHop)

        # check without homed axis
        position.Update("G1 x0 y0 z0")
        self.assertTrue(not position.IsZHop)
        position.Update("G1 x0 y0 z0.5")
        self.assertTrue(not position.IsZHop)

        # Home axis, check again
        position.Update("G28")
        self.assertTrue(not position.IsZHop)
        # Position reports as NotHomed (misnomer, need to replace), needs to get coordinates
        position.Update("G1 x0 y0 z0")

        # Move up without extrude, this is not a zhop since we haven't extruded anything!
        position.Update("g0 z0.5")
        self.assertTrue(not position.IsZHop)
        # move back down to 0 and extrude
        position.Update("g0 z0 e1")
        self.assertTrue(not position.IsZHop)
        # Move up without extrude, this should trigger zhop start
        position.Update("g0 z0.5")
        self.assertTrue(position.IsZHop)
        # move below zhop threshold
        position.Update("g0 z0.3")
        self.assertTrue(position.IsZHop)

        # move right up to zhop without going over, we are within the rounding error
        position.Update("g0 z0.4999")
        self.assertTrue(position.IsZHop)

        # Extrude on z5
        position.Update("g0 z0.5 e1")
        self.assertTrue(position.IsZHop)

        # partial z lift, , we are within the rounding error
        position.Update("g0 z0.9999")
        self.assertTrue(position.IsZHop)
        # zhop to 1
        position.Update("g0 z1")
        self.assertTrue(position.IsZHop)
        # test with extrusion start at 1.5
        position.Update("g0 z1.5 e1")
        self.assertTrue(position.IsZHop)
        # test with extrusion at 2
        position.Update("g0 z2 e1")
        self.assertTrue(not position.IsZHop)

        #zhop
        position.Update("g0 z2.5 e0")
        self.assertTrue(position.IsZHop)

        # do not move extruder
        position.Update("no-command")
        self.assertTrue(position.IsZHop)

    # todo:  IsAtCurrent/PreviousPosition tests
    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.Printer.printer_position_confirmation_tolerance = .0051
        position.Update("g28")
        position.Update("G1 X119.915 Y113.338 Z2.1 F7200")
        self.assertTrue(position.IsAtCurrentPosition(119.91, 113.34, 2.1))
        position.Update("g0 x120 y121 z2.1")
        self.assertTrue(position.IsAtPreviousPosition(119.91, 113.34, 2.1))
Beispiel #3
0
class Test_LayerTrigger(unittest.TestCase):
	def setUp(self):
		self.Settings = OctolapseSettings("c:\\test\\")
		self.OctoprintPrinterProfile = self.CreateOctoprintPrinterProfile()
	def tearDown(self):
		del self.Settings
		del self.OctoprintPrinterProfile
	def CreateOctoprintPrinterProfile(self):
		return dict(
				volume = dict(
					width= 250,
					depth= 200,
					height= 200,
					formFactor="Not A Circle",
					custom_box=False,
				)
			)

	def TestReset(self):
		"""Test the reset function"""
		position = Position(self.Settings, self.OctoprintPrinterProfile, False)
		trigger = LayerTrigger(self.Settings)
		# test initial state
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
		# set the flags to different valuse
		trigger.IsTriggered = True
		trigger.IsWaiting = True
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
		
		# test the reset state
		trigger.Reset()
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
	def test_LayerTrigger_LayerChange(self):
		"""Test the layer trigger for layer changes triggers"""

		position = Position(self.Settings, self.OctoprintPrinterProfile, False)
		trigger = LayerTrigger(self.Settings)
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,None,None,None,None,None,None,None,None) #Ignore extruder
		trigger.RequireZHop = False # no zhop required
		trigger.HeightIncrement = 0 # Trigger on any height change
		# test initial state
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# send commands that normally would trigger a layer change, but without all axis homed.
		position.Update("g0 x0 y0 z.2 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# Home all axis and try again
		position.Update("g28")
		trigger.Update(position)
		position.Update("g0 x0 y0 z.2 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)

		# extrude again on the same layer and make sure it does NOT trigger
		position.Update("g0 x1 y1 z.2 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# move to higher layer, but do not extrude (no layer change)
		position.Update("g0 x1 y1 z.4")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
		position.Update("g0 x2 y2 z.4")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# return to previous layer, do not extrude
		position.Update("g0 x2 y2 z.2")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
		position.Update("g0 x4 y4 z.2")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# extrude again on current layer
		position.Update("g0 x2 y2 z.2 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		#move up two times, down and extrude (this should trigger after the final command
		position.Update("g0 x2 y2 z.4")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
		position.Update("g0 x2 y2 z.6")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
		position.Update("g0 x2 y2 z.4 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)

		# This should never happen in a print, but test extruding on previous layers
		# move down to previous layer, extrude,
		position.Update("g0 x2 y2 z.2 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
		# move back to current layer (.4), extrude (no trigger)
		position.Update("g0 x2 y2 z.4 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
		# move up one more layer and extrude (trigger)
		position.Update("g0 x2 y2 z.6 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)
	def test_LayerTrigger_LayerChange_DefaultExtruderTriggers(self):
		position = Position(self.Settings, self.OctoprintPrinterProfile, False)
		currentSnapshot = self.Settings.CurrentSnapshot()
		trigger = LayerTrigger(self.Settings)
		trigger.ExtruderTriggers = ExtruderTriggers(False, True, True, False, None, None, True, True, None, False) 
		trigger.RequireZHop = False # no zhop required
		trigger.HeightIncrement = 0 # Trigger on any height change
		#create some gcode
		gcode = []
		# get the startup gcode
		gcode.extend(self.GetPrintStartGcode())
		# start layer 1
		gcode.append(('G1 Z0.250 F7200.000',False,""))
		# start priming extruder
		gcode.append(('G1 X50.0 E80.0  F1000.0',False,"ExtrudingStart")) # forbidden
		gcode.append(('G1 X160.0 E20.0  F1000.0',True,"Extruding"))
		gcode.append(('G1 Z0.200 F7200.000',False,"Extruding"))
		gcode.append(('G1 X220.0 E13 F1000.0',False,"Extruding"))
		gcode.append(('G1 X240.0 E0 F1000.0',False,"Extruding"))
		# Object print is starting
		gcode.append(('G1 E-4.00000 F3000.00000',False,"On Retracting, OnRetractingStart"))
		gcode.append(('G1 Z0.700 F7200.000',False,"FullyRetracted, Zhop"))
		gcode.append(('G1 X117.061 Y98.921 F7200.000',False,"FullyRetracted, Zhop"))
		gcode.append(('G1 Z0.200 F7200.000',False,"FullyRetracted"))
		gcode.append(('G1 E4.00000 F3000.00000',False,"DetractingStart, Detracted"))
		gcode.append(('M204 S1000',False,"Primed"))
		gcode.append(('G1 F1800',False,"Primed"))
		# start extruding
		gcode.append(('G1 X117.508 Y98.104 E0.02922',False,"ExtrudingStart")) # forbidden
		gcode.append(('G1 X117.947 Y97.636 E0.02011',False,"Extruding"))
		gcode.append(('G1 X118.472 Y97.267 E0.02011',False,"Extruding"))
		gcode.append(('G1 X119.061 Y97.013 E0.02011',False,"Extruding"))
		gcode.append(('G1 X119.690 Y96.884 E0.02011',False,"Extruding"))
		gcode.append(('G1 X130.004 Y96.869 E0.32341',False,"Extruding"))
		gcode.append(('G1 X131.079 Y97.061 E0.03423',False,"Extruding"))
		#Retraction
		gcode.append(('G1 E-2.40000 F3000.00000',False,"RetractingStart, Retracting, PartiallyRetracted"))
		gcode.append(('G1 F5760',False,"Retracting, PartiallyRetracted"))
		gcode.append(('G1 X119.824 Y97.629 E-0.50464',False,"Retracting, PartiallyRetracted"))
		gcode.append(('G1 F5760',False,"Retracting, PartiallyRetracted"))
		gcode.append(('G1 X121.876 Y97.628 E-1.01536',False,"Retracting, PartiallyRetracted"))
		gcode.append(('G1 E-0.08000 F3000.00000',False,"Retracting, Fully Retracted"))
		# Retracted, Zhop
		gcode.append(('G1 Z0.700 F7200.000',False,"FullyRetracted, Zhop"))
		# Moved while lifted
		gcode.append(('G1 X120.587 Y100.587 F7200.000',False,"FullyRetracted, Zhop"))
		gcode.append(('G1 Z0.200 F7200.000',False,"FullyRetracted"))
		# Zhop complete
		gcode.append(('G1 E4.00000 F3000.00000',False,"DetractingStart, Detracted"))
		#Retraction Complete
		gcode.append(('G1 F1800',False,"Primed"))# primed
		gcode.append(('G1 X129.413 Y100.587 E0.27673',False,"ExtrudingStart"))
		gcode.append(('G1 X129.413 Y109.413 E0.27673',False,"Extruding"))
		gcode.append(('G1 X120.587 Y109.413 E0.27673',False,"Extruding"))
		gcode.append(('G1 X120.587 Y100.647 E0.27485',False,"Extruding"))
		gcode.append(('G1 X120.210 Y100.210 F7200.000',False,"Extruding"))

		# layer 2
		# after layer change
		# retract
		gcode.append(('G1 E-4.00000 F3000.00000',False,"RetractingStart"))
		# zhop
		gcode.append(('G1 Z0.900 F7200.000',False,"FullyRetracted, Zhop"))
		# move while lifted
		gcode.append(('G1 X133.089 Y99.490 F7200.000',False,"FullyRetracted, Zhop"))
		# end zhop
		gcode.append(('G1 Z0.400 F7200.000',False,"FullyRetracted"))
		# detract
		gcode.append(('G1 E4.00000 F3000.00000',False,"DetractingStart"))
		gcode.append(('G1 F3000',False,"Detracted, Primed"))
		# start etruding
		gcode.append(('G1 X133.128 Y110.149 E0.33418',False,"ExtrudingStart"))
		gcode.append(('G1 X132.942 Y111.071 E0.02950',True,"Extruding"))
		gcode.append(('G1 X132.492 Y111.896 E0.02950',False,"Extruding"))
		gcode.append(('G1 X132.020 Y112.393 E0.02148',False,"Extruding"))
		gcode.append(('G1 X131.447 Y112.777 E0.02161',False,"Extruding"))

		# layer 3
		gcode.append(('G1 Z2.600 F7200.000',False,"Primed"))
		gcode.append(('G1 X120.632 Y100.632 F7200.000',False,"Primed"))
		gcode.append(('M204 S800',False,"Primed"))
		gcode.append(('G1 F1200',False,"Primed"))
		gcode.append(('G1 X129.368 Y100.632 E0.29570',False,"ExtrudingStart"))
		gcode.append(('G1 X129.368 Y109.368 E0.29570',True,"Extruding"))
		gcode.append(('G1 X120.632 Y109.368 E0.29570',False,"Extruding"))
		gcode.append(('G1 X120.632 Y100.692 E0.29367',False,"Extruding"))
		gcode.append(('M204 S1000',False,"Primed"))
		gcode.append(('G1 X120.225 Y100.225 F7200.000',False,"Extruding"))
		gcode.append(('M204 S800',False,"Primed"))
		gcode.append(('G1 F1200',False,"Extruding"))
		gcode.append(('G1 X129.775 Y100.225 E0.32326',False,"Extruding"))

		# layer 4
		gcode.append(('G1 Z2.800 F7200.000',False,"Primed"))
		gcode.append(('G1 X120.632 Y109.368 F7200.000',False,"Primed"))
		gcode.append(('M204 S800',False,"Primed"))
		gcode.append(('G1 F1200',False,"Primed"))
		gcode.append(('G1 X120.632 Y100.632 E0.29570',False,"ExtrudingStart"))
		gcode.append(('G1 X129.368 Y100.632 E0.29570',True,"Extruding"))
		gcode.append(('G1 X129.368 Y109.368 E0.29570',False,"Extruding"))
		gcode.append(('G1 X120.692 Y109.368 E0.29367',False,"Extruding"))
		gcode.append(('M204 S1000',False,"Primed"))
		gcode.append(('G1 X120.225 Y109.775 F7200.000',False,""))
		gcode.append(('M204 S800',False,"Primed"))
		gcode.append(('G1 F1200',False,"Primed"))
		gcode.append(('G1 X120.225 Y100.225 E0.32326',False,"ExtrudingStart"))
		gcode.append(('G1 X129.775 Y100.225 E0.32326',False,"Extruding"))
		gcode.append(('G1 X129.775 Y109.775 E0.32326',False,"Extruding"))
		gcode.append(('G1 X120.285 Y109.775 E0.32123',False,"Extruding"))

		# loop through all of the Gcode and test triggering
		for command in gcode:
			gcodeCommand = command[0]
			shouldTrigger = command[1]
			comment = command[2]
			position.Update(gcodeCommand)
			trigger.Update(position)
			self.assertTrue(trigger.IsTriggered == shouldTrigger,"Should have triggered on {0} command.  Command comment:".format(gcodeCommand,comment))

	def GetPrintStartGcode(self):
		# create gcode list
		gcode = []
		# Print Start Code
		gcode.append(('T0',False,"select tool 0"))
		gcode.append(('M104 S255',False,"set extruder temp"))
		gcode.append(('M140 S100',False,"set bed temp"))
		gcode.append(('M190 S100',False,"wait for bed temp"))
		gcode.append(('M109 S255',False,"wait for extruder temp"))
		gcode.append(('G21',False,"set units to millimeters"))
		gcode.append(('G90',False,"use absolute coordinates"))
		gcode.append(('M83',False,"use relative distances for extrusion"))
		gcode.append(('G28 W',False,""))
		gcode.append(('G80',False,""))
		gcode.append(('G92 E0.0',False,""))
		gcode.append(('M203 E100',False,""))
		gcode.append(('M92 E140',False,""))
		gcode.append(('G92 E0.0',False,""))
		gcode.append(('M900 K200',False,""))

		return gcode

	def test_LayerTrigger_HeightChange(self):
		"""Test the layer trigger height change """

		position = Position(self.Settings, self.OctoprintPrinterProfile, False)
		trigger = LayerTrigger(self.Settings)
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,None,None,None,None,None,None,None,None) #Ignore extruder
		trigger.RequireZHop = False # no zhop required
		trigger.HeightIncrement = .25 # Trigger every .25

		# test initial state
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# send commands that normally would trigger a layer change, but without all axis homed.
		position.Update("g0 x0 y0 z.2 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# cur increment 0.25
		# Home all axis and try again, under layer height
		position.Update("g28")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		position.Update("g0 x0 y0 z.2 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)

		# cur increment 0.25
		# extrude again on the same layer and make sure it does NOT trigger
		position.Update("g0 x1 y1 z.2 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# cur increment 0.25
		# move to higher layer, but do not extrude (no layer change)
		position.Update("g0 x1 y1 z.4")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
		position.Update("g0 x2 y2 z.4")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# cur increment 0.25
		# return to previous layer, do not extrude
		position.Update("g0 x2 y2 z.2")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
		position.Update("g0 x4 y4 z.2")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# cur increment 0.25
		# extrude again on current layer
		position.Update("g0 x2 y2 z.2 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# cur increment 0.25
		#move up two times, down and extrude (this should trigger after the final command
		position.Update("g0 x2 y2 z.4")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
		position.Update("g0 x2 y2 z.6")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
		position.Update("g0 x2 y2 z.4 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)

		# cur increment 0.5
		# This should never happen in a print, but test extruding on previous layers
		# move down to previous layer, extrude,
		position.Update("g0 x2 y2 z.2 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
		# move back to current layer (.4), extrude (no trigger)
		position.Update("g0 x2 y2 z.4 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
		# move up one more layer and extrude (trigger)
		position.Update("g0 x2 y2 z.6 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)

		# test very close to height increment (.75)
		# move up one more layer and extrude (trigger)
		position.Update("g0 x2 y2 z0.7499 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# Test at the increment (.75)
		position.Update("g0 x2 y2 z0.7500 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)
	def test_LayerTrigger_ExtruderTriggers_NotHomed(self):
		"""Make sure nothing triggers when the axis aren't homed"""
		position = Position(self.Settings, self.OctoprintPrinterProfile, False)
		trigger = LayerTrigger(self.Settings)
		trigger.RequireZHop = False # no zhop required
		trigger.HeightIncrement = 0 # Trigger on every layer change
		position.Extruder.PrinterRetractionLength = 4

		# Try on extruding start
		trigger.ExtruderTriggers = ExtruderTriggers(True,None,None,None,None,None,None,None,None,None) 
		position.Update("g0 x0 y0 z.2 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# try out on extruding
		trigger.ExtruderTriggers = ExtruderTriggers(None,True,None,None,None,None,None,None,None,None)
		position.Update("g0 x0 y0 z.3 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# try out on primed
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,True,None,None,None,None,None,None,None)
		position.Update("g0 x0 y0 z.4 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# try out on retracting start
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,None,True,None,None,None,None,None,None)
		position.Update("g0 x0 y0 z.5 e-1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# try out on retracting
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,None,None,True,None,None,None,None,None)
		position.Update("g0 x0 y0 z.5 e-1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# try out on partially retracted
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,None,None,None,True,None,None,None,None)
		position.Update("g0 x0 y0 z.5 e-1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# try out on retracted
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,None,None,None,None,True,None,None,None)
		position.Update("g0 x0 y0 z.5 e-1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# try out on detracting
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,None,None,None,None,True,None,None,None)
		position.Update("g0 x0 y0 z.5 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)
	def test_LayerTrigger_ExtruderTriggers(self):
		"""Test All Extruder Triggers"""
		position = Position(self.Settings, self.OctoprintPrinterProfile, False)
		# home the axis
		position.Update("G28")
		trigger = LayerTrigger(self.Settings)
		trigger.RequireZHop = False # no zhop required
		trigger.HeightIncrement = 0 # Trigger on every layer change

		#Reset the extruder
		
		position.Extruder.Reset()
		position.Extruder.IsPrimed = False
		trigger.IsWaiting = True
		# Try on extruding start right after home, should fail
		trigger.ExtruderTriggers = ExtruderTriggers(True,None,None,None,None,None,None,None,None,None)
		position.Extruder.IsExtrudingStart = True
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == True)

		# Try again, should trigger because the previous state was homed
		position.Update("m114");
		position.Extruder.IsExtrudingStart = True
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)


		#Reset the extruder
		position.Extruder.Reset()
		position.Extruder.IsPrimed = False
		trigger.IsWaiting = True
		# try out on extruding
		trigger.ExtruderTriggers = ExtruderTriggers(None,True,None,None,None,None,None,None,None,None)
		position.Extruder.IsExtruding = True
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)

		#Reset the extruder
		position.Extruder.Reset()
		position.Extruder.IsPrimed = False
		trigger.IsWaiting = True
		# try out on primed
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,True,None,None,None,None,None,None,None)
		position.Extruder.IsPrimed = True
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)

		#Reset the extruder
		position.Extruder.Reset()
		position.Extruder.IsPrimed = False
		trigger.IsWaiting = True
		# try out on retracting start
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,None,True,None,None,None,None,None,None)
		position.Extruder.IsRetractingStart = True
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)

		#Reset the extruder
		position.Extruder.Reset()
		position.Extruder.IsPrimed = False
		trigger.IsWaiting = True
		# try out on retracting
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,None,None,True,None,None,None,None,None)
		position.Extruder.IsRetracting = True
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)

		#Reset the extruder
		position.Extruder.Reset()
		position.Extruder.IsPrimed = False
		trigger.IsWaiting = True
		# try out on partially retracted
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,None,None,None,True,None,None,None,None)
		position.Extruder.IsPartiallyRetracted = True
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)

		#Reset the extruder
		position.Extruder.Reset()
		position.Extruder.IsPrimed = False
		trigger.IsWaiting = True
		# try out on retracted
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,None,None,None,None,True,None,None,None)
		position.Extruder.IsRetracted = True
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)

		#Reset the extruder
		position.Extruder.Reset()
		position.Extruder.IsPrimed = False
		trigger.IsWaiting = True
		# try out on detracting Start
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,None,None,None,None,None,True,None,None)
		position.Extruder.IsDetractingStart = True
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)

		#Reset the extruder
		position.Extruder.Reset()
		position.Extruder.IsPrimed = False
		trigger.IsWaiting = True
		# try out on detracting Start
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,None,None,None,None,None,None,True,None)
		position.Extruder.IsDetracting = True
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)

		#Reset the extruder
		position.Extruder.Reset()
		position.Extruder.IsPrimed = False
		trigger.IsWaiting = True
		# try out on detracting Start
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,None,None,None,None,None,None,None,True)
		position.Extruder.IsDetracted = True
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)
	def test_LayerTrigger_ExtruderTriggerWait(self):
		"""Test wait on extruder"""
		position = Position(self.Settings, self.OctoprintPrinterProfile, False)
		# home the axis and send another command to make sure the previous instruction was homed
		position.Update("G28")
		position.Update("PreviousHomed")
		trigger = LayerTrigger(self.Settings)
		trigger.RequireZHop = False # no zhop required
		trigger.HeightIncrement = 0 # Trigger on every layer change

		#Reset the extruder
		
		position.Extruder.Reset()
		position.Extruder.IsPrimed = False
		trigger.IsWaiting = False
		# Use on extruding start for this test.  
		trigger.ExtruderTriggers = ExtruderTriggers(True,None,None,None,None,None,None,None,None,None)
		position.Extruder.IsExtrudingStart = False
		position.IsLayerChange = True
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == True)

		# update again with no change
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == True)
		# set the trigger and try again
		position.Extruder.IsExtrudingStart = True
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)
	def test_LayerTrigger_LayerChange_ZHop(self):
		"""Test the layer trigger for layer changes triggers"""
		self.Settings.CurrentSnapshot().layer_trigger_require_zhop = True
		self.Settings.CurrentPrinter().z_hop = .5
		position = Position(self.Settings, self.OctoprintPrinterProfile, False)
		trigger = LayerTrigger(self.Settings)
		trigger.ExtruderTriggers = ExtruderTriggers(None,None,None,None,None,None,None,None,None,None) #Ignore extruder
		trigger.HeightIncrement = 0 # Trigger on any height change
		# test initial state
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# send commands that normally would trigger a layer change, but without all axis homed.
		position.Update("g0 x0 y0 z.2 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# Home all axis and try again, will not trigger or wait, previous axis not homed
		position.Update("g28")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == False)

		# Waiting on ZHop
		position.Update("g0 x0 y0 z.2 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == True)
		# try zhop
		position.Update("g0 x0 y0 z.7 ")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)

		# extrude on current layer, no trigger (wait on zhop)
		position.Update("g0 x0 y0 z.7 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == True)

		# do not extrude on current layer, still waiting
		position.Update("g0 x0 y0 z.7 ")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == True)

		# partial hop, but close enough based on our printer measurement tolerance (0.005)
		position.Update("g0 x0 y0 z1.1999")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)

		# creat wait state
		position.Update("g0 x0 y0 z1.3 e1")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == True)

		# move down (should never happen, should behave properly anyway)
		position.Update("g0 x0 y0 z.8")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == True)

		# move back up to current layer (should NOT trigger zhop)
		position.Update("g0 x0 y0 z1.3")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == True)

		# move up a bit, not enough to trigger zhop
		position.Update("g0 x0 y0 z1.79749")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == False)
		self.assertTrue(trigger.IsWaiting == True)

		# move up a bit, just enough to trigger zhop
		position.Update("g0 x0 y0 z1.79751")
		trigger.Update(position)
		self.assertTrue(trigger.IsTriggered == True)
		self.assertTrue(trigger.IsWaiting == False)