From 85d23d3db91a839408c1c28cf37225e04320bce0 Mon Sep 17 00:00:00 2001 From: jeffmer Date: Sat, 5 Dec 2020 10:41:50 +0000 Subject: [PATCH 01/12] update gpsnav to use locale + add en_NAV --- apps.json | 6 +-- apps/gpsnav/ChangeLog | 2 + apps/gpsnav/app.js | 87 +++++++++++++++++++----------------------- apps/gpsnav/app.min.js | 11 ++++++ apps/locale/ChangeLog | 1 + apps/locale/locales.js | 24 +++++++++++- 6 files changed, 79 insertions(+), 52 deletions(-) create mode 100644 apps/gpsnav/app.min.js diff --git a/apps.json b/apps.json index f8f46d4a7..8c00cfec8 100644 --- a/apps.json +++ b/apps.json @@ -65,7 +65,7 @@ { "id": "locale", "name": "Languages", "icon": "locale.png", - "version":"0.07", + "version":"0.08", "description": "Translations for different countries", "tags": "tool,system,locale,translate", "type": "locale", @@ -379,13 +379,13 @@ { "id": "gpsnav", "name": "GPS Navigation", "icon": "icon.png", - "version":"0.04", + "version":"0.05", "description": "Displays GPS Course and Speed, + Directions to waypoint and waypoint recording, now with waypoint editor", "tags": "tool,outdoors,gps", "readme": "README.md", "interface":"waypoints.html", "storage": [ - {"name":"gpsnav.app.js","url":"app.js"}, + {"name":"gpsnav.app.js","url":"app.min.js"}, {"name":"waypoints.json","url":"waypoints.json","evaluate":false}, {"name":"gpsnav.img","url":"app-icon.js","evaluate":true} ] diff --git a/apps/gpsnav/ChangeLog b/apps/gpsnav/ChangeLog index ee8b61d7b..b4eaf5472 100644 --- a/apps/gpsnav/ChangeLog +++ b/apps/gpsnav/ChangeLog @@ -2,3 +2,5 @@ 0.02: Add SCREENACCESS interface 0.03: Add Waypoint Editor 0.04: Fix great circle formula +0.05: Use locale for speed and distance + fix Vector font sizes + diff --git a/apps/gpsnav/app.js b/apps/gpsnav/app.js index 3bbc756b7..99b5cf2c9 100644 --- a/apps/gpsnav/app.js +++ b/apps/gpsnav/app.js @@ -4,18 +4,19 @@ var buf = Graphics.createArrayBuffer(240,50,2,{msb:true}); var candraw = true; function flip(b,y) { - g.drawImage({width:240,height:50,bpp:2,buffer:b.buffer, palette:pal2color},0,y); - b.clear(); + g.drawImage({width:240,height:50,bpp:2,buffer:b.buffer, palette:pal2color},0,y); + b.clear(); } var brg=0; var wpindex=0; const labels = ["N","NE","E","SE","S","SW","W","NW"]; +var loc = require("locale"); function drawCompass(course) { if (!candraw) return; buf.setColor(1); - buf.setFont("Vector",16); + buf.setFont("Vector",24); var start = course-90; if (start<0) start+=360; buf.fillRect(28,45,212,49); @@ -44,27 +45,21 @@ function drawCompass(course) { if (bpos>210) bpos = 226; buf.setColor(2); buf.fillCircle(bpos,40,8); - } + } flip(buf,Yoff); } //displayed heading var heading = 0; -function newHeading(m,h){ - var s = Math.abs(m - h); - var delta = 1; - if (s<2) return h; - if (m > h){ - if (s >= 180) { delta = -1; s = 360 - s;} - } else if (m <= h){ - if (s < 180) delta = -1; - else s = 360 -s; - } - delta = delta * (1 + Math.round(s/15)); - heading+=delta; - if (heading<0) heading += 360; - if (heading>360) heading -= 360; - return heading; +function newHeading(m,h){ + var s = Math.abs(m - h); + var delta = (m>h)?1:-1; + if (s>=180){s=360-s; delta = -delta;} + if (s<2) return h; + var hd = h + delta*(1 + Math.round(s/5)); + if (hd<0) hd+=360; + if (hd>360)hd-= 360; + return hd; } var course =0; @@ -93,27 +88,28 @@ function bearing(a,b){ } function distance(a,b){ - var dsigma = Math.acos(Math.sin(radians(a.lat))*Math.sin(radians(b.lat))+Math.cos(radians(a.lat))*Math.cos(radians(b.lat))*Math.cos(radians(a.lon-b.lon))); - return Math.round(dsigma*6371000); + var x = radians(a.lon-b.lon) * Math.cos(radians((a.lat+b.lat)/2)); + var y = radians(b.lat-a.lat); + return Math.round(Math.sqrt(x*x + y*y) * 6371000); } var selected = false; function drawN(){ + var txt = loc.speed(speed); buf.setColor(1); buf.setFont("6x8",2); buf.drawString("o",100,0); buf.setFont("6x8",1); - buf.drawString("kph",220,40); - buf.setFont("Vector",40); + buf.drawString(txt.substring(txt.length-3),220,40); + buf.setFont("Vector",48); var cs = course.toString(); cs = course<10?"00"+cs : course<100 ?"0"+cs : cs; buf.drawString(cs,10,0); - var txt = (speed<10) ? speed.toFixed(1) : Math.round(speed); - buf.drawString(txt,140,4); + buf.drawString(txt.substring(0,txt.length-3),140,4); flip(buf,Yoff+70); buf.setColor(1); - buf.setFont("Vector",20); + buf.setFont("Vector",24); var bs = brg.toString(); bs = brg<10?"00"+bs : brg<100 ?"0"+bs : bs; buf.setColor(3); @@ -123,10 +119,7 @@ function drawN(){ buf.drawString(wp.name,140,0); buf.setColor(1); buf.drawString(bs,60,0); - if (dist<1000) - buf.drawString(dist.toString()+"m",60,30); - else - buf.drawString((dist/1000).toFixed(2)+"Km",60,30); + buf.drawString(loc.distance(dist),60,30); flip(buf,Yoff+130); g.setFont("6x8",1); g.setColor(0,0,0); @@ -165,7 +158,7 @@ function stopdraw() { function startTimers() { candraw=true; intervalRefSec = setInterval(function() { - newHeading(course,heading); + heading = newHeading(course,heading); if (course!=heading) drawCompass(heading); },200); } @@ -189,20 +182,20 @@ function setButtons(){ setWatch(nextwp.bind(null,-1), BTN1, {repeat:true,edge:"falling"}); setWatch(doselect, BTN2, {repeat:true,edge:"falling"}); setWatch(nextwp.bind(null,1), BTN3, {repeat:true,edge:"falling"}); -} +}; var SCREENACCESS = { - withApp:true, - request:function(){ - this.withApp=false; - stopdraw(); - clearWatch(); - }, - release:function(){ - this.withApp=true; - startdraw(); - setButtons(); - } + withApp:true, + request:function(){ + this.withApp=false; + stopdraw(); + clearWatch(); + }, + release:function(){ + this.withApp=true; + startdraw(); + setButtons(); + } } Bangle.on('lcdPower',function(on) { @@ -227,10 +220,10 @@ function nextwp(inc){ } function doselect(){ - if (selected && waypoints[wpindex].lat===undefined && savedfix.fix) { - waypoints[wpindex] ={name:"@"+wp.name, lat:savedfix.lat, lon:savedfix.lon}; - wp = waypoints[wpindex]; - require("Storage").writeJSON("waypoints.json", waypoints); + if (selected && wpindex!=0 && waypoints[wpindex].lat===undefined && savedfix.fix) { + waypoints[wpindex] ={name:"@"+wp.name, lat:savedfix.lat, lon:savedfix.lon}; + wp = waypoints[wpindex]; + require("Storage").writeJSON("waypoints.json", waypoints); } selected=!selected; drawN(); diff --git a/apps/gpsnav/app.min.js b/apps/gpsnav/app.min.js new file mode 100644 index 000000000..7771e2b98 --- /dev/null +++ b/apps/gpsnav/app.min.js @@ -0,0 +1,11 @@ +var Yoff=40,pal2color=new Uint16Array([0,65535,2047,50712],0,2),buf=Graphics.createArrayBuffer(240,50,2,{msb:!0}),candraw=!0;function flip(a,c){g.drawImage({width:240,height:50,bpp:2,buffer:a.buffer,palette:pal2color},0,c);a.clear()}var brg=0,wpindex=0,labels="N NE E SE S SW W NW".split(" "),loc=require("locale"); +function drawCompass(a){if(candraw){buf.setColor(1);buf.setFont("Vector",24);var c=a-90;0>c&&(c+=360);buf.fillRect(28,45,212,49);var b=30,d=15-c%15;15>d?b+=d:d=0;for(var e=d;e<=180-d;e+=15){var f=c+e;0==f%90?(buf.drawString(labels[Math.floor(f/45)%8],b-8,0),buf.fillRect(b-2,25,b+2,45)):0==f%45?(buf.drawString(labels[Math.floor(f/45)%8],b-12,0),buf.fillRect(b-2,30,b+2,45)):0==f%15&&buf.fillRect(b,35,b+1,45);b+=15}0!=wpindex&&(a=brg-a,180a&&(a+=360),a+=120,30>a&&(a=14),210c?1:-1;180<=b&&(b=360-b,d=-d);if(2>b)return c;b=c+d*(1+Math.round(b/5));0>b&&(b+=360);360course?"00"+c:100>course?"0"+c:c;buf.drawString(c,10,0);buf.drawString(a.substring(0,a.length-3),140,4);flip(buf,Yoff+70);buf.setColor(1);buf.setFont("Vector",24);a=brg.toString();a=10>brg?"00"+a:100>brg?"0"+a:a;buf.setColor(3);buf.drawString("Brg: ",0,0);buf.drawString("Dist: ", +0,30);buf.setColor(selected?1:2);buf.drawString(wp.name,140,0);buf.setColor(1);buf.drawString(a,60,0);buf.drawString(loc.distance(dist),60,30);flip(buf,Yoff+130);g.setFont("6x8",1);g.setColor(0,0,0);g.fillRect(10,230,60,239);g.setColor(1,1,1);g.drawString("Sats "+satellites.toString(),10,230)}var savedfix; +function onGPS(a){savedfix=a;void 0!==a&&(course=isNaN(a.course)?course:Math.round(a.course),speed=isNaN(a.speed)?speed:a.speed,satellites=a.satellites);candraw&&(void 0!==a&&1==a.fix&&(dist=distance(a,wp),isNaN(dist)&&(dist=0),brg=bearing(a,wp),isNaN(brg)&&(brg=0)),drawN())}var intervalRef;function stopdraw(){candraw=!1;intervalRef&&clearInterval(intervalRef)} +function startTimers(){candraw=!0;intervalRefSec=setInterval(function(){heading=newHeading(course,heading);course!=heading&&drawCompass(heading)},200)}function drawAll(){g.setColor(1,.5,.5);g.fillPoly([120,Yoff+50,110,Yoff+70,130,Yoff+70]);g.setColor(1,1,1);drawN();drawCompass(heading)}function startdraw(){g.clear();Bangle.drawWidgets();startTimers();drawAll()} +function setButtons(){setWatch(nextwp.bind(null,-1),BTN1,{repeat:!0,edge:"falling"});setWatch(doselect,BTN2,{repeat:!0,edge:"falling"});setWatch(nextwp.bind(null,1),BTN3,{repeat:!0,edge:"falling"})}var SCREENACCESS={withApp:!0,request:function(){this.withApp=!1;stopdraw();clearWatch()},release:function(){this.withApp=!0;startdraw();setButtons()}};Bangle.on("lcdPower",function(a){SCREENACCESS.withApp&&(a?startdraw():stopdraw())});var waypoints=require("Storage").readJSON("waypoints.json")||[{name:"NONE"}]; +wp=waypoints[0];function nextwp(a){selected&&(wpindex+=a,wpindex>=waypoints.length&&(wpindex=0),0>wpindex&&(wpindex=waypoints.length-1),wp=waypoints[wpindex],drawN())}function doselect(){selected&&0!=wpindex&&void 0===waypoints[wpindex].lat&&savedfix.fix&&(waypoints[wpindex]={name:"@"+wp.name,lat:savedfix.lat,lon:savedfix.lon},wp=waypoints[wpindex],require("Storage").writeJSON("waypoints.json",waypoints));selected=!selected;drawN()}g.clear();Bangle.setLCDBrightness(1);Bangle.loadWidgets();Bangle.drawWidgets(); +Bangle.setGPSPower(1);drawAll();startTimers();Bangle.on("GPS",onGPS);setButtons(); diff --git a/apps/locale/ChangeLog b/apps/locale/ChangeLog index 8338f9f84..c6779bf27 100644 --- a/apps/locale/ChangeLog +++ b/apps/locale/ChangeLog @@ -7,3 +7,4 @@ 0.06: Remove translations if not required Ensure 'on' is always supplied for translations 0.07: Improve handling of non-ASCII characters (fix #469) +0.08: Added Mavigation units and en_NAV diff --git a/apps/locale/locales.js b/apps/locale/locales.js index c29a49937..8d5165711 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -4,13 +4,15 @@ const distanceUnits = { // how many meters per X? "yd": 0.9144, "mi": 1609.34, "km": 1000, - "kmi": 1000 + "kmi": 1000, + "nm": 1852 }; const speedUnits = { // how many kph per X? "kmh": 1, "kph": 1, "km/h": 1, - "mph": 1.60934 + "mph": 1.60934, + "kts": 1.852 }; /* @@ -99,6 +101,24 @@ var locales = { day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", // No translation for english... }, + "en_NAV": { // navigation units nautical miles and knots + lang: "en_NAV", + decimal_point: ".", + thousands_sep: ",", + currency_symbol: "£", currency_first: true, + int_curr_symbol: "GBP", + speed: 'kts', + distance: { "0": "m", "1": "nm" }, + temperature: '°C', + ampm: { 0: "am", 1: "pm" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%b %d %Y", 1: "%d/%m/%Y" }, // Feb 28 2020" // "01/03/2020"(short) + abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", + month: "January,February,March,April,May,June,July,August,September,October,November,December", + abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", + day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", + // No translation for english... + }, "de_DE": { lang: "de_DE", decimal_point: ",", From 15ee6212b8d96767fa5188fd946d57722bc5ce2a Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 7 Dec 2020 08:59:29 +0000 Subject: [PATCH 02/12] Fix en_IN speed, add NAV icons --- apps/locale/locale.html | 2 ++ apps/locale/locales.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/locale/locale.html b/apps/locale/locale.html index 2389203bb..3d806b44b 100644 --- a/apps/locale/locale.html +++ b/apps/locale/locale.html @@ -96,6 +96,8 @@ exports = { name : "en_GB", currencySym:"£", // If we have a 2 char ISO country code, use it to get the unicode flag if (localeParts[1] && localeParts[1].length==2) icon = localeParts[1].toUpperCase().replace(/./g, char => String.fromCodePoint(char.charCodeAt(0)+127397) )+" "; + if (localeParts[1]=="NAV") + icon = "⛵✈️ "; return `` }).join("\n"); diff --git a/apps/locale/locales.js b/apps/locale/locales.js index 8d5165711..0861bc907 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -89,7 +89,7 @@ var locales = { currency_symbol: "Rs.", currency_first: true, int_curr_symbol: "INR", - speed: 'kms', + speed: 'kmh', distance: { "0": "m", "1": "km" }, temperature: '°C', ampm: { 0: "am", 1: "pm" }, From bd76e1d98e6f85b21fa2668ea851a51528d75003 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 7 Dec 2020 09:01:04 +0000 Subject: [PATCH 03/12] minor tweak to make lint happy --- apps/gpsnav/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/gpsnav/app.js b/apps/gpsnav/app.js index 99b5cf2c9..8903e07fb 100644 --- a/apps/gpsnav/app.js +++ b/apps/gpsnav/app.js @@ -182,7 +182,7 @@ function setButtons(){ setWatch(nextwp.bind(null,-1), BTN1, {repeat:true,edge:"falling"}); setWatch(doselect, BTN2, {repeat:true,edge:"falling"}); setWatch(nextwp.bind(null,1), BTN3, {repeat:true,edge:"falling"}); -}; +} var SCREENACCESS = { withApp:true, From 9a3b203429d2270273baec6e0c8d34c21a420e4c Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 8 Dec 2020 14:13:01 +0000 Subject: [PATCH 04/12] gadgetbridge: 0.18: Added reporting of step count and HRM (new Gadgetbridges can now log this) --- apps.json | 2 +- apps/gbridge/ChangeLog | 1 + apps/gbridge/settings.js | 5 +++ apps/gbridge/widget.js | 84 +++++++++++++++++++++++++++++++++++++--- 4 files changed, 86 insertions(+), 6 deletions(-) diff --git a/apps.json b/apps.json index 03278f45d..fe9db5472 100644 --- a/apps.json +++ b/apps.json @@ -139,7 +139,7 @@ { "id": "gbridge", "name": "Gadgetbridge", "icon": "app.png", - "version":"0.17", + "version":"0.18", "description": "The default notification handler for Gadgetbridge notifications from Android", "tags": "tool,system,android,widget", "type":"widget", diff --git a/apps/gbridge/ChangeLog b/apps/gbridge/ChangeLog index 9a3090f5d..bec2d305a 100644 --- a/apps/gbridge/ChangeLog +++ b/apps/gbridge/ChangeLog @@ -17,3 +17,4 @@ 0.16: Handle dismissing notifications on the phone Nicer display of alarm clock notifications 0.17: Modified music notification for updated 'notify' library +0.18: Added reporting of step count and HRM (new Gadgetbridges can now log this) diff --git a/apps/gbridge/settings.js b/apps/gbridge/settings.js index d1ecb594b..fbb4d98a7 100644 --- a/apps/gbridge/settings.js +++ b/apps/gbridge/settings.js @@ -30,6 +30,11 @@ onchange: setIcon }, "Find Phone" : function() { E.showMenu(findPhone); }, + "Record HRM" : { + value: settings().hrm, + format: v => v?"Yes":"No", + onchange: v => updateSetting('hrm', v) + }, "< Back" : back, }; diff --git a/apps/gbridge/widget.js b/apps/gbridge/widget.js index b4c7e1f7b..c8e363c6b 100644 --- a/apps/gbridge/widget.js +++ b/apps/gbridge/widget.js @@ -1,4 +1,5 @@ (() => { + // Music handling const state = { music: "stop", @@ -10,13 +11,17 @@ scrollPos: 0 }; - + // activity reporting + var currentSteps = 0, lastSentSteps=0; + var activityInterval; + var hrmTimeout; + function settings() { let settings = require('Storage').readJSON("gbridge.json", true) || {}; if (!("showIcon" in settings)) { settings.showIcon = true; } - return settings + return settings; } function gbSend(message) { @@ -143,6 +148,36 @@ setTimeout(_=>Bangle.beep(), 1000); },2000); } + + function handleActivityEvent(event) { + // TODO: `t:"act", hrm:bool, stp:bool, int:int` - Enable realtime step counting, realtime heart rate. 'int' is the report interval in seconds + // add live view, + var s = settings(); + if (s.activityInterval===undefined || + s.activityInterval<30) + s.activityInterval = 30*60; // 3 minutes default + if (event.int) { + if (event.int<30) event.int = 30; // min 30 secs + s.activityInterval = event.int; + require('Storage').write("gbridge.json", s); + } + var interval = s.activityInterval; + if (activityInterval) + clearInterval(activityInterval); + activityInterval = undefined; + Bangle.setHRMPower(1); + if (event.hrm || event.stp) { + // if realtime reporting, leave HRM on and use that to trigger events + hrmTimeout = undefined; + } else { + // else trigger it manually every so often + hrmTimeout = 5; + activityInterval = setInterval(function() { + hrmTimeout = 5; + Bangle.setHRMPower(1); + }, interval*1000); + } + } var _GB = global.GB; global.GB = (event) => { @@ -163,6 +198,9 @@ case "find": handleFindEvent(event); break; + case "act": + handleActivityEvent(event); + break; } if(_GB)setTimeout(_GB,0,event); }; @@ -201,14 +239,50 @@ } } - WIDGETS["gbridgew"] = {area: "tl", width: 24, draw: draw, reload: reload}; - reload(); - function sendBattery() { gbSend({ t: "status", bat: E.getBattery() }); } + + // Turn on HRM and get a reading + function getHRM(callback) { + if (settings().hrm) { + Bangle.setHRMPower(1); + var timeout = 5; + + } else { + callback(-1); + } + } + + // Send a summary of activity to Gadgetbridge + function sendActivity(hrm) { + var steps = currentSteps - lastSentSteps; + lastSentSteps = 0; + gbSend({ t: "act", stp: steps, hrm:hrm }); + } + // Battery monitor NRF.on("connect", () => setTimeout(sendBattery, 2000)); setInterval(sendBattery, 10*60*1000); sendBattery(); + // Activity monitor + Bangle.on("step", s => { + if (!lastSentSteps) + lastSentSteps = s-1; + currentSteps = s; + }); + Bangle.on('HRM',function(hrm) { + var ok = hrm.confidence>80; + if (hrmTimeout!==undefined) hrmTimeout--; + if (ok || hrmTimeout<=0) { + if (hrmTimeout!==undefined) + Bangle.setHRMPower(0); + sendActivity(hrm.confidence>20 ? hrm.bpm : -1); + } + }); + handleActivityEvent({}); // kicks off activity reporting + + // Finally add widget + WIDGETS["gbridgew"] = {area: "tl", width: 24, draw: draw, reload: reload}; + reload(); })(); From 23aa25dbeff504418f66cb145c7dfd536f703baf Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 8 Dec 2020 14:41:38 +0000 Subject: [PATCH 05/12] tweaks - sort out activity handling when HRM=false (default), add README --- apps.json | 1 + apps/gbridge/README.md | 54 ++++++++++++++++++++++++++++++++++++++++ apps/gbridge/settings.js | 2 +- apps/gbridge/widget.js | 46 ++++++++++++++++------------------ 4 files changed, 78 insertions(+), 25 deletions(-) create mode 100644 apps/gbridge/README.md diff --git a/apps.json b/apps.json index fe9db5472..f31a77243 100644 --- a/apps.json +++ b/apps.json @@ -142,6 +142,7 @@ "version":"0.18", "description": "The default notification handler for Gadgetbridge notifications from Android", "tags": "tool,system,android,widget", + "readme": "README.md", "type":"widget", "dependencies": { "notify":"type" }, "storage": [ diff --git a/apps/gbridge/README.md b/apps/gbridge/README.md new file mode 100644 index 000000000..867b736ab --- /dev/null +++ b/apps/gbridge/README.md @@ -0,0 +1,54 @@ +Gadgetbridge +============= + +This widget allows your Bangle.js to communicate with the Gadgetbridge app on an Android phone. + +Download the [latest Gadgetbridge for Android here](https://f-droid.org/packages/nodomain.freeyourgadget.gadgetbridge/). + +This app supports: + +* Displaying Notifications +* Song display and control +* Call answering +* Find My Phone / Find My Bangle +* Activity reporting + +You can also add [the weather widget](https://banglejs.com/apps/#weather) + + +Notifications +------------- + +By default a notification at the top of the screen is displayed. If you'd like a fullscreen notification +(which will involve leaving the current app) then install [Fullscreen Notifications](https://banglejs.com/apps/#notifyfs) + + +Song display and control +------------------------ + +When the Song Display notification is showing on the screen and a song is playing, you +can swipe left or right on the screen to go to the next or previous song. + + +Find My Phone +------------- + +Go to `Settings`, `App/Widget Settings`, `Gadgetbridge`, `Find Phone`, `On` + +If in range and connected your phone should start ringing. + + +Find My Bangle +------------- + +Onyour phone `Settings`, `App/Widget Settings`, `Gadgetbridge`, `Find Phone`, `On` + +If in range and connected your phone should start ringing. + + +Activity reporting +------------------ + +You'll need a Gadgetbridge release *after* version 0.50.0 for Actvity Reporting to be enabled. + +By default heart rate isn't reported, but it can be enabled from `Settings`, `App/Widget Settings`, `Gadgetbridge`, `Record HRM` diff --git a/apps/gbridge/settings.js b/apps/gbridge/settings.js index fbb4d98a7..42fa84a3e 100644 --- a/apps/gbridge/settings.js +++ b/apps/gbridge/settings.js @@ -12,7 +12,7 @@ function updateSetting(setting, value) { let settings = require('Storage').readJSON("gbridge.json", true) || {}; settings[setting] = value - require('Storage').write('gbridge.json', settings); + require('Storage').writeJSON('gbridge.json', settings); } function setIcon(visible) { updateSetting('showIcon', visible); diff --git a/apps/gbridge/widget.js b/apps/gbridge/widget.js index c8e363c6b..d616e8816 100644 --- a/apps/gbridge/widget.js +++ b/apps/gbridge/widget.js @@ -150,31 +150,40 @@ } function handleActivityEvent(event) { - // TODO: `t:"act", hrm:bool, stp:bool, int:int` - Enable realtime step counting, realtime heart rate. 'int' is the report interval in seconds - // add live view, var s = settings(); + // handle setting activity interval if (s.activityInterval===undefined || s.activityInterval<30) - s.activityInterval = 30*60; // 3 minutes default + s.activityInterval = 3*60; // 3 minutes default if (event.int) { if (event.int<30) event.int = 30; // min 30 secs s.activityInterval = event.int; - require('Storage').write("gbridge.json", s); + require('Storage').writeJSON("gbridge.json", s); } + // set up interval/HRM to handle activity data var interval = s.activityInterval; + var realtime = event.hrm || event.stp; if (activityInterval) clearInterval(activityInterval); activityInterval = undefined; - Bangle.setHRMPower(1); - if (event.hrm || event.stp) { - // if realtime reporting, leave HRM on and use that to trigger events - hrmTimeout = undefined; - } else { - // else trigger it manually every so often - hrmTimeout = 5; - activityInterval = setInterval(function() { + if (s.hrm) Bangle.setHRMPower(1); + if (s.hrm) { + if (realtime) { + // if realtime reporting, leave HRM on and use that to trigger events + hrmTimeout = undefined; + } else { + // else trigger it manually every so often hrmTimeout = 5; - Bangle.setHRMPower(1); + activityInterval = setInterval(function() { + hrmTimeout = 5; + Bangle.setHRMPower(1); + }, interval*1000); + } + } else { + // no HRM - manually push data + if (realtime) interval=10; + activityInterval = setInterval(function() { + sendActivity(-1); }, interval*1000); } } @@ -243,17 +252,6 @@ gbSend({ t: "status", bat: E.getBattery() }); } - // Turn on HRM and get a reading - function getHRM(callback) { - if (settings().hrm) { - Bangle.setHRMPower(1); - var timeout = 5; - - } else { - callback(-1); - } - } - // Send a summary of activity to Gadgetbridge function sendActivity(hrm) { var steps = currentSteps - lastSentSteps; From 4dc6ea864c3df6718bc7041e49d22b352d2584c9 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 8 Dec 2020 15:23:53 +0000 Subject: [PATCH 06/12] remove custom progress bar - bangle loader does this now automatically --- apps/assistedgps/custom.html | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/assistedgps/custom.html b/apps/assistedgps/custom.html index e86c660b9..b615f2217 100644 --- a/apps/assistedgps/custom.html +++ b/apps/assistedgps/custom.html @@ -84,15 +84,13 @@ var chunkSize = 128; var js = "\x10Bangle.setGPSPower(1);\n"; // turn GPS on //js += `\x10Bangle.on('GPS-raw',function (d) { if (d.startsWith("\\xB5\\x62\\x05\\x01")) Terminal.println("GPS ACK"); else if (d.startsWith("\\xB5\\x62\\x05\\x00")) Terminal.println("GPS NACK"); })\n`; - js += "\x10E.showMessage('Uploading...','AGPS');function p(n) {g.fillRect(0,g.getHeight()-80,g.getWidth()*n,g.getHeight()-60);}"; //js += "\x10var t=getTime()+1;while(t>getTime());\n"; // wait 1 sec js += `\x10Serial1.write(atob("${btoa(String.fromCharCode.apply(null,UBX_MGA_INI_TIME_UTC()))}"))\n`; // set GPS time - + for (var i=0;i Date: Tue, 8 Dec 2020 15:40:15 +0000 Subject: [PATCH 07/12] openstmap: 0.04: Move map rendering to a module (fix #396) gpsrec: 0.14: Now use the openstmap lib for map plotting --- apps.json | 10 +++--- apps/gpsrec/ChangeLog | 1 + apps/gpsrec/app.js | 69 +++++++++++-------------------------- apps/openstmap/ChangeLog | 1 + apps/openstmap/app.js | 45 +++++------------------- apps/openstmap/openstmap.js | 66 +++++++++++++++++++++++++++++++++++ 6 files changed, 102 insertions(+), 90 deletions(-) create mode 100644 apps/openstmap/openstmap.js diff --git a/apps.json b/apps.json index f31a77243..697c78dc9 100644 --- a/apps.json +++ b/apps.json @@ -363,7 +363,7 @@ { "id": "gpsrec", "name": "GPS Recorder", "icon": "app.png", - "version":"0.13", + "version":"0.14", "interface": "interface.html", "description": "Application that allows you to record a GPS track. Can run in background", "tags": "tool,outdoors,gps,widget", @@ -942,12 +942,12 @@ ] }, { "id": "assistedgps", - "name": "Assisted GPS Update", + "name": "Assisted GPS Update (AGPS)", "icon": "app.png", "version":"0.01", "description": "Downloads assisted GPS data to Bangle.js for faster GPS startup and more accurate fixes", "custom": "custom.html", - "tags": "tool,outdoors", + "tags": "tool,outdoors,agps", "type": "RAM", "storage": [ ] }, @@ -1326,7 +1326,7 @@ "name": "OpenStreetMap", "shortName":"OpenStMap", "icon": "app.png", - "version":"0.03", + "version":"0.04", "description": "[BETA] Loads map tiles from OpenStreetMap onto your Bangle.js and displays a map of where you are", "tags": "outdoors,gps", "custom": "custom.html", @@ -2474,6 +2474,6 @@ "storage": [ {"name":"gmeter.app.js","url":"app.js"}, {"name":"gmeter.img","url":"app-icon.js","evaluate":true} - ] + ] } ] diff --git a/apps/gpsrec/ChangeLog b/apps/gpsrec/ChangeLog index 01788e08f..ddb7e7dc4 100644 --- a/apps/gpsrec/ChangeLog +++ b/apps/gpsrec/ChangeLog @@ -15,3 +15,4 @@ 0.12: Add option to plot on top of OpenStreetMap tiles (when they are installed on the watch) 0.13: Increase GPS recording accuracy by one decimal place Ensure default time period is 10 +0.14: Now use the openstmap lib for map plotting diff --git a/apps/gpsrec/app.js b/apps/gpsrec/app.js index c7de29d32..4fa51e3e1 100644 --- a/apps/gpsrec/app.js +++ b/apps/gpsrec/app.js @@ -2,7 +2,10 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); var settings = require("Storage").readJSON("gpsrec.json",1)||{}; -var qOpenStMap = (require("Storage").list("openstmap.json")>0); +var osm; +try { // if it's installed, use the OpenStreetMap module + osm = require("openstmap"); +} catch (e) {} function getFN(n) { return ".gpsrc"+n.toString(36); @@ -134,7 +137,7 @@ function viewTrack(n, info) { info.qOSTM = false; plotTrack(info); }; - if (qOpenStMap) + if (osm) menu['Plot OpenStMap'] = function() { info.qOSTM = true; plotTrack(info); @@ -161,49 +164,22 @@ function viewTrack(n, info) { return E.showMenu(menu); } -function drawopenstmap(lat, lon, map) { - var s = require("Storage"); - var cx = g.getWidth()/2; - var cy = g.getHeight()/2; - var p = Bangle.project({lat:lat,lon:lon}); - var ix = (p.x-map.center.x)*4096/map.scale + (map.imgx/2) - cx; - var iy = (map.center.y-p.y)*4096/map.scale + (map.imgy/2) - cy; - var tx = 0|(ix/map.tilesize); - var ty = 0|(iy/map.tilesize); - var ox = (tx*map.tilesize)-ix; - var oy = (ty*map.tilesize)-iy; - for (var x=ox,ttx=tx;x Date: Tue, 8 Dec 2020 15:56:53 +0000 Subject: [PATCH 08/12] openstmap: Show currently active gpsrec GPS trace (fix #395) --- apps.json | 4 ++-- apps/gpsrec/ChangeLog | 1 + apps/gpsrec/widget.js | 18 ++++++++++++++++++ apps/openstmap/ChangeLog | 1 + apps/openstmap/app.js | 4 ++++ 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 697c78dc9..2458646a4 100644 --- a/apps.json +++ b/apps.json @@ -363,7 +363,7 @@ { "id": "gpsrec", "name": "GPS Recorder", "icon": "app.png", - "version":"0.14", + "version":"0.15", "interface": "interface.html", "description": "Application that allows you to record a GPS track. Can run in background", "tags": "tool,outdoors,gps,widget", @@ -1326,7 +1326,7 @@ "name": "OpenStreetMap", "shortName":"OpenStMap", "icon": "app.png", - "version":"0.04", + "version":"0.05", "description": "[BETA] Loads map tiles from OpenStreetMap onto your Bangle.js and displays a map of where you are", "tags": "outdoors,gps", "custom": "custom.html", diff --git a/apps/gpsrec/ChangeLog b/apps/gpsrec/ChangeLog index ddb7e7dc4..b0d94f230 100644 --- a/apps/gpsrec/ChangeLog +++ b/apps/gpsrec/ChangeLog @@ -16,3 +16,4 @@ 0.13: Increase GPS recording accuracy by one decimal place Ensure default time period is 10 0.14: Now use the openstmap lib for map plotting +0.15: Add plotTrack method to allow current track to be plotted on a map (#395) diff --git a/apps/gpsrec/widget.js b/apps/gpsrec/widget.js index f07c9e43a..9ad1754c6 100644 --- a/apps/gpsrec/widget.js +++ b/apps/gpsrec/widget.js @@ -66,6 +66,24 @@ WIDGETS["gpsrec"]={area:"tl",width:24,draw:draw,reload:function() { reload(); Bangle.drawWidgets(); // relayout all widgets + },plotTrack:function(m) { // m=instance of openstmap module + settings = require("Storage").readJSON("gpsrec.json",1)||{}; + settings.file |= 0; + var n = settings.file.toString(36); + var f = require("Storage").open(".gpsrc"+n,"r"); + var l = f.readLine(f); + if (l===undefined) return; + var c = l.split(","); + var mp = m.latLonToXY(+c[1], +c[2]); + g.moveTo(mp.x,mp.y); + l = f.readLine(f); + while(l!==undefined) { + c = l.split(","); + mp = m.latLonToXY(+c[1], +c[2]); + g.lineTo(mp.x,mp.y); + g.fillCircle(mp.x,mp.y,2); // make the track more visible + l = f.readLine(f); + } }}; // load settings, set correct widget width reload(); diff --git a/apps/openstmap/ChangeLog b/apps/openstmap/ChangeLog index 1fbfd4c50..64b39b509 100644 --- a/apps/openstmap/ChangeLog +++ b/apps/openstmap/ChangeLog @@ -2,3 +2,4 @@ 0.02: Fix marker position, color, and map scaling 0.03: Show widgets (mainly so we can use the GPS recorder widget) 0.04: Move map rendering to a module (fix #396) +0.05: Show currently active gpsrec GPS trace (fix #395) diff --git a/apps/openstmap/app.js b/apps/openstmap/app.js index b678eca33..940557361 100644 --- a/apps/openstmap/app.js +++ b/apps/openstmap/app.js @@ -7,6 +7,10 @@ function redraw() { g.setClipRect(0,y1,g.getWidth()-1,y2); m.draw(); drawMarker(); + if (WIDGETS["gpsrec"] && WIDGETS["gpsrec"].plotTrack) { + g.setColor(0.75,0.2,0); + WIDGETS["gpsrec"].plotTrack(m); + } g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); } From 4caa6786f5bf1b7e62a49febd7dd58c2fad329fc Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 8 Dec 2020 15:59:00 +0000 Subject: [PATCH 09/12] oops - include library --- apps.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps.json b/apps.json index 2458646a4..84fbc681b 100644 --- a/apps.json +++ b/apps.json @@ -1331,6 +1331,7 @@ "tags": "outdoors,gps", "custom": "custom.html", "storage": [ + {"name":"openstmap","url":"openstmap.js"}, {"name":"openstmap.app.js","url":"app.js"}, {"name":"openstmap.img","url":"app-icon.js","evaluate":true} ] From 30f66a8775b326a1fe7e7057926e24854e644a04 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 8 Dec 2020 16:10:23 +0000 Subject: [PATCH 10/12] Add gpsrec app to Settings menu --- apps.json | 5 +++-- apps/gpsrec/ChangeLog | 1 + apps/gpsrec/settings.js | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 apps/gpsrec/settings.js diff --git a/apps.json b/apps.json index 84fbc681b..8982726fe 100644 --- a/apps.json +++ b/apps.json @@ -363,14 +363,15 @@ { "id": "gpsrec", "name": "GPS Recorder", "icon": "app.png", - "version":"0.15", + "version":"0.16", "interface": "interface.html", "description": "Application that allows you to record a GPS track. Can run in background", "tags": "tool,outdoors,gps,widget", "storage": [ {"name":"gpsrec.app.js","url":"app.js"}, {"name":"gpsrec.img","url":"app-icon.js","evaluate":true}, - {"name":"gpsrec.wid.js","url":"widget.js"} + {"name":"gpsrec.wid.js","url":"widget.js"}, + {"name":"gpsrec.settings.js","url":"settings.js"} ], "data": [ {"name":"gpsrec.json"}, diff --git a/apps/gpsrec/ChangeLog b/apps/gpsrec/ChangeLog index b0d94f230..8c08a4ec5 100644 --- a/apps/gpsrec/ChangeLog +++ b/apps/gpsrec/ChangeLog @@ -17,3 +17,4 @@ Ensure default time period is 10 0.14: Now use the openstmap lib for map plotting 0.15: Add plotTrack method to allow current track to be plotted on a map (#395) + Add gpsrec app to Settings menu diff --git a/apps/gpsrec/settings.js b/apps/gpsrec/settings.js new file mode 100644 index 000000000..23a58d58f --- /dev/null +++ b/apps/gpsrec/settings.js @@ -0,0 +1,4 @@ +(function(back) { + // just go right to our app - we need all the memory + load("gpsrec.app.js"); +})(); From 6a63a6ea47fde686b57580d7ac0b7020a9ecea23 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 8 Dec 2020 16:41:24 +0000 Subject: [PATCH 11/12] fileman 0.02: Improve handling of large amounts of files (fix #579) --- apps.json | 2 +- apps/fileman/ChangeLog | 1 + apps/fileman/fileman.app.js | 13 ++++++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/apps.json b/apps.json index 8982726fe..d44c0b051 100644 --- a/apps.json +++ b/apps.json @@ -2293,7 +2293,7 @@ "name": "File manager", "shortName":"FileManager", "icon": "icons8-filing-cabinet-48.png", - "version":"0.01", + "version":"0.02", "description": "Simple file manager, allows user to examine watch storage and display, load or delete individual files", "tags": "tools", "readme": "README.md", diff --git a/apps/fileman/ChangeLog b/apps/fileman/ChangeLog index 1a3bc1757..72ee0b566 100644 --- a/apps/fileman/ChangeLog +++ b/apps/fileman/ChangeLog @@ -1 +1,2 @@ 0.01: New app! +0.02: Improve handling of large amounts of files (fix #579) diff --git a/apps/fileman/fileman.app.js b/apps/fileman/fileman.app.js index a8acb22f6..03e135cb2 100644 --- a/apps/fileman/fileman.app.js +++ b/apps/fileman/fileman.app.js @@ -10,12 +10,12 @@ function delete_file(fn) { E.showPrompt("Delete\n"+fn+"?", {buttons: {"No":false, "Yes":true}}).then(function(v) { if (v) { if (fn.charCodeAt(fn.length-1)==1) { - var fh = STOR.open(fn.substr(0, fn.length-1), "w"); + var fh = STOR.open(fn.substr(0, fn.length-1), "r"); fh.erase(); } else STOR.erase(fn); } - }).then(function() { files=get_pruned_file_list(); }).then(drawMenu); + }).then(function() { filed=[];files=get_pruned_file_list(); }).then(drawMenu); } function get_length(fn) { @@ -90,10 +90,13 @@ function drawMenu() { } function get_pruned_file_list() { - var fl = STOR.list(/^[^\.]/); + // get storagefile list + var sf = STOR.list(/\1$/).map(s=>s.slice(0,-1)); + var sffilter = f=>!sf.includes(f.slice(0,-1)) || f.endsWith("\1"); + // get files - put '.' last + var fl = STOR.list(/^[^\.]/).filter(sffilter); fl.sort(); - fl = fl.concat(STOR.list(/^\./)); - fl = fl.filter(f => (f.charCodeAt(f.length-1)>31 || f.charCodeAt(f.length-1)<2)); + fl = fl.concat(STOR.list(/^\./).filter(sffilter).sort()); return fl; } From 4c78076603b36bcccff102ca2989c5ad82b8924b Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 9 Dec 2020 13:43:29 +0000 Subject: [PATCH 12/12] Allow custom modules for apps --- README.md | 12 ++++++++++++ core | 2 +- modules/README.md | 9 +++++++++ modules/testmodule.js | 3 +++ 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 modules/README.md create mode 100644 modules/testmodule.js diff --git a/README.md b/README.md index 240163f6c..307323846 100644 --- a/README.md +++ b/README.md @@ -394,6 +394,18 @@ It should also add `app.json` to `data`, to make sure it is cleaned up when the }, ``` +## Modules + +You can include any of [Espruino's modules](https://www.espruino.com/Modules) as +normal with `require("modulename")`. If you want to develop your own module for your +app(s) then you can do that too. Just add the module into the `modules` folder +then you can use it from your app as normal. + +You won't be able to develop apps using your own modules with the IDE, +so instead we'd recommend you write your module to a Storage File called +`modulename` on Bangle.js. You can then develop your app as normal on Bangle.js +from the IDE. + ## Coding hints - use `g.setFont(.., size)` to multiply the font size, eg ("6x8",3) : "18x24" diff --git a/core b/core index 0389671ba..8bfdeebf7 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 0389671ba6678a12c9f35644ffb96c190bbe0278 +Subproject commit 8bfdeebf705ced95699dcbbccfa05a99e7d3f4a9 diff --git a/modules/README.md b/modules/README.md new file mode 100644 index 000000000..6930da2b9 --- /dev/null +++ b/modules/README.md @@ -0,0 +1,9 @@ +App Modules +=========== + +These are modules used by apps - you can use them with: + +``` +var testmodule = require("testmodule"); +testmodule.test() +``` diff --git a/modules/testmodule.js b/modules/testmodule.js new file mode 100644 index 000000000..c7c93efa3 --- /dev/null +++ b/modules/testmodule.js @@ -0,0 +1,3 @@ +exports.test = function() { + console.log("Hello world!"); +};