02-09-2021 13:08
02-09-2021 13:08
Hello Community,
We are developing a SDK app to work with our virtual fitness application (both Android and iOS).
I am trying to do a file transfer (json file) every 30 seconds to send the Heart Rate and Calorie details to the app to show on the app UI.
The issue I am facing here is, the file transfer works fine until the point the display is active. As soon as the display goes off the file transfer stops.
Is there a way to make the file transfer more consistent?
Answered! Go to the Best Answer.
02-09-2021 16:41
02-09-2021 16:41
I think setInterval() might be your best bet, but there may not be a lot of point doing it every second. I think heart rate values are normally only updated every 5 seconds, and calorie values every minute. That said, I've never tried the Exercise API; if you're using that, you may indeed get HR changes every second.
02-09-2021 13:43
02-09-2021 13:43
Are you relying on ontick()?
02-09-2021 14:02
02-09-2021 14:02
No, I am basically calling the function to do the file transfer in onRender.
something like this.
onRender() {
if (exercise && exercise.stats) {
console.log("onRender");
msg.addScoreData({
currHR : exercise.stats.heartRate.current || 0,
score : 0,
calories : exercise.stats.calories || 0
});
}
and in Messaging something like this
export function addScoreData(data) {
if (MinTimer == 0) {
// pushing the heart rate to an array.
// Doing some calculations needed to to compute the score.
var scoreData = {
score : currScore,
currHR : data.currHR,
cal : data.calories,
hRate : [tempHR],
timeStamp : Date.now()
}
addMinScoreData(scoreData);
minTimer = 60;
} else {
if (minTimer == 30) {
var scoreData = { currHR : data.currHR, cal : data.calories, hRate : [heartRate], score : score , timeStamp : Date.now()};
console.log("Score 30 seconds", scoreData);
addMinScoreData(scoreData);
}
minTimer = minTimer - 1;
// push the heart rate to an array.
}
}
}
export function add5minScoreData(data) {
var newData = encode(data);
outbox.enqueue("scoredata.json", newData)
.then(ft => {
console.log(`Transfer of ${ft.name} successfully queued.`);
})
.catch(err => {
console.log(`Failed to schedule transfer: ${err}`);
})
}
02-09-2021 14:17
02-09-2021 14:17
I'm new around here, but I'd venture to bet that when the screen is off it's not rendering.
02-09-2021 14:21
02-09-2021 14:21
So what is the correct method that I should be using instead of onRender?
02-09-2021 14:33
02-09-2021 14:33
I think you'd probably want to use ontick:
//at top of file
import clock from "clock";
clock.granularity = "minutes";
clock.ontick = evt => {
//code to run once per minute
}
I'm not sure if passing evt is required for your purposes, but it holds information about the current date/time
02-09-2021 14:40
02-09-2021 14:40
Ok.
Can I use it for every 30 seconds?
02-09-2021 14:54
02-09-2021 14:54
I don't know what onRender() is. I don't think ontick() will solve your problem either, because it doesn't fire when the display is off. I think you'll need setInterval().
02-09-2021 16:05
02-09-2021 16:05
@Gondwana I have to gather the Heart Rate and calorie every second and then after 30 seconds I have to make the file transfer.
Do you think I can make this happen using setInterval() ?
FYI, onRender() is from a method in the Lib which is from the demo project for Exercise SDK app from Fitbit.
02-09-2021 16:41
02-09-2021 16:41
I think setInterval() might be your best bet, but there may not be a lot of point doing it every second. I think heart rate values are normally only updated every 5 seconds, and calorie values every minute. That said, I've never tried the Exercise API; if you're using that, you may indeed get HR changes every second.
02-09-2021 19:28
02-09-2021 19:28
Adapted from the heart rate documentation (per my other post there are actually some issues with the example there):
if (HeartRateSensor && appbit.permissions.granted("access_heart_rate")) {
//1 reading per second, 30 readings per batch for one batch every 30 sec
let hrm = new HeartRateSensor({ frequency: 1, batch: 30 });
hrm.addEventListener("reading", () => {
for (let index = 0; index < hrm.readings.timestamp.length; index++) {
console.log(
`HeartRateSensor Reading: \
timestamp=${hrm.readings.timestamp[index]}, \
[${hrm.readings.heartRate[index]}]`
);
};
});
hrm.start();
} else {
console.log("This device does NOT have a HeartRateSensor or permission not granted");
}
This will create an event listener for when a "reading" is complete, in this case we are actually setting it up to return a batch of readings so it will fire the event after 30 seconds and return an array containing 30 timestamp/heartrate combinations. I've tested and this continues to run when the display is off.
Cheers
02-10-2021 16:03
02-10-2021 16:03
I am new around here. So it would be great if you can help.
@Gondwana I am trying your approach at this moment.
Adding setInterval() this is how my code looks.
import document from "document";
import exercise from "exercise";
import { HeartRateSensor } from "heart-rate";
import { Application, View, $at } from "../lib/view";
import * as msg from "../lib/messaging";
import { me } from "appbit";
const $ = $at("#view-exercise");
export class ViewExercise extends View {
el = $();
handlePopupNo = () => {
};
handlePopupYes = () => {
};
handleToggle = () => {
};
handlePause = () => {
};
handleResume = () => {
};
handleFinish = () => {
};
handleCancel = () => {
}
handleRefresh = () => {
this.render();
}
handleButton = (evt) => {
}
addData() {
setInterval( () => {
console.log("AddData", this.excercise.stats);
if (this.exercise && this.exercise.stats) {
console.log("AddData in the loop");
this.msg.addScoreData({
currHR : exercise.stats.heartRate.current || 0,
score : 0,
calories : exercise.stats.calories || 0
});
}
}, 1000 * 10)
}
onMount() {
utils.hide(this.btnFinish);
// utils.hide(this.btnToggle);
utils.hide(this.btnResume);
this.btnToggle.addEventListener("click", this.handleToggle);
this.btnResume.addEventListener("click", this.handleResume);
this.btnFinish.addEventListener("click", this.handleFinish);
document.addEventListener("keypress", this.handleButton);
utils.show(this.btnToggle);
exercise.start(config.exerciseName, config.exerciseOptions);
this.addData();
}
onRender() {
if (exercise && exercise.stats) {
}
}
onUnmount() {
this.cycle.removeEvents();
this.btnToggle.removeEventListener("click", this.handleToggle);
this.btnFinish.removeEventListener("click", this.handleFinish);
this.btnResume.removeEventListener("click", this.handleResume);
document.removeEventListener("keypress", this.handleButton);
}
}
I am unable to access exercise in setInterval() which is in addData(). Can you suggest what am I missing here?
I get this,
Unhandled exception: TypeError: Cannot read property 'stats' of undefined
02-10-2021 17:06
02-10-2021 17:06
excercise
😁
02-10-2021 17:12
02-10-2021 17:12
@Gondwana I mistyped in here 😄
There are no typos in the code that I have.
02-10-2021 17:17
02-10-2021 17:17
**ahem**! 😉
Next guess: sometimes you have this.exercise and sometimes just exercise. One or the other is perhaps wrong.
02-10-2021 17:28
02-10-2021 17:28
It's just exercise. It worked 🙂
Thanks @Gondwana
I ll also try your suggestion @kozm0naut 🙂