117 lines
3.7 KiB
JavaScript
117 lines
3.7 KiB
JavaScript
'use strict'
|
|
/*
|
|
Open Rowing Monitor, https://github.com/laberning/openrowingmonitor
|
|
|
|
Initialization file of the Open Rowing Monitor App
|
|
*/
|
|
|
|
import NoSleep from 'nosleep.js'
|
|
import { filterObjectByKeys } from './helper.js'
|
|
|
|
const rowingMetricsFields = ['strokesTotal', 'distanceTotal', 'caloriesTotal', 'power', 'heartrate',
|
|
'heartrateBatteryLevel', 'splitFormatted', 'strokesPerMinute', 'durationTotalFormatted']
|
|
|
|
export function createApp (app) {
|
|
const mode = window.location.hash
|
|
const appMode = mode === '#:standalone:' ? 'STANDALONE' : mode === '#:kiosk:' ? 'KIOSK' : 'BROWSER'
|
|
app.updateState({ ...app.getState(), appMode })
|
|
|
|
let socket
|
|
|
|
initWebsocket()
|
|
resetFields()
|
|
requestWakeLock()
|
|
|
|
function initWebsocket () {
|
|
// use the native websocket implementation of browser to communicate with backend
|
|
// eslint-disable-next-line no-undef
|
|
socket = new WebSocket(`ws://${location.host}/websocket`)
|
|
|
|
socket.addEventListener('open', (event) => {
|
|
console.log('websocket opened')
|
|
})
|
|
|
|
socket.addEventListener('error', (error) => {
|
|
console.log('websocket error', error)
|
|
socket.close()
|
|
})
|
|
|
|
socket.addEventListener('close', (event) => {
|
|
console.log('websocket closed, attempting reconnect')
|
|
setTimeout(() => {
|
|
initWebsocket()
|
|
}, 1000)
|
|
})
|
|
|
|
// todo: we should use different types of messages to make processing easier
|
|
socket.addEventListener('message', (event) => {
|
|
try {
|
|
const data = JSON.parse(event.data)
|
|
|
|
let activeFields = rowingMetricsFields
|
|
// if we are in reset state only update heart rate
|
|
if (data.strokesTotal === 0) {
|
|
activeFields = ['heartrate', 'heartrateBatteryLevel']
|
|
}
|
|
|
|
const filteredData = filterObjectByKeys(data, activeFields)
|
|
|
|
let updatedState = { ...app.getState(), metrics: filteredData }
|
|
if (data.peripheralMode) {
|
|
updatedState = { ...app.getState(), peripheralMode: data.peripheralMode }
|
|
}
|
|
app.updateState(updatedState)
|
|
} catch (err) {
|
|
console.log(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
async function requestWakeLock () {
|
|
// Chrome enables the new Wake Lock API only if the connection is secured via SSL
|
|
// This is quite annoying for IoT use cases like this one, where the device sits on the
|
|
// local network and is directly addressed by its IP.
|
|
// In this case the only way of using SSL is by creating a self signed certificate, and
|
|
// that would pop up different warnings in the browser (and also prevents fullscreen via
|
|
// a home screen icon so it can show these warnings). Okay, enough ranting :-)
|
|
// In this case we use the good old hacky way of keeping the screen on via a hidden video.
|
|
const noSleep = new NoSleep()
|
|
document.addEventListener('click', function enableNoSleep () {
|
|
document.removeEventListener('click', enableNoSleep, false)
|
|
noSleep.enable()
|
|
}, false)
|
|
}
|
|
|
|
function resetFields () {
|
|
const appState = app.getState()
|
|
// drop all metrics except heartrate
|
|
appState.metrics = filterObjectByKeys(appState.metrics, ['heartrate', 'heartrateBatteryLevel'])
|
|
app.updateState(appState)
|
|
}
|
|
|
|
function handleAction (action) {
|
|
switch (action.command) {
|
|
case 'switchPeripheralMode': {
|
|
if (socket)socket.send(JSON.stringify({ command: 'switchPeripheralMode' }))
|
|
break
|
|
}
|
|
case 'reset': {
|
|
resetFields()
|
|
if (socket)socket.send(JSON.stringify({ command: 'reset' }))
|
|
break
|
|
}
|
|
case 'uploadTraining': {
|
|
if (socket)socket.send(JSON.stringify({ command: 'uploadTraining' }))
|
|
break
|
|
}
|
|
default: {
|
|
console.error('no handler defined for action', action)
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
handleAction
|
|
}
|
|
}
|