feat(battery): manual toggles, maintain --force-discharge, time remaining, daemon logs - #6
Closed
harryisfish wants to merge 1 commit into
Closed
Conversation
…-discharge, time remaining, daemon logs Feature parity pass against actuallymentor/battery v1.3.2, all verified live on M2 MacBook Air: - `battery charging on|off` and `battery adapter on|off`: expose the existing setChargingEnabled/setAdapterEnabled XPC calls in the CLI. When a maintain policy is active the CLI warns that the toggle may be overridden on the next evaluation (verified: it is, within seconds). - `battery maintain N --force-discharge`: the policy actively discharges down to the band by cutting adapter power while above the upper bound, and restores it once inside. Persisted as battery.force_discharge in config.toml. The evaluation loop re-asserts the cut every period, which makes it self-healing against the firmware quirk below. Switching back to a plain maintain hands the adapter back (daemon-side transition, verified both directions). - `battery status` shows time-to-empty/full from IOKit power sources (nil while the gauge is settling — mirrors pmset's "(no estimate)"). - `daemon logs [--last 1h]`: wraps `log show` with the smctl subsystem predicate. Field finding that shaped the design: writing the charging-enable key (CHTE) while an adapter cut (CHIE) is active made the SMC silently re-enable adapter power — observed live, it stalled a one-shot `battery discharge` forever at 79%. The one-shot discharge loop now re-asserts the cut every poll, and force-discharge inherits immunity from the policy loop (verified: triggering the same reset under force-discharge is corrected within one XPC call). PolicyEngine: BatteryObservation gains isAdapterEnabled (nil when adapter control is unsupported — the policy then never touches the adapter, which also keeps it out of the way of manual discharges). New transition-matrix tests for the force-discharge branches.
harryisfish
added a commit
that referenced
this pull request
Jun 10, 2026
Squashed replacement for closed stacked PR #6 after PR #4 and PR #5 landed.\n\nAdditional fixes included before merge:\n- persist battery.force_discharge in writeConfig\n- prevent disabled charge limiting from keeping force-discharge armed\n- document new CLI entries in English and Chinese README files\n\nValidated:\n- swift test --disable-sandbox\n- git diff --check\n- git merge-tree --write-tree --merge-base $(git merge-base HEAD origin/main) HEAD origin/main\n- GitHub CI Build & Test (macOS)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #4 (base =
fix/apple-silicon-integer-decode); rebase onto main after #4 merges.Feature parity pass against actuallymentor/battery v1.3.2 — see the commit message for the full list. Highlights:
battery maintain N --force-discharge— the maintain policy actively discharges down to the band by cutting adapter power (CHIE), restores it once inside, and is self-healing: the evaluation loop re-asserts the cut every period.battery dischargeat 79%. Both discharge paths now survive it (verified by deliberately triggering the reset under force-discharge).battery charging|adapter on|off, time-to-empty/full inbattery status,daemon logs --last 1h.Test plan