started with functionality in wifi selection

This commit is contained in:
Martin Bauer 2021-06-06 21:31:41 +02:00
parent fee67e04aa
commit a6db96ef29
6 changed files with 187 additions and 47 deletions

19
App.js
View File

@ -63,25 +63,31 @@ export default class App extends React.Component {
const screenOptions = { const screenOptions = {
headerShown: false, headerShown: false,
}; };
/*
return ( return (
<Provider store={store}> <Provider store={store}>
<PersistGate loading={<AppLoading />} persistor={persistor}> <PersistGate loading={<AppLoading />} persistor={persistor}>
<NavigationContainer> <NavigationContainer>
<Stack.Navigator initialRouteName="WifiPasswordView"> <Stack.Navigator initialRouteName="WifiSelectionView">
<Stack.Screen
name="WifiSelectionView"
options={screenOptions} >
{props => <WifiSelectionView {...props} device={this.device} />}
</Stack.Screen>
<Stack.Screen <Stack.Screen
name="WifiPasswordView" name="WifiPasswordView"
component={WifiPasswordView}
options={screenOptions} options={screenOptions}
/> component={WifiPasswordView}
>
</Stack.Screen>
</Stack.Navigator> </Stack.Navigator>
</NavigationContainer> </NavigationContainer>
</PersistGate> </PersistGate>
</Provider> </Provider>
); );
*/
/*
return ( return (
<Provider store={store}> <Provider store={store}>
<PersistGate loading={<AppLoading />} persistor={persistor}> <PersistGate loading={<AppLoading />} persistor={persistor}>
@ -112,6 +118,7 @@ export default class App extends React.Component {
</PersistGate> </PersistGate>
</Provider> </Provider>
); );
*/
} }
} }

View File

@ -1,22 +1,32 @@
import ReconnectingWebSocket from 'reconnecting-websocket'; import ReconnectingWebSocket from 'reconnecting-websocket';
import * as msgpack from 'msgpack-lite';
const OpCodes = { const OpCodes = {
// from device to frontend // from swim tracker device to frontend
INITIAL_INFO: 1, ERROR: 1,
SESSION_STARTED: 2,
SESSION_STOPPED: 3, INITIAL_INFO: 2,
SESSION_NEW_DATA: 4, SESSION_STARTED: 3,
ANSWER_USER_LIST : 5, SESSION_STOPPED: 4,
ANSWER_SESSION_LIST : 6, SESSION_NEW_DATA: 5,
ANSWER_USER_LIST: 6,
ANSWER_SESSION_LIST: 7,
WIFI_STATE_RESPONSE: 8,
WIFI_SCAN_RESPONSE: 9,
// from frontend to device // from frontend to device
START_SESSION: 7, START_SESSION: 128,
STOP_SESSION: 8, STOP_SESSION: 129,
TARE: 9, TARE: 130,
QUERY_USER_LIST: 10, QUERY_USER_LIST: 131,
QUERY_SESSION_LIST: 11 QUERY_SESSION_LIST: 132,
WIFI_STATE_SET: 133,
WIFI_STATE_GET: 134,
WIFI_TRIGGER_SCAN: 135,
}; };
export default class SwimTrackerWebsocketConnection { export default class SwimTrackerWebsocketConnection {
constructor(swimTrackerHost, onData, onStarted, onStopped, onConnect, onDisconnect) { constructor(swimTrackerHost, onData, onStarted, onStopped, onConnect, onDisconnect) {
this.swimTrackerHost = swimTrackerHost; this.swimTrackerHost = swimTrackerHost;
@ -36,6 +46,15 @@ export default class SwimTrackerWebsocketConnection {
this.ws.onclose = this.onDisconnect; this.ws.onclose = this.onDisconnect;
this.ws.onerror = this._onError; this.ws.onerror = this._onError;
this.ws.binaryType = 'arraybuffer'; 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() { sendStartCommand() {
@ -56,6 +75,24 @@ export default class SwimTrackerWebsocketConnection {
this.ws.send(data); 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) => { _onMessage = (e) => {
const dv = new DataView(e.data); const dv = new DataView(e.data);
const opCode = dv.getInt8(0); const opCode = dv.getInt8(0);
@ -78,6 +115,15 @@ export default class SwimTrackerWebsocketConnection {
} else if (opCode === OpCodes.SESSION_NEW_DATA) { } else if (opCode === OpCodes.SESSION_NEW_DATA) {
const data = new Uint16Array(e.data.slice(1)); const data = new Uint16Array(e.data.slice(1));
this.onData(data); 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);
}
} }
} }

View File

@ -7,7 +7,14 @@ export const ConnState = {
CONNECTED_STOPPED: 'connected_stopped', CONNECTED_STOPPED: 'connected_stopped',
CONNECTED_RUNNING: 'connected_running', CONNECTED_RUNNING: 'connected_running',
CONNECTED_STARTING: 'connected_starting', // start message sent, but device hasn't ack'ed it yet 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 --------------------------------------------- // -------------------------------------------- Actions ---------------------------------------------
@ -21,6 +28,12 @@ export const SESSION_NEW_DATA = "SESSION_NEW_DATA";
export const START_SESSION = "START_SESSION"; export const START_SESSION = "START_SESSION";
export const STOP_SESSION = "STOP_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) => ({ export const reportSessionStarted = (sessionId) => ({
type: SESSION_STARTED, type: SESSION_STARTED,
@ -107,6 +120,7 @@ const INITIAL_ANALYSIS = {
const INITIAL_DEVICE_STATE = { const INITIAL_DEVICE_STATE = {
connState: ConnState.DISCONNECTED, connState: ConnState.DISCONNECTED,
wifiState: WifiState.UNKNOWN,
sessionId: 0, sessionId: 0,
measurements: List(), measurements: List(),
analysis: INITIAL_ANALYSIS, analysis: INITIAL_ANALYSIS,
@ -130,18 +144,25 @@ export const deviceStateReducer = (state = INITIAL_DEVICE_STATE, action) => {
case SESSION_STOPPED: case SESSION_STOPPED:
return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPED }; return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPED };
case START_SESSION: case START_SESSION:
if(state.connState === ConnState.SESSION_STARTED) if (state.connState === ConnState.SESSION_STARTED)
return state; return state;
return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STARTING }; return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STARTING };
case STOP_SESSION: case STOP_SESSION:
if(state.connState === ConnState.SESSION_STOPPED) if (state.connState === ConnState.SESSION_STOPPED)
return state; return state;
return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPING }; 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: default:
console.log("Unhandled state in deviceStateReducer", action.type); console.log("Unhandled state in deviceStateReducer", action, action.type);
return state return state
} }
}; };

View File

@ -22,7 +22,7 @@ const INITIAL_SETTINGS = {
theme: "hot", theme: "hot",
username: "", username: "",
//swimTrackerHost: "192.168.178.107", // am pool //swimTrackerHost: "192.168.178.107", // am pool
swimTrackerHost: "192.168.178.110", // testgeraet swimTrackerHost: "192.168.42.1", // testgeraet
analysis: { analysis: {
peaksPerLap: 30, peaksPerLap: 30,

View File

@ -13,6 +13,7 @@ import themeColors from '../components/themeColors';
function WifiPasswordView(props) { function WifiPasswordView(props) {
props = {...props, ...props.route.params};
let iconName = "wifi-strength-" + props.strength; let iconName = "wifi-strength-" + props.strength;
if (props.lock) { if (props.lock) {

View File

@ -1,10 +1,11 @@
import React from "react"; import React from 'react';
import { import {
StyleSheet, StyleSheet,
Text, Text,
View, View,
TouchableOpacity, TouchableOpacity,
ScrollView, ScrollView,
ActivityIndicator,
} from "react-native"; } from "react-native";
import SetupView from '../components/SetupView'; import SetupView from '../components/SetupView';
import MaterialIcon from "react-native-vector-icons/MaterialCommunityIcons"; import MaterialIcon from "react-native-vector-icons/MaterialCommunityIcons";
@ -12,12 +13,12 @@ import MaterialIcon from "react-native-vector-icons/MaterialCommunityIcons";
function WifiListElement(props) { function WifiListElement(props) {
let iconName = "wifi-strength-" + props.strength; let iconName = "wifi-strength-" + props.strength;
if(props.lock) { if (props.lock) {
iconName += "-lock"; iconName += "-lock";
} }
return ( return (
<TouchableOpacity> <TouchableOpacity onPress={props.onPress}>
<View style={wifiListElementStyles.container}> <View style={wifiListElementStyles.container}>
<MaterialIcon style={wifiListElementStyles.icon} name={iconName}></MaterialIcon> <MaterialIcon style={wifiListElementStyles.icon} name={iconName}></MaterialIcon>
<Text style={wifiListElementStyles.text} >{props.text}</Text> <Text style={wifiListElementStyles.text} >{props.text}</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 = {};
<SetupView let result = [];
headerText="WiFi Connection" for (let i = 0; i < response.length; i++) {
lowerLeftButtonText="My WiFi wasn't found" if (response[i].ssid in ssidsAlreadyAdded)
lowerRightButtonText="Need help?" continue;
>
<View style={styles.listContainer}> 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 = (
<ScrollView> <ScrollView>
<WifiListElement text="WLAN" strength="4" lock={true}></WifiListElement> {this.state.wifiInfo.map(e => (
<WifiListElement text="GastWLAN" strength="2" lock={false}></WifiListElement> <WifiListElement
text={e.ssid}
strength={e.strength}
lock={e.locked}
key={e.ssid}
onPress={() => { 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",
}); }}>
</WifiListElement>)
)}
</ScrollView>)
}
else {
inner = (<ActivityIndicator size="large" color="#ffffff" />
<WifiListElement text="WLAN" strength="4"></WifiListElement> )
<WifiListElement text="GastWLAN" strength="2"></WifiListElement> }
<WifiListElement text="WLAN" strength="4"></WifiListElement> return (
<WifiListElement text="GastWLAN" strength="2"></WifiListElement> <SetupView
</ScrollView> headerText="WiFi Connection"
lowerLeftButtonText="My WiFi wasn't found"
</View> lowerRightButtonText="Need help?"
</SetupView> >
) <View style={styles.listContainer}>
{inner}
</View>
</SetupView>
)
}
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
listContainer: { listContainer: {
height: "75%", height: "75%",