Unity Development Postmortem

Retrieving Battery Levels on Meta Quest 2 and 3

My project required a low-battery UI warning for players, but the standard Unity APIs weren't behaving as expected when deployed to my Quest 3 target.

Need supporting assets, scene references, or production files to test this Unity workflow beyond the article?

Open on 3DCGHub

1. The Initial Symptom

While building a custom HUD for our VR experience, I assumed I could hook into the standard input system to pull real-time telemetry for both the headset and the Touch controllers. When I queried the device properties during a test build, I found my scripts were returning null values or static defaults.

My initial assumption was that the Meta XR SDK required a specific permission manifest entry or a hidden service initialization sequence that I had overlooked in the project settings.

  • Headset battery returns appeared inconsistent across builds.
  • Controller status properties failed to initialize.
  • No explicit build errors in the Unity Console.
  • UI elements remained unpopulated during runtime.

2. Capturing Headset Battery Data

After stripping back my implementation, I focused on the core Unity SystemInfo class. It turns out that on the Quest 3, SystemInfo.batteryLevel works reliably, provided the application has proper focus and the underlying Android hardware abstraction layer is accessible.

I verified this by logging the value directly to the adb logcat output, confirming that the headset reports a normalized float value between 0.0 and 1.0.

  • Access SystemInfo.batteryLevel via the standard Unity API.
  • Ensure the value is clamped or formatted for UI display.
  • Verify results using adb logcat to avoid Editor-specific bugs.

3. The Controller Reporting Wall

The issue hit a roadblock when I tried to pull specific battery telemetry for the Left and Right Touch controllers. Despite the Meta Quest companion app displaying 'Low Battery' alerts for the controllers, the SDK exposes no clean, programmatic hook to query those specific charge levels.

My investigation into the low-level XR input tracking confirmed that the hardware communicates this status to the Android OS level, but it does not propagate that data to the Unity input subsystem.

  • Confirmed no public API for controller battery levels.
  • Data found in Meta app is proprietary and non-exposed.
  • Attempted polling XRInputSubsystem with no success.

4. Strategic Recommendations

Given these constraints, the best path forward for production apps is to track the headset's energy consumption and provide a generic 'low battery' warning if the system level drops below a set threshold. Avoid building features that rely on granular per-controller battery telemetry.

This approach ensures your UI stays functional and avoids cluttering the player experience with data points that the engine simply cannot retrieve reliably.

  • Use headset battery as a proxy for the system state.
  • Focus on core gameplay rather than hardware telemetry.
  • Document these API limitations for future project updates.

FAQ

Can I use OVRManager to get controller battery levels?

Currently, the OVRManager does not provide direct access to controller battery levels. The data is managed by the Meta runtime and is not surfaced to Unity developers.

Does SystemInfo.batteryLevel work on Quest 2?

Based on my testing and common engine behavior, it should return the same valid float range as it does on the Quest 3.