using co2 for the bin activity along with cables

This commit is contained in:
csawatzky 2025-06-11 11:56:27 -06:00
parent ee8f34dcc6
commit 41a17ded94
7 changed files with 274 additions and 101 deletions

View file

@ -58,9 +58,9 @@ interface GrainDetails {
export default function BinCard(props: Props) {
const { bin, valDisplay } = props;
const [cables, setCables] = useState<GrainCable[]>();
const [modeDetails, setModeDetails] = useState("");
//const [modeDetails, setModeDetails] = useState("");
const [lidarPercentage, setLidarPercentage] = useState<number | undefined>();
const [lidarBushels, setLidarBushels] = useState<number | undefined>();
//const [lidarBushels, setLidarBushels] = useState<number | undefined>();
const [{ user }] = useGlobalState();
const classes = useStyles();
const [average, setAverage] = useState<GrainDetails>();
@ -84,6 +84,7 @@ export default function BinCard(props: Props) {
let coldestNode: GrainDetails | undefined;
let hottestNode: GrainDetails | undefined;
let now = moment();
//loop through the cables in the bin status to prep for display
bin.status.grainCables.forEach(cable => {
let c: GrainCable = new GrainCable();
//flip the cables so that for display node 1 is at the bottom
@ -137,8 +138,9 @@ export default function BinCard(props: Props) {
};
}
let lastRead = moment(cable.lastRead);
let elapsedMS = now.diff(lastRead);
//check cables missed readings
let lastCableRead = moment(cable.lastRead);
let elapsedMS = now.diff(lastCableRead);
if (elapsedMS > cable.measurementInterval) {
let missedReadings = Math.floor(elapsedMS / cable.measurementInterval);
@ -147,6 +149,18 @@ export default function BinCard(props: Props) {
}
}
});
//loop through the CO2's to check for missed readings
bin.status.co2.forEach(co2 => {
let lastRead = moment(co2.lastRead);
let elapsedMS = now.diff(lastRead);
if (elapsedMS > co2.measurementInterval) {
let missedReadings = Math.floor(elapsedMS / co2.measurementInterval);
if (missedReadings > mostMissedReadings) {
mostMissedReadings = missedReadings;
}
}
})
setCables(newGrainCables);
setMostMissed(mostMissedReadings);
setColdNode(coldestNode);
@ -165,28 +179,28 @@ export default function BinCard(props: Props) {
let ratio = 1 - cm / height;
let capacity = or(bin.settings.specs?.bushelCapacity, 0);
let lidarEstimate = Math.round(capacity * ratio);
setLidarBushels(lidarEstimate);
//setLidarBushels(lidarEstimate);
setLidarPercentage(Math.round((lidarEstimate / capacity) * 100));
}
}, [bin]);
useEffect(() => {
let now = moment();
let duration = moment.duration(moment(bin.status.lastModeChange).diff(now));
let days = duration.asDays();
days = Math.abs(days);
duration.subtract(moment.duration(days, "days"));
let hours = duration.hours();
hours = Math.abs(hours);
// useEffect(() => {
// let now = moment();
// let duration = moment.duration(moment(bin.status.lastModeChange).diff(now));
// let days = duration.asDays();
// days = Math.abs(days);
// duration.subtract(moment.duration(days, "days"));
// let hours = duration.hours();
// hours = Math.abs(hours);
if (days > 50 && bin.settings.mode === pond.BinMode.BIN_MODE_DRYING) {
setModeDetails("Calculating...");
} else if (bin.settings.mode === pond.BinMode.BIN_MODE_NONE) {
setModeDetails("No Mode");
} else {
setModeDetails(Math.floor(days) + "d " + hours + "h");
}
}, [bin]);
// if (days > 50 && bin.settings.mode === pond.BinMode.BIN_MODE_DRYING) {
// setModeDetails("Calculating...");
// } else if (bin.settings.mode === pond.BinMode.BIN_MODE_NONE) {
// setModeDetails("No Mode");
// } else {
// setModeDetails(Math.floor(days) + "d " + hours + "h");
// }
// }, [bin]);
const typeDisplay = () => {
let grainType = bin.settings.inventory?.grainType ?? pond.Grain.GRAIN_NONE;
@ -440,9 +454,10 @@ export default function BinCard(props: Props) {
const componentStateBanner = () => {
const hasCables = bin.status.grainCables.length > 0;
const hasCO2 = bin.status.co2.length > 0;
return (
<Box display="flex" justifyContent="space-between">
{hasCables ? (
{hasCables || hasCO2 ? (
<React.Fragment>
<Typography style={{ fontSize: 15, fontWeight: 650 }}>
{mostMissed < 3 ? "Active" : mostMissed <= warningThreshold ? "Missing" : "Inactive"}

View file

@ -32,6 +32,7 @@ import { MoreVert } from "@mui/icons-material";
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
import { Ambient } from "models/Ambient";
import { makeStyles } from "@mui/styles";
import { CO2 } from "models/CO2";
const useStyles = makeStyles((theme: Theme) => {
return ({
@ -123,7 +124,7 @@ export default function BinComponentTypes(props: Props) {
const [heaters, setHeaters] = useState<Controller[]>([]);
const [fans, setFans] = useState<Controller[]>([]);
const [lidars, setLidars] = useState<Component[]>([]);
const [headspaceCo2s, setHeadspaceCo2s] = useState<Component[]>([]);
const [headspaceCo2s, setHeadspaceCo2s] = useState<CO2[]>([]);
const [tempUnit, setTempUnit] = useState<pond.TemperatureUnit>();
const [pressureUnit, setPressureUnit] = useState<pond.PressureUnit>();
const [selectedComponentKey, setSelectedComponentKey] = useState("");
@ -176,7 +177,7 @@ export default function BinComponentTypes(props: Props) {
var lidar: Component[] = [];
var unassigned: Component[] = [];
var ambients: Ambient[] = [];
var headspaceCo2s: Component[] = [];
var headspaceCo2s: CO2[] = [];
components.forEach(comp => {
let pref = preferences.get(comp.key());
if (pref) {
@ -198,7 +199,8 @@ export default function BinComponentTypes(props: Props) {
} else if (comp.type() === quack.ComponentType.COMPONENT_TYPE_LIDAR) {
lidar.push(comp);
} else if (comp.type() === quack.ComponentType.COMPONENT_TYPE_CO2) {
headspaceCo2s.push(comp);
let coComp = CO2.create(comp)
headspaceCo2s.push(coComp);
}
}
} else {
@ -716,9 +718,8 @@ export default function BinComponentTypes(props: Props) {
return distanceCM + "cm";
};
const headspaceList = (sensors: Headspace[], lidars: Component[], headspaceCo2s: Component[]) => {
const headspaceList = (sensors: Headspace[], lidars: Component[], headspaceCo2s: CO2[]) => {
if (sensors.length < 1 && lidars.length < 1 && headspaceCo2s.length < 1) return null;
let headspaceComponents = lidars.concat(headspaceCo2s);
return (
<React.Fragment>
<ListSubheader component="div" disableGutters>
@ -778,7 +779,73 @@ export default function BinComponentTypes(props: Props) {
</ListItem>
);
})}
{headspaceComponents.map((component, index) => {
{headspaceCo2s.map((co2, index) => {
let cIcon = GetComponentIcon(
co2.settings.type,
co2.settings.subtype,
theme.palette.mode
);
let colour = "white"; //default colour if there are no measurements to get the type from
let ppmString = "--";
if (
co2.status.measurement[0] &&
co2.status.measurement[0].values[0] &&
co2.status.measurement[0].values[0].values[0]
) {
colour = describeMeasurement(
co2.status.measurement[0].type,
co2.type(),
co2.subType()
).colour();
ppmString = co2.status.measurement[0].values[0].values[0] + " ppm";
}
return (
<ListItem key={index}>
<ListItemAvatar>
<Avatar
variant="square"
src={cIcon}
alt={co2.name()}
style={{ width: theme.spacing(3), height: theme.spacing(3) }}
/>
</ListItemAvatar>
<ListItemText inset={cIcon === undefined}>{co2.name()}</ListItemText>
<ListItemSecondaryAction>
<Grid container direction="row" alignItems="center">
<Grid >
<Box className={classes.bgItem} padding={1}>
<div style={{ display: "flex", flexDirection: "row" }}>
<Typography
variant="body2"
style={{
color: colour
}}>
{ppmString}
</Typography>
</div>
</Box>
</Grid>
<Grid >
<IconButton
onClick={(event: React.MouseEvent<HTMLButtonElement>) => {
setComponentUnnassigned(false);
setSelectedComponentType(co2.type());
setSelectedComponentKey(co2.key());
setAnchorEl(event.currentTarget);
}}>
<MoreVert />
</IconButton>
</Grid>
</Grid>
</ListItemSecondaryAction>
</ListItem>
);
})
}
{lidars.map((component, index) => {
let cIcon = GetComponentIcon(
component.settings.type,
component.settings.subtype,

View file

@ -27,6 +27,7 @@ import React, { useEffect, useState } from "react";
import { avg, getTemperatureUnit } from "utils";
import { makeStyles } from "@mui/styles";
import { Mark } from "@mui/material/Slider/useSlider.types";
import { CO2 } from "models/CO2";
const useStyles = makeStyles((theme: Theme) => {
return ({
@ -117,7 +118,7 @@ const useStyles = makeStyles((theme: Theme) => {
interface Props {
bin: Bin;
headspaceCO2: Component[];
headspaceCO2: CO2[];
cables: GrainCable[];
}