mode-line-battery.lisp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. ;;; mode-line-battery.lisp --- Battery info for the mode line
  2. ;; Copyright © 2008 Julian Stecklina
  3. ;; Copyright © 2018–2019 Alex Kost <alezost@gmail.com>
  4. ;; This program is free software; you can redistribute it and/or modify
  5. ;; it under the terms of the GNU General Public License as published by
  6. ;; the Free Software Foundation, either version 3 of the License, or
  7. ;; (at your option) any later version.
  8. ;;
  9. ;; This program is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;;
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;; This file originates from
  18. ;; <https://github.com/stumpwm/stumpwm-contrib/blob/master/modeline/battery-portable>.
  19. ;; I do not like some things that module does, so I adjusted it for my
  20. ;; needs.
  21. ;; Meaning of "/sys/class/power_supply/<BAT>/*" files can be found at
  22. ;; <https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-power>.
  23. ;;; Code:
  24. (defpackage #:al/stumpwm-battery
  25. (:use :common-lisp
  26. :stumpwm)
  27. (:export #:all-batteries
  28. #:battery-mode-line-string))
  29. (in-package #:al/stumpwm-battery)
  30. (defun power-supply-parameter (path name &optional to-number)
  31. "Return a line (string) from 'PATH/NAME' sysfs file.
  32. If TO-NUMBER is non-nil, convert this string into a number.
  33. Return nil in case of any error."
  34. (al/read-sys-file
  35. (merge-pathnames (make-pathname :name name)
  36. path)
  37. to-number))
  38. (defun all-batteries ()
  39. "Return a list of files of all batteries."
  40. (remove nil
  41. (mapcar (lambda (path)
  42. (handler-case
  43. (when (string= "Battery"
  44. (power-supply-parameter path "type"))
  45. path)
  46. (file-error () nil)))
  47. (list-directory #P"/sys/class/power_supply/"))))
  48. (defun battery-time-left (battery &optional (type :charging))
  49. "Return estimated time left for BATTERY to become empty.
  50. Returned time is a floating number of hours.
  51. Return nil, if it is impossible to calculate.
  52. Calculation is performed depending on TYPE, which should be either
  53. `:charging' or `:discharging'."
  54. (let ((consumed (power-supply-parameter battery "current_now" t)))
  55. (if (zerop consumed)
  56. 0
  57. (let ((left (power-supply-parameter battery "charge_now" t)))
  58. (case type
  59. (:discharging (/ left consumed))
  60. (:charging
  61. (let ((full (power-supply-parameter battery "charge_full" t)))
  62. (/ (- full left) consumed))))))))
  63. (defun battery-state (battery)
  64. "Return values for the current state of BATTERY.
  65. If the battery is charged, return `:charged percent' values.
  66. If the battery is charging or discharging, return
  67. `:(dis)charging percent time-left' values.
  68. Otherwise, return `:unknown'."
  69. (if (zerop (power-supply-parameter battery "present" t))
  70. :unknown
  71. (let ((state (power-supply-parameter battery "status"))
  72. (percent (power-supply-parameter battery "capacity" t)))
  73. (cond
  74. ((string= state "Full") (values :charged percent))
  75. ((string= state "Discharging")
  76. (values :discharging percent
  77. (battery-time-left battery :discharging)))
  78. ((string= state "Charging")
  79. (values :charging percent
  80. (battery-time-left battery :charging)))
  81. (t :unknown)))))
  82. (defun format-hours (time)
  83. "Return 'HH:MM' string from TIME.
  84. TIME is a floating number of hours."
  85. (if (numberp time)
  86. (multiple-value-bind (hours rem)
  87. (truncate time)
  88. (format nil "~D:~2,'0D" hours (floor (* rem 60))))
  89. ""))
  90. (defun battery-mode-line-string (battery)
  91. "Return a string with BATTERY info suitable for the mode-line."
  92. (multiple-value-bind (state percent time)
  93. (battery-state battery)
  94. (concat "^[^b^7*"
  95. (ecase state
  96. (:unknown (format nil "(no info)"))
  97. (:charged (format nil "~D%%" percent))
  98. ((:charging :discharging)
  99. (format nil "^[~A~D^]%%~A^n~A"
  100. (bar-zone-color percent 90 60 30 t)
  101. percent
  102. (if (eq state :charging) "^B^2+" "^B^1-")
  103. (format-hours time))))
  104. "^]")))
  105. ;;; mode-line-battery.lisp ends here