화면 전원 끄기 DBUS 이벤트 구독

화면 전원 끄기 DBUS 이벤트 구독

내 MacBook Pro에는 꽤 멋진 키보드 백라이트가 있지만 약간의 버그가 있습니다. 일정 시간이 지나면 화면이 꺼지지만 키보드 백라이트는 계속 켜져 있습니다.

화면 보호기 상태에 변경 사항이 발생할 때 모니터링하기 위해 작은 DBUS Python 스크립트를 복사하고 엉망으로 만들었습니다. 하지만 화면이 꺼질 때 트리거되지 않고 화면 보호기가 활성화되거나 비활성화될 때만 트리거됩니다.

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()

이는 화면 보호기가 활성화될 때마다 훌륭하게 작동하지만 화면 보호기와 독립적으로 발생할 수 있는 화면 전원 상태가 변경되어도 변경되지 않습니다. 설정에서 밝기 및 잠금으로 이동하면 화면이 1분 후에 꺼지고 잠기지 않도록 설정할 수 있습니다. 그런 다음 화면 보호기 시간을 10분 등 다른 시간으로 설정할 수 있습니다.

org.gnome.SettingsDaemon.Power.Screen인터페이스 에서 신호를 들어보았지만 Changed화면 밝기를 수동으로 변경할 때만 이런 현상이 발생합니다.

화면 전원 상태가 언제 변경되었는지 확인하려면 무엇을 들을 수 있나요? 키보드 백라이트를 비활성화할 수 있도록 화면 전원이 꺼질 때마다 실행되는 스크립트를 작성하고 싶습니다.

답변1

글쎄요, "평판"이 없어서 댓글을 남길 수 없다는 게 아쉽네요. 이것은 해결책이라기보다는 의견에 가깝습니다.

비슷한 것을 찾고 있었는데 대신 'org.gnome.SessionManager.Presence'를 모니터링하고 있습니다. 모니터 뒤에 바이어스 조명용 LED가 있는데 모니터를 사용하여 LED를 끄거나 켜고 싶습니다.

컴퓨터를 수동으로 잠그면 작동합니다. 그러나 "화면 끄기"와 "다음 이후 화면 잠금" 설정을 서로 다른 간격으로 두면 모니터가 꺼질 때 LED가 꺼지지만 화면 보호기 잠금이 시작되면 화면 보호기가 켜집니다. LED가 다시 켜집니다.

_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
}

참조: https://www.organicdesign.co.nz/PoisonTap_solution

답변2

방금 Ubuntu 18.04를 설치했는데 기본적으로 화면 보호기가 없는 것으로 나타났습니다. 그리고 솔직히 말해서 저는 하나도 원하지 않기 때문에 귀찮게 설치하지도 않을 것입니다.

그러나 트릭을 수행하는 것처럼 보이는 gnome AddUserActiveWatch및 인터페이스 RemoveWatch에서 일부 메소드 호출을 발견했습니다.org.gnome.Mutter.IdleMonitor

내 스크립트는 다음과 같습니다.

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

결과는 다음과 같습니다.

  • 디스플레이가 어두워지기 시작하면 키보드 백라이트가 꺼지는 것입니다
  • 로그인 화면이 아닌 로그인에 성공한 후에만 키보드가 켜집니다(그러나 충분히 가깝습니다).

면책조항:

  1. org.gnome.Mutter.IdleMonitor의 모니터라는 단어는 화면이라고도 불리는 모니터가 아닌 모니터링 작업에서 유래합니다. 따라서 기본적으로 이는 사용자가 gnome에 의해 유휴 상태가 아닌 유휴 상태로 선언될 때 호출되는 메소드인 것 같습니다. 사실 제 경우에는 화면이 꺼지는 것과 동시에 발생합니다. 귀하의 경우에는 그렇지 않을 수도 있습니다.
  2. 화면이 필요하기 때문에 이것을 시스템 항목으로 추가할 수 없는 것 같습니다. 그러나 GUI에 추가하면 Startup Applications작동합니다.
  3. 저는 키보드 백라이트를 켜고 끄기 위해 g810 주도 실행 파일을 사용하고 있습니다. 이는 분명히 다른 키보드에서는 작동하지 않으므로 단지 예로만 다루어야 합니다.

추신: "버그"를 발견했습니다. 화면 페이드를 중단하면 키보드가 꺼진 상태로 유지됩니다.

답변3

알았어 그럼 나중에연령이에 대해 좌절감을 느끼고 마침내 이에 대해 조치를 취하고 DBus를 모니터링하고 세션 잠금/잠금 해제 이벤트를 올바르게 수신하는 Python 유틸리티 스크립트를 작성했습니다.

그만큼코드는 여기에서 호스팅됩니다., 하지만 아래에도 포함하겠습니다. 내 목표는 여러 가지 이유로 이것을 Rust로 다시 작성하는 것이지만, 주로 올바른 Python 라이브러리를 설치하기 위해 패키지를 설치하지 않고도 사람들이 더 쉽게 사용할 수 있도록 하는 것입니다.


전제조건

이 코드를 실행하려면 다음이 필요합니다.

  • 최근 Python 3에서는 Python 3.8.5에서 이것을 작성했습니다.
  • 달걀:
    • dbus-python >=1.2,<2
    • PyGObject >=3.36,<4

이러한 Python 계란은 특정 Ubuntu 패키지에서 제공되지만 올바른 버전이 아닐 수도 있습니다. 16.04에 필요한 패키지는 다음과 같습니다.

  • python3-gi, 이는PyGObject
  • python3-dbus, 이는dbus-python

다른 배포 버전에서는 이러한 패키지가 다를 수 있습니다. 이것이 제가 이것을 Rust로 다시 작성하고 싶은 많은 이유 중 하나입니다. 이 답변의 마지막 부분에 다른 동기를 나열하겠습니다.

암호

코드로 들어가 보겠습니다.

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()

이 코드를 흥미로운 작업으로 만들려면 다음을 편집하세요.

  • ScreenSaverEventListener.on_session_lock, 화면이 잠겼을 때 실행됩니다.

관련 정보