import { create } from 'zustand' import { AlarmManager, AlarmEvent } from '@/services/AlarmManager' export interface SensorConfig { id: string; x: number; y: number; zone: string; label: string; pin?: number; } export interface SensorData { id: string; x: number; y: number; zone: string; label: string; currentValue: number; // Changed from currentPressure to currentValue (0-4095) data: Array<{ time: string; timestamp: number; value: number }>; // Changed from pressure to value status: string; source?: 'hardware' | 'mock'; pin?: number; digitalState?: number; warningThreshold?: number; alarmThreshold?: number; warningDelayMs?: number; } export interface Alert { id: string; message: string; time: string; } interface BedPressureStore { // State sensorData: Record; sensorConfig: SensorConfig[]; selectedSensor: string | null; isModalOpen: boolean; isMonitoring: boolean; alerts: Alert[]; isConnected: boolean; selectedTimespan: number; // in milliseconds activeAlarms: AlarmEvent[]; alarmManager: AlarmManager; // Actions setSensorData: (data: Record) => void; updateSensorData: (updater: (prev: Record) => Record) => void; setSensorConfig: (config: SensorConfig[]) => void; setSelectedSensor: (sensorId: string | null) => void; setIsModalOpen: (isOpen: boolean) => void; setIsMonitoring: (isMonitoring: boolean) => void; addAlerts: (newAlerts: Alert[]) => void; setIsConnected: (isConnected: boolean) => void; setSelectedTimespan: (timespan: number) => void; setActiveAlarms: (alarms: AlarmEvent[]) => void; // Computed values averageValue: () => number; // Changed from averagePressure criticalSensors: () => number; // API actions fetchSensorConfig: () => Promise; fetchSensorData: () => Promise; fetchSensorHistory: (sensorId: string, timespan?: number) => Promise; // Alarm actions acknowledgeAlarm: (alarmId: string) => void; silenceAlarm: (alarmId: string, durationMs?: number) => void; silenceAllAlarms: (durationMs?: number) => void; } export const useBedPressureStore = create((set, get) => ({ // Initial state sensorData: {}, sensorConfig: [], selectedSensor: null, isModalOpen: false, isMonitoring: true, alerts: [], isConnected: false, selectedTimespan: 24 * 60 * 60 * 1000, // Default 24 hours activeAlarms: [], alarmManager: AlarmManager.getInstance(), // Actions setSensorData: (data) => set({ sensorData: data }), updateSensorData: (updater) => set((state) => ({ sensorData: updater(state.sensorData) })), setSensorConfig: (config) => set({ sensorConfig: config }), setSelectedSensor: (sensorId) => set({ selectedSensor: sensorId }), setIsModalOpen: (isOpen) => set({ isModalOpen: isOpen }), setIsMonitoring: (isMonitoring) => set({ isMonitoring }), addAlerts: (newAlerts) => set((state) => ({ alerts: [...newAlerts, ...state.alerts].slice(0, 10) })), setIsConnected: (isConnected) => set({ isConnected }), setSelectedTimespan: (timespan) => set({ selectedTimespan: timespan }), setActiveAlarms: (alarms) => set({ activeAlarms: alarms }), // Computed values averageValue: () => { const { sensorData } = get(); const sensors = Object.values(sensorData) as SensorData[]; if (sensors.length === 0) return 0; return sensors.reduce((sum: number, sensor: SensorData) => sum + sensor.currentValue, 0) / sensors.length; }, criticalSensors: () => { const { sensorData } = get(); return (Object.values(sensorData) as SensorData[]).filter((sensor: SensorData) => sensor.status === 'alarm' || sensor.status === 'critical' ).length; }, // API actions fetchSensorConfig: async () => { try { const response = await fetch('/api/sensors/config'); const data = await response.json(); if (data.success && data.sensors) { set({ sensorConfig: data.sensors }); } } catch (error) { console.error('Failed to fetch sensor config:', error); } }, fetchSensorData: async () => { try { const response = await fetch('/api/sensors'); const data = await response.json(); if (data.success && data.sensors) { const { sensorData, sensorConfig, alarmManager } = get(); const updated = { ...sensorData }; const newAlerts: Alert[] = []; data.sensors.forEach((sensor: { id: string; label: string; zone: string; value: number; // Changed from pressure to value source: 'hardware' | 'mock'; pin?: number; digitalState?: number; warningThreshold?: number; alarmThreshold?: number; status?: string; }) => { const currentSensor = updated[sensor.id]; const newValue = sensor.value; // Check for alarms based on thresholds if (sensor.alarmThreshold && newValue >= sensor.alarmThreshold) { alarmManager.addAlarm(sensor.id, sensor.label, 'alarm', newValue, sensor.alarmThreshold); } else if (sensor.warningThreshold && newValue >= sensor.warningThreshold) { alarmManager.addAlarm(sensor.id, sensor.label, 'warning', newValue, sensor.warningThreshold); } else { alarmManager.clearAlarm(sensor.id); } // Check for alerts (legacy alert system) if (newValue > 3000 && currentSensor && currentSensor.currentValue <= 3000) { newAlerts.push({ id: `${sensor.id}-${Date.now()}`, message: `High value detected at ${sensor.label}`, time: new Date().toLocaleTimeString(), }); } // Update sensor data updated[sensor.id] = { ...sensorConfig.find(s => s.id === sensor.id), id: sensor.id, x: sensorConfig.find(s => s.id === sensor.id)?.x || 50, y: sensorConfig.find(s => s.id === sensor.id)?.y || 50, zone: sensor.zone, label: sensor.label, currentValue: newValue, data: currentSensor ? [ ...currentSensor.data.slice(1), { time: new Date().toLocaleTimeString("en-US", { hour12: false }), timestamp: Date.now(), value: newValue, }, ] : [{ time: new Date().toLocaleTimeString("en-US", { hour12: false }), timestamp: Date.now(), value: newValue, }], status: sensor.status || (newValue > 3000 ? "critical" : newValue > 2500 ? "warning" : "normal"), source: sensor.source, pin: sensor.pin, digitalState: sensor.digitalState, warningThreshold: sensor.warningThreshold, alarmThreshold: sensor.alarmThreshold }; }); set({ sensorData: updated, isConnected: data.connected, activeAlarms: alarmManager.getActiveAlarms() }); if (newAlerts.length > 0) { get().addAlerts(newAlerts); } } } catch (error) { console.error('Failed to fetch sensor data:', error); } }, fetchSensorHistory: async (sensorId: string, timespan?: number) => { try { const { selectedTimespan } = get(); const timespanToUse = timespan || selectedTimespan; const response = await fetch(`/api/sensors/history?sensorId=${sensorId}×pan=${timespanToUse}`); const data = await response.json(); if (data.success && data.data) { const { sensorData } = get(); const updated = { ...sensorData }; if (updated[sensorId]) { updated[sensorId] = { ...updated[sensorId], data: data.data }; set({ sensorData: updated }); } } } catch (error) { console.error('Failed to fetch sensor history:', error); } }, // Alarm actions acknowledgeAlarm: (alarmId: string) => { const { alarmManager } = get(); alarmManager.acknowledgeAlarm(alarmId); set({ activeAlarms: alarmManager.getActiveAlarms() }); }, silenceAlarm: (alarmId: string, durationMs?: number) => { const { alarmManager } = get(); alarmManager.silenceAlarm(alarmId, durationMs); set({ activeAlarms: alarmManager.getActiveAlarms() }); }, silenceAllAlarms: (durationMs?: number) => { const { alarmManager } = get(); alarmManager.silenceAllAlarms(durationMs); set({ activeAlarms: alarmManager.getActiveAlarms() }); } }));