CEC-4517 reset TBOX remote command (#369)

* CEC-4517 Diagnostic Commands tab

* snapshot
This commit is contained in:
Eduard Voronkin
2023-06-23 12:38:09 -07:00
committed by GitHub
parent 3d4a07d8d8
commit fc7c1ea514
7 changed files with 236 additions and 3 deletions

View File

@@ -11242,7 +11242,7 @@ exports[`App Route /vehicle-status authenticated 1`] = `
<span <span
class="MuiTab-wrapper" class="MuiTab-wrapper"
> >
Fleets Remote Diagnostic Commands
</span> </span>
<span <span
class="MuiTouchRipple-root" class="MuiTouchRipple-root"
@@ -11256,6 +11256,24 @@ exports[`App Route /vehicle-status authenticated 1`] = `
role="tab" role="tab"
tabindex="-1" tabindex="-1"
type="button" type="button"
>
<span
class="MuiTab-wrapper"
>
Fleets
</span>
<span
class="MuiTouchRipple-root"
/>
</button>
<button
aria-controls="tabpanel-10"
aria-selected="false"
class="MuiButtonBase-root MuiTab-root MuiTab-textColorInherit"
id="tab-10"
role="tab"
tabindex="-1"
type="button"
> >
<span <span
class="MuiTab-wrapper" class="MuiTab-wrapper"
@@ -11590,6 +11608,13 @@ exports[`App Route /vehicle-status authenticated 1`] = `
id="tabpanel-9" id="tabpanel-9"
role="tabpanel" role="tabpanel"
/> />
<div
aria-labelledby="tab-10"
class="makeStyles-tabContainer-0"
hidden=""
id="tabpanel-10"
role="tabpanel"
/>
</div> </div>
</main> </main>
</main> </main>

View File

@@ -0,0 +1,30 @@
import useStyles from "../../useStyles";
import clsx from "clsx";
import Typography from "@material-ui/core/Typography";
import SendDiagnosticCommand from "../../Controls/SendDiagnosticCommand";
import { useParams } from "react-router";
import { useUserContext } from "../../Contexts/UserContext";
import {VehicleProvider} from "../../Contexts/VehicleContext";
const RemoteDiagnosticCommandsTab = (props) => {
const { vin } = useParams();
const classes = useStyles();
const {
token: {
idToken: { jwtToken: token },
},
} = useUserContext();
return (
<div className={clsx(classes.paper, classes.tableSize)}>
<Typography variant="h6">Vehicle Diagnostic Commands</Typography>
<VehicleProvider>
<SendDiagnosticCommand vin={vin} token={token} classes={classes}></SendDiagnosticCommand>
</VehicleProvider>
</div>
)
}
export default RemoteDiagnosticCommandsTab

View File

@@ -189,7 +189,7 @@ exports[`CarStatus Render 1`] = `
<span <span
class="MuiTab-wrapper" class="MuiTab-wrapper"
> >
Fleets Remote Diagnostic Commands
</span> </span>
<span <span
class="MuiTouchRipple-root" class="MuiTouchRipple-root"
@@ -203,6 +203,24 @@ exports[`CarStatus Render 1`] = `
role="tab" role="tab"
tabindex="-1" tabindex="-1"
type="button" type="button"
>
<span
class="MuiTab-wrapper"
>
Fleets
</span>
<span
class="MuiTouchRipple-root"
/>
</button>
<button
aria-controls="tabpanel-10"
aria-selected="false"
class="MuiButtonBase-root MuiTab-root MuiTab-textColorInherit"
id="tab-10"
role="tab"
tabindex="-1"
type="button"
> >
<span <span
class="MuiTab-wrapper" class="MuiTab-wrapper"
@@ -480,6 +498,13 @@ exports[`CarStatus Render 1`] = `
id="tabpanel-9" id="tabpanel-9"
role="tabpanel" role="tabpanel"
/> />
<div
aria-labelledby="tab-10"
class="makeStyles-tabContainer-0"
hidden=""
id="tabpanel-10"
role="tabpanel"
/>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -18,6 +18,7 @@ import DigitalTwinTab from "./DigitalTwinTab";
import ECUsTab from "./ECUsTab"; import ECUsTab from "./ECUsTab";
import FleetsTab from "./FleetsTab"; import FleetsTab from "./FleetsTab";
import RemoteCommandsTab from "./RemoteCommandsTab"; import RemoteCommandsTab from "./RemoteCommandsTab";
import RemoteDiagnosticCommandsTab from "./RemoteDiagnosticCommands";
import TRexLogsTab from "./TRexLogsTab"; import TRexLogsTab from "./TRexLogsTab";
const tabHashes = ["details", "updates", "filters"]; const tabHashes = ["details", "updates", "filters"];
@@ -63,6 +64,11 @@ const TabViews = [
component: RemoteCommandsTab, component: RemoteCommandsTab,
rolesPerProvider: Permissions.FiskerMagnaCreate, rolesPerProvider: Permissions.FiskerMagnaCreate,
}, },
{
label: "Remote Diagnostic Commands",
component: RemoteDiagnosticCommandsTab,
rolesPerProvider: Permissions.FiskerMagnaCreate,
},
{ {
label: "Fleets", label: "Fleets",
component: FleetsTab, component: FleetsTab,

View File

@@ -71,7 +71,7 @@ export const VehicleProvider = ({ children }) => {
const result = await api.addTags(vins, tags, token) const result = await api.addTags(vins, tags, token)
if (result.error) if (result.error)
throw new Error(`Add tags error. ${result.message}`); throw new Error(`Add tags error. ${result.message}`);
} finally { } finally {
setBusy(false) setBusy(false)
} }
@@ -202,6 +202,18 @@ export const VehicleProvider = ({ children }) => {
} }
}; };
const sendDiagnosticCommand = async (vins, command, token) => {
try {
setBusy(true);
const result = await api.sendDiagnosticCommand(vins, command, token);
if (result.error)
throw new Error(`Send diagnostic command error. ${result.message}`);
return result;
} finally {
setBusy(false);
}
};
const updateVehicle = async (vin, v, token) => { const updateVehicle = async (vin, v, token) => {
try { try {
setBusy(true); setBusy(true);
@@ -313,6 +325,7 @@ export const VehicleProvider = ({ children }) => {
getVehicle, getVehicle,
getVehicles, getVehicles,
sendCommand, sendCommand,
sendDiagnosticCommand,
updateVehicle, updateVehicle,
getFleets, getFleets,
getVersionLog, getVersionLog,

View File

@@ -0,0 +1,119 @@
import clsx from "clsx";
import { Button, FormControl, InputLabel, Select, FormControlLabel, FormGroup } from "@material-ui/core";
import Checkbox from '@mui/material/Checkbox';
import React, { useEffect, useState } from "react";
import { useStatusContext } from "../../Contexts/StatusContext";
import { logger } from "../../../services/monitoring";
import {
useVehicleContext
} from "../../Contexts/VehicleContext";
const commands = ["Reset"]
const ecus = ["TBOX"]
const SendDiagnosticCommand = ({ vin, token, classes }) => {
const { getState, sendDiagnosticCommand } = useVehicleContext();
const [carState, setCarState] = useState(null);
const { setMessage } = useStatusContext();
const [currentCommand, setCurrentCommand] = useState(commands[0].toLowerCase());
const [currentECUs] = useState([ecus[0]]);
const changeCommandHandler = (e) => {
setCurrentCommand(e.target.value);
};
//Update online/offline state
useEffect(() => {
if (!vin) return;
getCarState();
const interval = setInterval(getCarState, 5000);
return () => { clearInterval(interval); }
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [vin]);
const getCarState = async () => {
try {
const result = await getState(token, vin);
setCarState(result.data);
} catch (e) {
setMessage(e.message);
logger.warn(e.stack);
}
};
const clickHandler = async (_) => {
try {
await sendDiagnosticCommand([vin], { body: { command: currentCommand, ecus: currentECUs } }, token);
setMessage(`Sent diagnostic command to ${vin}`);
} catch (error) {
setMessage(error.message);
logger.error(error.stack);
}
};
return (
<div className={clsx(classes.paper, classes.tableSize)}>
<FormControl
className={classes.formControl}
variant="outlined"
size="small"
>
<InputLabel htmlFor="send-command" className={classes.whiteBackground}>
Diagnostic Command
</InputLabel>
<Select
native
variant="outlined"
inputProps={{
name: "send-command",
id: "send-command",
}}
onChange={changeCommandHandler}
>
{commands.map((command, index) => (
<option key={index} value={command.toLowerCase()}>
{command}
</option>
))}
</Select>
</FormControl>
<FormGroup>
{
ecus.map((ecu, idx) => {
return <FormControlLabel
control={<Checkbox key={idx} />}
label={ecu}
value={ecu}
checked={true} />
})
}
</FormGroup>
<Button
type="submit"
aria-label="send command"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
onClick={clickHandler}
disabled={!carState.online}
>
Send
</Button>
<div>
<b>
{carState && carState.online ? "ONLINE" : "OFFLINE"}
</b>
</div>
</div >
);
};
export default SendDiagnosticCommand;

View File

@@ -173,6 +173,21 @@ const vehiclesAPI = {
.then(fetchRespHandler) .then(fetchRespHandler)
.catch(errorHandler), .catch(errorHandler),
sendDiagnosticCommand: async (vins, command, token) =>
fetch(`${API_ENDPOINT}/vehiclediagnosticcommand`, {
method: "POST",
headers: Object.assign(
{ "Content-Type": "application/json" },
getAuthHeaderOptions(token)
),
body: JSON.stringify({
vins,
...command,
}),
})
.then(fetchRespHandler)
.catch(errorHandler),
updateVehicle: async (vin, vehicle, token) => updateVehicle: async (vin, vehicle, token) =>
fetch(`${API_ENDPOINT}/vehicle/${vin}`, { fetch(`${API_ENDPOINT}/vehicle/${vin}`, {
method: "PUT", method: "PUT",