Ich versuche, das Systemvolumen von Ubuntu 14.04 mithilfe von crontab zu ändern. Ich verwende den folgenden Befehl:
pactl set-sink-volume 1 75%
Das funktioniert einwandfrei, wenn ich es im Terminal verwende oder ein Skript ausführe, das diesen Befehl enthält. Wenn das System diesen Code jedoch von Crontab oder über ein Skript ausführt, das auf Crontab ausgeführt wird, ändert das System die Lautstärke nicht. Wie kann ich das beheben?
Ich habe auch versucht
amixer -D pulse sset Master 75%
So sieht Crontab aus (jede Minute zu Testzwecken)
* * * * * pactl set-sink-volume 1 75%
oder
* * * * * /usr/bin/pactl set-sink-volume 1 75\%
Antwort1
Es hat eine Weile gedauert, bis ich es herausgefunden habe. Sie können Folgendes tun:
1 9 * * * export DISPLAY=:0 && amixer -D pulse sset Master 48000
1 22 * * * export DISPLAY=:0 && amixer -D pulse sset Master 32000
Bei 100 % liegt die Lautstärke bei etwa 64.000. Dadurch wird die Lautstärke auf 9 erhöht und auf 22 verringert. Auch auf Ihrer Benutzer-Crontab, nicht auf der von Sudo.
Antwort2
Beginnen mitUbuntu 19.10, ein einfaches DISPLAY=:0
(oder sogar 0,0) hat in Cron nicht geholfen, ich habe diesen Fehler erhalten:
Connection failure: Connection refused
pa_context_connect() failed: Connection refused
Ich musste stattdessen Folgendes tun (Dies ist meinestumm in der Nachtcron, aber Sie können es an Ihre Bedürfnisse anpassen):
30 21 * * * bash -l -c "DISPLAY=:0.0 pactl --server unix:/run/user/$(id -u)/pulse/native set-sink-mute @DEFAULT_SINK@ on"
Abbauen:
bash -l
für die Login-Shell.DISPLAY=:0.0
Zur Ausstellung--server unix:/run/user/$(id -u)/pulse/native
: (expliziter Dateideskriptor, da sich cron nicht in einer Login-Shell befindet)@DEFAULT_SINK@ or 0
: Das Standard- oder erste Audiogerät. Für ein bestimmtes Gerät können Sie den vollständigen Gerätenamen verwenden, z. B.alsa_output.pci-0000_00_1f.3.analog-stereo
on
(oderoff
): Stummschaltung ein/aus
Das Teil, das ich in Ubuntu 19.10 hinzufügen musste, war das --server
Argument.
Antwort3
Ausführen von Befehlen von cron
Funktioniert in vielen Fällen einwandfrei und zuverlässig, aber wenn Sie beispielsweise GUI-Anwendungen ausführen müssen oder möchten oder in anderen Situationen, in denen Umgebungsvariablen beteiligt sind, kann es eine ziemliche Suche sein, herauszufinden, wie Sie einen (Kombination von) Cron-Job(s) richtig einrichten und herausfindenwelcheUmgebungsvariablen sollten festgelegt werden und wie.
Alternative
In diesen Situationen kann es praktisch sein, eine einfache Alternative zu haben, um einen Befehl zu einer bestimmten Zeit auszuführen oder sogar ein komplettes „Tagesprogramm“ aus der Umgebung des aktuellen Benutzers auszuführen.
Dies ist, was das folgende Skript tut. Es führt Befehle und/oder Anwendungen aus, die in einer Textdatei in einem einfachen Format aufgelistet sind und wie folgt aussehen:
11:09,gedit
11:10,gnome-terminal
11:20,pactl set-sink-volume 1 10%
Ich habe es mit Ihrem Befehl getestet und es funktioniert einwandfrei.
Wie stellt man das ein
Das Setup besteht aus drei kleinen Dateien, die Sie in ein und demselben Ordner ablegen müssen. In einer dieser Dateien ( command_data.txt
) müssen Sie die Befehle zusammen mit der Zeit auflisten, zu der die Befehle ausgeführt werden sollen, das ist alles.
Verwenden Sie das folgende Format:
time/comma/command (no spaces around the comma)
um die Lautstärke in 5 Minuten beispielsweise auf 100% zu erhöhen:
11:20,pactl set-sink-volume 1 0%
11:21,pactl set-sink-volume 1 20%
11:22,pactl set-sink-volume 1 40%
11:23,pactl set-sink-volume 1 60%
11:24,pactl set-sink-volume 1 80%
11:25,pactl set-sink-volume 1 100%
Die Dateien:
Wie gesagt: Die drei Dateien sollten in ein und demselben Ordner liegen.
Datei 1, das Hauptskript.
Kopiere es in eine leere Datei, speichere es unter schedule.py
(behalte den Namen) und mache es ausführbar (wichtig)
#!/usr/bin/env python3
import subprocess
import time
import datetime
import os
cmd_data = os.path.dirname(os.path.abspath(__file__))+"/command_data.txt"
with open(cmd_data) as data:
s = [item.strip().split(",")+[None] for item in data.readlines()]
def currtime(set_time):
return int(set_time.split(":")[0])*60+int(set_time.split(":")[1])
def run_command(t, now, cmd, last_run):
if currtime(t) == now and last_run != int(time.strftime("%d%m%Y"))+int(now):
subprocess.Popen(["/bin/bash", "-c", cmd])
else:
pass
while True:
now = currtime(str(datetime.datetime.now().time())[:5])
for i in range(len(s)):
cmdata = s[i]
run_command(cmdata[0], now, cmdata[1], cmdata[2])
s[i][2] = int(time.strftime("%d%m%Y"))+int(now)
time.sleep(30)
Datei 2, das Skript zum Starten/Stoppen des Zeitplans.
Speichern unter run_schedule.py
(den Namen beibehalten) und ausführbar machen (wichtig)
#!/usr/bin/env python3
import os
import subprocess
script_dir = os.path.dirname(os.path.abspath(__file__))
cmd = "ps -ef | grep schedule.py"
run = subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8").split("\n")
match = [line for line in run if script_dir+"/"+"schedule.py" in line]
if len(match) != 0:
subprocess.Popen(["kill", match[0].split()[1]])
subprocess.Popen(["notify-send", "Schedule stopped..."])
else:
subprocess.Popen(["/bin/bash", "-c", script_dir+"/"+"schedule.py"])
subprocess.Popen(["notify-send", "Schedule runs..."])
Datei 3, erstellen Sie eine leere Datei mit dem Namencommand_data.txt
Füllen Sie es mit Ihren Befehlen, wie unter „Einrichten“ beschrieben.
Starten/Stoppen (Umschalten) des Zeitplans mit dem Befehl:
/path/to/run_schedule.py
Es wird eine Benachrichtigungsmeldung angezeigt:
oder:
Erläuterung
Was die Dateien bewirken:
Wenn das Skript schedule.py
gestartet wird, liest es die Befehle und ihre geplante Ausführungszeit aus command_data.txt
. In einer Schleife wird die aktuelle Zeit mit der geplanten Zeit der aufgelisteten Befehle verglichen. Wenn die aktuelle Zeit einer oder mehreren der geplanten Jobzeiten entspricht, wird der Befehl ausgeführt und für die aktuelle Zeit als „erledigt“ markiert.
Das Skript run_schedule.py
prüft, ob das Hauptskript ( schedule.py
) ausgeführt wird. Wenn ja, wird der Job beendet, wenn nicht, wird das Skript gestartet. In beiden Fällen wird eine Bestätigungsmeldung angezeigt.
Antwort4
Vielen Dank dafür. Mein Bewegungsbildschirm/Audio funktioniert jetzt, wenn PIR ausgelöst wird.
import time
import subprocess
from gpiozero import MotionSensor
import os
import logging
import time
import subprocess
os.environ["DISPLAY"] = ":0"
# Set up logging
logging.basicConfig(filename='output.log', level=logging.DEBUG,
format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
# Read in value of default_sink.txt for default_sink
with open('default_sink.txt', 'r') as f:
default_sink = f.read().strip()
print(default_sink)
# Constants
IR_SENSOR_PIN = 4 # GPIO pin number of IR sensor
TIMER_DURATION = 60 # Timer duration in seconds
# Initialize IR sensor and timer
ir_sensor = MotionSensor(IR_SENSOR_PIN)
timer = time.time() + TIMER_DURATION # Set timer to expire immediately
#run pactl command like this DISPLAY=:0.0 pactl --server unix:/run/user/1000/pulse/native set-sink-mute 0 on"
while True:
if ir_sensor.motion_detected:
logging.debug("Motion detected")
# Reset timer
timer = time.time() + TIMER_DURATION
# Turn on display and audio
subprocess.call("xset dpms force on", shell=True)
result = subprocess.run(f"DISPLAY=:0.0 pactl --server unix:/run/user/1000/pulse/native set-sink-mute '{default_sink}' 0", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
with open("output.log", "a") as f:
f.write(result.stdout.decode())
f.write(result.stderr.decode())
f.write(f"Return code: {result.returncode}\n")
elif timer and time.time() > timer:
logging.debug("Timer expired")
# Turn off display and audio
subprocess.call("xset dpms force off", shell=True)
result = subprocess.run(f"DISPLAY=:0.0 pactl --server unix:/run/user/1000/pulse/native set-sink-mute '{default_sink}' 1", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
with open("output.log", "a") as f:
f.write(result.stdout.decode())
f.write(result.stderr.decode())
f.write(f"Return code: {result.returncode}\n")
timer = time.time() + TIMER_DURATION # Set timer to expire immediately
time.sleep(1)