diff --git a/apps/arrow/README.md b/apps/arrow/README.md index 4b77dbc42..2833eab24 100644 --- a/apps/arrow/README.md +++ b/apps/arrow/README.md @@ -43,3 +43,7 @@ charge. This app is based in the work done by [jeffmer](https://github.com/jeffmer/JeffsBangleAppsDev) + +Written by: [Hugh Barney](https://github.com/hughbarney) For support +and discussion please post in the [Bangle JS +Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/gpssetup/README.md b/apps/gpssetup/README.md index 8e64c6a30..8c9445ec9 100644 --- a/apps/gpssetup/README.md +++ b/apps/gpssetup/README.md @@ -107,3 +107,8 @@ try { * Some useful code on Github can be found [here](https://portal.u-blox.com/s/question/0D52p0000925T00CAE/ublox-max-m8q-getting-stuck-when-sleeping-with-extint-pin-control) and [here](https://github.com/thasti/utrak/blob/master/gps.c) + + +Written by: [Hugh Barney, with support from Gordon Williams](https://github.com/hughbarney) For support +and discussion please post in the [Bangle JS +Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/kitchen/README.md b/apps/kitchen/README.md index 2a1b148fd..102881d15 100644 --- a/apps/kitchen/README.md +++ b/apps/kitchen/README.md @@ -280,3 +280,8 @@ The following error codes will be displayed if one of the dependancies is not me * Add a small graph to the heart rate monitor app * Add a facility to call the Arrow calibration process * Maybe create waypoints.json file if missing + + +Written by: [Hugh Barney](https://github.com/hughbarney) For support +and discussion please post in the [Bangle JS +Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/mylocation/ChangeLog b/apps/mylocation/ChangeLog index 653f859ae..b9eba67f4 100644 --- a/apps/mylocation/ChangeLog +++ b/apps/mylocation/ChangeLog @@ -1,2 +1,3 @@ 0.01: First release 0.02: Enhanced icon, make it bolder +0.03: Fixed issue with defaulting back to London diff --git a/apps/mylocation/metadata.json b/apps/mylocation/metadata.json index b26a97290..a7fd8356c 100644 --- a/apps/mylocation/metadata.json +++ b/apps/mylocation/metadata.json @@ -4,7 +4,7 @@ "icon": "mylocation.png", "type": "app", "screenshots": [{"url":"screenshot_1.png"}], - "version":"0.02", + "version":"0.03", "description": "Sets and stores the lat and long of your preferred City or it can be set from the GPS. mylocation.json can be used by other apps that need your main location lat and lon. See README", "readme": "README.md", "tags": "tool,utility", diff --git a/apps/mylocation/mylocation.app.js b/apps/mylocation/mylocation.app.js index a2d39a8fd..27ab17ea5 100644 --- a/apps/mylocation/mylocation.app.js +++ b/apps/mylocation/mylocation.app.js @@ -12,7 +12,10 @@ let s = { }; function loadSettings() { - settings = require('Storage').readJSON(SETTINGS_FILE, 1) || s; + settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {}; + for (const key in settings) { + s[key] = settings[key] + } } function save() { @@ -49,7 +52,7 @@ function setFromGPS() { } function showMainMenu() { - // console.log("showMainMenu"); + //console.log("showMainMenu"); const mainmenu = { '': { 'title': 'My Location' }, '{ load(); }, diff --git a/apps/pastel/ChangeLog b/apps/pastel/ChangeLog index 570c37507..d133697b3 100644 --- a/apps/pastel/ChangeLog +++ b/apps/pastel/ChangeLog @@ -13,3 +13,6 @@ which requires 2.11.27 firmware to reset at midnight 0.13: call process.memory(false) to avoid triggering a GC of memory supported in pre 2.12.13 firmware +0.14: incorporated lazybones idle timer, configuration settings to come +0.15: fixed tendancy for mylocation to default to London + added setting to enable/disable idle timer warning diff --git a/apps/pastel/metadata.json b/apps/pastel/metadata.json index 0a04491fc..da3c18eae 100644 --- a/apps/pastel/metadata.json +++ b/apps/pastel/metadata.json @@ -2,8 +2,8 @@ "id": "pastel", "name": "Pastel Clock", "shortName": "Pastel", - "version": "0.13", - "description": "A Configurable clock with custom fonts, background and weather display. Has a cyclic information line that includes, day, date, battery, sunrise and sunset times.", + "version": "0.15", + "description": "A Configurable clock with custom fonts, background and weather display. Has a cyclic information line that includes, day, date, battery, sunrise and sunset times", "icon": "pastel.png", "dependencies": {"mylocation":"app","weather":"app"}, "screenshots": [{"url":"screenshot_pastel.png"}, {"url":"weather_icons.png"}], diff --git a/apps/pastel/pastel.app.js b/apps/pastel/pastel.app.js index 5def5737c..605b78ad0 100644 --- a/apps/pastel/pastel.app.js +++ b/apps/pastel/pastel.app.js @@ -4,9 +4,18 @@ const storage = require('Storage'); const locale = require("locale"); const SETTINGS_FILE = "pastel.json"; const LOCATION_FILE = "mylocation.json"; +const w = g.getWidth(); +const h = g.getHeight(); let settings; let location; +// variable for controlling idle alert +let lastStep = getTime(); +let lastStepTime = '??'; +let warned = 0; +let idle = false; +let IDLE_MINUTES = 26; + // cloud, sun, partSun, snow, rain, storm, error // create 1 bit, max contrast, brightness set to 85 var cloudIcon = require("heatshrink").decompress(atob("kEggIfcj+AAYM/8ADBuFwAYPAmADCCAMBwEf8ADBhFwg4aBnEPAYMYjAVBhgDDDoQDHCYc4jwDB+EP///FYIDBMTgA==")); @@ -16,16 +25,24 @@ var snowIcon = require("heatshrink").decompress(atob("kEggITQj/AAYM98ADBsEwAYPAj var rainIcon = require("heatshrink").decompress(atob("kEggIPMh+AAYM/8ADBuFwAYPgmADB4EbAYOAj/ggOAhnwg4aBnAeCjEcCIMMjADCDoQDHjAPCnAXCuEP///8EDAYJECAAXBwkAgPDhwDBwUMgEEhkggEOjFgFgMQLYQAOA==")); var errIcon = require("heatshrink").decompress(atob("kEggILIgOAAYsD4ADBg/gAYMGsADBhkwAYsYjADCjgDBmEMAYNxxwDBsOGAYPBwYDEgOBwOAgYDB4EDHYPAgwDBsADDhgDBFIcwjAHBjE4AYMcmADBhhNCKIcG/4AGOw4A==")); +// saves having to recode all the small font calls +function setSmallFont() { + g.setFontLatoSmall(); +} function loadSettings() { settings = require("Storage").readJSON(SETTINGS_FILE,1)||{}; settings.grid = settings.grid||false; settings.font = settings.font||"Lato"; + settings.idle_check = settings.idle_check||true; } // requires the myLocation app function loadLocation() { - location = require("Storage").readJSON(LOCATION_FILE,1)||{"lat":51.5072,"lon":0.1276,"location":"London"}; + location = require("Storage").readJSON(LOCATION_FILE,1)||{}; + location.lat = location.lat||51.5072; + location.lon = location.lon||0.1276; + location.location = location.location||"London"; } function extractTime(d){ @@ -71,17 +88,18 @@ function getSteps() { if (WIDGETS.wpedom !== undefined) return WIDGETS.wpedom.getSteps(); else - return '???' + return '???'; } } const infoData = { ID_BLANK: { calc: () => '' }, - ID_DATE: { calc: () => {var d = (new Date).toString().split(" "); return d[2] + ' ' + d[1] + ' ' + d[3];} }, - ID_DAY: { calc: () => {var d = require("locale").dow(new Date).toLowerCase(); return d[0].toUpperCase() + d.substring(1);} }, + ID_DATE: { calc: () => {var d = (new Date()).toString().split(" "); return d[2] + ' ' + d[1] + ' ' + d[3];} }, + ID_DAY: { calc: () => {var d = require("locale").dow(new Date()).toLowerCase(); return d[0].toUpperCase() + d.substring(1);} }, ID_SR: { calc: () => 'Sunrise: ' + sunRise }, ID_SS: { calc: () => 'Sunset: ' + sunSet }, ID_STEP: { calc: () => 'Steps: ' + getSteps() }, + ID_LAST: { calc: () => 'Last Step: ' + lastStepTime }, ID_BATT: { calc: () => 'Battery: ' + E.getBattery() + '%' }, ID_MEM: { calc: () => {var val = process.memory(false); return 'Ram: ' + Math.round(val.usage*100/val.total) + '%';} }, ID_ID: { calc: () => {var val = NRF.getAddress().split(':'); return 'Id: ' + val[4] + val[5];} }, @@ -152,6 +170,14 @@ function getWeather() { } function draw() { + if (!idle) + drawClock(); + else + drawIdle(); + queueDraw(); +} + +function drawClock() { var d = new Date(); var da = d.toString().split(" "); var time = da[4].substr(0,5); @@ -166,11 +192,8 @@ function draw() { if (parseInt(hh) > 12) hh = h2.substr(h2.length -2); - var w = g.getWidth(); - var h = g.getHeight(); var x = (g.getWidth()/2); var y = (g.getHeight()/3); - var weatherJson = getWeather(); var w_temp; var w_icon; @@ -190,7 +213,8 @@ function draw() { } g.reset(); - g.clearRect(0, 30, w, h - 24); + g.setColor(g.theme.bg); + g.fillRect(Bangle.appRect); // draw a grid like graph paper if (settings.grid && process.env.HWVERSION !=1) { @@ -249,6 +273,141 @@ function draw() { queueDraw(); } + +///////////////// IDLE TIMER ///////////////////////////////////// + +function log_debug(o) { + //print(o); +} + +function drawIdle() { + let mins = Math.round((getTime() - lastStep) / 60); + g.reset(); + g.setColor(g.theme.bg); + g.fillRect(Bangle.appRect); + g.setColor(g.theme.fg); + setSmallFont(); + g.setFontAlign(0, 0); + g.drawString('Last step was', w/2, (h/3)); + g.drawString(mins + ' minutes ago', w/2, 20+(h/3)); + dismissBtn.draw(); +} + +/////////////// BUTTON CLASS /////////////////////////////////////////// + +// simple on screen button class +function BUTTON(name,x,y,w,h,c,f,tx) { + this.name = name; + this.x = x; + this.y = y; + this.w = w; + this.h = h; + this.color = c; + this.callback = f; + this.text = tx; +} + +// if pressed the callback +BUTTON.prototype.check = function(x,y) { + //console.log(this.name + ":check() x=" + x + " y=" + y +"\n"); + + if (x>= this.x && x<= (this.x + this.w) && y>= this.y && y<= (this.y + this.h)) { + log_debug(this.name + ":callback\n"); + this.callback(); + return true; + } + return false; +}; + +BUTTON.prototype.draw = function() { + g.setColor(this.color); + g.fillRect(this.x, this.y, this.x + this.w, this.y + this.h); + g.setColor("#000"); // the icons and boxes are drawn black + setSmallFont(); + g.setFontAlign(0, 0); + g.drawString(this.text, (this.x + this.w/2), (this.y + this.h/2)); + g.drawRect(this.x, this.y, (this.x + this.w), (this.y + this.h)); +}; + +function dismissPrompt() { + idle = false; + warned = false; + lastStep = getTime(); + Bangle.buzz(100); + draw(); +} + +var dismissBtn = new BUTTON("big",0, 3*h/4 ,w, h/4, "#0ff", dismissPrompt, "Dismiss"); + +Bangle.on('touch', function(button, xy) { + if (idle && dismissBtn.check(xy.x, xy.y)) return; +}); + +// if we get a step then we are not idle +Bangle.on('step', s => { + setLastStepTime(); + lastStep = getTime(); + // redraw if we had been idle + if (idle == true) { + dismissPrompt(); + } + idle = false; + warned = 0; +}); + +function setLastStepTime() { + var date = new Date(); + lastStepTime = require("locale").time(date,1); +} + +function checkIdle() { + if (!settings.idle_check) { + idle = false; + warned = false; + return; + } + + let hour = (new Date()).getHours(); + let active = (hour >= 9 && hour < 21); + //let active = true; + let dur = getTime() - lastStep; + + if (active && dur > IDLE_MINUTES * 60) { + drawIdle(); + if (warned++ < 3) { + buzzer(warned); + log_debug("checkIdle: warned=" + warned); + Bangle.setLocked(false); + } + idle = true; + } else { + idle = false; + warned = 0; + } +} + +setLastStepTime(); + +// timeout for multi-buzzer +var buzzTimeout; + +// n buzzes +function buzzer(n) { + log_debug("buzzer n=" + n); + + if (n-- < 1) return; + Bangle.buzz(250); + + if (buzzTimeout) clearTimeout(buzzTimeout); + buzzTimeout = setTimeout(function() { + buzzTimeout = undefined; + buzzer(n); + }, 500); +} + + +/////////////////////////////////////////////////////////////////////////////// + // timeout used to update every minute var drawTimeout; @@ -258,6 +417,7 @@ function queueDraw() { drawTimeout = setTimeout(function() { drawTimeout = undefined; prevInfo(); + checkIdle(); draw(); }, 60000 - (Date.now() % 60000)); } diff --git a/apps/pastel/pastel.settings.js b/apps/pastel/pastel.settings.js index bf83fa7c2..26dafd271 100644 --- a/apps/pastel/pastel.settings.js +++ b/apps/pastel/pastel.settings.js @@ -5,6 +5,7 @@ let s = { 'grid': false, 'weather': false, + 'idle_check': true, 'font': "Lato" } @@ -51,6 +52,24 @@ s.weather = !s.weather; save(); }, + }, + // for use when the new menu system goes live + /* + 'Idle Warning': { + value: s.idle_check, + onchange : v => { + s.idle_check = v; + save(); + }, + }, + */ + 'Idle Warning': { + value: s.idle_check, + format: () => (s.idle_check ? 'Yes' : 'No'), + onchange: () => { + s.idle_check = !s.idle_check; + save(); + }, } }) }) diff --git a/apps/simplest/metadata.json b/apps/simplest/metadata.json index d938aab9f..d9d032376 100644 --- a/apps/simplest/metadata.json +++ b/apps/simplest/metadata.json @@ -3,6 +3,7 @@ "name": "Simplest Clock", "version": "0.06", "description": "The simplest working clock, acts as a tutorial piece", + "readme": "README.md", "icon": "simplest.png", "screenshots": [{"url":"screenshot_simplest.png"}], "type": "clock", diff --git a/apps/stepo/README.md b/apps/stepo/README.md index d26f656b7..d3eae7c41 100644 --- a/apps/stepo/README.md +++ b/apps/stepo/README.md @@ -34,3 +34,7 @@ clothing catches it. is 160*160 and is larger than required. The reason for this is that I plan to use this watch face with others in a multiclock format and want to be able to reuse the arrayBuffer with other clocks. + +Written by: [Hugh Barney](https://github.com/hughbarney) For support +and discussion please post in the [Bangle JS +Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/tapelauncher/README.md b/apps/tapelauncher/README.md index 2296dc357..899f15654 100644 --- a/apps/tapelauncher/README.md +++ b/apps/tapelauncher/README.md @@ -15,3 +15,8 @@ Reminiscent of a Telegram or Turing machine tape. **Swipe Left** - move forward to the next app icon **Swipe Right** - move backwards (to the left) to the previous app + + +Written by: [Hugh Barney](https://github.com/hughbarney) For support +and discussion please post in the [Bangle JS +Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/walkersclock/README.md b/apps/walkersclock/README.md index 7ff45a06a..e99b2e610 100644 --- a/apps/walkersclock/README.md +++ b/apps/walkersclock/README.md @@ -59,3 +59,8 @@ on the second line of the watch. ## Future Enhancements * Ability to turn on the heart rate monitor and display the rate on the info line * Maybe a simple stopwatch capability + + +Written by: [Hugh Barney](https://github.com/hughbarney) For support +and discussion please post in the [Bangle JS +Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/waypointer/README.md b/apps/waypointer/README.md index 3f0f529b8..e98fdbb7e 100644 --- a/apps/waypointer/README.md +++ b/apps/waypointer/README.md @@ -174,3 +174,7 @@ The majority of the code in this application is a merge of [jeffmer's](https://github.com/jeffmer/JeffsBangleAppsDev) GPS Navigation and Compass Navigation Applications. + +Written by: [Hugh Barney](https://github.com/hughbarney) For support +and discussion please post in the [Bangle JS +Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/widcom/README.md b/apps/widcom/README.md index 1e45d9090..5043dadea 100644 --- a/apps/widcom/README.md +++ b/apps/widcom/README.md @@ -9,3 +9,8 @@ aware. - Uses Bangle.isCompassOn(), requires firmware v2.08.167 or later - Shows in grey when the compass is off - Shows in amber when the compass is on + + +Written by: [Hugh Barney](https://github.com/hughbarney) For support +and discussion please post in the [Bangle JS +Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/widgps/README.md b/apps/widgps/README.md index 372747486..82aaf7d2f 100644 --- a/apps/widgps/README.md +++ b/apps/widgps/README.md @@ -8,3 +8,7 @@ it is useful to know if it has been switched on or not. - Uses Bangle.isGPSOn() - Shows in grey when the GPS is off - Shows in amber when the GPS is on + +Written by: [Hugh Barney](https://github.com/hughbarney) For support +and discussion please post in the [Bangle JS +Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/widhrt/README.md b/apps/widhrt/README.md index db16d3d35..dc1bb4388 100644 --- a/apps/widhrt/README.md +++ b/apps/widhrt/README.md @@ -6,3 +6,7 @@ Monitor. - Uses Bangle.isHRTOn(). Requires firmware v2.08.167 or later. - Shows in grey when the HRT is off - Shows in red when the HRT is on + +Written by: [Hugh Barney](https://github.com/hughbarney) For support +and discussion please post in the [Bangle JS +Forum](http://forum.espruino.com/microcosms/1424/)