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"; import React from "react"; import { useEffect, useState } from "react"; import ScannedI2C from "./ScannedI2C"; import ComponentForm from "component/ComponentForm"; import { Component, Device } from "models"; import { DeviceAvailabilityMap, FindAvailablePositions, OffsetAvailabilityMap } from "pbHelpers/DeviceAvailability"; import ResponsiveDialog from "common/ResponsiveDialog"; import { useComponentAPI, useDeviceAPI, useSnackbar } from "hooks"; import { ConfigurablePin } from "pbHelpers/AddressTypes"; import ScannedOneWirePort from "./OneWire/ScannedOneWirePort"; import I2CExpander from "./I2CExpander"; interface Props { scannedComponents: pond.ComponentAddressMap device: Device availablePositions: DeviceAvailabilityMap availableOffsets: OffsetAvailabilityMap refreshCallback: () => void } interface CompStep { label: string; completed?: boolean; } let i2cBlacklistAddresses: number[] = [0x70] let i2cExpanderAddresses: number[] = [0x71] export default function DeviceScannedComponents(props: Props){ const {scannedComponents, device, availablePositions, availableOffsets, refreshCallback} = props const compAPI = useComponentAPI(); const deviceAPI = useDeviceAPI() const [scannedI2C, setScannedI2C] = useState() //the unmodified scan of addresses const [scannedOneWire, setScannedOneWire] = useState([]) const [validI2CCompAddresses, setValidI2CComponentAddresses] = useState([]) //the filtered array of address data const [expanderAddresses, setExpanderAddresses] = 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); const [clearOpen, setClearOpen] = useState(false); useEffect(()=>{ if (scannedComponents.i2c) setScannedI2C(scannedComponents.i2c) if (scannedComponents.oneWire) setScannedOneWire(scannedComponents.oneWire) //makes the array empty for testing // if (scannedComponents.i2c) { // let clone = cloneDeep(scannedComponents.i2c) // if (clone.settings){ // clone.settings.foundAddresses = [] // } // setScannedI2C(clone) // } },[scannedComponents]) useEffect(() => { let steps: CompStep[] = [] components.forEach(comp => { steps.push({ label: comp.name(), completed: false }) }) setSteps(steps) },[components]) useEffect(()=>{ let valid: quack.AddressData[] = [] let expanders: quack.AddressData[] = [] //filter the address data let addr = scannedI2C?.settings?.foundAddresses console.log(addr) if(addr){ addr.forEach(addrData => { if(!i2cBlacklistAddresses.includes(addrData.address)){ if(i2cExpanderAddresses.includes(addrData.address) && addrData.expansionLine === 0){ expanders.push(addrData) }else{ valid.push(addrData) } } }) } console.log(valid) setExpanderAddresses(expanders) setValidI2CComponentAddresses(valid) },[scannedI2C]) const stepper = () => { return ( {steps.map(compStep => { const labelProps: { optional?: React.ReactNode; } = {}; return ( {compStep.label} ); })} ); }; 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 ( {setOpenDialog(false)}}> Adding Components {stepper()} { components[currentStep].settings = component.settings; setSettingsValid(isValid); }} /> {currentStep !== 0 && ( )} {currentStep !== steps.length - 1 && ( )} ); }; const componentSelection = (newComponents: Component[], checked: boolean) => { let cloneList = cloneDeep(components) if(checked){ //add the component to the list cloneList = cloneList.concat(newComponents) }else{ newComponents.forEach(newComponent => { //remove any components that match the component location: (type)-(addressType)-(address) cloneList.forEach((comp, i) => { //check the components location against the one in the list if(comp.locationString() === newComponent.locationString()){ cloneList.splice(i, 1) } }) }) } console.log(cloneList) setComponents(cloneList) } const removeScan = (key: string, type: pond.ObjectType) => { deviceAPI.removeFoundComponents(device.settings.deviceId, key, type) .then(resp => { console.log("Cleared this scan") }).catch(err => { console.log("There was a problem clearing this scan") }) } const removeAllScans = () => { deviceAPI.removeAllFoundComponents(device.settings.deviceId) .then(resp => { console.log("Cleared all scans") refreshCallback() }).catch(err => { console.log("There was a problem clearing scans") }) } const clearWarning = () => { return ( {setClearOpen(false)}}> Clear All Scans This action will clear all scans for this device. ) } return ( {clearWarning()} Sensor Scan {scannedI2C !== undefined && I2C Scan {expanderAddresses.length > 0 && Detected Expanders {expanderAddresses.map((expAddr, index) => { return ( ) })} } {validI2CCompAddresses.length > 0 ? Detected Sensors {validI2CCompAddresses.map((addr, index) => { return ( ()}/> ) })} : No Sensors Found } } {scannedOneWire.length > 0 && Pin Port Scan {scannedOneWire.map((scan,i) => { let map = FindAvailablePositions([], device.settings.product).availability.get(quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY) let portAddress = scan.settings?.oneWireData?.port let portLabel = "" map?.forEach(entry => { let pin = entry as ConfigurablePin if (pin.address && pin.address === portAddress) { portLabel = pin.label } }) return( Port: {portLabel} ) })} } {addComponentDialog()} ) }