aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZajcev Evgeny2020-02-06 10:35:12 +0300
committerStefan Monnier2020-02-06 09:13:19 -0500
commitd8f4317f03be69cfaf6a60bda228996590fd92b5 (patch)
treefec080eabc57b32d6f384caec3e47f76cbaf3fd2
parent7e0a4b7ca5682026397610a05a19d3a2ef023d74 (diff)
downloademacs-d8f4317f03be69cfaf6a60bda228996590fd92b5.tar.gz
emacs-d8f4317f03be69cfaf6a60bda228996590fd92b5.zip
Make 'M-x battery RET' work out-of-box for UPower users.
* battery.el (battery-upower-prop): Removed in favor for 'battery-upower-device-property'. (battery-upower-device): Can be nil, meaning autodetect the battery device. (battery-upower-line-power-device): New. line-power device. Can be nil, meaning autodetect line-power device. (battery-status-function): Check UPower service is available to use 'battery-upower' as status function. (battery-upower): Speedup. Request D-Bus only once, fetching all the properties at once. Provide string for "%b" format spec. (battery-upower-device-list, battery-upower-device-all-properties, battery-upower-device-property): New functions to work with UPower devices. (battery-upower-dbus-service, battery-upower-dbus-interface, battery-upower-dbus-path, battery-upower-dbus-device-interface, battery-upower-dbus-device-path): New constants describing UPower D-Bus service.
-rw-r--r--lisp/battery.el176
1 files changed, 124 insertions, 52 deletions
diff --git a/lisp/battery.el b/lisp/battery.el
index 1d3390070c3..5368e1b0e96 100644
--- a/lisp/battery.el
+++ b/lisp/battery.el
@@ -23,14 +23,16 @@
23;;; Commentary: 23;;; Commentary:
24 24
25;; There is at present support for GNU/Linux, macOS and Windows. This 25;; There is at present support for GNU/Linux, macOS and Windows. This
26;; library supports both the `/proc/apm' file format of Linux version 26;; library supports UPower (https://upower.freedesktop.org) via D-Bus
27;; 1.3.58 or newer and the `/proc/acpi/' directory structure of Linux 27;; API or the `/proc/apm' file format of Linux version 1.3.58 or newer
28;; 2.4.20 and 2.6. Darwin (macOS) is supported by using the `pmset' 28;; and the `/proc/acpi/' directory structure of Linux 2.4.20 and 2.6.
29;; program. Windows is supported by the GetSystemPowerStatus API call. 29;; Darwin (macOS) is supported by using the `pmset' program. Windows
30;; is supported by the GetSystemPowerStatus API call.
30 31
31;;; Code: 32;;; Code:
32 33
33(require 'timer) 34(require 'timer)
35(require 'dbus)
34(eval-when-compile (require 'cl-lib)) 36(eval-when-compile (require 'cl-lib))
35 37
36(defgroup battery nil 38(defgroup battery nil
@@ -38,12 +40,25 @@
38 :prefix "battery-" 40 :prefix "battery-"
39 :group 'hardware) 41 :group 'hardware)
40 42
41(defcustom battery-upower-device "battery_BAT1" 43(defcustom battery-upower-device nil
42 "Upower battery device name." 44 "UPower device of the `:battery' type.
43 :version "26.1" 45Use `battery-upower-device-list' to list all available UPower devices.
44 :type 'string 46If set to nil, then autodetect `:battery' device."
47 :version "28.1"
48 :type '(choice string (const :tag "Autodetect" nil))
45 :group 'battery) 49 :group 'battery)
46 50
51(defcustom battery-upower-line-power-device nil
52 "UPower device of the `:line-power' type.
53Use `battery-upower-device-list' to list all available UPower devices.
54If set to nil, then autodetect `:battery' device."
55 :version "28.1"
56 :type '(choice string (const :tag "Autodetect" nil))
57 :group 'battery)
58
59(defconst battery-upower-dbus-service "org.freedesktop.UPower"
60 "Well-known UPower service name for the D-Bus system.")
61
47(defun battery--find-linux-sysfs-batteries () 62(defun battery--find-linux-sysfs-batteries ()
48 (let ((dirs nil)) 63 (let ((dirs nil))
49 (dolist (file (directory-files "/sys/class/power_supply/" t)) 64 (dolist (file (directory-files "/sys/class/power_supply/" t))
@@ -54,7 +69,9 @@
54 (nreverse dirs))) 69 (nreverse dirs)))
55 70
56(defcustom battery-status-function 71(defcustom battery-status-function
57 (cond ((and (eq system-type 'gnu/linux) 72 (cond ((dbus-ping :system battery-upower-dbus-service)
73 #'battery-upower)
74 ((and (eq system-type 'gnu/linux)
58 (file-readable-p "/proc/apm")) 75 (file-readable-p "/proc/apm"))
59 #'battery-linux-proc-apm) 76 #'battery-linux-proc-apm)
60 ((and (eq system-type 'gnu/linux) 77 ((and (eq system-type 'gnu/linux)
@@ -537,17 +554,68 @@ The following %-sequences are provided:
537 (t "N/A")))))) 554 (t "N/A"))))))
538 555
539 556
540(declare-function dbus-get-property "dbus.el"
541 (bus service path interface property))
542
543;;; `upowerd' interface. 557;;; `upowerd' interface.
544(defsubst battery-upower-prop (pname &optional device) 558(defconst battery-upower-dbus-interface "org.freedesktop.UPower"
559 "The interface to UPower.
560See URL `https://upower.freedesktop.org/docs/'.")
561
562(defconst battery-upower-dbus-path "/org/freedesktop/UPower"
563 "D-Bus path to talk to UPower service.")
564
565(defconst battery-upower-dbus-device-interface
566 (concat battery-upower-dbus-interface ".Device")
567 "The Device interface of the UPower.
568See URL `https://upower.freedesktop.org/docs/Device.html'.")
569
570(defconst battery-upower-dbus-device-path
571 (concat battery-upower-dbus-path "/devices")
572 "D-Bus path to talk to devices part of the UPower service.")
573
574(defconst battery-upower-types
575 '((0 . :unknown) (1 . :line-power) (2 . :battery)
576 (3 . :ups) (4 . :monitor) (5 . :mouse)
577 (6 . :keyboard) (7 . :pda) (8 . :phone))
578 "Type of the device.")
579
580(defconst battery-upower-states
581 '((0 . "unknown") (1 . "charging") (2 . "discharging")
582 (3 . "empty") (4 . "fully-charged") (5 . "pending-charge")
583 (6 . "pending-discharge"))
584 "Alist of battery power states.
585Only valid for `:battery' devices.")
586
587(defun battery-upower-device-property (device property)
588 "Get value of the single PROPERTY for the UPower DEVICE."
545 (dbus-get-property 589 (dbus-get-property
546 :system 590 :system battery-upower-dbus-service
547 "org.freedesktop.UPower" 591 (expand-file-name device battery-upower-dbus-device-path)
548 (concat "/org/freedesktop/UPower/devices/" (or device battery-upower-device)) 592 battery-upower-dbus-device-interface
549 "org.freedesktop.UPower" 593 property))
550 pname)) 594
595(defun battery-upower-device-all-properties (device)
596 "Return value for all available properties for the UPower DEVICE."
597 (dbus-get-all-properties
598 :system battery-upower-dbus-service
599 (expand-file-name device battery-upower-dbus-device-path)
600 battery-upower-dbus-device-interface))
601
602(defun battery-upower-device-list ()
603 "Return list of all available UPower devices.
604Each element is the cons cell in form: (DEVICE . DEVICE-TYPE)."
605 (mapcar (lambda (device-path)
606 (let* ((device (file-relative-name
607 device-path battery-upower-dbus-device-path))
608 (type-num (battery-upower-device-property device "Type")))
609 (cons device (or (cdr (assq type-num battery-upower-types))
610 :unknown))))
611 (dbus-call-method :system battery-upower-dbus-service
612 battery-upower-dbus-path
613 battery-upower-dbus-interface
614 "EnumerateDevices")))
615
616(defun battery-upower-device-autodetect (device-type)
617 "Return first matching UPower device of DEVICE-TYPE."
618 (car (rassq device-type (battery-upower-device-list))))
551 619
552(defun battery-upower () 620(defun battery-upower ()
553 "Get battery status from dbus Upower interface. 621 "Get battery status from dbus Upower interface.
@@ -559,45 +627,49 @@ The following %-sequences are provided:
559%p Battery load percentage 627%p Battery load percentage
560%r Current rate 628%r Current rate
561%B Battery status (verbose) 629%B Battery status (verbose)
630%b Battery status: empty means high, `-' means low,
631 `!' means critical, and `+' means charging
562%L AC line status (verbose) 632%L AC line status (verbose)
563%s Remaining time (to charge or discharge) in seconds 633%s Remaining time (to charge or discharge) in seconds
564%m Remaining time (to charge or discharge) in minutes 634%m Remaining time (to charge or discharge) in minutes
565%h Remaining time (to charge or discharge) in hours 635%h Remaining time (to charge or discharge) in hours
566%t Remaining time (to charge or discharge) in the form `h:min'" 636%t Remaining time (to charge or discharge) in the form `h:min'"
567 (let ((percents (battery-upower-prop "Percentage")) 637 (let* ((bat-device (or battery-upower-device
568 (time-to-empty (battery-upower-prop "TimeToEmpty")) 638 (battery-upower-device-autodetect :battery)))
569 (time-to-full (battery-upower-prop "TimeToFull")) 639 (bat-props (when bat-device
570 (state (battery-upower-prop "State")) 640 (battery-upower-device-all-properties bat-device)))
571 (online (battery-upower-prop "Online" "line_power_ACAD")) 641 (percents (cdr (assoc "Percentage" bat-props)))
572 (energy (battery-upower-prop "Energy")) 642 (time-to-empty (cdr (assoc "TimeToEmpty" bat-props)))
573 (energy-rate (battery-upower-prop "EnergyRate")) 643 (time-to-full (cdr (assoc "TimeToFull" bat-props)))
574 (battery-states '((0 . "unknown") (1 . "charging") 644 (state (cdr (assoc "State" bat-props)))
575 (2 . "discharging") (3 . "empty") 645 (level (cdr (assoc "BatteryLevel" bat-props)))
576 (4 . "fully-charged") (5 . "pending-charge") 646 (energy (cdr (assoc "Energy" bat-props)))
577 (6 . "pending-discharge"))) 647 (energy-rate (cdr (assoc "EnergyRate" bat-props)))
578 seconds minutes hours remaining-time) 648 (lp-device (or battery-upower-line-power-device
579 (cond ((and online time-to-full) 649 (battery-upower-device-autodetect :line-power)))
580 (setq seconds time-to-full)) 650 (online-p (when lp-device
581 ((and (not online) time-to-empty) 651 (battery-upower-device-property lp-device "Online")))
582 (setq seconds time-to-empty))) 652 (seconds (if online-p time-to-full time-to-empty))
583 (when seconds 653 (minutes (when seconds (/ seconds 60)))
584 (setq minutes (/ seconds 60) 654 (hours (when minutes (/ minutes 60)))
585 hours (/ minutes 60) 655 (remaining-time (when hours
586 remaining-time (format "%d:%02d" hours (mod minutes 60)))) 656 (format "%d:%02d" hours (mod minutes 60)))))
587 (list (cons ?c (or (and energy 657 (list (cons ?c (if energy (number-to-string (round (* 1000 energy))) "N/A"))
588 (number-to-string (round (* 1000 energy)))) 658 (cons ?p (if percents (number-to-string (round percents)) "N/A"))
589 "N/A")) 659 (cons ?r (if energy-rate
590 (cons ?p (or (and percents (number-to-string (round percents))) 660 (concat (number-to-string energy-rate) " W")
591 "N/A")) 661 "N/A"))
592 (cons ?r (or (and energy-rate 662 (cons ?B (if state
593 (concat (number-to-string energy-rate) " W")) 663 (cdr (assq state battery-upower-states))
594 "N/A")) 664 "unknown"))
595 (cons ?B (or (and state (cdr (assoc state battery-states))) 665 (cons ?b (cond ((= level 3) "-")
596 "unknown")) 666 ((= level 4) "!")
597 (cons ?L (or (and online "on-line") "off-line")) 667 (online-p "+")
598 (cons ?s (or (and seconds (number-to-string seconds)) "N/A")) 668 (t "")))
599 (cons ?m (or (and minutes (number-to-string minutes)) "N/A")) 669 (cons ?L (if online-p "on-line" (if lp-device "off-line" "unknown")))
600 (cons ?h (or (and hours (number-to-string hours)) "N/A")) 670 (cons ?s (if seconds (number-to-string seconds) "N/A"))
671 (cons ?m (if minutes (number-to-string minutes) "N/A"))
672 (cons ?h (if hours (number-to-string hours) "N/A"))
601 (cons ?t (or remaining-time "N/A"))))) 673 (cons ?t (or remaining-time "N/A")))))
602 674
603 675