From 776b999d985548d797f8d9e26a57f2fdbebc4bdc Mon Sep 17 00:00:00 2001 From: Jonah Aden <151240959+adenjonah@users.noreply.github.com> Date: Wed, 22 May 2024 02:15:25 -0500 Subject: [PATCH] works --- server/json_databases/DCUUIA.json | 2 +- server/server.py | 36 ++++--- src/components/Navbar.js | 170 ++++++++++++++++++++---------- src/pages/constant/EVData.js | 23 +++- src/pages/constant/constant.js | 2 +- src/pages/focus/rover.js | 4 +- src/pages/focus/setup.js | 45 ++++---- 7 files changed, 174 insertions(+), 108 deletions(-) diff --git a/server/json_databases/DCUUIA.json b/server/json_databases/DCUUIA.json index 55f425a..d44adbd 100644 --- a/server/json_databases/DCUUIA.json +++ b/server/json_databases/DCUUIA.json @@ -1 +1 @@ -{"timestamp": "2024-05-20T05:50:15.085340", "dcu": {"eva1": {"batt": false, "oxy": true, "comm": false, "fan": true, "pump": false, "co2": false}, "eva2": {"batt": false, "oxy": false, "comm": true, "fan": false, "pump": false, "co2": false}}, "uia": {"eva1_power": false, "eva1_oxy": false, "eva1_water_supply": false, "eva1_water_waste": false, "eva2_power": false, "eva2_oxy": false, "eva2_water_supply": false, "eva2_water_waste": false, "oxy_vent": false, "depress": false}} \ No newline at end of file +{"timestamp": "2024-05-22T02:15:24.677766", "dcu": {"eva1": {"batt": false, "oxy": false, "comm": false, "fan": false, "pump": false, "co2": false}, "eva2": {"batt": false, "oxy": false, "comm": false, "fan": false, "pump": false, "co2": false}}, "uia": {"eva1_power": false, "eva1_oxy": false, "eva1_water_supply": false, "eva1_water_waste": true, "eva2_power": false, "eva2_oxy": false, "eva2_water_supply": true, "eva2_water_waste": false, "oxy_vent": false, "depress": true}} \ No newline at end of file diff --git a/server/server.py b/server/server.py index 6cc33eb..605bd6f 100644 --- a/server/server.py +++ b/server/server.py @@ -82,9 +82,8 @@ def initialize_files(): async def startup_event(): initialize_files() # Ensure files are created if they do not exist initialize_database_files() - scheduler = AsyncIOScheduler() - scheduler.add_job(periodic_fetch_and_store, 'interval', seconds=10) # Adjust the interval as needed - scheduler.start() + task = asyncio.create_task(periodic_fetch_and_store()) + await asyncio.sleep(1) async def periodic_fetch_and_store(): global team_number @@ -96,17 +95,22 @@ async def periodic_fetch_and_store(): telemetry_url = f"http://{tss_ip}/json_data/teams/{team_number}/TELEMETRY.json" dcu_url = f"http://{tss_ip}/json_data/DCU.json" uia_url = f"http://{tss_ip}/json_data/UIA.json" + warnings_url = f'http://{tss_ip}/json_data/ERROR.json' while True: + print('running') try: # Fetch EVA and telemetry data eva_data = await fetch_json(eva_url) telemetry_data = await fetch_json(telemetry_url) - if eva_data and telemetry_data: + warnings_data = await fetch_json(warnings_url) + + if eva_data and telemetry_data and warnings_data: combined_data = { "timestamp": datetime.now().isoformat(), "eva": eva_data, - "telemetry": telemetry_data + "telemetry": telemetry_data, + "warnings": warnings_data } with open(DATA_FILE, 'w') as f: json.dump(combined_data, f) @@ -137,6 +141,15 @@ async def get_dcu_uia(): else: raise HTTPException(status_code=404, detail="DCUUIA.json not found") +@app.get("/warnings") +async def get_warnings(): + if os.path.exists(DATA_FILE): + with open(DATA_FILE, 'r') as f: + data = json.load(f) + return data['warnings'] + else: + raise HTTPException(status_code=404, detail="DCUUIA.json not found") + def utm_to_latlon(easting, northing, zone_number=15, zone_letter='R'): return utm.to_latlon(easting, northing, zone_number, zone_letter) @@ -237,7 +250,7 @@ async def read_data(): # Check Hololens, Server, and TSS Connection @app.get("/check_connection") -async def check_connection(tss_ip: str = None, holo_ip: str = None, server_ip: str = None): +async def check_connection(tss_ip: str = None, server_ip: str = None): async with httpx.AsyncClient() as client: if tss_ip: try: @@ -248,15 +261,6 @@ async def check_connection(tss_ip: str = None, holo_ip: str = None, server_ip: s return {"status": "no connection", "type": "TSS_IP"} except Exception: return {"status": "no connection", "type": "TSS_IP"} - elif holo_ip: - try: - response = await client.get(f"https://{holo_ip}/") - if response.status_code == 200: - return {"status": "connected", "type": "HOLO_IP"} - else: - return {"status": "no connection", "type": "HOLO_IP"} - except Exception: - return {"status": "no connection", "type": "HOLO_IP"} elif server_ip: try: response = await client.get(f"http://{server_ip}/docs") @@ -267,7 +271,7 @@ async def check_connection(tss_ip: str = None, holo_ip: str = None, server_ip: s except Exception: return {"status": "no connection", "type": "SERVER_IP"} else: - raise HTTPException(status_code=400, detail="Invalid request, provide either tss_ip, holo_ip, or server_ip") + raise HTTPException(status_code=400, detail="Invalid request, provide either tss_ip or server_ip") class Marker(BaseModel): title: str diff --git a/src/components/Navbar.js b/src/components/Navbar.js index 81dd0d7..c7564c2 100644 --- a/src/components/Navbar.js +++ b/src/components/Navbar.js @@ -1,70 +1,124 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import { NavLink as Link } from "react-router-dom"; import './navbar.css'; -// WarningModal Component -const WarningModal = ({ closeModal, isVisible }) => { - return ( - <div className={`warning ${isVisible ? '' : 'hidden'}`}> - <div className="warning-modal-content"> - <p>This is a warning message!</p> - <button className="warning-acknowledge" onClick={closeModal}> - I Acknowledge - </button> - </div> - </div> - ); -}; - -// Navbar Component const Navbar = () => { - const [showModal, setShowModal] = useState(false); - const [isVisible, setIsVisible] = useState(true); + const [showModal, setShowModal] = useState(false); + const [isVisible, setIsVisible] = useState(false); + const [warnings, setWarnings] = useState([]); - const openModal = () => { - setShowModal(true); - setIsVisible(true); - }; + useEffect(() => { + const fetchWarnings = async () => { + try { + const response = await fetch('http://localhost:8000/warnings'); + const data = await response.json(); + const activeWarnings = Object.entries(data.error) + .filter(([key, value]) => value) + .map(([key]) => key); - const closeModal = () => { - setIsVisible(false); - setTimeout(() => setShowModal(false), 500); // Wait for the fade-out transition to complete + if (activeWarnings.length > 0) { + setWarnings(activeWarnings); + setShowModal(true); + setIsVisible(true); + } + } catch (error) { + console.error('Error fetching warnings:', error); + } }; - return ( - <nav className="Navbar"> - <div className="NavMenu"> - <img className="img" src={require("./../assets/Images/logo.jpg")} alt="Logo"/> - <h1 id="title">CUITS LMCC 2024</h1> - <Link className="NavLink" to="/Constant" activeStyle={{ color: '#69b3e7' }}> - Constant - </Link> - <Link className="NavLink" to="/Setup" activeStyle={{ color: '#69b3e7' }}> - Setup - </Link> - <Link className="NavLink" to="/Egress" activeStyle={{ color: '#69b3e7' }}> - Egress - </Link> - <Link className="NavLink" to="/Nav" activeStyle={{ color: '#69b3e7' }}> - Nav - </Link> - <Link className="NavLink" to="/Equipment" activeStyle={{ color: '#69b3e7' }}> - Equipment - </Link> - <Link className="NavLink" to="/Rocks" activeStyle={{ color: '#69b3e7' }}> - Rocks - </Link> - <Link className="NavLink" to="/Rover" activeStyle={{ color: '#69b3e7' }}> - Rover - </Link> - <Link className="NavLink" to="/Ingress" activeStyle={{ color: '#69b3e7' }}> - Ingress - </Link> - <button className="warning-btn" onClick={openModal}>Show Warning</button> - {showModal && <WarningModal closeModal={closeModal} isVisible={isVisible} />} + const interval = setInterval(fetchWarnings, 3000); // Fetch warnings every 3 seconds + return () => clearInterval(interval); + }, []); + + const closeModal = () => { + setIsVisible(false); + setTimeout(() => setShowModal(false), 500); // Wait for the fade-out transition to complete + }; + + const getProcedure = (errorType) => { + switch (errorType) { + case 'fan_error': + return ( + <> + <p>Fan Error Detected!</p> + <ol> + <li>Swap FAN switch to secondary position</li> + <li>Relay FAN position switch to LMCC</li> + <li>Begin navigation back to airlock</li> + </ol> + </> + ); + case 'oxy_error': + return ( + <> + <p>Oxygen Error Detected!</p> + <ol> + <li>Swap O2 switch to secondary position</li> + <li>Relay O2 position switch to LMCC</li> + <li>Begin navigation back to airlock</li> + </ol> + </> + ); + case 'pump_error': + return ( + <> + <p>Abort Procedure Detected!</p> + <ol> + <li>Relay abort mission and return to airlock command to EVs</li> + </ol> + </> + ); + default: + return null; + } + }; + + return ( + <nav className="Navbar"> + <div className="NavMenu"> + <img className="img" src={require("./../assets/Images/logo.jpg")} alt="Logo"/> + <h1 id="title">CUITS LMCC 2024</h1> + <Link className="NavLink" to="/Constant" activeStyle={{ color: '#69b3e7' }}> + Constant + </Link> + <Link className="NavLink" to="/Setup" activeStyle={{ color: '#69b3e7' }}> + Setup + </Link> + <Link className="NavLink" to="/Egress" activeStyle={{ color: '#69b3e7' }}> + Egress + </Link> + <Link className="NavLink" to="/Nav" activeStyle={{ color: '#69b3e7' }}> + Nav + </Link> + <Link className="NavLink" to="/Equipment" activeStyle={{ color: '#69b3e7' }}> + Equipment + </Link> + <Link className="NavLink" to="/Rocks" activeStyle={{ color: '#69b3e7' }}> + Rocks + </Link> + <Link className="NavLink" to="/Rover" activeStyle={{ color: '#69b3e7' }}> + Rover + </Link> + <Link className="NavLink" to="/Ingress" activeStyle={{ color: '#69b3e7' }}> + Ingress + </Link> + {showModal && ( + <div className={`warning ${isVisible ? '' : 'hidden'}`}> + <div className="warning-modal-content"> + {warnings.map((errorType) => ( + <div key={errorType}> + {getProcedure(errorType)} + </div> + ))} + <button className="warning-acknowledge" onClick={closeModal}> + I Acknowledge + </button> </div> - </nav> - ); + </div> + )} + </div> + </nav> + ); }; export default Navbar; diff --git a/src/pages/constant/EVData.js b/src/pages/constant/EVData.js index b18d724..6a2f495 100644 --- a/src/pages/constant/EVData.js +++ b/src/pages/constant/EVData.js @@ -1,12 +1,29 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { useGlobal } from '../../components/GlobalContext'; import './constant.css'; // Import CSS file for styling const EVData = ({ evNumber }) => { - const { allData, error } = useGlobal(); + const { error } = useGlobal(); + const [allData, setAllData] = useState(null); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await fetch('http://localhost:8000/get_telemetry_data'); + const data = await response.json(); + setAllData(data); + } catch (error) { + console.error('Error fetching data:', error); + } + }; + + fetchData(); + const interval = setInterval(fetchData, 1000); // Fetch data every second + return () => clearInterval(interval); // Clear interval on component unmount + }, []); if (error) return <div>Error: {error}</div>; - if (!allData.telemetry || !allData.telemetry.telemetry) return <div>Loading...</div>; + if (!allData || !allData.telemetry || !allData.telemetry.telemetry) return <div>Loading...</div>; const evaData = allData.telemetry.telemetry[`eva${evNumber}`]; diff --git a/src/pages/constant/constant.js b/src/pages/constant/constant.js index ab9f16c..5ec5c43 100644 --- a/src/pages/constant/constant.js +++ b/src/pages/constant/constant.js @@ -105,7 +105,7 @@ function Constant() { }; return ( - <GlobalProvider> + <GlobalProvider value={{ telemetryData, hasError }}> <div className="pagecontainer" id="constantpage"> {telemetryData && !hasError && ( <TopBar diff --git a/src/pages/focus/rover.js b/src/pages/focus/rover.js index 72ac2c8..dd5df76 100644 --- a/src/pages/focus/rover.js +++ b/src/pages/focus/rover.js @@ -29,9 +29,7 @@ const RoverCamContainer = styled.div` padding-bottom: 30px; padding-top: 30px; `; -const StreamContainer = styled.div` - padding-bottom: 30px; -`; + const MapContainer = styled.div` flex: 1; display: flex; diff --git a/src/pages/focus/setup.js b/src/pages/focus/setup.js index b06b444..3f655ec 100644 --- a/src/pages/focus/setup.js +++ b/src/pages/focus/setup.js @@ -15,8 +15,6 @@ function Setup() { const [roverIP, setRoverIP] = useState(''); const [tssIPStatus, setTssIPStatus] = useState('yellow'); - const [ev1HoloIPStatus, setEv1HoloIPStatus] = useState('yellow'); - const [ev2HoloIPStatus, setEv2HoloIPStatus] = useState('yellow'); const [serverIPStatus, setServerIPStatus] = useState('yellow'); const [mapBoxAPIStatus, setMapBoxAPIStatus] = useState('yellow'); @@ -41,8 +39,6 @@ function Setup() { setRoverIP(config.ROVER_IP); checkConnection(config.TSS_IP, setTssIPStatus, 'tss_ip'); - checkConnection(config.EV1_HOLO_IP, setEv1HoloIPStatus, 'ev1_holo_ip'); - checkConnection(config.EV2_HOLO_IP, setEv2HoloIPStatus, 'ev2_holo_ip'); checkConnection(config.SERVER_IP, setServerIPStatus, 'server_ip'); // Check Mapbox API Key checkMapboxAPIKey(config.MAPBOX_KEY); @@ -80,8 +76,6 @@ function Setup() { console.log(result.message); if (newConfig.TSS_IP) checkConnection(newConfig.TSS_IP, setTssIPStatus, 'tss_ip'); - if (newConfig.EV1_HOLO_IP) checkConnection(newConfig.EV1_HOLO_IP, setEv1HoloIPStatus, 'ev1_holo_ip'); - if (newConfig.EV2_HOLO_IP) checkConnection(newConfig.EV2_HOLO_IP, setEv2HoloIPStatus, 'ev2_holo_ip'); if (newConfig.SERVER_IP) checkConnection(newConfig.SERVER_IP, setServerIPStatus, 'server_ip'); if (newConfig.MAPBOX_KEY) { checkMapboxAPIKey(newConfig.MAPBOX_KEY); @@ -273,33 +267,36 @@ function Setup() { <span className="status-text"></span> </div> </div> + + <div className='dataEntry'> + <label htmlFor='mapbox_api'>Map Box API Key: </label> + <input type='text' id='mapbox_api' name='mapbox_api' defaultValue={mapBoxAPI} /> + <button id="info-button" onClick={() => setShowMapBoxAPIModal(true)}>?</button> + <button onClick={handleSetMapBoxAPI}>Set MapBox API Key</button> + <div className={`status ${mapBoxAPIStatus}`}> + <span className="status-text"></span> + </div> + </div> + + <div className='dataEntry'> + <label htmlFor='rover_ip'>Rover IP Address: </label> + <input type='text' id='rover_ip' name='rover_ip' defaultValue={roverIP} /> + <button onClick={handleSetRoverIP}>Set Rover IP</button> + </div> + <div className='dataEntry'> <label htmlFor='ev1_holo_ip'>EV1 HoloLens IP Address: </label> <input type='text' id='ev1_holo_ip' name='ev1_holo_ip' defaultValue={ev1HoloIP} /> <button id="info-button" onClick={() => setShowEv1HoloIPModal(true)}>?</button> <button onClick={handleSetEV1_HOLO_IP}>Set EV1 HoloLens IP</button> - <div className={`status ${ev1HoloIPStatus}`}> - <span className="status-text"></span> - </div> </div> <div className='dataEntry'> <label htmlFor='ev2_holo_ip'>EV2 HoloLens IP Address: </label> <input type='text' id='ev2_holo_ip' name='ev2_holo_ip' defaultValue={ev2HoloIP} /> <button id="info-button" onClick={() => setShowEv2HoloIPModal(true)}>?</button> <button onClick={handleSetEV2_HOLO_IP}>Set EV2 HoloLens IP</button> - <div className={`status ${ev2HoloIPStatus}`}> - <span className="status-text"></span> - </div> - </div> - <div className='dataEntry'> - <label htmlFor='mapbox_api'>Map Box API Key: </label> - <input type='text' id='mapbox_api' name='mapbox_api' defaultValue={mapBoxAPI} /> - <button id="info-button" onClick={() => setShowMapBoxAPIModal(true)}>?</button> - <button onClick={handleSetMapBoxAPI}>Set MapBox API Key</button> - <div className={`status ${mapBoxAPIStatus}`}> - <span className="status-text"></span> - </div> </div> + <div className='dataEntry'> <label htmlFor='ev1_team_id'>EV1 Team ID: </label> <input type='text' id='ev1_team_id' name='ev1_team_id' defaultValue={ev1TeamID} /> @@ -310,11 +307,7 @@ function Setup() { <input type='text' id='ev2_team_id' name='ev2_team_id' defaultValue={ev2TeamID} /> <button onClick={handleSetEV2TeamID}>Set EV2 Team ID</button> </div> - <div className='dataEntry'> - <label htmlFor='rover_ip'>Rover IP Address: </label> - <input type='text' id='rover_ip' name='rover_ip' defaultValue={roverIP} /> - <button onClick={handleSetRoverIP}>Set Rover IP</button> - </div> + </div> <div style={{ display: 'none' }}> <MapboxComponent handleMapBoxAPIStatus={setMapBoxAPIStatus} />