Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Accessing Barometer Measurements
-
I'm wondering whether it is possible to access the barometer (pressure) measurements on a supported iPhone from within a pythoninsta script? I've tried to use ObjCClass with the corresponding objective C class without much luck.
-
I wasn't even aware that iPhones had barometer measurements. What code have you tried, maybe someone can help debug?
-
Models since the iPhone 6 has a built in barometer. I believe it's primarily for measuring how many flights of stairs climbed. But the raw pressure measurements should be accessible:
To be honest, I'm fairly new to Pythoninsta, and am not entirely sure whether objCClass is for this purpose.
What I'm trying to do is to write a simple utility to map out a pressure and magnetic field variations in underground caves. The latter is possible with the motion module. I'm a caving hobbyist, and want to see whether sensors in phones can aid underground spatial orientation. (GPS obviously doesn't work underground!)
-
It's a little tricky because of the block-based API, but here's a working example that simply prints altitude/pressure data to the console (until the script is stopped). I've only tested this on an iPad Air 2 (which also has a barometer), but it should work the same on an iPhone 6.
from objc_util import ObjCInstance, ObjCClass, ObjCBlock, c_void_p def handler(_cmd, _data, _error): print(ObjCInstance(_data)) handler_block = ObjCBlock(handler, restype=None, argtypes=[c_void_p, c_void_p, c_void_p]) def main(): CMAltimeter = ObjCClass('CMAltimeter') NSOperationQueue = ObjCClass('NSOperationQueue') if not CMAltimeter.isRelativeAltitudeAvailable(): print('This device has no barometer.') return altimeter = CMAltimeter.new() main_q = NSOperationQueue.mainQueue() altimeter.startRelativeAltitudeUpdatesToQueue_withHandler_(main_q, handler_block) print('Started altitude updates.') try: while True: pass finally: altimeter.stopRelativeAltitudeUpdates() print('Updates stopped.') if __name__ == '__main__': main()
-
I'm a caver hobbyist myself, and want to see whether sensors in phones can aid underground spatial orientation. (GPS obviously doesn't work underground!)
That's a pretty awesome use case btw!
-
@omz , is this a dangerous example. I mean for battery life. Eg is it like the motion module. That if you don't actually call the stop update method, it will use extra battery. I am not sure what context that is in. No pun intended. But can that example be used with a context manager, or maybe it does not matter. I am not sure. Just going off what I read before from the Pythonista modules for hardware access. Maybe it's different when doing it this way
-
@Phuket2 Well, you'd need to stop the updates at some point (and I'm doing that in the example). I'm not sure how much altimeter updates drain the battery; I suspect that it's actually not very much with the M8/M9 motion co-processor all these devices have.
But even if you forget to stop the updates, iOS will suspend the app after a couple of minutes anyway, if it's not in the foreground, so you can't really drain the battery very much while you're not actively using the app.
-
@omz , ok perfect. I wasn't sure how global the settings were. Btw, if I stop the script, I don't get the 'Updates stopped" print.
-
Btw, if I stop the script, I don't get the 'Updates stopped" print.
@Phuket2 Hmm, that's weird. Are you using Pythonista 2 or 3?
-
@omz , sorry I was wrong it does print the stop msg. Not sure what I did wrong. I recopied the script from here and it worked as you described . I thought I was being attentive , but apparently not 😱
It was Pythonista 2. Again sorry, hate to waste your time -
I am sure that @tszheichoi takes an extra flashlight when spelunking just in case the iPhone batteries are drained!
-
I am not used to ObjC stuff. Is there an easy way to get a single barometer reading from the sensor?
-
@victordomingos, this Apple API only gives you relative readings, not one absolute value. Thus it seems that one single call would not be very useful?
-
... but of course you have the pressure value there. Here’s a modification that gives you a simple
get_pressure
function (a bit of a hack because of the global variable use).from objc_util import ObjCInstance, ObjCClass, ObjCBlock, c_void_p pressure = None def get_pressure(): def handler(_cmd, _data, _error): global pressure pressure = ObjCInstance(_data).pressure() handler_block = ObjCBlock(handler, restype=None, argtypes=[c_void_p, c_void_p, c_void_p]) CMAltimeter = ObjCClass('CMAltimeter') NSOperationQueue = ObjCClass('NSOperationQueue') if not CMAltimeter.isRelativeAltitudeAvailable(): print('This device has no barometer.') return altimeter = CMAltimeter.new() main_q = NSOperationQueue.mainQueue() altimeter.startRelativeAltitudeUpdatesToQueue_withHandler_(main_q, handler_block) #print('Started altitude updates.') try: while pressure is None: pass finally: altimeter.stopRelativeAltitudeUpdates() #print('Updates stopped.') return pressure if __name__ == '__main__': print(get_pressure())
-
What kind of value (units) is this last version of the script printing out?
-
timestamp (an NSTimeInterval in seconds since the device has been booted)
relativeAltitude (an NSNumber in meters)
pressure (an NSNumber in kilopascal) -
I want to use the NSNumber for pressure in a calculation. How do I convert it to something I can use with mathematical functions?
-
@DaveClark, change
return pressure
on line 28 toreturn pressure.CGFloatValue()
. -
That did it and now I know I need to read the documents more. Thanks you for your help
-
It was working after I change line 28 to your suggestion. But today without changing anything(I think)
line 28 was return pressure
line 28 now return pressure.CGFloatValue()
Now it is showing an error message complaining about line 28. It says:
AttributeError
no method found for
CGFloatValueagain, I am at a loss