Cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Battery drain problems with simple custom clockface

ANSWERED

Every clockface I create seems to be a major battery drain compared to fitbit stats clockface. Here's simple code where I'm just displaying battery, time, date. It uses about 5% battery/hour, whereas stats is only about 1%/hour. 

 

Is there a trick to making it more efficient? I'm only updating time by minutes and other every 5 seconds.

 

BTW, should my variables be defined as "const", "let", or "var"? I've seen both in fitbit examples and they seem to work the same.

 

import clock from "clock";
import document from "document";
import { preferences } from "user-settings";
import * as util from "../common/utils";

import { today } from "user-activity";
import { battery } from "power";

//import userSettings from "user-settings";
//import { display } from "display";
//import { vibration } from "haptics";
//import { user } from "user-profile";


// Update the clock every minute
clock.granularity = "minutes";

// Get a handle on the <text> element
const batteryLabel = document.getElementById("batteryLabel");
const dateLabel = document.getElementById("dateLabel");
const timeLabel = document.getElementById("timeLabel"); // why "const" instead of "let" or "var"?
const stepsLabel = document.getElementById("stepsLabel");

//-----------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------
function updateActivity() {
  batteryLabel.text = Math.floor(battery.chargeLevel) + "%";

  var stepsToday = today.local.steps || 0;
  stepsLabel.text = stepsToday;  
}


//-----------------------------------------------------------------------------------------
// Update the <text> element every tick with the current time
//-----------------------------------------------------------------------------------------
clock.ontick = (evt) => {  let todayDate = evt.date;

  let todayDate = new Date();
  let hours = todayDate.getHours();
  let ampm = hours >= 12 ? 'PM' : 'AM'
  let mins = util.zeroPad(todayDate.getMinutes());

  if (preferences.clockDisplay === "12h") {
    // 12h format
    hours = (hours % 12 || 12);  // the hour '0' should be '12'
  } else {
    // 24h format
    hours = util.zeroPad(hours);
  }

  let monthNames = [
  "Jan", "Feb", "Mar",
  "Apr", "May", "Jun", "Jul",
  "Aug", "Sep", "Oct",
  "Nov", "Dec"
  ];

  let weekdays = [
  "Sun", "Mon", "Tue",
  "Wed", "Thu", "Fri", "Sat"
  ];

  let weekdate = todayDate.getDate();
  let weekindex = todayDate.getDay();
  let monthIndex = todayDate.getMonth();

  timeLabel.text = `${hours}:${mins}`;
  dateLabel.text = `${weekdays[weekindex]}` + ` ${monthNames[monthIndex]} ${weekdate}` + ` ${ampm}`;

}                         
//-----------------------------------------------------------------------------------------

setInterval(updateActivity,5000);
updateActivity(); // display activity at start
Best Answer
0 Votes
1 BEST ANSWER

Accepted Solutions

@JonFitbitMy versa keeps locking up using your code. So, I've gone back to my simpler code and it's working to my satisfaction. It may not be optimized but it doesn't lock up my versa and it only burns about 1% per hour. Below is the relevant portions of the code.

 


function updateClock() { // get current time
let todayDate = new Date();
// do more clock functions
}

function updateHr() { hrm.start(); }

hrm.onreading = function() { // get current heart rate
if (!display.on) return; // do nothing if display is not on
hrmTest = hrm.heartRate;
// do more heart rate display stuff
hrm.stop();
}

function updateActivity() {
if (display.on) {
// do activity display stuff
}
}

clock.granularity = "minutes"; 
setInterval(updateActivity,1500); setInterval(updateHr,2000); clock.ontick = () => updateClock(); if (display.on) { // display activity at start updateClock(); hrm.start(); updateActivity(); updateHr(); }  

 

 

View best answer in original post

Best Answer
0 Votes
13 REPLIES 13

I don't know, but I wonder whether the setInterval() could be hurting you. An alternative approach would be to call updateActivity() from within clock.ontick() every fifth time, after changing granularity to seconds. It this helps, we'll know that setInterval() isn't implemented very well!

 

Another general idea is to only do once the things that only need doing once. For example, you're defining several constants in onTick() every time it's executed. While this makes for nice tight scoping of the variables, it wastes CPU time.

Peter McLennan
Gondwana Software
Best Answer

Ok, I removed the setinterval and called updateActivity() at end of the ontick. That fixed it. ontick is only every minute in my code so it should be efficient! I'll move the variables outside of the functions next. Then I'll see if it'll work efficiently with seconds ontick like the fitbit stats clockface.

 

Thanks for the suggestions, @Gondwana!

Best Answer
0 Votes

I moved most of the variable declarations out of the functions.That didn't seem to make much difference but seems like a good strategy.

 

I moved updateActivities() back into setInterval call for 30 seconds (30000 ms) and that seems to work comparably to the onTick() every minute. So setInterval() is not the problem. Whether I do onTick() by seconds and call updateActivities() every 5 or just use setInterval() with 5 seconds (5000 ms) it takes similar battery.

 

So I've made the clock semi-useful by limiting it to 30 second updates. The fitbit stats updates time in seconds; steps, calories and heart rate every few seconds at most and takes little battery. 

Best Answer
0 Votes

Hey there,

 

is it the clock event draining the battery, or is it the fact, that you update the display even if the display is off?

Try adding

if (display.on) {
}

around your code and see if it helps.

You will need to add this to your imports too:

import { display } from "display";

I made a (geeky Dr Who) "Gallifreyan Clock" that rotates three circles and adds lines for seconds every second and it does not seem to drain my battery at all, I think because I added the code for "display.on". It's good practice to only update the display when it is actually on, since it is usually not (at least not on my FitBit Ionic).

 

I hope that helps you onwards a bit.. 🙂

 

Cheers,

JDT

Best Answer
0 Votes

I will try the if (display.on). But, I thought the clock doesn't even run unless the display is on. Different for apps.

Best Answer
0 Votes

I stand corrected. I just tried it out and you are right, it seems not to tick when the display is off.

 

So that can't be it then.. weird stuff.. if your clock only ticks when you have the display on, and you only have the display on when you turn it on (and it turns of in 10-20 seconds after that), then it doesn't really explain why the battery would go down faster than normal.

Best Answer
0 Votes

I'm really confused. I added the display.on condition and it seems to help. I added a counter and console.log and it kept counting and printing to the log unless I added the display.on condition. And yet when I want it to save info when display is off, it won't because it stopped running when the display was off.

 

I suspect there's a bug. I think it's supposed to stop when the display is off but sometimes it doesn't so it's good practice to add the display.on condition.

Best Answer
0 Votes

Here's an example of using setInterval to do something every second, only when the screen is on, using the Display API to start/stop the interval.

 

import { display } from "display";

let myTimer = {
watchID: null,
start: function() {
if (!this.watchID) {
this.watchID = setInterval(this.doInterval.bind(this), 1000);
}
},
stop: function() {
clearInterval(this.watchID);
this.watchID = null;
},
doInterval: function() {
// DO SOMETHING HERE
},
wake: function() {
this.doInterval();
this.start();
}
}

myTimer.start();

display.onchange = function() {
if (display.on) {
myTimer.wake();
} else {
myTimer.stop();
}
}

 

Best Answer
0 Votes

@JonFitbit- Thanks for the code but that's far too complicated for me. I might try it on a simple clockface to understand it.

 

In the meantime, what I did which seems to resolve my issue:

 

function updateActivity() {

  if (!display.on) return;

  // do stuff

}

setInterval(updateActivity,1500);

 

Best Answer
0 Votes

Unfortunately, your setInterval(updateActivity,1500); is going to keep the CPU running and drain the battery.

 

In my example code, you just need to put your updateActivity call where it says: 

// DO SOMETHING HERE

 

Best Answer
0 Votes

Ok, I pasted that in and it seems to be working. I'll test the battery drain over the next few hours.

 

BTW, is there a way to get CPU info or something directly so I can make instantaneous battery comparisons with code?

Best Answer
0 Votes

Do console.log() calls take cpu or cause any problems when disconnected from the server? I'd prefer to leave them in for debugging.

Best Answer
0 Votes

@JonFitbitMy versa keeps locking up using your code. So, I've gone back to my simpler code and it's working to my satisfaction. It may not be optimized but it doesn't lock up my versa and it only burns about 1% per hour. Below is the relevant portions of the code.

 


function updateClock() { // get current time
let todayDate = new Date();
// do more clock functions
}

function updateHr() { hrm.start(); }

hrm.onreading = function() { // get current heart rate
if (!display.on) return; // do nothing if display is not on
hrmTest = hrm.heartRate;
// do more heart rate display stuff
hrm.stop();
}

function updateActivity() {
if (display.on) {
// do activity display stuff
}
}

clock.granularity = "minutes"; 
setInterval(updateActivity,1500); setInterval(updateHr,2000); clock.ontick = () => updateClock(); if (display.on) { // display activity at start updateClock(); hrm.start(); updateActivity(); updateHr(); }  

 

 

Best Answer
0 Votes