我正在尝试使用 crontab 更改 Ubuntu 14.04 系统卷。我使用以下命令:
pactl set-sink-volume 1 75%
当我在终端中使用它或运行包含此命令的脚本时,它工作正常,但当系统从 crontab 或通过在 crontab 上运行的脚本运行此代码时,系统不会改变音量。我该如何解决这个问题?
我也尝试过
amixer -D pulse sset Master 75%
Crontab 看起来像(每分钟进行一次,用于测试目的)
* * * * * pactl set-sink-volume 1 75%
或者
* * * * * /usr/bin/pactl set-sink-volume 1 75\%
答案1
我花了一段时间才弄明白,你可以这样做:
1 9 * * * export DISPLAY=:0 && amixer -D pulse sset Master 48000
1 22 * * * export DISPLAY=:0 && amixer -D pulse sset Master 32000
100% 音量大约为 64000。这样音量就会在 9 时上升,在 22 时下降。同样在您的用户 crontab 上,而不是 sudo 上。
答案2
从...开始Ubuntu 19.10,一个简单的DISPLAY=:0
(甚至是 0.0)在 cron 中没有帮助,我收到了这个错误:
Connection failure: Connection refused
pa_context_connect() failed: Connection refused
我不得不做以下事情(这是我的夜間靜音cron,但你可以根据需要进行调整):
30 21 * * * bash -l -c "DISPLAY=:0.0 pactl --server unix:/run/user/$(id -u)/pulse/native set-sink-mute @DEFAULT_SINK@ on"
分解:
bash -l
用于登录 shell。DISPLAY=:0.0
用于显示--server unix:/run/user/$(id -u)/pulse/native
: (由于 cron 不在登录 shell 中,因此使用显式文件描述符)@DEFAULT_SINK@ or 0
:默认或第一个音频设备。对于特定设备,您可以使用完整的设备名称,例如alsa_output.pci-0000_00_1f.3.analog-stereo
on
(或off
):静音开/关
我必须在 Ubuntu 19.10 中添加的部分是 arg --server
。
答案3
从 cron 运行命令
在很多场合下都能正常工作,但当你需要或者想要运行 GUI 应用程序,或者在涉及环境变量的其他情况下,你可能需要花很多时间才能找到如何正确设置 cron 作业(或多个 cron 作业的组合),并找出哪个应该设置环境变量以及如何设置。
选择
在这些情况下,有一个简单的替代方法会很方便,可以在特定时间运行命令,甚至在当前用户的环境中运行完整的“日间程序”。
这就是下面的脚本所做的。它运行命令和/或应用程序,这些命令和/或应用程序以简单的格式列在文本文件中,如下所示:
11:09,gedit
11:10,gnome-terminal
11:20,pactl set-sink-volume 1 10%
我用你的命令测试了它,它运行良好。
如何设置
该设置包含三个小文件,您需要将它们存储在同一个文件夹中。在其中一个文件 ( command_data.txt
) 中,您需要列出命令以及您希望执行命令的时间,仅此而已。
使用以下格式:
time/comma/command (no spaces around the comma)
例如在 5 分钟内将音量调高至 100%:
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%
文件:
如上所述:这三个文件应该位于同一个文件夹中。
文件1,主脚本。
将其复制到一个空文件中,另存为schedule.py
(保留原名)并使其可执行(重要)
#!/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)
文件 2,启动/停止计划的脚本。
将其另存为run_schedule.py
(保留原名)并使其可执行(重要)
#!/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..."])
文件3,创建一个空文件,名为command_data.txt
按照“如何设置”中的说明,用你的命令填充它
通过以下命令启动/停止(切换)计划:
/path/to/run_schedule.py
将出现一条通知消息:
或者:
解释
这些文件的作用:
脚本schedule.py
启动时,会从 读取命令及其预定的运行时间command_data.txt
。在循环中,将当前时间与所列命令的预定时间进行比较。如果当前时间等于一个或多个预定的作业时间,则执行该命令并将其标记为当前时间的“完成”。
该脚本run_schedule.py
检查主脚本 ( schedule.py
) 是否正在运行。如果是,则终止作业,如果不是,则启动脚本。在两种情况下都会显示确认通知。
答案4
谢谢你。当 PIR 被触发时,我的运动屏幕/音频现在就可以工作了。
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)