Merge branch 'staging_environment' into dev_environment

This commit is contained in:
csawatzky 2025-04-30 17:03:37 -06:00
commit e8b7eeb648
4 changed files with 230 additions and 2 deletions

205
src/common/StatusSen5x.tsx Normal file
View file

@ -0,0 +1,205 @@
import { Box, Grid2, Theme, Tooltip, Typography } from "@mui/material";
import { blue, green, orange } from "@mui/material/colors";
import { makeStyles } from "@mui/styles";
import { Device } from "models";
import PulseBox from "./PulseBox";
import { or } from "utils";
import { useEffect, useState } from "react";
interface Props {
device: Device
}
const useStyles = makeStyles((theme: Theme) => {
const lightMode = theme.palette?.mode === "light";
return ({
box: {
display: "inline-block",
borderRadius: "6px",
backgroundColor: lightMode ? "rgb(210, 210, 210)" : "rgb(50, 50, 50)",
padding: theme.spacing(0.75),
marginRight: "auto",
margin: theme.spacing(1),
width: "72px",
height: "50px",
},
carouselContainer: {
position: 'relative',
height: '40px',
overflow: 'hidden',
textAlign: "center",
},
carouselItem: {
opacity: 0,
transform: 'translateX(100%)',
transition: 'opacity 0.5s ease, transform 0.5s ease',
position: 'absolute',
width: '100%',
// height: '100%',
},
active: {
opacity: 1,
transform: 'translateX(0)',
},
inactive: {
transform: 'translateX(-100%)',
},
})
})
export default function StatusPlenum(props: Props) {
const { device } = props;
const classes = useStyles()
const colors = or(device.status.plenum?.overlays.map(overlay => overlay.color), []);
const messages = or(device.status.plenum?.overlays.map(overlay => overlay.message), []);
const [color, setColor] = useState(colors.length > 0 ? colors[0] : "");
const [, setColorIndex] = useState(0)
useEffect(() => {
const interval = setInterval(() => {
setColorIndex(prevIndex => {
const newIndex = prevIndex >= colors.length - 1 ? 0 : prevIndex + 1;
setColor(colors[newIndex]); // Use the new index here
return newIndex;
});
}, 5000);
return () => clearInterval(interval);
}, []);
const [currentIndex, setCurrentIndex] = useState(0);
// Auto-cycle through measurements every 3 seconds
useEffect(() => {
const interval = setInterval(() => {
setCurrentIndex((prevIndex) => (prevIndex + 1) % 4);
}, 3000); // Adjust timing as needed (3000ms = 3s)
return () => clearInterval(interval); // Cleanup on unmount
}, []);
const tooltip = () => {
if (messages.length === 0) return null
if (messages.length < 2) return (
messages[0]
)
return (
<Grid2 container direction={"column"}>
<Grid2 container direction="row">
<Typography fontWeight={"bold"} variant="caption">
Overlay Messages
</Typography>
</Grid2>
{messages.map((message, index) => {
return (
<Grid2 key={"tooltip-overly-message-" + message} container direction="row" alignItems={"center"}>
<Box
sx={{
width: 10, // Size of the square
height: 10,
backgroundColor: colors[index], // Passed color prop
borderRadius: 1, // Optional: slight rounding, remove for sharp square
border: "1px solid black",
}}
/>
<Typography variant="caption" sx={{ marginLeft: 1 }}>
{message}
</Typography>
</Grid2>
)
})}
</Grid2>
)
}
return (
<Tooltip title={tooltip()}>
<PulseBox color={color} className={classes.box} >
{/* <Grid2 container direction="column" > */}
<Grid2 container direction="column" >
<Grid2 container direction="column"
className={`${classes.carouselItem} ${
0 === currentIndex ? classes.active : classes.inactive
}`}
>
<Grid2>
<Typography variant="body2" style={{ color: orange[700]}}>
{device.status.sen5x?.temperature.toFixed(1)}°C
</Typography>
</Grid2>
<Grid2>
<Typography variant="body2" style={{ color: blue[700]}}>
{device.status.sen5x?.humidity.toFixed(1)}%
</Typography>
</Grid2>
</Grid2>
<Grid2 container direction="column"
className={`${classes.carouselItem} ${
1 === currentIndex ? classes.active : classes.inactive
}`}
>
<Grid2>
<Typography variant="body2" style={{ color: green[300]}}>
{device.status.sen5x?.dust_1ug.toFixed(1)}ug/m3
</Typography>
</Grid2>
<Grid2>
<Typography variant="body2" style={{ color: green[400]}}>
{device.status.sen5x?.dust_2ug.toFixed(1)}ug/m3
</Typography>
</Grid2>
</Grid2>
<Grid2 container direction="column"
className={`${classes.carouselItem} ${
2 === currentIndex ? classes.active : classes.inactive
}`}
>
<Grid2>
<Typography variant="body2" style={{ color: green[500]}}>
{device.status.sen5x?.dust_4ug.toFixed(1)}ug/m3
</Typography>
</Grid2>
<Grid2>
<Typography variant="body2" style={{ color: green[600]}}>
{device.status.sen5x?.dust_10ug.toFixed(1)}ug/m3
</Typography>
</Grid2>
</Grid2>
<Grid2 container direction="column"
className={`${classes.carouselItem} ${
3 === currentIndex ? classes.active : classes.inactive
}`}
>
<Grid2>
<Typography variant="body2" style={{ color: blue[300]}}>
{device.status.sen5x?.voc.toFixed(1)}%
</Typography>
</Grid2>
<Grid2>
<Typography variant="body2" style={{ color: blue[400]}}>
{device.status.sen5x?.nox.toFixed(1)}%
</Typography>
</Grid2>
</Grid2>
</Grid2>
{/* <Grid2>
<Typography variant="body2" style={{ color: orange[700]}}>
{device.status.sen5x?.temperature.toFixed(1)}°C
</Typography>
</Grid2>
<Grid2>
<Typography variant="body2" style={{ color: blue[700]}}>
{device.status.sen5x?.humidity.toFixed(1)}%
</Typography>
</Grid2> */}
{/* </Grid2> */}
</PulseBox>
</Tooltip>
)
}

View file

@ -23,6 +23,7 @@ import { describePower } from "pbHelpers/Power";
import { Tag as TagUI } from "common/Tag";
import moment from "moment";
import StatusPlenum from "common/StatusPlenum";
import StatusSen5x from "common/StatusSen5x";
const useStyles = makeStyles((theme: Theme) => {
return ({
@ -91,6 +92,7 @@ export default function Devices() {
const [devices, setDevices] = useState<Device[]>([])
const [isProvisionDialogOpen, setIsProvisionDialogOpen] = useState<boolean>(false);
const [hasPlenums, setHasPlenums] = useState(false)
const [hasSen5x, setHasSen5x] = useState(false)
const [groupsLoading, setGroupsLoading] = useState(false)
const [groups, setGroups] = useState<Group[]>([]);
@ -244,6 +246,9 @@ export default function Devices() {
if (device.status?.plenum?.temperature) {
setHasPlenums(true)
}
if (device.status?.sen5x?.temperature) {
setHasSen5x(true)
}
newDevices.push(Device.create(device))
})
setDevices(newDevices)
@ -365,6 +370,24 @@ export default function Devices() {
}
})
}
if (hasSen5x) {
columns.push({
title: "Sen5X",
render: (device: Device) => {
if (device.status.sen5x?.temperature) {
return (
<Box sx={{ marginLeft: 1 }}>
<StatusSen5x device={device} />
</Box>
)
} else {
return (
<></>
)
}
}
})
}
return columns
}