Merge branch 'i2c_detect' into dev_environment
This commit is contained in:
commit
0b31f5585d
17 changed files with 511 additions and 31 deletions
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -10889,7 +10889,7 @@
|
||||||
},
|
},
|
||||||
"node_modules/protobuf-ts": {
|
"node_modules/protobuf-ts": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#bb403eef199a68f470fc025ae97fed2185682504",
|
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#091928b04970731f9b543fcecc313b6f4ea7d4e2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"protobufjs": "^6.8.8"
|
"protobufjs": "^6.8.8"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,10 @@
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"build:staging": "VITE_AUTH0_CLIENT_DOMAIN=adaptivestaging.us.auth0.com VITE_AUTH0_AUDIENCE=stagingapi.brandxtech.ca VITE_AUTH0_CLIENT_ID=3ib460VvLwdeyse5iUSQfxkVdQaUmphP VITE_APP_API_URL=https://stagingapi.brandxtech.ca/v1 VITE_APP_WS_URL=wss://stagingapi.brandxtech.ca/v1/live NODE_OPTIONS=--max_old_space_size=4096 VITE_APP_GOOGLE_API_KEY=${GOOGLE_API_KEY} VITE_APP_STRIPE_PUBLIC_KEY=${STRIPE_PUBLIC_KEY_STAGING} VITE_MAPBOX_ACCESS_TOKEN=${MAPBOX_ACCESS_TOKEN} VITE_CNHI_CLIENT_ID=${CNHI_CLIENT_ID} VITE_CNHI_AUTHORIZE_URL=${CNHI_AUTHORIZE_URL} VITE_CNHI_REDIRECT_URI=${CNHI_REDIRECT_URI} VITE_CNHI_SCOPES=${CNHI_SCOPES} VITE_CNHI_CONNECTION=${CNHI_CONNECTION} VITE_CNHI_AUDIENCE=${CNHI_AUDIENCE} VITE_APP_IMAGE4IO_USERNAME=${IMAGE4IO_USERNAME} VITE_APP_IMAGE4IO_PASSWORD=${IMAGE4IO_PASSWORD} VITE_JD_CLIENT_ID=${JD_CLIENT_ID} VITE_JD_AUTHORIZE_URL=${JD_AUTHORIZE_URL} VITE_JD_REDIRECT_URI=${JD_REDIRECT_URI} VITE_JD_SCOPES=${JD_SCOPES} VITE_JD_STATE=${JD_STATE} VITE_OPEN_WEATHERMAP={OPEN_WEATHERMAP} vite build",
|
"build:staging": "VITE_AUTH0_CLIENT_DOMAIN=adaptivestaging.us.auth0.com VITE_AUTH0_AUDIENCE=stagingapi.brandxtech.ca VITE_AUTH0_CLIENT_ID=3ib460VvLwdeyse5iUSQfxkVdQaUmphP VITE_APP_API_URL=https://stagingapi.brandxtech.ca/v1 VITE_APP_WS_URL=wss://stagingapi.brandxtech.ca/v1/live NODE_OPTIONS=--max_old_space_size=4096 VITE_APP_GOOGLE_API_KEY=${GOOGLE_API_KEY} VITE_APP_STRIPE_PUBLIC_KEY=${STRIPE_PUBLIC_KEY_STAGING} VITE_MAPBOX_ACCESS_TOKEN=${MAPBOX_ACCESS_TOKEN} VITE_CNHI_CLIENT_ID=${CNHI_CLIENT_ID} VITE_CNHI_AUTHORIZE_URL=${CNHI_AUTHORIZE_URL} VITE_CNHI_REDIRECT_URI=${CNHI_REDIRECT_URI} VITE_CNHI_SCOPES=${CNHI_SCOPES} VITE_CNHI_CONNECTION=${CNHI_CONNECTION} VITE_CNHI_AUDIENCE=${CNHI_AUDIENCE} VITE_APP_IMAGE4IO_USERNAME=${IMAGE4IO_USERNAME} VITE_APP_IMAGE4IO_PASSWORD=${IMAGE4IO_PASSWORD} VITE_JD_CLIENT_ID=${JD_CLIENT_ID} VITE_JD_AUTHORIZE_URL=${JD_AUTHORIZE_URL} VITE_JD_REDIRECT_URI=${JD_REDIRECT_URI} VITE_JD_SCOPES=${JD_SCOPES} VITE_JD_STATE=${JD_STATE} VITE_OPEN_WEATHERMAP=${OPEN_WEATHERMAP} vite build",
|
||||||
"build:development": "VITE_AUTH0_CLIENT_ID=dzJTpqIeMA4Rwk4xujtwPbAO3TY32bM1 VITE_AUTH0_AUDIENCE=bxt-dev.api.adaptiveagriculture.ca VITE_APP_API_URL=https://bxt-dev.api.adaptiveagriculture.ca/v1 NODE_OPTIONS=--max_old_space_size=4096 VITE_APP_GOOGLE_API_KEY=${GOOGLE_API_KEY} VITE_APP_STRIPE_PUBLIC_KEY=${STRIPE_PUBLIC_KEY_DEVELOPMENT} VITE_MAPBOX_ACCESS_TOKEN=${MAPBOX_ACCESS_TOKEN} VITE_CNHI_CLIENT_ID=${CNHI_CLIENT_ID} VITE_CNHI_AUTHORIZE_URL=${CNHI_AUTHORIZE_URL} VITE_CNHI_REDIRECT_URI=${CNHI_REDIRECT_URI} VITE_CNHI_SCOPES=${CNHI_SCOPES} VITE_CNHI_CONNECTION=${CNHI_CONNECTION} VITE_CNHI_AUDIENCE=${CNHI_AUDIENCE} VITE_APP_IMAGE4IO_USERNAME=${IMAGE4IO_USERNAME} VITE_APP_IMAGE4IO_PASSWORD=${IMAGE4IO_PASSWORD} VITE_JD_CLIENT_ID=${JD_CLIENT_ID} VITE_JD_AUTHORIZE_URL=${JD_AUTHORIZE_URL} VITE_JD_REDIRECT_URI=${JD_REDIRECT_URI} VITE_JD_SCOPES=${JD_SCOPES} VITE_JD_STATE=${JD_STATE} VITE_OPEN_WEATHERMAP={OPEN_WEATHERMAP} vite build",
|
"build:development": "VITE_AUTH0_CLIENT_ID=dzJTpqIeMA4Rwk4xujtwPbAO3TY32bM1 VITE_AUTH0_AUDIENCE=bxt-dev.api.adaptiveagriculture.ca VITE_APP_API_URL=https://bxt-dev.api.adaptiveagriculture.ca/v1 NODE_OPTIONS=--max_old_space_size=4096 VITE_APP_GOOGLE_API_KEY=${GOOGLE_API_KEY} VITE_APP_STRIPE_PUBLIC_KEY=${STRIPE_PUBLIC_KEY_DEVELOPMENT} VITE_MAPBOX_ACCESS_TOKEN=${MAPBOX_ACCESS_TOKEN} VITE_CNHI_CLIENT_ID=${CNHI_CLIENT_ID} VITE_CNHI_AUTHORIZE_URL=${CNHI_AUTHORIZE_URL} VITE_CNHI_REDIRECT_URI=${CNHI_REDIRECT_URI} VITE_CNHI_SCOPES=${CNHI_SCOPES} VITE_CNHI_CONNECTION=${CNHI_CONNECTION} VITE_CNHI_AUDIENCE=${CNHI_AUDIENCE} VITE_APP_IMAGE4IO_USERNAME=${IMAGE4IO_USERNAME} VITE_APP_IMAGE4IO_PASSWORD=${IMAGE4IO_PASSWORD} VITE_JD_CLIENT_ID=${JD_CLIENT_ID} VITE_JD_AUTHORIZE_URL=${JD_AUTHORIZE_URL} VITE_JD_REDIRECT_URI=${JD_REDIRECT_URI} VITE_JD_SCOPES=${JD_SCOPES} VITE_JD_STATE=${JD_STATE} VITE_OPEN_WEATHERMAP=${OPEN_WEATHERMAP} vite build",
|
||||||
"build:production": "VITE_AUTH0_CLIENT_ID=5pUCkl2SfogkWmM244UDcLEUOp8EFdHd VITE_AUTH0_CLIENT_DOMAIN=brandxtech.auth0.com VITE_AUTH0_AUDIENCE=api.brandxtech.ca VITE_APP_API_URL=https://api.brandxtech.ca/v1 NODE_OPTIONS=--max_old_space_size=4096 VITE_APP_GOOGLE_API_KEY=${GOOGLE_API_KEY} VITE_APP_STRIPE_PUBLIC_KEY=${STRIPE_PUBLIC_KEY_PRODUCTION} VITE_MAPBOX_ACCESS_TOKEN=${MAPBOX_ACCESS_TOKEN} VITE_CNHI_CLIENT_ID=${CNHI_CLIENT_ID} VITE_CNHI_AUTHORIZE_URL=${CNHI_AUTHORIZE_URL} VITE_CNHI_REDIRECT_URI=${CNHI_REDIRECT_URI} VITE_CNHI_SCOPES=${CNHI_SCOPES} VITE_CNHI_CONNECTION=${CNHI_CONNECTION} VITE_CNHI_AUDIENCE=${CNHI_AUDIENCE} VITE_APP_IMAGE4IO_USERNAME=${IMAGE4IO_USERNAME} VITE_APP_IMAGE4IO_PASSWORD=${IMAGE4IO_PASSWORD} VITE_JD_CLIENT_ID=${JD_CLIENT_ID} VITE_JD_AUTHORIZE_URL=${JD_AUTHORIZE_URL} VITE_JD_REDIRECT_URI=${JD_REDIRECT_URI} VITE_JD_SCOPES=${JD_SCOPES} VITE_JD_STATE=${JD_STATE} VITE_OPEN_WEATHERMAP={OPEN_WEATHERMAP} vite build",
|
"build:production": "VITE_AUTH0_CLIENT_ID=5pUCkl2SfogkWmM244UDcLEUOp8EFdHd VITE_AUTH0_CLIENT_DOMAIN=brandxtech.auth0.com VITE_AUTH0_AUDIENCE=api.brandxtech.ca VITE_APP_API_URL=https://api.brandxtech.ca/v1 NODE_OPTIONS=--max_old_space_size=4096 VITE_APP_GOOGLE_API_KEY=${GOOGLE_API_KEY} VITE_APP_STRIPE_PUBLIC_KEY=${STRIPE_PUBLIC_KEY_PRODUCTION} VITE_MAPBOX_ACCESS_TOKEN=${MAPBOX_ACCESS_TOKEN} VITE_CNHI_CLIENT_ID=${CNHI_CLIENT_ID} VITE_CNHI_AUTHORIZE_URL=${CNHI_AUTHORIZE_URL} VITE_CNHI_REDIRECT_URI=${CNHI_REDIRECT_URI} VITE_CNHI_SCOPES=${CNHI_SCOPES} VITE_CNHI_CONNECTION=${CNHI_CONNECTION} VITE_CNHI_AUDIENCE=${CNHI_AUDIENCE} VITE_APP_IMAGE4IO_USERNAME=${IMAGE4IO_USERNAME} VITE_APP_IMAGE4IO_PASSWORD=${IMAGE4IO_PASSWORD} VITE_JD_CLIENT_ID=${JD_CLIENT_ID} VITE_JD_AUTHORIZE_URL=${JD_AUTHORIZE_URL} VITE_JD_REDIRECT_URI=${JD_REDIRECT_URI} VITE_JD_SCOPES=${JD_SCOPES} VITE_JD_STATE=${JD_STATE} VITE_OPEN_WEATHERMAP=${OPEN_WEATHERMAP} vite build",
|
||||||
"build:streamline": "VITE_AUTH0_CLIENT_ID=HwUV0hHNdVvU96zuMBTAU8i7nFdwwgIX VITE_AUTH0_CLIENT_DOMAIN=brandxtech.auth0.com VITE_AUTH0_AUDIENCE=streamline.api.adaptiveagriculture.ca VITE_APP_API_URL=https://streamline.api.adaptiveagriculture.ca/v1 NODE_OPTIONS=--max_old_space_size=4096 VITE_APP_GOOGLE_API_KEY=${GOOGLE_API_KEY} VITE_APP_STRIPE_PUBLIC_KEY=${STRIPE_PUBLIC_KEY_PRODUCTION} VITE_MAPBOX_ACCESS_TOKEN=${MAPBOX_ACCESS_TOKEN} VITE_CNHI_CLIENT_ID=${CNHI_CLIENT_ID} VITE_CNHI_AUTHORIZE_URL=${CNHI_AUTHORIZE_URL} VITE_CNHI_REDIRECT_URI=${CNHI_REDIRECT_URI} VITE_CNHI_SCOPES=${CNHI_SCOPES} VITE_CNHI_CONNECTION=${CNHI_CONNECTION} VITE_CNHI_AUDIENCE=${CNHI_AUDIENCE} VITE_APP_IMAGE4IO_USERNAME=${IMAGE4IO_USERNAME} VITE_APP_IMAGE4IO_PASSWORD=${IMAGE4IO_PASSWORD} VITE_JD_CLIENT_ID=${JD_CLIENT_ID} VITE_JD_AUTHORIZE_URL=${JD_AUTHORIZE_URL} VITE_JD_REDIRECT_URI=${JD_REDIRECT_URI} VITE_JD_SCOPES=${JD_SCOPES} VITE_JD_STATE=${JD_STATE} VITE_OPEN_WEATHERMAP={OPEN_WEATHERMAP} vite build",
|
"build:streamline": "VITE_AUTH0_CLIENT_ID=HwUV0hHNdVvU96zuMBTAU8i7nFdwwgIX VITE_AUTH0_CLIENT_DOMAIN=brandxtech.auth0.com VITE_AUTH0_AUDIENCE=streamline.api.adaptiveagriculture.ca VITE_APP_API_URL=https://streamline.api.adaptiveagriculture.ca/v1 NODE_OPTIONS=--max_old_space_size=4096 VITE_APP_GOOGLE_API_KEY=${GOOGLE_API_KEY} VITE_APP_STRIPE_PUBLIC_KEY=${STRIPE_PUBLIC_KEY_PRODUCTION} VITE_MAPBOX_ACCESS_TOKEN=${MAPBOX_ACCESS_TOKEN} VITE_CNHI_CLIENT_ID=${CNHI_CLIENT_ID} VITE_CNHI_AUTHORIZE_URL=${CNHI_AUTHORIZE_URL} VITE_CNHI_REDIRECT_URI=${CNHI_REDIRECT_URI} VITE_CNHI_SCOPES=${CNHI_SCOPES} VITE_CNHI_CONNECTION=${CNHI_CONNECTION} VITE_CNHI_AUDIENCE=${CNHI_AUDIENCE} VITE_APP_IMAGE4IO_USERNAME=${IMAGE4IO_USERNAME} VITE_APP_IMAGE4IO_PASSWORD=${IMAGE4IO_PASSWORD} VITE_JD_CLIENT_ID=${JD_CLIENT_ID} VITE_JD_AUTHORIZE_URL=${JD_AUTHORIZE_URL} VITE_JD_REDIRECT_URI=${JD_REDIRECT_URI} VITE_JD_SCOPES=${JD_SCOPES} VITE_JD_STATE=${JD_STATE} VITE_OPEN_WEATHERMAP=${OPEN_WEATHERMAP} vite build",
|
||||||
"build:offline": "npx env-cmd offline,whitelabel npm run build",
|
"build:offline": "npx env-cmd offline,whitelabel npm run build",
|
||||||
"test": "vitest"
|
"test": "vitest"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -555,10 +555,10 @@ const componentType: data = {
|
||||||
key: "COMPONENT_TYPE_CAPACITANCE",
|
key: "COMPONENT_TYPE_CAPACITANCE",
|
||||||
val: 24
|
val: 24
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
key: "COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT",
|
// key: "COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT", //this component type is deprecated?
|
||||||
val: 25
|
// val: 25
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
key: "COMPONENT_TYPE_WEIGHT",
|
key: "COMPONENT_TYPE_WEIGHT",
|
||||||
val: 26
|
val: 26
|
||||||
|
|
|
||||||
|
|
@ -414,7 +414,7 @@ export default function BinComponents(props: Props) {
|
||||||
)}
|
)}
|
||||||
<ListItemText inset={cIcon === undefined}>
|
<ListItemText inset={cIcon === undefined}>
|
||||||
<Grid container direction="row" justifyContent="space-between">
|
<Grid container direction="row" justifyContent="space-between">
|
||||||
<Grid >{comp.name()}</Grid>
|
<Grid >{comp.name() + " - " + comp.addressDescription(devMap.get(device)?.settings.product)}</Grid>
|
||||||
<Grid >
|
<Grid >
|
||||||
{components?.get(comp.key()) !== undefined ? (
|
{components?.get(comp.key()) !== undefined ? (
|
||||||
<CheckBoxIcon />
|
<CheckBoxIcon />
|
||||||
|
|
|
||||||
|
|
@ -238,6 +238,7 @@ export default function ComponentSettings(props: Props) {
|
||||||
componentType: quack.ComponentType
|
componentType: quack.ComponentType
|
||||||
): number[] => {
|
): number[] => {
|
||||||
let positions = availablePositions.get(addressType);
|
let positions = availablePositions.get(addressType);
|
||||||
|
console.log(positions)
|
||||||
if (!positions) return [];
|
if (!positions) return [];
|
||||||
switch (addressType) {
|
switch (addressType) {
|
||||||
case quack.AddressType.ADDRESS_TYPE_I2C:
|
case quack.AddressType.ADDRESS_TYPE_I2C:
|
||||||
|
|
@ -412,6 +413,7 @@ export default function ComponentSettings(props: Props) {
|
||||||
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);
|
||||||
|
console.log(availablePositions)
|
||||||
|
|
||||||
availableMenuItemPositions.push(
|
availableMenuItemPositions.push(
|
||||||
<MenuItem key={addressType} divider disabled>
|
<MenuItem key={addressType} divider disabled>
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,8 @@ import {
|
||||||
import { GetDeviceProductIcon, GetDeviceProductLabel } from "products/DeviceProduct";
|
import { GetDeviceProductIcon, GetDeviceProductLabel } 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 { useComponentAPI, useGlobalState, useSnackbar } from "providers";
|
import { useComponentAPI, useDeviceAPI, useGlobalState, useSnackbar } from "providers";
|
||||||
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import DeviceSVG, { PortInformation } from "./deviceSVG";
|
import DeviceSVG, { PortInformation } from "./deviceSVG";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
|
|
@ -83,6 +84,8 @@ export default function DeviceWizard(props: Props) {
|
||||||
);
|
);
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [selectedPort, setSelectedPort] = useState<PortInformation>();
|
const [selectedPort, setSelectedPort] = useState<PortInformation>();
|
||||||
|
const deviceAPI = useDeviceAPI()
|
||||||
|
const { openSnack } = useSnackbar()
|
||||||
//const [addressType, setAddressType] = useState<quack.AddressType>(quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY);
|
//const [addressType, setAddressType] = useState<quack.AddressType>(quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY);
|
||||||
|
|
||||||
const wizardMenu = () => {
|
const wizardMenu = () => {
|
||||||
|
|
@ -118,6 +121,22 @@ export default function DeviceWizard(props: Props) {
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
{selectedPort && selectedPort.addressType === quack.AddressType.ADDRESS_TYPE_I2C && device.featureSupported("detectI2C") && (
|
||||||
|
<Tooltip title="Used to tell the Device to scan its I2C port for any plugged in sensors">
|
||||||
|
<MenuItem
|
||||||
|
key={"scanI2C"}
|
||||||
|
onClick={() => {
|
||||||
|
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
|
||||||
|
</MenuItem>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
{portComponents.length > 0 && (
|
{portComponents.length > 0 && (
|
||||||
<List>
|
<List>
|
||||||
<ListSubheader>Current Components</ListSubheader>
|
<ListSubheader>Current Components</ListSubheader>
|
||||||
|
|
|
||||||
219
src/device/autoDetect/DeviceScannedComponents.tsx
Normal file
219
src/device/autoDetect/DeviceScannedComponents.tsx
Normal file
|
|
@ -0,0 +1,219 @@
|
||||||
|
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, 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 {
|
||||||
|
label: string;
|
||||||
|
completed?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function DeviceScannedComponents(props: Props){
|
||||||
|
const {scannedComponents, device, availablePositions, availableOffsets, refreshCallback} = props
|
||||||
|
const compAPI = useComponentAPI();
|
||||||
|
const [scannedI2C, setScannedI2C] = useState<pond.DetectI2C>()
|
||||||
|
const [components, setComponents] = useState<Component[]>([])
|
||||||
|
const [steps, setSteps] = useState<CompStep[]>([]);
|
||||||
|
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)
|
||||||
|
//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])
|
||||||
|
|
||||||
|
const stepper = () => {
|
||||||
|
return (
|
||||||
|
<Stepper nonLinear activeStep={currentStep} style={{ width: "100%" }}>
|
||||||
|
{steps.map(compStep => {
|
||||||
|
const labelProps: {
|
||||||
|
optional?: React.ReactNode;
|
||||||
|
} = {};
|
||||||
|
return (
|
||||||
|
<Step key={compStep.label} completed={compStep.completed}>
|
||||||
|
<StepLabel {...labelProps}>{compStep.label}</StepLabel>
|
||||||
|
</Step>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Stepper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<ResponsiveDialog open={openDialog} onClose={()=>{setOpenDialog(false)}}>
|
||||||
|
<DialogTitle>Adding Components</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
{stepper()}
|
||||||
|
<ComponentForm
|
||||||
|
component={components[currentStep]}
|
||||||
|
canEdit
|
||||||
|
device={device}
|
||||||
|
componentChanged={(component, isValid) => {
|
||||||
|
components[currentStep].settings = component.settings;
|
||||||
|
setSettingsValid(isValid);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Grid2 container direction="row" justifyContent="space-between">
|
||||||
|
<Grid2>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => {
|
||||||
|
close();
|
||||||
|
}}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</Grid2>
|
||||||
|
<Grid2>
|
||||||
|
{currentStep !== 0 && (
|
||||||
|
<Button
|
||||||
|
sx={{marginX: 1}}
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => {
|
||||||
|
setCurrentStep(currentStep - 1);
|
||||||
|
}}>
|
||||||
|
Back
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{currentStep !== steps.length - 1 && (
|
||||||
|
<React.Fragment>
|
||||||
|
<Button
|
||||||
|
sx={{marginX: 1}}
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => {
|
||||||
|
setCurrentStep(currentStep + 1);
|
||||||
|
}}>
|
||||||
|
Next
|
||||||
|
</Button>
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
sx={{marginX: 1}}
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => {
|
||||||
|
setOpenDialog(false)
|
||||||
|
addComponents();
|
||||||
|
}}>
|
||||||
|
Confirm
|
||||||
|
</Button>
|
||||||
|
</Grid2>
|
||||||
|
</Grid2>
|
||||||
|
</DialogActions>
|
||||||
|
</ResponsiveDialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<React.Fragment>
|
||||||
|
<Card raised sx={{padding: 1}}>
|
||||||
|
{scannedI2C !== undefined &&
|
||||||
|
<React.Fragment>
|
||||||
|
<Box>
|
||||||
|
<Typography sx={{fontWeight: 650}}>
|
||||||
|
I2C Sensors
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
{scannedI2C.settings?.foundAddresses && scannedI2C.settings.foundAddresses.length > 0 ? scannedI2C?.settings?.foundAddresses.map((addr, index) => {
|
||||||
|
return (
|
||||||
|
<ScannedI2C key={index} sensorNum={index+1} decimalAddress={addr} deviceProduct={device.settings.product} componentSelectionCallback={componentSelection} availablePositions={availablePositions.get(quack.AddressType.ADDRESS_TYPE_I2C) ?? []}/>
|
||||||
|
)
|
||||||
|
}) :
|
||||||
|
<Box sx={{
|
||||||
|
margin: 1,
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center"
|
||||||
|
}}>
|
||||||
|
<Typography>
|
||||||
|
No Sensors Found
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
|
</React.Fragment>
|
||||||
|
}
|
||||||
|
<Box display="flex" flexDirection="row-reverse" marginTop={2}>
|
||||||
|
<Button disabled={components.length === 0} variant="contained" color="primary" onClick={()=>{setOpenDialog(true)}}>Add Components</Button>
|
||||||
|
</Box>
|
||||||
|
</Card>
|
||||||
|
{addComponentDialog()}
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
}
|
||||||
150
src/device/autoDetect/ScannedI2C.tsx
Normal file
150
src/device/autoDetect/ScannedI2C.tsx
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
import { Box, Button, Checkbox, FormControlLabel, Grid2, MenuItem, Radio, RadioGroup, TextField, Tooltip, Typography } 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";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
decimalAddress: number
|
||||||
|
deviceProduct: pond.DeviceProduct
|
||||||
|
componentSelectionCallback: (component: Component, checked: boolean) => void
|
||||||
|
availablePositions: DevicePositions
|
||||||
|
sensorNum?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ScannedI2C(props: Props){
|
||||||
|
const {decimalAddress, deviceProduct, componentSelectionCallback, availablePositions, sensorNum} = props
|
||||||
|
const [types, setTypes] = useState<quack.ComponentType[]>([])
|
||||||
|
const [subtypeOptions, setSubtypeOptions] = useState<Array<Subtype>>([])
|
||||||
|
const [selectedType, setSelectedType] = useState<quack.ComponentType>(quack.ComponentType.COMPONENT_TYPE_INVALID)
|
||||||
|
const [selectedSubtype, setSelectedSubtype] = useState(0)
|
||||||
|
const [addressInUse, setAddressInUse] = useState(false)
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
let types: quack.ComponentType[] = []
|
||||||
|
//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(decimalAddress)){
|
||||||
|
types.push(key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//this if can be taken out if we dont want to select the first component type by default
|
||||||
|
if(types.length > 0) {
|
||||||
|
setSelectedType(types[0])
|
||||||
|
buildSubtypeOptions(types[0])
|
||||||
|
checkAddressAvailable(types[0])
|
||||||
|
}
|
||||||
|
setTypes(types)
|
||||||
|
},[decimalAddress, deviceProduct])
|
||||||
|
|
||||||
|
const buildSubtypeOptions = (compType: quack.ComponentType) => {
|
||||||
|
let subtypes = getSubtypes(compType)
|
||||||
|
let validSub: Subtype[] = []
|
||||||
|
//have to exclude subtypes that are not I2C
|
||||||
|
subtypes.forEach((sub,i) => {
|
||||||
|
let addrTypes = getAddressTypes(compType, sub.key)
|
||||||
|
if (addrTypes.includes(quack.AddressType.ADDRESS_TYPE_I2C)){
|
||||||
|
validSub.push(sub)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//set the selected on to be the first in the valid selection
|
||||||
|
if(validSub.length > 0){
|
||||||
|
setSelectedSubtype(validSub[0].key)
|
||||||
|
}
|
||||||
|
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<HTMLInputElement>, 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 (
|
||||||
|
<Box sx={{marginY: 1}}>
|
||||||
|
{sensorNum && <Typography>Sensor {sensorNum}</Typography>}
|
||||||
|
<Grid2 container direction="row" alignItems="center" justifyContent="space-between">
|
||||||
|
<Grid2 size={3}>
|
||||||
|
<RadioGroup
|
||||||
|
value={selectedType}
|
||||||
|
onChange={(_, value) => {
|
||||||
|
let v = parseInt(value)
|
||||||
|
if (!isNaN(v)){
|
||||||
|
buildSubtypeOptions(v)
|
||||||
|
checkAddressAvailable(v)
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
{types.map((type, i) => {
|
||||||
|
return (
|
||||||
|
<FormControlLabel
|
||||||
|
key={i}
|
||||||
|
value={type}
|
||||||
|
control={<Radio />}
|
||||||
|
label={getFriendlyName(type)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</RadioGroup>
|
||||||
|
</Grid2>
|
||||||
|
<Grid2 size={8}>
|
||||||
|
{subtypeOptions.length > 0 &&
|
||||||
|
<TextField
|
||||||
|
value={selectedSubtype}
|
||||||
|
fullWidth
|
||||||
|
onChange={(event)=>{
|
||||||
|
let val = +event.target.value
|
||||||
|
setSelectedSubtype(val)
|
||||||
|
}}
|
||||||
|
select>
|
||||||
|
{subtypeOptions.map(s => (
|
||||||
|
<MenuItem value={s.key}>{s.friendlyName}</MenuItem>
|
||||||
|
))}
|
||||||
|
</TextField>
|
||||||
|
}
|
||||||
|
</Grid2>
|
||||||
|
<Grid2 size={1}>
|
||||||
|
<Tooltip
|
||||||
|
title="Add to list to be added to the device"
|
||||||
|
children={
|
||||||
|
<Checkbox
|
||||||
|
onChange={componentSelected}
|
||||||
|
disabled={addressInUse}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</Grid2>
|
||||||
|
</Grid2>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ import { quack } from "protobuf-ts/pond";
|
||||||
import { or } from "utils/types";
|
import { or } from "utils/types";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import { getSubtypes } from "pbHelpers/ComponentType";
|
import { getSubtypes } from "pbHelpers/ComponentType";
|
||||||
|
import { getFriendlyAddressTypeName, getHumanReadableAddress } from "pbHelpers/AddressType";
|
||||||
// import { getSubtypes } from "pbHelpers/ComponentType";
|
// import { getSubtypes } from "pbHelpers/ComponentType";
|
||||||
|
|
||||||
export class Component {
|
export class Component {
|
||||||
|
|
@ -105,4 +106,33 @@ export class Component {
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addressDescription = (deviceProduct?: pond.DeviceProduct) => {
|
||||||
|
if (
|
||||||
|
this.settings.addressType === quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY ||
|
||||||
|
(this.settings.addressType >= quack.AddressType.ADDRESS_TYPE_PIN_OFFSET1 &&
|
||||||
|
this.settings.addressType <= quack.AddressType.ADDRESS_TYPE_PIN_OFFSET100)
|
||||||
|
) {
|
||||||
|
let addressDescription = getHumanReadableAddress(
|
||||||
|
this.settings.addressType,
|
||||||
|
this.settings.type,
|
||||||
|
this.settings.address,
|
||||||
|
deviceProduct
|
||||||
|
);
|
||||||
|
if (addressDescription === "") {
|
||||||
|
addressDescription = "Internal";
|
||||||
|
}
|
||||||
|
let port = "Port: " + addressDescription;
|
||||||
|
let cableID = "";
|
||||||
|
if (
|
||||||
|
this.settings.addressType >= quack.AddressType.ADDRESS_TYPE_PIN_OFFSET1 &&
|
||||||
|
this.settings.addressType <= quack.AddressType.ADDRESS_TYPE_PIN_OFFSET100
|
||||||
|
) {
|
||||||
|
cableID = "Cable: " + (this.settings.addressType - 8);
|
||||||
|
}
|
||||||
|
return port + " " + cableID;
|
||||||
|
} else {
|
||||||
|
return getFriendlyAddressTypeName(this.settings.addressType);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,21 @@ const featureVersions: Map<string, FeatureVersionByPlatform> = new Map([
|
||||||
v2CellBlue: "2.0.44",
|
v2CellBlue: "2.0.44",
|
||||||
v2EthBlue: "2.0.44"
|
v2EthBlue: "2.0.44"
|
||||||
}
|
}
|
||||||
|
],[
|
||||||
|
"detectI2C",
|
||||||
|
{
|
||||||
|
photon: "NA",
|
||||||
|
electron: "NA",
|
||||||
|
v2Wifi: "2.1.6",
|
||||||
|
v2Cell: "2.1.6",
|
||||||
|
v2WifiS3: "2.1.6",
|
||||||
|
v2CellS3: "2.1.6",
|
||||||
|
v2CellBlack: "2.1.6",
|
||||||
|
v2CellGreen: "2.1.6",
|
||||||
|
v2WifiBlue: "2.1.6",
|
||||||
|
v2CellBlue: "2.1.6",
|
||||||
|
v2EthBlue: "2.1.6"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
export class Device {
|
export class Device {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Button, Divider, List, ListItem, Typography } from "@mui/material";
|
import { Button, Card, Divider, List, ListItem, Typography } from "@mui/material";
|
||||||
import Grid from '@mui/material/Grid2';
|
import Grid from '@mui/material/Grid2';
|
||||||
import { Component, Device, Interaction, User } from "models";
|
import { Component, Device, Interaction, User } from "models";
|
||||||
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
||||||
|
|
@ -20,6 +20,7 @@ import { isController } from "pbHelpers/ComponentType";
|
||||||
import { or } from "utils";
|
import { or } from "utils";
|
||||||
import ComponentDiagnostics from "component/ComponentDiagnostics";
|
import ComponentDiagnostics from "component/ComponentDiagnostics";
|
||||||
import DeviceWizard from "device/DeviceWizard";
|
import DeviceWizard from "device/DeviceWizard";
|
||||||
|
import DeviceScannedComponents from "device/autoDetect/DeviceScannedComponents";
|
||||||
|
|
||||||
export interface DevicePageData {
|
export interface DevicePageData {
|
||||||
device: Device;
|
device: Device;
|
||||||
|
|
@ -56,6 +57,7 @@ export default function DevicePage() {
|
||||||
|
|
||||||
const [components, setComponents] = useState<Map<string, Component>>(new Map());
|
const [components, setComponents] = useState<Map<string, Component>>(new Map());
|
||||||
const [diagnosticComponents, setDiagnosticComponents] = useState<Component[]>([]);
|
const [diagnosticComponents, setDiagnosticComponents] = useState<Component[]>([]);
|
||||||
|
const [scannedAddresses, setScannedAddresses] = useState<pond.ComponentAddressMap | undefined>(undefined)
|
||||||
// const [components, setComponents] = useState<Component[]>([]);
|
// const [components, setComponents] = useState<Component[]>([]);
|
||||||
|
|
||||||
const [addComponentManualDialogOpen, setAddComponentManualDialogOpen] = useState(false)
|
const [addComponentManualDialogOpen, setAddComponentManualDialogOpen] = useState(false)
|
||||||
|
|
@ -162,8 +164,21 @@ export default function DevicePage() {
|
||||||
.finally(() => setLoading(false));
|
.finally(() => setLoading(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loadPortScan = () => {
|
||||||
|
deviceAPI.listFoundComponents(device.id())
|
||||||
|
.then(resp => {
|
||||||
|
if (resp.data.foundComponents?.i2c){
|
||||||
|
setScannedAddresses(resp.data.foundComponents ?? undefined)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadDevice()
|
loadDevice()
|
||||||
|
loadPortScan()
|
||||||
}, [deviceID, as])
|
}, [deviceID, as])
|
||||||
|
|
||||||
const toggleNotificationPreference = () => {
|
const toggleNotificationPreference = () => {
|
||||||
|
|
@ -390,6 +405,8 @@ export default function DevicePage() {
|
||||||
refreshCallback={loadDevice}
|
refreshCallback={loadDevice}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
{/* add grid card here for I2C detected components */}
|
||||||
|
|
||||||
{diagnosticComponents.map(comp => (
|
{diagnosticComponents.map(comp => (
|
||||||
<Grid size={{ xs: 12 }} key={comp.key()}>
|
<Grid size={{ xs: 12 }} key={comp.key()}>
|
||||||
<ComponentDiagnostics
|
<ComponentDiagnostics
|
||||||
|
|
@ -402,7 +419,7 @@ export default function DevicePage() {
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Grid size={{ xs: 6, sm: 6, lg: 4, xl: 3 }} >
|
<Grid size={{ xs: 6, sm: 6, lg: 4, xl: 4 }} >
|
||||||
<DeviceWizard
|
<DeviceWizard
|
||||||
device={device}
|
device={device}
|
||||||
//permissions={permissions}
|
//permissions={permissions}
|
||||||
|
|
@ -410,10 +427,21 @@ export default function DevicePage() {
|
||||||
refreshCallback={loadDevice}
|
refreshCallback={loadDevice}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid size={{ xs: 6, sm: 6, lg: 8, xl: 9 }} >
|
{scannedAddresses &&
|
||||||
<Grid container direction="row" spacing={2}>
|
<Grid size={{ xs: 6, sm: 6, lg: 4, xl: 4 }}>
|
||||||
|
<DeviceScannedComponents
|
||||||
|
scannedComponents={scannedAddresses}
|
||||||
|
device={device}
|
||||||
|
availablePositions={availablePositions}
|
||||||
|
availableOffsets={availableOffsets}
|
||||||
|
refreshCallback={loadDevice}/>
|
||||||
|
</Grid>
|
||||||
|
}
|
||||||
|
{diagnosticComponents.length > 0 &&
|
||||||
|
<Grid size={{ xs: 6, sm: 6, lg: 4, xl: 4 }}>
|
||||||
|
<Grid container direction="row" spacing={2} width={"100%"}>
|
||||||
{diagnosticComponents.map(comp => (
|
{diagnosticComponents.map(comp => (
|
||||||
<Grid size={{ sm: 12, lg: 6, xl: 4 }} key={comp.key()}>
|
<Grid size={12} key={comp.key()}>
|
||||||
<ComponentDiagnostics
|
<ComponentDiagnostics
|
||||||
component={comp}
|
component={comp}
|
||||||
device={device}
|
device={device}
|
||||||
|
|
@ -423,6 +451,7 @@ export default function DevicePage() {
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
@ -443,7 +472,8 @@ export default function DevicePage() {
|
||||||
<DeviceActions
|
<DeviceActions
|
||||||
device={device}
|
device={device}
|
||||||
scanFunction={() => {
|
scanFunction={() => {
|
||||||
deviceAPI.detectI2C(device.id()).then(resp => {console.log("No errors")}).catch(err => {console.log("error")})
|
//deviceAPI.detectI2C(device.id()).then(resp => {console.log("No errors")}).catch(err => {console.log("error")})
|
||||||
|
deviceAPI.listFoundComponents(device.id()).then(resp => console.log(resp)).catch(err => {console.log("errors")})
|
||||||
}}
|
}}
|
||||||
isPaused={false}
|
isPaused={false}
|
||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ export const I2C: AddressTypeExtension = {
|
||||||
[quack.ComponentType.COMPONENT_TYPE_STEPPER_MOTOR, 0x13],
|
[quack.ComponentType.COMPONENT_TYPE_STEPPER_MOTOR, 0x13],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_PH, 0x3f],
|
[quack.ComponentType.COMPONENT_TYPE_PH, 0x3f],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_DHT, 0x3f],
|
[quack.ComponentType.COMPONENT_TYPE_DHT, 0x3f],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, 0x3f],
|
// [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, 0x3f], //component type deprecated?
|
||||||
[quack.ComponentType.COMPONENT_TYPE_CAPACITANCE, 0x4f],
|
[quack.ComponentType.COMPONENT_TYPE_CAPACITANCE, 0x4f],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE, 0x4f],
|
[quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE, 0x4f],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_SEN5X, 0x68],
|
[quack.ComponentType.COMPONENT_TYPE_SEN5X, 0x68],
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ const DefaultAvailability: DeviceAvailabilityMap = new Map<quack.AddressType, De
|
||||||
[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]], //TODO temp fix, needs to be fixed to use channels similar to PH
|
||||||
[quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]],
|
// [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]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_CAPACITANCE, [0x50]],
|
[quack.ComponentType.COMPONENT_TYPE_CAPACITANCE, [0x50]],
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export const BindaptPlusAvailability: DeviceAvailabilityMap = new Map<
|
||||||
new Map<quack.ComponentType, number[]>([
|
new Map<quack.ComponentType, number[]>([
|
||||||
[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]],
|
// [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]], //component type deprecated?
|
||||||
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
||||||
|
|
@ -48,7 +48,7 @@ export const BindaptPlusModAvailability: DeviceAvailabilityMap = new Map<
|
||||||
new Map<quack.ComponentType, number[]>([
|
new Map<quack.ComponentType, number[]>([
|
||||||
//[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]],
|
// [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]], //component type deprecated?
|
||||||
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
||||||
|
|
@ -78,7 +78,7 @@ export const BindaptPlusProAvailability: DeviceAvailabilityMap = new Map<
|
||||||
new Map<quack.ComponentType, number[]>([
|
new Map<quack.ComponentType, number[]>([
|
||||||
[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]],
|
// [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
||||||
|
|
@ -109,7 +109,7 @@ export const BindaptPlusProModAvailability: DeviceAvailabilityMap = new Map<
|
||||||
new Map<quack.ComponentType, number[]>([
|
new Map<quack.ComponentType, number[]>([
|
||||||
//[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]],
|
// [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]], //component type deprecated?
|
||||||
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
||||||
|
|
@ -136,7 +136,7 @@ export const BindaptPlusLiteAvailability: DeviceAvailabilityMap = new Map<
|
||||||
new Map<quack.ComponentType, number[]>([
|
new Map<quack.ComponentType, number[]>([
|
||||||
[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]],
|
// [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]], //component type deprecated?
|
||||||
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
||||||
|
|
@ -192,7 +192,7 @@ export const BindaptUltimateAvailability: DeviceAvailabilityMap = new Map<
|
||||||
new Map<quack.ComponentType, number[]>([
|
new Map<quack.ComponentType, number[]>([
|
||||||
[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]],
|
// [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]], //component type deprecated?
|
||||||
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
||||||
|
|
@ -219,7 +219,7 @@ export const BinMonitorAvailability: DeviceAvailabilityMap = new Map<
|
||||||
new Map<quack.ComponentType, number[]>([
|
new Map<quack.ComponentType, number[]>([
|
||||||
[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]],
|
// [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]], //component type deprecated?
|
||||||
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]]
|
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]]
|
||||||
])
|
])
|
||||||
|
|
@ -248,7 +248,7 @@ export const BindaptV2MonitorAvailability: DeviceAvailabilityMap = new Map<
|
||||||
new Map<quack.ComponentType, number[]>([
|
new Map<quack.ComponentType, number[]>([
|
||||||
//[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]],
|
// [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]], //component type deprecated?
|
||||||
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
||||||
|
|
@ -280,7 +280,7 @@ export const BindaptV2AutomateAvailability: DeviceAvailabilityMap = new Map<
|
||||||
new Map<quack.ComponentType, number[]>([
|
new Map<quack.ComponentType, number[]>([
|
||||||
//[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]],
|
// [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]], //component type deprecated?
|
||||||
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
[quack.ComponentType.COMPONENT_TYPE_CO2, [0x61]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ const Weather: DeviceProductDescriber = {
|
||||||
new Map<quack.ComponentType, number[]>([
|
new Map<quack.ComponentType, number[]>([
|
||||||
[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]],
|
// [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]], //deprecated?
|
||||||
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]]
|
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]]
|
||||||
])
|
])
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ export const NexusSTAvailability: DeviceAvailabilityMap = new Map<
|
||||||
new Map<quack.ComponentType, number[]>([
|
new Map<quack.ComponentType, number[]>([
|
||||||
[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]],
|
// [quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT, [0x40]], //component type deprecated?
|
||||||
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
[quack.ComponentType.COMPONENT_TYPE_LIDAR, [0x62]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]]
|
||||||
])
|
])
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ export interface IDeviceAPIContext {
|
||||||
) => Promise<AxiosResponse<pond.GetDevicePageDataResponse>>;
|
) => Promise<AxiosResponse<pond.GetDevicePageDataResponse>>;
|
||||||
getMulti: (ids: number[] | string[], otherTeam?: string) => Promise<AxiosResponse<pond.GetMultiDeviceResponse>>;
|
getMulti: (ids: number[] | string[], otherTeam?: string) => Promise<AxiosResponse<pond.GetMultiDeviceResponse>>;
|
||||||
detectI2C: (id: number, otherTeam?: string) => Promise<AxiosResponse<pond.DetectI2CResponse>>;
|
detectI2C: (id: number, otherTeam?: string) => Promise<AxiosResponse<pond.DetectI2CResponse>>;
|
||||||
|
listFoundComponents: (id: number, otherTeam?: string) => Promise<AxiosResponse<pond.ListFoundComponentsResponse>>
|
||||||
getGeoJson: (id: number | string, demo?: boolean, otherTeam?: string) => Promise<any>;
|
getGeoJson: (id: number | string, demo?: boolean, otherTeam?: string) => Promise<any>;
|
||||||
getMultiGeoJson: (ids: number[] | string[], otherTeam?: string) => Promise<any>;
|
getMultiGeoJson: (ids: number[] | string[], otherTeam?: string) => Promise<any>;
|
||||||
list: (
|
list: (
|
||||||
|
|
@ -960,6 +961,19 @@ export default function DeviceProvider(props: PropsWithChildren<Props>) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const listFoundComponents = (id: number, otherTeam?: string) => {
|
||||||
|
let url = "/devices/" + id + "/listScannedComponents";
|
||||||
|
const view = otherTeam ? otherTeam : as
|
||||||
|
if(view) url = url + "?as=" + view
|
||||||
|
return new Promise<AxiosResponse<pond.ListFoundComponentsResponse>>((resolve, reject) => {
|
||||||
|
get<pond.ListFoundComponentsResponse>(pondURL(url)).then(resp => {
|
||||||
|
return resolve(resp)
|
||||||
|
}).catch(err => {
|
||||||
|
return reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DeviceAPIContext.Provider
|
<DeviceAPIContext.Provider
|
||||||
value={{
|
value={{
|
||||||
|
|
@ -1006,7 +1020,8 @@ export default function DeviceProvider(props: PropsWithChildren<Props>) {
|
||||||
buyData,
|
buyData,
|
||||||
updateComponentPreferences,
|
updateComponentPreferences,
|
||||||
listDeviceComponentPreferences,
|
listDeviceComponentPreferences,
|
||||||
detectI2C
|
detectI2C,
|
||||||
|
listFoundComponents
|
||||||
}}>
|
}}>
|
||||||
{children}
|
{children}
|
||||||
</DeviceAPIContext.Provider>
|
</DeviceAPIContext.Provider>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue