From a6db96ef2999a5e557e98d01e5e2122a8c3c5333 Mon Sep 17 00:00:00 2001 From: Martin Bauer Date: Sun, 6 Jun 2021 21:31:41 +0200 Subject: [PATCH] started with functionality in wifi selection --- App.js | 19 ++- .../SwimTrackerWebsocketConnection.js | 72 +++++++++--- state/DeviceReduxCoupling.js | 31 ++++- state/Reducer.js | 2 +- views/WifiPasswordView.js | 1 + views/WifiSelectionView.js | 109 ++++++++++++++---- 6 files changed, 187 insertions(+), 47 deletions(-) diff --git a/App.js b/App.js index 72b7ad0..2980ba1 100644 --- a/App.js +++ b/App.js @@ -63,25 +63,31 @@ export default class App extends React.Component { const screenOptions = { headerShown: false, }; - - /* + + return ( } persistor={persistor}> - + + + {props => } + + component={WifiPasswordView} + > + ); - */ + /* return ( } persistor={persistor}> @@ -112,6 +118,7 @@ export default class App extends React.Component { ); + */ } } diff --git a/data_processing/SwimTrackerWebsocketConnection.js b/data_processing/SwimTrackerWebsocketConnection.js index 37e8185..9a71a10 100644 --- a/data_processing/SwimTrackerWebsocketConnection.js +++ b/data_processing/SwimTrackerWebsocketConnection.js @@ -1,22 +1,32 @@ import ReconnectingWebSocket from 'reconnecting-websocket'; +import * as msgpack from 'msgpack-lite'; + const OpCodes = { - // from device to frontend - INITIAL_INFO: 1, - SESSION_STARTED: 2, - SESSION_STOPPED: 3, - SESSION_NEW_DATA: 4, - ANSWER_USER_LIST : 5, - ANSWER_SESSION_LIST : 6, - + // from swim tracker device to frontend + ERROR: 1, + + INITIAL_INFO: 2, + SESSION_STARTED: 3, + SESSION_STOPPED: 4, + SESSION_NEW_DATA: 5, + ANSWER_USER_LIST: 6, + ANSWER_SESSION_LIST: 7, + WIFI_STATE_RESPONSE: 8, + WIFI_SCAN_RESPONSE: 9, + // from frontend to device - START_SESSION: 7, - STOP_SESSION: 8, - TARE: 9, - QUERY_USER_LIST: 10, - QUERY_SESSION_LIST: 11 + START_SESSION: 128, + STOP_SESSION: 129, + TARE: 130, + QUERY_USER_LIST: 131, + QUERY_SESSION_LIST: 132, + WIFI_STATE_SET: 133, + WIFI_STATE_GET: 134, + WIFI_TRIGGER_SCAN: 135, }; + export default class SwimTrackerWebsocketConnection { constructor(swimTrackerHost, onData, onStarted, onStopped, onConnect, onDisconnect) { this.swimTrackerHost = swimTrackerHost; @@ -36,6 +46,15 @@ export default class SwimTrackerWebsocketConnection { this.ws.onclose = this.onDisconnect; this.ws.onerror = this._onError; this.ws.binaryType = 'arraybuffer'; + + this.msgpackCodec = msgpack.createCodec(); + this.msgpackCodec.addExtUnpacker(205, function (byteArr) { + const buffer = byteArr.buffer.slice(byteArr.byteOffset, byteArr.byteLength + byteArr.byteOffset); + const result = new Int16Array(buffer); + return result; + }); + + this._wifiScanPromise = null; } sendStartCommand() { @@ -56,6 +75,24 @@ export default class SwimTrackerWebsocketConnection { this.ws.send(data); } + scanWifiNetworks() { + // trigger scan + const data = new Uint8Array(1); + data[0] = OpCodes.WIFI_TRIGGER_SCAN; + this.ws.send(data); + + if (this._wifiScanPromise !== null) { + return Promise.reject("Scan in progress"); + } + else { + + let conn = this; + return new Promise((resolve, reject) => { + conn._wifiScanPromise = { resolve: resolve, reject: reject }; + }); + } + } + _onMessage = (e) => { const dv = new DataView(e.data); const opCode = dv.getInt8(0); @@ -78,6 +115,15 @@ export default class SwimTrackerWebsocketConnection { } else if (opCode === OpCodes.SESSION_NEW_DATA) { const data = new Uint16Array(e.data.slice(1)); this.onData(data); + } else if (opCode === OpCodes.WIFI_SCAN_RESPONSE) { + console.log("got data", e.data); + const scanResult = msgpack.decode(new Uint8Array(e.data).slice(1), { codec: this.msgpackCodec }); + if (this._wifiScanPromise !== null) { + this._wifiScanPromise.resolve(scanResult); + this._wifiScanPromise = null; + } else { + console.log("Got unexpected WiFi scan result", scanResult); + } } } diff --git a/state/DeviceReduxCoupling.js b/state/DeviceReduxCoupling.js index 027da32..c52cb8e 100644 --- a/state/DeviceReduxCoupling.js +++ b/state/DeviceReduxCoupling.js @@ -7,7 +7,14 @@ export const ConnState = { 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.. + CONNECTED_STOPPING: 'connected_stopping' // stop message sent.. +} + +export const WifiState = { + UNKNOWN: 'unknown', + STA: 'sta', // connected to regular wifi + AP_PROVISIONING: 'ap_provisioning', // acting as access point for provisioning + AP_SECURE: 'ap_secure', // acting as access point, password has been set } // -------------------------------------------- Actions --------------------------------------------- @@ -21,6 +28,12 @@ export const SESSION_NEW_DATA = "SESSION_NEW_DATA"; export const START_SESSION = "START_SESSION"; export const STOP_SESSION = "STOP_SESSION"; +export const WIFI_SET_STATE = "WIFI_SET_STATE"; + +export const reportNewWifiState = (newStateStr) => ({ + type: WIFI_SET_STATE, + newStateStr: newStateStr +}); export const reportSessionStarted = (sessionId) => ({ type: SESSION_STARTED, @@ -107,6 +120,7 @@ const INITIAL_ANALYSIS = { const INITIAL_DEVICE_STATE = { connState: ConnState.DISCONNECTED, + wifiState: WifiState.UNKNOWN, sessionId: 0, measurements: List(), analysis: INITIAL_ANALYSIS, @@ -130,18 +144,25 @@ export const deviceStateReducer = (state = INITIAL_DEVICE_STATE, action) => { case SESSION_STOPPED: return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPED }; case START_SESSION: - if(state.connState === ConnState.SESSION_STARTED) + 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) + if (state.connState === ConnState.SESSION_STOPPED) return state; return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPING }; + case WIFI_SET_STATE: + console.log("here"); + let wifState = WifiState.UNKNOWN; + if (action.data === "STATION_MODE") { wifState = WifiState.STA; } + else if (action.data === "AP_PROVISIONING") { wifState = WifiState.AP_PROVISIONING; } + else if (action.data === "AP_SECURE") { wifState = WifiState.AP_SECURE; } + return { ...state, wifiState: wifState }; default: - console.log("Unhandled state in deviceStateReducer", action.type); + console.log("Unhandled state in deviceStateReducer", action, action.type); return state } }; - + diff --git a/state/Reducer.js b/state/Reducer.js index 633abef..bf3035b 100644 --- a/state/Reducer.js +++ b/state/Reducer.js @@ -22,7 +22,7 @@ const INITIAL_SETTINGS = { theme: "hot", username: "", //swimTrackerHost: "192.168.178.107", // am pool - swimTrackerHost: "192.168.178.110", // testgeraet + swimTrackerHost: "192.168.42.1", // testgeraet analysis: { peaksPerLap: 30, diff --git a/views/WifiPasswordView.js b/views/WifiPasswordView.js index 30bbdaf..66e34b2 100644 --- a/views/WifiPasswordView.js +++ b/views/WifiPasswordView.js @@ -13,6 +13,7 @@ import themeColors from '../components/themeColors'; function WifiPasswordView(props) { + props = {...props, ...props.route.params}; let iconName = "wifi-strength-" + props.strength; if (props.lock) { diff --git a/views/WifiSelectionView.js b/views/WifiSelectionView.js index dd85469..31f0ed3 100644 --- a/views/WifiSelectionView.js +++ b/views/WifiSelectionView.js @@ -1,10 +1,11 @@ -import React from "react"; +import React from 'react'; import { StyleSheet, Text, View, TouchableOpacity, ScrollView, + ActivityIndicator, } from "react-native"; import SetupView from '../components/SetupView'; import MaterialIcon from "react-native-vector-icons/MaterialCommunityIcons"; @@ -12,12 +13,12 @@ import MaterialIcon from "react-native-vector-icons/MaterialCommunityIcons"; function WifiListElement(props) { let iconName = "wifi-strength-" + props.strength; - if(props.lock) { + if (props.lock) { iconName += "-lock"; } return ( - + {props.text} @@ -51,32 +52,96 @@ const wifiListElementStyles = { // --------------------------------------------------------------------------------------------- +class WifiSelectionView extends React.Component { + constructor() { + super(); + this.state = { wifiInfo: [] }; + } -function WifiSelectionView(props) { + processDeviceResponse(response) { + // sort from strong to weak + response.sort((e1, e2) => { + if (e1.rssi > e2.rssi) + return -1; + if (e1.rssi < e2.rssi) + return 1; + else + return 0; + }); - return ( - - + let ssidsAlreadyAdded = {}; + let result = []; + for (let i = 0; i < response.length; i++) { + if (response[i].ssid in ssidsAlreadyAdded) + continue; + + const locked = (response[i].sec != "open"); + let strength = 1; + if (response[i].rssi > -30) + strength = 4; + else if (response[i].rssi > -67) + strength = 3; + else if (response[i].rssi > -70) + strength = 2; + + result.push({ ssid: response[i].ssid, locked: locked, strength: strength }); + ssidsAlreadyAdded[response[i].ssid] = true; + } + return result; + } + + componentDidMount() { + this.props.device.conn.scanWifiNetworks().then( + (result) => { + this.setState({ wifiInfo: this.processDeviceResponse(result) }) + } + ); + } + + render() { + let inner; + + if (this.state.wifiInfo.length > 0) { + inner = ( - - + {this.state.wifiInfo.map(e => ( + { this.props.navigation.navigate("WifiPasswordView", { + ssid: e.ssid, + lock: e.locked, + strength: e.strength, + buttonText: "Set Password", + subText: "Please enter password for your home WiFi", + }); }}> + ) + )} + ) + } + else { + inner = ( - - + ) + } - - - - - - - ) + return ( + + + {inner} + + + ) + } } + const styles = StyleSheet.create({ listContainer: { height: "75%",