forked from FOSS/BangleApps
Merge branch 'upstream/master' into feat/bleadvert-module
Conflicts: .eslintignoremaster
commit
2d113883eb
|
@ -5,15 +5,22 @@ apps/gipy/pkg/gps.js
|
|||
# Needs to be ignored because it includes broken JS
|
||||
apps/health/chart.min.js
|
||||
|
||||
# TypeScript
|
||||
apps/btadv/
|
||||
apps/clkinfostopw/
|
||||
apps/ctrlpad/
|
||||
apps/drained/
|
||||
apps/folderlaunch/
|
||||
apps/popconlaunch/
|
||||
apps/rep/
|
||||
apps/widChargingStatus/
|
||||
apps/widbtstates/
|
||||
apps/widhid/
|
||||
# Generated from TS files that have already been linted
|
||||
apps/btadv/app.js
|
||||
apps/clkinfostopw/clkinfo.js
|
||||
apps/ctrlpad/main.js
|
||||
apps/drained/app.js
|
||||
apps/drained/boot.js
|
||||
apps/drained/settings.js
|
||||
apps/folderlaunch/app.js
|
||||
apps/folderlaunch/configLoad.js
|
||||
apps/folderlaunch/settings.js
|
||||
apps/folderlaunch/types.d.js
|
||||
apps/popconlaunch/boot.js
|
||||
apps/popconlaunch/settings.js
|
||||
apps/rep/app.js
|
||||
apps/rep/settings.js
|
||||
apps/widChargingStatus/widget.js
|
||||
apps/widbtstates/widget.js
|
||||
apps/widhid/wid.js
|
||||
modules/ble_advert.js
|
||||
|
|
|
@ -195,6 +195,28 @@ module.exports = {
|
|||
"no-control-regex" : "off"
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["*.ts"],
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint"],
|
||||
rules: {
|
||||
"no-delete-var": "off",
|
||||
"no-empty": ["error", { "allowEmptyCatch": true }],
|
||||
"no-prototype-builtins": "off",
|
||||
"prefer-const": "off",
|
||||
"prefer-rest-params": "off",
|
||||
"no-control-regex" : "off",
|
||||
"@typescript-eslint/no-delete-var": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-this-alias": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" } ],
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
}
|
||||
},
|
||||
...Object.entries(lintExemptions).map(([filePath, {rules}]) => ({
|
||||
files: [filePath],
|
||||
rules: Object.fromEntries(rules.map(rule => [rule, "off"])),
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
0.01: Initial version
|
||||
0.02: Minor code improvements
|
||||
0.03: Moved from cycling app, fixed connection issues and cadence
|
|
@ -0,0 +1,32 @@
|
|||
# BLE Cycling Speed Sencor (CSC)
|
||||
|
||||
Displays data from a BLE Cycling Speed and Cadence sensor.
|
||||
|
||||
Other than in the original version of the app, total distance is not stored on the Bangle, but instead is calculated from the CWR (cumulative wheel revolutions) reported by the sensor. This metric is, according to the BLE spec, an absolute value that persists throughout the lifetime of the sensor and never rolls over.
|
||||
|
||||
## Settings
|
||||
|
||||
Accessible from `Settings -> Apps -> BLE CSC`
|
||||
|
||||
Here you can set the wheel diameter
|
||||
|
||||
## Development
|
||||
|
||||
```
|
||||
var csc = require("blecsc").getInstance();
|
||||
csc.on("status", txt => {
|
||||
print("##", txt);
|
||||
E.showMessage(txt);
|
||||
});
|
||||
csc.on("data", e => print(e));
|
||||
csc.start();
|
||||
```
|
||||
|
||||
The `data` event contains:
|
||||
|
||||
* cwr/ccr => wheel/crank cumulative revs
|
||||
* lwet/lcet => wheel/crank last event time in 1/1024s
|
||||
* wrps/crps => calculated wheel/crank revs per second
|
||||
* wdt/cdt => time period in seconds between events
|
||||
* wr => wheel revs
|
||||
* kph => kilometers per hour
|
|
@ -0,0 +1,216 @@
|
|||
/**
|
||||
* This library communicates with a Bluetooth CSC peripherial using the Espruino NRF library.
|
||||
*
|
||||
* ## Usage:
|
||||
* 1. Register event handlers using the \`on(eventName, handlerFunction)\` method
|
||||
* You can subscribe to the \`wheelEvent\` and \`crankEvent\` events or you can
|
||||
* have raw characteristic values passed through using the \`value\` event.
|
||||
* 2. Search and connect to a BLE CSC peripherial by calling the \`connect()\` method
|
||||
* 3. To tear down the connection, call the \`disconnect()\` method
|
||||
*
|
||||
* ## Events
|
||||
* - \`status\` - string containing connection status
|
||||
* - \`data\` - the peripheral sends a notification containing wheel/crank event data
|
||||
* - \`disconnect\` - the peripheral ends the connection or the connection is lost
|
||||
*
|
||||
* cwr/ccr => wheel/crank cumulative revs
|
||||
* lwet/lcet => wheel/crank last event time in 1/1024s
|
||||
* wrps/crps => calculated wheel/crank revs per second
|
||||
* wdt/cdt => time period in seconds between events
|
||||
* wr => wheel revs
|
||||
* kph => kilometers per hour
|
||||
*/
|
||||
class BLECSC {
|
||||
constructor() {
|
||||
this.reconnect = false; // set when start called
|
||||
this.device = undefined; // set when device found
|
||||
this.gatt = undefined; // set when connected
|
||||
// .on("status", => string
|
||||
// .on("data"
|
||||
// .on("disconnect"
|
||||
this.resetStats();
|
||||
// Set default values and merge with stored values
|
||||
this.settings = Object.assign({
|
||||
circum: 2068 // circumference in mm
|
||||
}, (require('Storage').readJSON('blecsc.json', true) || {}));
|
||||
}
|
||||
|
||||
resetStats() {
|
||||
this.cwr = undefined;
|
||||
this.ccr = undefined;
|
||||
this.lwet = undefined;
|
||||
this.lcet = undefined;
|
||||
this.lastCwr = undefined;
|
||||
this.lastCcr = undefined;
|
||||
this.lastLwet = undefined;
|
||||
this.lastLcet = undefined;
|
||||
this.kph = undefined;
|
||||
this.wrps = 0; // wheel revs per second
|
||||
this.crps = 0; // crank revs per second
|
||||
//this.batteryLevel = undefined;
|
||||
}
|
||||
|
||||
getDeviceAddress() {
|
||||
if (!this.device || !this.device.id)
|
||||
return '00:00:00:00:00:00';
|
||||
return this.device.id.split(" ")[0];
|
||||
}
|
||||
|
||||
status(txt) {
|
||||
this.emit("status", txt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and connect to a device which exposes the CSC service.
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
connect() {
|
||||
this.status("Scanning");
|
||||
// Find a device, then get the CSC Service and subscribe to
|
||||
// notifications on the CSC Measurement characteristic.
|
||||
// NRF.setLowPowerConnection(true);
|
||||
var reconnect = this.reconnect; // auto-reconnect
|
||||
return NRF.requestDevice({
|
||||
timeout: 5000,
|
||||
filters: [{
|
||||
services: ["1816"]
|
||||
}],
|
||||
}).then(device => {
|
||||
this.status("Connecting");
|
||||
this.device = device;
|
||||
this.device.on('gattserverdisconnected', event => {
|
||||
this.device = undefined;
|
||||
this.gatt = undefined;
|
||||
this.resetStats();
|
||||
this.status("Disconnected");
|
||||
this.emit("disconnect", event);
|
||||
if (reconnect) {// auto-reconnect
|
||||
reconnect = false;
|
||||
setTimeout(() => {
|
||||
if (this.reconnect) this.connect().then(() => {}, () => {});
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
|
||||
return new Promise(resolve => setTimeout(resolve, 150)); // On CooSpo we get a 'Connection Timeout' if we try and connect too soon
|
||||
}).then(() => {
|
||||
return this.device.gatt.connect();
|
||||
}).then(gatt => {
|
||||
this.status("Connected");
|
||||
this.gatt = gatt;
|
||||
return gatt.getPrimaryService("1816");
|
||||
}).then(service => {
|
||||
return service.getCharacteristic("2a5b"); // UUID of the CSC measurement characteristic
|
||||
}).then(characteristic => {
|
||||
// register for changes on 2a5b
|
||||
characteristic.on('characteristicvaluechanged', event => {
|
||||
const flags = event.target.value.getUint8(0);
|
||||
var offs = 0;
|
||||
var data = {};
|
||||
if (flags & 1) { // FLAGS_WREV_BM
|
||||
this.lastCwr = this.cwr;
|
||||
this.lastLwet = this.lwet;
|
||||
this.cwr = event.target.value.getUint32(1, true);
|
||||
this.lwet = event.target.value.getUint16(5, true);
|
||||
if (this.lastCwr === undefined) this.lastCwr = this.cwr;
|
||||
if (this.lastLwet === undefined) this.lastLwet = this.lwet;
|
||||
if (this.lwet < this.lastLwet) this.lastLwet -= 65536;
|
||||
let secs = (this.lwet - this.lastLwet) / 1024;
|
||||
this.wrps = (this.cwr - this.lastCwr) / (secs?secs:1);
|
||||
this.kph = this.wrps * this.settings.circum / 3600;
|
||||
Object.assign(data, { // Notify the 'wheelEvent' handler
|
||||
cwr: this.cwr, // cumulative wheel revolutions
|
||||
lwet: this.lwet, // last wheel event time
|
||||
wrps: this.wrps, // wheel revs per second
|
||||
wr: this.cwr - this.lastCwr, // wheel revs
|
||||
wdt : secs, // time period
|
||||
kph : this.kph
|
||||
});
|
||||
offs += 6;
|
||||
}
|
||||
if (flags & 2) { // FLAGS_CREV_BM
|
||||
this.lastCcr = this.ccr;
|
||||
this.lastLcet = this.lcet;
|
||||
this.ccr = event.target.value.getUint16(offs + 1, true);
|
||||
this.lcet = event.target.value.getUint16(offs + 3, true);
|
||||
if (this.lastCcr === undefined) this.lastCcr = this.ccr;
|
||||
if (this.lastLcet === undefined) this.lastLcet = this.lcet;
|
||||
if (this.lcet < this.lastLcet) this.lastLcet -= 65536;
|
||||
let secs = (this.lcet - this.lastLcet) / 1024;
|
||||
this.crps = (this.ccr - this.lastCcr) / (secs?secs:1);
|
||||
Object.assign(data, { // Notify the 'crankEvent' handler
|
||||
ccr: this.ccr, // cumulative crank revolutions
|
||||
lcet: this.lcet, // last crank event time
|
||||
crps: this.crps, // crank revs per second
|
||||
cdt : secs, // time period
|
||||
});
|
||||
}
|
||||
this.emit("data",data);
|
||||
});
|
||||
return characteristic.startNotifications();
|
||||
/* }).then(() => {
|
||||
return this.gatt.getPrimaryService("180f");
|
||||
}).then(service => {
|
||||
return service.getCharacteristic("2a19");
|
||||
}).then(characteristic => {
|
||||
characteristic.on('characteristicvaluechanged', (event)=>{
|
||||
this.batteryLevel = event.target.value.getUint8(0);
|
||||
});
|
||||
return characteristic.startNotifications();*/
|
||||
}).then(() => {
|
||||
this.status("Ready");
|
||||
}, err => {
|
||||
this.status("Error: " + err);
|
||||
if (reconnect) { // auto-reconnect
|
||||
reconnect = false;
|
||||
setTimeout(() => {
|
||||
if (this.reconnect) this.connect().then(() => {}, () => {});
|
||||
}, 500);
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect the device.
|
||||
*/
|
||||
disconnect() {
|
||||
if (!this.gatt) return;
|
||||
this.gatt.disconnect();
|
||||
this.gatt = undefined;
|
||||
}
|
||||
|
||||
/* Start trying to connect - will keep searching and attempting to connect*/
|
||||
start() {
|
||||
this.reconnect = true;
|
||||
if (!this.device)
|
||||
this.connect().then(() => {}, () => {});
|
||||
}
|
||||
|
||||
/* Stop trying to connect, and disconnect */
|
||||
stop() {
|
||||
this.reconnect = false;
|
||||
this.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
// Get an instance of BLECSC or create one if it doesn't exist
|
||||
BLECSC.getInstance = function() {
|
||||
if (!BLECSC.instance) {
|
||||
BLECSC.instance = new BLECSC();
|
||||
}
|
||||
return BLECSC.instance;
|
||||
};
|
||||
|
||||
exports = BLECSC;
|
||||
|
||||
/*
|
||||
var csc = require("blecsc").getInstance();
|
||||
csc.on("status", txt => {
|
||||
print("##", txt);
|
||||
E.showMessage(txt);
|
||||
});
|
||||
csc.on("data", e => print(e));
|
||||
csc.start();
|
||||
*/
|
|
@ -0,0 +1,74 @@
|
|||
(function() {
|
||||
var csc = require("blecsc").getInstance();
|
||||
//csc.on("status", txt => { print("CSC",txt); });
|
||||
csc.on("data", e => {
|
||||
ci.items.forEach(it => { if (it._visible) it.emit('redraw'); });
|
||||
});
|
||||
csc.on("disconnect", e => {
|
||||
// redraw all with no info
|
||||
ci.items.forEach(it => { if (it._visible) it.emit('redraw'); });
|
||||
});
|
||||
var uses = 0;
|
||||
var ci = {
|
||||
name: "CSC",
|
||||
items: [
|
||||
{ name : "Speed",
|
||||
get : () => {
|
||||
return {
|
||||
text : (csc.kph === undefined) ? "--" : require("locale").speed(csc.kph),
|
||||
img : atob("GBiBAAAAAAAAAAAAAAABwAABwAeBgAMBgAH/gAH/wAPDwA/DcD9m/Ge35sW9o8//M8/7E8CBA2GBhn8A/h4AeAAAAAAAAAAAAAAAAA==")
|
||||
};
|
||||
},
|
||||
show : function() {
|
||||
uses++;
|
||||
if (uses==1) csc.start();
|
||||
this._visible = true;
|
||||
},
|
||||
hide : function() {
|
||||
this._visible = false;
|
||||
uses--;
|
||||
if (uses==0) csc.stop();
|
||||
}
|
||||
},
|
||||
{ name : "Distance",
|
||||
get : () => {
|
||||
return {
|
||||
text : (csc.kph === undefined) ? "--" : require("locale").distance(csc.cwr * csc.settings.circum / 1000),
|
||||
img : atob("GBiBAAAAAB8AADuAAGDAAGTAAGRAAEBAAGBAAGDAADCAADGAIB8B+A/BjAfjBgAyJgAyIgAyAj/jBnADBmABjGAA2HAA8D//4AAAAA==")
|
||||
};
|
||||
},
|
||||
show : function() {
|
||||
uses++;
|
||||
if (uses==1) csc.start();
|
||||
this._visible = true;
|
||||
},
|
||||
hide : function() {
|
||||
this._visible = false;
|
||||
uses--;
|
||||
if (uses==0) csc.stop();
|
||||
}
|
||||
},
|
||||
{ name : "Cadence",
|
||||
get : () => {
|
||||
return {
|
||||
text : (csc.crps === undefined) ? "--" : Math.round(csc.crps*60),
|
||||
img : atob("GBiBAAAAAAAAAAB+EAH/sAeB8A4A8AwB8BgAABgAADAAADAAADAAADAADDAADDAAABgAABgAGAwAEA4AAAeAwAH8gAB8AAAAAAAAAA==")
|
||||
};
|
||||
},
|
||||
show : function() {
|
||||
uses++;
|
||||
if (uses==1) csc.start();
|
||||
this._visible = true;
|
||||
},
|
||||
hide : function() {
|
||||
this._visible = false;
|
||||
uses--;
|
||||
if (uses==0) csc.stop();
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
return ci;
|
||||
})
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"id": "blecsc",
|
||||
"name": "BLE Cycling Speed Sensor Library",
|
||||
"shortName": "BLE CSC",
|
||||
"version": "0.03",
|
||||
"description": "Module to get live values from a BLE Cycle Speed (CSC) sensor. Includes recorder and clockinfo plugins",
|
||||
"icon": "icons8-cycling-48.png",
|
||||
"tags": "outdoors,exercise,ble,bluetooth,clkinfo",
|
||||
"type":"module",
|
||||
"provides_modules" : ["blecsc"],
|
||||
"supports": ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"blecsc","url":"blecsc.js"},
|
||||
{"name":"blecsc.settings.js","url":"settings.js"},
|
||||
{"name":"blecsc.recorder.js","url":"recorder.js"},
|
||||
{"name":"blecsc.clkinfo.js","url":"clkinfo.js"}
|
||||
],
|
||||
"data": [
|
||||
{"name":"blecsc.json"}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
(function(recorders) {
|
||||
recorders.blecsc = function() {
|
||||
var csc = require("blecsc").getInstance();
|
||||
var speed, cadence;
|
||||
csc.on("data", e => {
|
||||
speed = e.kph; // speed in KPH
|
||||
cadence = (e.crps===undefined)?"":Math.round(e.crps*60); // crank rotations per minute
|
||||
});
|
||||
return {
|
||||
name : "CSC",
|
||||
fields : ["Speed (kph)","Cadence (rpm)"],
|
||||
getValues : () => {
|
||||
var r = [speed,cadence];
|
||||
speed = "";
|
||||
cadence = "";
|
||||
return r;
|
||||
},
|
||||
start : () => {
|
||||
csc.start();
|
||||
},
|
||||
stop : () => {
|
||||
csc.stop();
|
||||
},
|
||||
draw : (x,y) => g.setColor(csc.device?"#0f0":"#8f8").drawImage(atob("Dw+BAAAAAAABgOIA5gHcBxw9fpfTPqYRC8HgAAAAAAAA"),x,y)
|
||||
};
|
||||
}
|
||||
})
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
(function(back) {
|
||||
const storage = require('Storage')
|
||||
const SETTINGS_FILE = 'blecsc.json'
|
||||
|
||||
// Set default values and merge with stored values
|
||||
let settings = Object.assign({
|
||||
circum: 2068 // circumference in mm
|
||||
}, (storage.readJSON(SETTINGS_FILE, true) || {}));
|
||||
|
||||
function saveSettings() {
|
||||
storage.writeJSON(SETTINGS_FILE, settings);
|
||||
}
|
||||
|
||||
function circumMenu() {
|
||||
var v = 0|settings.circum;
|
||||
var cm = 0|(v/10);
|
||||
var mm = v-(cm*10);
|
||||
E.showMenu({
|
||||
'': { title: /*LANG*/"Circumference", back: mainMenu },
|
||||
'cm': {
|
||||
value: cm,
|
||||
min: 80, max: 240, step: 1,
|
||||
onchange: (v) => {
|
||||
cm = v;
|
||||
settings.circum = (cm*10)+mm;
|
||||
saveSettings();
|
||||
},
|
||||
},
|
||||
'+ mm': {
|
||||
value: mm,
|
||||
min: 0, max: 9, step: 1,
|
||||
onchange: (v) => {
|
||||
mm = v;
|
||||
settings.circum = (cm*10)+mm;
|
||||
saveSettings();
|
||||
},
|
||||
},
|
||||
/*LANG*/'Std Wheels': function() {
|
||||
// https://support.wahoofitness.com/hc/en-us/articles/115000738484-Tire-Size-Wheel-Circumference-Chart
|
||||
E.showMenu({
|
||||
'': { title: /*LANG*/'Std Wheels', back: circumMenu },
|
||||
'650x38 wheel' : function() {
|
||||
settings.circum = 1995;
|
||||
saveSettings();
|
||||
mainMenu();
|
||||
},
|
||||
'700x32c wheel' : function() {
|
||||
settings.circum = 2152;
|
||||
saveSettings();
|
||||
mainMenu();
|
||||
},
|
||||
'24"x1.75 wheel' : function() {
|
||||
settings.circum = 1890;
|
||||
saveSettings();
|
||||
mainMenu();
|
||||
},
|
||||
'26"x1.5 wheel' : function() {
|
||||
settings.circum = 2010;
|
||||
saveSettings();
|
||||
mainMenu();
|
||||
},
|
||||
'27.5"x1.5 wheel' : function() {
|
||||
settings.circum = 2079;
|
||||
saveSettings();
|
||||
mainMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function mainMenu() {
|
||||
E.showMenu({
|
||||
'': { 'title': 'BLE CSC' },
|
||||
'< Back': back,
|
||||
/*LANG*/'Circumference': {
|
||||
value: settings.circum+"mm",
|
||||
onchange: circumMenu
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
mainMenu();
|
||||
})
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
// @ts-ignore helper
|
||||
// @ts-expect-error helper
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const __assign = Object.assign;
|
||||
|
||||
const Layout = require("Layout");
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
};
|
||||
|
||||
var info = {
|
||||
name: "Gps",
|
||||
name: "GPS",
|
||||
items: [
|
||||
{
|
||||
name: "gridref",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0.01: New Clock Info!
|
|
@ -0,0 +1,27 @@
|
|||
(function() {
|
||||
var speed;
|
||||
function gpsHandler(e) {
|
||||
speed = e.speed;
|
||||
ci.items[0].emit('redraw');
|
||||
}
|
||||
var ci = {
|
||||
name: "GPS",
|
||||
items: [
|
||||
{ name : "Speed",
|
||||
get : function() { return { text : isFinite(speed) ? require("locale").speed(speed) : "--",
|
||||
v : 0, min : isFinite(speed) ? speed : 0, max : 150,
|
||||
img : atob("GBiBAAAAAAAAAAAAAAAAAAD/AAHDgAMYwAbDYAwAMAoA0BgDmBgfGB4ceBgYGBgAGBoAWAwAMAwAMAf/4AP/wAAAAAAAAAAAAAAAAA==") }},
|
||||
show : function() {
|
||||
Bangle.setGPSPower(1, "clkinfogpsspeed");
|
||||
Bangle.on("GPS", gpsHandler);
|
||||
},
|
||||
hide : function() {
|
||||
Bangle.removeListener("GPS", gpsHandler);
|
||||
Bangle.setGPSPower(0, "clkinfogpsspeed");
|
||||
}
|
||||
// run : function() {} optional (called when tapped)
|
||||
}
|
||||
]
|
||||
};
|
||||
return ci;
|
||||
}) // must not have a semi-colon!
|
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,13 @@
|
|||
{ "id": "clkinfogpsspeed",
|
||||
"name": "GPS Speed Clockinfo",
|
||||
"shortName":"GPS Speed",
|
||||
"version":"0.01",
|
||||
"description": "A Clockinfo that displays your current speed according to the GPS",
|
||||
"icon": "icon.png",
|
||||
"type": "clkinfo",
|
||||
"tags": "clkinfo",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"clkinfogpsspeed.clkinfo.js","url":"clkinfo.js"}
|
||||
]
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
0.01: 1st ver,RGB565 and RGB888 colors in a common UI/UX
|
||||
0.02: Minor code improvements
|
||||
0.03: Minor code improvements
|
||||
|
|
|
@ -35,22 +35,22 @@ var v_model=process.env.BOARD;
|
|||
var v_color_text='#FB0E01';
|
||||
var v_color_statictxt='#e56e06'; //orange RGB format rrggbb
|
||||
//RGB565 requires only 16 (5+6+5) bits/2 bytes
|
||||
var a_colors_str= Array('White RGB565 0x','Orange','DarkGreen','Yellow',
|
||||
var a_colors_str= ['White RGB565 0x','Orange','DarkGreen','Yellow',
|
||||
'Maroon','Blue','green','Purple',
|
||||
'cyan','olive','DarkCyan','DarkGrey',
|
||||
'Navy','Red','Magenta','GreenYellow',
|
||||
'Blush RGB888','pure red','Orange','Grey green',
|
||||
'D. grey','Almond','Amber','Bone',
|
||||
'Canary','Aero blue','Camel','Baby pink',
|
||||
'Y.Corn','Cultured','Eigengrau','Citrine');
|
||||
var a_colors= Array(0xFFFF,0xFD20,0x03E0,0xFFE0,
|
||||
'Y.Corn','Cultured','Eigengrau','Citrine'];
|
||||
var a_colors= [0xFFFF,0xFD20,0x03E0,0xFFE0,
|
||||
0x7800,0x001F,0x07E0,0x780F,
|
||||
0x07FF,0x7BE0,0x03EF,0x7BEF,
|
||||
0x000F,0xF800,0xF81F,0xAFE5,
|
||||
'#DE5D83','#FB0E01','#E56E06','#7E795C',
|
||||
'#404040','#EFDECD','#FFBF00','#E3DAC9',
|
||||
'#FFFF99','#C0E8D5','#C19A6B','#F4C2C2',
|
||||
'#FBEC5D','#F5F5F5','#16161D','#E4D00A');
|
||||
'#FBEC5D','#F5F5F5','#16161D','#E4D00A'];
|
||||
var v_color_lines=0xFFFF; //White hex format
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "color_catalog",
|
||||
"name": "Colors Catalog",
|
||||
"shortName": "Colors Catalog",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "Displays RGB565 and RGB888 colors, its name and code in screen.",
|
||||
"icon": "app.png",
|
||||
"tags": "Color,input,buttons,touch,UI",
|
||||
|
|
|
@ -8,3 +8,5 @@
|
|||
0.07: Make Bangle.js 2 compatible
|
||||
0.08: Convert Yes/No On/Off in settings to checkboxes
|
||||
0.09: Automatically reconnect on error
|
||||
0.10: Fix cscsensor when using coospoo sensor that supports crank *and* wheel
|
||||
0.11: Update to use blecsc library
|
|
@ -1,8 +1,3 @@
|
|||
var device;
|
||||
var gatt;
|
||||
var service;
|
||||
var characteristic;
|
||||
|
||||
const SETTINGS_FILE = 'cscsensor.json';
|
||||
const storage = require('Storage');
|
||||
const W = g.getWidth();
|
||||
|
@ -17,12 +12,10 @@ class CSCSensor {
|
|||
constructor() {
|
||||
this.movingTime = 0;
|
||||
this.lastTime = 0;
|
||||
this.lastBangleTime = Date.now();
|
||||
this.lastRevs = -1;
|
||||
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;
|
||||
|
@ -34,8 +27,6 @@ class CSCSensor {
|
|||
this.distFactor = this.qMetric ? 1.609344 : 1;
|
||||
this.screenInit = true;
|
||||
this.batteryLevel = -1;
|
||||
this.lastCrankTime = 0;
|
||||
this.lastCrankRevs = 0;
|
||||
this.showCadence = false;
|
||||
this.cadence = 0;
|
||||
}
|
||||
|
@ -63,10 +54,6 @@ class CSCSensor {
|
|||
}
|
||||
}
|
||||
|
||||
updateBatteryLevel(event) {
|
||||
if (event.target.uuid == "0x2a19") this.setBatteryLevel(event.target.value.getUint8(0));
|
||||
}
|
||||
|
||||
drawBatteryIcon() {
|
||||
g.setColor(1, 1, 1).drawRect(10*W/240, yStart+0.029167*H, 20*W/240, yStart+0.1125*H)
|
||||
.fillRect(14*W/240, yStart+0.020833*H, 16*W/240, yStart+0.029167*H)
|
||||
|
@ -81,7 +68,7 @@ class CSCSensor {
|
|||
}
|
||||
|
||||
updateScreenRevs() {
|
||||
var dist = this.distFactor*(this.lastRevs-this.lastRevsStart)*this.wheelCirc/63360.0;
|
||||
var dist = this.distFactor*(this.lastRevs-this.lastRevsStart)*csc.settings.circum/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;
|
||||
|
@ -157,114 +144,38 @@ class CSCSensor {
|
|||
}
|
||||
}
|
||||
|
||||
updateSensor(event) {
|
||||
var qChanged = false;
|
||||
if (event.target.uuid == "0x2a5b") {
|
||||
if (event.target.value.getUint8(0, true) & 0x2) {
|
||||
// crank revolution - if enabled
|
||||
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)*(60*1024);
|
||||
qChanged = true;
|
||||
}
|
||||
this.lastCrankRevs = crankRevs;
|
||||
this.lastCrankTime = crankTime;
|
||||
} else {
|
||||
// wheel revolution
|
||||
var wheelRevs = event.target.value.getUint32(1, true);
|
||||
var dRevs = (this.lastRevs>0 ? wheelRevs-this.lastRevs : 0);
|
||||
if (dRevs>0) {
|
||||
qChanged = true;
|
||||
this.totaldist += dRevs*this.wheelCirc/63360.0;
|
||||
if ((this.totaldist-this.settings.totaldist)>0.1) {
|
||||
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);
|
||||
var dT = (wheelTime-this.lastTime)/1024;
|
||||
var dBT = (Date.now()-this.lastBangleTime)/1000;
|
||||
this.lastBangleTime = Date.now();
|
||||
if (dT<0) dT+=64;
|
||||
if (Math.abs(dT-dBT)>3) 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 += dT;
|
||||
} else if (!this.showCadence) {
|
||||
this.speedFailed++;
|
||||
qChanged = false;
|
||||
if (this.speedFailed>3) {
|
||||
this.speed = 0;
|
||||
qChanged = (this.lastSpeed>0);
|
||||
}
|
||||
}
|
||||
this.lastSpeed = this.speed;
|
||||
if (this.speed>this.maxSpeed && (this.movingTime>3 || this.speed<20) && this.speed<50) this.maxSpeed = this.speed;
|
||||
}
|
||||
}
|
||||
if (qChanged) this.updateScreen();
|
||||
}
|
||||
}
|
||||
|
||||
var mySensor = new CSCSensor();
|
||||
|
||||
function getSensorBatteryLevel(gatt) {
|
||||
gatt.getPrimaryService("180f").then(function(s) {
|
||||
return s.getCharacteristic("2a19");
|
||||
}).then(function(c) {
|
||||
c.on('characteristicvaluechanged', (event)=>mySensor.updateBatteryLevel(event));
|
||||
return c.startNotifications();
|
||||
});
|
||||
}
|
||||
var csc = require("blecsc").getInstance();
|
||||
csc.on("data", e => {
|
||||
mySensor.totaldist += e.wr * csc.settings.circum/*mm*/ / 1000000; // finally in km
|
||||
mySensor.lastRevs = e.cwr;
|
||||
if (mySensor.lastRevsStart<0) mySensor.lastRevsStart = e.cwr;
|
||||
mySensor.speed = e.kph;
|
||||
mySensor.movingTime += e.wdt;
|
||||
if (mySensor.speed>mySensor.maxSpeed && (mySensor.movingTime>3 || mySensor.speed<20) && mySensor.speed<50)
|
||||
mySensor.maxSpeed = mySensor.speed;
|
||||
mySensor.cadence = e.crps;
|
||||
mySensor.updateScreen();
|
||||
mySensor.updateScreen();
|
||||
});
|
||||
|
||||
function connection_setup() {
|
||||
mySensor.screenInit = true;
|
||||
E.showMessage("Scanning for CSC sensor...");
|
||||
NRF.requestDevice({ filters: [{services:["1816"]}], maxInterval: 100}).then(function(d) {
|
||||
device = d;
|
||||
E.showMessage("Found device");
|
||||
return device.gatt.connect();
|
||||
}).then(function(ga) {
|
||||
gatt = ga;
|
||||
E.showMessage("Connected");
|
||||
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.reset().clearRect(Bangle.appRect).flip();
|
||||
getSensorBatteryLevel(gatt);
|
||||
mySensor.updateScreen();
|
||||
}).catch(function(e) {
|
||||
E.showMessage(e.toString(), "ERROR");
|
||||
console.log(e);
|
||||
setTimeout(connection_setup, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
connection_setup();
|
||||
csc.on("status", txt => {
|
||||
//print("->", txt);
|
||||
E.showMessage(txt);
|
||||
});
|
||||
E.on('kill',()=>{
|
||||
if (gatt!=undefined) gatt.disconnect();
|
||||
csc.stop();
|
||||
mySensor.settings.totaldist = mySensor.totaldist;
|
||||
storage.writeJSON(SETTINGS_FILE, mySensor.settings);
|
||||
});
|
||||
NRF.on('disconnect', connection_setup); // restart if disconnected
|
||||
Bangle.setUI("updown", d=>{
|
||||
if (d<0) { mySensor.reset(); g.clearRect(0, yStart, W, H); mySensor.updateScreen(); }
|
||||
else if (d>0) { if (Date.now()-mySensor.lastBangleTime>10000) connection_setup(); }
|
||||
else { mySensor.toggleDisplayCadence(); g.clearRect(0, yStart, W, H); mySensor.updateScreen(); }
|
||||
else if (!d) { mySensor.toggleDisplayCadence(); g.clearRect(0, yStart, W, H); mySensor.updateScreen(); }
|
||||
});
|
||||
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
csc.start(); // start a connection
|
|
@ -2,10 +2,11 @@
|
|||
"id": "cscsensor",
|
||||
"name": "Cycling speed sensor",
|
||||
"shortName": "CSCSensor",
|
||||
"version": "0.09",
|
||||
"version": "0.11",
|
||||
"description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch",
|
||||
"icon": "icons8-cycling-48.png",
|
||||
"tags": "outdoors,exercise,ble,bluetooth,bike,cycle,bicycle",
|
||||
"dependencies" : { "blecsc":"module" },
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
0.01: New app - forked from widhid
|
||||
0.02: Minor code improvements
|
||||
|
|
|
@ -127,7 +127,7 @@
|
|||
text: "DnD",
|
||||
cb: function (tap) {
|
||||
var on;
|
||||
if (on = !!origBuzz) {
|
||||
if ((on = !!origBuzz)) {
|
||||
if (tap) {
|
||||
Bangle.buzz = origBuzz;
|
||||
origBuzz = undefined;
|
||||
|
|
|
@ -194,7 +194,7 @@
|
|||
text: "DnD",
|
||||
cb: tap => {
|
||||
let on;
|
||||
if(on = !!origBuzz){
|
||||
if((on = !!origBuzz)){
|
||||
if(tap){
|
||||
Bangle.buzz = origBuzz;
|
||||
origBuzz = undefined;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "ctrlpad",
|
||||
"name": "Control Panel",
|
||||
"shortName": "ctrlpad",
|
||||
"version": "0.01",
|
||||
"version": "0.02",
|
||||
"description": "Fast access (via a downward swipe) to common functions, such as bluetooth/HRM power and Do Not Disturb",
|
||||
"icon": "icon.png",
|
||||
"readme": "README.md",
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
0.01: Initial version
|
||||
0.02: Minor code improvements
|
||||
0.03: Move blecsc library into its own app so it can be shared (and fix some issues)
|
|
@ -1,4 +1,5 @@
|
|||
# Cycling
|
||||
|
||||
> Displays data from a BLE Cycling Speed and Cadence sensor.
|
||||
|
||||
*This is a fork of the CSCSensor app using the layout library and separate module for CSC functionality. It also drops persistence of total distance on the Bangle, as this information is also persisted on the sensor itself. Further, it allows configuration of display units (metric/imperial) independent of chosen locale. Finally, multiple sensors can be used and wheel circumference can be configured for each sensor individually.*
|
||||
|
@ -27,8 +28,5 @@ Inside the Cycling app, use button / tap screen to:
|
|||
## TODO
|
||||
* Sensor battery status
|
||||
* Implement crank events / show cadence
|
||||
* Bangle.js 1 compatibility
|
||||
* Allow setting CWR on the sensor (this is a feature intended by the BLE CSC spec, in case the sensor is replaced or transferred to a different bike)
|
||||
|
||||
## Development
|
||||
There is a "mock" version of the `blecsc` module, which can be used to test features in the emulator. Check `blecsc-emu.js` for usage.
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
// UUID of the Bluetooth CSC Service
|
||||
//const SERVICE_UUID = "1816";
|
||||
// UUID of the CSC measurement characteristic
|
||||
const MEASUREMENT_UUID = "2a5b";
|
||||
|
||||
// Wheel revolution present bit mask
|
||||
const FLAGS_WREV_BM = 0x01;
|
||||
// Crank revolution present bit mask
|
||||
const FLAGS_CREV_BM = 0x02;
|
||||
|
||||
/**
|
||||
* Fake BLECSC implementation for the emulator, where it's hard to test
|
||||
* with actual hardware. Generates "random" wheel events (no crank).
|
||||
*
|
||||
* To upload as a module, paste the entire file in the console using this
|
||||
* command: require("Storage").write("blecsc-emu",`<FILE CONTENT HERE>`);
|
||||
*/
|
||||
class BLECSCEmulator {
|
||||
constructor() {
|
||||
this.timeout = undefined;
|
||||
this.interval = 500;
|
||||
this.ccr = 0;
|
||||
this.lwt = 0;
|
||||
this.handlers = {
|
||||
// value
|
||||
// disconnect
|
||||
// wheelEvent
|
||||
// crankEvent
|
||||
};
|
||||
}
|
||||
|
||||
getDeviceAddress() {
|
||||
return 'fa:ke:00:de:vi:ce';
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the GATT characteristicvaluechanged event.
|
||||
* Consumers must not call this method!
|
||||
*/
|
||||
onValue(event) {
|
||||
// Not interested in non-CSC characteristics
|
||||
if (event.target.uuid != "0x" + MEASUREMENT_UUID) return;
|
||||
|
||||
// Notify the generic 'value' handler
|
||||
if (this.handlers.value) this.handlers.value(event);
|
||||
|
||||
const flags = event.target.value.getUint8(0, true);
|
||||
// Notify the 'wheelEvent' handler
|
||||
if ((flags & FLAGS_WREV_BM) && this.handlers.wheelEvent) this.handlers.wheelEvent({
|
||||
cwr: event.target.value.getUint32(1, true), // cumulative wheel revolutions
|
||||
lwet: event.target.value.getUint16(5, true), // last wheel event time
|
||||
});
|
||||
|
||||
// Notify the 'crankEvent' handler
|
||||
if ((flags & FLAGS_CREV_BM) && this.handlers.crankEvent) this.handlers.crankEvent({
|
||||
ccr: event.target.value.getUint16(7, true), // cumulative crank revolutions
|
||||
lcet: event.target.value.getUint16(9, true), // last crank event time
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an event handler.
|
||||
*
|
||||
* @param {string} event value|disconnect
|
||||
* @param {function} handler handler function that receives the event as its first argument
|
||||
*/
|
||||
on(event, handler) {
|
||||
this.handlers[event] = handler;
|
||||
}
|
||||
|
||||
fakeEvent() {
|
||||
this.interval = Math.max(50, Math.min(1000, this.interval + Math.random()*40-20));
|
||||
this.lwt = (this.lwt + this.interval) % 0x10000;
|
||||
this.ccr++;
|
||||
|
||||
var buffer = new ArrayBuffer(8);
|
||||
var view = new DataView(buffer);
|
||||
view.setUint8(0, 0x01); // Wheel revolution data present bit
|
||||
view.setUint32(1, this.ccr, true); // Cumulative crank revolutions
|
||||
view.setUint16(5, this.lwt, true); // Last wheel event time
|
||||
|
||||
this.onValue({
|
||||
target: {
|
||||
uuid: "0x2a5b",
|
||||
value: view,
|
||||
},
|
||||
});
|
||||
|
||||
this.timeout = setTimeout(this.fakeEvent.bind(this), this.interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and connect to a device which exposes the CSC service.
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
connect() {
|
||||
this.timeout = setTimeout(this.fakeEvent.bind(this), this.interval);
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect the device.
|
||||
*/
|
||||
disconnect() {
|
||||
if (!this.timeout) return;
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
}
|
||||
|
||||
exports = BLECSCEmulator;
|
|
@ -1,150 +0,0 @@
|
|||
const SERVICE_UUID = "1816";
|
||||
// UUID of the CSC measurement characteristic
|
||||
const MEASUREMENT_UUID = "2a5b";
|
||||
|
||||
// Wheel revolution present bit mask
|
||||
const FLAGS_WREV_BM = 0x01;
|
||||
// Crank revolution present bit mask
|
||||
const FLAGS_CREV_BM = 0x02;
|
||||
|
||||
/**
|
||||
* This class communicates with a Bluetooth CSC peripherial using the Espruino NRF library.
|
||||
*
|
||||
* ## Usage:
|
||||
* 1. Register event handlers using the \`on(eventName, handlerFunction)\` method
|
||||
* You can subscribe to the \`wheelEvent\` and \`crankEvent\` events or you can
|
||||
* have raw characteristic values passed through using the \`value\` event.
|
||||
* 2. Search and connect to a BLE CSC peripherial by calling the \`connect()\` method
|
||||
* 3. To tear down the connection, call the \`disconnect()\` method
|
||||
*
|
||||
* ## Events
|
||||
* - \`wheelEvent\` - the peripharial sends a notification containing wheel event data
|
||||
* - \`crankEvent\` - the peripharial sends a notification containing crank event data
|
||||
* - \`value\` - the peripharial sends any CSC characteristic notification (including wheel & crank event)
|
||||
* - \`disconnect\` - the peripherial ends the connection or the connection is lost
|
||||
*
|
||||
* Each event can only have one handler. Any call to \`on()\` will
|
||||
* replace a previously registered handler for the same event.
|
||||
*/
|
||||
class BLECSC {
|
||||
constructor() {
|
||||
this.device = undefined;
|
||||
this.ccInterval = undefined;
|
||||
this.gatt = undefined;
|
||||
this.handlers = {
|
||||
// wheelEvent
|
||||
// crankEvent
|
||||
// value
|
||||
// disconnect
|
||||
};
|
||||
}
|
||||
|
||||
getDeviceAddress() {
|
||||
if (!this.device || !this.device.id)
|
||||
return '00:00:00:00:00:00';
|
||||
return this.device.id.split(" ")[0];
|
||||
}
|
||||
|
||||
checkConnection() {
|
||||
if (!this.device)
|
||||
console.log("no device");
|
||||
// else
|
||||
// console.log("rssi: " + this.device.rssi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the GATT characteristicvaluechanged event.
|
||||
* Consumers must not call this method!
|
||||
*/
|
||||
onValue(event) {
|
||||
// Not interested in non-CSC characteristics
|
||||
if (event.target.uuid != "0x" + MEASUREMENT_UUID) return;
|
||||
|
||||
// Notify the generic 'value' handler
|
||||
if (this.handlers.value) this.handlers.value(event);
|
||||
|
||||
const flags = event.target.value.getUint8(0, true);
|
||||
// Notify the 'wheelEvent' handler
|
||||
if ((flags & FLAGS_WREV_BM) && this.handlers.wheelEvent) this.handlers.wheelEvent({
|
||||
cwr: event.target.value.getUint32(1, true), // cumulative wheel revolutions
|
||||
lwet: event.target.value.getUint16(5, true), // last wheel event time
|
||||
});
|
||||
|
||||
// Notify the 'crankEvent' handler
|
||||
if ((flags & FLAGS_CREV_BM) && this.handlers.crankEvent) this.handlers.crankEvent({
|
||||
ccr: event.target.value.getUint16(7, true), // cumulative crank revolutions
|
||||
lcet: event.target.value.getUint16(9, true), // last crank event time
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the NRF disconnect event.
|
||||
* Consumers must not call this method!
|
||||
*/
|
||||
onDisconnect(event) {
|
||||
console.log("disconnected");
|
||||
if (this.ccInterval)
|
||||
clearInterval(this.ccInterval);
|
||||
|
||||
if (!this.handlers.disconnect) return;
|
||||
this.handlers.disconnect(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an event handler.
|
||||
*
|
||||
* @param {string} event wheelEvent|crankEvent|value|disconnect
|
||||
* @param {function} handler function that will receive the event as its first argument
|
||||
*/
|
||||
on(event, handler) {
|
||||
this.handlers[event] = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and connect to a device which exposes the CSC service.
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
connect() {
|
||||
// Register handler for the disconnect event to be passed throug
|
||||
NRF.on('disconnect', this.onDisconnect.bind(this));
|
||||
|
||||
// Find a device, then get the CSC Service and subscribe to
|
||||
// notifications on the CSC Measurement characteristic.
|
||||
// NRF.setLowPowerConnection(true);
|
||||
return NRF.requestDevice({
|
||||
timeout: 5000,
|
||||
filters: [{ services: [SERVICE_UUID] }],
|
||||
}).then(device => {
|
||||
this.device = device;
|
||||
this.device.on('gattserverdisconnected', this.onDisconnect.bind(this));
|
||||
this.ccInterval = setInterval(this.checkConnection.bind(this), 2000);
|
||||
return device.gatt.connect();
|
||||
}).then(gatt => {
|
||||
this.gatt = gatt;
|
||||
return gatt.getPrimaryService(SERVICE_UUID);
|
||||
}).then(service => {
|
||||
return service.getCharacteristic(MEASUREMENT_UUID);
|
||||
}).then(characteristic => {
|
||||
characteristic.on('characteristicvaluechanged', this.onValue.bind(this));
|
||||
return characteristic.startNotifications();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect the device.
|
||||
*/
|
||||
disconnect() {
|
||||
if (this.ccInterval)
|
||||
clearInterval(this.ccInterval);
|
||||
|
||||
if (!this.gatt) return;
|
||||
try {
|
||||
this.gatt.disconnect();
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports = BLECSC;
|
|
@ -23,7 +23,6 @@ class CSCSensor {
|
|||
// CSC runtime variables
|
||||
this.movingTime = 0; // unit: s
|
||||
this.lastBangleTime = Date.now(); // unit: ms
|
||||
this.lwet = 0; // last wheel event time (unit: s/1024)
|
||||
this.cwr = -1; // cumulative wheel revolutions
|
||||
this.cwrTrip = 0; // wheel revolutions since trip start
|
||||
this.speed = 0; // unit: m/s
|
||||
|
@ -84,7 +83,7 @@ class CSCSensor {
|
|||
console.log("Trying to connect to BLE CSC");
|
||||
|
||||
// Hook up events
|
||||
this.blecsc.on('wheelEvent', this.onWheelEvent.bind(this));
|
||||
this.blecsc.on('data', this.onWheelEvent.bind(this));
|
||||
this.blecsc.on('disconnect', this.onDisconnect.bind(this));
|
||||
|
||||
// Scan for BLE device and connect
|
||||
|
@ -171,20 +170,11 @@ class CSCSensor {
|
|||
// Increment the trip revolutions counter
|
||||
this.cwrTrip += dRevs;
|
||||
|
||||
// Calculate time delta since last wheel event
|
||||
var dT = (event.lwet - this.lwet)/1024;
|
||||
var now = Date.now();
|
||||
var dBT = (now-this.lastBangleTime)/1000;
|
||||
this.lastBangleTime = now;
|
||||
if (dT<0) dT+=64; // wheel event time wraps every 64s
|
||||
if (Math.abs(dT-dBT)>3) dT = dBT; // not sure about the reason for this
|
||||
this.lwet = event.lwet;
|
||||
|
||||
// Recalculate current speed
|
||||
if (dRevs>0 && dT>0) {
|
||||
this.speed = dRevs * this.wheelCirc / dT;
|
||||
if (dRevs>0 ) {
|
||||
this.speed = event.wrps * this.wheelCirc;
|
||||
this.speedFailed = 0;
|
||||
this.movingTime += dT;
|
||||
this.movingTime += event.wdt;
|
||||
} else {
|
||||
this.speedFailed++;
|
||||
if (this.speedFailed>3) {
|
||||
|
@ -429,15 +419,7 @@ class CSCDisplay {
|
|||
}
|
||||
}
|
||||
|
||||
var BLECSC;
|
||||
if (process.env.BOARD === "EMSCRIPTEN" || process.env.BOARD === "EMSCRIPTEN2") {
|
||||
// Emulator
|
||||
BLECSC = require("blecsc-emu");
|
||||
} else {
|
||||
// Actual hardware
|
||||
BLECSC = require("blecsc");
|
||||
}
|
||||
var blecsc = new BLECSC();
|
||||
var blecsc = require("blecsc").getInstance();
|
||||
var display = new CSCDisplay();
|
||||
var sensor = new CSCSensor(blecsc, display);
|
||||
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
"id": "cycling",
|
||||
"name": "Bangle Cycling",
|
||||
"shortName": "Cycling",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "Display live values from a BLE CSC sensor",
|
||||
"icon": "icons8-cycling-48.png",
|
||||
"tags": "outdoors,exercise,ble,bluetooth",
|
||||
"dependencies" : { "blecsc":"module" },
|
||||
"supports": ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"cycling.app.js","url":"cycling.app.js"},
|
||||
{"name":"cycling.settings.js","url":"settings.js"},
|
||||
{"name":"blecsc","url":"blecsc.js"},
|
||||
{"name":"cycling.img","url":"cycling.icon.js","evaluate": true}
|
||||
],
|
||||
"data": [
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const app = "drained";
|
||||
|
||||
// from boot.js
|
||||
declare var drainedInterval: IntervalId | undefined;
|
||||
declare let drainedInterval: IntervalId | undefined;
|
||||
if(typeof drainedInterval !== "undefined")
|
||||
drainedInterval = clearInterval(drainedInterval) as undefined;
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
0.01: New app!
|
||||
0.02: Handle files potentially not existing
|
||||
0.03: Add setting to disable vibration
|
||||
0.03: Add setting to disable vibration
|
||||
0.04: Minor code improvements
|
||||
|
|
|
@ -78,19 +78,21 @@
|
|||
var text = void 0;
|
||||
var fontSize = void 0;
|
||||
switch (entry.type) {
|
||||
case 'app':
|
||||
case 'app': {
|
||||
var app_1 = storage_1.readJSON(entry.id + '.info', false);
|
||||
icon = storage_1.read(app_1.icon);
|
||||
text = app_1.name;
|
||||
empty = false;
|
||||
fontSize = config_1.display.font;
|
||||
break;
|
||||
case 'folder':
|
||||
}
|
||||
case 'folder': {
|
||||
icon = FOLDER_ICON_1;
|
||||
text = entry.id;
|
||||
empty = false;
|
||||
fontSize = config_1.display.font ? config_1.display.font : 12;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
@ -132,12 +134,13 @@
|
|||
y = config_1.display.rows - 1;
|
||||
var entry = grid_1[x][y];
|
||||
switch (entry.type) {
|
||||
case "app":
|
||||
case "app": {
|
||||
buzz_1();
|
||||
var infoFile = storage_1.readJSON(entry.id + '.info', false);
|
||||
load(infoFile.src);
|
||||
break;
|
||||
case "folder":
|
||||
}
|
||||
case "folder": {
|
||||
buzz_1();
|
||||
resetTimeout_1();
|
||||
page_1 = 0;
|
||||
|
@ -145,9 +148,11 @@
|
|||
folder_1 = getFolder_1(folderPath_1);
|
||||
render_1();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
resetTimeout_1();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
var page_1 = 0;
|
||||
|
|
|
@ -114,19 +114,21 @@
|
|||
|
||||
// Get the icon and text, skip if the space is empty. Always draw text for folders even if disabled
|
||||
switch (entry.type) {
|
||||
case 'app':
|
||||
case 'app': {
|
||||
let app = storage.readJSON(entry.id + '.info', false) as AppInfo;
|
||||
icon = storage.read(app.icon!)!;
|
||||
text = app.name;
|
||||
empty = false;
|
||||
fontSize = config.display.font;
|
||||
break;
|
||||
case 'folder':
|
||||
}
|
||||
case 'folder': {
|
||||
icon = FOLDER_ICON;
|
||||
text = entry.id;
|
||||
empty = false;
|
||||
fontSize = config.display.font ? config.display.font : 12;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
@ -184,12 +186,13 @@
|
|||
// Handle the grid cell
|
||||
let entry: GridEntry = grid[x]![y]!;
|
||||
switch (entry.type) {
|
||||
case "app":
|
||||
case "app": {
|
||||
buzz();
|
||||
let infoFile = storage.readJSON(entry.id + '.info', false) as AppInfo;
|
||||
load(infoFile.src);
|
||||
break;
|
||||
case "folder":
|
||||
}
|
||||
case "folder": {
|
||||
buzz();
|
||||
resetTimeout();
|
||||
page = 0;
|
||||
|
@ -197,9 +200,11 @@
|
|||
folder = getFolder(folderPath);
|
||||
render();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
resetTimeout();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ function cleanAndSave(config: Config): Config {
|
|||
let infoFileSorter = (a: string, b: string): number => {
|
||||
let aJson = storage.readJSON(a, false) as AppInfo;
|
||||
let bJson = storage.readJSON(b, false) as AppInfo;
|
||||
var n = (0 | aJson.sortorder!) - (0 | bJson.sortorder!);
|
||||
const n = (0 | aJson.sortorder!) - (0 | bJson.sortorder!);
|
||||
if (n) return n; // do sortorder first
|
||||
if (aJson.name < bJson.name) return -1;
|
||||
if (aJson.name > bJson.name) return 1;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "folderlaunch",
|
||||
"name": "Folder launcher",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "Launcher that allows you to put your apps into folders",
|
||||
"icon": "icon.png",
|
||||
"type": "launch",
|
||||
|
|
|
@ -11,7 +11,7 @@ type Config = {
|
|||
showClocks: boolean, // Whether clocks are shown
|
||||
showLaunchers: boolean, // Whether launchers are shown
|
||||
disableVibration: boolean, // Whether vibration is disabled
|
||||
hidden: Array<String>, // IDs of apps to explicitly hide
|
||||
hidden: Array<string>, // IDs of apps to explicitly hide
|
||||
display: {
|
||||
rows: number, // Display an X by X grid of apps
|
||||
icon: boolean, // Whether to show icons
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
0.02: Supports bottom widgets and UI based in UI4swatch!
|
||||
0.03: Added compatibility with BJS2, improvements
|
||||
0.04: Minor code improvements
|
||||
0.05: Minor code improvements
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
var v_color_statictxt='#b30000';
|
||||
//var v_color_b_area='#111111';
|
||||
//orange RGB format rrggbb //white,Orange,DarkGreen,Yellow,Maroon,Blue,green,Purple,cyan,olive,DarkCyan,pink
|
||||
var a_colors= Array(0xFFFF,0xFD20,0x03E0,0xFFE0,0x7800,0x001F,0x07E0,0x780F,0x07FF,0x7BE0,0x03EF,0xF81F);
|
||||
var a_colors= [0xFFFF,0xFD20,0x03E0,0xFFE0,0x7800,0x001F,0x07E0,0x780F,0x07FF,0x7BE0,0x03EF,0xF81F];
|
||||
|
||||
var x_max_screen=g.getWidth();
|
||||
//var y_max_screen=g.getHeight();
|
||||
|
@ -47,8 +47,8 @@ if (v_model=='BANGLEJS'||v_model=='EMSCRIPTEN') {
|
|||
var v_arraypos=0;
|
||||
var v_acolorpos=0; //for fg
|
||||
var v_aBGcolorPos=5; //for bg
|
||||
var a_string1 = Array('hola', 'hello', 'saluton', 'ola','ciao', 'salut','czesc','konnichiwa');
|
||||
var a_string2 = Array('mundo!', 'world!', 'mondo!','mundo!','mondo!','monde!','swiat!','sekai!');
|
||||
var a_string1 = ['hola', 'hello', 'saluton', 'ola','ciao', 'salut','czesc','konnichiwa'];
|
||||
var a_string2 = ['mundo!', 'world!', 'mondo!','mundo!','mondo!','monde!','swiat!','sekai!'];
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "helloworld",
|
||||
"name": "hello, world!",
|
||||
"shortName": "hello world",
|
||||
"version": "0.04",
|
||||
"version": "0.05",
|
||||
"description": "A cross cultural hello world!/hola mundo! app with colors and languages",
|
||||
"icon": "app.png",
|
||||
"tags": "input,interface,buttons,touch",
|
||||
|
|
|
@ -216,12 +216,6 @@ module.exports = {
|
|||
"no-unused-vars"
|
||||
]
|
||||
},
|
||||
"promenu/bootb2.js": {
|
||||
"hash": "4f7a0cb285c35a61e22325dafdd548845393df8d952d8934b04576efb4b19561",
|
||||
"rules": [
|
||||
"no-unused-vars"
|
||||
]
|
||||
},
|
||||
"poweroff/settings.js": {
|
||||
"hash": "c197afe72c612a4b3825a3a12a628d0f4ed83823da3f28885bbf473037a02506",
|
||||
"rules": [
|
||||
|
@ -1071,12 +1065,6 @@ module.exports = {
|
|||
"no-undef"
|
||||
]
|
||||
},
|
||||
"fuzzyw/fuzzyw.app.js": {
|
||||
"hash": "dbef30fe5639a240ada0968491c73242092bd2db7f3b060ef9c2f66a6cbbb19d",
|
||||
"rules": [
|
||||
"no-undef"
|
||||
]
|
||||
},
|
||||
"fontclock/fontclock.js": {
|
||||
"hash": "478c96b1319d548a79727c5af3191b77ac9753c6314789570e900e512a99a152",
|
||||
"rules": [
|
||||
|
@ -1125,12 +1113,6 @@ module.exports = {
|
|||
"no-undef"
|
||||
]
|
||||
},
|
||||
"drained/boot.js": {
|
||||
"hash": "914ea2c47aa6b9502b9dd354d490b2a8b838d4c6fafaa20e206f1f2396d4db40",
|
||||
"rules": [
|
||||
"no-undef"
|
||||
]
|
||||
},
|
||||
"dinoClock/app.js": {
|
||||
"hash": "e97566aa4f586ef654e3fc1ec286376352762ed8e0ea2e685a7b3ae687f51552",
|
||||
"rules": [
|
||||
|
|
|
@ -10,3 +10,4 @@
|
|||
0.09: Minor code improvements
|
||||
0.10: Handle missing alarm data, e.g. when our reset is fired from
|
||||
non-multitimer alarms
|
||||
0.11: Preserve setUI removal callbacks, e.g. those of showMenu
|
||||
|
|
|
@ -691,10 +691,12 @@ function setUI() {
|
|||
// E.showMenu/E.showScroller/E.showAlert call setUI, so we register onDrag() separately
|
||||
// and tack on uiRemove after the fact to avoid interfering
|
||||
Bangle.on("drag", onDrag);
|
||||
const origRemove = Bangle.uiRemove;
|
||||
Bangle.uiRemove = () => {
|
||||
Bangle.removeListener("drag", onDrag);
|
||||
Object.values(timerInt1).forEach(clearTimeout);
|
||||
Object.values(timerInt2).forEach(clearTimeout);
|
||||
if (origRemove) origRemove();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "multitimer",
|
||||
"name": "Multi Timer",
|
||||
"version": "0.10",
|
||||
"version": "0.11",
|
||||
"description": "Set timers and chronographs (stopwatches) and watch them count down in real time. Pause, create, edit, and delete timers and chronos, and add custom labels/messages. Also sets alarms.",
|
||||
"icon": "app.png",
|
||||
"screenshots": [
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
0.01: First release.
|
||||
0.02: No functional changes, just moved codebase to Typescript.
|
||||
0.03: Also buzz on disconnect from charging
|
||||
0.04: Minor code improvements
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "Charging Status",
|
||||
"shortName":"ChargingStatus",
|
||||
"icon": "widget.png",
|
||||
"version":"0.03",
|
||||
"version": "0.04",
|
||||
"type": "widget",
|
||||
"description": "A simple widget that shows a yellow lightning icon to indicate whenever the watch is charging. This way one can see the charging status at a glance, no matter which battery widget is being used.",
|
||||
"tags": "widget",
|
||||
|
|
|
@ -10,13 +10,13 @@
|
|||
});
|
||||
}
|
||||
}
|
||||
WIDGETS.chargingStatus = {
|
||||
WIDGETS["chargingStatus"] = {
|
||||
area: 'tr',
|
||||
width: Bangle.isCharging() ? iconWidth : 0,
|
||||
draw: draw,
|
||||
};
|
||||
Bangle.on('charging', function (charging) {
|
||||
var widget = WIDGETS.chargingStatus;
|
||||
var widget = WIDGETS["chargingStatus"];
|
||||
if (widget) {
|
||||
if (charging) {
|
||||
Bangle.buzz();
|
||||
|
|
|
@ -16,16 +16,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
WIDGETS.chargingStatus = {
|
||||
WIDGETS["chargingStatus"] = {
|
||||
area: 'tr',
|
||||
width: Bangle.isCharging() ? iconWidth : 0,
|
||||
draw: draw,
|
||||
};
|
||||
|
||||
Bangle.on('charging', (charging) => {
|
||||
// @ts-ignore
|
||||
const widget = WIDGETS.chargingStatus;
|
||||
const widget = WIDGETS["chargingStatus"];
|
||||
if (widget) {
|
||||
if (charging) {
|
||||
Bangle.buzz();
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
console.log("widhid: can't enable, HID setting isn't \"kbmedia\"");
|
||||
return;
|
||||
}
|
||||
// @ts-ignore
|
||||
// @ts-expect-error espruino-specific delete
|
||||
delete settings;
|
||||
|
||||
let anchor = {x:0,y:0};
|
||||
|
@ -128,7 +128,7 @@
|
|||
|
||||
if(connected)
|
||||
Bangle.on("swipe", onSwipe);
|
||||
// @ts-ignore
|
||||
// @ts-expect-error espruino-specific delete
|
||||
delete connected;
|
||||
|
||||
NRF.on("connect", () => {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
* node bin/bulk-update-apps.mjs GITHASH CHANGELOGMESSAGE
|
||||
*
|
||||
* Example command:
|
||||
* node bin/exempt-lint.mjs 29ced17i7 'Minor code improvements'
|
||||
* node bin/bulk-update-apps.mjs 29ced17i7 'Minor code improvements'
|
||||
*
|
||||
* You can also run it in output mode like this:
|
||||
* node bin/bulk-update-apps.mjs GITHASH --output
|
||||
|
|
|
@ -28,7 +28,7 @@ if (!lintRule) {
|
|||
|
||||
const filePathInput = process.argv[3];
|
||||
const filePathMatch = filePathInput?.match(
|
||||
/^(?:.*?\/apps\/|apps\/|\/)?(?<path>.*\.js)$/iu,
|
||||
/^(?:.*?\/apps\/|apps\/|\/)?(?<path>.*\.[jt]s)$/iu,
|
||||
);
|
||||
const filePath = filePathMatch?.groups?.path;
|
||||
if (!filePath) {
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
"acorn": "^7.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^7.8.0",
|
||||
"@typescript-eslint/parser": "^7.8.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
|
@ -152,12 +154,283 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/json5": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
|
||||
"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz",
|
||||
"integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "7.8.0",
|
||||
"@typescript-eslint/type-utils": "7.8.0",
|
||||
"@typescript-eslint/utils": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0",
|
||||
"debug": "^4.3.4",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^7.0.0",
|
||||
"eslint": "^8.56.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz",
|
||||
"integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "7.8.0",
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/typescript-estree": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.56.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz",
|
||||
"integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz",
|
||||
"integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "7.8.0",
|
||||
"@typescript-eslint/utils": "7.8.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.56.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz",
|
||||
"integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz",
|
||||
"integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "^9.0.4",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
|
||||
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz",
|
||||
"integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@typescript-eslint/scope-manager": "7.8.0",
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/typescript-estree": "7.8.0",
|
||||
"semver": "^7.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.56.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz",
|
||||
"integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"eslint-visitor-keys": "^3.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@ungap/structured-clone": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
|
||||
|
@ -284,6 +557,15 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/array-union": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
||||
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/array.prototype.filter": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz",
|
||||
|
@ -652,6 +934,18 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/dir-glob": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"path-type": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/doctrine": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
|
@ -1081,6 +1375,34 @@
|
|||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
|
||||
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
"@nodelib/fs.walk": "^1.2.3",
|
||||
"glob-parent": "^5.1.2",
|
||||
"merge2": "^1.3.0",
|
||||
"micromatch": "^4.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-glob/node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
|
@ -1344,6 +1666,26 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/globby": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
|
||||
"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"array-union": "^2.1.0",
|
||||
"dir-glob": "^3.0.1",
|
||||
"fast-glob": "^3.2.9",
|
||||
"ignore": "^5.2.0",
|
||||
"merge2": "^1.4.1",
|
||||
"slash": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
||||
|
@ -1924,6 +2266,40 @@
|
|||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
||||
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"braces": "^3.0.2",
|
||||
"picomatch": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
|
@ -2289,6 +2665,15 @@
|
|||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/path-type": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
|
@ -2680,6 +3065,15 @@
|
|||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
|
@ -2830,6 +3224,18 @@
|
|||
"nodetouch": "bin/nodetouch.js"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
|
||||
"integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tsconfig-paths": {
|
||||
"version": "3.15.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
|
||||
|
@ -2939,6 +3345,20 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.4.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
|
||||
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/unbox-primitive": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
|
||||
|
@ -3061,6 +3481,12 @@
|
|||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
|
@ -3168,12 +3594,176 @@
|
|||
"fastq": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"@types/json-schema": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/json5": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/semver": {
|
||||
"version": "7.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
|
||||
"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz",
|
||||
"integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "7.8.0",
|
||||
"@typescript-eslint/type-utils": "7.8.0",
|
||||
"@typescript-eslint/utils": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0",
|
||||
"debug": "^4.3.4",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz",
|
||||
"integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "7.8.0",
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/typescript-estree": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0",
|
||||
"debug": "^4.3.4"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz",
|
||||
"integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/type-utils": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz",
|
||||
"integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/typescript-estree": "7.8.0",
|
||||
"@typescript-eslint/utils": "7.8.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz",
|
||||
"integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz",
|
||||
"integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/visitor-keys": "7.8.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "^9.0.4",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
|
||||
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz",
|
||||
"integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@typescript-eslint/scope-manager": "7.8.0",
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"@typescript-eslint/typescript-estree": "7.8.0",
|
||||
"semver": "^7.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz",
|
||||
"integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "7.8.0",
|
||||
"eslint-visitor-keys": "^3.4.3"
|
||||
}
|
||||
},
|
||||
"@ungap/structured-clone": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
|
||||
|
@ -3264,6 +3854,12 @@
|
|||
"is-string": "^1.0.7"
|
||||
}
|
||||
},
|
||||
"array-union": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
||||
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
|
||||
"dev": true
|
||||
},
|
||||
"array.prototype.filter": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz",
|
||||
|
@ -3533,6 +4129,15 @@
|
|||
"object-keys": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"dir-glob": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-type": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"doctrine": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
|
@ -3871,6 +4476,30 @@
|
|||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true
|
||||
},
|
||||
"fast-glob": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
|
||||
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
"@nodelib/fs.walk": "^1.2.3",
|
||||
"glob-parent": "^5.1.2",
|
||||
"merge2": "^1.3.0",
|
||||
"micromatch": "^4.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
|
@ -4053,6 +4682,20 @@
|
|||
"define-properties": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"globby": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
|
||||
"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-union": "^2.1.0",
|
||||
"dir-glob": "^3.0.1",
|
||||
"fast-glob": "^3.2.9",
|
||||
"ignore": "^5.2.0",
|
||||
"merge2": "^1.4.1",
|
||||
"slash": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"gopd": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
||||
|
@ -4462,6 +5105,31 @@
|
|||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||
"dev": true
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||
"dev": true
|
||||
},
|
||||
"micromatch": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
||||
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"braces": "^3.0.2",
|
||||
"picomatch": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
|
@ -4729,6 +5397,12 @@
|
|||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true
|
||||
},
|
||||
"path-type": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
|
@ -4991,6 +5665,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
|
@ -5102,6 +5782,13 @@
|
|||
"nopt": "~1.0.10"
|
||||
}
|
||||
},
|
||||
"ts-api-utils": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
|
||||
"integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"tsconfig-paths": {
|
||||
"version": "3.15.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
|
||||
|
@ -5181,6 +5868,13 @@
|
|||
"possible-typed-array-names": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "5.4.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
|
||||
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"unbox-primitive": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
|
||||
|
@ -5279,6 +5973,12 @@
|
|||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
},
|
||||
"yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
"license": "MIT",
|
||||
"repository": "https://github.com/espruino/BangleApps",
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^7.8.0",
|
||||
"@typescript-eslint/parser": "^7.8.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
|
@ -13,8 +15,8 @@
|
|||
"npm-watch": "^0.11.0"
|
||||
},
|
||||
"scripts": {
|
||||
"lint-apps": "node bin/sync-lint-exemptions.mjs && eslint ./apps --ext .js",
|
||||
"lint-modules": "eslint ./modules --ext .js",
|
||||
"lint-apps": "node bin/sync-lint-exemptions.mjs && eslint ./apps",
|
||||
"lint-modules": "eslint ./modules",
|
||||
"test": "node bin/sanitycheck.js && npm run lint-apps && npm run lint-modules",
|
||||
"update-local-apps": "./bin/create_apps_json.sh apps.local.json",
|
||||
"local": "npm-watch & npx http-server -a localhost -c-1",
|
||||
|
|
Loading…
Reference in New Issue