From ae0c3fcff19ba1adc46bf5b52dab4fc0261b064b Mon Sep 17 00:00:00 2001 From: David Osbourn Date: Thu, 11 Apr 2024 23:41:29 +0100 Subject: [PATCH 1/9] Adding code and documentaion changes to notifier-enhancement branch --- docs/configuration.md | 10 ++--- moonraker/common.py | 1 + moonraker/components/job_state.py | 9 ++++- moonraker/components/notifier.py | 61 +++++++++++++++++++++++++++++-- 4 files changed, 69 insertions(+), 12 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index a035caa4a..b867f6ce6 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1746,15 +1746,11 @@ disk or cloned from unofficial sources are not supported. [update_manager] enable_auto_refresh: False -# When set to True, Moonraker will check roughly every 1 hour (only within -# the update window) whether it's time to fetch status about available updates. +# When set to True Moonraker will attempt to fetch status about +# available updates roughly every 24 hours, between 12am-4am. # When set to False Moonraker will only fetch update state on startup # and clients will need to request that Moonraker updates state. The # default is False. -refresh_window: 0-5 -# The hours between which the periodic update check will be done. -# Default is 0-5, meaning the refresh can only occur from midnight until 5am. -# It can go over midnight, e.g. 22-6. refresh_interval: 672 # The interval (in hours) after which the update manager will check # for new updates. This interval is applies to updates for Moonraker, @@ -2837,7 +2833,7 @@ state_response_template: # # The above example assumes a json response with multiple fields in a struct # is received. Individual measurements are extracted from that struct, coerced -# to a numeric format and passed to Moonraker. This parameter must be provided. +# to a numeric format and passed to Moonraker. The default is the payload. ``` !!! Note diff --git a/moonraker/common.py b/moonraker/common.py index c8460389d..4efdbaef8 100644 --- a/moonraker/common.py +++ b/moonraker/common.py @@ -109,6 +109,7 @@ def __str__(self) -> str: return self._name_.lower() # type: ignore class JobEvent(ExtendedEnum): + LAYER_CHANGED = 0 STANDBY = 1 STARTED = 2 PAUSED = 3 diff --git a/moonraker/components/job_state.py b/moonraker/components/job_state.py index eec17cd83..72c363e7b 100644 --- a/moonraker/components/job_state.py +++ b/moonraker/components/job_state.py @@ -79,9 +79,14 @@ async def _status_update(self, data: Dict[str, Any], _: float) -> None: if "info" in ps: cur_layer: Optional[int] = ps["info"].get("current_layer") if cur_layer is not None: - total: int = ps["info"].get("total_layer", 0) self.server.send_event( - "job_state:layer_changed", cur_layer, total + "job_state:layer_changed", + "layer_changed", + {}, # empty previous stats + ps # print stats + # This layout keeps the event.args[1] consistent with other + # notifier events as the current print stats in the + # moonraker.conf notifier configurations ) self.last_print_stats.update(ps) diff --git a/moonraker/components/notifier.py b/moonraker/components/notifier.py index 7f01296e6..92df2cea3 100644 --- a/moonraker/components/notifier.py +++ b/moonraker/components/notifier.py @@ -10,6 +10,7 @@ import logging import pathlib import re +from datetime import datetime # To allow timestamp to be generated from ..common import JobEvent, RequestType # Annotation imports @@ -41,7 +42,13 @@ def __init__(self, config: ConfigHelper) -> None: if job_event == JobEvent.STANDBY: continue evt_name = str(job_event) - if "*" in notifier.events or evt_name in notifier.events: + # add extra AND condition (and evt_name != 'layer_change') + # to * to exclude layer_change from being automatically picked + # up by the * otherwise it triggers on EVERY layer change + if ("*" in notifier.events and evt_name != 'layer_changed') or \ + evt_name in notifier.events: + + logging.info(f"Job Event loading: {evt_name}") self.events.setdefault(evt_name, []).append(notifier) logging.info(f"Registered notifier: '{notifier.get_name()}'") except Exception as e: @@ -54,6 +61,9 @@ def __init__(self, config: ConfigHelper) -> None: self.server.register_event_handler( "job_state:state_changed", self._on_job_state_changed ) + self.server.register_event_handler( + "job_state:layer_changed", self._on_job_layer_changed + ) def register_remote_actions(self): self.server.register_remote_method("notify", self.notify_action) @@ -74,6 +84,36 @@ async def _on_job_state_changed( for notifier in self.events.get(evt_name, []): await notifier.notify(evt_name, [prev_stats, new_stats]) + async def _on_job_layer_changed( + self, + job_event: JobEvent, + prev_stats: Dict[str, Any], + new_stats: Dict[str, Any] + ) -> None: + evt_name = str(job_event) + if "info" in new_stats: + for notifier in self.events.get(evt_name, []): + # get config value: + # percentage of layers to generate the layer change notification + layer_trigger = notifier.layer_trigger + # get config value: + # only send message if the layer number is greater than this value. + minimum_layers = notifier.minimum_layers + # total layers from the gcode + total = int(new_stats["info"]["total_layer"]) + # current layer counter + current = int(new_stats["info"]["current_layer"]) + # calculate if we've hit a % trigger point above the min height + # this isn't nice to read because of the 88 char line limit + if layer_trigger != 0 and total >= minimum_layers and current > 0 and \ + current != total and \ + round(current/total/layer_trigger, 5)//1 != \ + round(((current-1)/total)/layer_trigger, 5)//1: + + logging.info(f"Layer change notification at \ + {round(current/total/layer_trigger,5)//1*layer_trigger*100}%") + await notifier.notify(evt_name, [{}, new_stats]) + def register_endpoints(self, config: ConfigHelper): self.server.register_endpoint( "/server/notifiers/list", RequestType.GET, self._handle_notifier_list @@ -123,6 +163,16 @@ def __init__(self, config: ConfigHelper) -> None: self.apprise = apprise.Apprise() self.attach = config.gettemplate("attach", None) url_template = config.gettemplate("url") + self.layer_trigger = float(config.get("layer_trigger", 0)) + self.minimum_layers = int(config.get("minimum_layers", 0)) + if self.layer_trigger < 0 or self.layer_trigger > 1: + # layer_trigger out of range. Default to 0 and send logging info + logging.info( + f"Layer change trigger out of range for Notifier {self.name}. " + + f"Expected decimal between 0 and 1, found {self.layer_trigger}. " + + "Ignoring layer change trigger." + ) + self.layer_trigger = 0 self.url = url_template.render() if re.match(r"\w+?://", self.url) is None: @@ -145,7 +195,10 @@ def as_dict(self): "body": self.config.get("body", None), "body_format": self.config.get("body_format", None), "events": self.events, - "attach": self.attach + "attach": self.attach, + # include the additional parameters in the return data + "layer_trigger": self.config.get("layer_trigger", 0), + "minimum_layers": self.config.get("minimum_layers", 0) } async def notify( @@ -154,7 +207,9 @@ async def notify( context = { "event_name": event_name, "event_args": event_args, - "event_message": message + "event_message": message, + # Add linux timestamp to every notication payload + "timestamp": datetime.now() } rendered_title = ( From 554c10f547a90cd3b967033739bda15d8aadfca4 Mon Sep 17 00:00:00 2001 From: David Osbourn Date: Thu, 11 Apr 2024 23:41:29 +0100 Subject: [PATCH 2/9] Adding code and documentation changes to notifier-enhancement branch --- docs/configuration.md | 10 ++--- moonraker/common.py | 1 + moonraker/components/job_state.py | 9 ++++- moonraker/components/notifier.py | 61 +++++++++++++++++++++++++++++-- 4 files changed, 69 insertions(+), 12 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index a035caa4a..b867f6ce6 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1746,15 +1746,11 @@ disk or cloned from unofficial sources are not supported. [update_manager] enable_auto_refresh: False -# When set to True, Moonraker will check roughly every 1 hour (only within -# the update window) whether it's time to fetch status about available updates. +# When set to True Moonraker will attempt to fetch status about +# available updates roughly every 24 hours, between 12am-4am. # When set to False Moonraker will only fetch update state on startup # and clients will need to request that Moonraker updates state. The # default is False. -refresh_window: 0-5 -# The hours between which the periodic update check will be done. -# Default is 0-5, meaning the refresh can only occur from midnight until 5am. -# It can go over midnight, e.g. 22-6. refresh_interval: 672 # The interval (in hours) after which the update manager will check # for new updates. This interval is applies to updates for Moonraker, @@ -2837,7 +2833,7 @@ state_response_template: # # The above example assumes a json response with multiple fields in a struct # is received. Individual measurements are extracted from that struct, coerced -# to a numeric format and passed to Moonraker. This parameter must be provided. +# to a numeric format and passed to Moonraker. The default is the payload. ``` !!! Note diff --git a/moonraker/common.py b/moonraker/common.py index c8460389d..4efdbaef8 100644 --- a/moonraker/common.py +++ b/moonraker/common.py @@ -109,6 +109,7 @@ def __str__(self) -> str: return self._name_.lower() # type: ignore class JobEvent(ExtendedEnum): + LAYER_CHANGED = 0 STANDBY = 1 STARTED = 2 PAUSED = 3 diff --git a/moonraker/components/job_state.py b/moonraker/components/job_state.py index eec17cd83..72c363e7b 100644 --- a/moonraker/components/job_state.py +++ b/moonraker/components/job_state.py @@ -79,9 +79,14 @@ async def _status_update(self, data: Dict[str, Any], _: float) -> None: if "info" in ps: cur_layer: Optional[int] = ps["info"].get("current_layer") if cur_layer is not None: - total: int = ps["info"].get("total_layer", 0) self.server.send_event( - "job_state:layer_changed", cur_layer, total + "job_state:layer_changed", + "layer_changed", + {}, # empty previous stats + ps # print stats + # This layout keeps the event.args[1] consistent with other + # notifier events as the current print stats in the + # moonraker.conf notifier configurations ) self.last_print_stats.update(ps) diff --git a/moonraker/components/notifier.py b/moonraker/components/notifier.py index 7f01296e6..92df2cea3 100644 --- a/moonraker/components/notifier.py +++ b/moonraker/components/notifier.py @@ -10,6 +10,7 @@ import logging import pathlib import re +from datetime import datetime # To allow timestamp to be generated from ..common import JobEvent, RequestType # Annotation imports @@ -41,7 +42,13 @@ def __init__(self, config: ConfigHelper) -> None: if job_event == JobEvent.STANDBY: continue evt_name = str(job_event) - if "*" in notifier.events or evt_name in notifier.events: + # add extra AND condition (and evt_name != 'layer_change') + # to * to exclude layer_change from being automatically picked + # up by the * otherwise it triggers on EVERY layer change + if ("*" in notifier.events and evt_name != 'layer_changed') or \ + evt_name in notifier.events: + + logging.info(f"Job Event loading: {evt_name}") self.events.setdefault(evt_name, []).append(notifier) logging.info(f"Registered notifier: '{notifier.get_name()}'") except Exception as e: @@ -54,6 +61,9 @@ def __init__(self, config: ConfigHelper) -> None: self.server.register_event_handler( "job_state:state_changed", self._on_job_state_changed ) + self.server.register_event_handler( + "job_state:layer_changed", self._on_job_layer_changed + ) def register_remote_actions(self): self.server.register_remote_method("notify", self.notify_action) @@ -74,6 +84,36 @@ async def _on_job_state_changed( for notifier in self.events.get(evt_name, []): await notifier.notify(evt_name, [prev_stats, new_stats]) + async def _on_job_layer_changed( + self, + job_event: JobEvent, + prev_stats: Dict[str, Any], + new_stats: Dict[str, Any] + ) -> None: + evt_name = str(job_event) + if "info" in new_stats: + for notifier in self.events.get(evt_name, []): + # get config value: + # percentage of layers to generate the layer change notification + layer_trigger = notifier.layer_trigger + # get config value: + # only send message if the layer number is greater than this value. + minimum_layers = notifier.minimum_layers + # total layers from the gcode + total = int(new_stats["info"]["total_layer"]) + # current layer counter + current = int(new_stats["info"]["current_layer"]) + # calculate if we've hit a % trigger point above the min height + # this isn't nice to read because of the 88 char line limit + if layer_trigger != 0 and total >= minimum_layers and current > 0 and \ + current != total and \ + round(current/total/layer_trigger, 5)//1 != \ + round(((current-1)/total)/layer_trigger, 5)//1: + + logging.info(f"Layer change notification at \ + {round(current/total/layer_trigger,5)//1*layer_trigger*100}%") + await notifier.notify(evt_name, [{}, new_stats]) + def register_endpoints(self, config: ConfigHelper): self.server.register_endpoint( "/server/notifiers/list", RequestType.GET, self._handle_notifier_list @@ -123,6 +163,16 @@ def __init__(self, config: ConfigHelper) -> None: self.apprise = apprise.Apprise() self.attach = config.gettemplate("attach", None) url_template = config.gettemplate("url") + self.layer_trigger = float(config.get("layer_trigger", 0)) + self.minimum_layers = int(config.get("minimum_layers", 0)) + if self.layer_trigger < 0 or self.layer_trigger > 1: + # layer_trigger out of range. Default to 0 and send logging info + logging.info( + f"Layer change trigger out of range for Notifier {self.name}. " + + f"Expected decimal between 0 and 1, found {self.layer_trigger}. " + + "Ignoring layer change trigger." + ) + self.layer_trigger = 0 self.url = url_template.render() if re.match(r"\w+?://", self.url) is None: @@ -145,7 +195,10 @@ def as_dict(self): "body": self.config.get("body", None), "body_format": self.config.get("body_format", None), "events": self.events, - "attach": self.attach + "attach": self.attach, + # include the additional parameters in the return data + "layer_trigger": self.config.get("layer_trigger", 0), + "minimum_layers": self.config.get("minimum_layers", 0) } async def notify( @@ -154,7 +207,9 @@ async def notify( context = { "event_name": event_name, "event_args": event_args, - "event_message": message + "event_message": message, + # Add linux timestamp to every notication payload + "timestamp": datetime.now() } rendered_title = ( From e3028b7d5e207fc70da26a0572498ae07c36980f Mon Sep 17 00:00:00 2001 From: David Osbourn Date: Fri, 12 Apr 2024 00:11:30 +0100 Subject: [PATCH 3/9] Restarted configuration.md from main branch --- docs/configuration.md | 110 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 20 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index b867f6ce6..77c115a03 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1746,11 +1746,15 @@ disk or cloned from unofficial sources are not supported. [update_manager] enable_auto_refresh: False -# When set to True Moonraker will attempt to fetch status about -# available updates roughly every 24 hours, between 12am-4am. +# When set to True, Moonraker will check roughly every 1 hour (only within +# the update window) whether it's time to fetch status about available updates. # When set to False Moonraker will only fetch update state on startup # and clients will need to request that Moonraker updates state. The # default is False. +refresh_window: 0-5 +# The hours between which the periodic update check will be done. +# Default is 0-5, meaning the refresh can only occur from midnight until 5am. +# It can go over midnight, e.g. 22-6. refresh_interval: 672 # The interval (in hours) after which the update manager will check # for new updates. This interval is applies to updates for Moonraker, @@ -2620,6 +2624,7 @@ events: * # cancelled # paused # resumed +# layer_changed - note, this is excluded from *. See below. # This parameter must be provided. body: "Your printer status has changed to {event_name}" # The body of the notification. This option accepts Jinja2 templates, where @@ -2653,22 +2658,28 @@ attach: ``` !!! Tip - The `event_args` field of the Jinja2 context passed to templates in - this section receives a list of "arguments" passed to the event. For - those familiar with Python this list is known as "variable arguments". - Currently the notifier only supports two kinds of events: those - triggered by a change in the job state and those triggered from a remote - method call frm a `gcode_macro`. - - For `remote method` events the `event_args` field will always be - an empty list. For `job state` events the `event_args` field will - contain two items. The first item (`event_args[0]`) contains the - job state recorded prior to the event, the second item (`event_args[1]`) - contains the current job state. In most cases users will be interested - in the current job state (`event_args[1]`). - - The `job state` is a dict that contains the values reported by - Klipper's [print_stats](printer_objects.md#print_stats) object. +The `event_args` field of the Jinja2 context passed to templates in +this section receives a list of "arguments" passed to the event. For +those familiar with Python this list is known as "variable arguments". +Currently the notifier only supports two kinds of events: those +triggered by a change in the job state and those triggered from a remote +method call frm a `gcode_macro`. + +For `remote method` events the `event_args` field will always be +an empty list. For `job state` events the `event_args` field will +contain two items. The first item (`event_args[0]`) contains the +job state recorded prior to the event, the second item (`event_args[1]`) +contains the current job state. In most cases users will be interested +in the current job state (`event_args[1]`). + +The `job state` is a dict that contains the values reported by +Klipper's [print_stats](printer_objects.md#print_stats) object. + +A timestamp value, generated from Python's datetime.now() function, is also included +in the event data. This can be presented in a notification message in your preferred +date and time format in Jinja2 using the strftime function and [format +patterns](https://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior). +For example: `{timestamp.strftime('%d/%m/%Y %H:%M.%S')}` #### An example: ```ini @@ -2698,6 +2709,65 @@ body: {event_message} attach: http://192.168.1.100/webcam/?action=snapshot ``` +#### Configuring layer change progress notifications +The `layer_changed` notification event can be generated at configurable layer change +percentages during the print. Additional configuration parameters can be created in a +[notifier my_layer_change_message] block. + +The layer_change event receives a reduced set of information from the print. +`event_args[0]` is empty in the layer change event, with `event_args[1]` holding a +limited version of the current print state. + +``` +event_arg[1].total_duration: current number of seconds the job has been running. +event_arg[1].print_duration: current number of seconds the job has been printing. +event_arg[1].filament used: current length of filament used. +event_arg[1].info.total_layer: total number of layers declared in the job's G-code. +event_arg[1].info.current_layer: the current layer number. +``` + +Multiple `events: layer_changed` notifier configurations are permitted, e.g. if you +want to use multiple notifier services, or permit more frequent progress updates for +larger (taller) prints. + +In order to pass the total layer count and current layer count, additional G-code is +required from the the slicer. Add the following to the `Start G-code` and `After layer +change G-code`. The following are taken from the printer custom G-code in PrusaSlicer. + +#### Start G-code: +`SET_PRINT_STATS_INFO TOTAL_LAYER=[total_layer_count]` + +#### After layer change G-code: +`SET_PRINT_STATS_INFO CURRENT_LAYER={layer_num + 1}` + +An example: +```ini +# moonraker.conf + +[notifier event_layerchange] +url: tgram://{bottoken}/{ChatID} +events: layer_changed +layer_trigger: 0.25 +# a ratio between 0.0 and 1.0 representing at which percentage of the progess +# (current layer / total layers) to trigger the layer change message. +# Note this can only be generated based on layer progress. There are currently no +# estimated duration statistics available. +# 0.25 would generate a message every 25% (25%, 50% and 75%). No layer change is +# generated at 0%, because this is the start event, nor 100% as this is the complete +# event. If layer_trigger is not specified, or out of 0.0-1.0 it defaults to 0 and +# no messages are generated. +minimum_layers: 100 +# the whole number of total layers the print must be before progress messages are +# generated. This stops progress messages being generated in quick succession +# for smaller prints. +body: Progress Update + Layer Count: {event_args[1].info.current_layer} of {event_args[1].info.total_layer} + Layer Progress: { + (event_args[1].info.current_layer / event_args[1].info.total_layer * 100 + if event_args[1].info.total_layer is not none and event_args[1].info.total_layer > 0 + else 0)| int}% +``` + #### Notifying from Klipper It is possible to invoke your notifiers from the Klippy host, this can be done with a gcode_macro, such as: @@ -2833,7 +2903,7 @@ state_response_template: # # The above example assumes a json response with multiple fields in a struct # is received. Individual measurements are extracted from that struct, coerced -# to a numeric format and passed to Moonraker. The default is the payload. +# to a numeric format and passed to Moonraker. This parameter must be provided. ``` !!! Note @@ -3043,4 +3113,4 @@ make the changes. check to make sure that the formatting is correct. Once the changes are complete you may use the UI to restart Moonraker and -the warnings should clear. +the warnings should clear. \ No newline at end of file From 182bfdb034d7889fe53ecad70330974350e832db Mon Sep 17 00:00:00 2001 From: David Osbourn Date: Fri, 12 Apr 2024 00:15:56 +0100 Subject: [PATCH 4/9] Minor tweaks to configuration.md --- docs/configuration.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 77c115a03..6ca2e3137 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -2675,10 +2675,11 @@ in the current job state (`event_args[1]`). The `job state` is a dict that contains the values reported by Klipper's [print_stats](printer_objects.md#print_stats) object. -A timestamp value, generated from Python's datetime.now() function, is also included -in the event data. This can be presented in a notification message in your preferred -date and time format in Jinja2 using the strftime function and [format -patterns](https://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior). +A `timestamp` value, generated from Python's `datetime.now()` function, is also +included in the event data. This can be presented in a notification message in +your preferred date and time format in Jinja2 using the `strftime` function and +[format patterns]( +https://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior). For example: `{timestamp.strftime('%d/%m/%Y %H:%M.%S')}` #### An example: From db594acba6c71d30f91484347555fed3e177aebe Mon Sep 17 00:00:00 2001 From: David Osbourn Date: Fri, 12 Apr 2024 00:19:12 +0100 Subject: [PATCH 5/9] More minor tweaks to configuration.md --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 6ca2e3137..539a3317c 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -2713,7 +2713,7 @@ attach: http://192.168.1.100/webcam/?action=snapshot #### Configuring layer change progress notifications The `layer_changed` notification event can be generated at configurable layer change percentages during the print. Additional configuration parameters can be created in a -[notifier my_layer_change_message] block. +`[notifier my_layer_change_message]` block. The layer_change event receives a reduced set of information from the print. `event_args[0]` is empty in the layer change event, with `event_args[1]` holding a From 77f77fcf8fdcdb978941296339af77e268d02de5 Mon Sep 17 00:00:00 2001 From: thankyousam Date: Wed, 12 Jun 2024 19:18:43 +0100 Subject: [PATCH 6/9] Update moonraker/components/notifier.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Niccolò Maggioni --- moonraker/components/notifier.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/moonraker/components/notifier.py b/moonraker/components/notifier.py index 92df2cea3..9847f8810 100644 --- a/moonraker/components/notifier.py +++ b/moonraker/components/notifier.py @@ -110,8 +110,10 @@ async def _on_job_layer_changed( round(current/total/layer_trigger, 5)//1 != \ round(((current-1)/total)/layer_trigger, 5)//1: - logging.info(f"Layer change notification at \ - {round(current/total/layer_trigger,5)//1*layer_trigger*100}%") + logging.info( + "Layer change notification at " + f"{round(current/total/layer_trigger,5)//1*layer_trigger*100}%" + ) await notifier.notify(evt_name, [{}, new_stats]) def register_endpoints(self, config: ConfigHelper): From 2dcc238d080a0af71f3011ba152a386a910a2de2 Mon Sep 17 00:00:00 2001 From: thankyousam Date: Wed, 12 Jun 2024 19:19:09 +0100 Subject: [PATCH 7/9] Update moonraker/components/notifier.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Niccolò Maggioni --- moonraker/components/notifier.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/moonraker/components/notifier.py b/moonraker/components/notifier.py index 9847f8810..d32441476 100644 --- a/moonraker/components/notifier.py +++ b/moonraker/components/notifier.py @@ -171,8 +171,8 @@ def __init__(self, config: ConfigHelper) -> None: # layer_trigger out of range. Default to 0 and send logging info logging.info( f"Layer change trigger out of range for Notifier {self.name}. " - + f"Expected decimal between 0 and 1, found {self.layer_trigger}. " - + "Ignoring layer change trigger." + f"Expected decimal between 0 and 1, found {self.layer_trigger}. " + "Ignoring layer change trigger." ) self.layer_trigger = 0 self.url = url_template.render() From cfe6df3722433bd8842982684fc77736bae04cc5 Mon Sep 17 00:00:00 2001 From: David Osbourn Date: Wed, 12 Jun 2024 20:46:43 +0100 Subject: [PATCH 8/9] Adding filename to event_args[1] in layer_change notifier event --- moonraker/components/job_state.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/moonraker/components/job_state.py b/moonraker/components/job_state.py index 72c363e7b..9d61e81d6 100644 --- a/moonraker/components/job_state.py +++ b/moonraker/components/job_state.py @@ -78,6 +78,9 @@ async def _status_update(self, data: Dict[str, Any], _: float) -> None: ) if "info" in ps: cur_layer: Optional[int] = ps["info"].get("current_layer") + prev_ps = dict(self.last_print_stats) + if "filename" in prev_ps: # inject filename from last_print_stats + ps["filename"] = prev_ps["filename"] if cur_layer is not None: self.server.send_event( "job_state:layer_changed", From c705ef08b42837f166118599fc965e686da388cc Mon Sep 17 00:00:00 2001 From: David Osbourn Date: Wed, 12 Jun 2024 20:50:56 +0100 Subject: [PATCH 9/9] Fixed failed syntax style test --- moonraker/components/job_state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonraker/components/job_state.py b/moonraker/components/job_state.py index 9d61e81d6..50a874e16 100644 --- a/moonraker/components/job_state.py +++ b/moonraker/components/job_state.py @@ -79,7 +79,7 @@ async def _status_update(self, data: Dict[str, Any], _: float) -> None: if "info" in ps: cur_layer: Optional[int] = ps["info"].get("current_layer") prev_ps = dict(self.last_print_stats) - if "filename" in prev_ps: # inject filename from last_print_stats + if "filename" in prev_ps: # inject filename from last_print_stats ps["filename"] = prev_ps["filename"] if cur_layer is not None: self.server.send_event(