UNPKG

@sailboat-computer/health-monitoring

Version:

Comprehensive health monitoring system for sailboat computer v3 with marine-specific health checks

437 lines (378 loc) • 12.8 kB
/** * Example usage of marine health monitoring system * This demonstrates how to set up and use health checks for a sailboat */ import { HealthCheckEngine, defaultHealthCheckEngine, OperationalContext, OperationalContextType, MarineEnvironmentStatus, HealthMonitoringEvent, HealthStatus, HealthStatusType } from '../index'; import { GPSHealthCheck, createGPSHealthCheck, GPSData } from '../marine/GPSHealthCheck'; import { BatteryHealthCheck, createBatteryHealthCheck, BatteryData } from '../marine/BatteryHealthCheck'; /** * Example marine health monitoring setup for a sailboat */ export class MarineHealthMonitoringExample { private healthEngine: HealthCheckEngine; private gpsHealthCheck!: GPSHealthCheck; private battery48vHealthCheck!: BatteryHealthCheck; private battery12vHealthCheck!: BatteryHealthCheck; constructor() { this.healthEngine = defaultHealthCheckEngine; // Set up event listening this.setupEventHandling(); // Initialize health checks this.initializeHealthChecks(); } /** * Initialize all marine health checks */ private initializeHealthChecks(): void { // GPS Health Check this.gpsHealthCheck = createGPSHealthCheck( this.mockGPSDataProvider.bind(this), { // Custom configuration for this specific GPS unit interval: 15000, // Check every 15 seconds instead of default 10 thresholds: { warning: 0.7, // Slightly higher threshold for this critical system critical: 0.4, unit: 'health_score' } } ); // 48V House Battery Health Check this.battery48vHealthCheck = createBatteryHealthCheck( this.mock48VBatteryDataProvider.bind(this), { checkId: 'house-battery-48v', name: '48V House Battery Health', interval: 20000, // Check every 20 seconds thresholds: { warning: 0.6, critical: 0.3, unit: 'health_score' } } ); // 12V Service Battery Health Check this.battery12vHealthCheck = createBatteryHealthCheck( this.mock12VBatteryDataProvider.bind(this), { checkId: 'service-battery-12v', name: '12V Service Battery Health', interval: 30000, // Check every 30 seconds thresholds: { warning: 0.6, critical: 0.3, unit: 'health_score' } } ); // Register all health checks with the engine this.healthEngine.registerHealthCheck(this.gpsHealthCheck); this.healthEngine.registerHealthCheck(this.battery48vHealthCheck); this.healthEngine.registerHealthCheck(this.battery12vHealthCheck); } /** * Set up event handling for health monitoring events */ private setupEventHandling(): void { this.healthEngine.onEvent((event: HealthMonitoringEvent) => { console.log(`[${event.timestamp.toISOString()}] Health Event: ${event.eventType}`); console.log(` System: ${event.systemId}, Check: ${event.checkId}`); console.log(` Status: ${event.currentStatus}`); console.log(` Message: ${event.data.message}`); if (event.data.score !== undefined) { console.log(` Score: ${(event.data.score * 100).toFixed(1)}%`); } // Handle critical alerts if (event.eventType === 'alert_triggered' && event.currentStatus === HealthStatus.CRITICAL) { this.handleCriticalAlert(event); } // Handle system recovery if (event.eventType === 'system_recovery') { this.handleSystemRecovery(event); } }); } /** * Handle critical health alerts */ private handleCriticalAlert(event: HealthMonitoringEvent): void { console.error(`🚨 CRITICAL ALERT: ${event.data.message}`); // In a real implementation, this might: // - Send notifications to crew // - Log to emergency systems // - Trigger automatic responses // - Update navigation displays if (event.checkId === 'gps-health') { console.error('āš ļø GPS CRITICAL: Switch to backup navigation methods'); } else if (event.checkId && event.checkId.includes('battery')) { console.error('āš ļø BATTERY CRITICAL: Implement power conservation measures'); } } /** * Handle system recovery events */ private handleSystemRecovery(event: HealthMonitoringEvent): void { console.log(`āœ… System Recovery: ${event.data.message}`); } /** * Start the health monitoring system */ public start(): void { console.log('🚢 Starting Marine Health Monitoring System...'); // Set initial operational context this.healthEngine.updateOperationalContext(OperationalContext.DOCKED); // Set initial marine environment this.updateMarineEnvironment({ seaState: 'calm', weather: 'clear', powerStatus: 'normal', criticalOperationsOnly: false }); // Start the health check engine this.healthEngine.start(); console.log('āœ… Marine Health Monitoring System started'); } /** * Stop the health monitoring system */ public stop(): void { console.log('šŸ›‘ Stopping Marine Health Monitoring System...'); this.healthEngine.stop(); console.log('āœ… Marine Health Monitoring System stopped'); } /** * Update operational context (e.g., when leaving dock, anchoring, etc.) */ public updateOperationalContext(context: OperationalContextType): void { console.log(`šŸ”„ Updating operational context to: ${context}`); this.healthEngine.updateOperationalContext(context); } /** * Update marine environment conditions */ public updateMarineEnvironment(environment: Partial<MarineEnvironmentStatus>): void { console.log('🌊 Updating marine environment conditions'); // Get current environment and merge with updates const currentEnv: MarineEnvironmentStatus = { seaState: 'calm', weather: 'clear', windSpeed: 5, temperature: 22, powerStatus: 'normal', connectivityQuality: 0.9, expectedFailureRate: 1.0, recommendedTimeoutMultiplier: 1.0, criticalOperationsOnly: false, ...environment }; this.healthEngine.updateMarineEnvironment(currentEnv); } /** * Get current health status summary */ public async getHealthSummary(): Promise<void> { console.log('\nšŸ“Š Current Health Status Summary:'); console.log('================================'); const results = this.healthEngine.getAllResults(); for (const [checkId, result] of results) { const statusIcon = this.getStatusIcon(result.status); const scorePercent = (result.score * 100).toFixed(1); console.log(`${statusIcon} ${result.name}: ${result.status} (${scorePercent}%)`); console.log(` ${result.message}`); if (result.details) { const importantDetails = this.extractImportantDetails(result.details); if (importantDetails.length > 0) { console.log(` Details: ${importantDetails.join(', ')}`); } } console.log(''); } } /** * Simulate different sailing scenarios */ public async simulateScenarios(): Promise<void> { console.log('\nšŸŽ­ Simulating different sailing scenarios...\n'); // Scenario 1: Leaving dock console.log('šŸ“ Scenario 1: Leaving dock'); this.updateOperationalContext(OperationalContext.MOTORING); await this.wait(2000); await this.getHealthSummary(); // Scenario 2: Sailing in good conditions console.log('šŸ“ Scenario 2: Sailing in good conditions'); this.updateOperationalContext(OperationalContext.SAILING); this.updateMarineEnvironment({ seaState: 'moderate', // Valid enum value weather: 'clear' }); await this.wait(2000); await this.getHealthSummary(); // Scenario 3: Rough weather console.log('šŸ“ Scenario 3: Rough weather conditions'); this.updateMarineEnvironment({ seaState: 'rough', weather: 'storm' }); await this.wait(2000); await this.getHealthSummary(); // Scenario 4: Power conservation mode console.log('šŸ“ Scenario 4: Power conservation mode'); this.updateMarineEnvironment({ seaState: 'moderate', weather: 'cloudy', // Valid enum value powerStatus: 'conservation' }); await this.wait(2000); await this.getHealthSummary(); // Scenario 5: Emergency situation console.log('šŸ“ Scenario 5: Emergency situation'); this.updateOperationalContext(OperationalContext.EMERGENCY); this.updateMarineEnvironment({ seaState: 'very_rough', weather: 'storm', powerStatus: 'critical', criticalOperationsOnly: true }); await this.wait(2000); await this.getHealthSummary(); } /** * Mock GPS data provider (in real implementation, this would read from actual GPS) */ private async mockGPSDataProvider(): Promise<GPSData> { // Simulate some variability in GPS data const baseData = { latitude: 37.7749 + (Math.random() - 0.5) * 0.001, longitude: -122.4194 + (Math.random() - 0.5) * 0.001, altitude: 10 + Math.random() * 5, satelliteCount: 8 + Math.floor(Math.random() * 4), hdop: 1.0 + Math.random() * 2.0, vdop: 1.2 + Math.random() * 2.0, speed: Math.random() * 10, course: Math.random() * 360, timestamp: new Date(), fix: Math.random() > 0.1 ? '3d' as const : '2d' as const }; return baseData; } /** * Mock 48V battery data provider */ private async mock48VBatteryDataProvider(): Promise<BatteryData> { return { voltage: 50.4 + (Math.random() - 0.5) * 4.0, current: (Math.random() - 0.5) * 20, temperature: 25 + (Math.random() - 0.5) * 10, stateOfCharge: 60 + Math.random() * 35, capacity: 400 + (Math.random() - 0.5) * 50, nominalCapacity: 400, cycleCount: Math.floor(Math.random() * 500), timestamp: new Date(), batteryType: '48v' }; } /** * Mock 12V battery data provider */ private async mock12VBatteryDataProvider(): Promise<BatteryData> { return { voltage: 12.6 + (Math.random() - 0.5) * 1.0, current: (Math.random() - 0.5) * 10, temperature: 25 + (Math.random() - 0.5) * 8, stateOfCharge: 70 + Math.random() * 25, capacity: 100 + (Math.random() - 0.5) * 20, nominalCapacity: 100, cycleCount: Math.floor(Math.random() * 800), timestamp: new Date(), batteryType: '12v' }; } /** * Get status icon for display */ private getStatusIcon(status: HealthStatusType): string { switch (status) { case HealthStatus.HEALTHY: return 'āœ…'; case HealthStatus.DEGRADED: return 'āš ļø'; case HealthStatus.UNHEALTHY: return 'šŸ”¶'; case HealthStatus.CRITICAL: return '🚨'; default: return 'ā“'; } } /** * Extract important details for summary display */ private extractImportantDetails(details: Record<string, any>): string[] { const important: string[] = []; if (details['voltage'] !== undefined) { important.push(`${details['voltage'].toFixed(2)}V`); } if (details['stateOfCharge'] !== undefined) { important.push(`${details['stateOfCharge']}% SoC`); } if (details['satelliteCount'] !== undefined) { important.push(`${details['satelliteCount']} sats`); } if (details['hdop'] !== undefined) { important.push(`HDOP ${details['hdop'].toFixed(1)}`); } if (details['temperature'] !== undefined) { important.push(`${details['temperature']}°C`); } return important; } /** * Utility function to wait */ private wait(ms: number): Promise<void> { return new Promise(resolve => setTimeout(resolve, ms)); } } /** * Example usage function */ export async function runMarineHealthMonitoringExample(): Promise<void> { const monitor = new MarineHealthMonitoringExample(); try { // Start the monitoring system monitor.start(); // Wait a bit for initial health checks await new Promise(resolve => setTimeout(resolve, 3000)); // Get initial health summary await monitor.getHealthSummary(); // Run scenario simulations await monitor.simulateScenarios(); // Keep running for a bit to see ongoing monitoring console.log('\nā±ļø Running continuous monitoring for 30 seconds...'); await new Promise(resolve => setTimeout(resolve, 30000)); // Final health summary await monitor.getHealthSummary(); } finally { // Clean shutdown monitor.stop(); } } // Export for easy testing export default MarineHealthMonitoringExample;