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

This commit is contained in:
Noor 2025-07-31 10:26:04 -06:00
commit 7e821cf2d6
20 changed files with 209 additions and 75 deletions

4
package-lock.json generated
View file

@ -42,7 +42,7 @@
"mui-tel-input": "^7.0.0", "mui-tel-input": "^7.0.0",
"notistack": "^3.0.1", "notistack": "^3.0.1",
"openweathermap-ts": "^1.2.10", "openweathermap-ts": "^1.2.10",
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#libracart", "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#dev",
"query-string": "^9.2.1", "query-string": "^9.2.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-beautiful-dnd": "^13.1.1", "react-beautiful-dnd": "^13.1.1",
@ -10911,7 +10911,7 @@
}, },
"node_modules/protobuf-ts": { "node_modules/protobuf-ts": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#e1a765ee24fd1c6e374fd6d7a21edb82feb45c6f", "resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#46df972192510aa2aec201100382063607535a66",
"dependencies": { "dependencies": {
"protobufjs": "^6.8.8" "protobufjs": "^6.8.8"
} }

View file

@ -54,7 +54,7 @@
"mui-tel-input": "^7.0.0", "mui-tel-input": "^7.0.0",
"notistack": "^3.0.1", "notistack": "^3.0.1",
"openweathermap-ts": "^1.2.10", "openweathermap-ts": "^1.2.10",
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#libracart", "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#dev",
"query-string": "^9.2.1", "query-string": "^9.2.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-beautiful-dnd": "^13.1.1", "react-beautiful-dnd": "^13.1.1",

View file

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

View file

@ -169,6 +169,7 @@ export default function ComponentSettings(props: Props) {
const [removeDialogOpen, setRemoveDialogOpen] = useState(false); const [removeDialogOpen, setRemoveDialogOpen] = useState(false);
const [formComponent, setFormComponent] = useState<Component>(new Component()); const [formComponent, setFormComponent] = useState<Component>(new Component());
const [cableID, setCableID] = useState(0); const [cableID, setCableID] = useState(0);
const [expansionLine, setExpansionLine] = useState(0);
const [overlayIndex, setOverlayIndex] = useState(0); const [overlayIndex, setOverlayIndex] = useState(0);
const [overlayColourDialog, setOverlayCoulourDialog] = useState(false); const [overlayColourDialog, setOverlayCoulourDialog] = useState(false);
const [tabVal, setTabVal] = useState(0); const [tabVal, setTabVal] = useState(0);
@ -222,6 +223,9 @@ export default function ComponentSettings(props: Props) {
const isFormValid = () => { const isFormValid = () => {
//let { component } = form; //let { component } = form;
let type = or(formComponent.settings.type, ""); let type = or(formComponent.settings.type, "");
if(supportsExpansion() && expansionLine === 0){
return false
}
return isComponentTypeValid(type) && isAddressValid(formComponent); return isComponentTypeValid(type) && isAddressValid(formComponent);
}; };
@ -238,7 +242,6 @@ export default function ComponentSettings(props: Props) {
componentType: quack.ComponentType componentType: quack.ComponentType
): number[] => { ): number[] => {
let positions = availablePositions.get(addressType); let positions = availablePositions.get(addressType);
console.log(positions)
if (!positions) return []; if (!positions) return [];
switch (addressType) { switch (addressType) {
case quack.AddressType.ADDRESS_TYPE_I2C: case quack.AddressType.ADDRESS_TYPE_I2C:
@ -306,6 +309,7 @@ export default function ComponentSettings(props: Props) {
const component = formComponent; const component = formComponent;
//component.settings.calibrationCoefficient = Number(form.coefficient); //component.settings.calibrationCoefficient = Number(form.coefficient);
if (cableID > 0) component.settings.addressType = cableID + 8; if (cableID > 0) component.settings.addressType = cableID + 8;
component.settings.expansionLine = expansionLine
componentAPI componentAPI
.add(device.id(), component.settings, as) .add(device.id(), component.settings, as)
.then((_response: any) => { .then((_response: any) => {
@ -372,10 +376,10 @@ export default function ComponentSettings(props: Props) {
let ext = extension(type, subtype); let ext = extension(type, subtype);
formComponent.settings.type = type; formComponent.settings.type = type;
formComponent.settings.subtype = subtype; formComponent.settings.subtype = subtype;
formComponent.settings.addressType = getAddressTypes( formComponent.settings.addressType = or(addressTypeRestriction, getAddressTypes(
formComponent.settings.type, formComponent.settings.type,
formComponent.settings.subtype formComponent.settings.subtype
)[0]; )[0]);
formComponent.settings.address = or( formComponent.settings.address = or(
getAvailablePositions(formComponent.settings.addressType, formComponent.settings.type)[0], getAvailablePositions(formComponent.settings.addressType, formComponent.settings.type)[0],
Component.create().settings.address Component.create().settings.address
@ -398,11 +402,19 @@ export default function ComponentSettings(props: Props) {
}; };
const handlePositionChanged = (event: any) => { const handlePositionChanged = (event: any) => {
setCableID(0)
setExpansionLine(0)
let f = cloneDeep(formComponent); let f = cloneDeep(formComponent);
f.settings.address = event.target.value //split the string
.toString() let split: string[] = event.target.value.toString().split(":")
.split(":") // pop the addres off of the end of the array
.pop(); f.settings.address = parseInt(split.pop() ?? "0")
// pop the address type out of the array next
f.settings.addressType = parseInt(split.pop() ?? "0")
// f.settings.address = event.target.value
// .toString()
// .split(":")
// .pop();
setFormComponent(f); setFormComponent(f);
}; };
@ -413,7 +425,6 @@ export default function ComponentSettings(props: Props) {
for (let i = 0; i < addressTypes.length; i++) { for (let i = 0; i < addressTypes.length; i++) {
let addressType = addressTypes[i]; let addressType = addressTypes[i];
let availablePositions = getAvailablePositions(addressType, type); let availablePositions = getAvailablePositions(addressType, type);
console.log(availablePositions)
availableMenuItemPositions.push( availableMenuItemPositions.push(
<MenuItem key={addressType} divider disabled> <MenuItem key={addressType} divider disabled>
@ -490,6 +501,21 @@ export default function ComponentSettings(props: Props) {
); );
}; };
const isCableComponent = () => {
return (formComponent.settings.type === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE ||
formComponent.settings.type ===
quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE ||
formComponent.settings.type === quack.ComponentType.COMPONENT_TYPE_PRESSURE_CABLE ||
(formComponent.settings.type === quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE &&
formComponent.subType() ===
quack.CapacitorCableSubtype.CAPACITOR_CABLE_SUBTYPE_FROG))
}
const supportsExpansion = () => {
return (formComponent.settings.type === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE &&
formComponent.settings.addressType === quack.AddressType.ADDRESS_TYPE_I2C)
}
const addForm = () => { const addForm = () => {
return ( return (
<DialogContent> <DialogContent>
@ -543,14 +569,8 @@ export default function ComponentSettings(props: Props) {
formComponent.settings.subtype formComponent.settings.subtype
)} )}
</TextField> </TextField>
{(formComponent.settings.type === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE || {supportsExpansion() && setExpLine()}
formComponent.settings.type === {(isCableComponent() && !supportsExpansion())&& setComponentAddrType()}
quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE ||
formComponent.settings.type === quack.ComponentType.COMPONENT_TYPE_PRESSURE_CABLE ||
(formComponent.settings.type === quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE &&
formComponent.subType() ===
quack.CapacitorCableSubtype.CAPACITOR_CABLE_SUBTYPE_FROG)) &&
setComponentAddrType()}
</React.Fragment> </React.Fragment>
) : activeStep === 1 ? ( ) : activeStep === 1 ? (
<ComponentForm <ComponentForm
@ -582,6 +602,28 @@ export default function ComponentSettings(props: Props) {
</DialogContent> </DialogContent>
); );
}; };
const setExpLine = () => {
return (
<TextField
label="Expansion Line"
type="number"
margin="normal"
error={expansionLine < 1 || expansionLine > 12}
fullWidth
variant="outlined"
value={expansionLine}
helperText="Enter line the cable is connected to on your expander"
onChange={e => {
let number = parseInt(e.target.value);
if (number < 0 || isNaN(number)) number = 0;
if (number > 12) number = 12;
setExpansionLine(number);
}}
/>
);
};
const setComponentAddrType = () => { const setComponentAddrType = () => {
return ( return (
<TextField <TextField

View file

@ -198,16 +198,23 @@ export default function DeviceWizard(props: Props) {
/** /**
* function that restricts the pin availabilty in the availability map to the pin of the port that was selected * function that restricts the pin availabilty in the availability map to the pin of the port that was selected
* does nothing for I2C ports as the restrictions for that are handled by the component type
* @param port port that was selected * @param port port that was selected
* @param availability availability map of the device * @param availability availability map of the device
* @returns modified availability map * @returns modified availability map
*/ */
const adjustAvailablePositions = (port: PortInformation, availability: DeviceAvailabilityMap) => { const adjustAvailablePositions = (port: PortInformation, availability: DeviceAvailabilityMap) => {
let currentAvailability = availability; let currentAvailability = availability;
console.log(port)
switch (port.addressType) { switch (port.addressType) {
case quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY: case quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY:
currentAvailability.set(port.addressType, [{ address: port.address, label: port.label }]); currentAvailability.set(port.addressType, [{ address: port.address, label: port.label }]);
//since we now have a component type that can be pins or i2c need to remove i2c options if they selected a pin port
currentAvailability.set(quack.AddressType.ADDRESS_TYPE_I2C, new Map());
break;
case quack.AddressType.ADDRESS_TYPE_I2C:
//since we now have a component type that can be pins or i2c need to remove pin options if they selected the i2c port
currentAvailability.set(quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY, []);
break;
} }
return currentAvailability; return currentAvailability;
}; };

View file

@ -24,11 +24,14 @@ interface CompStep {
completed?: boolean; completed?: boolean;
} }
let i2cBlacklistAddresses: number[] = [0x70]
export default function DeviceScannedComponents(props: Props){ export default function DeviceScannedComponents(props: Props){
const {scannedComponents, device, availablePositions, availableOffsets, refreshCallback} = props const {scannedComponents, device, availablePositions, availableOffsets, refreshCallback} = props
const compAPI = useComponentAPI(); const compAPI = useComponentAPI();
const deviceAPI = useDeviceAPI() const deviceAPI = useDeviceAPI()
const [scannedI2C, setScannedI2C] = useState<pond.DetectI2C>() const [scannedI2C, setScannedI2C] = useState<pond.DetectI2C>() //the unmodified scan of addresses
const [validCompAddresses, setValidComponentAddresses] = useState<quack.AddressData[]>([]) //the filtered array of address data
const [components, setComponents] = useState<Component[]>([]) const [components, setComponents] = useState<Component[]>([])
const [steps, setSteps] = useState<CompStep[]>([]); const [steps, setSteps] = useState<CompStep[]>([]);
const { error, success } = useSnackbar(); const { error, success } = useSnackbar();
@ -59,6 +62,19 @@ export default function DeviceScannedComponents(props: Props){
setSteps(steps) setSteps(steps)
},[components]) },[components])
useEffect(()=>{
let valid: quack.AddressData[] = []
//filter the address data
scannedI2C?.settings?.foundAddresses.forEach(addrData => {
if(!i2cBlacklistAddresses.includes(addrData.address)){
if(!(addrData.address === 0x71 && addrData.expansionLine === undefined)){
valid.push(addrData)
}
}
})
setValidComponentAddresses(valid)
},[scannedI2C])
const stepper = () => { const stepper = () => {
return ( return (
<Stepper nonLinear activeStep={currentStep} style={{ width: "100%" }}> <Stepper nonLinear activeStep={currentStep} style={{ width: "100%" }}>
@ -205,9 +221,9 @@ export default function DeviceScannedComponents(props: Props){
</Typography> </Typography>
<Button variant="contained" color="primary" onClick={()=>{removeScan(scannedI2C.key)}}>Clear Scan</Button> <Button variant="contained" color="primary" onClick={()=>{removeScan(scannedI2C.key)}}>Clear Scan</Button>
</Box> </Box>
{scannedI2C.settings?.foundAddresses && scannedI2C.settings.foundAddresses.length > 0 ? scannedI2C?.settings?.foundAddresses.map((addr, index) => { {validCompAddresses.length > 0 ? validCompAddresses.map((addr, index) => {
return ( return (
<ScannedI2C key={index} sensorNum={index+1} decimalAddress={addr} deviceProduct={device.settings.product} componentSelectionCallback={componentSelection} availablePositions={availablePositions.get(quack.AddressType.ADDRESS_TYPE_I2C) ?? []}/> <ScannedI2C key={index} sensorNum={index+1} addressData={addr} deviceProduct={device.settings.product} componentSelectionCallback={componentSelection} availablePositions={availablePositions.get(quack.AddressType.ADDRESS_TYPE_I2C) ?? []}/>
) )
}) : }) :
<Box sx={{ <Box sx={{

View file

@ -8,7 +8,7 @@ import { quack } from "protobuf-ts/quack";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
interface Props { interface Props {
decimalAddress: number addressData: quack.AddressData
deviceProduct: pond.DeviceProduct deviceProduct: pond.DeviceProduct
componentSelectionCallback: (component: Component[], checked: boolean) => void componentSelectionCallback: (component: Component[], checked: boolean) => void
availablePositions: DevicePositions availablePositions: DevicePositions
@ -16,7 +16,7 @@ interface Props {
} }
export default function ScannedI2C(props: Props){ export default function ScannedI2C(props: Props){
const {decimalAddress, deviceProduct, componentSelectionCallback, availablePositions, sensorNum} = props const {addressData, deviceProduct, componentSelectionCallback, availablePositions, sensorNum} = props
const [types, setTypes] = useState<quack.ComponentType[]>([]) const [types, setTypes] = useState<quack.ComponentType[]>([])
const [subtypeOptions, setSubtypeOptions] = useState<Array<Subtype>>([]) const [subtypeOptions, setSubtypeOptions] = useState<Array<Subtype>>([])
const [selectedPrimaryType, setSelectedPrimaryType] = useState<quack.ComponentType>(quack.ComponentType.COMPONENT_TYPE_INVALID) const [selectedPrimaryType, setSelectedPrimaryType] = useState<quack.ComponentType>(quack.ComponentType.COMPONENT_TYPE_INVALID)
@ -34,7 +34,7 @@ export default function ScannedI2C(props: Props){
if(i2cMap){ if(i2cMap){
i2cMap.forEach((val, key) => { i2cMap.forEach((val, key) => {
let addresses = val as number[] ?? [] let addresses = val as number[] ?? []
if(addresses.length > 0 && addresses.includes(decimalAddress)){ if(addresses.length > 0 && addresses.includes(addressData.address)){
types.push(key) types.push(key)
} }
}) })
@ -47,7 +47,7 @@ export default function ScannedI2C(props: Props){
checkAddressAvailable(types[0]) checkAddressAvailable(types[0])
} }
setTypes(types) setTypes(types)
},[decimalAddress, deviceProduct]) },[addressData, deviceProduct])
const buildSubtypeOptions = (compType: quack.ComponentType) => { const buildSubtypeOptions = (compType: quack.ComponentType) => {
let subtypes = getSubtypes(compType) let subtypes = getSubtypes(compType)
@ -69,7 +69,7 @@ export default function ScannedI2C(props: Props){
const checkAddressAvailable = (compType: quack.ComponentType) => { const checkAddressAvailable = (compType: quack.ComponentType) => {
let i2cMap = availablePositions as ComponentAvailabilityMap let i2cMap = availablePositions as ComponentAvailabilityMap
let compAddresses = i2cMap.get(compType) ?? [] let compAddresses = i2cMap.get(compType) ?? []
if (!compAddresses.includes(decimalAddress)){ if (!compAddresses.includes(addressData.address)){
setAddressInUse(true) setAddressInUse(true)
}else{ }else{
setAddressInUse(false) setAddressInUse(false)
@ -86,7 +86,10 @@ export default function ScannedI2C(props: Props){
primaryComponent.settings.type = selectedPrimaryType primaryComponent.settings.type = selectedPrimaryType
primaryComponent.settings.subtype = selectedPrimarySubtype primaryComponent.settings.subtype = selectedPrimarySubtype
primaryComponent.settings.addressType = quack.AddressType.ADDRESS_TYPE_I2C primaryComponent.settings.addressType = quack.AddressType.ADDRESS_TYPE_I2C
primaryComponent.settings.address = decimalAddress primaryComponent.settings.address = addressData.address
primaryComponent.settings.expansionLine = addressData.expansionLine
primaryComponent.settings.muxLine = addressData.muxLine
primaryComponent.settings.name = getFriendlyName(selectedPrimaryType, selectedPrimarySubtype) primaryComponent.settings.name = getFriendlyName(selectedPrimaryType, selectedPrimarySubtype)
toAdd.push(primaryComponent) toAdd.push(primaryComponent)
@ -161,9 +164,6 @@ export default function ScannedI2C(props: Props){
</Grid2> </Grid2>
</Grid2> </Grid2>
{
}
</React.Fragment> </React.Fragment>
: :
<Typography>Sensor Not Supported By Product</Typography> <Typography>Sensor Not Supported By Product</Typography>

View file

@ -67,18 +67,25 @@ export class Component {
return quack.ComponentID.fromObject({ return quack.ComponentID.fromObject({
type: this.settings.type, type: this.settings.type,
addressType: this.settings.addressType, addressType: this.settings.addressType,
address: this.settings.address address: this.settings.address,
expansionLine: this.settings.expansionLine,
muxLine: this.settings.muxLine
}); });
} }
public locationString(): string { public locationString(): string {
return ( let compositeLocation = or(this.settings.type, 0).toString() +
or(this.settings.type, 0).toString() +
"-" + "-" +
or(this.settings.addressType, 0).toString() + or(this.settings.addressType, 0).toString() +
"-" + "-" +
or(this.settings.address, 0).toString() or(this.settings.address, 0).toString()
); if(this.settings.expansionLine){
compositeLocation = compositeLocation + "-" + this.settings.expansionLine
}
if(this.settings.muxLine){
compositeLocation = compositeLocation + ":" + this.settings.muxLine
}
return compositeLocation;
} }
public type(): quack.ComponentType { public type(): quack.ComponentType {

View file

@ -42,11 +42,11 @@ const featureVersions: Map<string, FeatureVersionByPlatform> = new Map([
v2Cell: "N/A", v2Cell: "N/A",
v2WifiS3: "N/A", v2WifiS3: "N/A",
v2CellS3: "N/A", v2CellS3: "N/A",
v2CellBlack: "N/A", v2CellBlack: "2.1.6",
v2CellGreen: "N/A", v2CellGreen: "N/A",
v2WifiBlue: "N/A", v2WifiBlue: "2.1.6",
v2CellBlue: "N/A", v2CellBlue: "2.1.6",
v2EthBlue: "N/A" v2EthBlue: "2.1.6"
} }
] ]
]); ]);

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)*100) /100
});
});
}
}
return newVals; return newVals;
} }

View file

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

View file

@ -16,6 +16,7 @@ export const GetBinShapeDescribers = (): BinShapeDescriber[] => {
]; ];
}; };
// DEPRECATED -- the bon now knows its components from the relative object table
export const HasGrainCable = (bin?: pond.BinSettings): boolean => { export const HasGrainCable = (bin?: pond.BinSettings): boolean => {
if (bin && bin.deviceComponents) { if (bin && bin.deviceComponents) {
bin.deviceComponents.forEach(dc => { bin.deviceComponents.forEach(dc => {

View file

@ -23,7 +23,9 @@ export function getComponentIDString(component?: Component): string {
? componentIDToString({ ? componentIDToString({
type: component.settings.type, type: component.settings.type,
addressType: component.settings.addressType, addressType: component.settings.addressType,
address: component.settings.address address: component.settings.address,
expansionLine: component.settings.expansionLine,
muxLine: component.settings.muxLine
}) })
: "0-0-0"; : "0-0-0";
} }
@ -40,13 +42,18 @@ export function componentIDToString(componentID?: quack.IComponentID | null): st
if (!componentID) { if (!componentID) {
return "0-0-0"; return "0-0-0";
} }
return ( let compositeLocation = or(componentID.type, 0).toString() +
or(componentID.type, 0).toString() +
"-" + "-" +
or(componentID.addressType, 0).toString() + or(componentID.addressType, 0).toString() +
"-" + "-" +
or(componentID.address, 0).toString() or(componentID.address, 0).toString()
); if(componentID.expansionLine){
compositeLocation = compositeLocation + "-" + componentID.expansionLine
}
if(componentID.muxLine){
compositeLocation = compositeLocation + ":" + componentID.muxLine
}
return compositeLocation;
} }
export function stringToComponentId(componentIDString: string): quack.ComponentID { export function stringToComponentId(componentIDString: string): quack.ComponentID {

View file

@ -146,7 +146,7 @@ export interface ComponentTypeExtension {
interactionResultTypes: Array<quack.InteractionResultType>; interactionResultTypes: Array<quack.InteractionResultType>;
states: Array<string>; states: Array<string>;
measurements: Array<ComponentMeasurement>; measurements: Array<ComponentMeasurement>;
measurementSummary: Function; //Deprecated: this summary used the old measurement structure measurementSummary?: Function; //Deprecated: this summary used the old measurement structure
unitMeasurementSummary: ( unitMeasurementSummary: (
measurements: convertedUnitMeasurement, measurements: convertedUnitMeasurement,
excludedNodes?: number[] excludedNodes?: number[]
@ -382,7 +382,8 @@ export async function getMeasurementSummary(
measurement: quack.IMeasurement, measurement: quack.IMeasurement,
filters: GraphFilters filters: GraphFilters
): Promise<Array<Summary>> { ): 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) => { const validNodes = (nodeVals: number[], filters?: GraphFilters) => {

View file

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

View file

@ -176,7 +176,7 @@ export function GrainCable(subtype: number = 0): ComponentTypeExtension {
isSource: true, isSource: true,
isArray: true, isArray: true,
isCalibratable: false, isCalibratable: false,
addressTypes: [quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY], addressTypes: [quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY, quack.AddressType.ADDRESS_TYPE_I2C],
interactionResultTypes: [], interactionResultTypes: [],
states: [], states: [],
measurements: [ measurements: [

View file

@ -60,7 +60,8 @@ const DefaultAvailability: DeviceAvailabilityMap = new Map<quack.AddressType, De
[quack.ComponentType.COMPONENT_TYPE_CAPACITANCE, [0x50]], [quack.ComponentType.COMPONENT_TYPE_CAPACITANCE, [0x50]],
[quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE, [0x50]], [quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE, [0x50]],
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]], [quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]],
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, [0x2a]] [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.AddressType.ADDRESS_TYPE_DAC, [0, 1]], [quack.AddressType.ADDRESS_TYPE_DAC, [0, 1]],
@ -103,7 +104,8 @@ export class DeviceAvailability {
ClaimAddress( ClaimAddress(
addressType: quack.AddressType, addressType: quack.AddressType,
componentType: quack.ComponentType, componentType: quack.ComponentType,
address: number address: number,
expansionLine?: number
) { ) {
let offset = addressType - 8; let offset = addressType - 8;
if (offset > 0) addressType = addressType - (7 + offset); if (offset > 0) addressType = addressType - (7 + offset);
@ -127,6 +129,9 @@ export class DeviceAvailability {
break; break;
case quack.AddressType.ADDRESS_TYPE_I2C: case quack.AddressType.ADDRESS_TYPE_I2C:
case quack.AddressType.ADDRESS_TYPE_SPI: case quack.AddressType.ADDRESS_TYPE_SPI:
if(expansionLine){
break;
}
let addressTypePositions = cloneDeep( let addressTypePositions = cloneDeep(
this.availability.get(addressType) as ComponentAvailabilityMap this.availability.get(addressType) as ComponentAvailabilityMap
); );
@ -171,7 +176,8 @@ export function FindAvailablePositions(
available.ClaimAddress( available.ClaimAddress(
component.settings.addressType, component.settings.addressType,
component.settings.type, component.settings.type,
or(component.settings.address, 0) or(component.settings.address, 0),
component.settings.expansionLine
); );
} }
}); });

View file

@ -450,8 +450,9 @@ export class MeasurementDescriber {
this.details.max = 100000; this.details.max = 100000;
break; break;
case quack.MeasurementType.MEASUREMENT_TYPE_SPEED: case quack.MeasurementType.MEASUREMENT_TYPE_SPEED:
let speedUnit = getDistanceUnit()
this.details.label = "Speed"; 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.colour = green["500"];
this.details.path = "edgeTriggered.rises"; this.details.path = "edgeTriggered.rises";
this.details.max = 500; this.details.max = 500;

View file

@ -246,12 +246,13 @@ export const BindaptV2MonitorAvailability: DeviceAvailabilityMap = new Map<
[ [
quack.AddressType.ADDRESS_TYPE_I2C, quack.AddressType.ADDRESS_TYPE_I2C,
new Map<quack.ComponentType, number[]>([ new Map<quack.ComponentType, number[]>([
//[quack.ComponentType.COMPONENT_TYPE_PRESSURE, [0x18]], [quack.ComponentType.COMPONENT_TYPE_PRESSURE, [0x18]],
[quack.ComponentType.COMPONENT_TYPE_DHT, [0x40]], [quack.ComponentType.COMPONENT_TYPE_DHT, [0x40]],
// [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]], //component type deprecated? // [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]], //component type deprecated?
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]], [quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]], [quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]] [quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]],
[quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE, [0x71]]
]) ])
], ],
[quack.AddressType.ADDRESS_TYPE_POWER, [0]], [quack.AddressType.ADDRESS_TYPE_POWER, [0]],
@ -278,12 +279,13 @@ export const BindaptV2AutomateAvailability: DeviceAvailabilityMap = new Map<
[ [
quack.AddressType.ADDRESS_TYPE_I2C, quack.AddressType.ADDRESS_TYPE_I2C,
new Map<quack.ComponentType, number[]>([ new Map<quack.ComponentType, number[]>([
//[quack.ComponentType.COMPONENT_TYPE_PRESSURE, [0x18]], [quack.ComponentType.COMPONENT_TYPE_PRESSURE, [0x18]],
[quack.ComponentType.COMPONENT_TYPE_DHT, [0x40]], [quack.ComponentType.COMPONENT_TYPE_DHT, [0x40]],
// [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]], //component type deprecated? // [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]], //component type deprecated?
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]], [quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]], [quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]] [quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]],
[quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE, [0x71]]
]) ])
], ],
[quack.AddressType.ADDRESS_TYPE_POWER, [0]], [quack.AddressType.ADDRESS_TYPE_POWER, [0]],

View file

@ -22,7 +22,7 @@ export const MiVentV1Availability: DeviceAvailabilityMap = new Map<
[quack.ComponentType.COMPONENT_TYPE_PRESSURE, [0x18]], [quack.ComponentType.COMPONENT_TYPE_PRESSURE, [0x18]],
[quack.ComponentType.COMPONENT_TYPE_DHT, [0x40]], [quack.ComponentType.COMPONENT_TYPE_DHT, [0x40]],
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]], [quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]],
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, [0x2a]] [quack.ComponentType.COMPONENT_TYPE_AIRFLOW, [0x6c]]
]) ])
], ],
[quack.AddressType.ADDRESS_TYPE_POWER, [0]], [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_PRESSURE, [0x18]],
[quack.ComponentType.COMPONENT_TYPE_DHT, [0x40]], [quack.ComponentType.COMPONENT_TYPE_DHT, [0x40]],
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]], [quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]],
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, [0x2a]] [quack.ComponentType.COMPONENT_TYPE_AIRFLOW, [0x6c]]
]) ])
], ],
[quack.AddressType.ADDRESS_TYPE_POWER, [0]], [quack.AddressType.ADDRESS_TYPE_POWER, [0]],