2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								# Generic Filament Sensor Module
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								# Copyright (C) 2019  Eric Callahan <arksine.code@gmail.com>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								# This file may be distributed under the terms of the GNU GPLv3 license.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import logging
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								class RunoutHelper:
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def __init__(self, config):
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.name = config.get_name().split()[-1]
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.printer = config.get_printer()
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.reactor = self.printer.get_reactor()
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.gcode = self.printer.lookup_object('gcode')
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-17 17:07:54 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # Read config
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.runout_pause = config.getboolean('pause_on_runout', True)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if self.runout_pause:
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-07 11:10:27 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            self.printer.try_load_module(config, 'pause_resume')
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-07 11:29:22 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.runout_gcode = self.insert_gcode = None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        gcode_macro = self.printer.try_load_module(config, 'gcode_macro')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if self.runout_pause or config.get('runout_gcode', None) is not None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self.runout_gcode = gcode_macro.load_template(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                config, 'runout_gcode', '')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if config.get('insert_gcode', None) is not None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self.insert_gcode = gcode_macro.load_template(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                config, 'insert_gcode')
							 | 
						
					
						
							
								
									
										
										
										
											2019-09-07 08:33:44 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.pause_delay = config.getfloat('pause_delay', .5, above=.0)
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.event_delay = config.getfloat('event_delay', 3., above=0.)
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-17 17:07:54 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # Internal state
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-17 16:57:27 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.min_event_systime = self.reactor.NEVER
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.filament_present = False
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.sensor_enabled = True
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-17 17:07:54 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # Register commands and event handlers
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.printer.register_event_handler("klippy:ready", self._handle_ready)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.gcode.register_mux_command(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            "QUERY_FILAMENT_SENSOR", "SENSOR", self.name,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self.cmd_QUERY_FILAMENT_SENSOR,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            desc=self.cmd_QUERY_FILAMENT_SENSOR_help)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.gcode.register_mux_command(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            "SET_FILAMENT_SENSOR", "SENSOR", self.name,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self.cmd_SET_FILAMENT_SENSOR,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            desc=self.cmd_SET_FILAMENT_SENSOR_help)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _handle_ready(self):
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-17 16:57:27 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.min_event_systime = self.reactor.monotonic() + 2.
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _runout_event_handler(self, eventtime):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # Pausing from inside an event requires that the pause portion
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # of pause_resume execute immediately.
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-07 11:29:22 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pause_prefix = ""
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-07 11:10:27 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if self.runout_pause:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pause_resume = self.printer.lookup_object('pause_resume')
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pause_resume.send_pause_command()
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-07 11:29:22 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            pause_prefix = "PAUSE\n"
							 | 
						
					
						
							
								
									
										
										
										
											2019-09-07 08:33:44 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            self.printer.get_reactor().pause(eventtime + self.pause_delay)
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-07 11:29:22 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self._exec_gcode(pause_prefix, self.runout_gcode)
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _insert_event_handler(self, eventtime):
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-07 11:29:22 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self._exec_gcode("", self.insert_gcode)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _exec_gcode(self, prefix, template):
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        try:
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 17:28:02 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            self.gcode.run_script(prefix + template.render() + "\nM400")
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        except Exception:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            logging.exception("Script running error")
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-17 16:57:27 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.min_event_systime = self.reactor.monotonic() + self.event_delay
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-17 16:51:00 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def note_filament_present(self, is_filament_present):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if is_filament_present == self.filament_present:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.filament_present = is_filament_present
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        eventtime = self.reactor.monotonic()
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-17 16:57:27 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if eventtime < self.min_event_systime or not self.sensor_enabled:
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            # do not process during the initialization time, duplicates,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            # during the event delay time, while an event is running, or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            # when the sensor is disabled
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-17 17:07:54 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # Determine "printing" status
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        idle_timeout = self.printer.lookup_object("idle_timeout")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        is_printing = idle_timeout.get_status(eventtime)["state"] == "Printing"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # Perform filament action associated with status change (if any)
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-17 16:51:00 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if is_filament_present:
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-17 17:07:54 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if not is_printing and self.insert_gcode is not None:
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                # insert detected
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-17 16:57:27 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                self.min_event_systime = self.reactor.NEVER
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                logging.info(
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    "Filament Sensor %s: insert event detected, Time %.2f" %
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    (self.name, eventtime))
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-16 07:18:56 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                self.reactor.register_callback(self._insert_event_handler)
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-17 17:07:54 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        elif is_printing and self.runout_gcode is not None:
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            # runout detected
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-17 16:57:27 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            self.min_event_systime = self.reactor.NEVER
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            logging.info(
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                "Filament Sensor %s: runout event detected, Time %.2f" %
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                (self.name, eventtime))
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-16 07:18:56 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            self.reactor.register_callback(self._runout_event_handler)
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-16 16:49:09 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def get_status(self, eventtime):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return {"filament_detected": bool(self.filament_present)}
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    cmd_QUERY_FILAMENT_SENSOR_help = "Query the status of the Filament Sensor"
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def cmd_QUERY_FILAMENT_SENSOR(self, params):
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if self.filament_present:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            msg = "Filament Sensor %s: filament detected" % (self.name)
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else:
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            msg = "Filament Sensor %s: filament not detected" % (self.name)
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.gcode.respond_info(msg)
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    cmd_SET_FILAMENT_SENSOR_help = "Sets the filament sensor on/off"
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 19:12:44 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def cmd_SET_FILAMENT_SENSOR(self, params):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.sensor_enabled = self.gcode.get_int("ENABLE", params, 1)
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								class SwitchSensor:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def __init__(self, config):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        printer = config.get_printer()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        buttons = printer.try_load_module(config, 'buttons')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        switch_pin = config.get('switch_pin')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        buttons.register_buttons([switch_pin], self._button_handler)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.runout_helper = RunoutHelper(config)
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-16 16:49:09 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.get_status = self.runout_helper.get_status
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-15 15:03:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def _button_handler(self, eventtime, state):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.runout_helper.note_filament_present(state)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2019-02-08 15:38:33 -05:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def load_config_prefix(config):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return SwitchSensor(config)
							 |