Skip to content

feat(power): add battery charge threshold controls - #3829

Open
eaceaser wants to merge 13 commits into
noctalia-dev:mainfrom
eaceaser:feature/battery-charge-limits
Open

feat(power): add battery charge threshold controls#3829
eaceaser wants to merge 13 commits into
noctalia-dev:mainfrom
eaceaser:feature/battery-charge-limits

Conversation

@eaceaser

@eaceaser eaceaser commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Add battery charge threshold information and controls to the Power tab.

This PR adds a Battery charging card after Power Profile. The card:

  • Shows the configured charging start and stop thresholds.
  • Lets users enable or disable UPower’s configured threshold preset.
  • Shows “Can charge to 100%” while the preset is disabled.
  • Supports multiple internal batteries.
  • Shows externally managed and read-only thresholds without offering a conflicting control.
  • Remains hidden when UPower is unavailable or no battery has useful threshold information.

Motivation

Noctalia shows battery status and health, but it does not expose charging thresholds supported by UPower.

Users currently need another interface to determine whether charging limits are active or to enable UPower’s configured preset. This change adds that functionality to the existing Power tab without requiring TLP, privileged helpers, or direct sysfs writes.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring
  • Build / packaging

Related Issue

Testing

Automated testing:

  • Built the debug target with meson compile -C build-charge-limits.
  • Ran the complete Meson test suite: 70/70 tests passed.
  • Repeated the private D-Bus integration test 20 times.
  • Ran python3 tools/i18n-check.py.
  • Ran the formatting commands used by just format with clang-format 22.1.8 because just was unavailable.

Test coverage includes:

  • Complete, partial, missing, malformed, and unreadable sysfs thresholds.
  • Safe and unsafe UPower NativePath values.
  • UPower-controlled, disabled, externally managed, firmware-managed, read-only, and unsupported states.
  • Hiding the card when no useful threshold capability or data exists.
  • Multiple internal batteries and peripheral exclusion.
  • Pending controls and successful state reconciliation.
  • PolicyKit denial and generic D-Bus failures.
  • Battery removal and replacement during an operation.
  • Transient UPower introspection failures.
  • Stable row layout during asynchronous toggle operations.
  • “Can charge to 100%” presentation while thresholds are disabled.

Manual verification:

  • Confirmed that BAT0 reports configured and applied 75%/80% thresholds through UPower and sysfs.
  • Confirmed that UPower can enable and disable the thresholds on this machine.
  • Used an isolated private-bus harness to exercise controllable, externally managed, unsupported, and unavailable states without changing the real UPower service.

Manual Coverage

  • Tested on Niri
  • Tested on Hyprland
  • Tested on Sway
  • Tested on another compositor:
  • Tested with different bar positions and density settings
  • Tested at different interface scaling values
  • Tested with multiple monitors

Screenshots / Videos

image

limits disabled:

image

limits set but not managed by upower:

image

multiple batteries:

image

Checklist

  • This PR is ready for review, or it is marked as Draft.
  • I read and followed the relevant guidance in CONTRIBUTING.md.
  • I ran just format with clang-format v22+ installed, or this PR has no code changes.
  • I ran the relevant build or test commands, or explained why they were not run.
  • I self-reviewed the changes.
  • I checked for new warnings or errors.
  • I will update end-user documentation after merge, or this PR does not change user-facing configuration or behavior.
  • I added or updated assets/translations/en.json, or this PR adds no new user-facing strings.
  • I did not edit non-English translation files unless this PR is explicitly for translation tooling, an import/export sync, or a maintainer-requested locale change.
  • I used the existing canonical names for config keys, IPC names, paths, and identifiers.

@AdityaKr015

Copy link
Copy Markdown
Contributor

Nice man, thats a wanted feature.

@Cleboost

Copy link
Copy Markdown
Contributor

@AdityaKr015

Copy link
Copy Markdown
Contributor

I didn't explore plugins, so we already have the feature

@eaceaser

Copy link
Copy Markdown
Contributor Author

The plugin doesn't inline it into the existing battery widget right, but adds another one to the bar? From what I could tell, adding content to the existing widget isn't supported in the current plugin API, and that's specifically what I wanted to implement here.

I haven't looked at the plugin API at all to know if it's reasonable to expose the ability to add content to existing widget panels, which could be an approach. But considering that battery limit functionality is already exposed by UPower which we already use for displaying battery charge levels etc. on the built-in widget, I don't really see why this wouldn't be appropriate for the built-in widget as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants