4

I need to run custom comand when:

  1. Computer is idle for X minutes (no key pressed)
  2. Key pressed

What I want o achieve actually is power saving feature for my keyboard.

I want to use:

g413-led -a 000000
g413-led -a FFFFFF

To turn on/off keyboard backlight using https://github.com/MatMoul/g810-led.

The first is fairly easy using one of:

  • xidle
  • xprintidle
  • xautolock

Please advice if there are better, more optimal ways?

But what about lighing it up again on keypress or resume from idle? I guess running command on each keypress is overkill. Is there event for power saving options? How does display power saving works?

enter image description here

Can I reuse same events/timeout?

umpirsky
  • 4,050

2 Answers2

5

The solution I came up with is DBUS events.

I first run dbus-monitor to see what events will trigger when monitor goes/wakes from sleep:

signal time=1515274499.244468 sender=org.freedesktop.DBus -> destination=:1.394 serial=2 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameAcquired
string ":1.394"
signal time=1515274499.244502 sender=org.freedesktop.DBus -> destination=:1.394 serial=4 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameLost
string ":1.394"
signal time=1515274559.337480 sender=:1.6 -> destination=:1.2 serial=29015 path=/org/gnome/Mutter/IdleMonitor/Core; interface=org.gnome.Mutter.IdleMonitor; member=WatchFired
uint32 440
signal time=1515274559.337878 sender=:1.2 -> destination=(null destination) serial=3288 path=/org/gnome/SessionManager/Presence; interface=org.gnome.SessionManager.Presence; member=StatusChanged
uint32 3
signal time=1515274559.338267 sender=:1.2 -> destination=(null destination) serial=3290 path=/org/gnome/SessionManager/Presence; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
string "org.gnome.SessionManager.Presence"
array [
dict entry(
string "status"
variant uint32 3
)
]
array [
]
signal time=1515274569.389778 sender=:1.6 -> destination=(null destination) serial=29018 path=/org/gnome/Shell; interface=org.gnome.Shell.Extensions; member=ExtensionStatusChanged
string "auto-move-windows@gnome-shell-extensions.gcampax.github.com"
int32 2
string ""
signal time=1515274569.398929 sender=:1.6 -> destination=(null destination) serial=29019 path=/org/gnome/Shell; interface=org.gnome.Shell.Extensions; member=ExtensionStatusChanged
string "clipboard-indicator@tudmotu.com"
int32 2
string ""
signal time=1515274569.399633 sender=org.freedesktop.DBus -> destination=:1.6 serial=5195 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameLost
string "org.kde.StatusNotifierWatcher"
signal time=1515274569.399660 sender=org.freedesktop.DBus -> destination=(null destination) serial=850 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameOwnerChanged
string "org.kde.StatusNotifierWatcher"
string ":1.6"
string ""
signal time=1515274569.404274 sender=:1.6 -> destination=(null destination) serial=29022 path=/org/gnome/Shell; interface=org.gnome.Shell.Extensions; member=ExtensionStatusChanged
string "ubuntu-appindicators@ubuntu.com"
int32 2
string ""
signal time=1515274569.442137 sender=:1.6 -> destination=(null destination) serial=29025 path=/org/gnome/Shell; interface=org.gnome.Shell.Extensions; member=ExtensionStatusChanged
string "ubuntu-dock@ubuntu.com"
int32 2
string ""
signal time=1515274569.455035 sender=:1.6 -> destination=(null destination) serial=29027 path=/org/gnome/ScreenSaver; interface=org.gnome.ScreenSaver; member=ActiveChanged
boolean true
signal time=1515274569.657300 sender=:1.6 -> destination=:1.42 serial=29037 path=/org/gnome/Mutter/IdleMonitor/Core; interface=org.gnome.Mutter.IdleMonitor; member=WatchFired
uint32 491
signal time=1515274569.657404 sender=:1.6 -> destination=(null destination) serial=29038 path=/org/gnome/Mutter/DisplayConfig; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
string "org.gnome.Mutter.DisplayConfig"
array [
dict entry(
string "PowerSaveMode"
variant int32 3
)
]
array [
]
signal time=1515276608.243100 sender=:1.6 -> destination=:1.2 serial=29039 path=/org/gnome/Mutter/IdleMonitor/Core; interface=org.gnome.Mutter.IdleMonitor; member=WatchFired
uint32 489
signal time=1515276608.243573 sender=:1.2 -> destination=(null destination) serial=3291 path=/org/gnome/SessionManager/Presence; interface=org.gnome.SessionManager.Presence; member=StatusChanged
uint32 0
signal time=1515276608.243843 sender=:1.2 -> destination=(null destination) serial=3292 path=/org/gnome/SessionManager/Presence; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
string "org.gnome.SessionManager.Presence"
array [
dict entry(
string "status"
variant uint32 0
)
]
array [
]
signal time=1515276608.244032 sender=:1.6 -> destination=:1.42 serial=29040 path=/org/gnome/Mutter/IdleMonitor/Core; interface=org.gnome.Mutter.IdleMonitor; member=WatchFired
uint32 494
signal time=1515276608.270459 sender=:1.6 -> destination=(null destination) serial=29042 path=/org/gnome/Mutter/DisplayConfig; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
string "org.gnome.Mutter.DisplayConfig"
array [
dict entry(
string "PowerSaveMode"
variant int32 0
)
]
array [
]
signal time=1515276623.523917 sender=:1.6 -> destination=:1.42 serial=29043 path=/org/gnome/Mutter/IdleMonitor/Core; interface=org.gnome.Mutter.IdleMonitor; member=WatchFired
uint32 491
signal time=1515276623.554451 sender=:1.6 -> destination=(null destination) serial=29047 path=/org/gnome/Mutter/DisplayConfig; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
string "org.gnome.Mutter.DisplayConfig"
array [
dict entry(
string "PowerSaveMode"
variant int32 3
)
]
array [
]
signal time=1515276668.529836 sender=:1.6 -> destination=:1.2 serial=29048 path=/org/gnome/Mutter/IdleMonitor/Core; interface=org.gnome.Mutter.IdleMonitor; member=WatchFired
uint32 440
signal time=1515276668.530236 sender=:1.2 -> destination=(null destination) serial=3293 path=/org/gnome/SessionManager/Presence; interface=org.gnome.SessionManager.Presence; member=StatusChanged
uint32 3
signal time=1515276668.530565 sender=:1.2 -> destination=(null destination) serial=3295 path=/org/gnome/SessionManager/Presence; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
string "org.gnome.SessionManager.Presence"
array [
dict entry(
string "status"
variant uint32 3
)
]
array [
]
signal time=1515279067.394398 sender=:1.6 -> destination=:1.2 serial=29051 path=/org/gnome/Mutter/IdleMonitor/Core; interface=org.gnome.Mutter.IdleMonitor; member=WatchFired
uint32 498
signal time=1515279067.394982 sender=:1.2 -> destination=(null destination) serial=3296 path=/org/gnome/SessionManager/Presence; interface=org.gnome.SessionManager.Presence; member=StatusChanged
uint32 0
signal time=1515279067.395139 sender=:1.2 -> destination=(null destination) serial=3297 path=/org/gnome/SessionManager/Presence; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
string "org.gnome.SessionManager.Presence"
array [
dict entry(
string "status"
variant uint32 0
)
]
array [
]
signal time=1515279067.395662 sender=:1.6 -> destination=:1.42 serial=29052 path=/org/gnome/Mutter/IdleMonitor/Core; interface=org.gnome.Mutter.IdleMonitor; member=WatchFired
uint32 496
signal time=1515279067.414904 sender=:1.6 -> destination=(null destination) serial=29054 path=/org/gnome/Mutter/DisplayConfig; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
string "org.gnome.Mutter.DisplayConfig"
array [
dict entry(
string "PowerSaveMode"
variant int32 0
)
]
array [
]
signal time=1515279076.828255 sender=:1.6 -> destination=(null destination) serial=29063 path=/org/gnome/Shell; interface=org.gnome.Shell.Extensions; member=ExtensionStatusChanged
string "ubuntu-dock@ubuntu.com"
int32 1
string ""
signal time=1515279076.829775 sender=org.freedesktop.DBus -> destination=(null destination) serial=851 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameOwnerChanged
string "org.kde.StatusNotifierWatcher"
string ""
string ":1.6"
signal time=1515279076.829812 sender=org.freedesktop.DBus -> destination=:1.6 serial=5215 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameAcquired
string "org.kde.StatusNotifierWatcher"
signal time=1515279076.829824 sender=:1.6 -> destination=(null destination) serial=29066 path=/org/gnome/Shell; interface=org.gnome.Shell.Extensions; member=ExtensionStatusChanged
string "ubuntu-appindicators@ubuntu.com"
int32 1
string ""
signal time=1515279076.841923 sender=:1.6 -> destination=(null destination) serial=29067 path=/org/gnome/Shell; interface=org.gnome.Shell.Extensions; member=ExtensionStatusChanged
string "clipboard-indicator@tudmotu.com"
int32 1
string ""
signal time=1515279076.844396 sender=:1.6 -> destination=(null destination) serial=29068 path=/org/gnome/Shell; interface=org.gnome.Shell.Extensions; member=ExtensionStatusChanged
string "auto-move-windows@gnome-shell-extensions.gcampax.github.com"
int32 1
string ""
signal time=1515279076.851323 sender=:1.6 -> destination=(null destination) serial=29069 path=/org/gnome/ScreenSaver; interface=org.gnome.ScreenSaver; member=ActiveChanged
boolean false
signal time=1515279076.896958 sender=:1.6 -> destination=(null destination) serial=29218 path=/StatusNotifierWatcher; interface=org.kde.StatusNotifierWatcher; member=StatusNotifierItemRegistered
string "/"
signal time=1515279076.921110 sender=:1.38 -> destination=(null destination) serial=2735 path=/org/gnome/evolution/dataserver/CalendarView/1887/93; interface=org.gnome.evolution.dataserver.CalendarView; member=complete
array [
string ""
string ""
]
signal time=1515279076.924727 sender=:1.34 -> destination=(null destination) serial=2701 path=/org/gnome/evolution/dataserver/CalendarView/1870/92; interface=org.gnome.evolution.dataserver.CalendarView; member=complete
array [
string ""
string ""
]
signal time=1515279077.686970 sender=:1.6 -> destination=(null destination) serial=30014 path=/StatusNotifierWatcher; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
string "org.kde.StatusNotifierWatcher"
array [
dict entry(
string "RegisteredStatusNotifierItems"
variant array [
string ":1.66/org/ayatana/NotificationItem/software_update_available"
]
)
]
array [

I first tried to go for org.gnome.Mutter.IdleMonitor, but uint32 values were constantly incrementing, not sure why?

I settled with StatusChanged, here is the final script:

#!/bin/bash
# Turn keyboard backlight on/off using https://github.com/MatMoul/g810-led

g413-led -a FFFFFF # always turn on on startup (it turns off for some reason on reboot)

dbus-monitor --session "type=signal,interface=org.gnome.SessionManager.Presence,member=StatusChanged" |
  while read x; do
      case "$x" in
        *"uint32 3"*) g413-led -a 000000;;
        *"uint32 0"*) g413-led -a FFFFFF;;
      esac
  done

Screensaver events can also work:

g413-led -a FFFFFF # always turn on on startup (it turns off for some reason on reboot)

dbus-monitor --session "type='signal',interface='org.gnome.ScreenSaver'" |
  while read x; do
      case "$x" in
        *"boolean true"*) g413-led -a 000000;;
        *"boolean false"*) g413-led -a FFFFFF;;
      esac
  done

Of course, you can put any command you wish. The advantage of the first script comparing to this one is that it lights up keyboard before user login which makes it easier to type password.

The only downside is that keyboards lights up after user login, not on keypress, but I can live with that.

I was experimenting with:

dbus-monitor --session "type='signal',interface='org.freedesktop.DBus.Properties',path='/org/gnome/Mutter/DisplayConfig'" | grep 'variant int32' |
  while read x; do
      case "$x" in
        *"variant int32 3"*) g413-led -a 000000;;
        *"variant int32 0"*) g413-led -a FFFFFF;;
      esac
  done

but it didn't work for some reason, probably grep issue.

umpirsky
  • 4,050
2

Tiny background process

Your setup seems quite a complicated one for a simple issue. What I would do is simply run a tiny backround process, checking idle time once per 2 seconds or so, take one action if idle time exceeds the limit, another action if it switches to below set idle time.

The script:

#!/usr/bin/env python3
import time
import subprocess

# set idle time (seconds)
t = 60

# set commands
on_idle = ["g413", "-led", "-a", "000000"]
on_active = ["g413", "-led", "-a", "FFFFFF"]

def set_state(cmd):
    subprocess.Popen(cmd)

def get_idle():
    return int(subprocess.check_output("xprintidle").decode("utf-8").strip())/1000

idle1 = 0

while True:
    time.sleep(2)
    idle2 = get_idle()
    # if idle time exceeds (passes) the limit, run one command
    if all([idle2 >= t, idle1 < t]):
        set_state(on_idle)
    # if idle time switches to below (passes) the limit, run another command
    elif all([idle2 <= t, idle1 > t]):
        set_state(on_active)
    idle1 = idle2

To use

  • Make sure xprintidle is installed

    sudo apt install xprintidle
    
  • Copy the script into an empty file, save it as switch_light.py

  • Set the desired idle time to take action after:

    # set idle time (seconds)
    t = 60
    
  • Run it by the command:

    python3 /path/to/switch_light.py
    
  • If all works fine, add it to Startup Applications.

Note(s)

  • Couldn't test it since I don't have your keyboard, but tested with other commands, it does the job nicely.

  • You can use the script with any other command:

    # set commands
    on_idle = ["g413", "-led", "-a", "000000"]
    on_active = ["g413", "-led", "-a", "FFFFFF"]
    

    Just make sure you separate arguments like in the example.

  • If you only want an action on exceeding idle time (or the other way around), just comment out:

    # if idle time switches to below (passes) the limit, run another 
    elif all([idle2 <= t, idle1 > t]):
        set_state(on_active)
    
Jacob Vlijm
  • 83,767
  • Thanks. I came up with bash solution. So, no python and xprintidle dependency. And no sleep, so I guess it will be also more performant. Please check my answer above and share your opinion. – umpirsky Jan 07 '18 at 14:39
  • Hi @umpirsky Thanks for the comment. Running this kind of background processes adds zero to the burden of your system. If well written, even running 10-20 of these will not be noticeable whatsoever, nor does the dependency on xprintidle add anything. For me, not being able to set the idle time independent to the screensaver events would be a major issue, but if it isn't for you, you could very well use your solution of course. – Jacob Vlijm Jan 07 '18 at 14:45
  • Yes, my solution will respect display settings. Your solution can be easily updated to respect screen idle time with gsettings get org.gnome.desktop.session idle-delay. ;) – umpirsky Jan 07 '18 at 20:41
  • @umpirsky Uuhhhm, not quite clear, the question was on how to run a command after x idle time and vice versa, *not* on how to combine it with screen actions. It seems now you are selling a downside in your solution as an advantage? – Jacob Vlijm Jan 08 '18 at 12:26
  • You are right, but I also asked if there is option to reuse power saving options and events. That is preferred over polling, I updated question title to match question body. Thanks! – umpirsky Jan 10 '18 at 10:06
  • I think you wrote an answer about a month ago to dim the monitor(s) when system inactive/idle for a period. It was also in Python but did it use xpriniIdle too? – WinEunuuchs2Unix Jun 17 '19 at 01:47
  • I believe youi mean this one: https://askubuntu.com/questions/1127810/how-to-standby-a-monitor-using-xset-in-multi-monitor-setup. @WinEunuuchs2Unix – Jacob Vlijm Jun 17 '19 at 05:55