class ZoffsetWizard(object):
    def __init__(self, state, **kwargs):
        super(ZoffsetWizard, self).__init__()

        self.debug_mode = True

        #set up wizard flow
        self.state = state
        #self.process_state()

        #set up the wizard screen
        self.bb = Wizard_BB()
        self.group = 'Z_Offset_Group'
        #add bb
        roboprinter.robosm.add_widget(self.bb)
        roboprinter.robosm.current = self.bb.name

        self.welcome = None
        self.workflow = None
        self.finish_screen = None

        #initialize wizard variables
        self.z_offset = {}
        self.selected_tool = 'tool0'
        self.dual = False

        #variables for saving old z_offset
        self.old_z_offset = {}
        self.welcome_screen()

    def cleanup(self):
        Logger.info("Deleting: z_offset_wizard")
        roboprinter.robosm.remove_widget(self.bb)
        self.bb.delete_node()

        if self.welcome != None:
            self.welcome.cleanup()
        if self.workflow != None:
            self.workflow.cleanup()
        if self.finish_screen != None:
            self.finish_screen.cleanup()
        del_list = []
        for self_var in self.__dict__:
            del_list.append(self_var)
            self.__dict__[self_var] = ''
        for self_var in del_list:
            #Logger.info("Deleting: " + str(self_var))
            del self.__dict__[self_var]
        #Tell Self to print out any remaining referrers
        # Logger.info("---> Printing referrers of Z-Offset")
        # gc.collect()
        # for referer in gc.get_referrers(self):
        #     Logger.info(referer)
        # Logger.info("---> Done printing referrers of Z-Offset")
        del self

    def welcome_screen(self):
        #Make screen content
        self.welcome = Button_Screen(
            lang.pack['ZOffset_Wizard']['Wizard_Description'],
            self.process_state,
            button_text=lang.pack['ZOffset_Wizard']['Start'])
        self.welcome.change_screen_actions = self.cleanup
        #populate screen
        self.bb.make_screen(self.welcome,
                            roboprinter.lang.pack['ZOffset_Wizard']['Welcome'],
                            option_function='no_option')

    def process_state(self):
        ext_number = 1
        if 'extruder' in self.state:
            ext_number = int(self.state['extruder'])

        #decide what the layout should be
        if ext_number > 1:
            # self.select_extruder() Re enable this when the new head comes out
            self.selected_tool = 'tool0'
            self.start_workflow()
        else:
            self.selected_tool = 'tool0'
            self.start_workflow()

    def select_extruder(self):
        #detirmine machine state and behaviour of the wizard
        es = Extruder_Selector(self.dual_or_single_fork,
                               make_screen=self.bb.make_screen,
                               group=self.group)
        es.show_screen()

    def dual_or_single_fork(self, extruder):
        extruders = ['EXT1', 'EXT2', 'BOTH']

        if extruder in extruders:
            if extruder == 'BOTH':
                self.dual = True
            else:
                self.dual = False
                tool_dict = {'EXT1': 'tool0', 'EXT2': 'tool1'}
                self.selected_tool = tool_dict[extruder]
            self.start_workflow()
        else:
            Logger.info("ERROR Invalid selection")
            raise ValueError(str(extruder) + " Is not a valid selection")

    def start_workflow(self):
        if self.dual:
            #this will go through the workflow for both extruders
            def second_extruder():
                self.workflow = Z_Offset_Workflow('tool1', self.finish_wizard,
                                                  self.update_z_offset,
                                                  self.bb, self.group)

            #callback to second extruder function
            self.workflow = Z_Offset_Workflow('tool0', self.second_extruder,
                                              self.update_z_offset, self.bb,
                                              self.group)
        else:
            #This will go through the workflow for one extruder.
            self.workflow = Z_Offset_Workflow(self.selected_tool,
                                              self.finish_wizard,
                                              self.update_z_offset, self.bb,
                                              self.group)

    #callback to update the Z_Offset for each extruder. This callback does not save anything, it simply records
    #the z offset to be shown in the finish wizard segment.
    def update_z_offset(self, extruder, z_offset):
        self.z_offset[extruder] = z_offset

    def finish_wizard(self, *args, **kwargs):
        title = roboprinter.lang.pack['ZOffset_Wizard']['Z_44']

        #title_text, body_text,image_source, button_function, button_text = roboprinter.lang.pack['Button_Screen']['Default_Button']
        self.finish_screen = Picture_Button_Screen(
            '[size=40][color=#69B3E7]' +
            lang.pack['ZOffset_Wizard']['Finish_Title'] + '[/color][/size]',
            '[size=30]' + lang.pack['ZOffset_Wizard']['Finish_Body1'] +
            ' {} '.format(self.z_offset['tool0']) +
            lang.pack['ZOffset_Wizard']['Finish_Body2'],
            'Icons/Manual_Control/check_icon.png',
            self.end_wizard,
            button_text="[size=30]" + lang.pack['ZOffset_Wizard']['Save'])
        self.finish_screen.change_screen_actions = self.reset_to_zero_on_back
        self.finish_screen.update = self.skip_screen

        self.bb.make_screen(self.finish_screen,
                            title,
                            option_function='no_option')

    def reset_to_zero_on_back(self):
        #set the ZOffset to zero
        Logger.info("Setting the Z-Offset to 0 due to a back screen!")
        roboprinter.printer_instance._printer.commands('M206 Z0.00')
        roboprinter.printer_instance._printer.commands("M851 Z0.00")
        roboprinter.printer_instance._printer.commands("M500")
        roboprinter.printer_instance._printer.commands('M114')

    def skip_screen(self):
        self.bb.back_function_flow()

    def end_wizard(self):
        #home and go back
        roboprinter.printer_instance._printer.commands('G28')
        self.cleanup()
        roboprinter.robosm.go_back_to_main('printer_status_tab')
Example #2
0
class FilamentWizard(object):

    extrude_event = None
    def __init__(self, loader_changer, name, title, back_destination, state,  **kwargs):
        super(FilamentWizard, self).__init__(**kwargs)
        self.bb = Wizard_BB()
        self.group = 'filament_wizard_group'
        self.welcome = None
        self.ph_overseer = None
        self.workflow = None
        self.debug_mode = True

        self.name = name #name of initial screen
        self.title = title
        self.back_destination = back_destination
        self.bb.back_destination = self.back_destination
        self.load_or_change = loader_changer
        self.dual = False
        self.state = state
        self.selected_tool = 'tool0'
        current_data = roboprinter.printer_instance._printer.get_current_data()
        self.is_printing = current_data['state']['flags']['printing']
        self.is_paused = current_data['state']['flags']['paused']

        #add bb
        roboprinter.robosm.add_widget(self.bb)
        roboprinter.robosm.current = self.bb.name

        # Check debug state, if true, print out instances of FilamentWizard
        #  recognized by the garbage collector
        # if self.debug_mode:
        #     Logger.info("--->Checking FilamentWizard")
        #     obj_len = 0
        #     for obj in gc.get_objects():
        #         if isinstance(obj, FilamentWizard):
        #             obj_len += 1
        #             Logger.info("GC: " + str(obj))
        #     Logger.info("There are " + str(obj_len) + " FilamentWizard Objects active")

        #     # Print out the instance of this class. The name of the instance and
        #     # address in memory will be printed
        #     Logger.info("SELF: " + str(self))

        #go to first screen
        self.first_screen()

    def cleanup(self):
        Logger.info("Deleting: filament_wizard")
        #Clean up the wizard
        roboprinter.robosm.remove_widget(self.bb)
        self.bb.delete_node()

        if self.welcome != None:
            self.welcome.cleanup()
        if self.ph_overseer != None:
            self.ph_overseer.cleanup()
        if self.workflow != None:
            self.workflow.cleanup()
        del_list = []
        for self_var in self.__dict__:
            del_list.append(self_var)
        for self_var in del_list:
            #Logger.info("Deleting " + str(self_var))
            del self.__dict__[self_var]

        #Tell Self to print out any remaining referrers 
        # Logger.info("---> Printing referrers of FilamentWizard")
        # gc.collect()
        # for referer in gc.get_referrers(self):
        #     Logger.info(referer)
        # Logger.info("---> Done printing referrers of FilamentWizard")
        del self

    def process_machine_state(self):
        ext_number = 1
        if 'extruder' in self.state:
            ext_number = int(self.state['extruder'])

        #decide what the layout should be
        if ext_number > 1:
            self.select_extruder()
        else:
            self.choose_material()


    def first_screen(self):
        """
        First Screen:
            displays Start button that will open second_screen
        """
        self.welcome = Picture_Image_on_Button_Screen(lang.pack['Filament_Wizard']['Wizard_Description'],
                                                'Icons/Manual_Control/info_icon.png',
                                                self.process_machine_state,
                                                'Icons/Manual_Control/start_button_icon.png',
                                                lang.pack['Filament_Wizard']['Start'])
        self.welcome.change_screen_actions = self.cleanup
        self.bb.make_screen(self.welcome,
                         self.title,
                         option_function='no_option')

    def choose_material(self, *args):
        #if we are printing we want to change the material at the current temperature
        if self.is_printing or self.is_paused:
            temps  = roboprinter.printer_instance._printer.get_current_temperatures()
            current_temperature = [0,0]
            extruder = self.selected_tool

            if extruder in temps and 'actual' in temps[extruder] and 'target' in temps[extruder]:
                current_temperature = [int(temps[extruder]['actual']), int(temps[extruder]['target'])]

            self.collect_heat_settings(current_temperature[1], 0)
        else:
            Logger.info("Making Preheat_Overseer with group: " + str(self.group))
            ### FLAGGED FOR CLEAN UP
            # self.ph_overseer = Preheat_Overseer(end_point=self.collect_heat_settings,
            self.ph_overseer = Preheat_Overseer(end_point=self.collect_heat_settings,
                             name='preheat_wizard',
                             title=roboprinter.lang.pack['Utilities']['Preheat'],
                             back_destination=self.bb.name,
                             dual = self.dual,
                             back_button_screen = self.bb,
                             group = self.group)


    def select_extruder(self):
        #detirmine machine state and behaviour of the wizard
        es = Extruder_Selector(self.dual_or_single_fork, make_screen=self.bb.make_screen, group=self.group)
        es.show_screen()

    def dual_or_single_fork(self, extruder):
        extruders = ['EXT1', 'EXT2', 'BOTH']

        if extruder in extruders:
            if extruder == 'BOTH':
                self.dual = True
            else:
                self.dual = False
                tool_dict = {
                    'EXT1': 'tool0',
                    'EXT2': 'tool1'
                }
                self.selected_tool = tool_dict[extruder]
            self.choose_material()
        else:
            Logger.info("ERROR Invalid selection")
            raise ValueError(str(extruder) + " Is not a valid selection")

    def collect_heat_settings(self, extruder, bed):
        if self.dual:
            def second_extruder():
                self.print_temperature = extruder[1]
                self.workflow = Filament_Workflow('tool1', self.print_temperature, self.load_or_change, self.finish_wizard, self.bb)

            #
            self.print_temperature = extruder[0]
            self.workflow = Filament_Workflow('tool0', self.print_temperature, self.load_or_change, second_extruder, self.bb)


        else:
            self.print_temperature = extruder
            self.workflow = Filament_Workflow(self.selected_tool, self.print_temperature, self.load_or_change, self.finish_wizard,self.bb)


    def finish_wizard(self):
        #title_text, body_text,image_source, button_function, button_image, button_text
        layout = Title_Picture_Image_on_Button_Screen(lang.pack['Filament_Wizard']['Complete_Title'],
                                                 lang.pack['Filament_Wizard']['Complete_Body'],
                                                 'Icons/Manual_Control/check_icon.png',
                                                 self.goto_main,
                                                 'Icons/Manual_Control/ok_button_icon.png',
                                                 lang.pack['Filament_Wizard']["Ok"])

        if self.load_or_change == 'CHANGE':
            _title = roboprinter.lang.pack['Filament_Wizard']['Title_55']

        else:
            _title = roboprinter.lang.pack['Filament_Wizard']['Title_44']

        back_destination = roboprinter.robo_screen()
        self.bb.make_screen(layout,
                         _title,
                         option_function='no_option')

    def goto_main(self):
        Logger.info("Going to main " + str(self))
        self.cleanup()
        roboprinter.robosm.go_back_to_main()
class Bed_Calibration(object):
    """Bed_Calibration Allows the user to move the head to three different points to manually level the bed through the
       Screws on the bed"""
    def __init__(self, name, title, back_destination):
        super(Bed_Calibration, self).__init__()

        #setup the wizard_bb screen
        self.bb = Wizard_BB()
        self.group = 'pid_wizard_group'
        self.workflow = None
        self.finish_wizard = None
        self.welcome = None
        self.debug = False

        self.name = name  #name of initial screen
        self.title = title
        self.back_destination = back_destination
        self.bb.back_destination = self.back_destination
        self.selected_tool = 'tool0'

        #add bb
        roboprinter.robosm.add_widget(self.bb)
        roboprinter.robosm.current = self.bb.name

        # Check the debug state. If true, print out a list of instances of
        # Bed_Calibration recognized by the garbage collector
        if self.debug:
            Logger.info("---> Checking Bed_Calibration instances")
            obj_len = 0
            for obj in gc.get_objects():
                if isinstance(obj, Bed_Calibration):
                    obj_len += 1
                    Logger.info("GC: " + str(obj))
            Logger.info("There are " + str(obj_len) +
                        " Bed_Calibration Objects active")

            # Print out the instance of this class. The name of the instance and
            # address in memory will be printed.
            Logger.info("SELF: " + str(self))

        #pconsole.query_eeprom()
        self.model = roboprinter.printer_instance._settings.get(['Model'])
        self.welcome_screen()
        self.mode = "manual"

    def cleanup(self):
        Logger.info("Cleaning up the bed Calibration Wizard!")
        self.bb.delete_node()

        #cleanup workflows
        if self.welcome != None:
            self.welcome.cleanup()

        if self.workflow != None:
            self.workflow.cleanup()

        if self.finish_wizard != None:
            self.finish_wizard.cleanup()

        #dereference self
        del_list = []
        for self_var in self.__dict__:
            del_list.append(self_var)
            self.__dict__[self_var] = ''  #set variables to nothing.
        for self_var in del_list:
            #Logger.info("Deleting " + str(self_var))
            del self.__dict__[self_var]

        #Tell Self to print out any remaining referrers
        # Logger.info("---> Printing referrers of Bed_Calibration")
        # gc.collect()
        # for referer in gc.get_referrers(self):
        #     Logger.info(referer)
        # Logger.info("---> Done printing referrers of Bed_Calibration")
        del self

    def welcome_screen(self):
        self.welcome = Button_Screen(
            roboprinter.lang.pack['Bed_Cal_Wizard']['Welcome']['Body'],
            self.tighten_all_screw_instructions,
            button_text=roboprinter.lang.pack['Bed_Cal_Wizard']['Welcome']
            ['Button'])
        title = roboprinter.lang.pack['Bed_Cal_Wizard']['Welcome']['Title']
        name = 'welcome_bed_calibration'
        back_destination = roboprinter.robo_screen()
        self.welcome.change_screen_actions = self.cleanup
        self.bb.make_screen(self.welcome, title, option_function='no_option')

    def tighten_all_screw_instructions(self):
        layout = Button_Screen(
            roboprinter.lang.pack['Bed_Cal_Wizard']['Tilt_Instructions']
            ['Body'],
            self.check_for_valid_start,
            button_text=roboprinter.lang.pack['Bed_Cal_Wizard']
            ['Tilt_Instructions']['Button'])
        title = roboprinter.lang.pack['Bed_Cal_Wizard']['Tilt_Instructions'][
            'Title']
        name = 'tilt1'
        back_destination = roboprinter.robo_screen()

        self.bb.make_screen(layout, title, option_function='no_option')

    def check_for_valid_start(self):
        start = self.check_offset()

        #if the ZOffset is not right don't allow the user to continue
        if start:
            self.ask_for_mode()
        else:
            zoff = pconsole.home_offset['Z']
            ep = Error_Popup(
                roboprinter.lang.pack['Warning']['Z_Offset_Warning']['Title'],
                roboprinter.lang.pack['Warning']['Z_Offset_Warning']['Body1'] +
                " " + str(zoff) + " " +
                roboprinter.lang.pack['Warning']['Z_Offset_Warning']['Body2'],
                callback=partial(roboprinter.robosm.go_back_to_main,
                                 tab='printer_status_tab'))
            ep.open()

    def ask_for_mode(self):
        def manual():
            self.mode = "manual"
            self.start_workflow()

        def guided():
            self.mode = "guided"
            self.start_workflow()

        layout = Modal_Question(
            roboprinter.lang.pack['Bed_Cal_Wizard']['Mode']['Sub_Title'],
            roboprinter.lang.pack['Bed_Cal_Wizard']['Mode']['Body'],
            roboprinter.lang.pack['Bed_Cal_Wizard']['Mode']['Button1'],
            roboprinter.lang.pack['Bed_Cal_Wizard']['Mode']['Button2'], manual,
            guided)

        title = roboprinter.lang.pack['Bed_Cal_Wizard']['Mode']['Title']
        name = 'guided_or_manual'
        back_destination = roboprinter.robo_screen()

        self.bb.make_screen(layout, title, option_function='no_option')

    #check the offset to see if it is in an acceptable range
    def check_offset(self):

        offset = float(pconsole.home_offset['Z'])
        #make sure the range is within -20 - 0
        if offset > -20.00 and not offset > 0.00 and offset != 0.00:
            return True
        else:
            return False

    def start_workflow(self):
        self.workflow = BedCal_Workflow(self.mode,
                                        self.finish_screws_instructions,
                                        self.bb,
                                        debug=self.debug)

    def finish_screws_instructions(self):
        layout = Button_Screen(
            roboprinter.lang.pack['Bed_Cal_Wizard']['Tilt_Instructions']
            ['Body'],
            self.finish_bed_cal_wizard,
            button_text=roboprinter.lang.pack['Bed_Cal_Wizard']
            ['Tilt_Instructions']['Button'])
        title = roboprinter.lang.pack['Bed_Cal_Wizard']['Tilt_Instructions'][
            'Title']
        name = 'tilt2'
        back_destination = 'guided_or_manual'

        self.bb.make_screen(layout, title, option_function='no_option')

    def finish_bed_cal_wizard(self):

        self.finish_wizard = Picture_Button_Screen(
            roboprinter.lang.pack['Bed_Cal_Wizard']['Finish_Wizard']
            ['Sub_Title'],
            roboprinter.lang.pack['Bed_Cal_Wizard']['Finish_Wizard']['Body'],
            'Icons/Manual_Control/check_icon.png', self.goto_main)
        title = roboprinter.lang.pack['Bed_Cal_Wizard']['Finish_Wizard'][
            'Title']
        name = 'finish_wizard'
        back_destination = roboprinter.robo_screen()

        self.bb.make_screen(self.finish_wizard,
                            title,
                            option_function='no_option')

    def goto_main(self):
        roboprinter.printer_instance._printer.commands('G28')
        roboprinter.robosm.go_back_to_main('utilities_tab')
        self.cleanup()
class PID_Overseer(object):
    """docstring for PID_Overseer"""
    def __init__(self, name, title, back_destination):
        super(PID_Overseer, self).__init__()
        self.autotune_complete = False
        pconsole.query_eeprom()
        self.bb = Wizard_BB()
        self.group = 'pid_wizard_group'
        self.welcome = None
        self.pid_screen = None
        self.debug_mode = False

        self.name = name  #name of initial screen
        self.title = title
        self.back_destination = back_destination
        self.bb.back_destination = self.back_destination
        self.selected_tool = 'tool0'

        #add bb
        roboprinter.robosm.add_widget(self.bb)
        roboprinter.robosm.current = self.bb.name
        #start wizard
        self.welcome_page()

    def cleanup(self):
        Logger.info("Deleting: PID_Overseer")
        #cleaning up bb elements
        self.bb.delete_node()
        self.bb = ''

        #cleanup workflow
        if self.welcome != None:
            self.welcome.cleanup()
        if self.pid_screen != None:
            self.pid_screen.cleanup()

        #dereference certain functions
        self.back_function_interrupt = ''

        #dereference self
        del_list = []
        for self_var in self.__dict__:
            del_list.append(self_var)
            self.__dict__[self_var] = ''  #set variables to nothing.
        for self_var in del_list:
            #Logger.info("Deleting " + str(self_var))
            del self.__dict__[self_var]

        #Tell Self to print out any remaining referrers
        # Logger.info("---> Printing referrers of PID_Overseer")
        # gc.collect()
        # for referer in gc.get_referrers(self):
        #     Logger.info(referer)
        # Logger.info("---> Done printing referrers of PID_Overseer")

        del self

    def welcome_page(self):

        self.welcome = Button_Screen(
            lang.pack['PID_Tool']['Welcome_Screen']['Body'],
            self.select_extruder,
            button_text=lang.pack['PID_Tool']['Welcome_Screen']['Button_Text'])

        title = lang.pack['PID_Tool']['Welcome_Screen']['Title']
        self.welcome.change_screen_actions = self.cleanup

        self.bb.make_screen(self.welcome, title, option_function='no_option')

    def select_extruder(self):
        #detirmine machine state and behaviour of the wizard
        model = roboprinter.printer_instance._settings.get(['Model'])

        if model == "Robo R2":
            es = Heater_Selector(self.heater_select,
                                 make_screen=self.bb.make_screen,
                                 group=self.group)
            es.show_screen()
        else:
            self.heater_select('EXT1')

    def heater_select(self, heater):
        heaters = ['EXT1', 'EXT2', 'BED']

        if heater in heaters:
            tool_dict = {'EXT1': '0', 'EXT2': '1', 'BED': '-1'}
            self.selected_tool = tool_dict[heater]
            self.start_workflow()
        else:
            Logger.info("ERROR Invalid selection")
            raise ValueError(str(extruder) + " Is not a valid selection")

    def start_workflow(self):
        self.autotune_complete = False  #reset autotune
        if self.pid_screen == None:
            self.pid_screen = PID_Test_Screen(self.selected_tool,
                                              self.finish_wizard,
                                              self.failure_callback,
                                              debug=self.debug_mode)
        else:
            self.pid_screen.cleanup()
            self.pid_screen = PID_Test_Screen(self.selected_tool,
                                              self.finish_wizard,
                                              self.failure_callback,
                                              debug=self.debug_mode)

        title = lang.pack['PID_Tool']['Workflow']['Title']

        self.bb.make_screen(self.pid_screen,
                            title,
                            back_function=self.back_function_interrupt,
                            option_function='no_option')

        #parse the correct command
        #The stage 3 variable will detirmine how many cycles the PID tool will do. This is so our Testers can easily adjust this number without having to consult me.
        if not self.debug_mode:
            command = 'M303 C' + str(lang.pack['PID_Tool']['Workflow']
                                     ['Stage3']) + ' E' + self.selected_tool
        else:

            def deffered_action(*args, **kwargs):
                command = ""

        if not self.debug_mode:
            #if it's the bed then set temp to 100, else set temp to 240
            if int(self.selected_tool) < 0:
                command = command + " S" + lang.pack['PID_Tool']['Workflow'][
                    'Target_Bed']
            else:
                command = command + " S" + lang.pack['PID_Tool']['Workflow'][
                    'Target_Ext']
        else:
            #Just make the wizard dwell for a little back_function_interrupt
            command = "G4 S3"

        Logger.info("Command sent is: " + str(command))

        #start the test
        roboprinter.printer_instance._printer.commands(command)
        roboprinter.printer_instance._printer.commands("M118 ACTION COMPLETE!")

    def back_function_interrupt(self):
        if self.autotune_complete:
            self.bb.back_function_flow()
        else:
            Info_Popup(
                lang.pack['PID_Tool']['Prevent_Back_Screen']['Title'],
                lang.pack['PID_Tool']['Prevent_Back_Screen']['Body']).show()

    def failure_callback(self):
        self.autotune_complete = True

        def cancel():
            roboprinter.robosm.go_back_to_main('printer_status_tab')

        layout = Button_Screen(lang.pack['PID_Tool']['Failure_Screen']['Body'],
                               cancel)

        title = lang.pack['PID_Tool']['Failure_Screen']['Title']
        self.bb.make_screen(layout, title, option_function='no_option')

    def finish_wizard(self, final_PID):
        self.autotune_complete = True

        def save_pid():
            self.save_PID(final_PID)

        body = lang.pack['PID_Tool']['Finish_Wizard']['Body']
        new_pid = lang.pack['PID_Tool']['Finish_Wizard']['New_PID']

        #make the text_object to put into the modal question
        finish_object = PID_Finish_Object(body, new_pid, final_PID)

        layout = Object_Modal_Question(
            finish_object, lang.pack['PID_Tool']['Finish_Wizard']['Save'],
            lang.pack['PID_Tool']['Finish_Wizard']['Cancel'], save_pid,
            self.goto_main)
        title = lang.pack['PID_Tool']['Finish_Wizard']['Title']

        self.bb.make_screen(layout, title, option_function='no_option')

    def save_PID(self, PID):
        #construct PID save command
        pid_command = ''
        if self.selected_tool == "-1":
            pid_command = 'M304 P' + str(PID['P']) + " I" + str(
                PID['I']) + " D" + str(PID['D'])
        else:
            pid_command = 'M301 P' + str(PID['P']) + " I" + str(
                PID['I']) + " D" + str(PID['D'])

        #save PID
        roboprinter.printer_instance._printer.commands(pid_command)
        roboprinter.printer_instance._printer.commands("M500")  #save

        #create a button screen
        layout = Button_Screen(lang.pack['PID_Tool']['Save_Screen']['Body'],
                               self.goto_main)

        title = lang.pack['PID_Tool']['Save_Screen']['Title']
        self.bb.make_screen(layout, title, option_function='no_option')

    def goto_main(self):
        #cleanup the wizard
        self.cleanup()
        roboprinter.robosm.go_back_to_main('printer_status_tab')
class Fine_Tune_ZOffset(object):
    """docstring for Fine_Tune_ZOffset"""
    def __init__(self, name, title, back_destination, state):
        super(Fine_Tune_ZOffset, self).__init__()
        self.bb = Wizard_BB()
        self.group = 'FTZO_group'
        self.welcome = None
        self.workflow = None
        self.ph_overseer = None
        self.zo_saver = None
        self.debug_mode = False

        self.name = name #name of initial screen
        self.title = title
        self.back_destination = back_destination
        self.bb.back_destination = self.back_destination
        self.dual = False
        self.state = state
        self.selected_tool = 'tool0'

        #add bb
        roboprinter.robosm.add_widget(self.bb)
        roboprinter.robosm.current = self.bb.name
        self.welcome_screen() #start the wizard

        #variable that does not get a soft restart
        self.preparing_in_progress = False

    #Cleanup the wizard by dereferrencing everything in the wizard
    def cleanup(self):
        Logger.info("Deleting: FTZO")   
        #Cleanup the wizard and remove all summoned objects from memory

        #remove BB from screen manager object
        roboprinter.robosm.remove_widget(self.bb)

        #ask BB to delete all of it's nodes
        self.bb.delete_node()

        #dereference BB
        self.bb =''

        #ask the welcome screen to kill itself
        if self.welcome != None:
            self.welcome.cleanup()

        #Ask the main workflow to clean itself up
        if self.workflow != None:
            self.workflow.cleanup()

        #Ask Preheat to clean itself up
        if self.ph_overseer != None:
            self.ph_overseer.cleanup()

        #ask the Z-Offset saver to clean itself up
        if self.zo_saver != None:
            self.zo_saver.cleanup()

        #dereference self    
        del_list = []
        for self_var in self.__dict__:
            del_list.append(self_var)
            self.__dict__[self_var] = '' #set variables to nothing.
        for self_var in del_list:
            #Logger.info("Deleting " + str(self_var))
            del self.__dict__[self_var]

        #Tell Self to print out any remaining referrers 
        # Logger.info("---> Printing referrers of FTZO")
        # gc.collect()
        # for referer in gc.get_referrers(self):
        #     Logger.info(referer)
        # Logger.info("---> Done printing referrers of FTZO")

        #delete self.
        del self


    def welcome_screen(self):
        self.welcome = Button_Screen(roboprinter.lang.pack['FT_ZOffset_Wizard']['Welcome']['Body'],
                               self.process_machine_state,
                               button_text=roboprinter.lang.pack['FT_ZOffset_Wizard']['Welcome']['Button_Text'])
        title = roboprinter.lang.pack['FT_ZOffset_Wizard']['Welcome']['Title']
        self.welcome.change_screen_actions = self.cleanup

        self.bb.make_screen(self.welcome,
                            title,
                            option_function='no_option')


    def process_machine_state(self):
        ext_number = 1
        if 'extruder' in self.state:
            ext_number = int(self.state['extruder'])

        #decide what the layout should be
        if ext_number > 1:
            self.select_extruder()
        else:
            self.choose_material()

    def select_extruder(self):
        #detirmine machine state and behaviour of the wizard
        es = Extruder_Selector(self.dual_or_single_fork, make_screen=self.bb.make_screen, group=self.group)
        es.show_screen()

    def dual_or_single_fork(self, extruder):
        extruders = ['EXT1', 'EXT2', 'BOTH']

        if extruder in extruders:
            if extruder == 'BOTH':
                self.dual = True
            else:
                self.dual = False
                tool_dict = {
                    'EXT1': 'tool0',
                    'EXT2': 'tool1'
                }
                self.selected_tool = tool_dict[extruder]
            self.choose_material()
        else:
            Logger.info("ERROR Invalid selection")
            raise ValueError(str(extruder) + " Is not a valid selection")

    def choose_material(self, *args):
        Logger.info("Making Preheat_Overseer with group: " + str(self.group))
        self.ph_overseer = Preheat_Overseer(end_point=self.collect_heat_settings,
                         name='preheat_wizard',
                         title=roboprinter.lang.pack['Utilities']['Preheat'],
                         back_destination=self.bb.name,
                         dual = self.dual,
                         back_button_screen = self.bb,
                         group = self.group)

    def collect_heat_settings(self, extruder, bed):
        #save the collected heat settings
        self.extruder = extruder
        self.bed = bed
        self.instruction1()

    def instruction1(self):
        layout = Button_Screen(roboprinter.lang.pack['FT_ZOffset_Wizard']['Instruction']['Body'],
                               self.instruction2)
        title = roboprinter.lang.pack['FT_ZOffset_Wizard']['Instruction']['Title']

        self.bb.make_screen(layout,
                            title,
                            option_function='no_option'
                            )


    def instruction2(self):
        layout = Picture_Instructions()
        title = roboprinter.lang.pack['FT_ZOffset_Wizard']['Instruction']['Title']

        self.bb.make_screen(layout,
                            title,
                            option_function=self.start_workflow,
                            option_icon="Icons/Slicer wizard icons/next.png"
                            )

    def start_workflow(self):
        if type(self.extruder) != list:
            temps = {
                'tool0': self.extruder,
                'bed': self.bed
            }
        else:
            temps = {
                'tool0': self.extruder[0],
                'tool1': self.extruder[1],
                'bed': self.bed
            }
        self.workflow = FTZO_workflow(self.dual, self.selected_tool, temps, self.finish_wizard, self.bb, debug=self.debug_mode)

    def finish_wizard(self):
        roboprinter.printer_instance._printer.commands('M500')
        offset = pconsole.home_offset['Z']
        self.zo_saver = Z_offset_saver(self.goto_main,
                                [roboprinter.lang.pack['FT_ZOffset_Wizard']['Save_Offset']['Saving'], roboprinter.lang.pack['FT_ZOffset_Wizard']['Finish']['Sub_Title'] ]
                                )
        title = roboprinter.lang.pack['FT_ZOffset_Wizard']['Finish']['Title']

        self.bb.make_screen(self.zo_saver,
                            title,
                            option_function = 'no_option')

    def goto_main(self):
        roboprinter.printer_instance._printer.commands('M104 S0')
        roboprinter.printer_instance._printer.commands('M140 S0')
        roboprinter.printer_instance._printer.commands('G28')
        roboprinter.robosm.go_back_to_main('utilities_tab')
        #cleanup self
        self.cleanup()