Merge branch 'dev_environment' of gitlab.com:brandx/bxt-app into libracart

This commit is contained in:
Noor 2025-08-06 09:24:46 -06:00
commit 1596f14ecd
62 changed files with 404 additions and 131682 deletions

View file

@ -87,54 +87,48 @@ export default function BinCard(props: Props) {
//loop through the cables in the bin status to prep for display
bin.status.grainCables.forEach(cable => {
let c: GrainCable = new GrainCable();
//flip the cables so that for display node 1 is at the bottom
//flip the cables so that for display node 1 is at the bottom,
let cableTemps = cloneDeep(cable.celcius);
let cableHums = cloneDeep(cable.relativeHumidity);
let cableEMC = cloneDeep(cable.moisture);
c.temperatures = cableTemps.reverse();
c.humidities = cableHums.reverse();
c.grainMoistures = cableEMC.reverse();
c.topNode = cable.topNode;
c.excludedNodes = cable.excludedNodes;
newGrainCables.push(c);
//determine the averages for temp/RH/EMC for the bin using all of the cables
let temps = cloneDeep(cable.celcius);
let hums = cloneDeep(cable.relativeHumidity);
let moistures = cloneDeep(cable.moisture);
const spliceEnd = cable.topNode > 0 ? cable.topNode : temps.length;
let grainTemps = temps.splice(0, spliceEnd);
let grainHums = hums.splice(0, spliceEnd);
let grainEMCs = moistures.splice(0, spliceEnd);
allTemps.push(...grainTemps);
allHums.push(...grainHums);
allMoistures.push(...grainEMCs);
//filter out the excluded nodes and any nodes above the top node
let filteredNodes = c.filteredNodes(true)
allTemps.push(...filteredNodes.temps);
allHums.push(...filteredNodes.humids);
allMoistures.push(...filteredNodes.moistures);
//set the hottest and coldest nodes
if (coldestNode === undefined || Math.min(...grainTemps) < coldestNode.temp) {
if (coldestNode === undefined || Math.min(...filteredNodes.temps) < coldestNode.temp) {
let lowTempIndex =
grainTemps.indexOf(Math.min(...grainTemps)) === -1
filteredNodes.temps.indexOf(Math.min(...filteredNodes.temps)) === -1
? 0
: grainTemps.indexOf(Math.min(...grainTemps));
: filteredNodes.temps.indexOf(Math.min(...filteredNodes.temps));
coldestNode = {
temp: grainTemps[lowTempIndex],
humid: grainHums[lowTempIndex],
emc: grainEMCs[lowTempIndex]
temp: filteredNodes.temps[lowTempIndex],
humid: filteredNodes.humids[lowTempIndex],
emc: filteredNodes.moistures[lowTempIndex]
};
}
if (hottestNode === undefined || Math.max(...grainTemps) > hottestNode.temp) {
if (hottestNode === undefined || Math.max(...filteredNodes.temps) > hottestNode.temp) {
let highTempIndex =
grainTemps.indexOf(Math.max(...grainTemps)) === -1
filteredNodes.temps.indexOf(Math.max(...filteredNodes.temps)) === -1
? 0
: grainTemps.indexOf(Math.max(...grainTemps));
: filteredNodes.temps.indexOf(Math.max(...filteredNodes.temps));
hottestNode = {
temp: grainTemps[highTempIndex],
humid: grainHums[highTempIndex],
emc: grainEMCs[highTempIndex]
temp: filteredNodes.temps[highTempIndex],
humid: filteredNodes.humids[highTempIndex],
emc: filteredNodes.moistures[highTempIndex]
};
}

View file

@ -86,6 +86,9 @@ const useStyles = makeStyles((theme: Theme) => {
cableNode: {
fill: "#fff"
},
excludedNode: {
fill: "grey"
},
hotNode: {
fill: "#fff",
animation: "$hotNode 1.0s infinite"
@ -168,7 +171,8 @@ interface NodeData { //this could be either a box or a circle depending
height: string | number
borderRad: string | number
nodeNumber: number
nodeTemp: number
nodeTemp: number,
excluded: boolean,
}
interface CircleData {
@ -609,19 +613,20 @@ export default function BinSVGV2(props: Props) {
//determine how high to draw the node on the cable
const nodeY = nodeSpacingY * (index + 1) + minNodeY;
//if we are using the auto top nodes only show the heatmap for nodes at or below the top node
if (cable.topNode > 0) {
if (nodeNumber <= cable.topNode) {
// nodeHeatMap.push(
// <ellipse
// key={index}
// cx={cablePos}
// cy={nodeY}
// rx="120"
// ry="60"
// fill={getGrainGradient(temp)}
// />
// );
//if we are using the auto top nodes only show the heatmap for nodes at or below the top node and it is not an ecluded node
if (!cable.excludedNodes.includes(nodeNumber - 1)){
if (cable.topNode > 0) {
if (nodeNumber <= cable.topNode) {
nodeHeatMapData.push({
key: index,
xCenter: cablePos,
yCenter: nodeY,
xRadius: "120",
yRadius: "60",
fillColour: getGrainGradient(temp)
})
}
} else if (nodeY > filledToY) {
nodeHeatMapData.push({
key: index,
xCenter: cablePos,
@ -631,26 +636,6 @@ export default function BinSVGV2(props: Props) {
fillColour: getGrainGradient(temp)
})
}
} else if (nodeY > filledToY) {
//otherwise use the fill level of the bin
// nodeHeatMap.push(
// <ellipse
// key={index}
// cx={cablePos}
// cy={nodeY}
// rx="120"
// ry="60"
// fill={getGrainGradient(temp)}
// />
// );
nodeHeatMapData.push({
key: index,
xCenter: cablePos,
yCenter: nodeY,
xRadius: "120",
yRadius: "60",
fillColour: getGrainGradient(temp)
})
}
const displayWidth = 90;
const displayHeight = 45;
@ -682,20 +667,9 @@ export default function BinSVGV2(props: Props) {
width: displayWidth,
borderRad: showTempHum ? cornerRad : "16",
nodeNumber: nodeNumber,
nodeTemp: temp
nodeTemp: temp,
excluded: cable.excludedNodes.includes(nodeNumber - 1)
})
// temps.push(
// <text
// key={"node" + index + "temp"}
// x={cablePos}
// y={nodeY + 10}
// stroke="blue"
// filter="drop-shadow( 4px 4px 10px rgba(0, 0, 0, .7))"
// className={classes.tempHum}>
// {displayTemp.toFixed(1)}°
// </text>
// );
tempData.push({
key: "node" + index + "temp",
x: cablePos,
@ -704,16 +678,6 @@ export default function BinSVGV2(props: Props) {
value: displayTemp.toFixed(1) +"°",
filter: "drop-shadow( 4px 4px 10px rgba(0, 0, 0, .7))"
})
// hums.push(
// <text
// key={"node" + index + "hum"}
// x={cablePos}
// y={nodeY + 10}
// stroke="green"
// className={classes.tempHum}>
// {ExtractMoisture(props.grainType, temp, cable.humidities[index] ?? 0).toFixed(1)}%
// </text>
// );
humData.push({
key: "node" + index + "hum",
x: cablePos,
@ -722,20 +686,6 @@ export default function BinSVGV2(props: Props) {
value: ExtractMoisture(props.grainType, temp, cable.humidities[index] ?? 0).toFixed(1)+"%",
})
!showTempHum &&
// nodeClickers.push(
// <circle
// key={"node" + index}
// onClick={() => {
// if (cable.key() !== "" && cableNodeClicked) {
// cableNodeClicked(cable, nodeNumber);
// }
// }}
// cx={cablePos}
// cy={nodeY}
// className={classes.clickableArea}
// r="50"
// />
// );
nodeClickData.push({
key: "node"+index,
centerX: cablePos,
@ -803,13 +753,13 @@ export default function BinSVGV2(props: Props) {
width={e.width}
height={e.height}
rx={e.borderRad}
className={classes.cableNode}/>
className={e.excluded ? classes.excludedNode : classes.cableNode}/>
)
} else {
return (
<g key={e.key}>
{e.nodeNumber === topNode && topNodeHat(cablePos, e.y)}
<circle cx={cablePos} cy={e.y} className={nodeClass(e.nodeTemp)} r="16"></circle>
{e.nodeNumber === topNode && !e.excluded && topNodeHat(cablePos, e.y)}
<circle cx={cablePos} cy={e.y} className={e.excluded ? classes.excludedNode : nodeClass(e.nodeTemp)} r="16"></circle>
</g>
)
}

View file

@ -181,13 +181,13 @@ export default function BinStorageConditions(props: Props) {
} else {
//with the way the measurements are stored the node closest to the device (highest on the cable) is the first position of the array
//so we will need to flip the array so that node 1 is the beginning of the array
let temps = cloneDeep(cable.temperatures).reverse();
let emcs = cloneDeep(cable.grainMoistures).reverse();
//let temps = cloneDeep(cable.temperatures).reverse();
//let emcs = cloneDeep(cable.grainMoistures).reverse();
let filteredNodes = cable.filteredNodes(true)
//only use the nodes up to the top node
let nodeTemps: number[] = [];
temps.forEach((temp, i) => {
if (i < cable.topNode) {
filteredNodes.temps.forEach((temp, i) => {
// if (i < cable.topNode) { //no longer need to check if it is below the top node as the filteredNodes function does it already and only returns active nodes
nodeTemps.push(temp);
tempCounts.total++;
if (temp > bin.settings.highTemp) {
@ -197,14 +197,14 @@ export default function BinStorageConditions(props: Props) {
} else {
tempCounts.onTarget++;
}
}
// }
});
let nodeEMCs: number[] = [];
emcs.forEach((emc, i) => {
filteredNodes.moistures.forEach((emc, i) => {
if (bin.settings.inventory?.targetMoisture) {
if (i < cable.topNode) {
// if (i < cable.topNode) {
nodeEMCs.push(emc);
emcCounts.total++;
if (
@ -222,7 +222,7 @@ export default function BinStorageConditions(props: Props) {
} else {
emcCounts.onTarget++;
}
}
// }
}
});
cableTempAvgs.push(avg(nodeTemps));
@ -260,7 +260,7 @@ export default function BinStorageConditions(props: Props) {
};
cables.forEach(cable => {
let emcs = cloneDeep(cable.grainMoistures).reverse();
let emcs = cable.filteredNodes(true).moistures
//let nodeEMCs: number[] = [];
emcs.forEach((emc, i) => {
@ -332,7 +332,7 @@ export default function BinStorageConditions(props: Props) {
total: 0
};
cables.forEach(cable => {
let temps = cloneDeep(cable.temperatures).reverse();
let temps = cable.filteredNodes(true).temps
let nodeTemps: number[] = [];
temps.forEach((temp, i) => {
if (i < cable.topNode) {

View file

@ -382,20 +382,25 @@ export default function BinVisualizer(props: Props) {
//only use the values below the top node
//because splice mutates the original array make a clone in the cables so the svg still has all of them for display
//also reverse it so that the node 1 (end of the cable) is in the first position
let tempClone = cloneDeep(cable.temperatures).reverse();
let humClone = cloneDeep(cable.humidities).reverse();
let emcClone = cloneDeep(cable.grainMoistures).reverse();
let filteredNodes = cable.filteredNodes(true)
temps.push(...filteredNodes.temps)
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();
//add the cable data to the proper arrays
if (cable.topNode > 0) {
temps.push(...tempClone.splice(0, cable.topNode));
humids.push(...humClone.splice(0, cable.topNode));
emcs.push(...emcClone.splice(0, cable.topNode));
} else {
//if the cable has no fill set (top node) then use all of the nodes
temps = tempClone;
humids = humClone;
emcs = emcClone;
}
// if (cable.topNode > 0) {
// temps.push(...tempClone.splice(0, cable.topNode));
// humids.push(...humClone.splice(0, cable.topNode));
// emcs.push(...emcClone.splice(0, cable.topNode));
// } else {
// //if the cable has no fill set (top node) then use all of the nodes
// temps = tempClone;
// humids = humClone;
// emcs = emcClone;
// }
//add the trend data to the proper arrays if the top node is set
let cableTrendData = binTrend.cableTrend[cable.key()];
tempTrends.push(cableTrendData.grainCelciusTrend);
@ -432,6 +437,7 @@ export default function BinVisualizer(props: Props) {
};
}
});
//set the average conditions
avgConditions = {
tempC: average(temps),

View file

@ -91,6 +91,7 @@ export default function GrainNodeInteractions(props: Props) {
const humDescriber = describeMeasurement(quack.MeasurementType.MEASUREMENT_TYPE_PERCENT);
const moistureDescriber = describeMeasurement(quack.MeasurementType.MEASUREMENT_TYPE_GRAIN_EMC);
const [topNode, setTopNode] = useState(false);
const [excluded, setExcluded] = useState(false);
const componentAPI = useComponentAPI();
const interactionAPI = useInteractionsAPI();
const binAPI = useBinAPI();
@ -131,6 +132,13 @@ export default function GrainNodeInteractions(props: Props) {
} else {
setTopNode(false);
}
//determine if the node is excluded
if (cable.excludedNodes.includes(displayNode - 1)){
setExcluded(true)
}else{
setExcluded(false)
}
}, [cable, displayNode]);
const goToComponent = () => {
@ -167,6 +175,7 @@ export default function GrainNodeInteractions(props: Props) {
.then(resp => {})
.catch(err => {});
});
updateComponentCallback(cable.key())
})
.catch(err => {
openSnack("Failed to update component");
@ -204,6 +213,15 @@ export default function GrainNodeInteractions(props: Props) {
setTopNode(checked);
};
const updateNodeExclusion = (checked: boolean) => {
if (checked) {
cable.settings.excludedNodes.push(selectedNode-1)
} else {
cable.settings.excludedNodes.splice(cable.settings.excludedNodes.indexOf(selectedNode - 1), 1)
}
setExcluded(checked)
}
const displayTemp = () => {
let tempFinal = nodeTemp ?? 0;
if (user.settings.temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
@ -312,15 +330,38 @@ export default function GrainNodeInteractions(props: Props) {
);
};
const fillNodeSet = () => {
const nodeControl = () => {
return (
<Box style={{ marginTop: 10 }}>
<Typography style={{ fontSize: 20, fontWeight: 650 }}>Top Node Control</Typography>
<Typography style={{ fontSize: 20, fontWeight: 650 }}>Node Control</Typography>
<FormControlLabel
style={{ marginTop: 10 }}
control={
<Checkbox
checked={excluded}
onChange={e => {
updateNodeExclusion(e.target.checked);
}}
name="excludedNode"
/>
}
label={
<React.Fragment>
<Typography style={{ fontSize: 15, fontWeight: 650 }}>
Exclude Node
</Typography>
<Typography style={{ fontSize: 15 }}>
If checked this will set the node to be disabled and will not be used for any calculations done for the bin
</Typography>
</React.Fragment>
}
/>
<FormControlLabel
style={{ marginTop: 10 }}
control={
<Checkbox
checked={topNode}
disabled={excluded}
onChange={e => {
updateTopNode(e.target.checked);
}}
@ -418,7 +459,7 @@ export default function GrainNodeInteractions(props: Props) {
</DialogTitle>
<DialogContent>
{latestReading()}
{fillNodeSet()}
{nodeControl()}
{interactionDisplay()}
</DialogContent>
<DialogActions>

View file

@ -151,7 +151,7 @@ export default function BinComponentGraph(props: Props) {
themeType
);
let nodes = 1;
let lastMeasurement = cloneDeep(component.status.measurement);
let lastMeasurement = cloneDeep(component.status.lastGoodMeasurement);
if (
lastMeasurement[0] &&
lastMeasurement[0].values[0] &&
@ -184,7 +184,7 @@ export default function BinComponentGraph(props: Props) {
<UnitMeasurementSummary
component={component}
reading={UnitMeasurement.convertLastMeasurement(
lastMeasurement.map(m => UnitMeasurement.create(m, user))
component.status.lastGoodMeasurement.map(m => UnitMeasurement.create(m, user))
)}
/>
}

View file

@ -143,6 +143,7 @@ export default function BinGraphs(props: Props) {
startDate.toISOString(),
endDate.toISOString(),
showErrors,
showErrors,
as
)
.then(resp => {

File diff suppressed because one or more lines are too long

View file

@ -285,7 +285,7 @@ export default function ComponentCard(props: Props) {
// ) : (
<UnitMeasurementSummary
component={component}
excludedNodes={deviceComponentPreferences?.excludedNodes}
excludedNodes={component.settings.excludedNodes}
reading={UnitMeasurement.convertLastMeasurement(measurements)}
//dense
/>

View file

@ -11,30 +11,31 @@ import {
FormControl,
FormControlLabel,
FormGroup,
FormLabel,
//FormLabel,
Grid2 as Grid,
Theme,
Tooltip,
Typography
} from "@mui/material";
import { lightGreen } from "@mui/material/colors";
import { ExpandMore } from "@mui/icons-material";
import { ExpandMore, Warning } from "@mui/icons-material";
import MeasurementsChart from "charts/MeasurementsChart";
//import { GraphOrientation } from "common/Graph";
import RangeInput, { Range } from "common/RangeInput";
//import RangeInput, { Range } from "common/RangeInput";
import { GetDefaultDateRange } from "common/time/DateRange";
import DateSelect from "common/time/DateSelect";
import MeasurementSummary from "component/MeasurementSummary";
//import DateSelect from "common/time/DateSelect";
//import MeasurementSummary from "component/MeasurementSummary";
import { grainName } from "grain";
import { useMobile, usePrevious } from "hooks";
import { useMobile } from "hooks";
import { cloneDeep } from "lodash";
import { Component, Interaction } from "models";
import { UnitMeasurement } from "models/UnitMeasurement";
import moment from "moment";
import { deviceComponentID } from "pbHelpers/Component";
//import { deviceComponentID } from "pbHelpers/Component";
import {
extension,
//getComponentVisual,
GetNumNodes,
//GetNumNodes,
GetNumNodesFromUnitMeasurement,
GraphFilters
} from "pbHelpers/ComponentType";
@ -43,9 +44,9 @@ import { findInteractionsAsSource } from "pbHelpers/Interaction";
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/quack";
import { useGlobalState } from "providers";
import React, { useEffect, useState } from "react";
import { or } from "utils/types";
//import { useGlobalState } from "providers";
import React, { useState } from "react";
//import { or } from "utils/types";
import UnitMeasurementSummary from "./UnitMeasurementSummary";
import { makeStyles } from "@mui/styles";
@ -82,34 +83,34 @@ interface Props {
component: Component;
interactions: Interaction[];
sampling: boolean;
samples?: pond.Measurement[]; //deprecated: old measurement structure
//samples?: pond.Measurement[]; //deprecated: old measurement structure
unitMeasurements?: UnitMeasurement[];
sampleLimit?: number;
updateDate?: (startDate: any, endDate: any, live?: boolean) => void;
allowLive?: boolean;
recentMeasurement?: pond.Measurement;
//recentMeasurement?: pond.Measurement;
recentUnitMeasurement?: UnitMeasurement[];
deviceComponentPreferences?: pond.DeviceComponentPreferences;
}
function setComponentGraphRanges(device: number | string, component: string, ranges: Range[]) {
const key: string = "graphRanges-" + deviceComponentID(device, component);
localStorage.setItem(key, JSON.stringify(or(ranges, [])));
}
// function setComponentGraphRanges(device: number | string, component: string, ranges: Range[]) {
// const key: string = "graphRanges-" + deviceComponentID(device, component);
// localStorage.setItem(key, JSON.stringify(or(ranges, [])));
// }
function getComponentGraphRanges(device: number | string, component: string): Range[] {
const key: string = "graphRanges-" + deviceComponentID(device, component);
return JSON.parse(or(localStorage.getItem(key), "[]"));
}
// function getComponentGraphRanges(device: number | string, component: string): Range[] {
// const key: string = "graphRanges-" + deviceComponentID(device, component);
// return JSON.parse(or(localStorage.getItem(key), "[]"));
// }
export default function ComponentChart(props: Props) {
const { component, deviceComponentPreferences } = props;
//const { component, deviceComponentPreferences } = props;
const classes = useStyles();
const isMobile = useMobile();
const { deviceKey, componentKey } = props;
const prevDevice = usePrevious(props.deviceKey);
const prevComponentKey = usePrevious(props.componentKey);
const prevComponent = usePrevious(props.component);
// const { deviceKey, componentKey } = props;
// const prevDevice = usePrevious(props.deviceKey);
// const prevComponentKey = usePrevious(props.componentKey);
// const prevComponent = usePrevious(props.component);
const defaultDateRange = GetDefaultDateRange();
const [startDate, setStartDate] = useState(defaultDateRange.start);
const [endDate, setEndDate] = useState(defaultDateRange.end);
@ -126,46 +127,47 @@ export default function ComponentChart(props: Props) {
const [expandData, setExpandData] = useState(false);
const [showOriginal, setShowOriginal] = useState(true);
const [showAveraged, setShowAveraged] = useState(false);
const [showAllNodes, setShowAllNodes] = useState(false);
useEffect(() => {
if (prevComponent !== props.component) {
let updatedFilters = cloneDeep(graphFilters);
let filledTo = props.component.settings.grainFilledTo;
updatedFilters.grainFilledTo = filledTo > 0 ? filledTo : undefined;
updatedFilters.grainType = props.component.settings.grainType;
setGraphFilters(updatedFilters);
}
}, [prevComponent, graphFilters, props.component]);
// useEffect(() => {
// if (prevComponent !== props.component) {
// let updatedFilters = cloneDeep(graphFilters);
// let filledTo = props.component.settings.grainFilledTo;
// updatedFilters.grainFilledTo = filledTo > 0 ? filledTo : undefined;
// updatedFilters.grainType = props.component.settings.grainType;
// setGraphFilters(updatedFilters);
// }
// }, [prevComponent, graphFilters, props.component]);
useEffect(() => {
if (prevDevice !== deviceKey || prevComponentKey !== componentKey) {
const ranges = getComponentGraphRanges(deviceKey, componentKey);
let updatedFilters = cloneDeep(graphFilters);
updatedFilters.ranges = ranges;
setGraphFilters(updatedFilters);
}
}, [deviceKey, prevDevice, prevComponentKey, componentKey, graphFilters]);
// useEffect(() => {
// if (prevDevice !== deviceKey || prevComponentKey !== componentKey) {
// const ranges = getComponentGraphRanges(deviceKey, componentKey);
// let updatedFilters = cloneDeep(graphFilters);
// updatedFilters.ranges = ranges;
// setGraphFilters(updatedFilters);
// }
// }, [deviceKey, prevDevice, prevComponentKey, componentKey, graphFilters]);
//use the excluded nodes to set the default for the graph filters
useEffect(() => {
let excludedNodes = deviceComponentPreferences?.excludedNodes;
if (excludedNodes === undefined || excludedNodes.length === 0) return;
let updatedFilters = cloneDeep(graphFilters);
if (excludedNodes && component.lastMeasurement[0]) {
let includedNodes: string[] = [];
let numNodes = GetNumNodesFromUnitMeasurement(
UnitMeasurement.any(component.lastMeasurement[0])
);
// useEffect(() => {
// let excludedNodes = component.settings.excludedNodes;
// if (excludedNodes === undefined || excludedNodes.length === 0) return;
// let updatedFilters = cloneDeep(graphFilters);
// if (excludedNodes && component.lastMeasurement[0]) {
// let includedNodes: string[] = [];
// let numNodes = GetNumNodesFromUnitMeasurement(
// UnitMeasurement.any(component.lastMeasurement[0])
// );
for (let i = 0; i < numNodes; i++) {
if (!excludedNodes.includes(i)) {
includedNodes.push(i.toString());
}
}
updatedFilters.selectedNodes = includedNodes;
}
setGraphFilters(updatedFilters);
}, [deviceComponentPreferences, component]); //eslint-disable-line react-hooks/exhaustive-deps
// for (let i = 0; i < numNodes; i++) {
// if (!excludedNodes.includes(i)) {
// includedNodes.push(i.toString());
// }
// }
// updatedFilters.selectedNodes = includedNodes;
// }
// setGraphFilters(updatedFilters);
// }, [component]); //eslint-disable-line react-hooks/exhaustive-deps
const updateDateRange = (newStartDate: any, newEndDate: any, live: boolean) => {
setStartDate(newStartDate);
@ -176,14 +178,14 @@ export default function ComponentChart(props: Props) {
}
};
const changeRange = (index: number, range: Range) => {
let updatedFilters = cloneDeep(graphFilters);
let ranges = updatedFilters.ranges ? updatedFilters.ranges : [];
ranges[index] = range;
updatedFilters.ranges = ranges;
setComponentGraphRanges(deviceKey, componentKey, ranges);
setGraphFilters(updatedFilters);
};
// const changeRange = (index: number, range: Range) => {
// let updatedFilters = cloneDeep(graphFilters);
// let ranges = updatedFilters.ranges ? updatedFilters.ranges : [];
// ranges[index] = range;
// updatedFilters.ranges = ranges;
// setComponentGraphRanges(deviceKey, componentKey, ranges);
// setGraphFilters(updatedFilters);
// };
const handleGrainCableControlsChange = (name: string) => (event: any) => {
let updatedFilters = cloneDeep(graphFilters);
@ -211,23 +213,22 @@ export default function ComponentChart(props: Props) {
};
const cableControls = () => {
const { component, samples, deviceComponentPreferences } = props;
const excludedNodes = deviceComponentPreferences?.excludedNodes ?? [];
const { recentUnitMeasurement } = props;
//const excludedNodes = component.settings.excludedNodes ?? [];
const selectedNodes = graphFilters.selectedNodes ? graphFilters.selectedNodes : ["all"];
const lastMeasurement = component.status.lastMeasurement;
let numNodes = 0;
if (samples) {
numNodes = GetNumNodes(
component.settings.type,
lastMeasurement && lastMeasurement.measurement
);
} else {
if (component.lastMeasurement && component.lastMeasurement[0]) {
// if (samples) {
// numNodes = GetNumNodes(
// component.settings.type,
// recentUnitMeasurement
// );
// } else {
if (recentUnitMeasurement && recentUnitMeasurement.length > 0) {
numNodes = GetNumNodesFromUnitMeasurement(
UnitMeasurement.any(component.lastMeasurement[0])
recentUnitMeasurement[0]
);
}
}
//}
if (numNodes <= 1) {
return null;
@ -301,17 +302,17 @@ export default function ComponentChart(props: Props) {
}
//TODO-DRAGER: this mey not be necessary to do anymore with them being split up
if (component.type() === quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE) {
let describer = describeMeasurement(
component.lastMeasurement[0].type,
component.type(),
component.subType()
);
let details = describer.nodeDetails();
if (details) {
nodeLabel = details.labels[i - 1];
}
}
// if (component.type() === quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE) {
// let describer = describeMeasurement(
// component.lastMeasurement[0].type,
// component.type(),
// component.subType()
// );
// let details = describer.nodeDetails();
// if (details) {
// nodeLabel = details.labels[i - 1];
// }
// }
grainCableControls.push(
<Grid size={{ xs: 6 }} key={"node-" + (i - 1).toString()}>
@ -322,7 +323,7 @@ export default function ComponentChart(props: Props) {
checked={selectedNodes.includes((i - 1).toString()) ? true : false}
onChange={handleGrainCableControlsChange((i - 1).toString())}
value={(i - 1).toString()}
disabled={excludedNodes.includes(i - 1)}
//disabled={excludedNodes.includes(i - 1)}
/>
}
label={<Typography variant="body2">{nodeLabel}</Typography>}
@ -695,19 +696,27 @@ export default function ComponentChart(props: Props) {
}
};
const displayExcludedNodes = () => {
const {component} = props
let nodes: number[] = []
component.settings.excludedNodes.forEach(node => {
nodes.push(node+1)
})
return nodes
}
const content = () => {
const {
component,
sampling,
samples,
recentMeasurement,
recentUnitMeasurement,
deviceComponentPreferences
recentUnitMeasurement
} = props;
const ext = extension(component.settings.type, component.settings.subtype);
const ranges = graphFilters.ranges ? graphFilters.ranges : [];
//const ext = extension(component.settings.type, component.settings.subtype);
//const ranges = graphFilters.ranges ? graphFilters.ranges : [];
let convertedLastMeasurement;
//console.log(recentUnitMeasurement)
if (recentUnitMeasurement && recentUnitMeasurement.length > 0) {
let measurements = recentUnitMeasurement;
convertedLastMeasurement = UnitMeasurement.convertLastMeasurement(measurements);
@ -716,18 +725,17 @@ export default function ComponentChart(props: Props) {
<Grid container spacing={2} direction={isMobile ? "column" : "row-reverse"}>
{isMobile && (
<Grid className={classes.borderedContainer}>
{samples ? (
{/* {samples ? (
<MeasurementSummary component={component} reading={recentMeasurement} />
) : (
) : ( */}
<Card raised className={classes.container}>
<Typography style={{ fontWeight: 650 }}>Latest Measurements:</Typography>
<UnitMeasurementSummary
component={component}
reading={convertedLastMeasurement}
excludedNodes={deviceComponentPreferences?.excludedNodes}
/>
</Card>
)}
{/* )} */}
</Grid>
)}
<Grid
@ -749,14 +757,29 @@ export default function ComponentChart(props: Props) {
<React.Fragment>
{/* {newStructure && ( */}
<Grid size={{ xs: 12 }}>
<Typography style={{ fontWeight: 650, fontSize: 20 }}>Status</Typography>
<Box display="flex" justifyContent="space-between">
<Box>
<Typography style={{ fontWeight: 650, fontSize: 20 }}>Status</Typography>
</Box>
{component.settings.excludedNodes.length > 0 &&
<Box display="flex" alignContent="center" margin="auto" marginX={0}>
<Typography textAlign="center" marginX={1}>
Excluded Nodes
</Typography>
<Tooltip
title={"You have excluded nodes (" + displayExcludedNodes().toLocaleString() + ") and they will not show up on this page, you can reveal them temporarily by selecting show errors"}>
<Warning color="warning"/>
</Tooltip>
</Box>
}
</Box>
<Divider variant="middle" className={classes.divider} />
</Grid>
{/* )} */}
<Grid size={{ xs: 12 }} className={classes.borderedContainer}>
{samples ? (
{/* {samples ? (
<MeasurementSummary component={component} reading={recentMeasurement} />
) : (
) : ( */}
<Card raised style={{ padding: 25, marginBottom: 20 }}>
<Typography style={{ fontWeight: 650 }}>Latest Measurements:</Typography>
<UnitMeasurementSummary
@ -764,10 +787,9 @@ export default function ComponentChart(props: Props) {
reading={convertedLastMeasurement}
largeText
boldMeasurements
excludedNodes={deviceComponentPreferences?.excludedNodes}
/>
</Card>
)}
{/* )} */}
</Grid>
</React.Fragment>
)}
@ -792,7 +814,7 @@ export default function ComponentChart(props: Props) {
</Grid>
)}
{!sampling &&
{/* {!sampling &&
ext.measurements.map((m, i) => {
const range = ranges[i] ? ranges[i] : ({} as Range);
if (m.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN) {
@ -810,7 +832,7 @@ export default function ComponentChart(props: Props) {
);
}
return null;
})}
})} */}
</Grid>
</Grid>
);

View file

@ -97,6 +97,7 @@ export default function ComponentDiagnostics(props: Props) {
undefined,
undefined,
undefined,
undefined,
as
)
.then(resp => {

View file

@ -181,11 +181,11 @@ export default function ComponentSettings(props: Props) {
setTabVal(newValue);
};
useEffect(() => {
if (deviceComponentPrefs) {
setExcludedNodes(deviceComponentPrefs.excludedNodes);
}
}, [deviceComponentPrefs]);
// useEffect(() => {
// if (deviceComponentPrefs) {
// setExcludedNodes(deviceComponentPrefs.excludedNodes);
// }
// }, [deviceComponentPrefs]);
const init = useCallback(() => {
let component = props.component;
@ -208,6 +208,7 @@ export default function ComponentSettings(props: Props) {
)
);
setFormComponent(initComponent);
setExcludedNodes(initComponent.settings.excludedNodes)
}, [props.component, componentTypeOptions]);
useEffect(() => {
@ -324,20 +325,21 @@ export default function ComponentSettings(props: Props) {
const updateComponent = () => {
const component = formComponent;
component.settings.excludedNodes = excludedNodes
componentAPI
.update(device.id(), component.settings, getContextKeys(), getContextTypes(), as)
.then((_response: any) => {
success(component.name() + " was successfully updated!");
let updatedPrefs = pond.DeviceComponentPreferences.create();
updatedPrefs.excludedNodes = excludedNodes;
deviceAPI
.updateComponentPreferences(device.id(), component.key(), updatedPrefs, undefined, undefined, as)
.then(_resp => {
console.log("Preferences updated");
})
.catch(_err => {
console.log("Preferences failed to update");
});
// let updatedPrefs = pond.DeviceComponentPreferences.create();
// updatedPrefs.excludedNodes = excludedNodes;
// deviceAPI
// .updateComponentPreferences(device.id(), component.key(), updatedPrefs, undefined, undefined, as)
// .then(_resp => {
// console.log("Preferences updated");
// })
// .catch(_err => {
// console.log("Preferences failed to update");
// });
refresh();
})
.catch((_err: any) => {
@ -929,11 +931,11 @@ export default function ComponentSettings(props: Props) {
let nodes;
if (
prevComponent &&
prevComponent.lastMeasurement[0] &&
prevComponent.lastMeasurement[0].values[0] &&
prevComponent.lastMeasurement[0].values[0].values
prevComponent.status.measurement[0] &&
prevComponent.status.measurement[0].values[0] &&
prevComponent.status.measurement[0].values[0].values
) {
nodes = prevComponent.lastMeasurement[0].values[0].values;
nodes = prevComponent.status.measurement[0].values[0].values;
}
return (
@ -1018,24 +1020,6 @@ export default function ComponentSettings(props: Props) {
}}>
Clear Excluded Nodes
</Button>
{/* button for testing the pref update */}
{/* {prevComponent && (
<Button
onClick={() => {
let pref = pond.DeviceComponentPreferences.create();
pref.excludedNodes = excludedNodes;
deviceAPI
.updateComponentPreferences(device.id(), prevComponent.key(), pref)
.then(resp => {
console.log("no errors");
})
.catch(err => {
console.log("errors");
});
}}>
Update Prefs
</Button>
)} */}
</Box>
);
};
@ -1061,7 +1045,7 @@ export default function ComponentSettings(props: Props) {
onChange={handleChange}>
<Tab label="General" />
<Tab label="Overlays" />
<Tab label="Preferences" disabled={!prevComponent} />
<Tab label="Nodes" disabled={!prevComponent} />
</Tabs>
)}
<TabPanelMine value={tabVal} index={0}>

View file

@ -109,7 +109,8 @@ class ExportDataSettings extends React.Component<Props, State> {
undefined,
[device.id().toString()],
["device"],
undefined,
undefined,
undefined,
as
)
.then(resp => {

View file

@ -21,7 +21,6 @@ interface Props {
onlyRecent?: boolean;
largeText?: boolean;
boldMeasurements?: boolean;
excludedNodes?: number[];
}
const useStyles = makeStyles((theme: Theme) => {
@ -61,8 +60,7 @@ export default function UnitMeasurementSummary(props: Props) {
dense,
onlyRecent,
largeText,
boldMeasurements,
excludedNodes
boldMeasurements
} = props;
const [summaries, setSummaries] = useState<Summary[]>([]);
const [timestamp, setTimestamp] = useState("");
@ -80,12 +78,11 @@ export default function UnitMeasurementSummary(props: Props) {
setTimestamp(reading.timestamp);
setSummaries(
extension(component.type(), component.subType()).unitMeasurementSummary(
reading,
excludedNodes
reading
)
);
}
}, [component, reading, excludedNodes]); // eslint-disable-line react-hooks/exhaustive-deps
}, [component, reading]); // eslint-disable-line react-hooks/exhaustive-deps
const noSummary = () => {
return (

View file

@ -119,7 +119,6 @@ export default function UpgradeDevice(props: Props) {
const percent = () => {
let progress = Math.round((upgrade.status.offset / upgrade.status.size) * 100)
console.log(progress)
return progress;
};

View file

@ -10,10 +10,12 @@ export class GrainCable {
public settings: pond.ComponentSettings = pond.ComponentSettings.create();
public status: pond.ComponentStatus = pond.ComponentStatus.create();
public lastReading: string = "";
//bear in mind these three arrays are reversed due to the bin svg needing the first node on the bottom of the image and the svg being drawn from the top
public temperatures: number[] = [];
public humidities: number[] = [];
public grainMoistures: number[] = [];
public topNode: number = 0;
public excludedNodes: number[] = [];
public static create(comp: Component): GrainCable {
let my = new GrainCable();
@ -58,6 +60,7 @@ export class GrainCable {
my.grainMoistures = emc;
my.lastReading = lastReading;
my.topNode = comp.settings.grainFilledTo;
my.excludedNodes = comp.settings.excludedNodes;
return my;
}
@ -239,4 +242,41 @@ export class GrainCable {
component.lastMeasurement = lastMeasurements;
return component;
}
/**
* Filters out the excluded nodes and anything above the top node of the cable, note that the nodes are reversed during creation if a grain cable ie: node 1 is the end of the array
*
* @param unReversed will tell the function to reverse the array back to its original state
* @returns array of active node values
*/
public filteredNodes(unReversed?: boolean): {temps: number[], humids: number[], moistures: number[]} {
//make clones of the node values and reverse them back to their original state for index purposes
let temps: number [] = cloneDeep(this.temperatures).reverse()
let humids: number [] = cloneDeep(this.humidities).reverse()
let moistures: number[] = cloneDeep(this.grainMoistures).reverse()
//filter out the excluded nodes
temps = this.filter(temps)
humids = this.filter(humids)
moistures = this.filter(moistures)
if(!unReversed){
temps.reverse()
humids.reverse()
moistures.reverse()
}
return {temps, humids, moistures}
}
private filter(values: number[]): number[] {
let filtered: number[] = []
values.forEach((val, index) => {
//if the node is not excluded AND is either under the top node OR top node is not set
if(!this.excludedNodes.includes(index) && (index <= this.topNode || this.topNode === 0)){
filtered.push(val)
}
})
return filtered
}
}

View file

@ -38,7 +38,7 @@ const Transactions = lazy(() => import("pages/Transactions"));
const BinCableEstimator = lazy(() => import("pages/BinCableEstimator"));
const APIDocs = lazy(() => import("pages/APIDocs"));
const Fields = lazy(()=> import("pages/Fields"));
const Marketplace = lazy(() => import("userFeatures/UserFeatures"))
const Marketplace = lazy(() => import("pages/Marketplace"))
const Logs = lazy(() => import("pages/Logs"))
const Firmware = lazy(() => import("pages/Firmware"));
const Nfc = lazy(() => import("pages/Nfc"));

View file

@ -437,7 +437,7 @@ export default function SideNavigator(props: Props) {
</ListItemButton>
</Tooltip>
}
{(isAg || isStreamline) &&
{(isAg || isStreamline || user.hasFeature("admin")) &&
<Tooltip title="Marketplace" placement="right">
<ListItemButton
id="tour-marketplace"

View file

@ -168,7 +168,8 @@ export default function DeviceComponent() {
getContextKeys(),
getContextTypes(),
showErrors,
as
showErrors,
as,
)
.then(resp => {
if (resp.data.measurements) {
@ -247,8 +248,8 @@ export default function DeviceComponent() {
if (rComponent?.status.lastMeasurement) {
setRM(rComponent.status.lastMeasurement);
}
if (rComponent?.lastMeasurement) {
let measurements = rComponent.lastMeasurement.map(um =>
if (rComponent?.status.measurement) {
let measurements = rComponent.status.measurement.map(um =>
UnitMeasurement.any(um, user)
);
setRecentUnitMeasurement(measurements);
@ -431,6 +432,7 @@ export default function DeviceComponent() {
getContextKeys(),
getContextTypes(),
showErrors,
showErrors,
as
)
.then(response => {
@ -487,7 +489,6 @@ export default function DeviceComponent() {
component={component}
reading={row}
tableCell={true}
excludedNodes={deviceComponentPrefs?.excludedNodes}
/>
)
}
@ -528,7 +529,7 @@ export default function DeviceComponent() {
// component={component}
// reading={row}
// tableCell={true}
// excludedNodes={deviceComponentPrefs?.excludedNodes}
// excludedNodes={component.settings.excludedNodes}
// />
// )
// }
@ -628,6 +629,7 @@ export default function DeviceComponent() {
getContextKeys(),
getContextTypes(),
showErrors,
showErrors,
as)
.then(resp => {
let newRows = UnitMeasurement.convertMeasurements(

View file

@ -17,7 +17,8 @@ export const I2C: AddressTypeExtension = {
[quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE, 0x4f],
[quack.ComponentType.COMPONENT_TYPE_SEN5X, 0x68],
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, 0x6b],
[quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE, 0x70]
[quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE, 0x70],
[quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE, 0x6c]
]);
const offset = offsets.get(componentType);

View file

@ -148,8 +148,7 @@ export interface ComponentTypeExtension {
measurements: Array<ComponentMeasurement>;
measurementSummary?: Function; //Deprecated: this summary used the old measurement structure
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
) => Summary[];
minMeasurementPeriodMs: number;
minCycleTimeMs?: number;
@ -229,20 +228,11 @@ export function simpleSummaries(
export function unitMeasurementSummary(
convertedMeasurement: MeasurementsFor,
describer: MeasurementDescriber,
excludedNodes?: number[]
): Summary {
let vals: string[] = [];
convertedMeasurement.values.forEach(val => {
vals.push(val + describer.unit());
});
//if nodes are excluded splice them out of the val array so they are not displayed in the summary
if (excludedNodes) {
vals.forEach((_val, i) => {
if (excludedNodes.includes(i)) {
vals.splice(i, 1);
}
});
}
let v = vals.join(", ");
if (describer.enumerations().length > 0) {
v = describer.enumerations()[parseFloat(vals[0])];
@ -259,19 +249,12 @@ export function unitMeasurementSummary(
export function unitMeasurementSummaries(
measurements: convertedUnitMeasurement,
compType: quack.ComponentType,
subtype?: number,
excludedNodes?: number[]
subtype?: number
): Summary[] {
let summaries: Summary[] = [];
measurements.measurementsFor.forEach(measurement => {
let describer = describeMeasurement(measurement.type, compType, subtype);
//TODO: implement the summary for node splitting when we make a component that uses it, drager was changed to use subtypes rather than nodes
//let details = describer.nodeDetails()
// if(details !== undefined){
// } else {
summaries.push(unitMeasurementSummary(measurement, describer, excludedNodes));
//}
summaries.push(unitMeasurementSummary(measurement, describer));
});
return summaries;
}

View file

@ -49,13 +49,11 @@ export function AirQuality(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_AIR_QUALITY,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -75,13 +75,11 @@ export function Airflow(subtype: number = 0): ComponentTypeExtension {
// },
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_AIRFLOW,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -79,13 +79,11 @@ export function AnalogInput(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_ANALOG_INPUT,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -50,14 +50,12 @@ export function CO2(subtype: number = 0): ComponentTypeExtension {
return simpleSummaries(measurement, co2);
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_CO2,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -37,14 +37,12 @@ export function Calcium(subtype: number = 0): ComponentTypeExtension {
return simpleSummaries(measurement, calcium);
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_CALCIUM,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -52,14 +52,12 @@ export function Capacitance(subtype: number = 0): ComponentTypeExtension {
return simpleSummaries(measurement, capacitance);
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_CAPACITANCE,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -148,14 +148,12 @@ export function CapacitorCable(subtype: number = 0): ComponentTypeExtension {
return Promise.resolve(summary);
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -37,14 +37,12 @@ export function Conductivity(subtype: number = 0): ComponentTypeExtension {
return simpleSummaries(measurement, conductivity);
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_CONDUCTIVITY,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -77,14 +77,12 @@ export function DHT(subtype: number = 0): ComponentTypeExtension {
return simpleSummaries(measurement, temperature, humidity);
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_DHT,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -48,16 +48,16 @@ export function dragerGasDongle(subtype: number = 0): ComponentTypeExtension {
return {
type: quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE,
subtypes: [
{
key: quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_NONE,
value: "DRAGER_GAS_DONGLE_SUBTYPE_NONE",
friendlyName: "Drager Gas Chain"
},
{
key: quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_DEBUG_VOLTAGE,
value: "DRAGER_GAS_DONGLE_SUBTYPE_ADVANCED",
friendlyName: "Drager Gas Chain - Voltage Debug"
},
// {
// key: quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_NONE,
// value: "DRAGER_GAS_DONGLE_SUBTYPE_NONE",
// friendlyName: "Drager Gas Chain"
// },
// {
// key: quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_DEBUG_VOLTAGE,
// value: "DRAGER_GAS_DONGLE_SUBTYPE_ADVANCED",
// friendlyName: "Drager Gas Chain - Voltage Debug"
// },
// {
// key: quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_CO_CO2_NO2_O2,
// value: "DRAGER_GAS_DONGLE_SUBTYPE_ADVANCED",
@ -100,7 +100,7 @@ export function dragerGasDongle(subtype: number = 0): ComponentTypeExtension {
isSource: true,
isArray: true,
isCalibratable: false,
addressTypes: [quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY],
addressTypes: [quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY, quack.AddressType.ADDRESS_TYPE_I2C],
interactionResultTypes: [],
states: [],
//this is apparently used by the interactions to determine what the possible options for measurement type are
@ -108,8 +108,7 @@ export function dragerGasDongle(subtype: number = 0): ComponentTypeExtension {
//believe this is only used with the old deprecated measurements system, unit measurements builds the summary in the UnitMeasurementSummary component
measurementSummary: () => {},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
//if it is O2 display percentage rather than ppm
if (subtype === quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_O2 || subtype === quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_LEL) {
@ -137,7 +136,7 @@ export function dragerGasDongle(subtype: number = 0): ComponentTypeExtension {
});
} else {
//create the simple summary for the voltage
summaries.push(unitMeasurementSummary(measurement, describer, excludedNodes));
summaries.push(unitMeasurementSummary(measurement, describer));
}
});
@ -146,8 +145,7 @@ export function dragerGasDongle(subtype: number = 0): ComponentTypeExtension {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE,
subtype,
excludedNodes
subtype
);
}
},

View file

@ -37,14 +37,12 @@ export function Ethylene(subtype: number = 0): ComponentTypeExtension {
return simpleSummaries(measurement, ethylene);
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_ETHYLENE,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -74,13 +74,11 @@ export function GPS(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_GPS,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -374,13 +374,11 @@ export function GrainCable(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -29,14 +29,12 @@ export function Invalid(subtype: number = 0): ComponentTypeExtension {
return Promise.reject();
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_INVALID,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -65,14 +65,12 @@ export function Lidar(subtype: number = 0): ComponentTypeExtension {
return simpleSummaries(measurement, distance);
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_LIDAR,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -37,14 +37,12 @@ export function Light(subtype: number = 0): ComponentTypeExtension {
return simpleSummaries(measurement, light);
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_LIGHT,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -45,14 +45,12 @@ export function Modem(subtype: number = 0): ComponentTypeExtension {
},
minMeasurementPeriodMs: 1000,
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_MODEM,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -37,14 +37,12 @@ export function Nitrate(subtype: number = 0): ComponentTypeExtension {
return simpleSummaries(measurement, nitrate);
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_NITRATE,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -37,14 +37,12 @@ export function O2(subtype: number = 0): ComponentTypeExtension {
return simpleSummaries(measurement, o2);
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_O2,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -38,13 +38,11 @@ export function ORP(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_ORP,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -37,14 +37,12 @@ export function OnOffInput(subtype: number = 0): ComponentTypeExtension {
return simpleSummaries(measurement, onOff);
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_BOOLEAN_INPUT,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -93,14 +93,12 @@ export function OnOffOutput(subtype: number = 0): ComponentTypeExtension {
return simpleSummaries(measurement, onOff);
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_BOOLEAN_OUTPUT,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -37,14 +37,12 @@ export function PH(subtype: number = 0): ComponentTypeExtension {
return simpleSummaries(measurement, ph);
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
measurements: convertedUnitMeasurement
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_PH,
subtype,
excludedNodes
subtype
);
},
areaChartData: (

View file

@ -38,13 +38,11 @@ export function Potassium(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_POTASSIUM,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -57,13 +57,11 @@ export function Power(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_POWER,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -67,13 +67,11 @@ export function Pressure(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_PRESSURE,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -147,13 +147,11 @@ export function PressureCable(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_PRESSURE_CABLE,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -94,13 +94,11 @@ export function Sen5x(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_SEN5X,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -41,13 +41,11 @@ export function StepperMotor(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_STEPPER_MOTOR,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -60,13 +60,11 @@ export function Temperature(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_TEMPERATURE,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -149,13 +149,11 @@ export function Trigger(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_EDGE_TRIGGERED,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -75,13 +75,11 @@ export function VPD(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -121,13 +121,11 @@ export function VibrationCable(subtype: number = 0): ComponentTypeExtension {
measurementSummary: async function() {},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_VIBRATION_CHAIN,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -38,13 +38,11 @@ export function Voltage(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_VOLTAGE,
subtype,
excludedNodes
);
},
areaChartData: (

View file

@ -38,13 +38,11 @@ export function Weight(subtype: number = 0): ComponentTypeExtension {
},
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
excludedNodes?: number[]
): Summary[] => {
return unitMeasurementSummaries(
measurements,
quack.ComponentType.COMPONENT_TYPE_WEIGHT,
subtype,
excludedNodes
);
},
lineChartData: (

View file

@ -61,7 +61,8 @@ const DefaultAvailability: DeviceAvailabilityMap = new Map<quack.AddressType, De
[quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE, [0x50]],
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]],
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, [0x6c]],
[quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE, [0x71]] // the address cables will use when they are plugged into the expander with V2 device only
[quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE, [0x71]], // the address cables will use when they are plugged into the expander with V2 device only
[quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE, [0x6d]]
])
],
[quack.AddressType.ADDRESS_TYPE_DAC, [0, 1]],

View file

@ -52,7 +52,9 @@ export const MiVentV2Availability: DeviceAvailabilityMap = new Map<
[quack.ComponentType.COMPONENT_TYPE_PRESSURE, [0x18]],
[quack.ComponentType.COMPONENT_TYPE_DHT, [0x40]],
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]],
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, [0x6c]]
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, [0x6c]],
[quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE, [0x6d]]
])
],
[quack.AddressType.ADDRESS_TYPE_POWER, [0]],

View file

@ -89,6 +89,7 @@ export interface IBinAPIContext {
start: string,
end: string,
showErrors?: boolean,
allNodes?: boolean,
otherTeam?: string
) => Promise<AxiosResponse<pond.ListBinComponentsMeasurementsResponse>>;
updateBinPermissions: (
@ -447,6 +448,7 @@ export default function BinProvider(props: PropsWithChildren<Props>) {
start: string,
end: string,
showErrors = false,
allNodes = false,
otherTeam?: string
) => {
const view = otherTeam ? otherTeam : as
@ -457,7 +459,8 @@ export default function BinProvider(props: PropsWithChildren<Props>) {
"&end=" +
end +
(view ? "&as=" + view : "") +
(showErrors ? "&showErrors=true" : "&showErrors=false")
(showErrors ? "&showErrors=true" : "&showErrors=false") +
(allNodes ? "&allNodes=true" : "&allNodes=false")
return new Promise<AxiosResponse<pond.ListBinComponentsMeasurementsResponse>>((resolve, reject) => {
get<pond.ListBinComponentsMeasurementsResponse>(pondURL(url))

View file

@ -98,6 +98,7 @@ export interface IComponentAPIContext {
keys?: string[],
types?: string[],
showErrors?: boolean,
allNodes?: boolean,
otherTeam?: string
) => Promise<AxiosResponse<pond.SampleUnitMeasurementsResponse>>;
// possibly a deprecated function as it is not used anywhere
@ -120,6 +121,7 @@ export interface IComponentAPIContext {
keys?: string[],
types?: string[],
showErrors?: boolean,
allNodes?: boolean,
otherTeam?: string
) => Promise<AxiosResponse<pond.ListUnitMeasurementsResponse>>;
}
@ -480,6 +482,7 @@ export default function ComponentProvider(props: PropsWithChildren<Props>) {
keys?: string[],
types?: string[],
showErrors: boolean = true,
allNodes: boolean = false,
otherTeam?: string
) => {
const view = otherTeam ? otherTeam : as
@ -495,7 +498,8 @@ export default function ComponentProvider(props: PropsWithChildren<Props>) {
(view ? "&as=" + view : "") +
(keys ? "&keys=" + keys : "&keys=" + [device]) +
(types ? "&types=" + types : "&types=" + ["device"]) +
(showErrors ? "&showErrors=true" : "&showErrors=false"),
(showErrors ? "&showErrors=true" : "&showErrors=false")+
(allNodes ? "&allNodes=true" : "&allNodes=false"),
demo
);
return new Promise<AxiosResponse<pond.SampleUnitMeasurementsResponse>>((resolve, reject) => {
@ -545,6 +549,7 @@ export default function ComponentProvider(props: PropsWithChildren<Props>) {
keys?: string[],
types?: string[],
showErrors?: boolean,
allNodes: boolean = false,
otherTeam?: string
) => {
const view = otherTeam ? otherTeam : as
@ -565,7 +570,8 @@ export default function ComponentProvider(props: PropsWithChildren<Props>) {
(view ? "&as=" + view : "") +
(keys ? "&keys=" + keys : "&keys=" + [device]) +
(types ? "&types=" + types : "&types=" + ["device"]) +
(showErrors ? "&showErrors=true" : "&showErrors=false")
(showErrors ? "&showErrors=true" : "&showErrors=false") +
(allNodes ? "&allNodes=true" : "&allNodes=false")
);
return new Promise<AxiosResponse<pond.ListUnitMeasurementsResponse>>((resolve,reject) => {
get<pond.ListUnitMeasurementsResponse>(url).then(resp => {

View file

@ -89,7 +89,7 @@ export default function Marketplace() {
useEffect(() => {
let list: ProductDetails[] = [];
if (IsAdaptiveAgriculture()) {
if (IsAdaptiveAgriculture() || user.hasFeature("admin")) {
list = list.concat(agFeatureList);
}
// if(IsAdCon()){