import { Box, Checkbox, FormControl, MenuItem, List, ListItem, InputLabel, Select, Typography, Stack } from "@mui/material"; import Bin3dView from "bin/3dView/Scene/Bin3dView"; import { Bin, Component, Device } from "models"; import { Controller } from "models/Controller"; import { pond, quack } from "protobuf-ts/pond"; import React, { useEffect } from "react"; import { useState } from "react"; import NodeControls from "./nodeControls"; import { NodeData } from "bin/3dView/Data/BuildNodeData"; import { CableData } from "bin/3dView/Data/BuildCableData"; import ModeChangeDialog from "bin/conditioning/modeChangeDialog"; import { cloneDeep } from "lodash"; import { useMobile } from "hooks"; interface Props { bin: Bin // cables?: GrainCable[] devices: Device[] fans?: Controller[] heaters?: Controller[] permissions: pond.Permission[] componentDevices: Map componentMap: Map binPrefs?: Map updateBinCallback?: (bin: Bin) => void } export default function bin3dVisualizer(props: Props){ const {bin, fans, heaters, permissions, devices, componentDevices, componentMap, binPrefs, updateBinCallback} = props const [showHeatmap, setShowHeatmap] = useState(true) // const [showHotspots, setShowHotspots] = useState(false) // const [showFill, setShowFill] = useState(false) const [showTemp, setShowTemp] = useState(true) const [showMoisture, setShowMoisture] = useState(false) const [showMoistureHeatmap, setShowMoistureHeatmap] = useState(false) const [binDisplay, setBinDisplay] = useState("temp") const [binMode, setBinMode] = useState(pond.BinMode.BIN_MODE_NONE) const [openModeChange, setOpenModeChange] = useState(false) const [selectedCable, setSelectedCable] = useState(undefined) const [selectedNode, setSelectedNode] = useState(undefined) const [selectedCableDevice, setSelectedCableDevice] = useState(Device.create()) //this is the device that the cable that has the node that was clicked on belongs to const [filteredComponents, setFilteredComponents] = useState([]) //components that are filtered to only include ones on the same device const [openNodeControls, setOpenNodeControls] = useState(false) const [devMap, setDevMap] = useState>(new Map()) const [modeChangeInProgress, setModeChangeInProgress] = useState(false) const isMobile = useMobile() useEffect(()=>{ let newMap: Map = new Map() devices.forEach(d => { newMap.set(d.id(), d) }) setDevMap(newMap) },[devices]) useEffect(()=>{ setBinMode(bin.settings.mode) },[bin]) const updateBin = () => { if(updateBinCallback){ let clone = cloneDeep(bin) clone.settings.mode = binMode updateBinCallback(clone) } }; const binModeControl = () => { return ( {bin.name()} ) } const heatmapDisplay = () => { return ( Heatmap Display {/* Display */} ) } const controllerState = (controller: Controller) => { let state = false controller.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 } const controllerDisplay = () => { return ( Controllers {fans && fans.map(fan => { let isOn = controllerState(fan) return ( {fan.name()} {isOn ? "ON" : "OFF"} )})} {heaters && heaters.map(heater => { let isOn = controllerState(heater) return ( {heater.name()} {isOn ? "ON" : "OFF"} )})} // loop through controllers displaying each one ) } const desktopHUD = () => { return ( {binModeControl()} {heatmapDisplay()} {controllerDisplay()} ) } const mobileHUD = () => { return ( {/* Top-left: Bin Name / Mode */} {binModeControl()} {/* Top-right: Heatmap Display */} {heatmapDisplay()} {/* Bottom-left: Controller Status */} {controllerDisplay()} ) } return ( {(selectedCable && selectedNode) && { setOpenNodeControls(false) }} /> } { setOpenModeChange(false) if(refresh) { updateBin() }else{ setBinMode(bin.settings.mode) }; }} defaultTargetMoisture={bin.settings.inventory?.initialMoisture} // defaultOutdoorTemp={outdoorTemp} // defaultOutdoorHumidity={outdoorHumidity} // changeTargetMoisture={newMoisture => { // setTargetMoisture(newMoisture) // }} // changeOutdoorTemp={newTemp => { // setOutdoorTemp(newTemp) // }} // changeOutdoorHumidity={newHumidity => { // setOutdoorHumidity(newHumidity) // }} startChange={() => { setModeChangeInProgress(true) }} changeComplete={() => { setModeChangeInProgress(false) }} /> { //this will be how to control the dialog to update the top nodes and node exclusion etc (make new component called NodeControls for this) //use the cable data to get the device it belongs to let d = devMap.get(cable.grainCable.device) if(d !== undefined){ setSelectedNode(node) setSelectedCable(cable) setSelectedCableDevice(d) //filter the controls so that only components on THIS device are options for new interactions, a side note of this using the components that are in the bins status //is that it will indirectly also filter by bin as well so only components that are both on the bin and the same device as the cable will appear let filtered: Component[] = [] if(fans){ fans.forEach((f) => { if(componentDevices.get(f.key()) === d.id()){ filtered.push(f.asComponent()) } }) } if(heaters){ heaters.forEach((h) => { if(componentDevices.get(h.key()) === d.id()){ filtered.push(h.asComponent()) } }) } //also make sure to push the cable into the list of filtered components for the source let c = componentMap.get(cable.grainCable.key) if(c !== undefined){ filtered.push(c) } setFilteredComponents(filtered) setOpenNodeControls(true) } }} scale={100} showTempHeatmap={showHeatmap} showMoistureHeatmap={showMoistureHeatmap} showTemp={showTemp} showMoisture={showMoisture} // showGrain={showFill} // showHotspots={showHotspots} xOffset={isMobile ? undefined : -150} /> {isMobile ? mobileHUD() : desktopHUD()} ) }