Skip to main content

nv_redfish/
sensor.rs

1// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! Sensor abstraction for Redfish entities.
17//!
18//! This module provides a unified interface for accessing sensor data from
19//! Redfish entities that support modern sensor links. The `HasSensors` trait
20//! is implemented by entities that have associated sensors, and provides access
21//! to a `Sensor` handle for sensor data retrieval.
22//!
23//! # Modern vs Legacy Approach
24//!
25//! This module supports the modern Redfish approach where entities have direct
26//! links to their sensors. For legacy BMCs that only expose sensor data through
27//! `Chassis/Power` and `Chassis/Thermal`, use those explicit endpoints instead.
28
29use crate::entity_link::EntityLink;
30use crate::schema::environment_metrics::EnvironmentMetrics;
31use crate::schema::sensor::Sensor as SchemaSensor;
32use crate::Error;
33use nv_redfish_core::Bmc;
34use nv_redfish_core::NavProperty;
35use nv_redfish_core::ODataId;
36
37/// Extracts sensor URIs from metric fields and creates sensor navigation properties.
38///
39/// Handles both single `Option<SensorExcerpt*>` and `Option<Vec<SensorExcerpt*>>` fields.
40/// All `single:` fields must come before `vec:` fields.
41///
42/// # Example
43/// ```ignore
44/// extract_sensor_uris!(metrics,
45///     single: temperature,
46///     single: voltage,
47///     vec: fan_speeds
48/// )
49/// ```
50#[macro_export(local_inner_macros)]
51macro_rules! extract_sensor_uris {
52    ($metrics:expr, $(single: $single_field:ident),* $(, vec: $vec_field:ident)* $(,)?) => {{
53        let mut uris = Vec::new();
54
55        $(
56            if let Some(Some(uri)) = $metrics.$single_field.as_ref()
57                .and_then(|f| f.data_source_uri.as_ref()) {
58                uris.push(uri.clone());
59            }
60        )*
61
62        $(
63            if let Some(items) = &$metrics.$vec_field {
64                for item in items {
65                    if let Some(Some(uri)) = item.data_source_uri.as_ref() {
66                        uris.push(uri.clone());
67                    }
68                }
69            }
70        )*
71
72        $crate::sensor::collect_sensors(uris)
73    }};
74}
75/// Link for accessing sensor.
76pub type SensorLink<B> = EntityLink<B, SchemaSensor>;
77
78/// Collect sensor refs from URIs
79pub(crate) fn collect_sensors(
80    uris: impl IntoIterator<Item = String>,
81) -> Vec<NavProperty<SchemaSensor>> {
82    uris.into_iter()
83        .map(|uri| NavProperty::<SchemaSensor>::new_reference(ODataId::from(uri)))
84        .collect()
85}
86
87/// Helper function to extract enviroment metrics
88pub(crate) async fn extract_environment_sensors<B: Bmc>(
89    metrics_ref: &NavProperty<EnvironmentMetrics>,
90    bmc: &B,
91) -> Result<Vec<NavProperty<SchemaSensor>>, Error<B>> {
92    metrics_ref
93        .get(bmc)
94        .await
95        .map(|m| {
96            extract_sensor_uris!(m,
97                single: temperature_celsius,
98                single: humidity_percent,
99                single: power_watts,
100                single: energyk_wh,
101                single: power_load_percent,
102                single: dew_point_celsius,
103                single: absolute_humidity,
104                single: energy_joules,
105                single: ambient_temperature_celsius,
106                single: voltage,
107                single: current_amps,
108                vec: fan_speeds_percent
109            )
110        })
111        .map_err(Error::Bmc)
112}