import { Accordion, AccordionDetails, AccordionSummary, Box, Button, darken, Grid, Slider, Theme, Typography } from "@mui/material"; import { ExpandMore } from "@mui/icons-material"; import UnitMeasurementSummary from "component/UnitMeasurementSummary"; import { ExtractMoisture } from "grain"; import { cloneDeep } from "lodash"; import { Component, Interaction } from "models"; import { UnitMeasurement } from "models/UnitMeasurement"; import { interactionConditionText, interactionResultText } from "pbHelpers/Interaction"; import { describeMeasurement } from "pbHelpers/MeasurementDescriber"; import { pond, quack } from "protobuf-ts/pond"; import { useGlobalState, useInteractionsAPI, useSnackbar } from "providers"; import React, { useEffect, useState } from "react"; import { avg, fahrenheitToCelsius } from "utils"; import { makeStyles } from "@mui/styles"; import { Mark } from "@mui/material/Slider/useSlider.types"; const useStyles = makeStyles((theme: Theme) => { return ({ displayBG: { marginTop: 10, background: darken(theme.palette.background.default, 0.05), borderRadius: 5, padding: 10 }, markContainer: { zIndex: 2 }, arrowDown: { width: 0, height: 0, borderLeft: "10px solid transparent", borderRight: "10px solid transparent" //borderTop: "10px solid yellow" }, sliderRoot: {}, sliderThumb: { height: 15, width: 15, backgroundColor: "yellow" }, sliderTrack: { height: 3, backgroundColor: "white" }, sliderRail: { height: 3, backgroundColor: "white" }, sliderValLabel: { left: -20, top: 40, background: "transparent", "& *": { color: "#fff" } }, sliderMark: { visibility: "hidden" }, sliderMarked: { marginTop: 25, marginBottom: 0 }, sliderMarkLabel: { top: -25 } }); }); interface Props { deviceId: number; interaction: Interaction; source: Component; sink: Component; grain?: pond.Grain; customGrain?: pond.GrainSettings } export default function BinConditioningInteraction(props: Props) { const { interaction, source, sink, grain, deviceId, customGrain } = props; const [sliderVals, setSliderVals] = useState>(new Map()); const [sliderMarks, setSliderMarks] = useState>(new Map()); //this is the emc value calculated from the interactions temp and humidity conditions const [baseEMC, setBaseEMC] = useState(); const [{ user, as }] = useGlobalState(); const classes = useStyles(); const interactionAPI = useInteractionsAPI(); const { openSnack } = useSnackbar(); useEffect(() => { let passedInteraction = interaction; let sliderVals: Map = new Map(); let sliderMarks: Map = new Map(); passedInteraction.conditions().forEach(condition => { let describer = describeMeasurement(condition.measurementType, source.type(), undefined, undefined, user); //NOTE: toDisplay will convert the temp value to fahrenheit sliderVals.set(condition.measurementType, describer.toDisplay(condition.value)); }); source.status.lastGoodMeasurement.forEach(measurement => { let m = pond.UnitMeasurementsForComponent.fromObject(measurement); if (m.values[0]) { let markVal = avg(m.values[0].values); //do this since this is how interactions handle the values so that the slider can use the toDisplay method of the describer for the marks if (m.type === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE) markVal = markVal * 10; if (m.type === quack.MeasurementType.MEASUREMENT_TYPE_PERCENT) markVal = markVal * 100; sliderMarks.set(m.type, markVal); } }); setSliderVals(sliderVals); setSliderMarks(sliderMarks); }, [interaction, source]); useEffect(() => { let temp = sliderVals.get(quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE); let hum = sliderVals.get(quack.MeasurementType.MEASUREMENT_TYPE_PERCENT); if ( grain !== undefined && grain !== pond.Grain.GRAIN_INVALID && temp && hum ) { if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) { //the emc calc needs the temp to be in celsius temp = fahrenheitToCelsius(temp); } let emc = ExtractMoisture(grain, temp, hum, customGrain) setBaseEMC(emc === hum ? undefined : emc); } }, [sliderVals, grain, user]); const updateInteraction = () => { interactionAPI .updateInteraction(deviceId, interaction.settings, as) .then(resp => { openSnack("Updated Interaction Conditions"); }) .catch(err => { openSnack("Failed to Update Interaction Conditions"); }); }; const customMark = (val: string, arrowColor: string) => { return ( {val} ); }; const conditionDisplay = () => { return ( {interaction.conditions().map((condition, i) => { let describer = describeMeasurement(condition.measurementType, source?.type(), source.subType(), undefined, user); let labelTail = describer.unit(); let marks: Mark[] = []; // if (condition.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE) { // if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) { // labelTail = "°F"; // } else { // labelTail = "°C"; // } // } if (condition.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_PERCENT) { labelTail = "%"; } let mark = sliderMarks.get(condition.measurementType); if (mark !== undefined) { marks.push({ label: customMark(describer.toDisplay(mark) + labelTail, describer.colour()), value: describer.toDisplay(mark) }); } return ( {interactionConditionText(source, condition, false, user)} { if ( condition.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE ) { if ( user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ) { return value.toFixed(1) + "°F"; } else { return value.toFixed(1) + "°C"; } } if ( condition.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_PERCENT ) { return value.toFixed(1) + "%"; } }} marks={marks} min={describer.min()} max={describer.max()} value={sliderVals.get(condition.measurementType) ?? describer.min()} onChange={(_, val) => { condition.value = Math.round(describer.toStored(val as number)); let sliders = cloneDeep(sliderVals); sliders.set(condition.measurementType, val as number); setSliderVals(sliders); }} /> ); })} ); }; const determineEMCRelation = () => { let relation = "Approximately:"; let tempRelation: quack.RelationalOperator | undefined = undefined; let humidRelation: quack.RelationalOperator | undefined = undefined; interaction.conditions().forEach(condition => { if (condition.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE) tempRelation = condition.comparison; if (condition.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_PERCENT) humidRelation = condition.comparison; }); if ( (tempRelation === quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN || tempRelation === quack.RelationalOperator.RELATIONAL_OPERATOR_EQUAL_TO) && (humidRelation === quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN || humidRelation === quack.RelationalOperator.RELATIONAL_OPERATOR_EQUAL_TO) ) { relation = "Less Than: "; } if ( (tempRelation === quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN || tempRelation === quack.RelationalOperator.RELATIONAL_OPERATOR_EQUAL_TO) && (humidRelation === quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN || humidRelation === quack.RelationalOperator.RELATIONAL_OPERATOR_EQUAL_TO) ) { relation = "Greater Than: "; } return relation; }; return ( {source.name()} UnitMeasurement.any(um, user)) )} /> {sink.name()} UnitMeasurement.any(um, user)) )} /> {interactionResultText(interaction, sink)} {baseEMC !== undefined ? ( }> EMC {determineEMCRelation()} {baseEMC.toFixed(1)}% {conditionDisplay()} ) : ( {conditionDisplay()} )} ); }