some tweaks to the 3d bin and nodes, finished up the table view

This commit is contained in:
csawatzky 2026-05-06 13:08:04 -06:00
parent 325d3ea7a0
commit 619f9b7bf4
9 changed files with 291 additions and 146 deletions

View file

@ -1,37 +1,165 @@
import { Box } from "@mui/material";
import { Box, Table, TableBody, TableCell, TableHead, TableRow } from "@mui/material";
import { green, grey, orange, red } from "@mui/material/colors";
import { Bin } from "models";
import { pond } from "protobuf-ts/pond";
import { useGlobalState } from "providers";
import React from "react";
import { useMemo } from "react";
import { avg, celsiusToFahrenheit } from "utils";
interface Props {
bin: Bin
}
interface LevelAvg {
temp: number
moisture: number
inGrain: boolean
interface BinLevel {
grainTemps: number[]
airTemps: number[]
grainMoistures: number[]
airMoistures: number[]
}
export default function BinTableView(props: Props) {
const {bin} = props
const [{user}] = useGlobalState()
const cableLevelAverages = useMemo(() => {
const binLevels = useMemo(() => {
const cables = bin.status.grainCables
let levels: LevelAvg[] = []
console.log(cables)
let levels: BinLevel[] = []
//note for future self, the first item in the measurement arrays is the lowest node on the cable
//the zones we are creating here will match with the node number because most cables will either have the same number of nodes or only have a difference of 1 or 2
//example: cable 1 has 5 nodes cable 2 has 7 nodes, the first five nodes of the cables will match up and average together for each zone
//and then zones 6 and 7 will be made using only cable 2 because cable 1 doesn't have them
cables.forEach(cable => {
cable.celcius.forEach((c, index) => {
//remember index will be 0 based but the top node starts at 1 for the lowest cable
let inGrain = index < cable.topNode
if (levels[index]){
if(cable.excludedNodes.includes(index+1)) return
if(inGrain){
levels[index].grainTemps.push(c)
//need to check that the cable not only has the moisture mutation on it, but also that it reads humidity
//cables that dont read humidity return an array of 0 values so if the average of all of the values is 0 then it is a temp only cable
if(cable.moisture.length > 0 && avg(cable.moisture) > 0){
//based on all the other checks and the fact that the indexes between the array should match this should never be 0 but put a guard here just in case
//also note that we are only doing moisture and not humidity, it seems like users dont care about humidity
levels[index].grainMoistures.push(cable.moisture[index] ?? 0)
}
}else{
levels[index].airTemps.push(c)
//need to check that the cable not only has the moisture mutation on it, but also that it reads humidity
//cables that dont read humidity return an array of 0 values so if the average of all of the values is 0 then it is a temp only cable
if(cable.moisture.length > 0 && avg(cable.moisture) > 0){
//based on all the other checks and the fact that the indexes between the array should match this should never be 0 but put a guard here just in case
levels[index].airMoistures.push(cable.moisture[index] ?? 0)
}
}
}else{
let newlevel: BinLevel = {
grainTemps: [],
grainMoistures: [],
airTemps: [],
airMoistures: []
}
if(!cable.excludedNodes.includes(index)){
if(inGrain){
newlevel.grainTemps.push(c)
if(cable.moisture.length > 0 && avg(cable.moisture) > 0){
newlevel.grainMoistures.push(cable.moisture[index] ?? 0)
}
}else{
newlevel.airTemps.push(c)
if(cable.moisture.length > 0 && avg(cable.moisture) > 0){
newlevel.airMoistures.push(cable.moisture[index] ?? 0)
}
}
}
levels.push(newlevel)
}
})
})
//flip the levels so that the highest nodes are on the top
levels.reverse()
return levels
},[bin])
const levelDisplay = (level: BinLevel) => {
let tempDisplay = "--"
let moistureDisplay = "--"
let lvlTemp
let lvlMoisture
let tempColour: string = grey[600]
let moistureColour: string = grey[600]
//determine the temp
if(level.grainTemps.length > 0){
lvlTemp = avg(level.grainTemps)
//if the average temp is 5 degrees above the bins threshold
if(lvlTemp > (bin.upperTempThreshold() + 5)){
tempColour = red[700]
}else if(lvlTemp > bin.upperTempThreshold()){
//if the average temp is greater than 5 degrees over
tempColour = orange[600]
}else {
tempColour = green[300]
}
}else if (level.airTemps.length > 0){
lvlTemp = avg(level.airTemps)
}
if (lvlTemp){
if(user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT){
lvlTemp = celsiusToFahrenheit(lvlTemp)
}
tempDisplay = lvlTemp.toFixed(2) + (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? " F" : " C")
}
//determine the moisture to show
if(level.grainMoistures.length > 0){
lvlMoisture = avg(level.grainMoistures)
if(lvlMoisture > (bin.targetMoisture() + 1.5)){
moistureColour = red[700]
}else if(lvlMoisture > bin.targetMoisture()){
//if the average temp is greater than 5 degrees over
moistureColour = orange[600]
}else {
moistureColour = green[300]
}
}else if (level.airMoistures.length > 0){
lvlMoisture = avg(level.airMoistures)
}
if(lvlMoisture){
moistureDisplay = lvlMoisture.toFixed(2) + "%"
}
return (
<React.Fragment>
<TableCell sx={{color: "black", fontWeight: 650, fontSize: 17, textAlign: "center", backgroundColor: tempColour}}>{tempDisplay}</TableCell>
<TableCell sx={{color: "black", fontWeight: 650, fontSize: 17, textAlign: "center", backgroundColor: moistureColour}}>{moistureDisplay}</TableCell>
</React.Fragment>
)
}
return (
<Box>Table View</Box>
<Box padding={2}>
<Table>
<TableHead>
<TableRow>
<TableCell sx={{ fontWeight: 650, fontSize: 20, textAlign: "center"}}>Level</TableCell>
<TableCell sx={{ fontWeight: 650, fontSize: 20, textAlign: "center"}}>Temperature</TableCell>
<TableCell sx={{ fontWeight: 650, fontSize: 20, textAlign: "center"}}>Moisture</TableCell>
</TableRow>
</TableHead>
<TableBody>
{binLevels.map((level, i) => (
<TableRow>
<TableCell sx={{color: "gray", fontWeight: 650, fontSize: 17, textAlign: "center"}}>{binLevels.length - i}</TableCell>
{levelDisplay(level)}
</TableRow>
))}
</TableBody>
</Table>
</Box>
)
}