UNPKG

@sailboat-computer/health-monitoring

Version:

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

194 lines 7.79 kB
"use strict"; /** * GPS Health Check for marine navigation systems */ Object.defineProperty(exports, "__esModule", { value: true }); exports.createGPSHealthCheck = exports.GPSHealthCheck = void 0; const index_1 = require("../index"); /** * GPS Health Check implementation */ class GPSHealthCheck extends index_1.BaseHealthCheck { constructor(config, gpsDataProvider) { super(config); this.gpsDataProvider = gpsDataProvider; } async performCheck(operationalContext, marineEnvironment) { try { const gpsData = await this.gpsDataProvider(); // Calculate health score based on multiple factors let score = 1.0; let status = index_1.HealthStatus.HEALTHY; const issues = []; const details = { satelliteCount: gpsData.satelliteCount, hdop: gpsData.hdop, vdop: gpsData.vdop, fix: gpsData.fix, dataAge: Date.now() - gpsData.timestamp.getTime() }; // Check GPS fix quality if (gpsData.fix === 'none') { score = 0.0; status = index_1.HealthStatus.CRITICAL; issues.push('No GPS fix available'); } else if (gpsData.fix === '2d') { score -= 0.3; issues.push('Only 2D GPS fix available'); } // Check satellite count if (gpsData.satelliteCount < 4) { score -= 0.4; issues.push(`Low satellite count: ${gpsData.satelliteCount}`); } else if (gpsData.satelliteCount < 6) { score -= 0.2; issues.push(`Marginal satellite count: ${gpsData.satelliteCount}`); } // Check HDOP (Horizontal Dilution of Precision) if (gpsData.hdop > 5.0) { score -= 0.3; issues.push(`Poor horizontal accuracy: HDOP ${gpsData.hdop}`); } else if (gpsData.hdop > 2.0) { score -= 0.1; issues.push(`Marginal horizontal accuracy: HDOP ${gpsData.hdop}`); } // Check data freshness const dataAge = Date.now() - gpsData.timestamp.getTime(); if (dataAge > 30000) { // 30 seconds score -= 0.4; issues.push(`Stale GPS data: ${Math.round(dataAge / 1000)}s old`); } else if (dataAge > 10000) { // 10 seconds score -= 0.2; issues.push(`Old GPS data: ${Math.round(dataAge / 1000)}s old`); } // Check for position jumps (if we have previous position) if (this.lastKnownPosition) { const distance = this.calculateDistance(this.lastKnownPosition.lat, this.lastKnownPosition.lon, gpsData.latitude, gpsData.longitude); const timeDiff = (gpsData.timestamp.getTime() - this.lastKnownPosition.timestamp.getTime()) / 1000; const maxReasonableSpeed = 50; // knots const maxDistance = (maxReasonableSpeed * 0.514444 * timeDiff) / 1000; // km if (distance > maxDistance * 2) { score -= 0.3; issues.push(`Suspicious position jump: ${distance.toFixed(2)}km`); details['positionJump'] = distance; } } // Environmental adjustments if (marineEnvironment) { if (marineEnvironment.weather === 'storm') { // GPS can be affected by heavy weather score = Math.max(score - 0.1, 0); details['environmentalImpact'] = 'Storm conditions may affect GPS accuracy'; } } // Update last known position if (gpsData.fix !== 'none') { this.lastKnownPosition = { lat: gpsData.latitude, lon: gpsData.longitude, timestamp: gpsData.timestamp }; } // Determine final status score = Math.max(0, Math.min(1, score)); if (score >= 0.8) { status = index_1.HealthStatus.HEALTHY; } else if (score >= 0.6) { status = index_1.HealthStatus.DEGRADED; } else if (score >= 0.3) { status = index_1.HealthStatus.UNHEALTHY; } else { status = index_1.HealthStatus.CRITICAL; } const message = issues.length > 0 ? `GPS issues detected: ${issues.join(', ')}` : 'GPS operating normally'; return { checkId: this.config.checkId, name: this.config.name, type: this.config.type, marineSystemType: this.config.marineSystemType, status, score, message, details, timestamp: new Date(), executionTime: 0, // Will be set by base class marineContext: { operationalContext, environmentalImpact: marineEnvironment?.weather === 'storm', safetyImpact: true, // GPS is critical for navigation safety powerImpact: 5 // GPS typically uses ~5W }, thresholds: this.config.thresholds }; } catch (error) { throw new Error(`GPS health check failed: ${error.message}`); } } /** * Calculate distance between two GPS coordinates using Haversine formula */ calculateDistance(lat1, lon1, lat2, lon2) { const R = 6371; // Earth's radius in kilometers const dLat = this.toRadians(lat2 - lat1); const dLon = this.toRadians(lon2 - lon1); const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(this.toRadians(lat1)) * Math.cos(this.toRadians(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return R * c; } toRadians(degrees) { return degrees * (Math.PI / 180); } } exports.GPSHealthCheck = GPSHealthCheck; /** * Factory function to create GPS health check with standard marine configuration */ function createGPSHealthCheck(gpsDataProvider, customConfig) { const defaultConfig = { checkId: 'gps-health', name: 'GPS Navigation Health', type: index_1.HealthCheckType.SENSOR, marineSystemType: index_1.MarineSystemType.NAVIGATION, interval: 10000, // Check every 10 seconds timeout: 5000, // 5 second timeout retryCount: 2, thresholds: { warning: 0.6, critical: 0.3, unit: 'health_score' }, marineSettings: { operationalContexts: [ index_1.OperationalContext.SAILING, index_1.OperationalContext.MOTORING, index_1.OperationalContext.ANCHORED, index_1.OperationalContext.DOCKED ], environmentalSensitivity: 0.3, // Moderately sensitive to weather powerAware: true, safetyImpact: true }, advanced: { trendAnalysis: true, predictiveAlerts: true, adaptiveThresholds: false, historicalComparison: true }, ...customConfig }; return new GPSHealthCheck(defaultConfig, gpsDataProvider); } exports.createGPSHealthCheck = createGPSHealthCheck; //# sourceMappingURL=GPSHealthCheck.js.map