m2-inno-bedpressure/utils/sensorConfig.ts
2025-06-21 13:29:01 +07:00

152 lines
No EOL
4.3 KiB
TypeScript

import { SensorConfig, SensorZoneConfig } from '@/types/sensor';
// Define zone-based default configurations
export const ZONE_CONFIGS: Record<string, SensorZoneConfig> = {
head: {
zone: 'head',
defaultThresholds: {
warningThreshold: 3000,
alarmThreshold: 3500,
warningDelayMs: 30000 // 30 seconds - critical area needs fast response
},
description: 'Head area - most critical, fastest escalation'
},
shoulders: {
zone: 'shoulders',
defaultThresholds: {
warningThreshold: 2800,
alarmThreshold: 3200,
warningDelayMs: 45000 // 45 seconds
},
description: 'Shoulder area - high priority, moderate escalation'
},
back: {
zone: 'back',
defaultThresholds: {
warningThreshold: 2500,
alarmThreshold: 3000,
warningDelayMs: 60000 // 1 minute
},
description: 'Back area - moderate priority, standard escalation'
},
hips: {
zone: 'hips',
defaultThresholds: {
warningThreshold: 2200,
alarmThreshold: 2800,
warningDelayMs: 90000 // 90 seconds
},
description: 'Hip area - moderate priority, longer escalation'
},
legs: {
zone: 'legs',
defaultThresholds: {
warningThreshold: 2000,
alarmThreshold: 2500,
warningDelayMs: 120000 // 2 minutes
},
description: 'Leg area - lower priority, extended escalation'
},
feet: {
zone: 'feet',
defaultThresholds: {
warningThreshold: 1500,
alarmThreshold: 1800,
warningDelayMs: 180000 // 3 minutes
},
description: 'Feet area - lowest priority, longest escalation'
}
};
/**
* Validates sensor configuration against zone defaults
*/
export function validateSensorConfig(config: SensorConfig): {
isValid: boolean;
warnings: string[];
errors: string[];
} {
const warnings: string[] = [];
const errors: string[] = [];
// Check if zone exists
const zoneConfig = ZONE_CONFIGS[config.zone];
if (!zoneConfig) {
errors.push(`Unknown zone: ${config.zone}`);
return { isValid: false, warnings, errors };
}
// Validate threshold values
if (config.alarmThreshold <= config.warningThreshold) {
errors.push(`Alarm threshold (${config.alarmThreshold}) must be greater than warning threshold (${config.warningThreshold})`);
}
if (config.warningThreshold <= 0 || config.alarmThreshold <= 0) {
errors.push('Thresholds must be positive values');
}
if (config.warningDelayMs <= 0) {
errors.push('Warning delay must be positive');
}
// Check against zone defaults (warnings only)
const defaults = zoneConfig.defaultThresholds;
const tolerance = 0.2; // 20% tolerance
if (Math.abs(config.warningThreshold - defaults.warningThreshold) / defaults.warningThreshold > tolerance) {
warnings.push(`Warning threshold (${config.warningThreshold}) differs significantly from zone default (${defaults.warningThreshold})`);
}
if (Math.abs(config.alarmThreshold - defaults.alarmThreshold) / defaults.alarmThreshold > tolerance) {
warnings.push(`Alarm threshold (${config.alarmThreshold}) differs significantly from zone default (${defaults.alarmThreshold})`);
}
if (Math.abs(config.warningDelayMs - defaults.warningDelayMs) / defaults.warningDelayMs > tolerance) {
warnings.push(`Warning delay (${config.warningDelayMs}ms) differs significantly from zone default (${defaults.warningDelayMs}ms)`);
}
return { isValid: errors.length === 0, warnings, errors };
}
/**
* Creates a sensor config with zone defaults as base
*/
export function createSensorConfig(
id: string,
position: { x: number; y: number },
zone: string,
label: string,
overrides: Partial<SensorConfig> = {}
): SensorConfig {
const zoneConfig = ZONE_CONFIGS[zone];
if (!zoneConfig) {
throw new Error(`Unknown zone: ${zone}`);
}
return {
id,
x: position.x,
y: position.y,
zone,
label,
...zoneConfig.defaultThresholds,
...overrides
};
}
/**
* Gets human-readable duration string
*/
export function formatDuration(ms: number): string {
const seconds = Math.floor(ms / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
if (hours > 0) {
return `${hours}h ${minutes % 60}m`;
} else if (minutes > 0) {
return `${minutes}m ${seconds % 60}s`;
} else {
return `${seconds}s`;
}
}