Jump to content

Battery Charge Thresholds and Related Controls


nijhawank
 Share

3 posts in this topic

Recommended Posts

Hi friends,

 

Recently I had been looking for ways to control the battery charging on my hackintosh which is a Thinkpad T460 with dual batteries. On Windows there's a program Lenovo Vantage that lets you set the Battery Charging Start and Stop Thresholds. These thresholds continue to apply even when the laptop is turned off as these thresholds are managed by the embedded controller, so from that perspective its a set once and forget.

 

But there was one more thing that was frustrating me. By default Lenovo uses the external battery first and once its almost drained (less than 5%), it switches to the internal battery.

Although the Charging Start and Stop Limits are a good way to increase the life span of Lithium batteries (by lowering the max charge limit), the complete drainage of the external battery prior to switching to internal is not a good idea.

Fortunately Lenovo EC provide options to force drain (use) a battery (even with the ac adapter connected) thereby allowing to manually switch to the internal one, however these are manual controls. In Linux, there's a program tpacpi-bat that runs as a daemon and performs an efficient management of the dual batteries such as switching to internal battery when the external one reaches a configurable lower limit. However, this is Linux only and uses the ACPI interface.

 

I did some research to understand my options in macOS. I found RehabMan's ACPIDebug.kext and its ability (using another RehabMan's tool ioio) to call a function defined in the DSDT. With information collected tpacpi-bat and ACPIDebug.kext, I have created a dirty version. 

 

So this is how you use it...

1. Use the attached SSDT-RMDT. As this was just a rough work to validate my understanding, I just did a hard coding for the first battery. 

2. Install ACPIDebug.kext

3. After the reboot, you can trigger the following battery operations...

a. Set Battery Charge Start Threshold

ioio -s org_rehabman_ACPIDebug dbg1 <start-percent>

a. Set Battery Charge Stop Threshold

ioio -s org_rehabman_ACPIDebug dbg2 <stop-percent>

a. Force Discharge

ioio -s org_rehabman_ACPIDebug dbg3 <0|1> //0 to disable, 1 to enable

a. Inhibit battery charging for specified number of minutes

ioio -s org_rehabman_ACPIDebug dbg4 <minutes> //0 to disable

a. View Battery Info

ioio -s org_rehabman_ACPIDebug dbg5 <anything> //pass anything, its ignored

a. View Battery Charge Start/Stop Thresholds

ioio -s org_rehabman_ACPIDebug dbg0 <anything> //pass anything, its ignored

 

You can see the output using the Log Viewer Console (filter on ACPIDebug). You'd see something like this...

default    19:34:35.175265 -0800    kernel    ACPIDebug: "View Thresholds"
default    19:34:35.176349 -0800    kernel    ACPIDebug: { "Charge Start Threshold=", 0x28, }
default    19:34:35.176489 -0800    kernel    ACPIDebug: { "Charge Stop  Threshold=", 0x3c, }
default    21:07:36.023627 -0800    kernel    ACPIDebug: "Battery Info"
default    21:07:36.032040 -0800    kernel    ACPIDebug: { "Conversion (mW[h] -> mA[h]) Required?=", 0x0, }
default    21:07:36.032323 -0800    kernel    ACPIDebug: { "Design Voltage=", 0x2a30, }
default    21:07:36.032519 -0800    kernel    ACPIDebug: { "Design Capacity=", 0xdb60, }
default    21:07:36.032772 -0800    kernel    ACPIDebug: { "Last Full Capacity=", 0x6a9a, }
default    21:07:36.033783 -0800    kernel    ACPIDebug: { "Remaining Capacity=", 0x2e7c, }
default    21:07:36.033968 -0800    kernel    ACPIDebug: { "Remaining Percent=", 0x2b, }
default    21:11:19.319090 -0800    kernel    ACPIDebug: { "Charge Stop Threshold=", 0x5a, }
default    21:11:30.722450 -0800    kernel    ACPIDebug: { "Charge Start Threshold=", 0x50, }
default    23:34:39.071335 -0800    kernel    ACPIDebug: "Force Discharge=Enabled"
default    23:34:59.427494 -0800    kernel    ACPIDebug: "Force Discharge=Disabled"
default    23:35:08.475281 -0800    kernel    ACPIDebug: { "Inhibit Charge Enabled (in Minutes)=", 0xf, }
default    23:35:12.971671 -0800    kernel    ACPIDebug: "Inhibit Charge=Disabled"
 

At this time, I just hard-coded for the BAT0 to quickly validate my understanding and its working well. 

 

What's next? As I understand (and please correct me if I'm wrong), I can't return values with ACPIDebug.kext along with ioio, plus this is also all very hacky.

To be able to create a program that reads the current remaining capacity (percent) and switches control to internal batter, I need a way to return this info. Currently I'm just outputting it to the logs.

 

My thinking is to modify ACPIDebug.kext or one of these other kexts (ACPISensors.kext) to add code for above and then create a program to optimally manage the operation of my two batteries.

However, I'm very new to all of this and will take some time.

 

In the meanwhile, here is it for your playing pleasures. Please be aware that my SSDT-RMDT is currently hard-coded for BAT0 and doesn't have all the validations. 

Credits to RehabMan, tpacpi-bat, and other resources on internet.

 

Thanks all.

 

 

SSDT-RMDT.dsl

Link to comment
Share on other sites

  • 4 months later...

HI there! I've been looking exactly what you describe here, to be able to control battery charge of a T480 running Catalina. Did you make any progress on this topic? Would be awesome to develop a app or extension for all of us running hackintosh on thinkpads with power bridge. Hope to hear from you soon!

Link to comment
Share on other sites

  • 1 month later...
 Share

×
×
  • Create New...