switched to status websocket instead of the dead full device websocket
This commit is contained in:
parent
d6e3fe7a16
commit
a288c9503a
1 changed files with 70 additions and 30 deletions
|
|
@ -3,7 +3,8 @@ import Grid from '@mui/material/Grid2';
|
||||||
import { Component, Device, Interaction, User } from "models";
|
import { Component, Device, Interaction, User } from "models";
|
||||||
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
||||||
import { useDeviceAPI, useGlobalState, useSnackbar } from "providers";
|
import { useDeviceAPI, useGlobalState, useSnackbar } from "providers";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useDeviceStatusStreams } from "hooks/useDeviceStatusStreams";
|
||||||
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { useLocation, useParams } from "react-router-dom";
|
import { useLocation, useParams } from "react-router-dom";
|
||||||
import PageContainer from "./PageContainer";
|
import PageContainer from "./PageContainer";
|
||||||
import { useHTTP, useMobile } from "hooks";
|
import { useHTTP, useMobile } from "hooks";
|
||||||
|
|
@ -23,6 +24,25 @@ import DeviceWizard from "device/DeviceWizard";
|
||||||
import DeviceScannedComponents from "device/autoDetect/DeviceScannedComponents";
|
import DeviceScannedComponents from "device/autoDetect/DeviceScannedComponents";
|
||||||
import { useWebSocket } from "hooks/useWebSocket";
|
import { useWebSocket } from "hooks/useWebSocket";
|
||||||
|
|
||||||
|
type TimestampedReading = { timestamp?: string };
|
||||||
|
|
||||||
|
function getTimestampMillis(timestamp?: string): number | undefined {
|
||||||
|
if (!timestamp) return undefined;
|
||||||
|
const parsed = Date.parse(timestamp);
|
||||||
|
return Number.isNaN(parsed) ? undefined : parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickNewestReading<T extends TimestampedReading>(
|
||||||
|
current: T | null | undefined,
|
||||||
|
incoming: T | null | undefined
|
||||||
|
): T | null | undefined {
|
||||||
|
const currentTs = getTimestampMillis(current?.timestamp);
|
||||||
|
const incomingTs = getTimestampMillis(incoming?.timestamp);
|
||||||
|
if (incomingTs === undefined) return current ?? incoming;
|
||||||
|
if (currentTs === undefined) return incoming ?? current;
|
||||||
|
return incomingTs >= currentTs ? incoming : current;
|
||||||
|
}
|
||||||
|
|
||||||
export interface DevicePageData {
|
export interface DevicePageData {
|
||||||
device: Device;
|
device: Device;
|
||||||
components: Component[];
|
components: Component[];
|
||||||
|
|
@ -76,6 +96,55 @@ export default function DevicePage() {
|
||||||
? as
|
? as
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
const liveStatusDeviceIds = useMemo(
|
||||||
|
() => (deviceID ? [deviceID] : []),
|
||||||
|
[deviceID]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleLiveDeviceStatus = useCallback(
|
||||||
|
(streamDeviceId: string, status: pond.DeviceStatus) => {
|
||||||
|
setDevice((prev) => {
|
||||||
|
if (prev.id().toString() !== streamDeviceId) return prev;
|
||||||
|
const updated = Device.clone(prev);
|
||||||
|
const incomingStatus = pond.DeviceStatus.fromObject(status);
|
||||||
|
const currentStatus = prev.status ?? pond.DeviceStatus.create();
|
||||||
|
|
||||||
|
incomingStatus.plenum = pickNewestReading(currentStatus.plenum, incomingStatus.plenum);
|
||||||
|
incomingStatus.sen5x = pickNewestReading(currentStatus.sen5x, incomingStatus.sen5x);
|
||||||
|
incomingStatus.co = pickNewestReading(currentStatus.co, incomingStatus.co);
|
||||||
|
incomingStatus.co2 = pickNewestReading(currentStatus.co2, incomingStatus.co2);
|
||||||
|
incomingStatus.no2 = pickNewestReading(currentStatus.no2, incomingStatus.no2);
|
||||||
|
incomingStatus.o2 = pickNewestReading(currentStatus.o2, incomingStatus.o2);
|
||||||
|
incomingStatus.lel = pickNewestReading(currentStatus.lel, incomingStatus.lel);
|
||||||
|
incomingStatus.h2s = pickNewestReading(currentStatus.h2s, incomingStatus.h2s);
|
||||||
|
|
||||||
|
const currentLastActive = getTimestampMillis(currentStatus.lastActive);
|
||||||
|
const incomingLastActive = getTimestampMillis(incomingStatus.lastActive);
|
||||||
|
if (
|
||||||
|
currentLastActive !== undefined &&
|
||||||
|
incomingLastActive !== undefined &&
|
||||||
|
incomingLastActive < currentLastActive
|
||||||
|
) {
|
||||||
|
incomingStatus.lastActive = currentStatus.lastActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
updated.status = incomingStatus;
|
||||||
|
return updated;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
useDeviceStatusStreams({
|
||||||
|
deviceIds: liveStatusDeviceIds,
|
||||||
|
onStatusUpdate: handleLiveDeviceStatus,
|
||||||
|
token,
|
||||||
|
keys: liveContextKeys,
|
||||||
|
types: liveContextTypes,
|
||||||
|
as: liveAs,
|
||||||
|
enabled: Boolean(deviceID && token),
|
||||||
|
});
|
||||||
|
|
||||||
const loadDevice = () => {
|
const loadDevice = () => {
|
||||||
if (loading) return
|
if (loading) return
|
||||||
if (state?.devicePageData) {
|
if (state?.devicePageData) {
|
||||||
|
|
@ -212,35 +281,6 @@ export default function DevicePage() {
|
||||||
enabled: !!deviceID,
|
enabled: !!deviceID,
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- Real-time device updates (optional) ---
|
|
||||||
// Updates device-level info (name, status, lastActive, etc.)
|
|
||||||
useWebSocket<Device | null>({
|
|
||||||
path: `/v1/live/devices/${deviceID}`,
|
|
||||||
parse: (e) => {
|
|
||||||
try {
|
|
||||||
const raw = JSON.parse(e.data);
|
|
||||||
const dev = Device.any(raw);
|
|
||||||
if (!dev?.settings) {
|
|
||||||
console.warn("[ws] received device without settings:", raw);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return dev;
|
|
||||||
} catch (err) {
|
|
||||||
console.warn("[ws] failed to parse device:", err);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onMessage: (updatedDevice) => {
|
|
||||||
if (!updatedDevice) return;
|
|
||||||
setDevice(updatedDevice);
|
|
||||||
},
|
|
||||||
keys: liveContextKeys,
|
|
||||||
types: liveContextTypes,
|
|
||||||
as: liveAs,
|
|
||||||
token,
|
|
||||||
enabled: !!deviceID,
|
|
||||||
});
|
|
||||||
|
|
||||||
const loadPortScan = () => {
|
const loadPortScan = () => {
|
||||||
deviceAPI.listFoundComponents(parseInt(deviceID))
|
deviceAPI.listFoundComponents(parseInt(deviceID))
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue