Altere o volume do sistema usando crontab e pactl

Altere o volume do sistema usando crontab e pactl

Estou tentando alterar o volume do sistema Ubuntu 14.04 usando o crontab. Estou usando o seguinte comando:

pactl set-sink-volume 1 75%

O que funciona bem quando eu uso no terminal ou quando executo um script que inclui este comando, mas quando o sistema executa esse código no crontab ou via script que é executado no crontab, o sistema não altera o volume. Como posso consertar isso?

Eu também tentei

amixer -D pulse sset Master 75%

A aparência do Crontab (a cada minuto para fins de teste)

* * * * * pactl set-sink-volume 1 75%

ou

* * * * * /usr/bin/pactl set-sink-volume 1 75\%

Responder1

Demorei um pouco para descobrir, você pode fazer isso:

1 9 * * * export DISPLAY=:0 && amixer -D pulse sset Master 48000

1 22 * * * export DISPLAY=:0 && amixer -D pulse sset Master 32000

Em 100%, o volume é aproximadamente 64.000. Isso aumentará o volume em 9 e diminuirá em 22. Também no crontab do usuário, não no sudo.

Responder2

Começando comUbuntu 19.10, um simples DISPLAY=:0(ou mesmo 0,0) não ajudou no cron, recebi este erro:

Connection failure: Connection refused
pa_context_connect() failed: Connection refused

Eu tive que fazer o seguinte (este é o meumudo à noitecron, mas você pode adaptar às suas necessidades):

30 21 * * * bash -l -c "DISPLAY=:0.0 pactl --server unix:/run/user/$(id -u)/pulse/native set-sink-mute @DEFAULT_SINK@ on"

Discriminação:

  • bash -lpara shell de login.
  • DISPLAY=:0.0para exibição
  • --server unix:/run/user/$(id -u)/pulse/native: (descritor de arquivo explícito, pois o cron não está em um shell de login)
  • @DEFAULT_SINK@ or 0: O padrão ou primeiro dispositivo de áudio. Para um dispositivo específico, você pode usar o nome completo do dispositivo, por exemploalsa_output.pci-0000_00_1f.3.analog-stereo
  • on(ou off): ativar/desativar mudo

A peça que tive que adicionar no Ubuntu 19.10 foi o --serverarg.

Responder3

Executando comandos do cron

Funciona bem e confiável em muitas ocasiões, mas quando você precisa ou deseja executar, por exemplo, aplicativos GUI, ou em outras situações onde variáveis ​​de ambiente estão envolvidas, pode ser uma grande pesquisa descobrir como configurar corretamente um (combinação de) cron trabalho(s) e para descobrirqualvariáveis ​​de ambiente devem ser definidas e como.

Alternativa

Nestas situações, pode ser conveniente ter uma alternativa simples, executar um comando em um horário específico, ou mesmo executar um “programa diurno” completo, a partir do ambiente do usuário atual.

É isso que o script abaixo faz. Ele executa comandos e/ou aplicativos, listados em um arquivo de texto em formato simples, parecido com:

11:09,gedit
11:10,gnome-terminal
11:20,pactl set-sink-volume 1 10%

Eu testei com seu comando e funciona bem.

Como configurar

A configuração consiste em três pequenos arquivos, que você precisa armazenar em uma mesma pasta. Em um desses arquivos ( command_data.txt), você precisa listar os comandos, juntamente com o horário em que deseja que os comandos sejam executados, só isso.

Use o seguinte formato:

time/comma/command (no spaces around the comma)

para aumentar o volume em 5 minutos para 100%, por exemplo:

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%

Os arquivos:

Como dito: os três arquivos devem estar localizados em uma mesma pasta.

arquivo 1, o script principal. Copie-o para um arquivo vazio, salve-o como schedule.py(mantenha o nome como está) e torne-o executável (importante)

#!/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)

arquivo 2, o script para iniciar/parar o agendamento. Salve-o como run_schedule.py(mantenha o nome como está) e torne-o executável (importante)

#!/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..."])

arquivo 3, crie um arquivo vazio, chamadocommand_data.txt preencha-o com seus comandos conforme explicado em "Como configurar"

iniciar/parar (alternar) o agendamento pelo comando:

/path/to/run_schedule.py

Uma mensagem de notificação aparecerá:

insira a descrição da imagem aqui ou:insira a descrição da imagem aqui

Explicação

O que os arquivos fazem:

Quando o script schedule.pyé iniciado, ele lê os comandos e seu tempo de execução agendado no arquivo command_data.txt. Em um loop, a hora atual é comparada com a hora agendada dos comandos listados. Se o horário atual for igual a um ou mais horários de trabalho agendados, o comando será executado e marcado como "concluído" para o horário atual.

O script run_schedule.pyverifica se o script principal ( schedule.py) está em execução. Nesse caso, o trabalho é encerrado; caso contrário, o script é iniciado. Em ambos os casos é exibida uma notificação de confirmação.

Responder4

Obrigado por isso. Minha tela/áudio de movimento agora funciona quando o PIR é acionado.

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)

informação relacionada