@BlinkyBill: Anmerkungen zum Shell-Skript: Die Backtick-Syntax würde ich nicht mehr verwenden. ``$(…)`` ist lesbarer, man kann es verschachteln, und die Klammern werden von den meisten Editoren auch deutlich besser unterstützt, beispielsweise durch visualles hervorheben der jeweils anderen Klammer wenn man mit dem Cursor auf einer Klammer steht, oder Short-Cuts zum Springen zur anderen Klammer oder auswählen von allem zwischen den Klammern.
Bei ``jq`` ist die ``-r``-Option redundant, denn das ist in ``-j`` schon enthalten.
In Skripten verwende ich oft die Langform von Optionen, das ist lesbarer und man kann oft leichter in der Dokumentation danach suchen.
Die betroffene Zeile sähe dann so aus:
Code: Alles auswählen
HAS_ALARM=$(curl --silent "${API_URL}" | jq --join-output '.success')
Und nun zum On-Topic-Teil: Die Portierung nach Python.
Initiale nahezu 1:1 Übersetzung (die davon ausgeht, das JSON enthält tatsächlich einen Wahrheitswert und nicht die Zeichenketten "true" und "false"):
Code: Alles auswählen
#!/usr/bin/env python3
from subprocess import run
from time import sleep
import requests
ACCESS_KEY = "DER-ALARM-ACCESSKEY"
API_URL = "https://www.xxxxxxxx"
def main():
is_monitor_active = True
while True:
has_alarm = requests.get(
API_URL, params={"accesskey": ACCESS_KEY}
).json()["success"]
if has_alarm and not is_monitor_active:
print("Turn display on")
run(["xscreensaver-command", "-deactivate"])
is_monitor_active = True
elif not has_alarm and is_monitor_active:
print("Turn display off")
run(["xscreensaver-command", "-activate"])
is_monitor_active = False
sleep(20)
if __name__ == "__main__":
main()
Da Python hier mit echten Wahrheitswerten arbeitet und nicht mit Zeichenketten "true" und "false" — oder eben auch was anderes wenn der Webserver was anderes sendet, lässt sich das mit etwas weniger Code-Wiederholung ausdrücken:
Code: Alles auswählen
if has_alarm and not is_monitor_active:
print("Turn display on")
run(["xscreensaver-command", "-deactivate"])
is_monitor_active = True
elif not has_alarm and is_monitor_active:
print("Turn display off")
run(["xscreensaver-command", "-activate"])
is_monitor_active = False
# =>
if has_alarm != is_monitor_active:
print("Turn display", "on" if has_alarm else "off")
run(
[
"xscreensaver-command",
"-deactivate" if has_alarm else "-activate",
]
)
is_monitor_active = has_alarm
Der Code wäre insgesamt etwas lesbarer wenn man die beiden Aktionen zum prüfen des Alarms und zum setzen des Bildschirmschonerzustands jeweils in eine Funktion auslagert. Bei der Gelegenheit könnte man auch gleich eine Funktion zur Abfrage des Zustands vom Bildschirmschoner hinzufügen und nicht bedingungslos mit der Annahme der Monitor sein an starten.
Code: Alles auswählen
#!/usr/bin/env python3
from subprocess import PIPE, run
from time import sleep
import requests
ACCESS_KEY = "DER-ALARM-ACCESSKEY"
API_URL = "https://www.xxxxxxxx"
XSCREENSAVER_COMMAND = "xscreensaver-command"
def check_alarm():
response = requests.get(API_URL, params={"accesskey": ACCESS_KEY})
response.raise_for_status()
return response.json()["success"]
def get_display_state():
return (
b"non-blanked"
in run([XSCREENSAVER_COMMAND, "-time"], stdout=PIPE, check=True).stdout
)
def set_display_state(state):
run(
[XSCREENSAVER_COMMAND, "-deactivate" if state else "-activate"],
check=True,
)
def main():
is_display_active = get_display_state()
while True:
has_alarm = check_alarm()
if has_alarm != is_display_active:
print("Turn display", "on" if has_alarm else "off")
set_display_state(has_alarm)
is_display_active = has_alarm
sleep(20)
if __name__ == "__main__":
main()
Jetzt haben wir noch den recht grossen Unterschied zwischen dem Shell-Skript und dem Python-Programm im Umgang mit Problemen: Das Shell-Skript macht immer einfach weiter als wäre nichts passiert. Das Python-Programm bricht mit einer Ausnahme ab. Um das möglichst leicht zu lösen, kann man `loguru` benutzen um Ausnahmen in einem ``with``-Block einfach zu protokollieren. Da kann man dann auch gleich von `print()` auf Logging umstellen.
Und um Strg+C zum Abbrechen des Programms könnte man sich noch explizit kümmern.
Ungetestet:
Code: Alles auswählen
#!/usr/bin/env python3
from subprocess import PIPE, run
from time import sleep
import requests
from loguru import logger
ACCESS_KEY = "DER-ALARM-ACCESSKEY"
API_URL = "https://www.xxxxxxxx"
XSCREENSAVER_COMMAND = "xscreensaver-command"
def check_alarm():
response = requests.get(API_URL, params={"accesskey": ACCESS_KEY})
response.raise_for_status()
result = response.json()["success"]
if not isinstance(result, bool):
raise ValueError(
f"expected boolean value, got {result!r} of type {type(result)}"
)
return result
def get_display_state():
return (
b"non-blanked"
in run([XSCREENSAVER_COMMAND, "-time"], stdout=PIPE, check=True).stdout
)
def set_display_state(state):
run(
[XSCREENSAVER_COMMAND, "-deactivate" if state else "-activate"],
check=True,
)
def main():
try:
is_display_active = get_display_state()
while True:
with logger.catch():
has_alarm = check_alarm()
if has_alarm != is_display_active:
logger.info(
"Turn display {}.", "on" if has_alarm else "off"
)
set_display_state(has_alarm)
is_display_active = has_alarm
sleep(20)
except KeyboardInterrupt:
logger.info("Strg+C / SIGINT caught.")
if __name__ == "__main__":
main()