added tons of files for component functionality; manual component adding added temporarily

This commit is contained in:
Carter 2025-02-11 16:31:03 -06:00
parent 58830d480e
commit 45ff49bcea
121 changed files with 25883 additions and 65 deletions

View file

@ -0,0 +1,688 @@
import {
blue,
brown,
deepOrange,
deepPurple,
green,
grey,
lightGreen,
orange,
purple,
red,
teal,
yellow
} from "@mui/material/colors";
import { GraphType } from "common/Graph";
import { IsCardController } from "products/DeviceProduct";
import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/quack";
import { getTextSecondary } from "theme/text";
// import { getTextSecondary } from "theme";
import { getDistanceUnit, getPressureUnit, getTemperatureUnit, roundTo } from "utils";
import { extract } from "utils/types";
interface Enumeration {
label: string;
colour: any;
}
interface NodeDetails {
labels: string[];
colours: string[];
}
interface MeasurementDetails {
label: string;
unit: string;
factor: number;
complexConversion: ((value: number, mode: "toStored" | "toDisplay") => number) | null;
multiply: boolean;
spacer: boolean;
enumerations: Enumeration[];
colour: any;
decimals: number;
path: string;
graph: GraphType;
min: number;
max: number;
step: number;
errorValue?: number;
nodeDetails?: NodeDetails;
}
function enumeration(label: string, colour: any) {
return { label, colour };
}
/**
* This is used to determine the measurements that will be shown on the y axis of the graph as well as the measurements table
*/
export class MeasurementDescriber {
private measurementType: quack.MeasurementType;
private details: MeasurementDetails;
constructor(
measurementType: quack.MeasurementType,
componentType: quack.ComponentType,
componentSubtype: number,
product?: pond.DeviceProduct
) {
this.measurementType = measurementType;
this.details = {
label: "Unknown",
unit: "",
factor: 1.0,
complexConversion: null,
multiply: false,
spacer: false,
enumerations: [],
colour: "",
decimals: 0,
path: "",
graph: GraphType.LINEAR,
min: 0,
max: 100,
step: 1
};
switch (measurementType) {
case quack.MeasurementType.MEASUREMENT_TYPE_INVALID:
break;
case quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE:
let temperatureUnit = getTemperatureUnit();
let isFahrenheit = temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT;
this.details.label = "Temperature";
this.details.unit = isFahrenheit ? "°F" : "°C";
this.details.factor = 10.0;
this.details.complexConversion = isFahrenheit
? (value: number, mode: "toStored" | "toDisplay"): number => {
if (mode === "toStored") {
return ((value - 32.0) / (9.0 / 5.0)) * this.details.factor;
}
return (value / this.details.factor) * (9.0 / 5.0) + 32.0;
}
: null;
this.details.colour = orange["500"];
this.details.decimals = 2;
this.details.path = "temperature.celciusTimes10";
this.details.errorValue = -127;
if (componentType === quack.ComponentType.COMPONENT_TYPE_DHT) {
this.details.path = "humidityAndTemperature.celciusTimes10";
}
if (componentType === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE) {
this.details.graph = GraphType.AREA;
}
if (componentType === quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT) {
this.details.path = "vpd.celciusTimes10";
if (componentSubtype === quack.DHTSubtype.DHT_SUBTYPE_22) {
this.details.decimals = 1;
}
}
if (IsCardController(product)) {
this.details.min = isFahrenheit ? 32 : 0;
this.details.max = isFahrenheit ? 113 : 45;
} else {
this.details.min = isFahrenheit ? -40 : -40;
this.details.max = isFahrenheit ? 212 : 100;
}
break;
case quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN:
this.details.label = "State";
this.details.enumerations = [enumeration("Off", "#f9a825"), enumeration("On", "#f9a825")];
this.details.path = "booleanOutput.value";
this.details.colour = "#f9a825";
this.details.min = 0;
this.details.max = 1;
if (componentType === quack.ComponentType.COMPONENT_TYPE_BOOLEAN_INPUT) {
this.details.path = "booleanInput.value";
}
if (componentType === quack.ComponentType.COMPONENT_TYPE_EDGE_TRIGGERED) {
this.details.path = "edgeTriggered.state";
this.details.graph = GraphType.SCATTER;
if (componentSubtype === quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_DOOR) {
this.details.enumerations = [
enumeration("Closed", "var(--status-ok)"),
enumeration("Open", "var(--status-alert)")
];
} else if (componentSubtype === quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_WATER) {
this.details.colour = "#2196f3";
this.details.enumerations = [
enumeration("Stopped", getTextSecondary()),
enumeration("Flowing", "#2196f3")
];
} else {
this.details.enumerations = [
enumeration("OK", "var(--status-ok)"),
enumeration("Triggered", "var(--status-alert)")
];
}
}
break;
case quack.MeasurementType.MEASUREMENT_TYPE_VOLTAGE:
this.details.label = "Voltage";
this.details.unit = "V";
this.details.factor = 10.0;
this.details.colour = deepOrange["700"];
this.details.path = "voltage.microvolts";
this.details.decimals = 3;
if (componentType === quack.ComponentType.COMPONENT_TYPE_POWER) {
this.details.path = "power.inputVoltageTimes10";
this.details.decimals = 1;
}
if (componentType === quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE) {
this.details.unit = "mV";
this.details.graph = GraphType.MULTILINE;
this.details.unit = "mV";
// this.details.nodeDetails = {
// colours: ["white", "black", "red", "blue"],
// labels: ["millivolt1", "millivolt2", "millivolt3", "millivolt4"]
// };
}
this.details.max = 30;
break;
case quack.MeasurementType.MEASUREMENT_TYPE_PERCENT:
this.details.label = "Percent";
this.details.unit = "%";
this.details.errorValue = 200;
this.details.factor = 100.0;
this.details.colour = teal["500"];
this.details.decimals = 2;
if (componentType === quack.ComponentType.COMPONENT_TYPE_DHT) {
this.details.label = "Humidity";
this.details.path = "humidityAndTemperature.relativeHumidityTimes100";
this.details.decimals = 1;
}
if (componentType === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE) {
this.details.label = "Humidity";
this.details.graph = GraphType.AREA;
// 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"],
// labels: ["hum1", "hum2"]
// };
}
if (componentType === quack.ComponentType.COMPONENT_TYPE_MODEM) {
this.details.label = "Quality";
this.details.factor = 2.0;
this.details.path = "modemSignal.quality";
this.details.colour = orange["500"];
this.details.multiply = true;
}
if (componentType === quack.ComponentType.COMPONENT_TYPE_POWER) {
this.details.label = "Charged";
this.details.path = "power.percentChargedTimes100";
this.details.colour = lightGreen["600"];
}
if (componentType === quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT) {
this.details.label = "Humidity";
this.details.path = "vpd.relativeHumidityTimes100";
if (componentSubtype === quack.DHTSubtype.DHT_SUBTYPE_22) {
this.details.decimals = 1;
}
}
if (componentType === quack.ComponentType.COMPONENT_TYPE_SEN5X) {
this.details.label = "Humidity";
}
break;
case quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE:
let pressureUnit = getPressureUnit();
let isIWG = pressureUnit === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER;
this.details.label = "Pressure";
this.details.unit = isIWG ? "iwg" : "kPa";
this.details.factor = isIWG ? 248.84 : 1000.0;
this.details.spacer = true;
this.details.colour = deepPurple["300"];
this.details.path = "pressure.pascals";
this.details.decimals = 2;
if (componentType === quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT) {
this.details.path = "vpd.pascals";
if (componentSubtype === quack.DHTSubtype.DHT_SUBTYPE_22) {
this.details.decimals = 1;
}
} else if (componentType === quack.ComponentType.COMPONENT_TYPE_PRESSURE_CABLE) {
this.details.path = "pressureCable.pascals";
this.details.graph = GraphType.AREA;
}
this.details.max = isIWG ? 20 : 5;
this.details.step = 0.1;
break;
case quack.MeasurementType.MEASUREMENT_TYPE_RSSI:
this.details.label = "Strength";
this.details.unit = "dBm";
this.details.spacer = true;
this.details.colour = yellow["500"];
this.details.path = "modemSignal.rssi";
this.details.min = -150;
this.details.max = 0;
break;
case quack.MeasurementType.MEASUREMENT_TYPE_LIGHT:
this.details.label = "Illuminance";
this.details.unit = "lux";
this.details.factor = 100.0;
this.details.spacer = true;
this.details.colour = orange["500"];
this.details.path = "light.luxTimes100";
this.details.decimals = 2;
this.details.max = 20000;
break;
case quack.MeasurementType.MEASUREMENT_TYPE_PPB:
this.details.label = "Concentration";
this.details.spacer = true;
this.details.unit = "ppb";
this.details.colour = green["500"];
this.details.decimals = 3;
this.details.max = 300;
this.details.path = "concentration.ppb";
switch (componentType) {
case quack.ComponentType.COMPONENT_TYPE_CALCIUM:
this.details.path = "concentration.ppb";
this.details.colour = teal["500"];
break;
case quack.ComponentType.COMPONENT_TYPE_NITRATE:
this.details.path = "concentration.ppb";
this.details.colour = green["500"];
break;
case quack.ComponentType.COMPONENT_TYPE_POTASSIUM:
this.details.path = "concentration.ppb";
this.details.colour = yellow["500"];
break;
case quack.ComponentType.COMPONENT_TYPE_ETHYLENE:
this.details.colour = red["300"];
this.details.max = 500000;
this.details.path = "gas.ppb";
break;
case quack.ComponentType.COMPONENT_TYPE_AIR_QUALITY:
this.details.path = "gas.ppb";
this.details.label = "TVOC";
this.details.max = 60000;
this.details.decimals = 1;
this.details.colour = green["300"];
break;
default:
break;
}
break;
case quack.MeasurementType.MEASUREMENT_TYPE_PPM:
this.details.label = "Gas";
this.details.spacer = true;
this.details.unit = "ppm";
this.details.path = "gas.ppm";
this.details.colour = brown["300"];
switch (componentType) {
case quack.ComponentType.COMPONENT_TYPE_CO2:
this.details.max = 5000;
break;
case quack.ComponentType.COMPONENT_TYPE_O2:
this.details.max = 500000;
break;
case quack.ComponentType.COMPONENT_TYPE_AIR_QUALITY:
this.details.label = "eCO2";
this.details.max = 60000;
break;
case quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE:
this.details.graph = GraphType.MULTILINE;
switch (componentSubtype) {
case quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_DEBUG_VOLTAGE:
this.details.label = "Voltage";
this.details.unit = "mV";
break;
case quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_O2:
this.details.colour = blue["400"];
this.details.decimals = 1;
this.details.unit = "%";
this.details.complexConversion = (
value: number,
mode: "toStored" | "toDisplay"
): number => {
if (mode === "toStored") {
//for O2 dragers the display is in percentage so convert the percent to ppm
return value * 10000;
}
return value / 10000;
};
break;
case quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_NO2:
this.details.colour = teal["500"];
break;
case quack.DragerGasDongleSubtype.DRAGER_GAS_DONGLE_SUBTYPE_CO:
this.details.colour = grey["500"];
}
break;
default:
break;
}
break;
case quack.MeasurementType.MEASUREMENT_TYPE_ANALOG:
this.details.label = "Value";
this.details.colour = orange["500"];
this.details.path = "analogInput.value";
this.details.max = 50;
switch (componentType) {
case quack.ComponentType.COMPONENT_TYPE_ANALOG_INPUT:
if (componentSubtype === quack.AnalogInputSubtype.ANALOG_INPUT_SUBTYPE_FUEL) {
this.details.factor = 10.0;
this.details.max = 100;
this.details.min = 0;
this.details.decimals = 1;
this.details.label = "Fuel";
this.details.unit = "%";
this.details.colour = "#CC9933";
} else if (
componentSubtype === quack.AnalogInputSubtype.ANALOG_INPUT_SUBTYPE_WIND_DIRECTION
) {
this.details.label = "Wind Direction";
this.details.colour = green["500"];
this.details.graph = GraphType.RADAR;
}
}
break;
case quack.MeasurementType.MEASUREMENT_TYPE_ORP:
this.details.label = "ORP";
this.details.unit = "mV";
this.details.factor = 1000.0;
this.details.spacer = true;
this.details.colour = blue["200"];
this.details.path = "orp.microvolts";
this.details.decimals = 3;
this.details.max = 1000;
break;
case quack.MeasurementType.MEASUREMENT_TYPE_PH:
this.details.label = "pH";
this.details.unit = "pH";
this.details.factor = 100000.0;
this.details.spacer = true;
this.details.colour = purple["500"];
this.details.path = "ph.phTimes100000";
this.details.decimals = 3;
this.details.min = 0;
this.details.max = 14;
this.details.step = 0.1;
break;
case quack.MeasurementType.MEASUREMENT_TYPE_CONDUCTIVITY:
this.details.label = "Conductivity";
this.details.unit = "μS/cm";
this.details.spacer = true;
this.details.colour = orange["500"];
this.details.path = "conductivity.microsiemensPerCm";
this.details.decimals = 3;
this.details.max = 5000;
break;
case quack.MeasurementType.MEASUREMENT_TYPE_CAPACITANCE:
this.details.label = "Capacitance";
this.details.unit = "nF";
this.details.path = "capacitance.picofarads";
if (componentType === quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE) {
this.details.unit = "fF";
}
this.details.factor = 1000.0;
this.details.spacer = true;
this.details.colour = orange["500"];
this.details.decimals = 3;
this.details.max = 100000;
break;
case quack.MeasurementType.MEASUREMENT_TYPE_WEIGHT:
this.details.label = "Weight";
this.details.unit = "g";
this.details.colour = green["500"];
this.details.path = "weight.grams";
this.details.max = 100000;
break;
case quack.MeasurementType.MEASUREMENT_TYPE_DISTANCE_CM:
let distanceUnit = getDistanceUnit();
this.details.label = "Distance";
this.details.unit = "cm";
if (distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
this.details.unit = "ft";
}
if (distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
this.details.unit = "m";
}
this.details.colour = blue["400"];
this.details.path = "distance.cm";
this.details.max = 100000;
break;
case quack.MeasurementType.MEASUREMENT_TYPE_SPEED:
this.details.label = "Speed";
this.details.unit = "km/h";
this.details.colour = green["500"];
this.details.path = "edgeTriggered.rises";
this.details.max = 500;
this.details.min = 0;
break;
case quack.MeasurementType.MEASUREMENT_TYPE_RAIN:
this.details.label = "Rain";
this.details.unit = "mm";
this.details.colour = blue["500"];
this.details.path = "edgeTriggered.rises";
break;
case quack.MeasurementType.MEASUREMENT_TYPE_GRAIN_EMC:
this.details.label = "Grain Moisture";
this.details.unit = "% WB";
this.details.decimals = 2;
this.details.colour = yellow["500"];
this.details.graph = GraphType.AREA;
break;
case quack.MeasurementType.MEASUREMENT_TYPE_CFM:
this.details.label = "Airflow";
this.details.unit = "CFM";
this.details.colour = blue["300"];
break;
case quack.MeasurementType.MEASUREMENT_TYPE_CAPACITANCE_GND_FF:
this.details.label = "Capacitance(Ground Ref)";
this.details.unit = "fF";
this.details.colour = orange["500"];
this.details.graph = GraphType.AREA;
break;
case quack.MeasurementType.MEASUREMENT_TYPE_CAPACITANCE_SELF_FF:
this.details.label = "Capacitance(Self Ref)";
this.details.unit = "fF";
this.details.colour = orange["500"];
this.details.graph = GraphType.AREA;
break;
case quack.MeasurementType.MEASUREMENT_TYPE_DUST_1UG:
this.details.label = "Dust <1um";
this.details.unit = "ug/m3";
this.details.factor = 10;
this.details.decimals = 2;
this.details.multiply = false;
this.details.colour = lightGreen["500"];
break;
case quack.MeasurementType.MEASUREMENT_TYPE_DUST_2UG:
this.details.label = "Dust <2.5um";
this.details.unit = "ug/m3";
this.details.factor = 10;
this.details.decimals = 2;
this.details.multiply = false;
this.details.colour = lightGreen["400"];
break;
case quack.MeasurementType.MEASUREMENT_TYPE_DUST_4UG:
this.details.label = "Dust <4um";
this.details.unit = "ug/m3";
this.details.factor = 10;
this.details.decimals = 2;
this.details.multiply = false;
this.details.colour = lightGreen["300"];
break;
case quack.MeasurementType.MEASUREMENT_TYPE_DUST_10UG:
this.details.label = "Dust <10um";
this.details.unit = "ug/m3";
this.details.factor = 10;
this.details.decimals = 2;
this.details.multiply = false;
this.details.colour = lightGreen["200"];
break;
case quack.MeasurementType.MEASUREMENT_TYPE_VOC_INDEX:
this.details.label = "VOC percent";
this.details.unit = "%";
this.details.factor = 10;
this.details.multiply = false;
this.details.colour = teal["400"];
break;
case quack.MeasurementType.MEASUREMENT_TYPE_NOX_INDEX:
this.details.label = "NOX percent";
this.details.unit = "%";
this.details.factor = 10;
this.details.multiply = false;
this.details.colour = teal["300"];
break;
case quack.MeasurementType.MEASUREMENT_TYPE_FREQUENCY:
this.details.label = "Frequency";
this.details.unit = "Hz";
this.details.colour = green["300"];
break;
case quack.MeasurementType.MEASUREMENT_TYPE_SINGLE_ACCELERATION_RMS:
case quack.MeasurementType.MEASUREMENT_TYPE_TOTAL_ACCELERATION_RMS:
this.details.label = "Acceleration";
this.details.unit = "m/s²";
this.details.colour = yellow["300"];
break;
}
}
isErrorMeasurement(measurement?: quack.Measurement | null): boolean {
if (this.details.errorValue === undefined || !measurement || this.details.path === "")
return false;
let value = extract<number>(measurement, this.details.path, 0);
return this.details.errorValue === value;
}
GetErrorValue() {
return this.details.errorValue;
}
GetUnit() {
return this.details.unit;
}
toDisplay(value: number): number {
let converted;
if (this.details.complexConversion !== null) {
converted = this.details.complexConversion(value, "toDisplay");
} else {
converted = this.details.multiply ? value * this.details.factor : value / this.details.factor;
}
return roundTo(converted, this.details.decimals);
}
toStored(value: number): number {
let converted;
if (this.details.complexConversion !== null) {
converted = this.details.complexConversion(value, "toStored");
} else {
converted = this.details.multiply ? value / this.details.factor : value * this.details.factor;
}
return converted;
}
forDisplay(measurement?: quack.Measurement | null): number {
if (!measurement) return 0;
if (this.details.path === "") return 0;
let storedValue = extract<number>(measurement, this.details.path, 0);
return this.toDisplay(storedValue);
}
convertWithUnits(value: number, unitMeasurement?: boolean): string {
let converted = unitMeasurement ? value : this.toDisplay(value);
if (
this.details.enumerations.length > 0 &&
converted >= 0 &&
this.details.enumerations.length > converted
) {
return this.details.enumerations[converted].label;
}
return (
converted.toFixed(this.details.decimals) +
(this.details.spacer ? " " : "") +
this.details.unit
);
}
convertWithoutUnits(value: number, unitMeasurement?: boolean): string {
let converted = unitMeasurement ? value : this.toDisplay(value);
if (
this.details.enumerations.length > 0 &&
converted >= 0 &&
this.details.enumerations.length > converted
) {
return this.details.enumerations[converted].label;
}
return converted.toFixed(this.details.decimals);
}
withUnits(measurement: quack.Measurement): string {
return this.convertWithUnits(extract(measurement, this.details.path, 0));
}
withoutUnits(measurement: quack.Measurement): string {
return this.convertWithoutUnits(extract(measurement, this.details.path, 0));
}
type(): quack.MeasurementType {
return this.measurementType;
}
label(): string {
return this.details.label;
}
unit(): string {
return this.details.unit;
}
colour(measurement?: quack.Measurement): any {
if (measurement) {
let value = this.forDisplay(measurement);
if (
this.details.enumerations.length > 0 &&
value >= 0 &&
this.details.enumerations.length > value
) {
return this.details.enumerations[value].colour;
}
}
return this.details.colour;
}
nodeDetails(): NodeDetails | undefined {
return this.details.nodeDetails;
}
graph(): GraphType {
return this.details.graph;
}
enumerations(): string[] {
return this.details.enumerations.map(e => e.label);
}
min(): number {
return this.details.min;
}
max(): number {
return this.details.max;
}
step(): number {
return this.details.step;
}
decimals(): number {
return this.details.decimals;
}
}
export function describeMeasurement(
measurementType: quack.MeasurementType | null | undefined,
componentType: quack.ComponentType | null | undefined = quack.ComponentType
.COMPONENT_TYPE_INVALID,
componentSubtype: number = 0,
product?: pond.DeviceProduct
): MeasurementDescriber {
measurementType = measurementType
? measurementType
: quack.MeasurementType.MEASUREMENT_TYPE_INVALID;
componentType = componentType ? componentType : quack.ComponentType.COMPONENT_TYPE_INVALID;
return new MeasurementDescriber(measurementType, componentType, componentSubtype, product);
}