import { Avatar, Box, Card, CardContent, CardHeader, List, ListItem, ListItemIcon, ListItemText, ListSubheader, Menu, MenuItem, Theme, Tooltip, Typography } from "@mui/material"; import ComponentSettings from "component/ComponentSettings"; import { Component, Device } from "models"; import { GetComponentIcon } from "pbHelpers/ComponentType"; import { DeviceAvailabilityMap, FindAvailablePositions, OffsetAvailabilityMap } from "pbHelpers/DeviceAvailability"; import { GetDeviceProductIcon, GetDeviceProductLabel } from "products/DeviceProduct"; import { pond } from "protobuf-ts/pond"; import { quack } from "protobuf-ts/quack"; import { useComponentAPI, useDeviceAPI, useGlobalState, useSnackbar } from "providers"; import React, { useState } from "react"; import DeviceSVG, { PortInformation } from "./deviceSVG"; import { makeStyles } from "@mui/styles"; interface Props { device: Device; //permissions: pond.Permission[]; components: Component[]; refreshCallback: () => void; scanInProgress?: boolean } const useStyles = makeStyles((theme: Theme) => { return ({ card: { // position: "relative", // display: "flex", // height: "100%", // flexDirection: "column", // overflow: "visible" minHeight: "200px" }, cardHeader: { padding: theme.spacing(1), paddingLeft: theme.spacing(2) }, cardContent: { display: "flex", flexDirection: "column", justifyContent: "space-between", alignItems: "center", padding: theme.spacing(1), paddingTop: 0 }, avatarIcon: { width: theme.spacing(3), height: theme.spacing(3) } }) }); export default function DeviceWizard(props: Props) { const { device, components, refreshCallback, scanInProgress } = props; const [{as}] = useGlobalState(); const [componentDialogOpen, setComponentDialogOpen] = useState(false); const [availableOffsets, setAvailableOffsets] = useState(new Map()); const [availablePositions, setAvailablePositions] = useState(new Map()); const compAPI = useComponentAPI(); const [menuAnchor, setMenuAnchor] = useState(null); const [portComponents, setPortComponents] = useState([]); const [componentToUpdate, setComponentToUpdate] = useState(); const { error, success } = useSnackbar(); const [ComponentSettingsMode, setComponentSettingsMode] = useState<"add" | "remove" | "update">( "add" ); const classes = useStyles(); const [selectedPort, setSelectedPort] = useState(); const deviceAPI = useDeviceAPI() const { openSnack } = useSnackbar() const [buttonClicked, setButtonClicked] = useState(false); //const [addressType, setAddressType] = useState(quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY); const wizardMenu = () => { return ( setMenuAnchor(null)} keepMounted disableAutoFocusItem> { setComponentSettingsMode("add"); setComponentToUpdate(undefined); setComponentDialogOpen(true); }}> Add Component {/* { }}> List Errors */} {selectedPort && selectedPort.autoDetectable && ( { setAutoDetect(); }}> Auto Detect )} {selectedPort && selectedPort.addressType === quack.AddressType.ADDRESS_TYPE_I2C && device.featureSupported("detectI2C") && ( { setButtonClicked(true) deviceAPI.detectI2C(device.id()) .then(resp => { openSnack("Device will scan port on next check-in") }).catch(err => { openSnack("Command failed to send to device") }) }}> Scan Port )} {selectedPort && selectedPort.addressType === quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY && device.featureSupported("detectOneWire") && selectedPort.autoDetectable && ( { setButtonClicked(true) console.log(selectedPort) deviceAPI.detectOneWire(device.id(), selectedPort.address) .then(resp => { openSnack("Device will scan port on next check-in") }).catch(err => { openSnack("Command failed to send to device") }) }}> Scan Port )} {portComponents.length > 0 && ( Current Components {portComponents.map(comp => ( { setComponentToUpdate(comp); setComponentSettingsMode("update"); setComponentDialogOpen(true); }}> {comp.name()} ))} )} ); }; /** * sets an autodetect component on the port that was selected * TODO: when the auto detect gets expanded out of being a grain cable component this will have to be re-factored to use the new component type since it is hard coded */ const setAutoDetect = () => { if (selectedPort) { let componentSettings = pond.ComponentSettings.create(); componentSettings.type = quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE; // use the grain cable component componentSettings.subtype = quack.GrainCableSubtype.GRAIN_CABLE_SUBTYPE_OPI_DIAG; //use the port diagnostic subtype componentSettings.addressType = quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY; componentSettings.address = selectedPort.address; // the address of the selected port componentSettings.measurementPeriodMs = 600000; //set the measurement period to 10 mins componentSettings.reportPeriodMs = 600000; componentSettings.name = "Port " + selectedPort.label + " Auto Detect"; compAPI .add(device.id(), componentSettings, as) .then(resp => { success("Added Auto Detect Component to Port"); }) .catch(err => { error("Failed to Add Auto Detect Component to Port"); }) .finally(() => { refreshCallback(); }); } }; /** * function that restricts the pin availabilty in the availability map to the pin of the port that was selected * @param port port that was selected * @param availability availability map of the device * @returns modified availability map */ const adjustAvailablePositions = (port: PortInformation, availability: DeviceAvailabilityMap) => { let currentAvailability = availability; switch (port.addressType) { case quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY: 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; }; const findPortComponents = (components: Component[], port: PortInformation) => { let pc: Component[] = []; switch (port.addressType) { case quack.AddressType.ADDRESS_TYPE_I2C: components.forEach(comp => { if (comp.settings.addressType === quack.AddressType.ADDRESS_TYPE_I2C) { pc.push(comp); } }); break; case quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY: components.forEach(comp => { if (comp.settings.address === port.address) { pc.push(comp); } }); } return pc; }; const setupCard = () => { const deviceIcon = GetDeviceProductIcon(device) return ( } title={GetDeviceProductLabel(device.settings.product) + " - ID:" + device.id()} className={classes.cardHeader} /> Select a port on the device below to modify components { let available = FindAvailablePositions(components, device.settings.product); setAvailableOffsets(available.offsetAvailability); setAvailablePositions(adjustAvailablePositions(port, available.availability)); //setAddressType(port.addressType); setSelectedPort(port); setPortComponents(findPortComponents(components, port)); setMenuAnchor(e.currentTarget); }} /> ); }; return ( {setupCard()} setComponentDialogOpen(false)} availablePositions={availablePositions} availableOffsets={availableOffsets} refreshCallback={refreshCallback} canEdit addressTypeRestriction={selectedPort && selectedPort.addressType} /> {wizardMenu()} ); }