PC-Nutzungszeit tracken

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mm96
User
Beiträge: 30
Registriert: Donnerstag 26. November 2020, 23:24

Hi Leute,

mein Ziel ist es, den Computer nach fünf Stunden Nutzungszeit abzuschalten.
Momentan sieht mein Ansatz so aus, das Ganze wird in den Autostart-Ordner gepackt:

Code: Alles auswählen

import time, os

start_time = time.time()
max_time = 5*3600           # maximale Betriebszeit des PC

while True:
    if start_time + max_time < time.time():
        os.system('shutdown /s /t 300 /c "Bitte Arbeit speichern. Computer wird in 5 Minuten heruntergefahren".')
        break
So schält er allerdings pauschal fünf Stunden nach Hochfahren aus.
Gibt es nun eine Möglichkeit, die Zeiten, in denen der PC im Standby ist, auszuklammern?

Vielleicht irgendeine Bedingung ala
if Ruhezustand == True:
...

Liebe Grüße
mm96
User
Beiträge: 30
Registriert: Donnerstag 26. November 2020, 23:24

Hab den Code nochmal n bisschen geändert, sodass er nicht komplett durchläuft, sondern alle 60 Sek. ne Abfrage macht.
Was mir einfach noch fehlt, ist die Bedingung "System im Standby"...

Code: Alles auswählen

import time, os

start_time = time.time()
max_time = 5*3600          # maximale Betriebszeit des PC

while True:
    if "System im Standby":
        time.sleep(60)
        start_time += 60
        continue
    time.sleep(60)
    if start_time + max_time < time.time():
        os.system('shutdown /s /t 300 /c "Bitte Arbeit speichern. Computer wird in 5 Minuten heruntergefahren".')
        break
LG
Benutzeravatar
__blackjack__
User
Beiträge: 13234
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@mm96: Das könnte so nicht funktionieren weil im Standby ja kein Code ausgeführt wird. Also das ``if "System im Standby":`` kann ja schon *im* Standby nie ausgeführt werden, weil im Standby ja nichts ausgeführt wird. Es müsste also eine API geben mit der man prüfen kann ob und wie lange das System *nach* einem Standby im Standby war, nach der letzten Prüfung in der es *nicht* im Standby war.

Keine Ahnung ob es so etwas gibt, aber wenn, dann dürfte das nicht betriebssystemunabhängig sein. Welches System Du da hast, hast Du glaube ich noch nicht verraten.
Please call it what it is: copyright infringement, not piracy. Piracy takes place in international waters, and involves one or more of theft, murder, rape and kidnapping. Making an unauthorized copy of a piece of software is not piracy, it is an infringement of a government-granted monopoly.
mm96
User
Beiträge: 30
Registriert: Donnerstag 26. November 2020, 23:24

Oh ja, ich hab Windows 10.

Vielleicht muss man da ein Skript für das Auslesen der Ereignisanzeige verwenden, da müssten die Daten ja eigentlich aufgelistet sein. Mit der kenn ich mich noch nicht aus, da muss ich noch genauer nachlesen.
Sirius3
User
Beiträge: 17819
Registriert: Sonntag 21. Oktober 2012, 17:20

mm96
User
Beiträge: 30
Registriert: Donnerstag 26. November 2020, 23:24

Super, vielen Dank!
Jetzt hab ich was, das immerhin funktioniert:

Code: Alles auswählen

from time import time, sleep
from os import system
from datetime import datetime
import subprocess as sp


def last_standby():
    # Ereignisprotokoll zum letzten Standbymodus auslesen und Ausgabe als byte-Objekt speichern
    proc = sp.Popen('''\
                wevtutil qe System /rd:true /f:Text /c:1 /q:"<QueryList><Query Id='0' Path='System'>\
                <Select Path='System'>*[System[Provider[@Name='Microsoft-Windows-Power-Troubleshooter'] and (Level=4 or Level=0)\
                and (EventID=1)]]</Select></Query></QueryList>"\
                ''', shell = True, stdout = sp.PIPE)
    try:
        event = proc.communicate(timeout=15)[0]
    except sp.TimeoutExpired:
        proc.kill()
        event = proc.communicate()[0]

    # Verarbeitung der Daten und Zeiten zu Sekunden seit epoch
    Dates = event.splitlines()[15:17]
    sleep_time = datetime.strptime(Dates[0][27:50].decode('UTF-8').replace('T', ' ').replace('?', ''), '%Y-%m-%d %H:%M:%S')
    sleep_time_sec = sleep_time.timestamp() + 2*3600
    awakening_time = datetime.strptime(Dates[1][21:44].decode('UTF-8').replace('T', ' ').replace('?', ''), '%Y-%m-%d %H:%M:%S')
    awakening_time_sec = awakening_time.timestamp() + 2*3600
    duration = awakening_time_sec - sleep_time_sec

    # Rückgabe Dauer des letzten Standbymodus' und Aktivierungszeitpunkt
    return duration, sleep_time_sec


# Main Program

start_time = time()         # Zeit zu der PC hochfährt
max_time = 5*3600           # maximale Betriebszeit des PC

sleeps = [0]                # Zeitpunkte, zu denen der Standbymodus aktiviert wird
standby = 0                 # Dauer, die der PC im Standbymodus verbringt


while True:        
    duration, sleeptime = last_standby()    

    # sleeptime > start_time soll verhindern, dass der gestrige Standby-Zustand mitgerechnet wird
    # sleeptime > sleeps[-1] soll verhindern, dass der letzte Standby-Zustand mehrmals gerechnet wird          
    if sleeptime > start_time and sleeptime > sleeps[-1]:       
        sleeps.append(sleeptime)
        standby += duration

    if start_time + max_time + standby < time():
        system('shutdown /s /t 300 /c "Maximale PC-Nutzungsdauer erreicht. Computer wird in 5 Minuten heruntergefahren".')
        break

    sleep(120)        # einmal alle halbe Stunde wird geprüft, ob Nutzunsdauer überschritten ist oder wegen Standby-Modus angepasst werden muss
N bisschen Kosmetik fehlt vielleicht noch, aber es läuft wenigstens.

Danke für die Hilfe!
Sirius3
User
Beiträge: 17819
Registriert: Sonntag 21. Oktober 2012, 17:20

Man benutzt keine Abkürzungen, sp für subprocess ist unüblich.
subprocess.Popen benutzt man nicht, subprocess.run kennt ein timeout-Argument. Den Aufruf gibt man als Liste an, nicht als String. Man deokodiert nicht selbst, sondern läßt das auch subprocess.run

Code: Alles auswählen

proc = subprocess.run(["wevtutil", "qe", "System", "/rd:true", "/f:Text", "/c:1",
    "/q:<QueryList><Query Id='0' Path='System'><Select Path='System'>*[System[Provider[@Name='Microsoft-Windows-Power-Troubleshooter'] and (Level=4 or Level=0) and (EventID=1)]]</Select></Query></QueryList>"],
    timeout=15, capture_output=True, text=True)
Im Fall eines Timeouts, macht es dann Sinn einfach weiter zu machen?

Man nimmt keine hart codierten Indizes.

Code: Alles auswählen

lines = proc.stdout.splitlines()
parts = (line.partition(':') for line in lines)
data = {k.strip():v.strip() for k,_,v in parts}
sleep_time = dateutil.parser.isoparse(data['Zeit im Energiesparmodus'].replace('?',''))
awakening_time = dateutil.parser.isoparse(data['Reaktivierungszeit'].replace('?',''))
`os.system` benutzt man erst recht nicht.
mm96
User
Beiträge: 30
Registriert: Donnerstag 26. November 2020, 23:24

Wow, danke für die vielen Tipps!
Ich hab die try-except-Schleife jetzt so bearbeitet, dass sie bei nem Timeout abbricht:

Code: Alles auswählen

try:
        proc = subprocess.run(["wevtutil", "qe", "System", "/rd:true", "/f:Text", "/c:1", "/q:<QueryList><Query Id='0' Path='System'>\
                <Select Path='System'>*[System[Provider[@Name='Microsoft-Windows-Power-Troubleshooter'] and (Level=4 or Level=0)\
                and (EventID=1)]]</Select></Query></QueryList>"], capture_output = True, timeout = 15, text = True)
except subprocess.TimeoutExpired:
        sys.exit(1)
Den zweiten Teil hab ich nachgemacht, ich hab nur ne Liste statt nem Generator genommen, da hab ich bisher noch gar keine Erfahrung, muss ich mich erst einlesen:

Code: Alles auswählen

lines = proc.stdout.splitlines()
parts = [line.partition(':') for line in lines]
data = {k.strip():v.strip(' Z') for k,_,v in parts}
sleep_time = parser.isoparse(data['Zeit im Energiesparmodus'].replace('?', ''))
Das os.system hab ich auch durch nen subprocess.run ersetzt:

Code: Alles auswählen

subprocess.run('shutdown /s /t 300 /c "Maximale PC-Nutzungsdauer erreicht. Computer wird in 5 Minuten heruntergefahren".')
Eines konnte ich jetzt noch nicht lösen: Der Code

Code: Alles auswählen

subprocess.run(['shutdown', '/s', '/t 300'])
funktioniert nicht, er liefert das gleiche Ergebnis, als würde man nur "shutdown" ausführen... Das Problem gibts zwar haufenweise im Internet, aber die Lösung hab ich nicht finden können, in
der Dokumentation heißts ja auch, man kann eine Liste aus Strings übergeben.

Danke vielmals nochmal!
Sirius3
User
Beiträge: 17819
Registriert: Sonntag 21. Oktober 2012, 17:20

Jedes Argument muß ein eigener Eintrag in der Liste sein, also '/t' und '300'.
mm96
User
Beiträge: 30
Registriert: Donnerstag 26. November 2020, 23:24

Fantastisch, das funktioniert.

Vielen Dank!
Antworten