2019-02-08 21:38:33 +01: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 21:03:28 +01:00
|
|
|
class RunoutHelper:
|
2019-02-08 21:38:33 +01:00
|
|
|
def __init__(self, config):
|
2020-02-15 21:03:28 +01:00
|
|
|
self.name = config.get_name().split()[-1]
|
2019-02-08 21:38:33 +01:00
|
|
|
self.printer = config.get_printer()
|
2020-02-15 21:03:28 +01:00
|
|
|
self.reactor = self.printer.get_reactor()
|
2019-02-08 21:38:33 +01:00
|
|
|
self.gcode = self.printer.lookup_object('gcode')
|
2020-02-17 23:07:54 +01:00
|
|
|
# Read config
|
2019-02-08 21:38:33 +01:00
|
|
|
self.runout_pause = config.getboolean('pause_on_runout', True)
|
|
|
|
if self.runout_pause:
|
2020-05-05 20:10:30 +02:00
|
|
|
self.printer.load_object(config, 'pause_resume')
|
2019-06-07 17:29:22 +02:00
|
|
|
self.runout_gcode = self.insert_gcode = None
|
2020-05-05 20:10:30 +02:00
|
|
|
gcode_macro = self.printer.load_object(config, 'gcode_macro')
|
2019-06-07 17:29:22 +02:00
|
|
|
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 14:33:44 +02:00
|
|
|
self.pause_delay = config.getfloat('pause_delay', .5, above=.0)
|
2020-02-15 21:03:28 +01:00
|
|
|
self.event_delay = config.getfloat('event_delay', 3., above=0.)
|
2020-02-17 23:07:54 +01:00
|
|
|
# Internal state
|
2020-02-17 22:57:27 +01:00
|
|
|
self.min_event_systime = self.reactor.NEVER
|
2020-02-15 21:03:28 +01:00
|
|
|
self.filament_present = False
|
|
|
|
self.sensor_enabled = True
|
2020-02-17 23:07:54 +01:00
|
|
|
# Register commands and event handlers
|
2020-02-15 21:03:28 +01: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 22:57:27 +01:00
|
|
|
self.min_event_systime = self.reactor.monotonic() + 2.
|
2019-02-08 21:38:33 +01: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 17:29:22 +02:00
|
|
|
pause_prefix = ""
|
2019-06-07 17:10:27 +02:00
|
|
|
if self.runout_pause:
|
|
|
|
pause_resume = self.printer.lookup_object('pause_resume')
|
2019-02-08 21:38:33 +01:00
|
|
|
pause_resume.send_pause_command()
|
2019-06-07 17:29:22 +02:00
|
|
|
pause_prefix = "PAUSE\n"
|
2019-09-07 14:33:44 +02:00
|
|
|
self.printer.get_reactor().pause(eventtime + self.pause_delay)
|
2019-06-07 17:29:22 +02:00
|
|
|
self._exec_gcode(pause_prefix, self.runout_gcode)
|
2019-02-08 21:38:33 +01:00
|
|
|
def _insert_event_handler(self, eventtime):
|
2019-06-07 17:29:22 +02:00
|
|
|
self._exec_gcode("", self.insert_gcode)
|
|
|
|
def _exec_gcode(self, prefix, template):
|
2019-02-08 21:38:33 +01:00
|
|
|
try:
|
2019-07-03 23:28:02 +02:00
|
|
|
self.gcode.run_script(prefix + template.render() + "\nM400")
|
2019-02-08 21:38:33 +01:00
|
|
|
except Exception:
|
|
|
|
logging.exception("Script running error")
|
2020-02-17 22:57:27 +01:00
|
|
|
self.min_event_systime = self.reactor.monotonic() + self.event_delay
|
2020-02-17 22:51:00 +01: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 21:03:28 +01:00
|
|
|
eventtime = self.reactor.monotonic()
|
2020-02-17 22:57:27 +01:00
|
|
|
if eventtime < self.min_event_systime or not self.sensor_enabled:
|
2020-02-15 21:03:28 +01: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 21:38:33 +01:00
|
|
|
return
|
2020-02-17 23:07:54 +01: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 22:51:00 +01:00
|
|
|
if is_filament_present:
|
2020-02-17 23:07:54 +01:00
|
|
|
if not is_printing and self.insert_gcode is not None:
|
2020-02-15 21:03:28 +01:00
|
|
|
# insert detected
|
2020-02-17 22:57:27 +01:00
|
|
|
self.min_event_systime = self.reactor.NEVER
|
2019-02-08 21:38:33 +01:00
|
|
|
logging.info(
|
2020-02-15 21:03:28 +01:00
|
|
|
"Filament Sensor %s: insert event detected, Time %.2f" %
|
|
|
|
(self.name, eventtime))
|
2020-02-16 13:18:56 +01:00
|
|
|
self.reactor.register_callback(self._insert_event_handler)
|
2020-02-17 23:07:54 +01:00
|
|
|
elif is_printing and self.runout_gcode is not None:
|
2020-02-15 21:03:28 +01:00
|
|
|
# runout detected
|
2020-02-17 22:57:27 +01:00
|
|
|
self.min_event_systime = self.reactor.NEVER
|
2019-02-08 21:38:33 +01:00
|
|
|
logging.info(
|
2020-02-15 21:03:28 +01:00
|
|
|
"Filament Sensor %s: runout event detected, Time %.2f" %
|
|
|
|
(self.name, eventtime))
|
2020-02-16 13:18:56 +01:00
|
|
|
self.reactor.register_callback(self._runout_event_handler)
|
2020-02-16 22:49:09 +01:00
|
|
|
def get_status(self, eventtime):
|
|
|
|
return {"filament_detected": bool(self.filament_present)}
|
2020-02-15 21:03:28 +01:00
|
|
|
cmd_QUERY_FILAMENT_SENSOR_help = "Query the status of the Filament Sensor"
|
2020-04-25 05:41:42 +02:00
|
|
|
def cmd_QUERY_FILAMENT_SENSOR(self, gcmd):
|
2020-02-15 21:03:28 +01:00
|
|
|
if self.filament_present:
|
|
|
|
msg = "Filament Sensor %s: filament detected" % (self.name)
|
2019-02-08 21:38:33 +01:00
|
|
|
else:
|
2020-02-15 21:03:28 +01:00
|
|
|
msg = "Filament Sensor %s: filament not detected" % (self.name)
|
2020-04-25 05:41:42 +02:00
|
|
|
gcmd.respond_info(msg)
|
2020-02-15 21:03:28 +01:00
|
|
|
cmd_SET_FILAMENT_SENSOR_help = "Sets the filament sensor on/off"
|
2020-04-25 05:41:42 +02:00
|
|
|
def cmd_SET_FILAMENT_SENSOR(self, gcmd):
|
|
|
|
self.sensor_enabled = gcmd.get_int("ENABLE", 1)
|
2019-02-08 21:38:33 +01:00
|
|
|
|
2020-02-15 21:03:28 +01:00
|
|
|
class SwitchSensor:
|
|
|
|
def __init__(self, config):
|
|
|
|
printer = config.get_printer()
|
2020-05-05 20:10:30 +02:00
|
|
|
buttons = printer.load_object(config, 'buttons')
|
2020-02-15 21:03:28 +01:00
|
|
|
switch_pin = config.get('switch_pin')
|
|
|
|
buttons.register_buttons([switch_pin], self._button_handler)
|
|
|
|
self.runout_helper = RunoutHelper(config)
|
2020-02-16 22:49:09 +01:00
|
|
|
self.get_status = self.runout_helper.get_status
|
2020-02-15 21:03:28 +01:00
|
|
|
def _button_handler(self, eventtime, state):
|
|
|
|
self.runout_helper.note_filament_present(state)
|
|
|
|
|
2019-02-08 21:38:33 +01:00
|
|
|
def load_config_prefix(config):
|
|
|
|
return SwitchSensor(config)
|