improves websocket connections

- enables multiple simultaneous websocket connections
- adds automatic reconnect on dropped websocket connection
This commit is contained in:
Lars Berning 2021-03-09 20:52:27 +00:00
parent 361e1c65f8
commit 197c714b03
5 changed files with 62 additions and 53 deletions

View File

@ -87,8 +87,6 @@ export default class IndoorBikeDataCharacteristic extends bleno.Characteristic {
buffer.writeUInt16LE(0xFF, 13) buffer.writeUInt16LE(0xFF, 13)
} }
this._updateValueCallback(buffer) this._updateValueCallback(buffer)
} else {
log.debug('can not notify indoor bike data, no central subscribed')
} }
return this.RESULT_SUCCESS return this.RESULT_SUCCESS
} }

View File

@ -85,8 +85,6 @@ export default class RowerDataCharacteristic extends bleno.Characteristic {
buffer.writeUInt16LE(0xFF, 16) buffer.writeUInt16LE(0xFF, 16)
} }
this._updateValueCallback(buffer) this._updateValueCallback(buffer)
} else {
log.debug('can not notify rower data, no central subscribed')
} }
return this.RESULT_SUCCESS return this.RESULT_SUCCESS
} }

View File

@ -7,32 +7,48 @@
*/ */
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
export function createApp () { 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'] const fields = ['strokesTotal', 'distanceTotal', 'caloriesTotal', 'power', 'splitFormatted', 'strokesPerMinute', 'durationTotal']
socket.addEventListener('open', function (event) { initWebsocket()
})
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)
}
})
resetFields() resetFields()
requestWakeLock() 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 () { async function requestWakeLock () {
// use the Wake Lock API to prevent the screen from going to standby // use the Wake Lock API to prevent the screen from going to standby
if (!('wakeLock' in navigator)) { if (!('wakeLock' in navigator)) {

View File

@ -21,7 +21,6 @@ import { createRowingStatistics } from './engine/RowingStatistics.js'
// sets the global log level // sets the global log level
log.setLevel(log.levels.INFO) log.setLevel(log.levels.INFO)
let websocket
// recordRowingSession('recordings/wrx700_2magnets.csv') // recordRowingSession('recordings/wrx700_2magnets.csv')
const peripheral = createRowingMachinePeripheral({ const peripheral = createRowingMachinePeripheral({
simulateIndoorBike: true simulateIndoorBike: true
@ -78,18 +77,14 @@ rowingStatistics.on('strokeFinished', (data) => {
speed: data.speed speed: data.speed
} }
if (websocket) { notifyWebClients(metrics)
websocket.send(JSON.stringify(metrics))
}
peripheral.notifyData(metrics) peripheral.notifyData(metrics)
}) })
rowingStatistics.on('durationUpdate', (data) => { rowingStatistics.on('durationUpdate', (data) => {
if (websocket) { notifyWebClients({
websocket.send(JSON.stringify({ durationTotal: data.durationTotal
durationTotal: data.durationTotal })
}))
}
}) })
const port = process.env.PORT || 80 const port = process.env.PORT || 80
@ -104,7 +99,7 @@ server.listen(port)
const wss = new WebSocket.Server({ server }) const wss = new WebSocket.Server({ server })
wss.on('connection', function connection (ws) { wss.on('connection', function connection (ws) {
websocket = ws log.debug('websocket client connected')
ws.on('message', function incoming (data) { ws.on('message', function incoming (data) {
try { try {
const message = JSON.parse(data) const message = JSON.parse(data)
@ -118,18 +113,20 @@ wss.on('connection', function connection (ws) {
log.error(err) log.error(err)
} }
}) })
/* ws.on('close', function () {
ws.send(JSON.stringify({ log.debug('websocket client disconnected')
strokesTotal: 15, })
distanceTotal: 206,
caloriesTotal: 51,
power: 174,
split: '02:30',
strokesPerMinute: 14
}))
*/
}) })
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({ const readInterface = readline.createInterface({
input: fs.createReadStream('recordings/wrx700_2magnets.csv') input: fs.createReadStream('recordings/wrx700_2magnets.csv')
@ -149,14 +146,15 @@ let simCalories = 0.0
function simulateRowing () { function simulateRowing () {
const metrics = { const metrics = {
strokesTotal: simStroke++, strokesTotal: simStroke++,
distanceTotal: simDistance += 10.1, distanceTotal: Math.round(simDistance += 10.1),
caloriesTotal: simCalories += 0.3, caloriesTotal: Math.round(simCalories += 0.3),
power: 80 + 20 * (Math.random() - 0.5), power: Math.round(80 + 20 * (Math.random() - 0.5)),
splitFormatted: 160 + 20 * (Math.random() - 0.5), splitFormatted: '02:30',
split: 80 + 20 * (Math.random() - 0.5), split: Math.round(80 + 20 * (Math.random() - 0.5)),
strokesPerMinute: 10 + 20 * (Math.random() - 0.5), strokesPerMinute: Math.round(10 + 20 * (Math.random() - 0.5)),
speed: (15 + 20 * (Math.random() - 0.5)).toFixed(2) speed: Math.round((15 + 20 * (Math.random() - 0.5)).toFixed(2))
} }
peripheral.notifyData(metrics) peripheral.notifyData(metrics)
notifyWebClients(metrics)
} }
*/ */

View File

@ -4,7 +4,6 @@ This is the very minimalistic Backlog for further development of this project.
## Soon ## Soon
* robust handling of websockets (reconnect, multiple connections)
* handle training interruptions (set stroke specific metrics to "0" if no impulse detected for x seconds) * 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 * check todo markers in code and add them to this backlog
* cleanup of the server.js start file * cleanup of the server.js start file