SDK for ReactNative
React Native documentation for Android/iOS apps
SDK Guide
This SDK will help you create your training app using heart rate sensors, the following steps cover the basic scenario of SDK usage.
SDK First steps
- You have to request an account.
- You must install and configure the SDK [Setup environment](#Setup environment)
- Read about the entities and rules
- User Entity
- Sensor Entity
- Training definition
- Create a User and set his information
- Create a Training
- Paint the Training
- Handle additional scenarios
User Entity
A User
- The person training using the app.
- Is the central Entity of the SDK, so we need to have a User in order to execute actions for or on his behalf.
- Has Basic information
- Has Physiological variables
Sensor Entity
A Sensor
- Is the device used to measure the Heart Rate
- It is supported if it meets the Heart Rate profile specification.
- A list of supported devices can be found here.
- Has these properties
- Belongs to the User
- A list of User sensors can be obtained
Training Entity
A Training:
- Is the exercise activity recorded with heart rate monitoring
- Has properties
- A User
- A Sensor
- A Training type
- Has records of
- Heart rate
- Steps/Jumps
- Cycling
- Has summaries of the training and from the records
Create a User and set his information
If you don't have a User, you can create a User
When you create a User you'll get a user_uuid,
- This uuid is required to perform every action over the user
With the user created you must set his basic info with updateInformation
Before starting any training for the User you must fill his physiological variables with updatePhysiologicalVariables
At this point the User profile is completed, you can update his profile later if required.
Now you must call getUser to retrieve the User data from the Server and store it on the local database.
Create a Training
Training requires:
- A User
- A training type
- A Sensor
The User was already created and filled in on Create a User and set his information
The Training Type: There are multiple available Training Types available, the procedure to select one for Training is as follows
- Get the Training types list with
getTrainingTypes
from UseRookTrainings - Select one from the returned list
- Get the Training types list with
The Sensor: The easiest way to get a Sensor is through the Trainer Hook:
- Start the Sensors discovery with
startScan
from useSensorScanner, this will retrieve a list of ``. - Select one from the list
discoveredSensors
- Start the Sensors discovery with
Now that we have the three elements User, Sensor, and Training Type
- Create a Training with useRookTrainer
- Connect the Sensor to the Training with
connectSensor
from useRookTrainer - Start the Training with
StartTraining
from useRookTrainer - The Hook will store the measurements in the database.
- You can read the useRookTrainer props for the Training Data that you want to display.
You can finish the Training with FinishAndUpload which will upload the training and upload it to the server.
When you want to show the User Trainings List you must:
- Get the User's Trainings with
retrieveUserTrainings
- Get the User's Trainings with
If you want to show the information of one of the returned Trainings you can get its information with
getTrainingInformation
SDKs
The SDK is divided into three packages available in npmjs
Setup environment
Required tools.
- Android Studio
- Xcode
- NodeJS
- React Native CLI
- Yarn
Install dependencies
- Install dependencies
yarn add yarn add react-native-device-info @nozbe/watermelondb react-native-ble-manager rook-core rook-bluetooth
Depending on your project dependencies, you may need to install the following manually:
yarn add @types/hoist-non-react-statics
yarn add @types/react
yarn add @babel/preset-env
Currently, Expo Go is not supported due to preference conflict with Expo and react-native-device-info, we're working on that.
If you have any issues installing the React-native-ble-manager, follow their instructions
- Set Android version requirements
buildscript {
ext {
...
buildToolsVersion = "31.0.0"
minSdkVersion = 21
compileSdkVersion = 31
targetSdkVersion = 31
kotlinVersion = '1.6.10'
...
}
dependencies {
...
classpath("com.android.tools.build:gradle:7.2.1")
...
}
RookMotion Core
RookMotion Core is a React Hooks library that will help you with the following tasks:
- For user:
- Create a new User and retrieve his uuid
- Set/Retrieve User's information
- Set/Retrieve User's physiological variables
- For trainings
- Discover nearby bluetooth devices
- Start a training with the selected device
- Store the training records and summaries
- Upload the training when finished
- Stats and history.
- Retrieve User's trainings from Server
- Retrieve User's historical training summaries
- Retrieve User's historical physiological variables
Hooks
Available hooks are:
- useRookUser - Manage User's creation/deletion, info, and variables.
- useRookPreference - Manage User preferences, i.e. last used Sensor
- useRookSensor - Manage User's sensors or devices
- useRookTrainer - Manage the training flow
- useRookTraings - Manage the training types and executed by the User
- useRookSummaries - Get training summaries types
- useRookRewards - Get rewards (RookPoints) obtained for training
- useRookTrainingUploader - Upload stored trainings
Configuration
RookMotion SDKs require auth credentials. If you don't have yours, please read this.
- Add RookWrapper provider in the highest position of your components tree.
- RookWrapper handles the RookMotion auth credentials for the module.
import { RookWrapper } from 'rook-core';
...
<RookWrapper
config={{
authorization: 'YOUR-BEARER-TOKEN',
tokenLevel: 'YOUR-CLIENT-TOKEN',
url: 'BASE URL SANDBOX OR PRODUCTION',
}}>
<YOUR-COMPONENTS />
</RookWrapper>
useRookUser
Description Handles the User creation/deletion, User’s Sensors, Info and Physiological variables.
Definition
`useRookUser: () => useRookUserTools`
Import
import {useRookUser} from 'rook-core';
Return
- @return bool ready - Indicates the hook is initialized and ready to use.
User
Create User
registerUserInApi: (props: registerUserInApiProps) => Promise<string>;
- Creates a new User in RookMotion Server
- Returns a user_uuid required to execute any User operation
- If the user email already exists, it only returns user_uuid
- @param props registerUserInApiProps.
- @returns string - user_uuid
Props
registerUserInApiProps.email
: user_email
Example
import React, {useState} from 'react';
import {StyleSheet, useColorScheme, Text, TextInput, Button} from 'react-native';
import {Colors} from 'react-native/Libraries/NewAppScreen';
import {useRookUser} from 'rook-core';
export const RegisterUser = () => {
const isDarkMode = useColorScheme() === 'dark';
const [email, setEmail] = useState('');
const {registerUserInApi} = useRookUser();
const verifyStatus = async (): Promise<any> => {
if (!email.trim()) {
console.log( 'Enter a valid email')
return;
}
console.log('signing up')
try {
const response = await registerUserInApi({email});
if (response) {
console.log(`User was created correctly with uuid: ${response}`)
} else {
console.log("Error while creating user")
}
} catch (error) {
console.log("Error while creating user")
}
};
return (
<View>
<Text
fontSize="xl"
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Register User
</Text>
<Input
autoCapitalize="none"
autoCorrect={false}
keyboardType="email-address"
placeholder="user email"
onChangeText={text => setEmail(text)}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
<View>
<Button title = 'Register User's onPress={verifyStatus} />
</View>
</View>
);
};
const styles = StyleSheet.create({
textCenter: {
textAlign: 'center',
marginBottom: 8,
},
});
Delete User
deleteAccount: (props: deleteAccountProps) => Promise<boolean>;
- Delete user on RookMotion Server
- @param props {deleteAccountProps}.
- @returns True if the account was deleted or if provided uuid does not exist, false on error.
props.user_uuid
: user_uuid
This will PERMANENTLY delete the user Entity, its information, and trainings.
This is used Use when your user has requested to delete his information permanently.
After successful deletion, clean up the local data:
- logout() on useRookMotionSession() hook.
- Clean up any remaining data that you have stored.
Example
import React, {useState} from 'react';
import {StyleSheet, useColorScheme, Text, TextInput, Button, View} from 'react-native';
import {Colors} from 'react-native/Libraries/NewAppScreen';
import {useRookUser} from 'rook-core';
export const DeleteAccount = () => {
const isDarkMode = useColorScheme() === 'dark';
const [uuid, setUUID] = useState('');
const {deleteAccount} = useRookUser();
const verifyStatus = async (): Promise<any> => {
if (!uuid.trim()) {
console.log('Enter a valid email')
return;
}
console.log('eliminando');
try {
const response = await deleteAccount({user_uuid: uuid});
if (response) {
console.log('the user account was deleted')
} else {
console.log('cannot delete the user account')
}
} catch (error) {
console.log("We can't verify your uuid");
}
};
return (
<View>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Delete account
</Text>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
User uuid
</Text>
<TextInput
autoCapitalize="none"
autoCorrect={false}
keyboardType="email-address"
placeholder="user uuid"
onChangeText={text => setUUID(text)}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
<View>
<Button title = 'Delete' onPress={verifyStatus} />
</View>
</View>
);
};
const styles = StyleSheet.create({
textCenter: {
textAlign: 'center',
marginBottom: 8,
},
});
User status
getUserStatusFromApi: (props: getUserStatusFromApiProps) => Promise<UserStatus>;
- Check if the user email exists on RookMotion Server
- If the user exists, it retrieves user’s info inside UserStatus
- @param props {@link getUserStatusFromApiProps}.
- @returns {@link UserStatus}.
props.email
: user_emailUserStatus.user_uuid
: user_uuidUserStatus.active
: True if user is registered in web service.UserStatus.profile_filled_at
: Timestamp when the user filled in his basic info
Before creating a user, you can verify if the user already exists with getUserStatusFromApi.
You can find the user_uuid from a user email already registered using getUserStatusFromApi
UserStatus.profile_filled_at
is intended to detect if you need to ask the user to fill in or update his information.
Example
import React, {useState} from 'react';
import {StyleSheet, useColorScheme, Text, TextInput, Button} from 'react-native';
import {Colors} from 'react-native/Libraries/NewAppScreen';
import {useRookUser} from 'rook-core';
export const UserStatus = () => {
const isDarkMode = useColorScheme() === 'dark';
const [email, setEmail] = useState('');
const {getUserStatusFromApi} = useRookUser();
const verifyStatus = async (): Promise<any> => {
if (!email.trim()) {
console.log('Enter a valid email');
return;
}
console.log('consultando', duration: 3000);
try {
const response = await getUserStatusFromApi({email});
if (response.active) {
console.log(`The user exists with uuid: ${response.user_uuid}`);
} else {
console.log('User doesn't exists);
}
} catch (error) {
console.log("We can't verify your email");
}
};
return (
<View>
<Text
fontSize="xl"
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Get user status
</Text>
<Input
autoCapitalize="none"
autoCorrect={false}
keyboardType="email-address"
placeholder="user email"
onChangeText={text => setEmail(text)}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
<View>
<Button title = 'Verify Status' onPress={verifyStatus} />
</View>
</View>
);
};
const styles = StyleSheet.create({
textCenter: {
textAlign: 'center',
marginBottom: 8,
},
});
Get user from Server
getUser: (props: getUserProps) => Promise<User>;
Retrieves user information and physiological variables
Form RookMotion Server as first attempt and stores the info on local database
From local database when internet is not available or the requests fails
@param props {@link getUserProps}
@returns A {User} instance associated with provided uuid.
@throws error if the information is not available from any source
Example
import React, {useState} from 'react';
import {StyleSheet, useColorScheme, Text, TextInput, Button, View} from 'react-native';
import {Colors} from 'react-native/Libraries/NewAppScreen';
import {useRookUser} from 'rook-core';
export const UserInformation = () => {
const isDarkMode = useColorScheme() === 'dark';
const [id, setID] = useState('');
const {getUser} = useRookUser();
const verifyStatus = async (): Promise<any> => {
if (!id.trim()) {
console.log('Enter a valid variables')
return;
}
console.log('updating');
try {
const response = await getUser({user_uuid: id});
if (response) {
console.log(`User has the uuid: ${response.user_uuid} and email ${response.email}`);
} else {
console.log('We cannot get the user');
}
} catch (error) {
console.log('We cannot get the user');
}
};
return (
<View>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
View User
</Text>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
user uuid
</Text>
<TextInput
keyboardType="numeric"
placeholder="80"
onChangeText={text => setID(text)}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
<View>
<Button title = 'View User's onPress={verifyStatus} />
</View>
</View>
);
};
const styles = StyleSheet.create({
textCenter: {
textAlign: 'center',
marginBottom: 8,
},
});
Get user from local database
getUserFromDatabase: () => Promise<User>;
- Retrieves user information and physiological variables from local database
- @returns {@link User}.
- @throws error if information is not available
- user: user_definition
Similar to getUser but from local database only
Make sure to call logout() on useRookMotionSession() hook, every time the user logs out from your app, this will clean the User information from database. otherwise, the info will remain in the database.
Example
import React, {useState} from 'react';
import {StyleSheet, useColorScheme, Text, TextInput, Button, View} from 'react-native';
import {Colors} from 'react-native/Libraries/NewAppScreen';
import {useRookUser} from 'rook-core';
export const UserInformationFromDatabase = () => {
const isDarkMode = useColorScheme() === 'dark';
const {getUserFromDatabase} = useRookUser();
const getInformationFromDatabase = async (): Promise<any> => {
try {
const response = await getUserFromDatabase();
if (response) {
console.log(`the user has the next uuid: ${response.user_uuid} and email ${response.email}`);
} else {
console.log('No user in database');
}
} catch (error) {
console.log("getUserFromDatabase error: ${error}");
}
};
return (
<View>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
View User in Database
</Text>
<View>
<Button title = 'View User' onPress={getInformationFromDatabase} />
</View>
</View>
);
};
const styles = StyleSheet.create({
textCenter: {
textAlign: 'center',
marginBottom: 8,
},
});
User information
User available information: User information
Update user information
updateInformation: (props: updateInformationProps) => Promise<User>;
- Updates User's information in RookMotion Server
- Updates User's information in local database
- @param props {@link updateInformationProps}.
- @returns The new {@link User} with the updates applied.
props.user_uuid
: user_uuidprops.updateInformationProps
: user_information
If internet is not available, it will update information only on local database. When the internet is available, you must try to push the information again.
Example
import React, {useState} from 'react';
import {Colors} from 'react-native/Libraries/NewAppScreen';
import {StyleSheet, useColorScheme, Text, Input, Button} from 'react-native';
import {useRookUser} from 'rook-core';
export const UpdateUserInformation = () => {
const isDarkMode = useColorScheme() === 'dark';
const [data, setData] = useState({
uuid: '',
name: '',
pseudonym: '',
lastName1: '',
lastName2: '',
birthday: new Date().toString(),
sex: '',
});
const {updateInformation} = useRookUser();
const verifyStatus = async (): Promise<any> => {
if (
!data.uuid.trim() ||
!data.name.trim() ||
!data.pseudonym.trim() ||
!data.lastName1.trim()
) {
console.log( 'Enter a valid variables');
return;
}
console.log('updating');
try {
const response = await updateInformation({
user_uuid: data.uuid,
information: {
name: data.name,
pseudonym: data.pseudonym,
last_name_1: data.lastName1,
last_name_2: data.lastName2 || '---',
birthday, // format: YYYY/MM/DD
sex: data.sex === 'male' ? 'male' : 'female',
},
});
if (response) {
console.log( `the user was register updated with the next uuid: ${response.user_uuid}`);
} else {
toast.show('We cannot update de user');
}
} catch (error) {
console.log("We can't update the information");
}
};
return (
<View>
<Text
fontSize="xl"
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Update Variables
</Text>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
user uuid
</Text>
<TextInput
keyboardType="numeric"
placeholder="80"
onChangeText={text => setData(prev => ({...prev, uuid: text}))}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Name
</Text>
<TextInput
placeholder="Rook"
onChangeText={text => setData(prev => ({...prev, name: text}))}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Pseudonym
</Text>
<TextInput
placeholder="80"
onChangeText={text => setData(prev => ({...prev, pseudonym: text}))}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Last Name 1
</Text>
<TextInput
keyboardType="numeric"
placeholder="80"
onChangeText={text => setData(prev => ({...prev, lastName1: text}))}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Last Name 2
</Text>
<TextInput
keyboardType="numeric"
placeholder="80"
onChangeText={text => setData(prev => ({...prev, lastName2: text}))}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Birthday
</Text>
<TextInput
keyboardType="numeric"
placeholder="80"
onChangeText={text => setData(prev => ({...prev, birthday: text}))}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
<View
justifyContent="center"
alignItems="center"
space={4}
marginTop={4}>
<Text
fontSize="md"
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Female or male
</Text>
<TextInput
placeholder="80"
onChangeText={text => setData(prev => ({...prev, sex: text}))}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
</View>
;
<View>
<Button title = 'Update User' onPress={verifyStatus} />
</View>
</View>
);
};
const styles = StyleSheet.create({
textCenter: {
textAlign: 'center',
marginBottom: 8,
},
});
User Physiological variables
Available variables are: user_physiological_variables_definition
Physiological variables are required so that RookMotion can perform training calculations for each user. If none are provided, training calculations aren't guaranteed to be correct.
Every time physiological variables are updated, a new entry is made on RookMotion Database instead or replaced, so It's possible to retrieve a historical list of variables.
Set User Physiological variables
updatePhysiologicalVariables: (props: updatePhysiologicalVariablesProps) => Promise<User>;
Set User's {@link UserPhysiologicalVariables} in RookMotion Server.
A new entry is generated on each request so that historical variables are created related to RookMotion Server.
Stores the variables on the local Database as the newest values; no history is created on the local database.
@param props {UserPhysiologicalVariables}.
@returns {user} with the updated variables applied.
props.user_uuid
: user_uuidprops.physiological_variables
: UserPhysiologicalVariables
If internet is not available, it will set the information only on local database. When the internet is available, you must try to push the data again.
Example
import React, {useState} from 'react';
import {StyleSheet, useColorScheme, Text, TextInput, Button, View} from 'react-native';
import {Colors} from 'react-native/Libraries/NewAppScreen';
import {useRookUser} from 'rook-core';
export const UpdateUserVariables = () => {
const isDarkMode = useColorScheme() === 'dark';
const [data, setData] = useState({
user: '',
height: '',
weight: '',
restingHR: '',
});
const {updatePhysiologicalVariables} = useRookUser();
const verifyStatus = async (): Promise<any> => {
if (
!data.user.trim() ||
Number.isNaN(Number(data.height)) ||
Number.isNaN(Number(data.weight)) ||
Number.isNaN(Number(data.restingHR))
) {
console.log('Enter a valid variables');
return;
}
console.log('updating');
try {
const response = await updatePhysiologicalVariables({
user_uuid: data.user,
physiological_variables: {
weight: data.weight,
height: data.height,
resting_heart_rate: data.restingHR,
},
});
if (response) {
console.log(`the user was register correctly with the next uuid: ${response.user_uuid}`);
} else {
console.log('We cannot register de user');
}
} catch (error) {
console.log("We can't update variables");
}
};
return (
<View>
<Text
fontSize="xl"
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Update Variables
</Text>
<Text
fontSize="md"
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
user uuid
</Text>
<TextInput
keyboardType="numeric"
placeholder="80"
onChangeText={text => setData(prev => ({...prev, user: text}))}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Weight
</Text>
<TextInput
keyboardType="numeric"
placeholder="80"
onChangeText={text =>
setData(prev => ({...prev, weight: Number(text).toString()}))
}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Height
</Text>
<TextInput
keyboardType="numeric"
placeholder="80"
onChangeText={text =>
setData(prev => ({...prev, height: Number(text).toString()}))
}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Resting HR
</Text>
<TextInput
keyboardType="numeric"
placeholder="80"
onChangeText={text =>
setData(prev => ({...prev, restingHR: Number(text).toString()}))
}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
<View>
<Button title = 'Update User's onPress={verifyStatus} />
</View>
</View>
);
};
const styles = StyleSheet.create({
textCenter: {
textAlign: 'center',
marginBottom: 8,
},
});
Retrieve User Physiological variables
getPhysiologicalVariablesByPeriod: (props: getPhysiologicalVariablesByPeriodProps) => Promise<PhysiologicalVariablesByPeriod>;
- Retrieves {@link getPhysiologicalVariablesByPeriodProps} between a range of dates in the format YYYY-MM-DD.
- Form RookMotion Server as first attempt and stores the last values on local database
- @param props {@link getPhysiologicalVariablesByPeriodProps}.
- @returns {@link PhysiologicalVariablesByPeriod}.
props.user_uuid
: user_uuidprops.from_date
: Starting date of the period (YYYY-MM-DD)props.to_date
: Ending date of the period (YYYY-MM-DD)props.page
: The page to fetchprops.type
: PhysiologicalVariableType
To get the user most recent variables, you must use the variables with the newest timestamp.
Each call to this method retrieves one variable type (weight, height, or resting heart rate). If you want the three of them, you'll need to call the method three times.
Example
import React, {useState} from 'react';
import {Colors} from 'react-native/Libraries/NewAppScreen';
import {useColorScheme, StyleSheet, View, Text, Button, TextInput} from 'react-native';
import {useRookUser, PhysiologicalVariableType} from 'rook-core';
export const UserVariablesInPeriod = () => {
const isDarkMode = useColorScheme() === 'dark';
const [date, setDate] = useState(');
const [secondDate, setSecondDate] = useState(');
const [start, setStart] = useState('');
const [end, setEnd] = useState('');
const [id, setID] = useState('');
const [data, setData] = useState<any>({});
const {getPhysiologicalVariablesByPeriod} = useRookUser();
const verifyVariables = async (): Promise<any> => {
try {
const props = {
user_uuid: id,
from_date: start, // Format: YYYY-MM-DD
to_date: end, // Format: YYYY-MM-DD
page: 1,
};
console.log('fetching . . .');
const [w, h, r] = await Promise.all([
getPhysiologicalVariablesByPeriod({
...props,
type: PhysiologicalVariableType.WEIGHT,
}),
getPhysiologicalVariablesByPeriod({
...props,
type: PhysiologicalVariableType.HEIGHT,
}),
getPhysiologicalVariablesByPeriod({
...props,
type: PhysiologicalVariableType.RESTING_HEART_RATE,
}),
]);
console.log(w.data, h.data, r.data);
setData({
weight: w.data[0]?.value || 0,
height: h.data[0]?.value || 0,
hr: r.data[0]?.value || 0,
});
} catch (error) {
console.log('We cannot show the info')
}
};
return (
<View>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Get variables in period
</Text>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
user uuid
</Text>
<TextInput
keyboardType="numeric"
placeholder="80"
onChangeText={text => setID(text)}
style={{color: isDarkMode ? Colors.white : Colors.black}}
/>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Starting date
</Text>
<TextInput
onChangeText={text => setDate(text)}
/>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
End date
</Text>
<TextInput
onChangeText={endDate => setSecondDate(endDate)}
/>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
weight: {data.weight}
</Text>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
height: {data.height}
</Text>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
hr: {data.hr}
</Text>
<View>
<Button
title = 'Verify Status'
onPress={verifyVariables}
/>
</View>
</View>
);
};
const styles = StyleSheet.create({
textCenter: {
textAlign: 'center',
marginBottom: 8,
},
});
User Indexes
User indexes have no direct usage for you, but are required to be keep on database for the training calculations.
Retrieve User Indexes
syncIndexes: (props: syncIndexesProps) => Promise<IndexesSyncResult>;
- Retrieve user indexes from RookMotion Server
- Stores the indexes in Database.
- @param props {syncIndexesProps}.
- @returns {IndexesSyncResult}.
props.user_uuid
: user_uuid
Sync user indexes periodically to keep them updated, ideally before starting a training.
Sync user indexes when the user updates their {@link UserPhysiologicalVariables} or {@link UserAttributes}
Definitions
user_definition
The User
user_uuid
: user_uuid_definition.email
: user_email_definition.url_image
(string): url_image User's profile picture link.information
: user_information_definition.physiological_variables
: user_physiological_variables.
user_uuid_definition
user_uuid
(string): Unique user identifier UUID4, it is assigned by RookMotion Server on user creation.
user_email_definition
user_email
(string): User's email; it's unique, according to RFC 5322.
user_information_definition
information.name
: User's nameinformation.pseudonym
: User's pseudonym or nicknameinformation.last_name_1
: User's first last nameinformation.last_name_2
: User's second last nameinformation.birthday
: User's birthday (YYYY-MM-DD)information.sex
: User's sex (male || female)
sex and birthday are important for training calculations, so real values must be used
user_physiological_variables_definition
weight
(string): User's weight in kg. (Range: 40-180).height
(string): User's height in cm. (Range: 120-220).resting_heart_rate
(string): User's resting_heart_rate, (Range: 40-99) (Default: 60).
Physiological variables are required so that RookMotion can perform training calculations for each user. If none are provided, training calculations aren't guaranteed to be correct.
user_physiological_variables_types_definition
PhysiologicalVariableType.WEIGHT
(enum element): Request or returned array are weight valuesPhysiologicalVariableType.HEIGHT
(enum element): Request or returned array are height valuesPhysiologicalVariableType.RESTING_HEART_RATE
(enum element): (enum element): Request or returned array are rest_hr values
user_historical_physiological_variables_definition
PhysiologicalVariablesByPeriod.type
: PhysiologicalVariableType.PhysiologicalVariablesByPeriod.data
: array(PhysiologicalVariable).PhysiologicalVariablesByPeriod.links
: Global.Links: Pagination page url.PhysiologicalVariablesByPeriod.meta
: Global.Meta: Request metadata, includes pagination counter.
useRookSensor
Description
Handles the training functionalities and Manages the User's sensors.
- Add User's sensors to Server
- Retrieve from Server
Definition
`useRookSensors: () => useRookSensorsTools;`
Import
import {useRookSensor} from 'rook-core';
Return
ready
- Indicates if the hook is ready.
User Sensors
Sensors are stored in RookMotion Server related to a user. They are required for trainings.
Add Sensor to user
saveSensor: (props: saveSensorProps) => Promise<Sensor>;
Add a Sensor to the user on the RookMotion Server
props
: Indicates the user and the Sensorprops.userUUID
: user_uuidprops.name
: sensor_nameprops.mac
: sensor_mac
Example
import React, {useState} from 'react';
import {
SafeAreaView,
StyleSheet,
Text,
TextInput,
TouchableHighlight,
} from 'react-native';
import {useRookSensors} from 'rook-core';
export const Sensors = () => {
const {ready, saveSensor} = useRookSensors();
const [userUUID, setUserUUID] = userState('');
const [sensor, setSensor] = useState({
sensor_name: ''
sensor_mac: ''
});
const keepSensor = async (): Promise<any> => {
try {
const resp = await saveSensor({
userUUID: userUUID,
name: sensor.sensor_name,
mac: sensor.sensor_mac,
});
if (resp) {
console.log('saved successfully');
}
else {
console.log('could not save the sensor');
}
}
catch (error) {
console.log(error)
}
};
return (
<SafeAreaView>
<TouchableHighlight onPress={keepSensor}>
<Text>Save</Text>
</TouchableHighlight>
<Text>User uuid</Text>
<TextInput
style={ styles.input }
onChangeText={text => setUserUUID(text)}
/>
<Text>Sensor Name</Text>
<TextInput
style={{...styles.input, color: colors.text}}
onChangeText={text =>
setSensor((prev: any) => ({...prev, sensor_name: text}))
}
/>
<Text>Sensor MAC</Text>
<TextInput
style={{...styles.input, color: colors.text}}
onChangeText={text =>
setSensor((prev: any) => ({...prev, sensor_mac: text}))
}
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
input: {
marginTop: 10,
height: 50,
borderWidth: 1,
borderStyle: 'solid',
borderRadius: 5,
},
});
Get user sensors
getSensors: (props: getSensorsProps) => Promise<SensorsFetchResponse>;
- Retrieve user sensors from RookMotion Server
- @return
SensorsFetchResponse
props.userUUID
: user_uuidprops.page
: Page for the API request, commonly it's limited to one page, so use 1.SensorsFetchResponse.data
: Array(sensor)SensorsFetchResponse.links
: Request pagination linkSensorsFetchResponse.meta
: Request response metadata.
Example
import React, {useState} from 'react';
import {
FlatList,
SafeAreaView,
StyleSheet,
Text,
TextInput,
TouchableHighlight,
} from 'react-native';
import {Sensor, useRookSensors} from 'rook-core';
export const Sensors = () => {
const {ready, getSensors} = useRookSensors();
const [userUUID, setUserUUID] = userState('');
const [data, setData] = useState<Sensor[]>([]);
const handleView = async (): Promise<any> => {
if (!ready) {
console.log('no ready');
return;
}
const resp = await getSensors({
page: 1,
userUUID: userUUID,
});
setData(resp ? resp.data : []);
};
return (
<SafeAreaView>
<TouchableHighlight onPress={handleView}>
<Text>Ver sensores</Text>
</TouchableHighlight>
<Text>User uuid</Text>
<TextInput
style={ styles.input }
onChangeText={text => setUserUUID(text)}
/>
<FlatList
data={data}
keyExtractor={item => item.sensor_uuid}
renderItem={({item}) => (
<Text>
{item.sensor_uuid} - {item.sensor_name}
</Text>
)}
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
input: {
marginTop: 10,
height: 50,
borderWidth: 1,
borderStyle: 'solid',
borderRadius: 5,
},
});
Remove Sensor from user
deleteSensor: (props: deleteSensorProps) => Promise<boolean>;
- Remove a Sensor from the user on the RookMotion Server
props
: Indicates the user and the Sensor
props.userUUID
: user_uuid 2props.name
: sensor_uuid
Example
import React, { useState } from 'react'
import { SafeAreaView, Button } from 'react-native'
import { useRookPreference } from 'rook-core'
export const Component = () => {
const { removeLastUsedSensor } = useRookPreference()
const deleteLastSensor = (): Promise<any> => {
try {
const response = await removeLastUsedSensor();
if (response) {
console.log('removed successfully');
}
else {
console.log('could not remove the Sensor');
}
}
catch(error) {
console.log(error);
}
}
return (
<SafeAreaView>
<Button title = 'remove last Sensor' onPress={ deleteLastSensor } />
</SafeAreaView>
)
}
Definitions
sensor_uuid_definition
sensor_uuid
(string): Unique identifier UUID4, it is assigned by RookMotion Server on Sensor creation.
sensor_name_definition
sensor_name
(string): Sensor discoverable name usually (brand+ID) e.g. RookC2 123456 it's defined by manufacturer.
sensor_mac_definition
sensor_mac
(string): Sensor Bluetooth MAC. Defined by the manufacturer.
user_sensor_definition
User Sensor is similar to Sensor but comes from the Server and has the Sensor to user relation.
sensor_uuid
: sensor_uuid_definition.sensor_name
sensor_name_definition.sensor_mac
sensor_mac_definition.ownership_type
(string): Sensor ownership (owned || borrowed) handled by RookMotion Server based on first owner of the Sensor.updated_at
(string) The date when the Sensor was assigned to the user.
useRookPreference
Description This hook handles User's preferences
- Last used Sensor
- @return bool ready - Indicates the hook is initialized and ready to use.
Definition
`useRookPreferences: () => useRookPreferencesTools;`
Import
import {useRookPreferences} from 'rook-core';
Preference: Last Used Sensor
Last used Sensor is a preference useful to start trainings without asking again for the user to select a Sensor.
Set Last Used Sensor
setLastUsedSensor: (props: setLastUsedSensorProps) => Promise<boolean>
Stores a Sensor as a preference.
props: setLastUsedSensorProps
: setLastUsedSensorPropsprops.setLastUsedSensorProps
: Sensor
Get Last Used Sensor
getLastUsedSensor: () => Promise<LastUsedSensor>;
- Retrieves the last Sensor used
- returns Sensor
- Sensor: Sensor
Example
import React, { useState, useEffect } from 'react'
import { SafeAreaView, Text, Input, Button } from 'react-native'
import { LastUsedSensor, useRookPreference } from 'rook-core'
export const Component = () => {
const [sensor, setSensor] = useState<LastUsedSensor>({
sensor_uuid: ''
sensor_mac: ''
sensor_name: ''
})
const { ready, getLastUsedSensor } = useRookPreference();
useEffect(() => {
if (ready) fetchSensor();
}, [ready])
const fetchSensor = async (): Promise<any> => {
try {
const response = await getLastUsedSensor();
setSensor( response );
}
catch(error) {
console.log(error);
}
}
return (
<SafeAreaView>
<Text>Sensor uuid: { sensor.sensor_uuid }</Text>
<Text>Sensor MAC: { sensor.sensor_mac }</Text>
<Text>Sensor name: { sensor.sensor_name }</Text>
</SafeAreaView>
)
}
Preference: Remove Last Used Sensor
removeLastUsedSensor: () => Promise<boolean>;
- Removes the lastUsedSensor from preferences
Preference: Clear all preferences
clearPreferences: () => Promise<boolean>;
- Clears the collection of preferences
Example
import React, { useState } from 'react'
import { SafeAreaView, Button } from 'react-native'
import { useRookPreference } from 'rook-core'
export const Component = () => {
const { clearPreferences } = useRookPreference()
const deleteLastSensor = (): Promise<any> => {
try {
const response = await clearPreferences();
if (response) {
console.log('removed successfully');
}
else {
console.log('could not remove the collection');
}
}
catch(error) {
console.log(error);
}
}
return (
<SafeAreaView>
<Button title = 'remove the collection' onPress={ saveSensor } />
</SafeAreaView>
)
}
Definitions
sensor_definition
sensor_uuid
: sensor_uuid_definition.sensor_mac
: sensor_mac_definition.sensor_name
: sensor_name_definition.
Sensor objects are discovered by the hook useSensorScanner from the rook-bluetooth
package
Example
import React, { useState } from 'react'
import { SafeAreaView, Text, Input, Button } from 'react-native'
import { LastUsedSensor, useRookPreference } from 'rook-core'
export const Component = () => {
const [sensor, setSensor] = useState<LastUsedSensor>({
sensor_uuid: ''
sensor_mac: ''
sensor_name: ''
})
const { setLastUsedSensor } = useRookPreference();
const saveSensor = async (): Promise<any> => {
try {
const response = await setLastUsedSensor( sensor );
if (response) {
console.log('saved successfully');
}
else {
console.log('could not save the sensor');
}
}
catch(error) {
console.log(error);
}
}
return (
<SafeAreaView>
<Text>Sensor uuid</Text>
<Input onChangeText={
text => setSensor(prev => ({ ...prev, sensor_uuid: text }))
}
/>
<Text>Sensor MAC</Text>
<Input onChangeText={
text => setSensor(prev => ({ ...prev, sensor_mac: text }))
}
/>
<Text>Sensor name</Text>
<Input onChangeText={
text => setSensor(prev => ({ ...prev, sensor_name: text }))
}
/>
<Button title = 'Save' onPress={ saveSensor } />
</SafeAreaView>
)
}
useRookTrainings
Description
This hook handles
The User's trainings
- Information
- Deletion
The available trainings types.
props
: Training Configuration
props.bluetoothConfig.emitter
: Notify events during the training:BleManagerDiscoverPeripheral
BleManagerStopScan
BleManagerDisconnectPeripheral
BleManagerDidUpdateValueForCharacteristic
props.bluetoothConfig.showAlerts
: Show alerts notifications- `props.trainingConfig.trainingType
props.trainingConfig.trainingType.training_type_uuid
: training_type_uuid assigned by RookMotion Server.props.trainingConfig.trainingType.training_name
: training_type_name assigned by RookMotion Server.props.trainingConfig.trainingType.use_steps
: Indicates if the training type records steps.props.trainingConfig.trainingType.use_heart_rate
: Indicates if the training records heart rate.props.trainingConfig.trainingType.use_gps
: Indicates if the gps records heart rate.props.trainingConfig.trainingType.use_cycling
: Indicates if the training records cycling
props.trainingConfig.withBicycleRecords
: Indicates if the training cycling records .
To perform a training, an existing user must be already on local using: useRookUser.getUser()
Definition
`useRookTrainer = (props: useRookTrainerProps): useRookTrainerTools`
Import
import { useRookTrainer } from 'rook-core'
Return
ready: boolean
: Indicates if the hook is ready.duration: number
: Current training duration (seconds)start
: UTC datetime when the training startedhrDerivedData: RMHrDerivedRecord;
Heart rate records.RMHrDerivedRecord.timestamp
: UTC datetime of the HR measurementRMHrDerivedRecord.heart_rate
: Heart rate measurement record (bpm)RMHrDerivedRecord.calories
: Calories counter record (kcal)RMHrDerivedRecord.effort
: Heart Rate Effort record (%)RMHrDerivedRecord.heart_rate_variability
: Indicates the heart_rate_variability of the user
batteryLevel: number
: Sensor battery levelsteps: StepsData;
Steps records.StepsData.steps
: Steps counter (steps)StepsData.cadence
: Steps cadence (steps/min)
// For remote classes only
remoteUsers
: List of users training in the same remote classremoteRemainSeconds
: Remaining seconds of the remote classclassFinished
: Has the remote class finished?userBanned
: Is the user banned or removed from the remote class?
Training actions
Connect Sensor
connectSensor: (sensor: BLPeripheral) => Promise<boolean>;
- Connects to Sensor to perform a training
- Uploads the Sensor to RookMotion Server using saveSensor
- @param props.sensor (BLPeripheral)
- @return success (bool)
props.sensor
: Sensor to connect returned byuseRookScanner.startScan
anduseRookScanner.discoveredSensors
fromrook-bluetooth
Must be called before to start a training
Start training
startTraining: () => Promise<boolean>;
- Starts the training previously initialized
Additionally to the training configuration, a connection with a Sensor had to be established before with connectSensor
Re-start training
startPendingTraining: (props: startPendingTrainingProps) => Promise<boolean>;
- Re-starts an unfinished training
props.start
: Datetime key of the training to be resumed.
Pause training
pauseTraining: () => void;
- Pause the current training.
Resume training
resumeTraining: () => void;
- Resume a paused training
Cancel training
cancelTraining: () => Promise<boolean>;
-
- Cancel the current training and clears the related data.
If a training is canceled all the training information will be lost.
Finish training
finishTraining: () => Promise<void>;
- Finish the current training
- A training finish time is stored on database
This will finish the training, but won't be uploaded. A call to uploadTrainings will be required to upload the training.
Finish training and upload
finishAndUploadTraining: () => Promise<boolean>;
- Finish the current training
- A training finish time is stored on database
- The training is uploaded to RookMotion Server
Additional measurements
Add cycling record
addBicycleRecord: (props: addBicycleRecordProps) => Promise<boolean>
- Insert a cycling record for the current timestamp to the training
- Useful for Apps with bicycle measurements
props.cadence
: Current cycling cadence (rpm)props.resistance
: Current cycling resistanceprops.power
: Current cycling power (W)
Definitions
training_stages_definition
A training has the following stages:
- The training is started when [Start training](#Start training) is executed.
start
property is set to the start timeend
property is null.uploaded_at
property is null
- A training is Paused or unfinished when [Pause training](#Pause training) is executed or the training is interrupted
start
property was set to the start timeend
property is null.uploaded_at
property is null
- A training is Resumed when [Resume training](#Resume training) is executed
start
property was set to the start timeend
property is null.uploaded_at
property is null
- The training is finished when [Finish training](#Finish training) is executed
start
property was set in the previous stagesend
property is set to the finished timeuploaded_at
property is null
- The training is uploaded when Upload trainings is executed
start
property was set in the previous stages.end
property was set in the previous stages.uploaded_at
property is null
training_summary_type
Every training has records obtained each certain time, and we create summaries of that records such like:
- hr_max
- hr_min
- effort_max
- effort_avg
- training_duration
A training summary type is composed of
name
(string): e.g. hr_maxuuid
(string): Unique summary type identifier UUID4, it is assigned by RookMotion Server, and they're fixed.
useRookTrainer
Description
This hook handles the training functionalities:
Bluetooth Sensor interactions
Training measurements storage
Training summaries generation and storage
props
: Training Configuration
props.bluetoothConfig.emitter
: Notify events during the training:BleManagerDiscoverPeripheral
BleManagerStopScan
BleManagerDisconnectPeripheral
BleManagerDidUpdateValueForCharacteristic
props.bluetoothConfig.showAlerts
: Show alerts notifications- `props.trainingConfig.trainingType
props.trainingConfig.trainingType.training_type_uuid
: training_type_uuid assigned by RookMotion Server.props.trainingConfig.trainingType.training_name
: training_type_name assigned by RookMotion Server.props.trainingConfig.trainingType.use_steps
: Indicates if the training type records steps.props.trainingConfig.trainingType.use_heart_rate
: Indicates if the training records heart rate.props.trainingConfig.trainingType.use_gps
: Indicates if the gps records heart rate.props.trainingConfig.trainingType.use_cycling
: Indicates if the training records cycling
props.trainingConfig.withBicycleRecords
: Indicates if the training cycling records .
To perform a training, an existing user must be already on local using: useRookUser.getUser()
Definition
`useRookTrainer = (props: useRookTrainerProps): useRookTrainerTools`
Import
import { useRookTrainer } from 'rook-core'
Return
ready: boolean
: Indicates if the hook is ready.duration: number
: Current training duration (seconds)start
: UTC datetime when the training startedhrDerivedData: RMHrDerivedRecord;
Heart rate records.RMHrDerivedRecord.timestamp
: UTC datetime of the HR measurementRMHrDerivedRecord.heart_rate
: Heart rate measurement record (bpm)RMHrDerivedRecord.calories
: Calories counter record (kcal)RMHrDerivedRecord.effort
: Heart Rate Effort record (%)RMHrDerivedRecord.heart_rate_variability
: Indicates the heart_rate_variability of the user
batteryLevel: number
: Sensor battery levelsteps: StepsData;
Steps records.StepsData.steps
: Steps counter (steps)StepsData.cadence
: Steps cadence (steps/min)
// For remote classes only
remoteUsers
: List of users training in the same remote classremoteRemainSeconds
: Remaining seconds of the remote classclassFinished
: Has the remote class finished?userBanned
: Is the user banned or removed from the remote class?
Training actions
Connect Sensor
connectSensor: (sensor: BLPeripheral) => Promise<boolean>;
- Connects to Sensor to perform a training
- Uploads the Sensor to RookMotion Server using saveSensor
- @param props.sensor (BLPeripheral)
- @return success (bool)
props.sensor
: Sensor to connect returned byuseRookScanner.startScan
anduseRookScanner.discoveredSensors
fromrook-bluetooth
Must be called before to start a training
This will also upload the Sensor to the Server and link it to the User, the returned sensor_uuid will be stored in the local db with the Training
Start training
startTraining: () => Promise<boolean>;
- Starts the training previously initialized
Additionally to the training configuration, a connection with a Sensor had to be established before with connectSensor
Re-start training
startPendingTraining: (props: startPendingTrainingProps) => Promise<boolean>;
- Re-starts an unfinished training
props.start
: Datetime key of the training to be resumed.
Pause training
pauseTraining: () => void;
- Pause the current training.
Resume training
resumeTraining: () => void;
- Resume a paused training
Cancel training
cancelTraining: () => Promise<boolean>;
-
- Cancel the current training and clears the related data.
If a training is canceled all the training information will be lost.
Finish training
finishTraining: () => Promise<void>;
- Finish the current training
- A training finish time is stored on database
This will finish the training, but won't be uploaded. A call to uploadTrainings will be required to upload the training.
Finish training and upload
finishAndUploadTraining: () => Promise<boolean>;
- Finish the current training
- A training finish time is stored on database
- The training is uploaded to RookMotion Server
Additional measurements
Add cycling record
addBicycleRecord: (props: addBicycleRecordProps) => Promise<boolean>
- Insert a cycling record for the current timestamp to the training
- Useful for Apps with bicycle measurements
props.cadence
: Current cycling cadence (rpm)props.resistance
: Current cycling resistanceprops.power
: Current cycling power (W)
Definitions
training_stages_definition
A training has the following stages:
- The training is started when [Start training](#Start training) is executed.
start
property is set to the start timeend
property is null.uploaded_at
property is null
- A training is Paused or unfinished when [Pause training](#Pause training) is executed or the training is interrupted
start
property was set to the start timeend
property is null.uploaded_at
property is null
- A training is Resumed when [Resume training](#Resume training) is executed
start
property was set to the start timeend
property is null.uploaded_at
property is null
- The training is finished when [Finish training](#Finish training) is executed
start
property was set in the previous stagesend
property is set to the finished timeuploaded_at
property is null
- The training is uploaded when Upload trainings is executed
start
property was set in the previous stages.end
property was set in the previous stages.uploaded_at
property is null
training_summary_type
Every training has records obtained each certain time, and we create summaries of that records such like:
- hr_max
- hr_min
- effort_max
- effort_avg
- training_duration
A training summary type is composed of
name
(string): e.g. hr_maxuuid
(string): Unique summary type identifier UUID4, it is assigned by RookMotion Server, and they're fixed.
useRookTrainingUploader
Description
This hook handles stored trainings
- Upload finished trainings
- Get finished trainings pending to be uploaded
- Delete stored trainings
A Training can be uploaded only when it has finished. You can check the Training stages here
To upload a Training, an existing user must be already on local using: useRookUser.getUser()
For training upload there are different scenarios based on the Training stages:
[Upload all finished trainings](#Upload all finished trainings) if you want to upload all the finished trainings in the local database.
- e.g. the user just finished a training, you want to upload it plus all the pending to upload trainings.
- e.g. the user performed multiple trainings without internet, they all were correctly finished, and you want to upload all of them:
[Finish and upload a Training](#Upload all finished trainings) if you want to upload all the finished trainings in the local database.
- e.g. the user just finished a training, you want to upload it plus all the pending to upload trainings.
- e.g. the user performed multiple trainings without internet, they all were correctly finished, and you want to upload all of them:
Definition
const uploader = useRookTrainingUploader();
Import
import { useRookTrainingUploader } from 'rook-core'
Return
ready
: Indicates if the hook is ready.
Stored Training actions
Upload all finished trainings
uploadPendingTrainings: () => Promise<UploadPendingTrainingsResult>
- Upload all the finished trainings stored in local database
Example
uploader
.uploadPendingTrainings()
.then(result => {
if (result.pending_trainings === result.uploaded_trainings) {
// If pending_trainings is the same as uploaded_trainings it means all trainings were successfuly uploaded
} else {
// We can loop through the failures array to check which trainings failed and what went wrong
result.failures.forEach(fail =>
console.log(`Error uploading ${fail.start} error: ${fail.error}`)
);
}
})
.catch(error => {
// Manage errors
});
Finish and upload a training
finishAndUploadTraining: (start: string) => Promise<UploadPendingTrainingsResult>
- Finishes an unfinished training stored in local database identified by Start.
- Start property comes from getPendingTrainings
- After finishing the training it uploaded.
Example
uploader
.getPendingTrainings()
.then(starts => {
if (starts.length > 0) {
uploader.finishAndUploadTraining(starts[0])
.then(result => {
})
.catch(error => {
// Manage errors
});
} else {
// No pending trainings
}
})
.catch(error => {
// Manage errors
});
Get Pending trainings
getPendingTrainings: () => Promise<Array<string>>
- Retrieves all the finished trainings pending to be uploaded from local database (see training stages)
- @return array(string: training start key)
Delete Uploaded trainings
deleteUploadedTrainings: () => Promise<void>
- Deletes from local database all the trainings already uploaded (see training stages)
Example
uploader
.uploadPendingTrainings()
.then(result => {
if (result.pending_trainings === result.uploaded_trainings) {
uploader
.deleteUploadedTrainings()
.then(() => console.log('finished'))
.catch(error => {
// Manage errors
});
} else {
result.failures.forEach(fail =>
console.log(`Error uploading ${fail.start} error: ${fail.error}`)
);
}
})
.catch(error => {
// Manage errors
});
Definitions
upload_trainings_result
UploadPendingTrainingsResult.result
:- ALREADY_UPLOADING: If you try to call the same method, (e.g. uploadPendingTrainings) without waiting for the previous call to end.
- NO_TRAININGS_TO_UPLOAD: No trainings in Database pending to be uploaded.
- TRAININGS_SYNCED: Trainings were uploaded. Check the failures array to verify which ones.
UploadPendingTrainingsResult.pending_trainings
(number): Counter of Trainings attempted to be uploaded.UploadPendingTrainingsResult.uploaded_trainings
(number): Counter of Trainings uploaded.failures
(TrainingUploadFailure[]): Array of training upload errors.start
(string): Start timestamp of the trainingerror
(string): Error description
useRookSummaries
Description training_summaries_types_definition
Definition
`useRookSummariesTypes: () => useRookSummariesTypesTools`
Import
import { useRookSummaries } from 'rook-core'
Return
ready
: Indicates if the hook is ready.
Training summaries types
Get training summaries types
getSummariesTypes: () => Promise<SummariesTypesResponse>;
- Retrieves the available training_summaries_types
Example
import React, {useState} from 'react';
import {SafeAreaView, Button, FlatList, Text, View} from 'react-native';
import {useRookSummariesTypes, SummaryType} from 'rook-core';
export const SummariesTypes = () => {
const {ready, getRewards} = useRookSummariesTypes();
const [data, setData] = useState<SummaryType[]>([]);
const handlePress = async (): Promise<any> => {
if (!ready) {
console.log('not ready');
return;
}
const response = await getSummariesTypes();
if (response && response.data) {
setData(response.data);
setRewards([]);
}
};
return (
<SafeAreaView>
<Button title="Ver Summaries Types" onPress={handleRewards} />
<FlatList
data={data}
keyExtractor={item => `${item.id}`}
renderItem={({item}) => (
<View>
<Text>id: {item.id}</Text>
<Text>Group: {item.group}</Text>
<Text>summary_name: {item.summary_name}</Text>
<Text>summary_type_uuid: {item.summary_type_uuid}</Text>
<Text>units: {item.units}</Text>
</View>
)}
/>
</SafeAreaView>
);
};
useRookRewards
Description
Retrieves the user rewards (RookPoints) obtained for trainings
Definition
`useRookRewards: () => useRookRewardsTools;`
Import
import { useRookRewards } from 'rook-core'
Return
ready
: Indicates if the hook is ready.
Rewards
Rewards are the RookPoints earned for training.
Get rewards
getRewards: (props: getRewardProps) => Promise<RewardsResponse>;
- Retrieve the user rewards
props
: Indicates de user
props.userUUID
: user_uuid_definition
import React, {useState} from 'react';
import {Button, FlatList, Text, View} from 'react-native';
import {SafeAreaView} from 'react-native';
import {useRookSummaries, Reward} from 'rook-core';
export const Summaries = () => {
const {ready, getRewards} = useRookSummaries();
const [ userUUID, setUserUUID ] = useState('')
const [rewards, setRewards] = useState<Reward[]>([]);
const handleRewards = async (): Promise<any> => {
if (!ready) {
console.log('not ready');
return;
}
try {
const response = await getRewards({
userUUID,
});
if (response && response.data) {
setRewards(response.data);
}
}
catch(error) {
console.log(error);
}
};
return (
<SafeAreaView>
<Button title="Ver Rewards" onPress={handleRewards} />
<Text>User uuid<Text>
<TextInput
onChangeText = { text => setUserUUID(text) }
/>
<FlatList
data={rewards}
keyExtractor={item => `${item.training_uuid}`}
renderItem={({item}) => (
<View>
<Text>training_uuid: {item.training_uuid}</Text>
<Text>points: {item.calories_points}</Text>
</View>
)}
/>
</SafeAreaView>
);
};
RookMotion Bluetooth
RookMotion Bluetooth is a React Hook library that will help you with the discovery and connection with sensors.
Installation
This package was already installed here:
if not, use:
yarn add rook-bluetooth
Hooks
Available hooks are:
- useSensorScanner: Discover nearby sensors.
- useSensorManager: Read the battery, heart rate and steps from sensors.
Configuration_
Auth credentials were set already here:
useSensorScanner
Description
- Discovers for nearby sensors
props
: Bluetooth configurationuseSensorScannerTools
: Returned properties
props.emitter
: This will notify certain events that happen during the session likeBleManagerDiscoverPeripheral
,BleManagerStopScan
,BleManagerDisconnectPeripheral
,BleManagerDidUpdateValueForCharacteristic
props.showAlert
: Show notifications by alerts
Definition
`useSensorScanner: (props: useSensorScannerProps)=> useSensorScannerTools`
Import
import { useSensorManager } from 'rook-bluetooth';
Return
isReady: boolean;
: Indicates when the hook is ready,discoveredSensors: Array<BLPeripheral>;
: List of discovered SensorsisScanning: boolean;
: Indicates if the hook is scanning for sensorsstartScan: (timeout: number) => void;
: Starts the process of scanning with a timeout
Example
import React, {FC, useEffect} from 'react';
import {Colors} from 'react-native/Libraries/NewAppScreen';
import {
TouchableWithoutFeedback,
Text
FlatList,
NativeEventEmitter,
NativeModules,
Platform,
StyleSheet,
useColorScheme,
} from 'react-native';
import {
BLPeripheral,
executeWithAndroidTrainingPermissions,
useSensorScanner,
} from 'rook-bluetooth';
type BLEScannerProps = {
selectedSensor: (sensor: BLPeripheral) => void;
};
export const BLEScanner: FC<BLEScannerProps> = ({selectedSensor}) => {
const isDarkMode = useColorScheme() === 'dark';
const {isReady, startScan, discoveredSensors, isScanning} = useSensorScanner({
emitter: new NativeEventEmitter(NativeModules.BleManager),
showAlert: true,
});
useEffect(() => {
if (isReady) {
startScanning();
}
}, [isReady]);
const waitForPermission = (): Promise<Boolean> => {
return new Promise((resolve, reject) => {
if (Platform.OS === 'android' && Platform.Version >= 23) {
executeWithAndroidTrainingPermissions(
() => resolve(true),
() => reject(),
);
} else {
// To give some extra time that all services are available
setTimeout(() => {
resolve(true);
}, 200);
}
});
};
const startScanning = async (): Promise<any> => {
try {
const result = await waitForPermission();
if (result) {
startScan(5);
console.log('Buscando . . .');
} else {
console.log('Permission required');
}
} catch (error) {
console.log('Permission required');
}
};
return (
<View>
{ isScanning && (
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Scanning
</Text>
)}
<FlatList
data={discoveredSensors}
keyExtractor={item => item.address}
renderItem={({item}) => {
return (
<TouchableWithoutFeedback
key={item.address}
onPress={() => selectedSensor(item)}>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
{`Connect to -> ${item.name}`}
</Text>
</TouchableWithoutFeedback>
);
}}
/>
</View>
);
};
const styles = StyleSheet.create({
textCenter: {
textAlign: 'center',
marginBottom: 8,
},
});
useSensorManager
Description
- Connects to specified Bluetooth Sensor
props
: Bluetooth configuration.useSensorManagerTools
: Connection properties
props.emitter
: This will notify events during the training likeBleManagerDiscoverPeripheral
BleManagerStopScan
BleManagerDisconnectPeripheral
BleManagerDidUpdateValueForCharacteristic
props.showAlert
: Show notifications by alertsprops.stepsEnable
: Enable steps during the training
Definition
` useSensorManager: (props : useSensorManagerProps) => useSensorManagerTools;`
Import
import { useSensorManager } from 'rook-bluetooth';
Return
batteryLevel: number;
- Indicate the battery for the connected Sensor
bpm: number;
- Indicate the beats per minute of the user
connectedPeripheral?: BLPeripheral;
- Indicate the Sensor that is connected
isReady: boolean;
- Indicates when the hook is ready
stepCount: number;
- Indicates the accumulated steps during the training
connect: (peripheral: BLPeripheral) => Promise<boolean>;
- Connect to a Sensor
peripheral
: Sensor to connect this could be found by the hookuseSensorScanner
boolean
: Indicates if the connection was successfully or failed
disconnect: () => Promise<boolean>;
- Disconnect of the Sensor
boolean
: Indicates if the connection was successfully or failed
disconnectFrom: (peripheral: BLPeripheral) => Promise<boolean>;
- Disconnect of the Sensor
peripheral
: Sensor to disconnect
boolean
: Indicates if the connection was successfully or failed
Example
import React, {FC, useEffect, useState} from 'react';
import {
Text
NativeEventEmitter,
NativeModules,
StyleSheet,
useColorScheme,
Button
} from 'react-native';
import {BLPeripheral, useSensorManager} from 'rook-bluetooth';
import {Colors} from 'react-native/Libraries/NewAppScreen';
type BLEConnectProps = {
sensor: BLPeripheral | null;
};
export const BLEConnect: FC<BLEConnectProps> = ({
sensor,
destroy,
}) => {
const isDarkMode = useColorScheme() === 'dark';
const [connecting, setConnecting] = useState(false);
const {
isReady,
batteryLevel,
bpm,
stepCount,
connectedPeripheral,
connect,
disconnect,
} = useSensorManager({
emitter: new NativeEventEmitter(NativeModules.BleManager),
showAlert: true,
stepsEnable: true,
});
useEffect(() => {
if (isReady) {
setTimeout(() => {
attemptToConnect();
}, 200);
}
}, [isReady, sensor]);
useEffect(() => {
return () => {
prepareDisconnection();
}
}, []);
const attemptToConnect = async (): Promise<any> => {
if (connecting || !sensor) {
return;
}
setConnecting(true);
try {
const result = await connect(sensor);
if (result) {
console.log('Connection successfully');
connected(true);
} else {
throw new Error();
}
} catch (error) {
connected(false);
console.log('Unable to connect');
}
};
const prepareDisconnection = (): void => {
disconnect();
};
return (
<View>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Bpm: {bpm}
</Text>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
Battery: {batteryLevel}
</Text>
<Text
style={[
{
color: isDarkMode ? Colors.white : Colors.black,
},
styles.textCenter,
]}>
steps: {stepCount}
</Text>
<View alignItems="center" marginTop={5}>
<Button
title = 'Disconnect'
onPress={prepareDisconnection}
/>
</View>
</View>
);
};
const styles = StyleSheet.create({
textCenter: {
textAlign: 'center',
marginBottom: 8,
},
});