From d385ad78d7ba1a53cfc7ef305dad6bfc2a9fa952 Mon Sep 17 00:00:00 2001 From: Lars Berning <151194+laberning@users.noreply.github.com> Date: Thu, 22 Apr 2021 21:03:59 +0200 Subject: [PATCH] adds support for ant+ heart rate monitors --- README.md | 2 +- app/ant/AntManager.js | 64 +++++++++++++++++++ app/server.js | 18 ++++-- config/default.config.js | 10 +++ docs/backlog.md | 1 - docs/installation.md | 19 +++++- package-lock.json | 131 +++++++++++++++++---------------------- package.json | 5 +- 8 files changed, 165 insertions(+), 85 deletions(-) create mode 100644 app/ant/AntManager.js diff --git a/README.md b/README.md index 41eb81b..cd2b726 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Open Rowing Monitor implements a physics model to simulate the typical metrics o * Strokes per Minute * Calories used (kcal) * Training Duration -* Heart Rate (requires a BLE Heart Rate Monitor) +* Heart Rate (supports BLE and ANT+ heart rate monitors, ANT+ requires an ANT+ USB stick) ### Web Interface diff --git a/app/ant/AntManager.js b/app/ant/AntManager.js new file mode 100644 index 0000000..6da4f76 --- /dev/null +++ b/app/ant/AntManager.js @@ -0,0 +1,64 @@ +'use strict' +/* + Open Rowing Monitor, https://github.com/laberning/openrowingmonitor + + This manager creates a module to listen to ANT+ devices. + This currently can be used to get the heart rate from ANT+ heart rate sensors. + + Requires an ANT+ USB stick, the following models might work: + - Garmin USB or USB2 ANT+ or an off-brand clone of it (ID 0x1008) + - Garmin mini ANT+ (ID 0x1009) +*/ +import log from 'loglevel' +import Ant from 'ant-plus' +import EventEmitter from 'node:events' + +function createAntManager () { + const emitter = new EventEmitter() + const antStick = new Ant.GarminStick2() + const antStick3 = new Ant.GarminStick3() + const heartrateSensor = new Ant.HeartRateSensor(antStick) + + heartrateSensor.on('hbData', (data) => { + emitter.emit('heartrateMeasurement', { heartrate: data.ComputedHeartRate, batteryLevel: data.BatteryLevel }) + }) + + heartrateSensor.on('attached', () => { + log.info('heart rate sensor attached') + }) + + heartrateSensor.on('detached', () => { + log.info('heart rate sensor detached') + }) + + antStick.on('startup', () => { + log.info('classic ANT+ stick found') + heartrateSensor.attach(0, 0) + }) + + antStick3.on('startup', () => { + log.info('mini ANT+ stick found') + heartrateSensor.attach(0, 0) + }) + + antStick.on('shutdown', () => { + log.info('classic ANT+ stick lost') + }) + + antStick3.on('shutdown', () => { + log.info('mini ANT+ stick lost') + }) + + if (!antStick.open()) { + log.debug('classic ANT+ stick not found') + } + + if (!antStick3.open()) { + log.debug('mini ANT+ stick not found') + } + + return Object.assign(emitter, { + }) +} + +export { createAntManager } diff --git a/app/server.js b/app/server.js index c954722..3cd9e18 100644 --- a/app/server.js +++ b/app/server.js @@ -15,6 +15,7 @@ import { createRowingEngine } from './engine/RowingEngine.js' import { createRowingStatistics } from './engine/RowingStatistics.js' import { createWebServer } from './WebServer.js' import { createPeripheralManager } from './ble/PeripheralManager.js' +import { createAntManager } from './ant/AntManager.js' // eslint-disable-next-line no-unused-vars import { replayRowingSession } from './tools/RowingRecorder.js' @@ -87,10 +88,19 @@ rowingStatistics.on('metricsUpdate', (metrics) => { peripheralManager.notifyMetrics('metricsUpdate', metrics) }) -const bleCentralService = fork('./app/ble/CentralService.js') -bleCentralService.on('message', (heartrateMeasurement) => { - rowingStatistics.handleHeartrateMeasurement(heartrateMeasurement) -}) +if (config.heartrateMonitorBLE) { + const bleCentralService = fork('./app/ble/CentralService.js') + bleCentralService.on('message', (heartrateMeasurement) => { + rowingStatistics.handleHeartrateMeasurement(heartrateMeasurement) + }) +} + +if (config.heartrateMonitorANT) { + const antManager = createAntManager() + antManager.on('heartrateMeasurement', (heartrateMeasurement) => { + rowingStatistics.handleHeartrateMeasurement(heartrateMeasurement) + }) +} const webServer = createWebServer() webServer.on('messageReceived', (message) => { diff --git a/config/default.config.js b/config/default.config.js index d3f9a27..dec3569 100644 --- a/config/default.config.js +++ b/config/default.config.js @@ -26,6 +26,16 @@ export default { // supported modes: FTMS, FTMSBIKE, PM5 bluetoothMode: 'FTMS', + // turn this on if you want support for Bluetooth Low Energy heart rate monitors + // will currenty the hear rate and battery level of the first device found + heartrateMonitorBLE: true, + + // turn this on if you want support for ANT+ heart rate monitors + // you will need an ANT+ USB stick for this to work, the following models might work: + // - Garmin USB or USB2 ANT+ or an off-brand clone of it (ID 0x1008) + // - Garmin mini ANT+ (ID 0x1009) + heartrateMonitorANT: false, + // defines the name that is used to announce the FTMS Rower via Bluetooth Low Energy (BLE) // some rowing training applications expect that the rowing device is announced with a certain name ftmsRowerPeripheralName: 'OpenRowingMonitor', diff --git a/docs/backlog.md b/docs/backlog.md index 59b6fa6..eb185cd 100644 --- a/docs/backlog.md +++ b/docs/backlog.md @@ -4,7 +4,6 @@ This is the very minimalistic Backlog for further development of this project. ## Soon -* add support for ANT+ heart rate monitors with USB dongles * add an option to the installation script to directly attach a touchscreen to the Raspberry Pi and automatically show WebUI on this in kiosk mode * validate FTMS with more training applications and harden implementation (i.e. Holofit and Coxswain) * record a longer rowing session and analyze two encountered problems: 1) rarely the stroke rate doubles for a short duration (might be a problem with stroke detection when measurements are imprecise), 2) in one occasion the measured power jumped to a very high value after a break (40000 watts) diff --git a/docs/installation.md b/docs/installation.md index 2207f9e..ceada09 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -35,12 +35,27 @@ Open Rowing Monitor does not provide proper releases (yet), but you can update t sudo /opt/openrowingmonitor/install/update.sh ``` -### If you want to run Bluetooth Low Energy and the Web-Server on port 80 without root +### Running Open Rowing Monitor without root permissions + +The default installation will run Open Rowing Monitor with root permissions. If you want you can also run it as user by modifying the following system services: + +#### To use BLE and open the Web-Server on port 80 + +Issue the following command: ```zsh sudo setcap cap_net_bind_service,cap_net_raw=+eip $(eval readlink -f `which node`) ``` +#### To access ANT+ USB sticks + +Create a file `/etc/udev/rules.d/51-garmin-usb.rules` with the following content: + +```zsh +ATTRS{idVendor}=="0fcf", ATTRS{idProduct}=="1008", MODE="0666" +ATTRS{idVendor}=="0fcf", ATTRS{idProduct}=="1009", MODE="0666" +``` + ## Hardware Installation Basically all that's left to do is hook up your sensor to the GPIO pins of the Raspberry Pi and configure the rowing machine specific parameters of the software. @@ -68,4 +83,4 @@ If your machine does not have something like this or if the sensor is not access * PAS sensor (i.e. from an E-bike) * Optical chopper wheel -You should now adjust the rower specific parameters in `config/config.js` to suit your rowing machine. +You should now adjust the rower specific parameters in `config/config.js` to suit your rowing machine. Have a look at [config/default.config.js](../config/default.config.js) to see what config parameters are available. diff --git a/package-lock.json b/package-lock.json index d0f5544..96e93e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "openrowingmonitor", - "version": "0.7.0", + "version": "0.7.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -130,9 +130,9 @@ "dev": true }, "@npmcli/git": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.0.7.tgz", - "integrity": "sha512-HUSqNDWYsTpboc7yV1C4yPd/jbaGXfWVmGoTyB+h3QQSKMpYPzTXLrqUMpz+LEA6Dt9usUeRtjytwcrfoBMJpg==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.0.8.tgz", + "integrity": "sha512-LPnzyBZ+1p7+JzHVwwKycMF8M3lr1ze3wxGRnxn/QxJtk++Y3prSJQrdBDGCxJyRpFsup6J3lrRBVYBhJVrM8Q==", "dev": true, "requires": { "@npmcli/promise-spawn": "^1.3.2", @@ -215,9 +215,9 @@ } }, "@npmcli/run-script": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.4.tgz", - "integrity": "sha512-Yd9HXTtF1JGDXZw0+SOn+mWLYS0e7bHBHVC/2C8yqs4wUrs/k8rwBSinD7rfk+3WG/MFGRZKxjyoD34Pch2E/A==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.5.tgz", + "integrity": "sha512-NQspusBCpTjNwNRFMtz2C5MxoxyzlbuJ4YEhxAKrIonTiirKDtatsZictx9RgamQIx6+QuHMNmPl0wQdoESs9A==", "dev": true, "requires": { "@npmcli/node-gyp": "^1.0.2", @@ -317,6 +317,14 @@ "color-convert": "^1.9.0" } }, + "ant-plus": { + "version": "0.1.24", + "resolved": "https://registry.npmjs.org/ant-plus/-/ant-plus-0.1.24.tgz", + "integrity": "sha512-otEIAN+9jtu/1mwHL81au0sO7muJT1QrWOm9j29NEg3x1Y+ZsSIYX+LSdY+BBr2mLA4hT/vpqv5pWX9KDWceVg==", + "requires": { + "usb": "^1.6.0" + } + }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -406,8 +414,7 @@ "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "optional": true + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "bcrypt-pbkdf": { "version": "1.0.2", @@ -434,7 +441,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "optional": true, "requires": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -445,7 +451,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "optional": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -476,7 +481,6 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "optional": true, "requires": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -606,9 +610,9 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -659,8 +663,7 @@ "chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "optional": true + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "clean-stack": { "version": "2.2.0", @@ -760,7 +763,6 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "optional": true, "requires": { "mimic-response": "^2.0.0" } @@ -836,8 +838,7 @@ "detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "optional": true + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" }, "diff": { "version": "5.0.0", @@ -905,7 +906,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "optional": true, "requires": { "once": "^1.4.0" } @@ -1348,8 +1348,7 @@ "expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "optional": true + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" }, "extend": { "version": "3.0.2", @@ -1491,8 +1490,7 @@ "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "optional": true + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "fs-minipass": { "version": "1.2.7", @@ -1570,8 +1568,7 @@ "github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", - "optional": true + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" }, "glob": { "version": "7.1.6", @@ -1750,8 +1747,7 @@ "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "optional": true + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "ignore": { "version": "4.0.6", @@ -2259,9 +2255,9 @@ "dev": true }, "js-yaml": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", - "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { "argparse": "^2.0.1" @@ -2308,8 +2304,7 @@ "mimic-response": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "optional": true + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" }, "mini-debounce": { "version": "1.0.8", @@ -2531,8 +2526,7 @@ "mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "optional": true + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" }, "mri": { "version": "1.1.6", @@ -2553,8 +2547,7 @@ "napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "optional": true + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" }, "napi-thread-safe-callback": { "version": "0.0.6", @@ -2596,10 +2589,9 @@ "dev": true }, "node-abi": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.21.0.tgz", - "integrity": "sha512-smhrivuPqEM3H5LmnY3KU6HfYv0u4QklgAxfFyRNujKUzbUcYZ+Jc2EhukB9SRcD2VpqhxM7n/MIcp1Ua1/JMg==", - "optional": true, + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.26.0.tgz", + "integrity": "sha512-ag/Vos/mXXpWLLAYWsAoQdgS+gW7IwvgMLOgqopm/DbzAjazLltzgzpVMsFlgmo9TzG5hGXeaBZx2AI731RIsQ==", "requires": { "semver": "^5.4.1" } @@ -2737,8 +2729,7 @@ "noop-logger": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", - "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=", - "optional": true + "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" }, "nopt": { "version": "4.0.3", @@ -2768,9 +2759,9 @@ "integrity": "sha512-9d1HbpKLh3sdWlhXMhU6MMH+wQzKkrgfRkYV0EBdvt99YJfj0ilCJrWRDYG2130Tm4GXbEoTCx5b34JSaP+HhA==" }, "npm-bundled": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", - "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", "requires": { "npm-normalize-package-bin": "^1.0.1" } @@ -3056,9 +3047,9 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.2.tgz", + "integrity": "sha512-gz58rdPpadwztRrPjZE9DZLOABUpTGdcANUgOwBFO1C+HZZhePoP83M65WGDmbpwFYJSWqavbl4SgDn4k8RYTA==", "dev": true }, "object-keys": { @@ -3395,7 +3386,6 @@ "version": "5.3.6", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.6.tgz", "integrity": "sha512-s8Aai8++QQGi4sSbs/M1Qku62PFK49Jm1CbgXklGz4nmHveDq0wzJkg7Na5QbnO1uNH8K7iqx2EQ/mV0MZEmOg==", - "optional": true, "requires": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", @@ -3456,7 +3446,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "optional": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -3743,14 +3732,12 @@ "simple-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "optional": true + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" }, "simple-get": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", - "optional": true, "requires": { "decompress-response": "^4.2.0", "once": "^1.3.1", @@ -3807,9 +3794,9 @@ "dev": true }, "snowpack": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/snowpack/-/snowpack-3.3.0.tgz", - "integrity": "sha512-LXoWtVQ9SGD7XhkFS9ixOoGO4eofJW/yj8gUYBopYhYIcOSeuokzJWkW0gF5M6pM7Vw9TMO8gK9KSfc2wAwTDw==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/snowpack/-/snowpack-3.3.5.tgz", + "integrity": "sha512-QI6/PcSud39ZAmrs7IiBSCr3PWXxc4/w2SNJp32+n7XsXxSB4waJ+jpG5rtJAeif5pqRNkX4887PKwWsMzFRCw==", "dev": true, "requires": { "cli-spinners": "^2.5.0", @@ -3825,9 +3812,9 @@ } }, "socks": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.0.tgz", - "integrity": "sha512-mNmr9owlinMplev0Wd7UHFlqI4ofnBnNzFuzrm63PPaHgbkqCFe4T5LzwKmtQ/f2tX0NTpcdVLyD/FHxFBstYw==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.1.tgz", + "integrity": "sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA==", "dev": true, "requires": { "ip": "^1.1.5", @@ -4008,9 +3995,9 @@ } }, "table": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.1.0.tgz", - "integrity": "sha512-T4G5KMmqIk6X87gLKWyU5exPpTjLjY5KyrFWaIjv3SvgaIUGXV7UEzGEnZJdTA38/yUS6f9PlKezQ0bYXG3iIQ==", + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/table/-/table-6.3.2.tgz", + "integrity": "sha512-I9/Ca6Huf2oxFag7crD0DhA+arIdfLtWunSn0NIXSzjtUlDgIBGVZY7SsMkNPNT3Psd/z4gza0nuEpmra9eRbg==", "dev": true, "requires": { "ajv": "^8.0.1", @@ -4095,7 +4082,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "optional": true, "requires": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -4107,7 +4093,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "optional": true, "requires": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -4120,7 +4105,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "optional": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -4263,7 +4247,6 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/usb/-/usb-1.7.0.tgz", "integrity": "sha512-LHm9d389NCzZSMd0DnilxT5Lord4P2E3ETwP1LeuJcEBmI5uLJv8Sd18z/9bairUMbDnnNqX+Hi5Xkl93Kvdmw==", - "optional": true, "requires": { "bindings": "^1.4.0", "node-addon-api": "3.0.2", @@ -4273,8 +4256,7 @@ "node-addon-api": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.2.tgz", - "integrity": "sha512-+D4s2HCnxPd5PjjI0STKwncjXTUKKqm74MDMz9OPXavjsGmjkvwgLtA5yoxJUdmpj52+2u+RrXgPipahKczMKg==", - "optional": true + "integrity": "sha512-+D4s2HCnxPd5PjjI0STKwncjXTUKKqm74MDMz9OPXavjsGmjkvwgLtA5yoxJUdmpj52+2u+RrXgPipahKczMKg==" } } }, @@ -4374,8 +4356,7 @@ "which-pm-runs": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", - "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", - "optional": true + "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=" }, "wide-align": { "version": "1.1.3", @@ -4397,9 +4378,9 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "ws": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", - "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==" + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", + "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==" }, "xpc-connect": { "version": "2.0.0", diff --git a/package.json b/package.json index beb9e91..3c4d4cb 100644 --- a/package.json +++ b/package.json @@ -26,13 +26,14 @@ "dependencies": { "@abandonware/bleno": "^0.5.1-4", "@abandonware/noble": "^1.9.2-13", + "ant-plus": "^0.1.24", "finalhandler": "^1.1.2", "http": "0.0.1-security", "loglevel": "^1.7.1", "nosleep.js": "^0.12.0", "onoff": "^6.0.2", "serve-static": "^1.14.1", - "ws": "^7.4.4" + "ws": "^7.4.5" }, "devDependencies": { "eslint": "^7.24.0", @@ -43,7 +44,7 @@ "husky": "^6.0.0", "markdownlint-cli": "^0.27.1", "npm-run-all": "^4.1.5", - "snowpack": "^3.3.0", + "snowpack": "^3.3.5", "uvu": "^0.5.1", "uvu-watch": "^1.0.11" }