diff --git a/app/api/test-scenarios/route.ts b/app/api/test-scenarios/route.ts index d4a4e8b..2854b52 100644 --- a/app/api/test-scenarios/route.ts +++ b/app/api/test-scenarios/route.ts @@ -1,197 +1,16 @@ -import { NextRequest, NextResponse } from 'next/server'; +import { NextResponse } from 'next/server'; -interface TestSensorData { - sensorId: string; - value: number; - status: string; - warningStartTime?: number; -} - -// Test scenarios for the bed pressure monitoring system -export async function POST(request: NextRequest) { - try { - const body = await request.json(); - const { scenario } = body; - - let testData: TestSensorData[] = []; - - switch (scenario) { - case 'normal': - testData = generateNormalScenario(); - break; - case 'warning': - testData = generateWarningScenario(); - break; - case 'alarm': - testData = generateAlarmScenario(); - break; - case 'escalation': - testData = generateEscalationScenario(); - break; - case 'mixed': - testData = generateMixedScenario(); - break; - default: - return NextResponse.json({ - success: false, - error: 'Invalid scenario. Use: normal, warning, alarm, escalation, or mixed' - }, { status: 400 }); - } - - return NextResponse.json({ - success: true, - scenario, - message: `Generated ${scenario} test scenario`, - testData, - timestamp: new Date().toISOString() - }); - - } catch (error) { - console.error('Test scenario API error:', error); - return NextResponse.json({ - success: false, - error: 'Failed to generate test scenario' - }, { status: 500 }); - } -} - -function generateNormalScenario() { - return [ - { sensorId: 'head-1', value: 1200, status: 'normal' }, - { sensorId: 'head-2', value: 1150, status: 'normal' }, - { sensorId: 'shoulder-1', value: 1800, status: 'normal' }, - { sensorId: 'shoulder-2', value: 1750, status: 'normal' }, - { sensorId: 'back-1', value: 2000, status: 'normal' }, - { sensorId: 'back-2', value: 2100, status: 'normal' }, - { sensorId: 'back-3', value: 1950, status: 'normal' }, - { sensorId: 'hip-1', value: 1900, status: 'normal' }, - { sensorId: 'hip-2', value: 2000, status: 'normal' }, - { sensorId: 'hip-3', value: 1850, status: 'normal' }, - { sensorId: 'thigh-1', value: 1600, status: 'normal' }, - { sensorId: 'thigh-2', value: 1550, status: 'normal' }, - { sensorId: 'calf-1', value: 1400, status: 'normal' }, - { sensorId: 'calf-2', value: 1350, status: 'normal' }, - { sensorId: 'feet-1', value: 1200, status: 'normal' }, - { sensorId: 'feet-2', value: 1150, status: 'normal' } - ]; -} - -function generateWarningScenario() { - return [ - { sensorId: 'head-1', value: 3100, status: 'warning' }, // Above warning threshold - { sensorId: 'head-2', value: 1150, status: 'normal' }, - { sensorId: 'shoulder-1', value: 2900, status: 'warning' }, // Above warning threshold - { sensorId: 'shoulder-2', value: 1750, status: 'normal' }, - { sensorId: 'back-1', value: 2600, status: 'warning' }, // Above warning threshold - { sensorId: 'back-2', value: 2100, status: 'normal' }, - { sensorId: 'back-3', value: 1950, status: 'normal' }, - { sensorId: 'hip-1', value: 1900, status: 'normal' }, - { sensorId: 'hip-2', value: 2300, status: 'warning' }, // Above warning threshold - { sensorId: 'hip-3', value: 1850, status: 'normal' }, - { sensorId: 'thigh-1', value: 1600, status: 'normal' }, - { sensorId: 'thigh-2', value: 1550, status: 'normal' }, - { sensorId: 'calf-1', value: 1400, status: 'normal' }, - { sensorId: 'calf-2', value: 1350, status: 'normal' }, - { sensorId: 'feet-1', value: 1200, status: 'normal' }, - { sensorId: 'feet-2', value: 1150, status: 'normal' } - ]; -} - -function generateAlarmScenario() { - return [ - { sensorId: 'head-1', value: 3600, status: 'alarm' }, // Above alarm threshold - { sensorId: 'head-2', value: 3550, status: 'alarm' }, // Above alarm threshold - { sensorId: 'shoulder-1', value: 3300, status: 'alarm' }, // Above alarm threshold - { sensorId: 'shoulder-2', value: 1750, status: 'normal' }, - { sensorId: 'back-1', value: 3100, status: 'alarm' }, // Above alarm threshold - { sensorId: 'back-2', value: 2100, status: 'normal' }, - { sensorId: 'back-3', value: 1950, status: 'normal' }, - { sensorId: 'hip-1', value: 2900, status: 'alarm' }, // Above alarm threshold - { sensorId: 'hip-2', value: 2000, status: 'normal' }, - { sensorId: 'hip-3', value: 1850, status: 'normal' }, - { sensorId: 'thigh-1', value: 1600, status: 'normal' }, - { sensorId: 'thigh-2', value: 1550, status: 'normal' }, - { sensorId: 'calf-1', value: 1400, status: 'normal' }, - { sensorId: 'calf-2', value: 1350, status: 'normal' }, - { sensorId: 'feet-1', value: 1200, status: 'normal' }, - { sensorId: 'feet-2', value: 1150, status: 'normal' } - ]; -} - -function generateEscalationScenario() { - // This scenario would simulate sensors that have been in warning state for a while - // and are about to escalate to alarm - const now = Date.now(); - const warningStartTime = now - 25000; // Started warning 25 seconds ago (close to 30s threshold) - - return [ - { sensorId: 'head-1', value: 3100, status: 'warning', warningStartTime }, - { sensorId: 'head-2', value: 1150, status: 'normal' }, - { sensorId: 'shoulder-1', value: 2900, status: 'warning', warningStartTime: now - 40000 }, // Close to 45s threshold - { sensorId: 'shoulder-2', value: 1750, status: 'normal' }, - { sensorId: 'back-1', value: 2600, status: 'warning', warningStartTime: now - 55000 }, // Close to 60s threshold - { sensorId: 'back-2', value: 2100, status: 'normal' }, - { sensorId: 'back-3', value: 1950, status: 'normal' }, - { sensorId: 'hip-1', value: 1900, status: 'normal' }, - { sensorId: 'hip-2', value: 2300, status: 'warning', warningStartTime: now - 85000 }, // Close to 90s threshold - { sensorId: 'hip-3', value: 1850, status: 'normal' }, - { sensorId: 'thigh-1', value: 2100, status: 'warning', warningStartTime: now - 115000 }, // Close to 120s threshold - { sensorId: 'thigh-2', value: 1550, status: 'normal' }, - { sensorId: 'calf-1', value: 1400, status: 'normal' }, - { sensorId: 'calf-2', value: 1350, status: 'normal' }, - { sensorId: 'feet-1', value: 1200, status: 'normal' }, - { sensorId: 'feet-2', value: 1150, status: 'normal' } - ]; -} - -function generateMixedScenario() { - const now = Date.now(); - - return [ - { sensorId: 'head-1', value: 3600, status: 'alarm' }, // Immediate alarm - { sensorId: 'head-2', value: 3100, status: 'warning', warningStartTime: now - 10000 }, // Recent warning - { sensorId: 'shoulder-1', value: 2900, status: 'warning', warningStartTime: now - 40000 }, // Long warning - { sensorId: 'shoulder-2', value: 1750, status: 'normal' }, - { sensorId: 'back-1', value: 3100, status: 'alarm' }, // Immediate alarm - { sensorId: 'back-2', value: 2600, status: 'warning', warningStartTime: now - 30000 }, // Warning close to escalation - { sensorId: 'back-3', value: 1950, status: 'normal' }, - { sensorId: 'hip-1', value: 1900, status: 'normal' }, - { sensorId: 'hip-2', value: 2900, status: 'alarm' }, // Immediate alarm - { sensorId: 'hip-3', value: 2300, status: 'warning', warningStartTime: now - 60000 }, // Warning - { sensorId: 'thigh-1', value: 1600, status: 'normal' }, - { sensorId: 'thigh-2', value: 2100, status: 'warning', warningStartTime: now - 90000 }, // Warning - { sensorId: 'calf-1', value: 2300, status: 'alarm' }, // Immediate alarm - { sensorId: 'calf-2', value: 1900, status: 'warning', warningStartTime: now - 120000 }, // Warning - { sensorId: 'feet-1', value: 1200, status: 'normal' }, - { sensorId: 'feet-2', value: 1900, status: 'alarm' } // Immediate alarm - ]; +// API endpoint disabled - only real MQTT data is used +export async function POST() { + return NextResponse.json({ + success: false, + error: 'Test scenarios have been removed. System uses real MQTT data only.' + }, { status: 410 }); } export async function GET() { return NextResponse.json({ - success: true, - availableScenarios: [ - { - name: 'normal', - description: 'All sensors operating within normal ranges' - }, - { - name: 'warning', - description: 'Several sensors in warning state (above warning threshold)' - }, - { - name: 'alarm', - description: 'Multiple sensors in immediate alarm state (above alarm threshold)' - }, - { - name: 'escalation', - description: 'Sensors in warning state close to escalating to alarm after delay' - }, - { - name: 'mixed', - description: 'Mixed scenario with normal, warning, and alarm states' - } - ], - usage: 'POST to /api/test-scenarios with body: { "scenario": "scenario_name" }' - }); + success: false, + error: 'Test scenarios have been removed. System uses real MQTT data only.' + }, { status: 410 }); } \ No newline at end of file diff --git a/components/bed-pressure/AlarmDashboard.tsx b/components/bed-pressure/AlarmDashboard.tsx index 2aa72e3..8ca5698 100644 --- a/components/bed-pressure/AlarmDashboard.tsx +++ b/components/bed-pressure/AlarmDashboard.tsx @@ -1,7 +1,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Badge } from "@/components/ui/badge" -import { AlertTriangle, VolumeX, CheckCircle, Bell, TestTube } from "lucide-react" +import { AlertTriangle, VolumeX, CheckCircle, Bell } from "lucide-react" import { useBedPressureStore } from "@/stores/bedPressureStore" import { useEffect, useState } from "react" @@ -12,35 +12,13 @@ export function AlarmDashboard() { acknowledgeAlarm, silenceAllAlarms } = useBedPressureStore() - const [unsilencedAlarms, setUnsilencedAlarms] = useState(0) - const [testScenario, setTestScenario] = useState('') - // Update alarm counts useEffect(() => { const unsilenced = activeAlarms.filter(alarm => !alarm.silenced).length setUnsilencedAlarms(unsilenced) }, [activeAlarms]) - const handleTestScenario = async (scenario: string) => { - try { - setTestScenario(scenario) - const response = await fetch('/api/test-scenarios', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ scenario }) - }) - - if (response.ok) { - console.log(`Applied ${scenario} test scenario`) - } - } catch (error) { - console.error('Failed to apply test scenario:', error) - } finally { - setTimeout(() => setTestScenario(''), 2000) - } - } - const getSystemStatus = () => { const alarmCount = activeAlarms.filter(a => a.type === 'alarm' && !a.silenced).length const warningCount = activeAlarms.filter(a => a.type === 'warning' && !a.silenced).length @@ -71,9 +49,8 @@ export function AlarmDashboard() {
SYSTEM STATUS: {systemStatus.status} - -

- {isConnected ? 'Hardware Connected' : 'Using Mock Data'} • +

+ {isConnected ? 'Hardware Connected' : 'Hardware Offline'} • {activeAlarms.length} Active Alarms • {unsilencedAlarms} Unsilenced

@@ -149,45 +126,9 @@ export function AlarmDashboard() {

{activeAlarms.filter(a => a.acknowledged).length}

- - +
- {/* Test Scenarios */} - - - - - Test Scenarios - - - -
- {[ - { name: 'normal', label: 'Normal', color: 'bg-green-100 text-green-700 hover:bg-green-200' }, - { name: 'warning', label: 'Warning', color: 'bg-yellow-100 text-yellow-700 hover:bg-yellow-200' }, - { name: 'alarm', label: 'Alarm', color: 'bg-red-100 text-red-700 hover:bg-red-200' }, - { name: 'escalation', label: 'Escalation', color: 'bg-orange-100 text-orange-700 hover:bg-orange-200' }, - { name: 'mixed', label: 'Mixed', color: 'bg-purple-100 text-purple-700 hover:bg-purple-200' } - ].map(scenario => ( - - ))} -
-

- Click to simulate different alarm scenarios for testing -

-
-
- {/* Recent Alarm Activity */} diff --git a/components/bed-pressure/SensorDetailModal.tsx b/components/bed-pressure/SensorDetailModal.tsx index 04752b3..f438241 100644 --- a/components/bed-pressure/SensorDetailModal.tsx +++ b/components/bed-pressure/SensorDetailModal.tsx @@ -143,10 +143,9 @@ export function SensorDetailModal() { - -

+

Showing data for the last {getTimespanLabel(selectedTimespan)} - {sensor.source === 'hardware' ? ' (Real sensor data)' : ' (Mock data)'} + {sensor.source === 'hardware' ? ' (Real sensor data)' : ' (Hardware offline - no data)'}

diff --git a/services/SensorDataStorage.ts b/services/SensorDataStorage.ts index d5a5013..a8c3e69 100644 --- a/services/SensorDataStorage.ts +++ b/services/SensorDataStorage.ts @@ -9,7 +9,7 @@ export interface SensorDataPoint { value: number; // Changed from pressure to value (0-4095) timestamp: number; time: string; - source: 'hardware' | 'mock'; + source: 'hardware'; pin?: number; digitalState?: number; } @@ -93,39 +93,24 @@ export class SensorDataStorage { async forceSave() { await this.saveData(); - } - - // Generate time series data for a specific timespan + } // Generate time series data for a specific timespan generateTimeSeriesData( sensorData: SensorDataPoint[], timespan: number = 24 * 60 * 60 * 1000 ): Array<{ time: string; timestamp: number; value: number }> { if (sensorData.length === 0) { - // Generate mock data if no real data exists - return this.generateMockTimeSeriesData(timespan); + // Return empty array if no real data exists + return []; } - return sensorData.map(point => ({ + // Filter data by timespan + const cutoffTime = Date.now() - timespan; + const filteredData = sensorData.filter(point => point.timestamp > cutoffTime); + + return filteredData.map(point => ({ time: point.time, timestamp: point.timestamp, value: point.value })); } - - private generateMockTimeSeriesData(timespan: number): Array<{ time: string; timestamp: number; value: number }> { - const data = []; - const now = Date.now(); - const interval = Math.max(1000, timespan / 288); // At least 1 second intervals, up to 288 points - - for (let i = timespan; i >= 0; i -= interval) { - const timestamp = now - i; - const time = new Date(timestamp); - data.push({ - time: time.toLocaleTimeString("en-US", { hour12: false }), - timestamp: timestamp, - value: Math.floor(Math.random() * 4096 + Math.sin(i / 60000) * 500 + 2000), // 0-4095 range - }); - } - return data; - } } \ No newline at end of file diff --git a/stores/bedPressureStore.ts b/stores/bedPressureStore.ts index 46f7246..72a94a4 100644 --- a/stores/bedPressureStore.ts +++ b/stores/bedPressureStore.ts @@ -11,7 +11,7 @@ export interface SensorData { 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'; + source?: 'hardware'; pin?: number; digitalState?: number; warningThreshold?: number; @@ -132,8 +132,7 @@ export const useBedPressureStore = create((set, get) => ({ console.error('Failed to fetch sensor config:', error); } }, - - fetchSensorData: async () => { + fetchSensorData: async () => { try { const response = await fetch('/api/sensors'); const data = await response.json(); @@ -143,12 +142,13 @@ export const useBedPressureStore = create((set, get) => ({ const updated = { ...sensorData }; const newAlerts: Alert[] = []; + // Only process hardware sensors, no mock data data.sensors.forEach((sensor: { id: string; label: string; zone: string; - value: number; // Changed from pressure to value - source: 'hardware' | 'mock'; + value: number; + source: 'hardware'; pin?: number; digitalState?: number; warningThreshold?: number; @@ -156,6 +156,10 @@ export const useBedPressureStore = create((set, get) => ({ warningDelayMs?: number; status?: string; }) => { + // Only process hardware data + if (sensor.source !== 'hardware') { + return; + } const currentSensor = updated[sensor.id]; const newValue = sensor.value; const config = sensorConfig.find(s => s.id === sensor.id); @@ -224,9 +228,7 @@ export const useBedPressureStore = create((set, get) => ({ } else { warningStartTime = undefined; // Clear warning timer alarmManager.clearAlarm(sensor.id); // Clear any existing alarms - } - - // Update sensor data + } // Update sensor data updated[sensor.id] = { ...sensorConfig.find(s => s.id === sensor.id), id: sensor.id, @@ -236,7 +238,7 @@ export const useBedPressureStore = create((set, get) => ({ label: sensor.label, currentValue: newValue, data: currentSensor ? [ - ...currentSensor.data.slice(1), + ...currentSensor.data.slice(-100), // Keep only last 100 points { time: new Date().toLocaleTimeString("en-US", { hour12: false }), timestamp: Date.now(),