diff options
| author | Zajcev Evgeny | 2020-02-06 10:35:12 +0300 |
|---|---|---|
| committer | Stefan Monnier | 2020-02-06 09:13:19 -0500 |
| commit | d8f4317f03be69cfaf6a60bda228996590fd92b5 (patch) | |
| tree | fec080eabc57b32d6f384caec3e47f76cbaf3fd2 | |
| parent | 7e0a4b7ca5682026397610a05a19d3a2ef023d74 (diff) | |
| download | emacs-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.el | 176 |
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" | 45 | Use `battery-upower-device-list' to list all available UPower devices. |
| 44 | :type 'string | 46 | If 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. | ||
| 53 | Use `battery-upower-device-list' to list all available UPower devices. | ||
| 54 | If 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. | ||
| 560 | See 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. | ||
| 568 | See 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. | ||
| 585 | Only 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. | ||
| 604 | Each 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 | ||