Accessing the LED flashlight
Is it possible to access the LED flashlight of an iPhone using Pythonista?
I haven't had a chance to play with this, but the engineer in me asks if there are an accessible light sensors in the iphone that can "read" the incoming morse code?
@omz I have been updating my scripts to run on Python3... I have the sense that your
toggle_flashlightcode above could be streamlined these daze but I am not sure how to make it work under P3.
@ccc Yes, much less boilerplate code is required now:
from objc_util import ObjCClass def toggle_flashlight(): AVCaptureDevice = ObjCClass('AVCaptureDevice') device = AVCaptureDevice.defaultDeviceWithMediaType_('vide') if not device.hasTorch(): raise RuntimeError('Device has no flashlight') mode = device.torchMode() device.lockForConfiguration_(None) device.setTorchMode_((mode + 1) % 2) device.unlockForConfiguration() if __name__ == '__main__': toggle_flashlight()
This is not as Flash 😁 But the way the new Iphones use the screen as a flash for the front facing camera is an interesting possibility, also for devices that don't have a flash. I don't know, but could prove more reliable depending on distance etc. just a thought
iPhone 6s and 6s Plus contain a custom display chip that allows the retina display to briefly flash 3 times brighter than its usual maximum illuminance. No new API was added to support this feature. Since iOS 4, AVCaptureDevice has supported the -hasFlash, -isFlashModeSupported: and -flashMode properties. The iPhone 6s and 6s Plus front-facing cameras are the first front-facing iOS cameras to respond YES to the -hasFlash property. By setting the front-facing camera's flashMode to AVCaptureFlashModeOn or AVCaptureFlashModeAuto, the retina flash fires when a still image is captured (see AVCaptureStillImageOutput’s captureStillImageAsynchronouslyFromConnection:completionHandler:), just as the True Tone flash fires for rear-facing camera stills.
Hope this. Only works on 6s, 6s+, and SE.
@blmacbeth , ok thanks. I didn't know how they did it, was just nice, I have tried it several times on my 6s. But I think for the application here, you could still just fake it. Well, I think you could. I think somehow, it could be a better option to fake it with the screen as you have control over the timing and can calibrate etc. I just assume this would be hard to do with the flash. But I can see why the flash is appealing.
I brought my 6s without even knowing that it had the screen flash option.when I seen it, I just thought really, this is so simple and genius. But I get your point about the special API. Timing and white point/Lums etc... Critical.
Edit: but not so critical for dot, dash
@omz @Phuket2 @ccc would any of you happen to know how to set a custom brightness for the flashlight as some apps in the App Store can do? Passing anything other than an integer to
setTorchMode()throws an error...
I tried as to do
device.setTorchModeOnWithLevel_()as per some objective c, and trying to recognize patterns between the. Objc c code on stack overflow and your Python example..., but get error
no method found for selector..
Tbh, I have no idea what I'm doing with objc_util .... :(
As a side note I would gladly pay for a Pythonista objc-util tutorial for dummies.
@Tizzy According to a random Stack Overflow question I googled, the call looks like this in Objective-C:
BOOL success = [device setTorchModeOnWithLevel:0.2 error:&outError];
There is a second
errorargument that you need to pass, so in Python the call would look like this:
NULL- if not, you need to pass something else there, but I know nothing about Objective-C, so I can't help you with that)
I believe you can usually use None for error arguments (often you see error:nil in stackoverflow). I suspect passing zero is the same thing.
You can't pass zero for a parameter that expects a pointer.
This should work:
I noticed that passing 0.0 for the level crashes (haven't checked why exactly, it probably throws an exception), so you'd need to use
setTorchMode_(as above) to turn it back off again.
Something to note: running through the levels in 0.1 increments, it appears the only actual discrete levels are 1.0,0.9,0.8, and 0.4, unless there are finer increments between 0.4 and 1.0 ....
from objc_util import ObjCClass import time def toggle_flashlight(): AVCaptureDevice = ObjCClass('AVCaptureDevice') device = AVCaptureDevice.defaultDeviceWithMediaType_('vide') if not device.hasTorch(): raise RuntimeError('Device has no flashlight') mode = device.torchMode() device.lockForConfiguration_(None) if device.torchMode()>0: device.setTorchMode_((mode + 1) % 2) else: a =[1.0,0.9,0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1] for each in a: device.setTorchModeOnWithLevel_error_(each, None) print('level '+str(each)) time.sleep(.6) #device.setTorchModeOnWithLevel_error_(0.88, None) device.unlockForConfiguration() #device.setTorchModeOnWithLevel_error_(0.2, None) if __name__ == '__main__': toggle_flashlight()```