or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

device-motion.mdenvironmental-sensors.mdindex.mdmagnetic-sensors.mdmotion-sensors.mdpedometer.md
tile.json

magnetic-sensors.mddocs/

Magnetic Field Sensors

Magnetometer functionality for compass applications and magnetic field detection, available in both calibrated and uncalibrated forms.

Capabilities

Magnetometer

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)`);
});

Magnetometer Uncalibrated

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");
  }
}

Magnetic Field Analysis

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`);
  }
}

Platform Considerations

Android

  • Magnetometer available on most devices (API Level 9+)
  • Both calibrated and uncalibrated magnetometer supported
  • Hardware calibration varies by device manufacturer

iOS

  • Magnetometer available on most devices (iOS 8+)
  • High-quality hardware calibration typically available
  • Some older devices may have less accurate readings

Web

  • Magnetometer not available on web platforms
  • Compass functionality can be approximated using DeviceOrientationEvent when available