aboutsummaryrefslogtreecommitdiffstats
path: root/klippy/extras
diff options
context:
space:
mode:
authorGareth Farrington <gareth@waves.ky>2025-03-20 16:55:33 -0700
committerGitHub <noreply@github.com>2025-03-20 19:55:33 -0400
commit272e815522b0bc8e0806e052b73a5cc1af979cd7 (patch)
tree8cbf07cad71d2113a55c45d53900ac3ad15ba8e2 /klippy/extras
parent06d65ef5ac139e2c84e7381c190ee2b1e4ec4237 (diff)
downloadkutter-272e815522b0bc8e0806e052b73a5cc1af979cd7.tar.gz
kutter-272e815522b0bc8e0806e052b73a5cc1af979cd7.tar.xz
kutter-272e815522b0bc8e0806e052b73a5cc1af979cd7.zip
buttons: Debounce gcode_button and filament_switch_sensor (#6848)
Add `debounce_delay` config option which sets the debounce time, defaults to 0 Signed-off-by: Gareth Farrington <gareth@waves.ky>
Diffstat (limited to 'klippy/extras')
-rw-r--r--klippy/extras/buttons.py35
-rw-r--r--klippy/extras/filament_motion_sensor.py4
-rw-r--r--klippy/extras/filament_switch_sensor.py19
-rw-r--r--klippy/extras/gcode_button.py8
-rw-r--r--klippy/extras/hall_filament_width_sensor.py2
5 files changed, 54 insertions, 14 deletions
diff --git a/klippy/extras/buttons.py b/klippy/extras/buttons.py
index daa998a9..4f012f51 100644
--- a/klippy/extras/buttons.py
+++ b/klippy/extras/buttons.py
@@ -244,6 +244,33 @@ class HalfStepRotaryEncoder(BaseRotaryEncoder):
BaseRotaryEncoder.R_START | BaseRotaryEncoder.R_DIR_CCW),
)
+class DebounceButton:
+ def __init__(self, config, button_action):
+ self.printer = config.get_printer()
+ self.reactor = self.printer.get_reactor()
+ self.button_action = button_action
+ self.debounce_delay = config.getfloat('debounce_delay', 0., minval=0.)
+ self.logical_state = None
+ self.physical_state = None
+ self.latest_eventtime = None
+ def button_handler(self, eventtime, state):
+ self.physical_state = state
+ self.latest_eventtime = eventtime
+ # if there would be no state transition, ignore the event:
+ if self.logical_state == self.physical_state:
+ return
+ trigger_time = eventtime + self.debounce_delay
+ self.reactor.register_callback(self._debounce_event, trigger_time)
+ def _debounce_event(self, eventtime):
+ # if there would be no state transition, ignore the event:
+ if self.logical_state == self.physical_state:
+ return
+ # if there were more recent events, they supersede this one:
+ if (eventtime - self.debounce_delay) < self.latest_eventtime:
+ return
+ # enact state transition and trigger action
+ self.logical_state = self.physical_state
+ self.button_action(self.latest_eventtime, self.logical_state)
######################################################################
# Button registration code
@@ -261,6 +288,14 @@ class PrinterButtons:
self.adc_buttons[pin] = adc_buttons = MCU_ADC_buttons(
self.printer, pin, pullup)
adc_buttons.setup_button(min_val, max_val, callback)
+ def register_debounce_button(self, pin, callback, config):
+ debounce = DebounceButton(config, callback)
+ return self.register_buttons([pin], debounce.button_handler)
+ def register_debounce_adc_button(self, pin, min_val, max_val, pullup
+ , callback, config):
+ debounce = DebounceButton(config, callback)
+ return self.register_adc_button(pin, min_val. min_val, max_val, pullup
+ , debounce.button_handler)
def register_adc_button_push(self, pin, min_val, max_val, pullup, callback):
def helper(eventtime, state, callback=callback):
if state:
diff --git a/klippy/extras/filament_motion_sensor.py b/klippy/extras/filament_motion_sensor.py
index fb886aa5..dd476d28 100644
--- a/klippy/extras/filament_motion_sensor.py
+++ b/klippy/extras/filament_motion_sensor.py
@@ -63,7 +63,7 @@ class EncoderSensor:
def _extruder_pos_update_event(self, eventtime):
extruder_pos = self._get_extruder_pos(eventtime)
# Check for filament runout
- self.runout_helper.note_filament_present(
+ self.runout_helper.note_filament_present(eventtime,
extruder_pos < self.filament_runout_pos)
return eventtime + CHECK_RUNOUT_TIMEOUT
def encoder_event(self, eventtime, state):
@@ -71,7 +71,7 @@ class EncoderSensor:
self._update_filament_runout_pos(eventtime)
# Check for filament insertion
# Filament is always assumed to be present on an encoder event
- self.runout_helper.note_filament_present(True)
+ self.runout_helper.note_filament_present(eventtime, True)
def load_config_prefix(config):
return EncoderSensor(config)
diff --git a/klippy/extras/filament_switch_sensor.py b/klippy/extras/filament_switch_sensor.py
index 51d8ba4b..d1acadd5 100644
--- a/klippy/extras/filament_switch_sensor.py
+++ b/klippy/extras/filament_switch_sensor.py
@@ -5,6 +5,7 @@
# This file may be distributed under the terms of the GNU GPLv3 license.
import logging
+
class RunoutHelper:
def __init__(self, config):
self.name = config.get_name().split()[-1]
@@ -24,7 +25,7 @@ class RunoutHelper:
self.insert_gcode = gcode_macro.load_template(
config, 'insert_gcode')
self.pause_delay = config.getfloat('pause_delay', .5, above=.0)
- self.event_delay = config.getfloat('event_delay', 3., above=0.)
+ self.event_delay = config.getfloat('event_delay', 3., minval=.0)
# Internal state
self.min_event_systime = self.reactor.NEVER
self.filament_present = False
@@ -59,19 +60,20 @@ class RunoutHelper:
except Exception:
logging.exception("Script running error")
self.min_event_systime = self.reactor.monotonic() + self.event_delay
- def note_filament_present(self, is_filament_present):
+ def note_filament_present(self, eventtime, is_filament_present):
if is_filament_present == self.filament_present:
return
self.filament_present = is_filament_present
- eventtime = self.reactor.monotonic()
+
if eventtime < self.min_event_systime or not self.sensor_enabled:
# do not process during the initialization time, duplicates,
# during the event delay time, while an event is running, or
# when the sensor is disabled
return
# Determine "printing" status
+ now = self.reactor.monotonic()
idle_timeout = self.printer.lookup_object("idle_timeout")
- is_printing = idle_timeout.get_status(eventtime)["state"] == "Printing"
+ is_printing = idle_timeout.get_status(now)["state"] == "Printing"
# Perform filament action associated with status change (if any)
if is_filament_present:
if not is_printing and self.insert_gcode is not None:
@@ -79,14 +81,14 @@ class RunoutHelper:
self.min_event_systime = self.reactor.NEVER
logging.info(
"Filament Sensor %s: insert event detected, Time %.2f" %
- (self.name, eventtime))
+ (self.name, now))
self.reactor.register_callback(self._insert_event_handler)
elif is_printing and self.runout_gcode is not None:
# runout detected
self.min_event_systime = self.reactor.NEVER
logging.info(
"Filament Sensor %s: runout event detected, Time %.2f" %
- (self.name, eventtime))
+ (self.name, now))
self.reactor.register_callback(self._runout_event_handler)
def get_status(self, eventtime):
return {
@@ -108,11 +110,12 @@ class SwitchSensor:
printer = config.get_printer()
buttons = printer.load_object(config, 'buttons')
switch_pin = config.get('switch_pin')
- buttons.register_buttons([switch_pin], self._button_handler)
+ buttons.register_debounce_button(switch_pin, self._button_handler
+ , config)
self.runout_helper = RunoutHelper(config)
self.get_status = self.runout_helper.get_status
def _button_handler(self, eventtime, state):
- self.runout_helper.note_filament_present(state)
+ self.runout_helper.note_filament_present(eventtime, state)
def load_config_prefix(config):
return SwitchSensor(config)
diff --git a/klippy/extras/gcode_button.py b/klippy/extras/gcode_button.py
index 669edfb4..de280c98 100644
--- a/klippy/extras/gcode_button.py
+++ b/klippy/extras/gcode_button.py
@@ -5,6 +5,7 @@
# This file may be distributed under the terms of the GNU GPLv3 license.
import logging
+
class GCodeButton:
def __init__(self, config):
self.printer = config.get_printer()
@@ -13,12 +14,13 @@ class GCodeButton:
self.last_state = 0
buttons = self.printer.load_object(config, "buttons")
if config.get('analog_range', None) is None:
- buttons.register_buttons([self.pin], self.button_callback)
+ buttons.register_debounce_button(self.pin, self.button_callback
+ , config)
else:
amin, amax = config.getfloatlist('analog_range', count=2)
pullup = config.getfloat('analog_pullup_resistor', 4700., above=0.)
- buttons.register_adc_button(self.pin, amin, amax, pullup,
- self.button_callback)
+ buttons.register_debounce_adc_button(self.pin, amin, amax, pullup,
+ self.button_callback, config)
gcode_macro = self.printer.load_object(config, 'gcode_macro')
self.press_template = gcode_macro.load_template(config, 'press_gcode')
self.release_template = gcode_macro.load_template(config,
diff --git a/klippy/extras/hall_filament_width_sensor.py b/klippy/extras/hall_filament_width_sensor.py
index 8dab3522..c71b2b2e 100644
--- a/klippy/extras/hall_filament_width_sensor.py
+++ b/klippy/extras/hall_filament_width_sensor.py
@@ -125,7 +125,7 @@ class HallFilamentWidthSensor:
# Update filament array for lastFilamentWidthReading
self.update_filament_array(last_epos)
# Check runout
- self.runout_helper.note_filament_present(
+ self.runout_helper.note_filament_present(eventtime,
self.runout_dia_min <= self.diameter <= self.runout_dia_max)
# Does filament exists
if self.diameter > 0.5: