diff --git a/apps/backswipe/ChangeLog b/apps/backswipe/ChangeLog index 5560f00bc..1e5479d6e 100644 --- a/apps/backswipe/ChangeLog +++ b/apps/backswipe/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Don't fire if the app uses swipes already. diff --git a/apps/backswipe/README.md b/apps/backswipe/README.md new file mode 100644 index 000000000..1611263bb --- /dev/null +++ b/apps/backswipe/README.md @@ -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 diff --git a/apps/backswipe/boot.js b/apps/backswipe/boot.js index 523149e8c..e46f902eb 100644 --- a/apps/backswipe/boot.js +++ b/apps/backswipe/boot.js @@ -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(); } } diff --git a/apps/backswipe/metadata.json b/apps/backswipe/metadata.json index 7aa9f6247..0274ec8d7 100644 --- a/apps/backswipe/metadata.json +++ b/apps/backswipe/metadata.json @@ -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", diff --git a/apps/backswipe/settings.js b/apps/backswipe/settings.js index 2c29e86f8..42ca7ae7d 100644 --- a/apps/backswipe/settings.js +++ b/apps/backswipe/settings.js @@ -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(); -}) \ No newline at end of file +}) diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 780d9cc7d..a63a54eaf 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -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 diff --git a/apps/boot/bootupdate.js b/apps/boot/bootupdate.js index 112dfeba8..d929b26a0 100644 --- a/apps/boot/bootupdate.js +++ b/apps/boot/bootupdate.js @@ -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. diff --git a/apps/boot/metadata.json b/apps/boot/metadata.json index 455563a16..9f64b672b 100644 --- a/apps/boot/metadata.json +++ b/apps/boot/metadata.json @@ -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", diff --git a/apps/mtnclock/ChangeLog b/apps/mtnclock/ChangeLog index cbf5c7f40..98cd0cc94 100644 --- a/apps/mtnclock/ChangeLog +++ b/apps/mtnclock/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Get weather from weather.json +0.03: Address unexpected undefined when reading weather.json \ No newline at end of file diff --git a/apps/mtnclock/app.js b/apps/mtnclock/app.js index c6adc7706..a65382dec 100644 --- a/apps/mtnclock/app.js +++ b/apps/mtnclock/app.js @@ -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, diff --git a/apps/mtnclock/metadata.json b/apps/mtnclock/metadata.json index 82a0cccab..2d3d0a02f 100644 --- a/apps/mtnclock/metadata.json +++ b/apps/mtnclock/metadata.json @@ -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", diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog index 85ccfa1a7..9a5579f07 100644 --- a/apps/setting/ChangeLog +++ b/apps/setting/ChangeLog @@ -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 diff --git a/apps/setting/README.md b/apps/setting/README.md index e5ea2b43d..2a7f7ee9c 100644 --- a/apps/setting/README.md +++ b/apps/setting/README.md @@ -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. diff --git a/apps/setting/metadata.json b/apps/setting/metadata.json index 92fc75915..6d5739d03 100644 --- a/apps/setting/metadata.json +++ b/apps/setting/metadata.json @@ -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", diff --git a/apps/setting/settings.js b/apps/setting/settings.js index a877ec79c..bc5f2a74a 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -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(); diff --git a/apps/simplest/simplest.app.js b/apps/simplest/simplest.app.js index 4038212d0..b1e22743d 100644 --- a/apps/simplest/simplest.app.js +++ b/apps/simplest/simplest.app.js @@ -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(); } diff --git a/apps/sleepphasealarm/ChangeLog b/apps/sleepphasealarm/ChangeLog index 4815e5e75..4b119b571 100644 --- a/apps/sleepphasealarm/ChangeLog +++ b/apps/sleepphasealarm/ChangeLog @@ -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 diff --git a/apps/sleepphasealarm/README.md b/apps/sleepphasealarm/README.md index 574e84e1e..5aded316e 100644 --- a/apps/sleepphasealarm/README.md +++ b/apps/sleepphasealarm/README.md @@ -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: -![](screenshot.jpg) +![](screenshot_log.png) + +The logs can also be viewed with the download button in the App Loader: + +![](interface.jpg) diff --git a/apps/sleepphasealarm/app.js b/apps/sleepphasealarm/app.js index 0aef07760..25ca7e781 100644 --- a/apps/sleepphasealarm/app.js +++ b/apps/sleepphasealarm/app.js @@ -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); diff --git a/apps/sleepphasealarm/screenshot.jpg b/apps/sleepphasealarm/interface.jpg similarity index 100% rename from apps/sleepphasealarm/screenshot.jpg rename to apps/sleepphasealarm/interface.jpg diff --git a/apps/sleepphasealarm/metadata.json b/apps/sleepphasealarm/metadata.json index 5382160c0..fabd9f135 100644 --- a/apps/sleepphasealarm/metadata.json +++ b/apps/sleepphasealarm/metadata.json @@ -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"} ] } diff --git a/apps/sleepphasealarm/screenshot.png b/apps/sleepphasealarm/screenshot.png new file mode 100644 index 000000000..769ebbbbc Binary files /dev/null and b/apps/sleepphasealarm/screenshot.png differ diff --git a/apps/sleepphasealarm/screenshot_log.png b/apps/sleepphasealarm/screenshot_log.png new file mode 100644 index 000000000..3442e36ca Binary files /dev/null and b/apps/sleepphasealarm/screenshot_log.png differ diff --git a/apps/sleepphasealarm/settings.js b/apps/sleepphasealarm/settings.js index a79abb598..b6fbdf60b 100644 --- a/apps/sleepphasealarm/settings.js +++ b/apps/sleepphasealarm/settings.js @@ -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(); }) diff --git a/apps/tempgraph/ChangeLog b/apps/tempgraph/ChangeLog index 58dd75a19..74f2d7255 100644 --- a/apps/tempgraph/ChangeLog +++ b/apps/tempgraph/ChangeLog @@ -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. diff --git a/apps/tempgraph/app.js b/apps/tempgraph/app.js index a0bb3016b..b8dd231ae 100644 --- a/apps/tempgraph/app.js +++ b/apps/tempgraph/app.js @@ -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{ - 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;nt){ - low=t; - } - if(hi10){ - 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;nexit()}, - ],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{ + 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;nt){ + low=t; + } + if(hi10){ + 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;nexit()}, + ],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(); diff --git a/apps/tempgraph/metadata.json b/apps/tempgraph/metadata.json index 6772429a5..63d4feddd 100644 --- a/apps/tempgraph/metadata.json +++ b/apps/tempgraph/metadata.json @@ -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", diff --git a/apps/widbat/ChangeLog b/apps/widbat/ChangeLog index 5986ecf3f..59c58af32 100644 --- a/apps/widbat/ChangeLog +++ b/apps/widbat/ChangeLog @@ -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 diff --git a/apps/widbat/metadata.json b/apps/widbat/metadata.json index 993310eb2..5f0d1b7d1 100644 --- a/apps/widbat/metadata.json +++ b/apps/widbat/metadata.json @@ -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", diff --git a/apps/widbat/widget.js b/apps/widbat/widget.js index a8a0c5382..7fce16335 100644 --- a/apps/widbat/widget.js +++ b/apps/widbat/widget.js @@ -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(); })()