diff --git a/README.md b/README.md index 7f746f50b..d5a50fbc0 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ Features merged into the master branch: - [probe: z_calibration](https://github.com/DangerKlippers/danger-klipper/pull/31) ([klipper#4614](https://github.com/Klipper3d/klipper/pull/4614) / [protoloft/z_calibration](https://github.com/protoloft/klipper_z_calibration)) +- [core: danger_options](https://github.com/DangerKlippers/danger-klipper/pull/67) + "Dangerous Klipper for dangerous users" Klipper is a 3d-Printer firmware. It combines the power of a general diff --git a/docs/Config_Reference.md b/docs/Config_Reference.md index 80bae72cc..db2fd576f 100644 --- a/docs/Config_Reference.md +++ b/docs/Config_Reference.md @@ -73,6 +73,31 @@ pins such as "extra_mcu:ar9" may then be used elsewhere in the config [mcu my_extra_mcu] # See the "mcu" section for configuration parameters. ``` +## ⚠️ Danger Options +A collection of DangerKlipper-specific system options +``` +[danger_options] + +# If an unused config option or section should cause an error +# if False, will warn but allow klipper to still run +error_on_unused_config_options: True + +# If statistics should be logged +# (helpful for keeping the log clean during development) +log_statistics: True + +# If the config file should be logged at startup +log_config_file_at_startup: True + +# If the bed mesh should be logged on startup +# (helpful for keeping the log clean during development) +log_bed_mesh_at_startup: True + +# If we should log detailed crash info when an exception occurs +# Most of it is overly-verbose and fluff and we still get a stack trace +# for normal exceptions, so setting to False can help save time while developing +log_shutdown_info: True +``` ## Common kinematic settings diff --git a/klippy/configfile.py b/klippy/configfile.py index e3800c7a0..dc7215da7 100644 --- a/klippy/configfile.py +++ b/klippy/configfile.py @@ -266,6 +266,8 @@ def __init__(self, printer): self.status_save_pending = {} self.status_settings = {} self.status_warnings = [] + self.unused_sections = [] + self.unused_options = [] self.save_config_pending = False gcode = self.printer.lookup_object("gcode") gcode.register_command( @@ -426,7 +428,7 @@ def read_main_config(self): cfg = self._build_config_wrapper(regular_data + autosave_data, filename) return cfg - def check_unused_options(self, config): + def check_unused_options(self, config, error_on_unused): fileconfig = config.fileconfig objects = dict(self.printer.lookup_objects()) # Determine all the fields that have been accessed @@ -439,16 +441,23 @@ def check_unused_options(self, config): for section_name in fileconfig.sections(): section = section_name.lower() if section not in valid_sections and section not in objects: - raise error( - "Section '%s' is not a valid config section" % (section,) - ) + if error_on_unused: + raise error( + "Section '%s' is not a valid config section" + % (section,) + ) + else: + self.unused_sections.append(section) for option in fileconfig.options(section_name): option = option.lower() if (section, option) not in access_tracking: - raise error( - "Option '%s' is not valid in section '%s'" - % (option, section) - ) + if error_on_unused: + raise error( + "Option '%s' is not valid in section '%s'" + % (option, section) + ) + else: + self.unused_options.append((section, option)) # Setup get_status() self._build_status(config) @@ -483,6 +492,20 @@ def _build_status(self, config): res["section"] = section res["option"] = option self.status_warnings.append(res) + for section, option in self.unused_options: + res = {"type": "unused_option"} + res["message"] = "Option '%s' in section '%s' is invalid" % ( + option, + section, + ) + res["section"] = section + res["option"] = option + self.status_warnings.append(res) + for section in self.unused_sections: + res = {"type": "unused_section"} + res["message"] = "Section '%s' is invalid" % (section,) + res["section"] = section + self.status_warnings.append(res) def get_status(self, eventtime): return { diff --git a/klippy/extras/bed_mesh.py b/klippy/extras/bed_mesh.py index 23e4ea4aa..f67786fff 100644 --- a/klippy/extras/bed_mesh.py +++ b/klippy/extras/bed_mesh.py @@ -161,7 +161,9 @@ def __init__(self, config): def handle_connect(self): self.toolhead = self.printer.lookup_object("toolhead") - self.bmc.print_generated_points(logging.info) + self.danger_options = self.printer.lookup_object("danger_options") + if self.danger_options.log_bed_mesh_at_startup: + self.bmc.print_generated_points(logging.info) def set_mesh(self, mesh): if mesh is not None and self.fade_end != self.FADE_DISABLE: diff --git a/klippy/extras/danger_options.py b/klippy/extras/danger_options.py new file mode 100644 index 000000000..c1724223c --- /dev/null +++ b/klippy/extras/danger_options.py @@ -0,0 +1,17 @@ +class DangerOptions: + def __init__(self, config): + self.log_statistics = config.getboolean("log_statistics", True) + self.log_config_file_at_startup = config.getboolean( + "log_config_file_at_startup", True + ) + self.log_bed_mesh_at_startup = config.getboolean( + "log_bed_mesh_at_startup", True + ) + self.log_shutdown_info = config.getboolean("log_shutdown_info", True) + self.error_on_unused_config_options = config.getboolean( + "error_on_unused_config_options", True + ) + + +def load_config(config): + return DangerOptions(config) diff --git a/klippy/extras/statistics.py b/klippy/extras/statistics.py index 2fd18dc19..e3ca9acab 100644 --- a/klippy/extras/statistics.py +++ b/klippy/extras/statistics.py @@ -61,6 +61,7 @@ def get_status(self, eventtime): class PrinterStats: def __init__(self, config): self.printer = config.get_printer() + self.danger_options = self.printer.lookup_object("danger_options") reactor = self.printer.get_reactor() self.stats_timer = reactor.register_timer(self.generate_stats) self.stats_cb = [] @@ -78,7 +79,7 @@ def handle_ready(self): def generate_stats(self, eventtime): stats = [cb(eventtime) for cb in self.stats_cb] - if max([s[0] for s in stats]): + if max([s[0] for s in stats]) and self.danger_options.log_statistics: logging.info( "Stats %.1f: %s", eventtime, " ".join([s[1] for s in stats]) ) diff --git a/klippy/klippy.py b/klippy/klippy.py index 01f3d5450..65c3ee527 100644 --- a/klippy/klippy.py +++ b/klippy/klippy.py @@ -154,7 +154,11 @@ def load_object(self, config, section, default=configfile.sentinel): def _read_config(self): self.objects["configfile"] = pconfig = configfile.PrinterConfig(self) config = pconfig.read_main_config() - if self.bglogger is not None: + danger_options = self.load_object(config, "danger_options") + if ( + self.bglogger is not None + and danger_options.log_config_file_at_startup + ): pconfig.log_config(config) # Create printer components for m in [pins, mcu]: @@ -164,7 +168,8 @@ def _read_config(self): for m in [toolhead]: m.add_printer_objects(config) # Validate that there are no undefined parameters in the config file - pconfig.check_unused_options(config) + error_on_unused = danger_options.error_on_unused_config_options + pconfig.check_unused_options(config, error_on_unused) def _build_protocol_error_message(self, e): host_version = self.start_args["software_version"] @@ -428,6 +433,7 @@ def main(): bglogger = queuelogger.setup_bg_logging(options.logfile, debuglevel) else: logging.getLogger().setLevel(debuglevel) + logging.info("=======================") logging.info("Starting Klippy...") git_info = util.get_git_version() git_vers = git_info["version"] diff --git a/klippy/mcu.py b/klippy/mcu.py index 4ea583921..8db088e8b 100644 --- a/klippy/mcu.py +++ b/klippy/mcu.py @@ -18,6 +18,7 @@ class error(Exception): # Command transmit helper classes ###################################################################### + # Class to retry sending of a query command until a given response is received class RetryAsyncCommand: TIMEOUT_TIME = 5.0 @@ -744,6 +745,7 @@ class MCU: def __init__(self, config, clocksync): self._printer = printer = config.get_printer() + self.danger_options = printer.lookup_object("danger_options") self._clocksync = clocksync self._reactor = printer.get_reactor() self._name = config.get_name() @@ -833,14 +835,15 @@ def _handle_shutdown(self, params): if clock is not None: self._shutdown_clock = self.clock32_to_clock64(clock) self._shutdown_msg = msg = params["static_string_id"] - logging.info( - "MCU '%s' %s: %s\n%s\n%s", - self._name, - params["#name"], - self._shutdown_msg, - self._clocksync.dump_debug(), - self._serial.dump_debug(), - ) + if self.danger_options.log_shutdown_info: + logging.info( + "MCU '%s' %s: %s\n%s\n%s", + self._name, + params["#name"], + self._shutdown_msg, + self._clocksync.dump_debug(), + self._serial.dump_debug(), + ) prefix = "MCU '%s' shutdown: " % (self._name,) if params["#name"] == "is_shutdown": prefix = "Previous MCU '%s' shutdown: " % (self._name,) diff --git a/klippy/toolhead.py b/klippy/toolhead.py index 58f4c2368..7f38a6969 100644 --- a/klippy/toolhead.py +++ b/klippy/toolhead.py @@ -11,6 +11,7 @@ # mm/second), _v2 is velocity squared (mm^2/s^2), _t is time (in # seconds), _r is ratio (scalar between 0.0 and 1.0) + # Class to track each move request class Move: def __init__(self, toolhead, start_pos, end_pos, speed): @@ -128,6 +129,7 @@ def set_junction(self, start_v2, cruise_v2, end_v2): LOOKAHEAD_FLUSH_TIME = 0.250 + # Class to track a list of pending move requests and to facilitate # "look-ahead" across moves to reduce acceleration between moves. class MoveQueue: diff --git a/test/klippy/danger_options.cfg b/test/klippy/danger_options.cfg new file mode 100644 index 000000000..17e4e97d7 --- /dev/null +++ b/test/klippy/danger_options.cfg @@ -0,0 +1,84 @@ + +[poopybutt] +[danger_options] +log_statistics: False +log_config_file_at_startup: False +error_on_unused_config_options: False +log_bed_mesh_at_startup: False +log_shutdown_info: False + +[stepper_x] +step_pin: PF0 +dir_pin: PF1 +enable_pin: !PD7 +microsteps: 16 +rotation_distance: 40 +endstop_pin: ^PE5 +position_endstop: 0 +position_max: 200 +homing_speed: 50 + +[stepper_y] +step_pin: PF6 +dir_pin: !PF7 +enable_pin: !PF2 +microsteps: 16 +rotation_distance: 40 +endstop_pin: ^PJ1 +position_endstop: 0 +position_max: 200 +homing_speed: 50 + +[stepper_z] +step_pin: PL3 +dir_pin: PL1 +enable_pin: !PK0 +microsteps: 16 +rotation_distance: 8 +endstop_pin: probe:z_virtual_endstop +position_max: 200 + +[extruder] +step_pin: PA4 +dir_pin: PA6 +enable_pin: !PA2 +microsteps: 16 +rotation_distance: 33.5 +nozzle_diameter: 0.400 +filament_diameter: 1.750 +heater_pin: PB4 +sensor_type: EPCOS 100K B57560G104F +sensor_pin: PK5 +control: pid +pid_Kp: 22.2 +pid_Ki: 1.08 +pid_Kd: 114 +min_temp: 0 +max_temp: 250 + +[heater_bed] +heater_pin: PH5 +sensor_type: EPCOS 100K B57560G104F +sensor_pin: PK6 +control: watermark +min_temp: 0 +max_temp: 130 + +[probe] +pin: PH6 +z_offset: 1.15 +drop_first_result: true + +[bed_mesh] +mesh_min: 10,10 +mesh_max: 180,180 + +[mcu] +serial: /dev/ttyACM0 + +[printer] +kinematics: cartesian +max_velocity: 300 +max_accel: 3000 +max_z_velocity: 5 +max_z_accel: 100 diff --git a/test/klippy/danger_options.test b/test/klippy/danger_options.test new file mode 100644 index 000000000..b226ad6f0 --- /dev/null +++ b/test/klippy/danger_options.test @@ -0,0 +1,12 @@ +CONFIG danger_options.cfg +DICTIONARY atmega2560.dict + +# Start by homing the printer. +G28 + +G1 F6000 + +# Z / X / Y moves +G1 Z1 +G1 X1 +G1 Y1