Magnetometer functionality for compass applications and magnetic field detection, available in both calibrated and uncalibrated forms.
Provides access to the device's magnetometer for measuring magnetic field strength. Essential for compass applications and magnetic field detection.
/**
* Magnetometer sensor instance providing access to magnetic field data
* @platform android
* @platform ios
*/
declare const Magnetometer: MagnetometerSensor;
interface MagnetometerSensor extends DeviceSensor<MagnetometerMeasurement> {
/**
* Subscribe for updates to the magnetometer
* @param listener - Callback invoked when magnetometer update is available
* @returns Subscription that can be removed when done
*/
addListener(listener: Listener<MagnetometerMeasurement>): Subscription;
/**
* Check the availability of the device magnetometer. Requires at least Android 2.3 (API Level 9) and iOS 8
* @returns Promise resolving to boolean denoting availability
*/
isAvailableAsync(): Promise<boolean>;
}
interface MagnetometerMeasurement {
/** Value representing strength of magnetic field recorded in X axis (μT) */
x: number;
/** Value representing strength of magnetic field recorded in Y axis (μT) */
y: number;
/** Value representing strength of magnetic field recorded in Z axis (μT) */
z: number;
/** Timestamp of the measurement in seconds */
timestamp: number;
}Usage Examples:
import { Magnetometer } from "expo-sensors";
// Check availability (not available on web)
const isAvailable = await Magnetometer.isAvailableAsync();
if (!isAvailable) {
console.log("Magnetometer not available on this device");
return;
}
// Subscribe to magnetometer updates
const subscription = Magnetometer.addListener(({ x, y, z, timestamp }) => {
// Calculate magnetic field magnitude
const magnitude = Math.sqrt(x * x + y * y + z * z);
console.log(`Magnetic field strength: ${magnitude.toFixed(2)} μT`);
// Calculate compass heading (simplified)
const heading = Math.atan2(y, x) * (180 / Math.PI);
const normalizedHeading = (heading + 360) % 360;
console.log(`Compass heading: ${normalizedHeading.toFixed(1)}°`);
});
// Set moderate update rate for compass applications
Magnetometer.setUpdateInterval(200); // 5 Hz
// Clean up
subscription.remove();Compass Implementation:
import { Magnetometer } from "expo-sensors";
interface CompassReading {
heading: number;
accuracy: 'high' | 'medium' | 'low';
}
class SimpleCompass {
private subscription: any;
private readings: number[] = [];
private maxReadings = 10;
startCompass(callback: (reading: CompassReading) => void) {
this.subscription = Magnetometer.addListener(({ x, y, z }) => {
// Calculate heading from magnetic field
let heading = Math.atan2(y, x) * (180 / Math.PI);
heading = (heading + 360) % 360; // Normalize to 0-360
// Store recent readings for accuracy calculation
this.readings.push(heading);
if (this.readings.length > this.maxReadings) {
this.readings.shift();
}
// Calculate standard deviation for accuracy
const accuracy = this.calculateAccuracy();
callback({ heading, accuracy });
});
Magnetometer.setUpdateInterval(100);
}
stopCompass() {
if (this.subscription) {
this.subscription.remove();
this.subscription = null;
}
}
private calculateAccuracy(): 'high' | 'medium' | 'low' {
if (this.readings.length < 3) return 'low';
const mean = this.readings.reduce((a, b) => a + b) / this.readings.length;
const variance = this.readings.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / this.readings.length;
const stdDev = Math.sqrt(variance);
if (stdDev < 5) return 'high';
if (stdDev < 15) return 'medium';
return 'low';
}
}
// Usage
const compass = new SimpleCompass();
compass.startCompass(({ heading, accuracy }) => {
console.log(`Heading: ${heading.toFixed(1)}° (${accuracy} accuracy)`);
});Provides access to uncalibrated magnetometer data, which may include device-specific biases but can be more accurate for some applications.
/**
* Uncalibrated magnetometer sensor instance
* @platform android
* @platform ios
*/
declare const MagnetometerUncalibrated: MagnetometerUncalibratedSensor;
interface MagnetometerUncalibratedSensor extends DeviceSensor<MagnetometerUncalibratedMeasurement> {
// Inherits all DeviceSensor methods but typically used for raw magnetic field data
}
interface MagnetometerUncalibratedMeasurement {
/** Value representing uncalibrated strength of magnetic field recorded in X axis (μT) */
x: number;
/** Value representing uncalibrated strength of magnetic field recorded in Y axis (μT) */
y: number;
/** Value representing uncalibrated strength of magnetic field recorded in Z axis (μT) */
z: number;
/** Timestamp of the measurement in seconds */
timestamp: number;
}Usage Examples:
import { MagnetometerUncalibrated } from "expo-sensors";
// Use uncalibrated magnetometer for applications needing raw data
const subscription = MagnetometerUncalibrated.addListener(({ x, y, z, timestamp }) => {
console.log(`Raw magnetic field - X: ${x.toFixed(2)}, Y: ${y.toFixed(2)}, Z: ${z.toFixed(2)} μT`);
// Process raw magnetic data without device calibration
processRawMagneticData(x, y, z);
});
function processRawMagneticData(x: number, y: number, z: number) {
// Custom calibration or analysis of raw magnetic field data
const totalField = Math.sqrt(x * x + y * y + z * z);
// Typical Earth's magnetic field is around 25-65 μT
if (totalField > 100) {
console.log("Strong magnetic interference detected");
}
}Metal Detection:
import { Magnetometer } from "expo-sensors";
class MetalDetector {
private baselineField: number | null = null;
private threshold = 10; // μT change threshold
private calibrationSamples: number[] = [];
private calibrationCount = 50;
startDetection() {
const subscription = Magnetometer.addListener(({ x, y, z }) => {
const magnitude = Math.sqrt(x * x + y * y + z * z);
// Calibration phase
if (this.calibrationSamples.length < this.calibrationCount) {
this.calibrationSamples.push(magnitude);
if (this.calibrationSamples.length === this.calibrationCount) {
this.baselineField = this.calibrationSamples.reduce((a, b) => a + b) / this.calibrationCount;
console.log(`Baseline magnetic field: ${this.baselineField.toFixed(2)} μT`);
}
return;
}
// Detection phase
if (this.baselineField !== null) {
const change = Math.abs(magnitude - this.baselineField);
if (change > this.threshold) {
console.log(`Metal detected! Field change: ${change.toFixed(2)} μT`);
}
}
});
return subscription;
}
}Magnetic Interference Detection:
import { Magnetometer, MagnetometerUncalibrated } from "expo-sensors";
// Compare calibrated vs uncalibrated readings to detect interference
let calibratedReading: MagnetometerMeasurement | null = null;
let uncalibratedReading: MagnetometerUncalibratedMeasurement | null = null;
const calibratedSub = Magnetometer.addListener((data) => {
calibratedReading = data;
checkInterference();
});
const uncalibratedSub = MagnetometerUncalibrated.addListener((data) => {
uncalibratedReading = data;
checkInterference();
});
function checkInterference() {
if (!calibratedReading || !uncalibratedReading) return;
const calibratedMag = Math.sqrt(
calibratedReading.x ** 2 + calibratedReading.y ** 2 + calibratedReading.z ** 2
);
const uncalibratedMag = Math.sqrt(
uncalibratedReading.x ** 2 + uncalibratedReading.y ** 2 + uncalibratedReading.z ** 2
);
const difference = Math.abs(calibratedMag - uncalibratedMag);
if (difference > 20) { // Large difference suggests interference
console.log(`Magnetic interference detected. Difference: ${difference.toFixed(2)} μT`);
}
}