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} />