new device communication & analysis

- switched to websockets
- analysis as pure function with internal hidden cache
- new redux reducers
This commit is contained in:
Martin Bauer
2020-06-28 18:55:58 +02:00
parent 00be9e1db2
commit fa1518546b
12 changed files with 336 additions and 169 deletions

View File

@@ -0,0 +1,66 @@
import { PeakDetectorSimple } from './PeakDetection';
import { List } from 'immutable';
export default class DataAnalysis {
constructor() {
this._resetCache(null, 0);
}
analyze(analysisParameters, sessionId, allMeasurements) {
const cacheValid = (
this.sessionId === sessionId &&
this.analyzedUpToIdx <= allMeasurements.size &&
this.analysisParameters === analysisParameters);
let newData = null;
if (cacheValid) {
newData = allMeasurements.slice(this.analyzedUpToIdx);
}
else {
this._resetCache(analysisParameters, sessionId);
newData = allMeasurements;
}
// peaks
const newPeaks = this.peakDetectorSimple.addVector(newData);
this.allPeaks = this.allPeaks.concat(List(newPeaks));
// aggregated sum/max
this.aggregatedMomentum = newData.reduce((sum, x) => sum + x, this.aggregatedMomentum);
this.peakMax = newData.reduce((running, x) => Math.max(x, running), this.peakMax);
// windowed
const windowNumDataPoints = analysisParameters.windowSizeInSecs * analysisParameters.numMeasurementsPerSec;
const windowed = allMeasurements.slice(-windowNumDataPoints);
const peakMaxWindow = windowed.reduce((running, x) => Math.max(x, running), 0);
const momentumWindow = windowed.reduce((sum, x) => sum + x, 0);
this.analyzedUpToIdx = allMeasurements.size;
return {
peaks: this.allPeaks,
totalTime: allMeasurements / analysisParameters.numMeasurementsPerSec,
totalMomentum: this.aggregatedMomentum / allMeasurements.size,
peakMax: this.peakMax,
momentumWindow: momentumWindow,
peakMaxWindow: peakMaxWindow,
};
}
_resetCache(analysisParameters, sessionId) {
this.peakDetectorSimple = analysisParameters ? new PeakDetectorSimple(analysisParameters.peakDetectorSimpleThreshold) : null;
this.allPeaks = List();
this.aggregatedMomentum = 0;
this.peakMax = 0;
this.sessionId = sessionId;
this.analyzedUpToIdx = 0;
this.analysisParameters = analysisParameters;
}
};

View File

@@ -0,0 +1,84 @@
import ReconnectingWebSocket from 'reconnecting-websocket';
const OpCodes = {
// from device to frontend
INITIAL_INFO: 1,
SESSION_STARTED: 2,
SESSION_STOPPED: 3,
SESSION_NEW_DATA: 4,
// from frontend to device
START_SESSION: 5,
STOP_SESSION: 6,
TARE: 7
};
export default class SwimTrackerWebsocketConnection {
constructor(swimTrackerHost, onData, onStarted, onStopped, onConnect, onDisconnect) {
this.swimTrackerHost = swimTrackerHost;
this.onData = onData;
this.onStarted = onStarted;
this.onStopped = onStopped;
this.onConnect = onConnect;
this.onDisconnect = onDisconnect;
const wsOptions = {
maxReconnectionDelay: 4000
};
this.ws = new ReconnectingWebSocket(`ws://${swimTrackerHost}:81`, [], wsOptions);
this.ws.onmessage = this._onMessage;
this.ws.onopen = this.onConnect;
this.ws.onclose = this.onDisconnect;
this.ws.onerror = this._onError;
this.ws.binaryType = 'arraybuffer';
}
sendStartCommand() {
const data = new Uint8Array(1);
data[0] = OpCodes.START_SESSION;
this.ws.send(data);
}
sendStopCommand() {
const data = new Uint8Array(1);
data[0] = OpCodes.STOP_SESSION;
this.ws.send(data);
}
sendTareCommand() {
const data = new Uint8Array(1);
data[0] = OpCodes.TARE;
this.ws.send(data);
}
_onMessage = (e) => {
const dv = new DataView(e.data);
const opCode = dv.getInt8(0);
if (opCode === OpCodes.INITIAL_INFO) {
const headerSize = 6;
const running = Boolean(dv.getInt8(1));
const sessionId = dv.getUint32(2);
if (running && e.data.byteLength > headerSize) {
const data = new Uint16Array(e.data.slice(headerSize));
this.onStarted(sessionId);
this.onData(data);
} else
this.onStopped();
} else if (opCode === OpCodes.SESSION_STARTED) {
const sessionId = dv.getUint32(1);
this.onStarted(sessionId);
} else if (opCode === OpCodes.SESSION_STOPPED) {
this.onStopped();
} else if (opCode === OpCodes.SESSION_NEW_DATA) {
const data = new Uint16Array(e.data.slice(1));
this.onData(data);
}
}
_onError = (ev) => {
console.log("Websocket error", ev);
}
};