使用 crontab 和 pactl 變更系統音量

使用 crontab 和 pactl 變更系統音量

我正在嘗試使用 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。

答案2

從...開始烏班圖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用於登入外殼。
  • 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(組合)可能會非常困難工作,並找出哪個應該設定環境變數以及如何設定。

選擇

在這些情況下,有一個簡單的替代方案可以很方便,即在特定時間運行命令,甚至從當前使用者的環境中運行完整的「日間程式」。

這就是下面的腳本所做的事情。它運行命令和/或應用程序,以簡單格式列出在文字檔案中,如下所示:

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)

相關內容