import { EventEmitter } from 'events'; import { AlarmStateStore, VolatileAlert } from '../store/AlarmStateStore'; import { MeasurementPointState } from '../types/FrontendState'; export class AlarmManagement extends EventEmitter { private alarmStore: AlarmStateStore; private measurementPoints: Map = new Map(); constructor() { super(); this.alarmStore = new AlarmStateStore(); this.setupEventListeners(); } private setupEventListeners(): void { // Forward alarm store events this.alarmStore.on('alertCreated', (alert: VolatileAlert) => { this.emit('alertCreated', alert); }); this.alarmStore.on('alertUpdated', (alert: VolatileAlert) => { this.emit('alertUpdated', alert); }); this.alarmStore.on('alertRemoved', (alert: VolatileAlert) => { this.emit('alertRemoved', alert); }); } // Update measurement points for reference updateMeasurementPoints(measurementPoints: Record): void { this.measurementPoints.clear(); Object.values(measurementPoints).forEach(mp => { this.measurementPoints.set(mp.id, mp); }); } // Process sensor reading and check for alerts processSensorReading(sensorId: string, value: number, timestamp: Date): void { // Find measurement point by sensorId const measurementPoint = Array.from(this.measurementPoints.values()) .find(mp => mp.sensorId === sensorId); if (!measurementPoint) { console.warn(`No measurement point found for sensor: ${sensorId}`); return; } this.checkAlerts(measurementPoint, value); } private checkAlerts(measurementPoint: MeasurementPointState, value: number): void { const { id: pointId, warningThreshold, alarmThreshold, warningDelayMs, label, zone } = measurementPoint; // Check if value exceeds alarm threshold (immediate alarm) if (value >= alarmThreshold) { this.alarmStore.clearWarningTimer(pointId); this.alarmStore.createAlert( pointId, measurementPoint.sensorId, 'ALARM', value, alarmThreshold, label, zone ); return; } // Check if value exceeds warning threshold if (value >= warningThreshold) { const existingAlert = this.alarmStore.getAlertByMeasurementPointId(pointId); if (!existingAlert) { // Create warning alert this.alarmStore.createAlert( pointId, measurementPoint.sensorId, 'WARNING', value, warningThreshold, label, zone ); // Set timer for warning to escalate to alarm const timer = setTimeout(() => { this.alarmStore.createAlert( pointId, measurementPoint.sensorId, 'ALARM', value, warningThreshold, label, zone ); }, warningDelayMs); this.alarmStore.setWarningTimer(pointId, timer); } } else { // Value is below warning threshold, clear any alerts for this point this.alarmStore.clearWarningTimer(pointId); this.alarmStore.removeAlertsByMeasurementPointId(pointId); } } // Get all active alerts getActiveAlerts(): VolatileAlert[] { return this.alarmStore.getAllAlerts(); } // Get alerts in frontend state format getAlertStates(): Record { return this.alarmStore.toAlertStates(); } // Acknowledge alert acknowledgeAlert(alertId: string): boolean { return this.alarmStore.acknowledgeAlert(alertId); } // Silence alert silenceAlert(alertId: string): boolean { return this.alarmStore.silenceAlert(alertId); } // Get alert by ID getAlert(alertId: string): VolatileAlert | undefined { return this.alarmStore.getAlert(alertId); } // Get statistics getStats() { return this.alarmStore.getStats(); } // Clear all alerts (for testing/reset) clearAllAlerts(): void { this.alarmStore.clearAll(); } // Cleanup cleanup(): void { this.alarmStore.clearAll(); this.removeAllListeners(); } }