Merge branch 'airflow' into node_exclusion_update

This commit is contained in:
csawatzky 2025-07-28 15:30:14 -06:00
commit 25fc5021fe
13 changed files with 107 additions and 31 deletions

2
package-lock.json generated
View file

@ -10911,7 +10911,7 @@
},
"node_modules/protobuf-ts": {
"version": "1.0.0",
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#83d9f47f0512161504cc82b52d850105807695b0",
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#dc29e71ec9598556c1b7cdff4dc02f74ecbac20c",
"dependencies": {
"protobufjs": "^6.8.8"
}

View file

@ -49,7 +49,7 @@ export default function BinsList(props: Props) {
//const scrollRef = useRef<any>(null);
const goToBin = (i: number) => {
let path = "/bins/" + bins[i].key();
let path = bins[i].key();
navigate(path, { state: {bin: bins[i]} });
};

View file

@ -482,7 +482,7 @@ export default function ComponentForm(props: Props) {
const updateCalibrationTypes = (event: any, index: number) => {
let f = cloneDeep(form);
f.component.settings.calibrations[index].type = event.target.value as quack.MeasurementType;
f.component.settings.calibrations[index].measurementType = event.target.value as quack.MeasurementType;
setForm(f);
};
@ -508,7 +508,7 @@ export default function ComponentForm(props: Props) {
if (dimensions !== undefined && dimensions !== null) {
dimensions.lengthCm = value;
} else {
dimensions = pond.Dimensions.create({
dimensions = quack.Dimensions.create({
heightCm: 0,
lengthCm: value,
widthCm: 0
@ -537,7 +537,7 @@ export default function ComponentForm(props: Props) {
if (dimensions !== undefined && dimensions !== null) {
dimensions.heightCm = value;
} else {
dimensions = pond.Dimensions.create({
dimensions = quack.Dimensions.create({
heightCm: value,
lengthCm: 0,
widthCm: 0
@ -566,7 +566,7 @@ export default function ComponentForm(props: Props) {
if (dimensions !== undefined && dimensions !== null) {
dimensions.widthCm = value;
} else {
dimensions = pond.Dimensions.create({
dimensions = quack.Dimensions.create({
heightCm: 0,
lengthCm: 0,
widthCm: value
@ -788,7 +788,7 @@ export default function ComponentForm(props: Props) {
// !isMeasurementTypeValid(interaction.settings.conditions[index].measurementType)
// }
disabled={!component.settings.calibrate}
value={calibration.type ?? quack.MeasurementType.MEASUREMENT_TYPE_INVALID}
value={calibration.measurementType ?? quack.MeasurementType.MEASUREMENT_TYPE_INVALID}
onChange={event => updateCalibrationTypes(event, i)}
autoFocus={false}
margin="normal"
@ -814,8 +814,8 @@ export default function ComponentForm(props: Props) {
f.coefficients.push("0");
f.offsets.push("0");
f.component.settings.calibrations.push(
pond.Calibration.create({
type: quack.MeasurementType.MEASUREMENT_TYPE_INVALID,
quack.Calibration.create({
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_INVALID,
calibrationOffset: 0,
calibrationCoefficient: 0
})

View file

@ -256,5 +256,15 @@ function unitConversion(
});
}
}
if (type === quack.MeasurementType.MEASUREMENT_TYPE_SPEED) {
if (user.settings.distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
newVals.forEach((val, i) => {
val.values.forEach((v, j) => {
//convert m/s to ft/m by multiplying by 196.9
newVals[i].values[j] = Math.round(v * 196.9)
});
});
}
}
return newVals;
}

View file

@ -81,6 +81,7 @@ import GrainBagList from "grainBag/grainBagList";
import BinYards from "bin/BinYards";
import ButtonGroup from "common/ButtonGroup";
import TeamDialog from "teams/TeamDialog";
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
// import { useHistory } from "react-router";
const useStyles = makeStyles((theme: Theme) => {
@ -311,6 +312,16 @@ export default function Bins(props: Props) {
}
}, [props.yardFilter]);
const getKeys = () => {
if (as) return undefined
return getContextKeys()
}
const getTypes = () => {
if (as) return undefined
return getContextTypes()
}
const loadBins = useCallback(() => {
//let filter = grainFilter;
let filter = yardFilter;
@ -325,7 +336,7 @@ export default function Bins(props: Props) {
setDisplayFert(false);
binAPI
.listBinsAndData(binsLimit, 0, order, orderBy, filter, as, false)
.listBinsAndData(binsLimit, 0, order, orderBy, filter, as, false, getKeys(), getTypes())
.then(resp => {
let grain: Bin[] = [];
let empty: Bin[] = [];
@ -623,8 +634,9 @@ export default function Bins(props: Props) {
preLoadedData={paginatedBins.bins}
rowClickFunction={data => {
let bin = data as Bin;
let path = "/bins/" + bin.key();
navigate(path, { state: { bin: bin }});
// let path = "bins/" + bin.key();
// navigate(path, { state: { bin: bin }});
navigate(bin.key(), { state: { bin: bin }, relative: "path"});
}}
customButtons={[
{

View file

@ -12,10 +12,10 @@ import { appendToUrl } from "navigation/Router";
import PageContainer from "pages/PageContainer";
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
import { pond } from "protobuf-ts/pond";
import { useSnackbar, useTeamAPI, useUserAPI } from "providers";
import { useGlobalState, useSnackbar, useTeamAPI, useUserAPI } from "providers";
import { useEffect, useState } from "react";
import { useLocation, useNavigate, useParams } from 'react-router-dom';
import { getSignatureAccentColour } from "services/whiteLabel";
import { getSignatureAccentColour, IsAdaptiveAgriculture, IsStreamline } from "services/whiteLabel";
import TeamActions from "teams/TeamActions";
import TeamKeyManager from "teams/TeamKeyManager";
import ObjectUsers from "user/ObjectUsers";
@ -88,6 +88,7 @@ export default function TeamPage() {
const [loadingUsers, setLoadingUsers] = useState(false)
const [userDialog, setUserDialog] = useState(false)
const teamKey = teamID ? teamID : "";
const [{ user }] = useGlobalState()
const getTeam = () => {
@ -213,6 +214,14 @@ export default function TeamPage() {
navigate(appendToUrl("groups"))
}
const toBins = () => {
// navigate(appendToUrl("bins"))
navigate("bins")
}
const isAg = IsAdaptiveAgriculture()
const isStreamline = IsStreamline()
return (
<PageContainer spacing={isMobile ? 0 : 2}>
<Box className={classes.container}>
@ -237,6 +246,7 @@ export default function TeamPage() {
isDialogOpen={userDialog}
closeDialogCallback={() => setUserDialog(false)}
refreshCallback={() => {}}
useImitation={false}
/>
<Grid2 container spacing={1}>
<Grid2 size={{ xs: 12, sm: 4 }}>
@ -255,6 +265,14 @@ export default function TeamPage() {
<ListItemButton onClick={toGroups}>
Groups
</ListItemButton>
{((isAg || isStreamline) || user.hasFeature("admin")) &&
<>
<Divider />
<ListItemButton onClick={toBins}>
Bins
</ListItemButton>
</>
}
<Divider />
</List>
</Card>

View file

@ -16,7 +16,7 @@ export const I2C: AddressTypeExtension = {
[quack.ComponentType.COMPONENT_TYPE_CAPACITANCE, 0x4f],
[quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE, 0x4f],
[quack.ComponentType.COMPONENT_TYPE_SEN5X, 0x68],
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, 0x29]
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, 0x6b]
]);
const offset = offsets.get(componentType);

View file

@ -146,7 +146,7 @@ export interface ComponentTypeExtension {
interactionResultTypes: Array<quack.InteractionResultType>;
states: Array<string>;
measurements: Array<ComponentMeasurement>;
measurementSummary: Function; //Deprecated: this summary used the old measurement structure
measurementSummary?: Function; //Deprecated: this summary used the old measurement structure
unitMeasurementSummary: (
measurements: convertedUnitMeasurement
) => Summary[];
@ -365,7 +365,8 @@ export async function getMeasurementSummary(
measurement: quack.IMeasurement,
filters: GraphFilters
): Promise<Array<Summary>> {
return extension(type, subtype).measurementSummary(measurement, filters);
let sumFunc = extension(type, subtype).measurementSummary
return sumFunc ? sumFunc(measurement, filters) : [];
}
const validNodes = (nodeVals: number[], filters?: GraphFilters) => {

View file

@ -1,14 +1,15 @@
import {
ComponentTypeExtension,
Summary,
simpleMeasurements,
simpleSummaries,
// simpleMeasurements,
// simpleSummaries,
unitMeasurementSummaries,
AreaChartData,
GraphFilters,
simpleAreaChartData,
LineChartData,
simpleLineChartData
simpleLineChartData,
ComponentMeasurement
} from "pbHelpers/ComponentType";
import PressureDarkIcon from "assets/components/pressureDark.png";
import PressureLightIcon from "assets/components/pressureLight.png";
@ -18,14 +19,46 @@ import { convertedUnitMeasurement } from "models/UnitMeasurement";
import { pond } from "protobuf-ts/pond";
export function Airflow(subtype: number = 0): ComponentTypeExtension {
let airflow = describeMeasurement(
let cfm = describeMeasurement(
quack.MeasurementType.MEASUREMENT_TYPE_CFM,
quack.ComponentType.COMPONENT_TYPE_AIRFLOW,
subtype
);
let velocity = describeMeasurement(
quack.MeasurementType.MEASUREMENT_TYPE_CFM,
quack.ComponentType.COMPONENT_TYPE_AIRFLOW,
subtype
);
let measurementTypes = [
{
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PPM,
label: cfm.label(),
colour: cfm.colour(),
graphType: cfm.graph()
} as ComponentMeasurement,
{
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_VOLTAGE,
label: velocity.label(),
colour: velocity.colour(),
graphType: velocity.graph()
} as ComponentMeasurement
];
return {
type: quack.ComponentType.COMPONENT_TYPE_AIRFLOW,
subtypes: [],
subtypes: [
{
key: quack.AirFlowSubtype.AIR_FLOW_SUBTYPE_PROSENSE,
value: "AIR_FLOW_SUBTYPE_PROSENSE",
friendlyName: "Prosense"
},
{
key: quack.AirFlowSubtype.AIR_FLOW_SUBTYPE_ULTRASONIC,
value: "AIR_FLOW_SUBTYPE_ULTRASONIC",
friendlyName: "Ultrasonic"
},
],
friendlyName: "Airflow",
description: "Measure the flow of air though a specified area",
isController: false,
@ -36,10 +69,10 @@ export function Airflow(subtype: number = 0): ComponentTypeExtension {
addressTypes: [quack.AddressType.ADDRESS_TYPE_I2C],
interactionResultTypes: [],
states: [],
measurements: simpleMeasurements(airflow),
measurementSummary: async function(measurement: quack.Measurement): Promise<Array<Summary>> {
return simpleSummaries(measurement, airflow);
},
measurements: measurementTypes,
// measurementSummary: async function(measurement: quack.Measurement): Promise<Array<Summary>> {
// return simpleSummaries(measurement, airflow);
// },
unitMeasurementSummary: (
measurements: convertedUnitMeasurement,
): Summary[] => {

View file

@ -60,7 +60,7 @@ const DefaultAvailability: DeviceAvailabilityMap = new Map<quack.AddressType, De
[quack.ComponentType.COMPONENT_TYPE_CAPACITANCE, [0x50]],
[quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE, [0x50]],
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]],
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, [0x2a]]
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, [0x6c]]
])
],
[quack.AddressType.ADDRESS_TYPE_DAC, [0, 1]],

View file

@ -450,8 +450,9 @@ export class MeasurementDescriber {
this.details.max = 100000;
break;
case quack.MeasurementType.MEASUREMENT_TYPE_SPEED:
let speedUnit = getDistanceUnit()
this.details.label = "Speed";
this.details.unit = "km/h";
this.details.unit = speedUnit === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m/s" : "ft/m";
this.details.colour = green["500"];
this.details.path = "edgeTriggered.rises";
this.details.max = 500;

View file

@ -22,7 +22,7 @@ export const MiVentV1Availability: 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, [0x2a]]
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, [0x6c]]
])
],
[quack.AddressType.ADDRESS_TYPE_POWER, [0]],
@ -52,7 +52,7 @@ 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, [0x2a]]
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, [0x6c]]
])
],
[quack.AddressType.ADDRESS_TYPE_POWER, [0]],

View file

@ -38,7 +38,8 @@ export default function AuthWrapper(props: Props) {
options.authorizationParams.login_hint = parsed.email.toString(); // prefill email
}
options.authorizationParams.redirect_uri = "https://" + url.hostname + "/signupCallback"
console.log(url)
options.authorizationParams.redirect_uri = url.origin + "/signupCallback"
console.log(options.authorizationParams.redirect_uri)
loginWithRedirect(options)