From c8105ef62486ccbb6aaa01bc406146710698a160 Mon Sep 17 00:00:00 2001 From: csawatzky Date: Fri, 27 Jun 2025 14:19:55 -0600 Subject: [PATCH] finished the card to detect i2c components and select ones to add --- src/component/ComponentSettings.tsx | 2 + .../autoDetect/DeviceScannedComponents.tsx | 163 +++++++++++++++--- src/device/autoDetect/ScannedI2C.tsx | 128 +++++++++----- src/pages/Device.tsx | 11 +- 4 files changed, 232 insertions(+), 72 deletions(-) diff --git a/src/component/ComponentSettings.tsx b/src/component/ComponentSettings.tsx index d762ee3..54653a2 100644 --- a/src/component/ComponentSettings.tsx +++ b/src/component/ComponentSettings.tsx @@ -238,6 +238,7 @@ export default function ComponentSettings(props: Props) { componentType: quack.ComponentType ): number[] => { let positions = availablePositions.get(addressType); + console.log(positions) if (!positions) return []; switch (addressType) { case quack.AddressType.ADDRESS_TYPE_I2C: @@ -412,6 +413,7 @@ export default function ComponentSettings(props: Props) { for (let i = 0; i < addressTypes.length; i++) { let addressType = addressTypes[i]; let availablePositions = getAvailablePositions(addressType, type); + console.log(availablePositions) availableMenuItemPositions.push( diff --git a/src/device/autoDetect/DeviceScannedComponents.tsx b/src/device/autoDetect/DeviceScannedComponents.tsx index e706da0..e07dd94 100644 --- a/src/device/autoDetect/DeviceScannedComponents.tsx +++ b/src/device/autoDetect/DeviceScannedComponents.tsx @@ -1,4 +1,4 @@ -import { Box, Card, DialogContent, FormControlLabel, Radio, RadioGroup, Step, StepLabel, Stepper } from "@mui/material"; +import { Box, Button, Card, DialogActions, DialogContent, DialogTitle, FormControlLabel, Grid2, Radio, RadioGroup, Step, StepLabel, Stepper, Typography } from "@mui/material"; import { cloneDeep } from "lodash"; import { getSubtypes, Subtype } from "pbHelpers/ComponentType"; import { pond, quack } from "protobuf-ts/pond"; @@ -7,10 +7,16 @@ import { useEffect, useState } from "react"; import ScannedI2C from "./ScannedI2C"; import ComponentForm from "component/ComponentForm"; import { Component, Device } from "models"; +import { DeviceAvailabilityMap, OffsetAvailabilityMap } from "pbHelpers/DeviceAvailability"; +import ResponsiveDialog from "common/ResponsiveDialog"; +import { useComponentAPI, useSnackbar } from "hooks"; interface Props { scannedComponents: pond.ComponentAddressMap device: Device + availablePositions: DeviceAvailabilityMap + availableOffsets: OffsetAvailabilityMap + refreshCallback: () => void } interface CompStep { @@ -19,12 +25,15 @@ interface CompStep { } export default function DeviceScannedComponents(props: Props){ - const {scannedComponents, device} = props + const {scannedComponents, device, availablePositions, availableOffsets, refreshCallback} = props + const compAPI = useComponentAPI(); const [scannedI2C, setScannedI2C] = useState() const [components, setComponents] = useState([]) const [steps, setSteps] = useState([]); + const { error, success } = useSnackbar(); const [currentStep, setCurrentStep] = useState(0) const [settingsValid, setSettingsValid] = useState(false); + const [openDialog, setOpenDialog] = useState(false); useEffect(()=>{ if (scannedComponents.i2c) setScannedI2C(scannedComponents.i2c) @@ -38,6 +47,7 @@ export default function DeviceScannedComponents(props: Props){ completed: false }) }) + setSteps(steps) },[components]) const stepper = () => { @@ -57,37 +67,136 @@ export default function DeviceScannedComponents(props: Props){ ); }; - const addComponentContent = () => { + const addComponents = () => { + let c: pond.MultiComponentSettings = pond.MultiComponentSettings.create(); + components.forEach(component => { + c.components.push(component.settings); + }); + compAPI + .addMultiComponents(device.id(), c) + .then(resp => { + success("Components added to Device"); + }) + .catch(err => { + error("One or more component failed to add"); + }) + .finally(() => { + refreshCallback(); + }); + }; + + const addComponentDialog = () => { return ( - - {stepper()} - { - components[currentStep].settings = component.settings; - setSettingsValid(isValid); - }} - /> - + {setOpenDialog(false)}}> + Adding Components + + {stepper()} + { + components[currentStep].settings = component.settings; + setSettingsValid(isValid); + }} + /> + + + + + + + + {currentStep !== 0 && ( + + )} + {currentStep !== steps.length - 1 && ( + + + + )} + + + + + ); }; + const componentSelection = (newComponent: Component, checked: boolean) => { + let cloneList = cloneDeep(components) + if(checked){ + //add the component to the list + cloneList.push(newComponent) + }else{ + //remove any components that match the component location: (type)-(addressType)-(address) + components.forEach((comp, i) => { + //check the components location against the one in the list + if(comp.locationString() === newComponent.locationString()){ + cloneList.splice(i, 1) + } + }) + } + setComponents(cloneList) + } + return ( - - {scannedI2C && - - I2C Components Found - {scannedI2C?.settings?.foundAddresses.map((addr, index) => { - return ( - {}} /> - ) - })} - - } - + + + {scannedI2C !== undefined && + + + + I2C Components Found + + + {scannedI2C?.settings?.foundAddresses.map((addr, index) => { + return ( + + ) + })} + + } + + + + + {addComponentDialog()} + ) } \ No newline at end of file diff --git a/src/device/autoDetect/ScannedI2C.tsx b/src/device/autoDetect/ScannedI2C.tsx index ff057d4..5b83d44 100644 --- a/src/device/autoDetect/ScannedI2C.tsx +++ b/src/device/autoDetect/ScannedI2C.tsx @@ -1,5 +1,7 @@ -import { Box, Button, FormControlLabel, MenuItem, Radio, RadioGroup, TextField } from "@mui/material"; +import { Box, Button, Checkbox, FormControlLabel, Grid2, MenuItem, Radio, RadioGroup, TextField, Tooltip } from "@mui/material"; +import { Component } from "models"; import { getAddressTypes, getFriendlyName, getSubtypes, Subtype } from "pbHelpers/ComponentType"; +import { ComponentAvailabilityMap, DevicePositions } from "pbHelpers/DeviceAvailability"; import { GetProductAvailability } from "products/DeviceProduct"; import { pond } from "protobuf-ts/pond"; import { quack } from "protobuf-ts/quack"; @@ -8,29 +10,29 @@ import { useEffect, useState } from "react"; interface Props { decimalAddress: number deviceProduct: pond.DeviceProduct - updateComponentList: () => void + componentSelectionCallback: (component: Component, checked: boolean) => void + availablePositions: DevicePositions } export default function ScannedI2C(props: Props){ - const {decimalAddress, deviceProduct} = props + const {decimalAddress, deviceProduct, componentSelectionCallback, availablePositions} = props const [types, setTypes] = useState([]) const [subtypeOptions, setSubtypeOptions] = useState>([]) const [selectedType, setSelectedType] = useState(quack.ComponentType.COMPONENT_TYPE_INVALID) const [selectedSubtype, setSelectedSubtype] = useState(0) + const [addressInUse, setAddressInUse] = useState(false) useEffect(()=>{ - //convert the address to hex - let hexAddress = parseInt(decimalAddress.toString(16)) - hexAddress = 0x2a //hardcoding for testing let types: quack.ComponentType[] = [] - //find what component types use that address + //find what component types use that address, this is different than the available positions passed in + //this is meant to get all possibilities according to product type and the given address, availablePositions is the restriction of what is available let productAvailability = GetProductAvailability(deviceProduct) if(productAvailability){ let i2cMap = productAvailability.get(quack.AddressType.ADDRESS_TYPE_I2C) if(i2cMap){ i2cMap.forEach((val, key) => { let addresses = val as number[] ?? [] - if(addresses.length > 0 && addresses.includes(hexAddress)){ + if(addresses.length > 0 && addresses.includes(decimalAddress)){ types.push(key) } }) @@ -40,6 +42,7 @@ export default function ScannedI2C(props: Props){ if(types.length > 0) { setSelectedType(types[0]) buildSubtypeOptions(types[0]) + checkAddressAvailable(types[0]) } setTypes(types) },[decimalAddress, deviceProduct]) @@ -61,47 +64,86 @@ export default function ScannedI2C(props: Props){ setSubtypeOptions(validSub) } + const checkAddressAvailable = (compType: quack.ComponentType) => { + let i2cMap = availablePositions as ComponentAvailabilityMap + let compAddresses = i2cMap.get(compType) ?? [] + if (!compAddresses.includes(decimalAddress)){ + setAddressInUse(true) + }else{ + setAddressInUse(false) + } + } + + + + const componentSelected = (event: React.ChangeEvent, checked: boolean) => { + //build a component with given information and defaults for the rest + let component = Component.create() + component.settings.type = selectedType + component.settings.subtype = selectedSubtype + component.settings.addressType = quack.AddressType.ADDRESS_TYPE_I2C + component.settings.address = decimalAddress + component.settings.name = getFriendlyName(selectedType, selectedSubtype) + //return the component and the checked status to the parent + componentSelectionCallback(component, checked) + } return ( Sensor 1 - { - console.log(value) - let v = parseInt(value) - if (!isNaN(v)){ - buildSubtypeOptions(v) - } - }}> - {types.map((type, i) => { - return ( - } - label={getFriendlyName(type)} + + + { + let v = parseInt(value) + if (!isNaN(v)){ + buildSubtypeOptions(v) + checkAddressAvailable(v) + } + }}> + {types.map((type, i) => { + return ( + } + label={getFriendlyName(type)} + /> + ) + })} + + + + {subtypeOptions.length > 0 && + { + let val = +event.target.value + setSelectedSubtype(val) + }} + select> + {subtypeOptions.map(s => ( + {s.friendlyName} + ))} + + } + + + - ) - })} - - {subtypeOptions.length > 0 && - { - let val = +event.target.value - console.log(event.target.value) - setSelectedSubtype(val) - }} - select> - {subtypeOptions.map(s => ( - {s.friendlyName} - ))} - - } - + } + /> + + + ) } \ No newline at end of file diff --git a/src/pages/Device.tsx b/src/pages/Device.tsx index 6b36115..6a769c0 100644 --- a/src/pages/Device.tsx +++ b/src/pages/Device.tsx @@ -167,7 +167,9 @@ export default function DevicePage() { const loadPortScan = () => { deviceAPI.listFoundComponents(device.id()) .then(resp => { - setScannedAddresses(resp.data.foundComponents ?? undefined) + if (resp.data.foundComponents?.i2c){ + setScannedAddresses(resp.data.foundComponents ?? undefined) + } }) .catch(err => { console.log(err) @@ -427,7 +429,12 @@ export default function DevicePage() { {scannedAddresses && - + } {diagnosticComponents.length > 0 &&