Ambient light level in lux from the device light sensor
One.LightSensor streams the ambient light level in lux. Reach for it
for auto-brightness companions, day and night theming, and camera
exposure hints.
On Android it reads the light sensor through SensorManager. On iOS
there is no public ambient light API, so the sensor reads unavailable
and listeners never fire. On web the generic-sensor AmbientLightSensor
supplies live lux where the browser has it.
import { useEffect, useState } from 'react'import { Text } from 'react-native'import { One } from 'one'
function LightLevel() { const [lux, setLux] = useState<number | null>(null)
useEffect(() => { if (!One.LightSensor.isAvailable()) return One.LightSensor.setUpdateInterval(1000) const subscription = One.LightSensor.addListener((event) => { setLux(event.illuminance) }) return () => subscription.remove() }, [])
if (lux === null) return null return <Text>{lux.toFixed(0)} lux</Text>}Availability gates the subscription, so iOS renders nothing instead of an empty stream. The interval keeps delivery to one event per second.
isAvailable is synchronous: a light sensor on Android, always false on
iOS. Each event carries illuminance in lux and a timestamp: seconds since
boot on Android, Unix seconds on web, so compare timestamps only within
one platform. setUpdateInterval paces Android delivery. The first
listener starts the native sensor and the last remover stops it.
| Methods | Type | Description |
|---|---|---|
isAvailable() => booleanWhether this device reports light. | () => boolean | Whether this device reports light. |
setUpdateInterval(intervalMs: number) => voidPace Android delivery. | (intervalMs: number) => void | Pace Android delivery. |
addListener(listener: (event: LightSensorMeasurement) => void) => LightSensorSubscriptionStream lux events. | (listener: (event: LightSensorMeasurement) => void) => LightSensorSubscription | Stream lux events. |
| Measurement | Type | Description |
|---|---|---|
illuminancenumberAmbient light in lux. | number | Ambient light in lux. |
timestampnumberBoot seconds on Android, Unix seconds on web. | number | Boot seconds on Android, Unix seconds on web. |
| Subscription | Type | Description |
|---|---|---|
remove() => voidStop this listener. | () => void | Stop this listener. |
| iOS | Android | Web | |
|---|---|---|---|
| Engine | None public | Light sensor | Generic sensor |
| Available | Never | With sensor | With browser API |
| Timestamp | None | Boot seconds | Unix seconds |
import { useEffect, useState } from 'react'import { One } from 'one'
function useAmbientTheme() { const [dark, setDark] = useState(false)
useEffect(() => { if (!One.LightSensor.isAvailable()) return const subscription = One.LightSensor.addListener((event) => { setDark(event.illuminance < 30) }) return () => subscription.remove() }, [])
return dark ? 'dark' : 'light'}A 30-lux threshold splits dim rooms from lit ones without flickering at the boundary of a single reading. Manual theme choice should still win over this signal.
import { One } from 'one'
async function readLight(timeoutMs = 5000): Promise<number | null> { if (!One.LightSensor.isAvailable()) return null return new Promise((resolve) => { const timer = setTimeout(() => { subscription.remove() resolve(null) }, timeoutMs) const subscription = One.LightSensor.addListener((event) => { clearTimeout(timer) subscription.remove() resolve(event.illuminance) }) })}One-shot reads subscribe and remove on the first event, with a timeout that resolves null where the sensor stays silent.
Edit this page on GitHub.