forked from STEDI-Balance/stedi-react-native
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Counter.js
151 lines (132 loc) · 5.58 KB
/
Counter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import React, { useState, useEffect, useRef } from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { Accelerometer } from 'expo-sensors';
import getSpikesFromAccelerometer from './utils/StepCalculator';
export default function Counter() {
const data = useRef({
x: 0,
y: 0,
z: 0,
});
const startTime = new Date().getTime();
const [subscription, setSubscription] = useState(null);
const recentAccelerationData = useRef([]);//useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.
const steps = useRef([]);//useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.
const [stepCount, setStepCount] = useState(0);
const previousHighPointTimeRef = useRef(0);//this is the most recent time we had a spike in acceleration, we initialize it to 0 meaning none
const previousValue = useRef(0);//we process every 20 measurements, and this will be the 20th measurement from the previous time we processed data, start it at 0
//Android Docs: The data delay (or sampling rate) controls the interval at which sensor events are sent to your application via the onSensorChanged() callback method. The default data delay is suitable for monitoring typical screen orientation changes and uses a delay of 200,000 microseconds. You can specify other data delays, such as SENSOR_DELAY_GAME (20,000 microsecond delay), SENSOR_DELAY_UI (60,000 microsecond delay), or SENSOR_DELAY_FASTEST (0 microsecond delay).
// https://developer.android.com/guide/topics/sensors/sensors_overview#java
//Unable to find the default update interval, however the game play rate in Android is 20 millisecond intervals
const _slow = () => {
Accelerometer.setUpdateInterval(1000);
};
const _fast = () => {
Accelerometer.setUpdateInterval(100);
};
const _subscribe = () => {
(async () => {
await Accelerometer.isAvailableAsync(); //this seems to initialize the Accelerometer for Android
})(); //check if Acceleromoter is available
setStepCount(0);
recentAccelerationData.current=[];
steps.current=[];
setSubscription( //we set this state variable so later we can use it to unsubscribe
Accelerometer.addListener((accelerometerData) => {
data.current=accelerometerData;
const { x, y, z } = data.current;
//console.log("x: "+x+" y:"+y+" z:"+z);
let total_amount_xyz = Math.sqrt(x * x+ y*y + z*z) * 9.81;
console.log(new Date().getTime()+","+total_amount_xyz);
console.log("Steps: "+steps.current.length);
recentAccelerationData.current.push({time: new Date().getTime(), value: total_amount_xyz});
if (recentAccelerationData.current.length>20){
tallyLatestSteps();
}
})
);
};
const tallyLatestSteps= ()=>{
console.log("RecentAccelerationData: "+JSON.stringify(recentAccelerationData.current));
const {spikes, previousHighPointTime} = getSpikesFromAccelerometer({recentAccelerationData: recentAccelerationData.current, threshold: 11, previousValue: previousValue.current, previousHighPointTime: previousHighPointTimeRef.current});
previousValue.current = recentAccelerationData.current[recentAccelerationData.current.length-1].value;//store this for when we need to remember the last value
previousHighPointTimeRef.current = previousHighPointTime;
console.log("Spikes: "+JSON.stringify(spikes)+ " with length: "+spikes.length);
console.log("Steps before: "+steps.current.length);
steps.current=steps.current.concat(spikes);
setStepCount(steps.current.length);
console.log("Steps after: "+steps.current.length);
recentAccelerationData.current=[];
}
const _unsubscribe = () => {
tallyLatestSteps();//count the last remaining steps before unsubscribing
subscription && subscription.remove();
setSubscription(null);
};
useEffect(() => {
//_subscribe();
steps.current=[];
Accelerometer.setUpdateInterval(100);
return () => _unsubscribe();
}, []);
const { x, y, z } = data.current;
//console.log("x: "+x+" y:"+y+" z:"+z);
let total_amount_xyz = Math.sqrt(x * x+ y*y + z*z) * 9.81;
return (
<View style={styles.container}>
<Text style={styles.text}>
steps: {stepCount}
</Text>
<View style={styles.buttonContainer}>
<TouchableOpacity
onPress={subscription ? _unsubscribe : _subscribe}
style={styles.button}
>
<Text>{subscription ? 'Stop' : 'Start'}</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={_slow}
style={[styles.button, styles.middleButton]}
>
<Text>Slow</Text>
</TouchableOpacity>
<TouchableOpacity onPress={_fast} style={styles.button}>
<Text>Fast</Text>
</TouchableOpacity>
</View>
</View>
);
}
function round(n) {
if (!n) {
return 0;
}
return Math.floor(n * 100) / 100;
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 10,
},
text: {
textAlign: 'center',
},
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',
},
});