New CSC sensor app

add support for cadence sensor
pull/822/head
Erik Andresen 2021-09-23 08:27:19 +02:00
parent 3b15a7f922
commit 891a32bf44
4 changed files with 91 additions and 38 deletions

View File

@ -2508,7 +2508,7 @@
"name": "Cycling speed sensor", "name": "Cycling speed sensor",
"shortName":"CSCSensor", "shortName":"CSCSensor",
"icon": "icons8-cycling-48.png", "icon": "icons8-cycling-48.png",
"version":"0.04", "version":"0.05",
"description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch", "description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch",
"tags": "outdoors,exercise,ble,bluetooth", "tags": "outdoors,exercise,ble,bluetooth",
"readme": "README.md", "readme": "README.md",

View File

@ -2,4 +2,4 @@
0.02: Add wheel circumference settings dialog 0.02: Add wheel circumference settings dialog
0.03: Save total distance traveled 0.03: Save total distance traveled
0.04: Add sensor battery level indicator 0.04: Add sensor battery level indicator
0.05: Add cadence sensor support

View File

@ -13,6 +13,6 @@ Currently the app displays the following data:
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. 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.
If the watch app has not received an update from the sensor for at least 10 seconds, pushing button 3 will attempt to reconnect to the sensor. If the watch app has not received an update from the sensor for at least 10 seconds, pushing button 3 will attempt to reconnect to the sensor.
Button 2 switches between the display for cycling speed and cadence.
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), Values displayed are imperial or metric (depending on locale), cadence is in RPM, the wheel circumference can be adjusted in the global settings app.
the wheel circumference can be adjusted in the global settings app.

View File

@ -28,6 +28,10 @@ class CSCSensor {
this.distFactor = this.qMetric ? 1.609344 : 1; this.distFactor = this.qMetric ? 1.609344 : 1;
this.screenInit = true; this.screenInit = true;
this.batteryLevel = -1; this.batteryLevel = -1;
this.lastCrankTime = 0;
this.lastCrankRevs = 0;
this.showCadence = false;
this.cadence = 0;
} }
reset() { reset() {
@ -40,6 +44,11 @@ class CSCSensor {
this.screenInit = true; this.screenInit = true;
} }
toggleDisplayCadence() {
this.showCadence = !this.showCadence;
this.screenInit = true;
}
setBatteryLevel(level) { setBatteryLevel(level) {
if (level!=this.batteryLevel) { if (level!=this.batteryLevel) {
this.batteryLevel = level; this.batteryLevel = level;
@ -62,7 +71,7 @@ class CSCSensor {
else g.setFontVector(14).setFontAlign(0, 0, 0).setColor(0xffff).drawString("?", 16, 66); else g.setFontVector(14).setFontAlign(0, 0, 0).setColor(0xffff).drawString("?", 16, 66);
} }
updateScreen() { updateScreenRevs() {
var dist = this.distFactor*(this.lastRevs-this.lastRevsStart)*this.wheelCirc/63360.0; var dist = this.distFactor*(this.lastRevs-this.lastRevsStart)*this.wheelCirc/63360.0;
var ddist = Math.round(100*dist)/100; var ddist = Math.round(100*dist)/100;
var tdist = Math.round(this.distFactor*this.totaldist*10)/10; var tdist = Math.round(this.distFactor*this.totaldist*10)/10;
@ -109,9 +118,51 @@ class CSCSensor {
g.setColor(0xffff).drawString(tdist + " " + this.distUnit, 92, 226); g.setColor(0xffff).drawString(tdist + " " + this.distUnit, 92, 226);
} }
updateScreenCadence() {
if (this.screenInit) {
for (var i=0; i<2; ++i) {
if ((i&1)==0) g.setColor(0, 0, 0);
else g.setColor(0x30cd);
g.fillRect(0, 48+i*32, 86, 48+(i+1)*32);
if ((i&1)==1) g.setColor(0);
else g.setColor(0x30cd);
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.moveTo(0, 80).lineTo(30, 80).lineTo(30, 48).lineTo(87, 48).lineTo(87, 239).lineTo(0, 239).lineTo(0, 80);
}
g.setFontAlign(1, 0, 0).setFontVector(19).setColor(1, 1, 0);
g.drawString("Cadence:", 87, 98);
this.drawBatteryIcon();
this.screenInit = false;
}
g.setFontAlign(-1, 0, 0).setFontVector(26);
g.setColor(0).fillRect(88, 81, 238, 111);
g.setColor(0xffff).drawString(Math.round(this.cadence), 92, 98);
}
updateScreen() {
if (!this.showCadence) {
this.updateScreenRevs();
} else {
this.updateScreenCadence();
}
}
updateSensor(event) { updateSensor(event) {
var qChanged = false; var qChanged = false;
if (event.target.uuid == "0x2a5b") { if (event.target.uuid == "0x2a5b") {
if (event.target.value.getUint8(0, true) & 0x2) {
// crank revolution
const crankRevs = event.target.value.getUint16(1, true);
const crankTime = event.target.value.getUint16(3, true);
if (crankTime > this.lastCrankTime) {
this.cadence = (crankRevs-this.lastCrankRevs)/(crankTime-this.lastCrankTime)*60000;
qChanged = true;
}
this.lastCrankRevs = crankRevs;
this.lastCrankTime = crankTime;
} else {
// wheel revolution
var wheelRevs = event.target.value.getUint32(1, true); var wheelRevs = event.target.value.getUint32(1, true);
var dRevs = (this.lastRevs>0 ? wheelRevs-this.lastRevs : 0); var dRevs = (this.lastRevs>0 ? wheelRevs-this.lastRevs : 0);
if (dRevs>0) { if (dRevs>0) {
@ -148,6 +199,7 @@ class CSCSensor {
this.lastSpeed = this.speed; this.lastSpeed = this.speed;
if (this.speed>this.maxSpeed && (this.movingTime>3 || this.speed<20) && this.speed<50) this.maxSpeed = this.speed; if (this.speed>this.maxSpeed && (this.movingTime>3 || this.speed<20) && this.speed<50) this.maxSpeed = this.speed;
} }
}
if (qChanged && this.qUpdateScreen) this.updateScreen(); if (qChanged && this.qUpdateScreen) this.updateScreen();
} }
} }
@ -199,6 +251,7 @@ connection_setup();
setWatch(function() { mySensor.reset(); g.clearRect(0, 48, 239, 239); mySensor.updateScreen(); }, BTN1, {repeat:true, debounce:20}); setWatch(function() { mySensor.reset(); g.clearRect(0, 48, 239, 239); mySensor.updateScreen(); }, BTN1, {repeat:true, debounce:20});
E.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); });
setWatch(function() { if (Date.now()-mySensor.lastBangleTime>10000) connection_setup(); }, BTN3, {repeat:true, debounce:20}); setWatch(function() { if (Date.now()-mySensor.lastBangleTime>10000) connection_setup(); }, BTN3, {repeat:true, debounce:20});
setWatch(function() { mySensor.toggleDisplayCadence(); g.clearRect(0, 48, 239, 239); mySensor.updateScreen(); }, BTN2, {repeat:true, debounce:20});
NRF.on('disconnect', connection_setup); NRF.on('disconnect', connection_setup);
Bangle.loadWidgets(); Bangle.loadWidgets();