Mac Simple Idea, where to start?

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
8,580
4,020
I'd like to make an app that displays the battery status of everything connected to the computer, say, a magic trackpad, wireless mouse or keyboard... maybe even an attached iPad or iPhone.

Unfortunately, I don't know where to look. I searched through the Apple docs but it seems that everything related to batteries brings up iOS references and everything related to the trackpad has to do with handling events.

So, any pointers on how I could make an app request the current battery status of any attached magic trackpads, for example?
 

phantax

macrumors member
Feb 2, 2009
72
0
You can get the battery percentage from ioreg, I am not sure if the bluetooth devices will give further detail such as battery capacity, etc.

Apple Keyboard:
ioreg -n "AppleBluetoothHIDKeyboard" | grep -i "batterypercent"

Magic Mouse:
ioreg -n "BNBMouseDevice" | grep -i "batterypercent"
 

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
8,580
4,020
Battery percent will be fine for my purposes.

Unless I'm mistaken, the code you gave is for terminal (which I'm going to have to confess I'm borderline clueless on how to use... I'll need to remedy that someday soon I'm sure,) would it be possible for you to tell me how I might have an NSLog that outputs the battery percentage in applicationDidFinishLaunching?
 

willieva

macrumors 6502
Mar 12, 2010
274
0
You can get the battery percentage from ioreg, I am not sure if the bluetooth devices will give further detail such as battery capacity, etc.

Apple Keyboard:
ioreg -n "AppleBluetoothHIDKeyboard" | grep -i "batterypercent"

Magic Mouse:
ioreg -n "BNBMouseDevice" | grep -i "batterypercent"
This output of this for my mouse is 65%. Yet when I click on the bluetooth logo on the menu bar and look at the device there, it says 100%. Since the batteries are fresh, I'm inclined to believe that number. Can anyone explain this discrepancy?
 

phantax

macrumors member
Feb 2, 2009
72
0
Seems there is a bug in Lion which hasn't been addressed yet, I saw some postings discussing it.

My findings are the opposite. My keyboard shows 100% in system preferences, ioreg shows 73% and the batteries are over a month old.
 

thundersteele

macrumors 68030
Oct 19, 2011
2,984
7
Switzerland
Battery percent will be fine for my purposes.

Unless I'm mistaken, the code you gave is for terminal (which I'm going to have to confess I'm borderline clueless on how to use... I'll need to remedy that someday soon I'm sure,) would it be possible for you to tell me how I might have an NSLog that outputs the battery percentage in applicationDidFinishLaunching?
Option 1:
Call the terminal code from within your program (NSTask), pipe it into a string (NSpipe) and parse it for the information you are looking for.

Option 2:
Look into IOkit and the IOregistry.


For option 1, I found some useful information here:
http://stackoverflow.com/questions/412562/execute-a-terminal-command-from-a-cocoa-app

For option 2... it's a mess... takes some time to learn, I still have to figure it out. One of Apples sample codes has implemented something like that, might be useful.
 

seepel

macrumors 6502
Dec 22, 2009
471
0
In my experience "simple ideas" are simple if Apple nticipates you doing it, and rather convoluted if they don't. I think this might fall into the latter category.
 

KnightWRX

macrumors Pentium
Jan 28, 2009
15,046
4
Quebec, Canada
In my experience "simple ideas" are simple if Apple nticipates you doing it, and rather convoluted if they don't. I think this might fall into the latter category.
Except as has been pointed out, the IO Registry does just this.

I myself would write this as a Dashboard widget or a menu bar icon.
 

seepel

macrumors 6502
Dec 22, 2009
471
0
Except as has been pointed out, the IO Registry does just this.

I myself would write this as a Dashboard widget or a menu bar icon.
Don't get me wrong I'm not saying it can't be done, but as per the bugs that were reported above, and adding in phones etc... I am just am little skeptical that the implementation can be as simple as the concept. There are often posts about simple ideas, and I'd like to caution that in my experience simple ideas often turn not so simple pretty quickly.
 

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
8,580
4,020
Except as has been pointed out, the IO Registry does just this.

I myself would write this as a Dashboard widget or a menu bar icon.
Ultimately I'd like to make a menu bar icon, but I figured I'd explore one thing I'm unfamiliar with at a time. So for the first attempt at this, I'm just going to make a single window application. Once I've gotten that figured out I'll try to do it as a menu bar icon. (Will Apple allow menu bar icons to be sold via the Mac App Store?)

Edit: I read what KnightWRX posted a link to, and... I still can't write a single line of code in the right direction for this.

Does anyone have any sample code that could help? It seems like this aught to be extremely simple, something like

[IOReg registeredDevices];

or... I suppose it would be C or C++, not Obj-C... still... I can't imagine a program for just making an NSLog with the battery percent would take more than ten lines of code.

2X Edit:

BNBTrackpadDevice inherits from BNBTrackpadDevice, BNBDevice, BluetoothMultitouchTransport, IOAppleBluetoothHIDDriver, IOBluetoothHIDDriver, IOHIDDevice, IOService, IORegistryEntry, and OSObject.

...

This almost seems like useful information, except the documentation on these classes... doesn't exist? It's not what I want. I want a function I can call to someone, get the device registry, and then a function that I can use to get the device registry to tell me which devices have BatteryPercent as a property...

3X Edit:

I'm finally making it somewhere... I've now written some C++ code that iterates through the registry and outputs the IOClass property for everything... I'll update this post once I've gotten it to give names and battery percents instead.
 
Last edited:

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
8,580
4,020
I get this log output:

Apple Wireless Trackpad - 100%
So... it works!

Next, I need to figure out how to move this into a window... and then after that, into the menubar. Getting this to appear in a window shouldn't be difficult, but the menubar is going to be a bit more difficult.

Does anyone know how I can
1 - Make the app run in the background, that is, without a dock icon
2 - Make an icon appear on the right side of the menubar, IE, where the battery icon on a laptop would show up
3 - Bundle it in such a way it'd be acceptable on the Mac App Store

Here's the code I'm using right now:
Code:
#import "BatTAppDelegate.h"

@implementation BatTAppDelegate

@synthesize window = _window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    mach_port_t     masterPort;
    kern_return_t   kr;
    io_iterator_t   ite;
    io_object_t     obj = 0;
    CFMutableDictionaryRef  properties;
    
    kr = IOMasterPort(bootstrap_port, &masterPort);
    if (kr != KERN_SUCCESS)
        printf("IOMasterPort() failed: %x\n", kr);
    
    kr = IORegistryCreateIterator(masterPort,
                                  kIOServicePlane,
                                  true,             /* recursive */
                                  &ite);
    
    while ((obj = IOIteratorNext(ite)))
    {
        kr = IORegistryEntryCreateCFProperties(obj,
                                               &properties,
                                               kCFAllocatorDefault,
                                               kNilOptions);
        
        if ((kr != KERN_SUCCESS) || !properties) {
            printf("IORegistryEntryCreateCFProperties error %x\n", kr);
        }
        
        else
        {
            CFNumberRef percent = (CFNumberRef) CFDictionaryGetValue(properties, CFSTR("BatteryPercent"));
            if (percent)
            {
                SInt32 s;
                if(!CFNumberGetValue(percent, kCFNumberSInt32Type, &s))
                {
                    printf("***CFNumber overflow***\n");
                }
                
                else
                {
                    CFStringRef name = (CFStringRef) CFDictionaryGetValue(properties, CFSTR("Product"));
                    
                    const char * c = CFStringGetCStringPtr(name, kCFStringEncodingMacRoman);
                    
                    if (c)
                        printf(c);
                    else
                    {
                        CFIndex bufferSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(name), kCFStringEncodingMacRoman) + sizeof('\0');
                        char *  buffer     = (char *) malloc(bufferSize);
                        
                        if (buffer)
                        {
                            if ( CFStringGetCString(
                                                    /* string     */ name,
                                                    /* buffer     */ buffer,
                                                    /* bufferSize */ bufferSize,
                                                    /* encoding   */ kCFStringEncodingMacRoman) )
                                printf(buffer);
                            
                            free(buffer);
                        }
                    }
                    
                    printf(" - %d%%\n", (int)s);
                }
                
            }
            
            else
            {
                //There wasn't a battery.
            }
        }
    }
}

@end
 

KnightWRX

macrumors Pentium
Jan 28, 2009
15,046
4
Quebec, Canada
Edit: I read what KnightWRX posted a link to, and... I still can't write a single line of code in the right direction for this.

Does anyone have any sample code that could help? It seems like this aught to be extremely simple, something like

[IOReg registeredDevices];

or... I suppose it would be C or C++, not Obj-C... still... I can't imagine a program for just making an NSLog with the battery percent would take more than ten lines of code.
I once set out to write a pretty simple Win32 apps (some 10 years ago). I wanted to check if the main volume in the sound mixer was muted. If it wasn't, I wanted to mute it, if it was, I wanted to unmute it. Basically, a quite mute toggle.

Simple uh ?

I ended up with something like 200 lines of codes and reading documentation on setting up about 3-4 big structs to pass along the various stages of the mixer API.

Low-level APIs are like that unfortunately.
 

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
8,580
4,020
I once set out to write a pretty simple Win32 apps (some 10 years ago). I wanted to check if the main volume in the sound mixer was muted. If it wasn't, I wanted to mute it, if it was, I wanted to unmute it. Basically, a quite mute toggle.

Simple uh ?

I ended up with something like 200 lines of codes and reading documentation on setting up about 3-4 big structs to pass along the various stages of the mixer API.

Low-level APIs are like that unfortunately.
I'm just going to have to use them more and get more comfortable with them, I think, given I'm going to be applying for an internship at Apple this summer (I'm not really expecting to get it, and I am applying for internships at other companies as well.)

Anyways, the code works, and it's entirely written in C (unless I'm mistaken.)

Getting it to appear in a windowed application would be a trivial step, but I'm curious if it'd be a step in the wrong direction.

I'd like to:
1 - Make the app run in the background, that is, without a dock icon
2 - Make an icon appear on the right side of the menubar, IE, where the battery icon on a laptop would show up
3 - Bundle it in such a way it'd be acceptable on the Mac App Store

Any suggestions?
 

KnightWRX

macrumors Pentium
Jan 28, 2009
15,046
4
Quebec, Canada
Getting it to appear in a windowed application would be a trivial step, but I'm curious if it'd be a step in the wrong direction.

I'd like to:
1 - Make the app run in the background, that is, without a dock icon
2 - Make an icon appear on the right side of the menubar, IE, where the battery icon on a laptop would show up
3 - Bundle it in such a way it'd be acceptable on the Mac App Store

Any suggestions?
I'm not versed in those areas of Mac development unfortunately. Maybe someone else can help you out on those.
 

seepel

macrumors 6502
Dec 22, 2009
471
0
I'm just going to have to use them more and get more comfortable with them, I think, given I'm going to be applying for an internship at Apple this summer (I'm not really expecting to get it, and I am applying for internships at other companies as well.)

Anyways, the code works, and it's entirely written in C (unless I'm mistaken.)

Getting it to appear in a windowed application would be a trivial step, but I'm curious if it'd be a step in the wrong direction.

I'd like to:
1 - Make the app run in the background, that is, without a dock icon
2 - Make an icon appear on the right side of the menubar, IE, where the battery icon on a laptop would show up
3 - Bundle it in such a way it'd be acceptable on the Mac App Store

Any suggestions?
1 - In your plist there is an element that needs the raw value LSUIElement (or something close to that) set to YES
2 - NSStatusItem
3 - nothing special needed here, just follow the normal guidelines.
 

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
8,580
4,020
Last edited: