Come inibire temporaneamente la sospensione?


10

Ho cercato un po 'per questo e non riesco a trovare nulla di utile.

Ho il mio PC con Ubuntu 12.10 impostato per la sospensione dopo 30 minuti di inattività. Non voglio cambiarlo, funziona alla grande per la maggior parte del tempo.

Quello che voglio fare è disabilitare la sospensione automatica se una particolare applicazione è in esecuzione. Come posso fare questo?

La cosa più vicina che ho trovato finora è quella di aggiungere uno script di shell in /usr/lib/pm-utils/sleep.dcui verifica se l'applicazione è in esecuzione e restituisce 1 per indicare che la sospensione dovrebbe essere impedita. Ma sembra che il sistema abbia rinunciato a sospendere automaticamente, invece di riprovare dopo altri 30 minuti. (Per quanto ne so, se muovo il mouse, questo riavvia nuovamente il timer.) È molto probabile che l'applicazione finisca dopo un paio d'ore, e preferirei che il mio PC si sospendesse automaticamente se non sto usando a quel punto . (Quindi non voglio aggiungere una chiamata a pm-suspend al termine dell'applicazione.)

È possibile?

EDIT: Come ho notato in uno dei commenti qui sotto, quello che volevo veramente era inibire la sospensione quando il mio PC serviva file su NFS; Volevo solo concentrarmi sulla parte "sospendi" della domanda perché avevo già un'idea di come risolvere la parte NFS. Usando l'idea 'xdotool' fornita in una delle risposte, ho escogitato il seguente script che eseguo da cron ogni pochi minuti. Non è l'ideale perché arresta anche lo screensaver, ma funziona. Devo vedere perché la "caffeina" non riattiva correttamente la sospensione in seguito, quindi probabilmente potrei fare di meglio. Ad ogni modo, questo sembra funzionare, quindi lo includo qui nel caso qualcun altro fosse interessato.

#!/bin/bash

# If the output of this function changes between two successive runs of this
# script, we inhibit auto-suspend.
function check_activity()
{
    /usr/sbin/nfsstat --server --list
}

# Prevent the automatic suspend from kicking in. 
function inhibit_suspend()
{
    # Slightly jiggle the mouse pointer about; we do a small step and
    # reverse step to try to stop this being annoying to anyone using the
    # PC. TODO: This isn't ideal, apart from being a bit hacky it stops
    # the screensaver kicking in as well, when all we want is to stop
    # the PC suspending. Can 'caffeine' help?
    export DISPLAY=:0.0
    xdotool mousemove_relative --sync --  1  1
    xdotool mousemove_relative --sync -- -1 -1
}

LOG="$HOME/log/nfs-suspend-blocker.log"
ACTIVITYFILE1="$HOME/tmp/nfs-suspend-blocker.current"
ACTIVITYFILE2="$HOME/tmp/nfs-suspend-blocker.previous"

echo "Started run at $(date)" >> "$LOG"
if [ ! -f "$ACTIVITYFILE1" ]; then
    check_activity > "$ACTIVITYFILE1"
    exit 0;
fi

/bin/mv "$ACTIVITYFILE1" "$ACTIVITYFILE2"
check_activity > "$ACTIVITYFILE1"

if cmp --quiet "$ACTIVITYFILE1" "$ACTIVITYFILE2"; then
    echo "No activity detected since last run" >> "$LOG"
else
    echo "Activity detected since last run; inhibiting suspend" >> "$LOG"
    inhibit_suspend
fi

EDIT 2: lo script sopra funziona ma grazie ad un altro commento qui sotto, sto usando questa coppia di script, che hanno il vantaggio di consentire allo screensaver di dare il via mentre inibisco la sospensione. Il primo è /usr/lib/pm-utils/sleep.d/000nfs-inhibit, che impedirà un tentativo di sospensione se esiste un file di inibizione:

#!/bin/sh

LOG="/home/zorn/log/nfs-suspend-blocker.log"
INHIBITFILE="/home/zorn/tmp/nfs-suspend-blocker.inhibit"

echo "$0: Started run at $(date), arguments: $*" >> "$LOG"
if [ "$1" = "suspend" ] && [ -f "$INHIBITFILE" ]; then
    echo "$0: Inhibiting suspend" >> "$LOG"
    exit 1
fi
exit 0

La seconda è una versione modificata del precedente script nfs-suspend-blocker e dovrebbe comunque essere eseguita da cron. Segue ora la strategia delineata nel commento qui sotto:

#!/bin/bash

# This works in tandem with /usr/lib/pm-utils/sleep.d/000nfs-inhibit, which
# will prevent a suspend occurring if $INHIBITFILE is present. Once it prevents
# a suspend, it appears that it requires some "user activity" to restart the
# timer which will cause a subsequent suspend attempt, so in addition to
# creating or removing $INHIBITFILE this script also jiggles the mouse after
# removing the file to restart the timer.

# If the output of this function changes between two successive runs of this
# script, we inhibit auto-suspend.
function check_activity()
{
    /usr/sbin/nfsstat --server --list
}

# Slightly jiggle the mouse pointer about; we do a small step and reverse step
# to try to stop this being annoying to anyone using the PC.
function jiggle_mouse()
{
    export DISPLAY=:0.0
    xdotool mousemove_relative --sync --  1  1
    xdotool mousemove_relative --sync -- -1 -1
}

LOG="$HOME/log/nfs-suspend-blocker.log"
ACTIVITYFILE1="$HOME/tmp/nfs-suspend-blocker.current"
ACTIVITYFILE2="$HOME/tmp/nfs-suspend-blocker.previous"
INHIBITFILE="$HOME/tmp/nfs-suspend-blocker.inhibit"

echo "$0: Started run at $(date)" >> "$LOG"
if [ ! -f "$ACTIVITYFILE1" ]; then
    check_activity > "$ACTIVITYFILE1"
    exit 0;
fi

/bin/mv "$ACTIVITYFILE1" "$ACTIVITYFILE2"
check_activity > "$ACTIVITYFILE1"

if cmp --quiet "$ACTIVITYFILE1" "$ACTIVITYFILE2"; then
    echo "$0: No activity detected since last run" >> "$LOG"
    if [ -f "$INHIBITFILE" ]; then
            echo "$0: Removing suspend inhibit file and jiggling mouse" >> "$LOG"
            /bin/rm "$INHIBITFILE"
            jiggle_mouse
    fi
else
    echo "$0: Activity detected since last run; inhibiting suspend" >> "$LOG"
    touch "$INHIBITFILE"
fi

Invece di ingombrare la domanda, dovresti mettere le tue due soluzioni al problema come risposta di seguito.
Cas

Risposte:


8

Un programma per mantenere sveglio il tuo computer è la caffeina . Vorrei creare un file .bash_aliases per chiamare anche caffeina quando viene chiamato il tuo codice originale.

alias newname="origcode && caffeine"

A seconda del codice per cui stai cercando di mantenere il tuo computer sveglio, dovrai creare uno script personalizzato che includa l'uccisione della caffeina quando viene fermato l'altro codice. Alcuni ulteriori dettagli su quel particolare codice sarebbero di aiuto.

Aggiornamento: un modo più semplice sarebbe eseguire xdotool , che può essere installato con sudo apt-get install xdotool. È possibile scrivere uno script chiamato quando viene aperto il codice di destinazione e quindi utilizzare il sleepcomando per 29 minuti e quindi eseguire xdotool key ao qualcosa di arbitrario per mantenere il computer sveglio.


2
Per xdo, probabilmente è meglio scegliere una chiave che non fa intrinsecamente qualcosa. Premendo Maiusc, ad esempio, si riattiva lo schermo senza digitare sulla finestra attiva.
Oli

1
Grazie. Stavo deliberatamente nascondendo un po 'di dettagli nella domanda originale - quello che voglio esplicitamente fare è fermare il mio PC (che serve contenuti multimediali tramite NFS) sospendendo mentre il mio media center vi accede. Se conosci un modo per affrontare in modo specifico questo sarebbe fantastico, altrimenti vedrò un paio di strade che consentiranno a questo di funzionare tramite Caffeina (ad esempio il media center entrerà nel mio PC ogni 10 minuti ed eseguirà uno script shell che dorme per 15 minuti).
Zorn,

1
Ho provato la caffeina e sembra funzionare tranne per il fatto che una volta che il programma in esecuzione scompare, l'output della caffeina dice che la sospensione non è più inibita ma l'ho lasciata per il doppio del periodo di inattività e sebbene lo schermo sospeso il PC non lo ha mai fatto. Giocherò ulteriormente con questo, anche se il percorso xdo sarà probabilmente ancora più conveniente e lo proverò prima. PS C'è un modo per inserire una nuova riga in un commento ?!
Zorn,

5

Se

  1. Uno script in /usr/lib/pm-utils/sleep.d può verificare se l'applicazione è in esecuzione e restituire 1 per indicare che è necessario impedire la sospensione.
  2. Il problema di "il sistema quindi rinuncia a sospendere automaticamente, invece di riprovare dopo altri 30 minuti" è risolto spostando il mouse che riavvia nuovamente il timer (spero di aver capito bene cosa intendi con questo)

allora perché non muovere semplicemente il puntatore del mouse al termine dell'applicazione.

Riassumere:

  1. Utilizzare sleep.d per impedire la sospensione del sistema.
  2. Scrivi una sceneggiatura che fa oscillare il mouse una volta.
  3. Chiama "Long-running-script && mousejiggle"

Ciò non ostacolerà lo screensaver.

L'unico problema è che saranno trascorsi 30 minuti dal termine del processo alla sospensione del sistema. Questo è il caso anche della soluzione "EDIT".

PS: stavo cercando una soluzione a un problema simile quando ho saputo di xdotool da questa pagina. Quindi grazie. Spero che sia di aiuto.


Geniale, grazie! Ci proverò questo fine settimana.
Zorn,

Il suggerimento riguardante ha pm-utilsaiutato. Si noti che il pacchetto pm-utilsdeve essere installato affinché questo funzioni: la directory stessa potrebbe esistere anche se il pacchetto non è installato.
krlmlr

1

Sebbene EDIT 2 consenta l'avvio dello screensaver e ripristini il servizio di sospensione automatica alla rimozione del file di inibizione, come notato sopra, saranno trascorsi 30 minuti dalla rimozione del file quando il sistema verrà sospeso.

Una possibile soluzione è disabilitare lo screen saver integrato e la funzionalità di auto-sospensione e implementarli da soli, e scegliere il comportamento del timer come richiesto. Il comando xprintidle(potrebbe essere necessario installarlo) stampa il numero di millisecondi per i quali non vi è stata alcuna attività da tastiera o mouse. Questo apre diverse possibilità. Ho implementato il seguente gestore di inattività in Python (non troppo di uno script di Bash). Le caratteristiche includono l'impostazione del comando, il timeout e l'inibizione del file (l'ho chiamato blocco) per lo screensaver e / o la sospensione automatica. Inoltre, è possibile scegliere se il timer di inattività deve essere riavviato quando il file di inibizione viene rimosso o meno (il comportamento può essere diverso per la sospensione e lo screensaver). Ho cercato di chiarire l'uso nelle note, ma se qualcosa non è chiaro chiedilo.

#!/usr/bin/python

#Notes:##################

#   1. All TIMEOUTs are specified in seconds
#   2. 0 or negative TIMEOUT disables a particular action.
#   3. If an actionCOMMAND (like pm-suspend) requires 'sudo'ing, make them 'sudo'able without password. Alternatively, you may run this script in sudo mode, and make this script sudoable without password. /ubuntu/159007/specific-sudo-commands-without-password
#   4. 'action'_timer_starts_... option: True - if a lock file is created and then removed, inactivity timer (for that action) restarts at the time of deletion of lock. False - doesn't restart.
#   5. screensaverCOMMAND can be screen-lock (security) or screen-off (power saving) or both. To do both, but at different times (I can't see any reason to do so) extend this script from two actions (screensaver, autosuspend) to three (screen-lock, screen-off, autosuspend).

#########################

import os
import time
import threading
import subprocess

HOME = os.getenv('HOME') + '/'

#Configuration###########

screensaverCOMMAND = "gnome-screensaver-command --lock && xset -display :0.0 +dpms dpms force off"
autosuspendCOMMAND = "gnome-screensaver-command --lock && sudo pm-suspend"

screensaverTIMEOUT = 10*60
autosuspendTIMEOUT = 20*60

screensaverLOCK = HOME + ".inactivitymanager/screensaverLOCK"
autosuspendLOCK = HOME + ".inactivitymanager/autosuspendLOCK"

screensaver_timer_starts_only_after_lockfile_is_deleted = False
autosuspend_timer_starts_only_after_lockfile_is_deleted = False

#########################

def stayOn():
    print "inactivitymanager is running..."
    try:
        while True:
            time.sleep(10)
    except:
        print "Closed."

class inactivity_action(threading.Thread):
    def __init__(self, command, timeout, lock, timer_starts_blah):
        threading.Thread.__init__(self)
        self.daemon = True
        self.command = command
        self.timeout = timeout
        self.lock = lock
        self.timer_starts_blah = timer_starts_blah
    def run(self):
        if not(self.timer_starts_blah):
            while True:
                try:
                    while True:
                        time.sleep(1)
                        f = open(self.lock, 'r')
                        f.close()
                except IOError:
                    xidletime = int(subprocess.Popen('xprintidle', stdout = subprocess.PIPE).communicate()[0])/1000
                    if xidletime > self.timeout:
                        os.system(self.command)
                    else:
                        time.sleep(self.timeout - xidletime + 2)
        else:
            lockremovetime = 0
            while True:
                lockdetected = False
                try:
                    while True:
                        time.sleep(1)
                        f = open(self.lock, 'r')
                        f.close()
                        lockdetected = True
                except IOError: #Will enter this section if/when lockfile is/becomes absent
                    xidletime = int(subprocess.Popen('xprintidle', stdout = subprocess.PIPE).communicate()[0])/1000
                    if lockdetected:
                        lockremovetime = int(time.time())
                    timesincelockremove = int(time.time()) - lockremovetime
                    if min(xidletime, timesincelockremove) > self.timeout:
                        os.system(self.command)

if screensaverTIMEOUT > 0:
    inactivity_screensaver = inactivity_action(screensaverCOMMAND, screensaverTIMEOUT, screensaverLOCK, screensaver_timer_starts_only_after_lockfile_is_deleted)
    inactivity_screensaver.start()

if autosuspendTIMEOUT > 0:
    inactivity_autosuspend = inactivity_action(autosuspendCOMMAND, autosuspendTIMEOUT, autosuspendLOCK, autosuspend_timer_starts_only_after_lockfile_is_deleted)
    inactivity_autosuspend.start()

stayOn()

Uso:

  1. Basta aggiungere inactivitymanager &a .profile o .xsessionrc nella home directory (vedi quale funziona per te. Non aggiungere in entrambi, altrimenti due istanze di questo script verranno eseguite contemporaneamente, qualcosa che non ho gestito. Immagino sia in questi dettagli che le implementazioni tradizionali prevalgono su quelle personalizzate).
  2. Potrebbe essere necessario installare xprintidle.

Il modo in cui il file di inibizione arriva lì è lasciato all'immaginazione dell'utente per ora (se mi porto a implementare un demone per questo, lo inserirò in un EDIT per questa risposta). Naturalmente tu (OP) hai risolto il problema. Una trappola da evitare quando si tenta di inibire la sospensione per più di un processo è l'eliminazione del file di blocco quando un processo termina mentre un altro è ancora in esecuzione. In alternativa, lo script può essere leggermente modificato per inibire la sospensione se esiste un file in una directory particolare (una directory di blocco). In questo modo ogni processo può avere il proprio file di blocco.

Appunti:

  1. Questo script è piuttosto leggero sul processore e sulla memoria. Ma rimuovere i time.sleep (1) nel codice potrebbe causare problemi, ma non ho controllato.
  2. pm-suspend richiede le autorizzazioni sudo. Per pm-suspend senza dare il checkout della password Come posso eseguire specifici comandi sudo senza una password? . In alternativa è possibile eseguire questo script in modalità sudo e renderlo eseguibile senza password (non è un problema se si esegue lo script come root)
  3. Lo script potrebbe incorrere in problemi se i timeout sono impostati su meno di ~ 10 secondi (non ho verificato dove inizia esattamente il problema deve essere inferiore a 5, immagino). Questo può essere gestito rimuovendo alcuni time.sleep (1) a spese delle risorse di sistema. Non pensare che qualcuno avrà bisogno di questo però.
  4. Poiché abbiamo un handle sui timer, non è necessario alcun mouse!
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.