Merge branch 'i2c_detect' into staging_environment

This commit is contained in:
csawatzky 2025-10-30 16:50:11 -06:00
commit 8fd63e249d
8 changed files with 69 additions and 21 deletions

View file

@ -36,6 +36,7 @@ import {
} from "pbHelpers/AddressType"; } from "pbHelpers/AddressType";
import { import {
extension, extension,
FilterSubtypeI2C,
getAddressTypes, getAddressTypes,
GetComponentTypeOptions, GetComponentTypeOptions,
getFriendlyName, getFriendlyName,
@ -240,7 +241,8 @@ export default function ComponentSettings(props: Props) {
const getAvailablePositions = ( const getAvailablePositions = (
addressType: quack.AddressType, addressType: quack.AddressType,
componentType: quack.ComponentType componentType: quack.ComponentType,
subtype: number
): number[] => { ): number[] => {
let positions = availablePositions.get(addressType); let positions = availablePositions.get(addressType);
if (!positions) return []; if (!positions) return [];
@ -249,7 +251,8 @@ export default function ComponentSettings(props: Props) {
case quack.AddressType.ADDRESS_TYPE_SPI: case quack.AddressType.ADDRESS_TYPE_SPI:
let componentPositions; let componentPositions;
if (positions) { if (positions) {
componentPositions = (positions as ComponentAvailabilityMap).get(componentType); componentPositions = (positions as ComponentAvailabilityMap).get(componentType); //gets the addresses that are not claimed yet
componentPositions = FilterSubtypeI2C(componentType, subtype, componentPositions as number[]) //filters the I2C addresses for valid ones for the subtype
} }
return componentPositions ? (componentPositions as number[]) : []; return componentPositions ? (componentPositions as number[]) : [];
case quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY: case quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY:
@ -264,7 +267,8 @@ export default function ComponentSettings(props: Props) {
if (mode === "add") { if (mode === "add") {
let positions = getAvailablePositions( let positions = getAvailablePositions(
component.settings.addressType, component.settings.addressType,
component.settings.type component.settings.type,
component.settings.subtype
); );
availablePosition = positions ? positions.length > 0 : false; availablePosition = positions ? positions.length > 0 : false;
} }
@ -285,7 +289,7 @@ export default function ComponentSettings(props: Props) {
component.settings.subtype component.settings.subtype
); );
for (let i = 0; i < addressTypes.length; i++) { for (let i = 0; i < addressTypes.length; i++) {
if (getAvailablePositions(addressTypes[i], component.settings.type).length > 0) { if (getAvailablePositions(addressTypes[i], component.settings.type, component.settings.subtype).length > 0) {
return true; return true;
} }
} }
@ -383,7 +387,7 @@ export default function ComponentSettings(props: Props) {
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, formComponent.settings.subtype)[0],
Component.create().settings.address Component.create().settings.address
); );
formComponent.settings.name = option.label; formComponent.settings.name = option.label;
@ -426,7 +430,7 @@ export default function ComponentSettings(props: Props) {
let availableMenuItemPositions = []; let availableMenuItemPositions = [];
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, subtype);
availableMenuItemPositions.push( availableMenuItemPositions.push(
<MenuItem key={addressType} divider disabled> <MenuItem key={addressType} divider disabled>

View file

@ -40,6 +40,7 @@ export default function DeviceScannedComponents(props: Props){
const [openDialog, setOpenDialog] = useState(false); const [openDialog, setOpenDialog] = useState(false);
useEffect(()=>{ useEffect(()=>{
//console.log(scannedComponents)
if (scannedComponents.i2c) setScannedI2C(scannedComponents.i2c) if (scannedComponents.i2c) setScannedI2C(scannedComponents.i2c)
//makes the array empty for testing //makes the array empty for testing
// if (scannedComponents.i2c) { // if (scannedComponents.i2c) {
@ -65,13 +66,16 @@ export default function DeviceScannedComponents(props: Props){
useEffect(()=>{ useEffect(()=>{
let valid: quack.AddressData[] = [] let valid: quack.AddressData[] = []
//filter the address data //filter the address data
scannedI2C?.settings?.foundAddresses.forEach(addrData => { let addr = scannedI2C?.settings?.foundAddresses
if(addr){
addr.forEach(addrData => {
if(!i2cBlacklistAddresses.includes(addrData.address)){ if(!i2cBlacklistAddresses.includes(addrData.address)){
if(!(addrData.address === 0x71 && addrData.expansionLine === undefined)){ if(!(addrData.address === 0x71 && addrData.expansionLine === undefined)){
valid.push(addrData) valid.push(addrData)
} }
} }
}) })
}
setValidComponentAddresses(valid) setValidComponentAddresses(valid)
},[scannedI2C]) },[scannedI2C])
@ -223,7 +227,7 @@ export default function DeviceScannedComponents(props: Props){
</Box> </Box>
{validCompAddresses.length > 0 ? validCompAddresses.map((addr, index) => { {validCompAddresses.length > 0 ? validCompAddresses.map((addr, index) => {
return ( return (
<ScannedI2C key={index} sensorNum={index+1} addressData={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) ?? new Map<quack.ComponentType, number[]>()}/>
) )
}) : }) :
<Box sx={{ <Box sx={{

View file

@ -107,6 +107,7 @@ export default function ScannedI2C(props: Props){
return ( return (
<Box sx={{marginY: 1}}> <Box sx={{marginY: 1}}>
{sensorNum && <Typography>Sensor {sensorNum}</Typography>} {sensorNum && <Typography>Sensor {sensorNum}</Typography>}
<Typography variant="caption">{addressData.expansionLine !== 0 && "Expansion Line: " + addressData.expansionLine}</Typography>
{types.length > 0 ? {types.length > 0 ?
<React.Fragment> <React.Fragment>
<Grid2 container direction="row" alignItems="center" justifyContent="space-between"> <Grid2 container direction="row" alignItems="center" justifyContent="space-between">
@ -145,7 +146,7 @@ export default function ScannedI2C(props: Props){
}} }}
select> select>
{subtypeOptions.map(s => ( {subtypeOptions.map(s => (
<MenuItem value={s.key}>{s.friendlyName}</MenuItem> <MenuItem key={s.key} value={s.key}>{s.friendlyName}</MenuItem>
))} ))}
</TextField> </TextField>
} }

View file

@ -167,7 +167,7 @@ export default function DevicePage() {
} }
const loadPortScan = () => { const loadPortScan = () => {
deviceAPI.listFoundComponents(device.id()) deviceAPI.listFoundComponents(parseInt(deviceID))
.then(resp => { .then(resp => {
if (resp.data.foundComponents?.i2c){ if (resp.data.foundComponents?.i2c){
setScannedAddresses(resp.data.foundComponents ?? undefined) setScannedAddresses(resp.data.foundComponents ?? undefined)

View file

@ -164,6 +164,10 @@ export interface ComponentTypeExtension {
filters?: GraphFilters filters?: GraphFilters
) => LineChartData; ) => LineChartData;
secondaryComponentSettings?: () => pond.ComponentSettings[] secondaryComponentSettings?: () => pond.ComponentSettings[]
//(only for I2C) possibly add an optional map here that has a number (subtype) as the key and the addresses available for that subtype
//if the map does not exist then just use the array from the device availability,
//if the map does exist filter the availability after claims to find matching address between them and use that
subtypeI2CMap?: Map<number, number[]>
} }
export interface Summary { export interface Summary {
@ -1090,3 +1094,31 @@ export const GetNumNodesFromUnitMeasurement = (unitMeasurement: UnitMeasurement)
} }
return nodes; return nodes;
}; };
export const FilterSubtypeI2C = (
componentType: quack.ComponentType,
subtype: number,
positions: number[]
) => {
console.log("Filter I2C")
console.log(positions)
let filtered: number[] = []
//create an extension using the type and subtype
let ext = extension(componentType, subtype)
//if the extension has a subtype map
if (ext.subtypeI2CMap !== undefined){
//check if any of the position passed in match to the map values according to the subtype
let subtypePositions = ext.subtypeI2CMap.get(subtype)
if(subtypePositions !== undefined){
positions.forEach(position => {
if(subtypePositions.includes(position)){
filtered.push(position)
}
})
}
}else{
filtered = positions
}
//return any matches between the arrays
return filtered
}

View file

@ -95,6 +95,11 @@ export function Lidar(subtype: number = 0): ComponentTypeExtension {
minMeasurementPeriodMs: 1000, minMeasurementPeriodMs: 1000,
icon: (theme?: "light" | "dark"): string | undefined => { icon: (theme?: "light" | "dark"): string | undefined => {
return theme === "light" ? LidarSensorDarkIcon : LidarSensorLightIcon; return theme === "light" ? LidarSensorDarkIcon : LidarSensorLightIcon;
} },
subtypeI2CMap: new Map<number, number[]>([
[quack.LidarSubtype.LIDAR_SUBTYPE_NONE, [0x62]],
[quack.LidarSubtype.LIDAR_SUBTYPE_LONG_DISTANCE, [0x66]],
[quack.LidarSubtype.LIDAR_SUBTYPE_BENEWAKE_TF02W_MID_RANGE, [0x10]],
])
}; };
} }

View file

@ -5,6 +5,7 @@ import { GetProductAvailability } from "products/DeviceProduct";
import { pond } from "protobuf-ts/pond"; import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/quack"; import { quack } from "protobuf-ts/quack";
import { or } from "utils/types"; import { or } from "utils/types";
import { FilterSubtypeI2C } from "./ComponentType";
export type ComponentAvailabilityMap = Map<quack.ComponentType, number[]>; export type ComponentAvailabilityMap = Map<quack.ComponentType, number[]>;
export type DevicePositions = number[] | ComponentAvailabilityMap | ConfigurablePin[]; export type DevicePositions = number[] | ComponentAvailabilityMap | ConfigurablePin[];
@ -47,16 +48,17 @@ const DefaultAvailability: DeviceAvailabilityMap = new Map<quack.AddressType, De
[quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY, DefaultPinArray], [quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY, DefaultPinArray],
[ [
quack.AddressType.ADDRESS_TYPE_I2C, quack.AddressType.ADDRESS_TYPE_I2C,
//this will contain all the possible addresses for a component type, if subtypes use specific addresses add a filter to the type describer, see lidar.ts for an example
new Map<quack.ComponentType, number[]>([ new Map<quack.ComponentType, number[]>([
[quack.ComponentType.COMPONENT_TYPE_PRESSURE, [0x18, 0x19, 0x1a]], [quack.ComponentType.COMPONENT_TYPE_PRESSURE, [0x18, 0x19, 0x1a]],
[quack.ComponentType.COMPONENT_TYPE_LIGHT, [0x29]], [quack.ComponentType.COMPONENT_TYPE_LIGHT, [0x29]],
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]], [quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
[quack.ComponentType.COMPONENT_TYPE_STEPPER_MOTOR, [0x14, 0x15, 0x16, 0x17]], [quack.ComponentType.COMPONENT_TYPE_STEPPER_MOTOR, [0x14, 0x15, 0x16, 0x17]],
[quack.ComponentType.COMPONENT_TYPE_PH, [0x40]], [quack.ComponentType.COMPONENT_TYPE_PH, [0x40]],
[quack.ComponentType.COMPONENT_TYPE_DHT, [0x40, 0x61]], //TODO temp fix, needs to be fixed to use channels similar to PH [quack.ComponentType.COMPONENT_TYPE_DHT, [0x40, 0x61]],
// [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_AIR_QUALITY, [0x58]], [quack.ComponentType.COMPONENT_TYPE_AIR_QUALITY, [0x58]],
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]], [quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62, 0x66, 0x10]],
[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]],

View file

@ -249,7 +249,7 @@ export const BindaptV2MonitorAvailability: 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_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, 0x66, 0x10]],
[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.ComponentType.COMPONENT_TYPE_GRAIN_CABLE, [0x71]]
@ -282,7 +282,7 @@ export const BindaptV2AutomateAvailability: 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_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, 0x66, 0x10]],
[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.ComponentType.COMPONENT_TYPE_GRAIN_CABLE, [0x71]]