Polling battery percentage on MacOs


This is an extension of my last post which covered polling battery percentage within iOS:

https://nsaxelby.com/2018/05/06/polling-battery-percentage-on-iphone/

This post is describes how to do it in MacOs

Introduction:

This post explores how to poll for the battery percentage on a MacOsx device. My MacOs device that I’m building on is a High Sierra MacBook Air ( 2014 ).

Implementation:

Fortunately querying the battery percentage on a MacOs device is much easier than on a iOS. You don’t have to worry about all of the ‘background capabilities’ and modes requires for the iOS implementation. We will use the same NSTimer to poll within the app every X seconds, but we will use IOPowerSources.h  within IOKit  to obtain the battery percentage.

Step 1:

Within your MacOs application AppDelegate.h  ( or wherever you want to put it ) import the IOKit ‘s IOPowerSources :

#import <IOKit/ps/IOPowerSources.h>

Within your AppDelegate.m create the method that will get the battery percentage and do whatever you want to do with the percentage, add the following method:

- (void)PollPercentage
{
    // Obtain blob data
    CFTypeRef powerSourceInfo = IOPSCopyPowerSourcesInfo();
    CFArrayRef powerSources = IOPSCopyPowerSourcesList(powerSourceInfo);
    
    CFDictionaryRef powerSource = NULL;

    
    long numberOfSources = CFArrayGetCount(powerSources);
    if(numberOfSources == 0)
    {
        NSLog(@"Problem, no power sources detected");
    }
    else
    {
        if(numberOfSources == 1)
        {
            NSLog(@"One power source detected");
            powerSource = IOPSGetPowerSourceDescription(powerSourceInfo, CFArrayGetValueAtIndex(powerSources, 0));
        }
        else
        {
            NSLog(@"More than one power source detected, using first one available");
            powerSource = IOPSGetPowerSourceDescription(powerSourceInfo, CFArrayGetValueAtIndex(powerSources, 0));
        }
        
        const void *psValue;
        int curCapacity = 0;
        int maxCapacity = 0;
        int percentage;
        
        // Work out percentage based on capacity current/max
        psValue = CFDictionaryGetValue(powerSource, CFSTR(kIOPSCurrentCapacityKey));
        CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity);
        
        psValue = CFDictionaryGetValue(powerSource, CFSTR(kIOPSMaxCapacityKey));
        CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity);
        
        percentage = (int)((double)curCapacity/(double)maxCapacity * 100);
        NSLog(@"Perentage of battery: %i", percentage);
        
        // TODO do whatever you want here code-wise with the percentage
    }
}
Step 2:

Hook up your method of a NSTimer by putting the following code in your applicationDidFinishLaunching  within the AppDelegate.m :

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    [NSTimer scheduledTimerWithTimeInterval:20.0
                                     target:self
                                   selector:@selector(PollPercentage)
                                   userInfo:nil
                                    repeats:YES];
}

If you fire up your app, you will see the the debug output look something like this:

 

Full git source code sample application here:

https://github.com/nsaxelby/MacOsBatteryMonitorApp