Merge pull request #480 from Fisker-Inc/CEC-5356
CEC-5356: use `after_utc` to get can signals
This commit is contained in:
@@ -5,6 +5,11 @@ import {
|
|||||||
TableCell,
|
TableCell,
|
||||||
TableHead,
|
TableHead,
|
||||||
TableRow,
|
TableRow,
|
||||||
|
Box,
|
||||||
|
FormControl,
|
||||||
|
InputLabel,
|
||||||
|
Select,
|
||||||
|
MenuItem,
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -13,7 +18,7 @@ import {
|
|||||||
} from "../../Contexts/CANSignalsContext";
|
} from "../../Contexts/CANSignalsContext";
|
||||||
|
|
||||||
const Main = ({ vin }) => {
|
const Main = ({ vin }) => {
|
||||||
const { signals, setVIN } = useCANSignalContext();
|
const { signals, setVIN, queryDate, delays, delayIndex, setDelayIndex } = useCANSignalContext();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setVIN(vin);
|
setVIN(vin);
|
||||||
@@ -26,24 +31,31 @@ const Main = ({ vin }) => {
|
|||||||
if (!signals || signals.length === 0) return <h3>Loading...</h3>;
|
if (!signals || signals.length === 0) return <h3>Loading...</h3>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Table>
|
<>
|
||||||
<TableHead>
|
<Box sx={{ display: "flex", alignItems: "baseline", gap: "8px" }}>
|
||||||
<TableRow>
|
<span>Searching every</span>
|
||||||
<TableCell>Timestamp</TableCell>
|
<DelayController delays={delays} delayIndex={delayIndex} setDelayIndex={setDelayIndex} />
|
||||||
<TableCell>Signal</TableCell>
|
<span>seconds for signals sent after {queryDate}.</span>
|
||||||
<TableCell>Value</TableCell>
|
</Box>
|
||||||
</TableRow>
|
<Table>
|
||||||
</TableHead>
|
<TableHead>
|
||||||
<TableBody>
|
<TableRow>
|
||||||
{signals.map((signal, i) => (
|
<TableCell>Timestamp</TableCell>
|
||||||
<TableRow key={i}>
|
<TableCell>Signal</TableCell>
|
||||||
<TableCell>{signal.timestamp}</TableCell>
|
<TableCell>Value</TableCell>
|
||||||
<TableCell>{signal.signal}</TableCell>
|
|
||||||
<TableCell>{signal.value}</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
</TableHead>
|
||||||
</TableBody>
|
<TableBody>
|
||||||
</Table>
|
{signals.map((signal, i) => (
|
||||||
|
<TableRow key={i}>
|
||||||
|
<TableCell>{signal.timestamp}</TableCell>
|
||||||
|
<TableCell>{signal.signal}</TableCell>
|
||||||
|
<TableCell>{signal.value}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,4 +65,33 @@ const CANSignals = (props) => (
|
|||||||
</CANSignalProvider>
|
</CANSignalProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const DelayController = ({
|
||||||
|
delays,
|
||||||
|
delayIndex,
|
||||||
|
setDelayIndex
|
||||||
|
}) => {
|
||||||
|
const label = "Delay";
|
||||||
|
const handleChange = (event) => {
|
||||||
|
setDelayIndex(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl variant="standard" sx={{ m: 1, minWidth: 120 }}>
|
||||||
|
<InputLabel id="can-signal-delay">{label}</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="can-signal-delay"
|
||||||
|
onChange={handleChange}
|
||||||
|
value={delayIndex}
|
||||||
|
label={label}
|
||||||
|
>
|
||||||
|
{delays.map((delay, i) => {
|
||||||
|
return (
|
||||||
|
<MenuItem value={i} selected={i === delayIndex} key={delay}>{delay / 1000}</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default CANSignals;
|
export default CANSignals;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React, {useContext, useState} from "react";
|
import React, { useContext, useState } from "react";
|
||||||
|
|
||||||
import api from "../../services/vehiclesAPI";
|
import api from "../../services/vehiclesAPI";
|
||||||
import { LocalDateTimeString } from "../../utils/dates";
|
import { LocalDateTimeString } from "../../utils/dates";
|
||||||
import {useInterval} from "usehooks-ts";
|
import { useInterval } from "usehooks-ts";
|
||||||
|
|
||||||
const CANSignalContext = React.createContext();
|
const CANSignalContext = React.createContext();
|
||||||
|
|
||||||
@@ -26,31 +26,43 @@ const transformSignals = (signals) =>
|
|||||||
.flat();
|
.flat();
|
||||||
|
|
||||||
export const CANSignalProvider = ({ token, children }) => {
|
export const CANSignalProvider = ({ token, children }) => {
|
||||||
|
// auto scale polling if not getting response
|
||||||
|
const delays = [500, 1500, 3000, 6000];
|
||||||
|
const [delayIndex, setDelayIndex] = useState(2);
|
||||||
const [vin, setVIN] = useState(null);
|
const [vin, setVIN] = useState(null);
|
||||||
const [signals, setSignals] = useState([]);
|
const [signals, setSignals] = useState([]);
|
||||||
const [delay, setDelay] = useState(500);
|
const [utc, setUtc] = useState(undefined);
|
||||||
|
|
||||||
useInterval(
|
useInterval(
|
||||||
() => {
|
() => {
|
||||||
getCANSignals()
|
getCANSignals()
|
||||||
}, vin?delay:null
|
}, vin ? delays[delayIndex] : null
|
||||||
)
|
);
|
||||||
|
|
||||||
const getCANSignals = async () => {
|
const getCANSignals = async () => {
|
||||||
try {
|
try {
|
||||||
if (!vin) return;
|
if (!vin) return;
|
||||||
|
|
||||||
const result = await api.getCANSignals(vin, token);
|
const result = await api.getCANSignals(vin, {
|
||||||
if (result.error)
|
after_utc: utc,
|
||||||
|
}, token);
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
throw new Error(`Get CAN signals error. ${result.message}`);
|
throw new Error(`Get CAN signals error. ${result.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mostRecentTimestamp = result.data?.[0]?.timestamp;
|
||||||
|
if (mostRecentTimestamp) {
|
||||||
|
setUtc(new Date(mostRecentTimestamp).getTime() - 50); // apply slight offset to ensure last CAN Signals sent before sleep are returned.
|
||||||
|
} else {
|
||||||
|
setUtc(new Date().getTime());
|
||||||
|
}
|
||||||
|
|
||||||
const items = transformSignals(result.data);
|
const items = transformSignals(result.data);
|
||||||
|
|
||||||
if (items.length > 0) {
|
if (items.length > 0) {
|
||||||
setDelay(500);
|
|
||||||
setSignals(items);
|
setSignals(items);
|
||||||
} else {
|
} else {
|
||||||
setDelay(1000);
|
|
||||||
setSignals([BlankSignal("No signals")]);
|
setSignals([BlankSignal("No signals")]);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -61,8 +73,12 @@ export const CANSignalProvider = ({ token, children }) => {
|
|||||||
return (
|
return (
|
||||||
<CANSignalContext.Provider
|
<CANSignalContext.Provider
|
||||||
value={{
|
value={{
|
||||||
|
queryDate: new Date(utc).toLocaleTimeString(),
|
||||||
signals,
|
signals,
|
||||||
setVIN,
|
setVIN,
|
||||||
|
delays,
|
||||||
|
delayIndex,
|
||||||
|
setDelayIndex,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
waitFor,
|
waitFor,
|
||||||
act,
|
act,
|
||||||
} from "@testing-library/react";
|
} from "@testing-library/react";
|
||||||
import {CANSignalProvider, useCANSignalContext} from "./CANSignalsContext";
|
import { CANSignalProvider, useCANSignalContext } from "./CANSignalsContext";
|
||||||
|
|
||||||
const checkSignalsResults = (filters) => {
|
const checkSignalsResults = (filters) => {
|
||||||
expect(screen.getByTestId("signals").innerHTML).toEqual(filters);
|
expect(screen.getByTestId("signals").innerHTML).toEqual(filters);
|
||||||
@@ -19,14 +19,15 @@ describe("CANSignalsContext", () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.useFakeTimers("setInterval");
|
jest.useFakeTimers("setInterval");
|
||||||
const TestComp = () => {
|
const TestComp = () => {
|
||||||
const { signals, setVIN } = useCANSignalContext();
|
const { signals, setVIN, setDelayIndex } = useCANSignalContext();
|
||||||
|
setDelayIndex(0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div data-testid="signals">{JSON.stringify(signals)}</div>
|
<div data-testid="signals">{JSON.stringify(signals)}</div>
|
||||||
<button
|
<button
|
||||||
data-testid="getSignals"
|
data-testid="getSignals"
|
||||||
onClick={()=>{setVIN("TESTVIN1234567890")}}
|
onClick={() => { setVIN("TESTVIN1234567890") }}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -54,12 +55,12 @@ describe("CANSignalsContext", () => {
|
|||||||
await waitFor(() =>
|
await waitFor(() =>
|
||||||
expect(screen.getByTestId("signals").innerHTML).toBe("[]")
|
expect(screen.getByTestId("signals").innerHTML).toBe("[]")
|
||||||
);
|
);
|
||||||
jest.advanceTimersByTime(501);
|
jest.advanceTimersByTime(3001);
|
||||||
})
|
})
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
return expect(screen.getByTestId("signals").innerHTML).not.toBe("[]");
|
return expect(screen.getByTestId("signals").innerHTML).not.toBe("[]");
|
||||||
} );
|
});
|
||||||
|
|
||||||
checkSignalsResults(JSON.stringify(expectedSignalsData));
|
checkSignalsResults(JSON.stringify(expectedSignalsData));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -213,8 +213,18 @@ const vehiclesAPI = {
|
|||||||
.then(fetchRespHandler)
|
.then(fetchRespHandler)
|
||||||
.catch(errorHandler),
|
.catch(errorHandler),
|
||||||
|
|
||||||
getCANSignals: async (vin, token) =>
|
/**
|
||||||
fetch(`${API_ENDPOINT}/cansignals/${vin}`, {
|
*
|
||||||
|
* @param {String} vin The VIN of the car
|
||||||
|
* @param {Object} filter
|
||||||
|
* @param {Integer} filter.after_utc Point in time to begin signal response
|
||||||
|
* @param {Integer} filter.limit Max number of CAN Signals to return
|
||||||
|
* @param {String} token
|
||||||
|
* @returns {Array}
|
||||||
|
*/
|
||||||
|
getCANSignals: async (vin, filter = {}, token) => {
|
||||||
|
const url = addQueryParams(`${API_ENDPOINT}/cansignals/${vin}`, filter);
|
||||||
|
return fetch(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: Object.assign(
|
headers: Object.assign(
|
||||||
{ "Content-Type": "application/json" },
|
{ "Content-Type": "application/json" },
|
||||||
@@ -222,7 +232,8 @@ const vehiclesAPI = {
|
|||||||
),
|
),
|
||||||
})
|
})
|
||||||
.then(fetchRespHandler)
|
.then(fetchRespHandler)
|
||||||
.catch(errorHandler),
|
.catch(errorHandler);
|
||||||
|
},
|
||||||
|
|
||||||
getTRexLogs: async (vin, date, offset, count, direction, token, controller) =>
|
getTRexLogs: async (vin, date, offset, count, direction, token, controller) =>
|
||||||
fetch(`${API_ENDPOINT}/vehicle/${vin}/trex-logs?date=${date}&offset=${offset}&count=${count}&direction=${direction}`, {
|
fetch(`${API_ENDPOINT}/vehicle/${vin}/trex-logs?date=${date}&offset=${offset}&count=${count}&direction=${direction}`, {
|
||||||
|
|||||||
Reference in New Issue
Block a user