Skip to content

Commit

Permalink
Fixed issues with HappyHare (#188)
Browse files Browse the repository at this point in the history
* Fixed issues with HappyHare

* Added doc and fixed reset behaviour

* Removed unused import
  • Loading branch information
Zeanon authored Apr 10, 2024
1 parent 5c196ee commit 898009a
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 30 deletions.
8 changes: 8 additions & 0 deletions docs/Config_Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -4807,6 +4807,13 @@ more information.
# If set to true the sensor will use the virtual_sd_card module to determine
# whether the printer is printing which is more reliable but will not work
# when streaming a print over usb or similar.
#always_fire_events:
# If set to true, runout events will always fire no matter whether the sensor
# is enabled or disabled. Usefull for MMUs
#check_on_print_start:
# If set to true, the sensor will be reevaluated when a print starts and if
# no filament is detected the runout_gcode will be run no matter the defined
# runout_distance(immediate_runout_gcode will not be run in this case)
```

### [filament_motion_sensor]
Expand Down Expand Up @@ -4834,6 +4841,7 @@ switch_pin:
#event_delay:
#pause_delay:
#smart:
#always_fire_events:
# See the "filament_switch_sensor" section for a description of the
# above parameters.
```
Expand Down
21 changes: 13 additions & 8 deletions docs/G-Codes.md
Original file line number Diff line number Diff line change
Expand Up @@ -549,29 +549,34 @@ depend on the sensor type defined in the configuration.
#### SET_FILAMENT_SENSOR
###### For filament_switch_sensor:
`SET_FILAMENT_SENSOR SENSOR=<sensor_name> [ENABLE=0|1] [RESET=0|1]
[RUNOUT_DISTANCE=<mm>] [SMART=0|1]`: Sets values for the
filament sensor. If all parameters are omitted, the current stats will
be reported. <br>
[RUNOUT_DISTANCE=<mm>] [SMART=0|1] [ALWAYS_FIRE_EVENTS=0|1] [CHECK_ON_PRINT_START=0|1]`:
Sets values for the filament sensor.
If all parameters are omitted, the current stats will be reported. <br>
ENABLE sets the filament sensor on/off. If ENABLE is set to 0, the
filament sensor will be disabled, if set to 1 it is enabled. If the state
of the sensor changes, a reset will be triggered. <br>
RESET removes all pending runout_gcodes and pauses and force a reevaluation
of the sensor state. <br>
RUNOUT_DISTANCE sets the runout_distance. <br>
SMART sets the smart parameter.
SMART sets the smart parameter. <br>
ALWAYS_FIRE_EVENTS sets the always_fire_events parameter, if set to true,
a reset of the sensor will be triggered. <br>
CHECK_ON_PRINT_START sets the check_on_print_start parameter.

###### For filament_motion_sensor:
`SET_FILAMENT_SENSOR SENSOR=<sensor_name> [ENABLE=0|1] [RESET=0|1]
[DETECTION_LENGTH=<mm>] [SMART=0|1]`: Sets values for the
filament sensor. If all parameters are omitted, the current stats will
be reported. <br>
[DETECTION_LENGTH=<mm>] [SMART=0|1] [ALWAYS_FIRE_EVENTS=0|1]`:
Sets values for the filament sensor.
If all parameters are omitted, the current stats will be reported. <br>
ENABLE sets the filament sensor on/off. If ENABLE is set to 0, the
filament sensor will be disabled, if set to 1 it is enabled. If the sensor
was previously disabled and gets enabled, a reset will be triggered. <br>
RESET resets the state of the sensor and sets it to filament detected. <br>
DETECTION_LENGTH sets the detection_length, if the new detection length is
different from the old one, a reset will be triggered. <br>
SMART sets the smart parameter.
SMART sets the smart parameter. <br>
ALWAYS_FIRE_EVENTS sets the always_fire_events parameter, no reset will
be triggered.

### [firmware_retraction]

Expand Down
12 changes: 7 additions & 5 deletions klippy/extras/filament_motion_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def _update_filament_runout_pos(self, eventtime=None):
if eventtime is None:
eventtime = self.reactor.monotonic()
self.filament_runout_pos = (
self._get_extruder_pos(eventtime) + self.detection_length
self.get_extruder_pos(eventtime) + self.detection_length
)

def _handle_ready(self):
Expand All @@ -68,14 +68,14 @@ def _handle_not_printing(self, print_time):
self._extruder_pos_update_timer, self.reactor.NEVER
)

def _get_extruder_pos(self, eventtime=None):
def get_extruder_pos(self, eventtime=None):
if eventtime is None:
eventtime = self.reactor.monotonic()
print_time = self.estimated_print_time(eventtime)
return self.extruder.find_past_position(print_time)

def _extruder_pos_update_event(self, eventtime):
extruder_pos = self._get_extruder_pos(eventtime)
extruder_pos = self.get_extruder_pos(eventtime)
# Check for filament runout
self.runout_helper.note_filament_present(
extruder_pos < self.filament_runout_pos
Expand All @@ -94,7 +94,8 @@ def get_sensor_status(self):
"Filament Sensor %s: %s\n"
"Filament Detected: %s\n"
"Detection Length: %.2f\n"
"Smart: %s"
"Smart: %s\n"
"Always Fire Events: %s"
% (
self.runout_helper.name,
(
Expand All @@ -105,6 +106,7 @@ def get_sensor_status(self):
"true" if self.runout_helper.filament_present else "false",
self.detection_length,
"true" if self.runout_helper.smart else "false",
"true" if self.runout_helper.always_fire_events else "false",
)
)

Expand All @@ -118,7 +120,7 @@ def get_info(self, gcmd):
return True
return False

def reset_needed(self, enable):
def reset_needed(self, enable=None, always_fire_events=None):
if enable and not self.runout_helper.sensor_enabled:
return True
return False
Expand Down
71 changes: 54 additions & 17 deletions klippy/extras/filament_switch_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
# This file may be distributed under the terms of the GNU GPLv3 license.
import logging


CHECK_RUNOUT_TIMEOUT = 0.250


Expand Down Expand Up @@ -40,15 +39,12 @@ def __init__(self, config, defined_sensor, runout_distance=0):
self.filament_present = False
self.sensor_enabled = True
self.smart = config.getboolean("smart", False)
self.always_fire_events = config.getboolean("always_fire_events", False)
self.runout_position = 0.0
self.runout_elapsed = 0.0
self.runout_distance_timer = None
self.force_trigger = False
# Register commands and event handlers
self.printer.register_event_handler("klippy:ready", self._handle_ready)
self.printer.register_event_handler(
"idle_timeout:printing", self._handle_printing
)
self.gcode.register_mux_command(
"QUERY_FILAMENT_SENSOR",
"SENSOR",
Expand All @@ -67,9 +63,6 @@ def __init__(self, config, defined_sensor, runout_distance=0):
def _handle_ready(self):
self.min_event_systime = self.reactor.monotonic() + 2.0

def _handle_printing(self, print_time):
self.note_filament_present(self.filament_present, True)

def _runout_event_handler(self, eventtime):
if self.immediate_runout_gcode is not None:
self._exec_gcode("", self.immediate_runout_gcode)
Expand Down Expand Up @@ -125,12 +118,18 @@ def _exec_gcode(self, prefix, template):
logging.exception("Script running error")
self.min_event_systime = self.reactor.monotonic() + self.event_delay

def note_filament_present(self, is_filament_present, force=False):
def note_filament_present(
self, is_filament_present=None, force=False, immediate=False
):
if is_filament_present is None:
is_filament_present = self.filament_present
if is_filament_present == self.filament_present and not force:
return
self.filament_present = is_filament_present
eventtime = self.reactor.monotonic()
if eventtime < self.min_event_systime:
if eventtime < self.min_event_systime or (
not self.always_fire_events and 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
Expand Down Expand Up @@ -166,13 +165,18 @@ def note_filament_present(self, is_filament_present, force=False):
"Filament Sensor %s: runout event detected, Time %.2f"
% (self.name, eventtime)
)
self.reactor.register_callback(self._runout_event_handler)
self.reactor.register_callback(
self._execute_runout
if immediate
else self._runout_event_handler
)

def get_status(self, eventtime):
status = {
"filament_detected": bool(self.filament_present),
"enabled": bool(self.sensor_enabled),
"smart": bool(self.smart),
"always_fire_events": bool(self.always_fire_events),
}
status.update(self.defined_sensor.sensor_get_status(eventtime))
return status
Expand All @@ -192,24 +196,32 @@ def cmd_SET_FILAMENT_SENSOR(self, gcmd):
enable = gcmd.get_int("ENABLE", None, minval=0, maxval=1)
reset = gcmd.get_int("RESET", None, minval=0, maxval=1)
smart = gcmd.get_int("SMART", None, minval=0, maxval=1)
always_fire_events = gcmd.get_int(
"ALWAYS_FIRE_EVENTS", None, minval=0, maxval=1
)
reset_needed = False
if (
enable is None
and reset is None
and smart is None
and always_fire_events is None
and self.defined_sensor.get_info(gcmd)
):
return
if enable is not None:
if self.defined_sensor.reset_needed(enable):
reset_needed = True
self.sensor_enabled = enable
if reset is not None and reset:
reset_needed = True
if smart is not None:
self.smart = smart
if always_fire_events is not None:
self.always_fire_events = always_fire_events
if self.defined_sensor.set_filament_sensor(gcmd):
reset_needed = True
if self.defined_sensor.reset_needed(
enable=enable, always_fire_events=always_fire_events
):
reset_needed = True
if reset_needed:
self.defined_sensor.reset()

Expand All @@ -222,6 +234,9 @@ def __init__(self, config):
switch_pin = config.get("switch_pin")
runout_distance = config.getfloat("runout_distance", 0.0, minval=0.0)
buttons.register_buttons([switch_pin], self._button_handler)
self.check_on_print_start = config.getboolean(
"check_on_print_start", False
)
self.reactor = self.printer.get_reactor()
self.estimated_print_time = None
self.runout_helper = RunoutHelper(config, self, runout_distance)
Expand All @@ -231,12 +246,19 @@ def __init__(self, config):
)
self.get_status = self.runout_helper.get_status
self.printer.register_event_handler("klippy:ready", self._handle_ready)
self.printer.register_event_handler(
"idle_timeout:printing", self._handle_printing
)

def _handle_ready(self):
self.estimated_print_time = self.printer.lookup_object(
"mcu"
).estimated_print_time

def _handle_printing(self, print_time):
if self.check_on_print_start:
self.runout_helper.note_filament_present(None, True, True)

def _button_handler(self, eventtime, state):
self.runout_helper.note_filament_present(state)

Expand All @@ -253,39 +275,54 @@ def get_sensor_status(self):
"Filament Detected: %s\n"
"Runout Distance: %.2f\n"
"Runout Elapsed: %.2f\n"
"Smart: %s"
"Smart: %s\n"
"Always Fire Events: %s\n"
"Check on Print Start: %s"
% (
self.runout_helper.name,
"enabled" if self.runout_helper.sensor_enabled else "disabled",
"true" if self.runout_helper.filament_present else "false",
self.runout_helper.runout_distance,
self.runout_helper.runout_elapsed,
"true" if self.runout_helper.smart else "false",
"true" if self.runout_helper.always_fire_events else "false",
"true" if self.check_on_print_start else "false",
)
)

def sensor_get_status(self, eventtime):
return {
"runout_distance": float(self.runout_helper.runout_distance),
"runout_elapsed": float(self.runout_helper.runout_elapsed),
"check_on_print_start": bool(self.check_on_print_start),
}

def get_info(self, gcmd):
runout_distance = gcmd.get_float("RUNOUT_DISTANCE", None, minval=0.0)
if runout_distance is None:
check_on_print_start = gcmd.get_int(
"CHECK_ON_PRINT_START", None, minval=0, maxval=1
)
if runout_distance is None and check_on_print_start is None:
gcmd.respond_info(self.get_sensor_status())
return True
return False

def reset_needed(self, enable):
if enable != self.runout_helper.sensor_enabled:
def reset_needed(self, enable=None, always_fire_events=None):
if enable is not None and enable != self.runout_helper.sensor_enabled:
return True
if always_fire_events is not None and always_fire_events:
return True
return False

def set_filament_sensor(self, gcmd):
runout_distance = gcmd.get_float("RUNOUT_DISTANCE", None, minval=0.0)
check_on_print_start = gcmd.get_int(
"CHECK_ON_PRINT_START", None, minval=0, maxval=1
)
if runout_distance is not None:
self.runout_helper.runout_distance = runout_distance
if check_on_print_start is not None:
self.check_on_print_start = check_on_print_start
# No reset is needed when changing the runout_distance, so we always
# return False
return False
Expand Down

0 comments on commit 898009a

Please sign in to comment.