From e3a54fe0fe8c01bfb2f53f412ac4f9d098b0e840 Mon Sep 17 00:00:00 2001 From: Sam Der Date: Mon, 27 May 2024 21:09:17 -0700 Subject: [PATCH] Display current FSM state in control panel (#61) --- control-station/src/App.tsx | 8 ++- .../components/ControlPanel/ControlPanel.css | 2 - .../components/ControlPanel/ControlPanel.tsx | 9 ++-- .../SensorBoxes/Sensors/SensorsContainer.tsx | 2 - .../StatusIndicator/StatusIndicator.css | 53 +++++++++++++++++++ .../StatusIndicator/StatusIndicator.tsx | 23 ++++++++ control-station/src/components/index.ts | 1 + .../src/services/PodSocketClient.ts | 21 +++++++- control-station/src/services/usePodData.tsx | 3 +- 9 files changed, 110 insertions(+), 12 deletions(-) create mode 100644 control-station/src/components/StatusIndicator/StatusIndicator.css create mode 100644 control-station/src/components/StatusIndicator/StatusIndicator.tsx diff --git a/control-station/src/App.tsx b/control-station/src/App.tsx index a6c6fcbb..450ae19a 100644 --- a/control-station/src/App.tsx +++ b/control-station/src/App.tsx @@ -1,11 +1,15 @@ -import { ControlPanel, Navbar, SensorData } from "@/components"; +import { ControlPanel, Navbar, SensorData, StatusIndicator } from "@/components"; +import usePodData from "./services/usePodData"; function App() { + const { podData, podSocketClient } = usePodData(); + return (
- + +
); } diff --git a/control-station/src/components/ControlPanel/ControlPanel.css b/control-station/src/components/ControlPanel/ControlPanel.css index 16640fd0..88c1befc 100644 --- a/control-station/src/components/ControlPanel/ControlPanel.css +++ b/control-station/src/components/ControlPanel/ControlPanel.css @@ -1,6 +1,4 @@ .controlpanel { - position: fixed; - bottom: 0; width: 100%; background-color: black; height: 9%; diff --git a/control-station/src/components/ControlPanel/ControlPanel.tsx b/control-station/src/components/ControlPanel/ControlPanel.tsx index e805dd63..0bae1ce1 100644 --- a/control-station/src/components/ControlPanel/ControlPanel.tsx +++ b/control-station/src/components/ControlPanel/ControlPanel.tsx @@ -1,8 +1,11 @@ import "./ControlPanel.css"; -import usePodData from "@/services/usePodData"; +import PodSocketClient from "@/services/PodSocketClient"; -function ControlPanel() { - const { podSocketClient } = usePodData(); +interface ControlPanelProps { + podSocketClient: PodSocketClient; +} + +function ControlPanel({ podSocketClient }: ControlPanelProps) { return (
); } diff --git a/control-station/src/components/StatusIndicator/StatusIndicator.css b/control-station/src/components/StatusIndicator/StatusIndicator.css new file mode 100644 index 00000000..d9432b40 --- /dev/null +++ b/control-station/src/components/StatusIndicator/StatusIndicator.css @@ -0,0 +1,53 @@ +.status-indicator { + background-color: lightgray; + border-radius: 10px; + padding: 1rem; + margin: 2rem; +} + +.group { + margin-bottom: 1rem; +} + +.state-text { + display: inline-block; + vertical-align: middle; +} + +.circle { + width: 25px; + height: 25px; + border-radius: 50%; + display: inline-block; + vertical-align: middle; + margin-right: 20px; + background-color: gray; +} + +.disconnected-state > .active { + background-color: white; +} + +.init-state > .active { + background-color: pink; +} + +.running-state > .active { + background-color: green; +} + +.stopped-state > .active { + background-color: red; +} + +.halted-state > .active { + background-color: darkred; +} + +.faulted-state > .active { + background-color: darkred; +} + +.load-state > .active { + background-color: rgb(0, 100, 188); +} diff --git a/control-station/src/components/StatusIndicator/StatusIndicator.tsx b/control-station/src/components/StatusIndicator/StatusIndicator.tsx new file mode 100644 index 00000000..d387456a --- /dev/null +++ b/control-station/src/components/StatusIndicator/StatusIndicator.tsx @@ -0,0 +1,23 @@ +import { State } from "@/services/PodSocketClient"; +import "./StatusIndicator.css"; + +interface StatusIndicatorProps { + state: State; +} + +function StatusIndicator({ state }: StatusIndicatorProps) { + return ( +
+ {Object.values(State).map((s) => { + return ( +
+ +
{s}
+
+ ); + })} +
+ ); +} + +export default StatusIndicator; diff --git a/control-station/src/components/index.ts b/control-station/src/components/index.ts index 4221f196..83df7944 100644 --- a/control-station/src/components/index.ts +++ b/control-station/src/components/index.ts @@ -2,3 +2,4 @@ export { default as ControlPanel } from "./ControlPanel/ControlPanel"; export { default as Navbar } from "./Navbar/Navbar"; export { default as SensorData } from "./SensorBoxes/SensorData"; export { default as Status } from "./Status/Status"; +export { default as StatusIndicator } from "./StatusIndicator/StatusIndicator"; diff --git a/control-station/src/services/PodSocketClient.ts b/control-station/src/services/PodSocketClient.ts index 2294c7c2..d47552b6 100644 --- a/control-station/src/services/PodSocketClient.ts +++ b/control-station/src/services/PodSocketClient.ts @@ -2,6 +2,16 @@ import { Dispatch, SetStateAction } from "react"; import { Socket } from "socket.io-client"; import { ioNamespace } from "./socketHandler"; +export enum State { + Disconnected = "Disconnected", + Init = "Init", + Load = "Load", + Running = "Running", + Stopped = "Stopped", + Halted = "Halted", + Faulted = "Faulted", +} + interface ServerToClientEvents { connect: () => void; disconnect: (reason: Socket.DisconnectReason) => void; @@ -17,6 +27,7 @@ interface ClientToServerEvents { export interface PodData { connected: boolean; + state: State; } type SetPodData = Dispatch>; @@ -63,35 +74,41 @@ class PodSocketClient { sendLoad(): void { this.socket.emit("load", (response: string) => { console.log("Server acknowledged:", response); + this.setPodData((d) => ({ ...d, state: State.Load })); }); } sendRun(): void { this.socket.emit("run", (response: string) => { console.log("Server acknowledged:", response); + this.setPodData((d) => ({ ...d, state: State.Running })); }); } sendStop(): void { this.socket.emit("stop", (response: string) => { console.log("Server acknowledged:", response); + this.setPodData((d) => ({ ...d, state: State.Stopped })); }); } sendHalt(): void { this.socket.emit("halt", (response: string) => { console.log("Server acknowledged:", response); + this.setPodData((d) => ({ ...d, state: State.Halted })); }); } private onConnect(): void { console.log("Connected to server as", this.socket.id); - this.setPodData((d) => ({ ...d, connected: true })); + // TODO: On connecting, the state below should be what's provided by the pod + // if it's already running. Otherwise, the states should be State.Init + this.setPodData((d) => ({ ...d, connected: true, state: State.Init })); } private onDisconnect(reason: Socket.DisconnectReason): void { console.log(`Disconnected from server: ${reason}`); - this.setPodData((d) => ({ ...d, connected: false })); + this.setPodData((d) => ({ ...d, connected: false, state: State.Disconnected })); } private onData(data: string): void { diff --git a/control-station/src/services/usePodData.tsx b/control-station/src/services/usePodData.tsx index d7cd0be8..5eda1aca 100644 --- a/control-station/src/services/usePodData.tsx +++ b/control-station/src/services/usePodData.tsx @@ -1,8 +1,9 @@ import { useEffect, useMemo, useState } from "react"; -import PodSocketClient, { PodData } from "./PodSocketClient"; +import PodSocketClient, { PodData, State } from "./PodSocketClient"; function usePodData() { const [podData, setPodData] = useState({ + state: State.Disconnected, connected: false, });