Merge branch 'custom_grain' into dev_environment

This commit is contained in:
csawatzky 2025-12-18 14:42:39 -06:00
commit 709d86eef1
20 changed files with 813 additions and 225 deletions

6
package-lock.json generated
View file

@ -10953,11 +10953,7 @@
}, },
"node_modules/protobuf-ts": { "node_modules/protobuf-ts": {
"version": "1.0.0", "version": "1.0.0",
<<<<<<< HEAD "resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#fa7ac81420665424e5490346c6a6e871480a1643",
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#80ad2f8b81afe9e04f10f9b52a8250e6824d2b41",
=======
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#c08965a296f2cd0799472fd8b163186cf6885d4c",
>>>>>>> tidio
"dependencies": { "dependencies": {
"protobufjs": "^6.8.8" "protobufjs": "^6.8.8"
} }

View file

@ -200,7 +200,8 @@ export default function BinCard(props: Props) {
const typeDisplay = () => { const typeDisplay = () => {
let grainType = bin.settings.inventory?.grainType ?? pond.Grain.GRAIN_NONE; let grainType = bin.settings.inventory?.grainType ?? pond.Grain.GRAIN_NONE;
if (bin.storage() === pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN) { switch (bin.storage()){
case pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN:
return ( return (
<Box> <Box>
<Typography variant="subtitle2" style={{ fontSize: "0.7rem", fontWeight: 700 }}> <Typography variant="subtitle2" style={{ fontSize: "0.7rem", fontWeight: 700 }}>
@ -210,15 +211,16 @@ export default function BinCard(props: Props) {
{bin.settings.inventory?.grainSubtype} {bin.settings.inventory?.grainSubtype}
</Typography> </Typography>
</Box> </Box>
); )
} default:
return ( return (
<Box> <Box>
<Typography variant="subtitle2" style={{ fontSize: "0.7rem", fontWeight: 700 }}> <Typography variant="subtitle2" style={{ fontSize: "0.7rem", fontWeight: 700 }}>
{bin.settings.inventory?.customTypeName} {bin.grainName()}
</Typography> </Typography>
</Box> </Box>
); );
}
}; };
const tempDisplay = () => { const tempDisplay = () => {
@ -417,6 +419,7 @@ export default function BinCard(props: Props) {
hottestNodeTemp={valDisplay === "high" ? hotNode?.temp : undefined} hottestNodeTemp={valDisplay === "high" ? hotNode?.temp : undefined}
coldestNodeTemp={valDisplay === "low" ? coldNode?.temp : undefined} coldestNodeTemp={valDisplay === "low" ? coldNode?.temp : undefined}
inventoryControl={bin.inventoryControl()} inventoryControl={bin.inventoryControl()}
customGrain={bin.customGrain()}
/> />
</Box> </Box>
</Box> </Box>

View file

@ -39,11 +39,12 @@ interface Props {
heaters?: Controller[]; heaters?: Controller[];
fans?: Controller[]; fans?: Controller[];
grain?: pond.Grain; grain?: pond.Grain;
customGrain?: pond.GrainSettings
} }
export default function BinConditioningCard(props: Props) { export default function BinConditioningCard(props: Props) {
const classes = useStyles(); const classes = useStyles();
const { interactions, interactionDevices, plenums, ambients, heaters, fans, grain, mode } = props; const { interactions, interactionDevices, plenums, ambients, heaters, fans, grain, mode, customGrain } = props;
const [sourceMap, setSourceMap] = useState<Map<string, Component>>(new Map()); const [sourceMap, setSourceMap] = useState<Map<string, Component>>(new Map());
const [sinkMap, setSinkMap] = useState<Map<string, Component>>(new Map()); const [sinkMap, setSinkMap] = useState<Map<string, Component>>(new Map());
@ -87,6 +88,7 @@ export default function BinConditioningCard(props: Props) {
sink={sink} sink={sink}
source={source} source={source}
grain={grain} grain={grain}
customGrain={customGrain}
/> />
); );
} }

View file

@ -84,10 +84,11 @@ interface Props {
source: Component; source: Component;
sink: Component; sink: Component;
grain?: pond.Grain; grain?: pond.Grain;
customGrain?: pond.GrainSettings
} }
export default function BinConditioningInteraction(props: Props) { export default function BinConditioningInteraction(props: Props) {
const { interaction, source, sink, grain, deviceId } = props; const { interaction, source, sink, grain, deviceId, customGrain } = props;
const [sliderVals, setSliderVals] = useState<Map<quack.MeasurementType, number>>(new Map()); const [sliderVals, setSliderVals] = useState<Map<quack.MeasurementType, number>>(new Map());
const [sliderMarks, setSliderMarks] = useState<Map<quack.MeasurementType, number>>(new Map()); const [sliderMarks, setSliderMarks] = useState<Map<quack.MeasurementType, number>>(new Map());
//this is the emc value calculated from the interactions temp and humidity conditions //this is the emc value calculated from the interactions temp and humidity conditions
@ -127,7 +128,6 @@ export default function BinConditioningInteraction(props: Props) {
if ( if (
grain !== undefined && grain !== undefined &&
grain !== pond.Grain.GRAIN_INVALID && grain !== pond.Grain.GRAIN_INVALID &&
grain !== pond.Grain.GRAIN_CUSTOM &&
temp && temp &&
hum hum
) { ) {
@ -135,8 +135,9 @@ export default function BinConditioningInteraction(props: Props) {
//the emc calc needs the temp to be in celsius //the emc calc needs the temp to be in celsius
temp = fahrenheitToCelsius(temp); temp = fahrenheitToCelsius(temp);
} }
let emc = ExtractMoisture(grain, temp, hum); let emc = ExtractMoisture(grain, temp, hum, customGrain)
setBaseEMC(emc); setBaseEMC(emc === hum ? undefined : emc);
} }
}, [sliderVals, grain]); }, [sliderVals, grain]);

View file

@ -147,6 +147,7 @@ interface Props {
hottestNodeTemp?: number; hottestNodeTemp?: number;
coldestNodeTemp?: number; coldestNodeTemp?: number;
inventoryControl?: pond.BinInventoryControl; inventoryControl?: pond.BinInventoryControl;
customGrain?: pond.GrainSettings;
} }
interface GrainNodePoint { interface GrainNodePoint {
@ -211,7 +212,8 @@ export default function BinSVGV2(props: Props) {
hottestNodeTemp, hottestNodeTemp,
coldestNodeTemp, coldestNodeTemp,
inventoryControl, inventoryControl,
co2Sensors co2Sensors,
customGrain
} = props; } = props;
const [{ user }] = useGlobalState(); const [{ user }] = useGlobalState();
const [extraDetails, setExtraDetails] = useState<"temps" | "hums">("temps"); const [extraDetails, setExtraDetails] = useState<"temps" | "hums">("temps");
@ -683,7 +685,7 @@ export default function BinSVGV2(props: Props) {
x: cablePos, x: cablePos,
y: nodeY + 10, y: nodeY + 10,
stroke: "green", stroke: "green",
value: ExtractMoisture(props.grainType, temp, cable.humidities[index] ?? 0).toFixed(1)+"%", value: ExtractMoisture(props.grainType, temp, cable.humidities[index] ?? 0, customGrain).toFixed(1)+"%",
}) })
!showTempHum && !showTempHum &&
nodeClickData.push({ nodeClickData.push({

View file

@ -65,6 +65,7 @@ import { getDistanceUnit, or, getTemperatureUnit, getGrainUnit } from "utils";
import { makeStyles } from "@mui/styles"; import { makeStyles } from "@mui/styles";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import BinSelector from "./BinSelector"; import BinSelector from "./BinSelector";
import CustomGrainForm from "grain/CustomGrainForm";
// import BinSelector from "./BinSelector"; // import BinSelector from "./BinSelector";
const useStyles = makeStyles((theme: Theme) => { const useStyles = makeStyles((theme: Theme) => {
@ -205,6 +206,7 @@ export default function BinSettings(props: Props) {
const libracartAPI = useLibraCartProxyAPI() const libracartAPI = useLibraCartProxyAPI()
const [lcDestination, setlcDestination] = useState<Option | null>() const [lcDestination, setlcDestination] = useState<Option | null>()
const [lcDestinationOptions, setlcDestinationOptions] = useState<Option[]>([]) const [lcDestinationOptions, setlcDestinationOptions] = useState<Option[]>([])
const [customGrain, setCustomGrain] = useState<pond.GrainSettings>()
useEffect(() => { useEffect(() => {
if (open) { if (open) {
@ -236,6 +238,9 @@ export default function BinSettings(props: Props) {
initForm.inventory.grainType initForm.inventory.grainType
).bushelsPerTonne; ).bushelsPerTonne;
} }
if (initForm.inventory.customGrain){
setCustomGrain(initForm.inventory.customGrain)
}
//if the target temp is not set (older bins) make it the midpoint of the high and low temps assuming they are set otherwise make it 15 //if the target temp is not set (older bins) make it the midpoint of the high and low temps assuming they are set otherwise make it 15
if (!initForm.inventory.targetTemperature || initForm.inventory.targetTemperature) { if (!initForm.inventory.targetTemperature || initForm.inventory.targetTemperature) {
if (initForm.highTemp && initForm.lowTemp) { if (initForm.highTemp && initForm.lowTemp) {
@ -444,6 +449,11 @@ export default function BinSettings(props: Props) {
form.inventory.inventoryControl = inventoryControl form.inventory.inventoryControl = inventoryControl
form.inventory.autoThreshold = autoFillThreshold form.inventory.autoThreshold = autoFillThreshold
form.inventory.lidarDropCm = getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? lidarDropDistance * 30.48 : lidarDropDistance form.inventory.lidarDropCm = getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? lidarDropDistance * 30.48 : lidarDropDistance
if(form.inventory.grainType !== pond.Grain.GRAIN_CUSTOM){
form.inventory.customGrain = undefined
}else{
form.inventory.customGrain = customGrain
}
} }
binAPI binAPI
@ -493,6 +503,11 @@ export default function BinSettings(props: Props) {
form.inventory.autoThreshold = autoFillThreshold form.inventory.autoThreshold = autoFillThreshold
//if the users preferences are in feet convert the distance to cm otherwise it was entered as cm so use that //if the users preferences are in feet convert the distance to cm otherwise it was entered as cm so use that
form.inventory.lidarDropCm = getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? lidarDropDistance * 30.48 : lidarDropDistance form.inventory.lidarDropCm = getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? lidarDropDistance * 30.48 : lidarDropDistance
if(form.inventory.grainType !== pond.Grain.GRAIN_CUSTOM){
form.inventory.customGrain = undefined
}else{
form.inventory.customGrain = customGrain
}
} }
binAPI binAPI
.updateBin(bin.key(), form, as) .updateBin(bin.key(), form, as)
@ -1014,7 +1029,37 @@ export default function BinSettings(props: Props) {
{isCustom ? "Custom" : "Grain"} {isCustom ? "Custom" : "Grain"}
</Typography> */} </Typography> */}
<Box> <Box>
{!isCustomInventory && ( {isCustomInventory ?
<React.Fragment>
{storageType === pond.BinStorage.BIN_STORAGE_FERTILIZER ?
<React.Fragment>
<TextField
label="Type"
value={customTypeName}
type="text"
onChange={event => {
updateForm(
"inventory",
pond.BinInventory.create({
...form.inventory,
customTypeName: event.target.value
})
);
updateFormExtension("customTypeName", event.target.value);
}}
fullWidth
variant="outlined"
className={classes.bottomSpacing}
/>
</React.Fragment>
:
<Box sx={{border: "1px solid white", borderRadius: 2, padding: 2, marginBottom: 2}}>
<CustomGrainForm initialGrain={customGrain} onGrainSettingsChange={(newGrainSettings) => {setCustomGrain(newGrainSettings)}}/>
</Box>
}
</React.Fragment>
:
<React.Fragment>
<Box className={classes.bottomSpacing}> <Box className={classes.bottomSpacing}>
<SearchSelect <SearchSelect
label="Type" label="Type"
@ -1040,49 +1085,6 @@ export default function BinSettings(props: Props) {
options={grainOptions} options={grainOptions}
/> />
</Box> </Box>
)}
{isCustomInventory ? (
<React.Fragment>
<TextField
label="Type"
value={customTypeName}
type="text"
onChange={event => {
updateForm(
"inventory",
pond.BinInventory.create({
...form.inventory,
customTypeName: event.target.value
})
);
updateFormExtension("customTypeName", event.target.value);
}}
fullWidth
variant="outlined"
className={classes.bottomSpacing}
/>
{storageType !== pond.BinStorage.BIN_STORAGE_FERTILIZER && (
<TextField
label="Bushels Per Tonne"
value={bushPerTonne}
type="number"
onChange={event => {
updateForm(
"inventory",
pond.BinInventory.create({
...form.inventory,
bushelsPerTonne: +event.target.value
})
);
updateFormExtension("bushelsPerTonne", event.target.value);
}}
fullWidth
variant="outlined"
className={classes.bottomSpacing}
/>
)}
</React.Fragment>
) : (
<TextField <TextField
label="Grain Variant" label="Grain Variant"
value={grainSubtype} value={grainSubtype}
@ -1102,7 +1104,8 @@ export default function BinSettings(props: Props) {
disabled={!grainType} disabled={!grainType}
className={classes.bottomSpacing} className={classes.bottomSpacing}
/> />
)} </React.Fragment>
}
{getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_BUSHELS || {getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_BUSHELS ||
storageType === pond.BinStorage.BIN_STORAGE_FERTILIZER || storageType === pond.BinStorage.BIN_STORAGE_FERTILIZER ||
formExtension.bushelsPerTonne === "0" || formExtension.bushelsPerTonne === "0" ||

View file

@ -70,6 +70,7 @@ import Edit from "@mui/icons-material/Edit";
import { makeStyles } from "@mui/styles"; import { makeStyles } from "@mui/styles";
import ButtonGroup from "common/ButtonGroup"; import ButtonGroup from "common/ButtonGroup";
import ModeChangeDialog from "./conditioning/modeChangeDialog"; import ModeChangeDialog from "./conditioning/modeChangeDialog";
import CustomGrainForm from "grain/CustomGrainForm";
const useStyles = makeStyles((theme: Theme) => { const useStyles = makeStyles((theme: Theme) => {
return ({ return ({
@ -286,6 +287,7 @@ export default function BinVisualizer(props: Props) {
const [openModeChange, setOpenModeChange] = useState(false) const [openModeChange, setOpenModeChange] = useState(false)
const [modeChangeInProgress, setModeChangeInProgress] = useState(false) const [modeChangeInProgress, setModeChangeInProgress] = useState(false)
const [newGrainSettings, setNewGrainSettings] = useState<pond.GrainSettings>()
useEffect(() => { useEffect(() => {
setModeTime(moment(bin.status.lastModeChange)); setModeTime(moment(bin.status.lastModeChange));
@ -327,6 +329,7 @@ export default function BinVisualizer(props: Props) {
setBushPerTonne(bin.settings.inventory.bushelsPerTonne.toFixed(2)); setBushPerTonne(bin.settings.inventory.bushelsPerTonne.toFixed(2));
setGrainSubtype(bin.subtype()); setGrainSubtype(bin.subtype());
setNewBinMode(bin.settings.mode); setNewBinMode(bin.settings.mode);
setNewGrainSettings(bin.customGrain());
} }
if (bin.settings) { if (bin.settings) {
let t = bin.settings.outdoorTemp; let t = bin.settings.outdoorTemp;
@ -515,18 +518,13 @@ export default function BinVisualizer(props: Props) {
const capacity = bin.settings.specs?.bushelCapacity ?? 0; const capacity = bin.settings.specs?.bushelCapacity ?? 0;
const grainBushels = bin.bushels(); const grainBushels = bin.bushels();
const isEmpty = bin.settings.inventory?.empty === true || !grainBushels || grainBushels <= 0; const isEmpty = bin.settings.inventory?.empty === true || !grainBushels || grainBushels <= 0;
const grainType = bin.settings.inventory?.grainType;
const grainTypeName = isEmpty || !grainType ? "" : GrainDescriber(grainType).name;
const customTypeName = bin.settings.inventory?.customTypeName;
const grainSubtype = bin.settings.inventory?.grainSubtype; const grainSubtype = bin.settings.inventory?.grainSubtype;
return ( return (
<Box> <Box>
{/* grain display */} {/* grain display */}
<Box display="flex" justifyContent="space-between"> <Box display="flex" justifyContent="space-between">
<Typography variant="subtitle2" color="textPrimary" style={{ fontWeight: 800 }}> <Typography variant="subtitle2" color="textPrimary" style={{ fontWeight: 800 }}>
{bin.storage() === pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN {isEmpty ? "" : bin.grainName()}
? grainTypeName
: customTypeName}
{grainSubtype !== "" ? " - " + grainSubtype : ""} {grainSubtype !== "" ? " - " + grainSubtype : ""}
</Typography> </Typography>
<Box <Box
@ -768,6 +766,7 @@ export default function BinVisualizer(props: Props) {
setGrainType(bin.settings.inventory.grainType); setGrainType(bin.settings.inventory.grainType);
setGrainOption(ToGrainOption(bin.settings.inventory.grainType)); setGrainOption(ToGrainOption(bin.settings.inventory.grainType));
setBushPerTonne(bin.settings.inventory.bushelsPerTonne.toFixed(2)); setBushPerTonne(bin.settings.inventory.bushelsPerTonne.toFixed(2));
setNewGrainSettings(bin.customGrain())
setGrainSubtype(bin.subtype()); setGrainSubtype(bin.subtype());
} }
setGrainChangeDialog(false); setGrainChangeDialog(false);
@ -799,11 +798,13 @@ export default function BinVisualizer(props: Props) {
setCustomTypeName(""); setCustomTypeName("");
setGrainOption(ToGrainOption(pond.Grain.GRAIN_NONE)); setGrainOption(ToGrainOption(pond.Grain.GRAIN_NONE));
if (checked) { if (checked) {
setStorageType(pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN);
setGrainType(pond.Grain.GRAIN_CUSTOM);
} else {
setStorageType(pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN); setStorageType(pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN);
setGrainType(pond.Grain.GRAIN_CUSTOM);
setNewGrainSettings(bin.customGrain())
} else {
setStorageType(pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN);
setGrainType(pond.Grain.GRAIN_NONE); setGrainType(pond.Grain.GRAIN_NONE);
setNewGrainSettings(undefined)
} }
}} }}
name="storage" name="storage"
@ -834,7 +835,7 @@ export default function BinVisualizer(props: Props) {
)} )}
{isCustomInventory ? ( {isCustomInventory ? (
<React.Fragment> <React.Fragment>
<TextField {/* <TextField
label="Type" label="Type"
value={customTypeName} value={customTypeName}
type="text" type="text"
@ -859,7 +860,8 @@ export default function BinVisualizer(props: Props) {
variant="outlined" variant="outlined"
className={classes.bottomSpacing} className={classes.bottomSpacing}
/> />
)} )} */}
<CustomGrainForm initialGrain={bin.customGrain()} onGrainSettingsChange={settings => {setNewGrainSettings(settings)}}/>
</React.Fragment> </React.Fragment>
) : ( ) : (
<TextField <TextField
@ -1404,6 +1406,7 @@ export default function BinVisualizer(props: Props) {
} }
}} }}
inventoryControl={bin.inventoryControl()} inventoryControl={bin.inventoryControl()}
customGrain={bin.customGrain()}
/> />
</Box> </Box>
</Box> </Box>
@ -1574,6 +1577,12 @@ export default function BinVisualizer(props: Props) {
const fanPerformance = () => { const fanPerformance = () => {
let totalCFM = bin.status.fanCfm; let totalCFM = bin.status.fanCfm;
let bushelCFM = bin.status.cfmPerBushel; let bushelCFM = bin.status.cfmPerBushel;
let emc = ExtractMoisture(
bin.grain(),
activePlenum?.tempHumidity?.temperature ?? 0,
activePlenum?.tempHumidity?.humidity ?? 0,
bin.customGrain()
)
return ( return (
<Box> <Box>
<Typography style={{ fontSize: isMobile ? "0.85rem" : "1.0rem", fontWeight: 650 }}> <Typography style={{ fontSize: isMobile ? "0.85rem" : "1.0rem", fontWeight: 650 }}>
@ -1617,19 +1626,17 @@ export default function BinVisualizer(props: Props) {
</Box> </Box>
</Grid> </Grid>
<Grid> <Grid>
{emc !== activePlenum?.tempHumidity?.humidity &&
<Box className={classes.lightBox}> <Box className={classes.lightBox}>
<Typography align="center" style={{ fontWeight: 650, color: emcColour }}> <Typography align="center" style={{ fontWeight: 650, color: emcColour }}>
{ExtractMoisture( {emc.toFixed(2)}
bin.grain(),
activePlenum?.tempHumidity?.temperature ?? 0,
activePlenum?.tempHumidity?.humidity ?? 0
).toFixed(2)}
% %
</Typography> </Typography>
<Typography align="center" style={{ fontWeight: 650 }}> <Typography align="center" style={{ fontWeight: 650 }}>
Plenum EMC Plenum EMC
</Typography> </Typography>
</Box> </Box>
}
</Grid> </Grid>
</Grid> </Grid>
</Box> </Box>
@ -1638,6 +1645,12 @@ export default function BinVisualizer(props: Props) {
}; };
const ambientDisplay = () => { const ambientDisplay = () => {
let emc = ExtractMoisture(
bin.grain(),
ambient?.temperature ?? 0,
ambient?.humidity ?? 0,
bin.customGrain()
)
return ( return (
<Box> <Box>
<Typography style={{ fontSize: isMobile ? "0.85rem" : "1.0rem", fontWeight: 650 }}> <Typography style={{ fontSize: isMobile ? "0.85rem" : "1.0rem", fontWeight: 650 }}>
@ -1677,19 +1690,17 @@ export default function BinVisualizer(props: Props) {
</Box> </Box>
</Grid> </Grid>
<Grid > <Grid >
{emc !== ambient?.humidity &&
<Box className={classes.lightBox}> <Box className={classes.lightBox}>
<Typography align="center" style={{ fontWeight: 650, color: emcColour }}> <Typography align="center" style={{ fontWeight: 650, color: emcColour }}>
{ExtractMoisture( {emc.toFixed(2)}
bin.grain(),
ambient?.temperature ?? 0,
ambient?.humidity ?? 0
).toFixed(2)}
% %
</Typography> </Typography>
<Typography align="center" style={{ fontWeight: 650 }}> <Typography align="center" style={{ fontWeight: 650 }}>
Ambient EMC Ambient EMC
</Typography> </Typography>
</Box> </Box>
}
</Grid> </Grid>
</Grid> </Grid>
</Box> </Box>
@ -1966,6 +1977,7 @@ export default function BinVisualizer(props: Props) {
? 0 ? 0
: parseFloat(bushPerTonne); : parseFloat(bushPerTonne);
b.settings.inventory.grainSubtype = grainSubtype; b.settings.inventory.grainSubtype = grainSubtype;
b.settings.inventory.customGrain = newGrainSettings
} }
if (b.settings.outdoorTemp !== undefined) { if (b.settings.outdoorTemp !== undefined) {

View file

@ -170,18 +170,18 @@ export default function BinGraphs(props: Props) {
setEndDate(newEndDate); setEndDate(newEndDate);
}; };
const determineGrainColour = () => { // const determineGrainColour = () => {
let col = "yellow"; // let col = "yellow";
let binInv = bin.settings.inventory; // let binInv = bin.settings.inventory;
if (binInv) { // if (binInv) {
if (binInv.grainType === pond.Grain.GRAIN_CUSTOM) { // if (binInv.grainType === pond.Grain.GRAIN_CUSTOM) {
col = stringToMaterialColour(binInv.customTypeName); // col = stringToMaterialColour(binInv.customTypeName);
} else if (binInv.grainType !== pond.Grain.GRAIN_NONE) { // } else if (binInv.grainType !== pond.Grain.GRAIN_NONE) {
col = GrainDescriber(binInv.grainType).colour; // col = GrainDescriber(binInv.grainType).colour;
} // }
} // }
return col; // return col;
}; // };
const inventoryGraph = () => { const inventoryGraph = () => {
return ( return (
@ -193,7 +193,7 @@ export default function BinGraphs(props: Props) {
endDate={endDate} endDate={endDate}
binLoading={binLoading} binLoading={binLoading}
bin={bin} bin={bin}
colour={determineGrainColour()} colour={bin.grainColour()}
fertilizerBin={bin.settings.storage === pond.BinStorage.BIN_STORAGE_FERTILIZER} fertilizerBin={bin.settings.storage === pond.BinStorage.BIN_STORAGE_FERTILIZER}
/> />
</Grid> </Grid>

View file

@ -92,7 +92,8 @@ export default function BinGraphsTrending(props: Props) {
trend: ExtractMoisture( trend: ExtractMoisture(
bin.grain(), bin.grain(),
val.values[0], val.values[0],
plenumHumidity.values[i].values[0] plenumHumidity.values[i].values[0],
bin.customGrain()
) )
}; };
trendData.push(trendPoint); trendData.push(trendPoint);

View file

@ -4,6 +4,7 @@ import {
AccordionSummary, AccordionSummary,
Alert, Alert,
AlertTitle, AlertTitle,
Box,
Button, Button,
Collapse, Collapse,
FormControl, FormControl,
@ -47,6 +48,7 @@ import { getDistanceUnit } from "utils";
import { GrainOptions } from "grain"; import { GrainOptions } from "grain";
import CompModes from "component/ComponentMode.json"; import CompModes from "component/ComponentMode.json";
import FanPicker from "fans/fanPicker"; import FanPicker from "fans/fanPicker";
import CustomGrainForm from "grain/CustomGrainForm";
const useStyles = makeStyles((theme: Theme) => { const useStyles = makeStyles((theme: Theme) => {
return ({ return ({
@ -136,6 +138,7 @@ export default function ComponentForm(props: Props) {
sensorDistance: "0", sensorDistance: "0",
}); });
const [compMode, setCompMode] = useState<any>(); const [compMode, setCompMode] = useState<any>();
const [useCustomGrain, setUseCustomGrain] = useState<boolean>(false)
//const [numCalibrations, setNumCalibrations] = useState(0) //const [numCalibrations, setNumCalibrations] = useState(0)
useEffect(() => { useEffect(() => {
@ -192,6 +195,10 @@ export default function ComponentForm(props: Props) {
sensorDistance = sensorDistance / 30.48; sensorDistance = sensorDistance / 30.48;
} }
if(formComponent.settings.customGrain){
setUseCustomGrain(true)
}
setForm({ setForm({
component: formComponent, component: formComponent,
measure: formComponent.settings.measurementPeriodMs > 0, measure: formComponent.settings.measurementPeriodMs > 0,
@ -383,6 +390,13 @@ export default function ComponentForm(props: Props) {
setForm(f); setForm(f);
}; };
const updateCustomGrain = (grainSettings?: pond.GrainSettings) => {
let f = cloneDeep(form)
f.component.settings.customGrain = grainSettings
f.component.settings.grainType = pond.Grain.GRAIN_CUSTOM
setForm(f)
}
const updateGrainType = (option: Option | null) => { const updateGrainType = (option: Option | null) => {
let f = cloneDeep(form); let f = cloneDeep(form);
@ -622,6 +636,27 @@ export default function ComponentForm(props: Props) {
const grainSelect = () => { const grainSelect = () => {
let selected = findSelectedGrain(grainOptions); let selected = findSelectedGrain(grainOptions);
return ( return (
<React.Fragment>
<FormControlLabel
control={
<Switch
value={useCustomGrain}
checked={useCustomGrain}
title="Custom Grain"
onClick={() => {
setUseCustomGrain(!useCustomGrain);
updateCustomGrain()
}}
/>
}
label="Custom Grain"
labelPlacement="start"
/>
{useCustomGrain ?
<Box sx={{border: "1px solid white", borderRadius: 2, padding: 2, marginBottom: 2}}>
<CustomGrainForm onGrainSettingsChange={updateCustomGrain} initialGrain={form.component.customGrainProps()}/>
</Box>
:
<SearchSelect <SearchSelect
selected={selected} selected={selected}
changeSelection={updateGrainType} changeSelection={updateGrainType}
@ -629,6 +664,8 @@ export default function ComponentForm(props: Props) {
options={grainOptions} options={grainOptions}
group group
/> />
}
</React.Fragment>
); );
}; };

View file

@ -10,6 +10,7 @@ import { Pressure } from "models/Pressure";
import { GrainCable } from "models/GrainCable"; import { GrainCable } from "models/GrainCable";
import { extension, Summary } from "pbHelpers/ComponentType"; import { extension, Summary } from "pbHelpers/ComponentType";
import { makeStyles } from "@mui/styles"; import { makeStyles } from "@mui/styles";
import { stringToMaterialColour } from "utils";
interface Props { interface Props {
component: Component | Plenum | Pressure | GrainCable; component: Component | Plenum | Pressure | GrainCable;
@ -100,13 +101,26 @@ export default function UnitMeasurementSummary(props: Props) {
); );
}; };
const grainName = () => {
if(component.settings.grainType === pond.Grain.GRAIN_CUSTOM && component.settings.customGrain?.name){
return component.settings.customGrain.name
}
return GrainDescriber(component.settings.grainType).name
}
const grainColor = () => {
if(component.settings.grainType === pond.Grain.GRAIN_CUSTOM && component.settings.customGrain?.name){
return stringToMaterialColour(component.settings.customGrain.name)
}
return GrainDescriber(component.settings.grainType).colour
}
const getSummaryComponent = (summaries: Summary[]): any => { const getSummaryComponent = (summaries: Summary[]): any => {
if (summaries.length < 1) { if (summaries.length < 1) {
return noSummary(); return noSummary();
} }
let overlays: JSX.Element[] = []; let overlays: JSX.Element[] = [];
let grain = GrainDescriber(component.settings.grainType);
return ( return (
<Grid container> <Grid container>
<Grid size={{ xs: 12 }}> <Grid size={{ xs: 12 }}>
@ -170,7 +184,7 @@ export default function UnitMeasurementSummary(props: Props) {
component.settings.grainType !== pond.Grain.GRAIN_INVALID && ( component.settings.grainType !== pond.Grain.GRAIN_INVALID && (
<Typography variant={largeText ? "body1" : "caption"} color="textPrimary"> <Typography variant={largeText ? "body1" : "caption"} color="textPrimary">
<span key={"grainType"}> <span key={"grainType"}>
Grain Type: <span style={{ color: grain.colour }}>{grain.name}</span> Grain Type: <span style={{ color: grainColor() }}>{grainName()}</span>
</span> </span>
</Typography> </Typography>
)} )}

View file

@ -0,0 +1,321 @@
import { ExpandMore } from "@mui/icons-material"
import { Accordion, AccordionDetails, AccordionSummary, Box, Button, MenuItem, TextField, Typography } from "@mui/material"
import SearchSelect, { Option } from "common/SearchSelect"
import { cloneDeep } from "lodash"
import { pond } from "protobuf-ts/pond"
import { useGlobalState } from "providers"
import { useGrainAPI } from "providers/pond/grainAPI"
import React, { useEffect, useState } from "react"
interface Props {
initialGrain?: pond.GrainSettings
onGrainSettingsChange: (settings: pond.GrainSettings) => void
}
export default function CustomGrainForm(props: Props) {
const {initialGrain, onGrainSettingsChange} = props
const grainAPI = useGrainAPI()
const [{as}] = useGlobalState()
const [name, setName] = useState(initialGrain ? initialGrain.name : "")
const [group, setGroup] = useState(initialGrain ? initialGrain.group : "")
const [equation, setEquation] = useState<pond.MoistureEquation>(initialGrain ? initialGrain.equation : pond.MoistureEquation.MOISTURE_EQUATION_NONE)
const [constantA, setConstantA] = useState(initialGrain ? initialGrain.a.toString() : "0")
const [constantB, setConstantB] = useState(initialGrain ? initialGrain.b.toString() : "0")
const [constantC, setConstantC] = useState(initialGrain ? initialGrain.c.toString() : "0")
const [kgPerBushel, setKgPerBushel] = useState(initialGrain ? initialGrain.kgPerBushel.toString() : "0")
const [bushelsPerTonne, setBushelsPerTonne] = useState(initialGrain ? initialGrain.bushelsPerTonne.toString() : "0")
const [newGrainSettings, setNewGrainSettings] = useState(initialGrain ?? pond.GrainSettings.create())
const [grainMap, setGrainMap] = useState<Map<string, pond.GrainObject>>(
initialGrain ?
new Map([
["Active", pond.GrainObject.create({key: "Active", name: initialGrain.name, settings: initialGrain})]
])
:
new Map())
const [grainOptions, setGrainOptions] = useState<Option[]>(
initialGrain ?
[
{
label: initialGrain.name,
value: "Active",
group: "Active"
}
]
:
[]
)
const [isNew, setIsNew] = useState(false)
const [selectedOption, setSelectedOption] = useState<Option | null>(initialGrain ? {
label: initialGrain.name,
value: "Active",
group: "Active"
} : null)
useEffect(()=>{
grainAPI.listGrains(0, 0, "asc", "name", undefined, undefined, undefined, as).then(resp => {
let options: Option[] = grainOptions
let map: Map<string, pond.GrainObject> = grainMap
if (resp.data.grains){
resp.data.grains.forEach(grain => {
map.set(grain.key, grain)
options.push({
label: grain.name,
value: grain.key,
group: grain.settings?.group,
})
})
}
setGrainOptions([...options])
setGrainMap(map)
})
},[grainAPI])
const invalid = () => {
if (name === "") return true
if (group === "") return true
if (isNaN(parseFloat(constantA))) return true
if (isNaN(parseFloat(constantB))) return true
if (isNaN(parseFloat(constantA))) return true
if (isNaN(parseFloat(kgPerBushel))) return true
if (isNaN(parseFloat(bushelsPerTonne))) return true
return false
}
const saveGrain = () => {
// console.log(newGrainSettings)
grainAPI.addGrain(newGrainSettings, as).then(resp => {
console.log("grain added")
}).catch(err => {
console.log("err")
})
}
const settingsChanged = (newSettings: pond.GrainSettings) => {
setNewGrainSettings(newSettings)
onGrainSettingsChange(newSettings)
}
const newGrain = () => {
return (
<React.Fragment>
<TextField
sx={{marginBottom: 2}}
fullWidth
label="Name*"
value={name}
onChange={(e) => {
let name = e.target.value
setName(name)
setIsNew(true)
let settings = cloneDeep(newGrainSettings)
settings.name = name
settingsChanged(settings)
}}/>
<TextField
sx={{marginBottom: 2}}
fullWidth
label="Group*"
value={group}
onChange={(e) => {
let group = e.target.value
setGroup(group)
setIsNew(true)
let settings = cloneDeep(newGrainSettings)
settings.group = group
settingsChanged(settings)
}}/>
<TextField
sx={{marginBottom: 2}}
fullWidth
value={equation}
helperText={"Not selecting an EMC equation to use will return the humidity instead of EMC"}
label="EMC Equation"
onChange={(e) => {
let enumVal = parseFloat(e.target.value)
setEquation(enumVal)
setIsNew(true)
let settings = cloneDeep(newGrainSettings)
settings.equation = enumVal
settingsChanged(settings)
}}
select>
<MenuItem key={pond.MoistureEquation.MOISTURE_EQUATION_NONE} value={pond.MoistureEquation.MOISTURE_EQUATION_NONE}>
None
</MenuItem>
<MenuItem key={pond.MoistureEquation.MOISTURE_EQUATION_CHUNG_PFOST} value={pond.MoistureEquation.MOISTURE_EQUATION_CHUNG_PFOST}>
Chung-Pfost
</MenuItem>
<MenuItem key={pond.MoistureEquation.MOISTURE_EQUATION_HENDERSON} value={pond.MoistureEquation.MOISTURE_EQUATION_HENDERSON}>
Henderson
</MenuItem>
<MenuItem key={pond.MoistureEquation.MOISTURE_EQUATION_HALSEY} value={pond.MoistureEquation.MOISTURE_EQUATION_HALSEY}>
Halsey
</MenuItem>
<MenuItem key={pond.MoistureEquation.MOISTURE_EQUATION_OSWIN} value={pond.MoistureEquation.MOISTURE_EQUATION_OSWIN}>
Oswin
</MenuItem>
</TextField>
<TextField
sx={{marginBottom: 2}}
fullWidth
type="number"
value={constantA}
error={isNaN(parseFloat(constantA))}
helperText={isNaN(parseFloat(constantA)) ? "Must be a valid number" : ""}
onChange={(e) => {
let val = e.target.value
setConstantA(val)
setIsNew(true)
if(!isNaN(parseFloat(val))){
let settings = cloneDeep(newGrainSettings)
settings.a = parseFloat(val)
settingsChanged(settings)
}
}}
label="Constant A"/>
<TextField
sx={{marginBottom: 2}}
fullWidth
type="number"
value={constantB}
error={isNaN(parseFloat(constantB))}
helperText={isNaN(parseFloat(constantB)) ? "Must be a valid number" : ""}
onChange={(e) => {
let val = e.target.value
setConstantB(val)
setIsNew(true)
if(!isNaN(parseFloat(val))){
let settings = cloneDeep(newGrainSettings)
settings.b = parseFloat(val)
settingsChanged(settings)
}
}}
label="Constant B"/>
<TextField
sx={{marginBottom: 2}}
fullWidth
type="number"
value={constantC}
error={isNaN(parseFloat(constantC))}
helperText={isNaN(parseFloat(constantC)) ? "Must be a valid number" : ""}
onChange={(e) => {
let val = e.target.value
setConstantC(val)
setIsNew(true)
if(!isNaN(parseFloat(val))){
let settings = cloneDeep(newGrainSettings)
settings.c = parseFloat(val)
settingsChanged(settings)
}
}}
label="Constant C"/>
<TextField
sx={{marginBottom: 2}}
fullWidth
type="number"
value={kgPerBushel}
error={isNaN(parseFloat(kgPerBushel))}
helperText={isNaN(parseFloat(kgPerBushel)) ? "Must be a valid number" : ""}
onChange={(e) => {
let val = e.target.value
setKgPerBushel(val)
setIsNew(true)
if(!isNaN(parseFloat(val))){
let settings = cloneDeep(newGrainSettings)
settings.kgPerBushel = parseFloat(val)
settingsChanged(settings)
}
}}
label="kg per Bushel"/>
<TextField
sx={{marginBottom: 2}}
fullWidth
type="number"
value={bushelsPerTonne}
error={isNaN(parseFloat(bushelsPerTonne))}
helperText={isNaN(parseFloat(bushelsPerTonne)) ? "Must be a valid number" : ""}
onChange={(e) => {
let val = e.target.value
setBushelsPerTonne(val)
setIsNew(true)
if(!isNaN(parseFloat(val))){
let settings = cloneDeep(newGrainSettings)
settings.bushelsPerTonne = parseFloat(val)
settingsChanged(settings)
}
}}
label="Bushels per Tonne"/>
{isNew &&
<Box display='flex' justifyContent="flex-end">
<Button
variant="contained"
disabled={invalid()}
onClick={() => {
saveGrain()
setIsNew(false)
}}
color="primary">
Save Custom Grain
</Button>
</Box>
}
</React.Fragment>
)
}
const grainAccordion = () => {
return (
<Accordion>
<AccordionSummary expandIcon={<ExpandMore />}>Custom Grain Properties</AccordionSummary>
<AccordionDetails>
{newGrain()}
</AccordionDetails>
</Accordion>
)
}
return (
<React.Fragment>
{grainOptions.length === 0 ?
<Box>
<Typography sx={{marginBottom: 1}}>Custom Grain Properties</Typography>
{newGrain()}
</Box>
:
<Box>
<Box sx={{marginBottom: 2}}>
<SearchSelect
label="My Grains"
selected={selectedOption}
changeSelection={option => {
setIsNew(false)
setSelectedOption(option)
//when an option is selected set all of the state variables controlling the form entries
let grain = grainMap.get(option?.value)
if(grain && grain.settings){
//set the form values
setName(grain.name)
setGroup(grain.settings.group)
setEquation(grain.settings.equation)
setConstantA(grain.settings.a.toString())
setConstantB(grain.settings.b.toString())
setConstantC(grain.settings.c.toString())
setKgPerBushel(grain.settings.kgPerBushel.toString())
setBushelsPerTonne(grain.settings.bushelsPerTonne.toString())
//the the new grain settings object
setNewGrainSettings(grain.settings)
//pass that settings object back up
settingsChanged(grain.settings)
}
}}
group
options={grainOptions}
/>
</Box>
{grainAccordion()}
</Box>
}
</React.Fragment>
)
}

View file

@ -14,12 +14,11 @@ import WheatImg from "assets/grain/wheat.jpg";
import { Option } from "common/SearchSelect"; import { Option } from "common/SearchSelect";
import { cloneDeep } from "lodash"; import { cloneDeep } from "lodash";
import { pond } from "protobuf-ts/pond"; import { pond } from "protobuf-ts/pond";
import { Equation } from "./GrainMoisture";
export interface GrainExtension { export interface GrainExtension {
name: string; name: string;
group: string; group: string;
equation: Equation; equation: pond.MoistureEquation;
a: number; a: number;
b: number; b: number;
c: number; c: number;
@ -37,7 +36,7 @@ const defaultSetTemp = 30.0;
const defaultGrain: GrainExtension = { const defaultGrain: GrainExtension = {
name: "None", name: "None",
group: "", group: "",
equation: Equation.none, equation: pond.MoistureEquation.MOISTURE_EQUATION_NONE,
a: 0, a: 0,
b: 0, b: 0,
c: 0, c: 0,
@ -56,7 +55,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Custom Type", name: "Custom Type",
group: "", group: "",
equation: Equation.none, equation: pond.MoistureEquation.MOISTURE_EQUATION_NONE,
a: 0, a: 0,
b: 0, b: 0,
c: 0, c: 0,
@ -72,7 +71,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Barley", name: "Barley",
group: "Barley", group: "Barley",
equation: Equation.chungPfost, equation: pond.MoistureEquation.MOISTURE_EQUATION_CHUNG_PFOST,
a: 475.12, a: 475.12,
b: 0.14843, b: 0.14843,
c: 71.996, c: 71.996,
@ -89,7 +88,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Buckwheat", name: "Buckwheat",
group: "Buckwheat", group: "Buckwheat",
equation: Equation.chungPfost, equation: pond.MoistureEquation.MOISTURE_EQUATION_CHUNG_PFOST,
a: 103540000, a: 103540000,
b: 0.1646, b: 0.1646,
c: 15853000, c: 15853000,
@ -106,7 +105,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Canola", name: "Canola",
group: "Canola", group: "Canola",
equation: Equation.halsey, equation: pond.MoistureEquation.MOISTURE_EQUATION_HALSEY,
a: 3.489, a: 3.489,
b: -0.010553, b: -0.010553,
c: 1.86, c: 1.86,
@ -124,7 +123,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Rapeseed", name: "Rapeseed",
group: "Canola", group: "Canola",
equation: Equation.halsey, equation: pond.MoistureEquation.MOISTURE_EQUATION_HALSEY,
a: 3.0026, a: 3.0026,
b: -0.0048967, b: -0.0048967,
c: 1.7607, c: 1.7607,
@ -141,7 +140,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Corn (Henderson)", name: "Corn (Henderson)",
group: "Corn", group: "Corn",
equation: Equation.henderson, equation: pond.MoistureEquation.MOISTURE_EQUATION_HENDERSON,
a: 0.000066612, a: 0.000066612,
b: 1.9677, b: 1.9677,
c: 42.143, c: 42.143,
@ -158,7 +157,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Corn (Chung-Pfost)", name: "Corn (Chung-Pfost)",
group: "Corn", group: "Corn",
equation: Equation.chungPfost, equation: pond.MoistureEquation.MOISTURE_EQUATION_CHUNG_PFOST,
a: 374.34, a: 374.34,
b: 0.18662, b: 0.18662,
c: 31.696, c: 31.696,
@ -175,7 +174,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Corn (Oswin)", name: "Corn (Oswin)",
group: "Corn", group: "Corn",
equation: Equation.oswin, equation: pond.MoistureEquation.MOISTURE_EQUATION_OSWIN,
a: 15.303, a: 15.303,
b: -0.10164, b: -0.10164,
c: 3.0358, c: 3.0358,
@ -192,7 +191,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Maize White", name: "Maize White",
group: "Corn", group: "Corn",
equation: Equation.henderson, equation: pond.MoistureEquation.MOISTURE_EQUATION_HENDERSON,
a: 0.000066612, a: 0.000066612,
b: 1.9677, b: 1.9677,
c: 70.143, c: 70.143,
@ -209,7 +208,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Maize Yellow", name: "Maize Yellow",
group: "Corn", group: "Corn",
equation: Equation.henderson, equation: pond.MoistureEquation.MOISTURE_EQUATION_HENDERSON,
a: 0.000066612, a: 0.000066612,
b: 1.9677, b: 1.9677,
c: 65.143, c: 65.143,
@ -226,7 +225,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Oats (Henderson)", name: "Oats (Henderson)",
group: "Oats", group: "Oats",
equation: Equation.henderson, equation: pond.MoistureEquation.MOISTURE_EQUATION_HENDERSON,
a: 0.000085511, a: 0.000085511,
b: 2.0087, b: 2.0087,
c: 37.811, c: 37.811,
@ -243,7 +242,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Oats (Chung-Pfost)", name: "Oats (Chung-Pfost)",
group: "Oats", group: "Oats",
equation: Equation.chungPfost, equation: pond.MoistureEquation.MOISTURE_EQUATION_CHUNG_PFOST,
a: 442.85, a: 442.85,
b: 0.21228, b: 0.21228,
c: 35.803, c: 35.803,
@ -260,7 +259,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Oats (Oswin)", name: "Oats (Oswin)",
group: "Oats", group: "Oats",
equation: Equation.oswin, equation: pond.MoistureEquation.MOISTURE_EQUATION_OSWIN,
a: 12.412, a: 12.412,
b: -0.060707, b: -0.060707,
c: 2.9397, c: 2.9397,
@ -277,7 +276,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Peanuts", name: "Peanuts",
group: "Peanuts", group: "Peanuts",
equation: Equation.oswin, equation: pond.MoistureEquation.MOISTURE_EQUATION_OSWIN,
a: 8.6588, a: 8.6588,
b: -0.057904, b: -0.057904,
c: 2.6204, c: 2.6204,
@ -294,7 +293,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Long Grain Rice", name: "Long Grain Rice",
group: "Rice", group: "Rice",
equation: Equation.henderson, equation: pond.MoistureEquation.MOISTURE_EQUATION_HENDERSON,
a: 0.000041276, a: 0.000041276,
b: 2.1191, b: 2.1191,
c: 49.828, c: 49.828,
@ -311,7 +310,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Medium Grain Rice", name: "Medium Grain Rice",
group: "Rice", group: "Rice",
equation: Equation.henderson, equation: pond.MoistureEquation.MOISTURE_EQUATION_HENDERSON,
a: 0.000035502, a: 0.000035502,
b: 2.31, b: 2.31,
c: 27.396, c: 27.396,
@ -328,7 +327,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Short Grain Rice", name: "Short Grain Rice",
group: "Rice", group: "Rice",
equation: Equation.henderson, equation: pond.MoistureEquation.MOISTURE_EQUATION_HENDERSON,
a: 0.000048524, a: 0.000048524,
b: 2.0794, b: 2.0794,
c: 45.646, c: 45.646,
@ -345,7 +344,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Sorghum", name: "Sorghum",
group: "Sorghum", group: "Sorghum",
equation: Equation.chungPfost, equation: pond.MoistureEquation.MOISTURE_EQUATION_CHUNG_PFOST,
a: 797.33, a: 797.33,
b: 0.18159, b: 0.18159,
c: 52.238, c: 52.238,
@ -362,7 +361,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Soybeans", name: "Soybeans",
group: "Soybeans", group: "Soybeans",
equation: Equation.chungPfost, //equation: Equation.chungPfost,
equation: pond.MoistureEquation.MOISTURE_EQUATION_CHUNG_PFOST,
a: 228.2, a: 228.2,
b: 0.2072, b: 0.2072,
c: 30, c: 30,
@ -379,7 +379,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Sunflower", name: "Sunflower",
group: "Sunflower", group: "Sunflower",
equation: Equation.henderson, equation: pond.MoistureEquation.MOISTURE_EQUATION_HENDERSON,
a: 0.00031, a: 0.00031,
b: 1.7459, b: 1.7459,
c: 66.603, c: 66.603,
@ -396,7 +396,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Durum Wheat", name: "Durum Wheat",
group: "Wheat", group: "Wheat",
equation: Equation.oswin, equation: pond.MoistureEquation.MOISTURE_EQUATION_OSWIN,
a: 13.101, a: 13.101,
b: -0.052626, b: -0.052626,
c: 2.9987, c: 2.9987,
@ -413,7 +413,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Hard Red Wheat", name: "Hard Red Wheat",
group: "Wheat", group: "Wheat",
equation: Equation.chungPfost, //equation: Equation.chungPfost,
equation: pond.MoistureEquation.MOISTURE_EQUATION_CHUNG_PFOST,
a: 610.34, a: 610.34,
b: 0.15526, b: 0.15526,
c: 93.213, c: 93.213,
@ -430,7 +431,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Wheat SAWOS", name: "Wheat SAWOS",
group: "Wheat", group: "Wheat",
equation: Equation.chungPfost, //equation: Equation.chungPfost,
equation: pond.MoistureEquation.MOISTURE_EQUATION_CHUNG_PFOST,
a: 610.34, a: 610.34,
b: 0.15526, b: 0.15526,
c: 93.213, c: 93.213,
@ -447,7 +449,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Un-retted Flax", name: "Un-retted Flax",
group: "Flax", group: "Flax",
equation: Equation.halsey, equation: pond.MoistureEquation.MOISTURE_EQUATION_HALSEY,
a: 5.11, a: 5.11,
b: Math.pow(-8.46 * 10, -3), b: Math.pow(-8.46 * 10, -3),
c: 2.26, c: 2.26,
@ -464,7 +466,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Dew-retted Flax", name: "Dew-retted Flax",
group: "Flax", group: "Flax",
equation: Equation.oswin, equation: pond.MoistureEquation.MOISTURE_EQUATION_OSWIN,
a: 6.5, a: 6.5,
b: Math.pow(-1.68 * 10, -2), b: Math.pow(-1.68 * 10, -2),
c: 3.2, c: 3.2,
@ -481,7 +483,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Yellow Peas", name: "Yellow Peas",
group: "Peas", group: "Peas",
equation: Equation.oswin, equation: pond.MoistureEquation.MOISTURE_EQUATION_OSWIN,
a: 14.81, a: 14.81,
b: -0.109, b: -0.109,
c: 3.019, c: 3.019,
@ -498,7 +500,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Blaze Lentils", name: "Blaze Lentils",
group: "Lentils", group: "Lentils",
equation: Equation.halsey, equation: pond.MoistureEquation.MOISTURE_EQUATION_HALSEY,
a: 5.39, a: 5.39,
b: -0.015, b: -0.015,
c: 2.273, c: 2.273,
@ -515,7 +517,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Redberry Lentils", name: "Redberry Lentils",
group: "Lentils", group: "Lentils",
equation: Equation.halsey, equation: pond.MoistureEquation.MOISTURE_EQUATION_HALSEY,
a: 4.749, a: 4.749,
b: -0.0116, b: -0.0116,
c: 2.066, c: 2.066,
@ -532,7 +534,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Robin Lentils", name: "Robin Lentils",
group: "Lentils", group: "Lentils",
equation: Equation.halsey, equation: pond.MoistureEquation.MOISTURE_EQUATION_HALSEY,
a: 5.176, a: 5.176,
b: -0.0065, b: -0.0065,
c: 2.337, c: 2.337,
@ -549,7 +551,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Dry Beans Red", name: "Dry Beans Red",
group: "Dry Beans", group: "Dry Beans",
equation: Equation.halsey, equation: pond.MoistureEquation.MOISTURE_EQUATION_HALSEY,
a: 4.2669, a: 4.2669,
b: -0.013382, b: -0.013382,
c: 1.6933, c: 1.6933,
@ -564,7 +566,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Dry Beans Black", name: "Dry Beans Black",
group: "Dry Beans", group: "Dry Beans",
equation: Equation.halsey, equation: pond.MoistureEquation.MOISTURE_EQUATION_HALSEY,
a: 5.2003, a: 5.2003,
b: -0.022685, b: -0.022685,
c: 1.9656, c: 1.9656,
@ -579,7 +581,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Rye (Henderson)", name: "Rye (Henderson)",
group: "Rye", group: "Rye",
equation: Equation.henderson, equation: pond.MoistureEquation.MOISTURE_EQUATION_HENDERSON,
a: 0.00006343, a: 0.00006343,
b: 2.2060, b: 2.2060,
c: 13.1810, c: 13.1810,
@ -594,7 +596,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Rye (Chung-Pfost)", name: "Rye (Chung-Pfost)",
group: "Rye", group: "Rye",
equation: Equation.chungPfost, //equation: Equation.chungPfost,
equation: pond.MoistureEquation.MOISTURE_EQUATION_CHUNG_PFOST,
a: 461.0230, a: 461.0230,
b: 0.1840, b: 0.1840,
c: 36.7410, c: 36.7410,
@ -609,7 +612,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Rye (Halsey)", name: "Rye (Halsey)",
group: "Rye", group: "Rye",
equation: Equation.halsey, equation: pond.MoistureEquation.MOISTURE_EQUATION_HALSEY,
a: 4.2970, a: 4.2970,
b: 0.380, b: 0.380,
c: 2.2710, c: 2.2710,
@ -624,7 +627,7 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
{ {
name: "Rye (Oswin)", name: "Rye (Oswin)",
group: "Rye", group: "Rye",
equation: Equation.oswin, equation: pond.MoistureEquation.MOISTURE_EQUATION_OSWIN,
a: 11.8870, a: 11.8870,
b: 0.0210, b: 0.0210,
c: 3.2620, c: 3.2620,

View file

@ -16,7 +16,8 @@ const toERH = (humidity: number): number => {
export function ExtractMoisture( export function ExtractMoisture(
type: pond.Grain | undefined, type: pond.Grain | undefined,
celsius: number, celsius: number,
humidity: number humidity: number,
customGrain?: pond.GrainSettings
): number { ): number {
if (humidity <= 0) { if (humidity <= 0) {
return 0; return 0;
@ -26,20 +27,43 @@ export function ExtractMoisture(
type === undefined || type === undefined ||
type === pond.Grain.GRAIN_NONE || type === pond.Grain.GRAIN_NONE ||
type === pond.Grain.GRAIN_INVALID || type === pond.Grain.GRAIN_INVALID ||
type === pond.Grain.GRAIN_CUSTOM (type === pond.Grain.GRAIN_CUSTOM && customGrain === undefined)
) { ) {
return humidity; return humidity;
} }
let dry = humidity; let dry = humidity;
let eq: pond.MoistureEquation
let constA: number
let constB: number
let constC: number
if(type === pond.Grain.GRAIN_CUSTOM && customGrain){
if(customGrain.equation === pond.MoistureEquation.MOISTURE_EQUATION_NONE) return humidity
eq = customGrain.equation
constA = customGrain.a
constB = customGrain.b
constC = customGrain.c
}else{
let ctx = GrainDescriber(type); let ctx = GrainDescriber(type);
dry = toDryMoisture(ctx.equation, celsius, humidity, ctx.a, ctx.b, ctx.c); eq = ctx.equation
constA = ctx.a
constB = ctx.b
constC = ctx.c
}
dry = toDryMoisture(eq, celsius, humidity, constA, constB, constC);
return dryToWet(dry); return dryToWet(dry);
} }
export function WaterContent(type: pond.Grain, bushels: number, moistureContent: number): number { export function WaterContent(type: pond.Grain, bushels: number, moistureContent: number, customGrain?: pond.GrainSettings): number {
let grain = GrainDescriber(type); //kg per bushel conversion
return bushels * grain.weightConversionKg * moistureContent; let conversion = 0
if(type === pond.Grain.GRAIN_CUSTOM && customGrain){
conversion = customGrain.kgPerBushel
}else{
conversion = GrainDescriber(type).weightConversionKg;
}
return bushels * conversion * moistureContent;
} }
export function MoistureToHumidity( export function MoistureToHumidity(
@ -69,7 +93,7 @@ function wetToDry(wetMC: number): number {
} }
function toDryMoisture( function toDryMoisture(
eq: Equation, eq: pond.MoistureEquation,
T: number, T: number,
RH: number, RH: number,
a: number, a: number,
@ -78,13 +102,13 @@ function toDryMoisture(
): number { ): number {
const ERH: number = toERH(RH); const ERH: number = toERH(RH);
switch (eq) { switch (eq) {
case Equation.chungPfost: case pond.MoistureEquation.MOISTURE_EQUATION_CHUNG_PFOST:
return chungPfost(T, ERH, a, b, c); return chungPfost(T, ERH, a, b, c);
case Equation.halsey: case pond.MoistureEquation.MOISTURE_EQUATION_HALSEY:
return halsey(T, ERH, a, b, c); return halsey(T, ERH, a, b, c);
case Equation.henderson: case pond.MoistureEquation.MOISTURE_EQUATION_HENDERSON:
return henderson(T, ERH, a, b, c); return henderson(T, ERH, a, b, c);
case Equation.oswin: case pond.MoistureEquation.MOISTURE_EQUATION_OSWIN:
return oswin(T, ERH, a, b, c); return oswin(T, ERH, a, b, c);
default: default:
return RH; return RH;
@ -92,7 +116,7 @@ function toDryMoisture(
} }
function dryMoistureToHumidity( function dryMoistureToHumidity(
eq: Equation, eq: pond.MoistureEquation,
celsius: number, celsius: number,
dryMC: number, dryMC: number,
a: number, a: number,
@ -101,16 +125,16 @@ function dryMoistureToHumidity(
): number { ): number {
let ERH = 0; let ERH = 0;
switch (eq) { switch (eq) {
case Equation.chungPfost: case pond.MoistureEquation.MOISTURE_EQUATION_CHUNG_PFOST:
ERH = chungPfostInverse(celsius, dryMC, a, b, c); ERH = chungPfostInverse(celsius, dryMC, a, b, c);
break; break;
case Equation.halsey: case pond.MoistureEquation.MOISTURE_EQUATION_HALSEY:
ERH = halseyInverse(celsius, dryMC, a, b, c); ERH = halseyInverse(celsius, dryMC, a, b, c);
break; break;
case Equation.henderson: case pond.MoistureEquation.MOISTURE_EQUATION_HENDERSON:
ERH = hendersonInverse(celsius, dryMC, a, b, c); ERH = hendersonInverse(celsius, dryMC, a, b, c);
break; break;
case Equation.oswin: case pond.MoistureEquation.MOISTURE_EQUATION_OSWIN:
ERH = oswinInverse(celsius, dryMC, a, b, c); ERH = oswinInverse(celsius, dryMC, a, b, c);
break; break;
default: default:

View file

@ -125,6 +125,7 @@ export default function GrainTransaction(props: Props) {
.then(resp => { .then(resp => {
//let sourceOps: Option[] = sourceOptions //let sourceOps: Option[] = sourceOptions
let binOps: Option[] = []; let binOps: Option[] = [];
if(resp.data.bins){
resp.data.bins.forEach(bin => { resp.data.bins.forEach(bin => {
let b = Bin.create(bin); let b = Bin.create(bin);
if (mainObject.key() !== b.key()) { if (mainObject.key() !== b.key()) {
@ -133,9 +134,10 @@ export default function GrainTransaction(props: Props) {
value: b, value: b,
group: "Bins" group: "Bins"
}; };
(!restrictMatching || grainTypesMatch(op.value, mainObject)) && binOps.push(op); (!restrictMatching || grainTypesMatch(op.value, mainObject) || op.value.grainName() === mainObject.grainName()) && binOps.push(op);
} }
}); });
}
setBinOptions([...binOps]); setBinOptions([...binOps]);
}) })
.finally(() => { .finally(() => {
@ -151,6 +153,7 @@ export default function GrainTransaction(props: Props) {
.then(resp => { .then(resp => {
//let sourceOps: Option[] = sourceOptions //let sourceOps: Option[] = sourceOptions
let bagOps: Option[] = []; let bagOps: Option[] = [];
if(resp.data.grainBags){
resp.data.grainBags.forEach(bag => { resp.data.grainBags.forEach(bag => {
let b = GrainBag.create(bag); let b = GrainBag.create(bag);
if (mainObject.key() !== b.key()) { if (mainObject.key() !== b.key()) {
@ -159,9 +162,10 @@ export default function GrainTransaction(props: Props) {
value: b, value: b,
group: "Grain Bags" group: "Grain Bags"
}; };
(!restrictMatching || grainTypesMatch(op.value, mainObject)) && bagOps.push(op); (!restrictMatching || grainTypesMatch(op.value, mainObject) || op.value.grainName() === mainObject.grainName()) && bagOps.push(op);
} }
}); });
}
setBagOptions([...bagOps]); setBagOptions([...bagOps]);
}) })
.finally(() => { .finally(() => {
@ -184,7 +188,7 @@ export default function GrainTransaction(props: Props) {
value: f, value: f,
group: "Fields" group: "Fields"
}; };
(!restrictMatching || grainTypesMatch(op.value, mainObject)) && fieldOps.push(op); (!restrictMatching || grainTypesMatch(op.value, mainObject) || op.value.grainName() === mainObject.grainName()) && fieldOps.push(op);
}); });
setFieldOptions([...fieldOps]); setFieldOptions([...fieldOps]);
}) })
@ -356,13 +360,6 @@ export default function GrainTransaction(props: Props) {
if (source.grain() === destination.grain()) { if (source.grain() === destination.grain()) {
matching = true; matching = true;
} }
} else if (source.storage() === pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN) {
if (
source.customType().toLowerCase() === destination.customType().toLowerCase() &&
source.bushelsPerTonne() === destination.bushelsPerTonne()
) {
matching = true;
}
} }
} }
return matching; return matching;
@ -373,7 +370,7 @@ export default function GrainTransaction(props: Props) {
if (grainTypesMatch(selectedSource.value, selectedDestination.value)) { if (grainTypesMatch(selectedSource.value, selectedDestination.value)) {
updateInventory(); updateInventory();
} else { } else {
//open dialog saying that the destinations grain type will change from this action //open dialog saying that the grain types do not match or because it is a custom type
setGrainChangeDialog(true); setGrainChangeDialog(true);
} }
} else { } else {
@ -381,6 +378,36 @@ export default function GrainTransaction(props: Props) {
} }
}; };
/**
* the function is used to determine what text to display to the user when the grain types dont match
* or when it sees any of the objects involved as having a custom grain type
* @param source the source of the grain
* @param destination the destination of the grain
* @returns the text describing the situation
*/
const confirmationText = () => {
if(selectedSource && selectedDestination){
let source = selectedSource?.value
let destination = selectedDestination?.value
//both are custom
if(source.storage() === pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN && destination.storage() === pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN){
return "Both source and destination are using custom grain types, they may not match. Would you like to continue with the transaction?"
}
//source is custom destination is not
if(source.storage() === pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN){
return "The source is using a custom grain type and may not match the destination. Would you like to continue with the transaction?"
}
//destination is custom source is not
if(destination.storage() === pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN){
return "The destination is using a custom grain type and may not match the source. Would you like to continue with the transaction?"
}
}
//neither are custom
return "The Grain types do not match. Are you sure you would like to perform this transaction?"
}
const grainChange = () => { const grainChange = () => {
return ( return (
<ResponsiveDialog <ResponsiveDialog
@ -389,7 +416,7 @@ export default function GrainTransaction(props: Props) {
setGrainChangeDialog(false); setGrainChangeDialog(false);
}}> }}>
<DialogContent> <DialogContent>
The grain type of the destination may change as a result of this action. {confirmationText()}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button <Button

View file

@ -90,11 +90,19 @@ export class Bin {
public customType(): string { public customType(): string {
let c = ""; let c = "";
if (this.settings.inventory) { if (this.settings.inventory) {
if (this.settings.inventory.customGrain){
c = this.settings.inventory.customGrain.name
}else{
c = this.settings.inventory.customTypeName; c = this.settings.inventory.customTypeName;
} }
}
return c; return c;
} }
public customGrain(): pond.GrainSettings | undefined {
return this.settings.inventory?.customGrain ?? undefined
}
public empty(): boolean { public empty(): boolean {
return this.settings.inventory?.empty || (this.settings.inventory !== undefined && this.settings.inventory !== null && this.bushels() < 5); return this.settings.inventory?.empty || (this.settings.inventory !== undefined && this.settings.inventory !== null && this.bushels() < 5);
} }

View file

@ -142,4 +142,9 @@ export class Component {
return getFriendlyAddressTypeName(this.settings.addressType); return getFriendlyAddressTypeName(this.settings.addressType);
} }
}; };
public customGrainProps(): pond.GrainSettings | undefined {
if(this.settings.customGrain) return this.settings.customGrain
return
}
} }

View file

@ -819,6 +819,7 @@ export default function Bin(props: Props) {
fans={fans} fans={fans}
heaters={heaters} heaters={heaters}
grain={bin.grain()} grain={bin.grain()}
customGrain={bin.customGrain()}
/> />
)} )}
<Box marginTop={2}> <Box marginTop={2}>
@ -980,6 +981,7 @@ export default function Bin(props: Props) {
fans={fans} fans={fans}
heaters={heaters} heaters={heaters}
grain={bin.grain()} grain={bin.grain()}
customGrain={bin.customGrain()}
/> />
</Box> </Box>
)} )}

View file

@ -0,0 +1,123 @@
import { useHTTP } from "hooks";
import { createContext, PropsWithChildren, useContext } from "react";
import { pond } from "protobuf-ts/pond";
import { pondURL } from "./pond";
import { AxiosResponse } from "axios";
import { useGlobalState } from "providers";
import { or } from "utils";
export interface IGrainInterface {
addGrain: (
settings: pond.GrainSettings,
otherTeam?: string
) => Promise<AxiosResponse<pond.AddGrainResponse>>;
getGrain: (key: string, otherTeam?: string) => Promise<AxiosResponse<pond.GetGrainResponse>>
listGrains: (
limit: number,
offset: number,
order?: "asc" | "desc",
orderBy?: string,
search?: string,
keys?: string[],
types?: string[],
otherTeam?: string,
) => Promise<AxiosResponse<pond.ListGrainsResponse>>;
removeGrain: (key: string, otherTeam?: string) => Promise<AxiosResponse<pond.RemoveGrainResponse>>;
}
export const GrainAPIcontext = createContext<IGrainInterface>({} as IGrainInterface);
interface Props {}
export default function GrainProvider(props: PropsWithChildren<Props>) {
const { children } = props;
const { get, del, post } = useHTTP();
const [{ as }] = useGlobalState();
//add
const addGrain = (settings: pond.GrainSettings, otherTeam?: string) => {
const view = otherTeam ? otherTeam : as
if (view) {
return post<pond.AddGrainResponse>(
pondURL("/grains?&as=" + view),
settings
);
}
return post<pond.AddGrainResponse>(pondURL("/grains"), settings);
};
//get
const getGrain = (key: string, otherTeam?: string) => {
const view = otherTeam ? otherTeam : as
const url = "/grains/" + key + (view ? "?as=" + view : "")
return new Promise<AxiosResponse<pond.GetGrainResponse>>((resolve, reject)=>{
get<pond.GetGrainResponse>(pondURL(url))
.then(resp => {
if (resp.data.grain){
resp.data.grain = pond.GrainObject.fromObject(resp.data.grain)
}
resolve(resp)
})
.catch(err => {
reject(err)
})
})
}
//list
const listGrains = (
limit: number,
offset: number,
order?: "asc" | "desc",
orderBy?: string,
search?: string,
keys?: string[],
types?: string[],
otherTeam?: string
) => {
return new Promise<AxiosResponse<pond.ListGrainsResponse>>((resolve, reject)=>{
const view = otherTeam ? otherTeam : as
get<pond.ListGrainsResponse>(
pondURL(
"/grains?limit=" +
"?limit=" +
limit +
"&offset=" +
offset +
("&order=" + or(order, "asc")) +
("&by=" + or(orderBy, "key")) +
(search ? "&search=" + search : "") +
(keys ? "&keys=" + keys.join(",") : "") +
(types ? "&types=" + types.join(",") : "") +
(view ? "&as=" + view : "")
)
).then(resp => {
resp.data = pond.ListGrainsResponse.fromObject(resp.data);
return resolve(resp)
}).catch(err => {
return reject(err)
})
})
};
//remove
const removeGrain = (key: string, otherTeam?: string) => {
const view = otherTeam ? otherTeam : as
if (view) {
return del<pond.RemoveGrainResponse>(pondURL("/grains/" + key + "?as=" + view));
}
return del<pond.RemoveGrainResponse>(pondURL("/grains/" + key));
};
return (
<GrainAPIcontext.Provider
value={{
addGrain,
getGrain,
listGrains,
removeGrain
}}>
{children}
</GrainAPIcontext.Provider>
);
}
export const useGrainAPI = () => useContext(GrainAPIcontext);

View file

@ -38,6 +38,7 @@ import JohnDeereProvider, { useJohnDeereProxyAPI } from "./johnDeereProxyAPI";
import LibraCartProvider, { useLibraCartProxyAPI } from "./libracartProxyAPI"; import LibraCartProvider, { useLibraCartProxyAPI } from "./libracartProxyAPI";
import CNHiProvider, { useCNHiProxyAPI } from "./cnhiProxyAPI"; import CNHiProvider, { useCNHiProxyAPI } from "./cnhiProxyAPI";
import DevicePresetProvider, { useDevicePresetAPI } from "./devicePresetAPI"; import DevicePresetProvider, { useDevicePresetAPI } from "./devicePresetAPI";
import GrainProvider, { useGrainAPI } from "./grainAPI";
// import NoteProvider from "providers/noteAPI"; // import NoteProvider from "providers/noteAPI";
export const pondURL = (partial: string, demo: boolean = false): string => { export const pondURL = (partial: string, demo: boolean = false): string => {
@ -93,7 +94,9 @@ export default function PondProvider(props: PropsWithChildren<any>) {
<KeyManagerProvider> <KeyManagerProvider>
<DevicePresetProvider> <DevicePresetProvider>
<ImagekitProvider> <ImagekitProvider>
<GrainProvider>
{children} {children}
</GrainProvider>
</ImagekitProvider> </ImagekitProvider>
</DevicePresetProvider> </DevicePresetProvider>
</KeyManagerProvider> </KeyManagerProvider>
@ -173,5 +176,6 @@ export {
useJohnDeereProxyAPI, useJohnDeereProxyAPI,
useCNHiProxyAPI, useCNHiProxyAPI,
useLibraCartProxyAPI, useLibraCartProxyAPI,
useDevicePresetAPI useDevicePresetAPI,
useGrainAPI
}; };