07-29-2018 04:31
07-29-2018 04:31
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.. )
07-29-2018 08:53
07-29-2018 08:53
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
07-29-2018 18:11 - edited 07-29-2018 18:48
07-29-2018 18:11 - edited 07-29-2018 18:48
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.
08-25-2018 13:50
08-25-2018 13:50
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.
08-25-2018 13:58
08-25-2018 13:58
I have not been able to do it either.
I gave up.
06-11-2020 14:51
06-11-2020 14:51
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.
06-11-2020 20:07
06-11-2020 20:07
@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,
06-11-2020 22:21
06-11-2020 22:21
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);
06-12-2020 16:06
06-12-2020 16:06
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.
06-20-2020 22:38
06-20-2020 22:38
Any other suggestions?
06-21-2020 07:58
06-21-2020 07:58
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
06-22-2020 09:49
06-22-2020 09:49
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);
06-22-2020 17:49
06-22-2020 17:49
@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:
When you get it working in the sandbox, you should be able to adapt it to your project.
Regards,
Reign
06-28-2020 15:19
06-28-2020 15:19
07-06-2020 12:13
07-06-2020 12:13
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 😃
07-06-2020 12:24
07-06-2020 12:24
where it says:high_voltage: put a charging emoji there 🙂
07-06-2020 12:48
07-06-2020 12:48
07-08-2020 13:56 - edited 07-08-2020 13:57
07-08-2020 13:56 - edited 07-08-2020 13:57
@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 🙃
07-08-2020 17:17
07-08-2020 17:17
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);
07-08-2020 17:26 - edited 07-08-2020 17:26
07-08-2020 17:26 - edited 07-08-2020 17:26
I don't know what to say then try this link if it helps. 🙂