bin sensors add the bins
This commit is contained in:
parent
c46cb5ce4b
commit
b5071dfb40
9 changed files with 7346 additions and 20 deletions
267
src/device/DeviceWizard.tsx
Normal file
267
src/device/DeviceWizard.tsx
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
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, 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;
|
||||
}
|
||||
|
||||
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 } = props;
|
||||
const [componentDialogOpen, setComponentDialogOpen] = useState(false);
|
||||
const [availableOffsets, setAvailableOffsets] = useState<OffsetAvailabilityMap>(new Map());
|
||||
const [availablePositions, setAvailablePositions] = useState<DeviceAvailabilityMap>(new Map());
|
||||
const compAPI = useComponentAPI();
|
||||
const [menuAnchor, setMenuAnchor] = useState<null | Element>(null);
|
||||
const [portComponents, setPortComponents] = useState<Component[]>([]);
|
||||
const [componentToUpdate, setComponentToUpdate] = useState<Component | undefined>();
|
||||
const { error, success } = useSnackbar();
|
||||
const [ComponentSettingsMode, setComponentSettingsMode] = useState<"add" | "remove" | "update">(
|
||||
"add"
|
||||
);
|
||||
const classes = useStyles();
|
||||
const [selectedPort, setSelectedPort] = useState<PortInformation>();
|
||||
//const [addressType, setAddressType] = useState<quack.AddressType>(quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY);
|
||||
|
||||
const wizardMenu = () => {
|
||||
return (
|
||||
<Menu
|
||||
id="groupMenu"
|
||||
anchorEl={menuAnchor}
|
||||
open={Boolean(menuAnchor)}
|
||||
onClose={() => setMenuAnchor(null)}
|
||||
keepMounted
|
||||
disableAutoFocusItem>
|
||||
<MenuItem
|
||||
key={"add"}
|
||||
onClick={() => {
|
||||
setComponentSettingsMode("add");
|
||||
setComponentToUpdate(undefined);
|
||||
setComponentDialogOpen(true);
|
||||
}}>
|
||||
Add Component
|
||||
</MenuItem>
|
||||
{/* <MenuItem key={"list_error"} onClick={() => {
|
||||
}}>
|
||||
List Errors
|
||||
</MenuItem> */}
|
||||
{selectedPort && selectedPort.autoDetectable && (
|
||||
<Tooltip title="Used to Detect Grain Cables">
|
||||
<MenuItem
|
||||
key={"auto"}
|
||||
onClick={() => {
|
||||
setAutoDetect();
|
||||
}}>
|
||||
Auto Detect
|
||||
</MenuItem>
|
||||
</Tooltip>
|
||||
)}
|
||||
{portComponents.length > 0 && (
|
||||
<List>
|
||||
<ListSubheader>Current Components</ListSubheader>
|
||||
{portComponents.map(comp => (
|
||||
<ListItem
|
||||
key={comp.key()}
|
||||
onClick={() => {
|
||||
setComponentToUpdate(comp);
|
||||
setComponentSettingsMode("update");
|
||||
setComponentDialogOpen(true);
|
||||
}}>
|
||||
<ListItemIcon>
|
||||
<Avatar
|
||||
className={classes.avatarIcon}
|
||||
alt={comp.subTypeName() + "Icon"}
|
||||
src={GetComponentIcon(comp.type(), comp.subType())}
|
||||
/>
|
||||
</ListItemIcon>
|
||||
<ListItemText>{comp.name()}</ListItemText>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
)}
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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)
|
||||
.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
|
||||
* does nothing for I2C ports as the restrictions for that are handled by the component type
|
||||
* @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 }]);
|
||||
}
|
||||
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 = () => {
|
||||
return (
|
||||
<Card className={classes.card} raised>
|
||||
<CardHeader
|
||||
avatar={
|
||||
<Avatar
|
||||
variant="square"
|
||||
src={GetDeviceProductIcon(device.settings)}
|
||||
className={classes.avatarIcon}
|
||||
alt={"devIcon"}
|
||||
/>
|
||||
}
|
||||
title={GetDeviceProductLabel(device.settings.product) + " - ID:" + device.id()}
|
||||
className={classes.cardHeader}
|
||||
/>
|
||||
<CardContent style={{ paddingTop: 0 }}>
|
||||
<Typography variant="caption">
|
||||
Select a port on the device below to modify components
|
||||
</Typography>
|
||||
<Box paddingLeft={"15%"} paddingRight={"15%"} paddingTop={"20px"}>
|
||||
<DeviceSVG
|
||||
device={device}
|
||||
openMenu={(e, port) => {
|
||||
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);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{setupCard()}
|
||||
<ComponentSettings
|
||||
mode={ComponentSettingsMode}
|
||||
component={componentToUpdate}
|
||||
device={device}
|
||||
isDialogOpen={componentDialogOpen}
|
||||
closeDialogCallback={() => setComponentDialogOpen(false)}
|
||||
availablePositions={availablePositions}
|
||||
availableOffsets={availableOffsets}
|
||||
refreshCallback={refreshCallback}
|
||||
canEdit
|
||||
addressTypeRestriction={selectedPort && selectedPort.addressType}
|
||||
/>
|
||||
{wizardMenu()}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
5246
src/device/deviceSVG.tsx
Normal file
5246
src/device/deviceSVG.tsx
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue