By using this site, you agree to have cookies stored on your device, strictly for functional purposes, such as storing your session and preferences.

Dismiss

battery: add notifications

roundabout,
created on Wednesday, 24 September 2025, 15:24:41 (1758727481), received on Wednesday, 24 September 2025, 15:24:44 (1758727484)
Author identity: Vlad <vlad.muntoiu@gmail.com>

f5f68d033395fba81a73051c747141673c78cfad

applets/battery/__init__.py

@@ -18,10 +18,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            from __future__ import annotations
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        import threading
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            import panorama_panel
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            import locale
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            from pathlib import Path
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        from pydbus import SystemBus
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        from pydbus import SystemBus, SessionBus
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            import gi
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            gi.require_version("Gtk", "4.0")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -65,6 +67,8 @@ class BatteryMonitor(panorama_panel.Applet):

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        config = {}
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.bus = SystemBus()
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.session_bus = SessionBus()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.notification_service = None
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.upower = self.bus.get("org.freedesktop.UPower")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.button = Gtk.MenuButton()
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -72,10 +76,20 @@ class BatteryMonitor(panorama_panel.Applet):

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.button.set_child(self.icon)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.append(self.button)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.low_threshold = config.get("low_threshold", 15/100)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.low_notification = None
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.critical_threshold = config.get("critical_threshold", 5/100)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.critical_notification = None
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.popover = Gtk.Popover()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.popover_content = Gtk.ListBox()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.update_batteries()
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    GLib.timeout_add_seconds(10, self.update_batteries)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                def update_batteries(self):
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.popover_content.remove_all()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    total_energy = max_energy = 0
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    any_charging = False
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -91,18 +105,78 @@ class BatteryMonitor(panorama_panel.Applet):

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                            if device.State == 1:
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                                any_charging = True
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                if not max_energy:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    return False
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    print(total_energy, max_energy)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.button.set_tooltip_text(f"{locale.format_string("%d", total_energy / max_energy * 1000)}‰")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.icon.set_from_icon_name(get_battery_icon(total_energy / max_energy, any_charging))
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                GLib.idle_add(self.do_notifications, total_energy, max_energy)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    return True
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            def do_notifications(self, total_energy, max_energy):
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                if self.session_bus.get("org.freedesktop.Notifications"):
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    self.notification_service = self.session_bus.get("org.freedesktop.Notifications")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                else:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    return
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                # This uses threading to make sure it doesn't hang while waiting to deliver the
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                # notification
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                if total_energy / max_energy < self.low_threshold:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    if not self.low_notification:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        def send_notification():
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            self.low_notification = self.notification_service.Notify(
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                _("Battery"),
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                self.low_notification or self.critical_notification or 0,
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                "battery-low",
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                _("The energy in the battery is low."),
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                "",
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                [],
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                {},
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                -1
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            )
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        threading.Thread(target=send_notification, daemon=True).start()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                elif self.low_notification:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    threading.Thread(
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        target=lambda: self.notification_service.CloseNotification(self.low_notification),
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        daemon=True
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    ).start()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    self.low_notification = None
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                if total_energy / max_energy < self.critical_threshold:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    if not self.critical_notification:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        def send_notification():
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            self.critical_notification = self.notification_service.Notify(
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                _("Battery"),
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                self.low_notification or self.critical_notification or 0,
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                "battery-empty",
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                _("The energy in the battery is very low; the device will shut down soon."),
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                "",
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                [],
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                {},
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                -1
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            )
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        threading.Thread(target=send_notification, daemon=True).start()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                elif self.critical_notification:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    threading.Thread(
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        target=lambda: self.notification_service.CloseNotification(self.critical_notification),
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        daemon=True
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    ).start()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    self.critical_notification = None
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                def get_config(self):
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    return {
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        "icon_size": self.icon.get_pixel_size(),
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    "low_threshold": self.low_threshold,
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    "critical_threshold": self.critical_threshold,
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    }
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                def shutdown(self, app):
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.publishing.unpublish()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                return
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                            
                                

config.yaml

@@ -60,6 +60,8 @@ panels:

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                right:
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                - BatteryMonitor:
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    icon_size: 24
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                low_threshold: 0.15
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                critical_threshold: 0.05
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                - Volume:
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    percentage_reveal: 1000
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    popdown_after_manual: 2000