-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
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
Asynchronous temperature setting, and cancel of temperature wait #6662
base: master
Are you sure you want to change the base?
Conversation
Report if g-code processing is delayed waiting for a heater to reach a temperature, along with the sensor that is being checked. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Add a mechanism for api clients to asynchronously set a target temperature. That is, a mechanism to set the temperature without needing to wait for G-Code commands to complete. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
hey @KevinOConnor! Thx for the ping and this feature! I started with the implementation with the display of "temperature_wait" and I took a closer look at the behavior. i would like to continue to set normal temperature changes with |
Yes - the SET_HEATER_TEMPERATURE command is still available and still a useful way to set the temperature. The proposed -Kevin |
We have now thought internally (Mainsail-Crew) about using this new API call and have found two use cases. use case 1: cancel print during the preheat (START_PRINT) use case 2: adjust bed or extruder temp during a preheat Do you have a better suggestion for implementing these two use cases, or do I misunderstand the API call? |
The main use case I had in mind was changing the temperature without waiting for other actions to complete. For example, if one sets the extruder to 240, sets the bed to 80, and then waits on the bed temperature - then this PR would allow one to change the extruder temperature (eg, set 210) without having to wait for the bed to fully heat first.
What follow up commands are required? If the print has issued a "wait for heater_bed to reach 60" and mainsail sends an "asynchronous set heater_bed to 0 command" then the target temperature for heater_bed will immediately be set to zero (ie, off). Then the "wait for heater_bed command" will raise an error, on_gcode_error will run, it will (likely) set the heater_bed temperature to zero (which is redundant but harmless). So, the heater should be off and the sdcard print will no longer progress.
I guess that is what I'd expect to happen in that case. What action is preferred? I guess, if I issue a command to "set the bed temperature to 80 and wait for that temperature" (ie, To be clear, this PR is open for discussion. We can certainly change the details, implement an alternative, or skip it. Cheers, EDIT: Other use cases would be changing temperatures during bed_mesh, quad_gantry_level, and other long running startup commands. |
In use case 1, we would prefer the command In use case 2, every Calling
Is there a good possibility of detecting that such a command like quad_gantry_level is being executed? I don't think there is an entry in |
I do see value in what is proposed here, however I do agree with @meteyou that the fact |
Okay - thanks for the feedback. I'm not entirely sure I understand the alternate implementation being suggested. It sounds like what is being proposed is that an asynchronous temperature change would not cause an existing "wait on temperature" (eg, FWIW, exiting the wait command early without raising an error does not seem viable to me, as it would have nasty failure situations. Consider the case where a user issued an It does sound like there isn't consensus on this change though. There might still be value in supporting asynchronous temperature changes, but it seems that it is probably best to not mix it with "cancelling" of an existing wait on temperature.
Just "thinking out lout", we could add a mechanism for Klipper to announce it is in a long running operation. Maybe something like Thanks again, |
Just for clarification. If something like this is added to on_gcode_error:
I know, code above needs more stuff, like cancel print when target temperature was set to 0. Lets say the printer is in a start macro, heating up the bed, the user notices it was a old gcode file and the new material needs 5°C more bed tempererature. Will the above even work? If yes, what will happen? The wait in start macro is canceled, on_gcode_error is called -> the above code will wait for new target. If the macro would continue, then a different exit path would be better. Instead of on_gcode_error, maybe something like on_wait_interrupt with parameters of the command that was interrupted and the new temperature target, if thats possible. If the macro would be canceled anyways. Print a warning and ignore the change of the temperature would be enough and additionaly adding a async cancel print would be better in my oppionion (no need to emergency stop and not losing home etc.) |
I have misunderstood the API call until now and therefore misinterpreted the Would such an implementation be possible?
I love the implementation of |
Hi,
Just to be clear, the code on this PR does three main things:
The reason I added the error check to
That doesn't sound like it would work well in the failure situation above. Changing the target of the wait is also problematic. It is probably technically possible for Happy to change this PR though or go a different direction.
Okay, thanks. I'm fine with merging that into mainline Klipper. Cheers, |
This is also why I only want to send this API command if a "set temp & wait" gcode is already active for this particular heater. For any normal state (just set a target without a wait), I would just set the target temperature via the SET_HEATER_TEMPERATURE (the standard behavior when you set a target in the temperature panel). We could also add a prompt in the GUI to ask the user if they want to "set & wait" or "queue the command in the gcode queue". But this confuses the user more than it helps them. However, this decision should not be made or blocked by the API call (in Klipper); in my opinion, the API call should "simply work". Too much logic in this API call could only lead to too many side effects, making it no longer helpful for the user.
I don't know if I can differentiate this properly in the GUI (target heater temp or temperature_wait). I have to test this use case to give a good answer. Right now, I'm talking only about the M109 and M190 gcodes. Maybe I have time this weekend to give here a better feedback. |
As a simple user (and likely all that have a Marlin background), I would expect to simply overwrite any previous "set and wait" with a new value from the webifs.
If there are any more complex API calls involved in the background, I'd expect the webifs to take care of whatever is needed. |
I have implemented this function so that you can see it live. So, when You can download a Mainsail build from the CI workflow (https://github.com/mainsail-crew/mainsail/actions/runs/10334206411?pr=1967). Just unzip the ZIP file and exchange the content of the folder /home/pi/mainsail with it. After a force refresh (ctrl+shift+F5), you have the test build and can play around with the API command. (You will also see a fire icon with a "!" behind the heater with a current I noticed two things during this test. The first has nothing to do with the command itself, but since there was no
It just waits for the extruder, and after that, it starts waiting for the bed. So, it's not a bug, but I think this will also create the same questions in the support channels when this feature is published. Now, let's move on to the second problem I noticed. Because we are not sending gcode here, the change does not appear in the console. An output would always be desirable here. However, I would make the output more "accurate" than the current error output. This is the current error output:
This is how I would like the output to be:
But if you now play around with the test-build and test the feature in live mode, you will probably recognize our problem with the |
As it is currently I think you would want to use the api call for setting the temperature only when temperature_wait is null (to avoid it erroring and aborting the print unintentionally). It might be good for it to show a confirmation box when temperature_wait is not null so that a user can choose either to issue it async (which will error and abort the print) or alternatively issue the gcode which will apply after the wait and any other queued commands. |
Thanks for working on this.
Good point. This is definitely one of the challenges with anything that involves "cancelling" or "altering" the command stream - the behaviour can be subtly different from the expected behaviour in a way that can cause notable surprise. For example, when I lasted attempted "cancel" logic I ran into the issue described at: #4398 (comment) I guess we could introduce new commands, but for what it is worth I'm not sure that would be worth the effort.
Okay, that's simple enough to change.
Okay, thanks for the feedback. I'll give it some further thought. For what it is worth though, I'm thinking this change may not be suitable for the gui frontends. Mixing asynchronous and synchronous commands is likely to be error prone in general (for example, if a synchronous change is made followed by an asynchronous change, then the two updates might get applied in the inverse order). I also now suspect that attempting any kind of "cancel" via an asynchronous update is also going to be error prone and confusing. In particular, I'm not sure there is consensus on what a "cancel" should do. Thanks again, |
I would currently only use the command if temperature_wait is set for another heater, but not for the current one I want to change. Otherwise, the command makes no sense because if no temperature_wait currently exists, I can send the standard gcode command without the risk of the print being canceled.
In the case of a cancel, I would see the execution of This gcode will already used for failed bed leveling commands (QGL, z-tilt, bed_mesh), which works very well. All reasonably current setups use But if a user also wants a unique solution, he/she can do the same by adding his/her gcode to You don't have to overthink "What should the printer do after canceling. What is wrong and right?" but rather leave this step to the user. We (Mainsail-Crew) only offer the user a "starting point" here, which he/she can change at any time. Just my 2 cents...
In general, an asynchronous method could have a positive impact, especially for frontends (if implemented correctly). I often see requests pointing in this direction, and we can only respond with, "Mainsail uses only gcodes, which are queued..." (this is most often requested for controlling the part fan). I've also seen some very complex macro collections to "block" these synchronous commands from the G-code file and only use the frontend to change it and more... |
Thank you for your contribution to Klipper. Unfortunately, a reviewer has not assigned themselves to this GitHub Pull Request. All Pull Requests are reviewed before merging, and a reviewer will need to volunteer. Further information is available at: https://www.klipper3d.org/CONTRIBUTING.html There are some steps that you can take now:
Unfortunately, if a reviewer does not assign themselves to this GitHub Pull Request then it will be automatically closed. If this happens, then it is a good idea to move further discussion to the Klipper Discourse server. Reviewers can reach out on that forum to let you know if they are interested and when they are available. Best regards, PS: I'm just an automated script, not a human being. |
This PR adds a new
heaters/set_target_temperature
API endpoint. It allows the frontends to asynchronously set a new target temperature. Currently, temperatures are set viaM109
,M104
,M190
,M140
, andSET_HEATER_TEMPERATURE
commands. However, these commands wait in the G-Code command queue, which can be delayed - in particular if the printer is waiting for another temperature to be met. In contrast, the new API call sets the requested target temperature as soon as it is received.To avoid conflicts, if a heater target temperature is set asynchronously through the API while a command is actively waiting for that heater to reach a temperature (
TEMPERATURE_WAIT
,M109
,M190
) then the new asynchronous temperature will be accepted and the waiting command will raise an error. So, for example, if the user ranM190 S200
and then issued a{"method": "heaters/set_target_temperature", "params": {"heater":"heater_bed", "target": 60.0}}
then the target temperature will be set to 60 and theM190
command will report an error. (If the command was issued from a virtual_sdcard based print then that error would cause theon_gcode_error
code to run which may change the target temperature again.)To alert API users of this conflict, this PR also introduces new
printer.heaters.temperature_wait
status information. If Klipper is actively waiting for a temperature (TEMPERATURE_WAIT
,M109
,M190
) it will report that heater (or sensor) involved in the wait. It will reportnull
in the common case where no temperature wait is in progress.These two mechanisms can also be utilized to "cancel a heater wait". An API session could determine if the code is waiting on a temperature and then purposely issue an asynchronous temperature assignment to cause the waiting command to exit early (with an error).
FYI, @meteyou , @pedrolamas , @Arksine .
Thoughts?
-Kevin