frontend/src/gate/GateDevice.tsx

390 lines
12 KiB
TypeScript

import {
Box,
Button,
Card,
Grid2 as Grid,
MenuItem,
Select,
ToggleButton,
ToggleButtonGroup,
Typography
} from "@mui/material";
import { Component, Device } from "models";
import { Gate } from "models/Gate";
import { pond } from "protobuf-ts/pond";
import { useGlobalState, useGateAPI } from "providers";
import { useEffect, useState } from "react";
import { useMobile, useSnackbar } from "hooks";
import { UnitMeasurement } from "models/UnitMeasurement";
import { quack } from "protobuf-ts/quack";
import GateDeviceInteraction from "./GateDeviceInteraction";
import GateSVG from "./GateSVG";
import GateGraphs from "./GateGraphs";
//import { ToggleButton, ToggleButtonGroup } from "@material-ui/lab";
import { getThemeType } from "theme";
import ButtonGroup from "common/ButtonGroup";
interface Props {
gate: Gate;
comprehensiveDevice: pond.ComprehensiveDevice;
linkedCompList: Component[];
drawerView?: boolean;
}
export default function GateDevice(props: Props) {
const { gate, comprehensiveDevice, linkedCompList, drawerView } = props;
const [{as}] = useGlobalState();
const [device, setDevice] = useState<Device>(Device.create());
const [componentOptions, setComponentOptions] = useState<Map<string, Component>>(
new Map<string, Component>()
);
const gateAPI = useGateAPI();
const [tempKey, setTempKey] = useState("");
const [pressureKey, setPressureKey] = useState("");
const [ambientKey, setAmbientKey] = useState("");
const [greenLightKey, setGreenLightKey] = useState("");
const [redLightKey, setRedLightKey] = useState("");
const { openSnack } = useSnackbar();
const [{ user }] = useGlobalState();
const [interactionDialog, setInteractionDialog] = useState(false);
const [densityTemp, setDensityTemp] = useState(0);
const isMobile = useMobile();
// const [pcaState, setPCAState] = useState(false);
// const [pcaFanOn, setPCAFanOn] = useState(false);
const [detail, setDetail] = useState<"sensors" | "analytics">("analytics");
const [lastAmbient, setLastAmbient] = useState(0);
const [lastTemps, setLastTemps] = useState({ t1: 0, t2: 0 });
const [lastPressures, setLastPressures] = useState({ p1: 0, p2: 0 });
useEffect(() => {
//addresses of controller LEDs on a V1 device
let redAddr = "3-1-512";
let greenAddr = "3-1-1024";
if (comprehensiveDevice.device) {
setDevice(Device.any(comprehensiveDevice.device));
//check if the device is a MiPCA V2 device since the lEDs will have different addresses
let dev = Device.create(comprehensiveDevice.device);
if (dev.settings.product === pond.DeviceProduct.DEVICE_PRODUCT_MIPCA_V2) {
redAddr = "3-1-256";
greenAddr = "3-1-512";
}
}
if (comprehensiveDevice.components) {
let components: Map<string, Component> = new Map<string, Component>();
setAmbientKey("");
setTempKey("");
setPressureKey("");
comprehensiveDevice.components.forEach(comp => {
let c = Component.any(comp);
if (linkedCompList.some(el => el.key() === c.key())) {
components.set(c.key(), c);
//determine the positioned components using the gates preferences for it components
switch (gate.preferences[c.key()]) {
case pond.GateComponentType.GATE_COMPONENT_TYPE_AMBIENT:
setAmbientKey(c.key());
c.status.measurement.forEach(um => {
let measurement = UnitMeasurement.any(um, user);
if (measurement.type === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE) {
if (measurement.values.length > 1 && measurement.values[0].values.length > 0) {
setDensityTemp(measurement.values[0].values[0]);
}
}
});
break;
case pond.GateComponentType.GATE_COMPONENT_TYPE_TEMP:
setTempKey(c.key());
break;
case pond.GateComponentType.GATE_COMPONENT_TYPE_PRESSURE:
setPressureKey(c.key());
// if (
// c.status.measurement[0] &&
// c.status.measurement[0].values[0] &&
// c.status.measurement[0].values[0].values[1]
// ) {
// setPCAFanOn(c.status.measurement[0].values[0].values[1] > 996); //apx 4 iwg
// }
break;
default:
// type is unknown, do nothing
break;
}
}
if (c.locationString() === redAddr && c.subType() === 1) {
setRedLightKey(c.key());
} else if (c.locationString() === greenAddr && c.subType() === 1) {
setGreenLightKey(c.key());
}
});
setComponentOptions(components);
}
}, [comprehensiveDevice, gate, linkedCompList, user]);
const gateComponentUpdate = (componentKey: string, gateCompType: pond.GateComponentType) => {
if (componentKey !== "") {
gateAPI
.updatePrefs(
gate.key,
"component",
device.id() + ":" + componentKey,
gateCompType,
[gate.key],
["gate"],
as
)
.then(resp => {
openSnack("Component Prefence Updated");
});
}
};
useEffect(() => {
let tempComponent = componentOptions.get(tempKey);
let t1 = 0;
let t2 = 0;
if (tempComponent) {
tempComponent.status.measurement.forEach(um => {
let measurement = UnitMeasurement.any(um, user);
if (
measurement.type === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE &&
measurement.values.length > 0
) {
let nodeVals = measurement.values[0].values;
if (nodeVals.length > 1) {
t1 = nodeVals[0]; //uses the first node
t2 = nodeVals[1]; //uses second node node
}
}
});
}
setLastTemps({ t1, t2 });
}, [componentOptions, tempKey, user]);
useEffect(() => {
let ambientComponent = componentOptions.get(ambientKey);
let temp = 0;
if (ambientComponent) {
ambientComponent.status.measurement.forEach(um => {
let measurement = UnitMeasurement.any(um, user);
if (measurement.type === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE) {
if (measurement.values.length > 0 && measurement.values[0].values.length > 0) {
temp = measurement.values[0].values[0];
}
}
});
}
setLastAmbient(temp);
}, [componentOptions, ambientKey, user]);
useEffect(() => {
let pressureComponent = componentOptions.get(pressureKey);
let p1 = 0;
let p2 = 0;
if (pressureComponent) {
pressureComponent.status.measurement.forEach(um => {
let measurement = UnitMeasurement.any(um, user);
if (
measurement.type === quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE &&
measurement.values.length > 0
) {
let nodeVals = measurement.values[0].values;
if (nodeVals.length > 1) {
p1 = nodeVals[0];
p2 = nodeVals[1];
}
}
});
}
setLastPressures({ p1, p2 });
}, [componentOptions, pressureKey, user]);
const ambientSelector = () => {
return (
<Select
id="ambientSelect"
variant="standard"
value={ambientKey}
style={{ fontSize: 8 }}
onChange={e => {
var key = e.target.value as string;
gateComponentUpdate(key, pond.GateComponentType.GATE_COMPONENT_TYPE_AMBIENT);
setAmbientKey(key);
if (tempKey === key) {
setTempKey("");
}
if (pressureKey === key) {
setPressureKey("");
}
}}
displayEmpty>
<MenuItem value="">
<em>Select Ambient Sensor</em>
</MenuItem>
{Array.from(componentOptions.values()).map(c => {
return (
<MenuItem key={c.key()} value={c.key()}>
{c.name()}
</MenuItem>
);
})}
</Select>
);
};
const tempSelector = () => {
return (
<Select
id="tempSelect"
variant="standard"
value={tempKey}
style={{ fontSize: 8 }}
onChange={e => {
gateComponentUpdate(
e.target.value as string,
pond.GateComponentType.GATE_COMPONENT_TYPE_TEMP
);
setTempKey(e.target.value as string);
if (pressureKey === e.target.value) {
setPressureKey("");
}
if (ambientKey === e.target.value) {
setAmbientKey("");
}
}}
displayEmpty>
<MenuItem value="">
<em>Select Temperature Chain</em>
</MenuItem>
{Array.from(componentOptions.values()).map(c => {
return (
<MenuItem key={c.key()} value={c.key()}>
{c.name()}
</MenuItem>
);
})}
</Select>
);
};
const pressureSelector = () => {
return (
<Select
id="pressureSelect"
variant="standard"
value={pressureKey}
style={{ fontSize: 8 }}
onChange={e => {
gateComponentUpdate(
e.target.value as string,
pond.GateComponentType.GATE_COMPONENT_TYPE_PRESSURE
);
setPressureKey(e.target.value as string);
if (tempKey === e.target.value) {
setTempKey("");
}
if (ambientKey === e.target.value) {
setAmbientKey("");
}
}}
displayEmpty>
<MenuItem value="">
<em>Select Pressure Chain</em>
</MenuItem>
{Array.from(componentOptions.values()).map(c => {
return (
<MenuItem key={c.key()} value={c.key()}>
{c.name()}
</MenuItem>
);
})}
</Select>
);
};
return (
<Grid
container
// direction={(isMobile) ? "column" : "row"}
width="100%"
//alignItems="center"
>
<Grid width={"100%"} size={{ sm: 12, lg: isMobile || drawerView ? 12 : 4}} style={{ padding: 10 }}>
<Box
display="flex"
justifyContent="space-between"
alignItems="center"
marginBottom={2}>
<Typography style={{ fontWeight: 650, fontSize: 20 }}>{device.name()}</Typography>
<ButtonGroup
toggle
buttons={[
{
title: "Analysis",
function: () => setDetail("analytics")
},
{
title: "Sensors",
function: () => setDetail("sensors")
}
]}
/>
</Box>
<Card>
<GateSVG
finalTemp={
gate.gateMutations[device.id().toString()] &&
!isNaN(gate.gateMutations[device.id().toString()].temp)
? gate.gateMutations[device.id().toString()].temp
: 0
}
ambientTemp={lastAmbient}
innerTemps={lastTemps}
innerPressures={lastPressures}
ambientSelector={ambientSelector}
tempChainSelector={tempSelector}
pressureChainSelector={pressureSelector}
pcaState={gate.status.pcaState}
// pcaFanState={pcaFanOn}
checkInTime={device.status.lastActive}
/>
<Button
variant="contained"
color="primary"
fullWidth
onClick={() => {
setInteractionDialog(true);
}}>
Set Interactions
</Button>
</Card>
<GateDeviceInteraction
open={interactionDialog}
gate={gate}
compDevice={comprehensiveDevice}
densityTemp={densityTemp}
close={canceled => {
setInteractionDialog(false);
}}
/>
</Grid>
<Grid size={{ sm: 12, lg: isMobile || drawerView ? 12 : 8}} style={{ padding: 10 }}>
<GateGraphs
gate={gate}
display={detail}
compMap={componentOptions}
// setPCAState={(state: boolean) => {
// setPCAState(state);
// }}
ambient={ambientKey}
pressure={pressureKey}
tempChain={tempKey}
redKey={redLightKey}
greenKey={greenLightKey}
device={device.id()}
/>
</Grid>
</Grid>
);
}