One Logo Pool Ball
wwwwwwwwwwwwwwwwwww

Barometer

Air pressure and relative altitude from the device barometer

One.Barometer streams air pressure from the device barometer, plus relative altitude on iOS. Reach for it for weather-aware UI, elevation gain on hikes, and floor-change hints indoors.

On iOS it uses CMAltimeter from Core Motion, with state on the main thread. On Android it reads the pressure sensor through SensorManager. On web browsers expose no barometer, so the sensor reads unavailable and listeners never fire.

Usage

import { useEffect, useState } from 'react'
import { Text } from 'react-native'
import { One } from 'one'
function Pressure() {
const [pressure, setPressure] = useState<number | null>(null)
useEffect(() => {
if (!One.Barometer.isAvailable()) return
One.Barometer.setUpdateInterval(1000)
const subscription = One.Barometer.addListener((event) => {
setPressure(event.pressure)
})
return () => subscription.remove()
}, [])
if (pressure === null) return null
return <Text>{pressure.toFixed(1)} hPa</Text>
}

The first listener starts the native sensor, so the first event can never race the subscription. Removing the last listener stops the hardware.

How it works

isAvailable is synchronous: relative-altitude hardware on iOS, a pressure sensor on Android. Each event carries pressure in hectopascals (iOS reports kilopascals and converts), the iOS-only relative altitude in meters above the first reading, and a timestamp in seconds since boot. setUpdateInterval paces delivery on Android; on iOS the altimeter has no interval API, so the call is accepted and ignored and delivery runs at the hardware rate.

On iOS physical devices need the motion usage description before the altimeter delivers anything; set native.app.pedometer.usage (see the pedometer). The interval and listener are validated before subscribing, throwing on a bad interval or callback.

API reference

MethodsTypeDescription
isAvailable() => booleanWhether this device has a barometer.
() => booleanWhether this device has a barometer.
setUpdateInterval(intervalMs: number) => voidPace Android delivery. Accepted, ignored on iOS.
(intervalMs: number) => voidPace Android delivery. Accepted, ignored on iOS.
addListener(listener: (event: BarometerMeasurement) => void) => BarometerSubscriptionStream pressure events.
(listener: (event: BarometerMeasurement) => void) => BarometerSubscriptionStream pressure events.
MeasurementTypeDescription
pressurenumberHectopascals.
numberHectopascals.
relativeAltitudenumberMeters above the first reading. iOS only.
numberMeters above the first reading. iOS only.
timestampnumberSeconds since boot.
numberSeconds since boot.
SubscriptionTypeDescription
remove() => voidStop this listener.
() => voidStop this listener.

Platform differences

iOSAndroidWeb
EngineAltimeterPressure sensorNone
PressureHectopascalsHectopascalsNever fires
AltitudeAbove firstOmittedOmitted
IntervalIgnoredHonoredIgnored
SetupMotion textNothingNothing

Limits and gotchas

Examples

Track elevation gain on a hike

import { useEffect, useRef, useState } from 'react'
import { Text } from 'react-native'
import { One } from 'one'
function ElevationGain() {
const [gain, setGain] = useState(0)
const lowest = useRef<number | null>(null)
useEffect(() => {
if (!One.Barometer.isAvailable()) return
const subscription = One.Barometer.addListener((event) => {
if (event.relativeAltitude === undefined) return
if (lowest.current === null) lowest.current = event.relativeAltitude
setGain(Math.max(0, event.relativeAltitude - lowest.current))
})
return () => subscription.remove()
}, [])
return <Text>Climbed {gain.toFixed(0)} m</Text>
}

The lowest reading anchors the gain so descents never subtract from the total. The undefined guard keeps Android quiet, where altitude is omitted.

Sample pressure once a minute

import { One } from 'one'
async function readPressure(timeoutMs = 5000): Promise<number | null> {
if (!One.Barometer.isAvailable()) return null
One.Barometer.setUpdateInterval(60_000)
return new Promise((resolve) => {
const timer = setTimeout(() => {
subscription.remove()
resolve(null)
}, timeoutMs)
const subscription = One.Barometer.addListener((event) => {
clearTimeout(timer)
subscription.remove()
resolve(event.pressure)
})
})
}

One-shot reads still go through a listener, removing it on the first event. The timeout resolves null where the sensor stays silent, and the minute interval keeps slow polling cheap on Android.

Edit this page on GitHub.