From cf179ca9bd46114133f21d751896e6a843d85de2 Mon Sep 17 00:00:00 2001 From: Stephen Horvath Date: Wed, 19 Mar 2025 15:07:10 +1000 Subject: [PATCH] Make battery page interactive --- yafi/ui/battery.ui | 4 +- yafi/ui/yafi.cmb | 4 +- yafi/yafi.py | 163 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 163 insertions(+), 8 deletions(-) diff --git a/yafi/ui/battery.ui b/yafi/ui/battery.ui index 6bff601..b432c46 100644 --- a/yafi/ui/battery.ui +++ b/yafi/ui/battery.ui @@ -91,7 +91,7 @@ - + Preserve the battery lifespan by gradually lowering battery charge voltage automatically if the system is connected to AC for more than the set day limit. 5 5 @@ -99,7 +99,7 @@ 5 Battery Extender - + Enable diff --git a/yafi/ui/yafi.cmb b/yafi/ui/yafi.cmb index a802d06..ebdb372 100644 --- a/yafi/ui/yafi.cmb +++ b/yafi/ui/yafi.cmb @@ -62,13 +62,13 @@ (4,5,"GtkBox",None,4,None,None,None,0,None,None), (4,6,"GtkScale","chg-limit-scale",5,None,None,None,0,None,None), (4,7,"GtkAdjustment",None,6,None,None,None,0,None,None), - (4,13,"AdwPreferencesGroup",None,2,None,None,None,5,None,None), + (4,13,"AdwPreferencesGroup","bat-ext-group",2,None,None,None,5,None,None), (4,27,"AdwSpinRow","bat-ext-trigger",13,None,None,None,5,None,None), (4,28,"GtkAdjustment",None,27,None,None,None,0,None,None), (4,29,"AdwSpinRow","bat-ext-reset",13,None,None,None,6,None,None), (4,30,"GtkAdjustment",None,29,None,None,None,0,None,None), (4,31,"AdwActionRow","bat-ext-stage",13,None,None,None,2,None,None), - (4,32,"AdwSwitchRow",None,13,None,None,None,1,None,None), + (4,32,"AdwSwitchRow","bat-ext-enable",13,None,None,None,1,None,None), (4,33,"AdwActionRow","bat-limit",2,None,None,None,3,None,None), (4,34,"GtkBox",None,33,None,None,None,0,None,None), (4,35,"GtkScale","bat-limit-scale",34,None,None,None,0,None,None), diff --git a/yafi/yafi.py b/yafi/yafi.py index 22623b8..1df263e 100644 --- a/yafi/yafi.py +++ b/yafi/yafi.py @@ -47,6 +47,7 @@ class YAFI(Adw.Application): self._change_page(builder, thermals_root) + # Fan control fan_rpm = thermals_builder.get_object("fan-rpm") fan_mode = thermals_builder.get_object("fan-mode") fan_set_rpm = thermals_builder.get_object("fan-set-rpm") @@ -83,6 +84,7 @@ class YAFI(Adw.Application): fan_set_rpm.connect("notify::text", lambda entry, _: handle_fan_rpm(entry)) + # Temperature sensors temperatures = thermals_builder.get_object("temperatures") temp_items = [] @@ -155,8 +157,10 @@ class YAFI(Adw.Application): for i, colour in enumerate(all_colours): if supported_colours[i]: strings.append(colour) - - add_colours(led_pwr_colour_strings, ec_commands.leds.EcLedId.EC_LED_ID_POWER_LED) + + add_colours( + led_pwr_colour_strings, ec_commands.leds.EcLedId.EC_LED_ID_POWER_LED + ) def handle_led_colour(combobox, led_id): colour = combobox.get_selected() - 2 @@ -192,8 +196,10 @@ class YAFI(Adw.Application): led_charge_colour = leds_builder.get_object("led-chg-colour") led_charge_colour_strings = led_charge_colour.get_model() - add_colours(led_charge_colour_strings, ec_commands.leds.EcLedId.EC_LED_ID_BATTERY_LED) - + add_colours( + led_charge_colour_strings, ec_commands.leds.EcLedId.EC_LED_ID_BATTERY_LED + ) + led_charge_colour.connect( "notify::selected", lambda combo, _: handle_led_colour( @@ -201,6 +207,25 @@ class YAFI(Adw.Application): ), ) + def _format_timedelta(self, timedelta): + days = f"{timedelta.days} days, " if timedelta.days else "" + hours, remainder = divmod(timedelta.seconds, 3600) + minutes, seconds = divmod(remainder, 60) + return days + f"{hours}:{minutes:02}:{seconds:02}" + + def _update_battery(self, bat_ext_stage, bat_ext_trigger_time, bat_ext_reset_time): + ec_extender = ec_commands.framework_laptop.get_battery_extender(self.cros_ec) + + bat_ext_stage.set_subtitle(str(ec_extender["current_stage"])) + bat_ext_trigger_time.set_subtitle( + self._format_timedelta(ec_extender["trigger_timedelta"]) + ) + bat_ext_reset_time.set_subtitle( + self._format_timedelta(ec_extender["reset_timedelta"]) + ) + + return self.current_page == 2 + def _battery_page(self, builder): # Load the battery.ui file battery_builder = Gtk.Builder() @@ -211,6 +236,136 @@ class YAFI(Adw.Application): self._change_page(builder, battery_root) + # Charge limiter + chg_limit_enable = battery_builder.get_object("chg-limit-enable") + chg_limit = battery_builder.get_object("chg-limit") + chg_limit_scale = battery_builder.get_object("chg-limit-scale") + bat_limit = battery_builder.get_object("bat-limit") + bat_limit_scale = battery_builder.get_object("bat-limit-scale") + chg_limit_override = battery_builder.get_object("chg-limit-override") + chg_limit_override_btn = battery_builder.get_object("chg-limit-override-btn") + + ec_limit = ec_commands.framework_laptop.get_charge_limit(self.cros_ec) + ec_limit_enabled = ec_limit != (0, 0) + chg_limit_enable.set_active(ec_limit_enabled) + if ec_limit_enabled: + chg_limit_scale.set_value(ec_limit[0]) + bat_limit_scale.set_value(ec_limit[1]) + chg_limit.set_sensitive(True) + bat_limit.set_sensitive(True) + chg_limit_override.set_sensitive(True) + + def handle_chg_limit_change(min, max): + ec_commands.framework_laptop.set_charge_limit( + self.cros_ec, int(min), int(max) + ) + + def handle_chg_limit_enable(switch): + active = switch.get_active() + if active: + handle_chg_limit_change( + chg_limit_scale.get_value(), bat_limit_scale.get_value() + ) + else: + ec_commands.framework_laptop.disable_charge_limit(self.cros_ec) + + chg_limit.set_sensitive(active) + bat_limit.set_sensitive(active) + chg_limit_override.set_sensitive(active) + + chg_limit_enable.connect( + "notify::active", lambda switch, _: handle_chg_limit_enable(switch) + ) + chg_limit_scale.connect( + "value-changed", + lambda scale: handle_chg_limit_change( + scale.get_value(), bat_limit_scale.get_value() + ), + ) + bat_limit_scale.connect( + "value-changed", + lambda scale: handle_chg_limit_change( + chg_limit_scale.get_value(), scale.get_value() + ), + ) + + chg_limit_override_btn.connect( + "clicked", + lambda _: ec_commands.framework_laptop.override_charge_limit(self.cros_ec), + ) + + # Battery Extender + bat_ext_group = battery_builder.get_object("bat-ext-group") + bat_ext_enable = battery_builder.get_object("bat-ext-enable") + bat_ext_stage = battery_builder.get_object("bat-ext-stage") + bat_ext_trigger_time = battery_builder.get_object("bat-ext-trigger-time") + bat_ext_reset_time = battery_builder.get_object("bat-ext-reset-time") + bat_ext_trigger = battery_builder.get_object("bat-ext-trigger") + bat_ext_reset = battery_builder.get_object("bat-ext-reset") + + ec_extender = ec_commands.framework_laptop.get_battery_extender(self.cros_ec) + bat_ext_enable.set_active(not ec_extender["disable"]) + bat_ext_stage.set_sensitive(not ec_extender["disable"]) + bat_ext_trigger_time.set_sensitive(not ec_extender["disable"]) + bat_ext_reset_time.set_sensitive(not ec_extender["disable"]) + bat_ext_trigger.set_sensitive(not ec_extender["disable"]) + bat_ext_reset.set_sensitive(not ec_extender["disable"]) + + bat_ext_stage.set_subtitle(str(ec_extender["current_stage"])) + bat_ext_trigger_time.set_subtitle( + self._format_timedelta(ec_extender["trigger_timedelta"]) + ) + bat_ext_reset_time.set_subtitle( + self._format_timedelta(ec_extender["reset_timedelta"]) + ) + bat_ext_trigger.set_value(ec_extender["trigger_days"]) + bat_ext_reset.set_value(ec_extender["reset_minutes"]) + + def handle_extender_enable(switch): + active = switch.get_active() + ec_commands.framework_laptop.set_battery_extender( + self.cros_ec, + not active, + int(bat_ext_trigger.get_value()), + int(bat_ext_reset.get_value()), + ) + bat_ext_stage.set_sensitive(active) + bat_ext_trigger_time.set_sensitive(active) + bat_ext_reset_time.set_sensitive(active) + bat_ext_trigger.set_sensitive(active) + bat_ext_reset.set_sensitive(active) + + bat_ext_enable.connect( + "notify::active", lambda switch, _: handle_extender_enable(switch) + ) + bat_ext_trigger.connect( + "notify::value", + lambda scale, _: ec_commands.framework_laptop.set_battery_extender( + self.cros_ec, + not bat_ext_enable.get_active(), + int(scale.get_value()), + int(bat_ext_reset.get_value()), + ), + ) + bat_ext_reset.connect( + "notify::value", + lambda scale, _: ec_commands.framework_laptop.set_battery_extender( + self.cros_ec, + not bat_ext_enable.get_active(), + int(bat_ext_trigger.get_value()), + int(scale.get_value()), + ), + ) + + # Schedule _update_battery to run every second + GLib.timeout_add_seconds( + 1, + self._update_battery, + bat_ext_stage, + bat_ext_trigger_time, + bat_ext_reset_time, + ) + def _hardware_page(self, builder): # Load the hardware.ui file hardware_builder = Gtk.Builder()