I'm using a Monoprice Select Mini V2, which likes to keep the part cooling fan on whenever the hot end is warmer than about 70 degrees. (In my particular case, there is now a separate always-on heat sink fan, but the MPSM doesn't know that.)
At the end of a print, there seem to be only three options:
Leave the fan on indefinitely.
Turn the fan off.
Wait for N seconds using G4, then turn the fan off.
The last option seems appealing, and I see it suggested pretty frequently. But it has the effect of locking up the printer for however long N seconds is. Even if I have another print I want to run right away, I pretty much have to wait out the cooling period.
OctoPrint knows when the print is finished. What I'd really like is for it, OctoPrint, to wait for N seconds on its own and then send a "turn the fan off immediately" command to the printer as long as I haven't initiated any other operation. Is there any way to achieve this effect?
Writing a plugin that starts a timer when the print finishes and unless some other event cancels said timer finally sends a fan off command when it triggers.
Or flash a firmware that already does that on its own (because that's actually something that should rather be done in firmware).
Probably because on some printers, if you turn off the fan too soon you get a nozzle clog thanks to heat creep. A problem which should be solved either in mechanical design or at the very least firmware, but alas, most cheap manufacturers either don't know what they are doing or don't give a fsck and so recommend blocking the whole serial with minute long dwell commands instead as a bandaid for the issue.
In my case... i cant write a plugin... i would write a bash script: Request the state of the printer and the temp. If printer state and temp are OK send command to turn off fan. If printerstate is printing ... (you restart the print)... exit script.
Below my bash script what i use the check the temp and state:
#!/bin/bash
LOG="/tmp/plug.log"
date | tee -a $LOG
URL="192.168.1.210:5000"
APIKEY="YOURKEY"
COUNT="0"
temp(){
MASTER=$(curl -s -k4 --request GET -H 'X-Api-Key: '"$APIKEY"'' -H 'Content-Type: application/json' http://$URL/api/printer | jq .)
TEMP1="$(jq .temperature.tool0.actual <<< "$MASTER")"
STATE="$(jq .state.flags.operational <<< "$MASTER")"
if [ -z "$TEMP1" ];then
echo "Temp Var is empty... exit script" | tee -a $LOG
exit
fi
TEMP1="$(echo $TEMP1/1|bc)"
echo "$TEMP1"
echo "$STATE"
}
until [ "$TEMP1" -le "40" ] && [ "$COUNT" -ge "10" ];do
echo "waiting for cool down $TEMP1 $(date)" | tee -a $LOG
temp
if [ "$TEMP1" -le "40" ];then
echo "Temp cal check count $COUNT" | tee -a $LOG
COUNT="$(( $COUNT + 1 ))"
else
COUNT=0
fi
if [ "$STATE" != "true" ];then
echo "Print in progress. Exit script" | tee -a $LOG
exit
fi
sleep 10
done
echo "i perform now a action"
curl -k4 --request POST -H 'X-Api-Key: '"$APIKEY"'' -H 'Content-Type: application/json' --data '{"command":"M107"}' http://$URL/api/printer/command
exit
The underlying problem, which I probably didn't communicate very clearly, is that any kind of G-code-based waiting--whether it's waiting for a period of time or waiting for a set temperature to be reached--appears to be uninterruptible as soon as it has been communicated to the printer. Once the command is sent, you're fully committed to that wait and there's nothing OctoPrint can do to cancel or override it.
@foosel's idea to just fix the firmware so it's not so grabby is really the right answer, but this particular printer (a Monoprice Select Mini V2) has proprietary firmware, so it's probably not an option.
It takes a couple of minutes for the hot end to cool to the point where you'd want to turn the fan off, so the wait is potentially problematic. Before the wait is over, you might well want to, e.g., heat the hot end up again to do a different print, or use the printer's front-panel controls to level the bed.
What I'd like to do is have OctoPrint (or an external script) do the waiting instead of the printer, because OctoPrint is a more sophisticated software system than the G-code interpreter and presumably would be able to decide at any point "OK, we can abort this wait because something else is going on."
I'm going to see if I can adapt @Schnello's code outline to the requirements of a plugin, using @foosel's suggestions. I'll keep you updated...