1import { computed } from 'vue'; 2import { useAllSubResources } from '@/api/composables/useAllSubResources'; 3 4/** 5 * Raw sensor data from Redfish API 6 */ 7interface RawSensor { 8 '@odata.id': string; 9 Name: string; 10 Status?: { Health?: string }; 11 Reading?: number; 12 ReadingCelsius?: number; 13 ReadingVolts?: number; 14 ReadingUnits?: string; 15 ReadingType?: string; 16 Thresholds?: { 17 LowerCaution?: { Reading?: number }; 18 UpperCaution?: { Reading?: number }; 19 LowerCritical?: { Reading?: number }; 20 UpperCritical?: { Reading?: number }; 21 }; 22 LowerThresholdNonCritical?: number; 23 UpperThresholdNonCritical?: number; 24 LowerThresholdCritical?: number; 25 UpperThresholdCritical?: number; 26} 27 28/** 29 * Sensor data format for display 30 */ 31export interface SensorDisplay { 32 name: string; 33 status: string; 34 currentValue: number | undefined; 35 lowerCaution: number | undefined; 36 upperCaution: number | undefined; 37 lowerCritical: number | undefined; 38 upperCritical: number | undefined; 39 units: string; 40 currentValueDisplay: string; 41 lowerCautionDisplay: string; 42 upperCautionDisplay: string; 43 lowerCriticalDisplay: string; 44 upperCriticalDisplay: string; 45} 46 47/** 48 * Helper function to format a value with units 49 * Only shows units if the value is defined 50 */ 51function formatValueWithUnit(value: number | undefined, units: string): string { 52 if (value === undefined) { 53 return ''; 54 } 55 return units ? ` ${units}` : ''; 56} 57 58/** 59 * Transforms raw sensor data from Redfish API to display format 60 * 61 * @param sensor - Raw sensor data from Redfish 62 * @returns Transformed sensor data for display 63 */ 64function transformSensorData(sensor: RawSensor): SensorDisplay { 65 const currentValue = 66 sensor.Reading ?? sensor.ReadingCelsius ?? sensor.ReadingVolts; 67 const lowerCaution = 68 sensor.Thresholds?.LowerCaution?.Reading ?? 69 sensor.LowerThresholdNonCritical; 70 const upperCaution = 71 sensor.Thresholds?.UpperCaution?.Reading ?? 72 sensor.UpperThresholdNonCritical; 73 const lowerCritical = 74 sensor.Thresholds?.LowerCritical?.Reading ?? sensor.LowerThresholdCritical; 75 const upperCritical = 76 sensor.Thresholds?.UpperCritical?.Reading ?? sensor.UpperThresholdCritical; 77 78 // Determine units based on sensor type 79 let units = ''; 80 if (sensor.ReadingUnits) { 81 units = sensor.ReadingUnits; 82 } else if (sensor.ReadingCelsius !== undefined) { 83 units = '℃'; 84 } else if ( 85 sensor.ReadingType === 'Voltage' || 86 sensor.ReadingVolts !== undefined 87 ) { 88 units = 'V'; 89 } 90 91 return { 92 name: sensor.Name, 93 status: sensor.Status?.Health || 'Unknown', 94 currentValue, 95 lowerCaution, 96 upperCaution, 97 lowerCritical, 98 upperCritical, 99 units, 100 currentValueDisplay: formatValueWithUnit(currentValue, units), 101 lowerCautionDisplay: formatValueWithUnit(lowerCaution, units), 102 upperCautionDisplay: formatValueWithUnit(upperCaution, units), 103 lowerCriticalDisplay: formatValueWithUnit(lowerCritical, units), 104 upperCriticalDisplay: formatValueWithUnit(upperCritical, units), 105 }; 106} 107 108/** 109 * Composable for fetching all sensors from all chassis 110 * Uses useAllSubResources for efficient fetching with: 111 * - Automatic expand query support detection 112 * - Deduplication by @odata.id 113 * - Error aggregation 114 * - Smart retry logic (skips 4xx errors) 115 * - TanStack Query caching and state management 116 * 117 * @returns TanStack Query result with transformed sensor data 118 */ 119export function useSensors() { 120 const { 121 data: rawSensors, 122 isLoading, 123 isError, 124 error, 125 refetch, 126 isFetching, 127 } = useAllSubResources<RawSensor>('/redfish/v1/Chassis/chassis', 'Sensors'); 128 129 // Transform raw sensor data to display format 130 const sensors = computed(() => { 131 if (!rawSensors.value) return []; 132 return rawSensors.value.map(transformSensorData); 133 }); 134 135 return { 136 data: sensors, 137 isLoading, 138 isError, 139 error, 140 refetch, 141 isFetching, 142 }; 143} 144