revisions based on pull request review

master
nravanelli 2025-05-06 09:55:55 +08:00
parent 45f1f612ef
commit 2e85c3570c
9 changed files with 67 additions and 19 deletions

View File

@ -39,11 +39,12 @@ function drawBackground(message) {
g.drawImage(corelogo, px - 146 / 2, 30); g.drawImage(corelogo, px - 146 / 2, 30);
g.drawString(message, g.getWidth() / 2, g.getHeight() / 2 + 16); g.drawString(message, g.getWidth() / 2, g.getHeight() / 2 + 16);
} }
Bangle.setCORESensorPower(1,"COREAPP");
Bangle.on('CORESensor', onCore);
if (!settings.enabled) { if (!settings.enabled) {
drawBackground("Sensor off\nEnable in Settings"); drawBackground("Sensor off\nEnable in Settings");
} else { } else {
Bangle.setCORESensorPower(1,"COREAPP");
Bangle.on('CORESensor', onCore);
drawBackground("Waiting for\ndata..."); drawBackground("Waiting for\ndata...");
} }

View File

@ -15,7 +15,7 @@
{"name":"coretemp.recorder.js","url":"recorder.js"}, {"name":"coretemp.recorder.js","url":"recorder.js"},
{"name":"coretemp.settings.js","url":"settings.js"}, {"name":"coretemp.settings.js","url":"settings.js"},
{"name":"coretemp.img","url":"coretemp-icon.js","evaluate":true}, {"name":"coretemp.img","url":"coretemp-icon.js","evaluate":true},
{"name":"coretemp.0..boot.js","url":"boot.js"} {"name":"coretemp.0.boot.js","url":"boot.js"}
], ],
"data": [{"name":"coretemp.json","url":"app-settings.json"}], "data": [{"name":"coretemp.json","url":"app-settings.json"}],
"screenshots": [{"url":"screenshot.png"}] "screenshots": [{"url":"screenshot.png"}]

View File

@ -27,13 +27,39 @@ This is a list of current features available when using the HeatSuite Watch Appl
+ Programmatic GPS monitoring, with adaptive power switching for battery optimization + Programmatic GPS monitoring, with adaptive power switching for battery optimization
+ Fall Detection and bluetooth broadcasting (beta) + Fall Detection and bluetooth broadcasting (beta)
## I just installed HeatSuite and I see a bunch of options. What do they mean?
HeatSuite uses a default studyTasks.json - visible and fully editable in the `Tasks` tab when installing HeatSuite on the watch. You can customize this to your liking by following the instructions [in the docs](https://heatsuitelabs.github.io/HeatSuiteDocs/watchapp/watchapp-tasks/). Some specific details are provided in this readme.
## What do the button colors mean?
![HeatSuite Main Application](heatsuite_layout.png)
The colors of each of the buttons provide the user some feedback:
+ <font color="green">Green</font> Means the task has been completed recently, or the user can press the button to navigate to or do a task.*
+ <font color="red">Red</font> means that the task can't be completed yet because another step needs to be done. This example shows that the external devices have yet to be paired with the watch.
+ <font color="yellow">Yellow</font> means you are scheduled to do this task.
_*Note: If the task requires a bluetooth device, the app will scan for the device and automatically handle the task once found._
## What does `Searching...` at the bottom of the HeatSuite app layout mean?
The `Searching...` text at the bottom of the screen shows that the watch is searching for devices that it may need to connect to via Bluetooth. This text will change when a device is found, and the appropriate handling of the task will ensue. As Bluetooth scanning drains the battery, the HeatSuite App will timeout after 3 minutes and revert back to the clock.
_Note: This will only show when a bluetooth device is associated with a task._
## Why does swiping right open the HeatSuite App?
The objective of HeatSuite was to make data collection in the field easier for participants. By default, swiping right when the HeatSuite widget is visible will open the app. This can be toggled off in the app settings.
## Can I request or add a feature? ## Can I request or add a feature?
Certainly!! To help ensure that the release on BangleApps is always functional and works with the other devices within the HeatSuite ecosystem, please make any feature requests or code updates to the forked version within the [HeatSuiteLabs repository](https://github.com/HeatSuiteLabs/BangleApps). That is our testing bed before we push to the official Bangle Apps git. Certainly!! To help ensure that the release on BangleApps is always functional and works with the other devices within the HeatSuite ecosystem, please make any feature requests or code updates to the forked version within the [HeatSuiteLabs repository](https://github.com/HeatSuiteLabs/BangleApps). That is our testing bed before we push to the official Bangle Apps git.
## Watch accelerometer data ## Watch accelerometer data
The current interation of the HeatSuite application provides the option to average the accelerometer `x,z,y` every second or as needed (known as High Temporal Resolution Accelerometer Logging), and/or magnitude per minute. Magnitude is calculated in the Espruino firmware as: The current interation of the HeatSuite application provides the option to average the accelerometer `x,y,z` every second or as needed (known as High Temporal Resolution Accelerometer Logging), and/or magnitude per minute. Magnitude is calculated in the Espruino firmware as:
``` ```
sqrt(x^2 + y^2 + z^2) sqrt(x^2 + y^2 + z^2)
@ -72,4 +98,4 @@ A full list of peer-reviewed research and conference preceedings using HeatSuite
## Creator ## Creator
[Nicholas Ravanelli, PhD](https://github.com/nravaneli) [Nicholas Ravanelli, PhD](https://github.com/nravanelli)

View File

@ -1 +1 @@
require("heatshrink").decompress(atob("ksqwcBkmSpICCmVCAoYCGyckyALIAQMmochDROSskmFJeZkmEBZEAhMmpFJkEABwtAgECpgaBMIMSBwmApEEyMJkkCoApFgGAhMiiVIAoILCAoIjCgFAggDBggIBEwICByEJB4UEDQJHBhAFCI4QaBAoZcCFIJHEAogjCI4QjBKYJoCgAODNAJKCBYQABRIY1BAoZTCNwhTBNARNEAQUBSQeQAoILC5LXBF4WAhADBXIVMEQJQBRgcJAoNkyUZhOQNAoFC5AaBiYpBI4cBAoWQeQOSoVJgmQFIQFByZJBBwK2CgEQKAMADoPJEAbdCa4ZuHkBuDXgiwCgS2FAoaqDgQFBWwQACiC/CEwSwDDoQyBI4i2DAoQsBEwIIBCgIFDJoIpBEYIFBGQQdCOISDBBQRWCJQjdFojdGAQUCoEkxBQBJoiSDFgLUBoApCBwhHBXgJxCBYgCDmVJNwYCGychmRNDAQ/IsgLJAQJJBDRWSsmEBAo")) require("heatshrink").decompress(atob("lsw4kC///A4IDB0UQqOMnnn8n6uut6ecrPO997x1zllj11z333885kQABGx8CCYUikANH8oXICpd2s2QCxIVIy1ms1QCxAVIg1pg9nIhIJIFQOWuByIAwtYwsAhJCBsoEBw/gR5VziM3IYNmtMAhURiZdIAAPjj/xnxaCFYMR4cfCpMJicA+KZBTgVB4FRiAWJyM1qcUFgfsj/nEAIAFhHKJgPxiMRj+V5+gMAIAB6EAzfHCoUPMYOQgvxj9DiMxAIMTx8T2EAuMRjYrCidPMYXugHriP0mM0gEOBQMDjmhjIFB4NAyMwJQcDjMEjgHDgp8CwCmBj+bibYE+PJ+OgA4ehjGTFgVTMgX5x/0gEHAwM1JAP/u5gBPYIcCrk/ugJCHwMH+fJPgQABm9Pnb7FgvBjGBiqoEid9iNAcBI0B+JdE0Ow8LgKqMaoMfegIABucTxhVDAAdWswQB0JRC4kx+7nCiI0Bu1mLIXmswWCvnHrgRCiM08nMBYIVBsxVCs3pAoQHCmNO+P1BAcGsvmsoFBu2Qq1gcBcOEgI9CFgIzBBYNVgGfiM8mMb8EJqAsBIQNuGQQFB8EF+Mf4MTZ4PxifTiPOQAVpY4eZAYPxmbhBr2EuAwBicR4EA9OVUA2Rn3jjAHDhkfhMTZJMHBYMxZIcAoPAqMeCY2YyHqHQPxmB5BxICBiPziM4h13OgIAB2IKCAIM5gHvLgMAhERj56BPALkBgFxAwMfyEHv0AhYwBi58BvMAwcR/8RFoMMjRjGLYJXBA4dRn0PPgWx4GB+ANDqcYQgPgcAcRz3xIYJjBmMUAgOqz2jV4UTwF7oo9BCAM+TIUxjpnCBQMf6cTp4FBPAXsiP5HgdeGwMx5kR+8As2QhExnvxJ4MOTgbgE+EPQQMGtMAhUcK4LgJgsRzLgCFgMAwP5oLSBABBjBiI6Bq1m8BLBiJ8BABPrme+CoVmGoPD/AQFkAZHg1mqxaBAA8iBJFmqGWsALHgQWIFgOWFhAVBCxBZDCpIWIq9p8AVKkRyINpAABA="))

View File

@ -108,7 +108,7 @@
<label class="form-switch"> <label class="form-switch">
<input type="checkbox" name="fallDetect"> <input type="checkbox" name="fallDetect">
<i class="form-icon"></i> Fall Detection <i class="form-icon"></i> Fall Detection (beta)
</label> </label>
<p class="form-input-hint mb-0">Will detect falls.</p> <p class="form-input-hint mb-0">Will detect falls.</p>
<label class="form-switch"> <label class="form-switch">
@ -116,6 +116,11 @@
<i class="form-icon"></i> Randomize EMA questions <i class="form-icon"></i> Randomize EMA questions
</label> </label>
<p class="form-input-hint mb-0">Enable this if you want your questions to be shuffled at random each time.</p> <p class="form-input-hint mb-0">Enable this if you want your questions to be shuffled at random each time.</p>
<label class="form-switch">
<input type="checkbox" name="swipeOpen" checked>
<i class="form-icon"></i> Swipe to Launch HeatSuite App
</label>
<p class="form-input-hint mb-0">On by default. Will enable quick access to the HeatSuite app for participants by simply swiping right on the screen.</p>
<label class="form-label" for="input-studyID">Study ID:</label> <label class="form-label" for="input-studyID">Study ID:</label>
<input class="form-input" type="text" name="studyID" id="input-studyID" value="" minlength="1" maxlength="4"> <input class="form-input" type="text" name="studyID" id="input-studyID" value="" minlength="1" maxlength="4">
<p class="form-input-hint mb-0">For communicating with HeatSuite Nodes. Maximum of 4 (no special) characters. <p class="form-input-hint mb-0">For communicating with HeatSuite Nodes. Maximum of 4 (no special) characters.

View File

@ -86,6 +86,7 @@ function queueTaskScreenTimeout() {
} }
function draw() { function draw() {
let btRequired = false;
g.clear(); g.clear();
g.reset(); g.reset();
if (studyTasks.length === 0) { if (studyTasks.length === 0) {
@ -143,9 +144,12 @@ function draw() {
if (settings["bt_" + task.id + "_id"] === undefined || !settings["bt_" + task.id + "_id"]) { if (settings["bt_" + task.id + "_id"] === undefined || !settings["bt_" + task.id + "_id"]) {
//make it clickable so we can go to settings and pair something //make it clickable so we can go to settings and pair something
btn.btnFaceCol = "#FF0000"; btn.btnFaceCol = "#FF0000";
btn.cb = l => taskButtonInterpretter("Bangle.load('heatsuite.settings.js');"); btn.cb = l => eval(require("Storage").read("heatsuite.settings.js"))(()=>load());
} }
} }
if(task.btInfo !== undefined){
btRequired = true;//we will be scanning for bluetooth devices
}
//builder for each icon in taskScreen //builder for each icon in taskScreen
if (row.c.length >= rowCount) { if (row.c.length >= rowCount) {
layoutOut.c.push(row); layoutOut.c.push(row);
@ -158,7 +162,7 @@ function draw() {
layoutOut.c.push(row); layoutOut.c.push(row);
} }
//Final //Final
layoutOut.c.push({ type: "txt", font: "6x8:2", label: "Searching...", id: "msg", fillx: 1 }); if(btRequired) layoutOut.c.push({ type: "txt", font: "6x8:2", label: "Searching...", id: "msg", fillx: 1 });
let options = { let options = {
lazy: true, lazy: true,
btns:[{label:"Exit", cb: l=>Bangle.showClock() }], btns:[{label:"Exit", cb: l=>Bangle.showClock() }],
@ -173,12 +177,13 @@ function draw() {
}; };
layout = new Layout(layoutOut, options); layout = new Layout(layoutOut, options);
layout.render(); layout.render();
queueNRFFindDeviceTimeout(); if(btRequired) queueNRFFindDeviceTimeout();
queueTaskScreenTimeout(); queueTaskScreenTimeout();
} }
Bangle.setLocked(false); //unlock screen! Bangle.setLocked(false); //unlock screen!
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets();
require("widget_utils").hide(); require("widget_utils").hide();
draw(); draw();
} }

View File

@ -16,6 +16,7 @@
s[key] = value; s[key] = value;
require('Storage').writeJSON(settingsJSON, s); require('Storage').writeJSON(settingsJSON, s);
settings = readSettings(); settings = readSettings();
if (global.WIDGETS && WIDGETS["heatsuite"]) WIDGETS["heatsuite"].changed(); //redraw widget on settings update if open
} }
function readSettings() { function readSettings() {
@ -173,6 +174,13 @@
menu['Devices'] = function () { E.showMenu(deviceSettings()) }; menu['Devices'] = function () { E.showMenu(deviceSettings()) };
menu['GPS'] = function () { E.showMenu(gpsSettings()) }; menu['GPS'] = function () { E.showMenu(gpsSettings()) };
menu['Language'] = function () { E.showMenu(languageMenu()) }; menu['Language'] = function () { E.showMenu(languageMenu()) };
menu['Swipe Launch'] = {
value: settings.swipeOpen || false,
onchange: v => {
settings.swipeOpen = v;
writeSettings("swipeOpen", v);
}
};
menu['Survey Random'] = { menu['Survey Random'] = {
value: settings.surveyRandomize || false, value: settings.surveyRandomize || false,
onchange: v => { onchange: v => {
@ -346,5 +354,6 @@
E.showMenu(submenu_scan); E.showMenu(submenu_scan);
}, { timeout: 4000, active: true, filters: [{ services: [service] }] }); }, { timeout: 4000, active: true, filters: [{ services: [service] }] });
} }
E.showMenu(mainMenuSettings()); E.showMenu(mainMenuSettings());
}) })

View File

@ -736,6 +736,15 @@
if (settings.highAcc !== undefined && settings.highAcc) { if (settings.highAcc !== undefined && settings.highAcc) {
perSecAcc(settings.highAcc); perSecAcc(settings.highAcc);
} }
if(settings.swipeOpen !== undefined && settings.swipeOpen){
Bangle.on('swipe', function(dir) {
if (dir === 1) { // 1 = right swipe
Bangle.buzz();
require("widget_utils").hide();
Bangle.load('heatsuite.app.js');
}
});
}
} }
startRecorder(); startRecorder();
@ -766,7 +775,7 @@
var iconWidth = 44; var iconWidth = 44;
function draw() { function draw() {
g.reset(); g.reset();
if (cache.taskQueue !== undefined) (cache.taskQueue.length > 0 ? g.setColor("#f00") : g.setColor("#0f0")); g.setColor(cache.taskQueue === undefined ? "#fff" : cache.taskQueue.length > 0 ? "#f00" : "#0f0");
g.setFontAlign(0, 0); g.setFontAlign(0, 0);
g.fillRect({ x: this.x, y: this.y, w: this.x + iconWidth - 1, h: this.y + 23, r: 8 }); g.fillRect({ x: this.x, y: this.y, w: this.x + iconWidth - 1, h: this.y + 23, r: 8 });
g.setColor(-1); g.setColor(-1);
@ -774,6 +783,7 @@
g.drawImage(atob("FBfCAP//AADk+kPKAAAoAAAAAKoAAAAAKAAAAFQoFQAAVTxVAFQVVVQVRABVABFVEBQEVQBUABUAAFUAVQCoFVVUKogAVQAiqBVVVCoAVQBVAABUABUAVRAUBFVEAFUAEVQVVVQVAFU8VQAAVCgVAAAAKAAAAACqAAAAACgAAA=="), this.x + 1, this.y + 1); g.drawImage(atob("FBfCAP//AADk+kPKAAAoAAAAAKoAAAAAKAAAAFQoFQAAVTxVAFQVVVQVRABVABFVEBQEVQBUABUAAFUAVQCoFVVUKogAVQAiqBVVVCoAVQBVAABUABUAVRAUBFVEAFUAEVQVVVQVAFU8VQAAVCgVAAAAKAAAAACqAAAAACgAAA=="), this.x + 1, this.y + 1);
g.setColor((Bangle.hasOwnProperty("isBTHRMConnected") && Bangle.isBTHRMConnected()) ? "#00F" : "#0f0"); g.setColor((Bangle.hasOwnProperty("isBTHRMConnected") && Bangle.isBTHRMConnected()) ? "#00F" : "#0f0");
g.drawImage(atob("EhCCAAKoAqgCqqiqqCqqqqqqqqqqqqqqqqqqqqqqqqqqqqqiqqqqqAqqqqoAKqqqgACqqqAAAqqoAAAKqgAAACqAAAAAoAAAAAoAAA=="), this.x + 22, this.y + 3); g.drawImage(atob("EhCCAAKoAqgCqqiqqCqqqqqqqqqqqqqqqqqqqqqqqqqqqqqiqqqqqAqqqqoAKqqqgACqqqAAAqqoAAAKqgAAACqAAAAAoAAAAAoAAA=="), this.x + 22, this.y + 3);
} }
WIDGETS.heatsuite = { WIDGETS.heatsuite = {
area: 'tr', area: 'tr',
@ -785,14 +795,6 @@
} }
}; };
Bangle.on('swipe', function(dir) {
if (dir === 1) { // 1 = right swipe
Bangle.buzz();
require("widget_utils").hide();
Bangle.load('heatsuite.app.js');
}
});
//Diagnosing BLUETOOTH Connection Issues //Diagnosing BLUETOOTH Connection Issues
//for managing memory issues - keeping code here for testing purposes in the future //for managing memory issues - keeping code here for testing purposes in the future
if (NRF.getSecurityStatus().connected) { //if widget starts while a bluetooth connection exits, force connection flag - but this is if (NRF.getSecurityStatus().connected) { //if widget starts while a bluetooth connection exits, force connection flag - but this is

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB