Suscríbase al evento DBUS de apagado de la pantalla

Suscríbase al evento DBUS de apagado de la pantalla

Mi MacBook Pro tiene una retroiluminación del teclado que es bastante impresionante, pero hay un pequeño error: la pantalla se apaga después de un tiempo determinado, pero la retroiluminación del teclado permanece encendida.

Copié y modifiqué un pequeño script DBUS Python para monitorear cuándo se producen cambios en el estado del protector de pantalla, pero no se activa cuando la pantalla se apaga, solo cuando el protector de pantalla se activa o desactiva:

from dbus.mainloop.glib import DBusGMainLoop

import dbus
import gobject
import logging

logging.basicConfig()

logger = logging.getLogger(__name__)

dbus_loop = DBusGMainLoop(set_as_default=True)

def message_callback(bus, message):
    if message.get_interface() == "org.gnome.ScreenSaver":
        if message.get_member() == "ActiveChanged":
            screensaver_enabled = bool(message.get_args_list()[0])
            logger.info("Screen saver changed. Active: %s", screensaver_enabled)

session = dbus.SessionBus(mainloop=dbus_loop)
session.add_match_string_non_blocking("interface='org.gnome.ScreenSaver'")

session.add_message_filter(message_callback)

logger.info("Starting up.")

loop = gobject.MainLoop()
loop.run()

Esto funciona muy bien siempre que se activa el protector de pantalla, pero no se modifica si cambia el estado de energía de la pantalla, lo que puede suceder independientemente del protector de pantalla. Al ir a Brillo y Bloqueo en Configuración, puede configurar las pantallas para que se apaguen después de 1 minuto y no se bloqueen. Luego puede configurar el tiempo del protector de pantalla en una cantidad de tiempo diferente, digamos 10 minutos.

Intenté escuchar org.gnome.SettingsDaemon.Power.Screenla Changedseñal en la interfaz, pero esto solo sucede cuando el brillo de la pantalla se cambia manualmente.

¿Qué puedo escuchar para determinar cuándo ha cambiado el estado de energía de la pantalla? Quiero escribir un script que se ejecute cada vez que se apague la pantalla para poder desactivar la luz de fondo del teclado.

Respuesta1

Bueno, es una pena que no pueda dejar un comentario porque no tengo la "reputación". Esto es más un comentario que una solución.

He estado buscando algo similar y en su lugar estoy monitoreando 'org.gnome.SessionManager.Presence'. Tengo LED detrás de mi monitor para iluminación polarizada y quiero apagarlos/encenderlos con el monitor.

Esto funciona si bloqueo mi computadora manualmente, sin embargo, si dejo las configuraciones de "pantalla apagada" y "pantalla de bloqueo después" en diferentes intervalos, los LED se apagan cuando el monitor se apaga, sin embargo, cuando se activa el bloqueo del protector de pantalla, se apaga. Los LED se encienden nuevamente.

_getState () {
  dbus-monitor --session "type=signal,interface=org.gnome.SessionManager.Presence,member=StatusChanged" |
  while read x; do
    case "$x" in 
      *"uint32 3"*)
          /home/victor/bin/devices/kasa_cntrl.sh off
          echo -e "$(date)\t-\tTurned off" >> "$log"
          ;;
      *"uint32 0"*)
          /home/victor/bin/devices/kasa_cntrl.sh on
          echo -e "$(date)\t-\tTurned on" >> "$log"
          ;;
    esac
  done
}

Referencia: https://www.organicdesign.co.nz/PoisonTap_solution

Respuesta2

Acabo de instalar Ubuntu 18.04 y resulta que no hay ningún protector de pantalla predeterminado. Y, sinceramente, no quiero uno, así que no me molestaré en instalarlo.

Sin embargo, encontré algunas llamadas a métodos de gnome que parecen funcionar: AddUserActiveWatchy RemoveWatchdesde org.gnome.Mutter.IdleMonitorla interfaz.

Aquí está mi guión:

#!/usr/bin/env python

import dbus, gobject
from dbus.mainloop.glib import DBusGMainLoop
from subprocess import call

def filter_cb(bus,message):
    if message.get_member() == "AddUserActiveWatch":
        print("Monitor off")
        call("/usr/bin/g810-led -dv 046d -dp c337 -a 000000", shell=True)
    elif message.get_member() == "RemoveWatch":
        print("Monitor on")
        call("/usr/bin/g810-led -dv 046d -dp c337 -p /etc/g810-led/profile", shell=True)
    return

DBusGMainLoop(set_as_default=True)
bus = dbus.SessionBus()

bus.add_match_string_non_blocking("interface='org.gnome.Mutter.IdleMonitor',eavesdrop='true'")
bus.add_message_filter(filter_cb)

mainloop = gobject.MainLoop ()
mainloop.run ()

El resultado es:

  • cuando la pantalla comienza a atenuarse, la luz de fondo de mi teclado se apaga
  • el teclado se ilumina solo DESPUÉS de iniciar sesión correctamente, no en la pantalla de inicio de sesión (pero está lo suficientemente cerca)

Descargos de responsabilidad:

  1. La palabra monitor en org.gnome.Mutter.IdleMonitor proviene de la acción de monitoreo, no del monitor, también conocido como pantalla. Básicamente, estos parecen ser métodos que se llaman cuando gnome declara al usuario inactivo y no inactivo. De hecho, en mi caso coincide con el apagado de la pantalla. En tu caso, puede que no sea así.
  2. Aparentemente no puedes agregar esto como una entrada systemd porque necesita una pantalla. Sin embargo, puedes agregarlo en la Startup ApplicationsGUI y funciona.
  3. Estoy usando el ejecutable g810-led para encender y apagar la luz de fondo de mi teclado, esto debería tratarse solo como un ejemplo, ya que obviamente no funcionará en otros teclados.

PD: encontré un "error". Si interrumpes el desvanecimiento de la pantalla, el teclado permanece apagado.

Respuesta3

Está bien, entonces despuésañosSin estar frustrado con esto, finalmente hice algo al respecto y escribí un script de utilidad Python que monitorea DBus y recibe adecuadamente los eventos de bloqueo/desbloqueo de sesión.

ElEl código está alojado aquí., pero también lo incluiré a continuación. Mi objetivo es reescribir esto en Rust por varias razones, pero principalmente para que sea más fácil de usar para las personas sin tener que instalar paquetes para instalar las bibliotecas de Python correctas.


Requisitos previos

Para ejecutar este código, necesitará:

  • Un Python 3 reciente, escribí esto en Python 3.8.5.
  • Huevos:
    • dbus-python >=1.2,<2
    • PyGObject >=3.36,<4

Estos huevos de Python los proporcionan ciertos paquetes de Ubuntu, pero es posible que no sean las versiones correctas. El 16.04, creo que los paquetes requeridos son:

  • python3-gi, cual esPyGObject
  • python3-dbus, cual esdbus-python

En diferentes versiones de distribución, estos paquetes pueden ser diferentes. Esta es una de las muchas razones por las que quiero reescribir esto en Rust. Enumeraré mis otras motivaciones al final de esta respuesta.

Código

Entremos en el código.

dbus-session-lock-watcher.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from dbus.mainloop.glib import DBusGMainLoop

from gi.repository import GLib

import dbus
import logging
import sys


class ScreenSaverEventListener(object):

    def __init__(self):
        self.logger = logging.getLogger(self.__class__.__name__)
        self.mainloop = DBusGMainLoop()
        self.loop = GLib.MainLoop()
        self.session_bus = dbus.SessionBus(mainloop=self.mainloop)

        self.receiver_args, self.receiver_kwargs = None, None

    def setup(self):
        self.receiver_args = (self.on_session_activity_change,)
        self.receiver_kwargs = dict(dbus_interface="org.freedesktop.DBus.Properties", path="/org/gnome/SessionManager",
                                    signal_name="PropertiesChanged",
                                    # callback arguments
                                    sender_keyword="sender", destination_keyword="dest",
                                    interface_keyword="interface", member_keyword="member", path_keyword="path",
                                    message_keyword="message")

        self.session_bus.add_signal_receiver(*self.receiver_args, **self.receiver_kwargs)

    def on_session_activity_change(self, target: dbus.String, changed_properties: dbus.Dictionary, *args, **kwargs):
        if target != "org.gnome.SessionManager" or "SessionIsActive" not in changed_properties:
            return

        if changed_properties.get("SessionIsActive"):
            self.on_session_unlock()
        else:
            self.on_session_lock()

    def on_session_lock(self):
        self.logger.info("Session Locked")

    def on_session_unlock(self):
        self.logger.info("Session Unlocked")

    def run(self):
        self.logger.debug("Starting event loop.")
        self.loop.run()

    def shutdown(self):
        self.logger.debug("Stopping event loop.")
        self.session_bus.remove_signal_receiver(*self.receiver_args, **self.receiver_kwargs)
        self.loop.quit()


def main():
    setup_logging()

    listener = ScreenSaverEventListener()
    listener.setup()

    try:
        listener.run()
    except KeyboardInterrupt:
        sys.stderr.write("ctrl+c received, shutting down...\n")
        listener.shutdown()


def setup_logging():
    console = logging.StreamHandler(sys.stderr)
    console.setFormatter(
        logging.Formatter("%(asctime)s [%(levelname)-5s] %(name)s: %(message)s", datefmt="%Y-%m-%dT%H:%M:%S%z"))
    logging.addLevelName(logging.WARNING, "WARN")
    logging.getLogger().addHandler(console)
    logging.getLogger().setLevel(logging.DEBUG)


if __name__ == "__main__":
    main()

Para que este código haga algo interesante, edite:

  • ScreenSaverEventListener.on_session_lock, que se ejecutará cuando la pantalla se haya bloqueado

información relacionada