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.
This commit is contained in:
parent
a767dc3635
commit
4ae5196ef1
12 changed files with 1189 additions and 1 deletions
201
store/AlarmStateStore.ts
Normal file
201
store/AlarmStateStore.ts
Normal file
|
@ -0,0 +1,201 @@
|
|||
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
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue