unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* [PATCH] battery.el, upower fixes
@ 2020-01-26 23:04 Evgeny Zajcev
  2020-01-27 14:43 ` Stefan Monnier
  2020-01-27 18:23 ` Eli Zaretskii
  0 siblings, 2 replies; 18+ messages in thread
From: Evgeny Zajcev @ 2020-01-26 23:04 UTC (permalink / raw)
  To: emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 114 bytes --]

Fixes problems users experiencing with `battery-upower'.

Also checks fore UPower is availability

Thanks

-- 
lg

[-- Attachment #1.2: Type: text/html, Size: 312 bytes --]

[-- Attachment #2: 0001-fix-battery.el-battery-upower-prop.patch --]
[-- Type: text/x-patch, Size: 2588 bytes --]

From 124ca9d38ae6752f32b88a7c45111ea1bb423829 Mon Sep 17 00:00:00 2001
From: Zajcev Evgeny <zevlg@yandex.ru>
Date: Mon, 27 Jan 2020 01:26:26 +0300
Subject: [PATCH] [fix] battery.el (battery-upower-prop)

- Commentary about UPower support

- Interface typofix, use "org.freedesktop.UPower.Device" interface
  instead of "org.freedesktop.UPower"

- Use "DisplayDevice" as `battery-upower-device'.  Making
  `battery-upower' to work out-of-box for most users.

- Detect upower availability.  Set `battery-status-function' to
  `battery-upower' in case upower is available.

All this makes `M-x battery RET' to work out-of-box using upower
interface in case of its availability
---
 lisp/battery.el | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/lisp/battery.el b/lisp/battery.el
index 49b01d5b54..057629318e 100644
--- a/lisp/battery.el
+++ b/lisp/battery.el
@@ -23,10 +23,11 @@
 ;;; Commentary:
 
 ;; There is at present support for GNU/Linux, macOS and Windows.  This
-;; library supports both the `/proc/apm' file format of Linux version
-;; 1.3.58 or newer and the `/proc/acpi/' directory structure of Linux
-;; 2.4.20 and 2.6.  Darwin (macOS) is supported by using the `pmset'
-;; program.  Windows is supported by the GetSystemPowerStatus API call.
+;; library supports UPower (https://upower.freedesktop.org) via D-Bus
+;; API or the `/proc/apm' file format of Linux version 1.3.58 or newer
+;; and the `/proc/acpi/' directory structure of Linux 2.4.20 and 2.6.
+;; Darwin (macOS) is supported by using the `pmset' program.  Windows
+;; is supported by the GetSystemPowerStatus API call.
 
 ;;; Code:
 
@@ -45,14 +46,18 @@
   :type 'regexp
   :group 'battery)
 
-(defcustom battery-upower-device "battery_BAT1"
+(defcustom battery-upower-device "DisplayDevice"
   "Upower battery device name."
   :version "26.1"
   :type 'string
   :group 'battery)
 
+(declare-function dbus-list-known-names "dbus.el" (bus))
+
 (defcustom battery-status-function
-  (cond ((and (eq system-type 'gnu/linux)
+  (cond ((member "org.freedesktop.UPower" (dbus-list-known-names :system))
+         #'battery-upower)
+        ((and (eq system-type 'gnu/linux)
 	      (file-readable-p "/proc/apm"))
 	 #'battery-linux-proc-apm)
 	((and (eq system-type 'gnu/linux)
@@ -547,7 +552,7 @@ The following %-sequences are provided:
    :system
    "org.freedesktop.UPower"
    (concat "/org/freedesktop/UPower/devices/" (or device battery-upower-device))
-   "org.freedesktop.UPower"
+   "org.freedesktop.UPower.Device"
    pname))
 
 (defun battery-upower ()
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-01-26 23:04 [PATCH] battery.el, upower fixes Evgeny Zajcev
@ 2020-01-27 14:43 ` Stefan Monnier
  2020-01-27 18:23 ` Eli Zaretskii
  1 sibling, 0 replies; 18+ messages in thread
From: Stefan Monnier @ 2020-01-27 14:43 UTC (permalink / raw)
  To: Evgeny Zajcev; +Cc: emacs-devel

> Fixes problems users experiencing with `battery-upower'.
> Also checks fore UPower is availability

Thanks, Evgeny.
I'm on a desktop right now so can't test it, but here are some comments:

> Subject: [PATCH] [fix] battery.el (battery-upower-prop)

Fine.

> - Commentary about UPower support
>
> - Interface typofix, use "org.freedesktop.UPower.Device" interface
>   instead of "org.freedesktop.UPower"
>
> - Use "DisplayDevice" as `battery-upower-device'.  Making
>   `battery-upower' to work out-of-box for most users.
>
> - Detect upower availability.  Set `battery-status-function' to
>   `battery-upower' in case upower is available.

Here, please try and use the ChangeLog format.  E.g.

    * lisp/battery.el (battery-upower-device): Use "DisplayDevice".
    Should make `battery-upower' work out-of-box for most users.
    (battery-upower-prop): Interface typofix, use
    "org.freedesktop.UPower.Device" interface instead of
    "org.freedesktop.UPower".
    (battery-status-function): Detect upower availability.
    Use `battery-upower' in case UPower is available.

>  ;; There is at present support for GNU/Linux, macOS and Windows.  This
> -;; library supports both the `/proc/apm' file format of Linux version
> -;; 1.3.58 or newer and the `/proc/acpi/' directory structure of Linux
> -;; 2.4.20 and 2.6.  Darwin (macOS) is supported by using the `pmset'
> -;; program.  Windows is supported by the GetSystemPowerStatus API call.
> +;; library supports UPower (https://upower.freedesktop.org) via D-Bus
> +;; API or the `/proc/apm' file format of Linux version 1.3.58 or newer
> +;; and the `/proc/acpi/' directory structure of Linux 2.4.20 and 2.6.
> +;; Darwin (macOS) is supported by using the `pmset' program.  Windows
> +;; is supported by the GetSystemPowerStatus API call.

Not a criticism, but I just notice that this doesn't mention the
/sys/class/power_supply interface used in more recent kernels.  If you
can update this comment accordingly it would be even better (but if you
don't, that's fine as well).

> -(defcustom battery-upower-device "battery_BAT1"
> +(defcustom battery-upower-device "DisplayDevice"

Could add some comment explaining why "DisplayDevice" is a good choice
(and what it means)?  Maybe a simple URL pointing to some
UPower documentation?

Intuitively, without any knowledge of UPower (or D-Bus for that matter),
this choice of name sounds rather odd (sounds like the it's talking
about the screen rather than the battery).

> +(declare-function dbus-list-known-names "dbus.el" (bus))
> +
>  (defcustom battery-status-function
> -  (cond ((and (eq system-type 'gnu/linux)
> +  (cond ((member "org.freedesktop.UPower" (dbus-list-known-names :system))
> +         #'battery-upower)

Since causes an error when I try it because `dbus` is not yet loaded
when we call this function.  Also, please make sure it still behaves
properly if Emacs was built without D-Bus support.

>     (concat "/org/freedesktop/UPower/devices/" (or device battery-upower-device))
> -   "org.freedesktop.UPower"
> +   "org.freedesktop.UPower.Device"

Here, as well, if you happen to have a URL handy that documents this
part of the UPower interface, it would make a good comment.


        Stefan




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-01-26 23:04 [PATCH] battery.el, upower fixes Evgeny Zajcev
  2020-01-27 14:43 ` Stefan Monnier
@ 2020-01-27 18:23 ` Eli Zaretskii
  2020-01-29  7:05   ` Evgeny Zajcev
  1 sibling, 1 reply; 18+ messages in thread
From: Eli Zaretskii @ 2020-01-27 18:23 UTC (permalink / raw)
  To: Evgeny Zajcev; +Cc: emacs-devel

> From: Evgeny Zajcev <lg.zevlg@gmail.com>
> Date: Mon, 27 Jan 2020 02:04:30 +0300
> 
> Fixes problems users experiencing with `battery-upower'.
> 
> Also checks fore UPower is availability

Thanks, a couple of comments below, in addition to what Stefan wrote:

> -(defcustom battery-upower-device "battery_BAT1"
> +(defcustom battery-upower-device "DisplayDevice"
>    "Upower battery device name."
>    :version "26.1"

Please update the :version tag to 28.1, since you are changing the
default value for that version.

Also, I think if D-Bus is not compiled into Emacs, the default value
should be what we had before these changes.



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-01-27 18:23 ` Eli Zaretskii
@ 2020-01-29  7:05   ` Evgeny Zajcev
  2020-01-29  8:37     ` Andreas Schwab
  0 siblings, 1 reply; 18+ messages in thread
From: Evgeny Zajcev @ 2020-01-29  7:05 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 496 bytes --]

Need some assistance guys.

I want to write code such as:

  (defcustom battery-status-function
    (cond ((battery-upower-usable-p)
           #'battery-upower)
    ....)

  (defun battery-upower-usable-p ()
     ...)

However such code triggers error:

   cond: Symbol’s function definition is void: battery-upower-usable-p

On fresh Emacs start and M-x battery RET

What is the best approach to write defcustoms with forward references to
functions?

Thanks

-- 
lg

[-- Attachment #2: Type: text/html, Size: 817 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-01-29  7:05   ` Evgeny Zajcev
@ 2020-01-29  8:37     ` Andreas Schwab
  2020-01-30 10:22       ` Evgeny Zajcev
  0 siblings, 1 reply; 18+ messages in thread
From: Andreas Schwab @ 2020-01-29  8:37 UTC (permalink / raw)
  To: Evgeny Zajcev; +Cc: Eli Zaretskii, emacs-devel

On Jan 29 2020, Evgeny Zajcev wrote:

> What is the best approach to write defcustoms with forward references to
> functions?

The only way to go is to define the function before the point it is
called first.

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-01-29  8:37     ` Andreas Schwab
@ 2020-01-30 10:22       ` Evgeny Zajcev
  2020-02-04 19:55         ` Stefan Monnier
  0 siblings, 1 reply; 18+ messages in thread
From: Evgeny Zajcev @ 2020-01-30 10:22 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Eli Zaretskii, emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 468 bytes --]

Ok, here is the updated version.  I rewrote it in the way to work
out-of-box for most (with single battery) users.
Checked it works fine with no D-Bus compiled in.  Or with disabled "upowerd"

Few users on different laptops tried this code and it works out-of-box for
them.

I did not documented power_supply interface, English is not my native
language, somebody could do it much better.  Also I have no knowledge at
all about power_supply interface.

Thanks

-- 
lg

[-- Attachment #1.2: Type: text/html, Size: 671 bytes --]

[-- Attachment #2: 0001-Make-M-x-battery-RET-work-out-of-box-for-UPower-user.patch --]
[-- Type: text/x-patch, Size: 12748 bytes --]

From 7f8219f12452e6a9409a413c0a4ef255a0d0e496 Mon Sep 17 00:00:00 2001
From: Zajcev Evgeny <zevlg@yandex.ru>
Date: Mon, 27 Jan 2020 01:26:26 +0300
Subject: [PATCH] Make 'M-x battery RET' work out-of-box for UPower users.

* battery.el (battery-upower-prop): Autodetect usable battery device.
  (battery-upower-line-power-device): Autodetect usable line power
  device.
  (battery-status-function): Detect usable UPower service to use
  'battery-upower' as status function.
  (battery-upower): Speedup.  Request D-Bus only once, fetching all
  the properties at once.
  (battery-upower-usable-p): New func, return non-nil if UPower
  service is usable.
  (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.
---
 lisp/battery.el | 244 +++++++++++++++++++++++++++++++++---------------
 1 file changed, 171 insertions(+), 73 deletions(-)

diff --git a/lisp/battery.el b/lisp/battery.el
index 49b01d5b54..9b402406da 100644
--- a/lisp/battery.el
+++ b/lisp/battery.el
@@ -23,14 +23,16 @@
 ;;; Commentary:
 
 ;; There is at present support for GNU/Linux, macOS and Windows.  This
-;; library supports both the `/proc/apm' file format of Linux version
-;; 1.3.58 or newer and the `/proc/acpi/' directory structure of Linux
-;; 2.4.20 and 2.6.  Darwin (macOS) is supported by using the `pmset'
-;; program.  Windows is supported by the GetSystemPowerStatus API call.
+;; library supports UPower (https://upower.freedesktop.org) via D-Bus
+;; API or the `/proc/apm' file format of Linux version 1.3.58 or newer
+;; and the `/proc/acpi/' directory structure of Linux 2.4.20 and 2.6.
+;; Darwin (macOS) is supported by using the `pmset' program.  Windows
+;; is supported by the GetSystemPowerStatus API call.
 
 ;;; Code:
 
 (require 'timer)
+(require 'dbus)
 (eval-when-compile (require 'cl-lib))
 \f
 (defgroup battery nil
@@ -45,14 +47,174 @@ battery-linux-sysfs-regexp
   :type 'regexp
   :group 'battery)
 
-(defcustom battery-upower-device "battery_BAT1"
-  "Upower battery device name."
-  :version "26.1"
-  :type 'string
+\f
+;;; `upowerd' interface.
+(require 'dbus)
+
+(defconst battery-upower-dbus-service "org.freedesktop.UPower"
+  "Well-known UPower service name for the D-Bus system.")
+
+(defconst battery-upower-dbus-interface "org.freedesktop.UPower"
+  "The interface to UPower.
+See URL `https://upower.freedesktop.org/docs/'.")
+
+(defconst battery-upower-dbus-path "/org/freedesktop/UPower"
+  "D-Bus path to talk to UPower service.")
+
+(defconst battery-upower-dbus-device-interface
+  (concat battery-upower-dbus-interface ".Device")
+  "The Device interface of the UPower.
+See URL `https://upower.freedesktop.org/docs/Device.html'.")
+
+(defconst battery-upower-dbus-device-path
+  (concat battery-upower-dbus-path "/devices")
+  "D-Bus path to talk to devices part of the UPower service.")
+
+(defconst battery-upower-types
+  '((0 . :unknown) (1 . :line-power) (2 . :battery)
+    (3 . :ups) (4 . :monitor) (5 . :mouse)
+    (6 . :keyboard) (7 . :pda) (8 . :phone))
+  "Type of the device.")
+
+(defconst battery-upower-states
+  '((0 . "unknown") (1 . "charging") (2 . "discharging")
+    (3 . "empty") (4 . "fully-charged") (5 . "pending-charge")
+    (6 . "pending-discharge"))
+  "Alist of battery power states.
+Only valid for `:battery' devices.")
+
+(defsubst battery-upower-device-property (device property)
+  "Get value of the single PROPERTY for the UPower DEVICE."
+  (dbus-get-property
+   :system battery-upower-dbus-service
+   (expand-file-name device battery-upower-dbus-device-path)
+   battery-upower-dbus-device-interface
+   property))
+
+(defun battery-upower-device-all-properties (device)
+  "Return value for all available properties for the UPower DEVICE."
+  (dbus-get-all-properties
+   :system battery-upower-dbus-service
+   (expand-file-name device battery-upower-dbus-device-path)
+   battery-upower-dbus-device-interface))
+
+(defun battery-upower-device-list ()
+  "Return list of all available UPower devices.
+Each element is the cons cell in form: (DEVICE . DEVICE-TYPE)."
+  (mapcar (lambda (device-path)
+            (let* ((device (file-relative-name
+                            device-path battery-upower-dbus-device-path))
+                   (type-num (battery-upower-device-property device "Type")))
+              (cons device (or (cdr (assq type-num battery-upower-types))
+                               :unknown))))
+          (dbus-call-method :system battery-upower-dbus-service
+                            battery-upower-dbus-path
+                            battery-upower-dbus-interface
+                            "EnumerateDevices")))
+
+(declare-function cl-find "cl-seq" (cl-item cl-seq &rest cl-keys))
+
+;;;###autoload
+(defun battery-upower-device-autodetect (device-type)
+  "Return first matching UPower device of DEVICE-TYPE."
+  (let ((devices (battery-upower-device-list)))
+    (car (cl-find device-type devices :key 'cdr))))
+
+(defcustom battery-upower-device
+  (dbus-ignore-errors
+    (battery-upower-device-autodetect :battery))
+  "UPower device of the `:battery' type.
+Use `battery-upower-device-list' to list all available UPower devices."
+  :version "28.1"
+  :type 'string-or-null-p
   :group 'battery)
 
+(defcustom battery-upower-line-power-device
+  (dbus-ignore-errors
+    (battery-upower-device-autodetect :line-power))
+  "UPower device of the `:line-power' type.
+Use `battery-upower-device-list' to list all available UPower devices."
+  :version "28.1"
+  :type 'string-or-null-p
+  :group 'battery)
+
+(defun battery-upower-usable-p ()
+  "Return non-nil if UPower interface is available and usable.
+If D-Bus support is not compiled into Emacs, then return nil.
+Issue warring if `battery-upower-device' or
+`battery-upower-line-power-device' is invalid.
+Return nil if `battery-upower-device' is invalid.
+However accept invalid `battery-upower-line-power-device' value,
+just showing warning."
+  (when (and battery-upower-device
+             (dbus-ping :system battery-upower-dbus-service))
+    (let ((bat-type (battery-upower-device-property
+                     battery-upower-device "Type"))
+          (lp-type (when battery-upower-line-power-device
+                     (battery-upower-device-property
+                      battery-upower-line-power-device "Type"))))
+      (unless (eq (cdr (assq lp-type battery-upower-types)) :line-power)
+        (display-warning 'battery (format "\
+Unknown `:line-power' UPower device `battery-upower-line-power-device' (%S).
+AC status won't be shown correctly."
+                                          battery-upower-line-power-device)
+                         :warning))
+
+      (if (eq (cdr (assq bat-type battery-upower-types)) :battery)
+          t
+
+        (display-warning 'battery (format "\
+Unknown `:battery' UPower device `battery-upower-device' (%S).
+Can't use UPower as source for the battery.
+Use `battery-upower-device-list' to list all the UPower devices."
+                                          battery-upower-device)
+                         :warning)
+        nil))))
+
+(defun battery-upower ()
+  "Get battery status from dbus Upower interface.
+This function works only in systems with `upowerd' daemon
+running.
+
+The following %-sequences are provided:
+%c Current capacity (mWh)
+%p Battery load percentage
+%r Current rate
+%B Battery status (verbose)
+%L AC line status (verbose)
+%s Remaining time (to charge or discharge) in seconds
+%m Remaining time (to charge or discharge) in minutes
+%h Remaining time (to charge or discharge) in hours
+%t Remaining time (to charge or discharge) in the form `h:min'"
+  (let* ((bat-props (battery-upower-device-all-properties battery-upower-device))
+         (percents (cdr (assoc "Percentage" bat-props)))
+         (time-to-empty (cdr (assoc "TimeToEmpty" bat-props)))
+         (time-to-full (cdr (assoc "TimeToFull" bat-props)))
+         (state (cdr (assoc "State" bat-props)))
+         (energy (cdr (assoc "Energy" bat-props)))
+         (energy-rate (cdr (assoc "EnergyRate" bat-props)))
+         (online-p (when battery-upower-line-power-device
+                     (battery-upower-device-property
+                      battery-upower-line-power-device "Online")))
+         (seconds (if online-p time-to-full time-to-empty))
+         (minutes (when seconds (/ seconds 60)))
+         (hours (when minutes (/ minutes 60)))
+         (remaining-time (when hours (format "%d:%02d" hours (mod minutes 60)))))
+    (list (cons ?c (if energy (number-to-string (round (* 1000 energy))) "N/A"))
+          (cons ?p (if percents (number-to-string (round percents)) "N/A"))
+          (cons ?r (if energy-rate (concat (number-to-string energy-rate) " W") "N/A"))
+          (cons ?B (if state (cdr (assq state battery-upower-states)) "unknown"))
+          (cons ?L (if online-p "on-line"
+                     (if battery-upower-line-power-device "off-line" "unknown")))
+          (cons ?s (if seconds (number-to-string seconds) "N/A"))
+          (cons ?m (if minutes (number-to-string minutes) "N/A"))
+          (cons ?h (if hours (number-to-string hours) "N/A"))
+          (cons ?t (or remaining-time "N/A")))))
+
 (defcustom battery-status-function
-  (cond ((and (eq system-type 'gnu/linux)
+  (cond ((battery-upower-usable-p)
+         #'battery-upower)
+        ((and (eq system-type 'gnu/linux)
 	      (file-readable-p "/proc/apm"))
 	 #'battery-linux-proc-apm)
 	((and (eq system-type 'gnu/linux)
@@ -538,70 +700,6 @@ battery-linux-sysfs
                     (t "N/A"))))))
 
 \f
-(declare-function dbus-get-property "dbus.el"
-                  (bus service path interface property))
-
-;;; `upowerd' interface.
-(defsubst battery-upower-prop (pname &optional device)
-  (dbus-get-property
-   :system
-   "org.freedesktop.UPower"
-   (concat "/org/freedesktop/UPower/devices/" (or device battery-upower-device))
-   "org.freedesktop.UPower"
-   pname))
-
-(defun battery-upower ()
-  "Get battery status from dbus Upower interface.
-This function works only in systems with `upowerd' daemon
-running.
-
-The following %-sequences are provided:
-%c Current capacity (mWh)
-%p Battery load percentage
-%r Current rate
-%B Battery status (verbose)
-%L AC line status (verbose)
-%s Remaining time (to charge or discharge) in seconds
-%m Remaining time (to charge or discharge) in minutes
-%h Remaining time (to charge or discharge) in hours
-%t Remaining time (to charge or discharge) in the form `h:min'"
-  (let ((percents (battery-upower-prop "Percentage"))
-        (time-to-empty (battery-upower-prop "TimeToEmpty"))
-        (time-to-full (battery-upower-prop "TimeToFull"))
-        (state (battery-upower-prop "State"))
-        (online (battery-upower-prop "Online" "line_power_ACAD"))
-        (energy (battery-upower-prop "Energy"))
-        (energy-rate (battery-upower-prop "EnergyRate"))
-        (battery-states '((0 . "unknown") (1 . "charging")
-                          (2 . "discharging") (3 . "empty")
-                          (4 . "fully-charged") (5 . "pending-charge")
-                          (6 . "pending-discharge")))
-        seconds minutes hours remaining-time)
-    (cond ((and online time-to-full)
-           (setq seconds time-to-full))
-          ((and (not online) time-to-empty)
-           (setq seconds time-to-empty)))
-    (when seconds
-      (setq minutes (/ seconds 60)
-            hours (/ minutes 60)
-	    remaining-time (format "%d:%02d" hours (mod minutes 60))))
-    (list (cons ?c (or (and energy
-                            (number-to-string (round (* 1000 energy))))
-                       "N/A"))
-          (cons ?p (or (and percents (number-to-string (round percents)))
-                       "N/A"))
-          (cons ?r (or (and energy-rate
-                            (concat (number-to-string energy-rate) " W"))
-                       "N/A"))
-          (cons ?B (or (and state (cdr (assoc state battery-states)))
-                       "unknown"))
-          (cons ?L (or (and online "on-line") "off-line"))
-          (cons ?s (or (and seconds (number-to-string seconds)) "N/A"))
-          (cons ?m (or (and minutes (number-to-string minutes)) "N/A"))
-          (cons ?h (or (and hours (number-to-string hours)) "N/A"))
-          (cons ?t (or remaining-time "N/A")))))
-
-\f
 ;;; `apm' interface for BSD.
 (defun battery-bsd-apm ()
   "Get APM status information from BSD apm binary.
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-01-30 10:22       ` Evgeny Zajcev
@ 2020-02-04 19:55         ` Stefan Monnier
  2020-02-04 20:16           ` Michael Albinus
  2020-02-05  0:22           ` Evgeny Zajcev
  0 siblings, 2 replies; 18+ messages in thread
From: Stefan Monnier @ 2020-02-04 19:55 UTC (permalink / raw)
  To: Evgeny Zajcev; +Cc: Andreas Schwab, Eli Zaretskii, emacs-devel

> Ok, here is the updated version.  I rewrote it in the way to work
> out-of-box for most (with single battery) users.
> Checked it works fine with no D-Bus compiled in.  Or with disabled "upowerd"

I get an error on `cl-find` that's a void function.

> I did not documented power_supply interface, English is not my native
> language, somebody could do it much better.  Also I have no knowledge at
> all about power_supply interface.

No problem, I'll take care of that afterwards.

> * battery.el (battery-upower-prop): Autodetect usable battery device.
>   (battery-upower-line-power-device): Autodetect usable line power
>   device.
>   (battery-status-function): Detect usable UPower service to use
>   'battery-upower' as status function.
>   (battery-upower): Speedup.  Request D-Bus only once, fetching all
>   the properties at once.
>   (battery-upower-usable-p): New func, return non-nil if UPower
>   service is usable.
>   (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.

Looks good, thanks.

Your patch failed to apply to `master`, tho; it seems like it was made
against an "old" version of battery.el (maybe from Emacs-26.3?).

>  (require 'timer)
> +(require 'dbus)
[...]
> -(defcustom battery-upower-device "battery_BAT1"
> -  "Upower battery device name."
> -  :version "26.1"
> -  :type 'string
> +\f
> +;;; `upowerd' interface.
> +(require 'dbus)

You (require 'dbus) twice.

> +(defsubst battery-upower-device-property (device property)

Don't make it a defubst: there's no point trying to optimize calls to
this function.

> +(declare-function cl-find "cl-seq" (cl-item cl-seq &rest cl-keys))

Better just (require 'cl-lib) since it seems like the above
`declare-function` (which promises that the function will have be made
available by the time we call it) is lying.
[ BTW, this use of `cl-find` can be replaced by `rassq`.  ]

> +;;;###autoload
> +(defun battery-upower-device-autodetect (device-type)

Why do we need to autoload it?

> +(defcustom battery-upower-device
> +  (dbus-ignore-errors
> +    (battery-upower-device-autodetect :battery))

I think there's a possibility that the set of devices changes over time
(e.g. on my machine (battery-upower-device-list) currently only shows
battery_BAT0, but I can insert a second battery and I'd expect the list
to then include a battery_BAT1 as well).  So maybe we should instead
allow a special value (e.g. nil) to mean "autodetect" and then do the
autodetection dynamically.  WDYT?

> +  "UPower device of the `:battery' type.
> +Use `battery-upower-device-list' to list all available UPower devices."
> +  :version "28.1"
> +  :type 'string-or-null-p
>    :group 'battery)

`string-or-null-p` is not a known widget type.  You probably need to use
(choice string (const nil)) or something like that instead.

On a related note: the battery.el in `master` by default uses the sysfs
interface and combines all available batteries in there into the single
output result (for those users whose laptop has 2 batteries).
[ But let's keep this for a later patch.  ]

> +(defun battery-upower ()

Could you keep this function where it was, so the patch shows clearly
what was changed?

BTW, I wonder if `battery-upower-usable-p` should maybe only check
(dbus-ping :system battery-upower-dbus-service) and nothing else, so we
use upower if the service is available and even we have it
mis-configured.  It also also have the benefit that the mere act of
loading `battery.el` (which can happen even without any intention to use
`battery`) wouldn't emit warnings when the device names are wrong, IMO.

Also, it'd be nice to keep/move more of the code underneath the `defcustom`s.


        Stefan




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-02-04 19:55         ` Stefan Monnier
@ 2020-02-04 20:16           ` Michael Albinus
  2020-02-04 23:10             ` Stefan Monnier
  2020-06-11 16:12             ` Basil L. Contovounesios
  2020-02-05  0:22           ` Evgeny Zajcev
  1 sibling, 2 replies; 18+ messages in thread
From: Michael Albinus @ 2020-02-04 20:16 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Andreas Schwab, Eli Zaretskii, Evgeny Zajcev, emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> +(defcustom battery-upower-device
>> +  (dbus-ignore-errors
>> +    (battery-upower-device-autodetect :battery))
>
> I think there's a possibility that the set of devices changes over time
> (e.g. on my machine (battery-upower-device-list) currently only shows
> battery_BAT0, but I can insert a second battery and I'd expect the list
> to then include a battery_BAT1 as well).  So maybe we should instead
> allow a special value (e.g. nil) to mean "autodetect" and then do the
> autodetection dynamically.  WDYT?

Usually, D-Bus services send a signal when a device is added/removed. IIUC
https://upower.freedesktop.org/docs/UPower.html,
org.freedesktop.UPower.DeviceAdded and org.freedesktop.UPower.DeviceRemoved
serve for that purpose. So you shall subscribe to those signals and
handle them accordingly.

>         Stefan

Best regards, Michael.



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-02-04 20:16           ` Michael Albinus
@ 2020-02-04 23:10             ` Stefan Monnier
  2020-06-11 16:12             ` Basil L. Contovounesios
  1 sibling, 0 replies; 18+ messages in thread
From: Stefan Monnier @ 2020-02-04 23:10 UTC (permalink / raw)
  To: Michael Albinus; +Cc: Andreas Schwab, Eli Zaretskii, Evgeny Zajcev, emacs-devel

>>> +(defcustom battery-upower-device
>>> +  (dbus-ignore-errors
>>> +    (battery-upower-device-autodetect :battery))
>>
>> I think there's a possibility that the set of devices changes over time
>> (e.g. on my machine (battery-upower-device-list) currently only shows
>> battery_BAT0, but I can insert a second battery and I'd expect the list
>> to then include a battery_BAT1 as well).  So maybe we should instead
>> allow a special value (e.g. nil) to mean "autodetect" and then do the
>> autodetection dynamically.  WDYT?
>
> Usually, D-Bus services send a signal when a device is added/removed. IIUC
> https://upower.freedesktop.org/docs/UPower.html,
> org.freedesktop.UPower.DeviceAdded and org.freedesktop.UPower.DeviceRemoved
> serve for that purpose. So you shall subscribe to those signals and
> handle them accordingly.

Sure, but you wouldn't want to set a `defcustom` in response to that, so
the `defcustom` should have a separate setting to mean "autodetect".


        Stefan




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-02-04 19:55         ` Stefan Monnier
  2020-02-04 20:16           ` Michael Albinus
@ 2020-02-05  0:22           ` Evgeny Zajcev
  2020-02-05  1:27             ` Stefan Monnier
  1 sibling, 1 reply; 18+ messages in thread
From: Evgeny Zajcev @ 2020-02-05  0:22 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Andreas Schwab, Eli Zaretskii, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 5878 bytes --]

вт, 4 февр. 2020 г. в 22:55, Stefan Monnier <monnier@iro.umontreal.ca>:

> > Ok, here is the updated version.  I rewrote it in the way to work
> > out-of-box for most (with single battery) users.
> > Checked it works fine with no D-Bus compiled in.  Or with disabled
> "upowerd"
>
> I get an error on `cl-find` that's a void function.
>
>
Yeah, will get rid of it

> I did not documented power_supply interface, English is not my native
> > language, somebody could do it much better.  Also I have no knowledge at
> > all about power_supply interface.
>
> No problem, I'll take care of that afterwards.
>
> > * battery.el (battery-upower-prop): Autodetect usable battery device.
> >   (battery-upower-line-power-device): Autodetect usable line power
> >   device.
> >   (battery-status-function): Detect usable UPower service to use
> >   'battery-upower' as status function.
> >   (battery-upower): Speedup.  Request D-Bus only once, fetching all
> >   the properties at once.
> >   (battery-upower-usable-p): New func, return non-nil if UPower
> >   service is usable.
> >   (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.
>
> Looks good, thanks.
>
> Your patch failed to apply to `master`, tho; it seems like it was made
> against an "old" version of battery.el (maybe from Emacs-26.3?).
>
>
oh, sorry, I thought I've applied it to Emacs28, Will reapply to master

>  (require 'timer)
> > +(require 'dbus)
> [...]
> > -(defcustom battery-upower-device "battery_BAT1"
> > -  "Upower battery device name."
> > -  :version "26.1"
> > -  :type 'string
> > +
> > +;;; `upowerd' interface.
> > +(require 'dbus)
>
> You (require 'dbus) twice.
>
> > +(defsubst battery-upower-device-property (device property)
>
> Don't make it a defubst: there's no point trying to optimize calls to
> this function.
>
> > +(declare-function cl-find "cl-seq" (cl-item cl-seq &rest cl-keys))
>
> Better just (require 'cl-lib) since it seems like the above
> `declare-function` (which promises that the function will have be made
> available by the time we call it) is lying.
> [ BTW, this use of `cl-find` can be replaced by `rassq`.  ]
>
>

Yeah, `rassq' is just what is needed here

> +;;;###autoload
> > +(defun battery-upower-device-autodetect (device-type)
>
> Why do we need to autoload it?


Hmm, maybe no reason actually.  My thought was about providing some way for
user to autodetect :battery and :line-power device in his init.el and
explicitly write something like:

  (setq battery-upower-device (battery-upower-device-autodetect :battery))

So he states in the config, that he has upower and want error to be rised
if upower service is not available.

This matters especially if we make `battery-upower-device' to be nil by
default in order to silently autodetect upower device and fallback to other
battery backend if upower service is not available.

> +(defcustom battery-upower-device
> > +  (dbus-ignore-errors
> > +    (battery-upower-device-autodetect :battery))
>
> I think there's a possibility that the set of devices changes over time
> (e.g. on my machine (battery-upower-device-list) currently only shows
> battery_BAT0, but I can insert a second battery and I'd expect the list
> to then include a battery_BAT1 as well).  So maybe we should instead
> allow a special value (e.g. nil) to mean "autodetect" and then do the
> autodetection dynamically.  WDYT?
>
> > +  "UPower device of the `:battery' type.
> > +Use `battery-upower-device-list' to list all available UPower devices."
> > +  :version "28.1"
> > +  :type 'string-or-null-p
> >    :group 'battery)
>
> `string-or-null-p` is not a known widget type.  You probably need to use
> (choice string (const nil)) or something like that instead.
>
>
noted.

On a related note: the battery.el in `master` by default uses the sysfs
> interface and combines all available batteries in there into the single
> output result (for those users whose laptop has 2 batteries).
> [ But let's keep this for a later patch.  ]
>
> > +(defun battery-upower ()
>
> Could you keep this function where it was, so the patch shows clearly
> what was changed?
>
> BTW, I wonder if `battery-upower-usable-p` should maybe only check
> (dbus-ping :system battery-upower-dbus-service) and nothing else, so we
> use upower if the service is available and even we have it
> mis-configured.  It also also have the benefit that the mere act of
> loading `battery.el` (which can happen even without any intention to use
> `battery`) wouldn't emit warnings when the device names are wrong, IMO.
>
>
If `battery.el` is loaded unintentionally, then all the custom vars will
have suitable values to have no warnings.  However if user explicitly set
`battery-upower-device` to invalid value, then warning will arise on
battery.el load.  Otherwise (no warning on invalid
`battery-upower-device`), if upower service is available -
`battery-status-function` will be set to upower, and `M-x battery RET` will
produce N/A values, and there is no clue for the user that he just have
invalid value for the `battery-upower-device`.

Also, it'd be nice to keep/move more of the code underneath the
> `defcustom`s.
>
>
Reason why I've put defcustom beneath all the functions is:
>> What is the best approach to write defcustoms with forward references to
>> functions?

> The only way to go is to define the function before the point it is
> called first.

-- 
lg

[-- Attachment #2: Type: text/html, Size: 7972 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-02-05  0:22           ` Evgeny Zajcev
@ 2020-02-05  1:27             ` Stefan Monnier
  2020-02-05  2:24               ` Evgeny Zajcev
  0 siblings, 1 reply; 18+ messages in thread
From: Stefan Monnier @ 2020-02-05  1:27 UTC (permalink / raw)
  To: Evgeny Zajcev; +Cc: Andreas Schwab, Eli Zaretskii, emacs-devel

> Hmm, maybe no reason actually.  My thought was about providing some way for
> user to autodetect :battery and :line-power device in his init.el and
> explicitly write something like:
>
>   (setq battery-upower-device (battery-upower-device-autodetect :battery))
>
> So he states in the config, that he has upower and want error to be rised
> if upower service is not available.

But

    (setq battery-status-function #'battery-upower)

already does that in a more direct and reliable way, no?

> If `battery.el` is loaded unintentionally, then all the custom vars will
> have suitable values to have no warnings.  However if user explicitly set
> `battery-upower-device` to invalid value, then warning will arise on
> battery.el load.

Exactly, and even if the user did not intend to use battery in this
session (Elisp files can be loaded "spuriously").

> Otherwise (no warning on invalid `battery-upower-device`), if upower
> service is available - `battery-status-function` will be set to
> upower, and `M-x battery RET` will produce N/A values, and there is no
> clue for the user that he just have invalid value for the
> `battery-upower-device`.

No: `M-x battery` will emit the warning.


        Stefan




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-02-05  1:27             ` Stefan Monnier
@ 2020-02-05  2:24               ` Evgeny Zajcev
  2020-02-05  3:03                 ` Stefan Monnier
  0 siblings, 1 reply; 18+ messages in thread
From: Evgeny Zajcev @ 2020-02-05  2:24 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Andreas Schwab, Eli Zaretskii, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 2088 bytes --]

ср, 5 февр. 2020 г. в 04:27, Stefan Monnier <monnier@iro.umontreal.ca>:

> > Hmm, maybe no reason actually.  My thought was about providing some way
> for
> > user to autodetect :battery and :line-power device in his init.el and
> > explicitly write something like:
> >
> >   (setq battery-upower-device (battery-upower-device-autodetect
> :battery))
> >
> > So he states in the config, that he has upower and want error to be rised
> > if upower service is not available.
>
> But
>
>     (setq battery-status-function #'battery-upower)
>
> already does that in a more direct and reliable way, no?
>
>
Yes, reasonable indeed.

> If `battery.el` is loaded unintentionally, then all the custom vars will
> > have suitable values to have no warnings.  However if user explicitly set
> > `battery-upower-device` to invalid value, then warning will arise on
> > battery.el load.
>
> Exactly, and even if the user did not intend to use battery in this
> session (Elisp files can be loaded "spuriously").
>
> > Otherwise (no warning on invalid `battery-upower-device`), if upower
> > service is available - `battery-status-function` will be set to
> > upower, and `M-x battery RET` will produce N/A values, and there is no
> > clue for the user that he just have invalid value for the
> > `battery-upower-device`.
>
> No: `M-x battery` will emit the warning.
>
>
So `battery-upower` should check the correctness of the
`battery-upower-device` on every call?  It would make it heavier, but of
course more reliable, because user might change the value of the
`batter-upower-device` in runtime

We might have `nil` values for the `battery-upower-device` and
`battery-upower-line-power-device` meaning "autodetect".  This will require
additional call to D-Bus (battery-upower-device-list) on every call to
`battery-upower`, probably this is OK.  If user want extra speed he just
set right values for that vars.  Sounds good?

Having `nil` values for those defcustom vars, also won't require putting
them after all the functions

-- 
lg

[-- Attachment #2: Type: text/html, Size: 2785 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-02-05  2:24               ` Evgeny Zajcev
@ 2020-02-05  3:03                 ` Stefan Monnier
  2020-02-06  0:55                   ` Richard Stallman
  2020-02-06  7:48                   ` Evgeny Zajcev
  0 siblings, 2 replies; 18+ messages in thread
From: Stefan Monnier @ 2020-02-05  3:03 UTC (permalink / raw)
  To: Evgeny Zajcev; +Cc: Andreas Schwab, Eli Zaretskii, emacs-devel

>> No: `M-x battery` will emit the warning.
> So `battery-upower` should check the correctness of the
> `battery-upower-device` on every call?  It would make it heavier, but of
> course more reliable, because user might change the value of the
> `batter-upower-device` in runtime
>
> We might have `nil` values for the `battery-upower-device` and
> `battery-upower-line-power-device` meaning "autodetect".  This will require
> additional call to D-Bus (battery-upower-device-list) on every call to
> `battery-upower`, probably this is OK.  If user want extra speed he just
> set right values for that vars.  Sounds good?

Right, we have to decouple the custom vars `battery-upower-device` and
`battery-upower-line-power-device` from the actual list of devices.
We can do this by recomputing the actual list (and checking its
validity) every time time.

Or if the performance impact matters, we can do this computation on the
first call and then check every time that the custom vars haven't
changed (and ask for D-Bus to calls us back when the list needs to be
changed).

> Having `nil` values for those defcustom vars, also won't require putting
> them after all the functions

Right.


        Stefan




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-02-05  3:03                 ` Stefan Monnier
@ 2020-02-06  0:55                   ` Richard Stallman
  2020-02-06 18:27                     ` Eli Zaretskii
  2020-02-06  7:48                   ` Evgeny Zajcev
  1 sibling, 1 reply; 18+ messages in thread
From: Richard Stallman @ 2020-02-06  0:55 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: schwab, eliz, lg.zevlg, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

When these changes are instakked, would you please tell me?
I would like to see if they work on Trisquel with my laptop.

-- 
Dr Richard Stallman
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-02-05  3:03                 ` Stefan Monnier
  2020-02-06  0:55                   ` Richard Stallman
@ 2020-02-06  7:48                   ` Evgeny Zajcev
  2020-02-06 14:18                     ` Stefan Monnier
  1 sibling, 1 reply; 18+ messages in thread
From: Evgeny Zajcev @ 2020-02-06  7:48 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Andreas Schwab, Eli Zaretskii, emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 1433 bytes --]

ср, 5 февр. 2020 г. в 06:03, Stefan Monnier <monnier@iro.umontreal.ca>:

> >> No: `M-x battery` will emit the warning.
> > So `battery-upower` should check the correctness of the
> > `battery-upower-device` on every call?  It would make it heavier, but of
> > course more reliable, because user might change the value of the
> > `batter-upower-device` in runtime
> >
> > We might have `nil` values for the `battery-upower-device` and
> > `battery-upower-line-power-device` meaning "autodetect".  This will
> require
> > additional call to D-Bus (battery-upower-device-list) on every call to
> > `battery-upower`, probably this is OK.  If user want extra speed he just
> > set right values for that vars.  Sounds good?
>
> Right, we have to decouple the custom vars `battery-upower-device` and
> `battery-upower-line-power-device` from the actual list of devices.
> We can do this by recomputing the actual list (and checking its
> validity) every time time.
>
> Or if the performance impact matters, we can do this computation on the
> first call and then check every time that the custom vars haven't
> changed (and ask for D-Bus to calls us back when the list needs to be
> changed).
>

Not much impact actually.  Here is the updated battery.el against the
master this time.
Also added "%b" format-spec, so 'M-x display-battery-mode RET' shows "+" in
case AC is on-line

Thanks


-- 
lg

[-- Attachment #1.2: Type: text/html, Size: 1940 bytes --]

[-- Attachment #2: 0001-Make-M-x-battery-RET-work-out-of-box-for-UPower-user.patch --]
[-- Type: text/x-patch, Size: 11125 bytes --]

From 9164b1da07b592585d84806a7f7afb8d4dba408e Mon Sep 17 00:00:00 2001
From: Zajcev Evgeny <zevlg@yandex.ru>
Date: Thu, 6 Feb 2020 10:35:12 +0300
Subject: [PATCH] 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.
---
 lisp/battery.el | 176 ++++++++++++++++++++++++++++++++++--------------
 1 file changed, 124 insertions(+), 52 deletions(-)

diff --git a/lisp/battery.el b/lisp/battery.el
index 1d3390070c..5368e1b0e9 100644
--- a/lisp/battery.el
+++ b/lisp/battery.el
@@ -23,14 +23,16 @@
 ;;; Commentary:
 
 ;; There is at present support for GNU/Linux, macOS and Windows.  This
-;; library supports both the `/proc/apm' file format of Linux version
-;; 1.3.58 or newer and the `/proc/acpi/' directory structure of Linux
-;; 2.4.20 and 2.6.  Darwin (macOS) is supported by using the `pmset'
-;; program.  Windows is supported by the GetSystemPowerStatus API call.
+;; library supports UPower (https://upower.freedesktop.org) via D-Bus
+;; API or the `/proc/apm' file format of Linux version 1.3.58 or newer
+;; and the `/proc/acpi/' directory structure of Linux 2.4.20 and 2.6.
+;; Darwin (macOS) is supported by using the `pmset' program.  Windows
+;; is supported by the GetSystemPowerStatus API call.
 
 ;;; Code:
 
 (require 'timer)
+(require 'dbus)
 (eval-when-compile (require 'cl-lib))
 \f
 (defgroup battery nil
@@ -38,12 +40,25 @@ battery
   :prefix "battery-"
   :group 'hardware)
 
-(defcustom battery-upower-device "battery_BAT1"
-  "Upower battery device name."
-  :version "26.1"
-  :type 'string
+(defcustom battery-upower-device nil
+  "UPower device of the `:battery' type.
+Use `battery-upower-device-list' to list all available UPower devices.
+If set to nil, then autodetect `:battery' device."
+  :version "28.1"
+  :type '(choice string (const :tag "Autodetect" nil))
   :group 'battery)
 
+(defcustom battery-upower-line-power-device nil
+  "UPower device of the `:line-power' type.
+Use `battery-upower-device-list' to list all available UPower devices.
+If set to nil, then autodetect `:battery' device."
+  :version "28.1"
+  :type '(choice string (const :tag "Autodetect" nil))
+  :group 'battery)
+
+(defconst battery-upower-dbus-service "org.freedesktop.UPower"
+  "Well-known UPower service name for the D-Bus system.")
+
 (defun battery--find-linux-sysfs-batteries ()
   (let ((dirs nil))
     (dolist (file (directory-files "/sys/class/power_supply/" t))
@@ -54,7 +69,9 @@ battery--find-linux-sysfs-batteries
     (nreverse dirs)))
 
 (defcustom battery-status-function
-  (cond ((and (eq system-type 'gnu/linux)
+  (cond ((dbus-ping :system battery-upower-dbus-service)
+         #'battery-upower)
+        ((and (eq system-type 'gnu/linux)
 	      (file-readable-p "/proc/apm"))
 	 #'battery-linux-proc-apm)
 	((and (eq system-type 'gnu/linux)
@@ -537,17 +554,68 @@ battery-linux-sysfs
                     (t "N/A"))))))
 
 \f
-(declare-function dbus-get-property "dbus.el"
-                  (bus service path interface property))
-
 ;;; `upowerd' interface.
-(defsubst battery-upower-prop (pname &optional device)
+(defconst battery-upower-dbus-interface "org.freedesktop.UPower"
+  "The interface to UPower.
+See URL `https://upower.freedesktop.org/docs/'.")
+
+(defconst battery-upower-dbus-path "/org/freedesktop/UPower"
+  "D-Bus path to talk to UPower service.")
+
+(defconst battery-upower-dbus-device-interface
+  (concat battery-upower-dbus-interface ".Device")
+  "The Device interface of the UPower.
+See URL `https://upower.freedesktop.org/docs/Device.html'.")
+
+(defconst battery-upower-dbus-device-path
+  (concat battery-upower-dbus-path "/devices")
+  "D-Bus path to talk to devices part of the UPower service.")
+
+(defconst battery-upower-types
+  '((0 . :unknown) (1 . :line-power) (2 . :battery)
+    (3 . :ups) (4 . :monitor) (5 . :mouse)
+    (6 . :keyboard) (7 . :pda) (8 . :phone))
+  "Type of the device.")
+
+(defconst battery-upower-states
+  '((0 . "unknown") (1 . "charging") (2 . "discharging")
+    (3 . "empty") (4 . "fully-charged") (5 . "pending-charge")
+    (6 . "pending-discharge"))
+  "Alist of battery power states.
+Only valid for `:battery' devices.")
+
+(defun battery-upower-device-property (device property)
+  "Get value of the single PROPERTY for the UPower DEVICE."
   (dbus-get-property
-   :system
-   "org.freedesktop.UPower"
-   (concat "/org/freedesktop/UPower/devices/" (or device battery-upower-device))
-   "org.freedesktop.UPower"
-   pname))
+   :system battery-upower-dbus-service
+   (expand-file-name device battery-upower-dbus-device-path)
+   battery-upower-dbus-device-interface
+   property))
+
+(defun battery-upower-device-all-properties (device)
+  "Return value for all available properties for the UPower DEVICE."
+  (dbus-get-all-properties
+   :system battery-upower-dbus-service
+   (expand-file-name device battery-upower-dbus-device-path)
+   battery-upower-dbus-device-interface))
+
+(defun battery-upower-device-list ()
+  "Return list of all available UPower devices.
+Each element is the cons cell in form: (DEVICE . DEVICE-TYPE)."
+  (mapcar (lambda (device-path)
+            (let* ((device (file-relative-name
+                            device-path battery-upower-dbus-device-path))
+                   (type-num (battery-upower-device-property device "Type")))
+              (cons device (or (cdr (assq type-num battery-upower-types))
+                               :unknown))))
+          (dbus-call-method :system battery-upower-dbus-service
+                            battery-upower-dbus-path
+                            battery-upower-dbus-interface
+                            "EnumerateDevices")))
+
+(defun battery-upower-device-autodetect (device-type)
+  "Return first matching UPower device of DEVICE-TYPE."
+  (car (rassq device-type (battery-upower-device-list))))
 
 (defun battery-upower ()
   "Get battery status from dbus Upower interface.
@@ -559,45 +627,49 @@ battery-upower
 %p Battery load percentage
 %r Current rate
 %B Battery status (verbose)
+%b Battery status: empty means high, `-' means low,
+   `!' means critical, and `+' means charging
 %L AC line status (verbose)
 %s Remaining time (to charge or discharge) in seconds
 %m Remaining time (to charge or discharge) in minutes
 %h Remaining time (to charge or discharge) in hours
 %t Remaining time (to charge or discharge) in the form `h:min'"
-  (let ((percents (battery-upower-prop "Percentage"))
-        (time-to-empty (battery-upower-prop "TimeToEmpty"))
-        (time-to-full (battery-upower-prop "TimeToFull"))
-        (state (battery-upower-prop "State"))
-        (online (battery-upower-prop "Online" "line_power_ACAD"))
-        (energy (battery-upower-prop "Energy"))
-        (energy-rate (battery-upower-prop "EnergyRate"))
-        (battery-states '((0 . "unknown") (1 . "charging")
-                          (2 . "discharging") (3 . "empty")
-                          (4 . "fully-charged") (5 . "pending-charge")
-                          (6 . "pending-discharge")))
-        seconds minutes hours remaining-time)
-    (cond ((and online time-to-full)
-           (setq seconds time-to-full))
-          ((and (not online) time-to-empty)
-           (setq seconds time-to-empty)))
-    (when seconds
-      (setq minutes (/ seconds 60)
-            hours (/ minutes 60)
-	    remaining-time (format "%d:%02d" hours (mod minutes 60))))
-    (list (cons ?c (or (and energy
-                            (number-to-string (round (* 1000 energy))))
-                       "N/A"))
-          (cons ?p (or (and percents (number-to-string (round percents)))
-                       "N/A"))
-          (cons ?r (or (and energy-rate
-                            (concat (number-to-string energy-rate) " W"))
-                       "N/A"))
-          (cons ?B (or (and state (cdr (assoc state battery-states)))
-                       "unknown"))
-          (cons ?L (or (and online "on-line") "off-line"))
-          (cons ?s (or (and seconds (number-to-string seconds)) "N/A"))
-          (cons ?m (or (and minutes (number-to-string minutes)) "N/A"))
-          (cons ?h (or (and hours (number-to-string hours)) "N/A"))
+  (let* ((bat-device (or battery-upower-device
+                         (battery-upower-device-autodetect :battery)))
+         (bat-props (when bat-device
+                      (battery-upower-device-all-properties bat-device)))
+         (percents (cdr (assoc "Percentage" bat-props)))
+         (time-to-empty (cdr (assoc "TimeToEmpty" bat-props)))
+         (time-to-full (cdr (assoc "TimeToFull" bat-props)))
+         (state (cdr (assoc "State" bat-props)))
+         (level (cdr (assoc "BatteryLevel" bat-props)))
+         (energy (cdr (assoc "Energy" bat-props)))
+         (energy-rate (cdr (assoc "EnergyRate" bat-props)))
+         (lp-device (or battery-upower-line-power-device
+                        (battery-upower-device-autodetect :line-power)))
+         (online-p (when lp-device
+                     (battery-upower-device-property lp-device "Online")))
+         (seconds (if online-p time-to-full time-to-empty))
+         (minutes (when seconds (/ seconds 60)))
+         (hours (when minutes (/ minutes 60)))
+         (remaining-time (when hours
+                           (format "%d:%02d" hours (mod minutes 60)))))
+    (list (cons ?c (if energy (number-to-string (round (* 1000 energy))) "N/A"))
+          (cons ?p (if percents (number-to-string (round percents)) "N/A"))
+          (cons ?r (if energy-rate
+                       (concat (number-to-string energy-rate) " W")
+                     "N/A"))
+          (cons ?B (if state
+                       (cdr (assq state battery-upower-states))
+                     "unknown"))
+          (cons ?b (cond ((= level 3) "-")
+                         ((= level 4) "!")
+                         (online-p "+")
+                         (t "")))
+          (cons ?L (if online-p "on-line" (if lp-device "off-line" "unknown")))
+          (cons ?s (if seconds (number-to-string seconds) "N/A"))
+          (cons ?m (if minutes (number-to-string minutes) "N/A"))
+          (cons ?h (if hours (number-to-string hours) "N/A"))
           (cons ?t (or remaining-time "N/A")))))
 
 \f
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-02-06  7:48                   ` Evgeny Zajcev
@ 2020-02-06 14:18                     ` Stefan Monnier
  0 siblings, 0 replies; 18+ messages in thread
From: Stefan Monnier @ 2020-02-06 14:18 UTC (permalink / raw)
  To: Evgeny Zajcev; +Cc: Andreas Schwab, Eli Zaretskii, emacs-devel

> Not much impact actually.  Here is the updated battery.el against the
> master this time.  Also added "%b" format-spec, so 'M-x
> display-battery-mode RET' shows "+" in case AC is on-line

Great, thanks, pushed,


        Stefan




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-02-06  0:55                   ` Richard Stallman
@ 2020-02-06 18:27                     ` Eli Zaretskii
  0 siblings, 0 replies; 18+ messages in thread
From: Eli Zaretskii @ 2020-02-06 18:27 UTC (permalink / raw)
  To: rms; +Cc: schwab, lg.zevlg, monnier, emacs-devel

> From: Richard Stallman <rms@gnu.org>
> Date: Wed, 05 Feb 2020 19:55:31 -0500
> Cc: schwab@suse.de, eliz@gnu.org, lg.zevlg@gmail.com, emacs-devel@gnu.org
> 
> When these changes are instakked, would you please tell me?

They are installed now (on the master branch).



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] battery.el, upower fixes
  2020-02-04 20:16           ` Michael Albinus
  2020-02-04 23:10             ` Stefan Monnier
@ 2020-06-11 16:12             ` Basil L. Contovounesios
  1 sibling, 0 replies; 18+ messages in thread
From: Basil L. Contovounesios @ 2020-06-11 16:12 UTC (permalink / raw)
  To: Michael Albinus
  Cc: Andreas Schwab, Eli Zaretskii, Evgeny Zajcev, Stefan Monnier,
	emacs-devel

Michael Albinus <michael.albinus@gmx.de> writes:

> Stefan Monnier <monnier@iro.umontreal.ca> writes:
>
>> I think there's a possibility that the set of devices changes over time
>> (e.g. on my machine (battery-upower-device-list) currently only shows
>> battery_BAT0, but I can insert a second battery and I'd expect the list
>> to then include a battery_BAT1 as well).  So maybe we should instead
>> allow a special value (e.g. nil) to mean "autodetect" and then do the
>> autodetection dynamically.  WDYT?
>
> Usually, D-Bus services send a signal when a device is added/removed. IIUC
> https://upower.freedesktop.org/docs/UPower.html,
> org.freedesktop.UPower.DeviceAdded and org.freedesktop.UPower.DeviceRemoved
> serve for that purpose. So you shall subscribe to those signals and
> handle them accordingly.

Now done in https://debbugs.gnu.org/39491#55.

-- 
Basil



^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2020-06-11 16:12 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-26 23:04 [PATCH] battery.el, upower fixes Evgeny Zajcev
2020-01-27 14:43 ` Stefan Monnier
2020-01-27 18:23 ` Eli Zaretskii
2020-01-29  7:05   ` Evgeny Zajcev
2020-01-29  8:37     ` Andreas Schwab
2020-01-30 10:22       ` Evgeny Zajcev
2020-02-04 19:55         ` Stefan Monnier
2020-02-04 20:16           ` Michael Albinus
2020-02-04 23:10             ` Stefan Monnier
2020-06-11 16:12             ` Basil L. Contovounesios
2020-02-05  0:22           ` Evgeny Zajcev
2020-02-05  1:27             ` Stefan Monnier
2020-02-05  2:24               ` Evgeny Zajcev
2020-02-05  3:03                 ` Stefan Monnier
2020-02-06  0:55                   ` Richard Stallman
2020-02-06 18:27                     ` Eli Zaretskii
2020-02-06  7:48                   ` Evgeny Zajcev
2020-02-06 14:18                     ` Stefan Monnier

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).