From 98717b7c00bd8c295b9946758bb036fbff08b4a7 Mon Sep 17 00:00:00 2001 From: csawatzky Date: Wed, 2 Jul 2025 16:49:38 -0600 Subject: [PATCH] expanded component extensions with secondary components (mainly due to the scd30) --- package-lock.json | 2 +- .../autoDetect/DeviceScannedComponents.tsx | 22 +-- src/device/autoDetect/ScannedI2C.tsx | 145 ++++++++++-------- src/pbHelpers/ComponentType.tsx | 6 + src/pbHelpers/ComponentTypes/CO2.ts | 31 +++- 5 files changed, 131 insertions(+), 75 deletions(-) diff --git a/package-lock.json b/package-lock.json index e96dec5..0e85caa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10889,7 +10889,7 @@ }, "node_modules/protobuf-ts": { "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": { "protobufjs": "^6.8.8" } diff --git a/src/device/autoDetect/DeviceScannedComponents.tsx b/src/device/autoDetect/DeviceScannedComponents.tsx index e1651de..8b7cf7c 100644 --- a/src/device/autoDetect/DeviceScannedComponents.tsx +++ b/src/device/autoDetect/DeviceScannedComponents.tsx @@ -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 @@ -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) } diff --git a/src/device/autoDetect/ScannedI2C.tsx b/src/device/autoDetect/ScannedI2C.tsx index 56b571d..d937c7d 100644 --- a/src/device/autoDetect/ScannedI2C.tsx +++ b/src/device/autoDetect/ScannedI2C.tsx @@ -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([]) const [subtypeOptions, setSubtypeOptions] = useState>([]) - const [selectedType, setSelectedType] = useState(quack.ComponentType.COMPONENT_TYPE_INVALID) - const [selectedSubtype, setSelectedSubtype] = useState(0) + const [selectedPrimaryType, setSelectedPrimaryType] = useState(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, 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){ {sensorNum && Sensor {sensorNum}} {types.length > 0 ? - - - { - let v = parseInt(value) - if (!isNaN(v)){ - buildSubtypeOptions(v) - checkAddressAvailable(v) - } - }}> - {types.map((type, i) => { - return ( - } - label={getFriendlyName(type)} - /> - ) - })} - - - - {subtypeOptions.length > 0 && - { - let val = +event.target.value - setSelectedSubtype(val) - }} - select> - {subtypeOptions.map(s => ( - {s.friendlyName} - ))} - - } - - - + + + + { + let v = parseInt(value) + if (!isNaN(v)){ + buildSubtypeOptions(v) + checkAddressAvailable(v) + } + }}> + {types.map((type, i) => { + return ( + } + label={getFriendlyName(type)} + /> + ) + })} + + + + {subtypeOptions.length > 0 && + { + let val = +event.target.value + setSelectedPrimarySubtype(val) + }} + select> + {subtypeOptions.map(s => ( + {s.friendlyName} + ))} + } - /> - + + + + } + /> + + - + { + + } + : Sensor Not Supported By Product } diff --git a/src/pbHelpers/ComponentType.tsx b/src/pbHelpers/ComponentType.tsx index 39b0773..2d66c9d 100644 --- a/src/pbHelpers/ComponentType.tsx +++ b/src/pbHelpers/ComponentType.tsx @@ -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, diff --git a/src/pbHelpers/ComponentTypes/CO2.ts b/src/pbHelpers/ComponentTypes/CO2.ts index 8483e31..e6ceeb6 100644 --- a/src/pbHelpers/ComponentTypes/CO2.ts +++ b/src/pbHelpers/ComponentTypes/CO2.ts @@ -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 } }; }