Conseguí una nueva laptop vieja
Esta laptop es bastante “vieja” comparada con el hardware nuevo y reluciente de hoy, pero cumple con todo lo que necesito.
- Era barata (para mí, era excedente de una empresa)
- Tiene un lindo procesador
11th Gen Intel(R) Core(TM) i7-11850H @ 2.50GHz - Tiene un montón de RAM (16G y un slot libre)
- Este modelo, o uno bastante parecido, está certificado para Ubuntu (esto significa que un equipo en Ubuntu se tomó el tiempo de verificar que cada versión de su sistema funcione en estas máquinas e incluso hizo cambios en su kernel oem para acomodar las rarezas que trae que Lenovo sea demasiado liberal con la interpretación de los estándares)
Live USB
La imagen Live de Ubuntu es hermosa y funciona de una con todo lo que mi laptop tiene para ofrecer (23.10 al momento de escribir esto). Ahora, acá es donde empieza la diversión.
Mi laptop tiene una tecla de silencio que tiene un led; el led se enciende cuando la laptop está silenciada, y tiene lo mismo en la de silenciar el micrófono.
Esto funciona sin fallas en la imagen live, pero una vez instalada solo funciona la luz de silencio del micrófono.
Ahora bien: sí que le saqué snapd a Ubuntu, así que puede que haya alterado el flujo normal de las cosas.
Después de leer un poco, no pude entender por qué esto no funcionaba; el mecanismo del kernel que lo hace funcionar está ahí e incluso puedo disparar el led a mano:
# This turns on the led
echo 1 | sudo tee /sys/class/leds/platform\:\:mute/brightness
Pasé unas horas probando varios arreglos e intentando entender qué era distinto en la imagen live, sin éxito; la gente que arma esa imagen es mucho más inteligente que yo.
La solución barata
Resulta que te podés suscribir a pulse audio y escuchar eventos, así que escribí un pequeño daemon de systemd para encender/apagar el led.
Para esto primero tuve que agregar una regla de udev para hacerlo escribible sin sudo.
Coloqué este archivo en /etc/udev/rules.d/99-mute_led.rules
ACTION=="add", SUBSYSTEM=="leds", KERNEL=="platform::mute", RUN+="/bin/chmod a+w /sys/class/leds/%k/brightness"Después escribí un script de python que hacía la suscripción a pulse; usé una biblioteca práctica
requirements.txt
pulsectl==23.5.2#!/usr/bin/env python
import time
from pulsectl import Pulse, PulseLoopStop
# This is the name for my laptop, a Thinkpad X1 Extreme Gen 4
SINK_NAME="alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__hw_sofhdadsp__sink"
def get_sink_number(pulse):
"""
return the index for the sink we care about
"""
return pulse.get_sink_by_name(SINK_NAME).index
def set_led_brightness(sink_number, is_muted):
"""
set the status of the led according to the mute status
"""
# Determine the LED brightness value based on mute status
brightness = 0 if not is_muted else 1
with open('/sys/class/leds/platform::mute/brightness', 'w') as led:
led.write(f'{brightness}')
def main():
with Pulse("mute-led-listener") as pulse:
sink_number = get_sink_number(pulse)
def mute_button(ev):
"""
callback to be invoked every time an event matches the set match
we only raise a loop stop exception to trigger the event loop to
exit, we cannot perform pulse operations while the loop is running.
"""
if ev.index == sink_number:
raise PulseLoopStop
pulse.event_mask_set("sink")
pulse.event_callback_set(mute_button)
while True:
# Lock until we have an event match.
pulse.event_listen()
# Get mute status for our sink
is_muted = pulse.get_sink_by_name(SINK_NAME).mute == 1
# Set LED brightness based on mute status
set_led_brightness(sink_number, is_muted)
# Then we will begin the listener again and only trigger next time button is pressed
if __name__ == "__main__":
main()Nota: Verificá si el nombre del dispositivo te sirve; podés chequear esto usando la herramienta pactl.
Y até todo junto con un daemon de systemd
$HOME/.local/share/systemd/user/led-control.service
# $HOME/.local/share/systemd/user/led-control.service
[Unit]
Description=LED Control Service
[Service]
Type=simple
ExecStart=/home/hduran/vimconfig/thinkpad/venv/bin/python /home/hduran/vimconfig/thinkpad/mute_led_helper.py
[Install]
WantedBy=default.targetNota: La ruta de python es un poco rara porque creé un virtualenv para esto (deberías hacer lo mismo si querés instalar este paquete, no instalarlo a nivel del sistema)
Después de esto necesitás correr:
systemctl --user enable led-control.service
systemctl --user start led-control.service