import { Subscription } from 'expo-modules-core'; import * as Sensors from 'expo-sensors'; import React from 'react'; import { ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; const FAST_INTERVAL = 16; const SLOW_INTERVAL = 1000; export default class SensorScreen extends React.Component { static navigationOptions = { title: 'Sensors', }; render() { return ( ); } } type State = { data: Measurement; isAvailable?: boolean; }; abstract class SensorBlock extends React.Component> { readonly state: State = { data: {} as Measurement }; _subscription?: Subscription; componentDidMount() { this.checkAvailability(); } checkAvailability = async () => { const isAvailable = await this.getSensor().isAvailableAsync(); this.setState({ isAvailable }); }; componentWillUnmount() { this._unsubscribe(); } abstract getName: () => string; abstract getSensor: () => Sensors.DeviceSensor; _toggle = () => { if (this._subscription) { this._unsubscribe(); } else { this._subscribe(); } }; _slow = () => { this.getSensor().setUpdateInterval(SLOW_INTERVAL); }; _fast = () => { this.getSensor().setUpdateInterval(FAST_INTERVAL); }; _subscribe = () => { this._subscription = this.getSensor().addListener((data: Measurement) => { this.setState({ data }); }); }; _unsubscribe = () => { this._subscription && this._subscription.remove(); this._subscription = undefined; }; renderData() { return ( this.state.data && ( {Object.entries(this.state.data) .map(([key, value]) => `${key}: ${typeof value === 'number' ? round(value) : 0}`) .join(' ')} ) ); } render() { if (this.state.isAvailable !== true) { return null; } return ( {this.getName()}: {this.renderData()} Toggle Slow Fast ); } } class GyroscopeSensor extends SensorBlock { getName = () => 'Gyroscope'; getSensor = () => Sensors.Gyroscope; } class AccelerometerSensor extends SensorBlock { getName = () => 'Accelerometer'; getSensor = () => Sensors.Accelerometer; } class MagnetometerSensor extends SensorBlock { getName = () => 'Magnetometer'; getSensor = () => Sensors.Magnetometer; } class MagnetometerUncalibratedSensor extends SensorBlock { getName = () => 'Magnetometer (Uncalibrated)'; getSensor = () => Sensors.MagnetometerUncalibrated; } class DeviceMotionSensor extends SensorBlock { getName = () => 'DeviceMotion'; getSensor = () => Sensors.DeviceMotion; renderXYZBlock = (name: string, event: null | { x?: number; y?: number; z?: number } = {}) => { if (!event) return null; const { x, y, z } = event; return ( {name}: x: {round(x)} y: {round(y)} z: {round(z)} ); }; renderABGBlock = ( name: string, event: null | { alpha?: number; beta?: number; gamma?: number } = {} ) => { if (!event) return null; const { alpha, beta, gamma } = event; return ( {name}: α: {round(alpha)} β: {round(beta)} γ: {round(gamma)} ); }; renderData = () => ( {this.renderXYZBlock('Acceleration', this.state.data.acceleration)} {this.renderXYZBlock('Acceleration w/gravity', this.state.data.accelerationIncludingGravity)} {this.renderABGBlock('Rotation', this.state.data.rotation)} {this.renderABGBlock('Rotation rate', this.state.data.rotationRate)} Orientation: {Sensors.DeviceMotionOrientation[this.state.data.orientation]} ); } class BarometerSensor extends SensorBlock { getName = () => 'Barometer'; getSensor = () => Sensors.Barometer; renderData = () => ( Pressure: {this.state.data.pressure} Relative Altitude: {this.state.data.relativeAltitude} ); } class LightSensor extends SensorBlock { getName = () => 'LightSensor'; getSensor = () => Sensors.LightSensor; renderData = () => ( Illuminance: {this.state.data.illuminance} ); } function round(n?: number) { return n ? Math.floor(n * 100) / 100 : 0; } const styles = StyleSheet.create({ container: { flex: 1, marginBottom: 10, }, buttonContainer: { flexDirection: 'row', alignItems: 'stretch', marginTop: 15, }, button: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#eee', padding: 10, }, middleButton: { borderLeftWidth: 1, borderRightWidth: 1, borderColor: '#ccc', }, sensor: { marginTop: 15, paddingHorizontal: 10, }, });