Skip to content

Commit

Permalink
Race tab should use live data from socket
Browse files Browse the repository at this point in the history
  • Loading branch information
alexwhelan12 committed Jan 25, 2025
1 parent 502f99d commit 092b0b9
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 50 deletions.
45 changes: 2 additions & 43 deletions packages/client/src/components/tabs/RaceTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import axios from "axios";
import Image from "next/image";
import { useEffect, useMemo, useState } from "react";

import { useLapData } from "@/contexts/LapDataContext";
import { usePacket } from "@/contexts/PacketContext";
import type { ILapData } from "@shared/helios-types";
import {
Expand Down Expand Up @@ -145,7 +146,7 @@ const exampleData: ILapData[] = [
];

function RaceTab() {
const [lapData, setLapData] = useState<ILapData[]>([]);
const { lapData } = useLapData();

const data = useMemo(() => lapData, [lapData]);

Expand All @@ -164,48 +165,6 @@ function RaceTab() {
return result;
}

const fetchLapData = async () => {
try {
const response = await axios.get(
`https://aedes.calgarysolarcar.ca:3001/laps`,
);
return response.data; // Assuming the API returns an array of lap data
} catch (error) {
return { error: "Error fetching lap data" };
}
};

useEffect(() => {
fetchLapData()
.then((response) => {
const formattedData = response.data.map(
(lapPacket: { data: ILapData }) => ({
ampHours: parseFloat(lapPacket.data.ampHours.toFixed(2)),
averagePackCurrent: parseFloat(
lapPacket.data.averagePackCurrent.toFixed(2),
),
averageSpeed: parseFloat(lapPacket.data.averageSpeed.toFixed(2)),
batterySecondsRemaining: parseFloat(
lapPacket.data.batterySecondsRemaining.toFixed(2),
),
distance: parseFloat(lapPacket.data.distance.toFixed(2)),
lapTime: parseFloat(lapPacket.data.lapTime.toFixed(2)),
netPowerOut: parseFloat(lapPacket.data.netPowerOut.toFixed(2)),
timeStamp: new Date(lapPacket.data.timeStamp).toLocaleDateString(
"en-US",
),
totalPowerIn: parseFloat(lapPacket.data.totalPowerIn.toFixed(2)),
totalPowerOut: parseFloat(lapPacket.data.totalPowerOut.toFixed(2)),
}),
);

setLapData(formattedData);
})
.catch((error) => {
throw new Error(error);
});
}, []);

return (
<div className="m-4 flex justify-around">
<div className="mb-4 flex flex-col flex-wrap justify-end gap-2">
Expand Down
92 changes: 92 additions & 0 deletions packages/client/src/contexts/LapDataContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import axios from "axios";
import {
type PropsWithChildren,
createContext,
useContext,
useEffect,
useState,
} from "react";

import { CONNECTIONTYPES, useAppState } from "@/contexts/AppStateContext";
import { socketIO } from "@/contexts/SocketContext";
import { ILapData } from "@shared/helios-types";

interface ILapDataContextReturn {
lapData: ILapData[];
}

const lapDataContext = createContext<ILapDataContextReturn>({
lapData: [],
});

export function LapDataContextProvider({
children,
}: PropsWithChildren): JSX.Element {
const { currentAppState } = useAppState();
const [lapData, setLapData] = useState<ILapData[]>([]);

const onLapData = (data: ILapData) => {
setLapData((prev) => [...prev, data]);
};

const fetchLapData = async () => {
try {
const response = await axios.get(
`https://aedes.calgarysolarcar.ca:3001/laps`,
);
return response.data; // Assuming the API returns an array of lap data
} catch (error) {
return { error: "Error fetching lap data" };
}
};

useEffect(() => {
fetchLapData()
.then((response) => {
const formattedData = response.data.map(
(lapPacket: { data: ILapData }) => ({
ampHours: parseFloat(lapPacket.data.ampHours.toFixed(2)),
averagePackCurrent: parseFloat(
lapPacket.data.averagePackCurrent.toFixed(2),
),
averageSpeed: parseFloat(lapPacket.data.averageSpeed.toFixed(2)),
batterySecondsRemaining: parseFloat(
lapPacket.data.batterySecondsRemaining.toFixed(2),
),
distance: parseFloat(lapPacket.data.distance.toFixed(2)),
lapTime: parseFloat(lapPacket.data.lapTime.toFixed(2)),
netPowerOut: parseFloat(lapPacket.data.netPowerOut.toFixed(2)),
timeStamp: new Date(lapPacket.data.timeStamp).toLocaleDateString(
"en-US",
),
totalPowerIn: parseFloat(lapPacket.data.totalPowerIn.toFixed(2)),
totalPowerOut: parseFloat(lapPacket.data.totalPowerOut.toFixed(2)),
}),
);

setLapData(formattedData);
})
.catch((error) => {
throw new Error(error);
});
}, []);

useEffect(() => {
if (currentAppState.connectionType === CONNECTIONTYPES.NETWORK) {
socketIO.on("lapData", onLapData);
return () => {
socketIO.off("lapData", onLapData);
};
}
}, [currentAppState.connectionType, currentAppState.playbackSwitch]);

return (
<lapDataContext.Provider value={{ lapData }}>
{children}
</lapDataContext.Provider>
);
}

export function useLapData(): ILapDataContextReturn {
return useContext(lapDataContext);
}
2 changes: 2 additions & 0 deletions packages/client/src/contexts/SocketContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
CoordInfoUpdate,
CoordUpdateResponse,
Coords,
ILapData,
ITelemetryData,
} from "@shared/helios-types";

Expand All @@ -25,6 +26,7 @@ interface ServerToClientEvents {
packet: (value: ITelemetryData) => void;
lapCoords: (coords: CoordUpdateResponse) => void;
carLatency: (value: number) => void;
lapData: (value: ILapData) => void;
}

const URL =
Expand Down
9 changes: 6 additions & 3 deletions packages/client/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { AppProps } from "next/app";

import LoadingWrapper from "@/components/global/LoadingWrapper";
import { AppStateContextProvider } from "@/contexts/AppStateContext";
import { LapDataContextProvider } from "@/contexts/LapDataContext";
import { PacketContextProvider } from "@/contexts/PacketContext";
import { SocketContextProvider } from "@/contexts/SocketContext";
import "@/styles/globals.css";
Expand All @@ -12,9 +13,11 @@ export default function App({ Component, pageProps }: AppProps) {
<AppStateContextProvider>
<SocketContextProvider>
<PacketContextProvider>
<LoadingWrapper>
<Component {...pageProps} />
</LoadingWrapper>
<LapDataContextProvider>
<LoadingWrapper>
<Component {...pageProps} />
</LoadingWrapper>
</LapDataContextProvider>
</PacketContextProvider>
</SocketContextProvider>
</AppStateContextProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { SolarMQTTClient } from "@/datasources/SolarMQTTClient/SolarMQTTClient";
import { options } from "@/datasources/SolarMQTTClient/SolarMQTTClient.types";

import { logger } from "@/index";
import { type ITelemetryData } from "@shared/helios-types";
import { ILapData, type ITelemetryData } from "@shared/helios-types";

export class BackendController implements BackendControllerTypes {
public dynamoDB: DynamoDB;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ export class LapController implements LapControllerType {
}
}

public async handleLapData(lapData: ILapData) {
await this.backendController.socketIO.broadcastLapData(lapData);
await this.backendController.dynamoDB.insertLapData(lapData);
}

public async handlePacket(packet: ITelemetryData) {
if (this.checkLap(packet) && this.lastLapPackets.length > 0) {
// mark lap, calculate lap, and add to lap table in database
Expand Down Expand Up @@ -83,8 +88,7 @@ export class LapController implements LapControllerType {
totalPowerIn: 1, // CHANGE THIS BASED ON CORRECTED TOTAL POWER VALUE!
totalPowerOut: this.getAveragePowerOut(this.lastLapPackets),
};

await this.backendController.dynamoDB.insertLapData(lapData);
this.handleLapData(lapData);
this.lastLapPackets = [];
}
this.lastLapPackets.push(packet);
Expand Down
4 changes: 4 additions & 0 deletions packages/server/src/datasources/SocketIO/SocketIO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { createLightweightApplicationLogger } from "@/utils/logger";
import type {
CoordInfoUpdate,
CoordUpdateResponse,
ILapData,
ITelemetryData,
} from "@shared/helios-types";

Expand Down Expand Up @@ -40,6 +41,9 @@ export class SocketIO implements SocketIOType {
public broadcastPacket(packet: ITelemetryData) {
this.io.emit("packet", packet);
}
public broadcastLapData(lapData: ILapData) {
this.io.emit("lapData", lapData);
}
public broadcastCarLatency(latency: number) {
this.io.emit("carLatency", latency);
}
Expand Down
3 changes: 2 additions & 1 deletion packages/server/src/datasources/SocketIO/SocketIO.types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { type Server, type Socket } from "socket.io";

import type { ITelemetryData } from "@shared/helios-types";
import type { ILapData, ITelemetryData } from "@shared/helios-types";

export interface SocketIOType {
broadcastCarLatency(latency: number): void;
broadcastPacket(packet: ITelemetryData): void;
initializeSocketListeners(socket: Socket): void;
io: Server;
broadcastLapData(lapData: ILapData): void;
}

0 comments on commit 092b0b9

Please sign in to comment.