blob: 2675e7f6d40d6500a721774caa0f3c71f04fe7d7 [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
3// SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01004#pragma once
5
Ed Tanousd7857202025-01-28 15:32:26 -08006#include "bmcweb_config.h"
7
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08008#include "app.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -08009#include "async_resp.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080010#include "dbus_singleton.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080011#include "dbus_utility.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080012#include "error_messages.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -070013#include "generated/enums/redundancy.hpp"
Matt Simmeringaaf08ac2023-10-04 08:41:01 -070014#include "generated/enums/resource.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080015#include "http_request.hpp"
16#include "logging.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080017#include "query.hpp"
18#include "registries/privilege_registry.hpp"
Ed Tanous50ebd4a2023-01-19 19:03:17 -080019#include "str_utility.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080020#include "utils/dbus_utils.hpp"
21#include "utils/json_utils.hpp"
22#include "utils/query_param.hpp"
Janet Adkins1516c212024-08-14 13:22:41 -050023#include "utils/sensor_utils.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070024
Ed Tanousd7857202025-01-28 15:32:26 -080025#include <asm-generic/errno.h>
26
27#include <boost/beast/http/status.hpp>
28#include <boost/beast/http/verb.hpp>
George Liue99073f2022-12-09 11:06:16 +080029#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070030#include <boost/url/format.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080031#include <boost/url/url.hpp>
32#include <nlohmann/json.hpp>
33#include <sdbusplus/message/native_types.hpp>
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +020034#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050035
Ed Tanousd7857202025-01-28 15:32:26 -080036#include <algorithm>
George Liu7a1dbc42022-12-07 16:03:22 +080037#include <array>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050038#include <cmath>
Ed Tanousd7857202025-01-28 15:32:26 -080039#include <cstddef>
40#include <cstdint>
41#include <functional>
Nan Zhoufe04d492022-06-22 17:10:41 +000042#include <iterator>
43#include <map>
Ed Tanousd7857202025-01-28 15:32:26 -080044#include <memory>
45#include <optional>
Ed Tanous3544d2a2023-08-06 18:12:20 -070046#include <ranges>
Nan Zhoufe04d492022-06-22 17:10:41 +000047#include <set>
Ed Tanousd7857202025-01-28 15:32:26 -080048#include <span>
Ed Tanous18f8f602023-07-18 10:07:23 -070049#include <string>
George Liu7a1dbc42022-12-07 16:03:22 +080050#include <string_view>
Ed Tanousd7857202025-01-28 15:32:26 -080051#include <unordered_map>
Ed Tanousb5a76932020-09-29 16:16:58 -070052#include <utility>
Ed Tanousabf2add2019-01-22 16:40:12 -080053#include <variant>
Ed Tanousd7857202025-01-28 15:32:26 -080054#include <vector>
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010055
Ed Tanous1abe55e2018-09-05 08:30:59 -070056namespace redfish
57{
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010058
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020059namespace sensors
60{
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020061
Ed Tanous02da7c52022-02-27 00:09:02 -080062// clang-format off
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020063namespace dbus
64{
Ed Tanouscf9e4172022-12-21 09:30:16 -080065constexpr auto powerPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080066 "/xyz/openbmc_project/sensors/voltage",
67 "/xyz/openbmc_project/sensors/power"
68});
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000069
Ed Tanous25b54db2024-04-17 15:40:31 -070070constexpr auto getSensorPaths(){
71 if constexpr(BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM){
72 return std::to_array<std::string_view>({
73 "/xyz/openbmc_project/sensors/power",
74 "/xyz/openbmc_project/sensors/current",
75 "/xyz/openbmc_project/sensors/airflow",
76 "/xyz/openbmc_project/sensors/humidity",
77 "/xyz/openbmc_project/sensors/voltage",
78 "/xyz/openbmc_project/sensors/fan_tach",
79 "/xyz/openbmc_project/sensors/temperature",
80 "/xyz/openbmc_project/sensors/fan_pwm",
81 "/xyz/openbmc_project/sensors/altitude",
82 "/xyz/openbmc_project/sensors/energy",
Zev Weiss44914192025-03-11 07:59:30 +000083 "/xyz/openbmc_project/sensors/liquidflow",
84 "/xyz/openbmc_project/sensors/pressure",
Ed Tanous25b54db2024-04-17 15:40:31 -070085 "/xyz/openbmc_project/sensors/utilization"});
86 } else {
87 return std::to_array<std::string_view>({"/xyz/openbmc_project/sensors/power",
88 "/xyz/openbmc_project/sensors/current",
89 "/xyz/openbmc_project/sensors/airflow",
90 "/xyz/openbmc_project/sensors/humidity",
91 "/xyz/openbmc_project/sensors/utilization"});
92}
93}
94
95constexpr auto sensorPaths = getSensorPaths();
Ed Tanous02da7c52022-02-27 00:09:02 -080096
Ed Tanouscf9e4172022-12-21 09:30:16 -080097constexpr auto thermalPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080098 "/xyz/openbmc_project/sensors/fan_tach",
99 "/xyz/openbmc_project/sensors/temperature",
100 "/xyz/openbmc_project/sensors/fan_pwm"
101});
102
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000103} // namespace dbus
Ed Tanous02da7c52022-02-27 00:09:02 -0800104// clang-format on
105
Janet Adkins0c728b42024-08-29 11:09:10 -0500106constexpr std::string_view powerNodeStr = sensor_utils::chassisSubNodeToString(
107 sensor_utils::ChassisSubNode::powerNode);
108constexpr std::string_view sensorsNodeStr =
109 sensor_utils::chassisSubNodeToString(
110 sensor_utils::ChassisSubNode::sensorsNode);
111constexpr std::string_view thermalNodeStr =
112 sensor_utils::chassisSubNodeToString(
113 sensor_utils::ChassisSubNode::thermalNode);
114
Ed Tanouscf9e4172022-12-21 09:30:16 -0800115using sensorPair =
116 std::pair<std::string_view, std::span<const std::string_view>>;
Ed Tanous02da7c52022-02-27 00:09:02 -0800117static constexpr std::array<sensorPair, 3> paths = {
Janet Adkins0c728b42024-08-29 11:09:10 -0500118 {{sensors::powerNodeStr, dbus::powerPaths},
119 {sensors::sensorsNodeStr, dbus::sensorPaths},
120 {sensors::thermalNodeStr, dbus::thermalPaths}}};
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000121
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200122} // namespace sensors
123
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100124/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200125 * SensorsAsyncResp
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100126 * Gathers data needed for response processing after async calls are done
127 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128class SensorsAsyncResp
129{
130 public:
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200131 using DataCompleteCb = std::function<void(
132 const boost::beast::http::status status,
Nan Zhoufe04d492022-06-22 17:10:41 +0000133 const std::map<std::string, std::string>& uriToDbus)>;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200134
135 struct SensorData
136 {
Ed Tanousf836c1d2024-09-06 16:05:11 -0700137 std::string name;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200138 std::string uri;
Ed Tanousf836c1d2024-09-06 16:05:11 -0700139 std::string dbusPath;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200140 };
141
Ed Tanous8a592812022-06-04 09:06:59 -0700142 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800143 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800144 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800145 std::string_view subNode) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400146 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
147 chassisSubNode(subNode), efficientExpand(false)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500148 {}
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200149
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200150 // Store extra data about sensor mapping and return it in callback
Ed Tanous8a592812022-06-04 09:06:59 -0700151 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800152 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800153 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800154 std::string_view subNode,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200155 DataCompleteCb&& creationComplete) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400156 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
157 chassisSubNode(subNode), efficientExpand(false),
158 metadata{std::vector<SensorData>()},
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200159 dataComplete{std::move(creationComplete)}
160 {}
161
Nan Zhou928fefb2022-03-28 08:45:00 -0700162 // sensor collections expand
Ed Tanous8a592812022-06-04 09:06:59 -0700163 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
Nan Zhou928fefb2022-03-28 08:45:00 -0700164 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800165 std::span<const std::string_view> typesIn,
Ed Tanous8a592812022-06-04 09:06:59 -0700166 const std::string_view& subNode, bool efficientExpandIn) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400167 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
168 chassisSubNode(subNode), efficientExpand(efficientExpandIn)
Nan Zhou928fefb2022-03-28 08:45:00 -0700169 {}
170
Ed Tanous1abe55e2018-09-05 08:30:59 -0700171 ~SensorsAsyncResp()
172 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800173 if (asyncResp->res.result() ==
174 boost::beast::http::status::internal_server_error)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700175 {
176 // Reset the json object to clear out any data that made it in
177 // before the error happened todo(ed) handle error condition with
178 // proper code
zhanghch058d1b46d2021-04-01 11:18:24 +0800179 asyncResp->res.jsonValue = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700180 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200181
182 if (dataComplete && metadata)
183 {
Nan Zhoufe04d492022-06-22 17:10:41 +0000184 std::map<std::string, std::string> map;
zhanghch058d1b46d2021-04-01 11:18:24 +0800185 if (asyncResp->res.result() == boost::beast::http::status::ok)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200186 {
187 for (auto& sensor : *metadata)
188 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700189 map.emplace(sensor.uri, sensor.dbusPath);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200190 }
191 }
zhanghch058d1b46d2021-04-01 11:18:24 +0800192 dataComplete(asyncResp->res.result(), map);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200193 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700194 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100195
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800196 SensorsAsyncResp(const SensorsAsyncResp&) = delete;
197 SensorsAsyncResp(SensorsAsyncResp&&) = delete;
198 SensorsAsyncResp& operator=(const SensorsAsyncResp&) = delete;
199 SensorsAsyncResp& operator=(SensorsAsyncResp&&) = delete;
200
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200201 void addMetadata(const nlohmann::json& sensorObject,
Ed Tanousc1d019a2022-08-06 09:36:06 -0700202 const std::string& dbusPath)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200203 {
204 if (metadata)
205 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700206 metadata->emplace_back(SensorData{
207 sensorObject["Name"], sensorObject["@odata.id"], dbusPath});
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200208 }
209 }
210
211 void updateUri(const std::string& name, const std::string& uri)
212 {
213 if (metadata)
214 {
215 for (auto& sensor : *metadata)
216 {
217 if (sensor.name == name)
218 {
219 sensor.uri = uri;
220 }
221 }
222 }
223 }
224
zhanghch058d1b46d2021-04-01 11:18:24 +0800225 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200226 const std::string chassisId;
Ed Tanouscf9e4172022-12-21 09:30:16 -0800227 const std::span<const std::string_view> types;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200228 const std::string chassisSubNode;
Nan Zhou928fefb2022-03-28 08:45:00 -0700229 const bool efficientExpand;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200230
231 private:
232 std::optional<std::vector<SensorData>> metadata;
233 DataCompleteCb dataComplete;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100234};
235
Janet Adkinsc9563602024-08-28 11:37:46 -0500236using InventoryItem = sensor_utils::InventoryItem;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500237
238/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530239 * @brief Get objects with connection necessary for sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200240 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100241 * @param sensorNames Sensors retrieved from chassis
242 * @param callback Callback for processing gathered connections
243 */
244template <typename Callback>
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530245void getObjectsWithConnection(
Ed Tanous81ce6092020-12-17 16:54:55 +0000246 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +0000247 const std::shared_ptr<std::set<std::string>>& sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530248 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700249{
Ed Tanous62598e32023-07-17 17:06:25 -0700250 BMCWEB_LOG_DEBUG("getObjectsWithConnection enter");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700251 const std::string path = "/xyz/openbmc_project/sensors";
George Liue99073f2022-12-09 11:06:16 +0800252 constexpr std::array<std::string_view, 1> interfaces = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700253 "xyz.openbmc_project.Sensor.Value"};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100254
George Liue99073f2022-12-09 11:06:16 +0800255 // Make call to ObjectMapper to find all sensors objects
256 dbus::utility::getSubTree(
257 path, 2, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700258 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
George Liue99073f2022-12-09 11:06:16 +0800259 sensorNames](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700260 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400261 // Response handler for parsing objects subtree
262 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler enter");
263 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700264 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400265 messages::internalError(sensorsAsyncResp->asyncResp->res);
266 BMCWEB_LOG_ERROR(
267 "getObjectsWithConnection resp_handler: Dbus error {}", ec);
268 return;
269 }
270
271 BMCWEB_LOG_DEBUG("Found {} subtrees", subtree.size());
272
273 // Make unique list of connections only for requested sensor types
274 // and found in the chassis
275 std::set<std::string> connections;
276 std::set<std::pair<std::string, std::string>> objectsWithConnection;
277
278 BMCWEB_LOG_DEBUG("sensorNames list count: {}", sensorNames->size());
279 for (const std::string& tsensor : *sensorNames)
280 {
281 BMCWEB_LOG_DEBUG("Sensor to find: {}", tsensor);
282 }
283
284 for (const std::pair<std::string,
285 std::vector<std::pair<
286 std::string, std::vector<std::string>>>>&
287 object : subtree)
288 {
289 if (sensorNames->find(object.first) != sensorNames->end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700290 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400291 for (const std::pair<std::string, std::vector<std::string>>&
292 objData : object.second)
293 {
294 BMCWEB_LOG_DEBUG("Adding connection: {}",
295 objData.first);
296 connections.insert(objData.first);
297 objectsWithConnection.insert(
298 std::make_pair(object.first, objData.first));
299 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700300 }
301 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400302 BMCWEB_LOG_DEBUG("Found {} connections", connections.size());
303 callback(std::move(connections), std::move(objectsWithConnection));
304 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler exit");
305 });
Ed Tanous62598e32023-07-17 17:06:25 -0700306 BMCWEB_LOG_DEBUG("getObjectsWithConnection exit");
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530307}
308
309/**
310 * @brief Create connections necessary for sensors
311 * @param SensorsAsyncResp Pointer to object holding response data
312 * @param sensorNames Sensors retrieved from chassis
313 * @param callback Callback for processing gathered connections
314 */
315template <typename Callback>
Ed Tanousdaadfb22024-12-20 09:25:54 -0800316void getConnections(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
317 const std::shared_ptr<std::set<std::string>>& sensorNames,
Nan Zhoufe04d492022-06-22 17:10:41 +0000318 Callback&& callback)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530319{
320 auto objectsWithConnectionCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -0700321 [callback = std::forward<Callback>(callback)](
322 const std::set<std::string>& connections,
323 const std::set<std::pair<std::string, std::string>>&
324 /*objectsWithConnection*/) { callback(connections); };
Ed Tanous81ce6092020-12-17 16:54:55 +0000325 getObjectsWithConnection(sensorsAsyncResp, sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530326 std::move(objectsWithConnectionCb));
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100327}
328
329/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700330 * @brief Shrinks the list of sensors for processing
331 * @param SensorsAysncResp The class holding the Redfish response
332 * @param allSensors A list of all the sensors associated to the
333 * chassis element (i.e. baseboard, front panel, etc...)
334 * @param activeSensors A list that is a reduction of the incoming
335 * allSensors list. Eliminate Thermal sensors when a Power request is
336 * made, and eliminate Power sensors when a Thermal request is made.
337 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000338inline void reduceSensorList(
Ed Tanous7f1cc262022-08-09 13:33:57 -0700339 crow::Response& res, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800340 std::span<const std::string_view> sensorTypes,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700341 const std::vector<std::string>* allSensors,
Nan Zhoufe04d492022-06-22 17:10:41 +0000342 const std::shared_ptr<std::set<std::string>>& activeSensors)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700343{
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700344 if ((allSensors == nullptr) || (activeSensors == nullptr))
345 {
Ed Tanous7f1cc262022-08-09 13:33:57 -0700346 messages::resourceNotFound(res, chassisSubNode,
Janet Adkins0c728b42024-08-29 11:09:10 -0500347 chassisSubNode == sensors::thermalNodeStr
Ed Tanous7f1cc262022-08-09 13:33:57 -0700348 ? "Temperatures"
349 : "Voltages");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700350
351 return;
352 }
353 if (allSensors->empty())
354 {
355 // Nothing to do, the activeSensors object is also empty
356 return;
357 }
358
Ed Tanous7f1cc262022-08-09 13:33:57 -0700359 for (std::string_view type : sensorTypes)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700360 {
361 for (const std::string& sensor : *allSensors)
362 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700363 if (sensor.starts_with(type))
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700364 {
365 activeSensors->emplace(sensor);
366 }
367 }
368 }
369}
370
Ed Tanous7f1cc262022-08-09 13:33:57 -0700371/*
372 *Populates the top level collection for a given subnode. Populates
373 *SensorCollection, Power, or Thermal schemas.
374 *
375 * */
376inline void populateChassisNode(nlohmann::json& jsonValue,
377 std::string_view chassisSubNode)
378{
Janet Adkins0c728b42024-08-29 11:09:10 -0500379 if (chassisSubNode == sensors::powerNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700380 {
381 jsonValue["@odata.type"] = "#Power.v1_5_2.Power";
382 }
Janet Adkins0c728b42024-08-29 11:09:10 -0500383 else if (chassisSubNode == sensors::thermalNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700384 {
385 jsonValue["@odata.type"] = "#Thermal.v1_4_0.Thermal";
386 jsonValue["Fans"] = nlohmann::json::array();
387 jsonValue["Temperatures"] = nlohmann::json::array();
388 }
Janet Adkins0c728b42024-08-29 11:09:10 -0500389 else if (chassisSubNode == sensors::sensorsNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700390 {
391 jsonValue["@odata.type"] = "#SensorCollection.SensorCollection";
392 jsonValue["Description"] = "Collection of Sensors for this Chassis";
393 jsonValue["Members"] = nlohmann::json::array();
394 jsonValue["Members@odata.count"] = 0;
395 }
396
Janet Adkins0c728b42024-08-29 11:09:10 -0500397 if (chassisSubNode != sensors::sensorsNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700398 {
399 jsonValue["Id"] = chassisSubNode;
400 }
401 jsonValue["Name"] = chassisSubNode;
402}
403
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700404/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100405 * @brief Retrieves requested chassis sensors and redundancy data from DBus .
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200406 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100407 * @param callback Callback for next step in gathered sensor processing
408 */
409template <typename Callback>
Ed Tanous7f1cc262022-08-09 13:33:57 -0700410void getChassis(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
411 std::string_view chassisId, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800412 std::span<const std::string_view> sensorTypes,
413 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700414{
Ed Tanous62598e32023-07-17 17:06:25 -0700415 BMCWEB_LOG_DEBUG("getChassis enter");
George Liu7a1dbc42022-12-07 16:03:22 +0800416 constexpr std::array<std::string_view, 2> interfaces = {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700417 "xyz.openbmc_project.Inventory.Item.Board",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500418 "xyz.openbmc_project.Inventory.Item.Chassis"};
George Liu7a1dbc42022-12-07 16:03:22 +0800419
420 // Get the Chassis Collection
421 dbus::utility::getSubTreePaths(
422 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700423 [callback = std::forward<Callback>(callback), asyncResp,
Ed Tanous7f1cc262022-08-09 13:33:57 -0700424 chassisIdStr{std::string(chassisId)},
Ed Tanous4e0d8782024-09-06 15:16:41 -0700425 chassisSubNode{std::string(chassisSubNode)},
426 sensorTypes](const boost::system::error_code& ec,
427 const dbus::utility::MapperGetSubTreePathsResponse&
428 chassisPaths) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400429 BMCWEB_LOG_DEBUG("getChassis respHandler enter");
430 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700431 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400432 BMCWEB_LOG_ERROR("getChassis respHandler DBUS error: {}", ec);
433 messages::internalError(asyncResp->res);
434 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700435 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400436 const std::string* chassisPath = nullptr;
437 for (const std::string& chassis : chassisPaths)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700438 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400439 sdbusplus::message::object_path path(chassis);
440 std::string chassisName = path.filename();
441 if (chassisName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700442 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400443 BMCWEB_LOG_ERROR("Failed to find '/' in {}", chassis);
444 continue;
445 }
446 if (chassisName == chassisIdStr)
447 {
448 chassisPath = &chassis;
449 break;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700450 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700451 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400452 if (chassisPath == nullptr)
453 {
454 messages::resourceNotFound(asyncResp->res, "Chassis",
455 chassisIdStr);
456 return;
457 }
458 populateChassisNode(asyncResp->res.jsonValue, chassisSubNode);
459
460 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
461 "/redfish/v1/Chassis/{}/{}", chassisIdStr, chassisSubNode);
462
463 // Get the list of all sensors for this Chassis element
464 std::string sensorPath = *chassisPath + "/all_sensors";
465 dbus::utility::getAssociationEndPoints(
Ed Tanous4e0d8782024-09-06 15:16:41 -0700466 sensorPath, [asyncResp, chassisSubNode, sensorTypes,
467 callback = std::forward<Callback>(callback)](
468 const boost::system::error_code& ec2,
469 const dbus::utility::MapperEndPoints&
470 nodeSensorList) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400471 if (ec2)
472 {
473 if (ec2.value() != EBADR)
474 {
475 messages::internalError(asyncResp->res);
476 return;
477 }
478 }
479 const std::shared_ptr<std::set<std::string>>
480 culledSensorList =
481 std::make_shared<std::set<std::string>>();
482 reduceSensorList(asyncResp->res, chassisSubNode,
483 sensorTypes, &nodeSensorList,
484 culledSensorList);
485 BMCWEB_LOG_DEBUG("Finishing with {}",
486 culledSensorList->size());
487 callback(culledSensorList);
488 });
George Liu7a1dbc42022-12-07 16:03:22 +0800489 });
Ed Tanous62598e32023-07-17 17:06:25 -0700490 BMCWEB_LOG_DEBUG("getChassis exit");
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100491}
492
493/**
Ed Tanous1d7c0052022-08-09 12:32:26 -0700494 * @brief Builds a json sensor representation of a sensor.
495 * @param sensorName The name of the sensor to be built
496 * @param sensorType The type (temperature, fan_tach, etc) of the sensor to
497 * build
Ed Tanous8ece0e42024-01-02 13:16:50 -0800498 * @param chassisSubNode The subnode (thermal, sensor, etc) of the sensor
Ed Tanous1d7c0052022-08-09 12:32:26 -0700499 * @param interfacesDict A dictionary of the interfaces and properties of said
500 * interfaces to be built from
501 * @param sensorJson The json object to fill
502 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
503 * be nullptr if no associated inventory item was found.
504 */
505inline void objectInterfacesToJson(
506 const std::string& sensorName, const std::string& sensorType,
Janet Adkins0c728b42024-08-29 11:09:10 -0500507 const sensor_utils::ChassisSubNode chassisSubNode,
Michael Shen80f79a42023-08-24 13:41:53 +0000508 const dbus::utility::DBusInterfacesMap& interfacesDict,
Ed Tanous1d7c0052022-08-09 12:32:26 -0700509 nlohmann::json& sensorJson, InventoryItem* inventoryItem)
510{
Ed Tanous1d7c0052022-08-09 12:32:26 -0700511 for (const auto& [interface, valuesDict] : interfacesDict)
512 {
Janet Adkinsc9563602024-08-28 11:37:46 -0500513 sensor_utils::objectPropertiesToJson(
514 sensorName, sensorType, chassisSubNode, valuesDict, sensorJson,
515 inventoryItem);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700516 }
Ed Tanous62598e32023-07-17 17:06:25 -0700517 BMCWEB_LOG_DEBUG("Added sensor {}", sensorName);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700518}
519
Ed Tanousb5a76932020-09-29 16:16:58 -0700520inline void populateFanRedundancy(
521 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
James Feist8bd25cc2019-03-15 15:14:00 -0700522{
George Liue99073f2022-12-09 11:06:16 +0800523 constexpr std::array<std::string_view, 1> interfaces = {
524 "xyz.openbmc_project.Control.FanRedundancy"};
525 dbus::utility::getSubTree(
526 "/xyz/openbmc_project/control", 2, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800527 [sensorsAsyncResp](
George Liue99073f2022-12-09 11:06:16 +0800528 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800529 const dbus::utility::MapperGetSubTreeResponse& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400530 if (ec)
James Feist8bd25cc2019-03-15 15:14:00 -0700531 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400532 return; // don't have to have this interface
James Feist8bd25cc2019-03-15 15:14:00 -0700533 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400534 for (const std::pair<std::string, dbus::utility::MapperServiceMap>&
535 pathPair : resp)
536 {
537 const std::string& path = pathPair.first;
538 const dbus::utility::MapperServiceMap& objDict =
539 pathPair.second;
540 if (objDict.empty())
James Feist8bd25cc2019-03-15 15:14:00 -0700541 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400542 continue; // this should be impossible
James Feist8bd25cc2019-03-15 15:14:00 -0700543 }
544
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400545 const std::string& owner = objDict.begin()->first;
546 dbus::utility::getAssociationEndPoints(
547 path + "/chassis",
548 [path, owner, sensorsAsyncResp](
549 const boost::system::error_code& ec2,
550 const dbus::utility::MapperEndPoints& endpoints) {
551 if (ec2)
James Feist8bd25cc2019-03-15 15:14:00 -0700552 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400553 return; // if they don't have an association we
554 // can't tell what chassis is
James Feist8bd25cc2019-03-15 15:14:00 -0700555 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400556 auto found = std::ranges::find_if(
557 endpoints,
558 [sensorsAsyncResp](const std::string& entry) {
559 return entry.find(
560 sensorsAsyncResp->chassisId) !=
561 std::string::npos;
562 });
563
564 if (found == endpoints.end())
James Feist8bd25cc2019-03-15 15:14:00 -0700565 {
566 return;
567 }
Ed Tanousdeae6a72024-11-11 21:58:57 -0800568 dbus::utility::getAllProperties(
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400569 *crow::connections::systemBus, owner, path,
570 "xyz.openbmc_project.Control.FanRedundancy",
571 [path, sensorsAsyncResp](
572 const boost::system::error_code& ec3,
573 const dbus::utility::DBusPropertiesMap& ret) {
574 if (ec3)
575 {
576 return; // don't have to have this
577 // interface
578 }
James Feist8bd25cc2019-03-15 15:14:00 -0700579
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400580 const uint8_t* allowedFailures = nullptr;
581 const std::vector<std::string>* collection =
582 nullptr;
583 const std::string* status = nullptr;
James Feist8bd25cc2019-03-15 15:14:00 -0700584
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400585 const bool success =
586 sdbusplus::unpackPropertiesNoThrow(
587 dbus_utils::UnpackErrorPrinter(), ret,
588 "AllowedFailures", allowedFailures,
589 "Collection", collection, "Status",
590 status);
James Feist8bd25cc2019-03-15 15:14:00 -0700591
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400592 if (!success)
593 {
594 messages::internalError(
595 sensorsAsyncResp->asyncResp->res);
596 return;
597 }
598
599 if (allowedFailures == nullptr ||
600 collection == nullptr || status == nullptr)
601 {
602 BMCWEB_LOG_ERROR(
603 "Invalid redundancy interface");
604 messages::internalError(
605 sensorsAsyncResp->asyncResp->res);
606 return;
607 }
608
609 sdbusplus::message::object_path objectPath(
610 path);
611 std::string name = objectPath.filename();
612 if (name.empty())
613 {
614 // this should be impossible
615 messages::internalError(
616 sensorsAsyncResp->asyncResp->res);
617 return;
618 }
619 std::ranges::replace(name, '_', ' ');
620
621 std::string health;
622
623 if (status->ends_with("Full"))
624 {
625 health = "OK";
626 }
627 else if (status->ends_with("Degraded"))
628 {
629 health = "Warning";
630 }
631 else
632 {
633 health = "Critical";
634 }
635 nlohmann::json::array_t redfishCollection;
636 const auto& fanRedfish =
637 sensorsAsyncResp->asyncResp->res
638 .jsonValue["Fans"];
639 for (const std::string& item : *collection)
640 {
641 sdbusplus::message::object_path itemPath(
642 item);
643 std::string itemName = itemPath.filename();
644 if (itemName.empty())
645 {
646 continue;
647 }
648 /*
649 todo(ed): merge patch that fixes the names
650 std::replace(itemName.begin(),
651 itemName.end(), '_', ' ');*/
652 auto schemaItem = std::ranges::find_if(
653 fanRedfish,
654 [itemName](const nlohmann::json& fan) {
655 return fan["Name"] == itemName;
656 });
657 if (schemaItem != fanRedfish.end())
658 {
659 nlohmann::json::object_t collectionId;
660 collectionId["@odata.id"] =
661 (*schemaItem)["@odata.id"];
662 redfishCollection.emplace_back(
663 std::move(collectionId));
664 }
665 else
666 {
667 BMCWEB_LOG_ERROR(
668 "failed to find fan in schema");
669 messages::internalError(
670 sensorsAsyncResp->asyncResp->res);
671 return;
672 }
673 }
674
675 size_t minNumNeeded =
676 collection->empty()
677 ? 0
678 : collection->size() - *allowedFailures;
679 nlohmann::json& jResp =
680 sensorsAsyncResp->asyncResp->res
681 .jsonValue["Redundancy"];
682
683 nlohmann::json::object_t redundancy;
684 boost::urls::url url = boost::urls::format(
685 "/redfish/v1/Chassis/{}/{}",
686 sensorsAsyncResp->chassisId,
687 sensorsAsyncResp->chassisSubNode);
688 url.set_fragment(
689 ("/Redundancy"_json_pointer / jResp.size())
690 .to_string());
691 redundancy["@odata.id"] = std::move(url);
692 redundancy["@odata.type"] =
693 "#Redundancy.v1_3_2.Redundancy";
694 redundancy["MinNumNeeded"] = minNumNeeded;
695 redundancy["Mode"] =
696 redundancy::RedundancyType::NPlusM;
697 redundancy["Name"] = name;
698 redundancy["RedundancySet"] = redfishCollection;
699 redundancy["Status"]["Health"] = health;
700 redundancy["Status"]["State"] =
701 resource::State::Enabled;
702
703 jResp.emplace_back(std::move(redundancy));
704 });
705 });
706 }
707 });
James Feist8bd25cc2019-03-15 15:14:00 -0700708}
709
Patrick Williams504af5a2025-02-03 14:29:03 -0500710inline void sortJSONResponse(
711 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700712{
zhanghch058d1b46d2021-04-01 11:18:24 +0800713 nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700714 std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
Janet Adkins0c728b42024-08-29 11:09:10 -0500715 if (sensorsAsyncResp->chassisSubNode == sensors::powerNodeStr)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700716 {
717 sensorHeaders = {"Voltages", "PowerSupplies"};
718 }
719 for (const std::string& sensorGroup : sensorHeaders)
720 {
721 nlohmann::json::iterator entry = response.find(sensorGroup);
Ed Tanous4e196b92024-09-27 17:45:09 -0700722 if (entry == response.end())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700723 {
Ed Tanous4e196b92024-09-27 17:45:09 -0700724 continue;
725 }
726 nlohmann::json::array_t* arr =
727 entry->get_ptr<nlohmann::json::array_t*>();
728 if (arr == nullptr)
729 {
730 continue;
731 }
732 json_util::sortJsonArrayByKey(*arr, "Name");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700733
Ed Tanous4e196b92024-09-27 17:45:09 -0700734 // add the index counts to the end of each entry
735 size_t count = 0;
736 for (nlohmann::json& sensorJson : *entry)
737 {
738 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
739 if (odata == sensorJson.end())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700740 {
Ed Tanous4e196b92024-09-27 17:45:09 -0700741 continue;
742 }
743 std::string* value = odata->get_ptr<std::string*>();
744 if (value != nullptr)
745 {
746 *value += "/" + std::to_string(count);
747 sensorJson["MemberId"] = std::to_string(count);
748 count++;
749 sensorsAsyncResp->updateUri(sensorJson["Name"], *value);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700750 }
751 }
752 }
753}
754
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100755/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500756 * @brief Finds the inventory item with the specified object path.
757 * @param inventoryItems D-Bus inventory items associated with sensors.
758 * @param invItemObjPath D-Bus object path of inventory item.
759 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500760 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000761inline InventoryItem* findInventoryItem(
Ed Tanousb5a76932020-09-29 16:16:58 -0700762 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500763 const std::string& invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500764{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500765 for (InventoryItem& inventoryItem : *inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500766 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500767 if (inventoryItem.objectPath == invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500768 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500769 return &inventoryItem;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500770 }
771 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500772 return nullptr;
773}
774
775/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500776 * @brief Finds the inventory item associated with the specified sensor.
777 * @param inventoryItems D-Bus inventory items associated with sensors.
778 * @param sensorObjPath D-Bus object path of sensor.
779 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500780 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000781inline InventoryItem* findInventoryItemForSensor(
Ed Tanousb5a76932020-09-29 16:16:58 -0700782 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500783 const std::string& sensorObjPath)
784{
785 for (InventoryItem& inventoryItem : *inventoryItems)
786 {
Ed Tanousdb0d36e2023-06-30 10:37:05 -0700787 if (inventoryItem.sensors.contains(sensorObjPath))
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500788 {
789 return &inventoryItem;
790 }
791 }
792 return nullptr;
793}
794
795/**
Anthony Wilsond5005492019-07-31 16:34:17 -0500796 * @brief Finds the inventory item associated with the specified led path.
797 * @param inventoryItems D-Bus inventory items associated with sensors.
798 * @param ledObjPath D-Bus object path of led.
799 * @return Inventory item within vector, or nullptr if no match found.
800 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400801inline InventoryItem* findInventoryItemForLed(
802 std::vector<InventoryItem>& inventoryItems, const std::string& ledObjPath)
Anthony Wilsond5005492019-07-31 16:34:17 -0500803{
804 for (InventoryItem& inventoryItem : inventoryItems)
805 {
806 if (inventoryItem.ledObjectPath == ledObjPath)
807 {
808 return &inventoryItem;
809 }
810 }
811 return nullptr;
812}
813
814/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500815 * @brief Adds inventory item and associated sensor to specified vector.
816 *
817 * Adds a new InventoryItem to the vector if necessary. Searches for an
818 * existing InventoryItem with the specified object path. If not found, one is
819 * added to the vector.
820 *
821 * Next, the specified sensor is added to the set of sensors associated with the
822 * InventoryItem.
823 *
824 * @param inventoryItems D-Bus inventory items associated with sensors.
825 * @param invItemObjPath D-Bus object path of inventory item.
826 * @param sensorObjPath D-Bus object path of sensor
827 */
Ed Tanousb5a76932020-09-29 16:16:58 -0700828inline void addInventoryItem(
829 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
830 const std::string& invItemObjPath, const std::string& sensorObjPath)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500831{
832 // Look for inventory item in vector
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400833 InventoryItem* inventoryItem =
834 findInventoryItem(inventoryItems, invItemObjPath);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500835
836 // If inventory item doesn't exist in vector, add it
837 if (inventoryItem == nullptr)
838 {
839 inventoryItems->emplace_back(invItemObjPath);
840 inventoryItem = &(inventoryItems->back());
841 }
842
843 // Add sensor to set of sensors associated with inventory item
844 inventoryItem->sensors.emplace(sensorObjPath);
845}
846
847/**
848 * @brief Stores D-Bus data in the specified inventory item.
849 *
850 * Finds D-Bus data in the specified map of interfaces. Stores the data in the
851 * specified InventoryItem.
852 *
853 * This data is later used to provide sensor property values in the JSON
854 * response.
855 *
856 * @param inventoryItem Inventory item where data will be stored.
857 * @param interfacesDict Map containing D-Bus interfaces and their properties
858 * for the specified inventory item.
859 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000860inline void storeInventoryItemData(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500861 InventoryItem& inventoryItem,
Michael Shen80f79a42023-08-24 13:41:53 +0000862 const dbus::utility::DBusInterfacesMap& interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500863{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500864 // Get properties from Inventory.Item interface
Ed Tanous711ac7a2021-12-20 09:34:41 -0800865
Ed Tanous9eb808c2022-01-25 10:19:23 -0800866 for (const auto& [interface, values] : interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500867 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800868 if (interface == "xyz.openbmc_project.Inventory.Item")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500869 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800870 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500871 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800872 if (name == "Present")
873 {
874 const bool* value = std::get_if<bool>(&dbusValue);
875 if (value != nullptr)
876 {
877 inventoryItem.isPresent = *value;
878 }
879 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500880 }
881 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800882 // Check if Inventory.Item.PowerSupply interface is present
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500883
Ed Tanous711ac7a2021-12-20 09:34:41 -0800884 if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500885 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800886 inventoryItem.isPowerSupply = true;
887 }
888
889 // Get properties from Inventory.Decorator.Asset interface
890 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
891 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800892 for (const auto& [name, dbusValue] : values)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500893 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800894 if (name == "Manufacturer")
895 {
896 const std::string* value =
897 std::get_if<std::string>(&dbusValue);
898 if (value != nullptr)
899 {
900 inventoryItem.manufacturer = *value;
901 }
902 }
903 if (name == "Model")
904 {
905 const std::string* value =
906 std::get_if<std::string>(&dbusValue);
907 if (value != nullptr)
908 {
909 inventoryItem.model = *value;
910 }
911 }
912 if (name == "SerialNumber")
913 {
914 const std::string* value =
915 std::get_if<std::string>(&dbusValue);
916 if (value != nullptr)
917 {
918 inventoryItem.serialNumber = *value;
919 }
920 }
921 if (name == "PartNumber")
922 {
923 const std::string* value =
924 std::get_if<std::string>(&dbusValue);
925 if (value != nullptr)
926 {
927 inventoryItem.partNumber = *value;
928 }
929 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500930 }
931 }
932
Ed Tanous711ac7a2021-12-20 09:34:41 -0800933 if (interface ==
934 "xyz.openbmc_project.State.Decorator.OperationalStatus")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500935 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800936 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500937 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800938 if (name == "Functional")
939 {
940 const bool* value = std::get_if<bool>(&dbusValue);
941 if (value != nullptr)
942 {
943 inventoryItem.isFunctional = *value;
944 }
945 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500946 }
947 }
948 }
949}
950
951/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500952 * @brief Gets D-Bus data for inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500953 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500954 * Uses the specified connections (services) to obtain D-Bus data for inventory
955 * items associated with sensors. Stores the resulting data in the
956 * inventoryItems vector.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500957 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500958 * This data is later used to provide sensor property values in the JSON
959 * response.
960 *
961 * Finds the inventory item data asynchronously. Invokes callback when data has
962 * been obtained.
963 *
964 * The callback must have the following signature:
965 * @code
Anthony Wilsond5005492019-07-31 16:34:17 -0500966 * callback(void)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500967 * @endcode
968 *
969 * This function is called recursively, obtaining data asynchronously from one
970 * connection in each call. This ensures the callback is not invoked until the
971 * last asynchronous function has completed.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500972 *
973 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500974 * @param inventoryItems D-Bus inventory items associated with sensors.
975 * @param invConnections Connections that provide data for the inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500976 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500977 * @param callback Callback to invoke when inventory data has been obtained.
978 * @param invConnectionsIndex Current index in invConnections. Only specified
979 * in recursive calls to this function.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500980 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500981template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -0700982void getInventoryItemsData(
Ed Tanousdaadfb22024-12-20 09:25:54 -0800983 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
984 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
985 const std::shared_ptr<std::set<std::string>>& invConnections,
986 Callback&& callback, size_t invConnectionsIndex = 0)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500987{
Ed Tanous62598e32023-07-17 17:06:25 -0700988 BMCWEB_LOG_DEBUG("getInventoryItemsData enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500989
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500990 // If no more connections left, call callback
991 if (invConnectionsIndex >= invConnections->size())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500992 {
Anthony Wilsond5005492019-07-31 16:34:17 -0500993 callback();
Ed Tanous62598e32023-07-17 17:06:25 -0700994 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500995 return;
996 }
997
998 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +0000999 auto it = invConnections->begin();
1000 std::advance(it, invConnectionsIndex);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001001 if (it != invConnections->end())
1002 {
1003 const std::string& invConnection = *it;
1004
George Liu5eb468d2023-06-20 17:03:24 +08001005 // Get all object paths and their interfaces for current connection
1006 sdbusplus::message::object_path path("/xyz/openbmc_project/inventory");
1007 dbus::utility::getManagedObjects(
1008 invConnection, path,
1009 [sensorsAsyncResp, inventoryItems, invConnections,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001010 callback = std::forward<Callback>(callback), invConnectionsIndex](
George Liu5eb468d2023-06-20 17:03:24 +08001011 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001012 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001013 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler enter");
1014 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001015 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001016 BMCWEB_LOG_ERROR(
1017 "getInventoryItemsData respHandler DBus error {}", ec);
1018 messages::internalError(sensorsAsyncResp->asyncResp->res);
1019 return;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001020 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001021
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001022 // Loop through returned object paths
1023 for (const auto& objDictEntry : resp)
1024 {
1025 const std::string& objPath =
1026 static_cast<const std::string&>(objDictEntry.first);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001027
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001028 // If this object path is one of the specified inventory
1029 // items
1030 InventoryItem* inventoryItem =
1031 findInventoryItem(inventoryItems, objPath);
1032 if (inventoryItem != nullptr)
1033 {
1034 // Store inventory data in InventoryItem
1035 storeInventoryItemData(*inventoryItem,
1036 objDictEntry.second);
1037 }
1038 }
1039
1040 // Recurse to get inventory item data from next connection
1041 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1042 invConnections, std::move(callback),
1043 invConnectionsIndex + 1);
1044
1045 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler exit");
1046 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001047 }
1048
Ed Tanous62598e32023-07-17 17:06:25 -07001049 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001050}
1051
1052/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001053 * @brief Gets connections that provide D-Bus data for inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001054 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001055 * Gets the D-Bus connections (services) that provide data for the inventory
1056 * items that are associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001057 *
1058 * Finds the connections asynchronously. Invokes callback when information has
1059 * been obtained.
1060 *
1061 * The callback must have the following signature:
1062 * @code
Nan Zhoufe04d492022-06-22 17:10:41 +00001063 * callback(std::shared_ptr<std::set<std::string>> invConnections)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001064 * @endcode
1065 *
1066 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001067 * @param inventoryItems D-Bus inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001068 * @param callback Callback to invoke when connections have been obtained.
1069 */
1070template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001071void getInventoryItemsConnections(
Ed Tanousb5a76932020-09-29 16:16:58 -07001072 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1073 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001074 Callback&& callback)
1075{
Ed Tanous62598e32023-07-17 17:06:25 -07001076 BMCWEB_LOG_DEBUG("getInventoryItemsConnections enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001077
1078 const std::string path = "/xyz/openbmc_project/inventory";
George Liue99073f2022-12-09 11:06:16 +08001079 constexpr std::array<std::string_view, 4> interfaces = {
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001080 "xyz.openbmc_project.Inventory.Item",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001081 "xyz.openbmc_project.Inventory.Item.PowerSupply",
1082 "xyz.openbmc_project.Inventory.Decorator.Asset",
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001083 "xyz.openbmc_project.State.Decorator.OperationalStatus"};
1084
George Liue99073f2022-12-09 11:06:16 +08001085 // Make call to ObjectMapper to find all inventory items
1086 dbus::utility::getSubTree(
1087 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001088 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001089 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001090 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001091 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001092 // Response handler for parsing output from GetSubTree
1093 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler enter");
1094 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001095 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001096 messages::internalError(sensorsAsyncResp->asyncResp->res);
1097 BMCWEB_LOG_ERROR(
1098 "getInventoryItemsConnections respHandler DBus error {}",
1099 ec);
1100 return;
1101 }
1102
1103 // Make unique list of connections for desired inventory items
1104 std::shared_ptr<std::set<std::string>> invConnections =
1105 std::make_shared<std::set<std::string>>();
1106
1107 // Loop through objects from GetSubTree
1108 for (const std::pair<std::string,
1109 std::vector<std::pair<
1110 std::string, std::vector<std::string>>>>&
1111 object : subtree)
1112 {
1113 // Check if object path is one of the specified inventory items
1114 const std::string& objPath = object.first;
1115 if (findInventoryItem(inventoryItems, objPath) != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001116 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001117 // Store all connections to inventory item
1118 for (const std::pair<std::string, std::vector<std::string>>&
1119 objData : object.second)
1120 {
1121 const std::string& invConnection = objData.first;
1122 invConnections->insert(invConnection);
1123 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001124 }
1125 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001126
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001127 callback(invConnections);
1128 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler exit");
1129 });
Ed Tanous62598e32023-07-17 17:06:25 -07001130 BMCWEB_LOG_DEBUG("getInventoryItemsConnections exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001131}
1132
1133/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001134 * @brief Gets associations from sensors to inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001135 *
1136 * Looks for ObjectMapper associations from the specified sensors to related
Anthony Wilsond5005492019-07-31 16:34:17 -05001137 * inventory items. Then finds the associations from those inventory items to
1138 * their LEDs, if any.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001139 *
1140 * Finds the inventory items asynchronously. Invokes callback when information
1141 * has been obtained.
1142 *
1143 * The callback must have the following signature:
1144 * @code
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001145 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001146 * @endcode
1147 *
1148 * @param sensorsAsyncResp Pointer to object holding response data.
1149 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001150 * implements ObjectManager.
1151 * @param callback Callback to invoke when inventory items have been obtained.
1152 */
1153template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001154void getInventoryItemAssociations(
Ed Tanousb5a76932020-09-29 16:16:58 -07001155 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001156 const std::shared_ptr<std::set<std::string>>& sensorNames,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001157 Callback&& callback)
1158{
Ed Tanous62598e32023-07-17 17:06:25 -07001159 BMCWEB_LOG_DEBUG("getInventoryItemAssociations enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001160
George Liu5eb468d2023-06-20 17:03:24 +08001161 // Call GetManagedObjects on the ObjectMapper to get all associations
1162 sdbusplus::message::object_path path("/");
1163 dbus::utility::getManagedObjects(
1164 "xyz.openbmc_project.ObjectMapper", path,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001165 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001166 sensorNames](const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001167 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001168 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler enter");
1169 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001170 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001171 BMCWEB_LOG_ERROR(
1172 "getInventoryItemAssociations respHandler DBus error {}",
1173 ec);
1174 messages::internalError(sensorsAsyncResp->asyncResp->res);
1175 return;
1176 }
1177
1178 // Create vector to hold list of inventory items
1179 std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1180 std::make_shared<std::vector<InventoryItem>>();
1181
1182 // Loop through returned object paths
1183 std::string sensorAssocPath;
1184 sensorAssocPath.reserve(128); // avoid memory allocations
1185 for (const auto& objDictEntry : resp)
1186 {
1187 const std::string& objPath =
1188 static_cast<const std::string&>(objDictEntry.first);
1189
1190 // If path is inventory association for one of the specified
1191 // sensors
1192 for (const std::string& sensorName : *sensorNames)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001193 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001194 sensorAssocPath = sensorName;
1195 sensorAssocPath += "/inventory";
1196 if (objPath == sensorAssocPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001197 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001198 // Get Association interface for object path
1199 for (const auto& [interface, values] :
1200 objDictEntry.second)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001201 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001202 if (interface == "xyz.openbmc_project.Association")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001203 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001204 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001205 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001206 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001207 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001208 const std::vector<std::string>*
1209 endpoints = std::get_if<
1210 std::vector<std::string>>(
1211 &value);
1212 if ((endpoints != nullptr) &&
1213 !endpoints->empty())
1214 {
1215 // Add inventory item to vector
1216 const std::string& invItemPath =
1217 endpoints->front();
1218 addInventoryItem(inventoryItems,
1219 invItemPath,
1220 sensorName);
1221 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001222 }
1223 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001224 }
1225 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001226 break;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001227 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001228 }
1229 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001230
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001231 // Now loop through the returned object paths again, this time to
1232 // find the leds associated with the inventory items we just found
1233 std::string inventoryAssocPath;
1234 inventoryAssocPath.reserve(128); // avoid memory allocations
1235 for (const auto& objDictEntry : resp)
Anthony Wilsond5005492019-07-31 16:34:17 -05001236 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001237 const std::string& objPath =
1238 static_cast<const std::string&>(objDictEntry.first);
1239
1240 for (InventoryItem& inventoryItem : *inventoryItems)
Anthony Wilsond5005492019-07-31 16:34:17 -05001241 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001242 inventoryAssocPath = inventoryItem.objectPath;
1243 inventoryAssocPath += "/leds";
1244 if (objPath == inventoryAssocPath)
Anthony Wilsond5005492019-07-31 16:34:17 -05001245 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001246 for (const auto& [interface, values] :
1247 objDictEntry.second)
Anthony Wilsond5005492019-07-31 16:34:17 -05001248 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001249 if (interface == "xyz.openbmc_project.Association")
Anthony Wilsond5005492019-07-31 16:34:17 -05001250 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001251 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001252 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001253 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001254 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001255 const std::vector<std::string>*
1256 endpoints = std::get_if<
1257 std::vector<std::string>>(
1258 &value);
1259 if ((endpoints != nullptr) &&
1260 !endpoints->empty())
1261 {
1262 // Add inventory item to vector
1263 // Store LED path in inventory item
1264 const std::string& ledPath =
1265 endpoints->front();
1266 inventoryItem.ledObjectPath =
1267 ledPath;
1268 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001269 }
1270 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001271 }
1272 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001273
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001274 break;
1275 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001276 }
1277 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001278 callback(inventoryItems);
1279 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler exit");
1280 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001281
Ed Tanous62598e32023-07-17 17:06:25 -07001282 BMCWEB_LOG_DEBUG("getInventoryItemAssociations exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001283}
1284
1285/**
Anthony Wilsond5005492019-07-31 16:34:17 -05001286 * @brief Gets D-Bus data for inventory item leds associated with sensors.
1287 *
1288 * Uses the specified connections (services) to obtain D-Bus data for inventory
1289 * item leds associated with sensors. Stores the resulting data in the
1290 * inventoryItems vector.
1291 *
1292 * This data is later used to provide sensor property values in the JSON
1293 * response.
1294 *
1295 * Finds the inventory item led data asynchronously. Invokes callback when data
1296 * has been obtained.
1297 *
1298 * The callback must have the following signature:
1299 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001300 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001301 * @endcode
1302 *
1303 * This function is called recursively, obtaining data asynchronously from one
1304 * connection in each call. This ensures the callback is not invoked until the
1305 * last asynchronous function has completed.
1306 *
1307 * @param sensorsAsyncResp Pointer to object holding response data.
1308 * @param inventoryItems D-Bus inventory items associated with sensors.
1309 * @param ledConnections Connections that provide data for the inventory leds.
1310 * @param callback Callback to invoke when inventory data has been obtained.
1311 * @param ledConnectionsIndex Current index in ledConnections. Only specified
1312 * in recursive calls to this function.
1313 */
1314template <typename Callback>
1315void getInventoryLedData(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001316 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1317 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1318 const std::shared_ptr<std::map<std::string, std::string>>& ledConnections,
Anthony Wilsond5005492019-07-31 16:34:17 -05001319 Callback&& callback, size_t ledConnectionsIndex = 0)
1320{
Ed Tanous62598e32023-07-17 17:06:25 -07001321 BMCWEB_LOG_DEBUG("getInventoryLedData enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001322
1323 // If no more connections left, call callback
1324 if (ledConnectionsIndex >= ledConnections->size())
1325 {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001326 callback();
Ed Tanous62598e32023-07-17 17:06:25 -07001327 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001328 return;
1329 }
1330
1331 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +00001332 auto it = ledConnections->begin();
1333 std::advance(it, ledConnectionsIndex);
Anthony Wilsond5005492019-07-31 16:34:17 -05001334 if (it != ledConnections->end())
1335 {
1336 const std::string& ledPath = (*it).first;
1337 const std::string& ledConnection = (*it).second;
1338 // Response handler for Get State property
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001339 auto respHandler =
1340 [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001341 callback = std::forward<Callback>(callback),
1342 ledConnectionsIndex](const boost::system::error_code& ec,
1343 const std::string& state) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001344 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler enter");
1345 if (ec)
1346 {
1347 BMCWEB_LOG_ERROR(
1348 "getInventoryLedData respHandler DBus error {}", ec);
1349 messages::internalError(sensorsAsyncResp->asyncResp->res);
1350 return;
1351 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001352
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001353 BMCWEB_LOG_DEBUG("Led state: {}", state);
1354 // Find inventory item with this LED object path
1355 InventoryItem* inventoryItem =
1356 findInventoryItemForLed(*inventoryItems, ledPath);
1357 if (inventoryItem != nullptr)
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001358 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001359 // Store LED state in InventoryItem
1360 if (state.ends_with("On"))
1361 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001362 inventoryItem->ledState = sensor_utils::LedState::ON;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001363 }
1364 else if (state.ends_with("Blink"))
1365 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001366 inventoryItem->ledState = sensor_utils::LedState::BLINK;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001367 }
1368 else if (state.ends_with("Off"))
1369 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001370 inventoryItem->ledState = sensor_utils::LedState::OFF;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001371 }
1372 else
1373 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001374 inventoryItem->ledState =
1375 sensor_utils::LedState::UNKNOWN;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001376 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001377 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001378
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001379 // Recurse to get LED data from next connection
1380 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1381 ledConnections, std::move(callback),
1382 ledConnectionsIndex + 1);
Anthony Wilsond5005492019-07-31 16:34:17 -05001383
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001384 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler exit");
1385 };
Anthony Wilsond5005492019-07-31 16:34:17 -05001386
1387 // Get the State property for the current LED
Ed Tanousdeae6a72024-11-11 21:58:57 -08001388 dbus::utility::getProperty<std::string>(
1389 ledConnection, ledPath, "xyz.openbmc_project.Led.Physical", "State",
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001390 std::move(respHandler));
Anthony Wilsond5005492019-07-31 16:34:17 -05001391 }
1392
Ed Tanous62598e32023-07-17 17:06:25 -07001393 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001394}
1395
1396/**
1397 * @brief Gets LED data for LEDs associated with given inventory items.
1398 *
1399 * Gets the D-Bus connections (services) that provide LED data for the LEDs
1400 * associated with the specified inventory items. Then gets the LED data from
1401 * each connection and stores it in the inventory item.
1402 *
1403 * This data is later used to provide sensor property values in the JSON
1404 * response.
1405 *
1406 * Finds the LED data asynchronously. Invokes callback when information has
1407 * been obtained.
1408 *
1409 * The callback must have the following signature:
1410 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001411 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001412 * @endcode
1413 *
1414 * @param sensorsAsyncResp Pointer to object holding response data.
1415 * @param inventoryItems D-Bus inventory items associated with sensors.
1416 * @param callback Callback to invoke when inventory items have been obtained.
1417 */
1418template <typename Callback>
1419void getInventoryLeds(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001420 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1421 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Anthony Wilsond5005492019-07-31 16:34:17 -05001422 Callback&& callback)
1423{
Ed Tanous62598e32023-07-17 17:06:25 -07001424 BMCWEB_LOG_DEBUG("getInventoryLeds enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001425
1426 const std::string path = "/xyz/openbmc_project";
George Liue99073f2022-12-09 11:06:16 +08001427 constexpr std::array<std::string_view, 1> interfaces = {
Anthony Wilsond5005492019-07-31 16:34:17 -05001428 "xyz.openbmc_project.Led.Physical"};
1429
George Liue99073f2022-12-09 11:06:16 +08001430 // Make call to ObjectMapper to find all inventory items
1431 dbus::utility::getSubTree(
1432 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001433 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001434 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001435 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001436 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001437 // Response handler for parsing output from GetSubTree
1438 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter");
1439 if (ec)
Anthony Wilsond5005492019-07-31 16:34:17 -05001440 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001441 messages::internalError(sensorsAsyncResp->asyncResp->res);
1442 BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}",
1443 ec);
1444 return;
Anthony Wilsond5005492019-07-31 16:34:17 -05001445 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001446
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001447 // Build map of LED object paths to connections
1448 std::shared_ptr<std::map<std::string, std::string>> ledConnections =
1449 std::make_shared<std::map<std::string, std::string>>();
1450
1451 // Loop through objects from GetSubTree
1452 for (const std::pair<std::string,
1453 std::vector<std::pair<
1454 std::string, std::vector<std::string>>>>&
1455 object : subtree)
1456 {
1457 // Check if object path is LED for one of the specified
1458 // inventory items
1459 const std::string& ledPath = object.first;
1460 if (findInventoryItemForLed(*inventoryItems, ledPath) !=
1461 nullptr)
1462 {
1463 // Add mapping from ledPath to connection
1464 const std::string& connection =
1465 object.second.begin()->first;
1466 (*ledConnections)[ledPath] = connection;
1467 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath,
1468 connection);
1469 }
1470 }
1471
1472 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1473 ledConnections, std::move(callback));
1474 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit");
1475 });
Ed Tanous62598e32023-07-17 17:06:25 -07001476 BMCWEB_LOG_DEBUG("getInventoryLeds exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001477}
1478
1479/**
Gunnar Mills42cbe532019-08-15 15:26:54 -05001480 * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
1481 *
1482 * Uses the specified connections (services) (currently assumes just one) to
1483 * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
1484 * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
1485 *
1486 * This data is later used to provide sensor property values in the JSON
1487 * response.
1488 *
1489 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1490 * when data has been obtained.
1491 *
1492 * The callback must have the following signature:
1493 * @code
1494 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1495 * @endcode
1496 *
1497 * @param sensorsAsyncResp Pointer to object holding response data.
1498 * @param inventoryItems D-Bus inventory items associated with sensors.
1499 * @param psAttributesConnections Connections that provide data for the Power
1500 * Supply Attributes
1501 * @param callback Callback to invoke when data has been obtained.
1502 */
1503template <typename Callback>
1504void getPowerSupplyAttributesData(
Ed Tanousb5a76932020-09-29 16:16:58 -07001505 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanousdaadfb22024-12-20 09:25:54 -08001506 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001507 const std::map<std::string, std::string>& psAttributesConnections,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001508 Callback&& callback)
1509{
Ed Tanous62598e32023-07-17 17:06:25 -07001510 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001511
1512 if (psAttributesConnections.empty())
1513 {
Ed Tanous62598e32023-07-17 17:06:25 -07001514 BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001515 callback(inventoryItems);
1516 return;
1517 }
1518
1519 // Assuming just one connection (service) for now
Nan Zhoufe04d492022-06-22 17:10:41 +00001520 auto it = psAttributesConnections.begin();
Gunnar Mills42cbe532019-08-15 15:26:54 -05001521
1522 const std::string& psAttributesPath = (*it).first;
1523 const std::string& psAttributesConnection = (*it).second;
1524
1525 // Response handler for Get DeratingFactor property
Patrick Williams5a39f772023-10-20 11:20:21 -05001526 auto respHandler = [sensorsAsyncResp, inventoryItems,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001527 callback = std::forward<Callback>(callback)](
Patrick Williams5a39f772023-10-20 11:20:21 -05001528 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001529 uint32_t value) mutable {
Ed Tanous62598e32023-07-17 17:06:25 -07001530 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001531 if (ec)
1532 {
Ed Tanous62598e32023-07-17 17:06:25 -07001533 BMCWEB_LOG_ERROR(
1534 "getPowerSupplyAttributesData respHandler DBus error {}", ec);
zhanghch058d1b46d2021-04-01 11:18:24 +08001535 messages::internalError(sensorsAsyncResp->asyncResp->res);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001536 return;
1537 }
1538
Ed Tanous62598e32023-07-17 17:06:25 -07001539 BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001540 // Store value in Power Supply Inventory Items
1541 for (InventoryItem& inventoryItem : *inventoryItems)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001542 {
Ed Tanous55f79e62022-01-25 11:26:16 -08001543 if (inventoryItem.isPowerSupply)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001544 {
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001545 inventoryItem.powerSupplyEfficiencyPercent =
1546 static_cast<int>(value);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001547 }
1548 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001549
Ed Tanous62598e32023-07-17 17:06:25 -07001550 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001551 callback(inventoryItems);
1552 };
1553
1554 // Get the DeratingFactor property for the PowerSupplyAttributes
1555 // Currently only property on the interface/only one we care about
Ed Tanousdeae6a72024-11-11 21:58:57 -08001556 dbus::utility::getProperty<uint32_t>(
1557 psAttributesConnection, psAttributesPath,
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001558 "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
1559 std::move(respHandler));
Gunnar Mills42cbe532019-08-15 15:26:54 -05001560
Ed Tanous62598e32023-07-17 17:06:25 -07001561 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001562}
1563
1564/**
1565 * @brief Gets the Power Supply Attributes such as EfficiencyPercent
1566 *
1567 * Gets the D-Bus connection (service) that provides Power Supply Attributes
1568 * data. Then gets the Power Supply Attributes data from the connection
1569 * (currently just assumes 1 connection) and stores the data in the inventory
1570 * item.
1571 *
1572 * This data is later used to provide sensor property values in the JSON
1573 * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
1574 *
1575 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1576 * when information has been obtained.
1577 *
1578 * The callback must have the following signature:
1579 * @code
1580 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1581 * @endcode
1582 *
1583 * @param sensorsAsyncResp Pointer to object holding response data.
1584 * @param inventoryItems D-Bus inventory items associated with sensors.
1585 * @param callback Callback to invoke when data has been obtained.
1586 */
1587template <typename Callback>
1588void getPowerSupplyAttributes(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001589 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1590 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001591 Callback&& callback)
1592{
Ed Tanous62598e32023-07-17 17:06:25 -07001593 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001594
1595 // Only need the power supply attributes when the Power Schema
Janet Adkins0c728b42024-08-29 11:09:10 -05001596 if (sensorsAsyncResp->chassisSubNode != sensors::powerNodeStr)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001597 {
Ed Tanous62598e32023-07-17 17:06:25 -07001598 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001599 callback(inventoryItems);
1600 return;
1601 }
1602
George Liue99073f2022-12-09 11:06:16 +08001603 constexpr std::array<std::string_view, 1> interfaces = {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001604 "xyz.openbmc_project.Control.PowerSupplyAttributes"};
1605
George Liue99073f2022-12-09 11:06:16 +08001606 // Make call to ObjectMapper to find the PowerSupplyAttributes service
1607 dbus::utility::getSubTree(
1608 "/xyz/openbmc_project", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001609 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001610 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001611 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001612 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001613 // Response handler for parsing output from GetSubTree
1614 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter");
1615 if (ec)
1616 {
1617 messages::internalError(sensorsAsyncResp->asyncResp->res);
1618 BMCWEB_LOG_ERROR(
1619 "getPowerSupplyAttributes respHandler DBus error {}", ec);
1620 return;
1621 }
1622 if (subtree.empty())
1623 {
1624 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
1625 callback(inventoryItems);
1626 return;
1627 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001628
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001629 // Currently we only support 1 power supply attribute, use this for
1630 // all the power supplies. Build map of object path to connection.
1631 // Assume just 1 connection and 1 path for now.
1632 std::map<std::string, std::string> psAttributesConnections;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001633
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001634 if (subtree[0].first.empty() || subtree[0].second.empty())
1635 {
1636 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1637 callback(inventoryItems);
1638 return;
1639 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001640
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001641 const std::string& psAttributesPath = subtree[0].first;
1642 const std::string& connection = subtree[0].second.begin()->first;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001643
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001644 if (connection.empty())
1645 {
1646 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1647 callback(inventoryItems);
1648 return;
1649 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001650
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001651 psAttributesConnections[psAttributesPath] = connection;
1652 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath,
1653 connection);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001654
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001655 getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
1656 psAttributesConnections,
1657 std::move(callback));
1658 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit");
1659 });
Ed Tanous62598e32023-07-17 17:06:25 -07001660 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001661}
1662
1663/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001664 * @brief Gets inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001665 *
1666 * Finds the inventory items that are associated with the specified sensors.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001667 * Then gets D-Bus data for the inventory items, such as presence and VPD.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001668 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001669 * This data is later used to provide sensor property values in the JSON
1670 * response.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001671 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001672 * Finds the inventory items asynchronously. Invokes callback when the
1673 * inventory items have been obtained.
1674 *
1675 * The callback must have the following signature:
1676 * @code
1677 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1678 * @endcode
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001679 *
1680 * @param sensorsAsyncResp Pointer to object holding response data.
1681 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001682 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001683 * @param callback Callback to invoke when inventory items have been obtained.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001684 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001685template <typename Callback>
Patrick Williams504af5a2025-02-03 14:29:03 -05001686inline void getInventoryItems(
1687 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1688 const std::shared_ptr<std::set<std::string>>& sensorNames,
1689 Callback&& callback)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001690{
Ed Tanous62598e32023-07-17 17:06:25 -07001691 BMCWEB_LOG_DEBUG("getInventoryItems enter");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001692 auto getInventoryItemAssociationsCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -07001693 [sensorsAsyncResp, callback = std::forward<Callback>(callback)](
Ed Tanousdaadfb22024-12-20 09:25:54 -08001694 const std::shared_ptr<std::vector<InventoryItem>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07001695 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001696 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter");
1697 auto getInventoryItemsConnectionsCb =
1698 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001699 callback = std::forward<Callback>(callback)](
Ed Tanousdaadfb22024-12-20 09:25:54 -08001700 const std::shared_ptr<std::set<std::string>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07001701 invConnections) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001702 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter");
1703 auto getInventoryItemsDataCb =
1704 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001705 callback =
1706 std::forward<Callback>(callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001707 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001708
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001709 auto getInventoryLedsCb =
1710 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001711 callback = std::forward<Callback>(
1712 callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001713 BMCWEB_LOG_DEBUG(
1714 "getInventoryLedsCb enter");
1715 // Find Power Supply Attributes and get the
1716 // data
1717 getPowerSupplyAttributes(
1718 sensorsAsyncResp, inventoryItems,
1719 std::move(callback));
1720 BMCWEB_LOG_DEBUG("getInventoryLedsCb exit");
1721 };
1722
1723 // Find led connections and get the data
1724 getInventoryLeds(sensorsAsyncResp, inventoryItems,
1725 std::move(getInventoryLedsCb));
1726 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit");
1727 };
1728
1729 // Get inventory item data from connections
1730 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1731 invConnections,
1732 std::move(getInventoryItemsDataCb));
1733 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001734 };
1735
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001736 // Get connections that provide inventory item data
1737 getInventoryItemsConnections(
1738 sensorsAsyncResp, inventoryItems,
1739 std::move(getInventoryItemsConnectionsCb));
1740 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001741 };
1742
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001743 // Get associations from sensors to inventory items
Ed Tanousd0090732022-10-04 17:22:56 -07001744 getInventoryItemAssociations(sensorsAsyncResp, sensorNames,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001745 std::move(getInventoryItemAssociationsCb));
Ed Tanous62598e32023-07-17 17:06:25 -07001746 BMCWEB_LOG_DEBUG("getInventoryItems exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001747}
1748
1749/**
1750 * @brief Returns JSON PowerSupply object for the specified inventory item.
1751 *
1752 * Searches for a JSON PowerSupply object that matches the specified inventory
1753 * item. If one is not found, a new PowerSupply object is added to the JSON
1754 * array.
1755 *
1756 * Multiple sensors are often associated with one power supply inventory item.
1757 * As a result, multiple sensor values are stored in one JSON PowerSupply
1758 * object.
1759 *
1760 * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1761 * @param inventoryItem Inventory item for the power supply.
1762 * @param chassisId Chassis that contains the power supply.
1763 * @return JSON PowerSupply object for the specified inventory item.
1764 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001765inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001766 const InventoryItem& inventoryItem,
1767 const std::string& chassisId)
1768{
Ed Tanous18f8f602023-07-18 10:07:23 -07001769 std::string nameS;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001770 nameS.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001771 std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' ');
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001772 // Check if matching PowerSupply object already exists in JSON array
1773 for (nlohmann::json& powerSupply : powerSupplyArray)
1774 {
Ed Tanous18f8f602023-07-18 10:07:23 -07001775 nlohmann::json::iterator nameIt = powerSupply.find("Name");
1776 if (nameIt == powerSupply.end())
1777 {
1778 continue;
1779 }
1780 const std::string* name = nameIt->get_ptr<std::string*>();
1781 if (name == nullptr)
1782 {
1783 continue;
1784 }
1785 if (nameS == *name)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001786 {
1787 return powerSupply;
1788 }
1789 }
1790
1791 // Add new PowerSupply object to JSON array
1792 powerSupplyArray.push_back({});
1793 nlohmann::json& powerSupply = powerSupplyArray.back();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001794 boost::urls::url url =
1795 boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
Willy Tueddfc432022-09-26 16:46:38 +00001796 url.set_fragment(("/PowerSupplies"_json_pointer).to_string());
1797 powerSupply["@odata.id"] = std::move(url);
Ed Tanous18f8f602023-07-18 10:07:23 -07001798 std::string escaped;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001799 escaped.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001800 std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' ');
1801 powerSupply["Name"] = std::move(escaped);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001802 powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1803 powerSupply["Model"] = inventoryItem.model;
1804 powerSupply["PartNumber"] = inventoryItem.partNumber;
1805 powerSupply["SerialNumber"] = inventoryItem.serialNumber;
Janet Adkinsc9563602024-08-28 11:37:46 -05001806 sensor_utils::setLedState(powerSupply, &inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001807
Gunnar Mills42cbe532019-08-15 15:26:54 -05001808 if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
1809 {
1810 powerSupply["EfficiencyPercent"] =
1811 inventoryItem.powerSupplyEfficiencyPercent;
1812 }
1813
Janet Adkinsc9563602024-08-28 11:37:46 -05001814 powerSupply["Status"]["State"] =
1815 sensor_utils::getState(&inventoryItem, true);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001816 const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1817 powerSupply["Status"]["Health"] = health;
1818
1819 return powerSupply;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001820}
1821
1822/**
Shawn McCarneyde629b62019-03-08 10:42:51 -06001823 * @brief Gets the values of the specified sensors.
1824 *
1825 * Stores the results as JSON in the SensorsAsyncResp.
1826 *
1827 * Gets the sensor values asynchronously. Stores the results later when the
1828 * information has been obtained.
1829 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001830 * The sensorNames set contains all requested sensors for the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001831 *
1832 * To minimize the number of DBus calls, the DBus method
1833 * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1834 * values of all sensors provided by a connection (service).
1835 *
1836 * The connections set contains all the connections that provide sensor values.
1837 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001838 * The InventoryItem vector contains D-Bus inventory items associated with the
1839 * sensors. Inventory item data is needed for some Redfish sensor properties.
1840 *
Shawn McCarneyde629b62019-03-08 10:42:51 -06001841 * @param SensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001842 * @param sensorNames All requested sensors within the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001843 * @param connections Connections that provide sensor values.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001844 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001845 * @param inventoryItems Inventory items associated with the sensors.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001846 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001847inline void getSensorData(
Ed Tanous81ce6092020-12-17 16:54:55 +00001848 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001849 const std::shared_ptr<std::set<std::string>>& sensorNames,
1850 const std::set<std::string>& connections,
Ed Tanousb5a76932020-09-29 16:16:58 -07001851 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001852{
Ed Tanous62598e32023-07-17 17:06:25 -07001853 BMCWEB_LOG_DEBUG("getSensorData enter");
Shawn McCarneyde629b62019-03-08 10:42:51 -06001854 // Get managed objects from all services exposing sensors
1855 for (const std::string& connection : connections)
1856 {
George Liu5eb468d2023-06-20 17:03:24 +08001857 sdbusplus::message::object_path sensorPath(
1858 "/xyz/openbmc_project/sensors");
1859 dbus::utility::getManagedObjects(
1860 connection, sensorPath,
Ed Tanous002d39b2022-05-31 08:59:27 -07001861 [sensorsAsyncResp, sensorNames,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001862 inventoryItems](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -07001863 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001864 BMCWEB_LOG_DEBUG("getManagedObjectsCb enter");
1865 if (ec)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001866 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001867 BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec);
1868 messages::internalError(sensorsAsyncResp->asyncResp->res);
1869 return;
1870 }
Janet Adkins0c728b42024-08-29 11:09:10 -05001871 auto chassisSubNode = sensor_utils::chassisSubNodeFromString(
1872 sensorsAsyncResp->chassisSubNode);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001873 // Go through all objects and update response with sensor data
1874 for (const auto& objDictEntry : resp)
1875 {
1876 const std::string& objPath =
1877 static_cast<const std::string&>(objDictEntry.first);
1878 BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}",
Ed Tanous62598e32023-07-17 17:06:25 -07001879 objPath);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001880
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001881 std::vector<std::string> split;
1882 // Reserve space for
1883 // /xyz/openbmc_project/sensors/<name>/<subname>
1884 split.reserve(6);
1885 // NOLINTNEXTLINE
1886 bmcweb::split(split, objPath, '/');
1887 if (split.size() < 6)
Nan Zhou928fefb2022-03-28 08:45:00 -07001888 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001889 BMCWEB_LOG_ERROR("Got path that isn't long enough {}",
1890 objPath);
1891 continue;
Nan Zhou928fefb2022-03-28 08:45:00 -07001892 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001893 // These indexes aren't intuitive, as split puts an empty
1894 // string at the beginning
1895 const std::string& sensorType = split[4];
1896 const std::string& sensorName = split[5];
1897 BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName,
1898 sensorType);
1899 if (sensorNames->find(objPath) == sensorNames->end())
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001900 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001901 BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName);
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001902 continue;
1903 }
1904
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001905 // Find inventory item (if any) associated with sensor
1906 InventoryItem* inventoryItem =
1907 findInventoryItemForSensor(inventoryItems, objPath);
1908
1909 const std::string& sensorSchema =
1910 sensorsAsyncResp->chassisSubNode;
1911
1912 nlohmann::json* sensorJson = nullptr;
1913
Janet Adkins0c728b42024-08-29 11:09:10 -05001914 if (sensorSchema == sensors::sensorsNodeStr &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001915 !sensorsAsyncResp->efficientExpand)
Nan Zhou928fefb2022-03-28 08:45:00 -07001916 {
Janet Adkins1516c212024-08-14 13:22:41 -05001917 std::string sensorId =
1918 redfish::sensor_utils::getSensorId(sensorName,
1919 sensorType);
Ed Tanous677bb752022-09-15 10:52:19 -07001920
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001921 sensorsAsyncResp->asyncResp->res
1922 .jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001923 "/redfish/v1/Chassis/{}/{}/{}",
Ed Tanous677bb752022-09-15 10:52:19 -07001924 sensorsAsyncResp->chassisId,
1925 sensorsAsyncResp->chassisSubNode, sensorId);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001926 sensorJson =
1927 &(sensorsAsyncResp->asyncResp->res.jsonValue);
Nan Zhou928fefb2022-03-28 08:45:00 -07001928 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001929 else
1930 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001931 std::string fieldName;
1932 if (sensorsAsyncResp->efficientExpand)
1933 {
1934 fieldName = "Members";
1935 }
1936 else if (sensorType == "temperature")
1937 {
1938 fieldName = "Temperatures";
1939 }
1940 else if (sensorType == "fan" ||
1941 sensorType == "fan_tach" ||
1942 sensorType == "fan_pwm")
1943 {
1944 fieldName = "Fans";
1945 }
1946 else if (sensorType == "voltage")
1947 {
1948 fieldName = "Voltages";
1949 }
1950 else if (sensorType == "power")
1951 {
1952 if (sensorName == "total_power")
1953 {
1954 fieldName = "PowerControl";
1955 }
1956 else if ((inventoryItem != nullptr) &&
1957 (inventoryItem->isPowerSupply))
1958 {
1959 fieldName = "PowerSupplies";
1960 }
1961 else
1962 {
1963 // Other power sensors are in SensorCollection
1964 continue;
1965 }
1966 }
1967 else
1968 {
1969 BMCWEB_LOG_ERROR(
1970 "Unsure how to handle sensorType {}",
1971 sensorType);
1972 continue;
1973 }
1974
1975 nlohmann::json& tempArray =
1976 sensorsAsyncResp->asyncResp->res
1977 .jsonValue[fieldName];
1978 if (fieldName == "PowerControl")
1979 {
1980 if (tempArray.empty())
1981 {
1982 // Put multiple "sensors" into a single
1983 // PowerControl. Follows MemberId naming and
1984 // naming in power.hpp.
1985 nlohmann::json::object_t power;
1986 boost::urls::url url = boost::urls::format(
1987 "/redfish/v1/Chassis/{}/{}",
1988 sensorsAsyncResp->chassisId,
1989 sensorsAsyncResp->chassisSubNode);
1990 url.set_fragment(
1991 (""_json_pointer / fieldName / "0")
1992 .to_string());
1993 power["@odata.id"] = std::move(url);
1994 tempArray.emplace_back(std::move(power));
1995 }
1996 sensorJson = &(tempArray.back());
1997 }
1998 else if (fieldName == "PowerSupplies")
1999 {
2000 if (inventoryItem != nullptr)
2001 {
2002 sensorJson = &(getPowerSupply(
2003 tempArray, *inventoryItem,
2004 sensorsAsyncResp->chassisId));
2005 }
2006 }
2007 else if (fieldName == "Members")
2008 {
Janet Adkins1516c212024-08-14 13:22:41 -05002009 std::string sensorId =
2010 redfish::sensor_utils::getSensorId(sensorName,
2011 sensorType);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002012
2013 nlohmann::json::object_t member;
2014 member["@odata.id"] = boost::urls::format(
2015 "/redfish/v1/Chassis/{}/{}/{}",
2016 sensorsAsyncResp->chassisId,
2017 sensorsAsyncResp->chassisSubNode, sensorId);
2018 tempArray.emplace_back(std::move(member));
2019 sensorJson = &(tempArray.back());
2020 }
2021 else
2022 {
2023 nlohmann::json::object_t member;
2024 boost::urls::url url = boost::urls::format(
2025 "/redfish/v1/Chassis/{}/{}",
2026 sensorsAsyncResp->chassisId,
2027 sensorsAsyncResp->chassisSubNode);
2028 url.set_fragment(
2029 (""_json_pointer / fieldName).to_string());
2030 member["@odata.id"] = std::move(url);
2031 tempArray.emplace_back(std::move(member));
2032 sensorJson = &(tempArray.back());
2033 }
2034 }
2035
2036 if (sensorJson != nullptr)
2037 {
Janet Adkins0c728b42024-08-29 11:09:10 -05002038 objectInterfacesToJson(
2039 sensorName, sensorType, chassisSubNode,
2040 objDictEntry.second, *sensorJson, inventoryItem);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002041
2042 std::string path = "/xyz/openbmc_project/sensors/";
2043 path += sensorType;
2044 path += "/";
2045 path += sensorName;
2046 sensorsAsyncResp->addMetadata(*sensorJson, path);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002047 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002048 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002049 if (sensorsAsyncResp.use_count() == 1)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002050 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002051 sortJSONResponse(sensorsAsyncResp);
Janet Adkins0c728b42024-08-29 11:09:10 -05002052 if (chassisSubNode ==
2053 sensor_utils::ChassisSubNode::sensorsNode &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002054 sensorsAsyncResp->efficientExpand)
2055 {
2056 sensorsAsyncResp->asyncResp->res
2057 .jsonValue["Members@odata.count"] =
2058 sensorsAsyncResp->asyncResp->res
2059 .jsonValue["Members"]
2060 .size();
2061 }
Janet Adkins0c728b42024-08-29 11:09:10 -05002062 else if (chassisSubNode ==
2063 sensor_utils::ChassisSubNode::thermalNode)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002064 {
2065 populateFanRedundancy(sensorsAsyncResp);
2066 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002067 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002068 BMCWEB_LOG_DEBUG("getManagedObjectsCb exit");
2069 });
Ed Tanous23a21a12020-07-25 04:45:05 +00002070 }
Ed Tanous62598e32023-07-17 17:06:25 -07002071 BMCWEB_LOG_DEBUG("getSensorData exit");
Shawn McCarneyde629b62019-03-08 10:42:51 -06002072}
2073
Patrick Williams504af5a2025-02-03 14:29:03 -05002074inline void processSensorList(
2075 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
2076 const std::shared_ptr<std::set<std::string>>& sensorNames)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002077{
Nan Zhoufe04d492022-06-22 17:10:41 +00002078 auto getConnectionCb = [sensorsAsyncResp, sensorNames](
2079 const std::set<std::string>& connections) {
Ed Tanous62598e32023-07-17 17:06:25 -07002080 BMCWEB_LOG_DEBUG("getConnectionCb enter");
Ed Tanousd0090732022-10-04 17:22:56 -07002081 auto getInventoryItemsCb =
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002082 [sensorsAsyncResp, sensorNames, connections](
2083 const std::shared_ptr<std::vector<InventoryItem>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07002084 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002085 BMCWEB_LOG_DEBUG("getInventoryItemsCb enter");
2086 // Get sensor data and store results in JSON
2087 getSensorData(sensorsAsyncResp, sensorNames, connections,
2088 inventoryItems);
2089 BMCWEB_LOG_DEBUG("getInventoryItemsCb exit");
2090 };
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002091
Ed Tanousd0090732022-10-04 17:22:56 -07002092 // Get inventory items associated with sensors
2093 getInventoryItems(sensorsAsyncResp, sensorNames,
2094 std::move(getInventoryItemsCb));
2095
Ed Tanous62598e32023-07-17 17:06:25 -07002096 BMCWEB_LOG_DEBUG("getConnectionCb exit");
Ed Tanous002d39b2022-05-31 08:59:27 -07002097 };
2098
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002099 // Get set of connections that provide sensor values
Ed Tanous81ce6092020-12-17 16:54:55 +00002100 getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002101}
2102
Shawn McCarneyde629b62019-03-08 10:42:51 -06002103/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002104 * @brief Entry point for retrieving sensors data related to requested
2105 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02002106 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002107 */
Patrick Williams504af5a2025-02-03 14:29:03 -05002108inline void getChassisData(
2109 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002110{
Ed Tanous62598e32023-07-17 17:06:25 -07002111 BMCWEB_LOG_DEBUG("getChassisData enter");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002112 auto getChassisCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002113 [sensorsAsyncResp](
Nan Zhoufe04d492022-06-22 17:10:41 +00002114 const std::shared_ptr<std::set<std::string>>& sensorNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002115 BMCWEB_LOG_DEBUG("getChassisCb enter");
2116 processSensorList(sensorsAsyncResp, sensorNames);
2117 BMCWEB_LOG_DEBUG("getChassisCb exit");
2118 };
Nan Zhou928fefb2022-03-28 08:45:00 -07002119 // SensorCollection doesn't contain the Redundancy property
Janet Adkins0c728b42024-08-29 11:09:10 -05002120 if (sensorsAsyncResp->chassisSubNode != sensors::sensorsNodeStr)
Nan Zhou928fefb2022-03-28 08:45:00 -07002121 {
2122 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
2123 nlohmann::json::array();
2124 }
Shawn McCarney26f03892019-05-03 13:20:24 -05002125 // Get set of sensors in chassis
Ed Tanous7f1cc262022-08-09 13:33:57 -07002126 getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId,
2127 sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types,
2128 std::move(getChassisCb));
Ed Tanous62598e32023-07-17 17:06:25 -07002129 BMCWEB_LOG_DEBUG("getChassisData exit");
Ed Tanous271584a2019-07-09 16:24:22 -07002130}
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002131
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302132/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002133 * @brief Find the requested sensorName in the list of all sensors supplied by
2134 * the chassis node
2135 *
2136 * @param sensorName The sensor name supplied in the PATCH request
2137 * @param sensorsList The list of sensors managed by the chassis node
2138 * @param sensorsModified The list of sensors that were found as a result of
2139 * repeated calls to this function
2140 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002141inline bool findSensorNameUsingSensorPath(
2142 std::string_view sensorName, const std::set<std::string>& sensorsList,
2143 std::set<std::string>& sensorsModified)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002144{
Nan Zhoufe04d492022-06-22 17:10:41 +00002145 for (const auto& chassisSensor : sensorsList)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002146 {
George Liu28aa8de2021-02-01 15:13:30 +08002147 sdbusplus::message::object_path path(chassisSensor);
Ed Tanousb00dcc22021-02-23 12:52:50 -08002148 std::string thisSensorName = path.filename();
George Liu28aa8de2021-02-01 15:13:30 +08002149 if (thisSensorName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002150 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002151 continue;
2152 }
2153 if (thisSensorName == sensorName)
2154 {
2155 sensorsModified.emplace(chassisSensor);
2156 return true;
2157 }
2158 }
2159 return false;
2160}
2161
2162/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302163 * @brief Entry point for overriding sensor values of given sensor
2164 *
zhanghch058d1b46d2021-04-01 11:18:24 +08002165 * @param sensorAsyncResp response object
Carol Wang4bb3dc32019-10-17 18:15:02 +08002166 * @param allCollections Collections extract from sensors' request patch info
jayaprakash Mutyala91e130a2020-03-04 22:26:38 +00002167 * @param chassisSubNode Chassis Node for which the query has to happen
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302168 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002169inline void setSensorsOverride(
Ed Tanousb5a76932020-09-29 16:16:58 -07002170 const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
Ed Tanous08850572024-03-06 15:09:17 -08002171 std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>&
jayaprakash Mutyala397fd612020-02-06 23:33:34 +00002172 allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302173{
Ed Tanous62598e32023-07-17 17:06:25 -07002174 BMCWEB_LOG_INFO("setSensorsOverride for subNode{}",
2175 sensorAsyncResp->chassisSubNode);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302176
Ed Tanousd02aad32024-02-13 14:43:34 -08002177 std::string_view propertyValueName;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302178 std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302179 std::string memberId;
Ed Tanous543f4402022-01-06 13:12:53 -08002180 double value = 0.0;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302181 for (auto& collectionItems : allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302182 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302183 if (collectionItems.first == "Temperatures")
2184 {
2185 propertyValueName = "ReadingCelsius";
2186 }
2187 else if (collectionItems.first == "Fans")
2188 {
2189 propertyValueName = "Reading";
2190 }
2191 else
2192 {
2193 propertyValueName = "ReadingVolts";
2194 }
2195 for (auto& item : collectionItems.second)
2196 {
Patrick Williams504af5a2025-02-03 14:29:03 -05002197 if (!json_util::readJsonObject( //
Myung Baeafc474a2024-10-09 00:53:29 -07002198 item, sensorAsyncResp->asyncResp->res, //
Patrick Williams504af5a2025-02-03 14:29:03 -05002199 "MemberId", memberId, //
2200 propertyValueName, value //
Myung Baeafc474a2024-10-09 00:53:29 -07002201 ))
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302202 {
2203 return;
2204 }
2205 overrideMap.emplace(memberId,
2206 std::make_pair(value, collectionItems.first));
2207 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302208 }
Carol Wang4bb3dc32019-10-17 18:15:02 +08002209
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002210 auto getChassisSensorListCb = [sensorAsyncResp, overrideMap,
2211 propertyValueNameStr =
2212 std::string(propertyValueName)](
2213 const std::shared_ptr<
2214 std::set<std::string>>& sensorsList) {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002215 // Match sensor names in the PATCH request to those managed by the
2216 // chassis node
Nan Zhoufe04d492022-06-22 17:10:41 +00002217 const std::shared_ptr<std::set<std::string>> sensorNames =
2218 std::make_shared<std::set<std::string>>();
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302219 for (const auto& item : overrideMap)
2220 {
2221 const auto& sensor = item.first;
Ed Tanousc71d6122022-11-29 14:10:32 -08002222 std::pair<std::string, std::string> sensorNameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002223 redfish::sensor_utils::splitSensorNameAndType(sensor);
Ed Tanousc71d6122022-11-29 14:10:32 -08002224 if (!findSensorNameUsingSensorPath(sensorNameType.second,
2225 *sensorsList, *sensorNames))
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302226 {
Ed Tanous62598e32023-07-17 17:06:25 -07002227 BMCWEB_LOG_INFO("Unable to find memberId {}", item.first);
zhanghch058d1b46d2021-04-01 11:18:24 +08002228 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302229 item.second.second, item.first);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302230 return;
2231 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302232 }
2233 // Get the connection to which the memberId belongs
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002234 auto getObjectsWithConnectionCb = [sensorAsyncResp, overrideMap,
2235 propertyValueNameStr](
2236 const std::set<
2237 std::string>& /*connections*/,
2238 const std::set<std::pair<
2239 std::string, std::string>>&
2240 objectsWithConnection) {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002241 if (objectsWithConnection.size() != overrideMap.size())
2242 {
Ed Tanous62598e32023-07-17 17:06:25 -07002243 BMCWEB_LOG_INFO(
2244 "Unable to find all objects with proper connection {} requested {}",
2245 objectsWithConnection.size(), overrideMap.size());
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002246 messages::resourceNotFound(
2247 sensorAsyncResp->asyncResp->res,
Janet Adkins0c728b42024-08-29 11:09:10 -05002248 sensorAsyncResp->chassisSubNode == sensors::thermalNodeStr
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002249 ? "Temperatures"
2250 : "Voltages",
2251 "Count");
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002252 return;
2253 }
2254 for (const auto& item : objectsWithConnection)
2255 {
2256 sdbusplus::message::object_path path(item.first);
2257 std::string sensorName = path.filename();
2258 if (sensorName.empty())
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302259 {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002260 messages::internalError(sensorAsyncResp->asyncResp->res);
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302261 return;
2262 }
Janet Adkins1516c212024-08-14 13:22:41 -05002263 std::string id = redfish::sensor_utils::getSensorId(
2264 sensorName, path.parent_path().filename());
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302265
Ban Feng3f5eb752023-06-29 09:19:20 +08002266 const auto& iterator = overrideMap.find(id);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002267 if (iterator == overrideMap.end())
2268 {
Ed Tanous62598e32023-07-17 17:06:25 -07002269 BMCWEB_LOG_INFO("Unable to find sensor object{}",
2270 item.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002271 messages::internalError(sensorAsyncResp->asyncResp->res);
2272 return;
2273 }
Ginu Georgee93abac2024-06-14 17:35:27 +05302274 setDbusProperty(sensorAsyncResp->asyncResp,
2275 propertyValueNameStr, item.second, item.first,
2276 "xyz.openbmc_project.Sensor.Value", "Value",
Ed Tanousd02aad32024-02-13 14:43:34 -08002277 iterator->second.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002278 }
2279 };
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302280 // Get object with connection for the given sensor name
2281 getObjectsWithConnection(sensorAsyncResp, sensorNames,
2282 std::move(getObjectsWithConnectionCb));
2283 };
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302284 // get full sensor list for the given chassisId and cross verify the sensor.
Ed Tanous7f1cc262022-08-09 13:33:57 -07002285 getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
2286 sensorAsyncResp->chassisSubNode, sensorAsyncResp->types,
2287 std::move(getChassisSensorListCb));
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302288}
2289
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002290/**
2291 * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2292 * path of the sensor.
2293 *
2294 * Function builds valid Redfish response for sensor query of given chassis and
2295 * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2296 * it to caller in a callback.
2297 *
2298 * @param chassis Chassis for which retrieval should be performed
Janet Adkinsc9563602024-08-28 11:37:46 -05002299 * @param node Node (group) of sensors. See sensor_utils::node for supported
2300 * values
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002301 * @param mapComplete Callback to be called with retrieval result
2302 */
Ed Tanous931edc72023-11-01 12:09:07 -07002303template <typename Callback>
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002304inline void retrieveUriToDbusMap(
2305 const std::string& chassis, const std::string& node, Callback&& mapComplete)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002306{
Ed Tanous02da7c52022-02-27 00:09:02 -08002307 decltype(sensors::paths)::const_iterator pathIt =
2308 std::find_if(sensors::paths.cbegin(), sensors::paths.cend(),
2309 [&node](auto&& val) { return val.first == node; });
2310 if (pathIt == sensors::paths.cend())
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002311 {
Ed Tanous62598e32023-07-17 17:06:25 -07002312 BMCWEB_LOG_ERROR("Wrong node provided : {}", node);
Ed Tanous6804b5c2023-10-31 14:50:03 -07002313 std::map<std::string, std::string> noop;
2314 mapComplete(boost::beast::http::status::bad_request, noop);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002315 return;
2316 }
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002317
Nan Zhou72374eb2022-01-27 17:06:51 -08002318 auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002319 auto callback =
2320 [asyncResp, mapCompleteCb = std::forward<Callback>(mapComplete)](
2321 const boost::beast::http::status status,
2322 const std::map<std::string, std::string>& uriToDbus) {
2323 mapCompleteCb(status, uriToDbus);
2324 };
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002325
2326 auto resp = std::make_shared<SensorsAsyncResp>(
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002327 asyncResp, chassis, pathIt->second, node, std::move(callback));
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002328 getChassisData(resp);
2329}
2330
Nan Zhoubacb2162022-04-06 11:28:32 -07002331namespace sensors
2332{
Nan Zhou928fefb2022-03-28 08:45:00 -07002333
Nan Zhoubacb2162022-04-06 11:28:32 -07002334inline void getChassisCallback(
Ed Tanousc1d019a2022-08-06 09:36:06 -07002335 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2336 std::string_view chassisId, std::string_view chassisSubNode,
Nan Zhoufe04d492022-06-22 17:10:41 +00002337 const std::shared_ptr<std::set<std::string>>& sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002338{
Ed Tanous62598e32023-07-17 17:06:25 -07002339 BMCWEB_LOG_DEBUG("getChassisCallback enter ");
Nan Zhoubacb2162022-04-06 11:28:32 -07002340
Ed Tanousc1d019a2022-08-06 09:36:06 -07002341 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
2342 for (const std::string& sensor : *sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002343 {
Ed Tanous62598e32023-07-17 17:06:25 -07002344 BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor);
Nan Zhoubacb2162022-04-06 11:28:32 -07002345
2346 sdbusplus::message::object_path path(sensor);
2347 std::string sensorName = path.filename();
2348 if (sensorName.empty())
2349 {
Ed Tanous62598e32023-07-17 17:06:25 -07002350 BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002351 messages::internalError(asyncResp->res);
Nan Zhoubacb2162022-04-06 11:28:32 -07002352 return;
2353 }
Ed Tanousc1d019a2022-08-06 09:36:06 -07002354 std::string type = path.parent_path().filename();
Janet Adkins1516c212024-08-14 13:22:41 -05002355 std::string id = redfish::sensor_utils::getSensorId(sensorName, type);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002356
Ed Tanous14766872022-03-15 10:44:42 -07002357 nlohmann::json::object_t member;
Ed Tanousef4c65b2023-04-24 15:28:50 -07002358 member["@odata.id"] = boost::urls::format(
2359 "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002360
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002361 entriesArray.emplace_back(std::move(member));
Nan Zhoubacb2162022-04-06 11:28:32 -07002362 }
2363
Ed Tanousc1d019a2022-08-06 09:36:06 -07002364 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Ed Tanous62598e32023-07-17 17:06:25 -07002365 BMCWEB_LOG_DEBUG("getChassisCallback exit");
Nan Zhoubacb2162022-04-06 11:28:32 -07002366}
Nan Zhoue6bd8462022-06-01 04:35:35 +00002367
Ed Tanousac106bf2023-06-07 09:24:59 -07002368inline void handleSensorCollectionGet(
2369 App& app, const crow::Request& req,
2370 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2371 const std::string& chassisId)
Nan Zhoude167a62022-06-01 04:47:45 +00002372{
2373 query_param::QueryCapabilities capabilities = {
2374 .canDelegateExpandLevel = 1,
2375 };
2376 query_param::Query delegatedQuery;
Ed Tanousac106bf2023-06-07 09:24:59 -07002377 if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
Nan Zhoude167a62022-06-01 04:47:45 +00002378 delegatedQuery, capabilities))
2379 {
2380 return;
2381 }
2382
2383 if (delegatedQuery.expandType != query_param::ExpandType::None)
2384 {
2385 // we perform efficient expand.
Ed Tanousac106bf2023-06-07 09:24:59 -07002386 auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>(
2387 asyncResp, chassisId, sensors::dbus::sensorPaths,
Janet Adkins0c728b42024-08-29 11:09:10 -05002388 sensors::sensorsNodeStr,
Nan Zhoude167a62022-06-01 04:47:45 +00002389 /*efficientExpand=*/true);
Ed Tanousac106bf2023-06-07 09:24:59 -07002390 getChassisData(sensorsAsyncResp);
Nan Zhoude167a62022-06-01 04:47:45 +00002391
Ed Tanous62598e32023-07-17 17:06:25 -07002392 BMCWEB_LOG_DEBUG(
2393 "SensorCollection doGet exit via efficient expand handler");
Nan Zhoude167a62022-06-01 04:47:45 +00002394 return;
Ed Tanous0bad3202022-06-02 13:53:59 -07002395 }
Nan Zhoude167a62022-06-01 04:47:45 +00002396
Nan Zhoude167a62022-06-01 04:47:45 +00002397 // We get all sensors as hyperlinkes in the chassis (this
2398 // implies we reply on the default query parameters handler)
Janet Adkins0c728b42024-08-29 11:09:10 -05002399 getChassis(asyncResp, chassisId, sensors::sensorsNodeStr, dbus::sensorPaths,
Ed Tanousac106bf2023-06-07 09:24:59 -07002400 std::bind_front(sensors::getChassisCallback, asyncResp,
Janet Adkins0c728b42024-08-29 11:09:10 -05002401 chassisId, sensors::sensorsNodeStr));
Ed Tanousc1d019a2022-08-06 09:36:06 -07002402}
Ed Tanous7f1cc262022-08-09 13:33:57 -07002403
Patrick Williams504af5a2025-02-03 14:29:03 -05002404inline void getSensorFromDbus(
2405 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2406 const std::string& sensorPath,
2407 const ::dbus::utility::MapperGetObject& mapperResponse)
Ed Tanousc1d019a2022-08-06 09:36:06 -07002408{
2409 if (mapperResponse.size() != 1)
2410 {
2411 messages::internalError(asyncResp->res);
2412 return;
2413 }
2414 const auto& valueIface = *mapperResponse.begin();
2415 const std::string& connectionName = valueIface.first;
Ed Tanous62598e32023-07-17 17:06:25 -07002416 BMCWEB_LOG_DEBUG("Looking up {}", connectionName);
2417 BMCWEB_LOG_DEBUG("Path {}", sensorPath);
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002418
Ed Tanousdeae6a72024-11-11 21:58:57 -08002419 ::dbus::utility::getAllProperties(
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002420 *crow::connections::systemBus, connectionName, sensorPath, "",
Ed Tanousc1d019a2022-08-06 09:36:06 -07002421 [asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002422 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002423 const ::dbus::utility::DBusPropertiesMap& valuesDict) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002424 if (ec)
2425 {
2426 messages::internalError(asyncResp->res);
2427 return;
2428 }
2429 sdbusplus::message::object_path path(sensorPath);
2430 std::string name = path.filename();
2431 path = path.parent_path();
2432 std::string type = path.filename();
Janet Adkinsc9563602024-08-28 11:37:46 -05002433 sensor_utils::objectPropertiesToJson(
Janet Adkins0c728b42024-08-29 11:09:10 -05002434 name, type, sensor_utils::ChassisSubNode::sensorsNode,
2435 valuesDict, asyncResp->res.jsonValue, nullptr);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002436 });
Nan Zhoude167a62022-06-01 04:47:45 +00002437}
2438
Nan Zhoue6bd8462022-06-01 04:35:35 +00002439inline void handleSensorGet(App& app, const crow::Request& req,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002440 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous677bb752022-09-15 10:52:19 -07002441 const std::string& chassisId,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002442 const std::string& sensorId)
Nan Zhoue6bd8462022-06-01 04:35:35 +00002443{
Ed Tanousc1d019a2022-08-06 09:36:06 -07002444 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Nan Zhoue6bd8462022-06-01 04:35:35 +00002445 {
2446 return;
2447 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002448 std::pair<std::string, std::string> nameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002449 redfish::sensor_utils::splitSensorNameAndType(sensorId);
Ed Tanousc71d6122022-11-29 14:10:32 -08002450 if (nameType.first.empty() || nameType.second.empty())
Ed Tanousc1d019a2022-08-06 09:36:06 -07002451 {
2452 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2453 return;
2454 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002455
Ed Tanousef4c65b2023-04-24 15:28:50 -07002456 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2457 "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002458
Ed Tanous62598e32023-07-17 17:06:25 -07002459 BMCWEB_LOG_DEBUG("Sensor doGet enter");
Nan Zhoue6bd8462022-06-01 04:35:35 +00002460
George Liu2b731192023-01-11 16:27:13 +08002461 constexpr std::array<std::string_view, 1> interfaces = {
Nan Zhoue6bd8462022-06-01 04:35:35 +00002462 "xyz.openbmc_project.Sensor.Value"};
Ed Tanousc71d6122022-11-29 14:10:32 -08002463 std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first +
2464 '/' + nameType.second;
Nan Zhoue6bd8462022-06-01 04:35:35 +00002465 // Get a list of all of the sensors that implement Sensor.Value
2466 // and get the path and service name associated with the sensor
George Liu2b731192023-01-11 16:27:13 +08002467 ::dbus::utility::getDbusObject(
2468 sensorPath, interfaces,
Myung Baeaec0ec32023-05-31 15:10:01 -05002469 [asyncResp, sensorId,
George Liu2b731192023-01-11 16:27:13 +08002470 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002471 const ::dbus::utility::MapperGetObject& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002472 BMCWEB_LOG_DEBUG("respHandler1 enter");
2473 if (ec == boost::system::errc::io_error)
2474 {
2475 BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths");
2476 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2477 return;
2478 }
2479 if (ec)
2480 {
2481 messages::internalError(asyncResp->res);
2482 BMCWEB_LOG_ERROR(
2483 "Sensor getSensorPaths resp_handler: Dbus error {}", ec);
2484 return;
2485 }
2486 getSensorFromDbus(asyncResp, sensorPath, subtree);
2487 BMCWEB_LOG_DEBUG("respHandler1 exit");
2488 });
Nan Zhoue6bd8462022-06-01 04:35:35 +00002489}
2490
Nan Zhoubacb2162022-04-06 11:28:32 -07002491} // namespace sensors
2492
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002493inline void requestRoutesSensorCollection(App& app)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002494{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002495 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
Ed Tanoused398212021-06-09 17:05:54 -07002496 .privileges(redfish::privileges::getSensorCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002497 .methods(boost::beast::http::verb::get)(
Nan Zhoude167a62022-06-01 04:47:45 +00002498 std::bind_front(sensors::handleSensorCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002499}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002500
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002501inline void requestRoutesSensor(App& app)
2502{
2503 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002504 .privileges(redfish::privileges::getSensor)
Ed Tanous002d39b2022-05-31 08:59:27 -07002505 .methods(boost::beast::http::verb::get)(
Nan Zhoue6bd8462022-06-01 04:35:35 +00002506 std::bind_front(sensors::handleSensorGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002507}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002508
Ed Tanous1abe55e2018-09-05 08:30:59 -07002509} // namespace redfish