diff --git a/app/ble/IndoorBikeDataCharacteristic.js b/app/ble/IndoorBikeDataCharacteristic.js index ef2a061..d61c993 100644 --- a/app/ble/IndoorBikeDataCharacteristic.js +++ b/app/ble/IndoorBikeDataCharacteristic.js @@ -87,8 +87,6 @@ export default class IndoorBikeDataCharacteristic extends bleno.Characteristic { buffer.writeUInt16LE(0xFF, 13) } this._updateValueCallback(buffer) - } else { - log.debug('can not notify indoor bike data, no central subscribed') } return this.RESULT_SUCCESS } diff --git a/app/ble/RowerDataCharacteristic.js b/app/ble/RowerDataCharacteristic.js index e2e154b..b825b95 100644 --- a/app/ble/RowerDataCharacteristic.js +++ b/app/ble/RowerDataCharacteristic.js @@ -85,8 +85,6 @@ export default class RowerDataCharacteristic extends bleno.Characteristic { buffer.writeUInt16LE(0xFF, 16) } this._updateValueCallback(buffer) - } else { - log.debug('can not notify rower data, no central subscribed') } return this.RESULT_SUCCESS } diff --git a/app/client/app.js b/app/client/app.js index b659059..4b9ef3b 100644 --- a/app/client/app.js +++ b/app/client/app.js @@ -7,32 +7,48 @@ */ // eslint-disable-next-line no-unused-vars export function createApp () { - // use the native websocket implementation of browser to communicate with backend - // eslint-disable-next-line no-undef - const socket = new WebSocket(`ws://${location.host}`) - const fields = ['strokesTotal', 'distanceTotal', 'caloriesTotal', 'power', 'splitFormatted', 'strokesPerMinute', 'durationTotal'] - socket.addEventListener('open', function (event) { - }) - - socket.addEventListener('message', function (event) { - try { - const data = JSON.parse(event.data) - - for (const [key, value] of Object.entries(data)) { - if (fields.includes(key)) { - document.getElementById(key).innerHTML = value - } - } - } catch (err) { - console.log(err) - } - }) - + initWebsocket() resetFields() requestWakeLock() + 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.addEventListener('open', (event) => { + console.log('websocket openend') + }) + + socket.addEventListener('error', (error) => { + console.log('websocket error', error) + socket.close() + }) + + socket.addEventListener('close', (event) => { + console.log('websocket closed, attempting reconnect') + setTimeout(() => { + initWebsocket() + }, 1000) + }) + + socket.addEventListener('message', (event) => { + try { + const data = JSON.parse(event.data) + + for (const [key, value] of Object.entries(data)) { + if (fields.includes(key)) { + document.getElementById(key).innerHTML = value + } + } + } catch (err) { + console.log(err) + } + }) + } + async function requestWakeLock () { // use the Wake Lock API to prevent the screen from going to standby if (!('wakeLock' in navigator)) { diff --git a/app/server.js b/app/server.js index 2d19972..cb2acca 100644 --- a/app/server.js +++ b/app/server.js @@ -21,7 +21,6 @@ import { createRowingStatistics } from './engine/RowingStatistics.js' // sets the global log level log.setLevel(log.levels.INFO) -let websocket // recordRowingSession('recordings/wrx700_2magnets.csv') const peripheral = createRowingMachinePeripheral({ simulateIndoorBike: true @@ -78,18 +77,14 @@ rowingStatistics.on('strokeFinished', (data) => { speed: data.speed } - if (websocket) { - websocket.send(JSON.stringify(metrics)) - } + notifyWebClients(metrics) peripheral.notifyData(metrics) }) rowingStatistics.on('durationUpdate', (data) => { - if (websocket) { - websocket.send(JSON.stringify({ - durationTotal: data.durationTotal - })) - } + notifyWebClients({ + durationTotal: data.durationTotal + }) }) const port = process.env.PORT || 80 @@ -104,7 +99,7 @@ server.listen(port) const wss = new WebSocket.Server({ server }) wss.on('connection', function connection (ws) { - websocket = ws + log.debug('websocket client connected') ws.on('message', function incoming (data) { try { const message = JSON.parse(data) @@ -118,18 +113,20 @@ wss.on('connection', function connection (ws) { log.error(err) } }) -/* - ws.send(JSON.stringify({ - strokesTotal: 15, - distanceTotal: 206, - caloriesTotal: 51, - power: 174, - split: '02:30', - strokesPerMinute: 14 - })) - */ + ws.on('close', function () { + log.debug('websocket client disconnected') + }) }) +function notifyWebClients (message) { + const messageString = JSON.stringify(message) + wss.clients.forEach(function each (client) { + if (client.readyState === WebSocket.OPEN) { + client.send(messageString) + } + }) +} + /* const readInterface = readline.createInterface({ input: fs.createReadStream('recordings/wrx700_2magnets.csv') @@ -149,14 +146,15 @@ let simCalories = 0.0 function simulateRowing () { const metrics = { strokesTotal: simStroke++, - distanceTotal: simDistance += 10.1, - caloriesTotal: simCalories += 0.3, - power: 80 + 20 * (Math.random() - 0.5), - splitFormatted: 160 + 20 * (Math.random() - 0.5), - split: 80 + 20 * (Math.random() - 0.5), - strokesPerMinute: 10 + 20 * (Math.random() - 0.5), - speed: (15 + 20 * (Math.random() - 0.5)).toFixed(2) + distanceTotal: Math.round(simDistance += 10.1), + caloriesTotal: Math.round(simCalories += 0.3), + power: Math.round(80 + 20 * (Math.random() - 0.5)), + splitFormatted: '02:30', + split: Math.round(80 + 20 * (Math.random() - 0.5)), + strokesPerMinute: Math.round(10 + 20 * (Math.random() - 0.5)), + speed: Math.round((15 + 20 * (Math.random() - 0.5)).toFixed(2)) } peripheral.notifyData(metrics) + notifyWebClients(metrics) } */ diff --git a/doc/backlog.md b/doc/backlog.md index 14ef6a0..e866579 100644 --- a/doc/backlog.md +++ b/doc/backlog.md @@ -4,7 +4,6 @@ This is the very minimalistic Backlog for further development of this project. ## Soon -* robust handling of websockets (reconnect, multiple connections) * handle training interruptions (set stroke specific metrics to "0" if no impulse detected for x seconds) * check todo markers in code and add them to this backlog * cleanup of the server.js start file