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
148
services/AlarmManagement.ts
Normal file
148
services/AlarmManagement.ts
Normal file
|
@ -0,0 +1,148 @@
|
|||
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<string, MeasurementPointState> = 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<string, MeasurementPointState>): 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<string, import('../types/FrontendState').AlertState> {
|
||||
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();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue