POLYGLOT PROGRAMMING

Better poly than sorry!

StumpWM - warn about low battery ΒΆ

My work laptop I use right now is rather old (the new one broke, and I'm waiting for the replacement), and it can't last as long on the battery as it should. A few posts back I posted my StumpWM mode-line configuration. You can see that there already is a battery capacity meter there.

The problem with this is that I don't look at it frequently. I can go on using my computer for hours without looking at it a single time. You can probably guess where this is going: the computer died a couple of times because the battery was empty, and I didn't realize it is.

I thought that I should have some alert that would remind me that I should plug the power cord. I couldn't find any ready-made solution for StumpWM, so I decided to roll my own. It wasn't that hard, actually, only a couple lines of code.

Here it is:

(defvar *current-battery-status* 100)

(defun low-battery-alert (&optional bat_percentage)
  ;; use a global value if the caller didn't provide its own value
  ;; (for ease of testing in the REPL)
  (when (not bat_percentage) (setf bat_percentage *current-battery-status*))
  (let
      ((*message-window-gravity* :center) ; make alert appear at the at the center of screen
       (*timeout-wait* 6))              ; wait 6 sec before making alert disappear
    (message "Your battery is running low!~%Only ~s% remaining..." bat_percentage)))


(defun get-battery-status ()
  "Needs the <code>upower</code> utility to be installed in the system, i.e. on Fedora:

$ sudo dnf install -y upower

  Also, try running:

$ upower --enumerate

  to learn what your battery is called. "

  (let* ((command (concat
                   "upower -i /org/freedesktop/UPower/devices/battery_BAT1 "
                   "| grep perc "
                   "| awk '{print $2}'"))
         ;; the command above returns a string looking like this: "11%\n"
         ;; we need to get rid of a percent sign and a newline char then convert
         ;; it into a number, which READ-FROM-STRING does for us
         (new-battery-status (->> (run-shell-command command t)
                                  (string-trim (string #\newline))
                                  (string-trim "%")
                                  read-from-string)))

    (when (and (<= *current-battery-status* 15)
               ;; show alert only when battery status changed since last check,
               ;; but don't do this if the new value is greater than the last
               ;; (this means we're probably plugged in and charging already)
               (> *current-battery-status* new-battery-status))
      (low-battery-alert new-battery-status))

    (setf *current-battery-status* new-battery-status)
    (format nil "~s%" new-battery-status)))

It works well enough for me. I'm putting it here in case someone has a similar problem. If you're interested in making this a StumpWM contrib module, please let me know, I'll try packaging it properly.

I'm not doing it right now because the code is simple, and I have no need for it to be accessible anywhere outside of my .stumpwm.d. I also don't know yet how do you declare and use packages in Common Lisp, but that's just a detail...

Comments