Cambiar el volumen del sistema usando crontab y pactl

Cambiar el volumen del sistema usando crontab y pactl

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 -lpara iniciar sesión en el shell.
  • DISPLAY=:0.0para 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(o off): activar/desactivar silencio

La pieza que tuve que agregar en Ubuntu 19.10 fue el --serverarg.

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:

ingrese la descripción de la imagen aquí o:ingrese la descripción de la imagen aquí

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.pycomprueba 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)

información relacionada