diff --git a/dawn/main/networking/FieldControl.js b/dawn/main/networking/FieldControl.js index 81e64990..d12ccc50 100644 --- a/dawn/main/networking/FieldControl.js +++ b/dawn/main/networking/FieldControl.js @@ -1,5 +1,5 @@ import io from 'socket.io-client'; -import { updateRobot, updateHeart } from '../../renderer/actions/FieldActions'; +import { updateRobot, updateHeart, updateMaster } from '../../renderer/actions/FieldActions'; import RendererBridge from '../RendererBridge'; import { Logger } from '../../renderer/utils/utils'; import Ansible from './Ansible'; @@ -33,6 +33,9 @@ class FCInternals { this.logger.log('Trying to send FC Info to Disconnected Robot'); } }); + this.socket.on('master', (data) => { + RendererBridge.reduxDispatch(updateMaster(JSON.parse(data))); + }); }); } diff --git a/dawn/renderer/actions/FieldActions.js b/dawn/renderer/actions/FieldActions.js index b58c2660..9da327fd 100644 --- a/dawn/renderer/actions/FieldActions.js +++ b/dawn/renderer/actions/FieldActions.js @@ -11,6 +11,12 @@ export const updateHeart = () => ({ type: ActionTypes.UPDATE_HEART, }); +export const updateMaster = msg => ({ + type: ActionTypes.UPDATE_MASTER, + alliance: msg.alliance, + teamNumber: msg.team_number, +}); + export const updateMatch = msg => ({ type: ActionTypes.UPDATE_MATCH, matchNumber: msg.match_number, diff --git a/dawn/renderer/actions/InfoActions.js b/dawn/renderer/actions/InfoActions.js index cd0ddf6b..26cfd5c8 100644 --- a/dawn/renderer/actions/InfoActions.js +++ b/dawn/renderer/actions/InfoActions.js @@ -11,6 +11,10 @@ export const runtimeConnect = () => ({ type: 'RUNTIME_CONNECT', }); +export const masterStatus = () => ({ + type: 'MASTER_ROBOT', +}); + export const runtimeDisconnect = () => ({ type: 'RUNTIME_DISCONNECT', }); diff --git a/dawn/renderer/components/App.js b/dawn/renderer/components/App.js index 071e00f7..49b0b15c 100644 --- a/dawn/renderer/components/App.js +++ b/dawn/renderer/components/App.js @@ -114,6 +114,7 @@ class AppComponent extends React.Component { @@ -150,6 +151,7 @@ class AppComponent extends React.Component { AppComponent.propTypes = { connectionStatus: PropTypes.bool.isRequired, runtimeStatus: PropTypes.bool.isRequired, + masterStatus: PropTypes.bool.isRequired, isRunningCode: PropTypes.bool.isRequired, asyncAlerts: PropTypes.array.isRequired, onAlertDone: PropTypes.func.isRequired, @@ -159,6 +161,7 @@ AppComponent.propTypes = { const mapStateToProps = state => ({ connectionStatus: state.info.connectionStatus, runtimeStatus: state.info.runtimeStatus, + masterStatus: state.fieldStore.masterStatus, isRunningCode: state.info.isRunningCode, asyncAlerts: state.asyncAlerts, }); diff --git a/dawn/renderer/components/ConfigBox.js b/dawn/renderer/components/ConfigBox.js index c091a660..f8035419 100644 --- a/dawn/renderer/components/ConfigBox.js +++ b/dawn/renderer/components/ConfigBox.js @@ -37,6 +37,7 @@ class ConfigBoxComponent extends React.Component { this.handleClose = this.handleClose.bind(this); } + componentDidMount() { storage.get('ipAddress', (err, data) => { if (err) { diff --git a/dawn/renderer/components/DNav.js b/dawn/renderer/components/DNav.js index af951508..c082e591 100644 --- a/dawn/renderer/components/DNav.js +++ b/dawn/renderer/components/DNav.js @@ -40,6 +40,13 @@ class DNavComponent extends React.Component { return `Dawn v${VERSION}`; } + createMaster() { + if (this.props.fieldControlStatus) { + return this.props.masterStatus; + } + return false; + } + render() { return ( @@ -47,6 +54,7 @@ class DNavComponent extends React.Component { isRunningCode={this.props.isRunningCode} connectionStatus={this.props.connectionStatus} runtimeStatus={this.props.runtimeStatus} + masterStatus={this.props.masterStatus} shouldShow={this.state.showUpdateModal} ipAddress={this.props.ipAddress} hide={this.toggleUpdateModal} @@ -75,6 +83,11 @@ class DNavComponent extends React.Component { ({ + masterStatus: state.fieldStore.masterStatus, + teamNumber: state.fieldStore.teamNumber, + teamColor: state.fieldStore.teamColor, robotState: state.info.robotState, heart: state.fieldStore.heart, ipAddress: state.info.ipAddress, diff --git a/dawn/renderer/components/StatusLabel.js b/dawn/renderer/components/StatusLabel.js index 8f880d4e..b7735d79 100644 --- a/dawn/renderer/components/StatusLabel.js +++ b/dawn/renderer/components/StatusLabel.js @@ -7,6 +7,15 @@ import numeral from 'numeral'; const StatusLabelComponent = (props) => { let labelStyle = 'default'; let labelText = 'Disconnected'; + const masterRobotHeader = 'Master Robot: Team '; + const teamIP = props.ipAddress.substring(props.ipAddress.length - 2, props.ipAddress.length); + let masterRobotStyle = ' '; + if (props.teamColor === 'blue') { + masterRobotStyle = 'primary'; + } else if (props.teamColor === 'gold') { + masterRobotStyle = 'warning'; + } + if (props.connectionStatus) { if (!props.runtimeStatus) { labelStyle = 'danger'; @@ -20,7 +29,14 @@ const StatusLabelComponent = (props) => { } } return ( - +
+ + {' '} + +
); }; @@ -29,12 +45,21 @@ StatusLabelComponent.propTypes = { runtimeStatus: PropTypes.bool.isRequired, batteryLevel: PropTypes.number.isRequired, batterySafety: PropTypes.bool.isRequired, + teamColor: PropTypes.string.isRequired, + teamNumber: PropTypes.number.isRequired, + ipAddress: PropTypes.string.isRequired, + fieldControlStatus: PropTypes.bool.isRequired, }; const mapStateToProps = state => ({ batteryLevel: state.peripherals.batteryLevel, batterySafety: state.peripherals.batterySafety, + masterStatus: state.fieldStore.masterStatus, + teamNumber: state.fieldStore.teamNumber, + teamColor: state.fieldStore.teamColor, + ipAddress: state.info.ipAddress, + fieldControlStatus: state.fieldStore.fieldControl, }); const StatusLabel = connect(mapStateToProps)(StatusLabelComponent); diff --git a/dawn/renderer/constants/Constants.js b/dawn/renderer/constants/Constants.js index 37fe67c3..212ca856 100755 --- a/dawn/renderer/constants/Constants.js +++ b/dawn/renderer/constants/Constants.js @@ -18,6 +18,7 @@ export const PeripheralTypes = keyMirror({ BatteryBuzzer: null, TeamFlag: null, GameValues: null, + master: null, }); export const ActionTypes = keyMirror({ @@ -39,6 +40,7 @@ export const ActionTypes = keyMirror({ UPDATE_HEART: null, UPDATE_ROBOT: null, UPDATE_MATCH: null, + UPDATE_MASTER: null, ADD_ALERT: null, REMOVE_ALERT: null, CLEAR_CONSOLE: null, diff --git a/dawn/renderer/reducers/FieldStore.js b/dawn/renderer/reducers/FieldStore.js index 2ad86c06..c30e12ce 100644 --- a/dawn/renderer/reducers/FieldStore.js +++ b/dawn/renderer/reducers/FieldStore.js @@ -7,9 +7,12 @@ const initialFieldState = { rTeamNumber: 0, rTeamName: 'Unknown', heart: false, + masterStatus: false, mMatchNumber: 0, mTeamNumbers: [0, 0, 0, 0], mTeamNames: ['Offline', 'Offline', 'Offline', 'Offline'], + teamNumber: 0, + teamColor: 'Unknown', }; const fieldStore = (state = initialFieldState, action) => { @@ -30,6 +33,13 @@ const fieldStore = (state = initialFieldState, action) => { ...state, heart: !state.heart, }; + case ActionTypes.UPDATE_MASTER: + return { + ...state, + masterStatus: true, + teamNumber: action.teamNumber, + teamColor: action.alliance, + }; case ActionTypes.UPDATE_MATCH: return { ...state, diff --git a/dawn/renderer/reducers/info.js b/dawn/renderer/reducers/info.js index df663435..dddc0ce7 100644 --- a/dawn/renderer/reducers/info.js +++ b/dawn/renderer/reducers/info.js @@ -9,6 +9,7 @@ const initialInfoState = { isRunningCode: false, connectionStatus: false, runtimeStatus: false, + masterStatus: false, notificationHold: 0, fieldControlDirective: robotState.TELEOP, fieldControlActivity: false, @@ -40,6 +41,11 @@ const info = (state = initialInfoState, action) => { ...state, runtimeStatus: true, }; + case 'MASTER_ROBOT': + return { + ...state, + masterStatus: true, + }; case 'RUNTIME_DISCONNECT': return { ...state,