nijhawank Posted January 25, 2020 Share Posted January 25, 2020 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 More sharing options...
zombillano Posted June 5, 2020 Share Posted June 5, 2020 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 More sharing options...
Zhen-zen Posted July 15, 2020 Share Posted July 15, 2020 Hi, I was working on a kext on those kind of operations at https://github.com/zhen-zen/YogaSMC. Currently I can't find enough document on each ACPI method and find some people testing it out. So I just implemented read only operations. Link to comment Share on other sites More sharing options...
Recommended Posts