What if I want to run daemon.g at less than 10 second intervals?
-
I just wanted to clarify a couple of things with regards to daemon.g
Of course I could just "suck it and see" but better if everyone learns something.I understand that the frequency that daemon.g is run was reduced from 1 second intervals to 10 seconds to reduce the amount of time spent accessing the SD card.
It has also been stated that a loop can be created in daemon.g should we require more frequent readings or actions.
What hasn't been covered (to my knowledge) is the implications of creating a loop which lasts longer than 10 seconds.
I presume RRF checks if the daemon process/thread is running before attempting to start a new one?
I.e "there can only be one"If an infinite loop were created, would it still be possible to rename daemon.g in order to modify?
Or would we need to do something like set a variable (which we can modify from the console) which we check before the loop for cases where we need to modify the daemon ?
e.g
if global.modify_daemon = true M99 ; exit daemon ; or maybe do test within loop and use "break" 🤔 ; rest of daemon will run in infinite loop at high frequency while true ; rest of code
Are there any other implications of running the daemon in an infinite loop?
-
Lazy sunday, so I decided to answer some of this myself
@owend said in daemon.g usage "rules" clarification:
What hasn't been covered (to my knowledge) is the implications of creating a loop which lasts longer than 10 seconds.
I presume RRF checks if the daemon process/thread is running before attempting to start a new one?
I.e "there can only be one"This seems to be the case. The daemon does not try to re-open if an instance already exists in memory.
If an infinite loop were created, would it still be possible to rename daemon.g in order to modify?
Yes, you can rename it in order to edit the contents. However your revision won't take effect until the runnning instance of daemon.g is stopped (which will allow the new file to be loaded from disk)
Or would we need to do something like set a variable (which we can modify from the console) which we check before the loop for cases where we need to modify the daemon ?
I chose to do this as a fail safe. Restarting would load the new file, but I wanted a way to ensure I wasn't stuck in a loop.
So I made a couple of global variable in config.gAre there any other implications of running the daemon in an infinite loop?
This question I haven't fully answered. More variables = more memory taken from the stack.
I guess it'll depend on what you do in daemon.g as to whether it could have effect on printing.For those interested here's what I did.
In config.g I added
if !exists(global.RunDaemon) global RunDaemon=true else set global.RunDaemon=true ; Global Variables for heater checking routine in daemon.g if !exists(global.HeaterCheckInterval) global HeaterCheckInterval=10 ; variable for use in daemon.g sets interval of heater checks else set global.HeaterCheckInterval=10 ; variable for use in daemon.g sets interval of heater checks
I then created two macros for "starting" and "stopping" the daemon
StartDaemon.g
;0:/macros/Daemon control/StartDaemon.g set global.RunDaemon = true M38 "0:/sys/daemon.g" ; check if dameon.g exists by trying to calculate hash if result = 2 ; file not found M38 "0:/sys/daemon.g.bak" ; check if dameon.g.bak exists by trying to calculate hash if result = 0 M291 P"No daemon.g found" R"Daemon.g not found but daemon.g.bak found. Rename now?" S3 M471 S"0:/sys/daemon.g.bak" T"0:/sys/daemon.g" ; rename dameon.g.bak to daemon.g if result = 0 echo "Daemon successfully renamed. Hit F5 on browser to refresh" else M291 P"Error" R"Unable to rename file" S2 else M291 P"No daemon found" R"Daemon.g not found." S2
StopDaemon.g
set global.RunDaemon = false M471 S"0:/sys/daemon.g" T"0:/sys/daemon.g.bak" ; rename dameon.g if result = 0 M291 R"Daemon.g stopped" P"Daemon.g has been stopped and renamed. Hit F5 to refresh browser" S2 else M291 R"Error" P"Could not rename daemon.g" S2
My daemon.g was then modified so that I had an infinite loop
I could use G4 to set the timing of this, however I have broken down sections which I can run at selected intervals
As it turns out, I wanted to check my heaters at 10 second intervals (which I was doing when daemon.g ran at 1Hz)Note that anything not contained inside the infinite loop would only ever get run at the first loading of daemon.g and only then if the code was placed BEFORE the infinite loop.
daemon.g
; 0:/sys/daemon.g ; runs continually in background at approximately 10 second intervals ; We have initiated an infinite loop at the start so that we can do things at intervals less than 10 seconds ; daemon.g won't be opened again if it it still running ; everything must be indented by 2 x tabs becasue of the infinite loop at the start to allow checks at intervals less than 10 seconds ; We have created a global variable in config.g called RunDaemon ; If RunDaemon is set to "false" nothing inside the infinite loop will run, however daemon.g will still be run every 10 seconds if it exists. ; Any code outside the infinite loop would run at 10 second intervals provided it came before the loop while true if global.RunDaemon == false M99 ; exit the macro else ;add code that must be run at less than 10 second intervals here ;HEATER CHECKS ; this section of daemon.g checks for heater faults ; RRF doesn't currently check for faults when idle but by default will shut down during printing if temperature excursion is > 15 degrees. ; Note: temp excursion value and time may be manually set using M570 ; checking if temp is rising requires a variable. ; G4 could be used but would also delay anything else in daemon.g ; this way allows other checks to run more frequently if needed however the G4 delays inside the loop will affect the frequency of daemon.g ; will be updated when variables are available in RRF. ; everything must be indented by 2 x tabs becasue of the infinite loop at the start to allow checks at intervals less than 10 seconds while iterations < #heat.heaters ; loop through all configured heaters set global.LastTemp=heat.heaters[1].current ; Set variable to current extruder temp. if state.upTime < 60 break; If uptime is < 60 seconds, break out so all fans etc have time to stabilise. if ((global.LastCheckTime + global.HeaterCheckInterval) > state.upTime) ; if checked in last 10 seconds escape loop and go to rest of daemon.g if present. offset will be zero at startup via config.g ;echo "skipping loop " ^ " " ^ state.upTime ^ " " ^ global.LastCheckTime+10 if global.LastCheckTime-state.upTime > 60 ; uptime must have rolled over so reset off set to zero G10 P2 Y0 echo "upTime has rolled over. Heater checking reset" break else ;echo "checking heater " ^ iterations ^ " " ^ state.upTime ^ " " ^ global.LastCheckTime+10 if heat.heaters[iterations].state="tuning" ;echo "heater " ^ iterations ^ " is tuning - no check carried out" continue ; don't check this heater as it is PID auto tuning if (heat.heaters[iterations].current) > (heat.heaters[iterations].max) ; temp is over max so emergency shutdown required ;M41 P5 S1 ; activate output connected to externally powered latching relay here to sound alarm M118 P0 S"heater over max temp fault detected in daemon.g. - shutting down" L1 M112; emergency shutdown M81 S1 ; turn off power when fans have turned off if (heat.heaters[iterations].current > 45) && (heat.heaters[iterations].active > 45); no real danger at below this temp as ambient may be close to this ;echo "heater " ^ iterations ^ " is above 45 degrees" if (heat.heaters[iterations].state!="off") && (heat.heaters[iterations].current > heat.heaters[iterations].active + 15) ; temp is > 15 degrees above target. ;echo "heater " ^ iterations ^ " is on or in standby - checking if temp is rising" set global.LastTemp=heat.heaters[iterations].current ; set the last check temp ;echo "heater " ^ iterations ^ " temp: " ^ heat.heaters[iterations].current G4 S3 ; wait 3 seconds if (heat.heaters[iterations].current > global.LastTemp + 0.5) ; heat is rising by more than 0.5 degrees in 3 seconds echo "heater runaway fault detected in daemon.g. - shutting down" if (state.status=="processing") M25 ; pause print so you might be able to save it using M119 ;M41 P5 S1 ; activate output connected to externally powered latching relay here to sound alarm M0 ; unconditional stop. If axes are homed and a print is being canceled will run cancel.g otherwise will run stop.g M81 S1 ; turn off power when fans have turned off else ;echo "heater is on or standby but temp is falling on heater " ^ iterations ^ " - no action needed" elif (heat.heaters[iterations].state="off") && ((heat.heaters[iterations].current) >= (fans[1].thermostatic.lowTemperature+0)) ; if heater is off and temp is greater than 50 there could be an issue set global.LastTemp=heat.heaters[iterations].current; ;echo "heater " ^ iterations ^ " is off but checking if temp is rising" G4 S3 ; wait 3 seconds if (heat.heaters[iterations].current > global.LastTemp + 0.5) ; heat is rising by more than 0.5 degrees in 3 seconds echo "heater is off but temp is rising on heater " ^ iterations ^ "emergency shutdown" ;M41 P5 S1 ; activate output connected to externally powered latching relay here to sound alarm echo "heater runaway fault detected in daemon.g. - shutting down" M112; emergency shutdown M81 S1 ; turn off power when fans have turned off else ;echo "heater " ^ iterations ^ " is off & temp is falling or stable on heater " ^ iterations ^ " - no action needed" else ;echo "heater " ^ iterations ^ " is below 45 degrees so check thermistor" ;"heater is below 45 degrees so only other fault may be an open circuit thermistor which should show -275 degrees" if heat.heaters[iterations].current < 0 ; we probably have a thermistor fault if heater is less than 0 degrees M112 ; emergency shutdown M81 S1 ; turn off power when fans have turned off ;Check if water pump is running correctly if (iterations=1) && ((heat.heaters[1].current) > (fans[1].thermostatic.lowTemperature+0)) if fans[1].rpm <= 500 ; Coolant pump RPM off or low G4 S3 ; check again in 3 seconds in case it's just spinning up if fans[1].rpm <= 500 echo "Water pump fault - shutting down heaters - RPM : " ^ fans[1].rpm M25 ; pause print so you might be able to save it using M119 M0 ; unconditional stop. If axes are homed and a print is being canceled will run cancel.g otherwise will run stop.g M81 S1 ; turn off power when fans have turned off elif (fans[1].rpm > 500) && (fans[1].rpm < 1400) G4 S3 ; check again in 3 seconds in case it's just spinning up if (fans[1].rpm > 500) && (fans[1].rpm < 1400) echo "WARNING: Water pump RPM low - RPM : " ^ fans[1].rpm if (state.status=="processing") M25 ; pause print so you might be able to save it using M119 ;M41 P5 S1 ; activate output connected to externally powered latching relay here to sound alarm M0 ; unconditional stop. If axes are homed and a print is being canceled will run cancel.g otherwise will run stop.g M81 S1 ; turn off power when fans have turned off else ;echo "Coolant OK - RPM : " ^ fans[1].rpm if fans[2].rpm <=1000 echo "WARNING: Water pump FAN RPM low - RPM : " ^ fans[2].rpm if (state.status=="processing") M25 ; pause print so you might be able to save it using M119 ;M41 P5 S1 ; activate output connected to externally powered latching relay here to sound alarm M0 ; unconditional stop. If axes are homed and a print is being canceled will run cancel.g otherwise will run stop.g M81 S1 ; turn off power when fans have turned off if iterations == #heat.heaters-1 ; all heaters have been checked set global.LastCheckTime=state.upTime ; set the new time to check ; END HEATER CHECKS ; BEGIN OTHER CHECKS AT INTERVALS LESS THAN 10 SECONDS ; run other checks - don't forget to add 2 x tabs ;echo state.upTime ^ ":" ^ state.msUpTime ; should run very fast ;G4 P500