Skip to content

Commit

Permalink
Display current FSM state in control panel (#61)
Browse files Browse the repository at this point in the history
  • Loading branch information
samderanova authored May 28, 2024
1 parent 242c454 commit e3a54fe
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 12 deletions.
8 changes: 6 additions & 2 deletions control-station/src/App.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<main>
<Navbar />
<SensorData />
<ControlPanel />
<StatusIndicator state={podData.state} />
<ControlPanel podSocketClient={podSocketClient} />
</main>
);
}
Expand Down
2 changes: 0 additions & 2 deletions control-station/src/components/ControlPanel/ControlPanel.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
.controlpanel {
position: fixed;
bottom: 0;
width: 100%;
background-color: black;
height: 9%;
Expand Down
9 changes: 6 additions & 3 deletions control-station/src/components/ControlPanel/ControlPanel.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="controlpanel">
<button className="button run" onClick={() => podSocketClient.sendRun()}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ function SensorContainer() {
<SensorBox />
<SensorBox />
<SensorBox />
<SensorBox />
<SensorBox />
</div>
);
}
Expand Down
53 changes: 53 additions & 0 deletions control-station/src/components/StatusIndicator/StatusIndicator.css
Original file line number Diff line number Diff line change
@@ -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);
}
23 changes: 23 additions & 0 deletions control-station/src/components/StatusIndicator/StatusIndicator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { State } from "@/services/PodSocketClient";
import "./StatusIndicator.css";

interface StatusIndicatorProps {
state: State;
}

function StatusIndicator({ state }: StatusIndicatorProps) {
return (
<div className="status-indicator">
{Object.values(State).map((s) => {
return (
<div key={s} className={`group ${s.toLowerCase()}-state`}>
<span className={`circle` + (s === state ? " active" : "")}></span>
<div className="state-text">{s}</div>
</div>
);
})}
</div>
);
}

export default StatusIndicator;
1 change: 1 addition & 0 deletions control-station/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
21 changes: 19 additions & 2 deletions control-station/src/services/PodSocketClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -17,6 +27,7 @@ interface ClientToServerEvents {

export interface PodData {
connected: boolean;
state: State;
}

type SetPodData = Dispatch<SetStateAction<PodData>>;
Expand Down Expand Up @@ -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 {
Expand Down
3 changes: 2 additions & 1 deletion control-station/src/services/usePodData.tsx
Original file line number Diff line number Diff line change
@@ -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<PodData>({
state: State.Disconnected,
connected: false,
});

Expand Down

0 comments on commit e3a54fe

Please sign in to comment.