Simple Idea, where to start?

Discussion in 'Mac Programming' started by ArtOfWarfare, Jan 9, 2012.

  1. macrumors 603

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #1
    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?
     
  2. macrumors member

    Joined:
    Feb 2, 2009
    #2
    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"
     
  3. thread starter macrumors 603

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #3
    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?
     
  4. macrumors Pentium

    KnightWRX

    Joined:
    Jan 28, 2009
    Location:
    Quebec, Canada
    #4
  5. macrumors 6502

    Joined:
    Mar 12, 2010
    #5
    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?
     
  6. macrumors member

    Joined:
    Feb 2, 2009
    #6
    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.
     
  7. macrumors 68030

    Joined:
    Oct 19, 2011
    Location:
    Switzerland
    #7
    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.
     
  8. macrumors 6502

    seepel

    Joined:
    Dec 22, 2009
    #8
    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.
     
  9. macrumors Pentium

    KnightWRX

    Joined:
    Jan 28, 2009
    Location:
    Quebec, Canada
    #9
    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.
     
  10. macrumors 6502

    seepel

    Joined:
    Dec 22, 2009
    #10
    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.
     
  11. ArtOfWarfare, Jan 10, 2012
    Last edited: Jan 10, 2012

    thread starter macrumors 603

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #11
    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.
     
  12. thread starter macrumors 603

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #12
    I get this log output:

    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
     
  13. macrumors Pentium

    KnightWRX

    Joined:
    Jan 28, 2009
    Location:
    Quebec, Canada
    #13
    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.
     
  14. thread starter macrumors 603

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #14
    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?
     
  15. macrumors Pentium

    KnightWRX

    Joined:
    Jan 28, 2009
    Location:
    Quebec, Canada
    #15
    I'm not versed in those areas of Mac development unfortunately. Maybe someone else can help you out on those.
     
  16. macrumors 6502

    seepel

    Joined:
    Dec 22, 2009
    #16
    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.
     
  17. ArtOfWarfare, Jan 11, 2012
    Last edited: Jan 11, 2012

    thread starter macrumors 603

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #17
    Thanks for the keywords :)

    This was too easy... I followed this tutorial a bit:
    http://www.sonsothunder.com/devres/livecode/tutorials/StatusMenu.html

    and I also looked at Apple's sample project entitled "ItemMenuView".
     

Share This Page