1
0
Fork 0
David Peer 2021-11-26 19:01:14 +01:00
commit 3e4ed5e49b
8 changed files with 104 additions and 84 deletions

View File

@ -734,11 +734,11 @@
{ {
"id": "slevel", "id": "slevel",
"name": "Spirit Level", "name": "Spirit Level",
"version": "0.01", "version": "0.02",
"description": "Show the current angle of the watch, so you can use it to make sure something is absolutely flat", "description": "Show the current angle of the watch, so you can use it to make sure something is absolutely flat",
"icon": "spiritlevel.png", "icon": "spiritlevel.png",
"tags": "tool", "tags": "tool",
"supports": ["BANGLEJS"], "supports": ["BANGLEJS","BANGLEJS2"],
"storage": [ "storage": [
{"name":"slevel.app.js","url":"spiritlevel.js"}, {"name":"slevel.app.js","url":"spiritlevel.js"},
{"name":"slevel.img","url":"spiritlevel-icon.js","evaluate":true} {"name":"slevel.img","url":"spiritlevel-icon.js","evaluate":true}
@ -2948,7 +2948,7 @@
"id": "cscsensor", "id": "cscsensor",
"name": "Cycling speed sensor", "name": "Cycling speed sensor",
"shortName": "CSCSensor", "shortName": "CSCSensor",
"version": "0.05", "version": "0.06",
"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",
"icon": "icons8-cycling-48.png", "icon": "icons8-cycling-48.png",
"tags": "outdoors,exercise,ble,bluetooth", "tags": "outdoors,exercise,ble,bluetooth",
@ -4039,10 +4039,11 @@
"id": "fd6fdetect", "id": "fd6fdetect",
"name": "fd6fdetect", "name": "fd6fdetect",
"shortName": "fd6fdetect", "shortName": "fd6fdetect",
"version": "0.1", "version": "0.2",
"description": "Allows you to see 0xFD6F beacons near you.", "description": "Allows you to see 0xFD6F beacons near you.",
"icon": "app.png", "icon": "app.png",
"tags": "tool", "tags": "tool",
"readme": "README.md",
"supports": ["BANGLEJS"], "supports": ["BANGLEJS"],
"storage": [ "storage": [
{"name":"fd6fdetect.app.js","url":"app.js"}, {"name":"fd6fdetect.app.js","url":"app.js"},

View File

@ -3,3 +3,5 @@
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 0.05: Add cadence sensor support
0.06: Now read wheel rev as well as cadence sensor
Improve connection code

View File

@ -16,3 +16,9 @@ If the watch app has not received an update from the sensor for at least 10 seco
Button 2 switches between the display for cycling speed and cadence. Button 2 switches between the display for cycling speed and cadence.
Values displayed are imperial or metric (depending on locale), cadence is in RPM, the wheel circumference can be adjusted in the global settings app. Values displayed are imperial or metric (depending on locale), cadence is in RPM, the wheel circumference can be adjusted in the global settings app.
# TODO
* Use Layout Library to provide proper Bangle.js 2 support
* Turn CSC sensor support into a library
* Support for `Recorder` app, to allow CSC readings to be logged alongside GPS

View File

@ -5,6 +5,8 @@ var characteristic;
const SETTINGS_FILE = 'cscsensor.json'; const SETTINGS_FILE = 'cscsensor.json';
const storage = require('Storage'); const storage = require('Storage');
const W = g.getWidth();
const H = g.getHeight();
class CSCSensor { class CSCSensor {
constructor() { constructor() {
@ -152,7 +154,7 @@ class CSCSensor {
var qChanged = false; var qChanged = false;
if (event.target.uuid == "0x2a5b") { if (event.target.uuid == "0x2a5b") {
if (event.target.value.getUint8(0, true) & 0x2) { if (event.target.value.getUint8(0, true) & 0x2) {
// crank revolution // crank revolution - if enabled
const crankRevs = event.target.value.getUint16(1, true); const crankRevs = event.target.value.getUint16(1, true);
const crankTime = event.target.value.getUint16(3, true); const crankTime = event.target.value.getUint16(3, true);
if (crankTime > this.lastCrankTime) { if (crankTime > this.lastCrankTime) {
@ -161,7 +163,7 @@ class CSCSensor {
} }
this.lastCrankRevs = crankRevs; this.lastCrankRevs = crankRevs;
this.lastCrankTime = crankTime; this.lastCrankTime = crankTime;
} else { }
// wheel revolution // 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);
@ -199,7 +201,6 @@ 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();
} }
} }
@ -215,44 +216,47 @@ function getSensorBatteryLevel(gatt) {
}); });
} }
function parseDevice(d) { function connection_setup() {
mySensor.screenInit = true;
E.showMessage("Scanning for CSC sensor...");
NRF.requestDevice({ filters: [{services:["1816"]}]}).then(function(d) {
device = d; device = d;
g.clearRect(0, 60, 239, 239).setFontAlign(0, 0, 0).setColor(0, 1, 0).drawString("Found device", 120, 120).flip(); E.showMessage("Found device");
device.gatt.connect().then(function(ga) { return device.gatt.connect();
}).then(function(ga) {
gatt = ga; gatt = ga;
g.clearRect(0, 60, 239, 239).setFontAlign(0, 0, 0).setColor(0, 1, 0).drawString("Connected", 120, 120).flip(); E.showMessage("Connected");
return gatt.getPrimaryService("1816"); return gatt.getPrimaryService("1816");
}).then(function(s) { }).then(function(s) {
service = s; service = s;
return service.getCharacteristic("2a5b"); return service.getCharacteristic("2a5b");
}).then(function(c) { }).then(function(c) {
characteristic = c; characteristic = c;
characteristic.on('characteristicvaluechanged', (event)=>mySensor.updateSensor(event)); characteristic.on('characteristicvaluechanged', (event)=>mySensor.updateSensor(event));
return characteristic.startNotifications(); return characteristic.startNotifications();
}).then(function() { }).then(function() {
console.log("Done!"); console.log("Done!");
g.clearRect(0, 60, 239, 239).setColor(1, 1, 1).flip(); g.reset().clearRect(Bangle.appRect).flip();
getSensorBatteryLevel(gatt); getSensorBatteryLevel(gatt);
mySensor.updateScreen(); mySensor.updateScreen();
}).catch(function(e) { }).catch(function(e) {
g.clearRect(0, 60, 239, 239).setColor(1, 0, 0).setFontAlign(0, 0, 0).drawString("ERROR"+e, 120, 120).flip(); E.showMessage(e.toString(), "ERROR");
console.log(e); console.log(e);
})} });
function connection_setup() {
NRF.setScan();
mySensor.screenInit = true;
NRF.setScan(parseDevice, { filters: [{services:["1816"]}], timeout: 2000});
g.clearRect(0, 48, 239, 239).setFontVector(18).setFontAlign(0, 0, 0).setColor(0, 1, 0);
g.drawString("Scanning for CSC sensor...", 120, 120);
} }
connection_setup(); connection_setup();
setWatch(function() { mySensor.reset(); g.clearRect(0, 48, 239, 239); mySensor.updateScreen(); }, BTN1, {repeat:true, debounce:20}); E.on('kill',()=>{
E.on('kill',()=>{ if (gatt!=undefined) gatt.disconnect(); mySensor.settings.totaldist = mySensor.totaldist; storage.writeJSON(SETTINGS_FILE, mySensor.settings); }); if (gatt!=undefined) gatt.disconnect();
setWatch(function() { if (Date.now()-mySensor.lastBangleTime>10000) connection_setup(); }, BTN3, {repeat:true, debounce:20}); mySensor.settings.totaldist = mySensor.totaldist;
setWatch(function() { mySensor.toggleDisplayCadence(); g.clearRect(0, 48, 239, 239); mySensor.updateScreen(); }, BTN2, {repeat:true, debounce:20}); storage.writeJSON(SETTINGS_FILE, mySensor.settings);
NRF.on('disconnect', connection_setup); });
NRF.on('disconnect', connection_setup); // restart if disconnected
Bangle.setUI("updown", d=>{
if (d<0) { mySensor.reset(); g.clearRect(0, 48, W, H); mySensor.updateScreen(); }
if (d==0) { if (Date.now()-mySensor.lastBangleTime>10000) connection_setup(); }
if (d>0) { mySensor.toggleDisplayCadence(); g.clearRect(0, 48, W, H); mySensor.updateScreen(); }
});
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();

View File

@ -1 +1,2 @@
0.1: Added source code 0.1: Added source code
0.2: Added a README file

View File

@ -0,0 +1,3 @@
# FD6FDetect
An app dedicated to letting you know how many Exposure Notification beacons are near you.

View File

@ -1 +1,2 @@
0.01: New App! 0.01: New App!
0.02: Updated to work with both Bangle.js 1 and 2.

View File

@ -1,5 +1,7 @@
g.clear(); g.clear();
var old = {x:0,y:0}; var old = {x:0,y:0};
var W = g.getWidth();
var H = g.getHeight();
Bangle.on('accel',function(v) { Bangle.on('accel',function(v) {
var max = Math.max(Math.abs(v.x),Math.abs(v.y),Math.abs(v.z)); var max = Math.max(Math.abs(v.x),Math.abs(v.y),Math.abs(v.z));
if (Math.abs(v.y)==max) { if (Math.abs(v.y)==max) {
@ -14,17 +16,17 @@ Bangle.on('accel',function(v) {
g.setColor(1,1,1); g.setColor(1,1,1);
g.setFont("6x8",2); g.setFont("6x8",2);
g.setFontAlign(0,-1); g.setFontAlign(0,-1);
g.clearRect(60,0,180,16); g.clearRect(W*(1/4),0,W*(3/4),H*(1/16));
g.drawString(ang.toFixed(1),120,0); g.drawString(ang.toFixed(1),W/2,0);
var n = { var n = {
x:E.clip(120+v.x*256,4,236), x:E.clip(W/2+v.x*256,4,W-4),
y:E.clip(120+v.y*256,4,236)}; y:E.clip(H/2+v.y*256,4,H-4)};
g.clearRect(old.x-3,old.y-3,old.x+6,old.y+6); g.clearRect(old.x-3,old.y-3,old.x+6,old.y+6);
g.setColor(1,1,1); g.setColor(1,1,1);
g.fillRect(n.x-3,n.y-3,n.x+6,n.y+6); g.fillRect(n.x-3,n.y-3,n.x+6,n.y+6);
g.setColor(1,0,0); g.setColor(1,0,0);
g.drawCircle(120,120,20); g.drawCircle(W/2,H/2,W*(1/12));
g.drawCircle(120,120,60); g.drawCircle(W/2,H/2,W*(1/4));
g.drawCircle(120,120,100); g.drawCircle(W/2,H/2,W*(5/12));
old = n; old = n;
}); });