expanded component extensions with secondary components (mainly due to the scd30)
This commit is contained in:
parent
1f733d1d01
commit
98717b7c00
5 changed files with 131 additions and 75 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#872519b46c04050d5cdf1c0efee7236119a83ed2",
|
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#c03dc20d337c77fbe06dfe880cd35fff28c9c244",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"protobufjs": "^6.8.8"
|
"protobufjs": "^6.8.8"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ export default function DeviceScannedComponents(props: Props){
|
||||||
},[scannedComponents])
|
},[scannedComponents])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.log(components)
|
||||||
let steps: CompStep[] = []
|
let steps: CompStep[] = []
|
||||||
components.forEach(comp => {
|
components.forEach(comp => {
|
||||||
steps.push({
|
steps.push({
|
||||||
|
|
@ -117,7 +118,7 @@ export default function DeviceScannedComponents(props: Props){
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
close();
|
setOpenDialog(false)
|
||||||
}}>
|
}}>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -164,20 +165,23 @@ export default function DeviceScannedComponents(props: Props){
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const componentSelection = (newComponent: Component, checked: boolean) => {
|
const componentSelection = (newComponents: Component[], checked: boolean) => {
|
||||||
let cloneList = cloneDeep(components)
|
let cloneList = cloneDeep(components)
|
||||||
if(checked){
|
if(checked){
|
||||||
//add the component to the list
|
//add the component to the list
|
||||||
cloneList.push(newComponent)
|
cloneList = cloneList.concat(newComponents)
|
||||||
}else{
|
}else{
|
||||||
//remove any components that match the component location: (type)-(addressType)-(address)
|
newComponents.forEach(newComponent => {
|
||||||
components.forEach((comp, i) => {
|
//remove any components that match the component location: (type)-(addressType)-(address)
|
||||||
//check the components location against the one in the list
|
cloneList.forEach((comp, i) => {
|
||||||
if(comp.locationString() === newComponent.locationString()){
|
//check the components location against the one in the list
|
||||||
cloneList.splice(i, 1)
|
if(comp.locationString() === newComponent.locationString()){
|
||||||
}
|
cloneList.splice(i, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
console.log(cloneList)
|
||||||
setComponents(cloneList)
|
setComponents(cloneList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
import { Box, Button, Checkbox, FormControlLabel, Grid2, MenuItem, Radio, RadioGroup, TextField, Tooltip, Typography } from "@mui/material";
|
import { Box, Button, Checkbox, FormControlLabel, Grid2, MenuItem, Radio, RadioGroup, TextField, Tooltip, Typography } from "@mui/material";
|
||||||
import { Component } from "models";
|
import { Component } from "models";
|
||||||
import { getAddressTypes, getFriendlyName, getSubtypes, Subtype } from "pbHelpers/ComponentType";
|
import { getAddressTypes, getFriendlyName, GetSecondaryComponents, getSubtypes, Subtype } from "pbHelpers/ComponentType";
|
||||||
import { ComponentAvailabilityMap, DevicePositions } from "pbHelpers/DeviceAvailability";
|
import { ComponentAvailabilityMap, DevicePositions } from "pbHelpers/DeviceAvailability";
|
||||||
import { GetProductAvailability } from "products/DeviceProduct";
|
import { GetProductAvailability } 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 { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
decimalAddress: number
|
decimalAddress: number
|
||||||
deviceProduct: pond.DeviceProduct
|
deviceProduct: pond.DeviceProduct
|
||||||
componentSelectionCallback: (component: Component, checked: boolean) => void
|
componentSelectionCallback: (component: Component[], checked: boolean) => void
|
||||||
availablePositions: DevicePositions
|
availablePositions: DevicePositions
|
||||||
sensorNum?: number
|
sensorNum?: number
|
||||||
}
|
}
|
||||||
|
|
@ -19,8 +19,9 @@ export default function ScannedI2C(props: Props){
|
||||||
const {decimalAddress, deviceProduct, componentSelectionCallback, availablePositions, sensorNum} = props
|
const {decimalAddress, deviceProduct, componentSelectionCallback, availablePositions, sensorNum} = props
|
||||||
const [types, setTypes] = useState<quack.ComponentType[]>([])
|
const [types, setTypes] = useState<quack.ComponentType[]>([])
|
||||||
const [subtypeOptions, setSubtypeOptions] = useState<Array<Subtype>>([])
|
const [subtypeOptions, setSubtypeOptions] = useState<Array<Subtype>>([])
|
||||||
const [selectedType, setSelectedType] = useState<quack.ComponentType>(quack.ComponentType.COMPONENT_TYPE_INVALID)
|
const [selectedPrimaryType, setSelectedPrimaryType] = useState<quack.ComponentType>(quack.ComponentType.COMPONENT_TYPE_INVALID)
|
||||||
const [selectedSubtype, setSelectedSubtype] = useState(0)
|
const [selectedPrimarySubtype, setSelectedPrimarySubtype] = useState(0)
|
||||||
|
const [added,setAdded] = useState(false)
|
||||||
const [addressInUse, setAddressInUse] = useState(false)
|
const [addressInUse, setAddressInUse] = useState(false)
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
|
|
@ -41,7 +42,7 @@ export default function ScannedI2C(props: Props){
|
||||||
}
|
}
|
||||||
//this if can be taken out if we dont want to select the first component type by default
|
//this if can be taken out if we dont want to select the first component type by default
|
||||||
if(types.length > 0) {
|
if(types.length > 0) {
|
||||||
setSelectedType(types[0])
|
setSelectedPrimaryType(types[0])
|
||||||
buildSubtypeOptions(types[0])
|
buildSubtypeOptions(types[0])
|
||||||
checkAddressAvailable(types[0])
|
checkAddressAvailable(types[0])
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +61,7 @@ export default function ScannedI2C(props: Props){
|
||||||
})
|
})
|
||||||
//set the selected on to be the first in the valid selection
|
//set the selected on to be the first in the valid selection
|
||||||
if(validSub.length > 0){
|
if(validSub.length > 0){
|
||||||
setSelectedSubtype(validSub[0].key)
|
setSelectedPrimarySubtype(validSub[0].key)
|
||||||
}
|
}
|
||||||
setSubtypeOptions(validSub)
|
setSubtypeOptions(validSub)
|
||||||
}
|
}
|
||||||
|
|
@ -78,15 +79,25 @@ export default function ScannedI2C(props: Props){
|
||||||
|
|
||||||
|
|
||||||
const componentSelected = (event: React.ChangeEvent<HTMLInputElement>, checked: boolean) => {
|
const componentSelected = (event: React.ChangeEvent<HTMLInputElement>, checked: boolean) => {
|
||||||
|
let toAdd: Component[] = []
|
||||||
|
setAdded(true)
|
||||||
//build a component with given information and defaults for the rest
|
//build a component with given information and defaults for the rest
|
||||||
let component = Component.create()
|
let primaryComponent = Component.create()
|
||||||
component.settings.type = selectedType
|
primaryComponent.settings.type = selectedPrimaryType
|
||||||
component.settings.subtype = selectedSubtype
|
primaryComponent.settings.subtype = selectedPrimarySubtype
|
||||||
component.settings.addressType = quack.AddressType.ADDRESS_TYPE_I2C
|
primaryComponent.settings.addressType = quack.AddressType.ADDRESS_TYPE_I2C
|
||||||
component.settings.address = decimalAddress
|
primaryComponent.settings.address = decimalAddress
|
||||||
component.settings.name = getFriendlyName(selectedType, selectedSubtype)
|
primaryComponent.settings.name = getFriendlyName(selectedPrimaryType, selectedPrimarySubtype)
|
||||||
|
toAdd.push(primaryComponent)
|
||||||
|
|
||||||
|
GetSecondaryComponents(selectedPrimaryType, selectedPrimarySubtype).forEach(secComp => {
|
||||||
|
let component = Component.create()
|
||||||
|
component.settings = secComp
|
||||||
|
toAdd.push(component)
|
||||||
|
})
|
||||||
|
|
||||||
//return the component and the checked status to the parent
|
//return the component and the checked status to the parent
|
||||||
componentSelectionCallback(component, checked)
|
componentSelectionCallback(toAdd, checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -94,58 +105,64 @@ export default function ScannedI2C(props: Props){
|
||||||
<Box sx={{marginY: 1}}>
|
<Box sx={{marginY: 1}}>
|
||||||
{sensorNum && <Typography>Sensor {sensorNum}</Typography>}
|
{sensorNum && <Typography>Sensor {sensorNum}</Typography>}
|
||||||
{types.length > 0 ?
|
{types.length > 0 ?
|
||||||
<Grid2 container direction="row" alignItems="center" justifyContent="space-between">
|
<React.Fragment>
|
||||||
<Grid2 size={3}>
|
<Grid2 container direction="row" alignItems="center" justifyContent="space-between">
|
||||||
<RadioGroup
|
<Grid2 size={3}>
|
||||||
value={selectedType}
|
<RadioGroup
|
||||||
onChange={(_, value) => {
|
value={selectedPrimaryType}
|
||||||
let v = parseInt(value)
|
onChange={(_, value) => {
|
||||||
if (!isNaN(v)){
|
let v = parseInt(value)
|
||||||
buildSubtypeOptions(v)
|
if (!isNaN(v)){
|
||||||
checkAddressAvailable(v)
|
buildSubtypeOptions(v)
|
||||||
}
|
checkAddressAvailable(v)
|
||||||
}}>
|
}
|
||||||
{types.map((type, i) => {
|
}}>
|
||||||
return (
|
{types.map((type, i) => {
|
||||||
<FormControlLabel
|
return (
|
||||||
key={i}
|
<FormControlLabel
|
||||||
value={type}
|
key={i}
|
||||||
control={<Radio />}
|
value={type}
|
||||||
label={getFriendlyName(type)}
|
control={<Radio />}
|
||||||
/>
|
label={getFriendlyName(type)}
|
||||||
)
|
/>
|
||||||
})}
|
)
|
||||||
</RadioGroup>
|
})}
|
||||||
</Grid2>
|
</RadioGroup>
|
||||||
<Grid2 size={8}>
|
</Grid2>
|
||||||
{subtypeOptions.length > 0 &&
|
<Grid2 size={8}>
|
||||||
<TextField
|
{subtypeOptions.length > 0 &&
|
||||||
value={selectedSubtype}
|
<TextField
|
||||||
fullWidth
|
value={selectedPrimarySubtype}
|
||||||
onChange={(event)=>{
|
fullWidth
|
||||||
let val = +event.target.value
|
onChange={(event)=>{
|
||||||
setSelectedSubtype(val)
|
let val = +event.target.value
|
||||||
}}
|
setSelectedPrimarySubtype(val)
|
||||||
select>
|
}}
|
||||||
{subtypeOptions.map(s => (
|
select>
|
||||||
<MenuItem value={s.key}>{s.friendlyName}</MenuItem>
|
{subtypeOptions.map(s => (
|
||||||
))}
|
<MenuItem value={s.key}>{s.friendlyName}</MenuItem>
|
||||||
</TextField>
|
))}
|
||||||
}
|
</TextField>
|
||||||
</Grid2>
|
|
||||||
<Grid2 size={1}>
|
|
||||||
<Tooltip
|
|
||||||
title="Add to list to be added to the device"
|
|
||||||
children={
|
|
||||||
<Checkbox
|
|
||||||
onChange={componentSelected}
|
|
||||||
disabled={addressInUse}
|
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
/>
|
</Grid2>
|
||||||
|
<Grid2 size={1}>
|
||||||
|
<Tooltip
|
||||||
|
title="Add to list to be added to the device"
|
||||||
|
children={
|
||||||
|
<Checkbox
|
||||||
|
value={added}
|
||||||
|
onChange={componentSelected}
|
||||||
|
//disabled={addressInUse}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</Grid2>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
</Grid2>
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
</React.Fragment>
|
||||||
:
|
:
|
||||||
<Typography>Sensor Not Supported By Product</Typography>
|
<Typography>Sensor Not Supported By Product</Typography>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,7 @@ export interface ComponentTypeExtension {
|
||||||
smoothingAverages?: number,
|
smoothingAverages?: number,
|
||||||
filters?: GraphFilters
|
filters?: GraphFilters
|
||||||
) => LineChartData;
|
) => LineChartData;
|
||||||
|
secondaryComponentSettings?: () => pond.ComponentSettings[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Summary {
|
export interface Summary {
|
||||||
|
|
@ -621,6 +622,11 @@ export function GetComponentIcon(
|
||||||
return describer.icon ? describer.icon(theme) : undefined;
|
return describer.icon ? describer.icon(theme) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function GetSecondaryComponents(type: quack.ComponentType, subtype?: number): pond.ComponentSettings[] {
|
||||||
|
let describer = extension(type, subtype)
|
||||||
|
return describer.secondaryComponentSettings ? describer.secondaryComponentSettings() : []
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: deprecated function, new graphs are handled in measurementChart (using reCharts instead of victory)
|
//TODO: deprecated function, new graphs are handled in measurementChart (using reCharts instead of victory)
|
||||||
// export function getGraphProps(
|
// export function getGraphProps(
|
||||||
// componentType: quack.ComponentType,
|
// componentType: quack.ComponentType,
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,18 @@ export function CO2(subtype: number = 0): ComponentTypeExtension {
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
type: quack.ComponentType.COMPONENT_TYPE_CO2,
|
type: quack.ComponentType.COMPONENT_TYPE_CO2,
|
||||||
subtypes: [],
|
subtypes: [
|
||||||
|
{
|
||||||
|
key: quack.Co2Subtype.CO2_SUBTYPE_NONE,
|
||||||
|
value: "CO2_SUBTYPE_NONE",
|
||||||
|
friendlyName: "CO2 Only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: quack.Co2Subtype.CO2_SUBTYPE_SCD30,
|
||||||
|
value: "CO2_SUBTYPE_SCD30",
|
||||||
|
friendlyName: "SCD30 (CO2)"
|
||||||
|
},
|
||||||
|
],
|
||||||
friendlyName: "CO2",
|
friendlyName: "CO2",
|
||||||
description: "Measures the parts per million of CO2",
|
description: "Measures the parts per million of CO2",
|
||||||
isController: false,
|
isController: false,
|
||||||
|
|
@ -71,6 +82,24 @@ export function CO2(subtype: number = 0): ComponentTypeExtension {
|
||||||
minMeasurementPeriodMs: 5000,
|
minMeasurementPeriodMs: 5000,
|
||||||
icon: (theme?: "light" | "dark"): string | undefined => {
|
icon: (theme?: "light" | "dark"): string | undefined => {
|
||||||
return theme === "light" ? Co2SensorDarkIcon : Co2SensorLightIcon;
|
return theme === "light" ? Co2SensorDarkIcon : Co2SensorLightIcon;
|
||||||
|
},
|
||||||
|
secondaryComponentSettings: () => {
|
||||||
|
let secondaryComps: pond.ComponentSettings[] = []
|
||||||
|
switch (subtype){ //doesn't have a default because it would just do nothing
|
||||||
|
case quack.Co2Subtype.CO2_SUBTYPE_SCD30:
|
||||||
|
let tempHumComp: pond.ComponentSettings = pond.ComponentSettings.create()
|
||||||
|
//set the defaults for the component
|
||||||
|
tempHumComp.type = quack.ComponentType.COMPONENT_TYPE_DHT
|
||||||
|
tempHumComp.subtype = quack.DHTSubtype.DHT_SUBTYPE_SCD30
|
||||||
|
tempHumComp.addressType = quack.AddressType.ADDRESS_TYPE_I2C
|
||||||
|
tempHumComp.address = 0x40
|
||||||
|
tempHumComp.name = "SCD30 (Temp/Humidity)"
|
||||||
|
//add it to the array to be returned
|
||||||
|
secondaryComps.push(tempHumComp)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
//switch statement here that uses the subtype to determine whaat the secondary component is
|
||||||
|
return secondaryComps
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue