diff --git a/src/bin/BinControllerDisplay.tsx b/src/bin/BinControllerDisplay.tsx
new file mode 100644
index 0000000..32cbd94
--- /dev/null
+++ b/src/bin/BinControllerDisplay.tsx
@@ -0,0 +1,168 @@
+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, useSnackbar } from "hooks";
+import ButtonGroup from "common/ButtonGroup";
+import ObjectHeaterIcon from "products/Construction/ObjectHeaterIcon";
+import ResponsiveDialog from "common/ResponsiveDialog";
+
+
+interface Props {
+ deviceID: number
+ component: Component
+ currentState?: boolean
+}
+
+const useStyles = makeStyles(() => {
+ return ({
+ controllerDisplay: {
+ display: "flex",
+ justifyContent: "space-between",
+ paddingLeft: 5,
+ paddingRight: 5
+ },
+ })
+})
+
+export default function BinControllerDisplay(props: Props) {
+ const {component, deviceID, currentState} = props
+ const [controllerState, setControllerState] = useState(0)
+ const [openDialog, setOpenDialog] = useState(false)
+ const [newOutputState, setNewOutputState] = useState(0)
+ const {openSnack} = useSnackbar()
+ 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
+ }else{
+ return
+ }
+ }
+
+ const setController = () => {
+ let newSettings = component.settings
+ newSettings.defaultOutputState = newOutputState
+ componentAPI.update(deviceID, newSettings).then(resp => {
+ openSnack("Updated controllers output state")
+ setControllerState(newOutputState)
+ }).catch(err => {
+ openSnack("There was a problem updating the controller")
+ }).finally(() => {
+ setOpenDialog(false)
+ })
+ }
+
+ const controllerDialog = () => {
+ return (
+ {setOpenDialog(false)}}>
+ Set Controller State
+
+ This Action will change the output state of the controller
+
+
+
+
+
+
+ )
+ }
+
+ const componentOn = () => {
+ if(currentState){
+ return currentState
+ }else{
+ let state = false
+ 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
+ }
+ }
+ }
+ }
+ })
+ return state
+ }
+ }
+
+ return (
+
+ {controllerDialog()}
+
+
+
+ {controllerIcon()}
+
+
+ {component.name()}
+
+
+
+ {
+ setNewOutputState(0)
+ setOpenDialog(true)
+ }
+ },
+ {
+ title: "On",
+ function: () => {
+ setNewOutputState(1)
+ setOpenDialog(true)
+ }
+ },
+ {
+ title: "Off",
+ function: () => {
+ setNewOutputState(2)
+ setOpenDialog(true)
+ }
+ }
+ ]}
+ toggledButtons={[controllerState]}
+ toggle
+ />
+
+ {componentOn() ? "ON" : "OFF"}
+
+
+
+
+ )
+
+}
\ No newline at end of file
diff --git a/src/bin/BinVisualizerV2.tsx b/src/bin/BinVisualizerV2.tsx
index 2e2f987..c51908a 100644
--- a/src/bin/BinVisualizerV2.tsx
+++ b/src/bin/BinVisualizerV2.tsx
@@ -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;
- componentDevices?: Map;
+ componentDevices: Map;
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()
+ const componentAPI = useComponentAPI()
+ const [openControllerDIalog, setOpenControllerDialog] = useState(false)
+ const [controllerOutputStates, setControllerOutputStates] = useState