Tiny script to suspend the computer if idle for X minutes

Forum Forums General Tips and Tricks Tiny script to suspend the computer if idle for X minutes

  • This topic has 14 replies, 4 voices, and was last updated Feb 2-2:16 am by Robin.
Viewing 15 posts - 1 through 15 (of 15 total)
  • Author
    Posts
  • #130531
    Member
    PPC

      I noticed antiX does seems to not have, out of the box, an easy way to suspend the computer after a given period of inactivity… so I patched together a tiny script that does just that:

      -Requirements: xprintidle, yad

      -How to use:
      Unzip the script and run it. If not indicating any amount in minutes in the terminal, an yad GUI will pop up allowing you do to so. After the set amount of time of being idle, the computer should suspend.
      To terminate the script, run the command:
      killall -q suspend_if_iddle

      P.

      • This topic was modified 2 months, 3 weeks ago by PPC.
      #130665
      Member
      PPC

        I improved the script a bit:
        – it now offers to install xprintidle, if it’s not already installed
        – in the GUI to select the time, clicking “cancel”, now does the logical thing: it not only closes the window but kills the script, stoping the system from suspending when idle for any previous amount of selected minutes.
        – fixed a typo in the script’s name

        I do think this is a niche script, but it’s tiny and adds a functionality that some users may expect, specially when using laptops.

        P.

        • This reply was modified 2 months, 3 weeks ago by PPC.
        #130672
        Member
        PPC

          Because this script is tiny, but adds what may be a very useful Power control setting, I took the liberty of including it in a commit to antix-goodies-2023- https://gitlab.com/antiX-Linux/antix-goodies-2023/-/merge_requests/2/diffs?commit_id=8f7a65d01df63fdc255f6d465fda5afd49cfe7fb
          Since most users won’t even know this feature is missing, if it’s included, any user that requires the system to suspend after being idle for some minutes, just has to run the script, let it install the tiny dependency, and then select the period of time to wait before the idle system sleeps… Or this can be included in the startup file, including the intended waiting period, ex:
          suspend_if_idle 60 &

          Will suspend the system if it’s idle for 60 minutes (1 hour).
          Side effect: the script will stay resident in RAM, using a tiny bit of memory and CPU resources. The other possibility would be altering it and running it as a cronjob, but most folks don’t even know what Cron is…

          P.

          #131054
          Member
          Robin

            Great idea, great script. Congratulations, PPC.

            You could save some CPU resources by increasing the timebase within the loop: Since you ask user for a value in “Minutes”, there is no need to recheck with a resolution of 5 seconds.

            – One possibility could be: If you’d check merely every minute, the shutdown might come a bit less precise, but instead of 720 calls per hour (12 calls per minute), you’d have merely 60 calls per hour.

            – Another one, even less resource wasting, would be: Set the checking interval dependent on the timeout given by user. This should be enough already. If after this interval the idle timer was not reset, send system to suspend state. Otherwise change the timebase from within the loop to the difference of the user-timeout and the lapsed idle time.

            I can’t see what a cronjob could help here: the job entry would also have to be constantly updated by the script, since when working at the PC, the crontab entry has constantly to be renewed after checking the lapsed idle time. Then you can use sleep as well, probably this uses less resources here.

            And you could save resources in RAM probably simply by “outsourcing” the loop without gui etc. to a temp script, running standalone in background, consisting of a couple of calculations and the loop command, while the “heavy” startup and GUI part was exited already. No need to keep the GUI in RAM while running.

            Another idea for further improvement: Instead of keeping the GUI open and waiting for the user to click the Cancel button, simply check on startup as the first task whether the outsourced timer is present in memory, and if so, ask user whether to stop the auto-shutdown. There could be already the enter field for setting the new value, preset with the current value:

            Auto-shutdown after x minutes activated.
            Do you want to stop the auto-shutdown
            service or change the timeout?
            New idle time: [    x ] Min.
            [Yes] [Change timeout] [Shutdown now] [No]
            

            Pressing ESC would have to be equivalent to “No”. The value x could be read from a temp file, written by the former instance. And depending on the answer, either stop the running outsourced loop, remove the temp file, and quit, or do nothing, or stop the running outsourced loop and start another one with the new timebase, change the timebase in temp file.
            If the loop would read the time base from the temp file (just a single integer value within a file) instead of having it hard coded on it’s generation time, you’d even not need to restart the background loop at all, just changing the value in the temp file would be enough after user pressed the change timeout button.
            Only in case no instance has left it’s loop script in memory, come up without the extended GUI, just present your current GUI then.

            And then: I could create an entry for it to live in control centre, using the new functions for adding or removing a startup file entry from within acc. Then this interesting function would be available to everybody, not only to people, fly to manage the startup entries manually in text editor.

            Just some ideas. Would be great if your script could make it just in time into antiX 23.1

            Windows is like a submarine. Open a window and serious problems will start.

            #131062
            Member
            PPC

              Many thanks for your positive review of this script, and specially for the suggestions!
              This script will probably be in the final version of antiX 23.1, since it’s now part of antiX-goodies (https://gitlab.com/antiX-Linux/antix-goodies-2023/-/blob/main/bin/suspend_if_idle?ref_type=heads )
              I wanted to have that script ready in time to be included in that release, out of the box, so I tried to make it as fully featured as I could, as fast as I could, as soon as I got the idea from it (a new user asked how to suspend the computer after it being inactive, what prompted me to check how to do that, notice we had no way of doing that, finding out how to do that, create the first draft of the script, test it, create a basic GUI, placing it here in the forum, having no testers for it, and even so risk presenting the idea to anticapitalista, for incorporation in the goodies package).

              On your suggestions:
              – I never even though about increasing the sleep time. I’m not comfortable with 60 seconds, but something like 30 seconds would still make sure that the computer always is put to sleep in the exact minute it should, while not using too many system resources (note: on my tests, I always chose to make the computer sleep after one minute, so in the extreme, I could end up waiting almost 2 minutes, for the computer to sleep, it the sleep command is 60 seconds right?)
              – I thought about saving the previously selected period in a file, and read that value from the file, to use as default on the GUI, but never got around to doing that (the script is prepared to do it, the script does read the default value from a variable, its just a matter of get the variable to the be the contents of a text file, instead of a just a fixed value)
              – I though about showing a warning before putting the computer to sleep, but I never got around to doing that- a yad window, with a count down, that give, say, some 30 seconds for the user to stop the suspension would be perfect. I pretty much like your suggested window
              – I never even though about outsourcing the “in RAM” part of the script to a sub-script, created on the fly. The script is tiny… that subscript would be even smaller! Excellent idea!

              Currently I won’t be able to spend much time on the script, so, please, if possible, feel free to alter the script in github (it includes a correction on the name of the script that is killed, not present on the last version uploaded here in the forum) and commit any changes that improve this idea.
              I have not created any .desktop file for this script because I think that people never even noticed this feature was missing… until I saw one person asking for it. So the initial idea is, if you require this, it’s already available, just run the command to install the required dependency (that ideally should come pre-installed in antiX its just 70kb or so) and then just run the command, or add it to the start up file… When the script is more matured, I guess it can be included in Control Center, in something like “Power Management”, maybe? The GUI, when possible should be translated in Transifex- as is, the script already has the text strings marked for translation…

              P.

              • This reply was modified 2 months, 3 weeks ago by PPC.
              #131073
              Member
              Robin

                its just a matter of get the variable to the be the contents of a text file, instead of a just a fixed value

                cat is your friend:

                var=$(cat file)

                Since there lives a single integer within this file, you neither need read command to separate lines nor any quotings.
                In case your path might contain blanks:

                var=$(cat "$path-to-file-stored-in-variable")

                And writing an integer from variable to file is as easy:

                cat >file <<<$var

                Also here, quoting only needed if path might contain blanks:

                cat >"$path-to-file-stored-in-variable" <<<$var

                And if $var contains blanks (which can’t happen since you control the file and perfectly know there can be a single integer merely):

                cat >file <<<“$var”

                The GUI, when possible should be translated in Transifex- as is, the script already has the text strings marked for translation

                I’ll put it up there soon as possible.

                I have not created any .desktop file

                A .desktop file is not needed if it has an entry in control centre.

                Currently I won’t be able to spend much time on the script

                Same here. Have to deal with the “abort update” issue @verdy has spotted (many thanks!) in aCSTV first, to get the fix ready timely to be included into antiX 23.1

                But: we could include your script already in current state into aCC, the improvements I have proposed can follow later as updates. They are not essential for providing the functionality, and as you’ve said already: the script is low resource as it is, and works fine.

                Windows is like a submarine. Open a window and serious problems will start.

                #131134
                Member
                anti-apXos

                  I use a similar script to suspend my system using xprintidle, but also with some of the other checks suggested in this discussion:
                  https://www.antixforum.com/forums/topic/poweroff-after-inactivity-a-script/

                  In particular, the check for audio playing and an option to temporarily disable the inactivity timer with a file in /tmp are nice for me. I also added a check of /sys/class/power_supply/AC/online since I only want the timer when I’m on battery. Maybe additional checks like this could be added as toggleable options in this script.

                  #131139
                  Member
                  PPC

                    In particular, the check for audio playing

                    Can you please share that check here on this thread? That would be gold!

                    EDIT1: … and in pure Alsa and also with Pipewire? That would be platine 🙂

                    EDIT2: I just tested this in ALSA, and it works:
                    fuser /dev/snd/timer && echo "Something is playing" || echo "There's silence"

                    But I can’t, for now, test in Pipewire…

                    P.

                    • This reply was modified 2 months, 3 weeks ago by PPC.
                    • This reply was modified 2 months, 3 weeks ago by PPC.
                    #131156
                    Member
                    anti-apXos

                      fuser /dev/snd/timer does not seem to work with Pipewire, but the method using /proc/asound/card* suggested in the other discussion does work Pipewire/PulseAudio as well as just ALSA.

                      This is the script I use (it’s part of another script that already runs every 30 seconds, which is why there’s no loop here).

                      
                      if [ ! -e /tmp/no-sleep ] && \
                        [ $(cat /sys/class/power_supply/AC/online) -eq 0 ] && \
                        [ ! "$(grep -r RUNNING /proc/asound/card*)" ] && \
                        [ $(xprintidle) -gt 3600000 ]; then
                          python3 /usr/local/bin/pm-panel.py &
                         sleep 20
                         [ ! -e /tmp/no-sleep ] && pm hybrid-suspend
                      fi
                      
                      #131158
                      Member
                      PPC

                        I tried to test the grep command and it seemed to do nothing, for some reason, in my tests…

                        But adapting your script does work fine (tested in ALSA):

                        [ ! "$(grep -r RUNNING /proc/asound/card*)" ] && echo "sound not playing"

                        Edit:
                        Neither solution seems “perfect”. I tested using Celluloid. If the media player is paused, even so both ways of getting information about the audio being played report that the audio is being played, when, in fact, it’s not.
                        I guess that what both commands get us is something like “Is a media player running, even if paused?”, and not “Is audio playing?”
                        This is still helpful in the script. Future versions can have the option to “Disable automatic suspension when idle, if a media player is running”.

                        In my particular case… I leave my system on all the time, with dvd disks playing, on pause. So, most of the time, I would disable that setting anyway, since it would stop the system from suspending…

                        P.

                        • This reply was modified 2 months, 3 weeks ago by PPC.
                        #131172
                        Member
                        anti-apXos

                          I tried to test the grep command and it seemed to do nothing, for some reason, in my tests…

                          The command as @Vincent17 wrote it uses the quiet (-q) switch of grep, which isn’t usable with a square-brackets test.

                          Either
                          [ ! "$(grep -r RUNNING /proc/asound/card*)" ] && echo "sound not playing"
                          or
                          ! grep -qr RUNNING /proc/asound/card* && echo "sound not playing"
                          will work. I’m sure the second is really better in several ways, but I prefer the first for some reason.

                          Neither solution seems “perfect”. I tested using Celluloid. If the media player is paused, even so both ways of getting information about the audio being played report that the audio is being played, when, in fact, it’s not.

                          I think some websites if open in a browser will also keep the soundcard RUNNING all the time, too, so, no, not perfect. Maybe there’s some other way, I don’t know.

                          • This reply was modified 2 months, 3 weeks ago by anti-apXos.
                          #131315
                          Member
                          zblsv

                            cat is your friend:
                            var=$(cat file)

                            And if somehow not:
                            var=$(< file)

                            Words are carried away by the wind...

                            #131547
                            Member
                            Robin

                              @PPC There is an issue with the idle-suspend script. While starting with integrating it into control centre yesterday evening, I noticed: If it is used in startup script the default way by coproc’ing it, user can start it a second time. If the new timeout is longer than the old one, only the shorter one of the two is active, while the longer interval set manually by the user later on is ignored. Analysing the strange behaviour turned up:
                              Your script starts multiple parallel instances of itself if called successively:

                              $ suspend_if_idle 21 &
                              $ suspend_if_idle 28 &
                              $ suspend_if_idle 15 &
                              $ suspend_if_idle 29 &
                              $ suspend_if_idle 37 &
                              $ suspend_if_idle 45 &
                              $ ps -aux | grep suspend_if_idle
                              demo      663731  0.0  0.0  77148  3528 pts/0    S    22:10   0:00 /bin/bash /usr/local/bin/suspend_if_idle 21
                              demo      676983  0.0  0.0  77148  3488 pts/0    S    22:11   0:00 /bin/bash /usr/local/bin/suspend_if_idle 28
                              demo      681274  0.0  0.0  77148  2244 pts/0    S    22:11   0:00 /bin/bash /usr/local/bin/suspend_if_idle 15
                              demo      683199  0.0  0.0  77148  3532 pts/0    S    22:11   0:00 /bin/bash /usr/local/bin/suspend_if_idle 29
                              demo      699732  0.0  0.0  77148  2280 pts/0    S    22:12   0:00 /bin/bash /usr/local/bin/suspend_if_idle 37
                              demo      713251  0.0  0.0  77148  2309 pts/0    S    22:12   0:00 /bin/bash /usr/local/bin/suspend_if_idle 45

                              Merely the 15 minute timeout is active, since it is the first one which hits. All the other ones just eat up system resources. And user might wonder why the new command isn’t obeyed sometimes (if he happens to feed a longer interval later), and sometimes obeyed (if he happens to feed a shorter interval later); from user perspective it would be logically to see the last command feeded being active, not the shortest…

                              Diagnosis:
                              You need to kill the old instance, either on startup of the script, or preferable: before starting the new infinite loop, so no restart is necessary if user just aborts.
                              Since killall -q suspend_if_idle as found in within the conditional clause on line 46 kills the currently running instance also (which must stay active), it’s not enough to move it outside the branching block.

                              Proposal for a solution:
                              Please urgently add the line 50/51 to your script:

                              50 # kill former instance before starting a new one.
                              51 for i in $(pidof -x suspend_if_idle); do [ $i -ne $$ ] && kill -15 $i; done

                              Without this being fixed either following my proposal or using any other method to make sure there can’t run multiple instances of this script parallel, it can’t be integrated into the control centre.

                              ———-

                              And then, please rethink the logical course of action, proceeding when pressing the “Abort” button. “Abort” means usually “leave the window, don’t change anything”. But here the abort button actively stops an already set timer. This is something user can’t expect or know. When calling it from the “run” entry in antiX main menu, he can’t know about that leaving the script by ESC key or Abort button actually has disabled something he had set up before (or what was set up by startup) :

                              $ ps -aux | grep suspend_if_idle
                              demo     2152439  0.0  0.0  76948  3340 pts/0    S    07:34   0:00 /bin/bash /usr/local/bin/suspend_if_idle 100
                              $ suspend_if_idle
                              xprintidle is installed, continuing...
                              No value was given, opening the GUI to you can select the value...
                              Variable is empty or zero. Exiting...
                              [1]+  Beendet                 suspend_if_idle 100
                              Beendet
                              $ ps -aux | grep suspend_if_idle | grep -v grep
                              $

                              This is completely unexpected behaviour (but this issue doesn’t impede control centre integration like the beforementioned one, integration will be completed soon) .

                              Nevertheless, please make sure nothing is actively changed or stopped when pressing ESC or Abort. Even when the wording fits and is perfectly right here (meaning implicitly: abort the formerly set up timeout), user is used seeing Abort button not actively aborting something, but as a method of leaveing safely a window without performing any action. This goes even more for the ESC key.

                              Best regards
                              Robin

                              P.S.: Great hint, @zblsv:

                              var=$(< file)
                              Words are carried away by the wind…

                              Hence: Without any further words.

                              Windows is like a submarine. Open a window and serious problems will start.

                              #131565
                              Member
                              PPC

                                @Robin, I tried, but I can’t make that commit – can you please try to do it yourself?

                                Thanks,
                                P.

                                #131651
                                Member
                                Robin

                                  can you please try to do it yourself?

                                  Most pressing fix is applied.
                                  https://gitlab.com/antiX-Linux/antix-goodies-2023/-/merge_requests/3

                                  That wasn’t that difficult, was it? You’d just have had to copy over the two lines from below I had posted formerly already:

                                  50 # kill former instance before starting a new one.
                                  51 for i in $(pidof -x suspend_if_idle); do [ $i -ne $$ ] && kill -15 $i; done

                                  Rest of it has to come when there is some more time. Hint: yad doesn’t seem to know a –range=<value> option found in line 40 of your script. It seems to be silently ignored in your script code. Please see control center lines 615 to 631 for proper syntax.

                                  Please check out it’s control centre integration:

                                  https://gitlab.com/Robin-antiX/control-centre-antix/-/tree/master
                                  You need to copy over the separate png icon files found there, also the ones from within the zip file (png format only) in size 48. Moreover you need to use the updated version of suspend_if_idle.

                                  Windows is like a submarine. Open a window and serious problems will start.

                                Viewing 15 posts - 1 through 15 (of 15 total)
                                • You must be logged in to reply to this topic.