m2-inno-bedpressure/store/AlarmStateStore.ts
Siwat Sirichai 4ae5196ef1 feat: Add Swagger documentation support and restructure routes
- Added @elysiajs/swagger dependency to package.json for API documentation.
- Removed the old bed router and replaced it with a new history router.
- Created a new state router to manage WebSocket connections and state updates.
- Implemented a comprehensive state management system with the StateManager service.
- Introduced AlarmManagement and BedService services for handling alarms and sensor readings.
- Established a new MQTT service for managing MQTT connections and subscriptions.
- Created an AlarmStateStore to manage volatile alerts and their states.
- Defined FrontendState types for structured state management and WebSocket messaging.
2025-06-21 18:56:34 +07:00

201 lines
No EOL
5.3 KiB
TypeScript

import { EventEmitter } from 'events';
import { AlertState } from '../types/FrontendState';
export interface VolatileAlert {
id: string;
measurementPointId: string;
sensorId: string;
type: 'WARNING' | 'ALARM';
value: number;
threshold: number;
acknowledged: boolean;
silenced: boolean;
startTime: Date;
sensorLabel: string;
zone: string;
}
export class AlarmStateStore extends EventEmitter {
private alerts: Map<string, VolatileAlert> = new Map();
private warningTimers: Map<string, NodeJS.Timeout> = new Map();
private alertIdCounter = 0;
// Generate unique alert ID
private generateAlertId(): string {
return `alert_${Date.now()}_${++this.alertIdCounter}`;
}
// Create a new alert
createAlert(
measurementPointId: string,
sensorId: string,
type: 'WARNING' | 'ALARM',
value: number,
threshold: number,
sensorLabel: string,
zone: string
): VolatileAlert {
// Check if there's already an active alert for this measurement point
const existingAlert = this.getAlertByMeasurementPointId(measurementPointId);
if (existingAlert) {
// If upgrading from WARNING to ALARM, update the existing alert
if (existingAlert.type === 'WARNING' && type === 'ALARM') {
existingAlert.type = 'ALARM';
existingAlert.value = value;
existingAlert.threshold = threshold;
this.emit('alertUpdated', existingAlert);
return existingAlert;
}
// If it's the same type or downgrading, return existing
return existingAlert;
}
const alert: VolatileAlert = {
id: this.generateAlertId(),
measurementPointId,
sensorId,
type,
value,
threshold,
acknowledged: false,
silenced: false,
startTime: new Date(),
sensorLabel,
zone
};
this.alerts.set(alert.id, alert);
this.emit('alertCreated', alert);
return alert;
}
// Get alert by measurement point ID
getAlertByMeasurementPointId(measurementPointId: string): VolatileAlert | undefined {
return Array.from(this.alerts.values())
.find(alert => alert.measurementPointId === measurementPointId);
}
// Remove alert
removeAlert(alertId: string): boolean {
const alert = this.alerts.get(alertId);
if (alert) {
this.alerts.delete(alertId);
this.emit('alertRemoved', alert);
return true;
}
return false;
}
// Remove alerts by measurement point ID
removeAlertsByMeasurementPointId(measurementPointId: string): void {
const alertsToRemove = Array.from(this.alerts.values())
.filter(alert => alert.measurementPointId === measurementPointId);
alertsToRemove.forEach(alert => {
this.alerts.delete(alert.id);
this.emit('alertRemoved', alert);
});
}
// Acknowledge alert
acknowledgeAlert(alertId: string): boolean {
const alert = this.alerts.get(alertId);
if (alert) {
alert.acknowledged = true;
this.emit('alertUpdated', alert);
return true;
}
return false;
}
// Silence alert
silenceAlert(alertId: string): boolean {
const alert = this.alerts.get(alertId);
if (alert) {
alert.silenced = true;
this.emit('alertUpdated', alert);
return true;
}
return false;
}
// Set warning timer
setWarningTimer(measurementPointId: string, timer: NodeJS.Timeout): void {
// Clear existing timer if any
this.clearWarningTimer(measurementPointId);
this.warningTimers.set(measurementPointId, timer);
}
// Clear warning timer
clearWarningTimer(measurementPointId: string): void {
const timer = this.warningTimers.get(measurementPointId);
if (timer) {
clearTimeout(timer);
this.warningTimers.delete(measurementPointId);
}
}
// Get all active alerts
getAllAlerts(): VolatileAlert[] {
return Array.from(this.alerts.values());
}
// Get alert by ID
getAlert(alertId: string): VolatileAlert | undefined {
return this.alerts.get(alertId);
}
// Convert to AlertState format for frontend
toAlertState(alert: VolatileAlert): AlertState {
return {
id: alert.id,
measurementPointId: alert.measurementPointId,
type: alert.type,
value: alert.value,
threshold: alert.threshold,
acknowledged: alert.acknowledged,
silenced: alert.silenced,
startTime: alert.startTime,
endTime: undefined, // Volatile alerts don't have end times
sensorLabel: alert.sensorLabel,
zone: alert.zone
};
}
// Convert all alerts to AlertState format
toAlertStates(): Record<string, AlertState> {
const result: Record<string, AlertState> = {};
this.alerts.forEach((alert, id) => {
result[id] = this.toAlertState(alert);
});
return result;
}
// Clear all alerts
clearAll(): void {
// Clear all warning timers
this.warningTimers.forEach(timer => clearTimeout(timer));
this.warningTimers.clear();
// Clear all alerts
this.alerts.clear();
this.emit('allAlertsCleared');
}
// Get statistics
getStats() {
const alerts = this.getAllAlerts();
return {
total: alerts.length,
warnings: alerts.filter(a => a.type === 'WARNING').length,
alarms: alerts.filter(a => a.type === 'ALARM').length,
acknowledged: alerts.filter(a => a.acknowledged).length,
silenced: alerts.filter(a => a.silenced).length
};
}
}