Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed issues with HappyHare #188

Merged
merged 3 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading