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

Add steps/heart rate monitor/calories/date back to custom clock face?

Hi I made a new custom clock face, I left space with the intention that the   Steps/hear rate monitor/calories and date would still have room.
But I have no idea how to add them.
What is the script for the original clock face apps?
Also why do they disappear for the custom clock face?
(In case you can't tel I know nothing of this programming language.. )

Best Answer
0 Votes
20 REPLIES 20

I'm not quite clear what you're asking. Have you created your own clock face using Fitbit Studio?

 

If you want to add other data to it, you'll need to take a look at the examples apps and reference documentation. 

https://dev.fitbit.com/build/reference/device-api/heart-rate/
https://dev.fitbit.com/build/reference/device-api/user-activity/

https://dev.fitbit.com/build/guides/permissions/

This project is a good starting point https://github.com/Fitbit/sdk-moment

Best Answer
0 Votes

Ill take a look at the guides, but for clarity,

When I first got the iconic, the clock face had time, date and then 3 apps:  heart rate, steps, and calories.
I replaced the image on the clock face with my own, but when I did that, the date and 3 apps were removed.   I basically just want them back exactly as they were AND my image.

 

Unfortunately my tech skill is low.

Best Answer
0 Votes

The project you have shared on github, how do you use that?  Sorry I'm very new to coding.  I was able to get a picture and move the clock but I am also trying to add at least the date to my clock face.  I clicked the github and see a whole bunch of information and am not sure how to use it. 

Best Answer
0 Votes

I have not been able to do it either.
I gave up.

Best Answer
0 Votes

Hi Jon, your project is perfect except I want to add battery life. I'm not a coder can you explain how I can do this? Thanks.

Best Answer
0 Votes

@fmkphoto wrote:

Hi Jon, your project is perfect except I want to add battery life. I'm not a coder can you explain how I can do this? Thanks.


Hello fmkphoto,

 

import {battery} from "power"

function updBat(cLev) {
  document.getElementById('tBatt').text=cLev
}

battery.onchange = evt => {
  updBat(battery.chargeLevel)
}

This assumes there is a <TEXT> tag with ID="tBatt" 

<text id="tBatt" x="19" y="0" text-anchor="middle">100%</text>

Regards,

Best Answer
0 Votes

Here is what index.js looks like:

import document from "document";

import * as simpleActivity from "./simple/activity";
import * as simpleClock from "./simple/clock";
import * as simpleHRM from "./simple/hrm";
import * as simpleSettings from "./simple/device-settings";

let background = document.getElementById("background");
let dividers = document.getElementsByClassName("divider");
let txtTime = document.getElementById("txtTime");
let txtDate = document.getElementById("txtDate");
let txtHRM = document.getElementById("txtHRM");
let iconHRM = document.getElementById("iconHRM");
let imgHRM = iconHRM.getElementById("icon");
let statsCycle = document.getElementById("stats-cycle");
let statsCycleItems = statsCycle.getElementsByClassName("cycle-item");

/* --------- CLOCK ---------- */
function clockCallback(data) {
txtTime.text = data.time;
txtDate.text = data.date;
}
simpleClock.initialize("minutes", "longDate", clockCallback);

/* ------- ACTIVITY --------- */
function activityCallback(data) {
statsCycleItems.forEach((item, index) => {
let img = item.firstChild;
let txt = img.nextSibling;
txt.text = data[Object.keys(data)[index]].pretty;
// Reposition the activity icon to the left of the variable length text
img.x = txt.getBBox().x - txt.parent.getBBox().x - img.width - 7;
});
}
simpleActivity.initialize("seconds", activityCallback);

/* -------- HRM ------------- */
function hrmCallback(data) {
txtHRM.text = `${data.bpm}`;
if (data.zone === "out-of-range") {
imgHRM.href = "images/heart_open.png";
} else {
imgHRM.href = "images/heart_solid.png";
}
if (data.bpm !== "--") {
iconHRM.animate("highlight");
}
}
simpleHRM.initialize(hrmCallback);

/* -------- SETTINGS -------- */
function settingsCallback(data) {
if (!data) {
return;
}
if (data.colorBackground) {
background.style.fill = data.colorBackground;
}
if (data.colorDividers) {
dividers.forEach(item => {
item.style.fill = data.colorDividers;
});
}
if (data.colorTime) {
txtTime.style.fill = data.colorTime;
}
if (data.colorDate) {
txtDate.style.fill = data.colorDate;
}
if (data.colorActivity) {
statsCycleItems.forEach((item, index) => {
let img = item.firstChild;
let txt = img.nextSibling;
img.style.fill = data.colorActivity;
txt.style.fill = data.colorActivity;
});
}
if (data.colorHRM) {
txtHRM.style.fill = data.colorHRM;
}
if (data.colorImgHRM) {
imgHRM.style.fill = data.colorImgHRM;
}
}
simpleSettings.initialize(settingsCallback);

 

Best Answer
0 Votes

Hi Morning Reign, I copy and pasted both of those at the bottom of their respective indexes and it just made the project go blank. 

Best Answer
0 Votes

Any other suggestions?

Best Answer
0 Votes

My apologies, I missed answering this when originally posted,...

 


@fmkphoto wrote:

Hi Morning Reign, I copy and pasted both of those at the bottom of their respective indexes and it just made the project go blank. 


When learning a language or platform, breaking projects is pretty normal. Take heart in the fact that everyone goes through this.

 

My general suggestion is: work the problem, break it up into little pieces and see how much you can add and still have the program run.

 

In this specific case, I would suggest:

 

1) add the import statement first, it belongs at the top with the other import statements, then compile and see if the project is still viable.

 

2) add minimal code to prove the battery function actually works:

 

battery.onchange = evt => {
  console.log(battery.chargeLevel)
}

 

compile the project and test using the simulator by changing the charge level and watching the console log display the power.

 

3) add the text tag to the index.gui file. Try putting it after some other text tag, changing the X, or Y location to get it where you want it on the display. Note that it will need to be in the middle of some other SVG or SECTION tag set. Tag sets are like <svg> </svg> or <section> </section>. A typical,minimal text tag would look like:

 

<svg>
  <text>My text here</text>
</svg>

 

4) Assign the value to the tag:

 

battery.onchange = evt => {
  document.getElementById('tBatt').text = battery.chargeLevel
}

 

The variety of approaches to resolving problems like this is likely endless, but the key to working the problem is to break it down to individual pieces that can be tested, understood, and perfected.

 

Also,... step 0 would be: identify where your development platform sends its errors. Often (not always), the build/execution errors will give you an idea of where your problem may lay. You still have to work the problem, but at least a good error message can tell you where to start.

 

Regards,

Good luck,

Reign

Best Answer
0 Votes

Thanks for getting back to me. I tried several variations to no avail. Do you think if I post the index here you could show me exactly how and where to fit it in?

 

import document from "document";

import * as simpleActivity from "./simple/activity";
import * as simpleClock from "./simple/clock";
import * as simpleHRM from "./simple/hrm";
import * as simpleSettings from "./simple/device-settings";

let background = document.getElementById("background");
let dividers = document.getElementsByClassName("divider");
let txtTime = document.getElementById("txtTime");
let txtDate = document.getElementById("txtDate");
let txtHRM = document.getElementById("txtHRM");
let iconHRM = document.getElementById("iconHRM");
let imgHRM = iconHRM.getElementById("icon");
let statsCycle = document.getElementById("stats-cycle");
let statsCycleItems = statsCycle.getElementsByClassName("cycle-item");

/* --------- CLOCK ---------- */
function clockCallback(data) {
txtTime.text = data.time;
txtDate.text = data.date;
}
simpleClock.initialize("minutes", "longDate", clockCallback);

/* ------- ACTIVITY --------- */
function activityCallback(data) {
statsCycleItems.forEach((item, index) => {
let img = item.firstChild;
let txt = img.nextSibling;
txt.text = data[Object.keys(data)[index]].pretty;
// Reposition the activity icon to the left of the variable length text
img.x = txt.getBBox().x - txt.parent.getBBox().x - img.width - 7;
});
}
simpleActivity.initialize("seconds", activityCallback);

/* -------- HRM ------------- */
function hrmCallback(data) {
txtHRM.text = `${data.bpm}`;
if (data.zone === "out-of-range") {
imgHRM.href = "images/heart_open.png";
} else {
imgHRM.href = "images/heart_solid.png";
}
if (data.bpm !== "--") {
iconHRM.animate("highlight");
}
}
simpleHRM.initialize(hrmCallback);

/* -------- SETTINGS -------- */
function settingsCallback(data) {
if (!data) {
return;
}
if (data.colorBackground) {
background.style.fill = data.colorBackground;
}
if (data.colorDividers) {
dividers.forEach(item => {
item.style.fill = data.colorDividers;
});
}
if (data.colorTime) {
txtTime.style.fill = data.colorTime;
}
if (data.colorDate) {
txtDate.style.fill = data.colorDate;
}
if (data.colorActivity) {
statsCycleItems.forEach((item, index) => {
let img = item.firstChild;
let txt = img.nextSibling;
img.style.fill = data.colorActivity;
txt.style.fill = data.colorActivity;
});
}
if (data.colorHRM) {
txtHRM.style.fill = data.colorHRM;
}
if (data.colorImgHRM) {
imgHRM.style.fill = data.colorImgHRM;
}
}
simpleSettings.initialize(settingsCallback);

Best Answer
0 Votes

@fmkphoto wrote:

Thanks for getting back to me. I tried several variations to no avail. Do you think if I post the index here you could show me exactly how and where to fit it in?


One of the tools that help with testing new concepts is to use a 'sandbox' project that has nothing but what you intend to test.

 

Open a new, blank project in Fitbit studio.

 

Copy the following into the project. It is a minimum project for a full implementation of a battery display:

 

app\index.js :

import document from "document"
import {battery} from "power"

function updBat(cLev) {
  document.getElementById('tBatt').text=cLev
  document.getElementById('rBatt').width=22*cLev/100
  document.getElementById('sFL').style.fill =
    cLev <= 15 ? "#f11" :
    cLev <= 30 ? "#ff0" :
    "#0f0"
}

updBat(battery.chargeLevel)

battery.onchange = evt => {
  updBat(battery.chargeLevel)
}

resources\index.gui

<svg id="mPage" viewport-fill="#000000" pointer-events="visible">

  <svg class="sFLt" id="sFL" x="100%-35" y="100%-24" fill="red">
    <line x1="0" y1="0" x2="5" y2="5"/>
    <line x1="5" y1="5" x2="30" y2="5"/>
    <line x1="30" y1="5" x2="30" y2="15"/>
    <line x1="5" y1="15" x2="30" y2="15"/>
    <line x1="5" y1="15" x2="0" y2="20"/>
    <line x1="0" y1="0" x2="0" y2="20"/>
    <text id="tBatt" x="19" y="-1" text-anchor="middle" font-size="18">100%</text>
    <rect id="rBatt" x="6" y="8" width="22" height="5"/>
    <arc class="sFLt" x="-13" y="-24" width="65" height="65" sweep-angle="360" arc-width="3" fill="inherit"/>
  </svg>
    
</svg>

resources\widgets.gui

<svg>
</svg>

When you build the first time, it will generate a package.json file.

Select every build target(Ionic, Versa, etc...), select any wipe color and tell it to "run"

 

This code does function and is copied from the Astrolabe watch face:

AstrolabeAnim.gif

 

 

 

 

 

 

 

 

 

 

When you get it working in the sandbox, you should be able to adapt it to your project.

 

Regards,

Reign

Best Answer
0 Votes
I guess this is just over my head. I'm going to look for a coder. Thanks
for your time anyways.
Best Answer
0 Votes

If you want to add battery add this in the index.js:

import { battery } from "power";
myBattery.text=(Math.floor(battery.chargeLevel) + "%");

You also have to add this to the index.js:

const myBattery = document.getElementById("myBattery");

Then add this into your index.gui:

<text id="myBattery"></text>

At last, add your CSS: 

#myBattery {
  font-size: 20;
  font-family: Seville-Bold ;
  text-length: 32;
  text-anchor: middle;
  x: 90%;
  y: 10%+0;
  fill: #FFFF7A;
}

If you want to display when it is charging add this into your index.js:

 

import { charger } from "power";
myCharge.text=(" " + (charger.connected ? ":high_voltage:" : "") + " ");
const myCharge = document.getElementById("myCharge");

Add this to your index.gui:

<text id="myCharge"></text>

At last the CSS: 

#myCharge {
  font-size: 15;
  font-family: Seville-Bold ;
  text-length: 32;
  text-anchor: middle;
  x: 72%;
  y: 9%+0;
  fill: #FFFF7A;
}

 

This Code should work 😃 

Best Answer

where it says:high_voltage: put a charging emoji there 🙂

Best Answer
0 Votes
Thank you, but this is what I get when I paste the index.js line. I imagine
I'm putting it in the wrong place???

[12:44:46 PM]Unhandled exception: TypeError: Cannot set property 'text' of
undefined

- ? at app/index.js:7,34
Best Answer
0 Votes

 @fmkphoto ,   You have put the 

 

const myBattery = document.getElementById("myBattery");

 

under the 

 

import { battery } from "power";
myBattery.text=(Math.floor(battery.chargeLevel) + "%");

 

put it like this 

 

const myBattery = document.getElementById("myBattery");

import { battery } from "power";
myBattery.text=(Math.floor(battery.chargeLevel) + "%");

 

Sorry if I put it the wrong way  🙃

Best Answer
0 Votes

That didn't seem to work either. Here is the entire original index.js if that helps:

 

import document from "document";

import * as simpleActivity from "./simple/activity";
import * as simpleClock from "./simple/clock";
import * as simpleHRM from "./simple/hrm";
import * as simpleSettings from "./simple/device-settings";

let background = document.getElementById("background");
let dividers = document.getElementsByClassName("divider");
let txtTime = document.getElementById("txtTime");
let txtDate = document.getElementById("txtDate");
let txtHRM = document.getElementById("txtHRM");
let iconHRM = document.getElementById("iconHRM");
let imgHRM = iconHRM.getElementById("icon");
let statsCycle = document.getElementById("stats-cycle");
let statsCycleItems = statsCycle.getElementsByClassName("cycle-item");

/* --------- CLOCK ---------- */
function clockCallback(data) {
txtTime.text = data.time;
txtDate.text = data.date;
}
simpleClock.initialize("minutes", "longDate", clockCallback);

/* ------- ACTIVITY --------- */
function activityCallback(data) {
statsCycleItems.forEach((item, index) => {
let img = item.firstChild;
let txt = img.nextSibling;
txt.text = data[Object.keys(data)[index]].pretty;
// Reposition the activity icon to the left of the variable length text
img.x = txt.getBBox().x - txt.parent.getBBox().x - img.width - 7;
});
}
simpleActivity.initialize("seconds", activityCallback);

/* -------- HRM ------------- */
function hrmCallback(data) {
txtHRM.text = `${data.bpm}`;
if (data.zone === "out-of-range") {
imgHRM.href = "images/heart_open.png";
} else {
imgHRM.href = "images/heart_solid.png";
}
if (data.bpm !== "--") {
iconHRM.animate("highlight");
}
}
simpleHRM.initialize(hrmCallback);

/* -------- SETTINGS -------- */
function settingsCallback(data) {
if (!data) {
return;
}
if (data.colorBackground) {
background.style.fill = data.colorBackground;
}
if (data.colorDividers) {
dividers.forEach(item => {
item.style.fill = data.colorDividers;
});
}
if (data.colorTime) {
txtTime.style.fill = data.colorTime;
}
if (data.colorDate) {
txtDate.style.fill = data.colorDate;
}
if (data.colorActivity) {
statsCycleItems.forEach((item, index) => {
let img = item.firstChild;
let txt = img.nextSibling;
img.style.fill = data.colorActivity;
txt.style.fill = data.colorActivity;
});
}
if (data.colorHRM) {
txtHRM.style.fill = data.colorHRM;
}
if (data.colorImgHRM) {
imgHRM.style.fill = data.colorImgHRM;
}
}
simpleSettings.initialize(settingsCallback);

 

Best Answer
0 Votes

 I don't know what to say then try this link if it helps. 🙂 

Best Answer
0 Votes