From 028367d6ffa54eae200a4c476d20476816448166 Mon Sep 17 00:00:00 2001 From: singintime Date: Fri, 4 Sep 2020 20:56:40 +0200 Subject: [PATCH 01/31] minionclk v0.04 --- apps.json | 2 +- apps/minionclk/ChangeLog | 1 + apps/minionclk/app.js | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index bb527533c..3a446edb7 100644 --- a/apps.json +++ b/apps.json @@ -1243,7 +1243,7 @@ { "id": "minionclk", "name": "Minion clock", "icon": "minionclk.png", - "version": "0.03", + "version": "0.04", "description": "Minion themed clock.", "tags": "clock,minion", "type": "clock", diff --git a/apps/minionclk/ChangeLog b/apps/minionclk/ChangeLog index 3b6757d9a..27dab7259 100755 --- a/apps/minionclk/ChangeLog +++ b/apps/minionclk/ChangeLog @@ -1,3 +1,4 @@ 0.01: First release 0.02: Improved date readability, fixed drawing of widgets 0.03: Fixed rendering for Espruino v2.06 +0.04: Fixed overlapped rendering of dates diff --git a/apps/minionclk/app.js b/apps/minionclk/app.js index 2d6a38603..b2813101b 100755 --- a/apps/minionclk/app.js +++ b/apps/minionclk/app.js @@ -56,6 +56,7 @@ function startDrawing() { hour = ''; minute = ''; date = ''; + g.clear(); g.drawImage(getBackground(), 0, 24, { scale: 2 }); Bangle.drawWidgets(); draw(); From 19549476dd080d54c3494103609c970d1cce26fa Mon Sep 17 00:00:00 2001 From: Stefano Baldan Date: Sat, 5 Sep 2020 00:00:48 +0200 Subject: [PATCH 02/31] Update app.js --- apps/minionclk/app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/minionclk/app.js b/apps/minionclk/app.js index b2813101b..537a6fe7d 100755 --- a/apps/minionclk/app.js +++ b/apps/minionclk/app.js @@ -56,7 +56,8 @@ function startDrawing() { hour = ''; minute = ''; date = ''; - g.clear(); + g.setColor(0x0000); + g.fillRect(0, 216, 240, 24); g.drawImage(getBackground(), 0, 24, { scale: 2 }); Bangle.drawWidgets(); draw(); From 51f95e0407b4b89ce3e76231b1d18deb876021ff Mon Sep 17 00:00:00 2001 From: Stefano Baldan Date: Sat, 5 Sep 2020 00:06:49 +0200 Subject: [PATCH 03/31] Update app.js --- apps/minionclk/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/minionclk/app.js b/apps/minionclk/app.js index 537a6fe7d..f0afbc45c 100755 --- a/apps/minionclk/app.js +++ b/apps/minionclk/app.js @@ -57,7 +57,7 @@ function startDrawing() { minute = ''; date = ''; g.setColor(0x0000); - g.fillRect(0, 216, 240, 24); + g.fillRect(0, 216, 240, 240); g.drawImage(getBackground(), 0, 24, { scale: 2 }); Bangle.drawWidgets(); draw(); From 255a89dc95280925cdf98fef6849df9185d2a259 Mon Sep 17 00:00:00 2001 From: marko Date: Tue, 8 Sep 2020 17:35:08 -0400 Subject: [PATCH 04/31] New CSC sensor app, first commit --- apps.json | 13 +++++ apps/cycling/README.md | 1 + apps/cycling/cscsensor-icon.js | 1 + apps/cycling/cscsensor.apps.js | 84 +++++++++++++++++++++++++++++ apps/cycling/icons8-cycling-48.png | Bin 0 -> 1487 bytes 5 files changed, 99 insertions(+) create mode 100644 apps/cycling/README.md create mode 100644 apps/cycling/cscsensor-icon.js create mode 100644 apps/cycling/cscsensor.apps.js create mode 100644 apps/cycling/icons8-cycling-48.png diff --git a/apps.json b/apps.json index bb527533c..6c09b1cb4 100644 --- a/apps.json +++ b/apps.json @@ -2170,6 +2170,19 @@ {"name":"tetra.stl","url":"tetra.stl"}, {"name":"cube.stl","url":"cube.stl"}, {"name":"icosa.stl","url":"icosa.stl"} + ] + }, + { "id": "cscsensor", + "name": "Cycling speed sensor", + "shortName":"CSCSensor", + "icon": "icons8-cycling-48.png", + "version":"0.01", + "description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch.", + "tags": "outdoors,exercise,ble,bluetooth", + "readme": "README.md", + "storage": [ + {"name":"cscsensor.app.js","url":"cscsensor.app.js"}, + {"name":"cscsensor.img","url":"cscsensor-icon.js","evaluate":true}, ] }, { "id": "worldclock", diff --git a/apps/cycling/README.md b/apps/cycling/README.md new file mode 100644 index 000000000..a0990367e --- /dev/null +++ b/apps/cycling/README.md @@ -0,0 +1 @@ +TBD diff --git a/apps/cycling/cscsensor-icon.js b/apps/cycling/cscsensor-icon.js new file mode 100644 index 000000000..12c597956 --- /dev/null +++ b/apps/cycling/cscsensor-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AH/OAAIuuGFYuEGFQv/ADOlwV8wK/qwN8AAelGAguiFogACWsulFw6SERcwAFSISLnSMuAFZWCGENWllWLRSZC0vOAAovWmUslkyvbqJwIuHGC4uBAARiDdAwueL4YACMQLmfX5IAFqwwoMIowpMQ4wpGIcywDiYAA2IAAgwGq2kFwIvGC5YtPDJIuCF4gXPFxQHLF44XQFxAKOF4oXRBg4LOFwYvEEag7OBgReQNZzLNF5IXPBJlXq4vVC5Qv8R9TXQFwbvYJBgLlNbYXRBoYOEA44XfCAgAFCxgXYDI4VPC7IA/AH4A/AH4AWA")) diff --git a/apps/cycling/cscsensor.apps.js b/apps/cycling/cscsensor.apps.js new file mode 100644 index 000000000..e95ca2179 --- /dev/null +++ b/apps/cycling/cscsensor.apps.js @@ -0,0 +1,84 @@ + +var device; +var gatt; +var service; +var characteristic; + +class CSCSensor { + constructor() { + this.lastTime = 0; + this.lastBangleTime = Date.now(); + this.lastRevs = -1; + this.wheelDia = 28.0; + this.speedFailed = 0; + this.speed = 0; + this.lastSpeed = 0; + this.qUpdateScreen = true; + } + + updateScreen() { + var dist = Math.round(100*this.lastRevs*this.wheelDia*Math.PI/63360.0)/100; + var dspeed = Math.round(10*this.speed)/10; + g.clearRect(0, 120-2*20, 239, 120+2*20).drawString(dspeed+" mph", 120, 100).drawString(dist+" miles", 120, 140); + return; + } + + updateSensor(event) { + var qChanged = false; + if (event.target.uuid == "0x2a5b") { + var wheelRevs = event.target.value.getUint32(1, true); + var dRevs = (this.lastRevs>0 ? wheelRevs-this.lastRevs : 0); + if (dRevs>0) qChanged = true; + this.lastRevs = wheelRevs; + var wheelTime = event.target.value.getUint16(5, true); + var dT = (wheelTime-this.lastTime)/1024; + var dBT = (Date.now()-this.lastBangleTime)/1000; + if (dT<0) dT+=64; + this.lastTime = wheelTime; + this.speed = this.lastSpeed; + if (dRevs>0 && dT>0) { + this.speed = (dRevs*this.wheelDia*Math.PI/63360.0)*3600/dT; + this.speedFailed = 0; + } + else { + this.speedFailed++; + qChanged = false; + if (this.speedFailed>3) { + this.speed = 0; + qChanged = (this.lastSpeed>0); + } + } + this.lastSpeed = this.speed; + } + if (qChanged && this.qUpdateScreen) this.updateScreen(); + } +}; + +var mySensor = new CSCSensor(); + +function parseDevice(d) { + device = d; + g.clear().drawString("Found device", 120, 120).flip(); + device.gatt.connect().then(function(ga) { + gatt = ga; + g.clear().drawString("Connected", 120, 120).flip(); + return gatt.getPrimaryService("1816"); +}).then(function(s) { + service = s; + return service.getCharacteristic("2a5b"); +}).then(function(c) { + characteristic = c; + characteristic.on('characteristicvaluechanged', (event)=>mySensor.updateSensor(event)); + return characteristic.startNotifications(); +}).then(function() { + console.log("Done!"); + g.clear().setFontVector("40").setColor(1, 1, 1).flip(); +}).catch(function(e) { + g.clear().setColor(1, 0, 0).drawString("ERROR"+e, 120, 120).flip(); +})} + +NRF.setScan(parseDevice, { filters: [{services:["1816"]}], timeout: 2000}); +g.clear().setFontVector(18).setFontAlign(0, 0, 0).setColor(0, 1, 0); +g.drawString("Scanning for CSC sensor...", 120, 120); + +Bangle.on('kill',()=>{ if (gatt!=undefined) gatt.disconnect()}); diff --git a/apps/cycling/icons8-cycling-48.png b/apps/cycling/icons8-cycling-48.png new file mode 100644 index 0000000000000000000000000000000000000000..0bc83859f1ac8d5b1d40aa787ab3c8bf339913fd GIT binary patch literal 1487 zcmV;=1u*)FP)BH^< zyW9n~y*qr_|Cil8&-47wInUcYcLAS#^2w*s6pf~HE?fR2B+da?2cQbX+sIIO#vR6} zC14F+`r0W52Ju37k`R;+ZG@6I2ZJY&z?9<-X7myuo-S{P&K=C?CBSq=-i|7FFn)>z zGlWX>KF@8r7q(gy1B1o}w0CMluJ4M^%-R8xwu0#!IG+Jvn>&239pdkH7KGgqBYtRX z)lMB~7s!Iy(Le8ue>L-ME?t%irW_D-wwd2XDaI0a{CFjS^1Q>z4XxT!ZQUV(a_xcY zE{>a0k)&U{slroVil2d!T}O7;Hcu~g6+8fRnFFc%UtKZp$@2HqpJHdAXn#>i&uvRZ zZKHNXw@71aWbpT6W)}f4c;Z))6)4X;oZQ+NP~X@#vf%BiZqhIKW&a1Sc;egR1P<-k z{(fzXNHrJz#96RAa7J5=dQ<-qCQE z#sWaFzaLh`#6j$w3wFY4@B61VVsb-5+>0Ap0N~oE+XF5)&8&G~VolTxt;^u;5muAI z_>fl;n3a~n52Q6S+yfz- z48{XqNg(<8jIQPm1UTEr`Kz%iCf2MA719#3*1J_6yDN_lu|C{ll(V;sW_)P6sQ&EA z`GY5RFQ4d%kKyF$lbAMStthU%DJ&Fw5yKGPCguXz*q;DLIxetq zQ&GO1>TEb!UZJ-wtLOsWr^WLUFR55a1JFZ+%wuOS_P?kzO>*eW))i2U?0003g14xmMV5(D= zZ)+Reo$m(#vmg$-zE*C@{b}Wv+)8JAH_U(7zD^lnc3c6*O@;Zc5&+BCtRi9%4{8tU z3bbC@QYuHZ@;KzXthu_VPlk?lHvFL^Vv3A`CVBba!c>K#2 zh4}zvSAa?YfJv1h2a}T^AOir1(O)_<)&blI;0B0S5!q)?A-+9YXT$Nbb2jB0BV5p zhYQ{teA!y4z+_T~w~NKZFaYQQ_@E@wkzQ5L?*O2Y{AYqV9l*<0I7)5>`!8};uXvO1 zvY0C{nbhHJVlELf;rgAm7ohxG!J2nQ8obi{Vaw^`W#@D(s8-t^BGESUbz+>c_z9mZ pnU^5{H~9$VZN5)F`Q(##^&bl8rz8LGDIEX+002ovPDHLkV1j9?%0U1C literal 0 HcmV?d00001 From 379323f93567d55ac62335ceff92e44597d86a68 Mon Sep 17 00:00:00 2001 From: marko Date: Tue, 8 Sep 2020 17:37:51 -0400 Subject: [PATCH 05/31] Fix apps.json --- apps.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps.json b/apps.json index 6c09b1cb4..610638d4c 100644 --- a/apps.json +++ b/apps.json @@ -2173,18 +2173,18 @@ ] }, { "id": "cscsensor", - "name": "Cycling speed sensor", - "shortName":"CSCSensor", - "icon": "icons8-cycling-48.png", - "version":"0.01", - "description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch.", - "tags": "outdoors,exercise,ble,bluetooth", - "readme": "README.md", - "storage": [ - {"name":"cscsensor.app.js","url":"cscsensor.app.js"}, - {"name":"cscsensor.img","url":"cscsensor-icon.js","evaluate":true}, - ] - }, + "name": "Cycling speed sensor", + "shortName":"CSCSensor", + "icon": "icons8-cycling-48.png", + "version":"0.01", + "description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch", + "tags": "outdoors,exercise,ble,bluetooth", + "readme": "README.md", + "storage": [ + {"name":"cscsensor.app.js","url":"cscsensor.app.js"}, + {"name":"cscsensor.img","url":"cscsensor-icon.js","evaluate":true} + ] + }, { "id": "worldclock", "name": "World Clock - 4 time zones", "shortName":"World Clock", From aec8fb6de2509ebb70980eaea3dacf4a513eb88e Mon Sep 17 00:00:00 2001 From: marko Date: Tue, 8 Sep 2020 17:44:28 -0400 Subject: [PATCH 06/31] Fix readme --- apps/cycling/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/cycling/README.md b/apps/cycling/README.md index a0990367e..b353c430e 100644 --- a/apps/cycling/README.md +++ b/apps/cycling/README.md @@ -1 +1,3 @@ +# CSCSensor + TBD From 67cdfeccf245f1b2e77a0e4dc6473c9871bd304b Mon Sep 17 00:00:00 2001 From: marko Date: Tue, 8 Sep 2020 17:46:03 -0400 Subject: [PATCH 07/31] renamed dir --- apps/{cycling => cscsensor}/README.md | 0 apps/{cycling => cscsensor}/cscsensor-icon.js | 0 apps/{cycling => cscsensor}/cscsensor.apps.js | 0 apps/{cycling => cscsensor}/icons8-cycling-48.png | Bin 4 files changed, 0 insertions(+), 0 deletions(-) rename apps/{cycling => cscsensor}/README.md (100%) rename apps/{cycling => cscsensor}/cscsensor-icon.js (100%) rename apps/{cycling => cscsensor}/cscsensor.apps.js (100%) rename apps/{cycling => cscsensor}/icons8-cycling-48.png (100%) diff --git a/apps/cycling/README.md b/apps/cscsensor/README.md similarity index 100% rename from apps/cycling/README.md rename to apps/cscsensor/README.md diff --git a/apps/cycling/cscsensor-icon.js b/apps/cscsensor/cscsensor-icon.js similarity index 100% rename from apps/cycling/cscsensor-icon.js rename to apps/cscsensor/cscsensor-icon.js diff --git a/apps/cycling/cscsensor.apps.js b/apps/cscsensor/cscsensor.apps.js similarity index 100% rename from apps/cycling/cscsensor.apps.js rename to apps/cscsensor/cscsensor.apps.js diff --git a/apps/cycling/icons8-cycling-48.png b/apps/cscsensor/icons8-cycling-48.png similarity index 100% rename from apps/cycling/icons8-cycling-48.png rename to apps/cscsensor/icons8-cycling-48.png From dd177c144c5b1c0c8fa9248ef393e3211b5c0e2e Mon Sep 17 00:00:00 2001 From: marko Date: Tue, 8 Sep 2020 18:25:14 -0400 Subject: [PATCH 08/31] Fix app filename --- apps/cscsensor/{cscsensor.apps.js => cscsensor.app.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename apps/cscsensor/{cscsensor.apps.js => cscsensor.app.js} (100%) diff --git a/apps/cscsensor/cscsensor.apps.js b/apps/cscsensor/cscsensor.app.js similarity index 100% rename from apps/cscsensor/cscsensor.apps.js rename to apps/cscsensor/cscsensor.app.js From e0c57f8e8c467745243b05d8d2fef4dd2890896c Mon Sep 17 00:00:00 2001 From: "Marko.Kl.Berkenbusch@gmail.com" Date: Tue, 8 Sep 2020 22:16:02 -0400 Subject: [PATCH 09/31] Add more display items --- apps/cscsensor/cscsensor.app.js | 41 ++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index e95ca2179..71197bccd 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -6,21 +6,40 @@ var characteristic; class CSCSensor { constructor() { + this.movingTime = 0; this.lastTime = 0; this.lastBangleTime = Date.now(); this.lastRevs = -1; this.wheelDia = 28.0; this.speedFailed = 0; this.speed = 0; + this.maxSpeed = 0; this.lastSpeed = 0; this.qUpdateScreen = true; } updateScreen() { - var dist = Math.round(100*this.lastRevs*this.wheelDia*Math.PI/63360.0)/100; + var dist = this.lastRevs*this.wheelDia*Math.PI/63360.0; + var ddist = Math.round(100*dist)/100; var dspeed = Math.round(10*this.speed)/10; - g.clearRect(0, 120-2*20, 239, 120+2*20).drawString(dspeed+" mph", 120, 100).drawString(dist+" miles", 120, 140); - return; + var dmins = Math.floor(this.movingTime/60).toString(); + if (dmins.length<2) dmins = "0"+dmins; + var dsecs = (Math.floor(this.movingTime) % 60).toString(); + if (dsecs.length<2) dsecs = "0"+dsecs; + var avespeed = Math.round(10*dist/this.movingTime)/10; + var maxspeed = Math.round(10*this.maxSpeed)/10; + g.setFontAlign(1, -1, 0).setFontVector(18).setColor(1, 1, 0); + g.drawString("Time:", 86, 60); + g.drawString("Speed:", 86, 94); + g.drawString("Ave spd:", 86, 128); + g.drawString("Max spd:", 86, 160); + g.drawString("Dist:", 86, 192); + g.setFontAlign(-1, -1, 0).setFontVector(24).setColor(1, 1, 1).clearRect(92, 60, 239, 240); + g.drawString(dmins+":"+dsecs, 92, 60); + g.drawString(dspeed+" mph", 92, 94); + g.drawString(avespeed + " mph", 92, 128); + g.drawString(maxspeed + " mph", 92, 160); + g.drawString(ddist + " miles", 92, 192); } updateSensor(event) { @@ -33,12 +52,14 @@ class CSCSensor { var wheelTime = event.target.value.getUint16(5, true); var dT = (wheelTime-this.lastTime)/1024; var dBT = (Date.now()-this.lastBangleTime)/1000; + this.lastBangleTime = Date.now(); if (dT<0) dT+=64; this.lastTime = wheelTime; this.speed = this.lastSpeed; if (dRevs>0 && dT>0) { this.speed = (dRevs*this.wheelDia*Math.PI/63360.0)*3600/dT; this.speedFailed = 0; + this.movingTime += dBT; } else { this.speedFailed++; @@ -49,6 +70,7 @@ class CSCSensor { } } this.lastSpeed = this.speed; + if (this.speed > this.maxSpeed) this.maxSpeed = this.speed; } if (qChanged && this.qUpdateScreen) this.updateScreen(); } @@ -58,10 +80,10 @@ var mySensor = new CSCSensor(); function parseDevice(d) { device = d; - g.clear().drawString("Found device", 120, 120).flip(); + g.clearRect(0, 60, 239, 239).drawString("Found device", 120, 120).flip(); device.gatt.connect().then(function(ga) { gatt = ga; - g.clear().drawString("Connected", 120, 120).flip(); + g.clearRect(0, 60, 239, 239).drawString("Connected", 120, 120).flip(); return gatt.getPrimaryService("1816"); }).then(function(s) { service = s; @@ -72,13 +94,16 @@ function parseDevice(d) { return characteristic.startNotifications(); }).then(function() { console.log("Done!"); - g.clear().setFontVector("40").setColor(1, 1, 1).flip(); + g.clearRect(0, 60, 239, 239).setColor(1, 1, 1).flip(); }).catch(function(e) { - g.clear().setColor(1, 0, 0).drawString("ERROR"+e, 120, 120).flip(); + g.clearRect(0, 60, 239, 239).setColor(1, 0, 0).drawString("ERROR"+e, 120, 120).flip(); })} NRF.setScan(parseDevice, { filters: [{services:["1816"]}], timeout: 2000}); -g.clear().setFontVector(18).setFontAlign(0, 0, 0).setColor(0, 1, 0); +g.clearRect(0, 60, 239, 239).setFontVector(18).setFontAlign(0, 0, 0).setColor(0, 1, 0); g.drawString("Scanning for CSC sensor...", 120, 120); Bangle.on('kill',()=>{ if (gatt!=undefined) gatt.disconnect()}); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); \ No newline at end of file From 095a06bda5434468bf24a68da7ec94246c2ce4ea Mon Sep 17 00:00:00 2001 From: marko Date: Wed, 9 Sep 2020 10:15:16 -0400 Subject: [PATCH 10/31] Fix font alignment --- apps/cscsensor/cscsensor.app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index 71197bccd..88abd43ff 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -80,10 +80,10 @@ var mySensor = new CSCSensor(); function parseDevice(d) { device = d; - g.clearRect(0, 60, 239, 239).drawString("Found device", 120, 120).flip(); + g.clearRect(0, 60, 239, 239).setFontAlign(0, 0, 0).setColor(0, 1, 0).drawString("Found device", 120, 120).flip(); device.gatt.connect().then(function(ga) { gatt = ga; - g.clearRect(0, 60, 239, 239).drawString("Connected", 120, 120).flip(); + g.clearRect(0, 60, 239, 239).setFontAlign(0, 0, 0).setColor(0, 1, 0).drawString("Connected", 120, 120).flip(); return gatt.getPrimaryService("1816"); }).then(function(s) { service = s; @@ -96,7 +96,7 @@ function parseDevice(d) { console.log("Done!"); g.clearRect(0, 60, 239, 239).setColor(1, 1, 1).flip(); }).catch(function(e) { - g.clearRect(0, 60, 239, 239).setColor(1, 0, 0).drawString("ERROR"+e, 120, 120).flip(); + g.clearRect(0, 60, 239, 239).setColor(1, 0, 0).setFontAlign(0, 0, 0).drawString("ERROR"+e, 120, 120).flip(); })} NRF.setScan(parseDevice, { filters: [{services:["1816"]}], timeout: 2000}); From f83d5e03e7d2439e1bb49472e4c5e1890104eb7e Mon Sep 17 00:00:00 2001 From: marko Date: Wed, 9 Sep 2020 10:52:47 -0400 Subject: [PATCH 11/31] Add reset button --- apps/cscsensor/README.md | 14 +++++++++++++- apps/cscsensor/cscsensor.app.js | 18 +++++++++++++----- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/apps/cscsensor/README.md b/apps/cscsensor/README.md index b353c430e..185aebc12 100644 --- a/apps/cscsensor/README.md +++ b/apps/cscsensor/README.md @@ -1,3 +1,15 @@ # CSCSensor -TBD +Simple app that can read a cycling speed and cadence (CSC) sensor and display the information on the watch. +Currently the app displays the following data: + +- moving time +- current speed +- average speed +- maximum speed +- distance traveled + +Button 1 resets all measurements. + +I do not have acces to a cadence sensor at the moment, so only the speed part is currently implemented. Values displayed are imperial, and a wheel diameter +of 28 inches is assumed. A settings dialog to configure units and wheel sizes will (hopefully) be added later. diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index 88abd43ff..1a250bda0 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -16,17 +16,23 @@ class CSCSensor { this.maxSpeed = 0; this.lastSpeed = 0; this.qUpdateScreen = true; + this.lastRevsStart = -1; + } + reset() { + this.maxSpeed = 0; + this.movingTime = 0; + this.lastRevsStart = this.lastRevs; + this.maxSpeed = 0; } - updateScreen() { - var dist = this.lastRevs*this.wheelDia*Math.PI/63360.0; + var dist = (this.lastRevs-this.lastRevsStart)*this.wheelDia*Math.PI/63360.0; var ddist = Math.round(100*dist)/100; var dspeed = Math.round(10*this.speed)/10; var dmins = Math.floor(this.movingTime/60).toString(); if (dmins.length<2) dmins = "0"+dmins; var dsecs = (Math.floor(this.movingTime) % 60).toString(); if (dsecs.length<2) dsecs = "0"+dsecs; - var avespeed = Math.round(10*dist/this.movingTime)/10; + var avespeed = (this.movingTime>0 ? Math.round(10*dist/(this.movingTime/3600))/10 : 0); var maxspeed = Math.round(10*this.maxSpeed)/10; g.setFontAlign(1, -1, 0).setFontVector(18).setColor(1, 1, 0); g.drawString("Time:", 86, 60); @@ -41,7 +47,6 @@ class CSCSensor { g.drawString(maxspeed + " mph", 92, 160); g.drawString(ddist + " miles", 92, 192); } - updateSensor(event) { var qChanged = false; if (event.target.uuid == "0x2a5b") { @@ -49,6 +54,7 @@ class CSCSensor { var dRevs = (this.lastRevs>0 ? wheelRevs-this.lastRevs : 0); if (dRevs>0) qChanged = true; this.lastRevs = wheelRevs; + if (this.lastRevsStart<0) this.lastRevsStart = wheelRevs; var wheelTime = event.target.value.getUint16(5, true); var dT = (wheelTime-this.lastTime)/1024; var dBT = (Date.now()-this.lastBangleTime)/1000; @@ -103,7 +109,9 @@ NRF.setScan(parseDevice, { filters: [{services:["1816"]}], timeout: 2000}); g.clearRect(0, 60, 239, 239).setFontVector(18).setFontAlign(0, 0, 0).setColor(0, 1, 0); g.drawString("Scanning for CSC sensor...", 120, 120); +setWatch(function() { mySensor.reset(); mySensor.updateScreen(); }, BTN1); + Bangle.on('kill',()=>{ if (gatt!=undefined) gatt.disconnect()}); Bangle.loadWidgets(); -Bangle.drawWidgets(); \ No newline at end of file +Bangle.drawWidgets(); From 8b84023f1dd4b7d817d25c5fff90b4e14551d1ef Mon Sep 17 00:00:00 2001 From: marko Date: Wed, 9 Sep 2020 11:05:41 -0400 Subject: [PATCH 12/31] Appease code checker --- apps/cscsensor/cscsensor.app.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index 1a250bda0..87ebe6230 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -68,11 +68,11 @@ class CSCSensor { this.movingTime += dBT; } else { - this.speedFailed++; + this.speedFailed++; qChanged = false; - if (this.speedFailed>3) { + if (this.speedFailed>3) { this.speed = 0; - qChanged = (this.lastSpeed>0); + qChanged = (this.lastSpeed>0); } } this.lastSpeed = this.speed; @@ -80,7 +80,7 @@ class CSCSensor { } if (qChanged && this.qUpdateScreen) this.updateScreen(); } -}; +} var mySensor = new CSCSensor(); From abb93b9820fab9adcec9415d2d89aa861a0d9f65 Mon Sep 17 00:00:00 2001 From: marko Date: Wed, 9 Sep 2020 11:20:38 -0400 Subject: [PATCH 13/31] Appease code checker, again --- apps/cscsensor/cscsensor.app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index 87ebe6230..b8e4e107e 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -64,7 +64,7 @@ class CSCSensor { this.speed = this.lastSpeed; if (dRevs>0 && dT>0) { this.speed = (dRevs*this.wheelDia*Math.PI/63360.0)*3600/dT; - this.speedFailed = 0; + this.speedFailed = 0; this.movingTime += dBT; } else { From d289bb08ecd96c94b2173a051bbe5a867ffcfbd0 Mon Sep 17 00:00:00 2001 From: marko Date: Wed, 9 Sep 2020 11:30:20 -0400 Subject: [PATCH 14/31] Add ChangeLog --- apps/cscsensor/ChangeLog | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/cscsensor/ChangeLog diff --git a/apps/cscsensor/ChangeLog b/apps/cscsensor/ChangeLog new file mode 100644 index 000000000..1a3bc1757 --- /dev/null +++ b/apps/cscsensor/ChangeLog @@ -0,0 +1 @@ +0.01: New app! From 7205ce9383b9a3322f30a647402d4650cedd0779 Mon Sep 17 00:00:00 2001 From: marko Date: Wed, 9 Sep 2020 14:20:58 -0400 Subject: [PATCH 15/31] Add (some) localisation --- apps/cscsensor/cscsensor.app.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index b8e4e107e..4d2306f30 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -17,6 +17,10 @@ class CSCSensor { this.lastSpeed = 0; this.qUpdateScreen = true; this.lastRevsStart = -1; + this.qMetric = !require("locale").speed(1).toString().endsWith("mph"); + this.speedUnit = this.qMetric ? "km/h" : "mph"; + this.distUnit = this.qMetric ? "km" : "mi"; + this.distFactor = this.qMetric ? 1.609344 : 1; } reset() { this.maxSpeed = 0; @@ -25,15 +29,15 @@ class CSCSensor { this.maxSpeed = 0; } updateScreen() { - var dist = (this.lastRevs-this.lastRevsStart)*this.wheelDia*Math.PI/63360.0; + var dist = this.distFactor*(this.lastRevs-this.lastRevsStart)*this.wheelDia*Math.PI/63360.0; var ddist = Math.round(100*dist)/100; - var dspeed = Math.round(10*this.speed)/10; + var dspeed = Math.round(10*this.distFactor*this.speed)/10; var dmins = Math.floor(this.movingTime/60).toString(); if (dmins.length<2) dmins = "0"+dmins; var dsecs = (Math.floor(this.movingTime) % 60).toString(); if (dsecs.length<2) dsecs = "0"+dsecs; var avespeed = (this.movingTime>0 ? Math.round(10*dist/(this.movingTime/3600))/10 : 0); - var maxspeed = Math.round(10*this.maxSpeed)/10; + var maxspeed = Math.round(10*this.distFactor*this.maxSpeed)/10; g.setFontAlign(1, -1, 0).setFontVector(18).setColor(1, 1, 0); g.drawString("Time:", 86, 60); g.drawString("Speed:", 86, 94); @@ -42,10 +46,10 @@ class CSCSensor { g.drawString("Dist:", 86, 192); g.setFontAlign(-1, -1, 0).setFontVector(24).setColor(1, 1, 1).clearRect(92, 60, 239, 240); g.drawString(dmins+":"+dsecs, 92, 60); - g.drawString(dspeed+" mph", 92, 94); - g.drawString(avespeed + " mph", 92, 128); - g.drawString(maxspeed + " mph", 92, 160); - g.drawString(ddist + " miles", 92, 192); + g.drawString(dspeed+" "+this.speedUnit, 92, 94); + g.drawString(avespeed + " " + this.speedUnit, 92, 128); + g.drawString(maxspeed + " " + this.speedUnit, 92, 160); + g.drawString(ddist + " " + this.distUnit, 92, 192); } updateSensor(event) { var qChanged = false; From 8785133e0fa50644d03a9543112da01de83dff19 Mon Sep 17 00:00:00 2001 From: marko Date: Wed, 9 Sep 2020 14:23:47 -0400 Subject: [PATCH 16/31] Add (some) localisation --- apps/cscsensor/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/cscsensor/README.md b/apps/cscsensor/README.md index 185aebc12..3775b4280 100644 --- a/apps/cscsensor/README.md +++ b/apps/cscsensor/README.md @@ -11,5 +11,5 @@ Currently the app displays the following data: Button 1 resets all measurements. -I do not have acces to a cadence sensor at the moment, so only the speed part is currently implemented. Values displayed are imperial, and a wheel diameter -of 28 inches is assumed. A settings dialog to configure units and wheel sizes will (hopefully) be added later. +I do not have acces to a cadence sensor at the moment, so only the speed part is currently implemented. Values displayed are imperial or metric (depending on locale), +and a wheel diameter of 28 inches is assumed. A settings dialog to configure wheel sizes will (hopefully) be added later. From 04cda3681f6359594b2dccb4fc39219e9f1de67e Mon Sep 17 00:00:00 2001 From: marko Date: Wed, 9 Sep 2020 15:25:00 -0400 Subject: [PATCH 17/31] Add wheel circumference setting --- apps.json | 5 +++-- apps/cscsensor/settings.js | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 apps/cscsensor/settings.js diff --git a/apps.json b/apps.json index 610638d4c..42fda17db 100644 --- a/apps.json +++ b/apps.json @@ -2181,8 +2181,9 @@ "tags": "outdoors,exercise,ble,bluetooth", "readme": "README.md", "storage": [ - {"name":"cscsensor.app.js","url":"cscsensor.app.js"}, - {"name":"cscsensor.img","url":"cscsensor-icon.js","evaluate":true} + {"name":"cscsensor.app.js","url":"cscsensor.app.js"}, + {"name":"cscsensor.settings.js","url":"settings.js"} + {"name":"cscsensor.img","url":"cscsensor-icon.js","evaluate":true} ] }, { "id": "worldclock", diff --git a/apps/cscsensor/settings.js b/apps/cscsensor/settings.js new file mode 100644 index 000000000..95fe28d42 --- /dev/null +++ b/apps/cscsensor/settings.js @@ -0,0 +1,38 @@ +// This file should contain exactly one function, which shows the app's settings +/** + * @param {function} back Use back() to return to settings menu + */ +(function(back) { + const SETTINGS_FILE = 'cscsensor.json' + // initialize with default settings... + let s = { + 'wheelcirc': 2230, + } + // ...and overwrite them with any saved values + // This way saved values are preserved if a new version adds more settings + const storage = require('Storage') + const saved = storage.readJSON(SETTINGS_FILE, 1) || {} + for (const key in saved) { + s[key] = saved[key]; + } + // creates a function to safe a specific setting, e.g. save('color')(1) + function save(key) { + return function (value) { + s[key] = value; + storage.write(SETTINGS_FILE, s); + } + } + + const menu = { + '': { 'title': 'Cycling speed sensor' }, + '< Back': back, + 'Wheel diameter (mm)': { + value: s.wheelcirc, + min: 800, + max: 2400, + step: 5, + onchange: save('wheelcirc'), + } + } + E.showMenu(menu); +}) From 55f06a9647e8e0f13401d5e8c6a09d7d93407d8a Mon Sep 17 00:00:00 2001 From: marko Date: Wed, 9 Sep 2020 15:26:50 -0400 Subject: [PATCH 18/31] Add wheel circumference setting --- apps.json | 2 +- apps/cscsensor/ChangeLog | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 42fda17db..38a5135af 100644 --- a/apps.json +++ b/apps.json @@ -2176,7 +2176,7 @@ "name": "Cycling speed sensor", "shortName":"CSCSensor", "icon": "icons8-cycling-48.png", - "version":"0.01", + "version":"0.02", "description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch", "tags": "outdoors,exercise,ble,bluetooth", "readme": "README.md", diff --git a/apps/cscsensor/ChangeLog b/apps/cscsensor/ChangeLog index 1a3bc1757..a52353801 100644 --- a/apps/cscsensor/ChangeLog +++ b/apps/cscsensor/ChangeLog @@ -1 +1,2 @@ 0.01: New app! +0.02: Add wheel circumference settings dialog From ff74f1eb44ce9435699db94a0e0e0ab06e5bdde8 Mon Sep 17 00:00:00 2001 From: marko Date: Wed, 9 Sep 2020 15:28:52 -0400 Subject: [PATCH 19/31] Add wheel circumference setting --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 38a5135af..4b74990cb 100644 --- a/apps.json +++ b/apps.json @@ -2182,7 +2182,7 @@ "readme": "README.md", "storage": [ {"name":"cscsensor.app.js","url":"cscsensor.app.js"}, - {"name":"cscsensor.settings.js","url":"settings.js"} + {"name":"cscsensor.settings.js","url":"settings.js"}, {"name":"cscsensor.img","url":"cscsensor-icon.js","evaluate":true} ] }, From d0c284f0d5a2a6fc72cbbb5fd211aea57e2d0929 Mon Sep 17 00:00:00 2001 From: marko Date: Wed, 9 Sep 2020 15:43:59 -0400 Subject: [PATCH 20/31] Add wheel circumference setting --- apps/cscsensor/README.md | 2 +- apps/cscsensor/cscsensor.app.js | 10 +++++++--- apps/cscsensor/settings.js | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/cscsensor/README.md b/apps/cscsensor/README.md index 3775b4280..d9284473e 100644 --- a/apps/cscsensor/README.md +++ b/apps/cscsensor/README.md @@ -12,4 +12,4 @@ Currently the app displays the following data: Button 1 resets all measurements. I do not have acces to a cadence sensor at the moment, so only the speed part is currently implemented. Values displayed are imperial or metric (depending on locale), -and a wheel diameter of 28 inches is assumed. A settings dialog to configure wheel sizes will (hopefully) be added later. +the wheel circumference can be adjusted in the global settings app. diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index 4d2306f30..58fe321a5 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -4,13 +4,17 @@ var gatt; var service; var characteristic; +const SETTINGS_FILE = 'cscsensor.json'; + class CSCSensor { constructor() { this.movingTime = 0; this.lastTime = 0; this.lastBangleTime = Date.now(); this.lastRevs = -1; - this.wheelDia = 28.0; + var settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {}; + this.wheelCirc = (settings.wheelcirc || 2230)/25.4; + console.log("wc = " + this.wheelCirc); this.speedFailed = 0; this.speed = 0; this.maxSpeed = 0; @@ -29,7 +33,7 @@ class CSCSensor { this.maxSpeed = 0; } updateScreen() { - var dist = this.distFactor*(this.lastRevs-this.lastRevsStart)*this.wheelDia*Math.PI/63360.0; + var dist = this.distFactor*(this.lastRevs-this.lastRevsStart)*this.wheelCirc/63360.0; var ddist = Math.round(100*dist)/100; var dspeed = Math.round(10*this.distFactor*this.speed)/10; var dmins = Math.floor(this.movingTime/60).toString(); @@ -67,7 +71,7 @@ class CSCSensor { this.lastTime = wheelTime; this.speed = this.lastSpeed; if (dRevs>0 && dT>0) { - this.speed = (dRevs*this.wheelDia*Math.PI/63360.0)*3600/dT; + this.speed = (dRevs*this.wheelCirc/63360.0)*3600/dT; this.speedFailed = 0; this.movingTime += dBT; } diff --git a/apps/cscsensor/settings.js b/apps/cscsensor/settings.js index 95fe28d42..8a1c21de5 100644 --- a/apps/cscsensor/settings.js +++ b/apps/cscsensor/settings.js @@ -24,9 +24,9 @@ } const menu = { - '': { 'title': 'Cycling speed sensor' }, + '': { 'title': 'Cycle speed sensor' }, '< Back': back, - 'Wheel diameter (mm)': { + 'Wheel circ.(mm)': { value: s.wheelcirc, min: 800, max: 2400, From e28cee9057f2ef61f1e9c20d3dd2dd20678d66fe Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 10 Sep 2020 16:45:11 -0400 Subject: [PATCH 21/31] Save total distanced traveled --- apps.json | 2 +- apps/cscsensor/ChangeLog | 4 ++- apps/cscsensor/README.md | 5 ++-- apps/cscsensor/cscsensor.app.js | 44 ++++++++++++++++++++++----------- 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/apps.json b/apps.json index 4b74990cb..917096897 100644 --- a/apps.json +++ b/apps.json @@ -2176,7 +2176,7 @@ "name": "Cycling speed sensor", "shortName":"CSCSensor", "icon": "icons8-cycling-48.png", - "version":"0.02", + "version":"0.03", "description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch", "tags": "outdoors,exercise,ble,bluetooth", "readme": "README.md", diff --git a/apps/cscsensor/ChangeLog b/apps/cscsensor/ChangeLog index a52353801..ae99905a6 100644 --- a/apps/cscsensor/ChangeLog +++ b/apps/cscsensor/ChangeLog @@ -1,2 +1,4 @@ 0.01: New app! -0.02: Add wheel circumference settings dialog +0.02: Add wheel circumference settings dialog +0.03: Save total distance traveled + diff --git a/apps/cscsensor/README.md b/apps/cscsensor/README.md index d9284473e..9fc43a276 100644 --- a/apps/cscsensor/README.md +++ b/apps/cscsensor/README.md @@ -7,9 +7,10 @@ Currently the app displays the following data: - current speed - average speed - maximum speed -- distance traveled +- trip distance traveled +- total distance traveled -Button 1 resets all measurements. +Button 1 resets all measurements except total distance traveled. The latter gets preserved by being written to storage every 0.2 miles and upon exitting the app. I do not have acces to a cadence sensor at the moment, so only the speed part is currently implemented. Values displayed are imperial or metric (depending on locale), the wheel circumference can be adjusted in the global settings app. diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index 58fe321a5..3cd6e73f8 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -1,10 +1,10 @@ - var device; var gatt; var service; var characteristic; const SETTINGS_FILE = 'cscsensor.json'; +const storage = require('Storage'); class CSCSensor { constructor() { @@ -12,9 +12,10 @@ class CSCSensor { this.lastTime = 0; this.lastBangleTime = Date.now(); this.lastRevs = -1; - var settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {}; - this.wheelCirc = (settings.wheelcirc || 2230)/25.4; - console.log("wc = " + this.wheelCirc); + this.settings = storage.readJSON(SETTINGS_FILE, 1) || {}; + this.settings.totaldist = this.settings.totaldist || 0; + this.totaldist = this.settings.totaldist; + this.wheelCirc = (this.settings.wheelcirc || 2230)/25.4; this.speedFailed = 0; this.speed = 0; this.maxSpeed = 0; @@ -35,6 +36,7 @@ class CSCSensor { updateScreen() { var dist = this.distFactor*(this.lastRevs-this.lastRevsStart)*this.wheelCirc/63360.0; var ddist = Math.round(100*dist)/100; + var tdist = Math.round(this.distFactor*this.totaldist*10)/10; var dspeed = Math.round(10*this.distFactor*this.speed)/10; var dmins = Math.floor(this.movingTime/60).toString(); if (dmins.length<2) dmins = "0"+dmins; @@ -44,23 +46,32 @@ class CSCSensor { var maxspeed = Math.round(10*this.distFactor*this.maxSpeed)/10; g.setFontAlign(1, -1, 0).setFontVector(18).setColor(1, 1, 0); g.drawString("Time:", 86, 60); - g.drawString("Speed:", 86, 94); - g.drawString("Ave spd:", 86, 128); - g.drawString("Max spd:", 86, 160); - g.drawString("Dist:", 86, 192); - g.setFontAlign(-1, -1, 0).setFontVector(24).setColor(1, 1, 1).clearRect(92, 60, 239, 240); + g.drawString("Speed:", 86, 92); + g.drawString("Ave spd:", 86, 124); + g.drawString("Max spd:", 86, 156); + g.drawString("Trip dist:", 86, 188); + g.drawString("Total:", 86, 220); + g.setFontAlign(-1, -1, 0).setFontVector(24).setColor(1, 1, 1).clearRect(92, 60, 239, 239); g.drawString(dmins+":"+dsecs, 92, 60); - g.drawString(dspeed+" "+this.speedUnit, 92, 94); - g.drawString(avespeed + " " + this.speedUnit, 92, 128); - g.drawString(maxspeed + " " + this.speedUnit, 92, 160); - g.drawString(ddist + " " + this.distUnit, 92, 192); + g.drawString(dspeed+" "+this.speedUnit, 92, 92); + g.drawString(avespeed + " " + this.speedUnit, 92, 124); + g.drawString(maxspeed + " " + this.speedUnit, 92, 156); + g.drawString(ddist + " " + this.distUnit, 92, 188); + g.drawString(tdist + " " + this.distUnit, 92, 220); } updateSensor(event) { var qChanged = false; if (event.target.uuid == "0x2a5b") { var wheelRevs = event.target.value.getUint32(1, true); var dRevs = (this.lastRevs>0 ? wheelRevs-this.lastRevs : 0); - if (dRevs>0) qChanged = true; + if (dRevs>0) { + qChanged = true; + this.totaldist += dRevs*this.wheelCirc/63360.0; + if ((this.totaldist-this.settings.totaldist)>0.2) { + this.settings.totaldist = this.totaldist; + storage.writeJSON(SETTINGS_FILE, this.settings); + } + } this.lastRevs = wheelRevs; if (this.lastRevsStart<0) this.lastRevsStart = wheelRevs; var wheelTime = event.target.value.getUint16(5, true); @@ -119,7 +130,10 @@ g.drawString("Scanning for CSC sensor...", 120, 120); setWatch(function() { mySensor.reset(); mySensor.updateScreen(); }, BTN1); -Bangle.on('kill',()=>{ if (gatt!=undefined) gatt.disconnect()}); +Bangle.on('kill',()=>{ if (gatt!=undefined) gatt.disconnect() + mySensor.settings.totaldist = mySensor.totaldist; + storage.writeJSON(SETTINGS_FILE, this.settings); + }); Bangle.loadWidgets(); Bangle.drawWidgets(); From ad11fa3c2c29655e17503288b2286f704fa12c05 Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 10 Sep 2020 16:48:26 -0400 Subject: [PATCH 22/31] Code checker --- apps/cscsensor/cscsensor.app.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index 3cd6e73f8..616449eff 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -130,10 +130,7 @@ g.drawString("Scanning for CSC sensor...", 120, 120); setWatch(function() { mySensor.reset(); mySensor.updateScreen(); }, BTN1); -Bangle.on('kill',()=>{ if (gatt!=undefined) gatt.disconnect() - mySensor.settings.totaldist = mySensor.totaldist; - storage.writeJSON(SETTINGS_FILE, this.settings); - }); +Bangle.on('kill',()=>{ if (gatt!=undefined) gatt.disconnect(); mySensor.settings.totaldist = mySensor.totaldist; storage.writeJSON(SETTINGS_FILE, this.settings); }); Bangle.loadWidgets(); Bangle.drawWidgets(); From 053eecc2ec86b90d4163f6c9dce0bcf70257af6c Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 10 Sep 2020 17:13:00 -0400 Subject: [PATCH 23/31] Add option to zero total distance --- apps/cscsensor/settings.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/cscsensor/settings.js b/apps/cscsensor/settings.js index 8a1c21de5..d7a7d565d 100644 --- a/apps/cscsensor/settings.js +++ b/apps/cscsensor/settings.js @@ -22,7 +22,6 @@ storage.write(SETTINGS_FILE, s); } } - const menu = { '': { 'title': 'Cycle speed sensor' }, '< Back': back, @@ -32,6 +31,14 @@ max: 2400, step: 5, onchange: save('wheelcirc'), + }, + 'Reset total distance': function() { + E.showPrompt("Zero total distance?", {buttons: {"No":false, "Yes":true}}).then(function(v) { + if (v) { + s['totaldist'] = 0; + storage.write(SETTINGS_FILE, s); + } + }).then(back); } } E.showMenu(menu); From 9d21a96860d77cbd10ed3346a2685f659e193f03 Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 10 Sep 2020 17:45:05 -0400 Subject: [PATCH 24/31] Fix typo --- apps/cscsensor/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/cscsensor/README.md b/apps/cscsensor/README.md index 9fc43a276..4df609e6c 100644 --- a/apps/cscsensor/README.md +++ b/apps/cscsensor/README.md @@ -10,7 +10,7 @@ Currently the app displays the following data: - trip distance traveled - total distance traveled -Button 1 resets all measurements except total distance traveled. The latter gets preserved by being written to storage every 0.2 miles and upon exitting the app. +Button 1 resets all measurements except total distance traveled. The latter gets preserved by being written to storage every 0.2 miles and upon exiting the app. -I do not have acces to a cadence sensor at the moment, so only the speed part is currently implemented. Values displayed are imperial or metric (depending on locale), +I do not have access to a cadence sensor at the moment, so only the speed part is currently implemented. Values displayed are imperial or metric (depending on locale), the wheel circumference can be adjusted in the global settings app. From 5cbc826e9555f86bf41165af27610306bdbf785d Mon Sep 17 00:00:00 2001 From: "Marko.Kl.Berkenbusch@gmail.com" Date: Thu, 10 Sep 2020 21:05:55 -0400 Subject: [PATCH 25/31] Add repeat setting for reset button --- apps/cscsensor/cscsensor.app.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index 616449eff..fad1e2f83 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -42,7 +42,7 @@ class CSCSensor { if (dmins.length<2) dmins = "0"+dmins; var dsecs = (Math.floor(this.movingTime) % 60).toString(); if (dsecs.length<2) dsecs = "0"+dsecs; - var avespeed = (this.movingTime>0 ? Math.round(10*dist/(this.movingTime/3600))/10 : 0); + var avespeed = (this.movingTime>2 ? Math.round(10*dist/(this.movingTime/3600))/10 : 0); var maxspeed = Math.round(10*this.distFactor*this.maxSpeed)/10; g.setFontAlign(1, -1, 0).setFontVector(18).setColor(1, 1, 0); g.drawString("Time:", 86, 60); @@ -120,6 +120,7 @@ function parseDevice(d) { }).then(function() { console.log("Done!"); g.clearRect(0, 60, 239, 239).setColor(1, 1, 1).flip(); + mySensor.updateScreen(); }).catch(function(e) { g.clearRect(0, 60, 239, 239).setColor(1, 0, 0).setFontAlign(0, 0, 0).drawString("ERROR"+e, 120, 120).flip(); })} @@ -128,9 +129,9 @@ NRF.setScan(parseDevice, { filters: [{services:["1816"]}], timeout: 2000}); g.clearRect(0, 60, 239, 239).setFontVector(18).setFontAlign(0, 0, 0).setColor(0, 1, 0); g.drawString("Scanning for CSC sensor...", 120, 120); -setWatch(function() { mySensor.reset(); mySensor.updateScreen(); }, BTN1); +setWatch(function() { mySensor.reset(); mySensor.updateScreen(); }, BTN1, {repeat:true, debounce:20}); -Bangle.on('kill',()=>{ if (gatt!=undefined) gatt.disconnect(); mySensor.settings.totaldist = mySensor.totaldist; storage.writeJSON(SETTINGS_FILE, this.settings); }); +Bangle.on('kill',()=>{ if (gatt!=undefined) gatt.disconnect(); mySensor.settings.totaldist = mySensor.totaldist; storage.writeJSON(SETTINGS_FILE, mySensor.settings); }); Bangle.loadWidgets(); Bangle.drawWidgets(); From 06b493d1ec9cc10a5f79a5499d0bac0e28842c91 Mon Sep 17 00:00:00 2001 From: "Marko.Kl.Berkenbusch@gmail.com" Date: Thu, 10 Sep 2020 21:19:48 -0400 Subject: [PATCH 26/31] Save mileage adjustment --- apps/cscsensor/README.md | 2 +- apps/cscsensor/cscsensor.app.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/cscsensor/README.md b/apps/cscsensor/README.md index 4df609e6c..8ba862241 100644 --- a/apps/cscsensor/README.md +++ b/apps/cscsensor/README.md @@ -10,7 +10,7 @@ Currently the app displays the following data: - trip distance traveled - total distance traveled -Button 1 resets all measurements except total distance traveled. The latter gets preserved by being written to storage every 0.2 miles and upon exiting the app. +Button 1 resets all measurements except total distance traveled. The latter gets preserved by being written to storage every 0.1 miles and upon exiting the app. I do not have access to a cadence sensor at the moment, so only the speed part is currently implemented. Values displayed are imperial or metric (depending on locale), the wheel circumference can be adjusted in the global settings app. diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index fad1e2f83..8db7ef41a 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -67,7 +67,7 @@ class CSCSensor { if (dRevs>0) { qChanged = true; this.totaldist += dRevs*this.wheelCirc/63360.0; - if ((this.totaldist-this.settings.totaldist)>0.2) { + if ((this.totaldist-this.settings.totaldist)>0.1) { this.settings.totaldist = this.totaldist; storage.writeJSON(SETTINGS_FILE, this.settings); } From e073362b249e2109b0a0a4caef36fb86f70f330b Mon Sep 17 00:00:00 2001 From: "Marko.Kl.Berkenbusch@gmail.com" Date: Thu, 10 Sep 2020 21:25:42 -0400 Subject: [PATCH 27/31] Clear screen on reset --- apps/cscsensor/cscsensor.app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index 8db7ef41a..3e6e54404 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -129,7 +129,7 @@ NRF.setScan(parseDevice, { filters: [{services:["1816"]}], timeout: 2000}); g.clearRect(0, 60, 239, 239).setFontVector(18).setFontAlign(0, 0, 0).setColor(0, 1, 0); g.drawString("Scanning for CSC sensor...", 120, 120); -setWatch(function() { mySensor.reset(); mySensor.updateScreen(); }, BTN1, {repeat:true, debounce:20}); +setWatch(function() { mySensor.reset(); g.clearRect(0, 60, 239, 239); mySensor.updateScreen(); }, BTN1, {repeat:true, debounce:20}); Bangle.on('kill',()=>{ if (gatt!=undefined) gatt.disconnect(); mySensor.settings.totaldist = mySensor.totaldist; storage.writeJSON(SETTINGS_FILE, mySensor.settings); }); From 142ccaddf8c911ac1b12b7d62e850d4c45f96de3 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 14 Sep 2020 10:50:26 +0100 Subject: [PATCH 28/31] 0.21: Handle echo off char from Gadgetbridge app when programmable:off (fix #558) --- apps.json | 3 +-- apps/boot/ChangeLog | 1 + apps/boot/boot0.js | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index f893deeac..bce3b60fb 100644 --- a/apps.json +++ b/apps.json @@ -2,7 +2,7 @@ { "id": "boot", "name": "Bootloader", "icon": "bootloader.png", - "version":"0.20", + "version":"0.21", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "tags": "tool,system", "type":"bootloader", @@ -2203,4 +2203,3 @@ ] } ] - diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 5dde04f9c..d2f68fd0e 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -19,3 +19,4 @@ 0.18: Fix 'GPS time' checks for western hemisphere 0.19: Tweaks to simplify code and lower memory usage 0.20: Allow Gadgetbridge to work even with programmable:off +0.21: Handle echo off char from Gadgetbridge app when programmable:off (fix #558) diff --git a/apps/boot/boot0.js b/apps/boot/boot0.js index b674d601f..630252dea 100644 --- a/apps/boot/boot0.js +++ b/apps/boot/boot0.js @@ -22,6 +22,7 @@ if (s.blerepl===false) { // If not programmable, force terminal off Bluetooth l.forEach(n=>Bluetooth.emit("line",n)); }); Bluetooth.on('line',function(l) { + if (l.startsWith('\x10')) l=l.slice(1); if (l.startsWith('GB({') && l.endsWith('})') && global.GB) try { global.GB(JSON.parse(l.slice(3,-1))); } catch(e) {} }); From 63fe1387fa99fc610349ad6b91d26b09dd86b8ad Mon Sep 17 00:00:00 2001 From: marko Date: Tue, 15 Sep 2020 15:07:44 -0400 Subject: [PATCH 29/31] Reconnect on disconnect, properly save on exit and reset, better time handling --- apps/cscsensor/cscsensor.app.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index 3e6e54404..bf534e734 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -15,7 +15,7 @@ class CSCSensor { this.settings = storage.readJSON(SETTINGS_FILE, 1) || {}; this.settings.totaldist = this.settings.totaldist || 0; this.totaldist = this.settings.totaldist; - this.wheelCirc = (this.settings.wheelcirc || 2230)/25.4; + this.wheelCirc = (this.settings.wheelcirc || 2165)/25.4; this.speedFailed = 0; this.speed = 0; this.maxSpeed = 0; @@ -28,6 +28,8 @@ class CSCSensor { this.distFactor = this.qMetric ? 1.609344 : 1; } reset() { + this.settings.totaldist = this.totaldist; + storage.writeJSON(SETTINGS_FILE, this.settings); this.maxSpeed = 0; this.movingTime = 0; this.lastRevsStart = this.lastRevs; @@ -79,12 +81,13 @@ class CSCSensor { var dBT = (Date.now()-this.lastBangleTime)/1000; this.lastBangleTime = Date.now(); if (dT<0) dT+=64; + if (Math.abs(dT-dBT)>2) dT = dBT; this.lastTime = wheelTime; this.speed = this.lastSpeed; if (dRevs>0 && dT>0) { this.speed = (dRevs*this.wheelCirc/63360.0)*3600/dT; this.speedFailed = 0; - this.movingTime += dBT; + this.movingTime += dT; } else { this.speedFailed++; @@ -125,13 +128,16 @@ function parseDevice(d) { g.clearRect(0, 60, 239, 239).setColor(1, 0, 0).setFontAlign(0, 0, 0).drawString("ERROR"+e, 120, 120).flip(); })} -NRF.setScan(parseDevice, { filters: [{services:["1816"]}], timeout: 2000}); -g.clearRect(0, 60, 239, 239).setFontVector(18).setFontAlign(0, 0, 0).setColor(0, 1, 0); -g.drawString("Scanning for CSC sensor...", 120, 120); +function connection_setup() { + NRF.setScan(parseDevice, { filters: [{services:["1816"]}], timeout: 2000}); + g.clearRect(0, 60, 239, 239).setFontVector(18).setFontAlign(0, 0, 0).setColor(0, 1, 0); + g.drawString("Scanning for CSC sensor...", 120, 120); +} +connection_setup(); setWatch(function() { mySensor.reset(); g.clearRect(0, 60, 239, 239); mySensor.updateScreen(); }, BTN1, {repeat:true, debounce:20}); - -Bangle.on('kill',()=>{ if (gatt!=undefined) gatt.disconnect(); mySensor.settings.totaldist = mySensor.totaldist; storage.writeJSON(SETTINGS_FILE, mySensor.settings); }); +E.on('kill',()=>{ if (gatt!=undefined) gatt.disconnect(); mySensor.settings.totaldist = mySensor.totaldist; storage.writeJSON(SETTINGS_FILE, mySensor.settings); }); +NRF.on('disconnect', connection_setup); Bangle.loadWidgets(); Bangle.drawWidgets(); From c22254a591eaf0c84b8cfadfa42ffe694bbc71a5 Mon Sep 17 00:00:00 2001 From: marko Date: Tue, 15 Sep 2020 17:48:41 -0400 Subject: [PATCH 30/31] Add sensor battery indicator --- apps.json | 2 +- apps/cscsensor/ChangeLog | 1 + apps/cscsensor/cscsensor.app.js | 27 ++++++++++++++++++++++++++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 917096897..cadc76ba5 100644 --- a/apps.json +++ b/apps.json @@ -2176,7 +2176,7 @@ "name": "Cycling speed sensor", "shortName":"CSCSensor", "icon": "icons8-cycling-48.png", - "version":"0.03", + "version":"0.04", "description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch", "tags": "outdoors,exercise,ble,bluetooth", "readme": "README.md", diff --git a/apps/cscsensor/ChangeLog b/apps/cscsensor/ChangeLog index ae99905a6..7be2ed3e2 100644 --- a/apps/cscsensor/ChangeLog +++ b/apps/cscsensor/ChangeLog @@ -1,4 +1,5 @@ 0.01: New app! 0.02: Add wheel circumference settings dialog 0.03: Save total distance traveled +0.04: Add sensor battery level indicator diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index bf534e734..915cb52fc 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -15,7 +15,7 @@ class CSCSensor { this.settings = storage.readJSON(SETTINGS_FILE, 1) || {}; this.settings.totaldist = this.settings.totaldist || 0; this.totaldist = this.settings.totaldist; - this.wheelCirc = (this.settings.wheelcirc || 2165)/25.4; + this.wheelCirc = (this.settings.wheelcirc || 2230)/25.4; this.speedFailed = 0; this.speed = 0; this.maxSpeed = 0; @@ -26,6 +26,7 @@ class CSCSensor { this.speedUnit = this.qMetric ? "km/h" : "mph"; this.distUnit = this.qMetric ? "km" : "mi"; this.distFactor = this.qMetric ? 1.609344 : 1; + this.batteryLevel = -1; } reset() { this.settings.totaldist = this.totaldist; @@ -35,6 +36,9 @@ class CSCSensor { this.lastRevsStart = this.lastRevs; this.maxSpeed = 0; } + setBatteryLevel(level) { + this.batteryLevel = level; + } updateScreen() { var dist = this.distFactor*(this.lastRevs-this.lastRevsStart)*this.wheelCirc/63360.0; var ddist = Math.round(100*dist)/100; @@ -60,6 +64,15 @@ class CSCSensor { g.drawString(maxspeed + " " + this.speedUnit, 92, 156); g.drawString(ddist + " " + this.distUnit, 92, 188); g.drawString(tdist + " " + this.distUnit, 92, 220); + if (this.batteryLevel!=-1) { + g.setColor(1, 1, 1).drawRect(10, 64, 20, 84).fillRect(14, 62, 16, 64); + if (this.batteryLevel<25) g.setColor(1, 0, 0); + else if (this.batteryLevel<50) g.setColor(1, 0.5, 0); + else g.setColor(0, 1, 0); + g.fillRect(11, 83-18*this.batteryLevel/100, 19, 83); + console.log(this.batteryLevel); + this.batteryLevel = -1; + } } updateSensor(event) { var qChanged = false; @@ -106,6 +119,16 @@ class CSCSensor { var mySensor = new CSCSensor(); +function getSensorBatteryLevel(gatt) { + gatt.getPrimaryService("180f").then(function(s) { + return s.getCharacteristic("2a19"); + }).then(function(c) { + return c.readValue(); + }).then(function(d) { + mySensor.setBatteryLevel(d.buffer[0]); + }); +} + function parseDevice(d) { device = d; g.clearRect(0, 60, 239, 239).setFontAlign(0, 0, 0).setColor(0, 1, 0).drawString("Found device", 120, 120).flip(); @@ -123,9 +146,11 @@ function parseDevice(d) { }).then(function() { console.log("Done!"); g.clearRect(0, 60, 239, 239).setColor(1, 1, 1).flip(); + getSensorBatteryLevel(gatt); mySensor.updateScreen(); }).catch(function(e) { g.clearRect(0, 60, 239, 239).setColor(1, 0, 0).setFontAlign(0, 0, 0).drawString("ERROR"+e, 120, 120).flip(); + console.log(e); })} function connection_setup() { From 3c0db6cd25ea980cba08616cf4932d6473360f94 Mon Sep 17 00:00:00 2001 From: marko Date: Tue, 15 Sep 2020 22:36:33 -0400 Subject: [PATCH 31/31] Make display more readable --- apps/cscsensor/cscsensor.app.js | 41 ++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index 915cb52fc..65b50dfe7 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -50,26 +50,35 @@ class CSCSensor { if (dsecs.length<2) dsecs = "0"+dsecs; var avespeed = (this.movingTime>2 ? Math.round(10*dist/(this.movingTime/3600))/10 : 0); var maxspeed = Math.round(10*this.distFactor*this.maxSpeed)/10; - g.setFontAlign(1, -1, 0).setFontVector(18).setColor(1, 1, 0); - g.drawString("Time:", 86, 60); - g.drawString("Speed:", 86, 92); - g.drawString("Ave spd:", 86, 124); - g.drawString("Max spd:", 86, 156); - g.drawString("Trip dist:", 86, 188); - g.drawString("Total:", 86, 220); - g.setFontAlign(-1, -1, 0).setFontVector(24).setColor(1, 1, 1).clearRect(92, 60, 239, 239); - g.drawString(dmins+":"+dsecs, 92, 60); - g.drawString(dspeed+" "+this.speedUnit, 92, 92); - g.drawString(avespeed + " " + this.speedUnit, 92, 124); - g.drawString(maxspeed + " " + this.speedUnit, 92, 156); - g.drawString(ddist + " " + this.distUnit, 92, 188); - g.drawString(tdist + " " + this.distUnit, 92, 220); + for (var i=0; i<6; ++i) { + if ((i&1)==0) g.setColor(0, 0, 0); + else g.setColor(0.2, 0.1, 0.4); + g.fillRect(0, 48+i*32, 86, 48+(i+1)*32); + if ((i&1)==1) g.setColor(0, 0, 0); + else g.setColor(0.2, 0.1, 0.4); + g.fillRect(87, 48+i*32, 239, 48+(i+1)*32); + g.setColor(0.5, 0.5, 0.5).drawRect(87, 48+i*32, 239, 48+(i+1)*32).drawLine(0, 239, 239, 239).drawRect(0, 48, 87, 239); + } + g.setFontAlign(1, 0, 0).setFontVector(19).setColor(1, 1, 0); + g.drawString("Time:", 87, 66); + g.drawString("Speed:", 87, 98); + g.drawString("Ave spd:", 87, 130); + g.drawString("Max spd:", 87, 162); + g.drawString("Trip:", 87, 194); + g.drawString("Total:", 87, 226); + g.setFontAlign(-1, 0, 0).setFontVector(26).setColor(1, 1, 1);//.clearRect(92, 60, 239, 239); + g.drawString(dmins+":"+dsecs, 92, 66); + g.drawString(dspeed+" "+this.speedUnit, 92, 98); + g.drawString(avespeed + " " + this.speedUnit, 92, 130); + g.drawString(maxspeed + " " + this.speedUnit, 92, 162); + g.drawString(ddist + " " + this.distUnit, 92, 194); + g.drawString(tdist + " " + this.distUnit, 92, 226); if (this.batteryLevel!=-1) { - g.setColor(1, 1, 1).drawRect(10, 64, 20, 84).fillRect(14, 62, 16, 64); + g.setColor(1, 1, 1).drawRect(10, 55, 20, 75).fillRect(14, 53, 16, 55); if (this.batteryLevel<25) g.setColor(1, 0, 0); else if (this.batteryLevel<50) g.setColor(1, 0.5, 0); else g.setColor(0, 1, 0); - g.fillRect(11, 83-18*this.batteryLevel/100, 19, 83); + g.fillRect(11, 74-18*this.batteryLevel/100, 19, 74); console.log(this.batteryLevel); this.batteryLevel = -1; }