blob: 2804b86dda8ca9586e5b7eed7fa44158ced9f657 [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",
83 "/xyz/openbmc_project/sensors/utilization"});
84 } else {
85 return std::to_array<std::string_view>({"/xyz/openbmc_project/sensors/power",
86 "/xyz/openbmc_project/sensors/current",
87 "/xyz/openbmc_project/sensors/airflow",
88 "/xyz/openbmc_project/sensors/humidity",
89 "/xyz/openbmc_project/sensors/utilization"});
90}
91}
92
93constexpr auto sensorPaths = getSensorPaths();
Ed Tanous02da7c52022-02-27 00:09:02 -080094
Ed Tanouscf9e4172022-12-21 09:30:16 -080095constexpr auto thermalPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080096 "/xyz/openbmc_project/sensors/fan_tach",
97 "/xyz/openbmc_project/sensors/temperature",
98 "/xyz/openbmc_project/sensors/fan_pwm"
99});
100
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000101} // namespace dbus
Ed Tanous02da7c52022-02-27 00:09:02 -0800102// clang-format on
103
Janet Adkins0c728b42024-08-29 11:09:10 -0500104constexpr std::string_view powerNodeStr = sensor_utils::chassisSubNodeToString(
105 sensor_utils::ChassisSubNode::powerNode);
106constexpr std::string_view sensorsNodeStr =
107 sensor_utils::chassisSubNodeToString(
108 sensor_utils::ChassisSubNode::sensorsNode);
109constexpr std::string_view thermalNodeStr =
110 sensor_utils::chassisSubNodeToString(
111 sensor_utils::ChassisSubNode::thermalNode);
112
Ed Tanouscf9e4172022-12-21 09:30:16 -0800113using sensorPair =
114 std::pair<std::string_view, std::span<const std::string_view>>;
Ed Tanous02da7c52022-02-27 00:09:02 -0800115static constexpr std::array<sensorPair, 3> paths = {
Janet Adkins0c728b42024-08-29 11:09:10 -0500116 {{sensors::powerNodeStr, dbus::powerPaths},
117 {sensors::sensorsNodeStr, dbus::sensorPaths},
118 {sensors::thermalNodeStr, dbus::thermalPaths}}};
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000119
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200120} // namespace sensors
121
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100122/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200123 * SensorsAsyncResp
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100124 * Gathers data needed for response processing after async calls are done
125 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700126class SensorsAsyncResp
127{
128 public:
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200129 using DataCompleteCb = std::function<void(
130 const boost::beast::http::status status,
Nan Zhoufe04d492022-06-22 17:10:41 +0000131 const std::map<std::string, std::string>& uriToDbus)>;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200132
133 struct SensorData
134 {
Ed Tanousf836c1d2024-09-06 16:05:11 -0700135 std::string name;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200136 std::string uri;
Ed Tanousf836c1d2024-09-06 16:05:11 -0700137 std::string dbusPath;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200138 };
139
Ed Tanous8a592812022-06-04 09:06:59 -0700140 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800141 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800142 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800143 std::string_view subNode) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400144 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
145 chassisSubNode(subNode), efficientExpand(false)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500146 {}
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200147
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200148 // Store extra data about sensor mapping and return it in callback
Ed Tanous8a592812022-06-04 09:06:59 -0700149 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800150 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800151 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800152 std::string_view subNode,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200153 DataCompleteCb&& creationComplete) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400154 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
155 chassisSubNode(subNode), efficientExpand(false),
156 metadata{std::vector<SensorData>()},
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200157 dataComplete{std::move(creationComplete)}
158 {}
159
Nan Zhou928fefb2022-03-28 08:45:00 -0700160 // sensor collections expand
Ed Tanous8a592812022-06-04 09:06:59 -0700161 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
Nan Zhou928fefb2022-03-28 08:45:00 -0700162 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800163 std::span<const std::string_view> typesIn,
Ed Tanous8a592812022-06-04 09:06:59 -0700164 const std::string_view& subNode, bool efficientExpandIn) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400165 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
166 chassisSubNode(subNode), efficientExpand(efficientExpandIn)
Nan Zhou928fefb2022-03-28 08:45:00 -0700167 {}
168
Ed Tanous1abe55e2018-09-05 08:30:59 -0700169 ~SensorsAsyncResp()
170 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800171 if (asyncResp->res.result() ==
172 boost::beast::http::status::internal_server_error)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700173 {
174 // Reset the json object to clear out any data that made it in
175 // before the error happened todo(ed) handle error condition with
176 // proper code
zhanghch058d1b46d2021-04-01 11:18:24 +0800177 asyncResp->res.jsonValue = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700178 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200179
180 if (dataComplete && metadata)
181 {
Nan Zhoufe04d492022-06-22 17:10:41 +0000182 std::map<std::string, std::string> map;
zhanghch058d1b46d2021-04-01 11:18:24 +0800183 if (asyncResp->res.result() == boost::beast::http::status::ok)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200184 {
185 for (auto& sensor : *metadata)
186 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700187 map.emplace(sensor.uri, sensor.dbusPath);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200188 }
189 }
zhanghch058d1b46d2021-04-01 11:18:24 +0800190 dataComplete(asyncResp->res.result(), map);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200191 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700192 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100193
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800194 SensorsAsyncResp(const SensorsAsyncResp&) = delete;
195 SensorsAsyncResp(SensorsAsyncResp&&) = delete;
196 SensorsAsyncResp& operator=(const SensorsAsyncResp&) = delete;
197 SensorsAsyncResp& operator=(SensorsAsyncResp&&) = delete;
198
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200199 void addMetadata(const nlohmann::json& sensorObject,
Ed Tanousc1d019a2022-08-06 09:36:06 -0700200 const std::string& dbusPath)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200201 {
202 if (metadata)
203 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700204 metadata->emplace_back(SensorData{
205 sensorObject["Name"], sensorObject["@odata.id"], dbusPath});
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200206 }
207 }
208
209 void updateUri(const std::string& name, const std::string& uri)
210 {
211 if (metadata)
212 {
213 for (auto& sensor : *metadata)
214 {
215 if (sensor.name == name)
216 {
217 sensor.uri = uri;
218 }
219 }
220 }
221 }
222
zhanghch058d1b46d2021-04-01 11:18:24 +0800223 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200224 const std::string chassisId;
Ed Tanouscf9e4172022-12-21 09:30:16 -0800225 const std::span<const std::string_view> types;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200226 const std::string chassisSubNode;
Nan Zhou928fefb2022-03-28 08:45:00 -0700227 const bool efficientExpand;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200228
229 private:
230 std::optional<std::vector<SensorData>> metadata;
231 DataCompleteCb dataComplete;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100232};
233
Janet Adkinsc9563602024-08-28 11:37:46 -0500234using InventoryItem = sensor_utils::InventoryItem;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500235
236/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530237 * @brief Get objects with connection necessary for sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200238 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100239 * @param sensorNames Sensors retrieved from chassis
240 * @param callback Callback for processing gathered connections
241 */
242template <typename Callback>
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530243void getObjectsWithConnection(
Ed Tanous81ce6092020-12-17 16:54:55 +0000244 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +0000245 const std::shared_ptr<std::set<std::string>>& sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530246 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700247{
Ed Tanous62598e32023-07-17 17:06:25 -0700248 BMCWEB_LOG_DEBUG("getObjectsWithConnection enter");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700249 const std::string path = "/xyz/openbmc_project/sensors";
George Liue99073f2022-12-09 11:06:16 +0800250 constexpr std::array<std::string_view, 1> interfaces = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700251 "xyz.openbmc_project.Sensor.Value"};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100252
George Liue99073f2022-12-09 11:06:16 +0800253 // Make call to ObjectMapper to find all sensors objects
254 dbus::utility::getSubTree(
255 path, 2, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700256 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
George Liue99073f2022-12-09 11:06:16 +0800257 sensorNames](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700258 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400259 // Response handler for parsing objects subtree
260 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler enter");
261 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700262 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400263 messages::internalError(sensorsAsyncResp->asyncResp->res);
264 BMCWEB_LOG_ERROR(
265 "getObjectsWithConnection resp_handler: Dbus error {}", ec);
266 return;
267 }
268
269 BMCWEB_LOG_DEBUG("Found {} subtrees", subtree.size());
270
271 // Make unique list of connections only for requested sensor types
272 // and found in the chassis
273 std::set<std::string> connections;
274 std::set<std::pair<std::string, std::string>> objectsWithConnection;
275
276 BMCWEB_LOG_DEBUG("sensorNames list count: {}", sensorNames->size());
277 for (const std::string& tsensor : *sensorNames)
278 {
279 BMCWEB_LOG_DEBUG("Sensor to find: {}", tsensor);
280 }
281
282 for (const std::pair<std::string,
283 std::vector<std::pair<
284 std::string, std::vector<std::string>>>>&
285 object : subtree)
286 {
287 if (sensorNames->find(object.first) != sensorNames->end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700288 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400289 for (const std::pair<std::string, std::vector<std::string>>&
290 objData : object.second)
291 {
292 BMCWEB_LOG_DEBUG("Adding connection: {}",
293 objData.first);
294 connections.insert(objData.first);
295 objectsWithConnection.insert(
296 std::make_pair(object.first, objData.first));
297 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700298 }
299 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400300 BMCWEB_LOG_DEBUG("Found {} connections", connections.size());
301 callback(std::move(connections), std::move(objectsWithConnection));
302 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler exit");
303 });
Ed Tanous62598e32023-07-17 17:06:25 -0700304 BMCWEB_LOG_DEBUG("getObjectsWithConnection exit");
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530305}
306
307/**
308 * @brief Create connections necessary for sensors
309 * @param SensorsAsyncResp Pointer to object holding response data
310 * @param sensorNames Sensors retrieved from chassis
311 * @param callback Callback for processing gathered connections
312 */
313template <typename Callback>
Ed Tanousdaadfb22024-12-20 09:25:54 -0800314void getConnections(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
315 const std::shared_ptr<std::set<std::string>>& sensorNames,
Nan Zhoufe04d492022-06-22 17:10:41 +0000316 Callback&& callback)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530317{
318 auto objectsWithConnectionCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -0700319 [callback = std::forward<Callback>(callback)](
320 const std::set<std::string>& connections,
321 const std::set<std::pair<std::string, std::string>>&
322 /*objectsWithConnection*/) { callback(connections); };
Ed Tanous81ce6092020-12-17 16:54:55 +0000323 getObjectsWithConnection(sensorsAsyncResp, sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530324 std::move(objectsWithConnectionCb));
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100325}
326
327/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700328 * @brief Shrinks the list of sensors for processing
329 * @param SensorsAysncResp The class holding the Redfish response
330 * @param allSensors A list of all the sensors associated to the
331 * chassis element (i.e. baseboard, front panel, etc...)
332 * @param activeSensors A list that is a reduction of the incoming
333 * allSensors list. Eliminate Thermal sensors when a Power request is
334 * made, and eliminate Power sensors when a Thermal request is made.
335 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000336inline void reduceSensorList(
Ed Tanous7f1cc262022-08-09 13:33:57 -0700337 crow::Response& res, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800338 std::span<const std::string_view> sensorTypes,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700339 const std::vector<std::string>* allSensors,
Nan Zhoufe04d492022-06-22 17:10:41 +0000340 const std::shared_ptr<std::set<std::string>>& activeSensors)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700341{
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700342 if ((allSensors == nullptr) || (activeSensors == nullptr))
343 {
Ed Tanous7f1cc262022-08-09 13:33:57 -0700344 messages::resourceNotFound(res, chassisSubNode,
Janet Adkins0c728b42024-08-29 11:09:10 -0500345 chassisSubNode == sensors::thermalNodeStr
Ed Tanous7f1cc262022-08-09 13:33:57 -0700346 ? "Temperatures"
347 : "Voltages");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700348
349 return;
350 }
351 if (allSensors->empty())
352 {
353 // Nothing to do, the activeSensors object is also empty
354 return;
355 }
356
Ed Tanous7f1cc262022-08-09 13:33:57 -0700357 for (std::string_view type : sensorTypes)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700358 {
359 for (const std::string& sensor : *allSensors)
360 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700361 if (sensor.starts_with(type))
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700362 {
363 activeSensors->emplace(sensor);
364 }
365 }
366 }
367}
368
Ed Tanous7f1cc262022-08-09 13:33:57 -0700369/*
370 *Populates the top level collection for a given subnode. Populates
371 *SensorCollection, Power, or Thermal schemas.
372 *
373 * */
374inline void populateChassisNode(nlohmann::json& jsonValue,
375 std::string_view chassisSubNode)
376{
Janet Adkins0c728b42024-08-29 11:09:10 -0500377 if (chassisSubNode == sensors::powerNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700378 {
379 jsonValue["@odata.type"] = "#Power.v1_5_2.Power";
380 }
Janet Adkins0c728b42024-08-29 11:09:10 -0500381 else if (chassisSubNode == sensors::thermalNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700382 {
383 jsonValue["@odata.type"] = "#Thermal.v1_4_0.Thermal";
384 jsonValue["Fans"] = nlohmann::json::array();
385 jsonValue["Temperatures"] = nlohmann::json::array();
386 }
Janet Adkins0c728b42024-08-29 11:09:10 -0500387 else if (chassisSubNode == sensors::sensorsNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700388 {
389 jsonValue["@odata.type"] = "#SensorCollection.SensorCollection";
390 jsonValue["Description"] = "Collection of Sensors for this Chassis";
391 jsonValue["Members"] = nlohmann::json::array();
392 jsonValue["Members@odata.count"] = 0;
393 }
394
Janet Adkins0c728b42024-08-29 11:09:10 -0500395 if (chassisSubNode != sensors::sensorsNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700396 {
397 jsonValue["Id"] = chassisSubNode;
398 }
399 jsonValue["Name"] = chassisSubNode;
400}
401
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700402/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100403 * @brief Retrieves requested chassis sensors and redundancy data from DBus .
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200404 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100405 * @param callback Callback for next step in gathered sensor processing
406 */
407template <typename Callback>
Ed Tanous7f1cc262022-08-09 13:33:57 -0700408void getChassis(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
409 std::string_view chassisId, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800410 std::span<const std::string_view> sensorTypes,
411 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700412{
Ed Tanous62598e32023-07-17 17:06:25 -0700413 BMCWEB_LOG_DEBUG("getChassis enter");
George Liu7a1dbc42022-12-07 16:03:22 +0800414 constexpr std::array<std::string_view, 2> interfaces = {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700415 "xyz.openbmc_project.Inventory.Item.Board",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500416 "xyz.openbmc_project.Inventory.Item.Chassis"};
George Liu7a1dbc42022-12-07 16:03:22 +0800417
418 // Get the Chassis Collection
419 dbus::utility::getSubTreePaths(
420 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700421 [callback = std::forward<Callback>(callback), asyncResp,
Ed Tanous7f1cc262022-08-09 13:33:57 -0700422 chassisIdStr{std::string(chassisId)},
Ed Tanous4e0d8782024-09-06 15:16:41 -0700423 chassisSubNode{std::string(chassisSubNode)},
424 sensorTypes](const boost::system::error_code& ec,
425 const dbus::utility::MapperGetSubTreePathsResponse&
426 chassisPaths) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400427 BMCWEB_LOG_DEBUG("getChassis respHandler enter");
428 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700429 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400430 BMCWEB_LOG_ERROR("getChassis respHandler DBUS error: {}", ec);
431 messages::internalError(asyncResp->res);
432 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700433 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400434 const std::string* chassisPath = nullptr;
435 for (const std::string& chassis : chassisPaths)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700436 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400437 sdbusplus::message::object_path path(chassis);
438 std::string chassisName = path.filename();
439 if (chassisName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700440 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400441 BMCWEB_LOG_ERROR("Failed to find '/' in {}", chassis);
442 continue;
443 }
444 if (chassisName == chassisIdStr)
445 {
446 chassisPath = &chassis;
447 break;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700448 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700449 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400450 if (chassisPath == nullptr)
451 {
452 messages::resourceNotFound(asyncResp->res, "Chassis",
453 chassisIdStr);
454 return;
455 }
456 populateChassisNode(asyncResp->res.jsonValue, chassisSubNode);
457
458 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
459 "/redfish/v1/Chassis/{}/{}", chassisIdStr, chassisSubNode);
460
461 // Get the list of all sensors for this Chassis element
462 std::string sensorPath = *chassisPath + "/all_sensors";
463 dbus::utility::getAssociationEndPoints(
Ed Tanous4e0d8782024-09-06 15:16:41 -0700464 sensorPath, [asyncResp, chassisSubNode, sensorTypes,
465 callback = std::forward<Callback>(callback)](
466 const boost::system::error_code& ec2,
467 const dbus::utility::MapperEndPoints&
468 nodeSensorList) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400469 if (ec2)
470 {
471 if (ec2.value() != EBADR)
472 {
473 messages::internalError(asyncResp->res);
474 return;
475 }
476 }
477 const std::shared_ptr<std::set<std::string>>
478 culledSensorList =
479 std::make_shared<std::set<std::string>>();
480 reduceSensorList(asyncResp->res, chassisSubNode,
481 sensorTypes, &nodeSensorList,
482 culledSensorList);
483 BMCWEB_LOG_DEBUG("Finishing with {}",
484 culledSensorList->size());
485 callback(culledSensorList);
486 });
George Liu7a1dbc42022-12-07 16:03:22 +0800487 });
Ed Tanous62598e32023-07-17 17:06:25 -0700488 BMCWEB_LOG_DEBUG("getChassis exit");
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100489}
490
491/**
Ed Tanous1d7c0052022-08-09 12:32:26 -0700492 * @brief Builds a json sensor representation of a sensor.
493 * @param sensorName The name of the sensor to be built
494 * @param sensorType The type (temperature, fan_tach, etc) of the sensor to
495 * build
Ed Tanous8ece0e42024-01-02 13:16:50 -0800496 * @param chassisSubNode The subnode (thermal, sensor, etc) of the sensor
Ed Tanous1d7c0052022-08-09 12:32:26 -0700497 * @param interfacesDict A dictionary of the interfaces and properties of said
498 * interfaces to be built from
499 * @param sensorJson The json object to fill
500 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
501 * be nullptr if no associated inventory item was found.
502 */
503inline void objectInterfacesToJson(
504 const std::string& sensorName, const std::string& sensorType,
Janet Adkins0c728b42024-08-29 11:09:10 -0500505 const sensor_utils::ChassisSubNode chassisSubNode,
Michael Shen80f79a42023-08-24 13:41:53 +0000506 const dbus::utility::DBusInterfacesMap& interfacesDict,
Ed Tanous1d7c0052022-08-09 12:32:26 -0700507 nlohmann::json& sensorJson, InventoryItem* inventoryItem)
508{
Ed Tanous1d7c0052022-08-09 12:32:26 -0700509 for (const auto& [interface, valuesDict] : interfacesDict)
510 {
Janet Adkinsc9563602024-08-28 11:37:46 -0500511 sensor_utils::objectPropertiesToJson(
512 sensorName, sensorType, chassisSubNode, valuesDict, sensorJson,
513 inventoryItem);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700514 }
Ed Tanous62598e32023-07-17 17:06:25 -0700515 BMCWEB_LOG_DEBUG("Added sensor {}", sensorName);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700516}
517
Ed Tanousb5a76932020-09-29 16:16:58 -0700518inline void populateFanRedundancy(
519 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
James Feist8bd25cc2019-03-15 15:14:00 -0700520{
George Liue99073f2022-12-09 11:06:16 +0800521 constexpr std::array<std::string_view, 1> interfaces = {
522 "xyz.openbmc_project.Control.FanRedundancy"};
523 dbus::utility::getSubTree(
524 "/xyz/openbmc_project/control", 2, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800525 [sensorsAsyncResp](
George Liue99073f2022-12-09 11:06:16 +0800526 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800527 const dbus::utility::MapperGetSubTreeResponse& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400528 if (ec)
James Feist8bd25cc2019-03-15 15:14:00 -0700529 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400530 return; // don't have to have this interface
James Feist8bd25cc2019-03-15 15:14:00 -0700531 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400532 for (const std::pair<std::string, dbus::utility::MapperServiceMap>&
533 pathPair : resp)
534 {
535 const std::string& path = pathPair.first;
536 const dbus::utility::MapperServiceMap& objDict =
537 pathPair.second;
538 if (objDict.empty())
James Feist8bd25cc2019-03-15 15:14:00 -0700539 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400540 continue; // this should be impossible
James Feist8bd25cc2019-03-15 15:14:00 -0700541 }
542
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400543 const std::string& owner = objDict.begin()->first;
544 dbus::utility::getAssociationEndPoints(
545 path + "/chassis",
546 [path, owner, sensorsAsyncResp](
547 const boost::system::error_code& ec2,
548 const dbus::utility::MapperEndPoints& endpoints) {
549 if (ec2)
James Feist8bd25cc2019-03-15 15:14:00 -0700550 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400551 return; // if they don't have an association we
552 // can't tell what chassis is
James Feist8bd25cc2019-03-15 15:14:00 -0700553 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400554 auto found = std::ranges::find_if(
555 endpoints,
556 [sensorsAsyncResp](const std::string& entry) {
557 return entry.find(
558 sensorsAsyncResp->chassisId) !=
559 std::string::npos;
560 });
561
562 if (found == endpoints.end())
James Feist8bd25cc2019-03-15 15:14:00 -0700563 {
564 return;
565 }
Ed Tanousdeae6a72024-11-11 21:58:57 -0800566 dbus::utility::getAllProperties(
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400567 *crow::connections::systemBus, owner, path,
568 "xyz.openbmc_project.Control.FanRedundancy",
569 [path, sensorsAsyncResp](
570 const boost::system::error_code& ec3,
571 const dbus::utility::DBusPropertiesMap& ret) {
572 if (ec3)
573 {
574 return; // don't have to have this
575 // interface
576 }
James Feist8bd25cc2019-03-15 15:14:00 -0700577
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400578 const uint8_t* allowedFailures = nullptr;
579 const std::vector<std::string>* collection =
580 nullptr;
581 const std::string* status = nullptr;
James Feist8bd25cc2019-03-15 15:14:00 -0700582
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400583 const bool success =
584 sdbusplus::unpackPropertiesNoThrow(
585 dbus_utils::UnpackErrorPrinter(), ret,
586 "AllowedFailures", allowedFailures,
587 "Collection", collection, "Status",
588 status);
James Feist8bd25cc2019-03-15 15:14:00 -0700589
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400590 if (!success)
591 {
592 messages::internalError(
593 sensorsAsyncResp->asyncResp->res);
594 return;
595 }
596
597 if (allowedFailures == nullptr ||
598 collection == nullptr || status == nullptr)
599 {
600 BMCWEB_LOG_ERROR(
601 "Invalid redundancy interface");
602 messages::internalError(
603 sensorsAsyncResp->asyncResp->res);
604 return;
605 }
606
607 sdbusplus::message::object_path objectPath(
608 path);
609 std::string name = objectPath.filename();
610 if (name.empty())
611 {
612 // this should be impossible
613 messages::internalError(
614 sensorsAsyncResp->asyncResp->res);
615 return;
616 }
617 std::ranges::replace(name, '_', ' ');
618
619 std::string health;
620
621 if (status->ends_with("Full"))
622 {
623 health = "OK";
624 }
625 else if (status->ends_with("Degraded"))
626 {
627 health = "Warning";
628 }
629 else
630 {
631 health = "Critical";
632 }
633 nlohmann::json::array_t redfishCollection;
634 const auto& fanRedfish =
635 sensorsAsyncResp->asyncResp->res
636 .jsonValue["Fans"];
637 for (const std::string& item : *collection)
638 {
639 sdbusplus::message::object_path itemPath(
640 item);
641 std::string itemName = itemPath.filename();
642 if (itemName.empty())
643 {
644 continue;
645 }
646 /*
647 todo(ed): merge patch that fixes the names
648 std::replace(itemName.begin(),
649 itemName.end(), '_', ' ');*/
650 auto schemaItem = std::ranges::find_if(
651 fanRedfish,
652 [itemName](const nlohmann::json& fan) {
653 return fan["Name"] == itemName;
654 });
655 if (schemaItem != fanRedfish.end())
656 {
657 nlohmann::json::object_t collectionId;
658 collectionId["@odata.id"] =
659 (*schemaItem)["@odata.id"];
660 redfishCollection.emplace_back(
661 std::move(collectionId));
662 }
663 else
664 {
665 BMCWEB_LOG_ERROR(
666 "failed to find fan in schema");
667 messages::internalError(
668 sensorsAsyncResp->asyncResp->res);
669 return;
670 }
671 }
672
673 size_t minNumNeeded =
674 collection->empty()
675 ? 0
676 : collection->size() - *allowedFailures;
677 nlohmann::json& jResp =
678 sensorsAsyncResp->asyncResp->res
679 .jsonValue["Redundancy"];
680
681 nlohmann::json::object_t redundancy;
682 boost::urls::url url = boost::urls::format(
683 "/redfish/v1/Chassis/{}/{}",
684 sensorsAsyncResp->chassisId,
685 sensorsAsyncResp->chassisSubNode);
686 url.set_fragment(
687 ("/Redundancy"_json_pointer / jResp.size())
688 .to_string());
689 redundancy["@odata.id"] = std::move(url);
690 redundancy["@odata.type"] =
691 "#Redundancy.v1_3_2.Redundancy";
692 redundancy["MinNumNeeded"] = minNumNeeded;
693 redundancy["Mode"] =
694 redundancy::RedundancyType::NPlusM;
695 redundancy["Name"] = name;
696 redundancy["RedundancySet"] = redfishCollection;
697 redundancy["Status"]["Health"] = health;
698 redundancy["Status"]["State"] =
699 resource::State::Enabled;
700
701 jResp.emplace_back(std::move(redundancy));
702 });
703 });
704 }
705 });
James Feist8bd25cc2019-03-15 15:14:00 -0700706}
707
Patrick Williams504af5a2025-02-03 14:29:03 -0500708inline void sortJSONResponse(
709 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700710{
zhanghch058d1b46d2021-04-01 11:18:24 +0800711 nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700712 std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
Janet Adkins0c728b42024-08-29 11:09:10 -0500713 if (sensorsAsyncResp->chassisSubNode == sensors::powerNodeStr)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700714 {
715 sensorHeaders = {"Voltages", "PowerSupplies"};
716 }
717 for (const std::string& sensorGroup : sensorHeaders)
718 {
719 nlohmann::json::iterator entry = response.find(sensorGroup);
Ed Tanous4e196b92024-09-27 17:45:09 -0700720 if (entry == response.end())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700721 {
Ed Tanous4e196b92024-09-27 17:45:09 -0700722 continue;
723 }
724 nlohmann::json::array_t* arr =
725 entry->get_ptr<nlohmann::json::array_t*>();
726 if (arr == nullptr)
727 {
728 continue;
729 }
730 json_util::sortJsonArrayByKey(*arr, "Name");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700731
Ed Tanous4e196b92024-09-27 17:45:09 -0700732 // add the index counts to the end of each entry
733 size_t count = 0;
734 for (nlohmann::json& sensorJson : *entry)
735 {
736 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
737 if (odata == sensorJson.end())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700738 {
Ed Tanous4e196b92024-09-27 17:45:09 -0700739 continue;
740 }
741 std::string* value = odata->get_ptr<std::string*>();
742 if (value != nullptr)
743 {
744 *value += "/" + std::to_string(count);
745 sensorJson["MemberId"] = std::to_string(count);
746 count++;
747 sensorsAsyncResp->updateUri(sensorJson["Name"], *value);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700748 }
749 }
750 }
751}
752
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100753/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500754 * @brief Finds the inventory item with the specified object path.
755 * @param inventoryItems D-Bus inventory items associated with sensors.
756 * @param invItemObjPath D-Bus object path of inventory item.
757 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500758 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000759inline InventoryItem* findInventoryItem(
Ed Tanousb5a76932020-09-29 16:16:58 -0700760 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500761 const std::string& invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500762{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500763 for (InventoryItem& inventoryItem : *inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500764 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500765 if (inventoryItem.objectPath == invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500766 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500767 return &inventoryItem;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500768 }
769 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500770 return nullptr;
771}
772
773/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500774 * @brief Finds the inventory item associated with the specified sensor.
775 * @param inventoryItems D-Bus inventory items associated with sensors.
776 * @param sensorObjPath D-Bus object path of sensor.
777 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500778 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000779inline InventoryItem* findInventoryItemForSensor(
Ed Tanousb5a76932020-09-29 16:16:58 -0700780 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500781 const std::string& sensorObjPath)
782{
783 for (InventoryItem& inventoryItem : *inventoryItems)
784 {
Ed Tanousdb0d36e2023-06-30 10:37:05 -0700785 if (inventoryItem.sensors.contains(sensorObjPath))
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500786 {
787 return &inventoryItem;
788 }
789 }
790 return nullptr;
791}
792
793/**
Anthony Wilsond5005492019-07-31 16:34:17 -0500794 * @brief Finds the inventory item associated with the specified led path.
795 * @param inventoryItems D-Bus inventory items associated with sensors.
796 * @param ledObjPath D-Bus object path of led.
797 * @return Inventory item within vector, or nullptr if no match found.
798 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400799inline InventoryItem* findInventoryItemForLed(
800 std::vector<InventoryItem>& inventoryItems, const std::string& ledObjPath)
Anthony Wilsond5005492019-07-31 16:34:17 -0500801{
802 for (InventoryItem& inventoryItem : inventoryItems)
803 {
804 if (inventoryItem.ledObjectPath == ledObjPath)
805 {
806 return &inventoryItem;
807 }
808 }
809 return nullptr;
810}
811
812/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500813 * @brief Adds inventory item and associated sensor to specified vector.
814 *
815 * Adds a new InventoryItem to the vector if necessary. Searches for an
816 * existing InventoryItem with the specified object path. If not found, one is
817 * added to the vector.
818 *
819 * Next, the specified sensor is added to the set of sensors associated with the
820 * InventoryItem.
821 *
822 * @param inventoryItems D-Bus inventory items associated with sensors.
823 * @param invItemObjPath D-Bus object path of inventory item.
824 * @param sensorObjPath D-Bus object path of sensor
825 */
Ed Tanousb5a76932020-09-29 16:16:58 -0700826inline void addInventoryItem(
827 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
828 const std::string& invItemObjPath, const std::string& sensorObjPath)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500829{
830 // Look for inventory item in vector
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400831 InventoryItem* inventoryItem =
832 findInventoryItem(inventoryItems, invItemObjPath);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500833
834 // If inventory item doesn't exist in vector, add it
835 if (inventoryItem == nullptr)
836 {
837 inventoryItems->emplace_back(invItemObjPath);
838 inventoryItem = &(inventoryItems->back());
839 }
840
841 // Add sensor to set of sensors associated with inventory item
842 inventoryItem->sensors.emplace(sensorObjPath);
843}
844
845/**
846 * @brief Stores D-Bus data in the specified inventory item.
847 *
848 * Finds D-Bus data in the specified map of interfaces. Stores the data in the
849 * specified InventoryItem.
850 *
851 * This data is later used to provide sensor property values in the JSON
852 * response.
853 *
854 * @param inventoryItem Inventory item where data will be stored.
855 * @param interfacesDict Map containing D-Bus interfaces and their properties
856 * for the specified inventory item.
857 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000858inline void storeInventoryItemData(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500859 InventoryItem& inventoryItem,
Michael Shen80f79a42023-08-24 13:41:53 +0000860 const dbus::utility::DBusInterfacesMap& interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500861{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500862 // Get properties from Inventory.Item interface
Ed Tanous711ac7a2021-12-20 09:34:41 -0800863
Ed Tanous9eb808c2022-01-25 10:19:23 -0800864 for (const auto& [interface, values] : interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500865 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800866 if (interface == "xyz.openbmc_project.Inventory.Item")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500867 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800868 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500869 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800870 if (name == "Present")
871 {
872 const bool* value = std::get_if<bool>(&dbusValue);
873 if (value != nullptr)
874 {
875 inventoryItem.isPresent = *value;
876 }
877 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500878 }
879 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800880 // Check if Inventory.Item.PowerSupply interface is present
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500881
Ed Tanous711ac7a2021-12-20 09:34:41 -0800882 if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500883 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800884 inventoryItem.isPowerSupply = true;
885 }
886
887 // Get properties from Inventory.Decorator.Asset interface
888 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
889 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800890 for (const auto& [name, dbusValue] : values)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500891 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800892 if (name == "Manufacturer")
893 {
894 const std::string* value =
895 std::get_if<std::string>(&dbusValue);
896 if (value != nullptr)
897 {
898 inventoryItem.manufacturer = *value;
899 }
900 }
901 if (name == "Model")
902 {
903 const std::string* value =
904 std::get_if<std::string>(&dbusValue);
905 if (value != nullptr)
906 {
907 inventoryItem.model = *value;
908 }
909 }
910 if (name == "SerialNumber")
911 {
912 const std::string* value =
913 std::get_if<std::string>(&dbusValue);
914 if (value != nullptr)
915 {
916 inventoryItem.serialNumber = *value;
917 }
918 }
919 if (name == "PartNumber")
920 {
921 const std::string* value =
922 std::get_if<std::string>(&dbusValue);
923 if (value != nullptr)
924 {
925 inventoryItem.partNumber = *value;
926 }
927 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500928 }
929 }
930
Ed Tanous711ac7a2021-12-20 09:34:41 -0800931 if (interface ==
932 "xyz.openbmc_project.State.Decorator.OperationalStatus")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500933 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800934 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500935 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800936 if (name == "Functional")
937 {
938 const bool* value = std::get_if<bool>(&dbusValue);
939 if (value != nullptr)
940 {
941 inventoryItem.isFunctional = *value;
942 }
943 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500944 }
945 }
946 }
947}
948
949/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500950 * @brief Gets D-Bus data for inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500951 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500952 * Uses the specified connections (services) to obtain D-Bus data for inventory
953 * items associated with sensors. Stores the resulting data in the
954 * inventoryItems vector.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500955 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500956 * This data is later used to provide sensor property values in the JSON
957 * response.
958 *
959 * Finds the inventory item data asynchronously. Invokes callback when data has
960 * been obtained.
961 *
962 * The callback must have the following signature:
963 * @code
Anthony Wilsond5005492019-07-31 16:34:17 -0500964 * callback(void)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500965 * @endcode
966 *
967 * This function is called recursively, obtaining data asynchronously from one
968 * connection in each call. This ensures the callback is not invoked until the
969 * last asynchronous function has completed.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500970 *
971 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500972 * @param inventoryItems D-Bus inventory items associated with sensors.
973 * @param invConnections Connections that provide data for the inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500974 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500975 * @param callback Callback to invoke when inventory data has been obtained.
976 * @param invConnectionsIndex Current index in invConnections. Only specified
977 * in recursive calls to this function.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500978 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500979template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -0700980void getInventoryItemsData(
Ed Tanousdaadfb22024-12-20 09:25:54 -0800981 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
982 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
983 const std::shared_ptr<std::set<std::string>>& invConnections,
984 Callback&& callback, size_t invConnectionsIndex = 0)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500985{
Ed Tanous62598e32023-07-17 17:06:25 -0700986 BMCWEB_LOG_DEBUG("getInventoryItemsData enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500987
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500988 // If no more connections left, call callback
989 if (invConnectionsIndex >= invConnections->size())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500990 {
Anthony Wilsond5005492019-07-31 16:34:17 -0500991 callback();
Ed Tanous62598e32023-07-17 17:06:25 -0700992 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500993 return;
994 }
995
996 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +0000997 auto it = invConnections->begin();
998 std::advance(it, invConnectionsIndex);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500999 if (it != invConnections->end())
1000 {
1001 const std::string& invConnection = *it;
1002
George Liu5eb468d2023-06-20 17:03:24 +08001003 // Get all object paths and their interfaces for current connection
1004 sdbusplus::message::object_path path("/xyz/openbmc_project/inventory");
1005 dbus::utility::getManagedObjects(
1006 invConnection, path,
1007 [sensorsAsyncResp, inventoryItems, invConnections,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001008 callback = std::forward<Callback>(callback), invConnectionsIndex](
George Liu5eb468d2023-06-20 17:03:24 +08001009 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001010 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001011 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler enter");
1012 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001013 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001014 BMCWEB_LOG_ERROR(
1015 "getInventoryItemsData respHandler DBus error {}", ec);
1016 messages::internalError(sensorsAsyncResp->asyncResp->res);
1017 return;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001018 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001019
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001020 // Loop through returned object paths
1021 for (const auto& objDictEntry : resp)
1022 {
1023 const std::string& objPath =
1024 static_cast<const std::string&>(objDictEntry.first);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001025
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001026 // If this object path is one of the specified inventory
1027 // items
1028 InventoryItem* inventoryItem =
1029 findInventoryItem(inventoryItems, objPath);
1030 if (inventoryItem != nullptr)
1031 {
1032 // Store inventory data in InventoryItem
1033 storeInventoryItemData(*inventoryItem,
1034 objDictEntry.second);
1035 }
1036 }
1037
1038 // Recurse to get inventory item data from next connection
1039 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1040 invConnections, std::move(callback),
1041 invConnectionsIndex + 1);
1042
1043 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler exit");
1044 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001045 }
1046
Ed Tanous62598e32023-07-17 17:06:25 -07001047 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001048}
1049
1050/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001051 * @brief Gets connections that provide D-Bus data for inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001052 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001053 * Gets the D-Bus connections (services) that provide data for the inventory
1054 * items that are associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001055 *
1056 * Finds the connections asynchronously. Invokes callback when information has
1057 * been obtained.
1058 *
1059 * The callback must have the following signature:
1060 * @code
Nan Zhoufe04d492022-06-22 17:10:41 +00001061 * callback(std::shared_ptr<std::set<std::string>> invConnections)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001062 * @endcode
1063 *
1064 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001065 * @param inventoryItems D-Bus inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001066 * @param callback Callback to invoke when connections have been obtained.
1067 */
1068template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001069void getInventoryItemsConnections(
Ed Tanousb5a76932020-09-29 16:16:58 -07001070 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1071 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001072 Callback&& callback)
1073{
Ed Tanous62598e32023-07-17 17:06:25 -07001074 BMCWEB_LOG_DEBUG("getInventoryItemsConnections enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001075
1076 const std::string path = "/xyz/openbmc_project/inventory";
George Liue99073f2022-12-09 11:06:16 +08001077 constexpr std::array<std::string_view, 4> interfaces = {
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001078 "xyz.openbmc_project.Inventory.Item",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001079 "xyz.openbmc_project.Inventory.Item.PowerSupply",
1080 "xyz.openbmc_project.Inventory.Decorator.Asset",
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001081 "xyz.openbmc_project.State.Decorator.OperationalStatus"};
1082
George Liue99073f2022-12-09 11:06:16 +08001083 // Make call to ObjectMapper to find all inventory items
1084 dbus::utility::getSubTree(
1085 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001086 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001087 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001088 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001089 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001090 // Response handler for parsing output from GetSubTree
1091 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler enter");
1092 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001093 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001094 messages::internalError(sensorsAsyncResp->asyncResp->res);
1095 BMCWEB_LOG_ERROR(
1096 "getInventoryItemsConnections respHandler DBus error {}",
1097 ec);
1098 return;
1099 }
1100
1101 // Make unique list of connections for desired inventory items
1102 std::shared_ptr<std::set<std::string>> invConnections =
1103 std::make_shared<std::set<std::string>>();
1104
1105 // Loop through objects from GetSubTree
1106 for (const std::pair<std::string,
1107 std::vector<std::pair<
1108 std::string, std::vector<std::string>>>>&
1109 object : subtree)
1110 {
1111 // Check if object path is one of the specified inventory items
1112 const std::string& objPath = object.first;
1113 if (findInventoryItem(inventoryItems, objPath) != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001114 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001115 // Store all connections to inventory item
1116 for (const std::pair<std::string, std::vector<std::string>>&
1117 objData : object.second)
1118 {
1119 const std::string& invConnection = objData.first;
1120 invConnections->insert(invConnection);
1121 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001122 }
1123 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001124
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001125 callback(invConnections);
1126 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler exit");
1127 });
Ed Tanous62598e32023-07-17 17:06:25 -07001128 BMCWEB_LOG_DEBUG("getInventoryItemsConnections exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001129}
1130
1131/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001132 * @brief Gets associations from sensors to inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001133 *
1134 * Looks for ObjectMapper associations from the specified sensors to related
Anthony Wilsond5005492019-07-31 16:34:17 -05001135 * inventory items. Then finds the associations from those inventory items to
1136 * their LEDs, if any.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001137 *
1138 * Finds the inventory items asynchronously. Invokes callback when information
1139 * has been obtained.
1140 *
1141 * The callback must have the following signature:
1142 * @code
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001143 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001144 * @endcode
1145 *
1146 * @param sensorsAsyncResp Pointer to object holding response data.
1147 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001148 * implements ObjectManager.
1149 * @param callback Callback to invoke when inventory items have been obtained.
1150 */
1151template <typename Callback>
Ed Tanous4ff0f1f2024-09-04 17:27:37 -07001152void getInventoryItemAssociations(
Ed Tanousb5a76932020-09-29 16:16:58 -07001153 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001154 const std::shared_ptr<std::set<std::string>>& sensorNames,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001155 Callback&& callback)
1156{
Ed Tanous62598e32023-07-17 17:06:25 -07001157 BMCWEB_LOG_DEBUG("getInventoryItemAssociations enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001158
George Liu5eb468d2023-06-20 17:03:24 +08001159 // Call GetManagedObjects on the ObjectMapper to get all associations
1160 sdbusplus::message::object_path path("/");
1161 dbus::utility::getManagedObjects(
1162 "xyz.openbmc_project.ObjectMapper", path,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001163 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001164 sensorNames](const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001165 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001166 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler enter");
1167 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001168 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001169 BMCWEB_LOG_ERROR(
1170 "getInventoryItemAssociations respHandler DBus error {}",
1171 ec);
1172 messages::internalError(sensorsAsyncResp->asyncResp->res);
1173 return;
1174 }
1175
1176 // Create vector to hold list of inventory items
1177 std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1178 std::make_shared<std::vector<InventoryItem>>();
1179
1180 // Loop through returned object paths
1181 std::string sensorAssocPath;
1182 sensorAssocPath.reserve(128); // avoid memory allocations
1183 for (const auto& objDictEntry : resp)
1184 {
1185 const std::string& objPath =
1186 static_cast<const std::string&>(objDictEntry.first);
1187
1188 // If path is inventory association for one of the specified
1189 // sensors
1190 for (const std::string& sensorName : *sensorNames)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001191 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001192 sensorAssocPath = sensorName;
1193 sensorAssocPath += "/inventory";
1194 if (objPath == sensorAssocPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001195 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001196 // Get Association interface for object path
1197 for (const auto& [interface, values] :
1198 objDictEntry.second)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001199 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001200 if (interface == "xyz.openbmc_project.Association")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001201 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001202 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001203 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001204 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001205 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001206 const std::vector<std::string>*
1207 endpoints = std::get_if<
1208 std::vector<std::string>>(
1209 &value);
1210 if ((endpoints != nullptr) &&
1211 !endpoints->empty())
1212 {
1213 // Add inventory item to vector
1214 const std::string& invItemPath =
1215 endpoints->front();
1216 addInventoryItem(inventoryItems,
1217 invItemPath,
1218 sensorName);
1219 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001220 }
1221 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001222 }
1223 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001224 break;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001225 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001226 }
1227 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001228
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001229 // Now loop through the returned object paths again, this time to
1230 // find the leds associated with the inventory items we just found
1231 std::string inventoryAssocPath;
1232 inventoryAssocPath.reserve(128); // avoid memory allocations
1233 for (const auto& objDictEntry : resp)
Anthony Wilsond5005492019-07-31 16:34:17 -05001234 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001235 const std::string& objPath =
1236 static_cast<const std::string&>(objDictEntry.first);
1237
1238 for (InventoryItem& inventoryItem : *inventoryItems)
Anthony Wilsond5005492019-07-31 16:34:17 -05001239 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001240 inventoryAssocPath = inventoryItem.objectPath;
1241 inventoryAssocPath += "/leds";
1242 if (objPath == inventoryAssocPath)
Anthony Wilsond5005492019-07-31 16:34:17 -05001243 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001244 for (const auto& [interface, values] :
1245 objDictEntry.second)
Anthony Wilsond5005492019-07-31 16:34:17 -05001246 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001247 if (interface == "xyz.openbmc_project.Association")
Anthony Wilsond5005492019-07-31 16:34:17 -05001248 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001249 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001250 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001251 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001252 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001253 const std::vector<std::string>*
1254 endpoints = std::get_if<
1255 std::vector<std::string>>(
1256 &value);
1257 if ((endpoints != nullptr) &&
1258 !endpoints->empty())
1259 {
1260 // Add inventory item to vector
1261 // Store LED path in inventory item
1262 const std::string& ledPath =
1263 endpoints->front();
1264 inventoryItem.ledObjectPath =
1265 ledPath;
1266 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001267 }
1268 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001269 }
1270 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001271
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001272 break;
1273 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001274 }
1275 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001276 callback(inventoryItems);
1277 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler exit");
1278 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001279
Ed Tanous62598e32023-07-17 17:06:25 -07001280 BMCWEB_LOG_DEBUG("getInventoryItemAssociations exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001281}
1282
1283/**
Anthony Wilsond5005492019-07-31 16:34:17 -05001284 * @brief Gets D-Bus data for inventory item leds associated with sensors.
1285 *
1286 * Uses the specified connections (services) to obtain D-Bus data for inventory
1287 * item leds associated with sensors. Stores the resulting data in the
1288 * inventoryItems vector.
1289 *
1290 * This data is later used to provide sensor property values in the JSON
1291 * response.
1292 *
1293 * Finds the inventory item led data asynchronously. Invokes callback when data
1294 * has been obtained.
1295 *
1296 * The callback must have the following signature:
1297 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001298 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001299 * @endcode
1300 *
1301 * This function is called recursively, obtaining data asynchronously from one
1302 * connection in each call. This ensures the callback is not invoked until the
1303 * last asynchronous function has completed.
1304 *
1305 * @param sensorsAsyncResp Pointer to object holding response data.
1306 * @param inventoryItems D-Bus inventory items associated with sensors.
1307 * @param ledConnections Connections that provide data for the inventory leds.
1308 * @param callback Callback to invoke when inventory data has been obtained.
1309 * @param ledConnectionsIndex Current index in ledConnections. Only specified
1310 * in recursive calls to this function.
1311 */
1312template <typename Callback>
1313void getInventoryLedData(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001314 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1315 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1316 const std::shared_ptr<std::map<std::string, std::string>>& ledConnections,
Anthony Wilsond5005492019-07-31 16:34:17 -05001317 Callback&& callback, size_t ledConnectionsIndex = 0)
1318{
Ed Tanous62598e32023-07-17 17:06:25 -07001319 BMCWEB_LOG_DEBUG("getInventoryLedData enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001320
1321 // If no more connections left, call callback
1322 if (ledConnectionsIndex >= ledConnections->size())
1323 {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001324 callback();
Ed Tanous62598e32023-07-17 17:06:25 -07001325 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001326 return;
1327 }
1328
1329 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +00001330 auto it = ledConnections->begin();
1331 std::advance(it, ledConnectionsIndex);
Anthony Wilsond5005492019-07-31 16:34:17 -05001332 if (it != ledConnections->end())
1333 {
1334 const std::string& ledPath = (*it).first;
1335 const std::string& ledConnection = (*it).second;
1336 // Response handler for Get State property
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001337 auto respHandler =
1338 [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001339 callback = std::forward<Callback>(callback),
1340 ledConnectionsIndex](const boost::system::error_code& ec,
1341 const std::string& state) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001342 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler enter");
1343 if (ec)
1344 {
1345 BMCWEB_LOG_ERROR(
1346 "getInventoryLedData respHandler DBus error {}", ec);
1347 messages::internalError(sensorsAsyncResp->asyncResp->res);
1348 return;
1349 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001350
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001351 BMCWEB_LOG_DEBUG("Led state: {}", state);
1352 // Find inventory item with this LED object path
1353 InventoryItem* inventoryItem =
1354 findInventoryItemForLed(*inventoryItems, ledPath);
1355 if (inventoryItem != nullptr)
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001356 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001357 // Store LED state in InventoryItem
1358 if (state.ends_with("On"))
1359 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001360 inventoryItem->ledState = sensor_utils::LedState::ON;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001361 }
1362 else if (state.ends_with("Blink"))
1363 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001364 inventoryItem->ledState = sensor_utils::LedState::BLINK;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001365 }
1366 else if (state.ends_with("Off"))
1367 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001368 inventoryItem->ledState = sensor_utils::LedState::OFF;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001369 }
1370 else
1371 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001372 inventoryItem->ledState =
1373 sensor_utils::LedState::UNKNOWN;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001374 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001375 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001376
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001377 // Recurse to get LED data from next connection
1378 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1379 ledConnections, std::move(callback),
1380 ledConnectionsIndex + 1);
Anthony Wilsond5005492019-07-31 16:34:17 -05001381
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001382 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler exit");
1383 };
Anthony Wilsond5005492019-07-31 16:34:17 -05001384
1385 // Get the State property for the current LED
Ed Tanousdeae6a72024-11-11 21:58:57 -08001386 dbus::utility::getProperty<std::string>(
1387 ledConnection, ledPath, "xyz.openbmc_project.Led.Physical", "State",
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001388 std::move(respHandler));
Anthony Wilsond5005492019-07-31 16:34:17 -05001389 }
1390
Ed Tanous62598e32023-07-17 17:06:25 -07001391 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001392}
1393
1394/**
1395 * @brief Gets LED data for LEDs associated with given inventory items.
1396 *
1397 * Gets the D-Bus connections (services) that provide LED data for the LEDs
1398 * associated with the specified inventory items. Then gets the LED data from
1399 * each connection and stores it in the inventory item.
1400 *
1401 * This data is later used to provide sensor property values in the JSON
1402 * response.
1403 *
1404 * Finds the LED data asynchronously. Invokes callback when information has
1405 * been obtained.
1406 *
1407 * The callback must have the following signature:
1408 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001409 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001410 * @endcode
1411 *
1412 * @param sensorsAsyncResp Pointer to object holding response data.
1413 * @param inventoryItems D-Bus inventory items associated with sensors.
1414 * @param callback Callback to invoke when inventory items have been obtained.
1415 */
1416template <typename Callback>
1417void getInventoryLeds(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001418 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1419 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Anthony Wilsond5005492019-07-31 16:34:17 -05001420 Callback&& callback)
1421{
Ed Tanous62598e32023-07-17 17:06:25 -07001422 BMCWEB_LOG_DEBUG("getInventoryLeds enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001423
1424 const std::string path = "/xyz/openbmc_project";
George Liue99073f2022-12-09 11:06:16 +08001425 constexpr std::array<std::string_view, 1> interfaces = {
Anthony Wilsond5005492019-07-31 16:34:17 -05001426 "xyz.openbmc_project.Led.Physical"};
1427
George Liue99073f2022-12-09 11:06:16 +08001428 // Make call to ObjectMapper to find all inventory items
1429 dbus::utility::getSubTree(
1430 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001431 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001432 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001433 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001434 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001435 // Response handler for parsing output from GetSubTree
1436 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter");
1437 if (ec)
Anthony Wilsond5005492019-07-31 16:34:17 -05001438 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001439 messages::internalError(sensorsAsyncResp->asyncResp->res);
1440 BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}",
1441 ec);
1442 return;
Anthony Wilsond5005492019-07-31 16:34:17 -05001443 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001444
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001445 // Build map of LED object paths to connections
1446 std::shared_ptr<std::map<std::string, std::string>> ledConnections =
1447 std::make_shared<std::map<std::string, std::string>>();
1448
1449 // Loop through objects from GetSubTree
1450 for (const std::pair<std::string,
1451 std::vector<std::pair<
1452 std::string, std::vector<std::string>>>>&
1453 object : subtree)
1454 {
1455 // Check if object path is LED for one of the specified
1456 // inventory items
1457 const std::string& ledPath = object.first;
1458 if (findInventoryItemForLed(*inventoryItems, ledPath) !=
1459 nullptr)
1460 {
1461 // Add mapping from ledPath to connection
1462 const std::string& connection =
1463 object.second.begin()->first;
1464 (*ledConnections)[ledPath] = connection;
1465 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath,
1466 connection);
1467 }
1468 }
1469
1470 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1471 ledConnections, std::move(callback));
1472 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit");
1473 });
Ed Tanous62598e32023-07-17 17:06:25 -07001474 BMCWEB_LOG_DEBUG("getInventoryLeds exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001475}
1476
1477/**
Gunnar Mills42cbe532019-08-15 15:26:54 -05001478 * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
1479 *
1480 * Uses the specified connections (services) (currently assumes just one) to
1481 * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
1482 * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
1483 *
1484 * This data is later used to provide sensor property values in the JSON
1485 * response.
1486 *
1487 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1488 * when data has been obtained.
1489 *
1490 * The callback must have the following signature:
1491 * @code
1492 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1493 * @endcode
1494 *
1495 * @param sensorsAsyncResp Pointer to object holding response data.
1496 * @param inventoryItems D-Bus inventory items associated with sensors.
1497 * @param psAttributesConnections Connections that provide data for the Power
1498 * Supply Attributes
1499 * @param callback Callback to invoke when data has been obtained.
1500 */
1501template <typename Callback>
1502void getPowerSupplyAttributesData(
Ed Tanousb5a76932020-09-29 16:16:58 -07001503 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanousdaadfb22024-12-20 09:25:54 -08001504 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001505 const std::map<std::string, std::string>& psAttributesConnections,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001506 Callback&& callback)
1507{
Ed Tanous62598e32023-07-17 17:06:25 -07001508 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001509
1510 if (psAttributesConnections.empty())
1511 {
Ed Tanous62598e32023-07-17 17:06:25 -07001512 BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001513 callback(inventoryItems);
1514 return;
1515 }
1516
1517 // Assuming just one connection (service) for now
Nan Zhoufe04d492022-06-22 17:10:41 +00001518 auto it = psAttributesConnections.begin();
Gunnar Mills42cbe532019-08-15 15:26:54 -05001519
1520 const std::string& psAttributesPath = (*it).first;
1521 const std::string& psAttributesConnection = (*it).second;
1522
1523 // Response handler for Get DeratingFactor property
Patrick Williams5a39f772023-10-20 11:20:21 -05001524 auto respHandler = [sensorsAsyncResp, inventoryItems,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001525 callback = std::forward<Callback>(callback)](
Patrick Williams5a39f772023-10-20 11:20:21 -05001526 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001527 uint32_t value) mutable {
Ed Tanous62598e32023-07-17 17:06:25 -07001528 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001529 if (ec)
1530 {
Ed Tanous62598e32023-07-17 17:06:25 -07001531 BMCWEB_LOG_ERROR(
1532 "getPowerSupplyAttributesData respHandler DBus error {}", ec);
zhanghch058d1b46d2021-04-01 11:18:24 +08001533 messages::internalError(sensorsAsyncResp->asyncResp->res);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001534 return;
1535 }
1536
Ed Tanous62598e32023-07-17 17:06:25 -07001537 BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001538 // Store value in Power Supply Inventory Items
1539 for (InventoryItem& inventoryItem : *inventoryItems)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001540 {
Ed Tanous55f79e62022-01-25 11:26:16 -08001541 if (inventoryItem.isPowerSupply)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001542 {
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001543 inventoryItem.powerSupplyEfficiencyPercent =
1544 static_cast<int>(value);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001545 }
1546 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001547
Ed Tanous62598e32023-07-17 17:06:25 -07001548 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001549 callback(inventoryItems);
1550 };
1551
1552 // Get the DeratingFactor property for the PowerSupplyAttributes
1553 // Currently only property on the interface/only one we care about
Ed Tanousdeae6a72024-11-11 21:58:57 -08001554 dbus::utility::getProperty<uint32_t>(
1555 psAttributesConnection, psAttributesPath,
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001556 "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
1557 std::move(respHandler));
Gunnar Mills42cbe532019-08-15 15:26:54 -05001558
Ed Tanous62598e32023-07-17 17:06:25 -07001559 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001560}
1561
1562/**
1563 * @brief Gets the Power Supply Attributes such as EfficiencyPercent
1564 *
1565 * Gets the D-Bus connection (service) that provides Power Supply Attributes
1566 * data. Then gets the Power Supply Attributes data from the connection
1567 * (currently just assumes 1 connection) and stores the data in the inventory
1568 * item.
1569 *
1570 * This data is later used to provide sensor property values in the JSON
1571 * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
1572 *
1573 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1574 * when information has been obtained.
1575 *
1576 * The callback must have the following signature:
1577 * @code
1578 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1579 * @endcode
1580 *
1581 * @param sensorsAsyncResp Pointer to object holding response data.
1582 * @param inventoryItems D-Bus inventory items associated with sensors.
1583 * @param callback Callback to invoke when data has been obtained.
1584 */
1585template <typename Callback>
1586void getPowerSupplyAttributes(
Ed Tanousdaadfb22024-12-20 09:25:54 -08001587 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1588 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001589 Callback&& callback)
1590{
Ed Tanous62598e32023-07-17 17:06:25 -07001591 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001592
1593 // Only need the power supply attributes when the Power Schema
Janet Adkins0c728b42024-08-29 11:09:10 -05001594 if (sensorsAsyncResp->chassisSubNode != sensors::powerNodeStr)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001595 {
Ed Tanous62598e32023-07-17 17:06:25 -07001596 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001597 callback(inventoryItems);
1598 return;
1599 }
1600
George Liue99073f2022-12-09 11:06:16 +08001601 constexpr std::array<std::string_view, 1> interfaces = {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001602 "xyz.openbmc_project.Control.PowerSupplyAttributes"};
1603
George Liue99073f2022-12-09 11:06:16 +08001604 // Make call to ObjectMapper to find the PowerSupplyAttributes service
1605 dbus::utility::getSubTree(
1606 "/xyz/openbmc_project", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001607 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001608 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001609 const boost::system::error_code& ec,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001610 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001611 // Response handler for parsing output from GetSubTree
1612 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter");
1613 if (ec)
1614 {
1615 messages::internalError(sensorsAsyncResp->asyncResp->res);
1616 BMCWEB_LOG_ERROR(
1617 "getPowerSupplyAttributes respHandler DBus error {}", ec);
1618 return;
1619 }
1620 if (subtree.empty())
1621 {
1622 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
1623 callback(inventoryItems);
1624 return;
1625 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001626
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001627 // Currently we only support 1 power supply attribute, use this for
1628 // all the power supplies. Build map of object path to connection.
1629 // Assume just 1 connection and 1 path for now.
1630 std::map<std::string, std::string> psAttributesConnections;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001631
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001632 if (subtree[0].first.empty() || subtree[0].second.empty())
1633 {
1634 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1635 callback(inventoryItems);
1636 return;
1637 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001638
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001639 const std::string& psAttributesPath = subtree[0].first;
1640 const std::string& connection = subtree[0].second.begin()->first;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001641
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001642 if (connection.empty())
1643 {
1644 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1645 callback(inventoryItems);
1646 return;
1647 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001648
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001649 psAttributesConnections[psAttributesPath] = connection;
1650 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath,
1651 connection);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001652
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001653 getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
1654 psAttributesConnections,
1655 std::move(callback));
1656 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit");
1657 });
Ed Tanous62598e32023-07-17 17:06:25 -07001658 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001659}
1660
1661/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001662 * @brief Gets inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001663 *
1664 * Finds the inventory items that are associated with the specified sensors.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001665 * Then gets D-Bus data for the inventory items, such as presence and VPD.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001666 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001667 * This data is later used to provide sensor property values in the JSON
1668 * response.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001669 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001670 * Finds the inventory items asynchronously. Invokes callback when the
1671 * inventory items have been obtained.
1672 *
1673 * The callback must have the following signature:
1674 * @code
1675 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1676 * @endcode
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001677 *
1678 * @param sensorsAsyncResp Pointer to object holding response data.
1679 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001680 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001681 * @param callback Callback to invoke when inventory items have been obtained.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001682 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001683template <typename Callback>
Patrick Williams504af5a2025-02-03 14:29:03 -05001684inline void getInventoryItems(
1685 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1686 const std::shared_ptr<std::set<std::string>>& sensorNames,
1687 Callback&& callback)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001688{
Ed Tanous62598e32023-07-17 17:06:25 -07001689 BMCWEB_LOG_DEBUG("getInventoryItems enter");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001690 auto getInventoryItemAssociationsCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -07001691 [sensorsAsyncResp, callback = std::forward<Callback>(callback)](
Ed Tanousdaadfb22024-12-20 09:25:54 -08001692 const std::shared_ptr<std::vector<InventoryItem>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07001693 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001694 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter");
1695 auto getInventoryItemsConnectionsCb =
1696 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001697 callback = std::forward<Callback>(callback)](
Ed Tanousdaadfb22024-12-20 09:25:54 -08001698 const std::shared_ptr<std::set<std::string>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07001699 invConnections) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001700 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter");
1701 auto getInventoryItemsDataCb =
1702 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001703 callback =
1704 std::forward<Callback>(callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001705 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001706
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001707 auto getInventoryLedsCb =
1708 [sensorsAsyncResp, inventoryItems,
Ed Tanous4e0d8782024-09-06 15:16:41 -07001709 callback = std::forward<Callback>(
1710 callback)]() mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001711 BMCWEB_LOG_DEBUG(
1712 "getInventoryLedsCb enter");
1713 // Find Power Supply Attributes and get the
1714 // data
1715 getPowerSupplyAttributes(
1716 sensorsAsyncResp, inventoryItems,
1717 std::move(callback));
1718 BMCWEB_LOG_DEBUG("getInventoryLedsCb exit");
1719 };
1720
1721 // Find led connections and get the data
1722 getInventoryLeds(sensorsAsyncResp, inventoryItems,
1723 std::move(getInventoryLedsCb));
1724 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit");
1725 };
1726
1727 // Get inventory item data from connections
1728 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1729 invConnections,
1730 std::move(getInventoryItemsDataCb));
1731 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001732 };
1733
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001734 // Get connections that provide inventory item data
1735 getInventoryItemsConnections(
1736 sensorsAsyncResp, inventoryItems,
1737 std::move(getInventoryItemsConnectionsCb));
1738 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001739 };
1740
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001741 // Get associations from sensors to inventory items
Ed Tanousd0090732022-10-04 17:22:56 -07001742 getInventoryItemAssociations(sensorsAsyncResp, sensorNames,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001743 std::move(getInventoryItemAssociationsCb));
Ed Tanous62598e32023-07-17 17:06:25 -07001744 BMCWEB_LOG_DEBUG("getInventoryItems exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001745}
1746
1747/**
1748 * @brief Returns JSON PowerSupply object for the specified inventory item.
1749 *
1750 * Searches for a JSON PowerSupply object that matches the specified inventory
1751 * item. If one is not found, a new PowerSupply object is added to the JSON
1752 * array.
1753 *
1754 * Multiple sensors are often associated with one power supply inventory item.
1755 * As a result, multiple sensor values are stored in one JSON PowerSupply
1756 * object.
1757 *
1758 * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1759 * @param inventoryItem Inventory item for the power supply.
1760 * @param chassisId Chassis that contains the power supply.
1761 * @return JSON PowerSupply object for the specified inventory item.
1762 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001763inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001764 const InventoryItem& inventoryItem,
1765 const std::string& chassisId)
1766{
Ed Tanous18f8f602023-07-18 10:07:23 -07001767 std::string nameS;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001768 nameS.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001769 std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' ');
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001770 // Check if matching PowerSupply object already exists in JSON array
1771 for (nlohmann::json& powerSupply : powerSupplyArray)
1772 {
Ed Tanous18f8f602023-07-18 10:07:23 -07001773 nlohmann::json::iterator nameIt = powerSupply.find("Name");
1774 if (nameIt == powerSupply.end())
1775 {
1776 continue;
1777 }
1778 const std::string* name = nameIt->get_ptr<std::string*>();
1779 if (name == nullptr)
1780 {
1781 continue;
1782 }
1783 if (nameS == *name)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001784 {
1785 return powerSupply;
1786 }
1787 }
1788
1789 // Add new PowerSupply object to JSON array
1790 powerSupplyArray.push_back({});
1791 nlohmann::json& powerSupply = powerSupplyArray.back();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001792 boost::urls::url url =
1793 boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
Willy Tueddfc432022-09-26 16:46:38 +00001794 url.set_fragment(("/PowerSupplies"_json_pointer).to_string());
1795 powerSupply["@odata.id"] = std::move(url);
Ed Tanous18f8f602023-07-18 10:07:23 -07001796 std::string escaped;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001797 escaped.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001798 std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' ');
1799 powerSupply["Name"] = std::move(escaped);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001800 powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1801 powerSupply["Model"] = inventoryItem.model;
1802 powerSupply["PartNumber"] = inventoryItem.partNumber;
1803 powerSupply["SerialNumber"] = inventoryItem.serialNumber;
Janet Adkinsc9563602024-08-28 11:37:46 -05001804 sensor_utils::setLedState(powerSupply, &inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001805
Gunnar Mills42cbe532019-08-15 15:26:54 -05001806 if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
1807 {
1808 powerSupply["EfficiencyPercent"] =
1809 inventoryItem.powerSupplyEfficiencyPercent;
1810 }
1811
Janet Adkinsc9563602024-08-28 11:37:46 -05001812 powerSupply["Status"]["State"] =
1813 sensor_utils::getState(&inventoryItem, true);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001814 const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1815 powerSupply["Status"]["Health"] = health;
1816
1817 return powerSupply;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001818}
1819
1820/**
Shawn McCarneyde629b62019-03-08 10:42:51 -06001821 * @brief Gets the values of the specified sensors.
1822 *
1823 * Stores the results as JSON in the SensorsAsyncResp.
1824 *
1825 * Gets the sensor values asynchronously. Stores the results later when the
1826 * information has been obtained.
1827 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001828 * The sensorNames set contains all requested sensors for the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001829 *
1830 * To minimize the number of DBus calls, the DBus method
1831 * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1832 * values of all sensors provided by a connection (service).
1833 *
1834 * The connections set contains all the connections that provide sensor values.
1835 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001836 * The InventoryItem vector contains D-Bus inventory items associated with the
1837 * sensors. Inventory item data is needed for some Redfish sensor properties.
1838 *
Shawn McCarneyde629b62019-03-08 10:42:51 -06001839 * @param SensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001840 * @param sensorNames All requested sensors within the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001841 * @param connections Connections that provide sensor values.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001842 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001843 * @param inventoryItems Inventory items associated with the sensors.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001844 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001845inline void getSensorData(
Ed Tanous81ce6092020-12-17 16:54:55 +00001846 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001847 const std::shared_ptr<std::set<std::string>>& sensorNames,
1848 const std::set<std::string>& connections,
Ed Tanousb5a76932020-09-29 16:16:58 -07001849 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001850{
Ed Tanous62598e32023-07-17 17:06:25 -07001851 BMCWEB_LOG_DEBUG("getSensorData enter");
Shawn McCarneyde629b62019-03-08 10:42:51 -06001852 // Get managed objects from all services exposing sensors
1853 for (const std::string& connection : connections)
1854 {
George Liu5eb468d2023-06-20 17:03:24 +08001855 sdbusplus::message::object_path sensorPath(
1856 "/xyz/openbmc_project/sensors");
1857 dbus::utility::getManagedObjects(
1858 connection, sensorPath,
Ed Tanous002d39b2022-05-31 08:59:27 -07001859 [sensorsAsyncResp, sensorNames,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001860 inventoryItems](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -07001861 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001862 BMCWEB_LOG_DEBUG("getManagedObjectsCb enter");
1863 if (ec)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001864 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001865 BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec);
1866 messages::internalError(sensorsAsyncResp->asyncResp->res);
1867 return;
1868 }
Janet Adkins0c728b42024-08-29 11:09:10 -05001869 auto chassisSubNode = sensor_utils::chassisSubNodeFromString(
1870 sensorsAsyncResp->chassisSubNode);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001871 // Go through all objects and update response with sensor data
1872 for (const auto& objDictEntry : resp)
1873 {
1874 const std::string& objPath =
1875 static_cast<const std::string&>(objDictEntry.first);
1876 BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}",
Ed Tanous62598e32023-07-17 17:06:25 -07001877 objPath);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001878
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001879 std::vector<std::string> split;
1880 // Reserve space for
1881 // /xyz/openbmc_project/sensors/<name>/<subname>
1882 split.reserve(6);
1883 // NOLINTNEXTLINE
1884 bmcweb::split(split, objPath, '/');
1885 if (split.size() < 6)
Nan Zhou928fefb2022-03-28 08:45:00 -07001886 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001887 BMCWEB_LOG_ERROR("Got path that isn't long enough {}",
1888 objPath);
1889 continue;
Nan Zhou928fefb2022-03-28 08:45:00 -07001890 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001891 // These indexes aren't intuitive, as split puts an empty
1892 // string at the beginning
1893 const std::string& sensorType = split[4];
1894 const std::string& sensorName = split[5];
1895 BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName,
1896 sensorType);
1897 if (sensorNames->find(objPath) == sensorNames->end())
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001898 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001899 BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName);
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001900 continue;
1901 }
1902
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001903 // Find inventory item (if any) associated with sensor
1904 InventoryItem* inventoryItem =
1905 findInventoryItemForSensor(inventoryItems, objPath);
1906
1907 const std::string& sensorSchema =
1908 sensorsAsyncResp->chassisSubNode;
1909
1910 nlohmann::json* sensorJson = nullptr;
1911
Janet Adkins0c728b42024-08-29 11:09:10 -05001912 if (sensorSchema == sensors::sensorsNodeStr &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001913 !sensorsAsyncResp->efficientExpand)
Nan Zhou928fefb2022-03-28 08:45:00 -07001914 {
Janet Adkins1516c212024-08-14 13:22:41 -05001915 std::string sensorId =
1916 redfish::sensor_utils::getSensorId(sensorName,
1917 sensorType);
Ed Tanous677bb752022-09-15 10:52:19 -07001918
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001919 sensorsAsyncResp->asyncResp->res
1920 .jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001921 "/redfish/v1/Chassis/{}/{}/{}",
Ed Tanous677bb752022-09-15 10:52:19 -07001922 sensorsAsyncResp->chassisId,
1923 sensorsAsyncResp->chassisSubNode, sensorId);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001924 sensorJson =
1925 &(sensorsAsyncResp->asyncResp->res.jsonValue);
Nan Zhou928fefb2022-03-28 08:45:00 -07001926 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001927 else
1928 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001929 std::string fieldName;
1930 if (sensorsAsyncResp->efficientExpand)
1931 {
1932 fieldName = "Members";
1933 }
1934 else if (sensorType == "temperature")
1935 {
1936 fieldName = "Temperatures";
1937 }
1938 else if (sensorType == "fan" ||
1939 sensorType == "fan_tach" ||
1940 sensorType == "fan_pwm")
1941 {
1942 fieldName = "Fans";
1943 }
1944 else if (sensorType == "voltage")
1945 {
1946 fieldName = "Voltages";
1947 }
1948 else if (sensorType == "power")
1949 {
1950 if (sensorName == "total_power")
1951 {
1952 fieldName = "PowerControl";
1953 }
1954 else if ((inventoryItem != nullptr) &&
1955 (inventoryItem->isPowerSupply))
1956 {
1957 fieldName = "PowerSupplies";
1958 }
1959 else
1960 {
1961 // Other power sensors are in SensorCollection
1962 continue;
1963 }
1964 }
1965 else
1966 {
1967 BMCWEB_LOG_ERROR(
1968 "Unsure how to handle sensorType {}",
1969 sensorType);
1970 continue;
1971 }
1972
1973 nlohmann::json& tempArray =
1974 sensorsAsyncResp->asyncResp->res
1975 .jsonValue[fieldName];
1976 if (fieldName == "PowerControl")
1977 {
1978 if (tempArray.empty())
1979 {
1980 // Put multiple "sensors" into a single
1981 // PowerControl. Follows MemberId naming and
1982 // naming in power.hpp.
1983 nlohmann::json::object_t power;
1984 boost::urls::url url = boost::urls::format(
1985 "/redfish/v1/Chassis/{}/{}",
1986 sensorsAsyncResp->chassisId,
1987 sensorsAsyncResp->chassisSubNode);
1988 url.set_fragment(
1989 (""_json_pointer / fieldName / "0")
1990 .to_string());
1991 power["@odata.id"] = std::move(url);
1992 tempArray.emplace_back(std::move(power));
1993 }
1994 sensorJson = &(tempArray.back());
1995 }
1996 else if (fieldName == "PowerSupplies")
1997 {
1998 if (inventoryItem != nullptr)
1999 {
2000 sensorJson = &(getPowerSupply(
2001 tempArray, *inventoryItem,
2002 sensorsAsyncResp->chassisId));
2003 }
2004 }
2005 else if (fieldName == "Members")
2006 {
Janet Adkins1516c212024-08-14 13:22:41 -05002007 std::string sensorId =
2008 redfish::sensor_utils::getSensorId(sensorName,
2009 sensorType);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002010
2011 nlohmann::json::object_t member;
2012 member["@odata.id"] = boost::urls::format(
2013 "/redfish/v1/Chassis/{}/{}/{}",
2014 sensorsAsyncResp->chassisId,
2015 sensorsAsyncResp->chassisSubNode, sensorId);
2016 tempArray.emplace_back(std::move(member));
2017 sensorJson = &(tempArray.back());
2018 }
2019 else
2020 {
2021 nlohmann::json::object_t member;
2022 boost::urls::url url = boost::urls::format(
2023 "/redfish/v1/Chassis/{}/{}",
2024 sensorsAsyncResp->chassisId,
2025 sensorsAsyncResp->chassisSubNode);
2026 url.set_fragment(
2027 (""_json_pointer / fieldName).to_string());
2028 member["@odata.id"] = std::move(url);
2029 tempArray.emplace_back(std::move(member));
2030 sensorJson = &(tempArray.back());
2031 }
2032 }
2033
2034 if (sensorJson != nullptr)
2035 {
Janet Adkins0c728b42024-08-29 11:09:10 -05002036 objectInterfacesToJson(
2037 sensorName, sensorType, chassisSubNode,
2038 objDictEntry.second, *sensorJson, inventoryItem);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002039
2040 std::string path = "/xyz/openbmc_project/sensors/";
2041 path += sensorType;
2042 path += "/";
2043 path += sensorName;
2044 sensorsAsyncResp->addMetadata(*sensorJson, path);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002045 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002046 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002047 if (sensorsAsyncResp.use_count() == 1)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002048 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002049 sortJSONResponse(sensorsAsyncResp);
Janet Adkins0c728b42024-08-29 11:09:10 -05002050 if (chassisSubNode ==
2051 sensor_utils::ChassisSubNode::sensorsNode &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002052 sensorsAsyncResp->efficientExpand)
2053 {
2054 sensorsAsyncResp->asyncResp->res
2055 .jsonValue["Members@odata.count"] =
2056 sensorsAsyncResp->asyncResp->res
2057 .jsonValue["Members"]
2058 .size();
2059 }
Janet Adkins0c728b42024-08-29 11:09:10 -05002060 else if (chassisSubNode ==
2061 sensor_utils::ChassisSubNode::thermalNode)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002062 {
2063 populateFanRedundancy(sensorsAsyncResp);
2064 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002065 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002066 BMCWEB_LOG_DEBUG("getManagedObjectsCb exit");
2067 });
Ed Tanous23a21a12020-07-25 04:45:05 +00002068 }
Ed Tanous62598e32023-07-17 17:06:25 -07002069 BMCWEB_LOG_DEBUG("getSensorData exit");
Shawn McCarneyde629b62019-03-08 10:42:51 -06002070}
2071
Patrick Williams504af5a2025-02-03 14:29:03 -05002072inline void processSensorList(
2073 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
2074 const std::shared_ptr<std::set<std::string>>& sensorNames)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002075{
Nan Zhoufe04d492022-06-22 17:10:41 +00002076 auto getConnectionCb = [sensorsAsyncResp, sensorNames](
2077 const std::set<std::string>& connections) {
Ed Tanous62598e32023-07-17 17:06:25 -07002078 BMCWEB_LOG_DEBUG("getConnectionCb enter");
Ed Tanousd0090732022-10-04 17:22:56 -07002079 auto getInventoryItemsCb =
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002080 [sensorsAsyncResp, sensorNames, connections](
2081 const std::shared_ptr<std::vector<InventoryItem>>&
Ed Tanous4e0d8782024-09-06 15:16:41 -07002082 inventoryItems) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002083 BMCWEB_LOG_DEBUG("getInventoryItemsCb enter");
2084 // Get sensor data and store results in JSON
2085 getSensorData(sensorsAsyncResp, sensorNames, connections,
2086 inventoryItems);
2087 BMCWEB_LOG_DEBUG("getInventoryItemsCb exit");
2088 };
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002089
Ed Tanousd0090732022-10-04 17:22:56 -07002090 // Get inventory items associated with sensors
2091 getInventoryItems(sensorsAsyncResp, sensorNames,
2092 std::move(getInventoryItemsCb));
2093
Ed Tanous62598e32023-07-17 17:06:25 -07002094 BMCWEB_LOG_DEBUG("getConnectionCb exit");
Ed Tanous002d39b2022-05-31 08:59:27 -07002095 };
2096
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002097 // Get set of connections that provide sensor values
Ed Tanous81ce6092020-12-17 16:54:55 +00002098 getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002099}
2100
Shawn McCarneyde629b62019-03-08 10:42:51 -06002101/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002102 * @brief Entry point for retrieving sensors data related to requested
2103 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02002104 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002105 */
Patrick Williams504af5a2025-02-03 14:29:03 -05002106inline void getChassisData(
2107 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002108{
Ed Tanous62598e32023-07-17 17:06:25 -07002109 BMCWEB_LOG_DEBUG("getChassisData enter");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002110 auto getChassisCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002111 [sensorsAsyncResp](
Nan Zhoufe04d492022-06-22 17:10:41 +00002112 const std::shared_ptr<std::set<std::string>>& sensorNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002113 BMCWEB_LOG_DEBUG("getChassisCb enter");
2114 processSensorList(sensorsAsyncResp, sensorNames);
2115 BMCWEB_LOG_DEBUG("getChassisCb exit");
2116 };
Nan Zhou928fefb2022-03-28 08:45:00 -07002117 // SensorCollection doesn't contain the Redundancy property
Janet Adkins0c728b42024-08-29 11:09:10 -05002118 if (sensorsAsyncResp->chassisSubNode != sensors::sensorsNodeStr)
Nan Zhou928fefb2022-03-28 08:45:00 -07002119 {
2120 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
2121 nlohmann::json::array();
2122 }
Shawn McCarney26f03892019-05-03 13:20:24 -05002123 // Get set of sensors in chassis
Ed Tanous7f1cc262022-08-09 13:33:57 -07002124 getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId,
2125 sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types,
2126 std::move(getChassisCb));
Ed Tanous62598e32023-07-17 17:06:25 -07002127 BMCWEB_LOG_DEBUG("getChassisData exit");
Ed Tanous271584a2019-07-09 16:24:22 -07002128}
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002129
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302130/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002131 * @brief Find the requested sensorName in the list of all sensors supplied by
2132 * the chassis node
2133 *
2134 * @param sensorName The sensor name supplied in the PATCH request
2135 * @param sensorsList The list of sensors managed by the chassis node
2136 * @param sensorsModified The list of sensors that were found as a result of
2137 * repeated calls to this function
2138 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002139inline bool findSensorNameUsingSensorPath(
2140 std::string_view sensorName, const std::set<std::string>& sensorsList,
2141 std::set<std::string>& sensorsModified)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002142{
Nan Zhoufe04d492022-06-22 17:10:41 +00002143 for (const auto& chassisSensor : sensorsList)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002144 {
George Liu28aa8de2021-02-01 15:13:30 +08002145 sdbusplus::message::object_path path(chassisSensor);
Ed Tanousb00dcc22021-02-23 12:52:50 -08002146 std::string thisSensorName = path.filename();
George Liu28aa8de2021-02-01 15:13:30 +08002147 if (thisSensorName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002148 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002149 continue;
2150 }
2151 if (thisSensorName == sensorName)
2152 {
2153 sensorsModified.emplace(chassisSensor);
2154 return true;
2155 }
2156 }
2157 return false;
2158}
2159
2160/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302161 * @brief Entry point for overriding sensor values of given sensor
2162 *
zhanghch058d1b46d2021-04-01 11:18:24 +08002163 * @param sensorAsyncResp response object
Carol Wang4bb3dc32019-10-17 18:15:02 +08002164 * @param allCollections Collections extract from sensors' request patch info
jayaprakash Mutyala91e130a2020-03-04 22:26:38 +00002165 * @param chassisSubNode Chassis Node for which the query has to happen
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302166 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002167inline void setSensorsOverride(
Ed Tanousb5a76932020-09-29 16:16:58 -07002168 const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
Ed Tanous08850572024-03-06 15:09:17 -08002169 std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>&
jayaprakash Mutyala397fd612020-02-06 23:33:34 +00002170 allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302171{
Ed Tanous62598e32023-07-17 17:06:25 -07002172 BMCWEB_LOG_INFO("setSensorsOverride for subNode{}",
2173 sensorAsyncResp->chassisSubNode);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302174
Ed Tanousd02aad32024-02-13 14:43:34 -08002175 std::string_view propertyValueName;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302176 std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302177 std::string memberId;
Ed Tanous543f4402022-01-06 13:12:53 -08002178 double value = 0.0;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302179 for (auto& collectionItems : allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302180 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302181 if (collectionItems.first == "Temperatures")
2182 {
2183 propertyValueName = "ReadingCelsius";
2184 }
2185 else if (collectionItems.first == "Fans")
2186 {
2187 propertyValueName = "Reading";
2188 }
2189 else
2190 {
2191 propertyValueName = "ReadingVolts";
2192 }
2193 for (auto& item : collectionItems.second)
2194 {
Patrick Williams504af5a2025-02-03 14:29:03 -05002195 if (!json_util::readJsonObject( //
Myung Baeafc474a2024-10-09 00:53:29 -07002196 item, sensorAsyncResp->asyncResp->res, //
Patrick Williams504af5a2025-02-03 14:29:03 -05002197 "MemberId", memberId, //
2198 propertyValueName, value //
Myung Baeafc474a2024-10-09 00:53:29 -07002199 ))
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302200 {
2201 return;
2202 }
2203 overrideMap.emplace(memberId,
2204 std::make_pair(value, collectionItems.first));
2205 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302206 }
Carol Wang4bb3dc32019-10-17 18:15:02 +08002207
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002208 auto getChassisSensorListCb = [sensorAsyncResp, overrideMap,
2209 propertyValueNameStr =
2210 std::string(propertyValueName)](
2211 const std::shared_ptr<
2212 std::set<std::string>>& sensorsList) {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002213 // Match sensor names in the PATCH request to those managed by the
2214 // chassis node
Nan Zhoufe04d492022-06-22 17:10:41 +00002215 const std::shared_ptr<std::set<std::string>> sensorNames =
2216 std::make_shared<std::set<std::string>>();
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302217 for (const auto& item : overrideMap)
2218 {
2219 const auto& sensor = item.first;
Ed Tanousc71d6122022-11-29 14:10:32 -08002220 std::pair<std::string, std::string> sensorNameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002221 redfish::sensor_utils::splitSensorNameAndType(sensor);
Ed Tanousc71d6122022-11-29 14:10:32 -08002222 if (!findSensorNameUsingSensorPath(sensorNameType.second,
2223 *sensorsList, *sensorNames))
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302224 {
Ed Tanous62598e32023-07-17 17:06:25 -07002225 BMCWEB_LOG_INFO("Unable to find memberId {}", item.first);
zhanghch058d1b46d2021-04-01 11:18:24 +08002226 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302227 item.second.second, item.first);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302228 return;
2229 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302230 }
2231 // Get the connection to which the memberId belongs
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002232 auto getObjectsWithConnectionCb = [sensorAsyncResp, overrideMap,
2233 propertyValueNameStr](
2234 const std::set<
2235 std::string>& /*connections*/,
2236 const std::set<std::pair<
2237 std::string, std::string>>&
2238 objectsWithConnection) {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002239 if (objectsWithConnection.size() != overrideMap.size())
2240 {
Ed Tanous62598e32023-07-17 17:06:25 -07002241 BMCWEB_LOG_INFO(
2242 "Unable to find all objects with proper connection {} requested {}",
2243 objectsWithConnection.size(), overrideMap.size());
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002244 messages::resourceNotFound(
2245 sensorAsyncResp->asyncResp->res,
Janet Adkins0c728b42024-08-29 11:09:10 -05002246 sensorAsyncResp->chassisSubNode == sensors::thermalNodeStr
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002247 ? "Temperatures"
2248 : "Voltages",
2249 "Count");
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002250 return;
2251 }
2252 for (const auto& item : objectsWithConnection)
2253 {
2254 sdbusplus::message::object_path path(item.first);
2255 std::string sensorName = path.filename();
2256 if (sensorName.empty())
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302257 {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002258 messages::internalError(sensorAsyncResp->asyncResp->res);
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302259 return;
2260 }
Janet Adkins1516c212024-08-14 13:22:41 -05002261 std::string id = redfish::sensor_utils::getSensorId(
2262 sensorName, path.parent_path().filename());
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302263
Ban Feng3f5eb752023-06-29 09:19:20 +08002264 const auto& iterator = overrideMap.find(id);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002265 if (iterator == overrideMap.end())
2266 {
Ed Tanous62598e32023-07-17 17:06:25 -07002267 BMCWEB_LOG_INFO("Unable to find sensor object{}",
2268 item.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002269 messages::internalError(sensorAsyncResp->asyncResp->res);
2270 return;
2271 }
Ginu Georgee93abac2024-06-14 17:35:27 +05302272 setDbusProperty(sensorAsyncResp->asyncResp,
2273 propertyValueNameStr, item.second, item.first,
2274 "xyz.openbmc_project.Sensor.Value", "Value",
Ed Tanousd02aad32024-02-13 14:43:34 -08002275 iterator->second.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002276 }
2277 };
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302278 // Get object with connection for the given sensor name
2279 getObjectsWithConnection(sensorAsyncResp, sensorNames,
2280 std::move(getObjectsWithConnectionCb));
2281 };
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302282 // get full sensor list for the given chassisId and cross verify the sensor.
Ed Tanous7f1cc262022-08-09 13:33:57 -07002283 getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
2284 sensorAsyncResp->chassisSubNode, sensorAsyncResp->types,
2285 std::move(getChassisSensorListCb));
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302286}
2287
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002288/**
2289 * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2290 * path of the sensor.
2291 *
2292 * Function builds valid Redfish response for sensor query of given chassis and
2293 * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2294 * it to caller in a callback.
2295 *
2296 * @param chassis Chassis for which retrieval should be performed
Janet Adkinsc9563602024-08-28 11:37:46 -05002297 * @param node Node (group) of sensors. See sensor_utils::node for supported
2298 * values
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002299 * @param mapComplete Callback to be called with retrieval result
2300 */
Ed Tanous931edc72023-11-01 12:09:07 -07002301template <typename Callback>
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002302inline void retrieveUriToDbusMap(
2303 const std::string& chassis, const std::string& node, Callback&& mapComplete)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002304{
Ed Tanous02da7c52022-02-27 00:09:02 -08002305 decltype(sensors::paths)::const_iterator pathIt =
2306 std::find_if(sensors::paths.cbegin(), sensors::paths.cend(),
2307 [&node](auto&& val) { return val.first == node; });
2308 if (pathIt == sensors::paths.cend())
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002309 {
Ed Tanous62598e32023-07-17 17:06:25 -07002310 BMCWEB_LOG_ERROR("Wrong node provided : {}", node);
Ed Tanous6804b5c2023-10-31 14:50:03 -07002311 std::map<std::string, std::string> noop;
2312 mapComplete(boost::beast::http::status::bad_request, noop);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002313 return;
2314 }
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002315
Nan Zhou72374eb2022-01-27 17:06:51 -08002316 auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002317 auto callback =
2318 [asyncResp, mapCompleteCb = std::forward<Callback>(mapComplete)](
2319 const boost::beast::http::status status,
2320 const std::map<std::string, std::string>& uriToDbus) {
2321 mapCompleteCb(status, uriToDbus);
2322 };
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002323
2324 auto resp = std::make_shared<SensorsAsyncResp>(
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002325 asyncResp, chassis, pathIt->second, node, std::move(callback));
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002326 getChassisData(resp);
2327}
2328
Nan Zhoubacb2162022-04-06 11:28:32 -07002329namespace sensors
2330{
Nan Zhou928fefb2022-03-28 08:45:00 -07002331
Nan Zhoubacb2162022-04-06 11:28:32 -07002332inline void getChassisCallback(
Ed Tanousc1d019a2022-08-06 09:36:06 -07002333 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2334 std::string_view chassisId, std::string_view chassisSubNode,
Nan Zhoufe04d492022-06-22 17:10:41 +00002335 const std::shared_ptr<std::set<std::string>>& sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002336{
Ed Tanous62598e32023-07-17 17:06:25 -07002337 BMCWEB_LOG_DEBUG("getChassisCallback enter ");
Nan Zhoubacb2162022-04-06 11:28:32 -07002338
Ed Tanousc1d019a2022-08-06 09:36:06 -07002339 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
2340 for (const std::string& sensor : *sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002341 {
Ed Tanous62598e32023-07-17 17:06:25 -07002342 BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor);
Nan Zhoubacb2162022-04-06 11:28:32 -07002343
2344 sdbusplus::message::object_path path(sensor);
2345 std::string sensorName = path.filename();
2346 if (sensorName.empty())
2347 {
Ed Tanous62598e32023-07-17 17:06:25 -07002348 BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002349 messages::internalError(asyncResp->res);
Nan Zhoubacb2162022-04-06 11:28:32 -07002350 return;
2351 }
Ed Tanousc1d019a2022-08-06 09:36:06 -07002352 std::string type = path.parent_path().filename();
Janet Adkins1516c212024-08-14 13:22:41 -05002353 std::string id = redfish::sensor_utils::getSensorId(sensorName, type);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002354
Ed Tanous14766872022-03-15 10:44:42 -07002355 nlohmann::json::object_t member;
Ed Tanousef4c65b2023-04-24 15:28:50 -07002356 member["@odata.id"] = boost::urls::format(
2357 "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002358
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002359 entriesArray.emplace_back(std::move(member));
Nan Zhoubacb2162022-04-06 11:28:32 -07002360 }
2361
Ed Tanousc1d019a2022-08-06 09:36:06 -07002362 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Ed Tanous62598e32023-07-17 17:06:25 -07002363 BMCWEB_LOG_DEBUG("getChassisCallback exit");
Nan Zhoubacb2162022-04-06 11:28:32 -07002364}
Nan Zhoue6bd8462022-06-01 04:35:35 +00002365
Ed Tanousac106bf2023-06-07 09:24:59 -07002366inline void handleSensorCollectionGet(
2367 App& app, const crow::Request& req,
2368 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2369 const std::string& chassisId)
Nan Zhoude167a62022-06-01 04:47:45 +00002370{
2371 query_param::QueryCapabilities capabilities = {
2372 .canDelegateExpandLevel = 1,
2373 };
2374 query_param::Query delegatedQuery;
Ed Tanousac106bf2023-06-07 09:24:59 -07002375 if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
Nan Zhoude167a62022-06-01 04:47:45 +00002376 delegatedQuery, capabilities))
2377 {
2378 return;
2379 }
2380
2381 if (delegatedQuery.expandType != query_param::ExpandType::None)
2382 {
2383 // we perform efficient expand.
Ed Tanousac106bf2023-06-07 09:24:59 -07002384 auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>(
2385 asyncResp, chassisId, sensors::dbus::sensorPaths,
Janet Adkins0c728b42024-08-29 11:09:10 -05002386 sensors::sensorsNodeStr,
Nan Zhoude167a62022-06-01 04:47:45 +00002387 /*efficientExpand=*/true);
Ed Tanousac106bf2023-06-07 09:24:59 -07002388 getChassisData(sensorsAsyncResp);
Nan Zhoude167a62022-06-01 04:47:45 +00002389
Ed Tanous62598e32023-07-17 17:06:25 -07002390 BMCWEB_LOG_DEBUG(
2391 "SensorCollection doGet exit via efficient expand handler");
Nan Zhoude167a62022-06-01 04:47:45 +00002392 return;
Ed Tanous0bad3202022-06-02 13:53:59 -07002393 }
Nan Zhoude167a62022-06-01 04:47:45 +00002394
Nan Zhoude167a62022-06-01 04:47:45 +00002395 // We get all sensors as hyperlinkes in the chassis (this
2396 // implies we reply on the default query parameters handler)
Janet Adkins0c728b42024-08-29 11:09:10 -05002397 getChassis(asyncResp, chassisId, sensors::sensorsNodeStr, dbus::sensorPaths,
Ed Tanousac106bf2023-06-07 09:24:59 -07002398 std::bind_front(sensors::getChassisCallback, asyncResp,
Janet Adkins0c728b42024-08-29 11:09:10 -05002399 chassisId, sensors::sensorsNodeStr));
Ed Tanousc1d019a2022-08-06 09:36:06 -07002400}
Ed Tanous7f1cc262022-08-09 13:33:57 -07002401
Patrick Williams504af5a2025-02-03 14:29:03 -05002402inline void getSensorFromDbus(
2403 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2404 const std::string& sensorPath,
2405 const ::dbus::utility::MapperGetObject& mapperResponse)
Ed Tanousc1d019a2022-08-06 09:36:06 -07002406{
2407 if (mapperResponse.size() != 1)
2408 {
2409 messages::internalError(asyncResp->res);
2410 return;
2411 }
2412 const auto& valueIface = *mapperResponse.begin();
2413 const std::string& connectionName = valueIface.first;
Ed Tanous62598e32023-07-17 17:06:25 -07002414 BMCWEB_LOG_DEBUG("Looking up {}", connectionName);
2415 BMCWEB_LOG_DEBUG("Path {}", sensorPath);
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002416
Ed Tanousdeae6a72024-11-11 21:58:57 -08002417 ::dbus::utility::getAllProperties(
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002418 *crow::connections::systemBus, connectionName, sensorPath, "",
Ed Tanousc1d019a2022-08-06 09:36:06 -07002419 [asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002420 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002421 const ::dbus::utility::DBusPropertiesMap& valuesDict) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002422 if (ec)
2423 {
2424 messages::internalError(asyncResp->res);
2425 return;
2426 }
2427 sdbusplus::message::object_path path(sensorPath);
2428 std::string name = path.filename();
2429 path = path.parent_path();
2430 std::string type = path.filename();
Janet Adkinsc9563602024-08-28 11:37:46 -05002431 sensor_utils::objectPropertiesToJson(
Janet Adkins0c728b42024-08-29 11:09:10 -05002432 name, type, sensor_utils::ChassisSubNode::sensorsNode,
2433 valuesDict, asyncResp->res.jsonValue, nullptr);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002434 });
Nan Zhoude167a62022-06-01 04:47:45 +00002435}
2436
Nan Zhoue6bd8462022-06-01 04:35:35 +00002437inline void handleSensorGet(App& app, const crow::Request& req,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002438 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous677bb752022-09-15 10:52:19 -07002439 const std::string& chassisId,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002440 const std::string& sensorId)
Nan Zhoue6bd8462022-06-01 04:35:35 +00002441{
Ed Tanousc1d019a2022-08-06 09:36:06 -07002442 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Nan Zhoue6bd8462022-06-01 04:35:35 +00002443 {
2444 return;
2445 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002446 std::pair<std::string, std::string> nameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002447 redfish::sensor_utils::splitSensorNameAndType(sensorId);
Ed Tanousc71d6122022-11-29 14:10:32 -08002448 if (nameType.first.empty() || nameType.second.empty())
Ed Tanousc1d019a2022-08-06 09:36:06 -07002449 {
2450 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2451 return;
2452 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002453
Ed Tanousef4c65b2023-04-24 15:28:50 -07002454 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2455 "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002456
Ed Tanous62598e32023-07-17 17:06:25 -07002457 BMCWEB_LOG_DEBUG("Sensor doGet enter");
Nan Zhoue6bd8462022-06-01 04:35:35 +00002458
George Liu2b731192023-01-11 16:27:13 +08002459 constexpr std::array<std::string_view, 1> interfaces = {
Nan Zhoue6bd8462022-06-01 04:35:35 +00002460 "xyz.openbmc_project.Sensor.Value"};
Ed Tanousc71d6122022-11-29 14:10:32 -08002461 std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first +
2462 '/' + nameType.second;
Nan Zhoue6bd8462022-06-01 04:35:35 +00002463 // Get a list of all of the sensors that implement Sensor.Value
2464 // and get the path and service name associated with the sensor
George Liu2b731192023-01-11 16:27:13 +08002465 ::dbus::utility::getDbusObject(
2466 sensorPath, interfaces,
Myung Baeaec0ec32023-05-31 15:10:01 -05002467 [asyncResp, sensorId,
George Liu2b731192023-01-11 16:27:13 +08002468 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002469 const ::dbus::utility::MapperGetObject& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002470 BMCWEB_LOG_DEBUG("respHandler1 enter");
2471 if (ec == boost::system::errc::io_error)
2472 {
2473 BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths");
2474 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2475 return;
2476 }
2477 if (ec)
2478 {
2479 messages::internalError(asyncResp->res);
2480 BMCWEB_LOG_ERROR(
2481 "Sensor getSensorPaths resp_handler: Dbus error {}", ec);
2482 return;
2483 }
2484 getSensorFromDbus(asyncResp, sensorPath, subtree);
2485 BMCWEB_LOG_DEBUG("respHandler1 exit");
2486 });
Nan Zhoue6bd8462022-06-01 04:35:35 +00002487}
2488
Nan Zhoubacb2162022-04-06 11:28:32 -07002489} // namespace sensors
2490
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002491inline void requestRoutesSensorCollection(App& app)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002492{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002493 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
Ed Tanoused398212021-06-09 17:05:54 -07002494 .privileges(redfish::privileges::getSensorCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002495 .methods(boost::beast::http::verb::get)(
Nan Zhoude167a62022-06-01 04:47:45 +00002496 std::bind_front(sensors::handleSensorCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002497}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002498
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002499inline void requestRoutesSensor(App& app)
2500{
2501 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002502 .privileges(redfish::privileges::getSensor)
Ed Tanous002d39b2022-05-31 08:59:27 -07002503 .methods(boost::beast::http::verb::get)(
Nan Zhoue6bd8462022-06-01 04:35:35 +00002504 std::bind_front(sensors::handleSensorGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002505}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002506
Ed Tanous1abe55e2018-09-05 08:30:59 -07002507} // namespace redfish