18

I'm trying to programmatically access the ambient light sensor in a Mac application running on OS X 10.5 and above, but can't find a way to do this.

Two other questions had been posed about this here, "Accessing mac's sensor data" and "Disable ambient-light sensor screen dimming programmatically on OS X", but they either didn't address this or present solutions that break on 10.5 and up.

What private API does Apple use to access the ambient light-sensor data on OS X and/or how would I find it?

Community
  • 1
  • 1
Indolering
  • 3,058
  • 30
  • 45
  • I think I was able to focus what you're asking here, which is indeed a good programming question, so I've reopened this. You might check to make sure I read you correctly in your question. – Brad Larson Aug 17 '13 at 16:10
  • That sounds great brad, thanks for clearing all that up : ) – Indolering Aug 17 '13 at 20:12

3 Answers3

33

I've found the closest thing I can -- example code from a Firefox bug report last modified in April 2013. The following works, producing a simple CLI program to query the sensor (taken freely from https://bugzilla.mozilla.org/show_bug.cgi?id=793728#attach_664102). The service polled is "AppleLMUController", which you can then extract relevant information from -- the snippet below creates a serviceObject=IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleLMUController")), which is then used.

// lmutracker.mm
//
// clang -o lmutracker lmutracker.mm -framework IOKit -framework CoreFoundation

#include <mach/mach.h>
#import <IOKit/IOKitLib.h>
#import <CoreFoundation/CoreFoundation.h>

static double updateInterval = 0.1;
static io_connect_t dataPort = 0;

void updateTimerCallBack(CFRunLoopTimerRef timer, void *info) {
  kern_return_t kr;
  uint32_t outputs = 2;
  uint64_t values[outputs];

  kr = IOConnectCallMethod(dataPort, 0, nil, 0, nil, 0, values, &outputs, nil, 0);
  if (kr == KERN_SUCCESS) {
    printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b%8lld %8lld", values[0], values[1]);
    return;
  }

  if (kr == kIOReturnBusy) {
    return;
  }

  mach_error("I/O Kit error:", kr);
  exit(kr);
}

int main(void) {
  kern_return_t kr;
  io_service_t serviceObject;
  CFRunLoopTimerRef updateTimer;

  serviceObject = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleLMUController"));
  if (!serviceObject) {
    fprintf(stderr, "failed to find ambient light sensors\n");
    exit(1);
  }

  kr = IOServiceOpen(serviceObject, mach_task_self(), 0, &dataPort);
  IOObjectRelease(serviceObject);
  if (kr != KERN_SUCCESS) {
    mach_error("IOServiceOpen:", kr);
    exit(kr);
  }

  setbuf(stdout, NULL);
  printf("%8ld %8ld", 0L, 0L);

  updateTimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
                  CFAbsoluteTimeGetCurrent() + updateInterval, updateInterval,
                  0, 0, updateTimerCallBack, NULL);
  CFRunLoopAddTimer(CFRunLoopGetCurrent(), updateTimer, kCFRunLoopDefaultMode);
  CFRunLoopRun();

  exit(0);
}
Landak
  • 904
  • 14
  • 26
  • 3
    I haven't had time to dig into the code, but it looks ike you nailed it. – Indolering Sep 06 '13 at 14:06
  • It works on El Capitan also... uncovered `512730 512730`, covered: `30 30` –  Feb 02 '16 at 07:14
  • 3
    macOS Mojave 10.14.3 -- Compiled like a charm, did not find any ambient light sensors though: `failed to find ambient light sensors`. However, I only attempted to read the data in order to check whether my sensor is broken or some software related error caused the problems. So maybe someone else should check again. – BadAtLaTeX Mar 06 '19 at 16:38
  • 3
    @gr4nt3d Alas this means you ran it on a Touchbar mac -- Apple has put more walls on its garden once again and we haven't broken through them yet. – Landak Jul 18 '19 at 16:57
  • @Landak: Yes, indeed! I've encountered, that my screen back light is not regulated automatically anymore and tried to find out, if it is a hardware problem. Moreover, the non-controllable touchbar (and keyboard backlights) brightness is at 100% all the time now. No progress yet. – BadAtLaTeX Jul 18 '19 at 17:45
1

While @Landak's answer is good for the time, that ambient light sensor api seems to have been deprecated.

The code that works now is as follows:

// lmutracker.mm
//
// clang -o lmutracker lmutracker.mm -F /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/PrivateFrameworks -framework Foundation -framework IOKit -framework CoreFoundation -framework BezelServices

#include <mach/mach.h>
#import <Foundation/Foundation.h>
#import <IOKit/IOKitLib.h>
#import <IOKit/hidsystem/IOHIDServiceClient.h>

typedef struct __IOHIDEvent *IOHIDEventRef;

#define kAmbientLightSensorEvent 12

#define IOHIDEventFieldBase(type) (type << 16)

extern "C" {
  IOHIDEventRef IOHIDServiceClientCopyEvent(IOHIDServiceClientRef, int64_t, int32_t, int64_t);
  double IOHIDEventGetFloatValue(IOHIDEventRef, int32_t);

  IOHIDServiceClientRef ALCALSCopyALSServiceClient(void);
}

static double updateInterval = 0.1;
static IOHIDServiceClientRef client;
static IOHIDEventRef event;

void updateTimerCallBack(CFRunLoopTimerRef timer, void *info) {
  double value;

  event = IOHIDServiceClientCopyEvent(client, kAmbientLightSensorEvent, 0, 0);

  value = IOHIDEventGetFloatValue(event, IOHIDEventFieldBase(kAmbientLightSensorEvent));

  printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b%8f", value);

  CFRelease(event);
}

int main(void) {
  kern_return_t kr;
  CFRunLoopTimerRef updateTimer;

  client = ALCALSCopyALSServiceClient();
  if (client) {
    event = IOHIDServiceClientCopyEvent(client, kAmbientLightSensorEvent, 0, 0);
  }
  if (!event) {
    fprintf(stderr, "failed to find ambient light sensors\n");
    exit(1);
  }

  CFRelease(event);

  setbuf(stdout, NULL);
  printf("%8f", 0.0);

  updateTimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
                  CFAbsoluteTimeGetCurrent() + updateInterval, updateInterval,
                  0, 0, updateTimerCallBack, NULL);
  CFRunLoopAddTimer(CFRunLoopGetCurrent(), updateTimer, kCFRunLoopDefaultMode);
  CFRunLoopRun();

  exit(0);
}

I found this in DarkModeBuddy (BSD 2-clause license), and adapted it into a cli tool in my dotfiles.

forivall
  • 9,504
  • 2
  • 33
  • 58
-1

You can get the value of ambient light sensor using terminal. For get the value first you should install the system management controller smc .exec then run it using terminal. After that run this command ./smc -l it's show's the list of all sensor's which exist on mac after that try to find the key which is ALSL this key give's the actual value of light ambient sensor of every mac.