10

How can I get an on-screen notification using notify-osd when I plug/unplug the charger?

Seth
  • 58,122
kernel_panic
  • 11,732
  • I could make a script to do this.. but that isn't a very elegant solution. – Seth Oct 29 '14 at 03:32
  • @Seth How would such a script look like? Could you post it in an answer? I'm specifically interested in how you identify a "charger unplugged" event... – landroni Mar 31 '15 at 15:58
  • @landroni Oh, didn't realize you weren't the OP. I posted an answer below. It works fine for me but a few of my friends are having issues. Let me know if it doesn't work for you. I'm working on a better way as we speak. – Seth Apr 02 '15 at 01:54
  • @Seth Thanks so much for looking into this. As it happens, my battery died on me a very quick death, so my query is a bit moot by now. But I'll keep this solution in mind for the future. – landroni Apr 02 '15 at 11:53

3 Answers3

8

Switching between AC power and battery power should generate an event on the D-Bus system bus. Run dbus-monitor --system and watch what events are generated on your system.

If you have upower running, you get more specialized notifications from upower -m.

#!/bin/sh
upower -m |
while read -r _time _2 _3 device; do
  [ "$device" = "/org/freedesktop/UPower/devices/line_power_AC" ] || continue
  notify-send "$(acpi -a)"
done

You can also get events from acpi_listen.

#!/bin/sh
acpi_listen |
while read -r what junk; do
  [ "$what" = "ac_adapter" ] || continue
  notify-send "$(acpi -a)"
done

Run this script when you want to start seeing notifications, or add it to your session startup.

Seth
  • 58,122
7

enter image description here enter image description here

dbus

Some people reported my earlier udev solution sent the notification too many times when the power cable was plugged in. I couldn't reproduce that but I wrote this python script to utilize dbus instead of udev. Save it as a .py file somewhere on your hard drive. Mark the file executable by running:

sudo chmod +x yourFile.py  

and add it to your startup applications as described here. This script requires the package acpi be installed.

#!/usr/bin/python

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


dbus_loop = DBusGMainLoop()
bus = dbus.SystemBus(mainloop=dbus_loop)

onMessage="Power plugged in!"
offMessage="Power unplugged!"
onImage="/usr/share/icons/gnome/32x32/devices/ac-adapter.png"
offImage="/usr/share/icons/gnome/32x32/status/battery-full.png"

def callback():
    state = subprocess.check_output(["acpi", "-a"]).split(':')[1].strip()
    if state == "on-line":
        subprocess.call(["notify-send", "-i", onImage, onMessage])
    elif state == "off-line":
        subprocess.call(["notify-send", "-i", offImage, offMessage])

bus.add_signal_receiver(callback, 'Changed', 'org.freedesktop.UPower.Device', 'org.freedesktop.UPower', '/org/freedesktop/UPower/devices/line_power_AC')

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

udev

With a little experimentation (and a little help) I was able to utilize a udev rule to accomplish this. Some people have reported that it sometimes sends the notification more than once but I have not had any problems. YMMV.

Create a script with the following contents:

#!/bin/bash

# Set this to your username
USER="some_user"

if [ "$POWER" == "on" ]
  then
  DISPLAY=:0 /bin/su $USER -c '/usr/bin/notify-send -i /usr/share/icons/gnome/32x32/devices/ac-adapter.png "Power cable plugged in."'
elif [ "$POWER" == "off" ]
  then
  DISPLAY=:0 /bin/su $USER -c '/usr/bin/notify-send -i /usr/share/icons/gnome/32x32/status/battery-full.png "Power cable unplugged."'
fi

replacing some_user with your username. Mark the file executable by running:

sudo chmod +x /path/to/script.sh  

replacing /path/to/script.sh with the path to where you saved the script.

Next create a file in /etc/udev/rules.d named 10-power.rules with the contents:

SUBSYSTEM=="power_supply", ACTION=="change", ENV{POWER_SUPPLY_ONLINE}=="0", OPTIONS+="last_rule", RUN+="/path/to/script.sh" ENV{POWER}="off"
SUBSYSTEM=="power_supply", ACTION=="change", ENV{POWER_SUPPLY_ONLINE}=="1", OPTIONS+="last_rule", RUN+="/path/to/script.sh" ENV{POWER}="on"

again replacing /path/to/script.sh with the path to the script you created earlier.

Now reload the udev rules by running:

sudo udevadm control --reload-rules                              

Unplug the power cable. You should get a notification.

Seth
  • 58,122
  • That works, but it requires root access, and complex machinery to get the notification to the desktop, or hard-coding the user as you did. I think you'll also need to set XAUTHORITY with some display managers such as gdm. – Gilles 'SO- stop being evil' Apr 01 '15 at 01:53
  • @Gilles IMO "requires root" and the hard coded user are pretty silly nitpicks, but I will add a cron solution later for the sake of completeness if you think it is that important. I'm pretty this works under GDM but I will double check. – Seth Apr 01 '15 at 02:07
  • 1
    I'm also taking a look at python-dbus and udev's dbus messaging API to perhaps create a daemon that will do the same thing as these udev rules, but the only problem is that is it will need to be constantly running and restart on any failures, something that I believe adds a higher amount of complexity to an already rather-decent solution. If there are any better solutions, however, I'd be happy to hear them. – joshumax Apr 01 '15 at 02:12
  • Not everybody runs Ubuntu as a single-user system. Cron isn't useful here. I know you needed the extra step of finding the location of the X cookie file older versions of Gdm, I don't know about recent versions but I think this hasn't changed. Same problem with KDM. @joshumax You can get the information from other sources, and even via dbus, you can do it from the shell with dbus-monitor. See my answer. – Gilles 'SO- stop being evil' Apr 01 '15 at 02:19
2

Script Source

#!/usr/bin/env bash
#
###########################################################
# Author: Serg Kolo , contact: 1047481448@qq.com 
# Date: March 11, 2016
# Purpose: Script to detect connection/disconnection
#          of the ac adapter
#          
# 
# Written for: http://askubuntu.com/q/542986/295286
# Tested on: Ubuntu 14.04 LTS
# Version: 0.2
###########################################################
# Copyright: Serg Kolo , 2016
#    
#     Permission to use, copy, modify, and distribute this software is hereby granted
#     without fee, provided that  the copyright notice above and this permission statement
#     appear in all copies.
#
#     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
#     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
#     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
#     DEALINGS IN THE SOFTWARE.
#set -x
ARGV0="$0"
ARGC=$#

test_presence()
{
  on_ac_power
  echo $?
}

notify_change()
{
   pgrep -f '/usr/bin/X' > /dev/null && GUI=true
   connected='AC adapter connected'
   disconnected='AC adapter disconnected'

   if [ $1 -eq 0 ]
   then
           wall <<< $connected        
           $GUI && DISPLAY=:0 notify-send 'AC adapter connected'

   else
           wall <<< $connected
           $GUI && DISPLAY=:0 notify-send 'AC adapter disconnected'
   fi
}

main()
{
  FLAG=$(test_presence)

  while true
  do
     STATUS=$(test_presence)

     if [ $STATUS -eq $FLAG   ]
     then
        continue
     else
        notify_change $STATUS
        FLAG=$STATUS
     fi

  sleep 3 #0.25
  done
}  

main 

Getting the script

The script is also added to my github ; that version will be updated and developed a tiny bit more.

You can get it by doing the following:

  1. sugo apt-get install git
  2. cd /opt

  3. git clone https://github.com/SergKolo/sergrep.git

The script will be in /opt/sergrep directory, named notify_ac_change.sh

Concept/Design

The key questions are "How do we check presence of the AC adapter ?" and "How do we detect changes?"

Well, this issue has been solved long ago by other developers. Ubuntu comes by default with a script called on_ac_power, which is stored in /usr/bin/on_ac_power. Power adapter can be mentioned under different subsystems in the kernel ( ACPI or APM ) , but this script makes our job simpler - authors have covered a lot of possible variations. It return only exit status so it's appropriate for use in if statements.

Why is on_ac_power is good choice ? Because it relies on checking multiple subsystems. It also provides simple enough command to work with - the result is either true or false.

Thus we have presence detecting tool, but what about logic ? We need to poll the presence and detect change in the state. What we can do is to store exit status of on_ac_power and continuously compare current state with what we have saved, once it changes - send notification, save the status again, and keep comparing again,looping. Basic idea is the use of flags.

In short, we initialize a snapshot of the state, and then continuously poll for change from the snapshot; once change occurs - notify and reset snapshot.

Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497