From 5630b85918182cb7e5aa7186aba44c26f3a18426 Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 29 Apr 2024 18:20:17 +0200 Subject: [PATCH 01/14] Enforce and fix typescript lints --- .eslintignore | 12 ------------ apps/ctrlpad/main.js | 5 +++-- apps/ctrlpad/main.ts | 5 +++-- apps/drained/app.js | 5 +++-- apps/drained/app.ts | 6 +++--- apps/drained/boot.js | 2 +- apps/drained/boot.ts | 2 +- apps/lint_exemptions.js | 12 ------------ 8 files changed, 14 insertions(+), 35 deletions(-) diff --git a/.eslintignore b/.eslintignore index 933dfaf69..1e3abd9ff 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,15 +4,3 @@ 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/ diff --git a/apps/ctrlpad/main.js b/apps/ctrlpad/main.js index f9614168e..41e62a2d7 100644 --- a/apps/ctrlpad/main.js +++ b/apps/ctrlpad/main.js @@ -126,8 +126,9 @@ { text: "DnD", cb: function (tap) { - var on; - if (on = !!origBuzz) { + var on = false; + if (origBuzz) { + on = true; if (tap) { Bangle.buzz = origBuzz; origBuzz = undefined; diff --git a/apps/ctrlpad/main.ts b/apps/ctrlpad/main.ts index 7f758a3b0..7d99b88f6 100644 --- a/apps/ctrlpad/main.ts +++ b/apps/ctrlpad/main.ts @@ -193,8 +193,9 @@ { text: "DnD", cb: tap => { - let on; - if(on = !!origBuzz){ + let on = false; + if(origBuzz){ + on = true; if(tap){ Bangle.buzz = origBuzz; origBuzz = undefined; diff --git a/apps/drained/app.js b/apps/drained/app.js index c74affea3..11f14713a 100644 --- a/apps/drained/app.js +++ b/apps/drained/app.js @@ -1,6 +1,7 @@ var app = "drained"; -if (typeof drainedInterval !== "undefined") - drainedInterval = clearInterval(drainedInterval); +var globals = global; +if (typeof globals.drainedInterval !== "undefined") + globals.drainedInterval = clearInterval(globals.drainedInterval); Bangle.setLCDBrightness(0); var powerNoop = function () { return false; }; var forceOff = function (name) { diff --git a/apps/drained/app.ts b/apps/drained/app.ts index 499609f5f..9918361e8 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -1,9 +1,9 @@ const app = "drained"; // from boot.js -declare var drainedInterval: IntervalId | undefined; -if(typeof drainedInterval !== "undefined") - drainedInterval = clearInterval(drainedInterval) as undefined; +const globals: { drainedInterval: IntervalId | undefined } = global as any; +if(typeof globals.drainedInterval !== "undefined") + globals.drainedInterval = clearInterval(globals.drainedInterval) as undefined; // backlight Bangle.setLCDBrightness(0); diff --git a/apps/drained/boot.js b/apps/drained/boot.js index 48c1572bd..3ce74527c 100644 --- a/apps/drained/boot.js +++ b/apps/drained/boot.js @@ -1,6 +1,6 @@ (function () { var _a = require("Storage").readJSON("drained.setting.json", true) || {}, _b = _a.battery, threshold = _b === void 0 ? 5 : _b, _c = _a.interval, interval = _c === void 0 ? 10 : _c, _d = _a.keepStartup, keepStartup = _d === void 0 ? true : _d; - drainedInterval = setInterval(function () { + global.drainedInterval = setInterval(function () { if (Bangle.isCharging()) return; if (E.getBattery() > threshold) diff --git a/apps/drained/boot.ts b/apps/drained/boot.ts index 1fcb0591b..2f5b9322e 100644 --- a/apps/drained/boot.ts +++ b/apps/drained/boot.ts @@ -2,7 +2,7 @@ const { battery: threshold = 5, interval = 10, keepStartup = true }: DrainedSettings = require("Storage").readJSON(`drained.setting.json`, true) || {}; -drainedInterval = setInterval(() => { +(global as any).drainedInterval = setInterval(() => { if(Bangle.isCharging()) return; if(E.getBattery() > threshold) diff --git a/apps/lint_exemptions.js b/apps/lint_exemptions.js index 5821db4c4..18a2919e8 100644 --- a/apps/lint_exemptions.js +++ b/apps/lint_exemptions.js @@ -1137,18 +1137,6 @@ module.exports = { "no-undef" ] }, - "drained/boot.js": { - "hash": "914ea2c47aa6b9502b9dd354d490b2a8b838d4c6fafaa20e206f1f2396d4db40", - "rules": [ - "no-undef" - ] - }, - "drained/app.js": { - "hash": "2b609ca5bf414b0e400e25512bf396a01f8cb0365b4edd02ea1697b51907d36c", - "rules": [ - "no-undef" - ] - }, "dinoClock/app.js": { "hash": "e97566aa4f586ef654e3fc1ec286376352762ed8e0ea2e685a7b3ae687f51552", "rules": [ From 14787e495c4e482d4479bd2c4c8739fe9d5a2863 Mon Sep 17 00:00:00 2001 From: Anton Date: Sat, 4 May 2024 22:53:34 +0200 Subject: [PATCH 02/14] Revert "Enforce and fix typescript lints" This reverts commit 5630b85918182cb7e5aa7186aba44c26f3a18426. --- .eslintignore | 12 ++++++++++++ apps/ctrlpad/main.js | 5 ++--- apps/ctrlpad/main.ts | 5 ++--- apps/drained/app.js | 5 ++--- apps/drained/app.ts | 6 +++--- apps/drained/boot.js | 2 +- apps/drained/boot.ts | 2 +- apps/lint_exemptions.js | 12 ++++++++++++ 8 files changed, 35 insertions(+), 14 deletions(-) diff --git a/.eslintignore b/.eslintignore index 1e3abd9ff..933dfaf69 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,3 +4,15 @@ 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/ diff --git a/apps/ctrlpad/main.js b/apps/ctrlpad/main.js index 41e62a2d7..f9614168e 100644 --- a/apps/ctrlpad/main.js +++ b/apps/ctrlpad/main.js @@ -126,9 +126,8 @@ { text: "DnD", cb: function (tap) { - var on = false; - if (origBuzz) { - on = true; + var on; + if (on = !!origBuzz) { if (tap) { Bangle.buzz = origBuzz; origBuzz = undefined; diff --git a/apps/ctrlpad/main.ts b/apps/ctrlpad/main.ts index 7d99b88f6..7f758a3b0 100644 --- a/apps/ctrlpad/main.ts +++ b/apps/ctrlpad/main.ts @@ -193,9 +193,8 @@ { text: "DnD", cb: tap => { - let on = false; - if(origBuzz){ - on = true; + let on; + if(on = !!origBuzz){ if(tap){ Bangle.buzz = origBuzz; origBuzz = undefined; diff --git a/apps/drained/app.js b/apps/drained/app.js index 11f14713a..c74affea3 100644 --- a/apps/drained/app.js +++ b/apps/drained/app.js @@ -1,7 +1,6 @@ var app = "drained"; -var globals = global; -if (typeof globals.drainedInterval !== "undefined") - globals.drainedInterval = clearInterval(globals.drainedInterval); +if (typeof drainedInterval !== "undefined") + drainedInterval = clearInterval(drainedInterval); Bangle.setLCDBrightness(0); var powerNoop = function () { return false; }; var forceOff = function (name) { diff --git a/apps/drained/app.ts b/apps/drained/app.ts index 9918361e8..499609f5f 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -1,9 +1,9 @@ const app = "drained"; // from boot.js -const globals: { drainedInterval: IntervalId | undefined } = global as any; -if(typeof globals.drainedInterval !== "undefined") - globals.drainedInterval = clearInterval(globals.drainedInterval) as undefined; +declare var drainedInterval: IntervalId | undefined; +if(typeof drainedInterval !== "undefined") + drainedInterval = clearInterval(drainedInterval) as undefined; // backlight Bangle.setLCDBrightness(0); diff --git a/apps/drained/boot.js b/apps/drained/boot.js index 3ce74527c..48c1572bd 100644 --- a/apps/drained/boot.js +++ b/apps/drained/boot.js @@ -1,6 +1,6 @@ (function () { var _a = require("Storage").readJSON("drained.setting.json", true) || {}, _b = _a.battery, threshold = _b === void 0 ? 5 : _b, _c = _a.interval, interval = _c === void 0 ? 10 : _c, _d = _a.keepStartup, keepStartup = _d === void 0 ? true : _d; - global.drainedInterval = setInterval(function () { + drainedInterval = setInterval(function () { if (Bangle.isCharging()) return; if (E.getBattery() > threshold) diff --git a/apps/drained/boot.ts b/apps/drained/boot.ts index 2f5b9322e..1fcb0591b 100644 --- a/apps/drained/boot.ts +++ b/apps/drained/boot.ts @@ -2,7 +2,7 @@ const { battery: threshold = 5, interval = 10, keepStartup = true }: DrainedSettings = require("Storage").readJSON(`drained.setting.json`, true) || {}; -(global as any).drainedInterval = setInterval(() => { +drainedInterval = setInterval(() => { if(Bangle.isCharging()) return; if(E.getBattery() > threshold) diff --git a/apps/lint_exemptions.js b/apps/lint_exemptions.js index 18a2919e8..5821db4c4 100644 --- a/apps/lint_exemptions.js +++ b/apps/lint_exemptions.js @@ -1137,6 +1137,18 @@ module.exports = { "no-undef" ] }, + "drained/boot.js": { + "hash": "914ea2c47aa6b9502b9dd354d490b2a8b838d4c6fafaa20e206f1f2396d4db40", + "rules": [ + "no-undef" + ] + }, + "drained/app.js": { + "hash": "2b609ca5bf414b0e400e25512bf396a01f8cb0365b4edd02ea1697b51907d36c", + "rules": [ + "no-undef" + ] + }, "dinoClock/app.js": { "hash": "e97566aa4f586ef654e3fc1ec286376352762ed8e0ea2e685a7b3ae687f51552", "rules": [ From a78858e1ac5d81639f17f268e5d409dc771f1b4c Mon Sep 17 00:00:00 2001 From: Anton Date: Sat, 4 May 2024 23:21:43 +0200 Subject: [PATCH 03/14] Also lint typescript files --- .eslintignore | 29 +- apps/.eslintrc.js | 22 + apps/btadv/app.ts | 3 +- apps/color_catalog/app.js | 8 +- apps/ctrlpad/main.js | 2 +- apps/ctrlpad/main.ts | 2 +- apps/drained/app.ts | 2 +- apps/folderlaunch/app.js | 15 +- apps/folderlaunch/app.ts | 15 +- apps/folderlaunch/configLoad.ts | 2 +- apps/folderlaunch/types.d.ts | 2 +- apps/helloworld/helloworld.app.js | 6 +- apps/lint_exemptions.js | 12 - apps/widChargingStatus/widget.js | 4 +- apps/widChargingStatus/widget.ts | 6 +- apps/widhid/wid.ts | 4 +- bin/exempt-lint.mjs | 2 +- package-lock.json | 700 ++++++++++++++++++++++++++++++ package.json | 6 +- 19 files changed, 785 insertions(+), 57 deletions(-) diff --git a/.eslintignore b/.eslintignore index 933dfaf69..de0fa8513 100644 --- a/.eslintignore +++ b/.eslintignore @@ -5,14 +5,21 @@ 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 diff --git a/apps/.eslintrc.js b/apps/.eslintrc.js index 4c86b8174..217f23035 100644 --- a/apps/.eslintrc.js +++ b/apps/.eslintrc.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"])), diff --git a/apps/btadv/app.ts b/apps/btadv/app.ts index 1d9501175..713172ca1 100644 --- a/apps/btadv/app.ts +++ b/apps/btadv/app.ts @@ -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"); diff --git a/apps/color_catalog/app.js b/apps/color_catalog/app.js index d5014bcaa..b2f39c7a7 100644 --- a/apps/color_catalog/app.js +++ b/apps/color_catalog/app.js @@ -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 diff --git a/apps/ctrlpad/main.js b/apps/ctrlpad/main.js index f9614168e..93f2864f7 100644 --- a/apps/ctrlpad/main.js +++ b/apps/ctrlpad/main.js @@ -127,7 +127,7 @@ text: "DnD", cb: function (tap) { var on; - if (on = !!origBuzz) { + if ((on = !!origBuzz)) { if (tap) { Bangle.buzz = origBuzz; origBuzz = undefined; diff --git a/apps/ctrlpad/main.ts b/apps/ctrlpad/main.ts index 7f758a3b0..5faac60fa 100644 --- a/apps/ctrlpad/main.ts +++ b/apps/ctrlpad/main.ts @@ -194,7 +194,7 @@ text: "DnD", cb: tap => { let on; - if(on = !!origBuzz){ + if((on = !!origBuzz)){ if(tap){ Bangle.buzz = origBuzz; origBuzz = undefined; diff --git a/apps/drained/app.ts b/apps/drained/app.ts index 499609f5f..de6114f99 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -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; diff --git a/apps/folderlaunch/app.js b/apps/folderlaunch/app.js index 438b9e06d..1a66dffac 100644 --- a/apps/folderlaunch/app.js +++ b/apps/folderlaunch/app.js @@ -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; diff --git a/apps/folderlaunch/app.ts b/apps/folderlaunch/app.ts index 993570e59..aff8e5c7e 100644 --- a/apps/folderlaunch/app.ts +++ b/apps/folderlaunch/app.ts @@ -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; + } } } diff --git a/apps/folderlaunch/configLoad.ts b/apps/folderlaunch/configLoad.ts index 37841cd36..56c398cdd 100644 --- a/apps/folderlaunch/configLoad.ts +++ b/apps/folderlaunch/configLoad.ts @@ -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; diff --git a/apps/folderlaunch/types.d.ts b/apps/folderlaunch/types.d.ts index 86c0465e5..a6f927cd0 100644 --- a/apps/folderlaunch/types.d.ts +++ b/apps/folderlaunch/types.d.ts @@ -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, // IDs of apps to explicitly hide + hidden: Array, // IDs of apps to explicitly hide display: { rows: number, // Display an X by X grid of apps icon: boolean, // Whether to show icons diff --git a/apps/helloworld/helloworld.app.js b/apps/helloworld/helloworld.app.js index a59f29c78..3951052e5 100644 --- a/apps/helloworld/helloworld.app.js +++ b/apps/helloworld/helloworld.app.js @@ -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!']; } diff --git a/apps/lint_exemptions.js b/apps/lint_exemptions.js index 5821db4c4..18a2919e8 100644 --- a/apps/lint_exemptions.js +++ b/apps/lint_exemptions.js @@ -1137,18 +1137,6 @@ module.exports = { "no-undef" ] }, - "drained/boot.js": { - "hash": "914ea2c47aa6b9502b9dd354d490b2a8b838d4c6fafaa20e206f1f2396d4db40", - "rules": [ - "no-undef" - ] - }, - "drained/app.js": { - "hash": "2b609ca5bf414b0e400e25512bf396a01f8cb0365b4edd02ea1697b51907d36c", - "rules": [ - "no-undef" - ] - }, "dinoClock/app.js": { "hash": "e97566aa4f586ef654e3fc1ec286376352762ed8e0ea2e685a7b3ae687f51552", "rules": [ diff --git a/apps/widChargingStatus/widget.js b/apps/widChargingStatus/widget.js index e0c1b3b42..873383cf8 100644 --- a/apps/widChargingStatus/widget.js +++ b/apps/widChargingStatus/widget.js @@ -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(); diff --git a/apps/widChargingStatus/widget.ts b/apps/widChargingStatus/widget.ts index 78753d691..db8f9a490 100644 --- a/apps/widChargingStatus/widget.ts +++ b/apps/widChargingStatus/widget.ts @@ -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(); diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts index 1de293b36..c92512959 100644 --- a/apps/widhid/wid.ts +++ b/apps/widhid/wid.ts @@ -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", () => { diff --git a/bin/exempt-lint.mjs b/bin/exempt-lint.mjs index 64d564e71..eb590a533 100755 --- a/bin/exempt-lint.mjs +++ b/bin/exempt-lint.mjs @@ -28,7 +28,7 @@ if (!lintRule) { const filePathInput = process.argv[3]; const filePathMatch = filePathInput?.match( - /^(?:.*?\/apps\/|apps\/|\/)?(?.*\.js)$/iu, + /^(?:.*?\/apps\/|apps\/|\/)?(?.*\.[jt]s)$/iu, ); const filePath = filePathMatch?.groups?.path; if (!filePath) { diff --git a/package-lock.json b/package-lock.json index 71f5cec90..d63d0171f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index 10d0c6768..b09e7780b 100644 --- a/package.json +++ b/package.json @@ -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", From 4bc4d17755689e762eb0a2dcbffb19b27b5275ab Mon Sep 17 00:00:00 2001 From: Anton Date: Sat, 4 May 2024 23:40:57 +0200 Subject: [PATCH 04/14] Fix incorrect example in bulk-update-apps --- bin/bulk-update-apps.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bulk-update-apps.mjs b/bin/bulk-update-apps.mjs index 92e084d8b..fda2fa283 100644 --- a/bin/bulk-update-apps.mjs +++ b/bin/bulk-update-apps.mjs @@ -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 From 62a16815d6a02f06543c3fc16c5a3a7049fff4b4 Mon Sep 17 00:00:00 2001 From: Anton Date: Sat, 4 May 2024 23:41:56 +0200 Subject: [PATCH 05/14] Bump app versions --- apps/btadv/ChangeLog | 1 + apps/btadv/metadata.json | 2 +- apps/color_catalog/ChangeLog | 1 + apps/color_catalog/metadata.json | 2 +- apps/ctrlpad/ChangeLog | 1 + apps/ctrlpad/metadata.json | 2 +- apps/drained/ChangeLog | 1 + apps/drained/metadata.json | 2 +- apps/folderlaunch/ChangeLog | 3 ++- apps/folderlaunch/metadata.json | 2 +- apps/helloworld/ChangeLog | 1 + apps/helloworld/metadata.json | 2 +- apps/widChargingStatus/ChangeLog | 1 + apps/widChargingStatus/metadata.json | 2 +- apps/widhid/ChangeLog | 1 + apps/widhid/metadata.json | 2 +- 16 files changed, 17 insertions(+), 9 deletions(-) diff --git a/apps/btadv/ChangeLog b/apps/btadv/ChangeLog index 07e67157c..dbfc37fd7 100644 --- a/apps/btadv/ChangeLog +++ b/apps/btadv/ChangeLog @@ -1,2 +1,3 @@ 0.01: New app! 0.02: Advertise accelerometer data and sensor location +0.03: Minor code improvements diff --git a/apps/btadv/metadata.json b/apps/btadv/metadata.json index efe024a2f..060c2b498 100644 --- a/apps/btadv/metadata.json +++ b/apps/btadv/metadata.json @@ -2,7 +2,7 @@ "id": "btadv", "name": "btadv", "shortName": "btadv", - "version": "0.02", + "version": "0.03", "description": "Advertise & export live heart rate, accel, pressure, GPS & mag data over bluetooth", "icon": "icon.png", "tags": "health,tool,sensors,bluetooth", diff --git a/apps/color_catalog/ChangeLog b/apps/color_catalog/ChangeLog index 1ae723feb..d1d409730 100644 --- a/apps/color_catalog/ChangeLog +++ b/apps/color_catalog/ChangeLog @@ -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 diff --git a/apps/color_catalog/metadata.json b/apps/color_catalog/metadata.json index 0669e6b0b..4d49308ef 100644 --- a/apps/color_catalog/metadata.json +++ b/apps/color_catalog/metadata.json @@ -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", diff --git a/apps/ctrlpad/ChangeLog b/apps/ctrlpad/ChangeLog index c2829d1b1..d8c477701 100644 --- a/apps/ctrlpad/ChangeLog +++ b/apps/ctrlpad/ChangeLog @@ -1 +1,2 @@ 0.01: New app - forked from widhid +0.02: Minor code improvements diff --git a/apps/ctrlpad/metadata.json b/apps/ctrlpad/metadata.json index b7ece7d61..273dcdd7f 100644 --- a/apps/ctrlpad/metadata.json +++ b/apps/ctrlpad/metadata.json @@ -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", diff --git a/apps/drained/ChangeLog b/apps/drained/ChangeLog index 65c93e70f..a860d8393 100644 --- a/apps/drained/ChangeLog +++ b/apps/drained/ChangeLog @@ -4,3 +4,4 @@ Also avoid polluting global scope. 0.04: Enhance menu: enable bluetooth, visit settings & visit recovery 0.05: Enhance menu: permit toggling bluetooth +0.06: Minor code improvements diff --git a/apps/drained/metadata.json b/apps/drained/metadata.json index 115289d09..a5389a91b 100644 --- a/apps/drained/metadata.json +++ b/apps/drained/metadata.json @@ -1,7 +1,7 @@ { "id": "drained", "name": "Drained", - "version": "0.05", + "version": "0.06", "description": "Switches to displaying a simple clock when the battery percentage is low, and disables some peripherals", "readme": "README.md", "icon": "icon.png", diff --git a/apps/folderlaunch/ChangeLog b/apps/folderlaunch/ChangeLog index 2670571d7..c92db0901 100644 --- a/apps/folderlaunch/ChangeLog +++ b/apps/folderlaunch/ChangeLog @@ -1,3 +1,4 @@ 0.01: New app! 0.02: Handle files potentially not existing -0.03: Add setting to disable vibration \ No newline at end of file +0.03: Add setting to disable vibration +0.04: Minor code improvements diff --git a/apps/folderlaunch/metadata.json b/apps/folderlaunch/metadata.json index 0194fcf66..9853c7daf 100644 --- a/apps/folderlaunch/metadata.json +++ b/apps/folderlaunch/metadata.json @@ -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", diff --git a/apps/helloworld/ChangeLog b/apps/helloworld/ChangeLog index 969aed43d..3444ec49a 100644 --- a/apps/helloworld/ChangeLog +++ b/apps/helloworld/ChangeLog @@ -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 diff --git a/apps/helloworld/metadata.json b/apps/helloworld/metadata.json index 3ec5c2a83..ebdc6dcf6 100644 --- a/apps/helloworld/metadata.json +++ b/apps/helloworld/metadata.json @@ -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", diff --git a/apps/widChargingStatus/ChangeLog b/apps/widChargingStatus/ChangeLog index 272d6e335..8f13618aa 100644 --- a/apps/widChargingStatus/ChangeLog +++ b/apps/widChargingStatus/ChangeLog @@ -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 diff --git a/apps/widChargingStatus/metadata.json b/apps/widChargingStatus/metadata.json index 53754b0a1..0feca7b44 100644 --- a/apps/widChargingStatus/metadata.json +++ b/apps/widChargingStatus/metadata.json @@ -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", diff --git a/apps/widhid/ChangeLog b/apps/widhid/ChangeLog index b0e479108..fdba7934b 100644 --- a/apps/widhid/ChangeLog +++ b/apps/widhid/ChangeLog @@ -3,3 +3,4 @@ launcher is active. 0.03: Handle errors when sending input over BLE and the special-case of replacing a single handler +0.04: Minor code improvements diff --git a/apps/widhid/metadata.json b/apps/widhid/metadata.json index b819c9b64..7c00fefec 100644 --- a/apps/widhid/metadata.json +++ b/apps/widhid/metadata.json @@ -2,7 +2,7 @@ "id": "widhid", "name": "Bluetooth Music Swipe Control Widget", "shortName": "BLE Swipe Widget", - "version": "0.03", + "version": "0.04", "description": "Based on Swipe Bluetooth Music Controls (based on Bluetooth Music Controls). Swipe down to enable, then swipe up/down for volume, left/right for previous and next and tap for play/pause. Enable HID in settings, pair with your phone/computer, then use this widget to control music from your watch!", "icon": "icon.png", "readme": "README.md", From 964ba309facd13153d2159ac7b31493215c63812 Mon Sep 17 00:00:00 2001 From: Anton Date: Sat, 4 May 2024 23:48:51 +0200 Subject: [PATCH 06/14] Unbump apps with only type changes --- apps/btadv/ChangeLog | 1 - apps/btadv/metadata.json | 2 +- apps/drained/ChangeLog | 1 - apps/drained/metadata.json | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/btadv/ChangeLog b/apps/btadv/ChangeLog index dbfc37fd7..07e67157c 100644 --- a/apps/btadv/ChangeLog +++ b/apps/btadv/ChangeLog @@ -1,3 +1,2 @@ 0.01: New app! 0.02: Advertise accelerometer data and sensor location -0.03: Minor code improvements diff --git a/apps/btadv/metadata.json b/apps/btadv/metadata.json index 060c2b498..efe024a2f 100644 --- a/apps/btadv/metadata.json +++ b/apps/btadv/metadata.json @@ -2,7 +2,7 @@ "id": "btadv", "name": "btadv", "shortName": "btadv", - "version": "0.03", + "version": "0.02", "description": "Advertise & export live heart rate, accel, pressure, GPS & mag data over bluetooth", "icon": "icon.png", "tags": "health,tool,sensors,bluetooth", diff --git a/apps/drained/ChangeLog b/apps/drained/ChangeLog index a860d8393..65c93e70f 100644 --- a/apps/drained/ChangeLog +++ b/apps/drained/ChangeLog @@ -4,4 +4,3 @@ Also avoid polluting global scope. 0.04: Enhance menu: enable bluetooth, visit settings & visit recovery 0.05: Enhance menu: permit toggling bluetooth -0.06: Minor code improvements diff --git a/apps/drained/metadata.json b/apps/drained/metadata.json index a5389a91b..115289d09 100644 --- a/apps/drained/metadata.json +++ b/apps/drained/metadata.json @@ -1,7 +1,7 @@ { "id": "drained", "name": "Drained", - "version": "0.06", + "version": "0.05", "description": "Switches to displaying a simple clock when the battery percentage is low, and disables some peripherals", "readme": "README.md", "icon": "icon.png", From d7286c451b34229929b9b1898d19c06b08855a74 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Tue, 14 May 2024 21:53:48 +0100 Subject: [PATCH 07/14] multitimer: preserve original `uiRemove` e.g. a `showMenu()`'s `setUI` call --- apps/multitimer/ChangeLog | 1 + apps/multitimer/app.js | 2 ++ apps/multitimer/metadata.json | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/multitimer/ChangeLog b/apps/multitimer/ChangeLog index 0facd0a26..a37b12a60 100644 --- a/apps/multitimer/ChangeLog +++ b/apps/multitimer/ChangeLog @@ -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 diff --git a/apps/multitimer/app.js b/apps/multitimer/app.js index 31da18796..91745310f 100644 --- a/apps/multitimer/app.js +++ b/apps/multitimer/app.js @@ -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(); }; } diff --git a/apps/multitimer/metadata.json b/apps/multitimer/metadata.json index b1cdcb34d..7f44698a9 100644 --- a/apps/multitimer/metadata.json +++ b/apps/multitimer/metadata.json @@ -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": [ From 799da731297d48d03f149bbf9a10389059494812 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 17 May 2024 12:45:32 +0100 Subject: [PATCH 08/14] 0.10: Fix cscsensor when using coospoo sensor that supports crank *and* wheel --- apps/cscsensor/ChangeLog | 1 + apps/cscsensor/cscsensor.app.js | 8 +++++--- apps/cscsensor/metadata.json | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/cscsensor/ChangeLog b/apps/cscsensor/ChangeLog index c01b35503..8ccca4253 100644 --- a/apps/cscsensor/ChangeLog +++ b/apps/cscsensor/ChangeLog @@ -8,3 +8,4 @@ 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 \ No newline at end of file diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index 1ad7a9e98..5b837e2c9 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -160,7 +160,8 @@ class CSCSensor { updateSensor(event) { var qChanged = false; if (event.target.uuid == "0x2a5b") { - if (event.target.value.getUint8(0, true) & 0x2) { + let flags = event.target.value.getUint8(0); + if (flags & 2) { // crank revolution - if enabled const crankRevs = event.target.value.getUint16(1, true); const crankTime = event.target.value.getUint16(3, true); @@ -170,7 +171,8 @@ class CSCSensor { } this.lastCrankRevs = crankRevs; this.lastCrankTime = crankTime; - } else { + } + if (flags & 1) { // wheel revolution var wheelRevs = event.target.value.getUint32(1, true); var dRevs = (this.lastRevs>0 ? wheelRevs-this.lastRevs : 0); @@ -226,7 +228,7 @@ function getSensorBatteryLevel(gatt) { function connection_setup() { mySensor.screenInit = true; E.showMessage("Scanning for CSC sensor..."); - NRF.requestDevice({ filters: [{services:["1816"]}], maxInterval: 100}).then(function(d) { + NRF.requestDevice({ filters: [{services:["1816"]}]}).then(function(d) { device = d; E.showMessage("Found device"); return device.gatt.connect(); diff --git a/apps/cscsensor/metadata.json b/apps/cscsensor/metadata.json index 5d70251da..5d93487d5 100644 --- a/apps/cscsensor/metadata.json +++ b/apps/cscsensor/metadata.json @@ -2,7 +2,7 @@ "id": "cscsensor", "name": "Cycling speed sensor", "shortName": "CSCSensor", - "version": "0.09", + "version": "0.10", "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", From 9841aeddebadd501d68bb77068ccfca1e58d6920 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 17 May 2024 13:16:45 +0100 Subject: [PATCH 09/14] really try and fix csc - it was so broken! --- apps/cscsensor/cscsensor.app.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index 5b837e2c9..c0f09a509 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -161,17 +161,7 @@ class CSCSensor { var qChanged = false; if (event.target.uuid == "0x2a5b") { let flags = event.target.value.getUint8(0); - if (flags & 2) { - // 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; - } + let offs = 0; if (flags & 1) { // wheel revolution var wheelRevs = event.target.value.getUint32(1, true); @@ -208,8 +198,21 @@ class CSCSensor { } this.lastSpeed = this.speed; if (this.speed>this.maxSpeed && (this.movingTime>3 || this.speed<20) && this.speed<50) this.maxSpeed = this.speed; + offs += 6; + } + if (flags & 2) { + // crank revolution - if enabled + const crankRevs = event.target.value.getUint16(offs + 1, true); + const crankTime = event.target.value.getUint16(offs + 3, true); + if (crankTime > this.lastCrankTime) { + this.cadence = (crankRevs-this.lastCrankRevs)/(crankTime-this.lastCrankTime)*(60*1024); + qChanged = true; + } + this.lastCrankRevs = crankRevs; + this.lastCrankTime = crankTime; } } + if (qChanged) this.updateScreen(); } } From 751f5ed9f3ad423aaf7da281efc718e4b075703b Mon Sep 17 00:00:00 2001 From: Anton Date: Fri, 17 May 2024 14:58:58 +0200 Subject: [PATCH 10/14] Unbump app with only comment change --- apps/widhid/ChangeLog | 1 - apps/widhid/metadata.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/widhid/ChangeLog b/apps/widhid/ChangeLog index fdba7934b..b0e479108 100644 --- a/apps/widhid/ChangeLog +++ b/apps/widhid/ChangeLog @@ -3,4 +3,3 @@ launcher is active. 0.03: Handle errors when sending input over BLE and the special-case of replacing a single handler -0.04: Minor code improvements diff --git a/apps/widhid/metadata.json b/apps/widhid/metadata.json index 7c00fefec..b819c9b64 100644 --- a/apps/widhid/metadata.json +++ b/apps/widhid/metadata.json @@ -2,7 +2,7 @@ "id": "widhid", "name": "Bluetooth Music Swipe Control Widget", "shortName": "BLE Swipe Widget", - "version": "0.04", + "version": "0.03", "description": "Based on Swipe Bluetooth Music Controls (based on Bluetooth Music Controls). Swipe down to enable, then swipe up/down for volume, left/right for previous and next and tap for play/pause. Enable HID in settings, pair with your phone/computer, then use this widget to control music from your watch!", "icon": "icon.png", "readme": "README.md", From 5c89b45722e1389137a160ae75224f719440371e Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 17 May 2024 16:00:31 +0100 Subject: [PATCH 11/14] Finally merge two broken Bluetooth Cycle Speed sensor apps to use one library that 'just works' (I hope!) - added clockinfo and recoder functionality --- apps/blecsc/ChangeLog | 3 + apps/blecsc/README.md | 32 +++++ apps/blecsc/blecsc.js | 216 ++++++++++++++++++++++++++++++ apps/blecsc/clkinfo.js | 74 ++++++++++ apps/blecsc/icons8-cycling-48.png | Bin 0 -> 1487 bytes apps/blecsc/metadata.json | 22 +++ apps/blecsc/recorder.js | 28 ++++ apps/blecsc/settings.js | 85 ++++++++++++ apps/cscsensor/ChangeLog | 3 +- apps/cscsensor/cscsensor.app.js | 136 +++---------------- apps/cscsensor/metadata.json | 3 +- apps/cycling/ChangeLog | 1 + apps/cycling/README.md | 4 +- apps/cycling/blecsc-emu.js | 111 --------------- apps/cycling/blecsc.js | 150 --------------------- apps/cycling/cycling.app.js | 28 +--- apps/cycling/metadata.json | 4 +- 17 files changed, 494 insertions(+), 406 deletions(-) create mode 100644 apps/blecsc/ChangeLog create mode 100644 apps/blecsc/README.md create mode 100644 apps/blecsc/blecsc.js create mode 100644 apps/blecsc/clkinfo.js create mode 100644 apps/blecsc/icons8-cycling-48.png create mode 100644 apps/blecsc/metadata.json create mode 100644 apps/blecsc/recorder.js create mode 100644 apps/blecsc/settings.js delete mode 100644 apps/cycling/blecsc-emu.js delete mode 100644 apps/cycling/blecsc.js diff --git a/apps/blecsc/ChangeLog b/apps/blecsc/ChangeLog new file mode 100644 index 000000000..4efacaabf --- /dev/null +++ b/apps/blecsc/ChangeLog @@ -0,0 +1,3 @@ +0.01: Initial version +0.02: Minor code improvements +0.03: Moved from cycling app, fixed connection issues and cadence \ No newline at end of file diff --git a/apps/blecsc/README.md b/apps/blecsc/README.md new file mode 100644 index 000000000..5cde87168 --- /dev/null +++ b/apps/blecsc/README.md @@ -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 \ No newline at end of file diff --git a/apps/blecsc/blecsc.js b/apps/blecsc/blecsc.js new file mode 100644 index 000000000..0b2024fc1 --- /dev/null +++ b/apps/blecsc/blecsc.js @@ -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(); +*/ diff --git a/apps/blecsc/clkinfo.js b/apps/blecsc/clkinfo.js new file mode 100644 index 000000000..9a9515c3a --- /dev/null +++ b/apps/blecsc/clkinfo.js @@ -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; +}) + + diff --git a/apps/blecsc/icons8-cycling-48.png b/apps/blecsc/icons8-cycling-48.png new file mode 100644 index 0000000000000000000000000000000000000000..0bc83859f1ac8d5b1d40aa787ab3c8bf339913fd GIT binary patch literal 1487 zcmV;=1u*)FP)BH^< zyW9n~y*qr_|Cil8&-47wInUcYcLAS#^2w*s6pf~HE?fR2B+da?2cQbX+sIIO#vR6} zC14F+`r0W52Ju37k`R;+ZG@6I2ZJY&z?9<-X7myuo-S{P&K=C?CBSq=-i|7FFn)>z zGlWX>KF@8r7q(gy1B1o}w0CMluJ4M^%-R8xwu0#!IG+Jvn>&239pdkH7KGgqBYtRX z)lMB~7s!Iy(Le8ue>L-ME?t%irW_D-wwd2XDaI0a{CFjS^1Q>z4XxT!ZQUV(a_xcY zE{>a0k)&U{slroVil2d!T}O7;Hcu~g6+8fRnFFc%UtKZp$@2HqpJHdAXn#>i&uvRZ zZKHNXw@71aWbpT6W)}f4c;Z))6)4X;oZQ+NP~X@#vf%BiZqhIKW&a1Sc;egR1P<-k z{(fzXNHrJz#96RAa7J5=dQ<-qCQE z#sWaFzaLh`#6j$w3wFY4@B61VVsb-5+>0Ap0N~oE+XF5)&8&G~VolTxt;^u;5muAI z_>fl;n3a~n52Q6S+yfz- z48{XqNg(<8jIQPm1UTEr`Kz%iCf2MA719#3*1J_6yDN_lu|C{ll(V;sW_)P6sQ&EA z`GY5RFQ4d%kKyF$lbAMStthU%DJ&Fw5yKGPCguXz*q;DLIxetq zQ&GO1>TEb!UZJ-wtLOsWr^WLUFR55a1JFZ+%wuOS_P?kzO>*eW))i2U?0003g14xmMV5(D= zZ)+Reo$m(#vmg$-zE*C@{b}Wv+)8JAH_U(7zD^lnc3c6*O@;Zc5&+BCtRi9%4{8tU z3bbC@QYuHZ@;KzXthu_VPlk?lHvFL^Vv3A`CVBba!c>K#2 zh4}zvSAa?YfJv1h2a}T^AOir1(O)_<)&blI;0B0S5!q)?A-+9YXT$Nbb2jB0BV5p zhYQ{teA!y4z+_T~w~NKZFaYQQ_@E@wkzQ5L?*O2Y{AYqV9l*<0I7)5>`!8};uXvO1 zvY0C{nbhHJVlELf;rgAm7ohxG!J2nQ8obi{Vaw^`W#@D(s8-t^BGESUbz+>c_z9mZ pnU^5{H~9$VZN5)F`Q(##^&bl8rz8LGDIEX+002ovPDHLkV1j9?%0U1C literal 0 HcmV?d00001 diff --git a/apps/blecsc/metadata.json b/apps/blecsc/metadata.json new file mode 100644 index 000000000..de8c76fec --- /dev/null +++ b/apps/blecsc/metadata.json @@ -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"} + ] +} diff --git a/apps/blecsc/recorder.js b/apps/blecsc/recorder.js new file mode 100644 index 000000000..510f50c3f --- /dev/null +++ b/apps/blecsc/recorder.js @@ -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) + }; + } +}) + diff --git a/apps/blecsc/settings.js b/apps/blecsc/settings.js new file mode 100644 index 000000000..b445b2541 --- /dev/null +++ b/apps/blecsc/settings.js @@ -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(); +}) \ No newline at end of file diff --git a/apps/cscsensor/ChangeLog b/apps/cscsensor/ChangeLog index 8ccca4253..8786e727c 100644 --- a/apps/cscsensor/ChangeLog +++ b/apps/cscsensor/ChangeLog @@ -8,4 +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 \ No newline at end of file +0.10: Fix cscsensor when using coospoo sensor that supports crank *and* wheel +0.11: Update to use blecsc library \ No newline at end of file diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index c0f09a509..e86a40626 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -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,119 +144,38 @@ class CSCSensor { } } - updateSensor(event) { - var qChanged = false; - if (event.target.uuid == "0x2a5b") { - let flags = event.target.value.getUint8(0); - let offs = 0; - if (flags & 1) { - // 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; - offs += 6; - } - if (flags & 2) { - // crank revolution - if enabled - const crankRevs = event.target.value.getUint16(offs + 1, true); - const crankTime = event.target.value.getUint16(offs + 3, true); - if (crankTime > this.lastCrankTime) { - this.cadence = (crankRevs-this.lastCrankRevs)/(crankTime-this.lastCrankTime)*(60*1024); - qChanged = true; - } - this.lastCrankRevs = crankRevs; - this.lastCrankTime = crankTime; - } - } - - 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"]}]}).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 \ No newline at end of file diff --git a/apps/cscsensor/metadata.json b/apps/cscsensor/metadata.json index 5d93487d5..d3752bad5 100644 --- a/apps/cscsensor/metadata.json +++ b/apps/cscsensor/metadata.json @@ -2,10 +2,11 @@ "id": "cscsensor", "name": "Cycling speed sensor", "shortName": "CSCSensor", - "version": "0.10", + "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": [ diff --git a/apps/cycling/ChangeLog b/apps/cycling/ChangeLog index b7e50d38d..9fec754fc 100644 --- a/apps/cycling/ChangeLog +++ b/apps/cycling/ChangeLog @@ -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) \ No newline at end of file diff --git a/apps/cycling/README.md b/apps/cycling/README.md index 7ba8ee224..485537293 100644 --- a/apps/cycling/README.md +++ b/apps/cycling/README.md @@ -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. diff --git a/apps/cycling/blecsc-emu.js b/apps/cycling/blecsc-emu.js deleted file mode 100644 index 1a313e08a..000000000 --- a/apps/cycling/blecsc-emu.js +++ /dev/null @@ -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",``); - */ -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; diff --git a/apps/cycling/blecsc.js b/apps/cycling/blecsc.js deleted file mode 100644 index 7a47108e5..000000000 --- a/apps/cycling/blecsc.js +++ /dev/null @@ -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; diff --git a/apps/cycling/cycling.app.js b/apps/cycling/cycling.app.js index 268284a29..7261d3519 100644 --- a/apps/cycling/cycling.app.js +++ b/apps/cycling/cycling.app.js @@ -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); diff --git a/apps/cycling/metadata.json b/apps/cycling/metadata.json index 95c0ca068..51e51b409 100644 --- a/apps/cycling/metadata.json +++ b/apps/cycling/metadata.json @@ -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": [ From e218df999c8a53948fc9eef25f19254c66f4a834 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 17 May 2024 16:33:19 +0100 Subject: [PATCH 12/14] tweak clockinfo category naming --- apps/clkinfogps/clkinfo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/clkinfogps/clkinfo.js b/apps/clkinfogps/clkinfo.js index ed2fc721a..7db9bbdae 100644 --- a/apps/clkinfogps/clkinfo.js +++ b/apps/clkinfogps/clkinfo.js @@ -91,7 +91,7 @@ }; var info = { - name: "Gps", + name: "GPS", items: [ { name: "gridref", From 83e32cd75d39b7479c0d9edb6a873d2ac461c919 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 17 May 2024 16:33:28 +0100 Subject: [PATCH 13/14] lint exemptions --- apps/lint_exemptions.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/apps/lint_exemptions.js b/apps/lint_exemptions.js index 98a069664..10cbc34d8 100644 --- a/apps/lint_exemptions.js +++ b/apps/lint_exemptions.js @@ -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": [ From 3eb1f8ff6bb81b2b728b30661f30e0edf297c9b6 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 17 May 2024 16:33:40 +0100 Subject: [PATCH 14/14] add GPS speed clockinfo --- apps/clkinfogpsspeed/ChangeLog | 1 + apps/clkinfogpsspeed/clkinfo.js | 27 +++++++++++++++++++++++++++ apps/clkinfogpsspeed/icon.png | Bin 0 -> 1439 bytes apps/clkinfogpsspeed/metadata.json | 13 +++++++++++++ 4 files changed, 41 insertions(+) create mode 100644 apps/clkinfogpsspeed/ChangeLog create mode 100644 apps/clkinfogpsspeed/clkinfo.js create mode 100644 apps/clkinfogpsspeed/icon.png create mode 100644 apps/clkinfogpsspeed/metadata.json diff --git a/apps/clkinfogpsspeed/ChangeLog b/apps/clkinfogpsspeed/ChangeLog new file mode 100644 index 000000000..78ba28f3b --- /dev/null +++ b/apps/clkinfogpsspeed/ChangeLog @@ -0,0 +1 @@ +0.01: New Clock Info! diff --git a/apps/clkinfogpsspeed/clkinfo.js b/apps/clkinfogpsspeed/clkinfo.js new file mode 100644 index 000000000..a2c1f51c1 --- /dev/null +++ b/apps/clkinfogpsspeed/clkinfo.js @@ -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! \ No newline at end of file diff --git a/apps/clkinfogpsspeed/icon.png b/apps/clkinfogpsspeed/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..10186f13fba597e4744fc13fd1fdebf68b430710 GIT binary patch literal 1439 zcmV;Q1z`G#P)B=?k!Z|jmKftBOY|=j{a0r|0y8?4 zIC0_@o|_K3!M(t!th=`~P#y_!ie|FuB5TZI#+VGDFjiQ(_m)RNDI??2vcBkxM=Z$T zGv}6D?kxpxOCkHCU-C z12{psaf14H74FqGHBQjE=v~SEU?-K@Cvbw1;so_KPSOw-kPpE~Q6D=_TqbLO7|kR` z(yp+H2LU5#7e-RYQJ*_P9w(SrFp};ICL$}>L%rGv?Oi4q8nJ`f;)a7?6|g|Rhm3a6 zbeZ71+6X1(Oo$bsdy7v~FK;V(jHHqajEGrFnoI*QG;LM8!Dw-@YAFO=2x^EY*I1OnE|gFkOhz~$yPNY2b-MWFcIC)u6U^HxC?PWY%fM^xKHJj*CMO}hinUTq&N#UBlX%hEd;;BBWi^bZQ7mT&|Z zI7d{Ng-hIh$Lx>m=ih^s7ZSjiTLC_4CHstsFYir;`R{%Mr)%?!HfXf-H?lbl0ko5I zG+EbXP%IWxivqJOz^*v(ou~qr*(RzVlf}(H)K-$!>W4%Lz({J5bL8q7grqNziW+$3 z#l&^wmtXym%{c$(o0yg(7*kNP%etQu8$$D;1SF^k0S2>KN zO@UA<{~1(u=h=#MyJFsCu|v&I7okx3qu_3gkv&g`Ex^ADOjaO_x+XhzYV+y`?so8Q zWTldb4d4Ncq^}hz^*)EoW81L|q}ccuUU002ovPDHLkV1oDemF)lk literal 0 HcmV?d00001 diff --git a/apps/clkinfogpsspeed/metadata.json b/apps/clkinfogpsspeed/metadata.json new file mode 100644 index 000000000..7fceeb7b8 --- /dev/null +++ b/apps/clkinfogpsspeed/metadata.json @@ -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"} + ] +}