Estoy intentando cambiar el volumen del sistema Ubuntu 14.04 usando crontab. Estoy usando el siguiente comando:
pactl set-sink-volume 1 75%
Lo cual funciona bien cuando lo uso en la terminal o cuando ejecuto un script que incluye este comando, pero cuando el sistema ejecuta este código desde crontab o mediante un script que se ejecuta en crontab, el sistema no cambia el volumen. ¿Cómo puedo arreglar esto?
yo también lo he probado
amixer -D pulse sset Master 75%
Crontab se ve así (cada minuto para fines de prueba)
* * * * * pactl set-sink-volume 1 75%
o
* * * * * /usr/bin/pactl set-sink-volume 1 75\%
Respuesta1
Me tomó un tiempo descubrirlo, puedes hacer esto:
1 9 * * * export DISPLAY=:0 && amixer -D pulse sset Master 48000
1 22 * * * export DISPLAY=:0 && amixer -D pulse sset Master 32000
Al 100%, el volumen es aproximadamente 64000. Eso aumentará el volumen en 9 y bajará en 22. También en el crontab de su usuario, no en el sudo.
Respuesta2
Empezando conubuntu 19.10, un simple DISPLAY=:0
(o incluso 0.0) no ayudó en cron, recibí este error:
Connection failure: Connection refused
pa_context_connect() failed: Connection refused
Tuve que hacer lo siguiente en su lugar (Este es misilencio por la nochecron, pero puedes adaptarlo a tus necesidades):
30 21 * * * bash -l -c "DISPLAY=:0.0 pactl --server unix:/run/user/$(id -u)/pulse/native set-sink-mute @DEFAULT_SINK@ on"
Descomponer:
bash -l
para iniciar sesión en el shell.DISPLAY=:0.0
para mostrar--server unix:/run/user/$(id -u)/pulse/native
: (descriptor de archivo explícito ya que cron no está en un shell de inicio de sesión)@DEFAULT_SINK@ or 0
: El dispositivo de audio predeterminado o primero. Para un dispositivo específico, puede utilizar el nombre completo del dispositivo, por ejemploalsa_output.pci-0000_00_1f.3.analog-stereo
on
(ooff
): activar/desactivar silencio
La pieza que tuve que agregar en Ubuntu 19.10 fue el --server
arg.
Respuesta3
Ejecutando comandos desde cron
Funciona bien y es confiable en muchas ocasiones, pero cuando necesita o desea ejecutar, por ejemplo, aplicaciones GUI, o en otras situaciones donde están involucradas variables de entorno, puede ser una gran búsqueda descubrir cómo configurar correctamente una (combinación de) cron. trabajo(s), y para averiguarcualLas variables de entorno deben configurarse y cómo.
Alternativa
En estas situaciones, puede resultar conveniente disponer de una alternativa sencilla, ejecutar un comando a una hora concreta, o incluso ejecutar un "programa diario" completo, desde el entorno actual del usuario.
Eso es lo que hace el siguiente script. Ejecuta comandos y/o aplicaciones, enumeradas en un archivo de texto en un formato simple, con el aspecto siguiente:
11:09,gedit
11:10,gnome-terminal
11:20,pactl set-sink-volume 1 10%
Lo probé con tu comando y funciona bien.
Como instalar
La configuración consta de tres archivos pequeños, que debe almacenar en la misma carpeta. En uno de estos archivos ( command_data.txt
), debe enumerar los comandos, junto con la hora en la que desea que se ejecuten los comandos, eso es todo.
Utilice el siguiente formato:
time/comma/command (no spaces around the comma)
para subir el volumen en 5 minutos al 100% por ejemplo:
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%
Los archivos:
Como se dijo: los tres archivos deben estar ubicados en la misma carpeta.
archivo 1, el script principal.
Cópielo en un archivo vacío, guárdelo como schedule.py
(mantenga el nombre como está) y hágalo ejecutable (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)
archivo 2, el script para iniciar/detener la programación.
Guárdelo como run_schedule.py
(mantenga el nombre como está) y hágalo ejecutable (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..."])
archivo 3, cree un archivo vacío, llamadocommand_data.txt
rellénelo con sus comandos como se explica en "Cómo configurar"
iniciar/detener (alternar) la programación con el comando:
/path/to/run_schedule.py
Aparecerá un mensaje de notificación:
o:
Explicación
Qué hacen los archivos:
Cuando se inicia el script schedule.py
, lee los comandos y su tiempo de ejecución programado desde command_data.txt
. En un bucle, la hora actual se compara con la hora programada de los comandos enumerados. Si la hora actual es igual a una o más de las horas de trabajo programadas, el comando se ejecuta y se marca como "hecho" para la hora actual.
El script run_schedule.py
comprueba si el script principal ( schedule.py
) se está ejecutando. Si es así, el trabajo se cancela; si no, se inicia el script. En ambos casos se muestra una notificación de confirmación.
Respuesta4
Gracias por esto. Mi pantalla de movimiento/audio ahora funciona cuando se activa el 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)