Merge branch 'auto_detect_cable_summary' into dev_environment

This commit is contained in:
csawatzky 2025-04-29 12:09:58 -06:00
commit 68ec1217c6
4 changed files with 236 additions and 227 deletions

View file

@ -96,6 +96,7 @@ export default function DevicePage() {
}
}
});
setDiagnosticComponents(diagComponents)
setComponents(rComponents)
let interactions: Interaction[] = [];
resp.data.interactions.forEach((interaction: pond.Interaction) => {

View file

@ -1,7 +1,7 @@
import {
GraphComponent,
GraphOrientation,
GraphPoint,
// GraphComponent,
// GraphOrientation,
// GraphPoint,
GraphType,
InteractionLine
} from "common/Graph";
@ -41,15 +41,15 @@ import {
Weight,
CapacitorCable
} from "pbHelpers/ComponentTypes";
import { multilineGrainCableData } from "pbHelpers/ComponentTypes/GrainCable";
import { multilineCapCableData } from "./ComponentTypes/CapacitorCable";
//import { multilineGrainCableData } from "pbHelpers/ComponentTypes/GrainCable";
//import { multilineCapCableData } from "./ComponentTypes/CapacitorCable";
import { findInteractionsAsSource } from "pbHelpers/Interaction";
import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/quack";
import { notNull, or } from "utils/types";
import { emptyComponentId } from "./Component";
import { multilinePressureCableData } from "./ComponentTypes/PressureCable";
//import { emptyComponentId } from "./Component";
//import { multilinePressureCableData } from "./ComponentTypes/PressureCable";
import { describeMeasurement, MeasurementDescriber } from "./MeasurementDescriber";
import { convertedUnitMeasurement, MeasurementsFor, UnitMeasurement } from "models/UnitMeasurement";
import { Sen5x } from "./ComponentTypes/Sen5x";
@ -622,194 +622,194 @@ export function GetComponentIcon(
}
//TODO: deprecated function, new graphs are handled in measurementChart (using reCharts instead of victory)
export function getGraphProps(
componentType: quack.ComponentType,
subtype: number,
measurements: pond.Measurement[],
interactions: Interaction[],
overlays: pond.ComponentOverlays[],
orientation: GraphOrientation,
filters?: GraphFilters
): any {
const componentID: quack.IComponentID = quack.ComponentID.fromObject(
or(measurements[0].measurement, {
id: emptyComponentId()
}).id as any
);
let graphProps = {
orientation: orientation
} as any;
let ext = extension(componentType, subtype);
ext.measurements.forEach((componentMeasurement: ComponentMeasurement, index: number) => {
let describer = describeMeasurement(
componentMeasurement.measurementType,
componentType,
subtype
);
let range =
filters && filters.ranges && filters.ranges[index] ? filters.ranges[index] : undefined;
let selectedInteractions =
filters && filters.selectedInteractions ? filters.selectedInteractions : [];
let interactionLines = getInteractionLines(
componentType,
subtype,
componentMeasurement.measurementType,
componentID,
interactions,
selectedInteractions
);
let selectedOverlays = filters?.selectedOverlays ?? [];
let overlayAreas = getOverlayAreas(
componentMeasurement.measurementType,
overlays,
selectedOverlays
);
graphProps["graphComponent" + (index + 1).toString()] = {
label: componentMeasurement.label,
data: [],
tick: describer.unit(),
colour: componentMeasurement.colour,
type: componentMeasurement.graphType,
range: range,
isBoolean:
componentMeasurement.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN,
isPercent:
componentMeasurement.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_PERCENT ||
(componentMeasurement.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_ANALOG &&
subtype === quack.AnalogInputSubtype.ANALOG_INPUT_SUBTYPE_FUEL),
interactionLines: interactionLines,
states: ext.states,
decimals: describer.decimals(),
overlays: overlayAreas
} as GraphComponent;
});
// export function getGraphProps(
// componentType: quack.ComponentType,
// subtype: number,
// measurements: pond.Measurement[],
// interactions: Interaction[],
// overlays: pond.ComponentOverlays[],
// orientation: GraphOrientation,
// filters?: GraphFilters
// ): any {
// const componentID: quack.IComponentID = quack.ComponentID.fromObject(
// or(measurements[0].measurement, {
// id: emptyComponentId()
// }).id as any
// );
// let graphProps = {
// orientation: orientation
// } as any;
// let ext = extension(componentType, subtype);
// ext.measurements.forEach((componentMeasurement: ComponentMeasurement, index: number) => {
// let describer = describeMeasurement(
// componentMeasurement.measurementType,
// componentType,
// subtype
// );
// let range =
// filters && filters.ranges && filters.ranges[index] ? filters.ranges[index] : undefined;
// let selectedInteractions =
// filters && filters.selectedInteractions ? filters.selectedInteractions : [];
// let interactionLines = getInteractionLines(
// componentType,
// subtype,
// componentMeasurement.measurementType,
// componentID,
// interactions,
// selectedInteractions
// );
// let selectedOverlays = filters?.selectedOverlays ?? [];
// let overlayAreas = getOverlayAreas(
// componentMeasurement.measurementType,
// overlays,
// selectedOverlays
// );
// graphProps["graphComponent" + (index + 1).toString()] = {
// label: componentMeasurement.label,
// data: [],
// tick: describer.unit(),
// colour: componentMeasurement.colour,
// type: componentMeasurement.graphType,
// range: range,
// isBoolean:
// componentMeasurement.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN,
// isPercent:
// componentMeasurement.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_PERCENT ||
// (componentMeasurement.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_ANALOG &&
// subtype === quack.AnalogInputSubtype.ANALOG_INPUT_SUBTYPE_FUEL),
// interactionLines: interactionLines,
// states: ext.states,
// decimals: describer.decimals(),
// overlays: overlayAreas
// } as GraphComponent;
// });
//for new cables add here to get the data for multiline
if (showMultilineCable(componentType, filters)) {
let cableData: any = {};
if (componentType === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE) {
cableData = multilineGrainCableData(measurements, filters);
} else if (componentType === quack.ComponentType.COMPONENT_TYPE_PRESSURE_CABLE) {
cableData = multilinePressureCableData(measurements, filters);
} else if (componentType === quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE) {
cableData = multilineCapCableData(measurements, filters);
}
//will loop through the keys in cableData
//IMPORTANT keys must be data1, data2, etc in the multiline function in the component
for (let i = 1; i <= Object.keys(cableData).length; i++) {
let gc = "graphComponent" + i;
if (graphProps[gc]) {
graphProps[gc].data = cableData["data" + i];
graphProps[gc].type = GraphType.MULTILINE;
}
}
} else {
measurements.forEach((reading: pond.Measurement, readIndex) => {
if (notNull(reading) && notNull(reading.timestamp) && notNull(reading.measurement)) {
let date = new Date(Date.parse(reading.timestamp));
for (let index = 0; index < ext.measurements.length; index++) {
let componentMeasurement: ComponentMeasurement = ext.measurements[index];
if (componentMeasurement.isErrorMeasurement(reading.measurement)) {
break;
}
let dataPoint = null;
switch (componentMeasurement.graphType) {
case GraphType.AREA:
let avg = componentMeasurement.extract(
or(reading.measurement, {} as quack.Measurement),
filters
);
if (avg && avg.low !== null && avg.high !== null) {
dataPoint = {
x: date,
y: avg.low,
y0: avg.high
} as GraphPoint;
}
break;
case GraphType.SCATTER:
let scatter = componentMeasurement.extract(
or(reading.measurement, {} as quack.Measurement),
filters
);
if (scatter && scatter.value !== undefined && scatter.value !== null) {
dataPoint = {
x: date,
y: Number(scatter.value),
bubble: or(scatter.bubble, 0)
} as GraphPoint;
}
break;
case GraphType.RADAR:
if (subtype === quack.AnalogInputSubtype.ANALOG_INPUT_SUBTYPE_WIND_DIRECTION) {
let value = componentMeasurement.extract(
or(reading.measurement, {} as quack.Measurement),
filters
);
// //for new cables add here to get the data for multiline
// if (showMultilineCable(componentType, filters)) {
// let cableData: any = {};
// if (componentType === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE) {
// cableData = multilineGrainCableData(measurements, filters);
// } else if (componentType === quack.ComponentType.COMPONENT_TYPE_PRESSURE_CABLE) {
// cableData = multilinePressureCableData(measurements, filters);
// } else if (componentType === quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE) {
// cableData = multilineCapCableData(measurements, filters);
// }
// //will loop through the keys in cableData
// //IMPORTANT keys must be data1, data2, etc in the multiline function in the component
// for (let i = 1; i <= Object.keys(cableData).length; i++) {
// let gc = "graphComponent" + i;
// if (graphProps[gc]) {
// graphProps[gc].data = cableData["data" + i];
// graphProps[gc].type = GraphType.MULTILINE;
// }
// }
// } else {
// measurements.forEach((reading: pond.Measurement, readIndex) => {
// if (notNull(reading) && notNull(reading.timestamp) && notNull(reading.measurement)) {
// let date = new Date(Date.parse(reading.timestamp));
// for (let index = 0; index < ext.measurements.length; index++) {
// let componentMeasurement: ComponentMeasurement = ext.measurements[index];
// if (componentMeasurement.isErrorMeasurement(reading.measurement)) {
// break;
// }
// let dataPoint = null;
// switch (componentMeasurement.graphType) {
// case GraphType.AREA:
// let avg = componentMeasurement.extract(
// or(reading.measurement, {} as quack.Measurement),
// filters
// );
// if (avg && avg.low !== null && avg.high !== null) {
// dataPoint = {
// x: date,
// y: avg.low,
// y0: avg.high
// } as GraphPoint;
// }
// break;
// case GraphType.SCATTER:
// let scatter = componentMeasurement.extract(
// or(reading.measurement, {} as quack.Measurement),
// filters
// );
// if (scatter && scatter.value !== undefined && scatter.value !== null) {
// dataPoint = {
// x: date,
// y: Number(scatter.value),
// bubble: or(scatter.bubble, 0)
// } as GraphPoint;
// }
// break;
// case GraphType.RADAR:
// if (subtype === quack.AnalogInputSubtype.ANALOG_INPUT_SUBTYPE_WIND_DIRECTION) {
// let value = componentMeasurement.extract(
// or(reading.measurement, {} as quack.Measurement),
// filters
// );
dataPoint = {
x: getWindDirection(value).dString,
y: getWindDirection(value).direction
};
}
break;
default:
//linear and bar
let value = componentMeasurement.extract(
or(reading.measurement, {} as quack.Measurement),
filters
);
// dataPoint = {
// x: getWindDirection(value).dString,
// y: getWindDirection(value).direction
// };
// }
// break;
// default:
// //linear and bar
// let value = componentMeasurement.extract(
// or(reading.measurement, {} as quack.Measurement),
// filters
// );
if (value !== undefined && value !== null) {
if (componentType === quack.ComponentType.COMPONENT_TYPE_ANALOG_INPUT) {
if (subtype === quack.AnalogInputSubtype.ANALOG_INPUT_SUBTYPE_FUEL) {
if (value > 100) {
value = 0;
}
}
}
if (componentType === quack.ComponentType.COMPONENT_TYPE_EDGE_TRIGGERED) {
if (subtype === quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_WIND_SPEED) {
if (readIndex < measurements.length - 1) {
//do math
//get the time of both the current reading and the reading before it
let currentTime = new Date(
Date.parse(measurements[readIndex].timestamp)
).valueOf();
let prevTime = new Date(
Date.parse(measurements[readIndex + 1].timestamp)
).valueOf();
// if (value !== undefined && value !== null) {
// if (componentType === quack.ComponentType.COMPONENT_TYPE_ANALOG_INPUT) {
// if (subtype === quack.AnalogInputSubtype.ANALOG_INPUT_SUBTYPE_FUEL) {
// if (value > 100) {
// value = 0;
// }
// }
// }
// if (componentType === quack.ComponentType.COMPONENT_TYPE_EDGE_TRIGGERED) {
// if (subtype === quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_WIND_SPEED) {
// if (readIndex < measurements.length - 1) {
// //do math
// //get the time of both the current reading and the reading before it
// let currentTime = new Date(
// Date.parse(measurements[readIndex].timestamp)
// ).valueOf();
// let prevTime = new Date(
// Date.parse(measurements[readIndex + 1].timestamp)
// ).valueOf();
//get the difference in seconds between the two
let deltaTime = (currentTime - prevTime) / 1000;
// //get the difference in seconds between the two
// let deltaTime = (currentTime - prevTime) / 1000;
//divide the ticks by the time between intervals for the average ticks per second and multiply
//by 2.4 to convert to km/h
value = (Number(value) / deltaTime) * 2.4;
} else {
value = 0;
}
}
if (subtype === quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_RAIN) {
value = Math.round(value * 0.2794);
}
}
dataPoint = {
x: date,
y: Number(value)
} as GraphPoint;
}
break;
}
if (dataPoint !== null) {
graphProps["graphComponent" + (index + 1).toString()].data.push(dataPoint);
}
}
}
});
}
return graphProps;
}
// //divide the ticks by the time between intervals for the average ticks per second and multiply
// //by 2.4 to convert to km/h
// value = (Number(value) / deltaTime) * 2.4;
// } else {
// value = 0;
// }
// }
// if (subtype === quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_RAIN) {
// value = Math.round(value * 0.2794);
// }
// }
// dataPoint = {
// x: date,
// y: Number(value)
// } as GraphPoint;
// }
// break;
// }
// if (dataPoint !== null) {
// graphProps["graphComponent" + (index + 1).toString()].data.push(dataPoint);
// }
// }
// }
// });
// }
// return graphProps;
// }
function getWindDirection(value: number) {
//determine the general direction based on the value

View file

@ -4,8 +4,8 @@ import GrainCableLightIcon from "assets/components/grainCableLight.png";
import TemperatureHumidityDarkIcon from "assets/components/temperatureHumidityDark.png";
import TemperatureHumidityLightIcon from "assets/components/temperatureHumidityLight.png";
import { ExtractMoisture, grainName } from "grain";
import { GraphPoint } from "common/Graph";
import moment from "moment";
//import { GraphPoint } from "common/Graph";
//import moment from "moment";
import {
AreaChartData,
ComponentMeasurement,
@ -418,38 +418,38 @@ export function binSplitAt(filters?: GraphFilters): number {
}
//TODO: deprecated function with new measurements
export function multilineGrainCableData(
measurements: Array<pond.Measurement>,
filters?: GraphFilters
) {
let temperature: Array<Array<GraphPoint>> = [];
let humidity: Array<Array<GraphPoint>> = []; //humidity is not being used by the graphs
let moisture: Array<Array<GraphPoint>> = [];
measurements.forEach((measurement: pond.Measurement, i) => {
let nodes = extractNodes(measurement.measurement);
let selectedNodes = filters ? or(filters.selectedNodes, []) : [];
for (let j = 0; j < selectedNodes.length; j++) {
if (i === 0) {
temperature[j] = [];
humidity[j] = [];
moisture[j] = [];
}
let nodeIndex = selectedNodes[j];
if (nodeIndex < nodes.length) {
let node = nodes[nodeIndex];
let ts = moment(measurement.timestamp);
temperature[j].push({ x: ts, y: node.temperature });
humidity[j].push({ x: ts, y: node.humidity });
let grain =
isBinSplit(filters) && nodeIndex >= binSplitAt(filters)
? pond.Grain.GRAIN_NONE
: or(filters, { grainType: pond.Grain.GRAIN_NONE }).grainType;
moisture[j].push({
x: ts,
y: ExtractMoisture(grain, node.temperature, node.humidity)
});
}
}
});
return { data1: temperature, data2: moisture, data3: humidity };
}
// export function multilineGrainCableData(
// measurements: Array<pond.Measurement>,
// filters?: GraphFilters
// ) {
// let temperature: Array<Array<GraphPoint>> = [];
// let humidity: Array<Array<GraphPoint>> = []; //humidity is not being used by the graphs
// let moisture: Array<Array<GraphPoint>> = [];
// measurements.forEach((measurement: pond.Measurement, i) => {
// let nodes = extractNodes(measurement.measurement);
// let selectedNodes = filters ? or(filters.selectedNodes, []) : [];
// for (let j = 0; j < selectedNodes.length; j++) {
// if (i === 0) {
// temperature[j] = [];
// humidity[j] = [];
// moisture[j] = [];
// }
// let nodeIndex = selectedNodes[j];
// if (nodeIndex < nodes.length) {
// let node = nodes[nodeIndex];
// let ts = moment(measurement.timestamp);
// temperature[j].push({ x: ts, y: node.temperature });
// humidity[j].push({ x: ts, y: node.humidity });
// let grain =
// isBinSplit(filters) && nodeIndex >= binSplitAt(filters)
// ? pond.Grain.GRAIN_NONE
// : or(filters, { grainType: pond.Grain.GRAIN_NONE }).grainType;
// moisture[j].push({
// x: ts,
// y: ExtractMoisture(grain, node.temperature, node.humidity)
// });
// }
// }
// });
// return { data1: temperature, data2: moisture, data3: humidity };
// }

View file

@ -110,6 +110,10 @@ export class MeasurementDescriber {
}
if (componentType === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE) {
this.details.graph = GraphType.AREA;
if(componentSubtype === quack.GrainCableSubtype.GRAIN_CABLE_SUBTYPE_OPI_DIAG){
this.details.label = "Cable ID"
this.details.unit = ""
}
}
if (componentType === quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT) {
this.details.path = "vpd.celciusTimes10";
@ -194,6 +198,10 @@ export class MeasurementDescriber {
if (componentType === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE) {
this.details.label = "Humidity";
this.details.graph = GraphType.AREA;
if(componentSubtype === quack.GrainCableSubtype.GRAIN_CABLE_SUBTYPE_OPI_DIAG){
this.details.label = "Cable Type"
this.details.unit = ""
}
// can be used for testing node splitting on a cable if you dont have a component that uses it
// this.details.nodeDetails = {
// colours: ["white", "black"],