xref: /openbmc/webui-vue/src/components/Composables/useSensors.ts (revision d3b05033fe82aed6c53f4f2b52c23d3bd285d423)
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