Merge branch 'object_status' into staging_environment
This commit is contained in:
commit
cc4d0d5736
7 changed files with 295 additions and 93 deletions
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -42,7 +42,7 @@
|
||||||
"mui-tel-input": "^7.0.0",
|
"mui-tel-input": "^7.0.0",
|
||||||
"notistack": "^3.0.1",
|
"notistack": "^3.0.1",
|
||||||
"openweathermap-ts": "^1.2.10",
|
"openweathermap-ts": "^1.2.10",
|
||||||
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#object_status",
|
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#staging",
|
||||||
"query-string": "^9.2.1",
|
"query-string": "^9.2.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-beautiful-dnd": "^13.1.1",
|
"react-beautiful-dnd": "^13.1.1",
|
||||||
|
|
@ -10953,7 +10953,7 @@
|
||||||
},
|
},
|
||||||
"node_modules/protobuf-ts": {
|
"node_modules/protobuf-ts": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#75f64f81d9b4ba7639d9978af37c361fca34c279",
|
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#c9ef7906fd97cda8ef4bd149ec4a796159a7c067",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"protobufjs": "^6.8.8"
|
"protobufjs": "^6.8.8"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@
|
||||||
"mui-tel-input": "^7.0.0",
|
"mui-tel-input": "^7.0.0",
|
||||||
"notistack": "^3.0.1",
|
"notistack": "^3.0.1",
|
||||||
"openweathermap-ts": "^1.2.10",
|
"openweathermap-ts": "^1.2.10",
|
||||||
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#object_status",
|
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#staging",
|
||||||
"query-string": "^9.2.1",
|
"query-string": "^9.2.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-beautiful-dnd": "^13.1.1",
|
"react-beautiful-dnd": "^13.1.1",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { Button, DialogActions, DialogContent, DialogTitle, Typography } from "@mui/material";
|
import { CheckBox } from "@mui/icons-material";
|
||||||
|
import { Button, Checkbox, DialogActions, DialogContent, DialogTitle, FormControl, FormControlLabel, FormLabel, InputAdornment, TextField, Typography } from "@mui/material";
|
||||||
import ResponsiveDialog from "common/ResponsiveDialog";
|
import ResponsiveDialog from "common/ResponsiveDialog";
|
||||||
import { Component, Device } from "models";
|
import { Component, Device } from "models";
|
||||||
import { Gate } from "models/Gate";
|
import { Gate } from "models/Gate";
|
||||||
|
|
@ -6,6 +7,7 @@ import moment from "moment";
|
||||||
import { pond, quack } from "protobuf-ts/pond";
|
import { pond, quack } from "protobuf-ts/pond";
|
||||||
import { useGlobalState, useInteractionsAPI, useSnackbar } from "providers";
|
import { useGlobalState, useInteractionsAPI, useSnackbar } from "providers";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { getPressureUnit } from "utils";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
|
@ -37,6 +39,7 @@ const densityMap = new Map<number, number>([
|
||||||
export default function GateDeviceInteraction(props: Props) {
|
export default function GateDeviceInteraction(props: Props) {
|
||||||
const { open, close, gate, compDevice, densityTemp } = props;
|
const { open, close, gate, compDevice, densityTemp } = props;
|
||||||
const [{ user, as }] = useGlobalState();
|
const [{ user, as }] = useGlobalState();
|
||||||
|
const [device, setDevice] = useState<Device>(Device.create())
|
||||||
const [lowDelta, setLowDelta] = useState(0);
|
const [lowDelta, setLowDelta] = useState(0);
|
||||||
const [highDelta, setHighDelta] = useState(0);
|
const [highDelta, setHighDelta] = useState(0);
|
||||||
const [greenComponent, setGreenComponent] = useState<Component>();
|
const [greenComponent, setGreenComponent] = useState<Component>();
|
||||||
|
|
@ -44,7 +47,12 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
const [pressureComponent, setPressureComponent] = useState<Component>();
|
const [pressureComponent, setPressureComponent] = useState<Component>();
|
||||||
const interactionsAPI = useInteractionsAPI();
|
const interactionsAPI = useInteractionsAPI();
|
||||||
const [adding, setAdding] = useState(false);
|
const [adding, setAdding] = useState(false);
|
||||||
|
//boolean to determine if a third condition should be put on the interaction for the red light, requires a V2 device running at least fromware version 2.1.9
|
||||||
|
const [useRedOffCondition, setUseRedOffCondition] = useState(false)
|
||||||
|
//if the pressure is under this value then the red light should be off
|
||||||
|
const [redThreshold, setRedThreshold] = useState("0")
|
||||||
const { openSnack } = useSnackbar();
|
const { openSnack } = useSnackbar();
|
||||||
|
const [pressureSource, setPressureSource] = useState<quack.ComponentID>(quack.ComponentID.create())
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
//math to determine what the delta pressures to set will be
|
//math to determine what the delta pressures to set will be
|
||||||
|
|
@ -95,46 +103,64 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
gate.preferences[component.key()] === pond.GateComponentType.GATE_COMPONENT_TYPE_PRESSURE
|
gate.preferences[component.key()] === pond.GateComponentType.GATE_COMPONENT_TYPE_PRESSURE
|
||||||
) {
|
) {
|
||||||
setPressureComponent(component);
|
setPressureComponent(component);
|
||||||
|
setPressureSource(
|
||||||
|
quack.ComponentID.create({
|
||||||
|
type: component.type(),
|
||||||
|
address: component.settings.address,
|
||||||
|
addressType: component.settings.addressType
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(compDevice.device){
|
||||||
|
setDevice(Device.create(compDevice.device))
|
||||||
|
}
|
||||||
}, [gate, densityTemp, user, compDevice]);
|
}, [gate, densityTemp, user, compDevice]);
|
||||||
|
|
||||||
// useEffect(() => {
|
const buttonDisabled = () => {
|
||||||
// //load current interactions for the device
|
if (greenComponent === undefined) return true
|
||||||
// let deviceID = Device.any(compDevice.device).id();
|
if (redComponent === undefined) return true
|
||||||
// interactionsAPI.listInteractionsByDevice(deviceID).then(resp => {
|
if (adding) return true
|
||||||
// setCurrentInteractions(resp);
|
if (useRedOffCondition && isNaN(parseFloat(redThreshold))) return true
|
||||||
// });
|
return false
|
||||||
// }, [compDevice.device, interactionsAPI]);
|
}
|
||||||
|
|
||||||
// const removeCurrentInteractions = () => {
|
|
||||||
// let deviceID = Device.any(compDevice.device).id();
|
|
||||||
// currentInteractions.forEach(interaction => {
|
|
||||||
// interactionsAPI.removeInteraction(deviceID, interaction.key());
|
|
||||||
// });
|
|
||||||
// };
|
|
||||||
|
|
||||||
const createInteractions = async () => {
|
const createInteractions = async () => {
|
||||||
//the interactions to be made
|
//the interactions to be made
|
||||||
|
|
||||||
//TOGGLE green ON when pressure within range of upper and lower
|
|
||||||
if (
|
if (
|
||||||
greenComponent !== undefined &&
|
greenComponent !== undefined &&
|
||||||
redComponent !== undefined &&
|
redComponent !== undefined &&
|
||||||
pressureComponent !== undefined
|
pressureComponent !== undefined
|
||||||
) {
|
) {
|
||||||
let greenToggle: pond.InteractionSettings = pond.InteractionSettings.create({
|
|
||||||
sink: quack.ComponentID.create({
|
let lightInteractions: pond.InteractionSettings[] = []
|
||||||
type: greenComponent.type(),
|
//making variables for the parameters of the interactions
|
||||||
address: greenComponent.settings.address,
|
const redSink = quack.ComponentID.create({
|
||||||
addressType: greenComponent.settings.addressType
|
type: redComponent.type(),
|
||||||
}),
|
address: redComponent.settings.address,
|
||||||
source: quack.ComponentID.create({
|
addressType: redComponent.settings.addressType
|
||||||
type: pressureComponent.type(),
|
})
|
||||||
address: pressureComponent.settings.address,
|
|
||||||
addressType: pressureComponent.settings.addressType
|
const greenSink = quack.ComponentID.create({
|
||||||
}),
|
type: greenComponent.type(),
|
||||||
|
address: greenComponent.settings.address,
|
||||||
|
addressType: greenComponent.settings.addressType
|
||||||
|
})
|
||||||
|
|
||||||
|
const lightSchedule = pond.InteractionSchedule.create({
|
||||||
|
timezone: moment.tz.guess(),
|
||||||
|
weekdays: ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"],
|
||||||
|
timeOfDayStart: "00:00",
|
||||||
|
timeOfDayEnd: "24:00"
|
||||||
|
})
|
||||||
|
|
||||||
|
//TOGGLE green ON when pressure within range of upper and lower, this will always be the same regardless
|
||||||
|
lightInteractions.push(pond.InteractionSettings.create({
|
||||||
|
sink: greenSink,
|
||||||
|
source: pressureSource,
|
||||||
conditions: [
|
conditions: [
|
||||||
pond.InteractionCondition.create({
|
pond.InteractionCondition.create({
|
||||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||||
|
|
@ -150,61 +176,146 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
nodeOne: 2,
|
nodeOne: 2,
|
||||||
nodeTwo: 1,
|
nodeTwo: 1,
|
||||||
subtype: 18,
|
subtype: 18,
|
||||||
schedule: pond.InteractionSchedule.create({
|
schedule: lightSchedule,
|
||||||
timezone: moment.tz.guess(),
|
|
||||||
weekdays: ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"],
|
|
||||||
timeOfDayStart: "00:00",
|
|
||||||
timeOfDayEnd: "24:00"
|
|
||||||
}),
|
|
||||||
result: pond.InteractionResult.create({
|
result: pond.InteractionResult.create({
|
||||||
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE,
|
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE,
|
||||||
value: 1
|
value: 1
|
||||||
})
|
})
|
||||||
});
|
}))
|
||||||
|
|
||||||
//TOGGLE red OFF when pressure within range of upper and lower
|
//if they want the red light off when below a certain pressure, it will need 4 seperate SET interactions
|
||||||
let redToggle: pond.InteractionSettings = pond.InteractionSettings.create({
|
if(useRedOffCondition){
|
||||||
sink: quack.ComponentID.create({
|
//need to make sure the redthreshold is in pascals
|
||||||
type: redComponent.type(),
|
let thresholdPascals = 0
|
||||||
address: redComponent.settings.address,
|
if(!isNaN(parseFloat(redThreshold))){
|
||||||
addressType: redComponent.settings.addressType
|
if(getPressureUnit() === pond.PressureUnit.PRESSURE_UNIT_KILOPASCALS){
|
||||||
}),
|
thresholdPascals = parseFloat(redThreshold)*1000
|
||||||
source: quack.ComponentID.create({
|
}else if (getPressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER){
|
||||||
type: pressureComponent.type(),
|
thresholdPascals = parseFloat(redThreshold)*249
|
||||||
address: pressureComponent.settings.address,
|
}
|
||||||
addressType: pressureComponent.settings.addressType
|
}
|
||||||
}),
|
|
||||||
conditions: [
|
//SET red on when above high
|
||||||
pond.InteractionCondition.create({
|
lightInteractions.push(pond.InteractionSettings.create({
|
||||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
sink: redSink,
|
||||||
value: -highDelta,
|
source: pressureSource,
|
||||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
conditions: [
|
||||||
}),
|
pond.InteractionCondition.create({
|
||||||
pond.InteractionCondition.create({
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
value: -highDelta,
|
||||||
value: -lowDelta,
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
})
|
||||||
|
],
|
||||||
|
nodeOne: 2,
|
||||||
|
nodeTwo: 1,
|
||||||
|
subtype: 18,
|
||||||
|
schedule: lightSchedule,
|
||||||
|
result: pond.InteractionResult.create({
|
||||||
|
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
||||||
|
value: 1
|
||||||
})
|
})
|
||||||
],
|
}))
|
||||||
nodeOne: 2,
|
//SET red off when below high and above low
|
||||||
nodeTwo: 1,
|
lightInteractions.push(pond.InteractionSettings.create({
|
||||||
subtype: 18,
|
sink: redSink,
|
||||||
schedule: pond.InteractionSchedule.create({
|
source: pressureSource,
|
||||||
timezone: moment.tz.guess(),
|
conditions: [
|
||||||
weekdays: ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"],
|
pond.InteractionCondition.create({
|
||||||
timeOfDayStart: "00:00",
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||||
timeOfDayEnd: "24:00"
|
value: -highDelta,
|
||||||
}),
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
result: pond.InteractionResult.create({
|
}),
|
||||||
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE,
|
pond.InteractionCondition.create({
|
||||||
value: 0
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||||
})
|
value: -lowDelta,
|
||||||
});
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
|
})
|
||||||
|
],
|
||||||
|
nodeOne: 2,
|
||||||
|
nodeTwo: 1,
|
||||||
|
subtype: 18,
|
||||||
|
schedule: lightSchedule,
|
||||||
|
result: pond.InteractionResult.create({
|
||||||
|
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
||||||
|
value: 0
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
//SET red on when below low and above threshold
|
||||||
|
lightInteractions.push(pond.InteractionSettings.create({
|
||||||
|
sink: redSink,
|
||||||
|
source: pressureSource,
|
||||||
|
conditions: [
|
||||||
|
pond.InteractionCondition.create({
|
||||||
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||||
|
value: -lowDelta,
|
||||||
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
|
}),
|
||||||
|
pond.InteractionCondition.create({
|
||||||
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||||
|
value: -thresholdPascals,
|
||||||
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
nodeOne: 2,
|
||||||
|
nodeTwo: 1,
|
||||||
|
subtype: 18,
|
||||||
|
schedule: lightSchedule,
|
||||||
|
result: pond.InteractionResult.create({
|
||||||
|
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
||||||
|
value: 1
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
//SET red off when below threshold
|
||||||
|
lightInteractions.push(pond.InteractionSettings.create({
|
||||||
|
sink: redSink,
|
||||||
|
source: pressureSource,
|
||||||
|
conditions: [
|
||||||
|
pond.InteractionCondition.create({
|
||||||
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||||
|
value: thresholdPascals,
|
||||||
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
subtype: 1,
|
||||||
|
schedule: lightSchedule,
|
||||||
|
result: pond.InteractionResult.create({
|
||||||
|
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
||||||
|
value: 0
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
}else{
|
||||||
|
//otherwise use the regular single TOGGLE interaction
|
||||||
|
//TOGGLE red OFF when pressure within range of upper and lower
|
||||||
|
lightInteractions.push(pond.InteractionSettings.create({
|
||||||
|
sink: redSink,
|
||||||
|
source: pressureSource,
|
||||||
|
conditions: [
|
||||||
|
pond.InteractionCondition.create({
|
||||||
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||||
|
value: -highDelta,
|
||||||
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
|
}),
|
||||||
|
pond.InteractionCondition.create({
|
||||||
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||||
|
value: -lowDelta,
|
||||||
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
|
})
|
||||||
|
],
|
||||||
|
nodeOne: 2,
|
||||||
|
nodeTwo: 1,
|
||||||
|
subtype: 18,
|
||||||
|
schedule: lightSchedule,
|
||||||
|
result: pond.InteractionResult.create({
|
||||||
|
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE,
|
||||||
|
value: 0
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
let deviceID = Device.any(compDevice.device).id();
|
let deviceID = Device.any(compDevice.device).id();
|
||||||
if (deviceID !== undefined) {
|
if (deviceID !== undefined) {
|
||||||
let multi = pond.MultiInteractionSettings.create({
|
let multi = pond.MultiInteractionSettings.create({
|
||||||
interactions: [greenToggle, redToggle]
|
interactions: lightInteractions
|
||||||
});
|
});
|
||||||
interactionsAPI
|
interactionsAPI
|
||||||
.addMultiInteractions(deviceID, multi, as)
|
.addMultiInteractions(deviceID, multi, as)
|
||||||
|
|
@ -230,11 +341,51 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
}}>
|
}}>
|
||||||
<DialogTitle>Set Interaction For Light Toggle</DialogTitle>
|
<DialogTitle>Set Interaction For Light Toggle</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
Your Delta Pressures, in pascals, will be:
|
{/* Your Delta Pressures, in pascals, will be:
|
||||||
<Typography>low = {lowDelta}</Typography>
|
<Typography>low = {lowDelta}</Typography>
|
||||||
<Typography>high = {highDelta}</Typography>
|
<Typography>high = {highDelta}</Typography>
|
||||||
<Typography>{greenComponent ? "" : "Green LED Component not found"}</Typography>
|
<Typography>{greenComponent ? "" : "Green LED Component not found"}</Typography>
|
||||||
<Typography>{redComponent ? "" : "Red LED Component not found"}</Typography>
|
<Typography>{redComponent ? "" : "Red LED Component not found"}</Typography> */}
|
||||||
|
<Typography>
|
||||||
|
This will clear existing interactions on the pressure chain and set new ones to toggle the green light on and the red light off
|
||||||
|
when the difference between the pressures falls within this range and vice versa:
|
||||||
|
</Typography>
|
||||||
|
<br />
|
||||||
|
<Typography>Upper Limit: {getPressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? (highDelta/249.089).toFixed(2) + " iwg" : highDelta/1000 + " kPa"}</Typography>
|
||||||
|
<Typography>Lower Limit: {getPressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? (lowDelta/249.089).toFixed(2) + " iwg" : lowDelta/1000 + " kPa"}</Typography>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<Typography>If you would like to have the interactions set in such a way that if the average pressure falls below a given value set the use off condition and set the value to use</Typography>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={useRedOffCondition}
|
||||||
|
onChange={(e, checked) => {
|
||||||
|
setUseRedOffCondition(checked)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={<Typography>Use Off Condition</Typography>}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
type="number"
|
||||||
|
fullWidth
|
||||||
|
disabled={!useRedOffCondition}
|
||||||
|
value={redThreshold}
|
||||||
|
error={isNaN(parseFloat(redThreshold))}
|
||||||
|
helperText={isNaN(parseFloat(redThreshold)) ? "Must be a valid number" : ""}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
{getPressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? "iwg" : "kPa"}
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
onChange={e => {
|
||||||
|
setRedThreshold(e.target.value)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -244,9 +395,13 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
//TODO: Once we figure out how to fix the backend to handle rapid addition/removal of interactions
|
//TODO: Once we figure out how to fix the backend to handle rapid addition/removal of interactions
|
||||||
//removeCurrentInteractions();
|
//removeCurrentInteractions();
|
||||||
setAdding(true);
|
setAdding(true);
|
||||||
createInteractions();
|
interactionsAPI.clearInteractions(device.id(), [pressureSource]).then(resp => {
|
||||||
|
createInteractions();
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
}}
|
}}
|
||||||
disabled={greenComponent === undefined || redComponent === undefined || adding}>
|
disabled={buttonDisabled()}>
|
||||||
{adding ? "Adding Interaction" : "Create Interaction"}
|
{adding ? "Adding Interaction" : "Create Interaction"}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
|
|
|
||||||
|
|
@ -70,13 +70,19 @@ export default function GateFlowGraph(props: Props) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [flowEvents, setFlowEvents] = useState<pond.AirFlowEvent[]>([]);
|
const [flowEvents, setFlowEvents] = useState<pond.AirFlowEvent[]>([]);
|
||||||
const [eventsLoading, setEventsLoading] = useState(false);
|
const [eventsLoading, setEventsLoading] = useState(false);
|
||||||
//these two constants could be entered by the user at time of retrieval
|
//these two constants could be entered by the user at time of retrieval or set in the gates settings
|
||||||
const eventThreshold = 5; //the threshold that if crossed from one measurement to the next during a flow event will end the current flow event and start a new one
|
const eventThreshold = 5; //the threshold that if crossed from one measurement to the next during a flow event will end the current flow event and start a new one
|
||||||
const idleFlow = 3.5; //the mass air flow that must be crossed in order to start a flow event, anything below this will not start an event but must go below this to end an event
|
//const idleFlow = 3.5; //the mass air flow that must be crossed in order to start a flow event, anything below this will not start an event but must go below this to end an event
|
||||||
|
const [idleFlow, setIdleFlow] = useState(3.5)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (loadingChartData) return;
|
if (loadingChartData) return;
|
||||||
if (ambient && pressureComponent) {
|
if (ambient && pressureComponent) {
|
||||||
|
let gateIdle = idleFlow
|
||||||
|
if(gate.settings.idleFlow){
|
||||||
|
gateIdle = gate.settings.idleFlow
|
||||||
|
}
|
||||||
|
|
||||||
let recent: SSAreaDataPoint | undefined;
|
let recent: SSAreaDataPoint | undefined;
|
||||||
setLoadingChartData(true);
|
setLoadingChartData(true);
|
||||||
gateAPI
|
gateAPI
|
||||||
|
|
@ -110,11 +116,11 @@ export default function GateFlowGraph(props: Props) {
|
||||||
|
|
||||||
/** determine runtime */
|
/** determine runtime */
|
||||||
// set the start time if the values is greater than the idleFlow and start is not already set
|
// set the start time if the values is greater than the idleFlow and start is not already set
|
||||||
if (val.airFlow >= idleFlow && !start) {
|
if (val.airFlow >= gateIdle && !start) {
|
||||||
start = time;
|
start = time;
|
||||||
}
|
}
|
||||||
// set the stop time when off or at the last measurements and the start time is set
|
// set the stop time when off or at the last measurements and the start time is set
|
||||||
if ((val.airFlow < idleFlow || i === resp.data.values.length - idleFlow) && start) {
|
if ((val.airFlow < gateIdle || i === resp.data.values.length - gateIdle) && start) {
|
||||||
stop = time;
|
stop = time;
|
||||||
}
|
}
|
||||||
// if both start and stop are set calculate add the timeframe to the total runtime
|
// if both start and stop are set calculate add the timeframe to the total runtime
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
||||||
import AddGateFab from "./AddGateFab";
|
import AddGateFab from "./AddGateFab";
|
||||||
import GateSettings from "./GateSettings";
|
import GateSettings from "./GateSettings";
|
||||||
import { useGateAPI, useGlobalState } from "providers";
|
import { useGateAPI, useGlobalState } from "providers";
|
||||||
import { CheckCircleOutline, DoNotDisturb, ErrorOutline, RemoveCircleOutline, Settings } from "@mui/icons-material";
|
import { CheckCircleOutline, DoNotDisturb, ErrorOutline, HelpOutlineOutlined, Settings } from "@mui/icons-material";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
|
@ -94,13 +94,13 @@ export default function GateList(props: Props) {
|
||||||
const displayPCAStatus = (state: pond.PCAState) => {
|
const displayPCAStatus = (state: pond.PCAState) => {
|
||||||
switch(state){
|
switch(state){
|
||||||
case pond.PCAState.PCA_STATE_IN_BOUNDS:
|
case pond.PCAState.PCA_STATE_IN_BOUNDS:
|
||||||
return <CheckCircleOutline sx={{color: "green"}}/>
|
return <CheckCircleOutline sx={{color: "green"}}/>
|
||||||
case pond.PCAState.PCA_STATE_OUT_BOUNDS:
|
case pond.PCAState.PCA_STATE_OUT_BOUNDS:
|
||||||
return <ErrorOutline sx={{color: "red"}} />
|
return <ErrorOutline sx={{color: "red"}} />
|
||||||
case pond.PCAState.PCA_STATE_OFF:
|
case pond.PCAState.PCA_STATE_OFF:
|
||||||
return <RemoveCircleOutline />
|
|
||||||
default:
|
|
||||||
return <DoNotDisturb />
|
return <DoNotDisturb />
|
||||||
|
default:
|
||||||
|
return <HelpOutlineOutlined />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ export default function GateSettings(props: Props) {
|
||||||
//user set identifier to be shown on the marker on the map
|
//user set identifier to be shown on the marker on the map
|
||||||
const [terminalIdentifier, setTerminalIdentifier] = useState("");
|
const [terminalIdentifier, setTerminalIdentifier] = useState("");
|
||||||
const [gateIdentifier, setGateIdentifier] = useState("");
|
const [gateIdentifier, setGateIdentifier] = useState("");
|
||||||
|
const [idleLimit, setIdleLimit] = useState<number>(0);
|
||||||
const [hourlyPCA, setHourlyPCA] = useState<number>(0);
|
const [hourlyPCA, setHourlyPCA] = useState<number>(0);
|
||||||
const [hourlyAPU, setHourlyAPU] = useState<number>(0);
|
const [hourlyAPU, setHourlyAPU] = useState<number>(0);
|
||||||
|
|
||||||
|
|
@ -140,6 +141,7 @@ export default function GateSettings(props: Props) {
|
||||||
settings.thermalResistance = ductProps.thermalResistance;
|
settings.thermalResistance = ductProps.thermalResistance;
|
||||||
settings.lowerFlow = lowerFlowBound;
|
settings.lowerFlow = lowerFlowBound;
|
||||||
settings.upperFlow = upperFlowBound;
|
settings.upperFlow = upperFlowBound;
|
||||||
|
settings.idleFlow = idleLimit;
|
||||||
settings.ductName = ductName;
|
settings.ductName = ductName;
|
||||||
settings.pcaType = pcaUnit;
|
settings.pcaType = pcaUnit;
|
||||||
settings.letterIdentifier = terminalIdentifier;
|
settings.letterIdentifier = terminalIdentifier;
|
||||||
|
|
@ -167,6 +169,7 @@ export default function GateSettings(props: Props) {
|
||||||
thermalResistance: ductProps.thermalResistance,
|
thermalResistance: ductProps.thermalResistance,
|
||||||
lowerFlow: lowerFlowBound,
|
lowerFlow: lowerFlowBound,
|
||||||
upperFlow: upperFlowBound,
|
upperFlow: upperFlowBound,
|
||||||
|
idleFlow: idleLimit,
|
||||||
ductName: ductName,
|
ductName: ductName,
|
||||||
pcaType: pcaUnit,
|
pcaType: pcaUnit,
|
||||||
letterIdentifier: terminalIdentifier,
|
letterIdentifier: terminalIdentifier,
|
||||||
|
|
@ -283,16 +286,18 @@ export default function GateSettings(props: Props) {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<TextField
|
<TextField
|
||||||
|
margin="dense"
|
||||||
label="Gate Name"
|
label="Gate Name"
|
||||||
fullWidth
|
fullWidth
|
||||||
value={gateName}
|
value={gateName}
|
||||||
onChange={e => setGateName(e.target.value)}
|
onChange={e => setGateName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
<Select
|
<TextField
|
||||||
|
margin="dense"
|
||||||
id="terminal"
|
id="terminal"
|
||||||
label="Terminal"
|
label="Terminal"
|
||||||
fullWidth
|
fullWidth
|
||||||
displayEmpty
|
select
|
||||||
value={terminalKey}
|
value={terminalKey}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
setTerminalKey(e.target.value as string);
|
setTerminalKey(e.target.value as string);
|
||||||
|
|
@ -305,8 +310,9 @@ export default function GateSettings(props: Props) {
|
||||||
{terminal.name}
|
{terminal.name}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</TextField>
|
||||||
<TextField
|
<TextField
|
||||||
|
margin="dense"
|
||||||
label="Low Mass Air Flow"
|
label="Low Mass Air Flow"
|
||||||
fullWidth
|
fullWidth
|
||||||
type="number"
|
type="number"
|
||||||
|
|
@ -314,19 +320,30 @@ export default function GateSettings(props: Props) {
|
||||||
onChange={e => setLowerFlowBound(+e.target.value)}
|
onChange={e => setLowerFlowBound(+e.target.value)}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
|
margin="dense"
|
||||||
label="High Mass Air Flow"
|
label="High Mass Air Flow"
|
||||||
fullWidth
|
fullWidth
|
||||||
type="number"
|
type="dense"
|
||||||
value={upperFlowBound}
|
value={upperFlowBound}
|
||||||
onChange={e => setUpperFlowBound(+e.target.value)}
|
onChange={e => setUpperFlowBound(+e.target.value)}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
|
margin="dense"
|
||||||
|
label="Idle Mass Air Flow"
|
||||||
|
fullWidth
|
||||||
|
type="number"
|
||||||
|
value={idleLimit}
|
||||||
|
onChange={e => setIdleLimit(+e.target.value)}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
margin="dense"
|
||||||
label="PCA Unit"
|
label="PCA Unit"
|
||||||
fullWidth
|
fullWidth
|
||||||
value={pcaUnit}
|
value={pcaUnit}
|
||||||
onChange={e => setPcaUnit(e.target.value)}
|
onChange={e => setPcaUnit(e.target.value)}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
|
margin="dense"
|
||||||
style={{ width: "45%" }}
|
style={{ width: "45%" }}
|
||||||
select
|
select
|
||||||
label="Terminal Identifier"
|
label="Terminal Identifier"
|
||||||
|
|
@ -340,6 +357,7 @@ export default function GateSettings(props: Props) {
|
||||||
{tiOptions}
|
{tiOptions}
|
||||||
</TextField>
|
</TextField>
|
||||||
<TextField
|
<TextField
|
||||||
|
margin="dense"
|
||||||
style={{ width: "45%", marginLeft: "10%" }}
|
style={{ width: "45%", marginLeft: "10%" }}
|
||||||
label="Gate Identifier"
|
label="Gate Identifier"
|
||||||
select
|
select
|
||||||
|
|
@ -351,6 +369,7 @@ export default function GateSettings(props: Props) {
|
||||||
{numberOptions}
|
{numberOptions}
|
||||||
</TextField>
|
</TextField>
|
||||||
<TextField
|
<TextField
|
||||||
|
margin="dense"
|
||||||
label="Hourly PCA Cost"
|
label="Hourly PCA Cost"
|
||||||
fullWidth
|
fullWidth
|
||||||
type="number"
|
type="number"
|
||||||
|
|
@ -361,6 +380,7 @@ export default function GateSettings(props: Props) {
|
||||||
onChange={e => setHourlyPCA(+e.target.value)}
|
onChange={e => setHourlyPCA(+e.target.value)}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
|
margin="dense"
|
||||||
label="Hourly APU Cost"
|
label="Hourly APU Cost"
|
||||||
fullWidth
|
fullWidth
|
||||||
type="number"
|
type="number"
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ export interface IInteractionsAPIContext {
|
||||||
alerts: pond.AlertData[],
|
alerts: pond.AlertData[],
|
||||||
otherTeam?: string
|
otherTeam?: string
|
||||||
) => Promise<AxiosResponse<pond.SetAlertInteractionsResponse>>;
|
) => Promise<AxiosResponse<pond.SetAlertInteractionsResponse>>;
|
||||||
|
clearInteractions: (device: number, sources?: quack.ComponentID[], otherTeam?: string) => Promise<AxiosResponse<pond.ClearInteractionsResponse>>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const InteractionsAPIContext = createContext<IInteractionsAPIContext>(
|
export const InteractionsAPIContext = createContext<IInteractionsAPIContext>(
|
||||||
|
|
@ -285,6 +286,25 @@ export default function InteractionProvider(props: PropsWithChildren<Props>) {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const clearInteractions = (device: number, sources?: quack.ComponentID[], otherTeam?: string): Promise<AxiosResponse<pond.ClearInteractionsResponse>> => {
|
||||||
|
const view = otherTeam ? otherTeam : as
|
||||||
|
let sourceArray: string[] = []
|
||||||
|
if (sources){
|
||||||
|
sources.forEach(source => {
|
||||||
|
sourceArray.push(componentIDToString(source))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let url = pondURL("/devices/"+ device + "/interactions/clear" + (view ? "?as=" + view : "") + (sources ? "&sources=" + sourceArray.toString() : ""))
|
||||||
|
return new Promise<AxiosResponse<pond.ClearInteractionsResponse>>((resolve, reject) => {
|
||||||
|
post<pond.ClearInteractionsResponse>(url).then(resp => {
|
||||||
|
resp.data = pond.ClearInteractionsResponse.fromObject(resp.data)
|
||||||
|
return resolve(resp)
|
||||||
|
}).catch(err => {
|
||||||
|
return reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InteractionsAPIContext.Provider
|
<InteractionsAPIContext.Provider
|
||||||
value={{
|
value={{
|
||||||
|
|
@ -296,7 +316,8 @@ export default function InteractionProvider(props: PropsWithChildren<Props>) {
|
||||||
updateInteractionPondSettings,
|
updateInteractionPondSettings,
|
||||||
removeInteraction,
|
removeInteraction,
|
||||||
listInteractionsByDevice,
|
listInteractionsByDevice,
|
||||||
listInteractionsByComponent
|
listInteractionsByComponent,
|
||||||
|
clearInteractions
|
||||||
}}>
|
}}>
|
||||||
{children}
|
{children}
|
||||||
</InteractionsAPIContext.Provider>
|
</InteractionsAPIContext.Provider>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue