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
|
|
@ -49,6 +49,7 @@ export default function DeviceScannedComponents(props: Props){
|
|||
},[scannedComponents])
|
||||
|
||||
useEffect(() => {
|
||||
console.log(components)
|
||||
let steps: CompStep[] = []
|
||||
components.forEach(comp => {
|
||||
steps.push({
|
||||
|
|
@ -117,7 +118,7 @@ export default function DeviceScannedComponents(props: Props){
|
|||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
close();
|
||||
setOpenDialog(false)
|
||||
}}>
|
||||
Cancel
|
||||
</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)
|
||||
if(checked){
|
||||
//add the component to the list
|
||||
cloneList.push(newComponent)
|
||||
cloneList = cloneList.concat(newComponents)
|
||||
}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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
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 { getAddressTypes, getFriendlyName, GetSecondaryComponents, 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";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
interface Props {
|
||||
decimalAddress: number
|
||||
deviceProduct: pond.DeviceProduct
|
||||
componentSelectionCallback: (component: Component, checked: boolean) => void
|
||||
componentSelectionCallback: (component: Component[], checked: boolean) => void
|
||||
availablePositions: DevicePositions
|
||||
sensorNum?: number
|
||||
}
|
||||
|
|
@ -19,8 +19,9 @@ 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 [selectedPrimaryType, setSelectedPrimaryType] = useState<quack.ComponentType>(quack.ComponentType.COMPONENT_TYPE_INVALID)
|
||||
const [selectedPrimarySubtype, setSelectedPrimarySubtype] = useState(0)
|
||||
const [added,setAdded] = useState(false)
|
||||
const [addressInUse, setAddressInUse] = useState(false)
|
||||
|
||||
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
|
||||
if(types.length > 0) {
|
||||
setSelectedType(types[0])
|
||||
setSelectedPrimaryType(types[0])
|
||||
buildSubtypeOptions(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
|
||||
if(validSub.length > 0){
|
||||
setSelectedSubtype(validSub[0].key)
|
||||
setSelectedPrimarySubtype(validSub[0].key)
|
||||
}
|
||||
setSubtypeOptions(validSub)
|
||||
}
|
||||
|
|
@ -78,15 +79,25 @@ export default function ScannedI2C(props: Props){
|
|||
|
||||
|
||||
const componentSelected = (event: React.ChangeEvent<HTMLInputElement>, checked: boolean) => {
|
||||
let toAdd: Component[] = []
|
||||
setAdded(true)
|
||||
//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)
|
||||
let primaryComponent = Component.create()
|
||||
primaryComponent.settings.type = selectedPrimaryType
|
||||
primaryComponent.settings.subtype = selectedPrimarySubtype
|
||||
primaryComponent.settings.addressType = quack.AddressType.ADDRESS_TYPE_I2C
|
||||
primaryComponent.settings.address = decimalAddress
|
||||
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
|
||||
componentSelectionCallback(component, checked)
|
||||
componentSelectionCallback(toAdd, checked)
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -94,58 +105,64 @@ export default function ScannedI2C(props: Props){
|
|||
<Box sx={{marginY: 1}}>
|
||||
{sensorNum && <Typography>Sensor {sensorNum}</Typography>}
|
||||
{types.length > 0 ?
|
||||
<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}
|
||||
/>
|
||||
<React.Fragment>
|
||||
<Grid2 container direction="row" alignItems="center" justifyContent="space-between">
|
||||
<Grid2 size={3}>
|
||||
<RadioGroup
|
||||
value={selectedPrimaryType}
|
||||
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={selectedPrimarySubtype}
|
||||
fullWidth
|
||||
onChange={(event)=>{
|
||||
let val = +event.target.value
|
||||
setSelectedPrimarySubtype(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
|
||||
value={added}
|
||||
onChange={componentSelected}
|
||||
//disabled={addressInUse}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
{
|
||||
|
||||
}
|
||||
</React.Fragment>
|
||||
:
|
||||
<Typography>Sensor Not Supported By Product</Typography>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ export interface ComponentTypeExtension {
|
|||
smoothingAverages?: number,
|
||||
filters?: GraphFilters
|
||||
) => LineChartData;
|
||||
secondaryComponentSettings?: () => pond.ComponentSettings[]
|
||||
}
|
||||
|
||||
export interface Summary {
|
||||
|
|
@ -621,6 +622,11 @@ export function GetComponentIcon(
|
|||
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)
|
||||
// export function getGraphProps(
|
||||
// componentType: quack.ComponentType,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,18 @@ export function CO2(subtype: number = 0): ComponentTypeExtension {
|
|||
);
|
||||
return {
|
||||
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",
|
||||
description: "Measures the parts per million of CO2",
|
||||
isController: false,
|
||||
|
|
@ -71,6 +82,24 @@ export function CO2(subtype: number = 0): ComponentTypeExtension {
|
|||
minMeasurementPeriodMs: 5000,
|
||||
icon: (theme?: "light" | "dark"): string | undefined => {
|
||||
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