mirror of https://github.com/espruino/BangleApps
Merge branch 'master' of github.com:espruino/BangleApps
commit
912f7dfc41
|
@ -1 +1,2 @@
|
|||
0.01: New App!
|
||||
0.02: Don't fire if the app uses swipes already.
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
Service that allows you to use an app's back button using left to right swipe gesture.
|
||||
|
||||
## Settings
|
||||
|
||||
Mode: Blacklist/Whitelist/Always On/Disabled
|
||||
App List: Black-/whitelisted apps
|
||||
Standard # of swipe handlers: 0-10 (Default: 0, must be changed for backswipe to work at all)
|
||||
Standard # of drag handlers: 0-10 (Default: 0, must be changed for backswipe to work at all)
|
||||
|
||||
|
||||
Standard # of handlers settings are used to fine tune when backswipe should trigger the back function. E.g. when using a keyboard that works on drags, we don't want the backswipe to trigger when we just wanted to select a letter. This might not be able to cover all cases however.
|
||||
|
||||
## Creator
|
||||
Kedlub
|
||||
|
||||
## Contributors
|
||||
thyttan
|
|
@ -15,18 +15,28 @@
|
|||
|
||||
var currentFile = global.__FILE__ || "";
|
||||
|
||||
if(global.BACK) delete global.BACK;
|
||||
if (global.BACK) delete global.BACK;
|
||||
if (options && options.back && enabledForApp(currentFile)) {
|
||||
global.BACK = options.back;
|
||||
}
|
||||
setUI(mode, cb);
|
||||
};
|
||||
|
||||
function goBack(lr, ud) {
|
||||
function countHandlers(eventType) {
|
||||
if (Bangle["#on"+eventType] === undefined) {
|
||||
return 0;
|
||||
} else if (Bangle["#on"+eventType] instanceof Array) {
|
||||
return Bangle["#on"+eventType].length;
|
||||
} else if (Bangle["#on"+eventType] !== undefined) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
function goBack(lr, _) {
|
||||
// if it is a left to right swipe
|
||||
if (lr === 1) {
|
||||
// if we're in an app that has a back button, run the callback for it
|
||||
if (global.BACK) {
|
||||
if (global.BACK && countHandlers("swipe")<=settings.standardNumSwipeHandlers && countHandlers("drag")<=settings.standardNumDragHandlers) {
|
||||
global.BACK();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "backswipe",
|
||||
"name": "Back Swipe",
|
||||
"shortName":"BackSwipe",
|
||||
"version":"0.01",
|
||||
"version":"0.02",
|
||||
"description": "Service that allows you to use an app's back button using left to right swipe gesture",
|
||||
"icon": "app.png",
|
||||
"tags": "back,gesture,swipe",
|
||||
|
|
|
@ -4,19 +4,21 @@
|
|||
// Apps is an array of app info objects, where all the apps that are there are either blocked or allowed, depending on the mode
|
||||
var DEFAULTS = {
|
||||
'mode': 0,
|
||||
'apps': []
|
||||
'apps': [],
|
||||
'standardNumSwipeHandlers': 0,
|
||||
'standardNumDragHandlers': 0
|
||||
};
|
||||
|
||||
|
||||
var settings = {};
|
||||
|
||||
|
||||
var loadSettings = function() {
|
||||
settings = require('Storage').readJSON(FILE, 1) || DEFAULTS;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
var saveSettings = function(settings) {
|
||||
require('Storage').write(FILE, settings);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Get all app info files
|
||||
var getApps = function() {
|
||||
var apps = require('Storage').list(/\.info$/).map(appInfoFileName => {
|
||||
|
@ -35,8 +37,8 @@
|
|||
return 0;
|
||||
});
|
||||
return apps;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
var showMenu = function() {
|
||||
var menu = {
|
||||
'': { 'title': 'Backswipe' },
|
||||
|
@ -55,11 +57,31 @@
|
|||
},
|
||||
'App List': () => {
|
||||
showAppSubMenu();
|
||||
},
|
||||
'Standard # of swipe handlers' : { // If more than this many handlers are present backswipe will not go back
|
||||
value: 0|settings.standardNumSwipeHandlers,
|
||||
min: 0,
|
||||
max: 10,
|
||||
format: v=>v,
|
||||
onchange: v => {
|
||||
settings.standardNumSwipeHandlers = v;
|
||||
saveSettings(settings);
|
||||
},
|
||||
},
|
||||
'Standard # of drag handlers' : { // If more than this many handlers are present backswipe will not go back
|
||||
value: 0|settings.standardNumDragHandlers,
|
||||
min: 0,
|
||||
max: 10,
|
||||
format: v=>v,
|
||||
onchange: v => {
|
||||
settings.standardNumDragHandlers = v;
|
||||
saveSettings(settings);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
E.showMenu(menu);
|
||||
}
|
||||
};
|
||||
|
||||
var showAppSubMenu = function() {
|
||||
var menu = {
|
||||
|
@ -101,4 +123,4 @@
|
|||
|
||||
loadSettings();
|
||||
showMenu();
|
||||
})
|
||||
})
|
||||
|
|
|
@ -64,3 +64,4 @@
|
|||
0.55: Add toLocalISOString polyfill for pre-2v15 firmwares
|
||||
Only add boot info comments if settings.bootDebug was set
|
||||
If settings.bootDebug is set, output timing for each section of .boot0
|
||||
0.56: Settings.log = 0,1,2,3 for off,display, log, both
|
||||
|
|
|
@ -32,14 +32,12 @@ if (s.ble!==false) {
|
|||
boot += `bleServiceOptions.hid=Bangle.HID;\n`;
|
||||
}
|
||||
}
|
||||
if (s.log==2) { // logging to file
|
||||
boot += `_DBGLOG=require("Storage").open("log.txt","a");
|
||||
`;
|
||||
} if (s.blerepl===false) { // If not programmable, force terminal off Bluetooth
|
||||
if (s.log==2) boot += `_DBGLOG=require("Storage").open("log.txt","a");
|
||||
LoopbackB.on('data',function(d) {_DBGLOG.write(d);Terminal.write(d);});
|
||||
// settings.log 0-off, 1-display, 2-log, 3-both
|
||||
if (s.blerepl===false) { // If not programmable, force terminal off Bluetooth
|
||||
if (s.log>=2) { boot += `_DBGLOG=require("Storage").open("log.txt","a");
|
||||
LoopbackB.on('data',function(d) {_DBGLOG.write(d);${(s.log==3)?"Terminal.write(d);":""}});
|
||||
LoopbackA.setConsole(true);\n`;
|
||||
else if (s.log) boot += `Terminal.setConsole(true);\n`; // if showing debug, force REPL onto terminal
|
||||
} else if (s.log==1) boot += `Terminal.setConsole(true);\n`; // if showing debug, force REPL onto terminal
|
||||
else boot += `E.setConsole(null,{force:true});\n`; // on new (2v05+) firmware we have E.setConsole which allows a 'null' console
|
||||
/* If not programmable add our own handler for Bluetooth data
|
||||
to allow Gadgetbridge commands to be received*/
|
||||
|
@ -56,10 +54,10 @@ Bluetooth.on('line',function(l) {
|
|||
try { global.GB(JSON.parse(l.slice(3,-1))); } catch(e) {}
|
||||
});\n`;
|
||||
} else {
|
||||
if (s.log==2) boot += `_DBGLOG=require("Storage").open("log.txt","a");
|
||||
LoopbackB.on('data',function(d) {_DBGLOG.write(d);Terminal.write(d);});
|
||||
if (s.log>=2) boot += `_DBGLOG=require("Storage").open("log.txt","a");
|
||||
LoopbackB.on('data',function(d) {_DBGLOG.write(d);${(s.log==3)?"Terminal.write(d);":""}});
|
||||
if (!NRF.getSecurityStatus().connected) LoopbackA.setConsole();\n`;
|
||||
else if (s.log) boot += `if (!NRF.getSecurityStatus().connected) Terminal.setConsole();\n`; // if showing debug, put REPL on terminal (until connection)
|
||||
else if (s.log==1) boot += `if (!NRF.getSecurityStatus().connected) Terminal.setConsole();\n`; // if showing debug, put REPL on terminal (until connection)
|
||||
else boot += `Bluetooth.setConsole(true);\n`; // else if no debug, force REPL to Bluetooth
|
||||
}
|
||||
// we just reset, so BLE should be on.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "boot",
|
||||
"name": "Bootloader",
|
||||
"version": "0.55",
|
||||
"version": "0.56",
|
||||
"description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings",
|
||||
"icon": "bootloader.png",
|
||||
"type": "bootloader",
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
0.01: New App!
|
||||
0.02: Get weather from weather.json
|
||||
0.03: Address unexpected undefined when reading weather.json
|
|
@ -326,7 +326,7 @@ function setWeather() {
|
|||
function readWeather() {
|
||||
var weatherJson = require("Storage").readJSON('weather.json', 1);
|
||||
// save updated weather data if available and it has been an hour since last updated
|
||||
if (weatherJson !== undefined && (data.time === undefined || (data.time + 3600000) < weatherJson.weather.time)) {
|
||||
if (weatherJson && weatherJson.weather && weatherJson.weather.time && (data.time === undefined || (data.time + 3600000) < weatherJson.weather.time)) {
|
||||
data = {
|
||||
time: weatherJson.weather.time,
|
||||
temp: weatherJson.weather.temp,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "mtnclock",
|
||||
"name": "Mountain Pass Clock",
|
||||
"shortName": "Mtn Clock",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "A clock that changes scenery based on time and weather.",
|
||||
"readme":"README.md",
|
||||
"icon": "app.png",
|
||||
|
|
|
@ -62,3 +62,4 @@
|
|||
0.55: More strings tagged for automatic translation.
|
||||
0.56: make System menu items shorter and more consistant, Eg 'Clock', intead
|
||||
of 'Select Clock'
|
||||
0.57: Settings.log = 0,1,2,3 for off,display,log,both
|
||||
|
|
|
@ -56,9 +56,10 @@ The exact effects depend on the app. In general the watch will not wake up by i
|
|||
|
||||
|
||||
* **Debug Info** should debug info be shown on the watch's screen or not?
|
||||
* `Hide` (default) do not show debug information
|
||||
* `Show` Show on the Bangle's screen (when not connected to Bluetooth or `Programmable:off`)
|
||||
* `Off` (default) do not show debug information
|
||||
* `Display` Show on the Bangle's screen (when not connected to Bluetooth or `Programmable:off`)
|
||||
* `Log` Show on the Bangle's screen **and** write to a file called `log.txt` on Storage (when not connected to Bluetooth or `Programmable:off`). Warning - this file is appended to so may grow to be large if this is left enabled.
|
||||
* `Both` Log and display on Bangle's screen
|
||||
* **Compact Storage** Removes deleted/old files from Storage - this will speed up your Bangle.js
|
||||
* **Rewrite Settings** Should not normally be required, but if `.boot0` has been deleted/corrupted (and so no settings are being loaded) this will fix it.
|
||||
* **Flatten Battery** Turns on all devices and draws as much power as possible, attempting to flatten the Bangle.js battery. This can still take 5+ hours.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "setting",
|
||||
"name": "Settings",
|
||||
"version": "0.56",
|
||||
"version": "0.57",
|
||||
"description": "A menu for setting up Bangle.js",
|
||||
"icon": "settings.png",
|
||||
"tags": "tool,system",
|
||||
|
|
|
@ -557,11 +557,11 @@ function showUtilMenu() {
|
|||
var menu = {
|
||||
'': { 'title': /*LANG*/'Utilities' },
|
||||
'< Back': ()=>showMainMenu(),
|
||||
/*LANG*/'Debug Info': {
|
||||
value: E.clip(0|settings.log,0,2),
|
||||
/*LANG*/'Debug': {
|
||||
value: E.clip(0|settings.log,0,3),
|
||||
min: 0,
|
||||
max: 2,
|
||||
format: v => [/*LANG*/"Hide",/*LANG*/"Show",/*LANG*/"Log"][E.clip(0|v,0,2)],
|
||||
max: 3,
|
||||
format: v => [/*LANG*/"Off",/*LANG*/"Display",/*LANG*/"Log", /*LANG*/"Both"][E.clip(0|v,0,3)],
|
||||
onchange: v => {
|
||||
settings.log = v;
|
||||
updateSettings();
|
||||
|
|
|
@ -13,6 +13,7 @@ function draw() {
|
|||
g.setFontAlign(0, 0);
|
||||
g.setColor(g.theme.fg);
|
||||
g.drawString(timeStr, w/2, h/2);
|
||||
console.log(timeStr + ", simplest");
|
||||
queueDraw();
|
||||
}
|
||||
|
||||
|
|
|
@ -14,3 +14,6 @@
|
|||
0.11: Minor tweaks
|
||||
0.12: Support javascript command to execute as defined in scheduler 'js' configuration
|
||||
0.13: Fix dated events alarm on wrong date
|
||||
0.14: Reduce update interval of current time when seconds are not shown
|
||||
Limit logging on Bangle.js 1 to one day due to low memory
|
||||
Add plot logged data to settings
|
||||
|
|
|
@ -23,6 +23,11 @@ Replacing the watch strap with a more comfortable one (e.g. made of nylon) is re
|
|||
## Logging
|
||||
|
||||
For each day of month (1..31) the ESS states are logged. An entry will be overwritten in the next month, e.g. an entry on the 4th May will overwrite an entry on the 4th April.
|
||||
The logs can be viewed with the download button:
|
||||
On Bangle.js 1 only one day is logged due to low memory.
|
||||
The logs can be plotted from the settings menu:
|
||||
|
||||

|
||||

|
||||
|
||||
The logs can also be viewed with the download button in the App Loader:
|
||||
|
||||

|
||||
|
|
|
@ -14,6 +14,7 @@ const active = alarms.filter(alarm => require("sched").getTimeToAlarm(alarm));
|
|||
const schedSettings = require("sched").getSettings();
|
||||
let buzzCount = schedSettings.buzzCount;
|
||||
let logs = [];
|
||||
let drawTimeTimeout;
|
||||
|
||||
// Sleep/Wake detection with Estimation of Stationary Sleep-segments (ESS):
|
||||
// Marko Borazio, Eugen Berlin, Nagihan Kücükyildiz, Philipp M. Scholl and Kristof Van Laerhoven, "Towards a Benchmark for Wearable Sleep Analysis with Inertial Wrist-worn Sensing Units", ICHI 2014, Verona, Italy, IEEE Press, 2014.
|
||||
|
@ -26,7 +27,7 @@ const nomothresh=0.023; // Original implementation: 6, resolution 11 bit, scale
|
|||
const sleepthresh=600;
|
||||
var ess_values = [];
|
||||
var slsnds = 0;
|
||||
function calc_ess(acc_magn) {
|
||||
function calc_ess(acc_magn) {"ram"
|
||||
ess_values.push(acc_magn);
|
||||
|
||||
if (ess_values.length == winwidth) {
|
||||
|
@ -90,10 +91,12 @@ function drawApp() {
|
|||
layout.alarm_date.label = `${LABEL_WAKEUP_TIME}: ${alarmHour}:${alarmMinute}`;
|
||||
layout.render();
|
||||
|
||||
function drawTime() {
|
||||
function drawTime() {"ram"
|
||||
const drawSeconds = !Bangle.isLocked();
|
||||
|
||||
if (Bangle.isLCDOn()) {
|
||||
const now = new Date();
|
||||
layout.date.label = locale.time(now, BANGLEJS2 && Bangle.isLocked() ? 1 : 0); // hide seconds on bangle 2
|
||||
layout.date.label = locale.time(now, !drawSeconds); // hide seconds on bangle 2
|
||||
const diff = nextAlarmDate - now;
|
||||
const diffHour = Math.floor((diff % 86400000) / 3600000).toString();
|
||||
const diffMinutes = Math.floor(((diff % 86400000) % 3600000) / 60000).toString();
|
||||
|
@ -101,11 +104,22 @@ function drawApp() {
|
|||
layout.render();
|
||||
}
|
||||
|
||||
setTimeout(()=>{
|
||||
const period = drawSeconds ? 1000 : 60000;
|
||||
if (this.drawTimeTimeout !== undefined) {
|
||||
clearTimeout(this.drawTimeTimeout);
|
||||
}
|
||||
drawTimeTimeout = setTimeout(()=>{
|
||||
drawTimeTimeout = undefined;
|
||||
drawTime();
|
||||
}, 1000 - (Date.now() % 1000));
|
||||
}, period - (Date.now() % period));
|
||||
}
|
||||
|
||||
Bangle.on('lock', function(on) {
|
||||
if (on === false) {
|
||||
drawTime();
|
||||
}
|
||||
});
|
||||
|
||||
drawTime();
|
||||
}
|
||||
|
||||
|
@ -132,8 +146,9 @@ function addLog(time, type) {
|
|||
var minAlarm = new Date();
|
||||
var measure = true;
|
||||
if (nextAlarmDate !== undefined) {
|
||||
config.logs[nextAlarmDate.getDate()] = []; // overwrite log on each day of month
|
||||
logs = config.logs[nextAlarmDate.getDate()];
|
||||
const logday = BANGLEJS2 ? nextAlarmDate.getDate() : 0;
|
||||
config.logs[logday] = []; // overwrite log on each day of month
|
||||
logs = config.logs[logday];
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
@ -146,7 +161,7 @@ if (nextAlarmDate !== undefined) {
|
|||
layout.render();
|
||||
Bangle.setOptions({powerSave: false}); // do not dynamically change accelerometer poll interval
|
||||
Bangle.setPollInterval(80); // 12.5Hz
|
||||
Bangle.on('accel', (accelData) => {
|
||||
Bangle.on('accel', (accelData) => {"ram"
|
||||
const now = new Date();
|
||||
const acc = accelData.mag;
|
||||
const swest = calc_ess(acc);
|
||||
|
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
|
@ -2,7 +2,7 @@
|
|||
"id": "sleepphasealarm",
|
||||
"name": "SleepPhaseAlarm",
|
||||
"shortName": "SleepPhaseAlarm",
|
||||
"version": "0.13",
|
||||
"version": "0.14",
|
||||
"description": "Uses the accelerometer to estimate sleep and wake states with the principle of Estimation of Stationary Sleep-segments (ESS, see https://ubicomp.eti.uni-siegen.de/home/datasets/ichi14/index.html.en). This app will read the next alarm from the alarm application and will wake you up to 30 minutes early at the best guessed time when you are almost already awake.",
|
||||
"icon": "app.png",
|
||||
"tags": "alarm",
|
||||
|
@ -15,5 +15,6 @@
|
|||
{"name":"sleepphasealarm.img","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
"data": [{"name":"sleepphasealarm.json"}],
|
||||
"interface": "interface.html"
|
||||
"interface": "interface.html",
|
||||
"screenshots": [ {"url":"screenshot.png"}, {"url":"screenshot_log.png"} ]
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
|
@ -13,25 +13,102 @@
|
|||
require('Storage').writeJSON(CONFIGFILE, config);
|
||||
}
|
||||
|
||||
// Show the menu
|
||||
E.showMenu({
|
||||
"" : { "title" : "SleepPhaseAlarm" },
|
||||
'Keep alarm enabled': {
|
||||
value: !!config.settings.disableAlarm,
|
||||
format: v => v?"No":"Yes",
|
||||
onchange: v => {
|
||||
config.settings.disableAlarm = v;
|
||||
writeSettings();
|
||||
function draw(log) {
|
||||
const step = 10*60*1000; // resolution 10min
|
||||
const yTicks = ["sleep", "awake", "alarm"];
|
||||
const starttime = new Date(log[0].time);
|
||||
const endtime = new Date(log[log.length-1].time);
|
||||
|
||||
let logidx = 0;
|
||||
let curtime = starttime;
|
||||
const data = new Uint8Array(Math.ceil((endtime-curtime)/step) + 1);
|
||||
let curval;
|
||||
let logtime;
|
||||
let i=0;
|
||||
while(curtime < endtime) {
|
||||
if (logtime === undefined || curtime > logtime) {
|
||||
curval = yTicks.indexOf(log[logidx].type);
|
||||
logidx++;
|
||||
logtime = new Date(log[logidx].time);
|
||||
}
|
||||
}, "< Back" : () => back(),
|
||||
'Run before alarm': {
|
||||
format: v => v === 0 ? 'disabled' : v+'h',
|
||||
value: config.settings.startBeforeAlarm,
|
||||
min: 0, max: 23,
|
||||
onchange: v => {
|
||||
config.settings.startBeforeAlarm = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
data[i++] = curval;
|
||||
curtime = new Date(curtime + step);
|
||||
}
|
||||
data[i] = 1; // always end with awake
|
||||
|
||||
Bangle.setUI({
|
||||
mode: "custom",
|
||||
back: () => selectday(),
|
||||
});
|
||||
g.reset().setFont("6x8",1);
|
||||
|
||||
require("graph").drawLine(g, data, {
|
||||
axes: true,
|
||||
x: 4,
|
||||
y: Bangle.appRect.y+8,
|
||||
height: Bangle.appRect.h-20,
|
||||
gridx: 1,
|
||||
gridy: 1,
|
||||
miny: -1,
|
||||
maxy: 2,
|
||||
title: /*LANG*/"Wakeup " + require("locale").date(endtime, 1),
|
||||
ylabel: y => y >= 0 && y <= 1 ? yTicks[y] : "",
|
||||
xlabel: x => {
|
||||
if (x === Math.round(data.length/10)) {
|
||||
return require("locale").time(starttime, 1);
|
||||
} else if (x === (data.length-2)-Math.round(data.length/10)) {
|
||||
return require("locale").time(endtime, 1);
|
||||
}
|
||||
return "";
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function selectday() {
|
||||
E.showMessage(/*LANG*/"Loading...");
|
||||
|
||||
const logs = config.logs.filter(log => log != null && log.filter(entry => entry.type === "alarm").length > 0);
|
||||
logs.sort(function(a, b) { // sort by alarm date desc
|
||||
const adate = new Date(a.filter(entry => entry.type === "alarm")[0].time);
|
||||
const bdate = new Date(b.filter(entry => entry.type === "alarm")[0].time);
|
||||
return bdate - adate;
|
||||
});
|
||||
|
||||
const menu = {};
|
||||
menu[""] = { title: /*LANG*/"Select day" };
|
||||
menu["< Back"] = () => settingsmenu();
|
||||
logs.forEach((log, i) => {
|
||||
const date = new Date(log.filter(entry => entry.type === "alarm")[0].time);
|
||||
menu[require("locale").date(date, 1)] = () => { E.showMenu(); draw(log); };
|
||||
});
|
||||
E.showMenu(menu);
|
||||
}
|
||||
|
||||
function settingsmenu() {
|
||||
// Show the menu
|
||||
E.showMenu({
|
||||
"" : { "title" : "SleepPhaseAlarm" },
|
||||
'Keep alarm enabled': {
|
||||
value: !!config.settings.disableAlarm,
|
||||
format: v => v?"No":"Yes",
|
||||
onchange: v => {
|
||||
config.settings.disableAlarm = v;
|
||||
writeSettings();
|
||||
}
|
||||
}, "< Back" : () => back(),
|
||||
'Run before alarm': {
|
||||
format: v => v === 0 ? 'disabled' : v+'h',
|
||||
value: config.settings.startBeforeAlarm,
|
||||
min: 0, max: 23,
|
||||
onchange: v => {
|
||||
config.settings.startBeforeAlarm = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
/*LANG*/'Select day': () => selectday(),
|
||||
});
|
||||
}
|
||||
|
||||
settingsmenu();
|
||||
})
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
0.01: 3/Feb/2023 Added 'Temperature Graph' app to depository.
|
||||
|
||||
0.02: 4/Feb/2023 Rewrote the widget handling after discovering there's a 'widget_utils' module to properly hide and show them.
|
||||
0.03: 4/Feb/2023 Fixed number error in timesData array.
|
||||
|
|
|
@ -1,395 +1,394 @@
|
|||
// Temperature Graph
|
||||
// BangleJS Script
|
||||
|
||||
Bangle.setBarometerPower(true,"tempgraph");
|
||||
Bangle.loadWidgets();
|
||||
var wids=WIDGETS;
|
||||
var widsOn=true;
|
||||
var rm=null;
|
||||
var gt=null;
|
||||
var dg=null;
|
||||
var Layout=require("Layout");
|
||||
var C=true;
|
||||
var temp,tempMode,readErrCnt,watchButton2;
|
||||
|
||||
var graph=require("Storage").readJSON("tempgraph.json",true);
|
||||
if(graph==undefined) {
|
||||
graph=[];
|
||||
}
|
||||
|
||||
var timesData=[
|
||||
// dur=duration, u=time units, d=divisions on graph, s=seconds per unit.
|
||||
{dur:10,u:"Mins",d:5,s:60},
|
||||
{dur:20,u:"Mins",d:4,s:60},
|
||||
{dur:30,u:"Mins",d:3,s:60},
|
||||
{dur:40,u:"Mins",d:4,s:60},
|
||||
{dur:1,u:"Hr",d:4,s:3600},
|
||||
{dur:2,u:"Hrs",d:4,s:3600},
|
||||
{dur:3,u:"Hrs",d:3,s:3600},
|
||||
{dur:4,u:"Hrs",d:4,s:3600},
|
||||
{dur:6,u:"Hrs",d:6,s:3600},
|
||||
{dur:8,u:"Hrs",d:4,s:3600},
|
||||
{dur:12,u:"Hrs",d:6,s:3600},
|
||||
{dur:16,u:"Hrs",d:4,s:3600},
|
||||
{dur:20,u:"Hrs",d:5,s:3600},
|
||||
{dur:1,u:"Day",d:4,s:3600},
|
||||
{dur:2,u:"Days",d:4,s:86400},
|
||||
{dur:3,u:"Days",d:3,s:86400},
|
||||
{dur:4,u:"Days",d:4,s:86400},
|
||||
{dur:5,u:"Days",d:5,s:86400},
|
||||
{dur:6,u:"Days",d:6,s:86400},
|
||||
{dur:7,u:"Days",d:7,s:86400}
|
||||
];
|
||||
var times=[];
|
||||
for(n=0;n<timesData.length;n++){
|
||||
times.push(timesData[n].dur+" "+timesData[n].u);
|
||||
}
|
||||
var durInd=0;
|
||||
var duration=times[durInd];
|
||||
|
||||
function drawWids(){
|
||||
g.clear();
|
||||
if(widsOn){
|
||||
WIDGETS=wids;
|
||||
Bangle.drawWidgets();
|
||||
} else {
|
||||
WIDGETS={};
|
||||
}
|
||||
}
|
||||
|
||||
function openMenu(){
|
||||
drawWids();
|
||||
E.showMenu(menu);
|
||||
}
|
||||
|
||||
function redoMenu(){
|
||||
clearInterval(rm);
|
||||
E.showMenu();
|
||||
openMenu();
|
||||
}
|
||||
|
||||
function refreshMenu(){
|
||||
rm = setInterval(redoMenu,100);
|
||||
}
|
||||
function getF(c){
|
||||
// Get Fahrenheit temperature from Celsius.
|
||||
return c*1.8+32;
|
||||
}
|
||||
|
||||
function getT(){
|
||||
Bangle.getPressure().then(p=>{
|
||||
temp=p.temperature;
|
||||
if(tempMode=="drawGraph"&&graph.length>0&&Math.abs(graph[graph.length-1].temp-temp)>10&&readErrCnt<2){
|
||||
// A large change in temperature may be a reading error. ie. A 0C or less reading after
|
||||
// a 20C reading. So if this happens, the reading is repeated up to 2 times to hopefully
|
||||
// skip such errors.
|
||||
readErrCnt++;
|
||||
print("readErrCnt "+readErrCnt);
|
||||
return;
|
||||
}
|
||||
clearInterval(gt);
|
||||
readErrCnt=0;
|
||||
switch (tempMode){
|
||||
case "showTemp":
|
||||
showT();
|
||||
break;
|
||||
case "drawGraph":
|
||||
var date=new Date();
|
||||
var dateStr=require("locale").date(date).trim();
|
||||
var hrs=date.getHours();
|
||||
var mins=date.getMinutes();
|
||||
var secs=date.getSeconds();
|
||||
graph.push({
|
||||
temp:temp,
|
||||
date:dateStr,
|
||||
hrs:hrs,
|
||||
mins:mins,
|
||||
secs:secs
|
||||
});
|
||||
if(graph.length==1){
|
||||
graph[0].dur=durInd;
|
||||
}
|
||||
require("Storage").writeJSON("tempgraph.json", graph);
|
||||
if(graph.length==150){
|
||||
clearInterval(dg);
|
||||
}
|
||||
drawG();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getTemp(){
|
||||
readErrCnt=0;
|
||||
gt = setInterval(getT,800);
|
||||
}
|
||||
|
||||
function setButton(){
|
||||
var watchButton=setWatch(function(){
|
||||
clearInterval(gt);
|
||||
clearInterval(dg);
|
||||
clearWatch(watchButton);
|
||||
Bangle.removeListener("touch",screenTouch);
|
||||
openMenu();
|
||||
},BTN);
|
||||
Bangle.on('touch',screenTouch);
|
||||
}
|
||||
|
||||
function setButton2(){
|
||||
watchButton2=setWatch(function(){
|
||||
clearWatch(watchButton2);
|
||||
openMenu();
|
||||
},BTN);
|
||||
}
|
||||
|
||||
function zPad(n){
|
||||
return n.toString().padStart(2,0);
|
||||
}
|
||||
|
||||
function screenTouch(n,ev){
|
||||
if(ev.y>23&&ev.y<152){
|
||||
C=C==false;
|
||||
drawG(false);
|
||||
}
|
||||
}
|
||||
|
||||
function drawG(){
|
||||
function cf(t){
|
||||
if(C){
|
||||
return t;
|
||||
}
|
||||
return getF(t);
|
||||
}
|
||||
drawWids();
|
||||
var top=1;
|
||||
var bar=21;
|
||||
var barBot=175-22;
|
||||
if(widsOn){
|
||||
top=25;
|
||||
bar=bar+24;
|
||||
barBot=barBot-24;
|
||||
}
|
||||
var low=graph[0].temp;
|
||||
var hi=low;
|
||||
for(n=0;n<graph.length;n++){
|
||||
var t=graph[n].temp;
|
||||
if(low>t){
|
||||
low=t;
|
||||
}
|
||||
if(hi<t){
|
||||
hi=t;
|
||||
}
|
||||
}
|
||||
var tempHi=Math.ceil((cf(hi)+2)/10)*10;
|
||||
var tempLow=Math.floor((cf(low)-2)/10)*10;
|
||||
var div=2;
|
||||
if(tempHi-tempLow>10){
|
||||
div=5;
|
||||
}
|
||||
if(C){
|
||||
g.setColor(1,0,0);
|
||||
}else{
|
||||
g.setColor(0,0,1);
|
||||
}
|
||||
var step=(barBot-bar)/((tempHi-tempLow)/div);
|
||||
for(n=0;n<graph.length;n++){
|
||||
var pos=tempLow-cf(graph[n].temp);
|
||||
g.drawLine(n+3,pos*(step/div)+barBot,n+3,barBot+3);
|
||||
}
|
||||
g.fillRect(161,barBot+5,174,barBot+20);
|
||||
g.setColor(1,1,1);
|
||||
g.setFont("6x8:2");
|
||||
if(C){
|
||||
g.drawString("C",163,barBot+5);
|
||||
}else{
|
||||
g.drawString("F",163,barBot+5);
|
||||
}
|
||||
g.setColor(0,0,0);
|
||||
g.setFont6x15();
|
||||
g.drawString("Temperature Graph - "+times[graph[0].dur],1,top);
|
||||
g.drawRect(2,bar-4,153,barBot+4);
|
||||
g.setFont("6x8:1");
|
||||
var num=tempHi;
|
||||
for(n=bar;n<=barBot;n=n+step){
|
||||
g.drawLine(3,n,152,n);
|
||||
g.drawString(num.toString().padStart(3," "),155,n-4);
|
||||
num=num-div;
|
||||
}
|
||||
step=151/timesData[graph[0].dur].d;
|
||||
for(n=step+2;n<152;n=n+step){
|
||||
g.drawLine(n,bar-4,n,barBot+4);
|
||||
}
|
||||
grSt=graph[0];
|
||||
g.drawString("Start: "+grSt.date+" "+grSt.hrs+":"+zPad(grSt.mins),1,barBot+6);
|
||||
var lastT=graph[graph.length-1].temp;
|
||||
g.drawString("Last Reading:",1,barBot+14);
|
||||
g.setColor(1,0,0);
|
||||
g.drawString(lastT.toFixed(1)+"C",85,barBot+14);
|
||||
g.setColor(0,0,1);
|
||||
g.drawString(getF(lastT).toFixed(1)+"F",121,barBot+14);
|
||||
process.memory(true);
|
||||
}
|
||||
|
||||
function drawGraph(){
|
||||
setButton();
|
||||
tempMode="drawGraph";
|
||||
durInd=times.indexOf(duration);
|
||||
graph=[];
|
||||
getTemp();
|
||||
dg=setInterval(getTemp,1000*timesData[durInd].dur*timesData[durInd].s/150);
|
||||
}
|
||||
|
||||
function showGraph(){
|
||||
setButton();
|
||||
drawG();
|
||||
}
|
||||
|
||||
function noBluetooth(){
|
||||
if(NRF.getSecurityStatus().connected){
|
||||
return false;
|
||||
}else{
|
||||
message("Error! Your\nBangle Watch\ncurrently has\nno Bluetooth\nconnection.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function saveGraph(){
|
||||
if(noBluetooth()){
|
||||
return;
|
||||
}
|
||||
drawG();
|
||||
g.flip();
|
||||
g.dump();
|
||||
message("Graph has\nbeen sent\nto Web IDE\nfor saving.\n");
|
||||
}
|
||||
|
||||
function saveData(){
|
||||
if(noBluetooth()){
|
||||
return;
|
||||
}
|
||||
drawG();
|
||||
g.flip();
|
||||
print("Temperature Graph - "+times[graph[0].dur]+"\n");
|
||||
print("\"Date\",\"Time\",\"Celsius\",\"Fahrenheit\"");
|
||||
for(n=0;n<graph.length;n++){
|
||||
var gr=graph[n];
|
||||
print("\""+gr.date+"\",\""+gr.hrs+":"+zPad(gr.mins)+":"+zPad(gr.secs)+"\","+gr.temp+","+getF(gr.temp));
|
||||
}
|
||||
message("Data has\nbeen sent\nto Web IDE\nfor saving.\n");
|
||||
}
|
||||
|
||||
function message(mes){
|
||||
setButton2();
|
||||
var messageLO=new Layout({
|
||||
type:"v",c:[
|
||||
{type:"txt",font:"6x8:2",width:171,label:mes,id:"label"},
|
||||
{type:"btn",font:"6x8:2",pad:3,label:"OK",cb:l=>exit()},
|
||||
],lazy:true
|
||||
});
|
||||
drawWids();
|
||||
messageLO.render();
|
||||
}
|
||||
|
||||
function showT(){
|
||||
tempLO.lab1.label=tempLO.lab3.label;
|
||||
tempLO.lab2.label=tempLO.lab4.label;
|
||||
tempLO.lab3.label=tempLO.lab5.label;
|
||||
tempLO.lab4.label=tempLO.lab6.label;
|
||||
tempLO.lab5.label=temp.toFixed(2)+"C";
|
||||
tempLO.lab6.label=getF(temp).toFixed(2)+"F";
|
||||
tempLO.render();
|
||||
}
|
||||
|
||||
function exit(){
|
||||
clearWatch(watchButton2);
|
||||
openMenu();
|
||||
}
|
||||
|
||||
function showTemp(){
|
||||
tempMode="showTemp";
|
||||
setButton2();
|
||||
tempLO=new Layout({
|
||||
type:"v",c:[
|
||||
{type:"h",c:[
|
||||
{type:"txt",pad:5,col:"#f77",font:"6x8:2",label:" ",id:"lab1"},
|
||||
{type:"txt",pad:5,col:"#77f",font:"6x8:2",label:" ",id:"lab2"}
|
||||
]},
|
||||
{type:"h",c:[
|
||||
{type:"txt",pad:5,col:"#f77",font:"6x8:2",label:" ",id:"lab3"},
|
||||
{type:"txt",pad:5,col:"#77f",font:"6x8:2",label:" ",id:"lab4"}
|
||||
]},
|
||||
{type:"h",c:[
|
||||
{type:"txt",pad:5,col:"#f00",font:"6x8:2",label:" ",id:"lab5"},
|
||||
{type:"txt",pad:5,col:"#00f",font:"6x8:2",label:" ",id:"lab6"}
|
||||
]},
|
||||
{type:"h",c:[
|
||||
{type:"btn",pad:2,font:"6x8:2",label:"Temp",cb:l=>getTemp()},
|
||||
{type:"btn",pad:2,font:"6x8:2",label:"Exit",cb:l=>exit()}
|
||||
]}
|
||||
]
|
||||
},{lazy:true});
|
||||
tempLO.render();
|
||||
getTemp();
|
||||
}
|
||||
|
||||
var menu={
|
||||
"":{
|
||||
"title":" Temp. Graph"
|
||||
},
|
||||
|
||||
"Widgets":{
|
||||
value:widsOn,
|
||||
format:vis=>vis?"Hide":"Show",
|
||||
onchange:vis=>{
|
||||
widsOn=vis;
|
||||
refreshMenu();
|
||||
}
|
||||
},
|
||||
|
||||
"Duration":{
|
||||
value:times.indexOf(duration),
|
||||
min:0,max:times.length-1,step:1,wrap:true,
|
||||
format:tim=>times[tim],
|
||||
onchange:(dur)=>{
|
||||
duration=times[dur];
|
||||
}
|
||||
},
|
||||
|
||||
"Draw Graph":function(){
|
||||
E.showMenu();
|
||||
drawGraph();
|
||||
},
|
||||
|
||||
"Show Graph" : function(){
|
||||
E.showMenu();
|
||||
if(graph.length>0){
|
||||
showGraph();
|
||||
}else{
|
||||
message("No graph to\nshow as no\ngraph has been\ndrawn yet.");
|
||||
}
|
||||
},
|
||||
|
||||
"Save Graph" : function(){
|
||||
E.showMenu();
|
||||
if(graph.length>0){
|
||||
saveGraph();
|
||||
}else{
|
||||
message("No graph to\nsave as no\ngraph has been\ndrawn yet.");
|
||||
}
|
||||
},
|
||||
|
||||
"Save Data" : function(){
|
||||
E.showMenu();
|
||||
if(graph.length>0){
|
||||
saveData();
|
||||
}else{
|
||||
message("No data to\nsave as no\ngraph has been\ndrawn yet.");
|
||||
}
|
||||
},
|
||||
|
||||
"Show Temp":function(){
|
||||
E.showMenu();
|
||||
showTemp();
|
||||
}
|
||||
};
|
||||
|
||||
openMenu();
|
||||
// Temperature Graph
|
||||
// BangleJS Script
|
||||
|
||||
Bangle.setBarometerPower(true,"tempgraph");
|
||||
Bangle.loadWidgets();
|
||||
var widsOn=true;
|
||||
var rm=null;
|
||||
var gt=null;
|
||||
var dg=null;
|
||||
var Layout=require("Layout");
|
||||
var C=true;
|
||||
var temp,tempMode,readErrCnt,watchButton2;
|
||||
|
||||
var graph=require("Storage").readJSON("tempgraph.json",true);
|
||||
if(graph==undefined) {
|
||||
graph=[];
|
||||
}
|
||||
|
||||
var timesData=[
|
||||
// dur=duration, u=time units, d=divisions on graph, s=seconds per unit.
|
||||
{dur:10,u:"Mins",d:5,s:60},
|
||||
{dur:20,u:"Mins",d:4,s:60},
|
||||
{dur:30,u:"Mins",d:3,s:60},
|
||||
{dur:40,u:"Mins",d:4,s:60},
|
||||
{dur:1,u:"Hr",d:4,s:3600},
|
||||
{dur:2,u:"Hrs",d:4,s:3600},
|
||||
{dur:3,u:"Hrs",d:3,s:3600},
|
||||
{dur:4,u:"Hrs",d:4,s:3600},
|
||||
{dur:6,u:"Hrs",d:6,s:3600},
|
||||
{dur:8,u:"Hrs",d:4,s:3600},
|
||||
{dur:12,u:"Hrs",d:6,s:3600},
|
||||
{dur:16,u:"Hrs",d:4,s:3600},
|
||||
{dur:20,u:"Hrs",d:5,s:3600},
|
||||
{dur:1,u:"Day",d:4,s:86400},
|
||||
{dur:2,u:"Days",d:4,s:86400},
|
||||
{dur:3,u:"Days",d:3,s:86400},
|
||||
{dur:4,u:"Days",d:4,s:86400},
|
||||
{dur:5,u:"Days",d:5,s:86400},
|
||||
{dur:6,u:"Days",d:6,s:86400},
|
||||
{dur:7,u:"Days",d:7,s:86400}
|
||||
];
|
||||
var times=[];
|
||||
for(n=0;n<timesData.length;n++){
|
||||
times.push(timesData[n].dur+" "+timesData[n].u);
|
||||
}
|
||||
var durInd=0;
|
||||
var duration=times[durInd];
|
||||
|
||||
function drawWids(){
|
||||
g.clear();
|
||||
if(widsOn){
|
||||
Bangle.drawWidgets();
|
||||
require("widget_utils").show();
|
||||
} else {
|
||||
require("widget_utils").hide();
|
||||
}
|
||||
}
|
||||
|
||||
function openMenu(){
|
||||
drawWids();
|
||||
E.showMenu(menu);
|
||||
}
|
||||
|
||||
function redoMenu(){
|
||||
clearInterval(rm);
|
||||
E.showMenu();
|
||||
openMenu();
|
||||
}
|
||||
|
||||
function refreshMenu(){
|
||||
rm = setInterval(redoMenu,100);
|
||||
}
|
||||
function getF(c){
|
||||
// Get Fahrenheit temperature from Celsius.
|
||||
return c*1.8+32;
|
||||
}
|
||||
|
||||
function getT(){
|
||||
Bangle.getPressure().then(p=>{
|
||||
temp=p.temperature;
|
||||
if(tempMode=="drawGraph"&&graph.length>0&&Math.abs(graph[graph.length-1].temp-temp)>10&&readErrCnt<2){
|
||||
// A large change in temperature may be a reading error. ie. A 0C or less reading after
|
||||
// a 20C reading. So if this happens, the reading is repeated up to 2 times to hopefully
|
||||
// skip such errors.
|
||||
readErrCnt++;
|
||||
print("readErrCnt "+readErrCnt);
|
||||
return;
|
||||
}
|
||||
clearInterval(gt);
|
||||
readErrCnt=0;
|
||||
switch (tempMode){
|
||||
case "showTemp":
|
||||
showT();
|
||||
break;
|
||||
case "drawGraph":
|
||||
var date=new Date();
|
||||
var dateStr=require("locale").date(date).trim();
|
||||
var hrs=date.getHours();
|
||||
var mins=date.getMinutes();
|
||||
var secs=date.getSeconds();
|
||||
graph.push({
|
||||
temp:temp,
|
||||
date:dateStr,
|
||||
hrs:hrs,
|
||||
mins:mins,
|
||||
secs:secs
|
||||
});
|
||||
if(graph.length==1){
|
||||
graph[0].dur=durInd;
|
||||
}
|
||||
require("Storage").writeJSON("tempgraph.json", graph);
|
||||
if(graph.length==150){
|
||||
clearInterval(dg);
|
||||
}
|
||||
drawG();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getTemp(){
|
||||
readErrCnt=0;
|
||||
gt = setInterval(getT,800);
|
||||
}
|
||||
|
||||
function setButton(){
|
||||
var watchButton=setWatch(function(){
|
||||
clearInterval(gt);
|
||||
clearInterval(dg);
|
||||
clearWatch(watchButton);
|
||||
Bangle.removeListener("touch",screenTouch);
|
||||
openMenu();
|
||||
},BTN);
|
||||
Bangle.on('touch',screenTouch);
|
||||
}
|
||||
|
||||
function setButton2(){
|
||||
watchButton2=setWatch(function(){
|
||||
clearWatch(watchButton2);
|
||||
openMenu();
|
||||
},BTN);
|
||||
}
|
||||
|
||||
function zPad(n){
|
||||
return n.toString().padStart(2,0);
|
||||
}
|
||||
|
||||
function screenTouch(n,ev){
|
||||
if(ev.y>23&&ev.y<152){
|
||||
C=C==false;
|
||||
drawG(false);
|
||||
}
|
||||
}
|
||||
|
||||
function drawG(){
|
||||
function cf(t){
|
||||
if(C){
|
||||
return t;
|
||||
}
|
||||
return getF(t);
|
||||
}
|
||||
drawWids();
|
||||
var top=1;
|
||||
var bar=21;
|
||||
var barBot=175-22;
|
||||
if(widsOn){
|
||||
top=25;
|
||||
bar=bar+24;
|
||||
barBot=barBot-24;
|
||||
}
|
||||
var low=graph[0].temp;
|
||||
var hi=low;
|
||||
for(n=0;n<graph.length;n++){
|
||||
var t=graph[n].temp;
|
||||
if(low>t){
|
||||
low=t;
|
||||
}
|
||||
if(hi<t){
|
||||
hi=t;
|
||||
}
|
||||
}
|
||||
var tempHi=Math.ceil((cf(hi)+2)/10)*10;
|
||||
var tempLow=Math.floor((cf(low)-2)/10)*10;
|
||||
var div=2;
|
||||
if(tempHi-tempLow>10){
|
||||
div=5;
|
||||
}
|
||||
if(C){
|
||||
g.setColor(1,0,0);
|
||||
}else{
|
||||
g.setColor(0,0,1);
|
||||
}
|
||||
var step=(barBot-bar)/((tempHi-tempLow)/div);
|
||||
for(n=0;n<graph.length;n++){
|
||||
var pos=tempLow-cf(graph[n].temp);
|
||||
g.drawLine(n+3,pos*(step/div)+barBot,n+3,barBot+3);
|
||||
}
|
||||
g.fillRect(161,barBot+5,174,barBot+20);
|
||||
g.setColor(1,1,1);
|
||||
g.setFont("6x8:2");
|
||||
if(C){
|
||||
g.drawString("C",163,barBot+5);
|
||||
}else{
|
||||
g.drawString("F",163,barBot+5);
|
||||
}
|
||||
g.setColor(0,0,0);
|
||||
g.setFont6x15();
|
||||
g.drawString("Temperature Graph - "+times[graph[0].dur],1,top);
|
||||
g.drawRect(2,bar-4,153,barBot+4);
|
||||
g.setFont("6x8:1");
|
||||
var num=tempHi;
|
||||
for(n=bar;n<=barBot;n=n+step){
|
||||
g.drawLine(3,n,152,n);
|
||||
g.drawString(num.toString().padStart(3," "),155,n-4);
|
||||
num=num-div;
|
||||
}
|
||||
step=151/timesData[graph[0].dur].d;
|
||||
for(n=step+2;n<152;n=n+step){
|
||||
g.drawLine(n,bar-4,n,barBot+4);
|
||||
}
|
||||
grSt=graph[0];
|
||||
g.drawString("Start: "+grSt.date+" "+grSt.hrs+":"+zPad(grSt.mins),1,barBot+6);
|
||||
var lastT=graph[graph.length-1].temp;
|
||||
g.drawString("Last Reading:",1,barBot+14);
|
||||
g.setColor(1,0,0);
|
||||
g.drawString(lastT.toFixed(1)+"C",85,barBot+14);
|
||||
g.setColor(0,0,1);
|
||||
g.drawString(getF(lastT).toFixed(1)+"F",121,barBot+14);
|
||||
process.memory(true);
|
||||
}
|
||||
|
||||
function drawGraph(){
|
||||
setButton();
|
||||
tempMode="drawGraph";
|
||||
durInd=times.indexOf(duration);
|
||||
graph=[];
|
||||
getTemp();
|
||||
dg=setInterval(getTemp,1000*timesData[durInd].dur*timesData[durInd].s/150);
|
||||
}
|
||||
|
||||
function showGraph(){
|
||||
setButton();
|
||||
drawG();
|
||||
}
|
||||
|
||||
function noBluetooth(){
|
||||
if(NRF.getSecurityStatus().connected){
|
||||
return false;
|
||||
}else{
|
||||
message("Error! Your\nBangle Watch\ncurrently has\nno Bluetooth\nconnection.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function saveGraph(){
|
||||
if(noBluetooth()){
|
||||
return;
|
||||
}
|
||||
drawG();
|
||||
g.flip();
|
||||
g.dump();
|
||||
message("Graph has\nbeen sent\nto Web IDE\nfor saving.\n");
|
||||
}
|
||||
|
||||
function saveData(){
|
||||
if(noBluetooth()){
|
||||
return;
|
||||
}
|
||||
drawG();
|
||||
g.flip();
|
||||
print("Temperature Graph - "+times[graph[0].dur]+"\n");
|
||||
print("\"Date\",\"Time\",\"Celsius\",\"Fahrenheit\"");
|
||||
for(n=0;n<graph.length;n++){
|
||||
var gr=graph[n];
|
||||
print("\""+gr.date+"\",\""+gr.hrs+":"+zPad(gr.mins)+":"+zPad(gr.secs)+"\","+gr.temp+","+getF(gr.temp));
|
||||
}
|
||||
message("Data has\nbeen sent\nto Web IDE\nfor saving.\n");
|
||||
}
|
||||
|
||||
function message(mes){
|
||||
setButton2();
|
||||
var messageLO=new Layout({
|
||||
type:"v",c:[
|
||||
{type:"txt",font:"6x8:2",width:171,label:mes,id:"label"},
|
||||
{type:"btn",font:"6x8:2",pad:3,label:"OK",cb:l=>exit()},
|
||||
],lazy:true
|
||||
});
|
||||
drawWids();
|
||||
messageLO.render();
|
||||
}
|
||||
|
||||
function showT(){
|
||||
tempLO.lab1.label=tempLO.lab3.label;
|
||||
tempLO.lab2.label=tempLO.lab4.label;
|
||||
tempLO.lab3.label=tempLO.lab5.label;
|
||||
tempLO.lab4.label=tempLO.lab6.label;
|
||||
tempLO.lab5.label=temp.toFixed(2)+"C";
|
||||
tempLO.lab6.label=getF(temp).toFixed(2)+"F";
|
||||
tempLO.render();
|
||||
}
|
||||
|
||||
function exit(){
|
||||
clearWatch(watchButton2);
|
||||
openMenu();
|
||||
}
|
||||
|
||||
function showTemp(){
|
||||
tempMode="showTemp";
|
||||
setButton2();
|
||||
tempLO=new Layout({
|
||||
type:"v",c:[
|
||||
{type:"h",c:[
|
||||
{type:"txt",pad:5,col:"#f77",font:"6x8:2",label:" ",id:"lab1"},
|
||||
{type:"txt",pad:5,col:"#77f",font:"6x8:2",label:" ",id:"lab2"}
|
||||
]},
|
||||
{type:"h",c:[
|
||||
{type:"txt",pad:5,col:"#f77",font:"6x8:2",label:" ",id:"lab3"},
|
||||
{type:"txt",pad:5,col:"#77f",font:"6x8:2",label:" ",id:"lab4"}
|
||||
]},
|
||||
{type:"h",c:[
|
||||
{type:"txt",pad:5,col:"#f00",font:"6x8:2",label:" ",id:"lab5"},
|
||||
{type:"txt",pad:5,col:"#00f",font:"6x8:2",label:" ",id:"lab6"}
|
||||
]},
|
||||
{type:"h",c:[
|
||||
{type:"btn",pad:2,font:"6x8:2",label:"Temp",cb:l=>getTemp()},
|
||||
{type:"btn",pad:2,font:"6x8:2",label:"Exit",cb:l=>exit()}
|
||||
]}
|
||||
]
|
||||
},{lazy:true});
|
||||
tempLO.render();
|
||||
getTemp();
|
||||
}
|
||||
|
||||
var menu={
|
||||
"":{
|
||||
"title":" Temp. Graph"
|
||||
},
|
||||
|
||||
"Widgets":{
|
||||
value:widsOn,
|
||||
format:vis=>vis?"Hide":"Show",
|
||||
onchange:vis=>{
|
||||
widsOn=vis;
|
||||
refreshMenu();
|
||||
}
|
||||
},
|
||||
|
||||
"Duration":{
|
||||
value:times.indexOf(duration),
|
||||
min:0,max:times.length-1,step:1,wrap:true,
|
||||
format:tim=>times[tim],
|
||||
onchange:(dur)=>{
|
||||
duration=times[dur];
|
||||
}
|
||||
},
|
||||
|
||||
"Draw Graph":function(){
|
||||
E.showMenu();
|
||||
drawGraph();
|
||||
},
|
||||
|
||||
"Show Graph" : function(){
|
||||
E.showMenu();
|
||||
if(graph.length>0){
|
||||
showGraph();
|
||||
}else{
|
||||
message("No graph to\nshow as no\ngraph has been\ndrawn yet.");
|
||||
}
|
||||
},
|
||||
|
||||
"Save Graph" : function(){
|
||||
E.showMenu();
|
||||
if(graph.length>0){
|
||||
saveGraph();
|
||||
}else{
|
||||
message("No graph to\nsave as no\ngraph has been\ndrawn yet.");
|
||||
}
|
||||
},
|
||||
|
||||
"Save Data" : function(){
|
||||
E.showMenu();
|
||||
if(graph.length>0){
|
||||
saveData();
|
||||
}else{
|
||||
message("No data to\nsave as no\ngraph has been\ndrawn yet.");
|
||||
}
|
||||
},
|
||||
|
||||
"Show Temp":function(){
|
||||
E.showMenu();
|
||||
showTemp();
|
||||
}
|
||||
};
|
||||
|
||||
openMenu();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "tempgraph",
|
||||
"name": "Temperature Graph",
|
||||
"shortName":"Temp Graph",
|
||||
"version":"0.01",
|
||||
"version":"0.03",
|
||||
"description": "An app for recording the temperature for time periods ranging from 10 minutes to 7 days.",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
|
|
|
@ -6,3 +6,4 @@
|
|||
0.07: Move CHARGING variable to more readable string
|
||||
0.08: Ensure battery updates every 60s even if LCD was on at boot and stays on
|
||||
0.09: Misc speed/memory tweaks
|
||||
0.10: Color changes due to the battery level
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "widbat",
|
||||
"name": "Battery Level Widget",
|
||||
"version": "0.09",
|
||||
"version": "0.10",
|
||||
"description": "Show the current battery level and charging status in the top right of the clock",
|
||||
"icon": "widget.png",
|
||||
"type": "widget",
|
||||
|
|
|
@ -31,7 +31,11 @@
|
|||
x+=16;
|
||||
}
|
||||
g.setColor(g.theme.fg).fillRect(x,y+2,x+s-4,y+21).clearRect(x+2,y+4,x+s-6,y+19).fillRect(x+s-3,y+10,x+s,y+14);
|
||||
g.setColor("#0f0").fillRect(x+4,y+6,x+4+E.getBattery()*(s-12)/100,y+17);
|
||||
var battery = E.getBattery();
|
||||
if(battery < 20) {g.setColor("#f00");}
|
||||
else if (battery < 50) {g.setColor("#ff0");}
|
||||
else {g.setColor("#0f0");}
|
||||
g.fillRect(x+4,y+6,x+4+battery*(s-12)/100,y+17);
|
||||
}};
|
||||
setWidth();
|
||||
})()
|
||||
|
|
Loading…
Reference in New Issue