added controller display component for the controllers on a bin

This commit is contained in:
csawatzky 2026-03-06 15:12:25 -06:00
parent e4fe48025e
commit a9f5b9594b
3 changed files with 180 additions and 52 deletions

View file

@ -0,0 +1,145 @@
import { Component } from "models"
import React, { useEffect, useState } from "react"
import { makeStyles } from "@mui/styles";
import { Box, Button, DialogActions, DialogContent, DialogTitle, Typography } from "@mui/material";
import AerationFanIcon from "products/AgIcons/AerationFanIcon";
import { quack } from "protobuf-ts/quack";
import { useComponentAPI, useMobile } from "hooks";
import ButtonGroup from "common/ButtonGroup";
import ObjectHeaterIcon from "products/Construction/ObjectHeaterIcon";
import ResponsiveDialog from "common/ResponsiveDialog";
interface Props {
deviceID: number
component: Component
}
const useStyles = makeStyles(() => {
return ({
controllerDisplay: {
display: "flex",
justifyContent: "space-between",
paddingLeft: 5,
paddingRight: 5
},
})
})
export default function BinControllerDisplay(props: Props) {
const {component, deviceID} = props
const [controllerState, setControllerState] = useState(0)
const [openDialog, setOpenDialog] = useState(false)
const [newOutputState, setNewOutputState] = useState(0)
const componentAPI = useComponentAPI()
const isMobile = useMobile()
const classes = useStyles()
useEffect(()=>{
setControllerState(component.settings.defaultOutputState)
},[component])
const controllerIcon = () => {
if(component.subType() === quack.BooleanOutputSubtype.BOOLEAN_OUTPUT_SUBTYPE_HEATER){
return <ObjectHeaterIcon />
}else{
return <AerationFanIcon />
}
}
const setController = () => {
let newSettings = component.settings
newSettings.defaultOutputState = newOutputState
}
const controllerDialog = () => {
return (
<ResponsiveDialog open={openDialog} onClose={() => {setOpenDialog(false)}}>
<DialogTitle>Set Controller State</DialogTitle>
<DialogContent>
This Action will change the output state of the controller
</DialogContent>
<DialogActions>
<Button onClick={()=>{setOpenDialog(false)}}>Cancel</Button>
<Button onClick={()=>{setController()}}>Confirm</Button>
</DialogActions>
</ResponsiveDialog>
)
}
const componentOn = () => {
let state = false
console.log(component.status)
component.status.lastGoodMeasurement.forEach(um => {
if(um.type === quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN){
if(um.values.length > 0){
let readings = um.values
if(readings[readings.length-1].values.length > 0){
let nodes = readings[readings.length-1].values
if (nodes[nodes.length -1] === 1){
state = true
}
//um.values[um.values.length-1].values[um.values[um.values.length-1].values.length-1]
}
}
}
})
return state
}
return (
<Box className={classes.controllerDisplay} key={component.key()}>
<Box display="flex" marginY="auto">
{controllerIcon()}
<Typography
align="center"
style={{
paddingLeft: 5,
fontSize: isMobile ? "0.85rem" : "1.0rem",
fontWeight: 650
}}>
{component.name()}
</Typography>
</Box>
<ButtonGroup
buttons={[
{
title: "Auto",
function: () => {
setNewOutputState(0)
setOpenDialog(true)
}
},
{
title: "On",
function: () => {
setNewOutputState(1)
setOpenDialog(true)
}
},
{
title: "Off",
function: () => {
setNewOutputState(2)
setOpenDialog(true)
}
}
]}
toggledButtons={[controllerState]}
toggle
/>
<Typography
style={{
marginBottom: "auto",
marginTop: "auto",
fontSize: isMobile ? "0.85rem" : "1.0rem",
fontWeight: 650,
color: componentOn() ? "green" : "orange"
}}>
{componentOn() ? "ON" : "OFF"}
</Typography>
</Box>
)
}

View file

@ -31,7 +31,7 @@ import { round } from "lodash";
import { Bin, Component, Device } from "models";
import { GetComponentIcon } from "pbHelpers/ComponentType";
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
import { useMobile } from "hooks";
import { useComponentAPI, useMobile } from "hooks";
import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/quack";
import { useGlobalState, useSnackbar } from "providers";
@ -71,6 +71,7 @@ import { makeStyles } from "@mui/styles";
import ButtonGroup from "common/ButtonGroup";
import ModeChangeDialog from "./conditioning/modeChangeDialog";
import CustomGrainSelector from "grain/CustomGrainSelector";
import BinControllerDisplay from "./BinControllerDisplay";
const useStyles = makeStyles((theme: Theme) => {
return ({
@ -180,7 +181,7 @@ interface Props {
bin: Bin;
loading: boolean;
components: Map<string, Component>;
componentDevices?: Map<string, number>;
componentDevices: Map<string, number>;
devices: Device[];
plenums?: Plenum[];
ambient?: Ambient;
@ -289,6 +290,12 @@ export default function BinVisualizer(props: Props) {
const [modeChangeInProgress, setModeChangeInProgress] = useState(false)
const [newGrainSettings, setNewGrainSettings] = useState<pond.GrainSettings>()
const componentAPI = useComponentAPI()
const [openControllerDIalog, setOpenControllerDialog] = useState(false)
const [controllerOutputStates, setControllerOutputStates] = useState<Map<string, number>>(new Map<string, number>())
const [selectedController, setSelectedController] = useState<Component>()
const [newOutputState, setNewOutputState] = useState()
useEffect(() => {
setModeTime(moment(bin.status.lastModeChange));
}, [bin.status.lastModeChange]);
@ -1544,54 +1551,24 @@ export default function BinVisualizer(props: Props) {
Controllers
</Typography>
<Box className={classes.displayBox}>
{bin.status.fans.map(fan => (
<Box className={classes.controllerDisplay} key={fan.key}>
<Box display="flex">
<AerationFanIcon />
<Typography
align="center"
style={{
paddingLeft: 5,
fontSize: isMobile ? "0.85rem" : "1.0rem",
fontWeight: 650
}}>
{fan.name}
</Typography>
</Box>
<Typography
style={{
fontSize: isMobile ? "0.85rem" : "1.0rem",
fontWeight: 650,
color: fan.state ? "green" : "orange"
}}>
{fan.state ? "ON" : "OFF"}
</Typography>
</Box>
))}
{bin.status.heaters.map(heater => (
<Box className={classes.controllerDisplay} key={heater.key}>
<Box display="flex">
<ObjectHeaterIcon />
<Typography
align="center"
style={{
paddingLeft: 5,
fontSize: isMobile ? "0.85rem" : "1.0rem",
fontWeight: 650
}}>
{heater.name}
</Typography>
</Box>
<Typography
style={{
fontSize: isMobile ? "0.85rem" : "1.0rem",
fontWeight: 650,
color: heater.state ? "green" : "orange"
}}>
{heater.state ? "ON" : "OFF"}
</Typography>
</Box>
))}
{bin.status.fans.map(fan => {
let fanComp = components.get(fan.key)
let device = componentDevices.get(fan.key)
if(fanComp && device){
return (
<BinControllerDisplay component={fanComp} deviceID={device}/>
)
}
})}
{bin.status.heaters.map(heater => {
let heaterComp = components.get(heater.key)
let device = componentDevices.get(heater.key)
if(heaterComp && device){
return (
<BinControllerDisplay component={heaterComp} deviceID={device}/>
)
}
})}
</Box>
</Box>
);