diff --git a/src/bin/BinCardV2.tsx b/src/bin/BinCardV2.tsx index e559c11..4bfcb4f 100644 --- a/src/bin/BinCardV2.tsx +++ b/src/bin/BinCardV2.tsx @@ -103,8 +103,10 @@ export default function BinCard(props: Props) { let filteredNodes = c.filteredNodes(true) allTemps.push(...filteredNodes.temps); - allHums.push(...filteredNodes.humids); - allMoistures.push(...filteredNodes.moistures); + if(avg(c.humidities) !== 0){ //if the average of the humidities is 0 that means that all the readings are 0 and it is a temp only cable + allHums.push(...filteredNodes.humids); + allMoistures.push(...filteredNodes.moistures); + } //set the hottest and coldest nodes if (coldestNode === undefined || Math.min(...filteredNodes.temps) < coldestNode.temp) { @@ -490,7 +492,7 @@ export default function BinCard(props: Props) { return ( - {user.hasFeature("admin") && ( + {user.hasFeature("installer") && ( { interface Props { interactions: Interaction[]; interactionDevices: Map; - mode: pond.BinMode.BIN_MODE_DRYING | pond.BinMode.BIN_MODE_HYDRATING; + mode: pond.BinMode; plenums?: Plenum[]; ambients?: Ambient[]; heaters?: Controller[]; @@ -94,10 +94,21 @@ export default function BinConditioningCard(props: Props) { return conditioningInteractions; }; + const modeDisplay = () => { + switch(mode){ + case pond.BinMode.BIN_MODE_DRYING: + return "Drying" + case pond.BinMode.BIN_MODE_HYDRATING: + return "Hydrating" + case pond.BinMode.BIN_MODE_COOLDOWN: + return "Cooldown" + } + } + return ( - {mode === pond.BinMode.BIN_MODE_DRYING ? "Drying" : "Hydrating"} Conditions + {modeDisplay()} Conditions {conditionsDisplay()} diff --git a/src/bin/BinConditioningInteraction.tsx b/src/bin/BinConditioningInteraction.tsx index 7f5ec13..7fe8bea 100644 --- a/src/bin/BinConditioningInteraction.tsx +++ b/src/bin/BinConditioningInteraction.tsx @@ -47,8 +47,6 @@ const useStyles = makeStyles((theme: Theme) => { sliderThumb: { height: 15, width: 15, - marginTop: -6, - marginLeft: -7.5, backgroundColor: "yellow" }, sliderTrack: { @@ -60,10 +58,10 @@ const useStyles = makeStyles((theme: Theme) => { backgroundColor: "white" }, sliderValLabel: { - left: "calc(-50%)", - top: 22, + left: -20, + top: 40, + background: "transparent", "& *": { - background: "transparent", color: "#fff" } }, diff --git a/src/bin/BinDuplication.tsx b/src/bin/BinDuplication.tsx index d546e44..113830a 100644 --- a/src/bin/BinDuplication.tsx +++ b/src/bin/BinDuplication.tsx @@ -34,7 +34,7 @@ export default function BinDuplication(props: Props) { binAPI .addBin(settings) .then(resp => { - openSnack("Successfully duplicated bin"); + openSnack("Successfully duplicated bin"); }) .catch(err => { openSnack("Failed to duplicate bin"); diff --git a/src/bin/BinSVGV2.tsx b/src/bin/BinSVGV2.tsx index 2c7a888..f3c3454 100644 --- a/src/bin/BinSVGV2.tsx +++ b/src/bin/BinSVGV2.tsx @@ -476,11 +476,11 @@ export default function BinSVGV2(props: Props) { return cableGrainPath; }; - const nodeClass = (nodeTemp: number) => { - if (hottestNodeTemp && hottestNodeTemp.toFixed(2) === nodeTemp.toFixed(2)) { + const nodeClass = (nodeTemp: number, underTop: boolean) => { + if (hottestNodeTemp && hottestNodeTemp.toFixed(2) === nodeTemp.toFixed(2) && underTop) { return classes.hotNode; } - if (coldestNodeTemp && coldestNodeTemp.toFixed(2) === nodeTemp.toFixed(2)) { + if (coldestNodeTemp && coldestNodeTemp.toFixed(2) === nodeTemp.toFixed(2) && underTop) { return classes.coldNode; } return classes.cableNode; @@ -507,12 +507,12 @@ export default function BinSVGV2(props: Props) { //if the cables have the same number of nodes if (b.temperatures.length === a.temperatures.length) { //sort by temp only last and any type that has humidity first - if ( - a.settings.subtype === quack.GrainCableSubtype.GRAIN_CABLE_SUBTYPE_OPI_TEMP && - b.settings.subtype !== quack.GrainCableSubtype.GRAIN_CABLE_SUBTYPE_OPI_TEMP - ) { + if ((avg(a.humidities) === 0) && (avg(b.humidities) !== 0)) { return 1; - } else { + } else if ((avg(b.humidities) === 0) && (avg(a.humidities) !== 0)) { + return -1; + } + else { return a.key() > b.key() ? 1 : -1; } } @@ -759,7 +759,7 @@ export default function BinSVGV2(props: Props) { return ( {e.nodeNumber === topNode && !e.excluded && topNodeHat(cablePos, e.y)} - + ) } diff --git a/src/bin/BinSettings.tsx b/src/bin/BinSettings.tsx index f970b2b..c65bd31 100644 --- a/src/bin/BinSettings.tsx +++ b/src/bin/BinSettings.tsx @@ -485,6 +485,7 @@ export default function BinSettings(props: Props) { form.inventory.inventoryControl = inventoryControl form.inventory.autoThreshold = autoFillThreshold } + console.log(form) binAPI .updateBin(bin.key(), form, as) .then(response => { @@ -741,7 +742,7 @@ export default function BinSettings(props: Props) { case pond.BinInventoryControl.BIN_INVENTORY_CONTROL_HYBRID_LIDAR: return "Hybrid (lidar)" case pond.BinInventoryControl.BIN_INVENTORY_CONTROL_LIBRACART: - return "Auto (LibraCart)" + return "Auto (Libra Cart)" default: return "Manual" } @@ -905,7 +906,7 @@ export default function BinSettings(props: Props) { } - label={"Auto (LibraCart)"} + label={"Auto (Libra Cart)"} /> } @@ -951,7 +952,7 @@ export default function BinSettings(props: Props) { {inventoryControl === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_LIBRACART && { let newForm = form; @@ -963,7 +964,7 @@ export default function BinSettings(props: Props) { options={lcDestinationOptions} /> - The linked bins inventory will be adjusted When the LibraCart Destination data is synced every 6 hours + The linked bins inventory will be adjusted When the Libra Cart Destination data is synced every 6 hours } diff --git a/src/bin/BinStorageConditions.tsx b/src/bin/BinStorageConditions.tsx index 0f4daac..fa0e957 100644 --- a/src/bin/BinStorageConditions.tsx +++ b/src/bin/BinStorageConditions.tsx @@ -21,7 +21,7 @@ import { Bin, Component } from "models"; import { GrainCable } from "models/GrainCable"; import { UnitMeasurement } from "models/UnitMeasurement"; import Co2Icon from "products/CommonIcons/co2Icon"; -import { pond } from "protobuf-ts/pond"; +import { pond, quack } from "protobuf-ts/pond"; import { useBinAPI, useGlobalState, useSnackbar } from "providers"; import React, { useEffect, useState } from "react"; import { avg, getTemperatureUnit } from "utils"; @@ -200,33 +200,32 @@ export default function BinStorageConditions(props: Props) { // } }); - let nodeEMCs: number[] = []; - - filteredNodes.moistures.forEach((emc, i) => { + if(cable.subType() !== quack.GrainCableSubtype.GRAIN_CABLE_SUBTYPE_OPI_TEMP){ + let nodeEMCs: number[] = []; + filteredNodes.moistures.forEach((emc, i) => { if (bin.settings.inventory?.targetMoisture) { - // if (i < cable.topNode) { - nodeEMCs.push(emc); + nodeEMCs.push(emc); emcCounts.total++; if ( emc > bin.settings.inventory.targetMoisture + - bin.settings.inventory.moistureTargetDeviation + bin.settings.inventory.moistureTargetDeviation ) { emcCounts.above++; } else if ( emc < bin.settings.inventory.targetMoisture - - bin.settings.inventory.moistureTargetDeviation + bin.settings.inventory.moistureTargetDeviation ) { emcCounts.below++; } else { emcCounts.onTarget++; } - // } - } - }); + } + }); + cableEMCAvgs.push(avg(nodeEMCs)); + } cableTempAvgs.push(avg(nodeTemps)); - cableEMCAvgs.push(avg(nodeEMCs)); } }); if (cableTempAvgs.length > 0) { diff --git a/src/bin/BinVisualizerV2.tsx b/src/bin/BinVisualizerV2.tsx index 0db4690..8cd41e0 100644 --- a/src/bin/BinVisualizerV2.tsx +++ b/src/bin/BinVisualizerV2.tsx @@ -250,6 +250,7 @@ export default function BinVisualizer(props: Props) { const [cfmHighOpen, setCFMHighOpen] = useState(false); const [{ user }] = useGlobalState(); const [newPreset, setNewPreset] = useState(pond.BinMode.BIN_MODE_NONE); + const [newBinMode, setNewBinMode] = useState(pond.BinMode.BIN_MODE_NONE); const [selectedCable, setSelectedCable] = useState(); const [openNodeDialog, setOpenNodeDialog] = useState(false); const [cableDevice, setCableDevice] = useState(); @@ -345,6 +346,7 @@ export default function BinVisualizer(props: Props) { setGrainOption(ToGrainOption(bin.settings.inventory.grainType)); setBushPerTonne(bin.settings.inventory.bushelsPerTonne.toFixed(2)); setGrainSubtype(bin.subtype()); + setNewBinMode(bin.settings.mode); } if (bin.settings) { let t = bin.settings.outdoorTemp; @@ -384,8 +386,11 @@ export default function BinVisualizer(props: Props) { //also reverse it so that the node 1 (end of the cable) is in the first position let filteredNodes = cable.filteredNodes(true) temps.push(...filteredNodes.temps) - humids.push(...filteredNodes.humids) - emcs.push(...filteredNodes.moistures) + //only push to the humidity values if the cable reads humidities + if(cable.subType() !== quack.GrainCableSubtype.GRAIN_CABLE_SUBTYPE_OPI_TEMP){ + humids.push(...filteredNodes.humids) + emcs.push(...filteredNodes.moistures) + } // let tempClone = cloneDeep(cable.temperatures).reverse(); // let humClone = cloneDeep(cable.humidities).reverse(); // let emcClone = cloneDeep(cable.grainMoistures).reverse(); @@ -409,14 +414,15 @@ export default function BinVisualizer(props: Props) { //if the lowest temp for this cable is less than the temp in the low node conditions or the low node conditions are not set //use this cables lowest node and trend data in the condition - if (!lowNodeConditions || Math.min(...temps) < lowNodeConditions.tempC) { + if (!lowNodeConditions || Math.min(...filteredNodes.temps) < lowNodeConditions.tempC) { //determine which node is the coldest so that the data displayed is for the same node let lowTempIndex = - temps.indexOf(Math.min(...temps)) === -1 ? 0 : temps.indexOf(Math.min(...temps)); + filteredNodes.temps.indexOf(Math.min(...filteredNodes.temps)) === -1 ? 0 : filteredNodes.temps.indexOf(Math.min(...filteredNodes.temps)); + console.log(lowTempIndex) lowNodeConditions = { - tempC: temps[lowTempIndex], - humidity: humids[lowTempIndex], - emc: emcs[lowTempIndex], + tempC: filteredNodes.temps[lowTempIndex], + humidity: filteredNodes.humids[lowTempIndex], + emc: filteredNodes.moistures[lowTempIndex], tempCTrend: cableTrendData.coldNodeTrend?.tempTrend ?? 0, humidityTrend: cableTrendData.coldNodeTrend?.humidityTrend ?? 0, emcTrend: cableTrendData.coldNodeTrend?.emcTrend ?? 0 @@ -424,13 +430,13 @@ export default function BinVisualizer(props: Props) { } //do the same for the high node - if (!highNodeConditions || cable.maxTemp() > highNodeConditions.tempC) { + if (!highNodeConditions || Math.max(...filteredNodes.temps) > highNodeConditions.tempC) { let highTempIndex = - temps.indexOf(Math.max(...temps)) === -1 ? 0 : temps.indexOf(Math.max(...temps)); + filteredNodes.temps.indexOf(Math.max(...filteredNodes.temps)) === -1 ? 0 : filteredNodes.temps.indexOf(Math.max(...filteredNodes.temps)); highNodeConditions = { - tempC: temps[highTempIndex], - humidity: humids[highTempIndex], - emc: emcs[highTempIndex], + tempC: filteredNodes.temps[highTempIndex], + humidity: filteredNodes.humids[highTempIndex], + emc: filteredNodes.moistures[highTempIndex], tempCTrend: cableTrendData.hotNodeTrend?.tempTrend ?? 0, humidityTrend: cableTrendData.hotNodeTrend?.humidityTrend ?? 0, emcTrend: cableTrendData.hotNodeTrend?.emcTrend ?? 0 @@ -1967,6 +1973,7 @@ export default function BinVisualizer(props: Props) { const setModeStorage = () => { setNewPreset(pond.BinMode.BIN_MODE_STORAGE); + setNewBinMode(pond.BinMode.BIN_MODE_STORAGE); }; const setModeCooldown = () => { @@ -1974,6 +1981,7 @@ export default function BinVisualizer(props: Props) { return; } setNewPreset(pond.BinMode.BIN_MODE_COOLDOWN); + setNewBinMode(pond.BinMode.BIN_MODE_COOLDOWN); }; const setModeDrying = () => { @@ -1982,13 +1990,16 @@ export default function BinVisualizer(props: Props) { bin.settings.inventory?.initialMoisture < bin.settings.inventory?.targetMoisture ) { setNewPreset(pond.BinMode.BIN_MODE_HYDRATING); + setNewBinMode(pond.BinMode.BIN_MODE_HYDRATING); } else { setNewPreset(pond.BinMode.BIN_MODE_DRYING); + setNewBinMode(pond.BinMode.BIN_MODE_DRYING); } }; const closeMoistureDialog = () => { setNewPreset(0); + setNewBinMode(bin.settings.mode); setShowInputMoisture(false); }; @@ -2049,6 +2060,7 @@ export default function BinVisualizer(props: Props) { {validCompAddresses.length > 0 ? validCompAddresses.map((addr, index) => { - return ()}/> + return ( + ()}/> + ) }) : ([]) const [subtypeOptions, setSubtypeOptions] = useState>([]) @@ -107,6 +107,7 @@ export default function ScannedI2C(props: Props){ return ( {sensorNum && Sensor {sensorNum}} + {addressData.expansionLine !== 0 && "Expansion Line: " + addressData.expansionLine} {types.length > 0 ? @@ -145,7 +146,7 @@ export default function ScannedI2C(props: Props){ }} select> {subtypeOptions.map(s => ( - {s.friendlyName} + {s.friendlyName} ))} } diff --git a/src/gate/GateDevice.tsx b/src/gate/GateDevice.tsx index 955aa50..cbf87e6 100644 --- a/src/gate/GateDevice.tsx +++ b/src/gate/GateDevice.tsx @@ -338,14 +338,12 @@ export default function GateDevice(props: Props) { return ( - {/* - setDetail("analytics")} - value={"analytics"} - aria-label="Analysis Graphs"> - Analysis - - setDetail("sensors")} - value={"sensors"} - aria-label="Sensor Graphs"> - Sensors - - */} {flowEvents.length > 0 ? ( - + - + Total Events: @@ -271,7 +271,7 @@ export default function GateFlowGraph(props: Props) { - Total Time: + Time: {moment.duration(totalTimeS, "s").humanize()} @@ -280,9 +280,9 @@ export default function GateFlowGraph(props: Props) { - + - + Events Inside: @@ -293,7 +293,7 @@ export default function GateFlowGraph(props: Props) { - Event Time: + Time: {moment.duration(timeSInside, "s").humanize()} @@ -302,9 +302,9 @@ export default function GateFlowGraph(props: Props) { - + - + Events Outside: @@ -315,7 +315,7 @@ export default function GateFlowGraph(props: Props) { - Event Time: + Time: {moment.duration(timeSOutside, "s").humanize()} @@ -324,15 +324,15 @@ export default function GateFlowGraph(props: Props) { - + - + Performance: - {(eventsInside / totalEvents) * 100}% + {((eventsInside / totalEvents) * 100).toFixed(2)}% @@ -367,7 +367,7 @@ export default function GateFlowGraph(props: Props) { {runtime && ( - + Approximate Runtime: @@ -379,7 +379,7 @@ export default function GateFlowGraph(props: Props) { - + Cost to run PCA: @@ -394,7 +394,7 @@ export default function GateFlowGraph(props: Props) { - + Cost to run APU: @@ -409,7 +409,7 @@ export default function GateFlowGraph(props: Props) { - + Total Cost: diff --git a/src/grain/GrainDescriber.ts b/src/grain/GrainDescriber.ts index ce394b3..3c5bceb 100644 --- a/src/grain/GrainDescriber.ts +++ b/src/grain/GrainDescriber.ts @@ -190,7 +190,7 @@ export const GrainExtensions: Map = new Map([ [ pond.Grain.GRAIN_OATS, { - name: "Oats", + name: "Oats a", group: "Oats", equation: Equation.henderson, a: 0.000085511, @@ -203,6 +203,40 @@ export const GrainExtensions: Map = new Map([ weightConversionKg: 15.4222988297197, bushelsPerTonne: 64.842 } + ], + [ + pond.Grain.GRAIN_OATS_B, + { + name: "Oats b", + group: "Oats", + equation: Equation.chungPfost, + a: 442.85, + b: 0.21228, + c: 35.803, + setTempC: 32.0, + targetMC: 13.6, + img: OatImg, + colour: "#79955a", + weightConversionKg: 15.4222988297197, + bushelsPerTonne: 64.842 + } + ], + [ + pond.Grain.GRAIN_OATS_C, + { + name: "Oats c", + group: "Oats", + equation: Equation.oswin, + a: 12.412, + b: -0.060707, + c: 2.9397, + setTempC: 32.0, + targetMC: 13.6, + img: OatImg, + colour: "#79955a", + weightConversionKg: 15.4222988297197, + bushelsPerTonne: 64.842 + } ], [ pond.Grain.GRAIN_PEANUTS, @@ -506,6 +540,66 @@ export const GrainExtensions: Map = new Map([ weightConversionKg: 27.2155, bushelsPerTonne: 36.744 } + ],[ + pond.Grain.GRAIN_RYE_A, + { + name: "Rye a", + group: "Rye", + equation: Equation.henderson, + a: 0.00006343, + b: 2.2060, + c: 13.1810, + setTempC: defaultSetTemp, + targetMC: 15.0, + colour: "grey", + weightConversionKg: 25.4, + bushelsPerTonne: 39.368 + } + ],[ + pond.Grain.GRAIN_RYE_B, + { + name: "Rye b", + group: "Rye", + equation: Equation.chungPfost, + a: 461.0230, + b: 0.1840, + c: 36.7410, + setTempC: defaultSetTemp, + targetMC: 15.0, + colour: "grey", + weightConversionKg: 25.4, + bushelsPerTonne: 39.368 + }, + ],[ + pond.Grain.GRAIN_RYE_C, + { + name: "Rye c", + group: "Rye", + equation: Equation.halsey, + a: 4.2970, + b: 0.380, + c: 2.2710, + setTempC: defaultSetTemp, + targetMC: 15.0, + colour: "grey", + weightConversionKg: 25.4, + bushelsPerTonne: 39.368 + }, + ],[ + pond.Grain.GRAIN_RYE_D, + { + name: "Rye d", + group: "Rye", + equation: Equation.oswin, + a: 11.8870, + b: 0.0210, + c: 3.2620, + setTempC: defaultSetTemp, + targetMC: 15.0, + colour: "grey", + weightConversionKg: 25.4, + bushelsPerTonne: 39.368 + } ] ]); diff --git a/src/integrations/LibraCart/LibraCartAccess.tsx b/src/integrations/LibraCart/LibraCartAccess.tsx index eb39433..cbb5caa 100644 --- a/src/integrations/LibraCart/LibraCartAccess.tsx +++ b/src/integrations/LibraCart/LibraCartAccess.tsx @@ -182,7 +182,7 @@ export default function LibraCartAccess() { color="primary" onClick={e => { e.preventDefault(); - window.open(`https://staging.cloud.agrimatics.com/grain/integrations`, "_blank"); + window.open(`https://cloud.agrimatics.com/grain/integrations`, "_blank"); }}> Link Libra Cart Account @@ -196,7 +196,7 @@ export default function LibraCartAccess() { - +