diff --git a/apps.json b/apps.json index bce3b60fb..07aa644f6 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 3e6e54404..65b50dfe7 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -26,13 +26,19 @@ 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; + storage.writeJSON(SETTINGS_FILE, this.settings); this.maxSpeed = 0; this.movingTime = 0; 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; @@ -44,20 +50,38 @@ 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, 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, 74-18*this.batteryLevel/100, 19, 74); + console.log(this.batteryLevel); + this.batteryLevel = -1; + } } updateSensor(event) { var qChanged = false; @@ -79,12 +103,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++; @@ -103,6 +128,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(); @@ -120,18 +155,23 @@ 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); })} -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();