import SwimTrackerWebsocketConnection from "../data_processing/SwimTrackerWebsocketConnection"; import DataAnalysis from "../data_processing/DataAnalysis"; import { List } from "immutable"; export const ConnState = { DISCONNECTED: 'disconnected', CONNECTED_STOPPED: 'connected_stopped', CONNECTED_RUNNING: 'connected_running', CONNECTED_STARTING: 'connected_starting', // start message sent, but device hasn't ack'ed it yet CONNECTED_STOPPING: 'connected_stopping' // stop message sent.. } // -------------------------------------------- Actions --------------------------------------------- export const DEVICE_DISCONNECT = "DEVICE_DISCONNECT"; export const DEVICE_CONNECT = "DEVICE_CONNECT"; export const SESSION_STARTED = "SESSION_STARTED"; export const SESSION_STOPPED = "SESSION_STOPPED"; export const SESSION_NEW_DATA = "SESSION_NEW_DATA"; export const START_SESSION = "START_SESSION"; export const STOP_SESSION = "STOP_SESSION"; export const reportSessionStarted = (sessionId) => ({ type: SESSION_STARTED, sessionId: sessionId }); export const reportSessionStopped = () => ({ type: SESSION_STOPPED }); export const reportNewSessionData = (allMeasurements, analysis) => ({ type: SESSION_NEW_DATA, data: allMeasurements, analysis: analysis }); export const reportDeviceConnect = () => ({ type: DEVICE_CONNECT }); export const reportDeviceDisconnect = () => ({ type: DEVICE_DISCONNECT }); export const startSession = () => ({ type: START_SESSION }); export const stopSession = () => ({ type: STOP_SESSION }); // -------------------------------------------- Device coupling ------------------------------------- export class DeviceReduxCoupling { constructor(reduxStore) { this.reduxStore = reduxStore; this.analysis = new DataAnalysis(); this.conn = null; this.reduxStore.subscribe(this._onStateChange); this._onStateChange(); } _onStateChange = () => { const state = this.reduxStore.getState(); if (this.conn === null || (state.settings.swimTrackerHost != this.conn.swimTrackerHost)) { this.conn = new SwimTrackerWebsocketConnection(state.settings.swimTrackerHost, this._onNewData, (sessionId) => this.reduxStore.dispatch(reportSessionStarted(sessionId)), () => this.reduxStore.dispatch(reportSessionStopped()), () => this.reduxStore.dispatch(reportDeviceConnect()), () => this.reduxStore.dispatch(reportDeviceDisconnect()) ); } if (state.deviceState.connState === ConnState.CONNECTED_STARTING) { console.log("sending start command to connection"); this.conn.sendStartCommand(); } else if (state.deviceState.connState === ConnState.CONNECTED_STOPPING) this.conn.sendStopCommand(); } _onNewData = (newData) => { const state = this.reduxStore.getState(); const allMeasurements = state.deviceState.measurements.concat(List(newData)); const analysisResult = this.analysis.analyze(state.settings.analysis, state.deviceState.sessionId, allMeasurements); this.reduxStore.dispatch(reportNewSessionData(allMeasurements, analysisResult)); } }; // -------------------------------------------- Reducer ----------------------------------------------- const INITIAL_ANALYSIS = { 'peaks': List(), 'totalTime': null, 'totalMomentum': null, 'peakMax': null, 'momentumWindow': null, 'peakMaxWindow': null, }; const INITIAL_DEVICE_STATE = { connState: ConnState.DISCONNECTED, sessionId: 0, measurements: List(), analysis: INITIAL_ANALYSIS, }; export const deviceStateReducer = (state = INITIAL_DEVICE_STATE, action) => { switch (action.type) { case SESSION_NEW_DATA: const res = { ...state, measurements: action.data, analysis: { ...state.analysis, ...action.analysis } }; return res; case DEVICE_CONNECT: return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPED }; case DEVICE_DISCONNECT: return { ...INITIAL_DEVICE_STATE, connState: ConnState.DISCONNECTED }; case SESSION_STARTED: return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_RUNNING, sessionId: action.sessionId }; case SESSION_STOPPED: return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPED }; case START_SESSION: if(state.connState === ConnState.SESSION_STARTED) return state; return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STARTING }; case STOP_SESSION: if(state.connState === ConnState.SESSION_STOPPED) return state; return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPING }; default: console.log("Unhandled state in deviceStateReducer", action.type); return state } };