@DonTomGot
This may be too complex as a first project. But let me start with giving you the overall structure of the code as that seems to be the problem at this point.
Manifest.json declares what input you need from the watch firmware, what data you intend to output from main.js to t.html and settings you use in the watch. This is parts of manifest.json
"in": [
{
"name": "Power",
"source": "/Activity/Move/-1/Power/Current",
"type": "subscribe"
},
{
"name": "HeartRate",
"source": "/Activity/Move/-1/HeartRate/Current",
"type": "subscribe"
},
{
"name": "Speed",
"source": "/Activity/Move/-1/Speed/Current",
"type": "subscribe"
},
{
"name": "SpeedAvg",
"source": "/Activity/Lap/-1/Speed/Avg",
"type": "subscribe"
}
],
"out": [
{
"name": "PaceTarget"
},
{
"name": "TimeRemaining"
},
{
"name": "Debug"
}
],
"template": [
{
"name": "t.html"
}
],
"settings": [
{"shownName": "Repeat count", "path": "appSettings.repeatCount", "type": "int", "min": 1, "max": 19},
{"shownName": "Target pace for WarmUp (m/s)", "path": "appSettings.targetPaceWarm", "type": "float", "min": 1, "max": 6},
{"shownName": "Target pace for Interval (m/s)", "path": "appSettings.targetPaceInterval", "type": "float", "min": 1, "max": 6},
{"shownName": "Target pace for Recovery (m/s)", "path": "appSettings.targetPaceRecovery", "type": "float", "min": 1, "max": 6},
{"shownName": "Target pace for CoolDown (m/s)", "path": "appSettings.targetPaceCool", "type": "float", "min": 1, "max": 6},
{"shownName": "Duration for WarmUp (s)", "path": "appSettings.durationWarm", "type": "int", "min": 1, "max": 14400},
{"shownName": "Duration for Interval (s)", "path": "appSettings.durationInterval", "type": "int", "min": 1, "max": 14400},
{"shownName": "Duration for Recovery (s)", "path": "appSettings.durationRecovery", "type": "int", "min": 1, "max": 14400},
{"shownName": "Duration for CoolDown (s)", "path": "appSettings.durationCool", "type": "int", "min": 1, "max": 14400}
]
The main.js contains declarations for some variables
// App settings, see also manifest and data.json
var settings;
var isPaused;
// State machine
var currentState = 'WarmUp';
var currentRepition = 1;
var repeatCount = 3;
var timeRemainingInStep = 10;
var currentPaceTarget = 2.326;
// Average pace and max HR for last lap
var lastLapAvgPace;
var lastLapPeakHR;
There is also a number methods that deal with the state machine needed for interval training. I give only their declarations and purpose for now.
// Function to translate speed to a pace string
var speedToPace = function(speed)
// Training session State Machine
// Get next step, set remaining time
// And increment interval counter
var setNextState = function()
// Function to get target pace for current state
var getTargetPace = function()
// Function to set text for the top right text block
var setTextBlock = function()
// Update last lap data, avg pace and peak HR
var updateLastLap = function(input, output)
The evaluate method may be of interest. Here it comes
// System starts calling this about once per second after the sports app is selected
// i.e. before the exercise is actually started.
// input: contains resources specified in "in" section of the manifest.
// output: resources passed to the device (specified in "out" section of the manifest).
function evaluate(input, output) {
// If we are in an Interval step remember average pace and max HR from this step
updateLastLap(input, output)
// Count down time remaining in current step
if (!isPaused) {
timeRemainingInStep -= 1;
// Handle the state transition if time remaining is zero
if (timeRemainingInStep === 0) {
// Trigger a silent lap
// $.put('Activity/Trigger', 24);
// Set the next state
setNextState();
} // End of if time remaining is 0
// Output remaining time to HTML after the new durations is set
// If we are done and countdown is negative display positive value
output.TimeRemaining = (timeRemainingInStep < 0) ? -timeRemainingInStep : timeRemainingInStep;
} // End of if not paused
// Get target pace for current step
getTargetPace();
// Output target to HTML
output.PaceTarget = currentPaceTarget;
// Update the top right text block
setTextBlock();
}
Settings are loaded in onLoad and defaults provided, like this
// main.js loaded and system starts calling evaluate()
function onLoad(input, output) {
// Load app settings
settings = localStorage.getObject("appSettings");
// Create default settings if none found
if (settings == null) {
settings = {
targetPaceWarm: 2.326,
targetPaceInterval: 2.857,
targetPaceRecovery: 2.083,
targetPaceCool: 2.083,
durationWarm: 10,
durationInterval: 12,
durationRecovery: 5,
durationCool: 20,
repeatCount: 2
}
}
isPaused = true;
}
The bulk of this code deals with interval training and not the gauges, so if you are only interested in the gauges, you do not need most of the things above.
In t.html the code should go inside quotes in the onLoad and onActivate methods, the beginning looks like this.
<uiView
onActivate = "
$.subscribe('/Dev/Time/Tick10hz', function(){ control('#cnv', 'REFRESH'); })
// Subscribe to HR, pace and targets to use in drawing gauges in the canvas
$.subscribe('/Activity/Move/-1/HeartRate/Current', function(v) { currentHR = parseFloat(v) * 60; })
$.subscribe('/Activity/Move/-1/Speed/Current', function(v) { currentPace = parseFloat(v); })
$.subscribe('/Zapp/{zapp_index}/Output/PaceTarget', function(v) { paceTarget = parseFloat(v); })
"
onLoad="
// Subscribed values
var currentHR;
var currentPace;
var paceTarget;
// Target zones
var hrZones = [0, 133, 144, 155, 165, 185];
var paceZones = [0, 2.299, 2.5, 2.703, 2.857, 5.556];
// Radius of the display in pixels
var radius = 233;
// Zone colors (muted, suitable as gauge backgrounds)
var z1Color = '#5B8FA8'; // Zone 1 - blue
var z2Color = '#6AA87A'; // Zone 2 - green
var z3Color = '#C4B050'; // Zone 3 - yellow
var z4Color = '#C87D45'; // Zone 4 - orange
var z5Color = '#B85555'; // Zone 5 - red
var zoneColors = [z1Color, z2Color, z3Color, z4Color, z5Color];
// Other colors
var outColor = '#B85555'; // Out of target range (low and high sectors)
var inColor = '#6AA87A'; // Target range (mid sector)
var inactiveColor = '#999999' // Inactive sector
var ptrColor = '#CCCCCC' // Gauge pointer
var bkgColor = '#000000' // Black background
// For debugging
var temp1 = '-';
var temp2 = '-';
// Functions to draw gauges on canvas ----------------------------------
// Draw an arc for a gauge
// from from angle in degrees
// to to angle in degrees
// color arc color
// width width of the arc
function arcSegment(ctx, from, to, color, width) {
ctx.beginPath();
ctx.arc(
radius, radius, // center of display
radius - 2 - width / 2, // radius - leave a small margin outside arc
Math.PI * from / 180, // Angles from - to in degrees converted to radians
Math.PI * to / 180
);
ctx.strokeStyle = color;
ctx.lineWidth = width;
ctx.stroke();
}
--- snip ---
Apart from the code for rendering the gauge background and pointer which you already have above, you also need methods to identify the current zone to highlight.
// Get the index of the the active zone for a 3 zone target gauge
// value current value
// targetLow low end of target range
// targetHigh high end of target range
function getActiveTarget(v, targetLow, targetHigh) {
if (!isFinite(v)) return 0;
if (v > targetHigh) {
return 2;
} else if (v > targetLow) {
return 1;
} else {
return 0;
}
}
// Get the index of the the active zone for a 5 zone HR gauge
// v current value
// zones an array of 4-values defining the 5 zones
function getActiveZone(v, zones) {
if (!isFinite(v)) return 0;
for (var i = 1; i < zones.length; i++) {
if (v < zones[i]) return i - 1;
}
return zones.length - 1;
}
The environment is very challenging to work in, you get very little support. Often the app just silently fails. A few tips.
build up in small steps and commit frequently
check thoroughly for typos and other mistakes that would be caught by other IDE
in the simulator toggle on “developer tools” , that will reveal some mistakes
insert systemEvent statements where you can put information in the event log