adds linting pre commit hook, cleans documentation

This commit is contained in:
Lars Berning 2021-03-13 19:20:36 +00:00
parent 3d08f06336
commit 6c5c1b8cb8
13 changed files with 184 additions and 25 deletions

4
.gitignore vendored
View File

@ -70,7 +70,9 @@ fabric.properties
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
.vscode
node_modules
.DS_Store
._*
tmp/
tmp/

1
.husky/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
_

4
.husky/pre-commit Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint

4
.markdownlint.json Normal file
View File

@ -0,0 +1,4 @@
{
"default": true,
"MD013": false
}

View File

@ -27,7 +27,7 @@ Open Rowing Monitor implements a physics model to simulate the typical metrics o
### Web Interface
The web interface visualizes the rowing metrics on any device that can run a browser (i.e. a smartphone that you attach to your rowing machine while training). It uses websockets to show the rowing status in realtime. Besides that it does not do much (yet).
The web interface visualizes the rowing metrics on any device that can run a browser (i.e. a smartphone that you attach to your rowing machine while training). It uses websockets to show the rowing status in Realtime. Besides that it does not do much (yet).
<!-- markdownlint-disable-next-line no-inline-html -->
<img src="doc/img/openrowingmonitor_frontend.png" width="700"><br clear="left">
@ -46,7 +46,7 @@ FTMS supports different types of fitness machines. Open Rowing Monitor currently
I originally started this project, because my rowing machine (Sportstech WRX700) has a very simple computer and I wanted to build something with a clean and simple interface that calculates more realistic metrics. Also, this was a good reason to learn a bit more about Bluetooth and all its specifics.
The original proof of concept version started as a sketch on an ardunio, but when I started adding things like a web frontend and BLE I moved it to the much more powerful Raspberry Pi. Maybe using a Raspi for this small IoT-project is a bit of an overkill, but it has the capacity for further features such as syncing training data or rowing games. And it has USB-Ports that I can use to charge my phone while rowing :-)
The original proof of concept version started as a sketch on an Arduino, but when I started adding things like a web frontend and BLE I moved it to the much more powerful Raspberry Pi. Maybe using a Raspberry Pi for this small IoT-project is a bit of an overkill, but it has the capacity for further features such as syncing training data or rowing games. And it has USB-Ports that I can use to charge my phone while rowing :-)
## Further information

View File

@ -50,7 +50,6 @@ function createRowingMachinePeripheral (options) {
bleno.on('accept', (clientAddress) => {
log.debug(`ble central connected: ${clientAddress}`)
// todo: do we need this?
bleno.updateRssi()
})

View File

@ -8,6 +8,7 @@
// eslint-disable-next-line no-unused-vars
export function createApp () {
const fields = ['strokesTotal', 'distanceTotal', 'caloriesTotal', 'power', 'splitFormatted', 'strokesPerMinute', 'durationTotal']
let socket
initWebsocket()
resetFields()
@ -16,7 +17,7 @@ export function createApp () {
function initWebsocket () {
// use the native websocket implementation of browser to communicate with backend
// eslint-disable-next-line no-undef
const socket = new WebSocket(`ws://${location.host}`)
socket = new WebSocket(`ws://${location.host}`)
socket.addEventListener('open', (event) => {
console.log('websocket openend')
@ -96,7 +97,7 @@ export function createApp () {
function reset () {
resetFields()
socket.send(JSON.stringify({ command: 'reset' }))
if (socket)socket.send(JSON.stringify({ command: 'reset' }))
}
return {

View File

@ -22,7 +22,7 @@ import { recordRowingSession, replayRowingSession } from './tools/RowingRecorder
log.setLevel(log.levels.INFO)
const peripheral = createRowingMachinePeripheral({
simulateIndoorBike: true
simulateIndoorBike: false
})
peripheral.on('controlPoint', (event) => {

View File

@ -1,6 +1,6 @@
# Attribution
Open Rowing Monitor uses some great work by others. Thank you for all the great ressources that helped me to make this project possible. I especially would like to thank:
Open Rowing Monitor uses some great work by others. Thank you for all the great resources that helped me to make this project possible. I especially would like to thank:
* A lot of helpful information for building the physics engine of the rowing machine was found in this scientific work by Anu Dudhia: [The Physics of Ergometers](http://eodg.atm.ox.ac.uk/user/dudhia/rowing/physics/ergometer.html).
@ -8,4 +8,4 @@ Open Rowing Monitor uses some great work by others. Thank you for all the great
* The app icon is based on this [image of a rowing machine](https://thenounproject.com/term/rowing-machine/659265) by [Gan Khoon Lay](https://thenounproject.com/leremy/) licensed under [CC BY 2.0](https://creativecommons.org/licenses/by/2.0/).
* Bluetooth is quite a complex biest, luckily the Bluetooth SIG releases all the [specifications here](https://www.bluetooth.com/specifications/specs)
* Bluetooth is quite a complex beast, luckily the Bluetooth SIG releases all the [specifications here](https://www.bluetooth.com/specifications/specs)

View File

@ -4,17 +4,21 @@ This is the very minimalistic Backlog for further development of this project.
## Soon
* check todo markers in code and add them to this backlog
* cleanup of the server.js start file
* figure out where to set the Service Advertising Data (FTMS.pdf p 15)
* Web UI: replace fullscreen button with exit Button when started from homescreen
* Web UI: replace fullscreen button with exit Button when started from home screen
* investigate bug: crash, when one unsubscribe to BLE "Generic Attribute", probably a bleno bug "handleAttribute.emit is not a function"
* set up a raspi with the installation instructions to see if they are correct
* add photo of wired device to installation instructions
* what value should we use for split, if we are in a rowing pause? technically should be infinity...
* set up a Raspberry Pi with the installation instructions to see if they are correct
## Later
* implement the proprietary Concept2 PM BLE protocol as described here [Concept2 PM Bluetooth Smart Communication Interface](https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf)
* add some attributes to BLE DeviceInformationService
* add a config file
* presets for rowing machine specific config parameters
* improve the physics model for waterrowers
* validate FTMS with more training applications and harden implementation
* make Web UI a proper Web Application (tooling and SPA framework)
* record the workout and show a visual graph of metrics
@ -26,3 +30,4 @@ This is the very minimalistic Backlog for further development of this project.
* add video playback in background of Web UI
* implement or integrate some rowing games
* add possibility to define workouts (i.e. training intervals with goals)
* directly attach a touchscreen to the Raspberry Pi and automatically show WebUI on this in kiosk mode

View File

@ -7,9 +7,9 @@ This guide roughly explains how to set up your device. I will probably build an
* A Raspberry Pi that supports Bluetooth Low Energy (Pi 3 or Pi 4). Probably this also runs on other devices.
* An SD Card, any size above 4GB should be fine
* A rowing machine (obviously) with some way to measure the rotation of the flywheel
* the WRX700 has a build in reed sensor that I can directly connect to the GPIO pins of the raspi
* the WRX700 has a build in reed sensor that I can directly connect to the GPIO pins of the Raspberry Pi
* if your machine doesn't have a sensor, it should be easy to build something similar (magnetically or optical)
* Some dupont wires to connect the GPIO pins to the sensor
* Some Dupont cables to connect the GPIO pins to the sensor
## Software Installation
@ -79,11 +79,11 @@ WantedBy=multi-user.target
## Hardware Installation
Basically all thats left to do is hook up your reed sensor to the GPIO pins of the Raspberry Pi.
Basically all that's left to do is hook up your reed sensor to the GPIO pins of the Raspberry Pi.
todo: add a photo of the wired device
Open Rowing Monitor reads the sensor signal from GPIO port 17 and expects it to pull on GND if the sensor is closed. To get a stable reading you should add a pull-up resistor to that pin. I prefer to use the internal resitor of the raspi to keep the wiring simple but of course you can also go with an external circuit.
Open Rowing Monitor reads the sensor signal from GPIO port 17 and expects it to pull on GND if the sensor is closed. To get a stable reading you should add a pull-up resistor to that pin. I prefer to use the internal resistor of the Raspberry Pi to keep the wiring simple but of course you can also go with an external circuit.
The internal pull-up can be enabled as described [here](https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md). So its as simple as adding the following to `/boot/config.txt` and then rebooting the device.

154
package-lock.json generated
View File

@ -441,6 +441,12 @@
"delayed-stream": "~1.0.0"
}
},
"commander": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.1.0.tgz",
"integrity": "sha512-pRxBna3MJe6HKnBGsDyMv8ETbptw3axEdYHoqNh7gu5oDcew8fs0xnivZGm06Ogk8zGAJ9VX+OPEr2GXEQK4dg==",
"dev": true
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -515,8 +521,7 @@
"deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"optional": true
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
},
"deep-is": {
"version": "0.1.3",
@ -614,6 +619,12 @@
"ansi-colors": "^4.1.1"
}
},
"entities": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
"integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
"dev": true
},
"epoll": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/epoll/-/epoll-4.0.0.tgz",
@ -1220,6 +1231,12 @@
"has-symbols": "^1.0.1"
}
},
"get-stdin": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz",
"integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==",
"dev": true
},
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
@ -1348,6 +1365,12 @@
"sshpk": "^1.7.0"
}
},
"husky": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/husky/-/husky-5.1.3.tgz",
"integrity": "sha512-fbNJ+Gz5wx2LIBtMweJNY1D7Uc8p1XERi5KNRMccwfQA+rXlxWNSdUxswo0gT8XqxywTIw7Ywm/F4v/O35RdMg==",
"dev": true
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@ -1411,8 +1434,7 @@
"ini": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
"optional": true
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
},
"is-arrayish": {
"version": "0.2.1",
@ -1572,6 +1594,12 @@
"minimist": "^1.2.0"
}
},
"jsonc-parser": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz",
"integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==",
"dev": true
},
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
@ -1594,6 +1622,15 @@
"type-check": "~0.4.0"
}
},
"linkify-it": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.2.tgz",
"integrity": "sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ==",
"dev": true,
"requires": {
"uc.micro": "^1.0.1"
}
},
"load-json-file": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
@ -1627,6 +1664,18 @@
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
},
"lodash.differencewith": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.differencewith/-/lodash.differencewith-4.5.0.tgz",
"integrity": "sha1-uvr7yRi1UVTheRdqALsK76rIVLc=",
"dev": true
},
"lodash.flatten": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
"integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=",
"dev": true
},
"loglevel": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz",
@ -1649,6 +1698,93 @@
}
}
},
"markdown-it": {
"version": "12.0.4",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.0.4.tgz",
"integrity": "sha512-34RwOXZT8kyuOJy25oJNJoulO8L0bTHYWXcdZBYZqFnjIy3NgjeoM3FmPXIOFQ26/lSHYMr8oc62B6adxXcb3Q==",
"dev": true,
"requires": {
"argparse": "^2.0.1",
"entities": "~2.1.0",
"linkify-it": "^3.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
},
"dependencies": {
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
}
}
},
"markdownlint": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.23.1.tgz",
"integrity": "sha512-iOEwhDfNmq2IJlaA8mzEkHYUi/Hwoa6Ss+HO5jkwUR6wQ4quFr0WzSx+Z9rsWZKUaPbyirIdL1zGmJRkWawr4Q==",
"dev": true,
"requires": {
"markdown-it": "12.0.4"
}
},
"markdownlint-cli": {
"version": "0.27.1",
"resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.27.1.tgz",
"integrity": "sha512-p1VV6aSbGrDlpUWzHizAnSNEQAweVR3qUI/AIUubxW7BGPXziSXkIED+uRtSohUlRS/jmqp3Wi4es5j6fIrdeQ==",
"dev": true,
"requires": {
"commander": "~7.1.0",
"deep-extend": "~0.6.0",
"get-stdin": "~8.0.0",
"glob": "~7.1.6",
"ignore": "~5.1.8",
"js-yaml": "^4.0.0",
"jsonc-parser": "~3.0.0",
"lodash.differencewith": "~4.5.0",
"lodash.flatten": "~4.4.0",
"markdownlint": "~0.23.1",
"markdownlint-rule-helpers": "~0.14.0",
"minimatch": "~3.0.4",
"minimist": "~1.2.5",
"rc": "~1.2.8"
},
"dependencies": {
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
"ignore": {
"version": "5.1.8",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
"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==",
"dev": true,
"requires": {
"argparse": "^2.0.1"
}
}
}
},
"markdownlint-rule-helpers": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/markdownlint-rule-helpers/-/markdownlint-rule-helpers-0.14.0.tgz",
"integrity": "sha512-vRTPqSU4JK8vVXmjICHSBhwXUvbfh/VJo+j7hvxqe15tLJyomv3FLgFdFgb8kpj0Fe8SsJa/TZUAXv7/sN+N7A==",
"dev": true
},
"mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
"dev": true
},
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
@ -2209,7 +2345,6 @@
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"optional": true,
"requires": {
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
@ -2604,8 +2739,7 @@
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"optional": true
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
},
"supports-color": {
"version": "5.5.0",
@ -2796,6 +2930,12 @@
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true
},
"uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
"dev": true
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",

View File

@ -14,7 +14,8 @@
"node": ">=12"
},
"scripts": {
"eslint": "eslint ./app",
"prepare": "husky install",
"lint": "eslint ./app && markdownlint '**/*.md' --ignore node_modules",
"start": "node app/server.js",
"test": ""
},
@ -32,6 +33,8 @@
"eslint-config-standard": "^16.0.2",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.3.1"
"eslint-plugin-promise": "^4.3.1",
"husky": "^5.1.3",
"markdownlint-cli": "^0.27.1"
}
}