From 30f0b4468ea99c90613072dc330d3567f0b98d93 Mon Sep 17 00:00:00 2001 From: Carter Date: Wed, 15 Oct 2025 11:49:26 -0600 Subject: [PATCH] devices listing now looks at the timestamp of status readings to determine if a column should exist --- src/common/StatusDust.tsx | 23 ++++++ src/common/StatusPlenum.tsx | 23 ++++++ src/common/StatusSen5x.tsx | 23 ++++++ src/pages/Devices.tsx | 137 ++++++++++++++++++++++++++++++++---- 4 files changed, 194 insertions(+), 12 deletions(-) diff --git a/src/common/StatusDust.tsx b/src/common/StatusDust.tsx index 2333318..a7e8e3a 100644 --- a/src/common/StatusDust.tsx +++ b/src/common/StatusDust.tsx @@ -114,6 +114,29 @@ export default function StatusDust(props: Props) { ) } + function compareTimestamps(timestamp1: string, timestamp2: string): number { + const date1 = new Date(timestamp1); + const date2 = new Date(timestamp2); + + // Check if dates are valid + if (isNaN(date1.getTime()) || isNaN(date2.getTime())) { + throw new Error("Invalid RFC3339 timestamp format"); + } + + // Compare using getTime() for millisecond precision + return date1.getTime() - date2.getTime(); + } + + if (device.status.sen5x?.timestamp) { + const now = new Date(); + const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000); + if (compareTimestamps(device.status.sen5x?.timestamp, oneDayAgo.toISOString()) < 0) { + return null + } + } else { + return null + } + return ( diff --git a/src/common/StatusPlenum.tsx b/src/common/StatusPlenum.tsx index 9cb7489..fe2b00d 100644 --- a/src/common/StatusPlenum.tsx +++ b/src/common/StatusPlenum.tsx @@ -80,6 +80,29 @@ export default function StatusPlenum(props: Props) { ) } + function compareTimestamps(timestamp1: string, timestamp2: string): number { + const date1 = new Date(timestamp1); + const date2 = new Date(timestamp2); + + // Check if dates are valid + if (isNaN(date1.getTime()) || isNaN(date2.getTime())) { + throw new Error("Invalid RFC3339 timestamp format"); + } + + // Compare using getTime() for millisecond precision + return date1.getTime() - date2.getTime(); + } + + if (device.status.plenum?.timestamp) { + const now = new Date(); + const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000); + if (compareTimestamps(device.status.plenum?.timestamp, oneDayAgo.toISOString()) < 0) { + return null + } + } else { + return null + } + return ( diff --git a/src/common/StatusSen5x.tsx b/src/common/StatusSen5x.tsx index 288eb10..fad0ecb 100644 --- a/src/common/StatusSen5x.tsx +++ b/src/common/StatusSen5x.tsx @@ -120,6 +120,29 @@ export default function StatusSen5x(props: Props) { ) } + function compareTimestamps(timestamp1: string, timestamp2: string): number { + const date1 = new Date(timestamp1); + const date2 = new Date(timestamp2); + + // Check if dates are valid + if (isNaN(date1.getTime()) || isNaN(date2.getTime())) { + throw new Error("Invalid RFC3339 timestamp format"); + } + + // Compare using getTime() for millisecond precision + return date1.getTime() - date2.getTime(); + } + + if (device.status.sen5x?.timestamp) { + const now = new Date(); + const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000); + if (compareTimestamps(device.status.sen5x?.timestamp, oneDayAgo.toISOString()) < 0) { + return null + } + } else { + return null + } + return ( diff --git a/src/pages/Devices.tsx b/src/pages/Devices.tsx index 673f097..5681d1a 100644 --- a/src/pages/Devices.tsx +++ b/src/pages/Devices.tsx @@ -208,6 +208,118 @@ export default function Devices() { }) }, [tab]) + function compareTimestamps(timestamp1: string, timestamp2: string): number { + const date1 = new Date(timestamp1); + const date2 = new Date(timestamp2); + + // Check if dates are valid + if (isNaN(date1.getTime()) || isNaN(date2.getTime())) { + throw new Error("Invalid RFC3339 timestamp format"); + } + + // Compare using getTime() for millisecond precision + return date1.getTime() - date2.getTime(); + } + + const doesDeviceHavePlenum = (device: pond.Device) => { + if (device.status?.plenum?.temperature && device.status?.plenum?.timestamp) { + if (device.status.plenum?.timestamp) { + const now = new Date(); + const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000); + if (compareTimestamps(device.status.plenum?.timestamp, oneDayAgo.toISOString()) < 0) { + return true + } + } else { + return false + } + } + return false + } + + const doesDeviceHaveSen5x = (device: pond.Device) => { + if (device.status?.sen5x?.temperature && device.status?.sen5x?.timestamp) { + if (device.status.sen5x?.timestamp) { + const now = new Date(); + const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000); + if (compareTimestamps(device.status.sen5x?.timestamp, oneDayAgo.toISOString()) < 0) { + return true + } + } else { + return false + } + } + return false + } + + // if (device.status?.o2) setHasO2(true) + // if (device.status?.co) setHasCo(true) + // if (device.status?.co2) setHasCo2(true) + // if (device.status?.no2) setHasNo2(true) + + const doesDeviceHaveO2 = (device: pond.Device) => { + if (device.status?.o2?.ppm && device.status?.o2?.timestamp) { + if (device.status.sen5x?.timestamp) { + const now = new Date(); + const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000); + if (compareTimestamps(device.status.o2?.timestamp, oneDayAgo.toISOString()) < 0) { + return true + } + } else { + return false + } + } + return false + } + + const doesDeviceHaveCo = (device: pond.Device) => { + if (device.status?.co?.ppm && device.status?.co?.timestamp) { + if (device.status.co?.timestamp) { + const now = new Date(); + const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000); + if (compareTimestamps(device.status.co?.timestamp, oneDayAgo.toISOString()) < 0) { + return true + } + } else { + return false + } + } + return false + } + + const doesDeviceHaveCo2 = (device: pond.Device) => { + if (device.status?.co2?.ppm && device.status?.co2?.timestamp) { + if (device.status.co2?.timestamp) { + const now = new Date(); + const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000); + if (compareTimestamps(device.status.co2?.timestamp, oneDayAgo.toISOString()) < 0) { + return true + } + } else { + return false + } + } + return false + } + + const doesDeviceHaveNo2 = (device: pond.Device) => { + if (device.status?.no2?.ppm && device.status?.no2?.timestamp) { + if (device.status.no2?.timestamp) { + const now = new Date(); + const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000); + if (compareTimestamps(device.status.no2?.timestamp, oneDayAgo.toISOString()) < 0) { + return true + } + } else { + return false + } + } + return false + } + + useEffect(() => { + console.log(hasPlenums) + }, [hasPlenums]) + const openProvisionDialog = () => { setIsProvisionDialogOpen(true); }; @@ -319,12 +431,13 @@ export default function Devices() { ).then(resp => { let newDevices: Device[] = [] resp.data.devices.forEach(device => { - if (device.status?.plenum?.temperature) setHasPlenums(true) - if (device.status?.sen5x?.temperature) setHasSen5x(true) - if (device.status?.o2) setHasO2(true) - if (device.status?.co) setHasCo(true) - if (device.status?.co2) setHasCo2(true) - if (device.status?.no2) setHasNo2(true) + setHasPlenums(doesDeviceHavePlenum(device)) + setHasPlenums(true) + setHasSen5x(doesDeviceHaveSen5x(device)) + setHasO2(doesDeviceHaveO2(device)) + setHasCo(doesDeviceHaveCo(device)) + setHasCo2(doesDeviceHaveCo2(device)) + setHasNo2(doesDeviceHaveNo2(device)) newDevices.push(Device.create(device)) }) setDevices(newDevices) @@ -809,12 +922,12 @@ export default function Devices() { ).then(resp => { let newDevices: Device[] = [] resp.data.devices.forEach(device => { - if (device.status?.plenum?.temperature) setHasPlenums(true) - if (device.status?.sen5x?.temperature) setHasSen5x(true) - if (device.status?.o2) setHasO2(true) - if (device.status?.co) setHasCo(true) - if (device.status?.co2) setHasCo2(true) - if (device.status?.no2) setHasNo2(true) + setHasPlenums(doesDeviceHavePlenum(device)) + setHasSen5x(doesDeviceHaveSen5x(device)) + setHasO2(doesDeviceHaveO2(device)) + setHasCo(doesDeviceHaveCo(device)) + setHasCo2(doesDeviceHaveCo2(device)) + setHasNo2(doesDeviceHaveNo2(device)) newDevices.push(Device.create(device)) }) setDevices(currentRows.concat(newDevices))